From 5330c014111101f7bf02bf87c2fa2b1b47592944 Mon Sep 17 00:00:00 2001 From: <> Date: Wed, 18 Sep 2024 15:47:02 +0000 Subject: [PATCH] Deployed 681bef8 with MkDocs version: 1.6.1 --- .nojekyll | 0 404.html | 2332 ++++ CNAME | 1 + README.md | 447 + README_backup/README_backup.md | 224 + README_backup/index.html | 2668 +++++ assets/_mkdocstrings.css | 119 + assets/images/favicon.png | Bin 0 -> 1870 bytes assets/javascripts/bundle.56dfad97.min.js | 16 + assets/javascripts/bundle.56dfad97.min.js.map | 7 + assets/javascripts/lunr/min/lunr.ar.min.js | 1 + assets/javascripts/lunr/min/lunr.da.min.js | 18 + assets/javascripts/lunr/min/lunr.de.min.js | 18 + assets/javascripts/lunr/min/lunr.du.min.js | 18 + assets/javascripts/lunr/min/lunr.el.min.js | 1 + assets/javascripts/lunr/min/lunr.es.min.js | 18 + assets/javascripts/lunr/min/lunr.fi.min.js | 18 + assets/javascripts/lunr/min/lunr.fr.min.js | 18 + assets/javascripts/lunr/min/lunr.he.min.js | 1 + assets/javascripts/lunr/min/lunr.hi.min.js | 1 + assets/javascripts/lunr/min/lunr.hu.min.js | 18 + assets/javascripts/lunr/min/lunr.hy.min.js | 1 + assets/javascripts/lunr/min/lunr.it.min.js | 18 + assets/javascripts/lunr/min/lunr.ja.min.js | 1 + assets/javascripts/lunr/min/lunr.jp.min.js | 1 + assets/javascripts/lunr/min/lunr.kn.min.js | 1 + assets/javascripts/lunr/min/lunr.ko.min.js | 1 + assets/javascripts/lunr/min/lunr.multi.min.js | 1 + assets/javascripts/lunr/min/lunr.nl.min.js | 18 + assets/javascripts/lunr/min/lunr.no.min.js | 18 + assets/javascripts/lunr/min/lunr.pt.min.js | 18 + assets/javascripts/lunr/min/lunr.ro.min.js | 18 + assets/javascripts/lunr/min/lunr.ru.min.js | 18 + assets/javascripts/lunr/min/lunr.sa.min.js | 1 + .../lunr/min/lunr.stemmer.support.min.js | 1 + assets/javascripts/lunr/min/lunr.sv.min.js | 18 + assets/javascripts/lunr/min/lunr.ta.min.js | 1 + assets/javascripts/lunr/min/lunr.te.min.js | 1 + assets/javascripts/lunr/min/lunr.th.min.js | 1 + assets/javascripts/lunr/min/lunr.tr.min.js | 18 + assets/javascripts/lunr/min/lunr.vi.min.js | 1 + assets/javascripts/lunr/min/lunr.zh.min.js | 1 + assets/javascripts/lunr/tinyseg.js | 206 + assets/javascripts/lunr/wordcut.js | 6708 ++++++++++++ .../workers/search.6ce7567c.min.js | 42 + .../workers/search.6ce7567c.min.js.map | 7 + assets/stylesheets/main.35f28582.min.css | 1 + assets/stylesheets/main.35f28582.min.css.map | 1 + assets/stylesheets/palette.06af60db.min.css | 1 + .../stylesheets/palette.06af60db.min.css.map | 1 + configs/__init__.py | 1 + configs/callbacks/default.yaml | 19 + configs/callbacks/early_stopping.yaml | 17 + configs/callbacks/learning_rate_monitor.yaml | 3 + configs/callbacks/model_checkpoint.yaml | 19 + configs/callbacks/model_summary.yaml | 7 + configs/callbacks/rich_progress_bar.yaml | 6 + configs/callbacks/speed_monitor.yaml | 7 + configs/debug/default.yaml | 45 + configs/debug/fdr.yaml | 9 + configs/debug/limit.yaml | 12 + configs/debug/overfit.yaml | 13 + configs/debug/profiler.yaml | 12 + configs/env/cvrp.yaml | 10 + configs/env/cvrptw.yaml | 10 + configs/env/default.yaml | 6 + configs/env/dpp.yaml | 10 + configs/env/ffsp.yaml | 10 + configs/env/fjsp/10j-5m.yaml | 13 + configs/env/fjsp/15j-10m.yaml | 13 + configs/env/fjsp/20j-10m.yaml | 13 + configs/env/fjsp/20j-5m.yaml | 13 + configs/env/jssp/10j-10m.yaml | 11 + configs/env/jssp/15j-15m.yaml | 11 + configs/env/jssp/20j-20m.yaml | 11 + configs/env/jssp/6j-6m.yaml | 11 + configs/env/mdcpdp.yaml | 13 + configs/env/mdpp.yaml | 11 + configs/env/mtsp.yaml | 11 + configs/env/op.yaml | 10 + configs/env/pctsp.yaml | 9 + configs/env/pdp.yaml | 12 + configs/env/sdvrp.yaml | 10 + configs/env/spctsp.yaml | 10 + configs/env/svrp.yaml | 10 + configs/env/tsp.yaml | 10 + configs/experiment/base.yaml | 48 + configs/experiment/eda/am-a2c.yaml | 35 + configs/experiment/eda/am-ppo.yaml | 42 + configs/experiment/eda/am.yaml | 30 + configs/experiment/graph/am.yaml | 30 + configs/experiment/routing/am-a2c.yaml | 22 + configs/experiment/routing/am-ppo.yaml | 52 + configs/experiment/routing/am-svrp.yaml | 40 + configs/experiment/routing/am-xl.yaml | 45 + configs/experiment/routing/am.yaml | 42 + configs/experiment/routing/ar-gnn.yaml | 47 + configs/experiment/routing/deepaco.yaml | 55 + configs/experiment/routing/mdpomo.yaml | 41 + configs/experiment/routing/polynet.yaml | 44 + configs/experiment/routing/pomo.yaml | 40 + configs/experiment/routing/ptrnet.yaml | 45 + configs/experiment/routing/symnco.yaml | 43 + .../experiment/routing/tsp-stepwise-ppo.yaml | 57 + configs/experiment/scheduling/am-pomo.yaml | 24 + configs/experiment/scheduling/am-ppo.yaml | 50 + configs/experiment/scheduling/base.yaml | 40 + .../experiment/scheduling/ffsp-matnet.yaml | 46 + configs/experiment/scheduling/gnn-ppo.yaml | 33 + configs/experiment/scheduling/hgnn-pomo.yaml | 28 + configs/experiment/scheduling/hgnn-ppo.yaml | 27 + .../experiment/scheduling/matnet-pomo.yaml | 38 + configs/experiment/scheduling/matnet-ppo.yaml | 42 + configs/extras/default.yaml | 8 + configs/hydra/default.yaml | 14 + configs/logger/aim.yaml | 28 + configs/logger/comet.yaml | 12 + configs/logger/csv.yaml | 7 + configs/logger/many_loggers.yaml | 9 + configs/logger/mlflow.yaml | 12 + configs/logger/neptune.yaml | 9 + configs/logger/none.yaml | 1 + configs/logger/tensorboard.yaml | 10 + configs/logger/wandb.yaml | 25 + configs/main.yaml | 65 + configs/model/am-ppo.yaml | 4 + configs/model/am.yaml | 3 + configs/model/deepaco.yaml | 3 + configs/model/default.yaml | 2 + configs/model/ham.yaml | 1 + configs/model/l2d.yaml | 1 + configs/model/matnet.yaml | 7 + configs/model/mdam.yaml | 1 + configs/model/polynet.yaml | 11 + configs/model/pomo.yaml | 10 + configs/model/ptrnet.yaml | 1 + configs/model/symnco.yaml | 10 + configs/paths/default.yaml | 18 + configs/trainer/default.yaml | 15 + docs/README.md | 26 + docs/__pycache__/hooks.cpython-312.pyc | Bin 0 -> 3662 bytes docs/assets/figs/MIT_logo.svg | 9 + docs/assets/figs/embeddings.png | Bin 0 -> 39019 bytes docs/assets/figs/framework.png | Bin 0 -> 28745 bytes docs/assets/figs/policies.png | Bin 0 -> 78113 bytes docs/assets/figs/rl4co-logo.svg | 38 + docs/assets/rl4co_animated_full_tricks.svg | 77 + docs/content/api/data/data.md | 23 + docs/content/api/data/index.html | 4656 ++++++++ docs/content/api/decoding/decoding.md | 5 + docs/content/api/decoding/index.html | 4437 ++++++++ docs/content/api/envs/base/base.md | 15 + docs/content/api/envs/base/index.html | 4135 +++++++ docs/content/api/envs/eda/eda.md | 14 + docs/content/api/envs/eda/index.html | 3397 ++++++ docs/content/api/envs/graph/graph.md | 14 + docs/content/api/envs/graph/index.html | 3184 ++++++ docs/content/api/envs/routing/index.html | 8328 ++++++++++++++ docs/content/api/envs/routing/routing.md | 61 + docs/content/api/envs/scheduling/index.html | 4005 +++++++ .../content/api/envs/scheduling/scheduling.md | 26 + .../networks/base_policies/base_policies.md | 42 + .../api/networks/base_policies/index.html | 5102 +++++++++ .../networks/env_embeddings/env_embeddings.md | 34 + .../api/networks/env_embeddings/index.html | 5046 +++++++++ .../improvement_policies.md | 7 + .../networks/improvement_policies/index.html | 3056 ++++++ docs/content/api/networks/nn/index.html | 5946 ++++++++++ docs/content/api/networks/nn/nn.md | 29 + docs/content/api/rl/a2c/a2c.md | 1 + docs/content/api/rl/a2c/index.html | 2685 +++++ docs/content/api/rl/base/base.md | 19 + docs/content/api/rl/base/index.html | 4206 ++++++++ docs/content/api/rl/ppo/index.html | 2718 +++++ docs/content/api/rl/ppo/ppo.md | 1 + docs/content/api/rl/reinforce/index.html | 4957 +++++++++ docs/content/api/rl/reinforce/reinforce.md | 10 + docs/content/api/tasks/index.html | 3491 ++++++ docs/content/api/tasks/tasks.md | 9 + docs/content/api/train_and_eval/index.html | 2357 ++++ .../api/train_and_eval/train_and_eval.md | 0 .../zoo/constructive_ar/constructive_ar.md | 113 + .../api/zoo/constructive_ar/index.html | 9594 +++++++++++++++++ .../zoo/constructive_nar/constructive_nar.md | 27 + .../api/zoo/constructive_nar/index.html | 5212 +++++++++ .../api/zoo/improvement/improvement.md | 55 + docs/content/api/zoo/improvement/index.html | 7042 ++++++++++++ docs/content/api/zoo/transductive/index.html | 5074 +++++++++ .../api/zoo/transductive/transductive.md | 23 + docs/content/general/ai4co/ai4co.md | 14 + docs/content/general/ai4co/index.html | 2447 +++++ docs/content/general/contribute/contribute.md | 14 + docs/content/general/contribute/index.html | 2447 +++++ docs/content/general/faq/faq.md | 24 + docs/content/general/faq/index.html | 2448 +++++ docs/content/general/licensing/index.html | 2390 ++++ docs/content/general/licensing/licensing.md | 14 + docs/content/general/paper/index.html | 2445 +++++ docs/content/general/paper/paper.md | 15 + .../intro/environments/environments.md | 193 + docs/content/intro/environments/index.html | 2944 +++++ docs/content/intro/intro/index.html | 2555 +++++ docs/content/intro/intro/intro.md | 49 + docs/content/intro/policies/index.html | 2556 +++++ docs/content/intro/policies/policies.md | 53 + docs/content/intro/rl/index.html | 2498 +++++ docs/content/intro/rl/rl.md | 43 + docs/content/start/hydra/hydra.md | 166 + docs/content/start/hydra/index.html | 2726 +++++ docs/content/start/installation/index.html | 2491 +++++ .../start/installation/installation.md | 45 + docs/hooks.py | 61 + docs/index.html | 2410 +++++ docs/js/autolink.js | 34 + docs/js/katex.js | 10 + docs/js/tsparticles.js | 2 + docs/overrides/fancylogo.txt | 257 + docs/overrides/main.html | 12 + docs/stylesheets/extra.css | 30 + docs/stylesheets/mkdocstrings.css | 54 + examples/1-quickstart/1-quickstart.ipynb | 455 + examples/1-quickstart/index.html | 3735 +++++++ .../2-full-training/2-full-training.ipynb | 937 ++ examples/2-full-training/index.html | 4469 ++++++++ examples/2b-train-simple.py | 69 + examples/2d-meta_train.py | 80 + .../3-creating-new-env-model.ipynb | 941 ++ examples/3-creating-new-env-model/index.html | 4916 +++++++++ examples/README.md | 30 + .../1-hydra-config/1-hydra-config.ipynb | 430 + examples/advanced/1-hydra-config/index.html | 3592 ++++++ .../2-flash-attention-2.ipynb | 410 + .../advanced/2-flash-attention-2/index.html | 3541 ++++++ .../3-local-search/3-local-search.ipynb | 185 + examples/advanced/3-local-search/index.html | 3235 ++++++ examples/advanced/README.md | 9 + examples/advanced/index.html | 2385 ++++ .../1-test-on-tsplib/1-test-on-tsplib.ipynb | 637 ++ examples/datasets/1-test-on-tsplib/index.html | 4090 +++++++ .../2-test-on-cvrplib/2-test-on-cvrplib.ipynb | 537 + .../datasets/2-test-on-cvrplib/index.html | 3949 +++++++ examples/datasets/README.md | 9 + examples/datasets/index.html | 2385 ++++ examples/index.html | 2449 +++++ .../1-decoding-strategies.ipynb | 679 ++ .../modeling/1-decoding-strategies/index.html | 4269 ++++++++ .../2-transductive-methods.ipynb | 436 + .../2-transductive-methods/index.html | 3625 +++++++ .../3-change-encoder/3-change-encoder.ipynb | 520 + examples/modeling/3-change-encoder/index.html | 3669 +++++++ examples/modeling/README.md | 10 + examples/modeling/index.html | 2386 ++++ examples/other/1-mtvrp/1-mtvrp.ipynb | 647 ++ examples/other/1-mtvrp/index.html | 3996 +++++++ .../other/2-scheduling/2-scheduling.ipynb | 829 ++ examples/other/2-scheduling/index.html | 4336 ++++++++ .../3-data-generator-distributions.ipynb | 372 + .../3-data-generator-distributions/index.html | 3483 ++++++ examples/other/README.md | 9 + examples/other/index.html | 2386 ++++ index.html | 3069 ++++++ objects.inv | Bin 0 -> 3291 bytes rl4co/__init__.py | 4 + rl4co/data/__init__.py | 0 rl4co/data/dataset.py | 134 + rl4co/data/generate_data.py | 386 + rl4co/data/transforms.py | 150 + rl4co/data/utils.py | 71 + rl4co/envs/__init__.py | 77 + rl4co/envs/common/__init__.py | 2 + rl4co/envs/common/base.py | 403 + rl4co/envs/common/distribution_utils.py | 292 + rl4co/envs/common/utils.py | 109 + rl4co/envs/eda/__init__.py | 2 + rl4co/envs/eda/dpp/__init__.py | 0 rl4co/envs/eda/dpp/env.py | 260 + rl4co/envs/eda/dpp/generator.py | 169 + rl4co/envs/eda/dpp/render.py | 84 + rl4co/envs/eda/mdpp/__init__.py | 0 rl4co/envs/eda/mdpp/env.py | 161 + rl4co/envs/eda/mdpp/generator.py | 178 + rl4co/envs/eda/mdpp/render.py | 161 + rl4co/envs/graph/__init__.py | 4 + rl4co/envs/graph/flp/__init__.py | 0 rl4co/envs/graph/flp/env.py | 169 + rl4co/envs/graph/flp/generator.py | 74 + rl4co/envs/graph/mcp/__init__.py | 0 rl4co/envs/graph/mcp/env.py | 193 + rl4co/envs/graph/mcp/generator.py | 138 + rl4co/envs/routing/__init__.py | 24 + rl4co/envs/routing/atsp/__init__.py | 0 rl4co/envs/routing/atsp/env.py | 173 + rl4co/envs/routing/atsp/generator.py | 71 + rl4co/envs/routing/atsp/render.py | 50 + rl4co/envs/routing/cvrp/__init__.py | 0 rl4co/envs/routing/cvrp/env.py | 258 + rl4co/envs/routing/cvrp/generator.py | 143 + rl4co/envs/routing/cvrp/local_search.py | 215 + rl4co/envs/routing/cvrp/render.py | 133 + rl4co/envs/routing/cvrptw/__init__.py | 0 rl4co/envs/routing/cvrptw/env.py | 291 + rl4co/envs/routing/cvrptw/generator.py | 162 + rl4co/envs/routing/cvrptw/render.py | 133 + rl4co/envs/routing/mdcpdp/__init__.py | 0 rl4co/envs/routing/mdcpdp/env.py | 354 + rl4co/envs/routing/mdcpdp/generator.py | 126 + rl4co/envs/routing/mdcpdp/render.py | 120 + rl4co/envs/routing/mpdp/__init__.py | 0 rl4co/envs/routing/mpdp/env.py | 405 + rl4co/envs/routing/mpdp/generator.py | 95 + rl4co/envs/routing/mpdp/render.py | 114 + rl4co/envs/routing/mtsp/__init__.py | 0 rl4co/envs/routing/mtsp/env.py | 246 + rl4co/envs/routing/mtsp/generator.py | 72 + rl4co/envs/routing/mtsp/render.py | 95 + rl4co/envs/routing/mtvrp/__init__.py | 0 .../envs/routing/mtvrp/baselines/__init__.py | 0 .../envs/routing/mtvrp/baselines/constants.py | 42 + rl4co/envs/routing/mtvrp/baselines/lkh.py | 214 + rl4co/envs/routing/mtvrp/baselines/ortools.py | 248 + rl4co/envs/routing/mtvrp/baselines/pyvrp.py | 109 + rl4co/envs/routing/mtvrp/baselines/solve.py | 83 + rl4co/envs/routing/mtvrp/baselines/utils.py | 36 + rl4co/envs/routing/mtvrp/env.py | 503 + rl4co/envs/routing/mtvrp/generator.py | 436 + rl4co/envs/routing/mtvrp/render.py | 145 + rl4co/envs/routing/op/__init__.py | 0 rl4co/envs/routing/op/env.py | 262 + rl4co/envs/routing/op/generator.py | 149 + rl4co/envs/routing/op/render.py | 86 + rl4co/envs/routing/pctsp/__init__.py | 0 rl4co/envs/routing/pctsp/env.py | 284 + rl4co/envs/routing/pctsp/generator.py | 143 + rl4co/envs/routing/pctsp/render.py | 93 + rl4co/envs/routing/pdp/__init__.py | 0 rl4co/envs/routing/pdp/env.py | 535 + rl4co/envs/routing/pdp/generator.py | 152 + rl4co/envs/routing/pdp/render.py | 142 + rl4co/envs/routing/sdvrp/__init__.py | 0 rl4co/envs/routing/sdvrp/env.py | 210 + rl4co/envs/routing/spctsp/__init__.py | 0 rl4co/envs/routing/spctsp/env.py | 31 + rl4co/envs/routing/svrp/__init__.py | 0 rl4co/envs/routing/svrp/env.py | 255 + rl4co/envs/routing/svrp/generator.py | 107 + rl4co/envs/routing/svrp/render.py | 103 + rl4co/envs/routing/tsp/__init__.py | 0 rl4co/envs/routing/tsp/env.py | 606 ++ rl4co/envs/routing/tsp/generator.py | 99 + rl4co/envs/routing/tsp/local_search.py | 74 + rl4co/envs/routing/tsp/render.py | 110 + rl4co/envs/scheduling/__init__.py | 4 + rl4co/envs/scheduling/ffsp/__init__.py | 0 rl4co/envs/scheduling/ffsp/env.py | 458 + rl4co/envs/scheduling/ffsp/generator.py | 65 + rl4co/envs/scheduling/ffsp/render.py | 72 + rl4co/envs/scheduling/fjsp/__init__.py | 2 + rl4co/envs/scheduling/fjsp/env.py | 508 + rl4co/envs/scheduling/fjsp/generator.py | 238 + rl4co/envs/scheduling/fjsp/parser.py | 180 + rl4co/envs/scheduling/fjsp/render.py | 72 + rl4co/envs/scheduling/fjsp/utils.py | 334 + rl4co/envs/scheduling/jssp/__init__.py | 0 rl4co/envs/scheduling/jssp/env.py | 123 + rl4co/envs/scheduling/jssp/generator.py | 208 + rl4co/envs/scheduling/jssp/parser.py | 110 + rl4co/envs/scheduling/smtwtp/__init__.py | 0 rl4co/envs/scheduling/smtwtp/env.py | 203 + rl4co/envs/scheduling/smtwtp/generator.py | 88 + rl4co/envs/scheduling/smtwtp/render.py | 15 + rl4co/models/__init__.py | 49 + rl4co/models/common/__init__.py | 21 + rl4co/models/common/constructive/__init__.py | 15 + .../constructive/autoregressive/__init__.py | 3 + .../constructive/autoregressive/decoder.py | 13 + .../constructive/autoregressive/encoder.py | 13 + .../constructive/autoregressive/policy.py | 46 + rl4co/models/common/constructive/base.py | 268 + .../nonautoregressive/__init__.py | 9 + .../constructive/nonautoregressive/decoder.py | 40 + .../constructive/nonautoregressive/encoder.py | 13 + .../constructive/nonautoregressive/policy.py | 40 + rl4co/models/common/improvement/__init__.py | 1 + rl4co/models/common/improvement/base.py | 146 + rl4co/models/common/transductive/__init__.py | 1 + rl4co/models/common/transductive/base.py | 93 + rl4co/models/nn/__init__.py | 0 rl4co/models/nn/attention.py | 537 + rl4co/models/nn/env_embeddings/__init__.py | 4 + rl4co/models/nn/env_embeddings/context.py | 372 + rl4co/models/nn/env_embeddings/dynamic.py | 121 + rl4co/models/nn/env_embeddings/edge.py | 153 + rl4co/models/nn/env_embeddings/init.py | 512 + rl4co/models/nn/flash_attention.py | 64 + rl4co/models/nn/graph/__init__.py | 0 rl4co/models/nn/graph/attnnet.py | 103 + rl4co/models/nn/graph/gcn.py | 114 + rl4co/models/nn/graph/gnn.py | 99 + rl4co/models/nn/graph/hgnn.py | 133 + rl4co/models/nn/graph/mpnn.py | 173 + rl4co/models/nn/mlp.py | 80 + rl4co/models/nn/moe.py | 277 + rl4co/models/nn/ops.py | 137 + rl4co/models/nn/pos_embeddings.py | 159 + rl4co/models/rl/__init__.py | 6 + rl4co/models/rl/a2c/__init__.py | 0 rl4co/models/rl/a2c/a2c.py | 58 + rl4co/models/rl/common/__init__.py | 0 rl4co/models/rl/common/base.py | 333 + rl4co/models/rl/common/critic.py | 77 + rl4co/models/rl/common/utils.py | 48 + rl4co/models/rl/ppo/__init__.py | 0 rl4co/models/rl/ppo/n_step_ppo.py | 282 + rl4co/models/rl/ppo/ppo.py | 235 + rl4co/models/rl/ppo/stepwise_ppo.py | 171 + rl4co/models/rl/reinforce/__init__.py | 0 rl4co/models/rl/reinforce/baselines.py | 311 + rl4co/models/rl/reinforce/reinforce.py | 210 + rl4co/models/zoo/__init__.py | 30 + rl4co/models/zoo/active_search/__init__.py | 1 + rl4co/models/zoo/active_search/search.py | 203 + rl4co/models/zoo/am/__init__.py | 2 + rl4co/models/zoo/am/decoder.py | 235 + rl4co/models/zoo/am/encoder.py | 91 + rl4co/models/zoo/am/model.py | 34 + rl4co/models/zoo/am/policy.py | 122 + rl4co/models/zoo/amppo/__init__.py | 1 + rl4co/models/zoo/amppo/model.py | 49 + rl4co/models/zoo/dact/__init__.py | 2 + rl4co/models/zoo/dact/decoder.py | 132 + rl4co/models/zoo/dact/encoder.py | 274 + rl4co/models/zoo/dact/model.py | 62 + rl4co/models/zoo/dact/policy.py | 186 + rl4co/models/zoo/deepaco/__init__.py | 2 + rl4co/models/zoo/deepaco/antsystem.py | 347 + rl4co/models/zoo/deepaco/model.py | 51 + rl4co/models/zoo/deepaco/policy.py | 147 + rl4co/models/zoo/eas/__init__.py | 1 + rl4co/models/zoo/eas/decoder.py | 128 + rl4co/models/zoo/eas/nn.py | 30 + rl4co/models/zoo/eas/search.py | 346 + rl4co/models/zoo/ham/__init__.py | 2 + rl4co/models/zoo/ham/attention.py | 488 + rl4co/models/zoo/ham/encoder.py | 73 + rl4co/models/zoo/ham/model.py | 37 + rl4co/models/zoo/ham/policy.py | 62 + rl4co/models/zoo/l2d/__init__.py | 2 + rl4co/models/zoo/l2d/decoder.py | 389 + rl4co/models/zoo/l2d/encoder.py | 26 + rl4co/models/zoo/l2d/model.py | 69 + rl4co/models/zoo/l2d/policy.py | 251 + rl4co/models/zoo/matnet/__init__.py | 2 + rl4co/models/zoo/matnet/decoder.py | 157 + rl4co/models/zoo/matnet/encoder.py | 224 + rl4co/models/zoo/matnet/matnet_w_sa.py | 202 + rl4co/models/zoo/matnet/model.py | 54 + rl4co/models/zoo/matnet/policy.py | 210 + rl4co/models/zoo/mdam/__init__.py | 2 + rl4co/models/zoo/mdam/decoder.py | 331 + rl4co/models/zoo/mdam/encoder.py | 101 + rl4co/models/zoo/mdam/mha.py | 87 + rl4co/models/zoo/mdam/model.py | 125 + rl4co/models/zoo/mdam/policy.py | 90 + rl4co/models/zoo/mvmoe/__init__.py | 2 + rl4co/models/zoo/mvmoe/model.py | 79 + rl4co/models/zoo/n2s/__init__.py | 2 + rl4co/models/zoo/n2s/decoder.py | 261 + rl4co/models/zoo/n2s/encoder.py | 217 + rl4co/models/zoo/n2s/model.py | 62 + rl4co/models/zoo/n2s/policy.py | 220 + rl4co/models/zoo/nargnn/__init__.py | 2 + rl4co/models/zoo/nargnn/encoder.py | 212 + rl4co/models/zoo/nargnn/policy.py | 107 + rl4co/models/zoo/neuopt/__init__.py | 2 + rl4co/models/zoo/neuopt/decoder.py | 77 + rl4co/models/zoo/neuopt/model.py | 62 + rl4co/models/zoo/neuopt/policy.py | 300 + rl4co/models/zoo/polynet/__init__.py | 1 + rl4co/models/zoo/polynet/decoder.py | 145 + rl4co/models/zoo/polynet/model.py | 241 + rl4co/models/zoo/polynet/policy.py | 101 + rl4co/models/zoo/pomo/__init__.py | 1 + rl4co/models/zoo/pomo/model.py | 144 + rl4co/models/zoo/ptrnet/__init__.py | 2 + rl4co/models/zoo/ptrnet/critic.py | 58 + rl4co/models/zoo/ptrnet/decoder.py | 182 + rl4co/models/zoo/ptrnet/encoder.py | 29 + rl4co/models/zoo/ptrnet/model.py | 35 + rl4co/models/zoo/ptrnet/policy.py | 107 + rl4co/models/zoo/symnco/__init__.py | 2 + rl4co/models/zoo/symnco/losses.py | 39 + rl4co/models/zoo/symnco/model.py | 142 + rl4co/models/zoo/symnco/policy.py | 91 + rl4co/tasks/README.md | 103 + rl4co/tasks/__init__.py | 0 rl4co/tasks/eval.py | 595 + rl4co/tasks/index.html | 2454 +++++ rl4co/tasks/train.py | 117 + rl4co/utils/__init__.py | 11 + rl4co/utils/callbacks/__init__.py | 0 rl4co/utils/callbacks/speed_monitor.py | 123 + rl4co/utils/decoding.py | 584 + rl4co/utils/instantiators.py | 61 + rl4co/utils/lightning.py | 76 + rl4co/utils/meta_trainer.py | 170 + rl4co/utils/ops.py | 262 + rl4co/utils/optim_helpers.py | 38 + rl4co/utils/pylogger.py | 25 + rl4co/utils/rich_utils.py | 97 + rl4co/utils/test_utils.py | 71 + rl4co/utils/trainer.py | 152 + rl4co/utils/utils.py | 285 + search/search_index.json | 1 + sitemap.xml | 223 + sitemap.xml.gz | Bin 0 -> 678 bytes tests/__init__.py | 0 tests/test_envs.py | 157 + tests/test_policy.py | 88 + tests/test_tasks.py | 78 + tests/test_training.py | 312 + tests/test_utils.py | 37 + 521 files changed, 258291 insertions(+) create mode 100644 .nojekyll create mode 100644 404.html create mode 100644 CNAME create mode 100644 README.md create mode 100644 README_backup/README_backup.md create mode 100644 README_backup/index.html create mode 100644 assets/_mkdocstrings.css create mode 100644 assets/images/favicon.png create mode 100644 assets/javascripts/bundle.56dfad97.min.js create mode 100644 assets/javascripts/bundle.56dfad97.min.js.map create mode 100644 assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 assets/javascripts/lunr/min/lunr.el.min.js create mode 100644 assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.he.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hy.min.js create mode 100644 assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 assets/javascripts/lunr/min/lunr.kn.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ko.min.js create mode 100644 assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sa.min.js create mode 100644 assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ta.min.js create mode 100644 assets/javascripts/lunr/min/lunr.te.min.js create mode 100644 assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 assets/javascripts/lunr/tinyseg.js create mode 100644 assets/javascripts/lunr/wordcut.js create mode 100644 assets/javascripts/workers/search.6ce7567c.min.js create mode 100644 assets/javascripts/workers/search.6ce7567c.min.js.map create mode 100644 assets/stylesheets/main.35f28582.min.css create mode 100644 assets/stylesheets/main.35f28582.min.css.map create mode 100644 assets/stylesheets/palette.06af60db.min.css create mode 100644 assets/stylesheets/palette.06af60db.min.css.map create mode 100644 configs/__init__.py create mode 100644 configs/callbacks/default.yaml create mode 100644 configs/callbacks/early_stopping.yaml create mode 100644 configs/callbacks/learning_rate_monitor.yaml create mode 100644 configs/callbacks/model_checkpoint.yaml create mode 100644 configs/callbacks/model_summary.yaml create mode 100644 configs/callbacks/rich_progress_bar.yaml create mode 100644 configs/callbacks/speed_monitor.yaml create mode 100644 configs/debug/default.yaml create mode 100644 configs/debug/fdr.yaml create mode 100644 configs/debug/limit.yaml create mode 100644 configs/debug/overfit.yaml create mode 100644 configs/debug/profiler.yaml create mode 100644 configs/env/cvrp.yaml create mode 100644 configs/env/cvrptw.yaml create mode 100644 configs/env/default.yaml create mode 100644 configs/env/dpp.yaml create mode 100644 configs/env/ffsp.yaml create mode 100644 configs/env/fjsp/10j-5m.yaml create mode 100644 configs/env/fjsp/15j-10m.yaml create mode 100644 configs/env/fjsp/20j-10m.yaml create mode 100644 configs/env/fjsp/20j-5m.yaml create mode 100644 configs/env/jssp/10j-10m.yaml create mode 100644 configs/env/jssp/15j-15m.yaml create mode 100644 configs/env/jssp/20j-20m.yaml create mode 100644 configs/env/jssp/6j-6m.yaml create mode 100644 configs/env/mdcpdp.yaml create mode 100644 configs/env/mdpp.yaml create mode 100644 configs/env/mtsp.yaml create mode 100644 configs/env/op.yaml create mode 100644 configs/env/pctsp.yaml create mode 100644 configs/env/pdp.yaml create mode 100644 configs/env/sdvrp.yaml create mode 100644 configs/env/spctsp.yaml create mode 100644 configs/env/svrp.yaml create mode 100644 configs/env/tsp.yaml create mode 100644 configs/experiment/base.yaml create mode 100644 configs/experiment/eda/am-a2c.yaml create mode 100644 configs/experiment/eda/am-ppo.yaml create mode 100644 configs/experiment/eda/am.yaml create mode 100644 configs/experiment/graph/am.yaml create mode 100644 configs/experiment/routing/am-a2c.yaml create mode 100644 configs/experiment/routing/am-ppo.yaml create mode 100644 configs/experiment/routing/am-svrp.yaml create mode 100644 configs/experiment/routing/am-xl.yaml create mode 100644 configs/experiment/routing/am.yaml create mode 100644 configs/experiment/routing/ar-gnn.yaml create mode 100644 configs/experiment/routing/deepaco.yaml create mode 100644 configs/experiment/routing/mdpomo.yaml create mode 100644 configs/experiment/routing/polynet.yaml create mode 100644 configs/experiment/routing/pomo.yaml create mode 100644 configs/experiment/routing/ptrnet.yaml create mode 100644 configs/experiment/routing/symnco.yaml create mode 100644 configs/experiment/routing/tsp-stepwise-ppo.yaml create mode 100644 configs/experiment/scheduling/am-pomo.yaml create mode 100644 configs/experiment/scheduling/am-ppo.yaml create mode 100644 configs/experiment/scheduling/base.yaml create mode 100644 configs/experiment/scheduling/ffsp-matnet.yaml create mode 100644 configs/experiment/scheduling/gnn-ppo.yaml create mode 100644 configs/experiment/scheduling/hgnn-pomo.yaml create mode 100644 configs/experiment/scheduling/hgnn-ppo.yaml create mode 100644 configs/experiment/scheduling/matnet-pomo.yaml create mode 100644 configs/experiment/scheduling/matnet-ppo.yaml create mode 100644 configs/extras/default.yaml create mode 100644 configs/hydra/default.yaml create mode 100644 configs/logger/aim.yaml create mode 100644 configs/logger/comet.yaml create mode 100644 configs/logger/csv.yaml create mode 100644 configs/logger/many_loggers.yaml create mode 100644 configs/logger/mlflow.yaml create mode 100644 configs/logger/neptune.yaml create mode 100644 configs/logger/none.yaml create mode 100644 configs/logger/tensorboard.yaml create mode 100644 configs/logger/wandb.yaml create mode 100644 configs/main.yaml create mode 100644 configs/model/am-ppo.yaml create mode 100644 configs/model/am.yaml create mode 100644 configs/model/deepaco.yaml create mode 100644 configs/model/default.yaml create mode 100644 configs/model/ham.yaml create mode 100644 configs/model/l2d.yaml create mode 100644 configs/model/matnet.yaml create mode 100644 configs/model/mdam.yaml create mode 100644 configs/model/polynet.yaml create mode 100644 configs/model/pomo.yaml create mode 100644 configs/model/ptrnet.yaml create mode 100644 configs/model/symnco.yaml create mode 100644 configs/paths/default.yaml create mode 100644 configs/trainer/default.yaml create mode 100644 docs/README.md create mode 100644 docs/__pycache__/hooks.cpython-312.pyc create mode 100644 docs/assets/figs/MIT_logo.svg create mode 100644 docs/assets/figs/embeddings.png create mode 100644 docs/assets/figs/framework.png create mode 100644 docs/assets/figs/policies.png create mode 100644 docs/assets/figs/rl4co-logo.svg create mode 100644 docs/assets/rl4co_animated_full_tricks.svg create mode 100644 docs/content/api/data/data.md create mode 100644 docs/content/api/data/index.html create mode 100644 docs/content/api/decoding/decoding.md create mode 100644 docs/content/api/decoding/index.html create mode 100644 docs/content/api/envs/base/base.md create mode 100644 docs/content/api/envs/base/index.html create mode 100644 docs/content/api/envs/eda/eda.md create mode 100644 docs/content/api/envs/eda/index.html create mode 100644 docs/content/api/envs/graph/graph.md create mode 100644 docs/content/api/envs/graph/index.html create mode 100644 docs/content/api/envs/routing/index.html create mode 100644 docs/content/api/envs/routing/routing.md create mode 100644 docs/content/api/envs/scheduling/index.html create mode 100644 docs/content/api/envs/scheduling/scheduling.md create mode 100644 docs/content/api/networks/base_policies/base_policies.md create mode 100644 docs/content/api/networks/base_policies/index.html create mode 100644 docs/content/api/networks/env_embeddings/env_embeddings.md create mode 100644 docs/content/api/networks/env_embeddings/index.html create mode 100644 docs/content/api/networks/improvement_policies/improvement_policies.md create mode 100644 docs/content/api/networks/improvement_policies/index.html create mode 100644 docs/content/api/networks/nn/index.html create mode 100644 docs/content/api/networks/nn/nn.md create mode 100644 docs/content/api/rl/a2c/a2c.md create mode 100644 docs/content/api/rl/a2c/index.html create mode 100644 docs/content/api/rl/base/base.md create mode 100644 docs/content/api/rl/base/index.html create mode 100644 docs/content/api/rl/ppo/index.html create mode 100644 docs/content/api/rl/ppo/ppo.md create mode 100644 docs/content/api/rl/reinforce/index.html create mode 100644 docs/content/api/rl/reinforce/reinforce.md create mode 100644 docs/content/api/tasks/index.html create mode 100644 docs/content/api/tasks/tasks.md create mode 100644 docs/content/api/train_and_eval/index.html create mode 100644 docs/content/api/train_and_eval/train_and_eval.md create mode 100644 docs/content/api/zoo/constructive_ar/constructive_ar.md create mode 100644 docs/content/api/zoo/constructive_ar/index.html create mode 100644 docs/content/api/zoo/constructive_nar/constructive_nar.md create mode 100644 docs/content/api/zoo/constructive_nar/index.html create mode 100644 docs/content/api/zoo/improvement/improvement.md create mode 100644 docs/content/api/zoo/improvement/index.html create mode 100644 docs/content/api/zoo/transductive/index.html create mode 100644 docs/content/api/zoo/transductive/transductive.md create mode 100644 docs/content/general/ai4co/ai4co.md create mode 100644 docs/content/general/ai4co/index.html create mode 100644 docs/content/general/contribute/contribute.md create mode 100644 docs/content/general/contribute/index.html create mode 100644 docs/content/general/faq/faq.md create mode 100644 docs/content/general/faq/index.html create mode 100644 docs/content/general/licensing/index.html create mode 100644 docs/content/general/licensing/licensing.md create mode 100644 docs/content/general/paper/index.html create mode 100644 docs/content/general/paper/paper.md create mode 100644 docs/content/intro/environments/environments.md create mode 100644 docs/content/intro/environments/index.html create mode 100644 docs/content/intro/intro/index.html create mode 100644 docs/content/intro/intro/intro.md create mode 100644 docs/content/intro/policies/index.html create mode 100644 docs/content/intro/policies/policies.md create mode 100644 docs/content/intro/rl/index.html create mode 100644 docs/content/intro/rl/rl.md create mode 100644 docs/content/start/hydra/hydra.md create mode 100644 docs/content/start/hydra/index.html create mode 100644 docs/content/start/installation/index.html create mode 100644 docs/content/start/installation/installation.md create mode 100644 docs/hooks.py create mode 100644 docs/index.html create mode 100644 docs/js/autolink.js create mode 100644 docs/js/katex.js create mode 100644 docs/js/tsparticles.js create mode 100644 docs/overrides/fancylogo.txt create mode 100644 docs/overrides/main.html create mode 100644 docs/stylesheets/extra.css create mode 100644 docs/stylesheets/mkdocstrings.css create mode 100644 examples/1-quickstart/1-quickstart.ipynb create mode 100644 examples/1-quickstart/index.html create mode 100644 examples/2-full-training/2-full-training.ipynb create mode 100644 examples/2-full-training/index.html create mode 100644 examples/2b-train-simple.py create mode 100644 examples/2d-meta_train.py create mode 100644 examples/3-creating-new-env-model/3-creating-new-env-model.ipynb create mode 100644 examples/3-creating-new-env-model/index.html create mode 100644 examples/README.md create mode 100644 examples/advanced/1-hydra-config/1-hydra-config.ipynb create mode 100644 examples/advanced/1-hydra-config/index.html create mode 100644 examples/advanced/2-flash-attention-2/2-flash-attention-2.ipynb create mode 100644 examples/advanced/2-flash-attention-2/index.html create mode 100644 examples/advanced/3-local-search/3-local-search.ipynb create mode 100644 examples/advanced/3-local-search/index.html create mode 100644 examples/advanced/README.md create mode 100644 examples/advanced/index.html create mode 100644 examples/datasets/1-test-on-tsplib/1-test-on-tsplib.ipynb create mode 100644 examples/datasets/1-test-on-tsplib/index.html create mode 100644 examples/datasets/2-test-on-cvrplib/2-test-on-cvrplib.ipynb create mode 100644 examples/datasets/2-test-on-cvrplib/index.html create mode 100644 examples/datasets/README.md create mode 100644 examples/datasets/index.html create mode 100644 examples/index.html create mode 100644 examples/modeling/1-decoding-strategies/1-decoding-strategies.ipynb create mode 100644 examples/modeling/1-decoding-strategies/index.html create mode 100644 examples/modeling/2-transductive-methods/2-transductive-methods.ipynb create mode 100644 examples/modeling/2-transductive-methods/index.html create mode 100644 examples/modeling/3-change-encoder/3-change-encoder.ipynb create mode 100644 examples/modeling/3-change-encoder/index.html create mode 100644 examples/modeling/README.md create mode 100644 examples/modeling/index.html create mode 100644 examples/other/1-mtvrp/1-mtvrp.ipynb create mode 100644 examples/other/1-mtvrp/index.html create mode 100644 examples/other/2-scheduling/2-scheduling.ipynb create mode 100644 examples/other/2-scheduling/index.html create mode 100644 examples/other/3-data-generator-distributions/3-data-generator-distributions.ipynb create mode 100644 examples/other/3-data-generator-distributions/index.html create mode 100644 examples/other/README.md create mode 100644 examples/other/index.html create mode 100644 index.html create mode 100644 objects.inv create mode 100644 rl4co/__init__.py create mode 100644 rl4co/data/__init__.py create mode 100644 rl4co/data/dataset.py create mode 100644 rl4co/data/generate_data.py create mode 100644 rl4co/data/transforms.py create mode 100644 rl4co/data/utils.py create mode 100644 rl4co/envs/__init__.py create mode 100644 rl4co/envs/common/__init__.py create mode 100644 rl4co/envs/common/base.py create mode 100644 rl4co/envs/common/distribution_utils.py create mode 100644 rl4co/envs/common/utils.py create mode 100644 rl4co/envs/eda/__init__.py create mode 100644 rl4co/envs/eda/dpp/__init__.py create mode 100644 rl4co/envs/eda/dpp/env.py create mode 100644 rl4co/envs/eda/dpp/generator.py create mode 100644 rl4co/envs/eda/dpp/render.py create mode 100644 rl4co/envs/eda/mdpp/__init__.py create mode 100644 rl4co/envs/eda/mdpp/env.py create mode 100644 rl4co/envs/eda/mdpp/generator.py create mode 100644 rl4co/envs/eda/mdpp/render.py create mode 100644 rl4co/envs/graph/__init__.py create mode 100644 rl4co/envs/graph/flp/__init__.py create mode 100644 rl4co/envs/graph/flp/env.py create mode 100644 rl4co/envs/graph/flp/generator.py create mode 100644 rl4co/envs/graph/mcp/__init__.py create mode 100644 rl4co/envs/graph/mcp/env.py create mode 100644 rl4co/envs/graph/mcp/generator.py create mode 100644 rl4co/envs/routing/__init__.py create mode 100644 rl4co/envs/routing/atsp/__init__.py create mode 100644 rl4co/envs/routing/atsp/env.py create mode 100644 rl4co/envs/routing/atsp/generator.py create mode 100644 rl4co/envs/routing/atsp/render.py create mode 100644 rl4co/envs/routing/cvrp/__init__.py create mode 100644 rl4co/envs/routing/cvrp/env.py create mode 100644 rl4co/envs/routing/cvrp/generator.py create mode 100644 rl4co/envs/routing/cvrp/local_search.py create mode 100644 rl4co/envs/routing/cvrp/render.py create mode 100644 rl4co/envs/routing/cvrptw/__init__.py create mode 100644 rl4co/envs/routing/cvrptw/env.py create mode 100644 rl4co/envs/routing/cvrptw/generator.py create mode 100644 rl4co/envs/routing/cvrptw/render.py create mode 100644 rl4co/envs/routing/mdcpdp/__init__.py create mode 100644 rl4co/envs/routing/mdcpdp/env.py create mode 100644 rl4co/envs/routing/mdcpdp/generator.py create mode 100644 rl4co/envs/routing/mdcpdp/render.py create mode 100644 rl4co/envs/routing/mpdp/__init__.py create mode 100644 rl4co/envs/routing/mpdp/env.py create mode 100644 rl4co/envs/routing/mpdp/generator.py create mode 100644 rl4co/envs/routing/mpdp/render.py create mode 100644 rl4co/envs/routing/mtsp/__init__.py create mode 100644 rl4co/envs/routing/mtsp/env.py create mode 100644 rl4co/envs/routing/mtsp/generator.py create mode 100644 rl4co/envs/routing/mtsp/render.py create mode 100644 rl4co/envs/routing/mtvrp/__init__.py create mode 100644 rl4co/envs/routing/mtvrp/baselines/__init__.py create mode 100644 rl4co/envs/routing/mtvrp/baselines/constants.py create mode 100644 rl4co/envs/routing/mtvrp/baselines/lkh.py create mode 100644 rl4co/envs/routing/mtvrp/baselines/ortools.py create mode 100644 rl4co/envs/routing/mtvrp/baselines/pyvrp.py create mode 100644 rl4co/envs/routing/mtvrp/baselines/solve.py create mode 100644 rl4co/envs/routing/mtvrp/baselines/utils.py create mode 100644 rl4co/envs/routing/mtvrp/env.py create mode 100644 rl4co/envs/routing/mtvrp/generator.py create mode 100644 rl4co/envs/routing/mtvrp/render.py create mode 100644 rl4co/envs/routing/op/__init__.py create mode 100644 rl4co/envs/routing/op/env.py create mode 100644 rl4co/envs/routing/op/generator.py create mode 100644 rl4co/envs/routing/op/render.py create mode 100644 rl4co/envs/routing/pctsp/__init__.py create mode 100644 rl4co/envs/routing/pctsp/env.py create mode 100644 rl4co/envs/routing/pctsp/generator.py create mode 100644 rl4co/envs/routing/pctsp/render.py create mode 100644 rl4co/envs/routing/pdp/__init__.py create mode 100644 rl4co/envs/routing/pdp/env.py create mode 100644 rl4co/envs/routing/pdp/generator.py create mode 100644 rl4co/envs/routing/pdp/render.py create mode 100644 rl4co/envs/routing/sdvrp/__init__.py create mode 100644 rl4co/envs/routing/sdvrp/env.py create mode 100644 rl4co/envs/routing/spctsp/__init__.py create mode 100644 rl4co/envs/routing/spctsp/env.py create mode 100644 rl4co/envs/routing/svrp/__init__.py create mode 100644 rl4co/envs/routing/svrp/env.py create mode 100644 rl4co/envs/routing/svrp/generator.py create mode 100644 rl4co/envs/routing/svrp/render.py create mode 100644 rl4co/envs/routing/tsp/__init__.py create mode 100644 rl4co/envs/routing/tsp/env.py create mode 100644 rl4co/envs/routing/tsp/generator.py create mode 100644 rl4co/envs/routing/tsp/local_search.py create mode 100644 rl4co/envs/routing/tsp/render.py create mode 100644 rl4co/envs/scheduling/__init__.py create mode 100644 rl4co/envs/scheduling/ffsp/__init__.py create mode 100644 rl4co/envs/scheduling/ffsp/env.py create mode 100644 rl4co/envs/scheduling/ffsp/generator.py create mode 100644 rl4co/envs/scheduling/ffsp/render.py create mode 100644 rl4co/envs/scheduling/fjsp/__init__.py create mode 100644 rl4co/envs/scheduling/fjsp/env.py create mode 100644 rl4co/envs/scheduling/fjsp/generator.py create mode 100644 rl4co/envs/scheduling/fjsp/parser.py create mode 100644 rl4co/envs/scheduling/fjsp/render.py create mode 100644 rl4co/envs/scheduling/fjsp/utils.py create mode 100644 rl4co/envs/scheduling/jssp/__init__.py create mode 100644 rl4co/envs/scheduling/jssp/env.py create mode 100644 rl4co/envs/scheduling/jssp/generator.py create mode 100644 rl4co/envs/scheduling/jssp/parser.py create mode 100644 rl4co/envs/scheduling/smtwtp/__init__.py create mode 100644 rl4co/envs/scheduling/smtwtp/env.py create mode 100644 rl4co/envs/scheduling/smtwtp/generator.py create mode 100644 rl4co/envs/scheduling/smtwtp/render.py create mode 100644 rl4co/models/__init__.py create mode 100644 rl4co/models/common/__init__.py create mode 100644 rl4co/models/common/constructive/__init__.py create mode 100644 rl4co/models/common/constructive/autoregressive/__init__.py create mode 100644 rl4co/models/common/constructive/autoregressive/decoder.py create mode 100644 rl4co/models/common/constructive/autoregressive/encoder.py create mode 100644 rl4co/models/common/constructive/autoregressive/policy.py create mode 100644 rl4co/models/common/constructive/base.py create mode 100644 rl4co/models/common/constructive/nonautoregressive/__init__.py create mode 100644 rl4co/models/common/constructive/nonautoregressive/decoder.py create mode 100644 rl4co/models/common/constructive/nonautoregressive/encoder.py create mode 100644 rl4co/models/common/constructive/nonautoregressive/policy.py create mode 100644 rl4co/models/common/improvement/__init__.py create mode 100644 rl4co/models/common/improvement/base.py create mode 100644 rl4co/models/common/transductive/__init__.py create mode 100644 rl4co/models/common/transductive/base.py create mode 100644 rl4co/models/nn/__init__.py create mode 100644 rl4co/models/nn/attention.py create mode 100644 rl4co/models/nn/env_embeddings/__init__.py create mode 100644 rl4co/models/nn/env_embeddings/context.py create mode 100644 rl4co/models/nn/env_embeddings/dynamic.py create mode 100644 rl4co/models/nn/env_embeddings/edge.py create mode 100644 rl4co/models/nn/env_embeddings/init.py create mode 100644 rl4co/models/nn/flash_attention.py create mode 100644 rl4co/models/nn/graph/__init__.py create mode 100644 rl4co/models/nn/graph/attnnet.py create mode 100644 rl4co/models/nn/graph/gcn.py create mode 100644 rl4co/models/nn/graph/gnn.py create mode 100644 rl4co/models/nn/graph/hgnn.py create mode 100644 rl4co/models/nn/graph/mpnn.py create mode 100644 rl4co/models/nn/mlp.py create mode 100644 rl4co/models/nn/moe.py create mode 100644 rl4co/models/nn/ops.py create mode 100644 rl4co/models/nn/pos_embeddings.py create mode 100644 rl4co/models/rl/__init__.py create mode 100644 rl4co/models/rl/a2c/__init__.py create mode 100644 rl4co/models/rl/a2c/a2c.py create mode 100644 rl4co/models/rl/common/__init__.py create mode 100644 rl4co/models/rl/common/base.py create mode 100644 rl4co/models/rl/common/critic.py create mode 100644 rl4co/models/rl/common/utils.py create mode 100644 rl4co/models/rl/ppo/__init__.py create mode 100644 rl4co/models/rl/ppo/n_step_ppo.py create mode 100644 rl4co/models/rl/ppo/ppo.py create mode 100644 rl4co/models/rl/ppo/stepwise_ppo.py create mode 100644 rl4co/models/rl/reinforce/__init__.py create mode 100644 rl4co/models/rl/reinforce/baselines.py create mode 100644 rl4co/models/rl/reinforce/reinforce.py create mode 100644 rl4co/models/zoo/__init__.py create mode 100644 rl4co/models/zoo/active_search/__init__.py create mode 100644 rl4co/models/zoo/active_search/search.py create mode 100644 rl4co/models/zoo/am/__init__.py create mode 100644 rl4co/models/zoo/am/decoder.py create mode 100644 rl4co/models/zoo/am/encoder.py create mode 100644 rl4co/models/zoo/am/model.py create mode 100644 rl4co/models/zoo/am/policy.py create mode 100644 rl4co/models/zoo/amppo/__init__.py create mode 100644 rl4co/models/zoo/amppo/model.py create mode 100644 rl4co/models/zoo/dact/__init__.py create mode 100644 rl4co/models/zoo/dact/decoder.py create mode 100644 rl4co/models/zoo/dact/encoder.py create mode 100644 rl4co/models/zoo/dact/model.py create mode 100644 rl4co/models/zoo/dact/policy.py create mode 100644 rl4co/models/zoo/deepaco/__init__.py create mode 100644 rl4co/models/zoo/deepaco/antsystem.py create mode 100644 rl4co/models/zoo/deepaco/model.py create mode 100644 rl4co/models/zoo/deepaco/policy.py create mode 100644 rl4co/models/zoo/eas/__init__.py create mode 100644 rl4co/models/zoo/eas/decoder.py create mode 100644 rl4co/models/zoo/eas/nn.py create mode 100644 rl4co/models/zoo/eas/search.py create mode 100644 rl4co/models/zoo/ham/__init__.py create mode 100644 rl4co/models/zoo/ham/attention.py create mode 100644 rl4co/models/zoo/ham/encoder.py create mode 100644 rl4co/models/zoo/ham/model.py create mode 100644 rl4co/models/zoo/ham/policy.py create mode 100644 rl4co/models/zoo/l2d/__init__.py create mode 100644 rl4co/models/zoo/l2d/decoder.py create mode 100644 rl4co/models/zoo/l2d/encoder.py create mode 100644 rl4co/models/zoo/l2d/model.py create mode 100644 rl4co/models/zoo/l2d/policy.py create mode 100644 rl4co/models/zoo/matnet/__init__.py create mode 100644 rl4co/models/zoo/matnet/decoder.py create mode 100644 rl4co/models/zoo/matnet/encoder.py create mode 100644 rl4co/models/zoo/matnet/matnet_w_sa.py create mode 100644 rl4co/models/zoo/matnet/model.py create mode 100644 rl4co/models/zoo/matnet/policy.py create mode 100644 rl4co/models/zoo/mdam/__init__.py create mode 100644 rl4co/models/zoo/mdam/decoder.py create mode 100644 rl4co/models/zoo/mdam/encoder.py create mode 100644 rl4co/models/zoo/mdam/mha.py create mode 100644 rl4co/models/zoo/mdam/model.py create mode 100644 rl4co/models/zoo/mdam/policy.py create mode 100644 rl4co/models/zoo/mvmoe/__init__.py create mode 100644 rl4co/models/zoo/mvmoe/model.py create mode 100644 rl4co/models/zoo/n2s/__init__.py create mode 100644 rl4co/models/zoo/n2s/decoder.py create mode 100644 rl4co/models/zoo/n2s/encoder.py create mode 100644 rl4co/models/zoo/n2s/model.py create mode 100644 rl4co/models/zoo/n2s/policy.py create mode 100644 rl4co/models/zoo/nargnn/__init__.py create mode 100644 rl4co/models/zoo/nargnn/encoder.py create mode 100644 rl4co/models/zoo/nargnn/policy.py create mode 100644 rl4co/models/zoo/neuopt/__init__.py create mode 100644 rl4co/models/zoo/neuopt/decoder.py create mode 100644 rl4co/models/zoo/neuopt/model.py create mode 100644 rl4co/models/zoo/neuopt/policy.py create mode 100644 rl4co/models/zoo/polynet/__init__.py create mode 100644 rl4co/models/zoo/polynet/decoder.py create mode 100644 rl4co/models/zoo/polynet/model.py create mode 100644 rl4co/models/zoo/polynet/policy.py create mode 100644 rl4co/models/zoo/pomo/__init__.py create mode 100644 rl4co/models/zoo/pomo/model.py create mode 100644 rl4co/models/zoo/ptrnet/__init__.py create mode 100644 rl4co/models/zoo/ptrnet/critic.py create mode 100644 rl4co/models/zoo/ptrnet/decoder.py create mode 100644 rl4co/models/zoo/ptrnet/encoder.py create mode 100644 rl4co/models/zoo/ptrnet/model.py create mode 100644 rl4co/models/zoo/ptrnet/policy.py create mode 100644 rl4co/models/zoo/symnco/__init__.py create mode 100644 rl4co/models/zoo/symnco/losses.py create mode 100644 rl4co/models/zoo/symnco/model.py create mode 100644 rl4co/models/zoo/symnco/policy.py create mode 100644 rl4co/tasks/README.md create mode 100644 rl4co/tasks/__init__.py create mode 100644 rl4co/tasks/eval.py create mode 100644 rl4co/tasks/index.html create mode 100644 rl4co/tasks/train.py create mode 100644 rl4co/utils/__init__.py create mode 100644 rl4co/utils/callbacks/__init__.py create mode 100644 rl4co/utils/callbacks/speed_monitor.py create mode 100644 rl4co/utils/decoding.py create mode 100644 rl4co/utils/instantiators.py create mode 100644 rl4co/utils/lightning.py create mode 100644 rl4co/utils/meta_trainer.py create mode 100644 rl4co/utils/ops.py create mode 100644 rl4co/utils/optim_helpers.py create mode 100644 rl4co/utils/pylogger.py create mode 100644 rl4co/utils/rich_utils.py create mode 100644 rl4co/utils/test_utils.py create mode 100644 rl4co/utils/trainer.py create mode 100644 rl4co/utils/utils.py create mode 100644 search/search_index.json create mode 100644 sitemap.xml create mode 100644 sitemap.xml.gz create mode 100644 tests/__init__.py create mode 100644 tests/test_envs.py create mode 100644 tests/test_policy.py create mode 100644 tests/test_tasks.py create mode 100644 tests/test_training.py create mode 100644 tests/test_utils.py diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/404.html b/404.html new file mode 100644 index 00000000..01a1ddce --- /dev/null +++ b/404.html @@ -0,0 +1,2332 @@ + + + + + + + + + + + + + + + + + + + + + RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..f5e8dcc0 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +rl4.co \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..fae5b469 --- /dev/null +++ b/README.md @@ -0,0 +1,447 @@ +--- +hide: +- navigation +- toc +--- + +
+ +
+ + +
+
+
+ + +
+
Loading...
+
+
+ AI4CO Logo +
+
+ + +
+
+
+ +An extensive Reinforcement Learning (RL) for Combinatorial Optimization (CO) benchmark. Our goal is to provide a unified framework for RL-based CO algorithms, and to facilitate reproducible research in this field, decoupling the science from the engineering. + + +RL4CO is built upon: +- [TorchRL](https://github.com/pytorch/rl): official PyTorch framework for RL algorithms and vectorized environments on GPUs +- [TensorDict](https://github.com/pytorch-labs/tensordict): a library to easily handle heterogeneous data such as states, actions and rewards +- [PyTorch Lightning](https://github.com/Lightning-AI/lightning): a lightweight PyTorch wrapper for high-performance AI research +- [Hydra](https://github.com/facebookresearch/hydra): a framework for elegantly configuring complex applications + +
+ RL4CO-Overview +
+ +We offer flexible and efficient implementations of the following policies: +- **Constructive**: learn to construct a solution from scratch + - _Autoregressive (AR)_: construct solutions one step at a time via a decoder + - _NonAutoregressive (NAR)_: learn to predict a heuristic, such as a heatmap, to then construct a solution +- **Improvement**: learn to improve a pre-existing solution + +
+ RL4CO-Policy-Overview +
+ +We provide several utilities and modularization. For example, we modularize reusable components such as _environment embeddings_ that can easily be swapped to [solve new problems](https://github.com/ai4co/rl4co/blob/main/examples/3-creating-new-env-model.ipynb). + + +
+ RL4CO-Env-Embedding +
+ + +## Getting started +Open In Colab + +RL4CO is now available for installation on `pip`! +```bash +pip install rl4co +``` + +To get started, we recommend checking out our [quickstart notebook](examples/1-quickstart.ipynb) or the [minimalistic example](#minimalistic-example) below. + +### Install from source +This command installs the bleeding edge `main` version, useful for staying up-to-date with the latest developments - for instance, if a bug has been fixed since the last official release but a new release hasn’t been rolled out yet: + +```bash +pip install -U git+https://github.com/ai4co/rl4co.git +``` + +### Local install and development +If you want to develop RL4CO we recommend you to install it locally with `pip` in editable mode: + +```bash +git clone https://github.com/ai4co/rl4co && cd rl4co +pip install -e . +``` + +We recommend using a virtual environment such as `conda` to install `rl4co` locally. + + + +## Usage + + +Train model with default configuration (AM on TSP environment): +```bash +python run.py +``` + +> [!TIP] +> You may check out [this notebook](examples/advanced/1-hydra-config.ipynb) to get started with Hydra! + +
+ Change experiment settings + +Train model with chosen experiment configuration from [configs/experiment/](configs/experiment/) +```bash +python run.py experiment=routing/am env=tsp env.num_loc=50 model.optimizer_kwargs.lr=2e-4 +``` +Here you may change the environment, e.g. with `env=cvrp` by command line or by modifying the corresponding experiment e.g. [configs/experiment/routing/am.yaml](configs/experiment/routing/am.yaml). + +
+ + + + +
+ Disable logging + +```bash +python run.py experiment=routing/am logger=none '~callbacks.learning_rate_monitor' +``` +Note that `~` is used to disable a callback that would need a logger. + +
+ + +
+ Create a sweep over hyperparameters (-m for multirun) + +```bash +python run.py -m experiment=routing/am model.optimizer.lr=1e-3,1e-4,1e-5 +``` +
+ + + +### Minimalistic Example + +Here is a minimalistic example training the Attention Model with greedy rollout baseline on TSP in less than 30 lines of code: + +```python +from rl4co.envs.routing import TSPEnv, TSPGenerator +from rl4co.models import AttentionModelPolicy, POMO +from rl4co.utils import RL4COTrainer + +# Instantiate generator and environment +generator = TSPGenerator(num_loc=50, loc_distribution="uniform") +env = TSPEnv(generator) + +# Create policy and RL model +policy = AttentionModelPolicy(env_name=env.name, num_encoder_layers=6) +model = POMO(env, policy, batch_size=64, optimizer_kwargs={"lr": 1e-4}) + +# Instantiate Trainer and fit +trainer = RL4COTrainer(max_epochs=10, accelerator="gpu", precision="16-mixed") +trainer.fit(model) +``` + +Other examples can be found on our [documentation](https://rl4.co/examples/1-quickstart/)! + + +### Testing + +Run tests with `pytest` from the root directory: + +```bash +pytest tests +``` + +### Known Bugs + + +#### Bugs installing PyTorch Geometric (PyG) + +Installing `PyG` via `Conda` seems to update Torch itself. We have found that this update introduces some bugs with `torchrl`. At this moment, we recommend installing `PyG` with `Pip`: +```bash +pip install torch_geometric +``` + + +## Contributing + +Have a suggestion, request, or found a bug? Feel free to [open an issue](https://github.com/ai4co/rl4co/issues) or [submit a pull request](https://github.com/ai4co/rl4co/pulls). +If you would like to contribute, please check out our contribution guidelines [here](.github/CONTRIBUTING.md). We welcome and look forward to all contributions to RL4CO! + +We are also on [Slack](https://join.slack.com/t/rl4co/shared_invite/zt-1ytz2c1v4-0IkQ8NQH4TRXIX8PrRmDhQ) if you have any questions or would like to discuss RL4CO with us. We are open to collaborations and would love to hear from you 🚀 + +### Contributors + + + + +## Citation +If you find RL4CO valuable for your research or applied projects: + +```bibtex +@article{berto2024rl4co, + title={{RL4CO: an Extensive Reinforcement Learning for Combinatorial Optimization Benchmark}}, + author={Federico Berto and Chuanbo Hua and Junyoung Park and Laurin Luttmann and Yining Ma and Fanchen Bu and Jiarui Wang and Haoran Ye and Minsu Kim and Sanghyeok Choi and Nayeli Gast Zepeda and Andr\'e Hottung and Jianan Zhou and Jieyi Bi and Yu Hu and Fei Liu and Hyeonah Kim and Jiwoo Son and Haeyeon Kim and Davide Angioni and Wouter Kool and Zhiguang Cao and Jie Zhang and Kijung Shin and Cathy Wu and Sungsoo Ahn and Guojie Song and Changhyun Kwon and Lin Xie and Jinkyoo Park}, + year={2024}, + journal={arXiv preprint arXiv:2306.17100}, + note={\url{https://github.com/ai4co/rl4co}} +} +``` + +Note that a [previous version of RL4CO](https://openreview.net/forum?id=YXSJxi8dOV) has been accepted as an oral presentation at the [NeurIPS 2023 GLFrontiers Workshop](https://glfrontiers.github.io/). Since then, the library has greatly evolved and improved! + +--- + + +## Join us +[![Slack](https://img.shields.io/badge/slack-chat-611f69.svg?logo=slack)](https://join.slack.com/t/rl4co/shared_invite/zt-1ytz2c1v4-0IkQ8NQH4TRXIX8PrRmDhQ) + +We invite you to join our AI4CO community, an open research group in Artificial Intelligence (AI) for Combinatorial Optimization (CO)! + + +
+ AI4CO Logo +
diff --git a/README_backup/README_backup.md b/README_backup/README_backup.md new file mode 100644 index 00000000..d5249344 --- /dev/null +++ b/README_backup/README_backup.md @@ -0,0 +1,224 @@ +
+
+ +AI4CO Logo + +

+ + +PyTorch +Lightning +base: TorchRL +config: Hydra +Code style: black +Slack +License: MIT +Open In Colab +PyPI +Codecov +Test + +

+ Documentation | + Getting Started | + Usage | + Contributing | + Paper | + Join Us +

+ + + +
+ + + +An extensive Reinforcement Learning (RL) for Combinatorial Optimization (CO) benchmark. Our goal is to provide a unified framework for RL-based CO algorithms, and to facilitate reproducible research in this field, decoupling the science from the engineering. + + +RL4CO is built upon: +- [TorchRL](https://github.com/pytorch/rl): official PyTorch framework for RL algorithms and vectorized environments on GPUs +- [TensorDict](https://github.com/pytorch-labs/tensordict): a library to easily handle heterogeneous data such as states, actions and rewards +- [PyTorch Lightning](https://github.com/Lightning-AI/lightning): a lightweight PyTorch wrapper for high-performance AI research +- [Hydra](https://github.com/facebookresearch/hydra): a framework for elegantly configuring complex applications + +
+ RL4CO-Overview +
+ +We offer flexible and efficient implementations of the following policies: +- **Constructive**: learn to construct a solution from scratch + - _Autoregressive (AR)_: construct solutions one step at a time via a decoder + - _NonAutoregressive (NAR)_: learn to predict a heuristic, such as a heatmap, to then construct a solution +- **Improvement**: learn to improve a pre-existing solution + +
+ RL4CO-Policy-Overview +
+ +We provide several utilities and modularization. For example, we modularize reusable components such as _environment embeddings_ that can easily be swapped to [solve new problems](https://github.com/ai4co/rl4co/blob/main/examples/3-creating-new-env-model.ipynb). + + +
+ RL4CO-Env-Embedding +
+ + +## Getting started +Open In Colab + +RL4CO is now available for installation on `pip`! +```bash +pip install rl4co +``` + +To get started, we recommend checking out our [quickstart notebook](examples/1-quickstart.ipynb) or the [minimalistic example](#minimalistic-example) below. + +### Install from source +This command installs the bleeding edge `main` version, useful for staying up-to-date with the latest developments - for instance, if a bug has been fixed since the last official release but a new release hasn’t been rolled out yet: + +```bash +pip install -U git+https://github.com/ai4co/rl4co.git +``` + +### Local install and development +If you want to develop RL4CO we recommend you to install it locally with `pip` in editable mode: + +```bash +git clone https://github.com/ai4co/rl4co && cd rl4co +pip install -e . +``` + +We recommend using a virtual environment such as `conda` to install `rl4co` locally. + + + +## Usage + + +Train model with default configuration (AM on TSP environment): +```bash +python run.py +``` + +> [!TIP] +> You may check out [this notebook](examples/advanced/1-hydra-config.ipynb) to get started with Hydra! + +
+ Change experiment settings + +Train model with chosen experiment configuration from [configs/experiment/](configs/experiment/) +```bash +python run.py experiment=routing/am env=tsp env.num_loc=50 model.optimizer_kwargs.lr=2e-4 +``` +Here you may change the environment, e.g. with `env=cvrp` by command line or by modifying the corresponding experiment e.g. [configs/experiment/routing/am.yaml](configs/experiment/routing/am.yaml). + +
+ + + + +
+ Disable logging + +```bash +python run.py experiment=routing/am logger=none '~callbacks.learning_rate_monitor' +``` +Note that `~` is used to disable a callback that would need a logger. + +
+ + +
+ Create a sweep over hyperparameters (-m for multirun) + +```bash +python run.py -m experiment=routing/am model.optimizer.lr=1e-3,1e-4,1e-5 +``` +
+ + + +### Minimalistic Example + +Here is a minimalistic example training the Attention Model with greedy rollout baseline on TSP in less than 30 lines of code: + +```python +from rl4co.envs.routing import TSPEnv, TSPGenerator +from rl4co.models import AttentionModelPolicy, POMO +from rl4co.utils import RL4COTrainer + +# Instantiate generator and environment +generator = TSPGenerator(num_loc=50, loc_distribution="uniform") +env = TSPEnv(generator) + +# Create policy and RL model +policy = AttentionModelPolicy(env_name=env.name, num_encoder_layers=6) +model = POMO(env, policy, batch_size=64, optimizer_kwargs={"lr": 1e-4}) + +# Instantiate Trainer and fit +trainer = RL4COTrainer(max_epochs=10, accelerator="gpu", precision="16-mixed") +trainer.fit(model) +``` + +Other examples can be found on our [documentation](https://rl4.co/examples/1-quickstart/)! + + +### Testing + +Run tests with `pytest` from the root directory: + +```bash +pytest tests +``` + +### Known Bugs + + +#### Bugs installing PyTorch Geometric (PyG) + +Installing `PyG` via `Conda` seems to update Torch itself. We have found that this update introduces some bugs with `torchrl`. At this moment, we recommend installing `PyG` with `Pip`: +```bash +pip install torch_geometric +``` + + +## Contributing + +Have a suggestion, request, or found a bug? Feel free to [open an issue](https://github.com/ai4co/rl4co/issues) or [submit a pull request](https://github.com/ai4co/rl4co/pulls). +If you would like to contribute, please check out our contribution guidelines [here](.github/CONTRIBUTING.md). We welcome and look forward to all contributions to RL4CO! + +We are also on [Slack](https://join.slack.com/t/rl4co/shared_invite/zt-1ytz2c1v4-0IkQ8NQH4TRXIX8PrRmDhQ) if you have any questions or would like to discuss RL4CO with us. We are open to collaborations and would love to hear from you 🚀 + +### Contributors + + + + +## Citation +If you find RL4CO valuable for your research or applied projects: + +```bibtex +@article{berto2024rl4co, + title={{RL4CO: an Extensive Reinforcement Learning for Combinatorial Optimization Benchmark}}, + author={Federico Berto and Chuanbo Hua and Junyoung Park and Laurin Luttmann and Yining Ma and Fanchen Bu and Jiarui Wang and Haoran Ye and Minsu Kim and Sanghyeok Choi and Nayeli Gast Zepeda and Andr\'e Hottung and Jianan Zhou and Jieyi Bi and Yu Hu and Fei Liu and Hyeonah Kim and Jiwoo Son and Haeyeon Kim and Davide Angioni and Wouter Kool and Zhiguang Cao and Jie Zhang and Kijung Shin and Cathy Wu and Sungsoo Ahn and Guojie Song and Changhyun Kwon and Lin Xie and Jinkyoo Park}, + year={2024}, + journal={arXiv preprint arXiv:2306.17100}, + note={\url{https://github.com/ai4co/rl4co}} +} +``` + +Note that a [previous version of RL4CO](https://openreview.net/forum?id=YXSJxi8dOV) has been accepted as an oral presentation at the [NeurIPS 2023 GLFrontiers Workshop](https://glfrontiers.github.io/). Since then, the library has greatly evolved and improved! + +--- + + +## Join us +[![Slack](https://img.shields.io/badge/slack-chat-611f69.svg?logo=slack)](https://join.slack.com/t/rl4co/shared_invite/zt-1ytz2c1v4-0IkQ8NQH4TRXIX8PrRmDhQ) + +We invite you to join our AI4CO community, an open research group in Artificial Intelligence (AI) for Combinatorial Optimization (CO)! + + +
+ AI4CO Logo +
diff --git a/README_backup/index.html b/README_backup/index.html new file mode 100644 index 00000000..1ba2f8f8 --- /dev/null +++ b/README_backup/index.html @@ -0,0 +1,2668 @@ + + + + + + + + + + + + + + + + + + + + + + + README backup - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Skip to content + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ + + + + + + + + +

README backup

+ +


+
+ +AI4CO Logo + +

+ + +PyTorch +Lightning +base: TorchRL +config: Hydra +Code style: black +Slack +License: MIT +Open In Colab +PyPI +Codecov +Test + +

+ Documentation | + Getting Started | + Usage | + Contributing | + Paper | + Join Us +

+ + + +
+ +

An extensive Reinforcement Learning (RL) for Combinatorial Optimization (CO) benchmark. Our goal is to provide a unified framework for RL-based CO algorithms, and to facilitate reproducible research in this field, decoupling the science from the engineering.

+

RL4CO is built upon:

+
    +
  • TorchRL: official PyTorch framework for RL algorithms and vectorized environments on GPUs
  • +
  • TensorDict: a library to easily handle heterogeneous data such as states, actions and rewards
  • +
  • PyTorch Lightning: a lightweight PyTorch wrapper for high-performance AI research
  • +
  • Hydra: a framework for elegantly configuring complex applications
  • +
+
+ RL4CO-Overview +
+ +

We offer flexible and efficient implementations of the following policies:

+
    +
  • Constructive: learn to construct a solution from scratch
      +
    • Autoregressive (AR): construct solutions one step at a time via a decoder
    • +
    • NonAutoregressive (NAR): learn to predict a heuristic, such as a heatmap, to then construct a solution
    • +
    +
  • +
  • Improvement: learn to improve a pre-existing solution
  • +
+
+ RL4CO-Policy-Overview +
+ +

We provide several utilities and modularization. For example, we modularize reusable components such as environment embeddings that can easily be swapped to solve new problems.

+
+ RL4CO-Env-Embedding +
+ +

Getting started

+

Open In Colab

+

RL4CO is now available for installation on pip! +

pip install rl4co
+

+

To get started, we recommend checking out our quickstart notebook or the minimalistic example below.

+

Install from source

+

This command installs the bleeding edge main version, useful for staying up-to-date with the latest developments - for instance, if a bug has been fixed since the last official release but a new release hasn’t been rolled out yet:

+
pip install -U git+https://github.com/ai4co/rl4co.git
+
+

Local install and development

+

If you want to develop RL4CO we recommend you to install it locally with pip in editable mode:

+
git clone https://github.com/ai4co/rl4co && cd rl4co
+pip install -e .
+
+

We recommend using a virtual environment such as conda to install rl4co locally.

+

Usage

+

Train model with default configuration (AM on TSP environment): +

python run.py
+

+
+

Tip

+

You may check out this notebook to get started with Hydra!

+
+
+ Change experiment settings + +Train model with chosen experiment configuration from [configs/experiment/](configs/experiment/) +
python run.py experiment=routing/am env=tsp env.num_loc=50 model.optimizer_kwargs.lr=2e-4
+
+Here you may change the environment, e.g. with `env=cvrp` by command line or by modifying the corresponding experiment e.g. [configs/experiment/routing/am.yaml](configs/experiment/routing/am.yaml). + +
+ +
+ Disable logging + +
python run.py experiment=routing/am logger=none '~callbacks.learning_rate_monitor'
+
+Note that `~` is used to disable a callback that would need a logger. + +
+ +
+ Create a sweep over hyperparameters (-m for multirun) + +
python run.py -m experiment=routing/am  model.optimizer.lr=1e-3,1e-4,1e-5
+
+
+ +

Minimalistic Example

+

Here is a minimalistic example training the Attention Model with greedy rollout baseline on TSP in less than 30 lines of code:

+
from rl4co.envs.routing import TSPEnv, TSPGenerator
+from rl4co.models import AttentionModelPolicy, POMO
+from rl4co.utils import RL4COTrainer
+
+# Instantiate generator and environment
+generator = TSPGenerator(num_loc=50, loc_distribution="uniform")
+env = TSPEnv(generator)
+
+# Create policy and RL model
+policy = AttentionModelPolicy(env_name=env.name, num_encoder_layers=6)
+model = POMO(env, policy, batch_size=64, optimizer_kwargs={"lr": 1e-4})
+
+# Instantiate Trainer and fit
+trainer = RL4COTrainer(max_epochs=10, accelerator="gpu", precision="16-mixed")
+trainer.fit(model)
+
+

Other examples can be found on our documentation!

+

Testing

+

Run tests with pytest from the root directory:

+
pytest tests
+
+

Known Bugs

+

Bugs installing PyTorch Geometric (PyG)

+

Installing PyG via Conda seems to update Torch itself. We have found that this update introduces some bugs with torchrl. At this moment, we recommend installing PyG with Pip: +

pip install torch_geometric
+

+

Contributing

+

Have a suggestion, request, or found a bug? Feel free to open an issue or submit a pull request. +If you would like to contribute, please check out our contribution guidelines here. We welcome and look forward to all contributions to RL4CO!

+

We are also on Slack if you have any questions or would like to discuss RL4CO with us. We are open to collaborations and would love to hear from you 🚀

+

Contributors

+

+ +

+

Citation

+

If you find RL4CO valuable for your research or applied projects:

+
@article{berto2024rl4co,
+    title={{RL4CO: an Extensive Reinforcement Learning for Combinatorial Optimization Benchmark}},
+    author={Federico Berto and Chuanbo Hua and Junyoung Park and Laurin Luttmann and Yining Ma and Fanchen Bu and Jiarui Wang and Haoran Ye and Minsu Kim and Sanghyeok Choi and Nayeli Gast Zepeda and Andr\'e Hottung and Jianan Zhou and Jieyi Bi and Yu Hu and Fei Liu and Hyeonah Kim and Jiwoo Son and Haeyeon Kim and Davide Angioni and Wouter Kool and Zhiguang Cao and Jie Zhang and Kijung Shin and Cathy Wu and Sungsoo Ahn and Guojie Song and Changhyun Kwon and Lin Xie and Jinkyoo Park},
+    year={2024},
+    journal={arXiv preprint arXiv:2306.17100},
+    note={\url{https://github.com/ai4co/rl4co}}
+}
+
+

Note that a previous version of RL4CO has been accepted as an oral presentation at the NeurIPS 2023 GLFrontiers Workshop. Since then, the library has greatly evolved and improved!

+
+

Join us

+

Slack

+

We invite you to join our AI4CO community, an open research group in Artificial Intelligence (AI) for Combinatorial Optimization (CO)!

+
+ AI4CO Logo +
+ + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/_mkdocstrings.css b/assets/_mkdocstrings.css new file mode 100644 index 00000000..85449ec7 --- /dev/null +++ b/assets/_mkdocstrings.css @@ -0,0 +1,119 @@ + +/* Avoid breaking parameter names, etc. in table cells. */ +.doc-contents td code { + word-break: normal !important; +} + +/* No line break before first paragraph of descriptions. */ +.doc-md-description, +.doc-md-description>p:first-child { + display: inline; +} + +/* Max width for docstring sections tables. */ +.doc .md-typeset__table, +.doc .md-typeset__table table { + display: table !important; + width: 100%; +} + +.doc .md-typeset__table tr { + display: table-row; +} + +/* Defaults in Spacy table style. */ +.doc-param-default { + float: right; +} + +/* Backward-compatibility: docstring section titles in bold. */ +.doc-section-title { + font-weight: bold; +} + +/* Symbols in Navigation and ToC. */ +:root, +[data-md-color-scheme="default"] { + --doc-symbol-attribute-fg-color: #953800; + --doc-symbol-function-fg-color: #8250df; + --doc-symbol-method-fg-color: #8250df; + --doc-symbol-class-fg-color: #0550ae; + --doc-symbol-module-fg-color: #5cad0f; + + --doc-symbol-attribute-bg-color: #9538001a; + --doc-symbol-function-bg-color: #8250df1a; + --doc-symbol-method-bg-color: #8250df1a; + --doc-symbol-class-bg-color: #0550ae1a; + --doc-symbol-module-bg-color: #5cad0f1a; +} + +[data-md-color-scheme="slate"] { + --doc-symbol-attribute-fg-color: #ffa657; + --doc-symbol-function-fg-color: #d2a8ff; + --doc-symbol-method-fg-color: #d2a8ff; + --doc-symbol-class-fg-color: #79c0ff; + --doc-symbol-module-fg-color: #baff79; + + --doc-symbol-attribute-bg-color: #ffa6571a; + --doc-symbol-function-bg-color: #d2a8ff1a; + --doc-symbol-method-bg-color: #d2a8ff1a; + --doc-symbol-class-bg-color: #79c0ff1a; + --doc-symbol-module-bg-color: #baff791a; +} + +code.doc-symbol { + border-radius: .1rem; + font-size: .85em; + padding: 0 .3em; + font-weight: bold; +} + +code.doc-symbol-attribute { + color: var(--doc-symbol-attribute-fg-color); + background-color: var(--doc-symbol-attribute-bg-color); +} + +code.doc-symbol-attribute::after { + content: "attr"; +} + +code.doc-symbol-function { + color: var(--doc-symbol-function-fg-color); + background-color: var(--doc-symbol-function-bg-color); +} + +code.doc-symbol-function::after { + content: "func"; +} + +code.doc-symbol-method { + color: var(--doc-symbol-method-fg-color); + background-color: var(--doc-symbol-method-bg-color); +} + +code.doc-symbol-method::after { + content: "meth"; +} + +code.doc-symbol-class { + color: var(--doc-symbol-class-fg-color); + background-color: var(--doc-symbol-class-bg-color); +} + +code.doc-symbol-class::after { + content: "class"; +} + +code.doc-symbol-module { + color: var(--doc-symbol-module-fg-color); + background-color: var(--doc-symbol-module-bg-color); +} + +code.doc-symbol-module::after { + content: "mod"; +} + +.doc-signature .autorefs { + color: inherit; + border-bottom: 1px dotted currentcolor; +} diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..1cf13b9f9d978896599290a74f77d5dbe7d1655c GIT binary patch literal 1870 zcmV-U2eJ5xP)Gc)JR9QMau)O=X#!i9;T z37kk-upj^(fsR36MHs_+1RCI)NNu9}lD0S{B^g8PN?Ww(5|~L#Ng*g{WsqleV}|#l zz8@ri&cTzw_h33bHI+12+kK6WN$h#n5cD8OQt`5kw6p~9H3()bUQ8OS4Q4HTQ=1Ol z_JAocz`fLbT2^{`8n~UAo=#AUOf=SOq4pYkt;XbC&f#7lb$*7=$na!mWCQ`dBQsO0 zLFBSPj*N?#u5&pf2t4XjEGH|=pPQ8xh7tpx;US5Cx_Ju;!O`ya-yF`)b%TEt5>eP1ZX~}sjjA%FJF?h7cX8=b!DZl<6%Cv z*G0uvvU+vmnpLZ2paivG-(cd*y3$hCIcsZcYOGh{$&)A6*XX&kXZd3G8m)G$Zz-LV z^GF3VAW^Mdv!)4OM8EgqRiz~*Cji;uzl2uC9^=8I84vNp;ltJ|q-*uQwGp2ma6cY7 z;`%`!9UXO@fr&Ebapfs34OmS9^u6$)bJxrucutf>`dKPKT%%*d3XlFVKunp9 zasduxjrjs>f8V=D|J=XNZp;_Zy^WgQ$9WDjgY=z@stwiEBm9u5*|34&1Na8BMjjgf3+SHcr`5~>oz1Y?SW^=K z^bTyO6>Gar#P_W2gEMwq)ot3; zREHn~U&Dp0l6YT0&k-wLwYjb?5zGK`W6S2v+K>AM(95m2C20L|3m~rN8dprPr@t)5lsk9Hu*W z?pS990s;Ez=+Rj{x7p``4>+c0G5^pYnB1^!TL=(?HLHZ+HicG{~4F1d^5Awl_2!1jICM-!9eoLhbbT^;yHcefyTAaqRcY zmuctDopPT!%k+}x%lZRKnzykr2}}XfG_ne?nRQO~?%hkzo;@RN{P6o`&mMUWBYMTe z6i8ChtjX&gXl`nvrU>jah)2iNM%JdjqoaeaU%yVn!^70x-flljp6Q5tK}5}&X8&&G zX3fpb3E(!rH=zVI_9Gjl45w@{(ITqngWFe7@9{mX;tO25Z_8 zQHEpI+FkTU#4xu>RkN>b3Tnc3UpWzPXWm#o55GKF09j^Mh~)K7{QqbO_~(@CVq! zS<8954|P8mXN2MRs86xZ&Q4EfM@JB94b=(YGuk)s&^jiSF=t3*oNK3`rD{H`yQ?d; ztE=laAUoZx5?RC8*WKOj`%LXEkgDd>&^Q4M^z`%u0rg-It=hLCVsq!Z%^6eB-OvOT zFZ28TN&cRmgU}Elrnk43)!>Z1FCPL2K$7}gwzIc48NX}#!A1BpJP?#v5wkNprhV** z?Cpalt1oH&{r!o3eSKc&ap)iz2BTn_VV`4>9M^b3;(YY}4>#ML6{~(4mH+?%07*qo IM6N<$f(jP3KmY&$ literal 0 HcmV?d00001 diff --git a/assets/javascripts/bundle.56dfad97.min.js b/assets/javascripts/bundle.56dfad97.min.js new file mode 100644 index 00000000..1df62cd7 --- /dev/null +++ b/assets/javascripts/bundle.56dfad97.min.js @@ -0,0 +1,16 @@ +"use strict";(()=>{var Fi=Object.create;var gr=Object.defineProperty;var Wi=Object.getOwnPropertyDescriptor;var Ui=Object.getOwnPropertyNames,Vt=Object.getOwnPropertySymbols,Di=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,io=Object.prototype.propertyIsEnumerable;var no=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,$=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&no(e,r,t[r]);if(Vt)for(var r of Vt(t))io.call(t,r)&&no(e,r,t[r]);return e};var ao=(e,t)=>{var r={};for(var o in e)yr.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Vt)for(var o of Vt(e))t.indexOf(o)<0&&io.call(e,o)&&(r[o]=e[o]);return r};var xr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Vi=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Ui(t))!yr.call(e,n)&&n!==r&&gr(e,n,{get:()=>t[n],enumerable:!(o=Wi(t,n))||o.enumerable});return e};var Lt=(e,t,r)=>(r=e!=null?Fi(Di(e)):{},Vi(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var so=(e,t,r)=>new Promise((o,n)=>{var i=p=>{try{s(r.next(p))}catch(c){n(c)}},a=p=>{try{s(r.throw(p))}catch(c){n(c)}},s=p=>p.done?o(p.value):Promise.resolve(p.value).then(i,a);s((r=r.apply(e,t)).next())});var po=xr((Er,co)=>{(function(e,t){typeof Er=="object"&&typeof co!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Er,function(){"use strict";function e(r){var o=!0,n=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(k){return!!(k&&k!==document&&k.nodeName!=="HTML"&&k.nodeName!=="BODY"&&"classList"in k&&"contains"in k.classList)}function p(k){var ft=k.type,qe=k.tagName;return!!(qe==="INPUT"&&a[ft]&&!k.readOnly||qe==="TEXTAREA"&&!k.readOnly||k.isContentEditable)}function c(k){k.classList.contains("focus-visible")||(k.classList.add("focus-visible"),k.setAttribute("data-focus-visible-added",""))}function l(k){k.hasAttribute("data-focus-visible-added")&&(k.classList.remove("focus-visible"),k.removeAttribute("data-focus-visible-added"))}function f(k){k.metaKey||k.altKey||k.ctrlKey||(s(r.activeElement)&&c(r.activeElement),o=!0)}function u(k){o=!1}function d(k){s(k.target)&&(o||p(k.target))&&c(k.target)}function y(k){s(k.target)&&(k.target.classList.contains("focus-visible")||k.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(k.target))}function M(k){document.visibilityState==="hidden"&&(n&&(o=!0),X())}function X(){document.addEventListener("mousemove",J),document.addEventListener("mousedown",J),document.addEventListener("mouseup",J),document.addEventListener("pointermove",J),document.addEventListener("pointerdown",J),document.addEventListener("pointerup",J),document.addEventListener("touchmove",J),document.addEventListener("touchstart",J),document.addEventListener("touchend",J)}function te(){document.removeEventListener("mousemove",J),document.removeEventListener("mousedown",J),document.removeEventListener("mouseup",J),document.removeEventListener("pointermove",J),document.removeEventListener("pointerdown",J),document.removeEventListener("pointerup",J),document.removeEventListener("touchmove",J),document.removeEventListener("touchstart",J),document.removeEventListener("touchend",J)}function J(k){k.target.nodeName&&k.target.nodeName.toLowerCase()==="html"||(o=!1,te())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",M,!0),X(),r.addEventListener("focus",d,!0),r.addEventListener("blur",y,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var qr=xr((ly,Sn)=>{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var ka=/["'&<>]/;Sn.exports=Ha;function Ha(e){var t=""+e,r=ka.exec(t);if(!r)return t;var o,n="",i=0,a=0;for(i=r.index;i{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof It=="object"&&typeof Yr=="object"?Yr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof It=="object"?It.ClipboardJS=r():t.ClipboardJS=r()})(It,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return ji}});var a=i(279),s=i.n(a),p=i(370),c=i.n(p),l=i(817),f=i.n(l);function u(V){try{return document.execCommand(V)}catch(A){return!1}}var d=function(A){var L=f()(A);return u("cut"),L},y=d;function M(V){var A=document.documentElement.getAttribute("dir")==="rtl",L=document.createElement("textarea");L.style.fontSize="12pt",L.style.border="0",L.style.padding="0",L.style.margin="0",L.style.position="absolute",L.style[A?"right":"left"]="-9999px";var F=window.pageYOffset||document.documentElement.scrollTop;return L.style.top="".concat(F,"px"),L.setAttribute("readonly",""),L.value=V,L}var X=function(A,L){var F=M(A);L.container.appendChild(F);var D=f()(F);return u("copy"),F.remove(),D},te=function(A){var L=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},F="";return typeof A=="string"?F=X(A,L):A instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(A==null?void 0:A.type)?F=X(A.value,L):(F=f()(A),u("copy")),F},J=te;function k(V){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?k=function(L){return typeof L}:k=function(L){return L&&typeof Symbol=="function"&&L.constructor===Symbol&&L!==Symbol.prototype?"symbol":typeof L},k(V)}var ft=function(){var A=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},L=A.action,F=L===void 0?"copy":L,D=A.container,Y=A.target,$e=A.text;if(F!=="copy"&&F!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Y!==void 0)if(Y&&k(Y)==="object"&&Y.nodeType===1){if(F==="copy"&&Y.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(F==="cut"&&(Y.hasAttribute("readonly")||Y.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if($e)return J($e,{container:D});if(Y)return F==="cut"?y(Y):J(Y,{container:D})},qe=ft;function Fe(V){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Fe=function(L){return typeof L}:Fe=function(L){return L&&typeof Symbol=="function"&&L.constructor===Symbol&&L!==Symbol.prototype?"symbol":typeof L},Fe(V)}function Ai(V,A){if(!(V instanceof A))throw new TypeError("Cannot call a class as a function")}function oo(V,A){for(var L=0;L0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof D.action=="function"?D.action:this.defaultAction,this.target=typeof D.target=="function"?D.target:this.defaultTarget,this.text=typeof D.text=="function"?D.text:this.defaultText,this.container=Fe(D.container)==="object"?D.container:document.body}},{key:"listenClick",value:function(D){var Y=this;this.listener=c()(D,"click",function($e){return Y.onClick($e)})}},{key:"onClick",value:function(D){var Y=D.delegateTarget||D.currentTarget,$e=this.action(Y)||"copy",Dt=qe({action:$e,container:this.container,target:this.target(Y),text:this.text(Y)});this.emit(Dt?"success":"error",{action:$e,text:Dt,trigger:Y,clearSelection:function(){Y&&Y.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(D){return vr("action",D)}},{key:"defaultTarget",value:function(D){var Y=vr("target",D);if(Y)return document.querySelector(Y)}},{key:"defaultText",value:function(D){return vr("text",D)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(D){var Y=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return J(D,Y)}},{key:"cut",value:function(D){return y(D)}},{key:"isSupported",value:function(){var D=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Y=typeof D=="string"?[D]:D,$e=!!document.queryCommandSupported;return Y.forEach(function(Dt){$e=$e&&!!document.queryCommandSupported(Dt)}),$e}}]),L}(s()),ji=Ii},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,p){for(;s&&s.nodeType!==n;){if(typeof s.matches=="function"&&s.matches(p))return s;s=s.parentNode}}o.exports=a},438:function(o,n,i){var a=i(828);function s(l,f,u,d,y){var M=c.apply(this,arguments);return l.addEventListener(u,M,y),{destroy:function(){l.removeEventListener(u,M,y)}}}function p(l,f,u,d,y){return typeof l.addEventListener=="function"?s.apply(null,arguments):typeof u=="function"?s.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(M){return s(M,f,u,d,y)}))}function c(l,f,u,d){return function(y){y.delegateTarget=a(y.target,f),y.delegateTarget&&d.call(l,y)}}o.exports=p},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(o,n,i){var a=i(879),s=i(438);function p(u,d,y){if(!u&&!d&&!y)throw new Error("Missing required arguments");if(!a.string(d))throw new TypeError("Second argument must be a String");if(!a.fn(y))throw new TypeError("Third argument must be a Function");if(a.node(u))return c(u,d,y);if(a.nodeList(u))return l(u,d,y);if(a.string(u))return f(u,d,y);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(u,d,y){return u.addEventListener(d,y),{destroy:function(){u.removeEventListener(d,y)}}}function l(u,d,y){return Array.prototype.forEach.call(u,function(M){M.addEventListener(d,y)}),{destroy:function(){Array.prototype.forEach.call(u,function(M){M.removeEventListener(d,y)})}}}function f(u,d,y){return s(document.body,u,d,y)}o.exports=p},817:function(o){function n(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var p=window.getSelection(),c=document.createRange();c.selectNodeContents(i),p.removeAllRanges(),p.addRange(c),a=p.toString()}return a}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,a,s){var p=this.e||(this.e={});return(p[i]||(p[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var p=this;function c(){p.off(i,c),a.apply(s,arguments)}return c._=a,this.on(i,c,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),p=0,c=s.length;for(p;p0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function N(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],a;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(s){a={error:s}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(a)throw a.error}}return i}function q(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||p(d,M)})},y&&(n[d]=y(n[d])))}function p(d,y){try{c(o[d](y))}catch(M){u(i[0][3],M)}}function c(d){d.value instanceof nt?Promise.resolve(d.value.v).then(l,f):u(i[0][2],d)}function l(d){p("next",d)}function f(d){p("throw",d)}function u(d,y){d(y),i.shift(),i.length&&p(i[0][0],i[0][1])}}function fo(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof he=="function"?he(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(a){return new Promise(function(s,p){a=e[i](a),n(s,p,a.done,a.value)})}}function n(i,a,s,p){Promise.resolve(p).then(function(c){i({value:c,done:s})},a)}}function H(e){return typeof e=="function"}function ut(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var zt=ut(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Qe(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var We=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=he(a),p=s.next();!p.done;p=s.next()){var c=p.value;c.remove(this)}}catch(M){t={error:M}}finally{try{p&&!p.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var l=this.initialTeardown;if(H(l))try{l()}catch(M){i=M instanceof zt?M.errors:[M]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=he(f),d=u.next();!d.done;d=u.next()){var y=d.value;try{uo(y)}catch(M){i=i!=null?i:[],M instanceof zt?i=q(q([],N(i)),N(M.errors)):i.push(M)}}}catch(M){o={error:M}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new zt(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)uo(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Qe(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Qe(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Tr=We.EMPTY;function qt(e){return e instanceof We||e&&"closed"in e&&H(e.remove)&&H(e.add)&&H(e.unsubscribe)}function uo(e){H(e)?e():e.unsubscribe()}var Pe={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var dt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,a=n.isStopped,s=n.observers;return i||a?Tr:(this.currentObservers=null,s.push(r),new We(function(){o.currentObservers=null,Qe(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,a=o.isStopped;n?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new j;return r.source=this,r},t.create=function(r,o){return new wo(r,o)},t}(j);var wo=function(e){oe(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:Tr},t}(g);var _r=function(e){oe(t,e);function t(r){var o=e.call(this)||this;return o._value=r,o}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(r){var o=e.prototype._subscribe.call(this,r);return!o.closed&&r.next(this._value),o},t.prototype.getValue=function(){var r=this,o=r.hasError,n=r.thrownError,i=r._value;if(o)throw n;return this._throwIfClosed(),i},t.prototype.next=function(r){e.prototype.next.call(this,this._value=r)},t}(g);var At={now:function(){return(At.delegate||Date).now()},delegate:void 0};var Ct=function(e){oe(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=At);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,a=o._infiniteTimeWindow,s=o._timestampProvider,p=o._windowTime;n||(i.push(r),!a&&i.push(s.now()+p)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,a=n._buffer,s=a.slice(),p=0;p0?e.prototype.schedule.call(this,r,o):(this.delay=o,this.state=r,this.scheduler.flush(this),this)},t.prototype.execute=function(r,o){return o>0||this.closed?e.prototype.execute.call(this,r,o):this._execute(r,o)},t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.flush(this),0)},t}(gt);var Oo=function(e){oe(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t}(yt);var kr=new Oo(So);var Mo=function(e){oe(t,e);function t(r,o){var n=e.call(this,r,o)||this;return n.scheduler=r,n.work=o,n}return t.prototype.requestAsyncId=function(r,o,n){return n===void 0&&(n=0),n!==null&&n>0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=vt.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var a=r.actions;o!=null&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==o&&(vt.cancelAnimationFrame(o),r._scheduled=void 0)},t}(gt);var Lo=function(e){oe(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(yt);var me=new Lo(Mo);var S=new j(function(e){return e.complete()});function Yt(e){return e&&H(e.schedule)}function Hr(e){return e[e.length-1]}function Xe(e){return H(Hr(e))?e.pop():void 0}function ke(e){return Yt(Hr(e))?e.pop():void 0}function Bt(e,t){return typeof Hr(e)=="number"?e.pop():t}var xt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Gt(e){return H(e==null?void 0:e.then)}function Jt(e){return H(e[bt])}function Xt(e){return Symbol.asyncIterator&&H(e==null?void 0:e[Symbol.asyncIterator])}function Zt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Ji(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var er=Ji();function tr(e){return H(e==null?void 0:e[er])}function rr(e){return mo(this,arguments,function(){var r,o,n,i;return Nt(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,nt(r.read())];case 3:return o=a.sent(),n=o.value,i=o.done,i?[4,nt(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,nt(n)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function or(e){return H(e==null?void 0:e.getReader)}function W(e){if(e instanceof j)return e;if(e!=null){if(Jt(e))return Xi(e);if(xt(e))return Zi(e);if(Gt(e))return ea(e);if(Xt(e))return _o(e);if(tr(e))return ta(e);if(or(e))return ra(e)}throw Zt(e)}function Xi(e){return new j(function(t){var r=e[bt]();if(H(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function Zi(e){return new j(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?b(function(n,i){return e(n,i,o)}):le,Te(1),r?De(t):qo(function(){return new ir}))}}function jr(e){return e<=0?function(){return S}:E(function(t,r){var o=[];t.subscribe(T(r,function(n){o.push(n),e=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new g}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,p=s===void 0?!0:s;return function(c){var l,f,u,d=0,y=!1,M=!1,X=function(){f==null||f.unsubscribe(),f=void 0},te=function(){X(),l=u=void 0,y=M=!1},J=function(){var k=l;te(),k==null||k.unsubscribe()};return E(function(k,ft){d++,!M&&!y&&X();var qe=u=u!=null?u:r();ft.add(function(){d--,d===0&&!M&&!y&&(f=Wr(J,p))}),qe.subscribe(ft),!l&&d>0&&(l=new at({next:function(Fe){return qe.next(Fe)},error:function(Fe){M=!0,X(),f=Wr(te,n,Fe),qe.error(Fe)},complete:function(){y=!0,X(),f=Wr(te,a),qe.complete()}}),W(k).subscribe(l))})(c)}}function Wr(e,t){for(var r=[],o=2;oe.next(document)),e}function P(e,t=document){return Array.from(t.querySelectorAll(e))}function R(e,t=document){let r=fe(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function fe(e,t=document){return t.querySelector(e)||void 0}function Ie(){var e,t,r,o;return(o=(r=(t=(e=document.activeElement)==null?void 0:e.shadowRoot)==null?void 0:t.activeElement)!=null?r:document.activeElement)!=null?o:void 0}var xa=O(h(document.body,"focusin"),h(document.body,"focusout")).pipe(_e(1),Q(void 0),m(()=>Ie()||document.body),G(1));function et(e){return xa.pipe(m(t=>e.contains(t)),K())}function $t(e,t){return C(()=>O(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?Ht(r=>Me(+!r*t)):le,Q(e.matches(":hover"))))}function Go(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Go(e,r)}function x(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)Go(o,n);return o}function sr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function Tt(e){let t=x("script",{src:e});return C(()=>(document.head.appendChild(t),O(h(t,"load"),h(t,"error").pipe(v(()=>$r(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),_(()=>document.head.removeChild(t)),Te(1))))}var Jo=new g,Ea=C(()=>typeof ResizeObserver=="undefined"?Tt("https://unpkg.com/resize-observer-polyfill"):I(void 0)).pipe(m(()=>new ResizeObserver(e=>e.forEach(t=>Jo.next(t)))),v(e=>O(Ye,I(e)).pipe(_(()=>e.disconnect()))),G(1));function ce(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ge(e){let t=e;for(;t.clientWidth===0&&t.parentElement;)t=t.parentElement;return Ea.pipe(w(r=>r.observe(t)),v(r=>Jo.pipe(b(o=>o.target===t),_(()=>r.unobserve(t)))),m(()=>ce(e)),Q(ce(e)))}function St(e){return{width:e.scrollWidth,height:e.scrollHeight}}function cr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}function Xo(e){let t=[],r=e.parentElement;for(;r;)(e.clientWidth>r.clientWidth||e.clientHeight>r.clientHeight)&&t.push(r),r=(e=r).parentElement;return t.length===0&&t.push(document.documentElement),t}function Ve(e){return{x:e.offsetLeft,y:e.offsetTop}}function Zo(e){let t=e.getBoundingClientRect();return{x:t.x+window.scrollX,y:t.y+window.scrollY}}function en(e){return O(h(window,"load"),h(window,"resize")).pipe(Le(0,me),m(()=>Ve(e)),Q(Ve(e)))}function pr(e){return{x:e.scrollLeft,y:e.scrollTop}}function Ne(e){return O(h(e,"scroll"),h(window,"scroll"),h(window,"resize")).pipe(Le(0,me),m(()=>pr(e)),Q(pr(e)))}var tn=new g,wa=C(()=>I(new IntersectionObserver(e=>{for(let t of e)tn.next(t)},{threshold:0}))).pipe(v(e=>O(Ye,I(e)).pipe(_(()=>e.disconnect()))),G(1));function tt(e){return wa.pipe(w(t=>t.observe(e)),v(t=>tn.pipe(b(({target:r})=>r===e),_(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function rn(e,t=16){return Ne(e).pipe(m(({y:r})=>{let o=ce(e),n=St(e);return r>=n.height-o.height-t}),K())}var lr={drawer:R("[data-md-toggle=drawer]"),search:R("[data-md-toggle=search]")};function on(e){return lr[e].checked}function Je(e,t){lr[e].checked!==t&&lr[e].click()}function ze(e){let t=lr[e];return h(t,"change").pipe(m(()=>t.checked),Q(t.checked))}function Ta(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Sa(){return O(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(Q(!1))}function nn(){let e=h(window,"keydown").pipe(b(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:on("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),b(({mode:t,type:r})=>{if(t==="global"){let o=Ie();if(typeof o!="undefined")return!Ta(o,r)}return!0}),pe());return Sa().pipe(v(t=>t?S:e))}function ye(){return new URL(location.href)}function lt(e,t=!1){if(B("navigation.instant")&&!t){let r=x("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function an(){return new g}function sn(){return location.hash.slice(1)}function cn(e){let t=x("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Oa(e){return O(h(window,"hashchange"),e).pipe(m(sn),Q(sn()),b(t=>t.length>0),G(1))}function pn(e){return Oa(e).pipe(m(t=>fe(`[id="${t}"]`)),b(t=>typeof t!="undefined"))}function Pt(e){let t=matchMedia(e);return ar(r=>t.addListener(()=>r(t.matches))).pipe(Q(t.matches))}function ln(){let e=matchMedia("print");return O(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(Q(e.matches))}function Nr(e,t){return e.pipe(v(r=>r?t():S))}function zr(e,t){return new j(r=>{let o=new XMLHttpRequest;return o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network error"))}),o.addEventListener("abort",()=>{r.complete()}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{var i;if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let a=(i=o.getResponseHeader("Content-Length"))!=null?i:0;t.progress$.next(n.loaded/+a*100)}}),t.progress$.next(5)),o.send(),()=>o.abort()})}function je(e,t){return zr(e,t).pipe(v(r=>r.text()),m(r=>JSON.parse(r)),G(1))}function mn(e,t){let r=new DOMParser;return zr(e,t).pipe(v(o=>o.text()),m(o=>r.parseFromString(o,"text/html")),G(1))}function fn(e,t){let r=new DOMParser;return zr(e,t).pipe(v(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),G(1))}function un(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function dn(){return O(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(un),Q(un()))}function hn(){return{width:innerWidth,height:innerHeight}}function bn(){return h(window,"resize",{passive:!0}).pipe(m(hn),Q(hn()))}function vn(){return z([dn(),bn()]).pipe(m(([e,t])=>({offset:e,size:t})),G(1))}function mr(e,{viewport$:t,header$:r}){let o=t.pipe(ee("size")),n=z([o,r]).pipe(m(()=>Ve(e)));return z([r,t,n]).pipe(m(([{height:i},{offset:a,size:s},{x:p,y:c}])=>({offset:{x:a.x-p,y:a.y-c+i},size:s})))}function Ma(e){return h(e,"message",t=>t.data)}function La(e){let t=new g;return t.subscribe(r=>e.postMessage(r)),t}function gn(e,t=new Worker(e)){let r=Ma(t),o=La(t),n=new g;n.subscribe(o);let i=o.pipe(Z(),ie(!0));return n.pipe(Z(),Re(r.pipe(U(i))),pe())}var _a=R("#__config"),Ot=JSON.parse(_a.textContent);Ot.base=`${new URL(Ot.base,ye())}`;function xe(){return Ot}function B(e){return Ot.features.includes(e)}function Ee(e,t){return typeof t!="undefined"?Ot.translations[e].replace("#",t.toString()):Ot.translations[e]}function Se(e,t=document){return R(`[data-md-component=${e}]`,t)}function ae(e,t=document){return P(`[data-md-component=${e}]`,t)}function Aa(e){let t=R(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>R(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function yn(e){if(!B("announce.dismiss")||!e.childElementCount)return S;if(!e.hidden){let t=R(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return C(()=>{let t=new g;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),Aa(e).pipe(w(r=>t.next(r)),_(()=>t.complete()),m(r=>$({ref:e},r)))})}function Ca(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function xn(e,t){let r=new g;return r.subscribe(({hidden:o})=>{e.hidden=o}),Ca(e,t).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))}function Rt(e,t){return t==="inline"?x("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"})):x("div",{class:"md-tooltip",id:e,role:"tooltip"},x("div",{class:"md-tooltip__inner md-typeset"}))}function En(...e){return x("div",{class:"md-tooltip2",role:"tooltip"},x("div",{class:"md-tooltip2__inner md-typeset"},e))}function wn(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return x("aside",{class:"md-annotation",tabIndex:0},Rt(t),x("a",{href:r,class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}else return x("aside",{class:"md-annotation",tabIndex:0},Rt(t),x("span",{class:"md-annotation__index",tabIndex:-1},x("span",{"data-md-annotation-id":e})))}function Tn(e){return x("button",{class:"md-clipboard md-icon",title:Ee("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}var On=Lt(qr());function Qr(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(p=>!e.terms[p]).reduce((p,c)=>[...p,x("del",null,(0,On.default)(c))," "],[]).slice(0,-1),i=xe(),a=new URL(e.location,i.base);B("search.highlight")&&a.searchParams.set("h",Object.entries(e.terms).filter(([,p])=>p).reduce((p,[c])=>`${p} ${c}`.trim(),""));let{tags:s}=xe();return x("a",{href:`${a}`,class:"md-search-result__link",tabIndex:-1},x("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&x("div",{class:"md-search-result__icon md-icon"}),r>0&&x("h1",null,e.title),r<=0&&x("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&e.tags.map(p=>{let c=s?p in s?`md-tag-icon md-tag--${s[p]}`:"md-tag-icon":"";return x("span",{class:`md-tag ${c}`},p)}),o>0&&n.length>0&&x("p",{class:"md-search-result__terms"},Ee("search.result.term.missing"),": ",...n)))}function Mn(e){let t=e[0].score,r=[...e],o=xe(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),a=r.findIndex(l=>l.scoreQr(l,1)),...p.length?[x("details",{class:"md-search-result__more"},x("summary",{tabIndex:-1},x("div",null,p.length>0&&p.length===1?Ee("search.result.more.one"):Ee("search.result.more.other",p.length))),...p.map(l=>Qr(l,1)))]:[]];return x("li",{class:"md-search-result__item"},c)}function Ln(e){return x("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>x("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?sr(r):r)))}function Kr(e){let t=`tabbed-control tabbed-control--${e}`;return x("div",{class:t,hidden:!0},x("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function _n(e){return x("div",{class:"md-typeset__scrollwrap"},x("div",{class:"md-typeset__table"},e))}function $a(e){var o;let t=xe(),r=new URL(`../${e.version}/`,t.base);return x("li",{class:"md-version__item"},x("a",{href:`${r}`,class:"md-version__link"},e.title,((o=t.version)==null?void 0:o.alias)&&e.aliases.length>0&&x("span",{class:"md-version__alias"},e.aliases[0])))}function An(e,t){var o;let r=xe();return e=e.filter(n=>{var i;return!((i=n.properties)!=null&&i.hidden)}),x("div",{class:"md-version"},x("button",{class:"md-version__current","aria-label":Ee("select.version")},t.title,((o=r.version)==null?void 0:o.alias)&&t.aliases.length>0&&x("span",{class:"md-version__alias"},t.aliases[0])),x("ul",{class:"md-version__list"},e.map($a)))}var Pa=0;function Ra(e){let t=z([et(e),$t(e)]).pipe(m(([o,n])=>o||n),K()),r=C(()=>Xo(e)).pipe(ne(Ne),pt(1),He(t),m(()=>Zo(e)));return t.pipe(Ae(o=>o),v(()=>z([t,r])),m(([o,n])=>({active:o,offset:n})),pe())}function Ia(e,t){let{content$:r,viewport$:o}=t,n=`__tooltip2_${Pa++}`;return C(()=>{let i=new g,a=new _r(!1);i.pipe(Z(),ie(!1)).subscribe(a);let s=a.pipe(Ht(c=>Me(+!c*250,kr)),K(),v(c=>c?r:S),w(c=>c.id=n),pe());z([i.pipe(m(({active:c})=>c)),s.pipe(v(c=>$t(c,250)),Q(!1))]).pipe(m(c=>c.some(l=>l))).subscribe(a);let p=a.pipe(b(c=>c),re(s,o),m(([c,l,{size:f}])=>{let u=e.getBoundingClientRect(),d=u.width/2;if(l.role==="tooltip")return{x:d,y:8+u.height};if(u.y>=f.height/2){let{height:y}=ce(l);return{x:d,y:-16-y}}else return{x:d,y:16+u.height}}));return z([s,i,p]).subscribe(([c,{offset:l},f])=>{c.style.setProperty("--md-tooltip-host-x",`${l.x}px`),c.style.setProperty("--md-tooltip-host-y",`${l.y}px`),c.style.setProperty("--md-tooltip-x",`${f.x}px`),c.style.setProperty("--md-tooltip-y",`${f.y}px`),c.classList.toggle("md-tooltip2--top",f.y<0),c.classList.toggle("md-tooltip2--bottom",f.y>=0)}),a.pipe(b(c=>c),re(s,(c,l)=>l),b(c=>c.role==="tooltip")).subscribe(c=>{let l=ce(R(":scope > *",c));c.style.setProperty("--md-tooltip-width",`${l.width}px`),c.style.setProperty("--md-tooltip-tail","0px")}),a.pipe(K(),ve(me),re(s)).subscribe(([c,l])=>{l.classList.toggle("md-tooltip2--active",c)}),z([a.pipe(b(c=>c)),s]).subscribe(([c,l])=>{l.role==="dialog"?(e.setAttribute("aria-controls",n),e.setAttribute("aria-haspopup","dialog")):e.setAttribute("aria-describedby",n)}),a.pipe(b(c=>!c)).subscribe(()=>{e.removeAttribute("aria-controls"),e.removeAttribute("aria-describedby"),e.removeAttribute("aria-haspopup")}),Ra(e).pipe(w(c=>i.next(c)),_(()=>i.complete()),m(c=>$({ref:e},c)))})}function mt(e,{viewport$:t},r=document.body){return Ia(e,{content$:new j(o=>{let n=e.title,i=En(n);return o.next(i),e.removeAttribute("title"),r.append(i),()=>{i.remove(),e.setAttribute("title",n)}}),viewport$:t})}function ja(e,t){let r=C(()=>z([en(e),Ne(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:a,height:s}=ce(e);return{x:o-i.x+a/2,y:n-i.y+s/2}}));return et(e).pipe(v(o=>r.pipe(m(n=>({active:o,offset:n})),Te(+!o||1/0))))}function Cn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return C(()=>{let i=new g,a=i.pipe(Z(),ie(!0));return i.subscribe({next({offset:s}){e.style.setProperty("--md-tooltip-x",`${s.x}px`),e.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),tt(e).pipe(U(a)).subscribe(s=>{e.toggleAttribute("data-md-visible",s)}),O(i.pipe(b(({active:s})=>s)),i.pipe(_e(250),b(({active:s})=>!s))).subscribe({next({active:s}){s?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(Le(16,me)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(pt(125,me),b(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?e.style.setProperty("--md-tooltip-0",`${-s}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(U(a),b(s=>!(s.metaKey||s.ctrlKey))).subscribe(s=>{s.stopPropagation(),s.preventDefault()}),h(n,"mousedown").pipe(U(a),re(i)).subscribe(([s,{active:p}])=>{var c;if(s.button!==0||s.metaKey||s.ctrlKey)s.preventDefault();else if(p){s.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(c=Ie())==null||c.blur()}}),r.pipe(U(a),b(s=>s===o),Ge(125)).subscribe(()=>e.focus()),ja(e,t).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))})}function Fa(e){return e.tagName==="CODE"?P(".c, .c1, .cm",e):[e]}function Wa(e){let t=[];for(let r of Fa(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let a;for(;a=/(\(\d+\))(!)?/.exec(i.textContent);){let[,s,p]=a;if(typeof p=="undefined"){let c=i.splitText(a.index);i=c.splitText(s.length),t.push(c)}else{i.textContent=s,t.push(i);break}}}}return t}function kn(e,t){t.append(...Array.from(e.childNodes))}function fr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,a=new Map;for(let s of Wa(t)){let[,p]=s.textContent.match(/\((\d+)\)/);fe(`:scope > li:nth-child(${p})`,e)&&(a.set(p,wn(p,i)),s.replaceWith(a.get(p)))}return a.size===0?S:C(()=>{let s=new g,p=s.pipe(Z(),ie(!0)),c=[];for(let[l,f]of a)c.push([R(".md-typeset",f),R(`:scope > li:nth-child(${l})`,e)]);return o.pipe(U(p)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of c)l?kn(f,u):kn(u,f)}),O(...[...a].map(([,l])=>Cn(l,t,{target$:r}))).pipe(_(()=>s.complete()),pe())})}function Hn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Hn(t)}}function $n(e,t){return C(()=>{let r=Hn(e);return typeof r!="undefined"?fr(r,e,t):S})}var Pn=Lt(Br());var Ua=0;function Rn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Rn(t)}}function Da(e){return ge(e).pipe(m(({width:t})=>({scrollable:St(e).width>t})),ee("scrollable"))}function In(e,t){let{matches:r}=matchMedia("(hover)"),o=C(()=>{let n=new g,i=n.pipe(jr(1));n.subscribe(({scrollable:c})=>{c&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let a=[];if(Pn.default.isSupported()&&(e.closest(".copy")||B("content.code.copy")&&!e.closest(".no-copy"))){let c=e.closest("pre");c.id=`__code_${Ua++}`;let l=Tn(c.id);c.insertBefore(l,e),B("content.tooltips")&&a.push(mt(l,{viewport$}))}let s=e.closest(".highlight");if(s instanceof HTMLElement){let c=Rn(s);if(typeof c!="undefined"&&(s.classList.contains("annotate")||B("content.code.annotate"))){let l=fr(c,e,t);a.push(ge(s).pipe(U(i),m(({width:f,height:u})=>f&&u),K(),v(f=>f?l:S)))}}return P(":scope > span[id]",e).length&&e.classList.add("md-code__content"),Da(e).pipe(w(c=>n.next(c)),_(()=>n.complete()),m(c=>$({ref:e},c)),Re(...a))});return B("content.lazy")?tt(e).pipe(b(n=>n),Te(1),v(()=>o)):o}function Va(e,{target$:t,print$:r}){let o=!0;return O(t.pipe(m(n=>n.closest("details:not([open])")),b(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(b(n=>n||!o),w(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function jn(e,t){return C(()=>{let r=new g;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),Va(e,t).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}var Fn=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel p,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel p{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel,.nodeLabel p{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}a .nodeLabel{text-decoration:underline}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var Gr,za=0;function qa(){return typeof mermaid=="undefined"||mermaid instanceof Element?Tt("https://unpkg.com/mermaid@11/dist/mermaid.min.js"):I(void 0)}function Wn(e){return e.classList.remove("mermaid"),Gr||(Gr=qa().pipe(w(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Fn,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),G(1))),Gr.subscribe(()=>so(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${za++}`,r=x("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),a=r.attachShadow({mode:"closed"});a.innerHTML=n,e.replaceWith(r),i==null||i(a)})),Gr.pipe(m(()=>({ref:e})))}var Un=x("table");function Dn(e){return e.replaceWith(Un),Un.replaceWith(_n(e)),I({ref:e})}function Qa(e){let t=e.find(r=>r.checked)||e[0];return O(...e.map(r=>h(r,"change").pipe(m(()=>R(`label[for="${r.id}"]`))))).pipe(Q(R(`label[for="${t.id}"]`)),m(r=>({active:r})))}function Vn(e,{viewport$:t,target$:r}){let o=R(".tabbed-labels",e),n=P(":scope > input",e),i=Kr("prev");e.append(i);let a=Kr("next");return e.append(a),C(()=>{let s=new g,p=s.pipe(Z(),ie(!0));z([s,ge(e),tt(e)]).pipe(U(p),Le(1,me)).subscribe({next([{active:c},l]){let f=Ve(c),{width:u}=ce(c);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=pr(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),z([Ne(o),ge(o)]).pipe(U(p)).subscribe(([c,l])=>{let f=St(o);i.hidden=c.x<16,a.hidden=c.x>f.width-l.width-16}),O(h(i,"click").pipe(m(()=>-1)),h(a,"click").pipe(m(()=>1))).pipe(U(p)).subscribe(c=>{let{width:l}=ce(o);o.scrollBy({left:l*c,behavior:"smooth"})}),r.pipe(U(p),b(c=>n.includes(c))).subscribe(c=>c.click()),o.classList.add("tabbed-labels--linked");for(let c of n){let l=R(`label[for="${c.id}"]`);l.replaceChildren(x("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(U(p),b(f=>!(f.metaKey||f.ctrlKey)),w(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return B("content.tabs.link")&&s.pipe(Ce(1),re(t)).subscribe(([{active:c},{offset:l}])=>{let f=c.innerText.trim();if(c.hasAttribute("data-md-switching"))c.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let y of P("[data-tabs]"))for(let M of P(":scope > input",y)){let X=R(`label[for="${M.id}"]`);if(X!==c&&X.innerText.trim()===f){X.setAttribute("data-md-switching",""),M.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),s.pipe(U(p)).subscribe(()=>{for(let c of P("audio, video",e))c.pause()}),Qa(n).pipe(w(c=>s.next(c)),_(()=>s.complete()),m(c=>$({ref:e},c)))}).pipe(Ke(se))}function Nn(e,{viewport$:t,target$:r,print$:o}){return O(...P(".annotate:not(.highlight)",e).map(n=>$n(n,{target$:r,print$:o})),...P("pre:not(.mermaid) > code",e).map(n=>In(n,{target$:r,print$:o})),...P("pre.mermaid",e).map(n=>Wn(n)),...P("table:not([class])",e).map(n=>Dn(n)),...P("details",e).map(n=>jn(n,{target$:r,print$:o})),...P("[data-tabs]",e).map(n=>Vn(n,{viewport$:t,target$:r})),...P("[title]",e).filter(()=>B("content.tooltips")).map(n=>mt(n,{viewport$:t})))}function Ka(e,{alert$:t}){return t.pipe(v(r=>O(I(!0),I(!1).pipe(Ge(2e3))).pipe(m(o=>({message:r,active:o})))))}function zn(e,t){let r=R(".md-typeset",e);return C(()=>{let o=new g;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),Ka(e,t).pipe(w(n=>o.next(n)),_(()=>o.complete()),m(n=>$({ref:e},n)))})}var Ya=0;function Ba(e,t){document.body.append(e);let{width:r}=ce(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=cr(t),n=typeof o!="undefined"?Ne(o):I({x:0,y:0}),i=O(et(t),$t(t)).pipe(K());return z([i,n]).pipe(m(([a,s])=>{let{x:p,y:c}=Ve(t),l=ce(t),f=t.closest("table");return f&&t.parentElement&&(p+=f.offsetLeft+t.parentElement.offsetLeft,c+=f.offsetTop+t.parentElement.offsetTop),{active:a,offset:{x:p-s.x+l.width/2-r/2,y:c-s.y+l.height+8}}}))}function qn(e){let t=e.title;if(!t.length)return S;let r=`__tooltip_${Ya++}`,o=Rt(r,"inline"),n=R(".md-typeset",o);return n.innerHTML=t,C(()=>{let i=new g;return i.subscribe({next({offset:a}){o.style.setProperty("--md-tooltip-x",`${a.x}px`),o.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),O(i.pipe(b(({active:a})=>a)),i.pipe(_e(250),b(({active:a})=>!a))).subscribe({next({active:a}){a?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe(Le(16,me)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(pt(125,me),b(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?o.style.setProperty("--md-tooltip-0",`${-a}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),Ba(o,e).pipe(w(a=>i.next(a)),_(()=>i.complete()),m(a=>$({ref:e},a)))}).pipe(Ke(se))}function Ga({viewport$:e}){if(!B("header.autohide"))return I(!1);let t=e.pipe(m(({offset:{y:n}})=>n),Be(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),K()),o=ze("search");return z([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),K(),v(n=>n?r:I(!1)),Q(!1))}function Qn(e,t){return C(()=>z([ge(e),Ga(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),K((r,o)=>r.height===o.height&&r.hidden===o.hidden),G(1))}function Kn(e,{header$:t,main$:r}){return C(()=>{let o=new g,n=o.pipe(Z(),ie(!0));o.pipe(ee("active"),He(t)).subscribe(([{active:a},{hidden:s}])=>{e.classList.toggle("md-header--shadow",a&&!s),e.hidden=s});let i=ue(P("[title]",e)).pipe(b(()=>B("content.tooltips")),ne(a=>qn(a)));return r.subscribe(o),t.pipe(U(n),m(a=>$({ref:e},a)),Re(i.pipe(U(n))))})}function Ja(e,{viewport$:t,header$:r}){return mr(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=ce(e);return{active:o>=n}}),ee("active"))}function Yn(e,t){return C(()=>{let r=new g;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=fe(".md-content h1");return typeof o=="undefined"?S:Ja(o,t).pipe(w(n=>r.next(n)),_(()=>r.complete()),m(n=>$({ref:e},n)))})}function Bn(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),K()),n=o.pipe(v(()=>ge(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),ee("bottom"))));return z([o,n,t]).pipe(m(([i,{top:a,bottom:s},{offset:{y:p},size:{height:c}}])=>(c=Math.max(0,c-Math.max(0,a-p,i)-Math.max(0,c+p-s)),{offset:a-i,height:c,active:a-i<=p})),K((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function Xa(e){let t=__md_get("__palette")||{index:e.findIndex(o=>matchMedia(o.getAttribute("data-md-color-media")).matches)},r=Math.max(0,Math.min(t.index,e.length-1));return I(...e).pipe(ne(o=>h(o,"change").pipe(m(()=>o))),Q(e[r]),m(o=>({index:e.indexOf(o),color:{media:o.getAttribute("data-md-color-media"),scheme:o.getAttribute("data-md-color-scheme"),primary:o.getAttribute("data-md-color-primary"),accent:o.getAttribute("data-md-color-accent")}})),G(1))}function Gn(e){let t=P("input",e),r=x("meta",{name:"theme-color"});document.head.appendChild(r);let o=x("meta",{name:"color-scheme"});document.head.appendChild(o);let n=Pt("(prefers-color-scheme: light)");return C(()=>{let i=new g;return i.subscribe(a=>{if(document.body.setAttribute("data-md-color-switching",""),a.color.media==="(prefers-color-scheme)"){let s=matchMedia("(prefers-color-scheme: light)"),p=document.querySelector(s.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");a.color.scheme=p.getAttribute("data-md-color-scheme"),a.color.primary=p.getAttribute("data-md-color-primary"),a.color.accent=p.getAttribute("data-md-color-accent")}for(let[s,p]of Object.entries(a.color))document.body.setAttribute(`data-md-color-${s}`,p);for(let s=0;sa.key==="Enter"),re(i,(a,s)=>s)).subscribe(({index:a})=>{a=(a+1)%t.length,t[a].click(),t[a].focus()}),i.pipe(m(()=>{let a=Se("header"),s=window.getComputedStyle(a);return o.content=s.colorScheme,s.backgroundColor.match(/\d+/g).map(p=>(+p).toString(16).padStart(2,"0")).join("")})).subscribe(a=>r.content=`#${a}`),i.pipe(ve(se)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),Xa(t).pipe(U(n.pipe(Ce(1))),ct(),w(a=>i.next(a)),_(()=>i.complete()),m(a=>$({ref:e},a)))})}function Jn(e,{progress$:t}){return C(()=>{let r=new g;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(w(o=>r.next({value:o})),_(()=>r.complete()),m(o=>({ref:e,value:o})))})}var Jr=Lt(Br());function Za(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function Xn({alert$:e}){Jr.default.isSupported()&&new j(t=>{new Jr.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||Za(R(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(w(t=>{t.trigger.focus()}),m(()=>Ee("clipboard.copied"))).subscribe(e)}function Zn(e,t){return e.protocol=t.protocol,e.hostname=t.hostname,e}function es(e,t){let r=new Map;for(let o of P("url",e)){let n=R("loc",o),i=[Zn(new URL(n.textContent),t)];r.set(`${i[0]}`,i);for(let a of P("[rel=alternate]",o)){let s=a.getAttribute("href");s!=null&&i.push(Zn(new URL(s),t))}}return r}function ur(e){return fn(new URL("sitemap.xml",e)).pipe(m(t=>es(t,new URL(e))),de(()=>I(new Map)))}function ts(e,t){if(!(e.target instanceof Element))return S;let r=e.target.closest("a");if(r===null)return S;if(r.target||e.metaKey||e.ctrlKey)return S;let o=new URL(r.href);return o.search=o.hash="",t.has(`${o}`)?(e.preventDefault(),I(new URL(r.href))):S}function ei(e){let t=new Map;for(let r of P(":scope > *",e.head))t.set(r.outerHTML,r);return t}function ti(e){for(let t of P("[href], [src]",e))for(let r of["href","src"]){let o=t.getAttribute(r);if(o&&!/^(?:[a-z]+:)?\/\//i.test(o)){t[r]=t[r];break}}return I(e)}function rs(e){for(let o of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...B("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let n=fe(o),i=fe(o,e);typeof n!="undefined"&&typeof i!="undefined"&&n.replaceWith(i)}let t=ei(document);for(let[o,n]of ei(e))t.has(o)?t.delete(o):document.head.appendChild(n);for(let o of t.values()){let n=o.getAttribute("name");n!=="theme-color"&&n!=="color-scheme"&&o.remove()}let r=Se("container");return Ue(P("script",r)).pipe(v(o=>{let n=e.createElement("script");if(o.src){for(let i of o.getAttributeNames())n.setAttribute(i,o.getAttribute(i));return o.replaceWith(n),new j(i=>{n.onload=()=>i.complete()})}else return n.textContent=o.textContent,o.replaceWith(n),S}),Z(),ie(document))}function ri({location$:e,viewport$:t,progress$:r}){let o=xe();if(location.protocol==="file:")return S;let n=ur(o.base);I(document).subscribe(ti);let i=h(document.body,"click").pipe(He(n),v(([p,c])=>ts(p,c)),pe()),a=h(window,"popstate").pipe(m(ye),pe());i.pipe(re(t)).subscribe(([p,{offset:c}])=>{history.replaceState(c,""),history.pushState(null,"",p)}),O(i,a).subscribe(e);let s=e.pipe(ee("pathname"),v(p=>mn(p,{progress$:r}).pipe(de(()=>(lt(p,!0),S)))),v(ti),v(rs),pe());return O(s.pipe(re(e,(p,c)=>c)),s.pipe(v(()=>e),ee("pathname"),v(()=>e),ee("hash")),e.pipe(K((p,c)=>p.pathname===c.pathname&&p.hash===c.hash),v(()=>i),w(()=>history.back()))).subscribe(p=>{var c,l;history.state!==null||!p.hash?window.scrollTo(0,(l=(c=history.state)==null?void 0:c.y)!=null?l:0):(history.scrollRestoration="auto",cn(p.hash),history.scrollRestoration="manual")}),e.subscribe(()=>{history.scrollRestoration="manual"}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),t.pipe(ee("offset"),_e(100)).subscribe(({offset:p})=>{history.replaceState(p,"")}),s}var oi=Lt(qr());function ni(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,a)=>`${i}${a}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return a=>(0,oi.default)(a).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function jt(e){return e.type===1}function dr(e){return e.type===3}function ii(e,t){let r=gn(e);return O(I(location.protocol!=="file:"),ze("search")).pipe(Ae(o=>o),v(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:B("search.suggest")}}})),r}function ai({document$:e}){let t=xe(),r=je(new URL("../versions.json",t.base)).pipe(de(()=>S)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:a,aliases:s})=>a===i||s.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),v(n=>h(document.body,"click").pipe(b(i=>!i.metaKey&&!i.ctrlKey),re(o),v(([i,a])=>{if(i.target instanceof Element){let s=i.target.closest("a");if(s&&!s.target&&n.has(s.href)){let p=s.href;return!i.target.closest(".md-version")&&n.get(p)===a?S:(i.preventDefault(),I(p))}}return S}),v(i=>ur(new URL(i)).pipe(m(a=>{let p=ye().href.replace(t.base,i);return a.has(p.split("#")[0])?new URL(p):new URL(i)})))))).subscribe(n=>lt(n,!0)),z([r,o]).subscribe(([n,i])=>{R(".md-header__topic").appendChild(An(n,i))}),e.pipe(v(()=>o)).subscribe(n=>{var a;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let s=((a=t.version)==null?void 0:a.default)||"latest";Array.isArray(s)||(s=[s]);e:for(let p of s)for(let c of n.aliases.concat(n.version))if(new RegExp(p,"i").test(c)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let s of ae("outdated"))s.hidden=!1})}function is(e,{worker$:t}){let{searchParams:r}=ye();r.has("q")&&(Je("search",!0),e.value=r.get("q"),e.focus(),ze("search").pipe(Ae(i=>!i)).subscribe(()=>{let i=ye();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=et(e),n=O(t.pipe(Ae(jt)),h(e,"keyup"),o).pipe(m(()=>e.value),K());return z([n,o]).pipe(m(([i,a])=>({value:i,focus:a})),G(1))}function si(e,{worker$:t}){let r=new g,o=r.pipe(Z(),ie(!0));z([t.pipe(Ae(jt)),r],(i,a)=>a).pipe(ee("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(ee("focus")).subscribe(({focus:i})=>{i&&Je("search",i)}),h(e.form,"reset").pipe(U(o)).subscribe(()=>e.focus());let n=R("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),is(e,{worker$:t}).pipe(w(i=>r.next(i)),_(()=>r.complete()),m(i=>$({ref:e},i)),G(1))}function ci(e,{worker$:t,query$:r}){let o=new g,n=rn(e.parentElement).pipe(b(Boolean)),i=e.parentElement,a=R(":scope > :first-child",e),s=R(":scope > :last-child",e);ze("search").subscribe(l=>s.setAttribute("role",l?"list":"presentation")),o.pipe(re(r),Ur(t.pipe(Ae(jt)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:a.textContent=f.length?Ee("search.result.none"):Ee("search.result.placeholder");break;case 1:a.textContent=Ee("search.result.one");break;default:let u=sr(l.length);a.textContent=Ee("search.result.other",u)}});let p=o.pipe(w(()=>s.innerHTML=""),v(({items:l})=>O(I(...l.slice(0,10)),I(...l.slice(10)).pipe(Be(4),Vr(n),v(([f])=>f)))),m(Mn),pe());return p.subscribe(l=>s.appendChild(l)),p.pipe(ne(l=>{let f=fe("details",l);return typeof f=="undefined"?S:h(f,"toggle").pipe(U(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(b(dr),m(({data:l})=>l)).pipe(w(l=>o.next(l)),_(()=>o.complete()),m(l=>$({ref:e},l)))}function as(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=ye();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function pi(e,t){let r=new g,o=r.pipe(Z(),ie(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(U(o)).subscribe(n=>n.preventDefault()),as(e,t).pipe(w(n=>r.next(n)),_(()=>r.complete()),m(n=>$({ref:e},n)))}function li(e,{worker$:t,keyboard$:r}){let o=new g,n=Se("search-query"),i=O(h(n,"keydown"),h(n,"focus")).pipe(ve(se),m(()=>n.value),K());return o.pipe(He(i),m(([{suggest:s},p])=>{let c=p.split(/([\s-]+)/);if(s!=null&&s.length&&c[c.length-1]){let l=s[s.length-1];l.startsWith(c[c.length-1])&&(c[c.length-1]=l)}else c.length=0;return c})).subscribe(s=>e.innerHTML=s.join("").replace(/\s/g," ")),r.pipe(b(({mode:s})=>s==="search")).subscribe(s=>{switch(s.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(b(dr),m(({data:s})=>s)).pipe(w(s=>o.next(s)),_(()=>o.complete()),m(()=>({ref:e})))}function mi(e,{index$:t,keyboard$:r}){let o=xe();try{let n=ii(o.search,t),i=Se("search-query",e),a=Se("search-result",e);h(e,"click").pipe(b(({target:p})=>p instanceof Element&&!!p.closest("a"))).subscribe(()=>Je("search",!1)),r.pipe(b(({mode:p})=>p==="search")).subscribe(p=>{let c=Ie();switch(p.type){case"Enter":if(c===i){let l=new Map;for(let f of P(":first-child [href]",a)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}p.claim()}break;case"Escape":case"Tab":Je("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof c=="undefined")i.focus();else{let l=[i,...P(":not(details) > [href], summary, details[open] [href]",a)],f=Math.max(0,(Math.max(0,l.indexOf(c))+l.length+(p.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}p.claim();break;default:i!==Ie()&&i.focus()}}),r.pipe(b(({mode:p})=>p==="global")).subscribe(p=>{switch(p.type){case"f":case"s":case"/":i.focus(),i.select(),p.claim();break}});let s=si(i,{worker$:n});return O(s,ci(a,{worker$:n,query$:s})).pipe(Re(...ae("search-share",e).map(p=>pi(p,{query$:s})),...ae("search-suggest",e).map(p=>li(p,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,Ye}}function fi(e,{index$:t,location$:r}){return z([t,r.pipe(Q(ye()),b(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>ni(o.config)(n.searchParams.get("h"))),m(o=>{var a;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let s=i.nextNode();s;s=i.nextNode())if((a=s.parentElement)!=null&&a.offsetHeight){let p=s.textContent,c=o(p);c.length>p.length&&n.set(s,c)}for(let[s,p]of n){let{childNodes:c}=x("span",null,p);s.replaceWith(...Array.from(c))}return{ref:e,nodes:n}}))}function ss(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return z([r,t]).pipe(m(([{offset:i,height:a},{offset:{y:s}}])=>(a=a+Math.min(n,Math.max(0,s-i))-n,{height:a,locked:s>=i+n})),K((i,a)=>i.height===a.height&&i.locked===a.locked))}function Xr(e,o){var n=o,{header$:t}=n,r=ao(n,["header$"]);let i=R(".md-sidebar__scrollwrap",e),{y:a}=Ve(i);return C(()=>{let s=new g,p=s.pipe(Z(),ie(!0)),c=s.pipe(Le(0,me));return c.pipe(re(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*a}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),c.pipe(Ae()).subscribe(()=>{for(let l of P(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ce(f);f.scrollTo({top:u-d/2})}}}),ue(P("label[tabindex]",e)).pipe(ne(l=>h(l,"click").pipe(ve(se),m(()=>l),U(p)))).subscribe(l=>{let f=R(`[id="${l.htmlFor}"]`);R(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),ss(e,r).pipe(w(l=>s.next(l)),_(()=>s.complete()),m(l=>$({ref:e},l)))})}function ui(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return st(je(`${r}/releases/latest`).pipe(de(()=>S),m(o=>({version:o.tag_name})),De({})),je(r).pipe(de(()=>S),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),De({}))).pipe(m(([o,n])=>$($({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return je(r).pipe(m(o=>({repositories:o.public_repos})),De({}))}}function di(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return st(je(`${r}/releases/permalink/latest`).pipe(de(()=>S),m(({tag_name:o})=>({version:o})),De({})),je(r).pipe(de(()=>S),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),De({}))).pipe(m(([o,n])=>$($({},o),n)))}function hi(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return ui(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return di(r,o)}return S}var cs;function ps(e){return cs||(cs=C(()=>{let t=__md_get("__source",sessionStorage);if(t)return I(t);if(ae("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return S}return hi(e.href).pipe(w(o=>__md_set("__source",o,sessionStorage)))}).pipe(de(()=>S),b(t=>Object.keys(t).length>0),m(t=>({facts:t})),G(1)))}function bi(e){let t=R(":scope > :last-child",e);return C(()=>{let r=new g;return r.subscribe(({facts:o})=>{t.appendChild(Ln(o)),t.classList.add("md-source__repository--active")}),ps(e).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}function ls(e,{viewport$:t,header$:r}){return ge(document.body).pipe(v(()=>mr(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),ee("hidden"))}function vi(e,t){return C(()=>{let r=new g;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(B("navigation.tabs.sticky")?I({hidden:!1}):ls(e,t)).pipe(w(o=>r.next(o)),_(()=>r.complete()),m(o=>$({ref:e},o)))})}function ms(e,{viewport$:t,header$:r}){let o=new Map,n=P(".md-nav__link",e);for(let s of n){let p=decodeURIComponent(s.hash.substring(1)),c=fe(`[id="${p}"]`);typeof c!="undefined"&&o.set(s,c)}let i=r.pipe(ee("height"),m(({height:s})=>{let p=Se("main"),c=R(":scope > :first-child",p);return s+.8*(c.offsetTop-p.offsetTop)}),pe());return ge(document.body).pipe(ee("height"),v(s=>C(()=>{let p=[];return I([...o].reduce((c,[l,f])=>{for(;p.length&&o.get(p[p.length-1]).tagName>=f.tagName;)p.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return c.set([...p=[...p,l]].reverse(),u)},new Map))}).pipe(m(p=>new Map([...p].sort(([,c],[,l])=>c-l))),He(i),v(([p,c])=>t.pipe(Fr(([l,f],{offset:{y:u},size:d})=>{let y=u+d.height>=Math.floor(s.height);for(;f.length;){let[,M]=f[0];if(M-c=u&&!y)f=[l.pop(),...f];else break}return[l,f]},[[],[...p]]),K((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([s,p])=>({prev:s.map(([c])=>c),next:p.map(([c])=>c)})),Q({prev:[],next:[]}),Be(2,1),m(([s,p])=>s.prev.length{let i=new g,a=i.pipe(Z(),ie(!0));if(i.subscribe(({prev:s,next:p})=>{for(let[c]of p)c.classList.remove("md-nav__link--passed"),c.classList.remove("md-nav__link--active");for(let[c,[l]]of s.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",c===s.length-1)}),B("toc.follow")){let s=O(t.pipe(_e(1),m(()=>{})),t.pipe(_e(250),m(()=>"smooth")));i.pipe(b(({prev:p})=>p.length>0),He(o.pipe(ve(se))),re(s)).subscribe(([[{prev:p}],c])=>{let[l]=p[p.length-1];if(l.offsetHeight){let f=cr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=ce(f);f.scrollTo({top:u-d/2,behavior:c})}}})}return B("navigation.tracking")&&t.pipe(U(a),ee("offset"),_e(250),Ce(1),U(n.pipe(Ce(1))),ct({delay:250}),re(i)).subscribe(([,{prev:s}])=>{let p=ye(),c=s[s.length-1];if(c&&c.length){let[l]=c,{hash:f}=new URL(l.href);p.hash!==f&&(p.hash=f,history.replaceState({},"",`${p}`))}else p.hash="",history.replaceState({},"",`${p}`)}),ms(e,{viewport$:t,header$:r}).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))})}function fs(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:a}})=>a),Be(2,1),m(([a,s])=>a>s&&s>0),K()),i=r.pipe(m(({active:a})=>a));return z([i,n]).pipe(m(([a,s])=>!(a&&s)),K(),U(o.pipe(Ce(1))),ie(!0),ct({delay:250}),m(a=>({hidden:a})))}function yi(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new g,a=i.pipe(Z(),ie(!0));return i.subscribe({next({hidden:s}){e.hidden=s,s?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(U(a),ee("height")).subscribe(({height:s})=>{e.style.top=`${s+16}px`}),h(e,"click").subscribe(s=>{s.preventDefault(),window.scrollTo({top:0})}),fs(e,{viewport$:t,main$:o,target$:n}).pipe(w(s=>i.next(s)),_(()=>i.complete()),m(s=>$({ref:e},s)))}function xi({document$:e,viewport$:t}){e.pipe(v(()=>P(".md-ellipsis")),ne(r=>tt(r).pipe(U(e.pipe(Ce(1))),b(o=>o),m(()=>r),Te(1))),b(r=>r.offsetWidth{let o=r.innerText,n=r.closest("a")||r;return n.title=o,B("content.tooltips")?mt(n,{viewport$:t}).pipe(U(e.pipe(Ce(1))),_(()=>n.removeAttribute("title"))):S})).subscribe(),B("content.tooltips")&&e.pipe(v(()=>P(".md-status")),ne(r=>mt(r,{viewport$:t}))).subscribe()}function Ei({document$:e,tablet$:t}){e.pipe(v(()=>P(".md-toggle--indeterminate")),w(r=>{r.indeterminate=!0,r.checked=!1}),ne(r=>h(r,"change").pipe(Dr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),re(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function us(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function wi({document$:e}){e.pipe(v(()=>P("[data-md-scrollfix]")),w(t=>t.removeAttribute("data-md-scrollfix")),b(us),ne(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Ti({viewport$:e,tablet$:t}){z([ze("search"),t]).pipe(m(([r,o])=>r&&!o),v(r=>I(r).pipe(Ge(r?400:100))),re(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function ds(){return location.protocol==="file:"?Tt(`${new URL("search/search_index.js",Zr.base)}`).pipe(m(()=>__index),G(1)):je(new URL("search/search_index.json",Zr.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var ot=Bo(),Wt=an(),Mt=pn(Wt),eo=nn(),Oe=vn(),hr=Pt("(min-width: 960px)"),Oi=Pt("(min-width: 1220px)"),Mi=ln(),Zr=xe(),Li=document.forms.namedItem("search")?ds():Ye,to=new g;Xn({alert$:to});var ro=new g;B("navigation.instant")&&ri({location$:Wt,viewport$:Oe,progress$:ro}).subscribe(ot);var Si;((Si=Zr.version)==null?void 0:Si.provider)==="mike"&&ai({document$:ot});O(Wt,Mt).pipe(Ge(125)).subscribe(()=>{Je("drawer",!1),Je("search",!1)});eo.pipe(b(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=fe("link[rel=prev]");typeof t!="undefined"&<(t);break;case"n":case".":let r=fe("link[rel=next]");typeof r!="undefined"&<(r);break;case"Enter":let o=Ie();o instanceof HTMLLabelElement&&o.click()}});xi({viewport$:Oe,document$:ot});Ei({document$:ot,tablet$:hr});wi({document$:ot});Ti({viewport$:Oe,tablet$:hr});var rt=Qn(Se("header"),{viewport$:Oe}),Ft=ot.pipe(m(()=>Se("main")),v(e=>Bn(e,{viewport$:Oe,header$:rt})),G(1)),hs=O(...ae("consent").map(e=>xn(e,{target$:Mt})),...ae("dialog").map(e=>zn(e,{alert$:to})),...ae("header").map(e=>Kn(e,{viewport$:Oe,header$:rt,main$:Ft})),...ae("palette").map(e=>Gn(e)),...ae("progress").map(e=>Jn(e,{progress$:ro})),...ae("search").map(e=>mi(e,{index$:Li,keyboard$:eo})),...ae("source").map(e=>bi(e))),bs=C(()=>O(...ae("announce").map(e=>yn(e)),...ae("content").map(e=>Nn(e,{viewport$:Oe,target$:Mt,print$:Mi})),...ae("content").map(e=>B("search.highlight")?fi(e,{index$:Li,location$:Wt}):S),...ae("header-title").map(e=>Yn(e,{viewport$:Oe,header$:rt})),...ae("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Nr(Oi,()=>Xr(e,{viewport$:Oe,header$:rt,main$:Ft})):Nr(hr,()=>Xr(e,{viewport$:Oe,header$:rt,main$:Ft}))),...ae("tabs").map(e=>vi(e,{viewport$:Oe,header$:rt})),...ae("toc").map(e=>gi(e,{viewport$:Oe,header$:rt,main$:Ft,target$:Mt})),...ae("top").map(e=>yi(e,{viewport$:Oe,header$:rt,main$:Ft,target$:Mt})))),_i=ot.pipe(v(()=>bs),Re(hs),G(1));_i.subscribe();window.document$=ot;window.location$=Wt;window.target$=Mt;window.keyboard$=eo;window.viewport$=Oe;window.tablet$=hr;window.screen$=Oi;window.print$=Mi;window.alert$=to;window.progress$=ro;window.component$=_i;})(); +//# sourceMappingURL=bundle.56dfad97.min.js.map + diff --git a/assets/javascripts/bundle.56dfad97.min.js.map b/assets/javascripts/bundle.56dfad97.min.js.map new file mode 100644 index 00000000..eb83bdb3 --- /dev/null +++ b/assets/javascripts/bundle.56dfad97.min.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/escape-html/index.js", "node_modules/clipboard/dist/clipboard.js", "src/templates/assets/javascripts/bundle.ts", "node_modules/tslib/tslib.es6.mjs", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/BehaviorSubject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/QueueAction.ts", "node_modules/rxjs/src/internal/scheduler/QueueScheduler.ts", "node_modules/rxjs/src/internal/scheduler/queue.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/observable/throwError.ts", "node_modules/rxjs/src/internal/util/EmptyError.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/audit.ts", "node_modules/rxjs/src/internal/operators/auditTime.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/debounce.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/throwIfEmpty.ts", "node_modules/rxjs/src/internal/operators/endWith.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/first.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/repeat.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/throttleTime.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/templates/assets/javascripts/browser/document/index.ts", "src/templates/assets/javascripts/browser/element/_/index.ts", "src/templates/assets/javascripts/browser/element/focus/index.ts", "src/templates/assets/javascripts/browser/element/hover/index.ts", "src/templates/assets/javascripts/utilities/h/index.ts", "src/templates/assets/javascripts/utilities/round/index.ts", "src/templates/assets/javascripts/browser/script/index.ts", "src/templates/assets/javascripts/browser/element/size/_/index.ts", "src/templates/assets/javascripts/browser/element/size/content/index.ts", "src/templates/assets/javascripts/browser/element/offset/_/index.ts", "src/templates/assets/javascripts/browser/element/offset/content/index.ts", "src/templates/assets/javascripts/browser/element/visibility/index.ts", "src/templates/assets/javascripts/browser/toggle/index.ts", "src/templates/assets/javascripts/browser/keyboard/index.ts", "src/templates/assets/javascripts/browser/location/_/index.ts", "src/templates/assets/javascripts/browser/location/hash/index.ts", "src/templates/assets/javascripts/browser/media/index.ts", "src/templates/assets/javascripts/browser/request/index.ts", "src/templates/assets/javascripts/browser/viewport/offset/index.ts", "src/templates/assets/javascripts/browser/viewport/size/index.ts", "src/templates/assets/javascripts/browser/viewport/_/index.ts", "src/templates/assets/javascripts/browser/viewport/at/index.ts", "src/templates/assets/javascripts/browser/worker/index.ts", "src/templates/assets/javascripts/_/index.ts", "src/templates/assets/javascripts/components/_/index.ts", "src/templates/assets/javascripts/components/announce/index.ts", "src/templates/assets/javascripts/components/consent/index.ts", "src/templates/assets/javascripts/templates/tooltip/index.tsx", "src/templates/assets/javascripts/templates/annotation/index.tsx", "src/templates/assets/javascripts/templates/clipboard/index.tsx", "src/templates/assets/javascripts/templates/search/index.tsx", "src/templates/assets/javascripts/templates/source/index.tsx", "src/templates/assets/javascripts/templates/tabbed/index.tsx", "src/templates/assets/javascripts/templates/table/index.tsx", "src/templates/assets/javascripts/templates/version/index.tsx", "src/templates/assets/javascripts/components/tooltip2/index.ts", "src/templates/assets/javascripts/components/content/annotation/_/index.ts", "src/templates/assets/javascripts/components/content/annotation/list/index.ts", "src/templates/assets/javascripts/components/content/annotation/block/index.ts", "src/templates/assets/javascripts/components/content/code/_/index.ts", "src/templates/assets/javascripts/components/content/details/index.ts", "src/templates/assets/javascripts/components/content/mermaid/index.css", "src/templates/assets/javascripts/components/content/mermaid/index.ts", "src/templates/assets/javascripts/components/content/table/index.ts", "src/templates/assets/javascripts/components/content/tabs/index.ts", "src/templates/assets/javascripts/components/content/_/index.ts", "src/templates/assets/javascripts/components/dialog/index.ts", "src/templates/assets/javascripts/components/tooltip/index.ts", "src/templates/assets/javascripts/components/header/_/index.ts", "src/templates/assets/javascripts/components/header/title/index.ts", "src/templates/assets/javascripts/components/main/index.ts", "src/templates/assets/javascripts/components/palette/index.ts", "src/templates/assets/javascripts/components/progress/index.ts", "src/templates/assets/javascripts/integrations/clipboard/index.ts", "src/templates/assets/javascripts/integrations/sitemap/index.ts", "src/templates/assets/javascripts/integrations/instant/index.ts", "src/templates/assets/javascripts/integrations/search/highlighter/index.ts", "src/templates/assets/javascripts/integrations/search/worker/message/index.ts", "src/templates/assets/javascripts/integrations/search/worker/_/index.ts", "src/templates/assets/javascripts/integrations/version/index.ts", "src/templates/assets/javascripts/components/search/query/index.ts", "src/templates/assets/javascripts/components/search/result/index.ts", "src/templates/assets/javascripts/components/search/share/index.ts", "src/templates/assets/javascripts/components/search/suggest/index.ts", "src/templates/assets/javascripts/components/search/_/index.ts", "src/templates/assets/javascripts/components/search/highlight/index.ts", "src/templates/assets/javascripts/components/sidebar/index.ts", "src/templates/assets/javascripts/components/source/facts/github/index.ts", "src/templates/assets/javascripts/components/source/facts/gitlab/index.ts", "src/templates/assets/javascripts/components/source/facts/_/index.ts", "src/templates/assets/javascripts/components/source/_/index.ts", "src/templates/assets/javascripts/components/tabs/index.ts", "src/templates/assets/javascripts/components/toc/index.ts", "src/templates/assets/javascripts/components/top/index.ts", "src/templates/assets/javascripts/patches/ellipsis/index.ts", "src/templates/assets/javascripts/patches/indeterminate/index.ts", "src/templates/assets/javascripts/patches/scrollfix/index.ts", "src/templates/assets/javascripts/patches/scrolllock/index.ts", "src/templates/assets/javascripts/polyfills/index.ts"], + "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*!\n * clipboard.js v2.0.11\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Create fake copy action wrapper using a fake element.\n * @param {String} target\n * @param {Object} options\n * @return {String}\n */\n\nvar fakeCopyAction = function fakeCopyAction(value, options) {\n var fakeElement = createFakeElement(value);\n options.container.appendChild(fakeElement);\n var selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n return selectedText;\n};\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n selectedText = fakeCopyAction(target, options);\n } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) {\n // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange\n selectedText = fakeCopyAction(target.value, options);\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});", "/*\n * Copyright (c) 2016-2024 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n defer,\n delay,\n filter,\n map,\n merge,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getActiveElement,\n getOptionalElement,\n requestJSON,\n setLocation,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchScript,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountAnnounce,\n mountBackToTop,\n mountConsent,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountProgress,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantNavigation,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchEllipsis,\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\nimport \"./polyfills\"\n\n/* ----------------------------------------------------------------------------\n * Functions - @todo refactor\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch search index\n *\n * @returns Search index observable\n */\nfunction fetchSearchIndex(): Observable {\n if (location.protocol === \"file:\") {\n return watchScript(\n `${new URL(\"search/search_index.js\", config.base)}`\n )\n .pipe(\n // @ts-ignore - @todo fix typings\n map(() => __index),\n shareReplay(1)\n )\n } else {\n return requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget(location$)\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? fetchSearchIndex()\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up progress indicator */\nconst progress$ = new Subject()\n\n/* Set up instant navigation, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantNavigation({ location$, viewport$, progress$ })\n .subscribe(document$)\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector({ document$ })\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getOptionalElement(\"link[rel=prev]\")\n if (typeof prev !== \"undefined\")\n setLocation(prev)\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getOptionalElement(\"link[rel=next]\")\n if (typeof next !== \"undefined\")\n setLocation(next)\n break\n\n /* Expand navigation, see https://bit.ly/3ZjG5io */\n case \"Enter\":\n const active = getActiveElement()\n if (active instanceof HTMLLabelElement)\n active.click()\n }\n })\n\n/* Set up patches */\npatchEllipsis({ viewport$, document$ })\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Consent */\n ...getComponentElements(\"consent\")\n .map(el => mountConsent(el, { target$ })),\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Progress bar */\n ...getComponentElements(\"progress\")\n .map(el => mountProgress(el, { progress$ })),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Announcement bar */\n ...getComponentElements(\"announce\")\n .map(el => mountAnnounce(el)),\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { viewport$, target$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : EMPTY\n ),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, {\n viewport$, header$, main$, target$\n })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Media tablet observable */\nwindow.screen$ = screen$ /* Media screen observable */\nwindow.print$ = print$ /* Media print observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.progress$ = progress$ /* Progress indicator subject */\nwindow.component$ = component$ /* Component observable */\n", "/******************************************************************************\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n***************************************************************************** */\n/* global Reflect, Promise, SuppressedError, Symbol, Iterator */\n\nvar extendStatics = function(d, b) {\n extendStatics = Object.setPrototypeOf ||\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\n return extendStatics(d, b);\n};\n\nexport function __extends(d, b) {\n if (typeof b !== \"function\" && b !== null)\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n extendStatics(d, b);\n function __() { this.constructor = d; }\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\n\nexport var __assign = function() {\n __assign = Object.assign || function __assign(t) {\n for (var s, i = 1, n = arguments.length; i < n; i++) {\n s = arguments[i];\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n }\n return t;\n }\n return __assign.apply(this, arguments);\n}\n\nexport function __rest(s, e) {\n var t = {};\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\n t[p] = s[p];\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\n t[p[i]] = s[p[i]];\n }\n return t;\n}\n\nexport function __decorate(decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n}\n\nexport function __param(paramIndex, decorator) {\n return function (target, key) { decorator(target, key, paramIndex); }\n}\n\nexport function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {\n function accept(f) { if (f !== void 0 && typeof f !== \"function\") throw new TypeError(\"Function expected\"); return f; }\n var kind = contextIn.kind, key = kind === \"getter\" ? \"get\" : kind === \"setter\" ? \"set\" : \"value\";\n var target = !descriptorIn && ctor ? contextIn[\"static\"] ? ctor : ctor.prototype : null;\n var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});\n var _, done = false;\n for (var i = decorators.length - 1; i >= 0; i--) {\n var context = {};\n for (var p in contextIn) context[p] = p === \"access\" ? {} : contextIn[p];\n for (var p in contextIn.access) context.access[p] = contextIn.access[p];\n context.addInitializer = function (f) { if (done) throw new TypeError(\"Cannot add initializers after decoration has completed\"); extraInitializers.push(accept(f || null)); };\n var result = (0, decorators[i])(kind === \"accessor\" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);\n if (kind === \"accessor\") {\n if (result === void 0) continue;\n if (result === null || typeof result !== \"object\") throw new TypeError(\"Object expected\");\n if (_ = accept(result.get)) descriptor.get = _;\n if (_ = accept(result.set)) descriptor.set = _;\n if (_ = accept(result.init)) initializers.unshift(_);\n }\n else if (_ = accept(result)) {\n if (kind === \"field\") initializers.unshift(_);\n else descriptor[key] = _;\n }\n }\n if (target) Object.defineProperty(target, contextIn.name, descriptor);\n done = true;\n};\n\nexport function __runInitializers(thisArg, initializers, value) {\n var useValue = arguments.length > 2;\n for (var i = 0; i < initializers.length; i++) {\n value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);\n }\n return useValue ? value : void 0;\n};\n\nexport function __propKey(x) {\n return typeof x === \"symbol\" ? x : \"\".concat(x);\n};\n\nexport function __setFunctionName(f, name, prefix) {\n if (typeof name === \"symbol\") name = name.description ? \"[\".concat(name.description, \"]\") : \"\";\n return Object.defineProperty(f, \"name\", { configurable: true, value: prefix ? \"\".concat(prefix, \" \", name) : name });\n};\n\nexport function __metadata(metadataKey, metadataValue) {\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\n}\n\nexport function __awaiter(thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n}\n\nexport function __generator(thisArg, body) {\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === \"function\" ? Iterator : Object).prototype);\n return g.next = verb(0), g[\"throw\"] = verb(1), g[\"return\"] = verb(2), typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\n function verb(n) { return function (v) { return step([n, v]); }; }\n function step(op) {\n if (f) throw new TypeError(\"Generator is already executing.\");\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n if (y = 0, t) op = [op[0] & 2, t.value];\n switch (op[0]) {\n case 0: case 1: t = op; break;\n case 4: _.label++; return { value: op[1], done: false };\n case 5: _.label++; y = op[1]; op = [0]; continue;\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\n default:\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\n if (t[2]) _.ops.pop();\n _.trys.pop(); continue;\n }\n op = body.call(thisArg, _);\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\n }\n}\n\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n var desc = Object.getOwnPropertyDescriptor(m, k);\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\n desc = { enumerable: true, get: function() { return m[k]; } };\n }\n Object.defineProperty(o, k2, desc);\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n});\n\nexport function __exportStar(m, o) {\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\n}\n\nexport function __values(o) {\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\n if (m) return m.call(o);\n if (o && typeof o.length === \"number\") return {\n next: function () {\n if (o && i >= o.length) o = void 0;\n return { value: o && o[i++], done: !o };\n }\n };\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\n}\n\nexport function __read(o, n) {\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\n if (!m) return o;\n var i = m.call(o), r, ar = [], e;\n try {\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\n }\n catch (error) { e = { error: error }; }\n finally {\n try {\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\n }\n finally { if (e) throw e.error; }\n }\n return ar;\n}\n\n/** @deprecated */\nexport function __spread() {\n for (var ar = [], i = 0; i < arguments.length; i++)\n ar = ar.concat(__read(arguments[i]));\n return ar;\n}\n\n/** @deprecated */\nexport function __spreadArrays() {\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\n r[k] = a[j];\n return r;\n}\n\nexport function __spreadArray(to, from, pack) {\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n if (ar || !(i in from)) {\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n ar[i] = from[i];\n }\n }\n return to.concat(ar || Array.prototype.slice.call(from));\n}\n\nexport function __await(v) {\n return this instanceof __await ? (this.v = v, this) : new __await(v);\n}\n\nexport function __asyncGenerator(thisArg, _arguments, generator) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\n return i = Object.create((typeof AsyncIterator === \"function\" ? AsyncIterator : Object).prototype), verb(\"next\"), verb(\"throw\"), verb(\"return\", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;\n function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }\n function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\n function fulfill(value) { resume(\"next\", value); }\n function reject(value) { resume(\"throw\", value); }\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\n}\n\nexport function __asyncDelegator(o) {\n var i, p;\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }\n}\n\nexport function __asyncValues(o) {\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\n var m = o[Symbol.asyncIterator], i;\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\n}\n\nexport function __makeTemplateObject(cooked, raw) {\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\n return cooked;\n};\n\nvar __setModuleDefault = Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n};\n\nexport function __importStar(mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n}\n\nexport function __importDefault(mod) {\n return (mod && mod.__esModule) ? mod : { default: mod };\n}\n\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n}\n\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n}\n\nexport function __classPrivateFieldIn(state, receiver) {\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\n}\n\nexport function __addDisposableResource(env, value, async) {\n if (value !== null && value !== void 0) {\n if (typeof value !== \"object\" && typeof value !== \"function\") throw new TypeError(\"Object expected.\");\n var dispose, inner;\n if (async) {\n if (!Symbol.asyncDispose) throw new TypeError(\"Symbol.asyncDispose is not defined.\");\n dispose = value[Symbol.asyncDispose];\n }\n if (dispose === void 0) {\n if (!Symbol.dispose) throw new TypeError(\"Symbol.dispose is not defined.\");\n dispose = value[Symbol.dispose];\n if (async) inner = dispose;\n }\n if (typeof dispose !== \"function\") throw new TypeError(\"Object not disposable.\");\n if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };\n env.stack.push({ value: value, dispose: dispose, async: async });\n }\n else if (async) {\n env.stack.push({ async: true });\n }\n return value;\n}\n\nvar _SuppressedError = typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n var e = new Error(message);\n return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n};\n\nexport function __disposeResources(env) {\n function fail(e) {\n env.error = env.hasError ? new _SuppressedError(e, env.error, \"An error was suppressed during disposal.\") : e;\n env.hasError = true;\n }\n var r, s = 0;\n function next() {\n while (r = env.stack.pop()) {\n try {\n if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);\n if (r.dispose) {\n var result = r.dispose.call(r.value);\n if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });\n }\n else s |= 1;\n }\n catch (e) {\n fail(e);\n }\n }\n if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();\n if (env.hasError) throw env.error;\n }\n return next();\n}\n\nexport default {\n __extends,\n __assign,\n __rest,\n __decorate,\n __param,\n __metadata,\n __awaiter,\n __generator,\n __createBinding,\n __exportStar,\n __values,\n __read,\n __spread,\n __spreadArrays,\n __spreadArray,\n __await,\n __asyncGenerator,\n __asyncDelegator,\n __asyncValues,\n __makeTemplateObject,\n __importStar,\n __importDefault,\n __classPrivateFieldGet,\n __classPrivateFieldSet,\n __classPrivateFieldIn,\n __addDisposableResource,\n __disposeResources,\n};\n", "/**\n * Returns true if the object is a function.\n * @param value The value to check\n */\nexport function isFunction(value: any): value is (...args: any[]) => any {\n return typeof value === 'function';\n}\n", "/**\n * Used to create Error subclasses until the community moves away from ES5.\n *\n * This is because compiling from TypeScript down to ES5 has issues with subclassing Errors\n * as well as other built-in types: https://github.com/Microsoft/TypeScript/issues/12123\n *\n * @param createImpl A factory function to create the actual constructor implementation. The returned\n * function should be a named function that calls `_super` internally.\n */\nexport function createErrorClass(createImpl: (_super: any) => any): T {\n const _super = (instance: any) => {\n Error.call(instance);\n instance.stack = new Error().stack;\n };\n\n const ctorFunc = createImpl(_super);\n ctorFunc.prototype = Object.create(Error.prototype);\n ctorFunc.prototype.constructor = ctorFunc;\n return ctorFunc;\n}\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface UnsubscriptionError extends Error {\n readonly errors: any[];\n}\n\nexport interface UnsubscriptionErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (errors: any[]): UnsubscriptionError;\n}\n\n/**\n * An error thrown when one or more errors have occurred during the\n * `unsubscribe` of a {@link Subscription}.\n */\nexport const UnsubscriptionError: UnsubscriptionErrorCtor = createErrorClass(\n (_super) =>\n function UnsubscriptionErrorImpl(this: any, errors: (Error | string)[]) {\n _super(this);\n this.message = errors\n ? `${errors.length} errors occurred during unsubscription:\n${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\\n ')}`\n : '';\n this.name = 'UnsubscriptionError';\n this.errors = errors;\n }\n);\n", "/**\n * Removes an item from an array, mutating it.\n * @param arr The array to remove the item from\n * @param item The item to remove\n */\nexport function arrRemove(arr: T[] | undefined | null, item: T) {\n if (arr) {\n const index = arr.indexOf(item);\n 0 <= index && arr.splice(index, 1);\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { UnsubscriptionError } from './util/UnsubscriptionError';\nimport { SubscriptionLike, TeardownLogic, Unsubscribable } from './types';\nimport { arrRemove } from './util/arrRemove';\n\n/**\n * Represents a disposable resource, such as the execution of an Observable. A\n * Subscription has one important method, `unsubscribe`, that takes no argument\n * and just disposes the resource held by the subscription.\n *\n * Additionally, subscriptions may be grouped together through the `add()`\n * method, which will attach a child Subscription to the current Subscription.\n * When a Subscription is unsubscribed, all its children (and its grandchildren)\n * will be unsubscribed as well.\n *\n * @class Subscription\n */\nexport class Subscription implements SubscriptionLike {\n /** @nocollapse */\n public static EMPTY = (() => {\n const empty = new Subscription();\n empty.closed = true;\n return empty;\n })();\n\n /**\n * A flag to indicate whether this Subscription has already been unsubscribed.\n */\n public closed = false;\n\n private _parentage: Subscription[] | Subscription | null = null;\n\n /**\n * The list of registered finalizers to execute upon unsubscription. Adding and removing from this\n * list occurs in the {@link #add} and {@link #remove} methods.\n */\n private _finalizers: Exclude[] | null = null;\n\n /**\n * @param initialTeardown A function executed first as part of the finalization\n * process that is kicked off when {@link #unsubscribe} is called.\n */\n constructor(private initialTeardown?: () => void) {}\n\n /**\n * Disposes the resources held by the subscription. May, for instance, cancel\n * an ongoing Observable execution or cancel any other type of work that\n * started when the Subscription was created.\n * @return {void}\n */\n unsubscribe(): void {\n let errors: any[] | undefined;\n\n if (!this.closed) {\n this.closed = true;\n\n // Remove this from it's parents.\n const { _parentage } = this;\n if (_parentage) {\n this._parentage = null;\n if (Array.isArray(_parentage)) {\n for (const parent of _parentage) {\n parent.remove(this);\n }\n } else {\n _parentage.remove(this);\n }\n }\n\n const { initialTeardown: initialFinalizer } = this;\n if (isFunction(initialFinalizer)) {\n try {\n initialFinalizer();\n } catch (e) {\n errors = e instanceof UnsubscriptionError ? e.errors : [e];\n }\n }\n\n const { _finalizers } = this;\n if (_finalizers) {\n this._finalizers = null;\n for (const finalizer of _finalizers) {\n try {\n execFinalizer(finalizer);\n } catch (err) {\n errors = errors ?? [];\n if (err instanceof UnsubscriptionError) {\n errors = [...errors, ...err.errors];\n } else {\n errors.push(err);\n }\n }\n }\n }\n\n if (errors) {\n throw new UnsubscriptionError(errors);\n }\n }\n }\n\n /**\n * Adds a finalizer to this subscription, so that finalization will be unsubscribed/called\n * when this subscription is unsubscribed. If this subscription is already {@link #closed},\n * because it has already been unsubscribed, then whatever finalizer is passed to it\n * will automatically be executed (unless the finalizer itself is also a closed subscription).\n *\n * Closed Subscriptions cannot be added as finalizers to any subscription. Adding a closed\n * subscription to a any subscription will result in no operation. (A noop).\n *\n * Adding a subscription to itself, or adding `null` or `undefined` will not perform any\n * operation at all. (A noop).\n *\n * `Subscription` instances that are added to this instance will automatically remove themselves\n * if they are unsubscribed. Functions and {@link Unsubscribable} objects that you wish to remove\n * will need to be removed manually with {@link #remove}\n *\n * @param teardown The finalization logic to add to this subscription.\n */\n add(teardown: TeardownLogic): void {\n // Only add the finalizer if it's not undefined\n // and don't add a subscription to itself.\n if (teardown && teardown !== this) {\n if (this.closed) {\n // If this subscription is already closed,\n // execute whatever finalizer is handed to it automatically.\n execFinalizer(teardown);\n } else {\n if (teardown instanceof Subscription) {\n // We don't add closed subscriptions, and we don't add the same subscription\n // twice. Subscription unsubscribe is idempotent.\n if (teardown.closed || teardown._hasParent(this)) {\n return;\n }\n teardown._addParent(this);\n }\n (this._finalizers = this._finalizers ?? []).push(teardown);\n }\n }\n }\n\n /**\n * Checks to see if a this subscription already has a particular parent.\n * This will signal that this subscription has already been added to the parent in question.\n * @param parent the parent to check for\n */\n private _hasParent(parent: Subscription) {\n const { _parentage } = this;\n return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));\n }\n\n /**\n * Adds a parent to this subscription so it can be removed from the parent if it\n * unsubscribes on it's own.\n *\n * NOTE: THIS ASSUMES THAT {@link _hasParent} HAS ALREADY BEEN CHECKED.\n * @param parent The parent subscription to add\n */\n private _addParent(parent: Subscription) {\n const { _parentage } = this;\n this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;\n }\n\n /**\n * Called on a child when it is removed via {@link #remove}.\n * @param parent The parent to remove\n */\n private _removeParent(parent: Subscription) {\n const { _parentage } = this;\n if (_parentage === parent) {\n this._parentage = null;\n } else if (Array.isArray(_parentage)) {\n arrRemove(_parentage, parent);\n }\n }\n\n /**\n * Removes a finalizer from this subscription that was previously added with the {@link #add} method.\n *\n * Note that `Subscription` instances, when unsubscribed, will automatically remove themselves\n * from every other `Subscription` they have been added to. This means that using the `remove` method\n * is not a common thing and should be used thoughtfully.\n *\n * If you add the same finalizer instance of a function or an unsubscribable object to a `Subscription` instance\n * more than once, you will need to call `remove` the same number of times to remove all instances.\n *\n * All finalizer instances are removed to free up memory upon unsubscription.\n *\n * @param teardown The finalizer to remove from this subscription\n */\n remove(teardown: Exclude): void {\n const { _finalizers } = this;\n _finalizers && arrRemove(_finalizers, teardown);\n\n if (teardown instanceof Subscription) {\n teardown._removeParent(this);\n }\n }\n}\n\nexport const EMPTY_SUBSCRIPTION = Subscription.EMPTY;\n\nexport function isSubscription(value: any): value is Subscription {\n return (\n value instanceof Subscription ||\n (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe))\n );\n}\n\nfunction execFinalizer(finalizer: Unsubscribable | (() => void)) {\n if (isFunction(finalizer)) {\n finalizer();\n } else {\n finalizer.unsubscribe();\n }\n}\n", "import { Subscriber } from './Subscriber';\nimport { ObservableNotification } from './types';\n\n/**\n * The {@link GlobalConfig} object for RxJS. It is used to configure things\n * like how to react on unhandled errors.\n */\nexport const config: GlobalConfig = {\n onUnhandledError: null,\n onStoppedNotification: null,\n Promise: undefined,\n useDeprecatedSynchronousErrorHandling: false,\n useDeprecatedNextContext: false,\n};\n\n/**\n * The global configuration object for RxJS, used to configure things\n * like how to react on unhandled errors. Accessible via {@link config}\n * object.\n */\nexport interface GlobalConfig {\n /**\n * A registration point for unhandled errors from RxJS. These are errors that\n * cannot were not handled by consuming code in the usual subscription path. For\n * example, if you have this configured, and you subscribe to an observable without\n * providing an error handler, errors from that subscription will end up here. This\n * will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onUnhandledError: ((err: any) => void) | null;\n\n /**\n * A registration point for notifications that cannot be sent to subscribers because they\n * have completed, errored or have been explicitly unsubscribed. By default, next, complete\n * and error notifications sent to stopped subscribers are noops. However, sometimes callers\n * might want a different behavior. For example, with sources that attempt to report errors\n * to stopped subscribers, a caller can configure RxJS to throw an unhandled error instead.\n * This will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onStoppedNotification: ((notification: ObservableNotification, subscriber: Subscriber) => void) | null;\n\n /**\n * The promise constructor used by default for {@link Observable#toPromise toPromise} and {@link Observable#forEach forEach}\n * methods.\n *\n * @deprecated As of version 8, RxJS will no longer support this sort of injection of a\n * Promise constructor. If you need a Promise implementation other than native promises,\n * please polyfill/patch Promise as you see appropriate. Will be removed in v8.\n */\n Promise?: PromiseConstructorLike;\n\n /**\n * If true, turns on synchronous error rethrowing, which is a deprecated behavior\n * in v6 and higher. This behavior enables bad patterns like wrapping a subscribe\n * call in a try/catch block. It also enables producer interference, a nasty bug\n * where a multicast can be broken for all observers by a downstream consumer with\n * an unhandled error. DO NOT USE THIS FLAG UNLESS IT'S NEEDED TO BUY TIME\n * FOR MIGRATION REASONS.\n *\n * @deprecated As of version 8, RxJS will no longer support synchronous throwing\n * of unhandled errors. All errors will be thrown on a separate call stack to prevent bad\n * behaviors described above. Will be removed in v8.\n */\n useDeprecatedSynchronousErrorHandling: boolean;\n\n /**\n * If true, enables an as-of-yet undocumented feature from v5: The ability to access\n * `unsubscribe()` via `this` context in `next` functions created in observers passed\n * to `subscribe`.\n *\n * This is being removed because the performance was severely problematic, and it could also cause\n * issues when types other than POJOs are passed to subscribe as subscribers, as they will likely have\n * their `this` context overwritten.\n *\n * @deprecated As of version 8, RxJS will no longer support altering the\n * context of next functions provided as part of an observer to Subscribe. Instead,\n * you will have access to a subscription or a signal or token that will allow you to do things like\n * unsubscribe and test closed status. Will be removed in v8.\n */\n useDeprecatedNextContext: boolean;\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetTimeoutFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearTimeoutFunction = (handle: TimerHandle) => void;\n\ninterface TimeoutProvider {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n delegate:\n | {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n }\n | undefined;\n}\n\nexport const timeoutProvider: TimeoutProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setTimeout(handler: () => void, timeout?: number, ...args) {\n const { delegate } = timeoutProvider;\n if (delegate?.setTimeout) {\n return delegate.setTimeout(handler, timeout, ...args);\n }\n return setTimeout(handler, timeout, ...args);\n },\n clearTimeout(handle) {\n const { delegate } = timeoutProvider;\n return (delegate?.clearTimeout || clearTimeout)(handle as any);\n },\n delegate: undefined,\n};\n", "import { config } from '../config';\nimport { timeoutProvider } from '../scheduler/timeoutProvider';\n\n/**\n * Handles an error on another job either with the user-configured {@link onUnhandledError},\n * or by throwing it on that new job so it can be picked up by `window.onerror`, `process.on('error')`, etc.\n *\n * This should be called whenever there is an error that is out-of-band with the subscription\n * or when an error hits a terminal boundary of the subscription and no error handler was provided.\n *\n * @param err the error to report\n */\nexport function reportUnhandledError(err: any) {\n timeoutProvider.setTimeout(() => {\n const { onUnhandledError } = config;\n if (onUnhandledError) {\n // Execute the user-configured error handler.\n onUnhandledError(err);\n } else {\n // Throw so it is picked up by the runtime's uncaught error mechanism.\n throw err;\n }\n });\n}\n", "/* tslint:disable:no-empty */\nexport function noop() { }\n", "import { CompleteNotification, NextNotification, ErrorNotification } from './types';\n\n/**\n * A completion object optimized for memory use and created to be the\n * same \"shape\" as other notifications in v8.\n * @internal\n */\nexport const COMPLETE_NOTIFICATION = (() => createNotification('C', undefined, undefined) as CompleteNotification)();\n\n/**\n * Internal use only. Creates an optimized error notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function errorNotification(error: any): ErrorNotification {\n return createNotification('E', undefined, error) as any;\n}\n\n/**\n * Internal use only. Creates an optimized next notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function nextNotification(value: T) {\n return createNotification('N', value, undefined) as NextNotification;\n}\n\n/**\n * Ensures that all notifications created internally have the same \"shape\" in v8.\n *\n * TODO: This is only exported to support a crazy legacy test in `groupBy`.\n * @internal\n */\nexport function createNotification(kind: 'N' | 'E' | 'C', value: any, error: any) {\n return {\n kind,\n value,\n error,\n };\n}\n", "import { config } from '../config';\n\nlet context: { errorThrown: boolean; error: any } | null = null;\n\n/**\n * Handles dealing with errors for super-gross mode. Creates a context, in which\n * any synchronously thrown errors will be passed to {@link captureError}. Which\n * will record the error such that it will be rethrown after the call back is complete.\n * TODO: Remove in v8\n * @param cb An immediately executed function.\n */\nexport function errorContext(cb: () => void) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n const isRoot = !context;\n if (isRoot) {\n context = { errorThrown: false, error: null };\n }\n cb();\n if (isRoot) {\n const { errorThrown, error } = context!;\n context = null;\n if (errorThrown) {\n throw error;\n }\n }\n } else {\n // This is the general non-deprecated path for everyone that\n // isn't crazy enough to use super-gross mode (useDeprecatedSynchronousErrorHandling)\n cb();\n }\n}\n\n/**\n * Captures errors only in super-gross mode.\n * @param err the error to capture\n */\nexport function captureError(err: any) {\n if (config.useDeprecatedSynchronousErrorHandling && context) {\n context.errorThrown = true;\n context.error = err;\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { Observer, ObservableNotification } from './types';\nimport { isSubscription, Subscription } from './Subscription';\nimport { config } from './config';\nimport { reportUnhandledError } from './util/reportUnhandledError';\nimport { noop } from './util/noop';\nimport { nextNotification, errorNotification, COMPLETE_NOTIFICATION } from './NotificationFactories';\nimport { timeoutProvider } from './scheduler/timeoutProvider';\nimport { captureError } from './util/errorContext';\n\n/**\n * Implements the {@link Observer} interface and extends the\n * {@link Subscription} class. While the {@link Observer} is the public API for\n * consuming the values of an {@link Observable}, all Observers get converted to\n * a Subscriber, in order to provide Subscription-like capabilities such as\n * `unsubscribe`. Subscriber is a common type in RxJS, and crucial for\n * implementing operators, but it is rarely used as a public API.\n *\n * @class Subscriber\n */\nexport class Subscriber extends Subscription implements Observer {\n /**\n * A static factory for a Subscriber, given a (potentially partial) definition\n * of an Observer.\n * @param next The `next` callback of an Observer.\n * @param error The `error` callback of an\n * Observer.\n * @param complete The `complete` callback of an\n * Observer.\n * @return A Subscriber wrapping the (partially defined)\n * Observer represented by the given arguments.\n * @nocollapse\n * @deprecated Do not use. Will be removed in v8. There is no replacement for this\n * method, and there is no reason to be creating instances of `Subscriber` directly.\n * If you have a specific use case, please file an issue.\n */\n static create(next?: (x?: T) => void, error?: (e?: any) => void, complete?: () => void): Subscriber {\n return new SafeSubscriber(next, error, complete);\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected isStopped: boolean = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected destination: Subscriber | Observer; // this `any` is the escape hatch to erase extra type param (e.g. R)\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * There is no reason to directly create an instance of Subscriber. This type is exported for typings reasons.\n */\n constructor(destination?: Subscriber | Observer) {\n super();\n if (destination) {\n this.destination = destination;\n // Automatically chain subscriptions together here.\n // if destination is a Subscription, then it is a Subscriber.\n if (isSubscription(destination)) {\n destination.add(this);\n }\n } else {\n this.destination = EMPTY_OBSERVER;\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `next` from\n * the Observable, with a value. The Observable may call this method 0 or more\n * times.\n * @param {T} [value] The `next` value.\n * @return {void}\n */\n next(value?: T): void {\n if (this.isStopped) {\n handleStoppedNotification(nextNotification(value), this);\n } else {\n this._next(value!);\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `error` from\n * the Observable, with an attached `Error`. Notifies the Observer that\n * the Observable has experienced an error condition.\n * @param {any} [err] The `error` exception.\n * @return {void}\n */\n error(err?: any): void {\n if (this.isStopped) {\n handleStoppedNotification(errorNotification(err), this);\n } else {\n this.isStopped = true;\n this._error(err);\n }\n }\n\n /**\n * The {@link Observer} callback to receive a valueless notification of type\n * `complete` from the Observable. Notifies the Observer that the Observable\n * has finished sending push-based notifications.\n * @return {void}\n */\n complete(): void {\n if (this.isStopped) {\n handleStoppedNotification(COMPLETE_NOTIFICATION, this);\n } else {\n this.isStopped = true;\n this._complete();\n }\n }\n\n unsubscribe(): void {\n if (!this.closed) {\n this.isStopped = true;\n super.unsubscribe();\n this.destination = null!;\n }\n }\n\n protected _next(value: T): void {\n this.destination.next(value);\n }\n\n protected _error(err: any): void {\n try {\n this.destination.error(err);\n } finally {\n this.unsubscribe();\n }\n }\n\n protected _complete(): void {\n try {\n this.destination.complete();\n } finally {\n this.unsubscribe();\n }\n }\n}\n\n/**\n * This bind is captured here because we want to be able to have\n * compatibility with monoid libraries that tend to use a method named\n * `bind`. In particular, a library called Monio requires this.\n */\nconst _bind = Function.prototype.bind;\n\nfunction bind any>(fn: Fn, thisArg: any): Fn {\n return _bind.call(fn, thisArg);\n}\n\n/**\n * Internal optimization only, DO NOT EXPOSE.\n * @internal\n */\nclass ConsumerObserver implements Observer {\n constructor(private partialObserver: Partial>) {}\n\n next(value: T): void {\n const { partialObserver } = this;\n if (partialObserver.next) {\n try {\n partialObserver.next(value);\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n\n error(err: any): void {\n const { partialObserver } = this;\n if (partialObserver.error) {\n try {\n partialObserver.error(err);\n } catch (error) {\n handleUnhandledError(error);\n }\n } else {\n handleUnhandledError(err);\n }\n }\n\n complete(): void {\n const { partialObserver } = this;\n if (partialObserver.complete) {\n try {\n partialObserver.complete();\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n}\n\nexport class SafeSubscriber extends Subscriber {\n constructor(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((e?: any) => void) | null,\n complete?: (() => void) | null\n ) {\n super();\n\n let partialObserver: Partial>;\n if (isFunction(observerOrNext) || !observerOrNext) {\n // The first argument is a function, not an observer. The next\n // two arguments *could* be observers, or they could be empty.\n partialObserver = {\n next: (observerOrNext ?? undefined) as (((value: T) => void) | undefined),\n error: error ?? undefined,\n complete: complete ?? undefined,\n };\n } else {\n // The first argument is a partial observer.\n let context: any;\n if (this && config.useDeprecatedNextContext) {\n // This is a deprecated path that made `this.unsubscribe()` available in\n // next handler functions passed to subscribe. This only exists behind a flag\n // now, as it is *very* slow.\n context = Object.create(observerOrNext);\n context.unsubscribe = () => this.unsubscribe();\n partialObserver = {\n next: observerOrNext.next && bind(observerOrNext.next, context),\n error: observerOrNext.error && bind(observerOrNext.error, context),\n complete: observerOrNext.complete && bind(observerOrNext.complete, context),\n };\n } else {\n // The \"normal\" path. Just use the partial observer directly.\n partialObserver = observerOrNext;\n }\n }\n\n // Wrap the partial observer to ensure it's a full observer, and\n // make sure proper error handling is accounted for.\n this.destination = new ConsumerObserver(partialObserver);\n }\n}\n\nfunction handleUnhandledError(error: any) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n captureError(error);\n } else {\n // Ideal path, we report this as an unhandled error,\n // which is thrown on a new call stack.\n reportUnhandledError(error);\n }\n}\n\n/**\n * An error handler used when no error handler was supplied\n * to the SafeSubscriber -- meaning no error handler was supplied\n * do the `subscribe` call on our observable.\n * @param err The error to handle\n */\nfunction defaultErrorHandler(err: any) {\n throw err;\n}\n\n/**\n * A handler for notifications that cannot be sent to a stopped subscriber.\n * @param notification The notification being sent\n * @param subscriber The stopped subscriber\n */\nfunction handleStoppedNotification(notification: ObservableNotification, subscriber: Subscriber) {\n const { onStoppedNotification } = config;\n onStoppedNotification && timeoutProvider.setTimeout(() => onStoppedNotification(notification, subscriber));\n}\n\n/**\n * The observer used as a stub for subscriptions where the user did not\n * pass any arguments to `subscribe`. Comes with the default error handling\n * behavior.\n */\nexport const EMPTY_OBSERVER: Readonly> & { closed: true } = {\n closed: true,\n next: noop,\n error: defaultErrorHandler,\n complete: noop,\n};\n", "/**\n * Symbol.observable or a string \"@@observable\". Used for interop\n *\n * @deprecated We will no longer be exporting this symbol in upcoming versions of RxJS.\n * Instead polyfill and use Symbol.observable directly *or* use https://www.npmjs.com/package/symbol-observable\n */\nexport const observable: string | symbol = (() => (typeof Symbol === 'function' && Symbol.observable) || '@@observable')();\n", "/**\n * This function takes one parameter and just returns it. Simply put,\n * this is like `(x: T): T => x`.\n *\n * ## Examples\n *\n * This is useful in some cases when using things like `mergeMap`\n *\n * ```ts\n * import { interval, take, map, range, mergeMap, identity } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(5));\n *\n * const result$ = source$.pipe(\n * map(i => range(i)),\n * mergeMap(identity) // same as mergeMap(x => x)\n * );\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * Or when you want to selectively apply an operator\n *\n * ```ts\n * import { interval, take, identity } from 'rxjs';\n *\n * const shouldLimit = () => Math.random() < 0.5;\n *\n * const source$ = interval(1000);\n *\n * const result$ = source$.pipe(shouldLimit() ? take(5) : identity);\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * @param x Any value that is returned by this function\n * @returns The value passed as the first parameter to this function\n */\nexport function identity(x: T): T {\n return x;\n}\n", "import { identity } from './identity';\nimport { UnaryFunction } from '../types';\n\nexport function pipe(): typeof identity;\nexport function pipe(fn1: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction,\n ...fns: UnaryFunction[]\n): UnaryFunction;\n\n/**\n * pipe() can be called on one or more functions, each of which can take one argument (\"UnaryFunction\")\n * and uses it to return a value.\n * It returns a function that takes one argument, passes it to the first UnaryFunction, and then\n * passes the result to the next one, passes that result to the next one, and so on. \n */\nexport function pipe(...fns: Array>): UnaryFunction {\n return pipeFromArray(fns);\n}\n\n/** @internal */\nexport function pipeFromArray(fns: Array>): UnaryFunction {\n if (fns.length === 0) {\n return identity as UnaryFunction;\n }\n\n if (fns.length === 1) {\n return fns[0];\n }\n\n return function piped(input: T): R {\n return fns.reduce((prev: any, fn: UnaryFunction) => fn(prev), input as any);\n };\n}\n", "import { Operator } from './Operator';\nimport { SafeSubscriber, Subscriber } from './Subscriber';\nimport { isSubscription, Subscription } from './Subscription';\nimport { TeardownLogic, OperatorFunction, Subscribable, Observer } from './types';\nimport { observable as Symbol_observable } from './symbol/observable';\nimport { pipeFromArray } from './util/pipe';\nimport { config } from './config';\nimport { isFunction } from './util/isFunction';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A representation of any set of values over any amount of time. This is the most basic building block\n * of RxJS.\n *\n * @class Observable\n */\nexport class Observable implements Subscribable {\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n source: Observable | undefined;\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n operator: Operator | undefined;\n\n /**\n * @constructor\n * @param {Function} subscribe the function that is called when the Observable is\n * initially subscribed to. This function is given a Subscriber, to which new values\n * can be `next`ed, or an `error` method can be called to raise an error, or\n * `complete` can be called to notify of a successful completion.\n */\n constructor(subscribe?: (this: Observable, subscriber: Subscriber) => TeardownLogic) {\n if (subscribe) {\n this._subscribe = subscribe;\n }\n }\n\n // HACK: Since TypeScript inherits static properties too, we have to\n // fight against TypeScript here so Subject can have a different static create signature\n /**\n * Creates a new Observable by calling the Observable constructor\n * @owner Observable\n * @method create\n * @param {Function} subscribe? the subscriber function to be passed to the Observable constructor\n * @return {Observable} a new observable\n * @nocollapse\n * @deprecated Use `new Observable()` instead. Will be removed in v8.\n */\n static create: (...args: any[]) => any = (subscribe?: (subscriber: Subscriber) => TeardownLogic) => {\n return new Observable(subscribe);\n };\n\n /**\n * Creates a new Observable, with this Observable instance as the source, and the passed\n * operator defined as the new observable's operator.\n * @method lift\n * @param operator the operator defining the operation to take on the observable\n * @return a new observable with the Operator applied\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * If you have implemented an operator using `lift`, it is recommended that you create an\n * operator by simply returning `new Observable()` directly. See \"Creating new operators from\n * scratch\" section here: https://rxjs.dev/guide/operators\n */\n lift(operator?: Operator): Observable {\n const observable = new Observable();\n observable.source = this;\n observable.operator = operator;\n return observable;\n }\n\n subscribe(observerOrNext?: Partial> | ((value: T) => void)): Subscription;\n /** @deprecated Instead of passing separate callback arguments, use an observer argument. Signatures taking separate callback arguments will be removed in v8. Details: https://rxjs.dev/deprecations/subscribe-arguments */\n subscribe(next?: ((value: T) => void) | null, error?: ((error: any) => void) | null, complete?: (() => void) | null): Subscription;\n /**\n * Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.\n *\n * Use it when you have all these Observables, but still nothing is happening.\n *\n * `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It\n * might be for example a function that you passed to Observable's constructor, but most of the time it is\n * a library implementation, which defines what will be emitted by an Observable, and when it be will emitted. This means\n * that calling `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often\n * the thought.\n *\n * Apart from starting the execution of an Observable, this method allows you to listen for values\n * that an Observable emits, as well as for when it completes or errors. You can achieve this in two\n * of the following ways.\n *\n * The first way is creating an object that implements {@link Observer} interface. It should have methods\n * defined by that interface, but note that it should be just a regular JavaScript object, which you can create\n * yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular, do\n * not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also\n * that your object does not have to implement all methods. If you find yourself creating a method that doesn't\n * do anything, you can simply omit it. Note however, if the `error` method is not provided and an error happens,\n * it will be thrown asynchronously. Errors thrown asynchronously cannot be caught using `try`/`catch`. Instead,\n * use the {@link onUnhandledError} configuration option or use a runtime handler (like `window.onerror` or\n * `process.on('error)`) to be notified of unhandled errors. Because of this, it's recommended that you provide\n * an `error` method to avoid missing thrown errors.\n *\n * The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.\n * This means you can provide three functions as arguments to `subscribe`, where the first function is equivalent\n * of a `next` method, the second of an `error` method and the third of a `complete` method. Just as in case of an Observer,\n * if you do not need to listen for something, you can omit a function by passing `undefined` or `null`,\n * since `subscribe` recognizes these functions by where they were placed in function call. When it comes\n * to the `error` function, as with an Observer, if not provided, errors emitted by an Observable will be thrown asynchronously.\n *\n * You can, however, subscribe with no parameters at all. This may be the case where you're not interested in terminal events\n * and you also handled emissions internally by using operators (e.g. using `tap`).\n *\n * Whichever style of calling `subscribe` you use, in both cases it returns a Subscription object.\n * This object allows you to call `unsubscribe` on it, which in turn will stop the work that an Observable does and will clean\n * up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback\n * provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.\n *\n * Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.\n * It is an Observable itself that decides when these functions will be called. For example {@link of}\n * by default emits all its values synchronously. Always check documentation for how given Observable\n * will behave when subscribed and if its default behavior can be modified with a `scheduler`.\n *\n * #### Examples\n *\n * Subscribe with an {@link guide/observer Observer}\n *\n * ```ts\n * import { of } from 'rxjs';\n *\n * const sumObserver = {\n * sum: 0,\n * next(value) {\n * console.log('Adding: ' + value);\n * this.sum = this.sum + value;\n * },\n * error() {\n * // We actually could just remove this method,\n * // since we do not really care about errors right now.\n * },\n * complete() {\n * console.log('Sum equals: ' + this.sum);\n * }\n * };\n *\n * of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.\n * .subscribe(sumObserver);\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Subscribe with functions ({@link deprecations/subscribe-arguments deprecated})\n *\n * ```ts\n * import { of } from 'rxjs'\n *\n * let sum = 0;\n *\n * of(1, 2, 3).subscribe(\n * value => {\n * console.log('Adding: ' + value);\n * sum = sum + value;\n * },\n * undefined,\n * () => console.log('Sum equals: ' + sum)\n * );\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Cancel a subscription\n *\n * ```ts\n * import { interval } from 'rxjs';\n *\n * const subscription = interval(1000).subscribe({\n * next(num) {\n * console.log(num)\n * },\n * complete() {\n * // Will not be called, even when cancelling subscription.\n * console.log('completed!');\n * }\n * });\n *\n * setTimeout(() => {\n * subscription.unsubscribe();\n * console.log('unsubscribed!');\n * }, 2500);\n *\n * // Logs:\n * // 0 after 1s\n * // 1 after 2s\n * // 'unsubscribed!' after 2.5s\n * ```\n *\n * @param {Observer|Function} observerOrNext (optional) Either an observer with methods to be called,\n * or the first of three possible handlers, which is the handler for each value emitted from the subscribed\n * Observable.\n * @param {Function} error (optional) A handler for a terminal event resulting from an error. If no error handler is provided,\n * the error will be thrown asynchronously as unhandled.\n * @param {Function} complete (optional) A handler for a terminal event resulting from successful completion.\n * @return {Subscription} a subscription reference to the registered handlers\n * @method subscribe\n */\n subscribe(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((error: any) => void) | null,\n complete?: (() => void) | null\n ): Subscription {\n const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);\n\n errorContext(() => {\n const { operator, source } = this;\n subscriber.add(\n operator\n ? // We're dealing with a subscription in the\n // operator chain to one of our lifted operators.\n operator.call(subscriber, source)\n : source\n ? // If `source` has a value, but `operator` does not, something that\n // had intimate knowledge of our API, like our `Subject`, must have\n // set it. We're going to just call `_subscribe` directly.\n this._subscribe(subscriber)\n : // In all other cases, we're likely wrapping a user-provided initializer\n // function, so we need to catch errors and handle them appropriately.\n this._trySubscribe(subscriber)\n );\n });\n\n return subscriber;\n }\n\n /** @internal */\n protected _trySubscribe(sink: Subscriber): TeardownLogic {\n try {\n return this._subscribe(sink);\n } catch (err) {\n // We don't need to return anything in this case,\n // because it's just going to try to `add()` to a subscription\n // above.\n sink.error(err);\n }\n }\n\n /**\n * Used as a NON-CANCELLABLE means of subscribing to an observable, for use with\n * APIs that expect promises, like `async/await`. You cannot unsubscribe from this.\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * #### Example\n *\n * ```ts\n * import { interval, take } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(4));\n *\n * async function getTotal() {\n * let total = 0;\n *\n * await source$.forEach(value => {\n * total += value;\n * console.log('observable -> ' + value);\n * });\n *\n * return total;\n * }\n *\n * getTotal().then(\n * total => console.log('Total: ' + total)\n * );\n *\n * // Expected:\n * // 'observable -> 0'\n * // 'observable -> 1'\n * // 'observable -> 2'\n * // 'observable -> 3'\n * // 'Total: 6'\n * ```\n *\n * @param next a handler for each value emitted by the observable\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n */\n forEach(next: (value: T) => void): Promise;\n\n /**\n * @param next a handler for each value emitted by the observable\n * @param promiseCtor a constructor function used to instantiate the Promise\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n * @deprecated Passing a Promise constructor will no longer be available\n * in upcoming versions of RxJS. This is because it adds weight to the library, for very\n * little benefit. If you need this functionality, it is recommended that you either\n * polyfill Promise, or you create an adapter to convert the returned native promise\n * to whatever promise implementation you wanted. Will be removed in v8.\n */\n forEach(next: (value: T) => void, promiseCtor: PromiseConstructorLike): Promise;\n\n forEach(next: (value: T) => void, promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n const subscriber = new SafeSubscriber({\n next: (value) => {\n try {\n next(value);\n } catch (err) {\n reject(err);\n subscriber.unsubscribe();\n }\n },\n error: reject,\n complete: resolve,\n });\n this.subscribe(subscriber);\n }) as Promise;\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): TeardownLogic {\n return this.source?.subscribe(subscriber);\n }\n\n /**\n * An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable\n * @method Symbol.observable\n * @return {Observable} this instance of the observable\n */\n [Symbol_observable]() {\n return this;\n }\n\n /* tslint:disable:max-line-length */\n pipe(): Observable;\n pipe(op1: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction,\n ...operations: OperatorFunction[]\n ): Observable;\n /* tslint:enable:max-line-length */\n\n /**\n * Used to stitch together functional operators into a chain.\n * @method pipe\n * @return {Observable} the Observable result of all of the operators having\n * been called in the order they were passed in.\n *\n * ## Example\n *\n * ```ts\n * import { interval, filter, map, scan } from 'rxjs';\n *\n * interval(1000)\n * .pipe(\n * filter(x => x % 2 === 0),\n * map(x => x + x),\n * scan((acc, x) => acc + x)\n * )\n * .subscribe(x => console.log(x));\n * ```\n */\n pipe(...operations: OperatorFunction[]): Observable {\n return pipeFromArray(operations)(this);\n }\n\n /* tslint:disable:max-line-length */\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: typeof Promise): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: PromiseConstructorLike): Promise;\n /* tslint:enable:max-line-length */\n\n /**\n * Subscribe to this Observable and get a Promise resolving on\n * `complete` with the last emission (if any).\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * @method toPromise\n * @param [promiseCtor] a constructor function used to instantiate\n * the Promise\n * @return A Promise that resolves with the last value emit, or\n * rejects on an error. If there were no emissions, Promise\n * resolves with undefined.\n * @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise\n */\n toPromise(promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n let value: T | undefined;\n this.subscribe(\n (x: T) => (value = x),\n (err: any) => reject(err),\n () => resolve(value)\n );\n }) as Promise;\n }\n}\n\n/**\n * Decides between a passed promise constructor from consuming code,\n * A default configured promise constructor, and the native promise\n * constructor and returns it. If nothing can be found, it will throw\n * an error.\n * @param promiseCtor The optional promise constructor to passed by consuming code\n */\nfunction getPromiseCtor(promiseCtor: PromiseConstructorLike | undefined) {\n return promiseCtor ?? config.Promise ?? Promise;\n}\n\nfunction isObserver(value: any): value is Observer {\n return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete);\n}\n\nfunction isSubscriber(value: any): value is Subscriber {\n return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value));\n}\n", "import { Observable } from '../Observable';\nimport { Subscriber } from '../Subscriber';\nimport { OperatorFunction } from '../types';\nimport { isFunction } from './isFunction';\n\n/**\n * Used to determine if an object is an Observable with a lift function.\n */\nexport function hasLift(source: any): source is { lift: InstanceType['lift'] } {\n return isFunction(source?.lift);\n}\n\n/**\n * Creates an `OperatorFunction`. Used to define operators throughout the library in a concise way.\n * @param init The logic to connect the liftedSource to the subscriber at the moment of subscription.\n */\nexport function operate(\n init: (liftedSource: Observable, subscriber: Subscriber) => (() => void) | void\n): OperatorFunction {\n return (source: Observable) => {\n if (hasLift(source)) {\n return source.lift(function (this: Subscriber, liftedSource: Observable) {\n try {\n return init(liftedSource, this);\n } catch (err) {\n this.error(err);\n }\n });\n }\n throw new TypeError('Unable to lift unknown Observable type');\n };\n}\n", "import { Subscriber } from '../Subscriber';\n\n/**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional teardown logic here. This will only be called on teardown if the\n * subscriber itself is not already closed. This is called after all other teardown logic is executed.\n */\nexport function createOperatorSubscriber(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n onFinalize?: () => void\n): Subscriber {\n return new OperatorSubscriber(destination, onNext, onComplete, onError, onFinalize);\n}\n\n/**\n * A generic helper for allowing operators to be created with a Subscriber and\n * use closures to capture necessary state from the operator function itself.\n */\nexport class OperatorSubscriber extends Subscriber {\n /**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional finalization logic here. This will only be called on finalization if the\n * subscriber itself is not already closed. This is called after all other finalization logic is executed.\n * @param shouldUnsubscribe An optional check to see if an unsubscribe call should truly unsubscribe.\n * NOTE: This currently **ONLY** exists to support the strange behavior of {@link groupBy}, where unsubscription\n * to the resulting observable does not actually disconnect from the source if there are active subscriptions\n * to any grouped observable. (DO NOT EXPOSE OR USE EXTERNALLY!!!)\n */\n constructor(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n private onFinalize?: () => void,\n private shouldUnsubscribe?: () => boolean\n ) {\n // It's important - for performance reasons - that all of this class's\n // members are initialized and that they are always initialized in the same\n // order. This will ensure that all OperatorSubscriber instances have the\n // same hidden class in V8. This, in turn, will help keep the number of\n // hidden classes involved in property accesses within the base class as\n // low as possible. If the number of hidden classes involved exceeds four,\n // the property accesses will become megamorphic and performance penalties\n // will be incurred - i.e. inline caches won't be used.\n //\n // The reasons for ensuring all instances have the same hidden class are\n // further discussed in this blog post from Benedikt Meurer:\n // https://benediktmeurer.de/2018/03/23/impact-of-polymorphism-on-component-based-frameworks-like-react/\n super(destination);\n this._next = onNext\n ? function (this: OperatorSubscriber, value: T) {\n try {\n onNext(value);\n } catch (err) {\n destination.error(err);\n }\n }\n : super._next;\n this._error = onError\n ? function (this: OperatorSubscriber, err: any) {\n try {\n onError(err);\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._error;\n this._complete = onComplete\n ? function (this: OperatorSubscriber) {\n try {\n onComplete();\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._complete;\n }\n\n unsubscribe() {\n if (!this.shouldUnsubscribe || this.shouldUnsubscribe()) {\n const { closed } = this;\n super.unsubscribe();\n // Execute additional teardown if we have any and we didn't already do so.\n !closed && this.onFinalize?.();\n }\n }\n}\n", "import { Subscription } from '../Subscription';\n\ninterface AnimationFrameProvider {\n schedule(callback: FrameRequestCallback): Subscription;\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n delegate:\n | {\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n }\n | undefined;\n}\n\nexport const animationFrameProvider: AnimationFrameProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n schedule(callback) {\n let request = requestAnimationFrame;\n let cancel: typeof cancelAnimationFrame | undefined = cancelAnimationFrame;\n const { delegate } = animationFrameProvider;\n if (delegate) {\n request = delegate.requestAnimationFrame;\n cancel = delegate.cancelAnimationFrame;\n }\n const handle = request((timestamp) => {\n // Clear the cancel function. The request has been fulfilled, so\n // attempting to cancel the request upon unsubscription would be\n // pointless.\n cancel = undefined;\n callback(timestamp);\n });\n return new Subscription(() => cancel?.(handle));\n },\n requestAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.requestAnimationFrame || requestAnimationFrame)(...args);\n },\n cancelAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.cancelAnimationFrame || cancelAnimationFrame)(...args);\n },\n delegate: undefined,\n};\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface ObjectUnsubscribedError extends Error {}\n\nexport interface ObjectUnsubscribedErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (): ObjectUnsubscribedError;\n}\n\n/**\n * An error thrown when an action is invalid because the object has been\n * unsubscribed.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n *\n * @class ObjectUnsubscribedError\n */\nexport const ObjectUnsubscribedError: ObjectUnsubscribedErrorCtor = createErrorClass(\n (_super) =>\n function ObjectUnsubscribedErrorImpl(this: any) {\n _super(this);\n this.name = 'ObjectUnsubscribedError';\n this.message = 'object unsubscribed';\n }\n);\n", "import { Operator } from './Operator';\nimport { Observable } from './Observable';\nimport { Subscriber } from './Subscriber';\nimport { Subscription, EMPTY_SUBSCRIPTION } from './Subscription';\nimport { Observer, SubscriptionLike, TeardownLogic } from './types';\nimport { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';\nimport { arrRemove } from './util/arrRemove';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A Subject is a special type of Observable that allows values to be\n * multicasted to many Observers. Subjects are like EventEmitters.\n *\n * Every Subject is an Observable and an Observer. You can subscribe to a\n * Subject, and you can call next to feed values as well as error and complete.\n */\nexport class Subject extends Observable implements SubscriptionLike {\n closed = false;\n\n private currentObservers: Observer[] | null = null;\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n observers: Observer[] = [];\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n isStopped = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n hasError = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n thrownError: any = null;\n\n /**\n * Creates a \"subject\" by basically gluing an observer to an observable.\n *\n * @nocollapse\n * @deprecated Recommended you do not use. Will be removed at some point in the future. Plans for replacement still under discussion.\n */\n static create: (...args: any[]) => any = (destination: Observer, source: Observable): AnonymousSubject => {\n return new AnonymousSubject(destination, source);\n };\n\n constructor() {\n // NOTE: This must be here to obscure Observable's constructor.\n super();\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n lift(operator: Operator): Observable {\n const subject = new AnonymousSubject(this, this);\n subject.operator = operator as any;\n return subject as any;\n }\n\n /** @internal */\n protected _throwIfClosed() {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n }\n }\n\n next(value: T) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n if (!this.currentObservers) {\n this.currentObservers = Array.from(this.observers);\n }\n for (const observer of this.currentObservers) {\n observer.next(value);\n }\n }\n });\n }\n\n error(err: any) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.hasError = this.isStopped = true;\n this.thrownError = err;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.error(err);\n }\n }\n });\n }\n\n complete() {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.isStopped = true;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.complete();\n }\n }\n });\n }\n\n unsubscribe() {\n this.isStopped = this.closed = true;\n this.observers = this.currentObservers = null!;\n }\n\n get observed() {\n return this.observers?.length > 0;\n }\n\n /** @internal */\n protected _trySubscribe(subscriber: Subscriber): TeardownLogic {\n this._throwIfClosed();\n return super._trySubscribe(subscriber);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._checkFinalizedStatuses(subscriber);\n return this._innerSubscribe(subscriber);\n }\n\n /** @internal */\n protected _innerSubscribe(subscriber: Subscriber) {\n const { hasError, isStopped, observers } = this;\n if (hasError || isStopped) {\n return EMPTY_SUBSCRIPTION;\n }\n this.currentObservers = null;\n observers.push(subscriber);\n return new Subscription(() => {\n this.currentObservers = null;\n arrRemove(observers, subscriber);\n });\n }\n\n /** @internal */\n protected _checkFinalizedStatuses(subscriber: Subscriber) {\n const { hasError, thrownError, isStopped } = this;\n if (hasError) {\n subscriber.error(thrownError);\n } else if (isStopped) {\n subscriber.complete();\n }\n }\n\n /**\n * Creates a new Observable with this Subject as the source. You can do this\n * to create custom Observer-side logic of the Subject and conceal it from\n * code that uses the Observable.\n * @return {Observable} Observable that the Subject casts to\n */\n asObservable(): Observable {\n const observable: any = new Observable();\n observable.source = this;\n return observable;\n }\n}\n\n/**\n * @class AnonymousSubject\n */\nexport class AnonymousSubject extends Subject {\n constructor(\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n public destination?: Observer,\n source?: Observable\n ) {\n super();\n this.source = source;\n }\n\n next(value: T) {\n this.destination?.next?.(value);\n }\n\n error(err: any) {\n this.destination?.error?.(err);\n }\n\n complete() {\n this.destination?.complete?.();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n return this.source?.subscribe(subscriber) ?? EMPTY_SUBSCRIPTION;\n }\n}\n", "import { Subject } from './Subject';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\n\n/**\n * A variant of Subject that requires an initial value and emits its current\n * value whenever it is subscribed to.\n *\n * @class BehaviorSubject\n */\nexport class BehaviorSubject extends Subject {\n constructor(private _value: T) {\n super();\n }\n\n get value(): T {\n return this.getValue();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n const subscription = super._subscribe(subscriber);\n !subscription.closed && subscriber.next(this._value);\n return subscription;\n }\n\n getValue(): T {\n const { hasError, thrownError, _value } = this;\n if (hasError) {\n throw thrownError;\n }\n this._throwIfClosed();\n return _value;\n }\n\n next(value: T): void {\n super.next((this._value = value));\n }\n}\n", "import { TimestampProvider } from '../types';\n\ninterface DateTimestampProvider extends TimestampProvider {\n delegate: TimestampProvider | undefined;\n}\n\nexport const dateTimestampProvider: DateTimestampProvider = {\n now() {\n // Use the variable rather than `this` so that the function can be called\n // without being bound to the provider.\n return (dateTimestampProvider.delegate || Date).now();\n },\n delegate: undefined,\n};\n", "import { Subject } from './Subject';\nimport { TimestampProvider } from './types';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * A variant of {@link Subject} that \"replays\" old values to new subscribers by emitting them when they first subscribe.\n *\n * `ReplaySubject` has an internal buffer that will store a specified number of values that it has observed. Like `Subject`,\n * `ReplaySubject` \"observes\" values by having them passed to its `next` method. When it observes a value, it will store that\n * value for a time determined by the configuration of the `ReplaySubject`, as passed to its constructor.\n *\n * When a new subscriber subscribes to the `ReplaySubject` instance, it will synchronously emit all values in its buffer in\n * a First-In-First-Out (FIFO) manner. The `ReplaySubject` will also complete, if it has observed completion; and it will\n * error if it has observed an error.\n *\n * There are two main configuration items to be concerned with:\n *\n * 1. `bufferSize` - This will determine how many items are stored in the buffer, defaults to infinite.\n * 2. `windowTime` - The amount of time to hold a value in the buffer before removing it from the buffer.\n *\n * Both configurations may exist simultaneously. So if you would like to buffer a maximum of 3 values, as long as the values\n * are less than 2 seconds old, you could do so with a `new ReplaySubject(3, 2000)`.\n *\n * ### Differences with BehaviorSubject\n *\n * `BehaviorSubject` is similar to `new ReplaySubject(1)`, with a couple of exceptions:\n *\n * 1. `BehaviorSubject` comes \"primed\" with a single value upon construction.\n * 2. `ReplaySubject` will replay values, even after observing an error, where `BehaviorSubject` will not.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n * @see {@link shareReplay}\n */\nexport class ReplaySubject extends Subject {\n private _buffer: (T | number)[] = [];\n private _infiniteTimeWindow = true;\n\n /**\n * @param bufferSize The size of the buffer to replay on subscription\n * @param windowTime The amount of time the buffered items will stay buffered\n * @param timestampProvider An object with a `now()` method that provides the current timestamp. This is used to\n * calculate the amount of time something has been buffered.\n */\n constructor(\n private _bufferSize = Infinity,\n private _windowTime = Infinity,\n private _timestampProvider: TimestampProvider = dateTimestampProvider\n ) {\n super();\n this._infiniteTimeWindow = _windowTime === Infinity;\n this._bufferSize = Math.max(1, _bufferSize);\n this._windowTime = Math.max(1, _windowTime);\n }\n\n next(value: T): void {\n const { isStopped, _buffer, _infiniteTimeWindow, _timestampProvider, _windowTime } = this;\n if (!isStopped) {\n _buffer.push(value);\n !_infiniteTimeWindow && _buffer.push(_timestampProvider.now() + _windowTime);\n }\n this._trimBuffer();\n super.next(value);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._trimBuffer();\n\n const subscription = this._innerSubscribe(subscriber);\n\n const { _infiniteTimeWindow, _buffer } = this;\n // We use a copy here, so reentrant code does not mutate our array while we're\n // emitting it to a new subscriber.\n const copy = _buffer.slice();\n for (let i = 0; i < copy.length && !subscriber.closed; i += _infiniteTimeWindow ? 1 : 2) {\n subscriber.next(copy[i] as T);\n }\n\n this._checkFinalizedStatuses(subscriber);\n\n return subscription;\n }\n\n private _trimBuffer() {\n const { _bufferSize, _timestampProvider, _buffer, _infiniteTimeWindow } = this;\n // If we don't have an infinite buffer size, and we're over the length,\n // use splice to truncate the old buffer values off. Note that we have to\n // double the size for instances where we're not using an infinite time window\n // because we're storing the values and the timestamps in the same array.\n const adjustedBufferSize = (_infiniteTimeWindow ? 1 : 2) * _bufferSize;\n _bufferSize < Infinity && adjustedBufferSize < _buffer.length && _buffer.splice(0, _buffer.length - adjustedBufferSize);\n\n // Now, if we're not in an infinite time window, remove all values where the time is\n // older than what is allowed.\n if (!_infiniteTimeWindow) {\n const now = _timestampProvider.now();\n let last = 0;\n // Search the array for the first timestamp that isn't expired and\n // truncate the buffer up to that point.\n for (let i = 1; i < _buffer.length && (_buffer[i] as number) <= now; i += 2) {\n last = i;\n }\n last && _buffer.splice(0, last + 1);\n }\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Subscription } from '../Subscription';\nimport { SchedulerAction } from '../types';\n\n/**\n * A unit of work to be executed in a `scheduler`. An action is typically\n * created from within a {@link SchedulerLike} and an RxJS user does not need to concern\n * themselves about creating and manipulating an Action.\n *\n * ```ts\n * class Action extends Subscription {\n * new (scheduler: Scheduler, work: (state?: T) => void);\n * schedule(state?: T, delay: number = 0): Subscription;\n * }\n * ```\n *\n * @class Action\n */\nexport class Action extends Subscription {\n constructor(scheduler: Scheduler, work: (this: SchedulerAction, state?: T) => void) {\n super();\n }\n /**\n * Schedules this action on its parent {@link SchedulerLike} for execution. May be passed\n * some context object, `state`. May happen at some point in the future,\n * according to the `delay` parameter, if specified.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler.\n * @return {void}\n */\n public schedule(state?: T, delay: number = 0): Subscription {\n return this;\n }\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetIntervalFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearIntervalFunction = (handle: TimerHandle) => void;\n\ninterface IntervalProvider {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n delegate:\n | {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n }\n | undefined;\n}\n\nexport const intervalProvider: IntervalProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setInterval(handler: () => void, timeout?: number, ...args) {\n const { delegate } = intervalProvider;\n if (delegate?.setInterval) {\n return delegate.setInterval(handler, timeout, ...args);\n }\n return setInterval(handler, timeout, ...args);\n },\n clearInterval(handle) {\n const { delegate } = intervalProvider;\n return (delegate?.clearInterval || clearInterval)(handle as any);\n },\n delegate: undefined,\n};\n", "import { Action } from './Action';\nimport { SchedulerAction } from '../types';\nimport { Subscription } from '../Subscription';\nimport { AsyncScheduler } from './AsyncScheduler';\nimport { intervalProvider } from './intervalProvider';\nimport { arrRemove } from '../util/arrRemove';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncAction extends Action {\n public id: TimerHandle | undefined;\n public state?: T;\n // @ts-ignore: Property has no initializer and is not definitely assigned\n public delay: number;\n protected pending: boolean = false;\n\n constructor(protected scheduler: AsyncScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (this.closed) {\n return this;\n }\n\n // Always replace the current state with the new state.\n this.state = state;\n\n const id = this.id;\n const scheduler = this.scheduler;\n\n //\n // Important implementation note:\n //\n // Actions only execute once by default, unless rescheduled from within the\n // scheduled callback. This allows us to implement single and repeat\n // actions via the same code path, without adding API surface area, as well\n // as mimic traditional recursion but across asynchronous boundaries.\n //\n // However, JS runtimes and timers distinguish between intervals achieved by\n // serial `setTimeout` calls vs. a single `setInterval` call. An interval of\n // serial `setTimeout` calls can be individually delayed, which delays\n // scheduling the next `setTimeout`, and so on. `setInterval` attempts to\n // guarantee the interval callback will be invoked more precisely to the\n // interval period, regardless of load.\n //\n // Therefore, we use `setInterval` to schedule single and repeat actions.\n // If the action reschedules itself with the same delay, the interval is not\n // canceled. If the action doesn't reschedule, or reschedules with a\n // different delay, the interval will be canceled after scheduled callback\n // execution.\n //\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, delay);\n }\n\n // Set the pending flag indicating that this action has been scheduled, or\n // has recursively rescheduled itself.\n this.pending = true;\n\n this.delay = delay;\n // If this action has already an async Id, don't request a new one.\n this.id = this.id ?? this.requestAsyncId(scheduler, this.id, delay);\n\n return this;\n }\n\n protected requestAsyncId(scheduler: AsyncScheduler, _id?: TimerHandle, delay: number = 0): TimerHandle {\n return intervalProvider.setInterval(scheduler.flush.bind(scheduler, this), delay);\n }\n\n protected recycleAsyncId(_scheduler: AsyncScheduler, id?: TimerHandle, delay: number | null = 0): TimerHandle | undefined {\n // If this action is rescheduled with the same delay time, don't clear the interval id.\n if (delay != null && this.delay === delay && this.pending === false) {\n return id;\n }\n // Otherwise, if the action's delay time is different from the current delay,\n // or the action has been rescheduled before it's executed, clear the interval id\n if (id != null) {\n intervalProvider.clearInterval(id);\n }\n\n return undefined;\n }\n\n /**\n * Immediately executes this action and the `work` it contains.\n * @return {any}\n */\n public execute(state: T, delay: number): any {\n if (this.closed) {\n return new Error('executing a cancelled action');\n }\n\n this.pending = false;\n const error = this._execute(state, delay);\n if (error) {\n return error;\n } else if (this.pending === false && this.id != null) {\n // Dequeue if the action didn't reschedule itself. Don't call\n // unsubscribe(), because the action could reschedule later.\n // For example:\n // ```\n // scheduler.schedule(function doWork(counter) {\n // /* ... I'm a busy worker bee ... */\n // var originalAction = this;\n // /* wait 100ms before rescheduling the action */\n // setTimeout(function () {\n // originalAction.schedule(counter + 1);\n // }, 100);\n // }, 1000);\n // ```\n this.id = this.recycleAsyncId(this.scheduler, this.id, null);\n }\n }\n\n protected _execute(state: T, _delay: number): any {\n let errored: boolean = false;\n let errorValue: any;\n try {\n this.work(state);\n } catch (e) {\n errored = true;\n // HACK: Since code elsewhere is relying on the \"truthiness\" of the\n // return here, we can't have it return \"\" or 0 or false.\n // TODO: Clean this up when we refactor schedulers mid-version-8 or so.\n errorValue = e ? e : new Error('Scheduled action threw falsy error');\n }\n if (errored) {\n this.unsubscribe();\n return errorValue;\n }\n }\n\n unsubscribe() {\n if (!this.closed) {\n const { id, scheduler } = this;\n const { actions } = scheduler;\n\n this.work = this.state = this.scheduler = null!;\n this.pending = false;\n\n arrRemove(actions, this);\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, null);\n }\n\n this.delay = null!;\n super.unsubscribe();\n }\n }\n}\n", "import { Action } from './scheduler/Action';\nimport { Subscription } from './Subscription';\nimport { SchedulerLike, SchedulerAction } from './types';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * An execution context and a data structure to order tasks and schedule their\n * execution. Provides a notion of (potentially virtual) time, through the\n * `now()` getter method.\n *\n * Each unit of work in a Scheduler is called an `Action`.\n *\n * ```ts\n * class Scheduler {\n * now(): number;\n * schedule(work, delay?, state?): Subscription;\n * }\n * ```\n *\n * @class Scheduler\n * @deprecated Scheduler is an internal implementation detail of RxJS, and\n * should not be used directly. Rather, create your own class and implement\n * {@link SchedulerLike}. Will be made internal in v8.\n */\nexport class Scheduler implements SchedulerLike {\n public static now: () => number = dateTimestampProvider.now;\n\n constructor(private schedulerActionCtor: typeof Action, now: () => number = Scheduler.now) {\n this.now = now;\n }\n\n /**\n * A getter method that returns a number representing the current time\n * (at the time this function was called) according to the scheduler's own\n * internal clock.\n * @return {number} A number that represents the current time. May or may not\n * have a relation to wall-clock time. May or may not refer to a time unit\n * (e.g. milliseconds).\n */\n public now: () => number;\n\n /**\n * Schedules a function, `work`, for execution. May happen at some point in\n * the future, according to the `delay` parameter, if specified. May be passed\n * some context object, `state`, which will be passed to the `work` function.\n *\n * The given arguments will be processed an stored as an Action object in a\n * queue of actions.\n *\n * @param {function(state: ?T): ?Subscription} work A function representing a\n * task, or some unit of work to be executed by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler itself.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @return {Subscription} A subscription in order to be able to unsubscribe\n * the scheduled work.\n */\n public schedule(work: (this: SchedulerAction, state?: T) => void, delay: number = 0, state?: T): Subscription {\n return new this.schedulerActionCtor(this, work).schedule(state, delay);\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Action } from './Action';\nimport { AsyncAction } from './AsyncAction';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncScheduler extends Scheduler {\n public actions: Array> = [];\n /**\n * A flag to indicate whether the Scheduler is currently executing a batch of\n * queued actions.\n * @type {boolean}\n * @internal\n */\n public _active: boolean = false;\n /**\n * An internal ID used to track the latest asynchronous task such as those\n * coming from `setTimeout`, `setInterval`, `requestAnimationFrame`, and\n * others.\n * @type {any}\n * @internal\n */\n public _scheduled: TimerHandle | undefined;\n\n constructor(SchedulerAction: typeof Action, now: () => number = Scheduler.now) {\n super(SchedulerAction, now);\n }\n\n public flush(action: AsyncAction): void {\n const { actions } = this;\n\n if (this._active) {\n actions.push(action);\n return;\n }\n\n let error: any;\n this._active = true;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions.shift()!)); // exhaust the scheduler queue\n\n this._active = false;\n\n if (error) {\n while ((action = actions.shift()!)) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\n/**\n *\n * Async Scheduler\n *\n * Schedule task as if you used setTimeout(task, duration)\n *\n * `async` scheduler schedules tasks asynchronously, by putting them on the JavaScript\n * event loop queue. It is best used to delay tasks in time or to schedule tasks repeating\n * in intervals.\n *\n * If you just want to \"defer\" task, that is to perform it right after currently\n * executing synchronous code ends (commonly achieved by `setTimeout(deferredTask, 0)`),\n * better choice will be the {@link asapScheduler} scheduler.\n *\n * ## Examples\n * Use async scheduler to delay task\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * const task = () => console.log('it works!');\n *\n * asyncScheduler.schedule(task, 2000);\n *\n * // After 2 seconds logs:\n * // \"it works!\"\n * ```\n *\n * Use async scheduler to repeat task in intervals\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * function task(state) {\n * console.log(state);\n * this.schedule(state + 1, 1000); // `this` references currently executing Action,\n * // which we reschedule with new state and delay\n * }\n *\n * asyncScheduler.schedule(task, 3000, 0);\n *\n * // Logs:\n * // 0 after 3s\n * // 1 after 4s\n * // 2 after 5s\n * // 3 after 6s\n * ```\n */\n\nexport const asyncScheduler = new AsyncScheduler(AsyncAction);\n\n/**\n * @deprecated Renamed to {@link asyncScheduler}. Will be removed in v8.\n */\nexport const async = asyncScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { Subscription } from '../Subscription';\nimport { QueueScheduler } from './QueueScheduler';\nimport { SchedulerAction } from '../types';\nimport { TimerHandle } from './timerHandle';\n\nexport class QueueAction extends AsyncAction {\n constructor(protected scheduler: QueueScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (delay > 0) {\n return super.schedule(state, delay);\n }\n this.delay = delay;\n this.state = state;\n this.scheduler.flush(this);\n return this;\n }\n\n public execute(state: T, delay: number): any {\n return delay > 0 || this.closed ? super.execute(state, delay) : this._execute(state, delay);\n }\n\n protected requestAsyncId(scheduler: QueueScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n\n if ((delay != null && delay > 0) || (delay == null && this.delay > 0)) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n\n // Otherwise flush the scheduler starting with this action.\n scheduler.flush(this);\n\n // HACK: In the past, this was returning `void`. However, `void` isn't a valid\n // `TimerHandle`, and generally the return value here isn't really used. So the\n // compromise is to return `0` which is both \"falsy\" and a valid `TimerHandle`,\n // as opposed to refactoring every other instanceo of `requestAsyncId`.\n return 0;\n }\n}\n", "import { AsyncScheduler } from './AsyncScheduler';\n\nexport class QueueScheduler extends AsyncScheduler {\n}\n", "import { QueueAction } from './QueueAction';\nimport { QueueScheduler } from './QueueScheduler';\n\n/**\n *\n * Queue Scheduler\n *\n * Put every next task on a queue, instead of executing it immediately\n *\n * `queue` scheduler, when used with delay, behaves the same as {@link asyncScheduler} scheduler.\n *\n * When used without delay, it schedules given task synchronously - executes it right when\n * it is scheduled. However when called recursively, that is when inside the scheduled task,\n * another task is scheduled with queue scheduler, instead of executing immediately as well,\n * that task will be put on a queue and wait for current one to finish.\n *\n * This means that when you execute task with `queue` scheduler, you are sure it will end\n * before any other task scheduled with that scheduler will start.\n *\n * ## Examples\n * Schedule recursively first, then do something\n * ```ts\n * import { queueScheduler } from 'rxjs';\n *\n * queueScheduler.schedule(() => {\n * queueScheduler.schedule(() => console.log('second')); // will not happen now, but will be put on a queue\n *\n * console.log('first');\n * });\n *\n * // Logs:\n * // \"first\"\n * // \"second\"\n * ```\n *\n * Reschedule itself recursively\n * ```ts\n * import { queueScheduler } from 'rxjs';\n *\n * queueScheduler.schedule(function(state) {\n * if (state !== 0) {\n * console.log('before', state);\n * this.schedule(state - 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * console.log('after', state);\n * }\n * }, 0, 3);\n *\n * // In scheduler that runs recursively, you would expect:\n * // \"before\", 3\n * // \"before\", 2\n * // \"before\", 1\n * // \"after\", 1\n * // \"after\", 2\n * // \"after\", 3\n *\n * // But with queue it logs:\n * // \"before\", 3\n * // \"after\", 3\n * // \"before\", 2\n * // \"after\", 2\n * // \"before\", 1\n * // \"after\", 1\n * ```\n */\n\nexport const queueScheduler = new QueueScheduler(QueueAction);\n\n/**\n * @deprecated Renamed to {@link queueScheduler}. Will be removed in v8.\n */\nexport const queue = queueScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\nimport { SchedulerAction } from '../types';\nimport { animationFrameProvider } from './animationFrameProvider';\nimport { TimerHandle } from './timerHandle';\n\nexport class AnimationFrameAction extends AsyncAction {\n constructor(protected scheduler: AnimationFrameScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n protected requestAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay is greater than 0, request as an async action.\n if (delay !== null && delay > 0) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n // Push the action to the end of the scheduler queue.\n scheduler.actions.push(this);\n // If an animation frame has already been requested, don't request another\n // one. If an animation frame hasn't been requested yet, request one. Return\n // the current animation frame request id.\n return scheduler._scheduled || (scheduler._scheduled = animationFrameProvider.requestAnimationFrame(() => scheduler.flush(undefined)));\n }\n\n protected recycleAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle | undefined {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n if (delay != null ? delay > 0 : this.delay > 0) {\n return super.recycleAsyncId(scheduler, id, delay);\n }\n // If the scheduler queue has no remaining actions with the same async id,\n // cancel the requested animation frame and set the scheduled flag to\n // undefined so the next AnimationFrameAction will request its own.\n const { actions } = scheduler;\n if (id != null && actions[actions.length - 1]?.id !== id) {\n animationFrameProvider.cancelAnimationFrame(id as number);\n scheduler._scheduled = undefined;\n }\n // Return undefined so the action knows to request a new async id if it's rescheduled.\n return undefined;\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\nexport class AnimationFrameScheduler extends AsyncScheduler {\n public flush(action?: AsyncAction): void {\n this._active = true;\n // The async id that effects a call to flush is stored in _scheduled.\n // Before executing an action, it's necessary to check the action's async\n // id to determine whether it's supposed to be executed in the current\n // flush.\n // Previous implementations of this method used a count to determine this,\n // but that was unsound, as actions that are unsubscribed - i.e. cancelled -\n // are removed from the actions array and that can shift actions that are\n // scheduled to be executed in a subsequent flush into positions at which\n // they are executed within the current flush.\n const flushId = this._scheduled;\n this._scheduled = undefined;\n\n const { actions } = this;\n let error: any;\n action = action || actions.shift()!;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions[0]) && action.id === flushId && actions.shift());\n\n this._active = false;\n\n if (error) {\n while ((action = actions[0]) && action.id === flushId && actions.shift()) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AnimationFrameAction } from './AnimationFrameAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\n\n/**\n *\n * Animation Frame Scheduler\n *\n * Perform task when `window.requestAnimationFrame` would fire\n *\n * When `animationFrame` scheduler is used with delay, it will fall back to {@link asyncScheduler} scheduler\n * behaviour.\n *\n * Without delay, `animationFrame` scheduler can be used to create smooth browser animations.\n * It makes sure scheduled task will happen just before next browser content repaint,\n * thus performing animations as efficiently as possible.\n *\n * ## Example\n * Schedule div height animation\n * ```ts\n * // html:
\n * import { animationFrameScheduler } from 'rxjs';\n *\n * const div = document.querySelector('div');\n *\n * animationFrameScheduler.schedule(function(height) {\n * div.style.height = height + \"px\";\n *\n * this.schedule(height + 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * }, 0, 0);\n *\n * // You will see a div element growing in height\n * ```\n */\n\nexport const animationFrameScheduler = new AnimationFrameScheduler(AnimationFrameAction);\n\n/**\n * @deprecated Renamed to {@link animationFrameScheduler}. Will be removed in v8.\n */\nexport const animationFrame = animationFrameScheduler;\n", "import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\n\n/**\n * A simple Observable that emits no items to the Observer and immediately\n * emits a complete notification.\n *\n * Just emits 'complete', and nothing else.\n *\n * ![](empty.png)\n *\n * A simple Observable that only emits the complete notification. It can be used\n * for composing with other Observables, such as in a {@link mergeMap}.\n *\n * ## Examples\n *\n * Log complete notification\n *\n * ```ts\n * import { EMPTY } from 'rxjs';\n *\n * EMPTY.subscribe({\n * next: () => console.log('Next'),\n * complete: () => console.log('Complete!')\n * });\n *\n * // Outputs\n * // Complete!\n * ```\n *\n * Emit the number 7, then complete\n *\n * ```ts\n * import { EMPTY, startWith } from 'rxjs';\n *\n * const result = EMPTY.pipe(startWith(7));\n * result.subscribe(x => console.log(x));\n *\n * // Outputs\n * // 7\n * ```\n *\n * Map and flatten only odd numbers to the sequence `'a'`, `'b'`, `'c'`\n *\n * ```ts\n * import { interval, mergeMap, of, EMPTY } from 'rxjs';\n *\n * const interval$ = interval(1000);\n * const result = interval$.pipe(\n * mergeMap(x => x % 2 === 1 ? of('a', 'b', 'c') : EMPTY),\n * );\n * result.subscribe(x => console.log(x));\n *\n * // Results in the following to the console:\n * // x is equal to the count on the interval, e.g. (0, 1, 2, 3, ...)\n * // x will occur every 1000ms\n * // if x % 2 is equal to 1, print a, b, c (each on its own)\n * // if x % 2 is not equal to 1, nothing will be output\n * ```\n *\n * @see {@link Observable}\n * @see {@link NEVER}\n * @see {@link of}\n * @see {@link throwError}\n */\nexport const EMPTY = new Observable((subscriber) => subscriber.complete());\n\n/**\n * @param scheduler A {@link SchedulerLike} to use for scheduling\n * the emission of the complete notification.\n * @deprecated Replaced with the {@link EMPTY} constant or {@link scheduled} (e.g. `scheduled([], scheduler)`). Will be removed in v8.\n */\nexport function empty(scheduler?: SchedulerLike) {\n return scheduler ? emptyScheduled(scheduler) : EMPTY;\n}\n\nfunction emptyScheduled(scheduler: SchedulerLike) {\n return new Observable((subscriber) => scheduler.schedule(() => subscriber.complete()));\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport function isScheduler(value: any): value is SchedulerLike {\n return value && isFunction(value.schedule);\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\nimport { isScheduler } from './isScheduler';\n\nfunction last(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\n\nexport function popResultSelector(args: any[]): ((...args: unknown[]) => unknown) | undefined {\n return isFunction(last(args)) ? args.pop() : undefined;\n}\n\nexport function popScheduler(args: any[]): SchedulerLike | undefined {\n return isScheduler(last(args)) ? args.pop() : undefined;\n}\n\nexport function popNumber(args: any[], defaultValue: number): number {\n return typeof last(args) === 'number' ? args.pop()! : defaultValue;\n}\n", "export const isArrayLike = ((x: any): x is ArrayLike => x && typeof x.length === 'number' && typeof x !== 'function');", "import { isFunction } from \"./isFunction\";\n\n/**\n * Tests to see if the object is \"thennable\".\n * @param value the object to test\n */\nexport function isPromise(value: any): value is PromiseLike {\n return isFunction(value?.then);\n}\n", "import { InteropObservable } from '../types';\nimport { observable as Symbol_observable } from '../symbol/observable';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being Observable (but not necessary an Rx Observable) */\nexport function isInteropObservable(input: any): input is InteropObservable {\n return isFunction(input[Symbol_observable]);\n}\n", "import { isFunction } from './isFunction';\n\nexport function isAsyncIterable(obj: any): obj is AsyncIterable {\n return Symbol.asyncIterator && isFunction(obj?.[Symbol.asyncIterator]);\n}\n", "/**\n * Creates the TypeError to throw if an invalid object is passed to `from` or `scheduled`.\n * @param input The object that was passed.\n */\nexport function createInvalidObservableTypeError(input: any) {\n // TODO: We should create error codes that can be looked up, so this can be less verbose.\n return new TypeError(\n `You provided ${\n input !== null && typeof input === 'object' ? 'an invalid object' : `'${input}'`\n } where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`\n );\n}\n", "export function getSymbolIterator(): symbol {\n if (typeof Symbol !== 'function' || !Symbol.iterator) {\n return '@@iterator' as any;\n }\n\n return Symbol.iterator;\n}\n\nexport const iterator = getSymbolIterator();\n", "import { iterator as Symbol_iterator } from '../symbol/iterator';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being an Iterable */\nexport function isIterable(input: any): input is Iterable {\n return isFunction(input?.[Symbol_iterator]);\n}\n", "import { ReadableStreamLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport async function* readableStreamLikeToAsyncGenerator(readableStream: ReadableStreamLike): AsyncGenerator {\n const reader = readableStream.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n return;\n }\n yield value!;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function isReadableStreamLike(obj: any): obj is ReadableStreamLike {\n // We don't want to use instanceof checks because they would return\n // false for instances from another Realm, like an ' ) + } + else if ( linkText.match( /vimeo/ ) ) { + let vimeoID = replace.split( '/' ).slice(-1)[0]; + aLink.push( '
' ) + } + else { + aLink.push( '
' + linkText + '' ); + } + text = text.split( linksFound[i] ).map(item => { return aLink[i].includes('iframe') ? item.trim() : item } ).join( aLink[i] ); + } + return text; + + } + else { + return input; + } + } \ No newline at end of file diff --git a/docs/js/katex.js b/docs/js/katex.js new file mode 100644 index 00000000..841e35ad --- /dev/null +++ b/docs/js/katex.js @@ -0,0 +1,10 @@ +document$.subscribe(({ body }) => { + renderMathInElement(body, { + delimiters: [ + { left: "$$", right: "$$", display: true }, + { left: "$", right: "$", display: false }, + { left: "\\(", right: "\\)", display: false }, + { left: "\\[", right: "\\]", display: true } + ], + }) +}) \ No newline at end of file diff --git a/docs/js/tsparticles.js b/docs/js/tsparticles.js new file mode 100644 index 00000000..bf96e09b --- /dev/null +++ b/docs/js/tsparticles.js @@ -0,0 +1,2 @@ +/*! For license information please see tsparticles.bundle.min.js.LICENSE.txt */ +!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var i=e();for(var s in i)("object"==typeof exports?exports:t)[s]=i[s]}}(this,(()=>(()=>{"use strict";var t={d:(e,i)=>{for(var s in i)t.o(i,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:i[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{AnimatableColor:()=>Se,AnimationOptions:()=>Me,AnimationValueWithRandom:()=>Ee,Background:()=>le,BackgroundMask:()=>de,BackgroundMaskCover:()=>he,Circle:()=>yi,ClickEvent:()=>pe,Collisions:()=>Fe,CollisionsAbsorb:()=>De,CollisionsOverlap:()=>Te,ColorAnimation:()=>Pe,DivEvent:()=>fe,Events:()=>ge,ExternalInteractorBase:()=>Si,FullScreen:()=>ue,HoverEvent:()=>ye,HslAnimation:()=>Oe,HslColorManager:()=>Pi,Interactivity:()=>we,ManualParticle:()=>xe,Modes:()=>be,Move:()=>Xe,MoveAngle:()=>qe,MoveAttract:()=>He,MoveCenter:()=>Ve,MoveGravity:()=>Ue,MovePath:()=>We,MoveTrail:()=>je,Opacity:()=>Ze,OpacityAnimation:()=>Ye,Options:()=>li,OptionsColor:()=>ce,OutModes:()=>Ge,Parallax:()=>ve,ParticlesBounce:()=>Ae,ParticlesBounceFactor:()=>Le,ParticlesDensity:()=>Qe,ParticlesInteractorBase:()=>Di,ParticlesNumber:()=>Ke,ParticlesNumberLimit:()=>Je,ParticlesOptions:()=>ai,Point:()=>pi,Range:()=>fi,RangedAnimationOptions:()=>Ce,RangedAnimationValueWithRandom:()=>Ie,Rectangle:()=>vi,ResizeEvent:()=>me,Responsive:()=>_e,RgbColorManager:()=>Oi,Shadow:()=>ti,Shape:()=>ei,Size:()=>si,SizeAnimation:()=>ii,Spin:()=>Ne,Stroke:()=>oi,Theme:()=>ze,ThemeDefault:()=>ke,ValueWithRandom:()=>Re,Vector:()=>y,Vector3d:()=>v,ZIndex:()=>ni,addColorManager:()=>Pt,addEasing:()=>b,alterHsl:()=>se,areBoundsInside:()=>et,arrayRandomIndex:()=>J,calcExactPositionOrRandomFromSize:()=>B,calcExactPositionOrRandomFromSizeRanged:()=>q,calcPositionFromSize:()=>L,calcPositionOrRandomFromSize:()=>A,calcPositionOrRandomFromSizeRanged:()=>F,calculateBounds:()=>it,circleBounce:()=>lt,circleBounceDataFromParticle:()=>ct,clamp:()=>k,clear:()=>Zt,collisionVelocity:()=>I,colorMix:()=>Vt,colorToHsl:()=>Tt,colorToRgb:()=>Dt,deepExtend:()=>st,divMode:()=>rt,divModeExecute:()=>nt,drawEffect:()=>Jt,drawLine:()=>Nt,drawParticle:()=>Qt,drawParticlePlugin:()=>ie,drawPlugin:()=>ee,drawShape:()=>Kt,drawShapeAfterDraw:()=>te,errorPrefix:()=>f,executeOnSingleOrMultiple:()=>dt,findItemFromSingleOrMultiple:()=>pt,generatedAttribute:()=>i,getDistance:()=>T,getDistances:()=>D,getEasing:()=>w,getHslAnimationFromHsl:()=>jt,getHslFromAnimation:()=>$t,getLinkColor:()=>Ut,getLinkRandomColor:()=>Wt,getLogger:()=>W,getParticleBaseVelocity:()=>E,getParticleDirectionAngle:()=>R,getPosition:()=>yt,getRandom:()=>_,getRandomRgbColor:()=>Bt,getRangeMax:()=>O,getRangeMin:()=>P,getRangeValue:()=>C,getSize:()=>mt,getStyleFromHsl:()=>Ht,getStyleFromRgb:()=>qt,hasMatchMedia:()=>G,hslToRgb:()=>At,hslaToRgba:()=>Ft,initParticleNumericAnimationValue:()=>ft,isArray:()=>kt,isBoolean:()=>gt,isDivModeEnabled:()=>ot,isFunction:()=>xt,isInArray:()=>Z,isNumber:()=>wt,isObject:()=>_t,isPointInside:()=>tt,isSsr:()=>j,isString:()=>bt,itemFromArray:()=>K,itemFromSingleOrMultiple:()=>ut,loadFont:()=>Q,loadFull:()=>gn,loadOptions:()=>ri,loadParticlesOptions:()=>ci,loadSlim:()=>an,mix:()=>z,mouseDownEvent:()=>s,mouseLeaveEvent:()=>n,mouseMoveEvent:()=>r,mouseOutEvent:()=>a,mouseUpEvent:()=>o,paintBase:()=>Xt,paintImage:()=>Yt,parseAlpha:()=>H,randomInRange:()=>M,rangeColorToHsl:()=>Rt,rangeColorToRgb:()=>St,rectBounce:()=>ht,resizeEvent:()=>u,rgbToHsl:()=>Et,safeIntersectionObserver:()=>X,safeMatchMedia:()=>N,safeMutationObserver:()=>Y,setLogger:()=>U,setRandom:()=>x,setRangeValue:()=>S,singleDivModeExecute:()=>at,stringToAlpha:()=>It,stringToRgb:()=>Lt,touchCancelEvent:()=>d,touchEndEvent:()=>l,touchMoveEvent:()=>h,touchStartEvent:()=>c,tsParticles:()=>Ti,visibilityChangeEvent:()=>p});const i="generated",s="pointerdown",o="pointerup",n="pointerleave",a="pointerout",r="pointermove",c="touchstart",l="touchend",h="touchmove",d="touchcancel",u="resize",p="visibilitychange",f="tsParticles - Error";class v{constructor(t,e,i){if(this._updateFromAngle=(t,e)=>{this.x=Math.cos(t)*e,this.y=Math.sin(t)*e},!wt(t)&&t){this.x=t.x,this.y=t.y;const e=t;this.z=e.z?e.z:0}else{if(void 0===t||void 0===e)throw new Error(`${f} Vector3d not initialized correctly`);this.x=t,this.y=e,this.z=i??0}}static get origin(){return v.create(0,0,0)}get angle(){return Math.atan2(this.y,this.x)}set angle(t){this._updateFromAngle(t,this.length)}get length(){return Math.sqrt(this.getLengthSq())}set length(t){this._updateFromAngle(this.angle,t)}static clone(t){return v.create(t.x,t.y,t.z)}static create(t,e,i){return new v(t,e,i)}add(t){return v.create(this.x+t.x,this.y+t.y,this.z+t.z)}addTo(t){this.x+=t.x,this.y+=t.y,this.z+=t.z}copy(){return v.clone(this)}distanceTo(t){return this.sub(t).length}distanceToSq(t){return this.sub(t).getLengthSq()}div(t){return v.create(this.x/t,this.y/t,this.z/t)}divTo(t){this.x/=t,this.y/=t,this.z/=t}getLengthSq(){return this.x**2+this.y**2}mult(t){return v.create(this.x*t,this.y*t,this.z*t)}multTo(t){this.x*=t,this.y*=t,this.z*=t}normalize(){const t=this.length;0!=t&&this.multTo(1/t)}rotate(t){return v.create(this.x*Math.cos(t)-this.y*Math.sin(t),this.x*Math.sin(t)+this.y*Math.cos(t),0)}setTo(t){this.x=t.x,this.y=t.y;const e=t;this.z=e.z?e.z:0}sub(t){return v.create(this.x-t.x,this.y-t.y,this.z-t.z)}subFrom(t){this.x-=t.x,this.y-=t.y,this.z-=t.z}}class y extends v{constructor(t,e){super(t,e,0)}static get origin(){return y.create(0,0)}static clone(t){return y.create(t.x,t.y)}static create(t,e){return new y(t,e)}}let m=Math.random;const g=new Map;function b(t,e){g.get(t)||g.set(t,e)}function w(t){return g.get(t)||(t=>t)}function x(t=Math.random){m=t}function _(){return k(m(),0,1-1e-16)}function k(t,e,i){return Math.min(Math.max(t,e),i)}function z(t,e,i,s){return Math.floor((t*i+e*s)/(i+s))}function M(t){const e=O(t);let i=P(t);return e===i&&(i=0),_()*(e-i)+i}function C(t){return wt(t)?t:M(t)}function P(t){return wt(t)?t:t.min}function O(t){return wt(t)?t:t.max}function S(t,e){if(t===e||void 0===e&&wt(t))return t;const i=P(t),s=O(t);return void 0!==e?{min:Math.min(i,e),max:Math.max(s,e)}:S(i,s)}function D(t,e){const i=t.x-e.x,s=t.y-e.y;return{dx:i,dy:s,distance:Math.sqrt(i**2+s**2)}}function T(t,e){return D(t,e).distance}function R(t,e,i){if(wt(t))return t*Math.PI/180;switch(t){case"top":return.5*-Math.PI;case"top-right":return.25*-Math.PI;case"right":return 0;case"bottom-right":return.25*Math.PI;case"bottom":return.5*Math.PI;case"bottom-left":return.75*Math.PI;case"left":return Math.PI;case"top-left":return.75*-Math.PI;case"inside":return Math.atan2(i.y-e.y,i.x-e.x);case"outside":return Math.atan2(e.y-i.y,e.x-i.x);default:return _()*Math.PI*2}}function E(t){const e=y.origin;return e.length=1,e.angle=t,e}function I(t,e,i,s){return y.create(t.x*(i-s)/(i+s)+2*e.x*s/(i+s),t.y)}function L(t){return t.position&&void 0!==t.position.x&&void 0!==t.position.y?{x:t.position.x*t.size.width/100,y:t.position.y*t.size.height/100}:void 0}function A(t){return{x:(t.position?.x??100*_())*t.size.width/100,y:(t.position?.y??100*_())*t.size.height/100}}function F(t){const e={x:void 0!==t.position?.x?C(t.position.x):void 0,y:void 0!==t.position?.y?C(t.position.y):void 0};return A({size:t.size,position:e})}function B(t){return{x:t.position?.x??_()*t.size.width,y:t.position?.y??_()*t.size.height}}function q(t){const e={x:void 0!==t.position?.x?C(t.position.x):void 0,y:void 0!==t.position?.y?C(t.position.y):void 0};return B({size:t.size,position:e})}function H(t){return t?t.endsWith("%")?parseFloat(t)/100:parseFloat(t):1}const V={debug:console.debug,error:console.error,info:console.info,log:console.log,verbose:console.log,warning:console.warn};function U(t){V.debug=t.debug||V.debug,V.error=t.error||V.error,V.info=t.info||V.info,V.log=t.log||V.log,V.verbose=t.verbose||V.verbose,V.warning=t.warning||V.warning}function W(){return V}function $(t){const e={bounced:!1},{pSide:i,pOtherSide:s,rectSide:o,rectOtherSide:n,velocity:a,factor:r}=t;return s.minn.max||s.maxn.max||(i.max>=o.min&&i.max<=.5*(o.max+o.min)&&a>0||i.min<=o.max&&i.min>.5*(o.max+o.min)&&a<0)&&(e.velocity=a*-r,e.bounced=!0),e}function j(){return"undefined"==typeof window||!window||void 0===window.document||!window.document}function G(){return!j()&&"undefined"!=typeof matchMedia}function N(t){if(G())return matchMedia(t)}function X(t){if(!j()&&"undefined"!=typeof IntersectionObserver)return new IntersectionObserver(t)}function Y(t){if(!j()&&"undefined"!=typeof MutationObserver)return new MutationObserver(t)}function Z(t,e){return t===e||kt(e)&&e.indexOf(t)>-1}async function Q(t,e){try{await document.fonts.load(`${e??"400"} 36px '${t??"Verdana"}'`)}catch{}}function J(t){return Math.floor(_()*t.length)}function K(t,e,i=!0){return t[void 0!==e&&i?e%t.length:J(t)]}function tt(t,e,i,s,o){return et(it(t,s??0),e,i,o)}function et(t,e,i,s){let o=!0;return s&&"bottom"!==s||(o=t.topi.x),!o||s&&"right"!==s||(o=t.lefti.y),o}function it(t,e){return{bottom:t.y+e,left:t.x-e,right:t.x+e,top:t.y-e}}function st(t,...e){for(const i of e){if(null==i)continue;if(!_t(i)){t=i;continue}const e=Array.isArray(i);!e||!_t(t)&&t&&Array.isArray(t)?e||!_t(t)&&t&&!Array.isArray(t)||(t={}):t=[];for(const e in i){if("__proto__"===e)continue;const s=i[e],o=t;o[e]=_t(s)&&Array.isArray(s)?s.map((t=>st(o[e],t))):st(o[e],s)}}return t}function ot(t,e){return!!pt(e,(e=>e.enable&&Z(t,e.mode)))}function nt(t,e,i){dt(e,(e=>{const s=e.mode;e.enable&&Z(t,s)&&at(e,i)}))}function at(t,e){dt(t.selectors,(i=>{e(i,t)}))}function rt(t,e){if(e&&t)return pt(t,(t=>function(t,e){const i=dt(e,(e=>t.matches(e)));return kt(i)?i.some((t=>t)):i}(e,t.selectors)))}function ct(t){return{position:t.getPosition(),radius:t.getRadius(),mass:t.getMass(),velocity:t.velocity,factor:y.create(C(t.options.bounce.horizontal.value),C(t.options.bounce.vertical.value))}}function lt(t,e){const{x:i,y:s}=t.velocity.sub(e.velocity),[o,n]=[t.position,e.position],{dx:a,dy:r}=D(n,o);if(i*a+s*r<0)return;const c=-Math.atan2(r,a),l=t.mass,h=e.mass,d=t.velocity.rotate(c),u=e.velocity.rotate(c),p=I(d,u,l,h),f=I(u,d,l,h),v=p.rotate(-c),y=f.rotate(-c);t.velocity.x=v.x*t.factor.x,t.velocity.y=v.y*t.factor.y,e.velocity.x=y.x*e.factor.x,e.velocity.y=y.y*e.factor.y}function ht(t,e){const i=it(t.getPosition(),t.getRadius()),s=t.options.bounce,o=$({pSide:{min:i.left,max:i.right},pOtherSide:{min:i.top,max:i.bottom},rectSide:{min:e.left,max:e.right},rectOtherSide:{min:e.top,max:e.bottom},velocity:t.velocity.x,factor:C(s.horizontal.value)});o.bounced&&(void 0!==o.velocity&&(t.velocity.x=o.velocity),void 0!==o.position&&(t.position.x=o.position));const n=$({pSide:{min:i.top,max:i.bottom},pOtherSide:{min:i.left,max:i.right},rectSide:{min:e.top,max:e.bottom},rectOtherSide:{min:e.left,max:e.right},velocity:t.velocity.y,factor:C(s.vertical.value)});n.bounced&&(void 0!==n.velocity&&(t.velocity.y=n.velocity),void 0!==n.position&&(t.position.y=n.position))}function dt(t,e){return kt(t)?t.map(((t,i)=>e(t,i))):e(t,0)}function ut(t,e,i){return kt(t)?K(t,e,i):t}function pt(t,e){return kt(t)?t.find(((t,i)=>e(t,i))):e(t,0)?t:void 0}function ft(t,e){const i=t.value,s=t.animation,o={delayTime:1e3*C(s.delay),enable:s.enable,value:C(t.value)*e,max:O(i)*e,min:P(i)*e,loops:0,maxLoops:C(s.count),time:0};if(s.enable){switch(o.decay=1-C(s.decay),s.mode){case"increase":o.status="increasing";break;case"decrease":o.status="decreasing";break;case"random":o.status=_()>=.5?"increasing":"decreasing"}const t="auto"===s.mode;switch(s.startValue){case"min":o.value=o.min,t&&(o.status="increasing");break;case"max":o.value=o.max,t&&(o.status="decreasing");break;default:o.value=M(o),t&&(o.status=_()>=.5?"increasing":"decreasing")}}return o.initialValue=o.value,o}function vt(t,e){if(!("percent"===t.mode)){const{mode:e,...i}=t;return i}return"x"in t?{x:t.x/100*e.width,y:t.y/100*e.height}:{width:t.width/100*e.width,height:t.height/100*e.height}}function yt(t,e){return vt(t,e)}function mt(t,e){return vt(t,e)}function gt(t){return"boolean"==typeof t}function bt(t){return"string"==typeof t}function wt(t){return"number"==typeof t}function xt(t){return"function"==typeof t}function _t(t){return"object"==typeof t&&null!==t}function kt(t){return Array.isArray(t)}const zt="random",Mt="mid",Ct=new Map;function Pt(t){Ct.set(t.key,t)}function Ot(t){for(const[,e]of Ct)if(t.startsWith(e.stringPrefix))return e.parseString(t);const e=t.replace(/^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i,((t,e,i,s,o)=>e+e+i+i+s+s+(void 0!==o?o+o:""))),i=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(e);return i?{a:void 0!==i[4]?parseInt(i[4],16)/255:1,b:parseInt(i[3],16),g:parseInt(i[2],16),r:parseInt(i[1],16)}:void 0}function St(t,e,i=!0){if(!t)return;const s=bt(t)?{value:t}:t;if(bt(s.value))return Dt(s.value,e,i);if(kt(s.value))return St({value:K(s.value,e,i)});for(const[,t]of Ct){const e=t.handleRangeColor(s);if(e)return e}}function Dt(t,e,i=!0){if(!t)return;const s=bt(t)?{value:t}:t;if(bt(s.value))return s.value===zt?Bt():Lt(s.value);if(kt(s.value))return Dt({value:K(s.value,e,i)});for(const[,t]of Ct){const e=t.handleColor(s);if(e)return e}}function Tt(t,e,i=!0){const s=Dt(t,e,i);return s?Et(s):void 0}function Rt(t,e,i=!0){const s=St(t,e,i);return s?Et(s):void 0}function Et(t){const e=t.r/255,i=t.g/255,s=t.b/255,o=Math.max(e,i,s),n=Math.min(e,i,s),a={h:0,l:.5*(o+n),s:0};return o!==n&&(a.s=a.l<.5?(o-n)/(o+n):(o-n)/(2-o-n),a.h=e===o?(i-s)/(o-n):a.h=i===o?2+(s-e)/(o-n):4+(e-i)/(o-n)),a.l*=100,a.s*=100,a.h*=60,a.h<0&&(a.h+=360),a.h>=360&&(a.h-=360),a}function It(t){return Ot(t)?.a}function Lt(t){return Ot(t)}function At(t){const e=(t.h%360+360)%360,i=Math.max(0,Math.min(100,t.s)),s=e/360,o=i/100,n=Math.max(0,Math.min(100,t.l))/100;if(0===i){const t=Math.round(255*n);return{r:t,g:t,b:t}}const a=(t,e,i)=>(i<0&&(i+=1),i>1&&(i-=1),6*i<1?t+6*(e-t)*i:2*i<1?e:3*i<2?t+(e-t)*(2/3-i)*6:t),r=n<.5?n*(1+o):n+o-n*o,c=2*n-r,l=Math.min(255,255*a(c,r,s+1/3)),h=Math.min(255,255*a(c,r,s)),d=Math.min(255,255*a(c,r,s-1/3));return{r:Math.round(l),g:Math.round(h),b:Math.round(d)}}function Ft(t){const e=At(t);return{a:t.a,b:e.b,g:e.g,r:e.r}}function Bt(t){const e=t??0;return{b:Math.floor(M(S(e,256))),g:Math.floor(M(S(e,256))),r:Math.floor(M(S(e,256)))}}function qt(t,e){return`rgba(${t.r}, ${t.g}, ${t.b}, ${e??1})`}function Ht(t,e){return`hsla(${t.h}, ${t.s}%, ${t.l}%, ${e??1})`}function Vt(t,e,i,s){let o=t,n=e;return void 0===o.r&&(o=At(t)),void 0===n.r&&(n=At(e)),{b:z(o.b,n.b,i,s),g:z(o.g,n.g,i,s),r:z(o.r,n.r,i,s)}}function Ut(t,e,i){if(i===zt)return Bt();if(i!==Mt)return i;{const i=t.getFillColor()??t.getStrokeColor(),s=e?.getFillColor()??e?.getStrokeColor();if(i&&s&&e)return Vt(i,s,t.getRadius(),e.getRadius());{const t=i??s;if(t)return At(t)}}}function Wt(t,e,i){const s=bt(t)?t:t.value;return s===zt?i?St({value:s}):e?zt:Mt:s===Mt?Mt:St({value:s})}function $t(t){return void 0!==t?{h:t.h.value,s:t.s.value,l:t.l.value}:void 0}function jt(t,e,i){const s={h:{enable:!1,value:t.h},s:{enable:!1,value:t.s},l:{enable:!1,value:t.l}};return e&&(Gt(s.h,e.h,i),Gt(s.s,e.s,i),Gt(s.l,e.l,i)),s}function Gt(t,e,i){t.enable=e.enable,t.enable?(t.velocity=C(e.speed)/100*i,t.decay=1-C(e.decay),t.status="increasing",t.loops=0,t.maxLoops=C(e.count),t.time=0,t.delayTime=1e3*C(e.delay),e.sync||(t.velocity*=_(),t.value*=_()),t.initialValue=t.value):t.velocity=0}function Nt(t,e,i){t.beginPath(),t.moveTo(e.x,e.y),t.lineTo(i.x,i.y),t.closePath()}function Xt(t,e,i){t.fillStyle=i??"rgba(0,0,0,0)",t.fillRect(0,0,e.width,e.height)}function Yt(t,e,i,s){i&&(t.globalAlpha=s,t.drawImage(i,0,0,e.width,e.height),t.globalAlpha=1)}function Zt(t,e){t.clearRect(0,0,e.width,e.height)}function Qt(t){const{container:e,context:i,particle:s,delta:o,colorStyles:n,backgroundMask:a,composite:r,radius:c,opacity:l,shadow:h,transform:d}=t,u=s.getPosition(),p=s.rotation+(s.pathRotation?s.velocity.angle:0),f=Math.sin(p),v=Math.cos(p),y={a:v*(d.a??1),b:f*(d.b??1),c:-f*(d.c??1),d:v*(d.d??1)};i.setTransform(y.a,y.b,y.c,y.d,u.x,u.y),a&&(i.globalCompositeOperation=r);const m=s.shadowColor;h.enable&&m&&(i.shadowBlur=h.blur,i.shadowColor=qt(m),i.shadowOffsetX=h.offset.x,i.shadowOffsetY=h.offset.y),n.fill&&(i.fillStyle=n.fill);const g=s.strokeWidth??0;i.lineWidth=g,n.stroke&&(i.strokeStyle=n.stroke);const b={container:e,context:i,particle:s,radius:c,opacity:l,delta:o,transformData:y};i.beginPath(),Kt(b),s.shapeClose&&i.closePath(),g>0&&i.stroke(),s.shapeFill&&i.fill(),te(b),Jt(b),i.globalCompositeOperation="source-over",i.setTransform(1,0,0,1,0,0)}function Jt(t){const{container:e,context:i,particle:s,radius:o,opacity:n,delta:a,transformData:r}=t;if(!s.effect)return;const c=e.effectDrawers.get(s.effect);c&&c.draw({context:i,particle:s,radius:o,opacity:n,delta:a,pixelRatio:e.retina.pixelRatio,transformData:{...r}})}function Kt(t){const{container:e,context:i,particle:s,radius:o,opacity:n,delta:a,transformData:r}=t;if(!s.shape)return;const c=e.shapeDrawers.get(s.shape);c&&c.draw({context:i,particle:s,radius:o,opacity:n,delta:a,pixelRatio:e.retina.pixelRatio,transformData:{...r}})}function te(t){const{container:e,context:i,particle:s,radius:o,opacity:n,delta:a,transformData:r}=t;if(!s.shape)return;const c=e.shapeDrawers.get(s.shape);c&&c.afterDraw&&c.afterDraw({context:i,particle:s,radius:o,opacity:n,delta:a,pixelRatio:e.retina.pixelRatio,transformData:{...r}})}function ee(t,e,i){e.draw&&e.draw(t,i)}function ie(t,e,i,s){e.drawParticle&&e.drawParticle(t,i,s)}function se(t,e,i){return{h:t.h,s:t.s,l:t.l+("darken"===e?-1:1)*i}}function oe(t,e,i){const s=e[i];void 0!==s&&(t[i]=(t[i]??1)*s)}class ne{constructor(t){this.container=t,this._applyPostDrawUpdaters=t=>{for(const e of this._postDrawUpdaters)e.afterDraw&&e.afterDraw(t)},this._applyPreDrawUpdaters=(t,e,i,s,o,n)=>{for(const a of this._preDrawUpdaters){if(a.getColorStyles){const{fill:n,stroke:r}=a.getColorStyles(e,t,i,s);n&&(o.fill=n),r&&(o.stroke=r)}if(a.getTransformValues){const t=a.getTransformValues(e);for(const e in t)oe(n,t,e)}a.beforeDraw&&a.beforeDraw(e)}},this._applyResizePlugins=()=>{for(const t of this._resizePlugins)t.resize&&t.resize()},this._getPluginParticleColors=t=>{let e,i;for(const s of this._colorPlugins)if(!e&&s.particleFillColor&&(e=Rt(s.particleFillColor(t))),!i&&s.particleStrokeColor&&(i=Rt(s.particleStrokeColor(t))),e&&i)break;return[e,i]},this._initCover=()=>{const t=this.container.actualOptions.backgroundMask.cover,e=St(t.color);if(e){const i={...e,a:t.opacity};this._coverColorStyle=qt(i,i.a)}},this._initStyle=()=>{const t=this.element,e=this.container.actualOptions;if(t){this._fullScreen?(this._originalStyle=st({},t.style),this._setFullScreenStyle()):this._resetOriginalStyle();for(const i in e.style){if(!i||!e.style)continue;const s=e.style[i];s&&t.style.setProperty(i,s,"important")}}},this._initTrail=async()=>{const t=this.container.actualOptions,e=t.particles.move.trail,i=e.fill;if(e.enable)if(i.color){const e=St(i.color);if(!e)return;const s=t.particles.move.trail;this._trailFill={color:{...e},opacity:1/s.length}}else await new Promise(((t,s)=>{if(!i.image)return;const o=document.createElement("img");o.addEventListener("load",(()=>{this._trailFill={image:o,opacity:1/e.length},t()})),o.addEventListener("error",(t=>{s(t.error)})),o.src=i.image}))},this._paintBase=t=>{this.draw((e=>Xt(e,this.size,t)))},this._paintImage=(t,e)=>{this.draw((i=>Yt(i,this.size,t,e)))},this._repairStyle=()=>{const t=this.element;t&&(this._safeMutationObserver((t=>t.disconnect())),this._initStyle(),this.initBackground(),this._safeMutationObserver((e=>e.observe(t,{attributes:!0}))))},this._resetOriginalStyle=()=>{const t=this.element,e=this._originalStyle;if(!t||!e)return;const i=t.style;i.position=e.position,i.zIndex=e.zIndex,i.top=e.top,i.left=e.left,i.width=e.width,i.height=e.height},this._safeMutationObserver=t=>{this._mutationObserver&&t(this._mutationObserver)},this._setFullScreenStyle=()=>{const t=this.element;if(!t)return;const e="important",i=t.style;i.setProperty("position","fixed",e),i.setProperty("z-index",this.container.actualOptions.fullScreen.zIndex.toString(10),e),i.setProperty("top","0",e),i.setProperty("left","0",e),i.setProperty("width","100%",e),i.setProperty("height","100%",e)},this.size={height:0,width:0},this._context=null,this._generated=!1,this._preDrawUpdaters=[],this._postDrawUpdaters=[],this._resizePlugins=[],this._colorPlugins=[]}get _fullScreen(){return this.container.actualOptions.fullScreen.enable}clear(){const t=this.container.actualOptions,e=t.particles.move.trail,i=this._trailFill;t.backgroundMask.enable?this.paint():e.enable&&e.length>0&&i?i.color?this._paintBase(qt(i.color,i.opacity)):i.image&&this._paintImage(i.image,i.opacity):t.clear&&this.draw((t=>{Zt(t,this.size)}))}destroy(){if(this.stop(),this._generated){const t=this.element;t&&t.remove()}else this._resetOriginalStyle();this._preDrawUpdaters=[],this._postDrawUpdaters=[],this._resizePlugins=[],this._colorPlugins=[]}draw(t){const e=this._context;if(e)return t(e)}drawParticle(t,e){if(t.spawning||t.destroyed)return;const i=t.getRadius();if(i<=0)return;const s=t.getFillColor(),o=t.getStrokeColor()??s;let[n,a]=this._getPluginParticleColors(t);n||(n=s),a||(a=o),(n||a)&&this.draw((s=>{const o=this.container,r=o.actualOptions,c=t.options.zIndex,l=(1-t.zIndexFactor)**c.opacityRate,h=t.bubble.opacity??t.opacity?.value??1,d=h*l,u=(t.strokeOpacity??h)*l,p={},f={fill:n?Ht(n,d):void 0};f.stroke=a?Ht(a,u):f.fill,this._applyPreDrawUpdaters(s,t,i,d,f,p),Qt({container:o,context:s,particle:t,delta:e,colorStyles:f,backgroundMask:r.backgroundMask.enable,composite:r.backgroundMask.composite,radius:i*(1-t.zIndexFactor)**c.sizeRate,opacity:d,shadow:t.options.shadow,transform:p}),this._applyPostDrawUpdaters(t)}))}drawParticlePlugin(t,e,i){this.draw((s=>ie(s,t,e,i)))}drawPlugin(t,e){this.draw((i=>ee(i,t,e)))}async init(){this._safeMutationObserver((t=>t.disconnect())),this._mutationObserver=Y((t=>{for(const e of t)"attributes"===e.type&&"style"===e.attributeName&&this._repairStyle()})),this.resize(),this._initStyle(),this._initCover();try{await this._initTrail()}catch(t){W().error(t)}this.initBackground(),this._safeMutationObserver((t=>{this.element&&t.observe(this.element,{attributes:!0})})),this.initUpdaters(),this.initPlugins(),this.paint()}initBackground(){const t=this.container.actualOptions.background,e=this.element;if(!e)return;const i=e.style;if(i){if(t.color){const e=St(t.color);i.backgroundColor=e?qt(e,t.opacity):""}else i.backgroundColor="";i.backgroundImage=t.image||"",i.backgroundPosition=t.position||"",i.backgroundRepeat=t.repeat||"",i.backgroundSize=t.size||""}}initPlugins(){this._resizePlugins=[];for(const[,t]of this.container.plugins)t.resize&&this._resizePlugins.push(t),(t.particleFillColor||t.particleStrokeColor)&&this._colorPlugins.push(t)}initUpdaters(){this._preDrawUpdaters=[],this._postDrawUpdaters=[];for(const t of this.container.particles.updaters)t.afterDraw&&this._postDrawUpdaters.push(t),(t.getColorStyles||t.getTransformValues||t.beforeDraw)&&this._preDrawUpdaters.push(t)}loadCanvas(t){this._generated&&this.element&&this.element.remove(),this._generated=t.dataset&&i in t.dataset?"true"===t.dataset[i]:this._generated,this.element=t,this.element.ariaHidden="true",this._originalStyle=st({},this.element.style),this.size.height=t.offsetHeight,this.size.width=t.offsetWidth,this._context=this.element.getContext("2d"),this._safeMutationObserver((t=>{this.element&&t.observe(this.element,{attributes:!0})})),this.container.retina.init(),this.initBackground()}paint(){const t=this.container.actualOptions;this.draw((e=>{t.backgroundMask.enable&&t.backgroundMask.cover?(Zt(e,this.size),this._paintBase(this._coverColorStyle)):this._paintBase()}))}resize(){if(!this.element)return!1;const t=this.container,e=t.retina.pixelRatio,i=t.canvas.size,s=this.element.offsetWidth*e,o=this.element.offsetHeight*e;if(o===i.height&&s===i.width&&o===this.element.height&&s===this.element.width)return!1;const n={...i};return this.element.width=i.width=this.element.offsetWidth*e,this.element.height=i.height=this.element.offsetHeight*e,this.container.started&&t.particles.setResizeFactor({width:i.width/n.width,height:i.height/n.height}),!0}stop(){this._safeMutationObserver((t=>t.disconnect())),this._mutationObserver=void 0,this.draw((t=>Zt(t,this.size)))}async windowResize(){if(!this.element||!this.resize())return;const t=this.container,e=t.updateActualOptions();t.particles.setDensity(),this._applyResizePlugins(),e&&await t.refresh()}}function ae(t,e,i,s,o){if(s){let s={passive:!0};gt(o)?s.capture=o:void 0!==o&&(s=o),t.addEventListener(e,i,s)}else{const s=o;t.removeEventListener(e,i,s)}}class re{constructor(t){this.container=t,this._doMouseTouchClick=t=>{const e=this.container,i=e.actualOptions;if(this._canPush){const t=e.interactivity.mouse,s=t.position;if(!s)return;t.clickPosition={...s},t.clickTime=(new Date).getTime();dt(i.interactivity.events.onClick.mode,(t=>this.container.handleClickMode(t)))}"touchend"===t.type&&setTimeout((()=>this._mouseTouchFinish()),500)},this._handleThemeChange=t=>{const e=t,i=this.container,s=i.options,o=s.defaultThemes,n=e.matches?o.dark:o.light,a=s.themes.find((t=>t.name===n));a&&a.default.auto&&i.loadTheme(n)},this._handleVisibilityChange=()=>{const t=this.container,e=t.actualOptions;this._mouseTouchFinish(),e.pauseOnBlur&&(document&&document.hidden?(t.pageHidden=!0,t.pause()):(t.pageHidden=!1,t.getAnimationStatus()?t.play(!0):t.draw(!0)))},this._handleWindowResize=async()=>{this._resizeTimeout&&(clearTimeout(this._resizeTimeout),delete this._resizeTimeout),this._resizeTimeout=setTimeout((async()=>{const t=this.container.canvas;t&&await t.windowResize()}),1e3*this.container.actualOptions.interactivity.events.resize.delay)},this._manageInteractivityListeners=(t,e)=>{const i=this._handlers,n=this.container,a=n.actualOptions,u=n.interactivity.element;if(!u)return;const p=u,f=n.canvas.element;f&&(f.style.pointerEvents=p===f?"initial":"none"),(a.interactivity.events.onHover.enable||a.interactivity.events.onClick.enable)&&(ae(u,r,i.mouseMove,e),ae(u,c,i.touchStart,e),ae(u,h,i.touchMove,e),a.interactivity.events.onClick.enable?(ae(u,l,i.touchEndClick,e),ae(u,o,i.mouseUp,e),ae(u,s,i.mouseDown,e)):ae(u,l,i.touchEnd,e),ae(u,t,i.mouseLeave,e),ae(u,d,i.touchCancel,e))},this._manageListeners=t=>{const e=this._handlers,i=this.container,s=i.actualOptions.interactivity.detectsOn,o=i.canvas.element;let r=n;"window"===s?(i.interactivity.element=window,r=a):i.interactivity.element="parent"===s&&o?o.parentElement??o.parentNode:o,this._manageMediaMatch(t),this._manageResize(t),this._manageInteractivityListeners(r,t),document&&ae(document,p,e.visibilityChange,t,!1)},this._manageMediaMatch=t=>{const e=this._handlers,i=N("(prefers-color-scheme: dark)");i&&(void 0===i.addEventListener?void 0!==i.addListener&&(t?i.addListener(e.oldThemeChange):i.removeListener(e.oldThemeChange)):ae(i,"change",e.themeChange,t))},this._manageResize=t=>{const e=this._handlers,i=this.container;if(!i.actualOptions.interactivity.events.resize)return;if("undefined"==typeof ResizeObserver)return void ae(window,u,e.resize,t);const s=i.canvas.element;this._resizeObserver&&!t?(s&&this._resizeObserver.unobserve(s),this._resizeObserver.disconnect(),delete this._resizeObserver):!this._resizeObserver&&t&&s&&(this._resizeObserver=new ResizeObserver((async t=>{t.find((t=>t.target===s))&&await this._handleWindowResize()})),this._resizeObserver.observe(s))},this._mouseDown=()=>{const{interactivity:t}=this.container;if(!t)return;const{mouse:e}=t;e.clicking=!0,e.downPosition=e.position},this._mouseTouchClick=t=>{const e=this.container,i=e.actualOptions,{mouse:s}=e.interactivity;s.inside=!0;let o=!1;const n=s.position;if(n&&i.interactivity.events.onClick.enable){for(const[,t]of e.plugins)if(t.clickPositionValid&&(o=t.clickPositionValid(n),o))break;o||this._doMouseTouchClick(t),s.clicking=!1}},this._mouseTouchFinish=()=>{const t=this.container.interactivity;if(!t)return;const e=t.mouse;delete e.position,delete e.clickPosition,delete e.downPosition,t.status=n,e.inside=!1,e.clicking=!1},this._mouseTouchMove=t=>{const e=this.container,i=e.actualOptions,s=e.interactivity,o=e.canvas.element;if(!s||!s.element)return;let n;if(s.mouse.inside=!0,t.type.startsWith("pointer")){this._canPush=!0;const e=t;if(s.element===window){if(o){const t=o.getBoundingClientRect();n={x:e.clientX-t.left,y:e.clientY-t.top}}}else if("parent"===i.interactivity.detectsOn){const t=e.target,i=e.currentTarget;if(t&&i&&o){const s=t.getBoundingClientRect(),a=i.getBoundingClientRect(),r=o.getBoundingClientRect();n={x:e.offsetX+2*s.left-(a.left+r.left),y:e.offsetY+2*s.top-(a.top+r.top)}}else n={x:e.offsetX??e.clientX,y:e.offsetY??e.clientY}}else e.target===o&&(n={x:e.offsetX??e.clientX,y:e.offsetY??e.clientY})}else if(this._canPush="touchmove"!==t.type,o){const e=t,i=e.touches[e.touches.length-1],s=o.getBoundingClientRect();n={x:i.clientX-(s.left??0),y:i.clientY-(s.top??0)}}const a=e.retina.pixelRatio;n&&(n.x*=a,n.y*=a),s.mouse.position=n,s.status=r},this._touchEnd=t=>{const e=t,i=Array.from(e.changedTouches);for(const t of i)this._touches.delete(t.identifier);this._mouseTouchFinish()},this._touchEndClick=t=>{const e=t,i=Array.from(e.changedTouches);for(const t of i)this._touches.delete(t.identifier);this._mouseTouchClick(t)},this._touchStart=t=>{const e=t,i=Array.from(e.changedTouches);for(const t of i)this._touches.set(t.identifier,performance.now());this._mouseTouchMove(t)},this._canPush=!0,this._touches=new Map,this._handlers={mouseDown:()=>this._mouseDown(),mouseLeave:()=>this._mouseTouchFinish(),mouseMove:t=>this._mouseTouchMove(t),mouseUp:t=>this._mouseTouchClick(t),touchStart:t=>this._touchStart(t),touchMove:t=>this._mouseTouchMove(t),touchEnd:t=>this._touchEnd(t),touchCancel:t=>this._touchEnd(t),touchEndClick:t=>this._touchEndClick(t),visibilityChange:()=>this._handleVisibilityChange(),themeChange:t=>this._handleThemeChange(t),oldThemeChange:t=>this._handleThemeChange(t),resize:()=>{this._handleWindowResize()}}}addListeners(){this._manageListeners(!0)}removeListeners(){this._manageListeners(!1)}}class ce{constructor(){this.value=""}static create(t,e){const i=new ce;return i.load(t),void 0!==e&&(bt(e)||kt(e)?i.load({value:e}):i.load(e)),i}load(t){void 0!==t?.value&&(this.value=t.value)}}class le{constructor(){this.color=new ce,this.color.value="",this.image="",this.position="",this.repeat="",this.size="",this.opacity=1}load(t){t&&(void 0!==t.color&&(this.color=ce.create(this.color,t.color)),void 0!==t.image&&(this.image=t.image),void 0!==t.position&&(this.position=t.position),void 0!==t.repeat&&(this.repeat=t.repeat),void 0!==t.size&&(this.size=t.size),void 0!==t.opacity&&(this.opacity=t.opacity))}}class he{constructor(){this.color=new ce,this.color.value="#fff",this.opacity=1}load(t){t&&(void 0!==t.color&&(this.color=ce.create(this.color,t.color)),void 0!==t.opacity&&(this.opacity=t.opacity))}}class de{constructor(){this.composite="destination-out",this.cover=new he,this.enable=!1}load(t){if(t){if(void 0!==t.composite&&(this.composite=t.composite),void 0!==t.cover){const e=t.cover,i=bt(t.cover)?{color:t.cover}:t.cover;this.cover.load(void 0!==e.color?e:{color:i})}void 0!==t.enable&&(this.enable=t.enable)}}}class ue{constructor(){this.enable=!0,this.zIndex=0}load(t){t&&(void 0!==t.enable&&(this.enable=t.enable),void 0!==t.zIndex&&(this.zIndex=t.zIndex))}}class pe{constructor(){this.enable=!1,this.mode=[]}load(t){t&&(void 0!==t.enable&&(this.enable=t.enable),void 0!==t.mode&&(this.mode=t.mode))}}class fe{constructor(){this.selectors=[],this.enable=!1,this.mode=[],this.type="circle"}load(t){t&&(void 0!==t.selectors&&(this.selectors=t.selectors),void 0!==t.enable&&(this.enable=t.enable),void 0!==t.mode&&(this.mode=t.mode),void 0!==t.type&&(this.type=t.type))}}class ve{constructor(){this.enable=!1,this.force=2,this.smooth=10}load(t){t&&(void 0!==t.enable&&(this.enable=t.enable),void 0!==t.force&&(this.force=t.force),void 0!==t.smooth&&(this.smooth=t.smooth))}}class ye{constructor(){this.enable=!1,this.mode=[],this.parallax=new ve}load(t){t&&(void 0!==t.enable&&(this.enable=t.enable),void 0!==t.mode&&(this.mode=t.mode),this.parallax.load(t.parallax))}}class me{constructor(){this.delay=.5,this.enable=!0}load(t){void 0!==t&&(void 0!==t.delay&&(this.delay=t.delay),void 0!==t.enable&&(this.enable=t.enable))}}class ge{constructor(){this.onClick=new pe,this.onDiv=new fe,this.onHover=new ye,this.resize=new me}load(t){if(!t)return;this.onClick.load(t.onClick);const e=t.onDiv;void 0!==e&&(this.onDiv=dt(e,(t=>{const e=new fe;return e.load(t),e}))),this.onHover.load(t.onHover),this.resize.load(t.resize)}}class be{constructor(t,e){this._engine=t,this._container=e}load(t){if(!t)return;if(!this._container)return;const e=this._engine.interactors.get(this._container);if(e)for(const i of e)i.loadModeOptions&&i.loadModeOptions(this,t)}}class we{constructor(t,e){this.detectsOn="window",this.events=new ge,this.modes=new be(t,e)}load(t){if(!t)return;const e=t.detectsOn;void 0!==e&&(this.detectsOn=e),this.events.load(t.events),this.modes.load(t.modes)}}class xe{load(t){t&&(t.position&&(this.position={x:t.position.x??50,y:t.position.y??50,mode:t.position.mode??"percent"}),t.options&&(this.options=st({},t.options)))}}class _e{constructor(){this.maxWidth=1/0,this.options={},this.mode="canvas"}load(t){t&&(void 0!==t.maxWidth&&(this.maxWidth=t.maxWidth),void 0!==t.mode&&("screen"===t.mode?this.mode="screen":this.mode="canvas"),void 0!==t.options&&(this.options=st({},t.options)))}}class ke{constructor(){this.auto=!1,this.mode="any",this.value=!1}load(t){t&&(void 0!==t.auto&&(this.auto=t.auto),void 0!==t.mode&&(this.mode=t.mode),void 0!==t.value&&(this.value=t.value))}}class ze{constructor(){this.name="",this.default=new ke}load(t){t&&(void 0!==t.name&&(this.name=t.name),this.default.load(t.default),void 0!==t.options&&(this.options=st({},t.options)))}}class Me{constructor(){this.count=0,this.enable=!1,this.speed=1,this.decay=0,this.delay=0,this.sync=!1}load(t){t&&(void 0!==t.count&&(this.count=S(t.count)),void 0!==t.enable&&(this.enable=t.enable),void 0!==t.speed&&(this.speed=S(t.speed)),void 0!==t.decay&&(this.decay=S(t.decay)),void 0!==t.delay&&(this.delay=S(t.delay)),void 0!==t.sync&&(this.sync=t.sync))}}class Ce extends Me{constructor(){super(),this.mode="auto",this.startValue="random"}load(t){super.load(t),t&&(void 0!==t.mode&&(this.mode=t.mode),void 0!==t.startValue&&(this.startValue=t.startValue))}}class Pe extends Me{constructor(){super(),this.offset=0,this.sync=!0}load(t){super.load(t),t&&void 0!==t.offset&&(this.offset=S(t.offset))}}class Oe{constructor(){this.h=new Pe,this.s=new Pe,this.l=new Pe}load(t){t&&(this.h.load(t.h),this.s.load(t.s),this.l.load(t.l))}}class Se extends ce{constructor(){super(),this.animation=new Oe}static create(t,e){const i=new Se;return i.load(t),void 0!==e&&(bt(e)||kt(e)?i.load({value:e}):i.load(e)),i}load(t){if(super.load(t),!t)return;const e=t.animation;void 0!==e&&(void 0!==e.enable?this.animation.h.load(e):this.animation.load(t.animation))}}class De{constructor(){this.speed=2}load(t){t&&void 0!==t.speed&&(this.speed=t.speed)}}class Te{constructor(){this.enable=!0,this.retries=0}load(t){t&&(void 0!==t.enable&&(this.enable=t.enable),void 0!==t.retries&&(this.retries=t.retries))}}class Re{constructor(){this.value=0}load(t){t&&void 0!==t.value&&(this.value=S(t.value))}}class Ee extends Re{constructor(){super(),this.animation=new Me}load(t){if(super.load(t),!t)return;const e=t.animation;void 0!==e&&this.animation.load(e)}}class Ie extends Ee{constructor(){super(),this.animation=new Ce}load(t){super.load(t)}}class Le extends Re{constructor(){super(),this.value=1}}class Ae{constructor(){this.horizontal=new Le,this.vertical=new Le}load(t){t&&(this.horizontal.load(t.horizontal),this.vertical.load(t.vertical))}}class Fe{constructor(){this.absorb=new De,this.bounce=new Ae,this.enable=!1,this.maxSpeed=50,this.mode="bounce",this.overlap=new Te}load(t){t&&(this.absorb.load(t.absorb),this.bounce.load(t.bounce),void 0!==t.enable&&(this.enable=t.enable),void 0!==t.maxSpeed&&(this.maxSpeed=S(t.maxSpeed)),void 0!==t.mode&&(this.mode=t.mode),this.overlap.load(t.overlap))}}class Be{constructor(){this.close=!0,this.fill=!0,this.options={},this.type=[]}load(t){if(!t)return;const e=t.options;if(void 0!==e)for(const t in e){const i=e[t];i&&(this.options[t]=st(this.options[t]??{},i))}void 0!==t.close&&(this.close=t.close),void 0!==t.fill&&(this.fill=t.fill),void 0!==t.type&&(this.type=t.type)}}class qe{constructor(){this.offset=0,this.value=90}load(t){t&&(void 0!==t.offset&&(this.offset=S(t.offset)),void 0!==t.value&&(this.value=S(t.value)))}}class He{constructor(){this.distance=200,this.enable=!1,this.rotate={x:3e3,y:3e3}}load(t){if(t&&(void 0!==t.distance&&(this.distance=S(t.distance)),void 0!==t.enable&&(this.enable=t.enable),t.rotate)){const e=t.rotate.x;void 0!==e&&(this.rotate.x=e);const i=t.rotate.y;void 0!==i&&(this.rotate.y=i)}}}class Ve{constructor(){this.x=50,this.y=50,this.mode="percent",this.radius=0}load(t){t&&(void 0!==t.x&&(this.x=t.x),void 0!==t.y&&(this.y=t.y),void 0!==t.mode&&(this.mode=t.mode),void 0!==t.radius&&(this.radius=t.radius))}}class Ue{constructor(){this.acceleration=9.81,this.enable=!1,this.inverse=!1,this.maxSpeed=50}load(t){t&&(void 0!==t.acceleration&&(this.acceleration=S(t.acceleration)),void 0!==t.enable&&(this.enable=t.enable),void 0!==t.inverse&&(this.inverse=t.inverse),void 0!==t.maxSpeed&&(this.maxSpeed=S(t.maxSpeed)))}}class We{constructor(){this.clamp=!0,this.delay=new Re,this.enable=!1,this.options={}}load(t){t&&(void 0!==t.clamp&&(this.clamp=t.clamp),this.delay.load(t.delay),void 0!==t.enable&&(this.enable=t.enable),this.generator=t.generator,t.options&&(this.options=st(this.options,t.options)))}}class $e{load(t){t&&(void 0!==t.color&&(this.color=ce.create(this.color,t.color)),void 0!==t.image&&(this.image=t.image))}}class je{constructor(){this.enable=!1,this.length=10,this.fill=new $e}load(t){t&&(void 0!==t.enable&&(this.enable=t.enable),void 0!==t.fill&&this.fill.load(t.fill),void 0!==t.length&&(this.length=t.length))}}class Ge{constructor(){this.default="out"}load(t){t&&(void 0!==t.default&&(this.default=t.default),this.bottom=t.bottom??t.default,this.left=t.left??t.default,this.right=t.right??t.default,this.top=t.top??t.default)}}class Ne{constructor(){this.acceleration=0,this.enable=!1}load(t){t&&(void 0!==t.acceleration&&(this.acceleration=S(t.acceleration)),void 0!==t.enable&&(this.enable=t.enable),t.position&&(this.position=st({},t.position)))}}class Xe{constructor(){this.angle=new qe,this.attract=new He,this.center=new Ve,this.decay=0,this.distance={},this.direction="none",this.drift=0,this.enable=!1,this.gravity=new Ue,this.path=new We,this.outModes=new Ge,this.random=!1,this.size=!1,this.speed=2,this.spin=new Ne,this.straight=!1,this.trail=new je,this.vibrate=!1,this.warp=!1}load(t){if(!t)return;this.angle.load(wt(t.angle)?{value:t.angle}:t.angle),this.attract.load(t.attract),this.center.load(t.center),void 0!==t.decay&&(this.decay=S(t.decay)),void 0!==t.direction&&(this.direction=t.direction),void 0!==t.distance&&(this.distance=wt(t.distance)?{horizontal:t.distance,vertical:t.distance}:{...t.distance}),void 0!==t.drift&&(this.drift=S(t.drift)),void 0!==t.enable&&(this.enable=t.enable),this.gravity.load(t.gravity);const e=t.outModes;void 0!==e&&(_t(e)?this.outModes.load(e):this.outModes.load({default:e})),this.path.load(t.path),void 0!==t.random&&(this.random=t.random),void 0!==t.size&&(this.size=t.size),void 0!==t.speed&&(this.speed=S(t.speed)),this.spin.load(t.spin),void 0!==t.straight&&(this.straight=t.straight),this.trail.load(t.trail),void 0!==t.vibrate&&(this.vibrate=t.vibrate),void 0!==t.warp&&(this.warp=t.warp)}}class Ye extends Ce{constructor(){super(),this.destroy="none",this.speed=2}load(t){super.load(t),t&&void 0!==t.destroy&&(this.destroy=t.destroy)}}class Ze extends Ie{constructor(){super(),this.animation=new Ye,this.value=1}load(t){if(!t)return;super.load(t);const e=t.animation;void 0!==e&&this.animation.load(e)}}class Qe{constructor(){this.enable=!1,this.width=1920,this.height=1080}load(t){if(!t)return;void 0!==t.enable&&(this.enable=t.enable);const e=t.width;void 0!==e&&(this.width=e);const i=t.height;void 0!==i&&(this.height=i)}}class Je{constructor(){this.mode="delete",this.value=0}load(t){t&&(void 0!==t.mode&&(this.mode=t.mode),void 0!==t.value&&(this.value=t.value))}}class Ke{constructor(){this.density=new Qe,this.limit=new Je,this.value=0}load(t){t&&(this.density.load(t.density),this.limit.load(t.limit),void 0!==t.value&&(this.value=t.value))}}class ti{constructor(){this.blur=0,this.color=new ce,this.enable=!1,this.offset={x:0,y:0},this.color.value="#000"}load(t){t&&(void 0!==t.blur&&(this.blur=t.blur),this.color=ce.create(this.color,t.color),void 0!==t.enable&&(this.enable=t.enable),void 0!==t.offset&&(void 0!==t.offset.x&&(this.offset.x=t.offset.x),void 0!==t.offset.y&&(this.offset.y=t.offset.y)))}}class ei{constructor(){this.close=!0,this.fill=!0,this.options={},this.type="circle"}load(t){if(!t)return;const e=t.options;if(void 0!==e)for(const t in e){const i=e[t];i&&(this.options[t]=st(this.options[t]??{},i))}void 0!==t.close&&(this.close=t.close),void 0!==t.fill&&(this.fill=t.fill),void 0!==t.type&&(this.type=t.type)}}class ii extends Ce{constructor(){super(),this.destroy="none",this.speed=5}load(t){super.load(t),t&&void 0!==t.destroy&&(this.destroy=t.destroy)}}class si extends Ie{constructor(){super(),this.animation=new ii,this.value=3}load(t){if(super.load(t),!t)return;const e=t.animation;void 0!==e&&this.animation.load(e)}}class oi{constructor(){this.width=0}load(t){t&&(void 0!==t.color&&(this.color=Se.create(this.color,t.color)),void 0!==t.width&&(this.width=S(t.width)),void 0!==t.opacity&&(this.opacity=S(t.opacity)))}}class ni extends Re{constructor(){super(),this.opacityRate=1,this.sizeRate=1,this.velocityRate=1}load(t){super.load(t),t&&(void 0!==t.opacityRate&&(this.opacityRate=t.opacityRate),void 0!==t.sizeRate&&(this.sizeRate=t.sizeRate),void 0!==t.velocityRate&&(this.velocityRate=t.velocityRate))}}class ai{constructor(t,e){this._engine=t,this._container=e,this.bounce=new Ae,this.collisions=new Fe,this.color=new Se,this.color.value="#fff",this.effect=new Be,this.groups={},this.move=new Xe,this.number=new Ke,this.opacity=new Ze,this.reduceDuplicates=!1,this.shadow=new ti,this.shape=new ei,this.size=new si,this.stroke=new oi,this.zIndex=new ni}load(t){if(!t)return;if(void 0!==t.groups)for(const e of Object.keys(t.groups)){if(!Object.hasOwn(t.groups,e))continue;const i=t.groups[e];void 0!==i&&(this.groups[e]=st(this.groups[e]??{},i))}void 0!==t.reduceDuplicates&&(this.reduceDuplicates=t.reduceDuplicates),this.bounce.load(t.bounce),this.color.load(Se.create(this.color,t.color)),this.effect.load(t.effect),this.move.load(t.move),this.number.load(t.number),this.opacity.load(t.opacity),this.shape.load(t.shape),this.size.load(t.size),this.shadow.load(t.shadow),this.zIndex.load(t.zIndex),this.collisions.load(t.collisions),void 0!==t.interactivity&&(this.interactivity=st({},t.interactivity));const e=t.stroke;if(e&&(this.stroke=dt(e,(t=>{const e=new oi;return e.load(t),e}))),this._container){const e=this._engine.updaters.get(this._container);if(e)for(const i of e)i.loadOptions&&i.loadOptions(this,t);const i=this._engine.interactors.get(this._container);if(i)for(const e of i)e.loadParticlesOptions&&e.loadParticlesOptions(this,t)}}}function ri(t,...e){for(const i of e)t.load(i)}function ci(t,e,...i){const s=new ai(t,e);return ri(s,...i),s}class li{constructor(t,e){this._findDefaultTheme=t=>this.themes.find((e=>e.default.value&&e.default.mode===t))??this.themes.find((t=>t.default.value&&"any"===t.default.mode)),this._importPreset=t=>{this.load(this._engine.getPreset(t))},this._engine=t,this._container=e,this.autoPlay=!0,this.background=new le,this.backgroundMask=new de,this.clear=!0,this.defaultThemes={},this.delay=0,this.fullScreen=new ue,this.detectRetina=!0,this.duration=0,this.fpsLimit=120,this.interactivity=new we(t,e),this.manualParticles=[],this.particles=ci(this._engine,this._container),this.pauseOnBlur=!0,this.pauseOnOutsideViewport=!0,this.responsive=[],this.smooth=!1,this.style={},this.themes=[],this.zLayers=100}load(t){if(!t)return;void 0!==t.preset&&dt(t.preset,(t=>this._importPreset(t))),void 0!==t.autoPlay&&(this.autoPlay=t.autoPlay),void 0!==t.clear&&(this.clear=t.clear),void 0!==t.name&&(this.name=t.name),void 0!==t.delay&&(this.delay=S(t.delay));const e=t.detectRetina;void 0!==e&&(this.detectRetina=e),void 0!==t.duration&&(this.duration=S(t.duration));const i=t.fpsLimit;void 0!==i&&(this.fpsLimit=i),void 0!==t.pauseOnBlur&&(this.pauseOnBlur=t.pauseOnBlur),void 0!==t.pauseOnOutsideViewport&&(this.pauseOnOutsideViewport=t.pauseOnOutsideViewport),void 0!==t.zLayers&&(this.zLayers=t.zLayers),this.background.load(t.background);const s=t.fullScreen;gt(s)?this.fullScreen.enable=s:this.fullScreen.load(s),this.backgroundMask.load(t.backgroundMask),this.interactivity.load(t.interactivity),t.manualParticles&&(this.manualParticles=t.manualParticles.map((t=>{const e=new xe;return e.load(t),e}))),this.particles.load(t.particles),this.style=st(this.style,t.style),this._engine.loadOptions(this,t),void 0!==t.smooth&&(this.smooth=t.smooth);const o=this._engine.interactors.get(this._container);if(o)for(const e of o)e.loadOptions&&e.loadOptions(this,t);if(void 0!==t.responsive)for(const e of t.responsive){const t=new _e;t.load(e),this.responsive.push(t)}if(this.responsive.sort(((t,e)=>t.maxWidth-e.maxWidth)),void 0!==t.themes)for(const e of t.themes){const t=this.themes.find((t=>t.name===e.name));if(t)t.load(e);else{const t=new ze;t.load(e),this.themes.push(t)}}this.defaultThemes.dark=this._findDefaultTheme("dark")?.name,this.defaultThemes.light=this._findDefaultTheme("light")?.name}setResponsive(t,e,i){this.load(i);const s=this.responsive.find((i=>"screen"===i.mode&&screen?i.maxWidth>screen.availWidth:i.maxWidth*e>t));return this.load(s?.options),s?.maxWidth}setTheme(t){if(t){const e=this.themes.find((e=>e.name===t));e&&this.load(e.options)}else{const t=N("(prefers-color-scheme: dark)"),e=t&&t.matches,i=this._findDefaultTheme(e?"dark":"light");i&&this.load(i.options)}}}class hi{constructor(t,e){this.container=e,this._engine=t,this._interactors=t.getInteractors(this.container,!0),this._externalInteractors=[],this._particleInteractors=[]}async externalInteract(t){for(const e of this._externalInteractors)e.isEnabled()&&await e.interact(t)}handleClickMode(t){for(const e of this._externalInteractors)e.handleClickMode&&e.handleClickMode(t)}init(){this._externalInteractors=[],this._particleInteractors=[];for(const t of this._interactors){switch(t.type){case"external":this._externalInteractors.push(t);break;case"particles":this._particleInteractors.push(t)}t.init()}}async particlesInteract(t,e){for(const i of this._externalInteractors)i.clear(t,e);for(const i of this._particleInteractors)i.isEnabled(t)&&await i.interact(t,e)}async reset(t){for(const e of this._externalInteractors)e.isEnabled()&&e.reset(t);for(const e of this._particleInteractors)e.isEnabled(t)&&e.reset(t)}}function di(t){if(!Z(t.outMode,t.checkModes))return;const e=2*t.radius;t.coord>t.maxCoord-e?t.setCb(-t.radius):t.coord{for(const[,s]of t.plugins){const t=void 0!==s.particlePosition?s.particlePosition(e,this):void 0;if(t)return v.create(t.x,t.y,i)}const o=B({size:t.canvas.size,position:e}),n=v.create(o.x,o.y,i),a=this.getRadius(),r=this.options.move.outModes,c=e=>{di({outMode:e,checkModes:["bounce","bounce-horizontal"],coord:n.x,maxCoord:t.canvas.size.width,setCb:t=>n.x+=t,radius:a})},l=e=>{di({outMode:e,checkModes:["bounce","bounce-vertical"],coord:n.y,maxCoord:t.canvas.size.height,setCb:t=>n.y+=t,radius:a})};return c(r.left??r.default),c(r.right??r.default),l(r.top??r.default),l(r.bottom??r.default),this._checkOverlap(n,s)?this._calcPosition(t,void 0,i,s+1):n},this._calculateVelocity=()=>{const t=E(this.direction).copy(),e=this.options.move;if("inside"===e.direction||"outside"===e.direction)return t;const i=Math.PI/180*C(e.angle.value),s=Math.PI/180*C(e.angle.offset),o={left:s-.5*i,right:s+.5*i};return e.straight||(t.angle+=M(S(o.left,o.right))),e.random&&"number"==typeof e.speed&&(t.length*=_()),t},this._checkOverlap=(t,e=0)=>{const i=this.options.collisions,s=this.getRadius();if(!i.enable)return!1;const o=i.overlap;if(o.enable)return!1;const n=o.retries;if(n>=0&&e>n)throw new Error(`${f} particle is overlapping and can't be placed`);return!!this.container.particles.find((e=>T(t,e.position){if(!t||!this.roll||!this.backColor&&!this.roll.alter)return t;const e=this.roll.horizontal&&this.roll.vertical?2:1,i=this.roll.horizontal?.5*Math.PI:0;return Math.floor(((this.roll.angle??0)+i)/(Math.PI/e))%2?this.backColor?this.backColor:this.roll.alter?se(t,this.roll.alter.type,this.roll.alter.value):t:t},this._initPosition=t=>{const e=this.container,i=C(this.options.zIndex.value);this.position=this._calcPosition(e,t,k(i,0,e.zLayers)),this.initialPosition=this.position.copy();const s=e.canvas.size;switch(this.moveCenter={...yt(this.options.move.center,s),radius:this.options.move.center.radius??0,mode:this.options.move.center.mode??"percent"},this.direction=R(this.options.move.direction,this.position,this.moveCenter),this.options.move.direction){case"inside":this.outType="inside";break;case"outside":this.outType="outside"}this.offset=y.origin},this._engine=t,this.init(e,s,o,n)}destroy(t){if(this.unbreakable||this.destroyed)return;this.destroyed=!0,this.bubble.inRange=!1,this.slow.inRange=!1;const e=this.container,i=this.pathGenerator,s=e.shapeDrawers.get(this.shape);s&&s.particleDestroy&&s.particleDestroy(this);for(const[,i]of e.plugins)i.particleDestroyed&&i.particleDestroyed(this,t);for(const i of e.particles.updaters)i.particleDestroyed&&i.particleDestroyed(this,t);i&&i.reset(this),this._engine.dispatchEvent("particleDestroyed",{container:this.container,data:{particle:this}})}draw(t){const e=this.container,i=e.canvas;for(const[,s]of e.plugins)i.drawParticlePlugin(s,this,t);i.drawParticle(this,t)}getFillColor(){return this._getRollColor(this.bubble.color??$t(this.color))}getMass(){return this.getRadius()**2*Math.PI*.5}getPosition(){return{x:this.position.x+this.offset.x,y:this.position.y+this.offset.y,z:this.position.z}}getRadius(){return this.bubble.radius??this.size.value}getStrokeColor(){return this._getRollColor(this.bubble.color??$t(this.strokeColor))}init(t,e,i,s){const o=this.container,n=this._engine;this.id=t,this.group=s,this.effectClose=!0,this.effectFill=!0,this.shapeClose=!0,this.shapeFill=!0,this.pathRotation=!1,this.lastPathTime=0,this.destroyed=!1,this.unbreakable=!1,this.rotation=0,this.misplaced=!1,this.retina={maxDistance:{}},this.outType="normal",this.ignoresResizeRatio=!0;const a=o.retina.pixelRatio,r=o.actualOptions,c=ci(this._engine,o,r.particles),l=c.effect.type,h=c.shape.type,{reduceDuplicates:d}=c;this.effect=ut(l,this.id,d),this.shape=ut(h,this.id,d);const u=c.effect,p=c.shape;if(i){if(i.effect&&i.effect.type){const t=ut(i.effect.type,this.id,d);t&&(this.effect=t,u.load(i.effect))}if(i.shape&&i.shape.type){const t=ut(i.shape.type,this.id,d);t&&(this.shape=t,p.load(i.shape))}}this.effectData=function(t,e,i,s){const o=e.options[t];if(o)return st({close:e.close,fill:e.fill},ut(o,i,s))}(this.effect,u,this.id,d),this.shapeData=function(t,e,i,s){const o=e.options[t];if(o)return st({close:e.close,fill:e.fill},ut(o,i,s))}(this.shape,p,this.id,d),c.load(i);const f=this.effectData;f&&c.load(f.particles);const v=this.shapeData;v&&c.load(v.particles);const y=new we(n,o);y.load(o.actualOptions.interactivity),y.load(c.interactivity),this.interactivity=y,this.effectFill=f?.fill??c.effect.fill,this.effectClose=f?.close??c.effect.close,this.shapeFill=v?.fill??c.shape.fill,this.shapeClose=v?.close??c.shape.close,this.options=c;const m=this.options.move.path;this.pathDelay=1e3*C(m.delay.value),m.generator&&(this.pathGenerator=this._engine.getPathGenerator(m.generator),this.pathGenerator&&o.addPath(m.generator,this.pathGenerator)&&this.pathGenerator.init(o)),o.retina.initParticle(this),this.size=ft(this.options.size,a),this.bubble={inRange:!1},this.slow={inRange:!1,factor:1},this._initPosition(e),this.initialVelocity=this._calculateVelocity(),this.velocity=this.initialVelocity.copy(),this.moveDecay=1-C(this.options.move.decay);const g=o.particles;g.setLastZIndex(this.position.z),this.zIndexFactor=this.position.z/o.zLayers,this.sides=24;let b=o.effectDrawers.get(this.effect);b||(b=this._engine.getEffectDrawer(this.effect),b&&o.effectDrawers.set(this.effect,b)),b&&b.loadEffect&&b.loadEffect(this);let w=o.shapeDrawers.get(this.shape);w||(w=this._engine.getShapeDrawer(this.shape),w&&o.shapeDrawers.set(this.shape,w)),w&&w.loadShape&&w.loadShape(this);const x=w?.getSidesCount;x&&(this.sides=x(this)),this.spawning=!1,this.shadowColor=St(this.options.shadow.color);for(const t of g.updaters)t.init(this);for(const t of g.movers)t.init&&t.init(this);b&&b.particleInit&&b.particleInit(o,this),w&&w.particleInit&&w.particleInit(o,this);for(const[,t]of o.plugins)t.particleCreated&&t.particleCreated(this)}isInsideCanvas(){const t=this.getRadius(),e=this.container.canvas.size,i=this.position;return i.x>=-t&&i.y>=-t&&i.y<=e.height+t&&i.x<=e.width+t}isVisible(){return!this.destroyed&&!this.spawning&&this.isInsideCanvas()}reset(){for(const t of this.container.particles.updaters)t.reset&&t.reset(this)}}class pi{constructor(t,e){this.position=t,this.particle=e}}class fi{constructor(t,e){this.position={x:t,y:e}}}class vi extends fi{constructor(t,e,i,s){super(t,e),this.size={height:s,width:i}}contains(t){const e=this.size.width,i=this.size.height,s=this.position;return t.x>=s.x&&t.x<=s.x+e&&t.y>=s.y&&t.y<=s.y+i}intersects(t){t instanceof yi&&t.intersects(this);const e=this.size.width,i=this.size.height,s=this.position,o=t.position,n=t instanceof vi?t.size:{width:0,height:0},a=n.width,r=n.height;return o.xs.x&&o.ys.y}}class yi extends fi{constructor(t,e,i){super(t,e),this.radius=i}contains(t){return T(t,this.position)<=this.radius}intersects(t){const e=this.position,i=t.position,s=Math.abs(i.x-e.x),o=Math.abs(i.y-e.y),n=this.radius;if(t instanceof yi){return n+t.radius>Math.sqrt(s**2+o**2)}if(t instanceof vi){const{width:e,height:i}=t.size;return Math.pow(s-e,2)+Math.pow(o-i,2)<=n**2||s<=n+e&&o<=n+i||s<=e||o<=i}return!1}}class mi{constructor(t,e){this.rectangle=t,this.capacity=e,this._subdivide=()=>{const{x:t,y:e}=this.rectangle.position,{width:i,height:s}=this.rectangle.size,{capacity:o}=this;for(let n=0;n<4;n++)this._subs.push(new mi(new vi(t+.5*i*(n%2),e+.5*s*(Math.round(.5*n)-n%2),.5*i,.5*s),o));this._divided=!0},this._points=[],this._divided=!1,this._subs=[]}insert(t){return!!this.rectangle.contains(t.position)&&(this._points.lengthe.insert(t)))))}query(t,e,i){const s=i||[];if(!t.intersects(this.rectangle))return[];for(const i of this._points)!t.contains(i.position)&&T(t.position,i.position)>i.particle.getRadius()&&(!e||e(i.particle))||s.push(i.particle);if(this._divided)for(const i of this._subs)i.query(t,e,s);return s}queryCircle(t,e,i){return this.query(new yi(t.x,t.y,e),i)}queryRectangle(t,e,i){return this.query(new vi(t.x,t.y,e.width,e.height),i)}}const gi=t=>{const{height:e,width:i}=t;return new vi(-.25*i,-.25*e,1.5*i,1.5*e)};class bi{constructor(t,e){this._addToPool=(...t)=>{for(const e of t)this._pool.push(e)},this._applyDensity=(t,e,i)=>{const s=t.number;if(!t.number.density?.enable)return void(void 0===i?this._limit=s.limit.value:s.limit&&this._groupLimits.set(i,s.limit.value));const o=this._initDensityFactor(s.density),n=s.value,a=s.limit.value>0?s.limit.value:n,r=Math.min(n,a)*o+e,c=Math.min(this.count,this.filter((t=>t.group===i)).length);void 0===i?this._limit=s.limit.value*o:this._groupLimits.set(i,s.limit.value*o),cr&&this.removeQuantity(c-r,i)},this._initDensityFactor=t=>{const e=this._container;if(!e.canvas.element||!t.enable)return 1;const i=e.canvas.element,s=e.retina.pixelRatio;return i.width*i.height/(t.height*t.width*s**2)},this._pushParticle=(t,e,i,s)=>{try{let o=this._pool.pop();o?o.init(this._nextId,t,e,i):o=new ui(this._engine,this._nextId,this._container,t,e,i);let n=!0;if(s&&(n=s(o)),!n)return;return this._array.push(o),this._zArray.push(o),this._nextId++,this._engine.dispatchEvent("particleAdded",{container:this._container,data:{particle:o}}),o}catch(t){return void W().warning(`${f} adding particle: ${t}`)}},this._removeParticle=(t,e,i)=>{const s=this._array[t];if(!s||s.group!==e)return!1;const o=this._zArray.indexOf(s);return this._array.splice(t,1),this._zArray.splice(o,1),s.destroy(i),this._engine.dispatchEvent("particleRemoved",{container:this._container,data:{particle:s}}),this._addToPool(s),!0},this._engine=t,this._container=e,this._nextId=0,this._array=[],this._zArray=[],this._pool=[],this._limit=0,this._groupLimits=new Map,this._needsSort=!1,this._lastZIndex=0,this._interactionManager=new hi(t,e);const i=e.canvas.size;this.quadTree=new mi(gi(i),4),this.movers=this._engine.getMovers(e,!0),this.updaters=this._engine.getUpdaters(e,!0)}get count(){return this._array.length}addManualParticles(){const t=this._container,e=t.actualOptions;for(const i of e.manualParticles)this.addParticle(i.position?yt(i.position,t.canvas.size):void 0,i.options)}addParticle(t,e,i,s){const o=this._container.actualOptions.particles.number.limit,n=void 0===i?this._limit:this._groupLimits.get(i)??this._limit,a=this.count;if(n>0)if("delete"===o.mode){const t=a+1-n;t>0&&this.removeQuantity(t)}else if("wait"===o.mode&&a>=n)return;return this._pushParticle(t,e,i,s)}clear(){this._array=[],this._zArray=[]}destroy(){this._array=[],this._zArray=[],this.movers=[],this.updaters=[]}async draw(t){const e=this._container,i=e.canvas;i.clear(),await this.update(t);for(const[,s]of e.plugins)i.drawPlugin(s,t);for(const e of this._zArray)e.draw(t)}filter(t){return this._array.filter(t)}find(t){return this._array.find(t)}get(t){return this._array[t]}handleClickMode(t){this._interactionManager.handleClickMode(t)}init(){const t=this._container,e=t.actualOptions;this._lastZIndex=0,this._needsSort=!1;let i=!1;this.updaters=this._engine.getUpdaters(t,!0),this._interactionManager.init();for(const[,e]of t.plugins)if(void 0!==e.particlesInitialization&&(i=e.particlesInitialization()),i)break;this._interactionManager.init();for(const[,e]of t.pathGenerators)e.init(t);if(this.addManualParticles(),!i){const t=e.particles,i=t.groups;for(const e in i){const s=i[e];for(let i=this.count,o=0;othis.count)return;let o=0;for(let n=t;o!i.has(t);this._array=this.filter(t),this._zArray=this._zArray.filter(t);for(const t of i)this._engine.dispatchEvent("particleRemoved",{container:this._container,data:{particle:t}});this._addToPool(...i)}await this._interactionManager.externalInteract(t);for(const e of this._array){for(const i of this.updaters)i.update(e,t);e.destroyed||e.spawning||await this._interactionManager.particlesInteract(e,t)}if(delete this._resizeFactor,this._needsSort){const t=this._zArray;t.sort(((t,e)=>e.position.z-t.position.z||t.id-e.id)),this._lastZIndex=t[t.length-1].position.z,this._needsSort=!1}}}class wi{constructor(t){this.container=t,this.pixelRatio=1,this.reduceFactor=1}init(){const t=this.container,e=t.actualOptions;this.pixelRatio=!e.detectRetina||j()?1:window.devicePixelRatio,this.reduceFactor=1;const i=this.pixelRatio,s=t.canvas;if(s.element){const t=s.element;s.size.width=t.offsetWidth*i,s.size.height=t.offsetHeight*i}const o=e.particles,n=o.move;this.maxSpeed=C(n.gravity.maxSpeed)*i,this.sizeAnimationSpeed=C(o.size.animation.speed)*i}initParticle(t){const e=t.options,i=this.pixelRatio,s=e.move,o=s.distance,n=t.retina;n.moveDrift=C(s.drift)*i,n.moveSpeed=C(s.speed)*i,n.sizeAnimationSpeed=C(e.size.animation.speed)*i;const a=n.maxDistance;a.horizontal=void 0!==o.horizontal?o.horizontal*i:void 0,a.vertical=void 0!==o.vertical?o.vertical*i:void 0,n.maxSpeed=C(s.gravity.maxSpeed)*i}}function xi(t){return t&&!t.destroyed}function _i(t,e,...i){const s=new li(t,e);return ri(s,...i),s}class ki{constructor(t,e,i){this._intersectionManager=t=>{if(xi(this)&&this.actualOptions.pauseOnOutsideViewport)for(const e of t)e.target===this.interactivity.element&&(e.isIntersecting?this.play:this.pause)()},this._nextFrame=async t=>{try{if(!this._smooth&&void 0!==this._lastFrameTime&&t1e3)return void this.draw(!1);if(await this.particles.draw(e),!this.alive())return void this.destroy();this.getAnimationStatus()&&this.draw(!1)}catch(t){W().error(`${f} in animation loop`,t)}},this._engine=t,this.id=Symbol(e),this.fpsLimit=120,this._smooth=!1,this._delay=0,this._duration=0,this._lifeTime=0,this._firstStart=!0,this.started=!1,this.destroyed=!1,this._paused=!0,this._lastFrameTime=0,this.zLayers=100,this.pageHidden=!1,this._sourceOptions=i,this._initialSourceOptions=i,this.retina=new wi(this),this.canvas=new ne(this),this.particles=new bi(this._engine,this),this.pathGenerators=new Map,this.interactivity={mouse:{clicking:!1,inside:!1}},this.plugins=new Map,this.effectDrawers=new Map,this.shapeDrawers=new Map,this._options=_i(this._engine,this),this.actualOptions=_i(this._engine,this),this._eventListeners=new re(this),this._intersectionObserver=X((t=>this._intersectionManager(t))),this._engine.dispatchEvent("containerBuilt",{container:this})}get options(){return this._options}get sourceOptions(){return this._sourceOptions}addClickHandler(t){if(!xi(this))return;const e=this.interactivity.element;if(!e)return;const i=(e,i,s)=>{if(!xi(this))return;const o=this.retina.pixelRatio,n={x:i.x*o,y:i.y*o},a=this.particles.quadTree.queryCircle(n,s*o);t(e,a)};let s=!1,o=!1;e.addEventListener("click",(t=>{if(!xi(this))return;const e=t,s={x:e.offsetX||e.clientX,y:e.offsetY||e.clientY};i(t,s,1)})),e.addEventListener("touchstart",(()=>{xi(this)&&(s=!0,o=!1)})),e.addEventListener("touchmove",(()=>{xi(this)&&(o=!0)})),e.addEventListener("touchend",(t=>{if(xi(this)){if(s&&!o){const e=t;let s=e.touches[e.touches.length-1];if(!s&&(s=e.changedTouches[e.changedTouches.length-1],!s))return;const o=this.canvas.element,n=o?o.getBoundingClientRect():void 0,a={x:s.clientX-(n?n.left:0),y:s.clientY-(n?n.top:0)};i(t,a,Math.max(s.radiusX,s.radiusY))}s=!1,o=!1}})),e.addEventListener("touchcancel",(()=>{xi(this)&&(s=!1,o=!1)}))}addLifeTime(t){this._lifeTime+=t}addPath(t,e,i=!1){return!(!xi(this)||!i&&this.pathGenerators.has(t))&&(this.pathGenerators.set(t,e),!0)}alive(){return!this._duration||this._lifeTime<=this._duration}destroy(){if(!xi(this))return;this.stop(),this.particles.destroy(),this.canvas.destroy();for(const[,t]of this.effectDrawers)t.destroy&&t.destroy(this);for(const[,t]of this.shapeDrawers)t.destroy&&t.destroy(this);for(const t of this.effectDrawers.keys())this.effectDrawers.delete(t);for(const t of this.shapeDrawers.keys())this.shapeDrawers.delete(t);this._engine.clearPlugins(this),this.destroyed=!0;const t=this._engine.dom(),e=t.findIndex((t=>t===this));e>=0&&t.splice(e,1),this._engine.dispatchEvent("containerDestroyed",{container:this})}draw(t){if(!xi(this))return;let e=t;this._drawAnimationFrame=requestAnimationFrame((async t=>{e&&(this._lastFrameTime=void 0,e=!1),await this._nextFrame(t)}))}async export(t,e={}){for(const[,i]of this.plugins){if(!i.export)continue;const s=await i.export(t,e);if(s.supported)return s.blob}W().error(`${f} - Export plugin with type ${t} not found`)}getAnimationStatus(){return!this._paused&&!this.pageHidden&&xi(this)}handleClickMode(t){if(xi(this)){this.particles.handleClickMode(t);for(const[,e]of this.plugins)e.handleClickMode&&e.handleClickMode(t)}}async init(){if(!xi(this))return;const t=this._engine.getSupportedEffects();for(const e of t){const t=this._engine.getEffectDrawer(e);t&&this.effectDrawers.set(e,t)}const e=this._engine.getSupportedShapes();for(const t of e){const e=this._engine.getShapeDrawer(t);e&&this.shapeDrawers.set(t,e)}this._options=_i(this._engine,this,this._initialSourceOptions,this.sourceOptions),this.actualOptions=_i(this._engine,this,this._options);const i=this._engine.getAvailablePlugins(this);for(const[t,e]of i)this.plugins.set(t,e);this.retina.init(),await this.canvas.init(),this.updateActualOptions(),this.canvas.initBackground(),this.canvas.resize(),this.zLayers=this.actualOptions.zLayers,this._duration=1e3*C(this.actualOptions.duration),this._delay=1e3*C(this.actualOptions.delay),this._lifeTime=0,this.fpsLimit=this.actualOptions.fpsLimit>0?this.actualOptions.fpsLimit:120,this._smooth=this.actualOptions.smooth;for(const[,t]of this.effectDrawers)t.init&&await t.init(this);for(const[,t]of this.shapeDrawers)t.init&&await t.init(this);for(const[,t]of this.plugins)t.init&&await t.init();this._engine.dispatchEvent("containerInit",{container:this}),this.particles.init(),this.particles.setDensity();for(const[,t]of this.plugins)t.particlesSetup&&t.particlesSetup();this._engine.dispatchEvent("particlesSetup",{container:this})}async loadTheme(t){xi(this)&&(this._currentTheme=t,await this.refresh())}pause(){if(xi(this)&&(void 0!==this._drawAnimationFrame&&(cancelAnimationFrame(this._drawAnimationFrame),delete this._drawAnimationFrame),!this._paused)){for(const[,t]of this.plugins)t.pause&&t.pause();this.pageHidden||(this._paused=!0),this._engine.dispatchEvent("containerPaused",{container:this})}}play(t){if(!xi(this))return;const e=this._paused||t;if(!this._firstStart||this.actualOptions.autoPlay){if(this._paused&&(this._paused=!1),e)for(const[,t]of this.plugins)t.play&&t.play();this._engine.dispatchEvent("containerPlay",{container:this}),this.draw(e||!1)}else this._firstStart=!1}async refresh(){if(xi(this))return this.stop(),this.start()}async reset(){if(xi(this))return this._initialSourceOptions=void 0,this._options=_i(this._engine,this),this.actualOptions=_i(this._engine,this,this._options),this.refresh()}async start(){xi(this)&&!this.started&&(await this.init(),this.started=!0,await new Promise((t=>{this._delayTimeout=setTimeout((async()=>{this._eventListeners.addListeners(),this.interactivity.element instanceof HTMLElement&&this._intersectionObserver&&this._intersectionObserver.observe(this.interactivity.element);for(const[,t]of this.plugins)t.start&&await t.start();this._engine.dispatchEvent("containerStarted",{container:this}),this.play(),t()}),this._delay)})))}stop(){if(xi(this)&&this.started){this._delayTimeout&&(clearTimeout(this._delayTimeout),delete this._delayTimeout),this._firstStart=!0,this.started=!1,this._eventListeners.removeListeners(),this.pause(),this.particles.clear(),this.canvas.stop(),this.interactivity.element instanceof HTMLElement&&this._intersectionObserver&&this._intersectionObserver.unobserve(this.interactivity.element);for(const[,t]of this.plugins)t.stop&&t.stop();for(const t of this.plugins.keys())this.plugins.delete(t);this._sourceOptions=this._options,this._engine.dispatchEvent("containerStopped",{container:this})}}updateActualOptions(){this.actualOptions.responsive=[];const t=this.actualOptions.setResponsive(this.canvas.size.width,this.retina.pixelRatio,this._options);return this.actualOptions.setTheme(this._currentTheme),this._responsiveMaxWidth!==t&&(this._responsiveMaxWidth=t,!0)}}class zi{constructor(){this._listeners=new Map}addEventListener(t,e){this.removeEventListener(t,e);let i=this._listeners.get(t);i||(i=[],this._listeners.set(t,i)),i.push(e)}dispatchEvent(t,e){const i=this._listeners.get(t);i&&i.forEach((t=>t(e)))}hasEventListener(t){return!!this._listeners.get(t)}removeAllEventListeners(t){t?this._listeners.delete(t):this._listeners=new Map}removeEventListener(t,e){const i=this._listeners.get(t);if(!i)return;const s=i.length,o=i.indexOf(e);o<0||(1===s?this._listeners.delete(t):i.splice(o,1))}}function Mi(t,e,i,s=!1){let o=e.get(t);return o&&!s||(o=[...i.values()].map((e=>e(t))),e.set(t,o)),o}class Ci{constructor(){this._configs=new Map,this._domArray=[],this._eventDispatcher=new zi,this._initialized=!1,this.plugins=[],this._initializers={interactors:new Map,movers:new Map,updaters:new Map},this.interactors=new Map,this.movers=new Map,this.updaters=new Map,this.presets=new Map,this.effectDrawers=new Map,this.shapeDrawers=new Map,this.pathGenerators=new Map}get configs(){const t={};for(const[e,i]of this._configs)t[e]=i;return t}get version(){return"3.0.2"}addConfig(t){const e=t.name??"default";this._configs.set(e,t),this._eventDispatcher.dispatchEvent("configAdded",{data:{name:e,config:t}})}async addEffect(t,e,i=!0){dt(t,(t=>{!this.getEffectDrawer(t)&&this.effectDrawers.set(t,e)})),await this.refresh(i)}addEventListener(t,e){this._eventDispatcher.addEventListener(t,e)}async addInteractor(t,e,i=!0){this._initializers.interactors.set(t,e),await this.refresh(i)}async addMover(t,e,i=!0){this._initializers.movers.set(t,e),await this.refresh(i)}async addParticleUpdater(t,e,i=!0){this._initializers.updaters.set(t,e),await this.refresh(i)}async addPathGenerator(t,e,i=!0){!this.getPathGenerator(t)&&this.pathGenerators.set(t,e),await this.refresh(i)}async addPlugin(t,e=!0){!this.getPlugin(t.id)&&this.plugins.push(t),await this.refresh(e)}async addPreset(t,e,i=!1,s=!0){(i||!this.getPreset(t))&&this.presets.set(t,e),await this.refresh(s)}async addShape(t,e,i=!0){dt(t,(t=>{!this.getShapeDrawer(t)&&this.shapeDrawers.set(t,e)})),await this.refresh(i)}clearPlugins(t){this.updaters.delete(t),this.movers.delete(t),this.interactors.delete(t)}dispatchEvent(t,e){this._eventDispatcher.dispatchEvent(t,e)}dom(){return this._domArray}domItem(t){const e=this.dom(),i=e[t];if(i&&!i.destroyed)return i;e.splice(t,1)}getAvailablePlugins(t){const e=new Map;for(const i of this.plugins)i.needsPlugin(t.actualOptions)&&e.set(i.id,i.getPlugin(t));return e}getEffectDrawer(t){return this.effectDrawers.get(t)}getInteractors(t,e=!1){return Mi(t,this.interactors,this._initializers.interactors,e)}getMovers(t,e=!1){return Mi(t,this.movers,this._initializers.movers,e)}getPathGenerator(t){return this.pathGenerators.get(t)}getPlugin(t){return this.plugins.find((e=>e.id===t))}getPreset(t){return this.presets.get(t)}getShapeDrawer(t){return this.shapeDrawers.get(t)}getSupportedEffects(){return this.effectDrawers.keys()}getSupportedShapes(){return this.shapeDrawers.keys()}getUpdaters(t,e=!1){return Mi(t,this.updaters,this._initializers.updaters,e)}init(){this._initialized||(this._initialized=!0)}async load(t){const e=t.id??`tsparticles${Math.floor(1e4*_())}`,{index:s,url:o}=t,n=o?await async function(t){const e=ut(t.url,t.index);if(!e)return t.fallback;const i=await fetch(e);return i.ok?i.json():(W().error(`${f} ${i.status} while retrieving config file`),t.fallback)}({fallback:t.options,url:o,index:s}):t.options;let a=t.element??document.getElementById(e);a||(a=document.createElement("div"),a.id=e,document.body.append(a));const r=ut(n,s),c=this.dom(),l=c.findIndex((t=>t.id.description===e));if(l>=0){const t=this.domItem(l);t&&!t.destroyed&&(t.destroy(),c.splice(l,1))}let h;if("canvas"===a.tagName.toLowerCase())h=a,h.dataset[i]="false";else{const t=a.getElementsByTagName("canvas");t.length?(h=t[0],h.dataset[i]="false"):(h=document.createElement("canvas"),h.dataset[i]="true",a.appendChild(h))}h.style.width||(h.style.width="100%"),h.style.height||(h.style.height="100%");const d=new ki(this,e,r);return l>=0?c.splice(l,0,d):c.push(d),d.canvas.loadCanvas(h),await d.start(),d}loadOptions(t,e){for(const i of this.plugins)i.loadOptions(t,e)}loadParticlesOptions(t,e,...i){const s=this.updaters.get(t);if(s)for(const t of s)t.loadOptions&&t.loadOptions(e,...i)}async refresh(t=!0){t&&this.dom().forEach((t=>t.refresh()))}removeEventListener(t,e){this._eventDispatcher.removeEventListener(t,e)}setOnClickHandler(t){const e=this.dom();if(!e.length)throw new Error(`${f} can only set click handlers after calling tsParticles.load()`);for(const i of e)i.addClickHandler(t)}}class Pi{constructor(){this.key="hsl",this.stringPrefix="hsl"}handleColor(t){const e=t.value.hsl??t.value;if(void 0!==e.h&&void 0!==e.s&&void 0!==e.l)return At(e)}handleRangeColor(t){const e=t.value.hsl??t.value;if(void 0!==e.h&&void 0!==e.l)return At({h:C(e.h),l:C(e.l),s:C(e.s)})}parseString(t){if(!t.startsWith("hsl"))return;const e=/hsla?\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*(,\s*([\d.%]+)\s*)?\)/i.exec(t);return e?Ft({a:e.length>4?H(e[5]):1,h:parseInt(e[1],10),l:parseInt(e[3],10),s:parseInt(e[2],10)}):void 0}}class Oi{constructor(){this.key="rgb",this.stringPrefix="rgb"}handleColor(t){const e=t.value.rgb??t.value;if(void 0!==e.r)return e}handleRangeColor(t){const e=t.value.rgb??t.value;if(void 0!==e.r)return{r:C(e.r),g:C(e.g),b:C(e.b)}}parseString(t){if(!t.startsWith(this.stringPrefix))return;const e=/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([\d.%]+)\s*)?\)/i.exec(t);return e?{a:e.length>4?H(e[5]):1,b:parseInt(e[3],10),g:parseInt(e[2],10),r:parseInt(e[1],10)}:void 0}}class Si{constructor(t){this.container=t,this.type="external"}}class Di{constructor(t){this.container=t,this.type="particles"}}const Ti=function(){const t=new Oi,e=new Pi;Pt(t),Pt(e);const i=new Ci;return i.init(),i}();j()||(window.tsParticles=Ti);class Ri{constructor(){this.radius=0,this.mass=0}load(t){t&&(void 0!==t.mass&&(this.mass=t.mass),void 0!==t.radius&&(this.radius=t.radius))}}class Ei extends Re{constructor(){super(),this.density=5,this.value=50,this.limit=new Ri}load(t){t&&(super.load(t),void 0!==t.density&&(this.density=t.density),wt(t.limit)?this.limit.radius=t.limit:this.limit.load(t.limit))}}class Ii{constructor(){this.color=new ce,this.color.value="#000000",this.draggable=!1,this.opacity=1,this.destroy=!0,this.orbits=!1,this.size=new Ei}load(t){void 0!==t&&(void 0!==t.color&&(this.color=ce.create(this.color,t.color)),void 0!==t.draggable&&(this.draggable=t.draggable),this.name=t.name,void 0!==t.opacity&&(this.opacity=t.opacity),void 0!==t.position&&(this.position={},void 0!==t.position.x&&(this.position.x=S(t.position.x)),void 0!==t.position.y&&(this.position.y=S(t.position.y))),void 0!==t.size&&this.size.load(t.size),void 0!==t.destroy&&(this.destroy=t.destroy),void 0!==t.orbits&&(this.orbits=t.orbits))}}class Li{constructor(t,e,i,s){this.absorbers=t,this.container=e,this._calcPosition=()=>{const t=F({size:this.container.canvas.size,position:this.options.position});return y.create(t.x,t.y)},this._updateParticlePosition=(t,e)=>{if(t.destroyed)return;const i=this.container,s=i.canvas.size;if(t.needsNewPosition){const e=A({size:s});t.position.setTo(e),t.velocity.setTo(t.initialVelocity),t.absorberOrbit=void 0,t.needsNewPosition=!1}if(this.options.orbits){if(void 0===t.absorberOrbit&&(t.absorberOrbit=y.create(0,0),t.absorberOrbit.length=T(t.getPosition(),this.position),t.absorberOrbit.angle=_()*Math.PI*2),t.absorberOrbit.length<=this.size&&!this.options.destroy){const e=Math.min(s.width,s.height);t.absorberOrbit.length=e*(.2*_()-.1+1)}void 0===t.absorberOrbitDirection&&(t.absorberOrbitDirection=t.velocity.x>=0?"clockwise":"counter-clockwise");const o=t.absorberOrbit.length,n=t.absorberOrbit.angle,a=t.absorberOrbitDirection;t.velocity.setTo(y.origin);const r={x:"clockwise"===a?Math.cos:Math.sin,y:"clockwise"===a?Math.sin:Math.cos};t.position.x=this.position.x+o*r.x(n),t.position.y=this.position.y+o*r.y(n),t.absorberOrbit.length-=e.length,t.absorberOrbit.angle+=(t.retina.moveSpeed??0)*i.retina.pixelRatio/100*i.retina.reduceFactor}else{const i=y.origin;i.length=e.length,i.angle=e.angle,t.velocity.addTo(i)}},this.initialPosition=s?y.create(s.x,s.y):void 0,i instanceof Ii?this.options=i:(this.options=new Ii,this.options.load(i)),this.dragging=!1,this.name=this.options.name,this.opacity=this.options.opacity,this.size=C(this.options.size.value)*e.retina.pixelRatio,this.mass=this.size*this.options.size.density*e.retina.reduceFactor;const o=this.options.size.limit;this.limit={radius:o.radius*e.retina.pixelRatio*e.retina.reduceFactor,mass:o.mass},this.color=St(this.options.color)??{b:0,g:0,r:0},this.position=this.initialPosition?.copy()??this._calcPosition()}attract(t){const e=this.container,i=this.options;if(i.draggable){const t=e.interactivity.mouse;if(t.clicking&&t.downPosition){T(this.position,t.downPosition)<=this.size&&(this.dragging=!0)}else this.dragging=!1;this.dragging&&t.position&&(this.position.x=t.position.x,this.position.y=t.position.y)}const s=t.getPosition(),{dx:o,dy:n,distance:a}=D(this.position,s),r=y.create(o,n);if(r.length=this.mass/Math.pow(a,2)*e.retina.reduceFactor,at.getRadius()&&avoid 0===t||wt(t)?this.array[t||0]:this.array.find((e=>e.name===t)),t.addAbsorber=(t,e)=>this.addAbsorber(t,e)}addAbsorber(t,e){const i=new Li(this,this.container,t,e);return this.array.push(i),i}draw(t){for(const e of this.array)e.draw(t)}handleClickMode(t){const e=this.absorbers,i=this.interactivityAbsorbers;if("absorber"===t){const t=ut(i)??ut(e),s=this.container.interactivity.mouse.clickPosition;this.addAbsorber(t,s)}}async init(){this.absorbers=this.container.actualOptions.absorbers,this.interactivityAbsorbers=this.container.actualOptions.interactivity.modes.absorbers,dt(this.absorbers,(t=>{this.addAbsorber(t)}))}particleUpdate(t){for(const e of this.array)if(e.attract(t),t.destroyed)break}removeAbsorber(t){const e=this.array.indexOf(t);e>=0&&this.array.splice(e,1)}resize(){for(const t of this.array)t.resize()}stop(){this.array=[]}}class Fi{constructor(){this.id="absorbers"}getPlugin(t){return new Ai(t)}loadOptions(t,e){(this.needsPlugin(t)||this.needsPlugin(e))&&(e?.absorbers&&(t.absorbers=dt(e.absorbers,(t=>{const e=new Ii;return e.load(t),e}))),t.interactivity.modes.absorbers=dt(e?.interactivity?.modes?.absorbers,(t=>{const e=new Ii;return e.load(t),e})))}needsPlugin(t){if(!t)return!1;const e=t.absorbers;return kt(e)?!!e.length:!!e||!(!t.interactivity?.events?.onClick?.mode||!Z("absorber",t.interactivity.events.onClick.mode))}}class Bi{load(t){t&&(void 0!==t.bottom&&(this.bottom=S(t.bottom)),void 0!==t.left&&(this.left=S(t.left)),void 0!==t.right&&(this.right=S(t.right)),void 0!==t.top&&(this.top=S(t.top)))}}class qi extends Re{constructor(){super(),this.value=3}}class Hi extends Re{constructor(){super(),this.value={min:4,max:9}}}class Vi{constructor(){this.count=1,this.factor=new qi,this.rate=new Hi,this.sizeOffset=!0}load(t){t&&(void 0!==t.color&&(this.color=ce.create(this.color,t.color)),void 0!==t.count&&(this.count=t.count),this.factor.load(t.factor),this.rate.load(t.rate),this.particles=dt(t.particles,(t=>st({},t))),void 0!==t.sizeOffset&&(this.sizeOffset=t.sizeOffset),t.colorOffset&&(this.colorOffset=this.colorOffset??{},void 0!==t.colorOffset.h&&(this.colorOffset.h=t.colorOffset.h),void 0!==t.colorOffset.s&&(this.colorOffset.s=t.colorOffset.s),void 0!==t.colorOffset.l&&(this.colorOffset.l=t.colorOffset.l)))}}class Ui{constructor(){this.bounds=new Bi,this.mode="none",this.split=new Vi}load(t){t&&(t.mode&&(this.mode=t.mode),t.bounds&&this.bounds.load(t.bounds),this.split.load(t.split))}}function Wi(t,e,i,s){const o=i.options.destroy;if(!o)return;const n=o.split,a=ci(t,e,i.options),r=C(n.factor.value),c=i.getFillColor();n.color?a.color.load(n.color):n.colorOffset&&c?a.color.load({value:{hsl:{h:c.h+C(n.colorOffset.h??0),s:c.s+C(n.colorOffset.s??0),l:c.l+C(n.colorOffset.l??0)}}}):a.color.load({value:{hsl:i.getFillColor()}}),a.move.load({center:{x:i.position.x,y:i.position.y,mode:"precise"}}),wt(a.size.value)?a.size.value/=r:(a.size.value.min/=r,a.size.value.max/=r),a.load(s);const l=n.sizeOffset?S(-i.size.value,i.size.value):0,h={x:i.position.x+M(l),y:i.position.y+M(l)};return e.particles.addParticle(h,a,i.group,(t=>!(t.size.value<.5)&&(t.velocity.length=M(S(i.velocity.length,t.velocity.length)),t.splitCount=(i.splitCount??0)+1,t.unbreakable=!0,setTimeout((()=>{t.unbreakable=!1}),500),!0)))}class $i{constructor(t,e){this.engine=t,this.container=e}init(t){const e=this.container,i=t.options.destroy;if(!i)return;t.splitCount=0;const s=i.bounds;t.destroyBounds||(t.destroyBounds={});const{bottom:o,left:n,right:a,top:r}=s,{destroyBounds:c}=t,l=e.canvas.size;o&&(c.bottom=C(o)*l.height/100),n&&(c.left=C(n)*l.width/100),a&&(c.right=C(a)*l.width/100),r&&(c.top=C(r)*l.height/100)}isEnabled(t){return!t.destroyed}loadOptions(t,...e){t.destroy||(t.destroy=new Ui);for(const i of e)t.destroy.load(i?.destroy)}particleDestroyed(t,e){if(e)return;const i=t.options.destroy;i&&"split"===i.mode&&function(t,e,i){const s=i.options.destroy;if(!s)return;const o=s.split;if(o.count>=0&&(void 0===i.splitCount||i.splitCount++>o.count))return;const n=C(o.rate.value),a=ut(o.particles);for(let s=0;s=i.bottom||void 0!==i.left&&e.x<=i.left||void 0!==i.right&&e.x>=i.right||void 0!==i.top&&e.y<=i.top)&&t.destroy()}}class ji{constructor(){this.wait=!1}load(t){t&&(void 0!==t.count&&(this.count=t.count),void 0!==t.delay&&(this.delay=S(t.delay)),void 0!==t.duration&&(this.duration=S(t.duration)),void 0!==t.wait&&(this.wait=t.wait))}}class Gi{constructor(){this.quantity=1,this.delay=.1}load(t){void 0!==t&&(void 0!==t.quantity&&(this.quantity=S(t.quantity)),void 0!==t.delay&&(this.delay=S(t.delay)))}}class Ni{constructor(){this.color=!1,this.opacity=!1}load(t){t&&(void 0!==t.color&&(this.color=t.color),void 0!==t.opacity&&(this.opacity=t.opacity))}}class Xi{constructor(){this.options={},this.replace=new Ni,this.type="square"}load(t){t&&(void 0!==t.options&&(this.options=st({},t.options??{})),this.replace.load(t.replace),void 0!==t.type&&(this.type=t.type))}}class Yi{constructor(){this.mode="percent",this.height=0,this.width=0}load(t){void 0!==t&&(void 0!==t.mode&&(this.mode=t.mode),void 0!==t.height&&(this.height=t.height),void 0!==t.width&&(this.width=t.width))}}class Zi{constructor(){this.autoPlay=!0,this.fill=!0,this.life=new ji,this.rate=new Gi,this.shape=new Xi,this.startCount=0}load(t){t&&(void 0!==t.autoPlay&&(this.autoPlay=t.autoPlay),void 0!==t.size&&(this.size||(this.size=new Yi),this.size.load(t.size)),void 0!==t.direction&&(this.direction=t.direction),this.domId=t.domId,void 0!==t.fill&&(this.fill=t.fill),this.life.load(t.life),this.name=t.name,this.particles=dt(t.particles,(t=>st({},t))),this.rate.load(t.rate),this.shape.load(t.shape),void 0!==t.position&&(this.position={},void 0!==t.position.x&&(this.position.x=S(t.position.x)),void 0!==t.position.y&&(this.position.y=S(t.position.y))),void 0!==t.spawnColor&&(void 0===this.spawnColor&&(this.spawnColor=new Se),this.spawnColor.load(t.spawnColor)),void 0!==t.startCount&&(this.startCount=t.startCount))}}function Qi(t,e){t.color?t.color.value=e:t.color={value:e}}class Ji{constructor(t,e,i,s,o){this.emitters=e,this.container=i,this._destroy=()=>{this._mutationObserver?.disconnect(),this._mutationObserver=void 0,this._resizeObserver?.disconnect(),this._resizeObserver=void 0,this.emitters.removeEmitter(this),this._engine.dispatchEvent("emitterDestroyed",{container:this.container,data:{emitter:this}})},this._prepareToDie=()=>{if(this._paused)return;const t=void 0!==this.options.life?.duration?C(this.options.life.duration):void 0;this.container.retina.reduceFactor&&(this._lifeCount>0||this._immortal)&&void 0!==t&&t>0&&(this._duration=1e3*t)},this._setColorAnimation=(t,e,i)=>{const s=this.container;if(!t.enable)return e;const o=M(t.offset),n=1e3*C(this.options.rate.delay)/s.retina.reduceFactor;return(e+C(t.speed??0)*s.fpsLimit/n+3.6*o)%i},this._engine=t,this._currentDuration=0,this._currentEmitDelay=0,this._currentSpawnDelay=0,this._initialPosition=o,s instanceof Zi?this.options=s:(this.options=new Zi,this.options.load(s)),this._spawnDelay=1e3*C(this.options.life.delay??0)/this.container.retina.reduceFactor,this.position=this._initialPosition??this._calcPosition(),this.name=this.options.name,this.fill=this.options.fill,this._firstSpawn=!this.options.life.wait,this._startParticlesAdded=!1;let n=st({},this.options.particles);if(n??={},n.move??={},n.move.direction??=this.options.direction,this.options.spawnColor&&(this.spawnColor=Rt(this.options.spawnColor)),this._paused=!this.options.autoPlay,this._particlesOptions=n,this._size=this._calcSize(),this.size=mt(this._size,this.container.canvas.size),this._lifeCount=this.options.life.count??-1,this._immortal=this._lifeCount<=0,this.options.domId){const t=document.getElementById(this.options.domId);t&&(this._mutationObserver=new MutationObserver((()=>{this.resize()})),this._resizeObserver=new ResizeObserver((()=>{this.resize()})),this._mutationObserver.observe(t,{attributes:!0,attributeFilter:["style","width","height"]}),this._resizeObserver.observe(t))}const a=this.options.shape,r=this._engine.emitterShapeManager?.getShapeGenerator(a.type);r&&(this._shape=r.generate(this.position,this.size,this.fill,a.options)),this._engine.dispatchEvent("emitterCreated",{container:i,data:{emitter:this}}),this.play()}externalPause(){this._paused=!0,this.pause()}externalPlay(){this._paused=!1,this.play()}async init(){await(this._shape?.init())}pause(){this._paused||delete this._emitDelay}play(){if(!this._paused&&this.container.retina.reduceFactor&&(this._lifeCount>0||this._immortal||!this.options.life.count)&&(this._firstSpawn||this._currentSpawnDelay>=(this._spawnDelay??0))){if(void 0===this._emitDelay){const t=C(this.options.rate.delay);this._emitDelay=1e3*t/this.container.retina.reduceFactor}(this._lifeCount>0||this._immortal)&&this._prepareToDie()}}resize(){const t=this._initialPosition;this.position=t&&tt(t,this.container.canvas.size,y.origin)?t:this._calcPosition(),this._size=this._calcSize(),this.size=mt(this._size,this.container.canvas.size),this._shape?.resize(this.position,this.size)}async update(t){this._paused||(this._firstSpawn&&(this._firstSpawn=!1,this._currentSpawnDelay=this._spawnDelay??0,this._currentEmitDelay=this._emitDelay??0),this._startParticlesAdded||(this._startParticlesAdded=!0,await this._emitParticles(this.options.startCount)),void 0!==this._duration&&(this._currentDuration+=t.value,this._currentDuration>=this._duration&&(this.pause(),void 0!==this._spawnDelay&&delete this._spawnDelay,this._immortal||this._lifeCount--,this._lifeCount>0||this._immortal?(this.position=this._calcPosition(),this._shape?.resize(this.position,this.size),this._spawnDelay=1e3*C(this.options.life.delay??0)/this.container.retina.reduceFactor):this._destroy(),this._currentDuration-=this._duration,delete this._duration)),void 0!==this._spawnDelay&&(this._currentSpawnDelay+=t.value,this._currentSpawnDelay>=this._spawnDelay&&(this._engine.dispatchEvent("emitterPlay",{container:this.container}),this.play(),this._currentSpawnDelay-=this._currentSpawnDelay,delete this._spawnDelay)),void 0!==this._emitDelay&&(this._currentEmitDelay+=t.value,this._currentEmitDelay>=this._emitDelay&&(this._emit(),this._currentEmitDelay-=this._emitDelay)))}_calcPosition(){if(this.options.domId){const t=this.container,e=document.getElementById(this.options.domId);if(e){const i=e.getBoundingClientRect();return{x:(i.x+i.width/2)*t.retina.pixelRatio,y:(i.y+i.height/2)*t.retina.pixelRatio}}}return F({size:this.container.canvas.size,position:this.options.position})}_calcSize(){const t=this.container;if(this.options.domId){const e=document.getElementById(this.options.domId);if(e){const i=e.getBoundingClientRect();return{width:i.width*t.retina.pixelRatio,height:i.height*t.retina.pixelRatio,mode:"precise"}}}return this.options.size??(()=>{const t=new Yi;return t.load({height:0,mode:"percent",width:0}),t})()}async _emit(){if(this._paused)return;const t=C(this.options.rate.quantity);await this._emitParticles(t)}async _emitParticles(t){const e=ut(this._particlesOptions);for(let i=0;ivoid 0===t||wt(t)?this.array[t||0]:this.array.find((e=>e.name===t)),e.addEmitter=async(t,e)=>this.addEmitter(t,e),e.removeEmitter=t=>{const i=e.getEmitter(t);i&&this.removeEmitter(i)},e.playEmitter=t=>{const i=e.getEmitter(t);i&&i.externalPlay()},e.pauseEmitter=t=>{const i=e.getEmitter(t);i&&i.externalPause()}}async addEmitter(t,e){const i=new Zi;i.load(t);const s=new Ji(this._engine,this,this.container,i,e);return await s.init(),this.array.push(s),s}handleClickMode(t){const e=this.emitters,i=this.interactivityEmitters;if("emitter"!==t)return;let s;if(i&&kt(i.value))if(i.value.length>0&&i.random.enable){s=[];const t=[];for(let e=0;e{this.addEmitter(t,n)}))}async init(){if(this.emitters=this.container.actualOptions.emitters,this.interactivityEmitters=this.container.actualOptions.interactivity.modes.emitters,this.emitters)if(kt(this.emitters))for(const t of this.emitters)await this.addEmitter(t);else await this.addEmitter(this.emitters)}pause(){for(const t of this.array)t.pause()}play(){for(const t of this.array)t.play()}removeEmitter(t){const e=this.array.indexOf(t);e>=0&&this.array.splice(e,1)}resize(){for(const t of this.array)t.resize()}stop(){this.array=[]}async update(t){for(const e of this.array)await e.update(t)}}const ts=new Map;class es{constructor(t){this._engine=t}addShapeGenerator(t,e){this.getShapeGenerator(t)||ts.set(t,e)}getShapeGenerator(t){return ts.get(t)}getSupportedShapeGenerators(){return ts.keys()}}class is{constructor(t,e,i,s){this.position=t,this.size=e,this.fill=i,this.options=s}resize(t,e){this.position=t,this.size=e}}class ss{constructor(t){this._engine=t,this.id="emitters"}getPlugin(t){return new Ki(this._engine,t)}loadOptions(t,e){if(!this.needsPlugin(t)&&!this.needsPlugin(e))return;e?.emitters&&(t.emitters=dt(e.emitters,(t=>{const e=new Zi;return e.load(t),e})));const i=e?.interactivity?.modes?.emitters;if(i)if(kt(i))t.interactivity.modes.emitters={random:{count:1,enable:!0},value:i.map((t=>{const e=new Zi;return e.load(t),e}))};else{const e=i;if(void 0!==e.value)if(kt(e.value))t.interactivity.modes.emitters={random:{count:e.random.count??1,enable:e.random.enable??!1},value:e.value.map((t=>{const e=new Zi;return e.load(t),e}))};else{const i=new Zi;i.load(e.value),t.interactivity.modes.emitters={random:{count:e.random.count??1,enable:e.random.enable??!1},value:i}}else{(t.interactivity.modes.emitters={random:{count:1,enable:!1},value:new Zi}).value.load(i)}}}needsPlugin(t){if(!t)return!1;const e=t.emitters;return kt(e)&&!!e.length||void 0!==e||!!t.interactivity?.events?.onClick?.mode&&Z("emitter",t.interactivity.events.onClick.mode)}}class os extends is{constructor(t,e,i,s){super(t,e,i,s)}async init(){}async randomPosition(){const t=this.size,e=this.fill,i=this.position,[s,o]=[t.width/2,t.height/2],n=((t,e)=>{const i=_()/4,s=Math.atan(e/t*Math.tan(2*Math.PI*i)),o=_();return o<.25?s:o<.5?Math.PI-s:o<.75?Math.PI+s:-s})(s,o),a=(h=n,(c=s)*(l=o)/Math.sqrt((l*Math.cos(h))**2+(c*Math.sin(h))**2)),r=e?a*Math.sqrt(_()):a;var c,l,h;return{position:{x:i.x+r*Math.cos(n),y:i.y+r*Math.sin(n)}}}}class ns{generate(t,e,i,s){return new os(t,e,i,s)}}function as(t,e){return t+e*(_()-.5)}class rs extends is{constructor(t,e,i,s){super(t,e,i,s)}async init(){}async randomPosition(){const t=this.fill,e=this.position,i=this.size;if(t)return{position:{x:as(e.x,i.width),y:as(e.y,i.height)}};{const t=i.width/2,s=i.height/2,o=Math.floor(4*_()),n=2*(_()-.5);switch(o){case 0:return{position:{x:e.x+n*t,y:e.y-s}};case 1:return{position:{x:e.x-t,y:e.y+n*s}};case 2:return{position:{x:e.x+n*t,y:e.y+s}};default:return{position:{x:e.x+t,y:e.y+n*s}}}}}}class cs{generate(t,e,i,s){return new rs(t,e,i,s)}}class ls{constructor(){this.delay=1,this.pauseOnStop=!1,this.quantity=1}load(t){t&&(void 0!==t.delay&&(this.delay=t.delay),void 0!==t.quantity&&(this.quantity=t.quantity),void 0!==t.particles&&(this.particles=st({},t.particles)),void 0!==t.pauseOnStop&&(this.pauseOnStop=t.pauseOnStop))}}const hs="trail";class ds extends Si{constructor(t){super(t),this._delay=0}clear(){}init(){}async interact(t){const e=this.container,{interactivity:i}=e;if(!e.retina.reduceFactor)return;const s=e.actualOptions.interactivity.modes.trail;if(!s)return;const o=1e3*s.delay/this.container.retina.reduceFactor;if(this._delay=.5?"darken":"enlighten";t.roll.alter={type:i,value:C("darken"===i?e.darken.value:e.enlighten.value)}}else e.darken.enable?t.roll.alter={type:"darken",value:C(e.darken.value)}:e.enlighten.enable&&(t.roll.alter={type:"enlighten",value:C(e.enlighten.value)});else t.roll={enable:!1,horizontal:!1,vertical:!1,angle:0,speed:0}}(t)}isEnabled(t){const e=t.options.roll;return!t.destroyed&&!t.spawning&&!!e?.enable}loadOptions(t,...e){t.roll||(t.roll=new ps);for(const i of e)t.roll.load(i?.roll)}update(t,e){this.isEnabled(t)&&function(t,e){const i=t.options.roll,s=t.roll;if(!s||!i?.enable)return;const o=s.speed*e.factor,n=2*Math.PI;s.angle+=o,s.angle>n&&(s.angle-=n)}(t,e)}}function vs(t,e,i,s,o,n){!function(t,e){const i=t.options,s=i.move.path;if(!s.enable)return;if(t.lastPathTime<=t.pathDelay)return void(t.lastPathTime+=e.value);const o=t.pathGenerator?.generate(t,e);o&&t.velocity.addTo(o);s.clamp&&(t.velocity.x=k(t.velocity.x,-1,1),t.velocity.y=k(t.velocity.y,-1,1));t.lastPathTime-=t.pathDelay}(t,n);const a=t.gravity,r=a?.enable&&a.inverse?-1:1;o&&i&&(t.velocity.x+=o*n.factor/(60*i)),a?.enable&&i&&(t.velocity.y+=r*(a.acceleration*n.factor)/(60*i));const c=t.moveDecay;t.velocity.multTo(c);const l=t.velocity.mult(i);a?.enable&&s>0&&(!a.inverse&&l.y>=0&&l.y>=s||a.inverse&&l.y<=0&&l.y<=-s)&&(l.y=r*s,i&&(t.velocity.y=l.y/i));const h=t.options.zIndex,d=(1-t.zIndexFactor)**h.velocityRate;l.multTo(d);const{position:u}=t;u.addTo(l),e.vibrate&&(u.x+=Math.sin(u.x*Math.cos(u.y)),u.y+=Math.cos(u.y*Math.sin(u.x)))}class ys{constructor(){this._initSpin=t=>{const e=t.container,i=t.options.move.spin;if(!i.enable)return;const s=i.position??{x:50,y:50},o={x:.01*s.x*e.canvas.size.width,y:.01*s.y*e.canvas.size.height},n=T(t.getPosition(),o),a=C(i.acceleration);t.retina.spinAcceleration=a*e.retina.pixelRatio,t.spin={center:o,direction:t.velocity.x>=0?"clockwise":"counter-clockwise",angle:t.velocity.angle,radius:n,acceleration:t.retina.spinAcceleration}}}init(t){const e=t.options.move.gravity;t.gravity={enable:e.enable,acceleration:C(e.acceleration),inverse:e.inverse},this._initSpin(t)}isEnabled(t){return!t.destroyed&&t.options.move.enable}move(t,e){const i=t.options,s=i.move;if(!s.enable)return;const o=t.container,n=o.retina.pixelRatio,a=function(t){return t.slow.inRange?t.slow.factor:1}(t),r=(t.retina.moveSpeed??=C(s.speed)*n)*o.retina.reduceFactor,c=t.retina.moveDrift??=C(t.options.move.drift)*n,l=O(i.size.value)*n,h=r*(s.size?t.getRadius()/l:1)*a*(e.factor||1)/2,d=t.retina.maxSpeed??o.retina.maxSpeed;s.spin.enable?function(t,e){const i=t.container;if(!t.spin)return;const s={x:"clockwise"===t.spin.direction?Math.cos:Math.sin,y:"clockwise"===t.spin.direction?Math.sin:Math.cos};t.position.x=t.spin.center.x+t.spin.radius*s.x(t.spin.angle),t.position.y=t.spin.center.y+t.spin.radius*s.y(t.spin.angle),t.spin.radius+=t.spin.acceleration;const o=Math.max(i.canvas.size.width,i.canvas.size.height),n=.5*o;t.spin.radius>n?(t.spin.radius=n,t.spin.acceleration*=-1):t.spin.radius<0&&(t.spin.radius=0,t.spin.acceleration*=-1),t.spin.angle+=.01*e*(1-t.spin.radius/o)}(t,h):vs(t,s,h,d,c,e),function(t){const e=t.initialPosition,{dx:i,dy:s}=D(e,t.position),o=Math.abs(i),n=Math.abs(s),{maxDistance:a}=t.retina,r=a.horizontal,c=a.vertical;if(r||c)if((r&&o>=r||c&&n>=c)&&!t.misplaced)t.misplaced=!!r&&o>r||!!c&&n>c,r&&(t.velocity.x=.5*t.velocity.y-t.velocity.x),c&&(t.velocity.y=.5*t.velocity.x-t.velocity.y);else if((!r||oe.x&&s.x>0)&&(s.x*=-_()),c&&(i.ye.y&&s.y>0)&&(s.y*=-_())}}(t)}}class ms{draw(t){const{context:e,particle:i,radius:s}=t;i.circleRange||(i.circleRange={min:0,max:2*Math.PI});const o=i.circleRange;e.arc(0,0,s,o.min,o.max,!1)}getSidesCount(){return 12}particleInit(t,e){const i=e.shapeData,s=i?.angle??{max:360,min:0};e.circleRange=_t(s)?{min:s.min*Math.PI/180,max:s.max*Math.PI/180}:{min:0,max:s*Math.PI/180}}}function gs(t,e,i,s,o){if(!e||!i.enable||(e.maxLoops??0)>0&&(e.loops??0)>(e.maxLoops??0))return;if(e.time||(e.time=0),(e.delayTime??0)>0&&e.time<(e.delayTime??0)&&(e.time+=t.value),(e.delayTime??0)>0&&e.time<(e.delayTime??0))return;const n=M(i.offset),a=(e.velocity??0)*t.factor+3.6*n,r=e.decay??1;o&&"increasing"!==e.status?(e.value-=a,e.value<0&&(e.loops||(e.loops=0),e.loops++,e.status="increasing",e.value+=e.value)):(e.value+=a,e.value>s&&(e.loops||(e.loops=0),e.loops++,o&&(e.status="decreasing",e.value-=e.value%s))),e.velocity&&1!==r&&(e.velocity*=r),e.value>s&&(e.value%=s)}class bs{constructor(t){this.container=t}init(t){const e=Rt(t.options.color,t.id,t.options.reduceDuplicates);e&&(t.color=jt(e,t.options.color.animation,this.container.retina.reduceFactor))}isEnabled(t){const{h:e,s:i,l:s}=t.options.color.animation,{color:o}=t;return!t.destroyed&&!t.spawning&&(void 0!==o?.h.value&&e.enable||void 0!==o?.s.value&&i.enable||void 0!==o?.l.value&&s.enable)}update(t,e){!function(t,e){const{h:i,s,l:o}=t.options.color.animation,{color:n}=t;if(!n)return;const{h:a,s:r,l:c}=n;a&&gs(e,a,i,360,!1),r&&gs(e,r,s,100,!0),c&&gs(e,c,o,100,!0)}(t,e)}}class ws{constructor(t){this.container=t}init(t){const e=t.options.opacity;t.opacity=ft(e,1);const i=e.animation;i.enable&&(t.opacity.velocity=C(i.speed)/100*this.container.retina.reduceFactor,i.sync||(t.opacity.velocity*=_()))}isEnabled(t){return!t.destroyed&&!t.spawning&&!!t.opacity&&t.opacity.enable&&((t.opacity.maxLoops??0)<=0||(t.opacity.maxLoops??0)>0&&(t.opacity.loops??0)<(t.opacity.maxLoops??0))}reset(t){t.opacity&&(t.opacity.time=0,t.opacity.loops=0)}update(t,e){this.isEnabled(t)&&function(t,e){const i=t.opacity;if(t.destroyed||!i?.enable||(i.maxLoops??0)>0&&(i.loops??0)>(i.maxLoops??0))return;const s=i.min,o=i.max,n=i.decay??1;if(i.time||(i.time=0),(i.delayTime??0)>0&&i.time<(i.delayTime??0)&&(i.time+=e.value),!((i.delayTime??0)>0&&i.time<(i.delayTime??0))){switch(i.status){case"increasing":i.value>=o?(i.status="decreasing",i.loops||(i.loops=0),i.loops++):i.value+=(i.velocity??0)*e.factor;break;case"decreasing":i.value<=s?(i.status="increasing",i.loops||(i.loops=0),i.loops++):i.value-=(i.velocity??0)*e.factor}i.velocity&&1!==i.decay&&(i.velocity*=n),function(t,e,i,s){switch(t.options.opacity.animation.destroy){case"max":e>=s&&t.destroy();break;case"min":e<=i&&t.destroy()}}(t,i.value,s,o),t.destroyed||(i.value=k(i.value,s,o))}}(t,e)}}class xs{constructor(t){this.container=t,this.modes=["bounce","bounce-vertical","bounce-horizontal","bounceVertical","bounceHorizontal","split"]}update(t,e,i,s){if(!this.modes.includes(s))return;const o=this.container;let n=!1;for(const[,s]of o.plugins)if(void 0!==s.particleBounce&&(n=s.particleBounce(t,i,e)),n)break;if(n)return;const a=t.getPosition(),r=t.offset,c=t.getRadius(),l=it(a,c),h=o.canvas.size;!function(t){if("bounce"!==t.outMode&&"bounce-horizontal"!==t.outMode&&"bounceHorizontal"!==t.outMode&&"split"!==t.outMode||"left"!==t.direction&&"right"!==t.direction)return;t.bounds.right<0&&"left"===t.direction?t.particle.position.x=t.size+t.offset.x:t.bounds.left>t.canvasSize.width&&"right"===t.direction&&(t.particle.position.x=t.canvasSize.width-t.size-t.offset.x);const e=t.particle.velocity.x;let i=!1;if("right"===t.direction&&t.bounds.right>=t.canvasSize.width&&e>0||"left"===t.direction&&t.bounds.left<=0&&e<0){const e=C(t.particle.options.bounce.horizontal.value);t.particle.velocity.x*=-e,i=!0}if(!i)return;const s=t.offset.x+t.size;t.bounds.right>=t.canvasSize.width&&"right"===t.direction?t.particle.position.x=t.canvasSize.width-s:t.bounds.left<=0&&"left"===t.direction&&(t.particle.position.x=s),"split"===t.outMode&&t.particle.destroy()}({particle:t,outMode:s,direction:e,bounds:l,canvasSize:h,offset:r,size:c}),function(t){if("bounce"!==t.outMode&&"bounce-vertical"!==t.outMode&&"bounceVertical"!==t.outMode&&"split"!==t.outMode||"bottom"!==t.direction&&"top"!==t.direction)return;t.bounds.bottom<0&&"top"===t.direction?t.particle.position.y=t.size+t.offset.y:t.bounds.top>t.canvasSize.height&&"bottom"===t.direction&&(t.particle.position.y=t.canvasSize.height-t.size-t.offset.y);const e=t.particle.velocity.y;let i=!1;if("bottom"===t.direction&&t.bounds.bottom>=t.canvasSize.height&&e>0||"top"===t.direction&&t.bounds.top<=0&&e<0){const e=C(t.particle.options.bounce.vertical.value);t.particle.velocity.y*=-e,i=!0}if(!i)return;const s=t.offset.y+t.size;t.bounds.bottom>=t.canvasSize.height&&"bottom"===t.direction?t.particle.position.y=t.canvasSize.height-s:t.bounds.top<=0&&"top"===t.direction&&(t.particle.position.y=s),"split"===t.outMode&&t.particle.destroy()}({particle:t,outMode:s,direction:e,bounds:l,canvasSize:h,offset:r,size:c})}}class _s{constructor(t){this.container=t,this.modes=["destroy"]}update(t,e,i,s){if(!this.modes.includes(s))return;const o=this.container;switch(t.outType){case"normal":case"outside":if(tt(t.position,o.canvas.size,y.origin,t.getRadius(),e))return;break;case"inside":{const{dx:e,dy:i}=D(t.position,t.moveCenter),{x:s,y:o}=t.velocity;if(s<0&&e>t.moveCenter.radius||o<0&&i>t.moveCenter.radius||s>=0&&e<-t.moveCenter.radius||o>=0&&i<-t.moveCenter.radius)return;break}}o.particles.remove(t,void 0,!0)}}class ks{constructor(t){this.container=t,this.modes=["none"]}update(t,e,i,s){if(!this.modes.includes(s))return;if(t.options.move.distance.horizontal&&("left"===e||"right"===e)||t.options.move.distance.vertical&&("top"===e||"bottom"===e))return;const o=t.options.move.gravity,n=this.container,a=n.canvas.size,r=t.getRadius();if(o.enable){const i=t.position;(!o.inverse&&i.y>a.height+r&&"bottom"===e||o.inverse&&i.y<-r&&"top"===e)&&n.particles.remove(t)}else{if(t.velocity.y>0&&t.position.y<=a.height+r||t.velocity.y<0&&t.position.y>=-r||t.velocity.x>0&&t.position.x<=a.width+r||t.velocity.x<0&&t.position.x>=-r)return;tt(t.position,n.canvas.size,y.origin,r,e)||n.particles.remove(t)}}}class zs{constructor(t){this.container=t,this.modes=["out"]}update(t,e,i,s){if(!this.modes.includes(s))return;const o=this.container;switch(t.outType){case"inside":{const{x:e,y:i}=t.velocity,s=y.origin;s.length=t.moveCenter.radius,s.angle=t.velocity.angle+Math.PI,s.addTo(y.create(t.moveCenter));const{dx:n,dy:a}=D(t.position,s);if(e<=0&&n>=0||i<=0&&a>=0||e>=0&&n<=0||i>=0&&a<=0)return;t.position.x=Math.floor(M({min:0,max:o.canvas.size.width})),t.position.y=Math.floor(M({min:0,max:o.canvas.size.height}));const{dx:r,dy:c}=D(t.position,t.moveCenter);t.direction=Math.atan2(-c,-r),t.velocity.angle=t.direction;break}default:if(tt(t.position,o.canvas.size,y.origin,t.getRadius(),e))return;switch(t.outType){case"outside":{t.position.x=Math.floor(M({min:-t.moveCenter.radius,max:t.moveCenter.radius}))+t.moveCenter.x,t.position.y=Math.floor(M({min:-t.moveCenter.radius,max:t.moveCenter.radius}))+t.moveCenter.y;const{dx:e,dy:i}=D(t.position,t.moveCenter);t.moveCenter.radius&&(t.direction=Math.atan2(i,e),t.velocity.angle=t.direction);break}case"normal":{const i=t.options.move.warp,s=o.canvas.size,n={bottom:s.height+t.getRadius()+t.offset.y,left:-t.getRadius()-t.offset.x,right:s.width+t.getRadius()+t.offset.x,top:-t.getRadius()-t.offset.y},a=t.getRadius(),r=it(t.position,a);"right"===e&&r.left>s.width+t.offset.x?(t.position.x=n.left,t.initialPosition.x=t.position.x,i||(t.position.y=_()*s.height,t.initialPosition.y=t.position.y)):"left"===e&&r.right<-t.offset.x&&(t.position.x=n.right,t.initialPosition.x=t.position.x,i||(t.position.y=_()*s.height,t.initialPosition.y=t.position.y)),"bottom"===e&&r.top>s.height+t.offset.y?(i||(t.position.x=_()*s.width,t.initialPosition.x=t.position.x),t.position.y=n.top,t.initialPosition.y=t.position.y):"top"===e&&r.bottom<-t.offset.y&&(i||(t.position.x=_()*s.width,t.initialPosition.x=t.position.x),t.position.y=n.bottom,t.initialPosition.y=t.position.y);break}}}}}class Ms{constructor(t){this.container=t,this._updateOutMode=(t,e,i,s)=>{for(const o of this.updaters)o.update(t,s,e,i)},this.updaters=[new xs(t),new _s(t),new zs(t),new ks(t)]}init(){}isEnabled(t){return!t.destroyed&&!t.spawning}update(t,e){const i=t.options.move.outModes;this._updateOutMode(t,e,i.bottom??i.default,"bottom"),this._updateOutMode(t,e,i.left??i.default,"left"),this._updateOutMode(t,e,i.right??i.default,"right"),this._updateOutMode(t,e,i.top??i.default,"top")}}class Cs{init(t){const e=t.container,i=t.options.size.animation;i.enable&&(t.size.velocity=(t.retina.sizeAnimationSpeed??e.retina.sizeAnimationSpeed)/100*e.retina.reduceFactor,i.sync||(t.size.velocity*=_()))}isEnabled(t){return!t.destroyed&&!t.spawning&&t.size.enable&&((t.size.maxLoops??0)<=0||(t.size.maxLoops??0)>0&&(t.size.loops??0)<(t.size.maxLoops??0))}reset(t){t.size.loops=0}update(t,e){this.isEnabled(t)&&function(t,e){const i=t.size;if(t.destroyed||!i||!i.enable||(i.maxLoops??0)>0&&(i.loops??0)>(i.maxLoops??0))return;const s=(i.velocity??0)*e.factor,o=i.min,n=i.max,a=i.decay??1;if(i.time||(i.time=0),(i.delayTime??0)>0&&i.time<(i.delayTime??0)&&(i.time+=e.value),!((i.delayTime??0)>0&&i.time<(i.delayTime??0))){switch(i.status){case"increasing":i.value>=n?(i.status="decreasing",i.loops||(i.loops=0),i.loops++):i.value+=s;break;case"decreasing":i.value<=o?(i.status="increasing",i.loops||(i.loops=0),i.loops++):i.value-=s}i.velocity&&1!==a&&(i.velocity*=a),function(t,e,i,s){switch(t.options.size.animation.destroy){case"max":e>=s&&t.destroy();break;case"min":e<=i&&t.destroy()}}(t,i.value,o,n),t.destroyed||(i.value=k(i.value,o,n))}}(t,e)}}async function Ps(t,e=!0){await async function(t,e=!0){await t.addMover("base",(()=>new ys),e)}(t,!1),await async function(t,e=!0){await t.addShape("circle",new ms,e)}(t,!1),await async function(t,e=!0){await t.addParticleUpdater("color",(t=>new bs(t)),e)}(t,!1),await async function(t,e=!0){await t.addParticleUpdater("opacity",(t=>new ws(t)),e)}(t,!1),await async function(t,e=!0){await t.addParticleUpdater("outModes",(t=>new Ms(t)),e)}(t,!1),await async function(t,e=!0){await t.addParticleUpdater("size",(()=>new Cs),e)}(t,!1),await t.refresh(e)}const Os=["emoji"],Ss='"Twemoji Mozilla", Apple Color Emoji, "Segoe UI Emoji", "Noto Color Emoji", "EmojiOne Color"';class Ds{constructor(){this._emojiShapeDict=new Map}destroy(){for(const[,t]of this._emojiShapeDict)t instanceof ImageBitmap&&t?.close()}draw(t){const{context:e,particle:i,radius:s,opacity:o}=t,n=i.emojiData;n&&(e.globalAlpha=o,e.drawImage(n,-s,-s,2*s,2*s),e.globalAlpha=1)}async init(t){const e=t.actualOptions;if(Os.find((t=>Z(t,e.particles.shape.type)))){const t=[Q(Ss)],i=Os.map((t=>e.particles.shape.options[t])).find((t=>!!t));i&&dt(i,(e=>{e.font&&t.push(Q(e.font))})),await Promise.all(t)}}particleDestroy(t){delete t.emojiData}particleInit(t,e){if(!e.emojiData){const t=e.shapeData;if(!t?.value)return;const i=ut(t.value,e.randomIndexData),s=t.font??Ss;if(!i)return;const o=`${i}_${s}`,n=this._emojiShapeDict.get(o);if(n)return void(e.emojiData=n);const a=2*O(e.size.value);let r;if("undefined"!=typeof OffscreenCanvas){const t=new OffscreenCanvas(a,a),o=t.getContext("2d");if(!o)return;o.font=`400 ${2*O(e.size.value)}px ${s}`,o.textBaseline="middle",o.textAlign="center",o.fillText(i,O(e.size.value),O(e.size.value)),r=t.transferToImageBitmap()}else{const t=document.createElement("canvas");t.width=a,t.height=a;const o=t.getContext("2d");if(!o)return;o.font=`400 ${2*O(e.size.value)}px ${s}`,o.textBaseline="middle",o.textAlign="center",o.fillText(i,O(e.size.value),O(e.size.value)),r=t}this._emojiShapeDict.set(o,r),e.emojiData=r}}}class Ts{constructor(){this.distance=200,this.duration=.4,this.easing="ease-out-quad",this.factor=1,this.maxSpeed=50,this.speed=1}load(t){t&&(void 0!==t.distance&&(this.distance=t.distance),void 0!==t.duration&&(this.duration=t.duration),void 0!==t.easing&&(this.easing=t.easing),void 0!==t.factor&&(this.factor=t.factor),void 0!==t.maxSpeed&&(this.maxSpeed=t.maxSpeed),void 0!==t.speed&&(this.speed=t.speed))}}const Rs="attract";class Es extends Si{constructor(t,e){super(e),this._clickAttract=()=>{const t=this.container;t.attract||(t.attract={particles:[]});const{attract:e}=t;if(e.finish||(e.count||(e.count=0),e.count++,e.count===t.particles.count&&(e.finish=!0)),e.clicking){const e=t.interactivity.mouse.clickPosition,i=t.retina.attractModeDistance;if(!i||i<0||!e)return;this._processAttract(e,i,new yi(e.x,e.y,i))}else!1===e.clicking&&(e.particles=[])},this._hoverAttract=()=>{const t=this.container,e=t.interactivity.mouse.position,i=t.retina.attractModeDistance;!i||i<0||!e||this._processAttract(e,i,new yi(e.x,e.y,i))},this._processAttract=(t,e,i)=>{const s=this.container,o=s.actualOptions.interactivity.modes.attract;if(!o)return;const n=s.particles.quadTree.query(i,(t=>this.isEnabled(t)));for(const i of n){const{dx:s,dy:n,distance:a}=D(i.position,t),r=o.speed*o.factor,c=k(w(o.easing)(1-a/e)*r,0,o.maxSpeed),l=y.create(0===a?r:s/a*c,0===a?r:n/a*c);i.position.subFrom(l)}},this._engine=t,e.attract||(e.attract={particles:[]}),this.handleClickMode=t=>{const i=this.container.actualOptions.interactivity.modes.attract;if(i&&t===Rs){e.attract||(e.attract={particles:[]}),e.attract.clicking=!0,e.attract.count=0;for(const t of e.attract.particles)this.isEnabled(t)&&t.velocity.setTo(t.initialVelocity);e.attract.particles=[],e.attract.finish=!1,setTimeout((()=>{e.destroyed||(e.attract||(e.attract={particles:[]}),e.attract.clicking=!1)}),1e3*i.duration)}}}clear(){}init(){const t=this.container,e=t.actualOptions.interactivity.modes.attract;e&&(t.retina.attractModeDistance=e.distance*t.retina.pixelRatio)}async interact(){const t=this.container,e=t.actualOptions,i=t.interactivity.status===r,s=e.interactivity.events,o=s.onHover.enable,n=s.onHover.mode,a=s.onClick.enable,c=s.onClick.mode;i&&o&&Z(Rs,n)?this._hoverAttract():a&&Z(Rs,c)&&this._clickAttract()}isEnabled(t){const e=this.container,i=e.actualOptions,s=e.interactivity.mouse,o=(t?.interactivity??i.interactivity).events;if(!(s.position&&o.onHover.enable||s.clickPosition&&o.onClick.enable))return!1;const n=o.onHover.mode,a=o.onClick.mode;return Z(Rs,n)||Z(Rs,a)}loadModeOptions(t,...e){t.attract||(t.attract=new Ts);for(const i of e)t.attract.load(i?.attract)}reset(){}}class Is{constructor(){this.distance=200}load(t){t&&void 0!==t.distance&&(this.distance=t.distance)}}const Ls="bounce";class As extends Si{constructor(t){super(t),this._processBounce=(t,e,i)=>{const s=this.container.particles.quadTree.query(i,(t=>this.isEnabled(t)));for(const o of s)i instanceof yi?lt(ct(o),{position:t,radius:e,mass:e**2*Math.PI/2,velocity:y.origin,factor:y.origin}):i instanceof vi&&ht(o,it(t,e))},this._processMouseBounce=()=>{const t=this.container,e=10*t.retina.pixelRatio,i=t.interactivity.mouse.position,s=t.retina.bounceModeDistance;!s||s<0||!i||this._processBounce(i,s,new yi(i.x,i.y,s+e))},this._singleSelectorBounce=(t,e)=>{const i=this.container,s=document.querySelectorAll(t);s.length&&s.forEach((t=>{const s=t,o=i.retina.pixelRatio,n={x:(s.offsetLeft+s.offsetWidth/2)*o,y:(s.offsetTop+s.offsetHeight/2)*o},a=s.offsetWidth/2*o,r=10*o,c="circle"===e.type?new yi(n.x,n.y,a+r):new vi(s.offsetLeft*o-r,s.offsetTop*o-r,s.offsetWidth*o+2*r,s.offsetHeight*o+2*r);this._processBounce(n,a,c)}))}}clear(){}init(){const t=this.container,e=t.actualOptions.interactivity.modes.bounce;e&&(t.retina.bounceModeDistance=e.distance*t.retina.pixelRatio)}async interact(){const t=this.container,e=t.actualOptions.interactivity.events,i=t.interactivity.status===r,s=e.onHover.enable,o=e.onHover.mode,n=e.onDiv;i&&s&&Z(Ls,o)?this._processMouseBounce():nt(Ls,n,((t,e)=>this._singleSelectorBounce(t,e)))}isEnabled(t){const e=this.container,i=e.actualOptions,s=e.interactivity.mouse,o=(t?.interactivity??i.interactivity).events,n=o.onDiv;return s.position&&o.onHover.enable&&Z(Ls,o.onHover.mode)||ot(Ls,n)}loadModeOptions(t,...e){t.bounce||(t.bounce=new Is);for(const i of e)t.bounce.load(i?.bounce)}reset(){}}class Fs{constructor(){this.distance=200,this.duration=.4,this.mix=!1}load(t){if(t){if(void 0!==t.distance&&(this.distance=t.distance),void 0!==t.duration&&(this.duration=t.duration),void 0!==t.mix&&(this.mix=t.mix),void 0!==t.opacity&&(this.opacity=t.opacity),void 0!==t.color){const e=kt(this.color)?void 0:this.color;this.color=dt(t.color,(t=>ce.create(e,t)))}void 0!==t.size&&(this.size=t.size)}}}class Bs extends Fs{constructor(){super(),this.selectors=[]}load(t){super.load(t),t&&void 0!==t.selectors&&(this.selectors=t.selectors)}}class qs extends Fs{load(t){super.load(t),t&&(this.divs=dt(t.divs,(t=>{const e=new Bs;return e.load(t),e})))}}function Hs(t,e,i,s){if(e>=i){return k(t+(e-i)*s,t,e)}if(e{const t=this.container,e=t.actualOptions,i=t.interactivity.mouse.clickPosition,s=e.interactivity.modes.bubble;if(!s||!i)return;t.bubble||(t.bubble={});const o=t.retina.bubbleModeDistance;if(!o||o<0)return;const n=t.particles.quadTree.queryCircle(i,o,(t=>this.isEnabled(t))),{bubble:a}=t;for(const e of n){if(!a.clicking)continue;e.bubble.inRange=!a.durationEnd;const n=T(e.getPosition(),i),r=((new Date).getTime()-(t.interactivity.mouse.clickTime||0))/1e3;r>s.duration&&(a.durationEnd=!0),r>2*s.duration&&(a.clicking=!1,a.durationEnd=!1);const c={bubbleObj:{optValue:t.retina.bubbleModeSize,value:e.bubble.radius},particlesObj:{optValue:O(e.options.size.value)*t.retina.pixelRatio,value:e.size.value},type:"size"};this._process(e,n,r,c);const l={bubbleObj:{optValue:s.opacity,value:e.bubble.opacity},particlesObj:{optValue:O(e.options.opacity.value),value:e.opacity?.value??1},type:"opacity"};this._process(e,n,r,l),!a.durationEnd&&n<=o?this._hoverBubbleColor(e,n):delete e.bubble.color}},this._hoverBubble=()=>{const t=this.container,e=t.interactivity.mouse.position,i=t.retina.bubbleModeDistance;if(!i||i<0||void 0===e)return;const s=t.particles.quadTree.queryCircle(e,i,(t=>this.isEnabled(t)));for(const o of s){o.bubble.inRange=!0;const s=T(o.getPosition(),e),a=1-s/i;s<=i?a>=0&&t.interactivity.status===r&&(this._hoverBubbleSize(o,a),this._hoverBubbleOpacity(o,a),this._hoverBubbleColor(o,a)):this.reset(o),t.interactivity.status===n&&this.reset(o)}},this._hoverBubbleColor=(t,e,i)=>{const s=this.container.actualOptions,o=i??s.interactivity.modes.bubble;if(o){if(!t.bubble.finalColor){const e=o.color;if(!e)return;const i=ut(e);t.bubble.finalColor=Rt(i)}if(t.bubble.finalColor)if(o.mix){t.bubble.color=void 0;const i=t.getFillColor();t.bubble.color=i?Et(Vt(i,t.bubble.finalColor,1-e,e)):t.bubble.finalColor}else t.bubble.color=t.bubble.finalColor}},this._hoverBubbleOpacity=(t,e,i)=>{const s=this.container.actualOptions,o=i?.opacity??s.interactivity.modes.bubble?.opacity;if(!o)return;const n=t.options.opacity.value,a=Hs(t.opacity?.value??1,o,O(n),e);void 0!==a&&(t.bubble.opacity=a)},this._hoverBubbleSize=(t,e,i)=>{const s=this.container,o=i?.size?i.size*s.retina.pixelRatio:s.retina.bubbleModeSize;if(void 0===o)return;const n=O(t.options.size.value)*s.retina.pixelRatio,a=Hs(t.size.value,o,n,e);void 0!==a&&(t.bubble.radius=a)},this._process=(t,e,i,s)=>{const o=this.container,n=s.bubbleObj.optValue,a=o.actualOptions.interactivity.modes.bubble;if(!a||void 0===n)return;const r=a.duration,c=o.retina.bubbleModeDistance,l=s.particlesObj.optValue,h=s.bubbleObj.value,d=s.particlesObj.value||0,u=s.type;if(c&&!(c<0)&&n!==l)if(o.bubble||(o.bubble={}),o.bubble.durationEnd)h&&("size"===u&&delete t.bubble.radius,"opacity"===u&&delete t.bubble.opacity);else if(e<=c){if((h??d)!==n){const e=d-i*(d-n)/r;"size"===u&&(t.bubble.radius=e),"opacity"===u&&(t.bubble.opacity=e)}}else"size"===u&&delete t.bubble.radius,"opacity"===u&&delete t.bubble.opacity},this._singleSelectorHover=(t,e,i)=>{const s=this.container,o=document.querySelectorAll(e),n=s.actualOptions.interactivity.modes.bubble;n&&o.length&&o.forEach((e=>{const o=e,a=s.retina.pixelRatio,r={x:(o.offsetLeft+o.offsetWidth/2)*a,y:(o.offsetTop+o.offsetHeight/2)*a},c=o.offsetWidth/2*a,l="circle"===i.type?new yi(r.x,r.y,c):new vi(o.offsetLeft*a,o.offsetTop*a,o.offsetWidth*a,o.offsetHeight*a),h=s.particles.quadTree.query(l,(t=>this.isEnabled(t)));for(const e of h){if(!l.contains(e.getPosition()))continue;e.bubble.inRange=!0;const i=rt(n.divs,o);e.bubble.div&&e.bubble.div===o||(this.clear(e,t,!0),e.bubble.div=o),this._hoverBubbleSize(e,1,i),this._hoverBubbleOpacity(e,1,i),this._hoverBubbleColor(e,1,i)}}))},t.bubble||(t.bubble={}),this.handleClickMode=e=>{e===Vs&&(t.bubble||(t.bubble={}),t.bubble.clicking=!0)}}clear(t,e,i){t.bubble.inRange&&!i||(delete t.bubble.div,delete t.bubble.opacity,delete t.bubble.radius,delete t.bubble.color)}init(){const t=this.container,e=t.actualOptions.interactivity.modes.bubble;e&&(t.retina.bubbleModeDistance=e.distance*t.retina.pixelRatio,void 0!==e.size&&(t.retina.bubbleModeSize=e.size*t.retina.pixelRatio))}async interact(t){const e=this.container.actualOptions.interactivity.events,i=e.onHover,s=e.onClick,o=i.enable,n=i.mode,a=s.enable,r=s.mode,c=e.onDiv;o&&Z(Vs,n)?this._hoverBubble():a&&Z(Vs,r)?this._clickBubble():nt(Vs,c,((e,i)=>this._singleSelectorHover(t,e,i)))}isEnabled(t){const e=this.container,i=e.actualOptions,s=e.interactivity.mouse,o=(t?.interactivity??i.interactivity).events,{onClick:n,onDiv:a,onHover:r}=o,c=ot(Vs,a);return!!(c||r.enable&&s.position||n.enable&&s.clickPosition)&&(Z(Vs,r.mode)||Z(Vs,n.mode)||c)}loadModeOptions(t,...e){t.bubble||(t.bubble=new qs);for(const i of e)t.bubble.load(i?.bubble)}reset(t){t.bubble.inRange=!1}}class Ws{constructor(){this.opacity=.5}load(t){t&&void 0!==t.opacity&&(this.opacity=t.opacity)}}class $s{constructor(){this.distance=80,this.links=new Ws,this.radius=60}load(t){t&&(void 0!==t.distance&&(this.distance=t.distance),this.links.load(t.links),void 0!==t.radius&&(this.radius=t.radius))}}function js(t,e,i,s){const o=t.actualOptions.interactivity.modes.connect;if(o)return function(t,e,i,s){const o=Math.floor(i.getRadius()/e.getRadius()),n=e.getFillColor(),a=i.getFillColor();if(!n||!a)return;const r=e.getPosition(),c=i.getPosition(),l=Vt(n,a,e.getRadius(),i.getRadius()),h=t.createLinearGradient(r.x,r.y,c.x,c.y);return h.addColorStop(0,Ht(n,s)),h.addColorStop(o>1?1:o,qt(l,s)),h.addColorStop(1,Ht(a,s)),h}(e,i,s,o.links.opacity)}function Gs(t,e,i){t.canvas.draw((s=>{const o=js(t,s,e,i);if(!o)return;const n=e.getPosition(),a=i.getPosition();!function(t,e,i,s,o){Nt(t,s,o),t.lineWidth=e,t.strokeStyle=i,t.stroke()}(s,e.retina.linksWidth??0,o,n,a)}))}class Ns extends Si{constructor(t){super(t)}clear(){}init(){const t=this.container,e=t.actualOptions.interactivity.modes.connect;e&&(t.retina.connectModeDistance=e.distance*t.retina.pixelRatio,t.retina.connectModeRadius=e.radius*t.retina.pixelRatio)}async interact(){const t=this.container;if(t.actualOptions.interactivity.events.onHover.enable&&"pointermove"===t.interactivity.status){const e=t.interactivity.mouse.position;if(!t.retina.connectModeDistance||t.retina.connectModeDistance<0||!t.retina.connectModeRadius||t.retina.connectModeRadius<0||!e)return;const i=Math.abs(t.retina.connectModeRadius),s=t.particles.quadTree.queryCircle(e,i,(t=>this.isEnabled(t)));let o=0;for(const e of s){const i=e.getPosition();for(const n of s.slice(o+1)){const s=n.getPosition(),o=Math.abs(t.retina.connectModeDistance),a=Math.abs(i.x-s.x),r=Math.abs(i.y-s.y);a{const n=e.getPosition();!function(t,e,i,s,o,n){Nt(t,i,s),t.strokeStyle=qt(o,n),t.lineWidth=e,t.stroke()}(t,e.retina.linksWidth??0,n,o,i,s)}))}class Qs extends Si{constructor(t){super(t)}clear(){}init(){const t=this.container,e=t.actualOptions.interactivity.modes.grab;e&&(t.retina.grabModeDistance=e.distance*t.retina.pixelRatio)}async interact(){const t=this.container,e=t.actualOptions.interactivity;if(!e.modes.grab||!e.events.onHover.enable||t.interactivity.status!==r)return;const i=t.interactivity.mouse.position;if(!i)return;const s=t.retina.grabModeDistance;if(!s||s<0)return;const o=t.particles.quadTree.queryCircle(i,s,(t=>this.isEnabled(t)));for(const n of o){const o=T(n.getPosition(),i);if(o>s)continue;const a=e.modes.grab.links,r=a.opacity,c=r-o*r/s;if(c<=0)continue;const l=a.color??n.options.links?.color;if(!t.particles.grabLineColor&&l){const i=e.modes.grab.links;t.particles.grabLineColor=Wt(l,i.blink,i.consent)}const h=Ut(n,void 0,t.particles.grabLineColor);h&&Zs(t,n,h,c,i)}}isEnabled(t){const e=this.container,i=e.interactivity.mouse,s=(t?.interactivity??e.actualOptions.interactivity).events;return s.onHover.enable&&!!i.position&&Z("grab",s.onHover.mode)}loadModeOptions(t,...e){t.grab||(t.grab=new Ys);for(const i of e)t.grab.load(i?.grab)}reset(){}}class Js extends Si{constructor(t){super(t),this.handleClickMode=t=>{if("pause"!==t)return;const e=this.container;e.getAnimationStatus()?e.pause():e.play()}}clear(){}init(){}async interact(){}isEnabled(){return!0}reset(){}}class Ks{constructor(){this.default=!0,this.groups=[],this.quantity=4}load(t){if(!t)return;void 0!==t.default&&(this.default=t.default),void 0!==t.groups&&(this.groups=t.groups.map((t=>t))),this.groups.length||(this.default=!0);const e=t.quantity;void 0!==e&&(this.quantity=S(e))}}class to extends Si{constructor(t){super(t),this.handleClickMode=t=>{if("push"!==t)return;const e=this.container,i=e.actualOptions.interactivity.modes.push;if(!i)return;const s=C(i.quantity);if(s<=0)return;const o=K([void 0,...i.groups]),n=void 0!==o?e.actualOptions.particles.groups[o]:void 0;e.particles.push(s,e.interactivity.mouse,n,o)}}clear(){}init(){}async interact(){}isEnabled(){return!0}loadModeOptions(t,...e){t.push||(t.push=new Ks);for(const i of e)t.push.load(i?.push)}reset(){}}class eo{constructor(){this.quantity=2}load(t){if(!t)return;const e=t.quantity;void 0!==e&&(this.quantity=S(e))}}class io extends Si{constructor(t){super(t),this.handleClickMode=t=>{const e=this.container,i=e.actualOptions;if(!i.interactivity.modes.remove||"remove"!==t)return;const s=C(i.interactivity.modes.remove.quantity);e.particles.removeQuantity(s)}}clear(){}init(){}async interact(){}isEnabled(){return!0}loadModeOptions(t,...e){t.remove||(t.remove=new eo);for(const i of e)t.remove.load(i?.remove)}reset(){}}class so{constructor(){this.distance=200,this.duration=.4,this.factor=100,this.speed=1,this.maxSpeed=50,this.easing="ease-out-quad"}load(t){t&&(void 0!==t.distance&&(this.distance=t.distance),void 0!==t.duration&&(this.duration=t.duration),void 0!==t.easing&&(this.easing=t.easing),void 0!==t.factor&&(this.factor=t.factor),void 0!==t.speed&&(this.speed=t.speed),void 0!==t.maxSpeed&&(this.maxSpeed=t.maxSpeed))}}class oo extends so{constructor(){super(),this.selectors=[]}load(t){super.load(t),t&&void 0!==t.selectors&&(this.selectors=t.selectors)}}class no extends so{load(t){super.load(t),t&&(this.divs=dt(t.divs,(t=>{const e=new oo;return e.load(t),e})))}}const ao="repulse";class ro extends Si{constructor(t,e){super(e),this._clickRepulse=()=>{const t=this.container,e=t.actualOptions.interactivity.modes.repulse;if(!e)return;const i=t.repulse||{particles:[]};if(i.finish||(i.count||(i.count=0),i.count++,i.count===t.particles.count&&(i.finish=!0)),i.clicking){const s=t.retina.repulseModeDistance;if(!s||s<0)return;const o=Math.pow(s/6,3),n=t.interactivity.mouse.clickPosition;if(void 0===n)return;const a=new yi(n.x,n.y,o),r=t.particles.quadTree.query(a,(t=>this.isEnabled(t)));for(const t of r){const{dx:s,dy:a,distance:r}=D(n,t.position),c=r**2,l=-o*e.speed/c;if(c<=o){i.particles.push(t);const e=y.create(s,a);e.length=l,t.velocity.setTo(e)}}}else if(!1===i.clicking){for(const t of i.particles)t.velocity.setTo(t.initialVelocity);i.particles=[]}},this._hoverRepulse=()=>{const t=this.container,e=t.interactivity.mouse.position,i=t.retina.repulseModeDistance;!i||i<0||!e||this._processRepulse(e,i,new yi(e.x,e.y,i))},this._processRepulse=(t,e,i,s)=>{const o=this.container,n=o.particles.quadTree.query(i,(t=>this.isEnabled(t))),a=o.actualOptions.interactivity.modes.repulse;if(!a)return;const{easing:r,speed:c,factor:l,maxSpeed:h}=a,d=w(r),u=(s?.speed??c)*l;for(const i of n){const{dx:s,dy:o,distance:n}=D(i.position,t),a=k(d(1-n/e)*u,0,h),r=y.create(0===n?u:s/n*a,0===n?u:o/n*a);i.position.addTo(r)}},this._singleSelectorRepulse=(t,e)=>{const i=this.container,s=i.actualOptions.interactivity.modes.repulse;if(!s)return;const o=document.querySelectorAll(t);o.length&&o.forEach((t=>{const o=t,n=i.retina.pixelRatio,a={x:(o.offsetLeft+o.offsetWidth/2)*n,y:(o.offsetTop+o.offsetHeight/2)*n},r=o.offsetWidth/2*n,c="circle"===e.type?new yi(a.x,a.y,r):new vi(o.offsetLeft*n,o.offsetTop*n,o.offsetWidth*n,o.offsetHeight*n),l=rt(s.divs,o);this._processRepulse(a,r,c,l)}))},this._engine=t,e.repulse||(e.repulse={particles:[]}),this.handleClickMode=t=>{const i=this.container.actualOptions.interactivity.modes.repulse;if(!i||t!==ao)return;e.repulse||(e.repulse={particles:[]});const s=e.repulse;s.clicking=!0,s.count=0;for(const t of e.repulse.particles)this.isEnabled(t)&&t.velocity.setTo(t.initialVelocity);s.particles=[],s.finish=!1,setTimeout((()=>{e.destroyed||(s.clicking=!1)}),1e3*i.duration)}}clear(){}init(){const t=this.container,e=t.actualOptions.interactivity.modes.repulse;e&&(t.retina.repulseModeDistance=e.distance*t.retina.pixelRatio)}async interact(){const t=this.container,e=t.actualOptions,i=t.interactivity.status===r,s=e.interactivity.events,o=s.onHover,n=o.enable,a=o.mode,c=s.onClick,l=c.enable,h=c.mode,d=s.onDiv;i&&n&&Z(ao,a)?this._hoverRepulse():l&&Z(ao,h)?this._clickRepulse():nt(ao,d,((t,e)=>this._singleSelectorRepulse(t,e)))}isEnabled(t){const e=this.container,i=e.actualOptions,s=e.interactivity.mouse,o=(t?.interactivity??i.interactivity).events,n=o.onDiv,a=o.onHover,r=o.onClick,c=ot(ao,n);if(!(c||a.enable&&s.position||r.enable&&s.clickPosition))return!1;const l=a.mode,h=r.mode;return Z(ao,l)||Z(ao,h)||c}loadModeOptions(t,...e){t.repulse||(t.repulse=new no);for(const i of e)t.repulse.load(i?.repulse)}reset(){}}class co{constructor(){this.factor=3,this.radius=200}load(t){t&&(void 0!==t.factor&&(this.factor=t.factor),void 0!==t.radius&&(this.radius=t.radius))}}class lo extends Si{constructor(t){super(t)}clear(t,e,i){t.slow.inRange&&!i||(t.slow.factor=1)}init(){const t=this.container,e=t.actualOptions.interactivity.modes.slow;e&&(t.retina.slowModeRadius=e.radius*t.retina.pixelRatio)}async interact(){}isEnabled(t){const e=this.container,i=e.interactivity.mouse,s=(t?.interactivity??e.actualOptions.interactivity).events;return s.onHover.enable&&!!i.position&&Z("slow",s.onHover.mode)}loadModeOptions(t,...e){t.slow||(t.slow=new co);for(const i of e)t.slow.load(i?.slow)}reset(t){t.slow.inRange=!1;const e=this.container,i=e.actualOptions,s=e.interactivity.mouse.position,o=e.retina.slowModeRadius,n=i.interactivity.modes.slow;if(!n||!o||o<0||!s)return;const a=T(s,t.getPosition()),r=a/o,c=n.factor,{slow:l}=t;a>o||(l.inRange=!0,l.factor=r/c)}}const ho=[0,4,2,1],uo=[8,8,4,2];class po{constructor(t){this.pos=0,this.data=new Uint8ClampedArray(t)}getString(t){const e=this.data.slice(this.pos,this.pos+t);return this.pos+=e.length,e.reduce(((t,e)=>t+String.fromCharCode(e)),"")}nextByte(){return this.data[this.pos++]}nextTwoBytes(){return this.pos+=2,this.data[this.pos-2]+(this.data[this.pos-1]<<8)}readSubBlocks(){let t="",e=0;do{e=this.data[this.pos++];for(let i=e;--i>=0;t+=String.fromCharCode(this.data[this.pos++]));}while(0!==e);return t}readSubBlocksBin(){let t=0,e=0;for(let i=0;0!==(t=this.data[this.pos+i]);i+=t+1)e+=t;const i=new Uint8Array(e);for(let e=0;0!==(t=this.data[this.pos++]);)for(let s=t;--s>=0;i[e++]=this.data[this.pos++]);return i}skipSubBlocks(){for(;0!==this.data[this.pos];this.pos+=this.data[this.pos]+1);this.pos++}}function fo(t,e){const i=[];for(let s=0;s>>3;const h=1<<1+(7&r);c&&(a.localColorTable=fo(t,h));const d=t=>{const{r:s,g:n,b:r}=(c?a.localColorTable:e.globalColorTable)[t];return{r:s,g:n,b:r,a:t===o(null)?i?~~((s+n+r)/3):0:255}},u=(()=>{try{return new ImageData(a.width,a.height,{colorSpace:"srgb"})}catch(t){if(t instanceof DOMException&&"IndexSizeError"===t.name)return null;throw t}})();if(null==u)throw new EvalError("GIF frame size is to large");const p=t.nextByte(),f=t.readSubBlocksBin(),v=1<{const i=t>>>3,s=7&t;return(f[i]+(f[i+1]<<8)+(f[i+2]<<16)&(1<>>s};if(l){for(let i=0,o=p+1,r=0,c=[[0]],l=0;l<4;l++){if(ho[l]=c.length?c.push(c[s].concat(c[s][0])):s!==v&&c.push(c[s].concat(c[i][0]));for(let s=0;s=a.height))break}n?.(t.pos/(t.data.length-1),s(!1)+1,u,{x:a.left,y:a.top},{width:e.width,height:e.height})}a.image=u,a.bitmap=await createImageBitmap(u)}else{for(let t=0,e=p+1,i=0,s=[[0]],o=-4;;){const n=t;if(t=y(i,e),i+=e,t===v){e=p+1,s.length=v+2;for(let t=0;t=s.length?s.push(s[n].concat(s[n][0])):n!==v&&s.push(s[n].concat(s[t][0]));for(let e=0;e=1<>>5,o.disposalMethod=(28&n)>>>2,o.userInputDelayFlag=2==(2&n);const a=1==(1&n);o.delayTime=10*t.nextTwoBytes();const r=t.nextByte();a&&s(r),t.pos++;break}case 255:{t.pos++;const i={identifier:t.getString(8),authenticationCode:t.getString(3),data:t.readSubBlocksBin()};e.applicationExtensions.push(i);break}case 254:e.comments.push([i(!1),t.readSubBlocks()]);break;case 1:if(0===e.globalColorTable.length)throw new EvalError("plain text extension without global color table");t.pos++,e.frames[i(!1)].plainTextData={left:t.nextTwoBytes(),top:t.nextTwoBytes(),width:t.nextTwoBytes(),height:t.nextTwoBytes(),charSize:{width:t.nextTwoBytes(),height:t.nextTwoBytes()},foregroundColor:t.nextByte(),backgroundColor:t.nextByte(),text:t.readSubBlocks()};break;default:t.skipSubBlocks()}}(t,e,s,o);break;default:throw new EvalError("undefined block found")}return!1}const yo=/(#(?:[0-9a-f]{2}){2,4}|(#[0-9a-f]{3})|(rgb|hsl)a?\((-?\d+%?[,\s]+){2,3}\s*[\d.]+%?\))|currentcolor/gi;async function mo(t){return new Promise((e=>{t.loading=!0;const i=new Image;t.element=i,i.addEventListener("load",(()=>{t.loading=!1,e()})),i.addEventListener("error",(()=>{t.element=void 0,t.error=!0,t.loading=!1,W().error(`${f} loading image: ${t.source}`),e()})),i.src=t.source}))}async function go(t){if("gif"===t.type){t.loading=!0;try{t.gifData=await async function(t,e,i){i||(i=!1);const s=await fetch(t);if(!s.ok&&404===s.status)throw new EvalError("file not found");const o=await s.arrayBuffer(),n={width:0,height:0,totalTime:0,colorRes:0,pixelAspectRatio:0,frames:[],sortFlag:!1,globalColorTable:[],backgroundImage:new ImageData(1,1,{colorSpace:"srgb"}),comments:[],applicationExtensions:[]},a=new po(new Uint8ClampedArray(o));if("GIF89a"!==a.getString(6))throw new Error("not a supported GIF file");n.width=a.nextTwoBytes(),n.height=a.nextTwoBytes();const r=a.nextByte(),c=128==(128&r);n.colorRes=(112&r)>>>4,n.sortFlag=8==(8&r);const l=1<<1+(7&r),h=a.nextByte();n.pixelAspectRatio=a.nextByte(),0!==n.pixelAspectRatio&&(n.pixelAspectRatio=(n.pixelAspectRatio+15)/64),c&&(n.globalColorTable=fo(a,l));const d=(()=>{try{return new ImageData(n.width,n.height,{colorSpace:"srgb"})}catch(t){if(t instanceof DOMException&&"IndexSizeError"===t.name)return null;throw t}})();if(null==d)throw new Error("GIF frame size is to large");const{r:u,g:p,b:f}=n.globalColorTable[h];d.data.set(c?[u,p,f,255]:[0,0,0,0]);for(let t=4;t(t&&(y=!0),v),b=t=>(null!=t&&(m=t),m);try{do{y&&(n.frames.push({left:0,top:0,width:0,height:0,disposalMethod:0,image:new ImageData(1,1,{colorSpace:"srgb"}),plainTextData:null,userInputDelayFlag:!1,delayTime:0,sortFlag:!1,localColorTable:[],reserved:0,GCreserved:0}),v++,m=-1,y=!1)}while(!await vo(a,n,i,g,b,e));n.frames.length--;for(const t of n.frames){if(t.userInputDelayFlag&&0===t.delayTime){n.totalTime=1/0;break}n.totalTime+=t.delayTime}return n}catch(t){if(t instanceof EvalError)throw new Error(`error while parsing frame ${v} "${t.message}"`);throw t}}(t.source),t.gifLoopCount=function(t){for(const e of t.applicationExtensions)if(e.identifier+e.authenticationCode==="NETSCAPE2.0")return e.data[1]+(e.data[2]<<8);return NaN}(t.gifData)??0,0===t.gifLoopCount&&(t.gifLoopCount=1/0)}catch{t.error=!0}t.loading=!1}else await mo(t)}async function bo(t){if("svg"!==t.type)return void await mo(t);t.loading=!0;const e=await fetch(t.source);e.ok?t.svgData=await e.text():(W().error(`${f} Image not found`),t.error=!0),t.loading=!1}function wo(t,e,i,s){const o=function(t,e,i){const{svgData:s}=t;if(!s)return"";const o=Ht(e,i);if(s.includes("fill"))return s.replace(yo,(()=>o));const n=s.indexOf(">");return`${s.substring(0,n)} fill="${o}"${s.substring(n)}`}(t,i,s.opacity?.value??1),n={color:i,gif:e.gif,data:{...t,svgData:o},loaded:!1,ratio:e.width/e.height,replaceColor:e.replaceColor,source:e.src};return new Promise((e=>{const i=new Blob([o],{type:"image/svg+xml"}),s=URL||window.URL||window.webkitURL||window,a=s.createObjectURL(i),r=new Image;r.addEventListener("load",(()=>{n.loaded=!0,n.element=r,e(n),s.revokeObjectURL(a)})),r.addEventListener("error",(async()=>{s.revokeObjectURL(a);const i={...t,error:!1,loading:!0};await mo(i),n.loaded=!0,n.element=i.element,e(n)})),r.src=a}))}class xo{constructor(t){this.loadImageShape=async t=>{if(!this._engine.loadImage)throw new Error(`${f} image shape not initialized`);await this._engine.loadImage({gif:t.gif,name:t.name,replaceColor:t.replaceColor??!1,src:t.src})},this._engine=t}addImage(t){this._engine.images||(this._engine.images=[]),this._engine.images.push(t)}draw(t){const{context:e,radius:i,particle:s,opacity:o,delta:n}=t,a=s.image,r=a?.element;if(a){if(e.globalAlpha=o,a.gif&&a.gifData){const t=new OffscreenCanvas(a.gifData.width,a.gifData.height),o=t.getContext("2d");if(!o)throw new Error("could not create offscreen canvas context");o.imageSmoothingQuality="low",o.imageSmoothingEnabled=!1,o.clearRect(0,0,t.width,t.height),void 0===s.gifLoopCount&&(s.gifLoopCount=a.gifLoopCount??0);let r=s.gifFrame??0;const c={x:.5*-a.gifData.width,y:.5*-a.gifData.height},l=a.gifData.frames[r];if(void 0===s.gifTime&&(s.gifTime=0),!l.bitmap)return;switch(e.scale(i/a.gifData.width,i/a.gifData.height),l.disposalMethod){case 4:case 5:case 6:case 7:case 0:o.drawImage(l.bitmap,l.left,l.top),e.drawImage(t,c.x,c.y),o.clearRect(0,0,t.width,t.height);break;case 1:o.drawImage(l.bitmap,l.left,l.top),e.drawImage(t,c.x,c.y);break;case 2:o.drawImage(l.bitmap,l.left,l.top),e.drawImage(t,c.x,c.y),o.clearRect(0,0,t.width,t.height),0===a.gifData.globalColorTable.length?o.putImageData(a.gifData.frames[0].image,c.x+l.left,c.y+l.top):o.putImageData(a.gifData.backgroundImage,c.x,c.y);break;case 3:{const i=o.getImageData(0,0,t.width,t.height);o.drawImage(l.bitmap,l.left,l.top),e.drawImage(t,c.x,c.y),o.clearRect(0,0,t.width,t.height),o.putImageData(i,0,0)}}if(s.gifTime+=n.value,s.gifTime>l.delayTime){if(s.gifTime-=l.delayTime,++r>=a.gifData.frames.length){if(--s.gifLoopCount<=0)return;r=0,o.clearRect(0,0,t.width,t.height)}s.gifFrame=r}e.scale(a.gifData.width/i,a.gifData.height/i)}else if(r){const t=a.ratio,s={x:-i,y:-i},o=2*i;e.drawImage(r,s.x,s.y,o,o/t)}e.globalAlpha=1}}getSidesCount(){return 12}async init(t){const e=t.actualOptions;if(e.preload&&this._engine.loadImage)for(const t of e.preload)await this._engine.loadImage(t)}loadShape(t){if("image"!==t.shape&&"images"!==t.shape)return;this._engine.images||(this._engine.images=[]);const e=t.shapeData;if(!e)return;this._engine.images.find((t=>t.name===e.name||t.source===e.src))||this.loadImageShape(e).then((()=>{this.loadShape(t)}))}particleInit(t,e){if("image"!==e.shape&&"images"!==e.shape)return;this._engine.images||(this._engine.images=[]);const i=this._engine.images,s=e.shapeData;if(!s)return;const o=e.getFillColor(),n=i.find((t=>t.name===s.name||t.source===s.src));if(!n)return;const a=s.replaceColor??n.replaceColor;n.loading?setTimeout((()=>{this.particleInit(t,e)})):(async()=>{let t;t=n.svgData&&o?await wo(n,s,o,e):{color:o,data:n,element:n.element,gif:n.gif,gifData:n.gifData,gifLoopCount:n.gifLoopCount,loaded:!0,ratio:s.width&&s.height?s.width/s.height:n.ratio??1,replaceColor:a,source:s.src},t.ratio||(t.ratio=1);const i={image:t,fill:s.fill??e.shapeFill,close:s.close??e.shapeClose};e.image=i.image,e.shapeFill=i.fill,e.shapeClose=i.close})()}}class _o{constructor(){this.src="",this.gif=!1}load(t){t&&(void 0!==t.gif&&(this.gif=t.gif),void 0!==t.height&&(this.height=t.height),void 0!==t.name&&(this.name=t.name),void 0!==t.replaceColor&&(this.replaceColor=t.replaceColor),void 0!==t.src&&(this.src=t.src),void 0!==t.width&&(this.width=t.width))}}class ko{constructor(t){this.id="imagePreloader",this._engine=t}getPlugin(){return{}}loadOptions(t,e){if(!e||!e.preload)return;t.preload||(t.preload=[]);const i=t.preload;for(const t of e.preload){const e=i.find((e=>e.name===t.name||e.src===t.src));if(e)e.load(t);else{const e=new _o;e.load(t),i.push(e)}}}needsPlugin(){return!0}}async function zo(t,e=!0){!function(t){t.loadImage||(t.loadImage=async e=>{if(!e.name&&!e.src)throw new Error(`${f} no image source provided`);if(t.images||(t.images=[]),!t.images.find((t=>t.name===e.name||t.source===e.src)))try{const i={gif:e.gif??!1,name:e.name??e.src,source:e.src,type:e.src.substring(e.src.length-3),error:!1,loading:!0,replaceColor:e.replaceColor,ratio:e.width&&e.height?e.width/e.height:void 0};t.images.push(i);const s=e.gif?go:e.replaceColor?bo:mo;await s(i)}catch{throw new Error(`${f} ${e.name??e.src} not found`)}})}(t);const i=new ko(t);await t.addPlugin(i,e),await t.addShape(["image","images"],new xo(t),e)}class Mo extends Re{constructor(){super(),this.sync=!1}load(t){t&&(super.load(t),void 0!==t.sync&&(this.sync=t.sync))}}class Co extends Re{constructor(){super(),this.sync=!1}load(t){t&&(super.load(t),void 0!==t.sync&&(this.sync=t.sync))}}class Po{constructor(){this.count=0,this.delay=new Mo,this.duration=new Co}load(t){t&&(void 0!==t.count&&(this.count=t.count),this.delay.load(t.delay),this.duration.load(t.duration))}}class Oo{constructor(t){this.container=t}init(t){const e=this.container,i=t.options.life;i&&(t.life={delay:e.retina.reduceFactor?C(i.delay.value)*(i.delay.sync?1:_())/e.retina.reduceFactor*1e3:0,delayTime:0,duration:e.retina.reduceFactor?C(i.duration.value)*(i.duration.sync?1:_())/e.retina.reduceFactor*1e3:0,time:0,count:i.count},t.life.duration<=0&&(t.life.duration=-1),t.life.count<=0&&(t.life.count=-1),t.life&&(t.spawning=t.life.delay>0))}isEnabled(t){return!t.destroyed}loadOptions(t,...e){t.life||(t.life=new Po);for(const i of e)t.life.load(i?.life)}update(t,e){if(!this.isEnabled(t)||!t.life)return;const i=t.life;let s=!1;if(t.spawning){if(i.delayTime+=e.value,!(i.delayTime>=t.life.delay))return;s=!0,t.spawning=!1,i.delayTime=0,i.time=0}if(-1===i.duration)return;if(t.spawning)return;if(s?i.time=0:i.time+=e.value,i.time0&&t.life.count--,0===t.life.count)return void t.destroy();const o=this.container.canvas.size,n=S(0,o.width),a=S(0,o.width);t.position.x=M(n),t.position.y=M(a),t.spawning=!0,i.delayTime=0,i.time=0,t.reset();const r=t.options.life;r&&(i.delay=1e3*C(r.delay.value),i.duration=1e3*C(r.duration.value))}}class So{draw(t){const{context:e,particle:i,radius:s}=t,o=i.shapeData;e.moveTo(-s/2,0),e.lineTo(s/2,0),e.lineCap=o?.cap??"butt"}getSidesCount(){return 1}}class Do{init(){}isEnabled(t){return!j()&&!t.destroyed&&t.container.actualOptions.interactivity.events.onHover.parallax.enable}move(t){const e=t.container,i=e.actualOptions.interactivity.events.onHover.parallax;if(j()||!i.enable)return;const s=i.force,o=e.interactivity.mouse.position;if(!o)return;const n=e.canvas.size,a=.5*n.width,r=.5*n.height,c=i.smooth,l=t.getRadius()/s,h=(o.x-a)*l,d=(o.y-r)*l,{offset:u}=t;u.x+=(h-u.x)/c,u.y+=(d-u.y)/c}}class To extends Di{constructor(t){super(t)}clear(){}init(){}async interact(t){const e=this.container;void 0===t.attractDistance&&(t.attractDistance=C(t.options.move.attract.distance)*e.retina.pixelRatio);const i=t.attractDistance,s=t.getPosition(),o=e.particles.quadTree.queryCircle(s,i);for(const e of o){if(t===e||!e.options.move.attract.enable||e.destroyed||e.spawning)continue;const i=e.getPosition(),{dx:o,dy:n}=D(s,i),a=t.options.move.attract.rotate,r=o/(1e3*a.x),c=n/(1e3*a.y),l=e.size.value/t.size.value,h=1/l;t.velocity.x-=r*l,t.velocity.y-=c*l,e.velocity.x+=r*h,e.velocity.y+=c*h}}isEnabled(t){return t.options.move.attract.enable}reset(){}}function Ro(t,e,i,s,o,n){const a=k(t.options.collisions.absorb.speed*o.factor/10,0,s);t.size.value+=a/2,i.size.value-=a,s<=n&&(i.size.value=0,i.destroy())}const Eo=t=>{void 0===t.collisionMaxSpeed&&(t.collisionMaxSpeed=C(t.options.collisions.maxSpeed)),t.velocity.length>t.collisionMaxSpeed&&(t.velocity.length=t.collisionMaxSpeed)};function Io(t,e){lt(ct(t),ct(e)),Eo(t),Eo(e)}function Lo(t,e,i,s){switch(t.options.collisions.mode){case"absorb":!function(t,e,i,s){const o=t.getRadius(),n=e.getRadius();void 0===o&&void 0!==n?t.destroy():void 0!==o&&void 0===n?e.destroy():void 0!==o&&void 0!==n&&(o>=n?Ro(t,0,e,n,i,s):Ro(e,0,t,o,i,s))}(t,e,i,s);break;case"bounce":Io(t,e);break;case"destroy":!function(t,e){t.unbreakable||e.unbreakable||Io(t,e),void 0===t.getRadius()&&void 0!==e.getRadius()?t.destroy():void 0!==t.getRadius()&&void 0===e.getRadius()?e.destroy():void 0!==t.getRadius()&&void 0!==e.getRadius()&&(t.getRadius()>=e.getRadius()?e:t).destroy()}(t,e)}}class Ao extends Di{constructor(t){super(t)}clear(){}init(){}async interact(t,e){if(t.destroyed||t.spawning)return;const i=this.container,s=t.getPosition(),o=t.getRadius(),n=i.particles.quadTree.queryCircle(s,2*o);for(const a of n){if(t===a||!a.options.collisions.enable||t.options.collisions.mode!==a.options.collisions.mode||a.destroyed||a.spawning)continue;const n=a.getPosition(),r=a.getRadius();if(Math.abs(Math.round(s.z)-Math.round(n.z))>o+r)continue;T(s,n)>o+r||Lo(t,a,e,i.retina.pixelRatio)}}isEnabled(t){return t.options.collisions.enable}reset(){}}class Fo extends yi{constructor(t,e,i,s){super(t,e,i),this.canvasSize=s,this.canvasSize={...s}}contains(t){const{width:e,height:i}=this.canvasSize,{x:s,y:o}=t;return super.contains(t)||super.contains({x:s-e,y:o})||super.contains({x:s-e,y:o-i})||super.contains({x:s,y:o-i})}intersects(t){if(super.intersects(t))return!0;const e=t,i=t,s={x:t.position.x-this.canvasSize.width,y:t.position.y-this.canvasSize.height};if(void 0!==i.radius){const t=new yi(s.x,s.y,2*i.radius);return super.intersects(t)}if(void 0!==e.size){const t=new vi(s.x,s.y,2*e.size.width,2*e.size.height);return super.intersects(t)}return!1}}class Bo{constructor(){this.blur=5,this.color=new ce,this.color.value="#000",this.enable=!1}load(t){t&&(void 0!==t.blur&&(this.blur=t.blur),this.color=ce.create(this.color,t.color),void 0!==t.enable&&(this.enable=t.enable))}}class qo{constructor(){this.enable=!1,this.frequency=1}load(t){t&&(void 0!==t.color&&(this.color=ce.create(this.color,t.color)),void 0!==t.enable&&(this.enable=t.enable),void 0!==t.frequency&&(this.frequency=t.frequency),void 0!==t.opacity&&(this.opacity=t.opacity))}}class Ho{constructor(){this.blink=!1,this.color=new ce,this.color.value="#fff",this.consent=!1,this.distance=100,this.enable=!1,this.frequency=1,this.opacity=1,this.shadow=new Bo,this.triangles=new qo,this.width=1,this.warp=!1}load(t){t&&(void 0!==t.id&&(this.id=t.id),void 0!==t.blink&&(this.blink=t.blink),this.color=ce.create(this.color,t.color),void 0!==t.consent&&(this.consent=t.consent),void 0!==t.distance&&(this.distance=t.distance),void 0!==t.enable&&(this.enable=t.enable),void 0!==t.frequency&&(this.frequency=t.frequency),void 0!==t.opacity&&(this.opacity=t.opacity),this.shadow.load(t.shadow),this.triangles.load(t.triangles),void 0!==t.width&&(this.width=t.width),void 0!==t.warp&&(this.warp=t.warp))}}function Vo(t,e,i,s,o){const{dx:n,dy:a,distance:r}=D(t,e);if(!o||r<=i)return r;const c={x:Math.abs(n),y:Math.abs(a)},l=Math.min(c.x,s.width-c.x),h=Math.min(c.y,s.height-c.y);return Math.sqrt(l**2+h**2)}class Uo extends Di{constructor(t){super(t),this._setColor=t=>{if(!t.options.links)return;const e=this.linkContainer,i=t.options.links;let s=void 0===i.id?e.particles.linksColor:e.particles.linksColors.get(i.id);if(s)return;s=Wt(i.color,i.blink,i.consent),void 0===i.id?e.particles.linksColor=s:e.particles.linksColors.set(i.id,s)},this.linkContainer=t}clear(){}init(){this.linkContainer.particles.linksColor=void 0,this.linkContainer.particles.linksColors=new Map}async interact(t){if(!t.options.links)return;t.links=[];const e=t.getPosition(),i=this.container,s=i.canvas.size;if(e.x<0||e.y<0||e.x>s.width||e.y>s.height)return;const o=t.options.links,n=o.opacity,a=t.retina.linksDistance??0,r=o.warp,c=r?new Fo(e.x,e.y,a,s):new yi(e.x,e.y,a),l=i.particles.quadTree.query(c);for(const i of l){const c=i.options.links;if(t===i||!c?.enable||o.id!==c.id||i.spawning||i.destroyed||!i.links||t.links.some((t=>t.destination===i))||i.links.some((e=>e.destination===t)))continue;const l=i.getPosition();if(l.x<0||l.y<0||l.x>s.width||l.y>s.height)continue;const h=Vo(e,l,a,s,r&&c.warp);if(h>a)continue;const d=(1-h/a)*n;this._setColor(t),t.links.push({destination:i,opacity:d})}}isEnabled(t){return!!t.options.links?.enable}loadParticlesOptions(t,...e){t.links||(t.links=new Ho);for(const i of e)t.links.load(i?.links)}reset(){}}function Wo(t,e){const i=((s=t.map((t=>t.id))).sort(((t,e)=>t-e)),s.join("_"));var s;let o=e.get(i);return void 0===o&&(o=_(),e.set(i,o)),o}class $o{constructor(t){this.container=t,this._drawLinkLine=(t,e)=>{const i=t.options.links;if(!i?.enable)return;const s=this.container,o=s.actualOptions,n=e.destination,a=t.getPosition(),r=n.getPosition();let c=e.opacity;s.canvas.draw((e=>{let l;const h=t.options.twinkle?.lines;if(h?.enable){const t=h.frequency,e=St(h.color);_(){const s=t.options.links;if(!s?.enable)return;const o=s.triangles;if(!o.enable)return;const n=this.container,a=n.actualOptions,r=e.destination,c=i.destination,l=o.opacity??(e.opacity+i.opacity)/2;l<=0||n.canvas.draw((e=>{const i=t.getPosition(),h=r.getPosition(),d=c.getPosition(),u=t.retina.linksDistance??0;if(T(i,h)>u||T(d,h)>u||T(d,i)>u)return;let p=St(o.color);if(!p){const e=void 0!==s.id?n.particles.linksColors.get(s.id):n.particles.linksColor;p=Ut(t,r,e)}p&&function(t){const{context:e,pos1:i,pos2:s,pos3:o,backgroundMask:n,colorTriangle:a,opacityTriangle:r}=t;!function(t,e,i,s){t.beginPath(),t.moveTo(e.x,e.y),t.lineTo(i.x,i.y),t.lineTo(s.x,s.y),t.closePath()}(e,i,s,o),n.enable&&(e.globalCompositeOperation=n.composite),e.fillStyle=qt(a,r),e.fill()}({context:e,pos1:i,pos2:h,pos3:d,backgroundMask:a.backgroundMask,colorTriangle:p,opacityTriangle:l})}))},this._drawTriangles=(t,e,i,s)=>{const o=i.destination;if(!t.links?.triangles.enable||!o.options.links?.triangles.enable)return;const n=o.links?.filter((t=>{const e=this._getLinkFrequency(o,t.destination);return o.options.links&&e<=o.options.links.frequency&&s.findIndex((e=>e.destination===t.destination))>=0}));if(n?.length)for(const s of n){const n=s.destination;this._getTriangleFrequency(e,o,n)>t.links.triangles.frequency||this._drawLinkTriangle(e,i,s)}},this._getLinkFrequency=(t,e)=>Wo([t,e],this._freqs.links),this._getTriangleFrequency=(t,e,i)=>Wo([t,e,i],this._freqs.triangles),this._freqs={links:new Map,triangles:new Map}}drawParticle(t,e){const{links:i,options:s}=e;if(!i||i.length<=0)return;const o=i.filter((t=>s.links&&this._getLinkFrequency(e,t.destination)<=s.links.frequency));for(const t of o)this._drawTriangles(s,e,t,o),t.opacity>0&&(e.retina.linksWidth??0)>0&&this._drawLinkLine(e,t)}async init(){this._freqs.links=new Map,this._freqs.triangles=new Map}particleCreated(t){if(t.links=[],!t.options.links)return;const e=this.container.retina.pixelRatio,{retina:i}=t,{distance:s,width:o}=t.options.links;i.linksDistance=s*e,i.linksWidth=o*e}particleDestroyed(t){t.links=[]}}class jo{constructor(){this.id="links"}getPlugin(t){return new $o(t)}loadOptions(){}needsPlugin(){return!0}}async function Go(t,e=!0){await async function(t,e=!0){await t.addInteractor("particlesLinks",(t=>new Uo(t)),e)}(t,e),await async function(t,e=!0){const i=new jo;await t.addPlugin(i,e)}(t,e)}class No{draw(t){const{context:e,particle:i,radius:s}=t,o=this.getCenter(i,s),n=this.getSidesData(i,s),a=n.count.numerator*n.count.denominator,r=n.count.numerator/n.count.denominator,c=180*(r-2)/r,l=Math.PI-Math.PI*c/180;if(e){e.beginPath(),e.translate(o.x,o.y),e.moveTo(0,0);for(let t=0;t0?"counter-clockwise":"clockwise"}switch(i){case"counter-clockwise":case"counterClockwise":t.rotate.status="decreasing";break;case"clockwise":t.rotate.status="increasing"}const s=e.animation;s.enable&&(t.rotate.decay=1-C(s.decay),t.rotate.velocity=C(s.speed)/360*this.container.retina.reduceFactor,s.sync||(t.rotate.velocity*=_())),t.rotation=t.rotate.value}isEnabled(t){const e=t.options.rotate;return!!e&&(!t.destroyed&&!t.spawning&&e.animation.enable&&!e.path)}loadOptions(t,...e){t.rotate||(t.rotate=new Jo);for(const i of e)t.rotate.load(i?.rotate)}update(t,e){this.isEnabled(t)&&(!function(t,e){const i=t.rotate,s=t.options.rotate;if(!i||!s)return;const o=s.animation,n=(i.velocity??0)*e.factor,a=2*Math.PI,r=i.decay??1;o.enable&&("increasing"===i.status?(i.value+=n,i.value>a&&(i.value-=a)):(i.value-=n,i.value<0&&(i.value+=a)),i.velocity&&1!==r&&(i.velocity*=r))}(t,e),t.rotation=t.rotate?.value??0)}}const tn=Math.sqrt(2);class en{draw(t){const{context:e,radius:i}=t,s=i/tn,o=2*s;e.rect(-s,-s,o,o)}getSidesCount(){return 4}}class sn{draw(t){const{context:e,particle:i,radius:s}=t,o=i.sides,n=i.starInset??2;e.moveTo(0,0-s);for(let t=0;t0&&(e.loops??0)>(e.maxLoops??0))return;if(e.time||(e.time=0),(e.delayTime??0)>0&&e.time<(e.delayTime??0)&&(e.time+=t.value),(e.delayTime??0)>0&&e.time<(e.delayTime??0))return;const n=M(i.offset),a=(e.velocity??0)*t.factor+3.6*n,r=e.decay??1;o&&"increasing"!==e.status?(e.value-=a,e.value<0&&(e.loops||(e.loops=0),e.loops++,e.status="increasing",e.value+=e.value)):(e.value+=a,e.value>s&&(e.loops||(e.loops=0),e.loops++,o&&(e.status="decreasing",e.value-=e.value%s))),e.velocity&&1!==r&&(e.velocity*=r),e.value>s&&(e.value%=s)}class nn{constructor(t){this.container=t}init(t){const e=this.container,i=t.options,s=ut(i.stroke,t.id,i.reduceDuplicates);t.strokeWidth=C(s.width)*e.retina.pixelRatio,t.strokeOpacity=C(s.opacity??1),t.strokeAnimation=s.color?.animation;const o=Rt(s.color)??t.getFillColor();o&&(t.strokeColor=jt(o,t.strokeAnimation,e.retina.reduceFactor))}isEnabled(t){const e=t.strokeAnimation,{strokeColor:i}=t;return!t.destroyed&&!t.spawning&&!!e&&(void 0!==i?.h.value&&i.h.enable||void 0!==i?.s.value&&i.s.enable||void 0!==i?.l.value&&i.l.enable)}update(t,e){this.isEnabled(t)&&function(t,e){if(!t.strokeColor||!t.strokeAnimation)return;const{h:i,s,l:o}=t.strokeColor,{h:n,s:a,l:r}=t.strokeAnimation;i&&on(e,i,n,360,!1),s&&on(e,s,a,100,!0),o&&on(e,o,r,100,!0)}(t,e)}}async function an(t,e=!0){await async function(t,e=!0){await t.addMover("parallax",(()=>new Do),e)}(t,!1),await async function(t,e=!0){await t.addInteractor("externalAttract",(e=>new Es(t,e)),e)}(t,!1),await async function(t,e=!0){await t.addInteractor("externalBounce",(t=>new As(t)),e)}(t,!1),await async function(t,e=!0){await t.addInteractor("externalBubble",(t=>new Us(t)),e)}(t,!1),await async function(t,e=!0){await t.addInteractor("externalConnect",(t=>new Ns(t)),e)}(t,!1),await async function(t,e=!0){await t.addInteractor("externalGrab",(t=>new Qs(t)),e)}(t,!1),await async function(t,e=!0){await t.addInteractor("externalPause",(t=>new Js(t)),e)}(t,!1),await async function(t,e=!0){await t.addInteractor("externalPush",(t=>new to(t)),e)}(t,!1),await async function(t,e=!0){await t.addInteractor("externalRemove",(t=>new io(t)),e)}(t,!1),await async function(t,e=!0){await t.addInteractor("externalRepulse",(e=>new ro(t,e)),e)}(t,!1),await async function(t,e=!0){await t.addInteractor("externalSlow",(t=>new lo(t)),e)}(t,!1),await async function(t,e=!0){await t.addInteractor("particlesAttract",(t=>new To(t)),e)}(t,!1),await async function(t,e=!0){await t.addInteractor("particlesCollisions",(t=>new Ao(t)),e)}(t,!1),await Go(t,!1),await async function(){b("ease-in-quad",(t=>t**2)),b("ease-out-quad",(t=>1-(1-t)**2)),b("ease-in-out-quad",(t=>t<.5?2*t**2:1-(-2*t+2)**2/2))}(),await async function(t,e=!0){await t.addShape(Os,new Ds,e)}(t,!1),await zo(t,!1),await async function(t,e=!0){await t.addShape("line",new So,e)}(t,!1),await Zo(t,!1),await async function(t,e=!0){await t.addShape(["edge","square"],new en,e)}(t,!1),await async function(t,e=!0){await t.addShape("star",new sn,e)}(t,!1),await async function(t,e=!0){await t.addParticleUpdater("life",(t=>new Oo(t)),e)}(t,!1),await async function(t,e=!0){await t.addParticleUpdater("rotate",(t=>new Ko(t)),e)}(t,!1),await async function(t,e=!0){await t.addParticleUpdater("strokeColor",(t=>new nn(t)),e)}(t,!1),await Ps(t,e)}const rn=["text","character","char","multiline-text"];class cn{constructor(){this._drawLine=(t,e,i,s,o,n)=>{const a={x:-(e.length*i/2),y:i/2},r=2*i;n?t.fillText(e,a.x,a.y+r*o):t.strokeText(e,a.x,a.y+r*o)}}draw(t){const{context:e,particle:i,radius:s,opacity:o}=t,n=i.shapeData;if(!n)return;const a=n.value;if(void 0===a)return;void 0===i.text&&(i.text=ut(a,i.randomIndexData));const r=i.text,c=n.style??"",l=n.weight??"400",h=2*Math.round(s),d=n.font??"Verdana",u=i.shapeFill,p=r?.split("\n");if(p){e.font=`${c} ${l} ${h}px "${d}"`,e.globalAlpha=o;for(let t=0;tZ(t,e.particles.shape.type)))){const t=rn.map((t=>e.particles.shape.options[t])).find((t=>!!t)),i=[];dt(t,(t=>{i.push(Q(t.font,t.weight))})),await Promise.all(i)}}particleInit(t,e){if(!e.shape||!rn.includes(e.shape))return;const i=e.shapeData;if(void 0===i)return;const s=i.value;void 0!==s&&(e.text=ut(s,e.randomIndexData))}}class ln{constructor(){this.enable=!1,this.speed=0,this.decay=0,this.sync=!1}load(t){t&&(void 0!==t.enable&&(this.enable=t.enable),void 0!==t.speed&&(this.speed=S(t.speed)),void 0!==t.decay&&(this.decay=S(t.decay)),void 0!==t.sync&&(this.sync=t.sync))}}class hn extends Re{constructor(){super(),this.animation=new ln,this.direction="clockwise",this.enable=!1,this.value=0}load(t){super.load(t),t&&(this.animation.load(t.animation),void 0!==t.direction&&(this.direction=t.direction),void 0!==t.enable&&(this.enable=t.enable))}}class dn{constructor(t){this.container=t}getTransformValues(t){const e=t.tilt?.enable&&t.tilt;return{b:e?Math.cos(e.value)*e.cosDirection:void 0,c:e?Math.sin(e.value)*e.sinDirection:void 0}}init(t){const e=t.options.tilt;if(!e)return;t.tilt={enable:e.enable,value:C(e.value)*Math.PI/180,sinDirection:_()>=.5?1:-1,cosDirection:_()>=.5?1:-1};let i=e.direction;if("random"===i){i=Math.floor(2*_())>0?"counter-clockwise":"clockwise"}switch(i){case"counter-clockwise":case"counterClockwise":t.tilt.status="decreasing";break;case"clockwise":t.tilt.status="increasing"}const s=t.options.tilt?.animation;s?.enable&&(t.tilt.decay=1-C(s.decay),t.tilt.velocity=C(s.speed)/360*this.container.retina.reduceFactor,s.sync||(t.tilt.velocity*=_()))}isEnabled(t){const e=t.options.tilt?.animation;return!t.destroyed&&!t.spawning&&!!e?.enable}loadOptions(t,...e){t.tilt||(t.tilt=new hn);for(const i of e)t.tilt.load(i?.tilt)}update(t,e){this.isEnabled(t)&&function(t,e){if(!t.tilt||!t.options.tilt)return;const i=t.options.tilt.animation,s=(t.tilt.velocity??0)*e.factor,o=2*Math.PI,n=t.tilt.decay??1;i.enable&&("increasing"===t.tilt.status?(t.tilt.value+=s,t.tilt.value>o&&(t.tilt.value-=o)):(t.tilt.value-=s,t.tilt.value<0&&(t.tilt.value+=o)),t.tilt.velocity&&1!==n&&(t.tilt.velocity*=n))}(t,e)}}class un{constructor(){this.enable=!1,this.frequency=.05,this.opacity=1}load(t){t&&(void 0!==t.color&&(this.color=ce.create(this.color,t.color)),void 0!==t.enable&&(this.enable=t.enable),void 0!==t.frequency&&(this.frequency=t.frequency),void 0!==t.opacity&&(this.opacity=S(t.opacity)))}}class pn{constructor(){this.lines=new un,this.particles=new un}load(t){t&&(this.lines.load(t.lines),this.particles.load(t.particles))}}class fn{getColorStyles(t,e,i,s){const o=t.options.twinkle;if(!o)return{};const n=o.particles,a=n.enable&&_()a&&(s.angle-=a),r.x+=n*Math.cos(s.angle),r.y+=n*Math.abs(Math.sin(s.angle))}(t,e)}}async function gn(t,e=!0){await async function(t,e=!0){await t.addParticleUpdater("destroy",(e=>new $i(t,e)),e)}(t,!1),await async function(t,e=!0){await t.addParticleUpdater("roll",(()=>new fs),e)}(t,!1),await async function(t,e=!0){await t.addParticleUpdater("tilt",(t=>new dn(t)),e)}(t,!1),await async function(t,e=!0){await t.addParticleUpdater("twinkle",(()=>new fn),e)}(t,!1),await async function(t,e=!0){await t.addParticleUpdater("wobble",(t=>new mn(t)),e)}(t,!1),await async function(t,e=!0){await t.addShape(rn,new cn,e)}(t,!1),await async function(t,e=!0){await t.addInteractor("externalTrail",(t=>new ds(t)),e)}(t,!1),await async function(t,e=!0){await t.addPlugin(new Fi,e)}(t,!1),await async function(t,e=!0){t.emitterShapeManager||(t.emitterShapeManager=new es(t)),t.addEmitterShapeGenerator||(t.addEmitterShapeGenerator=(e,i)=>{t.emitterShapeManager?.addShapeGenerator(e,i)});const i=new ss(t);await t.addPlugin(i,e)}(t,!1),await async function(t,e=!0){const i=t;i.addEmitterShapeGenerator&&i.addEmitterShapeGenerator("circle",new ns),await i.refresh(e)}(t,!1),await async function(t,e=!0){const i=t;i.addEmitterShapeGenerator&&i.addEmitterShapeGenerator("square",new cs),await i.refresh(e)}(t,!1),await an(t,e)}return gn(Ti),e})())); \ No newline at end of file diff --git a/docs/overrides/fancylogo.txt b/docs/overrides/fancylogo.txt new file mode 100644 index 00000000..230d5476 --- /dev/null +++ b/docs/overrides/fancylogo.txt @@ -0,0 +1,257 @@ +--- +hide: +- navigation +- toc +--- + +
+ +
+ + +
+
+
+ + +
+
Loading...
+
+
+ AI4CO Logo +
+
+ + +
+
+
\ No newline at end of file diff --git a/docs/overrides/main.html b/docs/overrides/main.html new file mode 100644 index 00000000..01fd277c --- /dev/null +++ b/docs/overrides/main.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} +{% block content %} +{% if page.nb_url %} + {% set path_parts = page.url.strip('/').split('/') %} + {% set last_part = path_parts[-1] %} + {% set notebook_url = page.url ~ last_part ~ '.ipynb' %} + + {% include ".icons/material/download.svg" %} + +{% endif %} +{{ super() }} +{% endblock content %} \ No newline at end of file diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css new file mode 100644 index 00000000..58d3e427 --- /dev/null +++ b/docs/stylesheets/extra.css @@ -0,0 +1,30 @@ +/* Custom colors */ +:root { + --md-primary-fg-color: #B92B0F; + --md-primary-fg-color--light: #F05F42; + --md-primary-fg-color--dark: #B92B0F; + + --md-accent-fg-color: #B92B0F; + --md-accent-fg-color--transparent: var(--md-accent-fg-color); /* Default to current color */ + --md-accent-bg-color: #ffffff; + --md-accent-bg-color--light: #B92B0F; + } + +[data-md-color-scheme="default"] { + --md-accent-fg-color--transparent: #f8d2cb; /* Transparent color for 'default' scheme */ +} + +[data-md-color-scheme="slate"] { + --md-accent-fg-color--transparent: #492821; /* Transparent color for 'default' scheme */ +} + +/* Ensure code blocks wrap text */ +.codehilite pre { + white-space: pre-wrap; /* Allow text to wrap within the pre element */ + word-break: break-word; /* Break the word at the edge of the container if necessary */ +} + +/* Improve overall readability of code by adding some padding */ +.codehilite { + padding: 8px; /* Adjust padding to fit your design */ +} diff --git a/docs/stylesheets/mkdocstrings.css b/docs/stylesheets/mkdocstrings.css new file mode 100644 index 00000000..abea38a6 --- /dev/null +++ b/docs/stylesheets/mkdocstrings.css @@ -0,0 +1,54 @@ +/* Indentation. */ +div.doc-contents:not(.first) { + padding-left: 15px; + border-left: .05rem solid var(--md-typeset-table-color); +} + + +/* Fancier color for operators such as * and |. */ +.doc-signature .o { + color: var(--md-code-hl-special-color); +} + +/* Fancier color for constants such as None, True, and False. */ +.doc-signature .kc { + color: var(--md-code-hl-constant-color); +} + +/* Fancier color for built-in types (only useful when cross-references are used). */ +.doc-signature .n > a[href^="https://docs.python.org/"][href*="/functions.html#"], +.doc-signature .n > a[href^="https://docs.python.org/"][href*="/stdtypes.html#"] { + color: var(--md-code-hl-constant-color); +} + + +/* Nice names only in TOC */ +.doc-symbol-toc.doc-symbol-method::after { + content: "m"; +} + +.doc-symbol-toc.doc-symbol-function::after { + content: "f"; +} + +.doc-symbol-toc.doc-symbol-class::after { + content: "C"; +} + +.doc-symbol-toc.doc-symbol-module::after { + content: "M"; +} + +.doc-symbol-toc.doc-symbol-attribute::after { + content: "A"; +} + +.doc-symbol-toc.doc-symbol-parameter::after { + content: "P"; +} + +/* Line under link as solid */ +.doc-signature .autorefs { + color: inherit; + border-bottom: 1px solid currentcolor; +} \ No newline at end of file diff --git a/examples/1-quickstart/1-quickstart.ipynb b/examples/1-quickstart/1-quickstart.ipynb new file mode 100644 index 00000000..f8d9c15e --- /dev/null +++ b/examples/1-quickstart/1-quickstart.ipynb @@ -0,0 +1,455 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# RL4CO Quickstart Notebook\n", + "\n", + "\"Open\n", + "\n", + "[**Documentation**](https://rl4co.readthedocs.io/) | [**Getting Started**](https://github.com/ai4co/rl4co/tree/main#getting-started) | [**Usage**](https://github.com/ai4co/rl4co/tree/main#usage) | [**Contributing**](#contributing) | [**Paper**](https://arxiv.org/abs/2306.17100) | [**Citation**](#cite-us)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this notebook we will train the AttentionModel (AM) on the TSP environment for 20 nodes. On a GPU, this should less than 2 minutes! 🚀" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Alt text](https://user-images.githubusercontent.com/48984123/245925317-0db4efdd-1c93-4991-8f09-f3c6c1f35d60.png)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Installation" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "## Uncomment the following line to install the package from PyPI\n", + "## You may need to restart the runtime in Colab after this\n", + "## Remember to choose a GPU runtime for faster training!\n", + "\n", + "# !pip install rl4co" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The autoreload extension is already loaded. To reload it, use:\n", + " %reload_ext autoreload\n" + ] + } + ], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "import torch\n", + "\n", + "from rl4co.envs import TSPEnv\n", + "from rl4co.models import AttentionModelPolicy, REINFORCE\n", + "from rl4co.utils.trainer import RL4COTrainer" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Environment, Policy and Model\n", + "\n", + "Full documentation of:https://rl4.co/docs/content/api/envs/base/\n", + "\n", + "- Base environment class [here](https://rl4.co/docs/content/api/envs/base/)\n", + "- Base policy class [here](https://rl4.co/docs/content/api/networks/base_policies/)\n", + "- Base model class [here](https://rl4.co/docs/content/api/rl/base/)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "# RL4CO env based on TorchRL\n", + "env = TSPEnv(generator_params={'num_loc': 50})\n", + "\n", + "# Policy: neural network, in this case with encoder-decoder architecture\n", + "policy = AttentionModelPolicy(env_name=env.name, \n", + " embed_dim=128,\n", + " num_encoder_layers=3,\n", + " num_heads=8,\n", + " )\n", + "\n", + "# RL Model: REINFORCE and greedy rollout baseline\n", + "model = REINFORCE(env, \n", + " policy,\n", + " baseline=\"rollout\",\n", + " batch_size=512,\n", + " train_data_size=100_000,\n", + " val_data_size=10_000,\n", + " optimizer_kwargs={\"lr\": 1e-4},\n", + " ) " + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Test greedy rollout with untrained model and plot" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Problem 1 | Cost: 10.648\n", + "Problem 2 | Cost: 9.375\n", + "Problem 3 | Cost: 11.713\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGdCAYAAADAAnMpAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAADmNklEQVR4nOydd1hTydfHvwmh995BLIsFuyL2XhDL2gvYe29r17V311UXey8oduwVddW1YlfsggUBKUqvyXn/8CU/LkkggYRQ5vM899E7d+bMmYTce+7MmXN4RERgMBgMBoPBUBN8dSvAYDAYDAajdMOMEQaDwWAwGGqFGSMMBoPBYDDUCjNGGAwGg8FgqBVmjDAYDAaDwVArzBhhMBgMBoOhVpgxwmAwGAwGQ60wY4TBYDAYDIZaEahbAXkQiUT49u0bDA0NwePx1K0Og8FgMBgMOSAiJCQkwM7ODny+7PmPYmGMfPv2DY6OjupWg8FgMBgMRj748uULHBwcZF4vFsaIoaEhgF+DMTIyUrM2DAaDwWAw5CE+Ph6Ojo7i57gsioUxkrU0Y2RkxIwRBoPBYDCKGXm5WDAHVgaDwWAwGGqFGSMMBoPBYDDUCjNGGAwGg8FgqBVmjDAYDAaDwVArzBhhMBgMBoOhVpgxwmAwGAwGQ60wY4TBYDAYDIZaYcYIg8FgMBgMtcKMEQaDwWAwGGpFYWPkxo0b6NixI+zs7MDj8RAQEJBnm+vXr6NWrVrQ1tZG+fLlsXv37nyoymAwGAwGoySisDGSlJSE6tWrY8OGDXLVDwkJgZeXF5o3b44nT55g4sSJGDp0KC5evKiwsgwGg8FgMEoeCuem8fT0hKenp9z1N2/eDBcXF/z1118AgEqVKuHWrVv4+++/0bZtW0W7ZzAYDAaDUcJQuc/InTt30KpVK05Z27ZtcefOHZlt0tLSEB8fzzkYDAaDwWCUTFRujERERMDa2ppTZm1tjfj4eKSkpEhts2zZMhgbG4sPR0dHVavJYDAYDAZDTRTJ3TQzZ85EXFyc+Pjy5Yu6VWIwGACEIsKdDzE4+SQMdz7EQCgidavEYDBKAAr7jCiKjY0NIiMjOWWRkZEwMjKCrq6u1Dba2trQ1tZWtWoMBkMBLrwIx4LTwQiPSxWX2RrrYF7HymjnZqvy/oUiwv2QWHxPSIWVoQ7cXcygweepvF8Gg6F6VG6M1K9fH+fOneOUXb58GfXr11d11wwGQ0lceBGOUfsfIec8SERcKkbtf4RNPrVUapCo2xBiMBiqReFlmsTERDx58gRPnjwB8Gvr7pMnT/D582cAv5ZY+vfvL64/cuRIfPz4EdOmTcPr16+xceNGHD58GJMmTVLOCBgMRp6kpaXh7du3iI6ORmZmpkJthSLCgtPBIADp30OQEvJYfC3LOFlwOlhlSzZZhlB2QwT4nyF04UW4SvplMBiFh8IzI0FBQWjevLn4fPLkyQCAAQMGYPfu3QgPDxcbJgDg4uKCs2fPYtKkSVi3bh0cHBywfft2tq2XwShEtLS08Oeff+LQoUMAACMjI5iamsLMzAxmZmbi/0srC40T4e2/J5D08hrSvgZDYGIDu2FbwONrAPhlkITHpeJ+SCzqlzNXqt7ZDSFRWhL42vriawSAh1+GUOvKNmzJhsEoxvCIqMh7oMXHx8PY2BhxcXEwMjJStzoMRrEkOTkZjRs3xqNHjwosy6LLbOj/xl1qXde7BjrXsC+w7Ozc+RCDPtvuIun1LcRe+AeW3edBx6GyRL2DwzyUbggxGIyCI+/zW+U+IwwGo2igp6eHgIAA1K1bV8KpXFGSnl6UMEasDHXybCcSiZCYmIj4+HgkJCSID1nnLz9F4tvdB8iICgUAfD8yH7b910DT3IEj93tCqpTeGAxGcYEZIwxGCSc8PBy3b98WH7GxsfmWJTC2hmHtjjCo1lpcxgNgY/xrd4s0Hj16hG7duiEqKgpJSUn57hsAKD0ZMRd9YdN3OadcHkOIwWAUXZgxwmCUIDIzM/H8+XOO8REaGlpgudXrNUK4fXPolqsD/L+vCPDLEAGAeR0ry/TZqFWrFrZt24ZOnToVWA9NyzKw6PAHp//cDCEGg1E8YMYIg1GM+fHjB+7evSs2PO7du1fg2YcsdHR00K9fP4wfPx5ubm5St9fayLm9tlWrVrh48SK8vLyQkJCQP32ca8Cyy0yxE6s8hhCDwSgeMGOEwSgmEBHevn3LmfUIDg5WSAaPx4OhoWGu+Z7s7e0xbtw4DB06FObm/3MKbedmi9aVbRQOPJaRkYFLly7Bz89P4W3FWbTs1AMJdQYjMkkoLpPXEGIwGEUfZowwGEWU5ORkPHjwQGx43LlzBzExMQrJMDIyQt26daGrq4vnz5/j06dPMg2RWrVqYebMmfj9998hEEi/NWjweXLtWiEi3Lt3D/v378ehQ4cQHR2tkN7ZmTt3LhYsWAARgUVgZTBKKMwYYTCKCF++fOHMejx58kThmYQKFSqgQYMGaNCgAcqUKYPLly9jx44d+PHjh9T6PB4PLVu2xIoVK1CrVq0Cj+Ht27fw8/ODn58fPnz4UCBZGhoa2Lx5M4YOHfrrnAe2fZfBKKEwY4TBUAMZGRl48uQJx/j4+vWrQjJ0dHRQt25dsfFRv359WFhY4ObNm1i3bh0CAgIgEomktuXxePDy8sLmzZthb1+w2CCRkZHw9/eHn58fHjx4kGtdMzMzuLi44OHDh7nW09fXx5EjR+Dp6Vkg3RgMRWE5kNQDM0YYjEIgOjoad+7cERseDx48QEpKikIy7Ozs0LBhQ7HxUaNGDWhpaQEAUlNTcfDgQaxfv16cqkEadevWRePGjTF9+nRYWVnlezyJiYkICAjA/v37ceXKFQiFQpl1dXR00LFjR/j4+KBdu3ZYuXKl2Bjh8XjIGXfRxsYGZ8+eVcpMDYOhCCwHkvpgxgiDoWREIhFevXrFmfV4+/atQjI0NDRQo0YNseHRoEEDODo6gsfjvqF9+/YNGzduxJYtW2T6ZQgEAvTo0QPjx4+Hh4dHvseVkZGBy5cvw8/PDwEBAUhOTpZZl8fjoUWLFvD29kbXrl1hbGwsvvbp0ycAv2Y/cu78qVSpEs6dO4cyZcrkW08GIz9ceBGOkfuCQEIhwAN4GpoACi8ZZGmHGSMMRgFJSEjA/fv3xYbH3bt38fPnT4VkmJqacgyPunXrQl9fX2b9u3fvYt26dTh69KhMvxILCwuMGDECo0aNyvdSDBHh/v37YkfUqKioXOvXrFkT3t7e6N27t8w+379/D0tLSwlZTZo0QUBAAExNTfOlK6NwISJkZmYiIyND4pBVrqprypCblp4B0K9lTcM6nWHWctivcYLlQCoMmDHCYCgAESE0NJQz6/Hs2TOZvhmyqFSpEsf4+O2338Dn555EOz09HUeOHMH69etx//59mfWqV6+OCRMmoE+fPtDRyV9k0nfv3sHPzw/79+/P0xHV2dkZ3t7e8Pb2RuXKknljsvP582d8/PhRwhDp2bMn9uzZk299izpEBKFQqJYHtaoe8LktzRV3KIObXkCVySAZv2DGCCPfxMfH49y5czhz5gzWrVvHiUlRUkhLS8OjR484xkdERIRCMvT09FCvXj2x4eHh4QEzM/kjhkZGRmLLli3YtGmTzL75fD5+//13TJgwAY0bN5ZYzpG3n0OHDsHPzy9XYwf4NZPTs2dP+Pj4oEGDBnkaUgDw5MkTtG/fHuHh4ZzyqVOnYvny5RwZIpGoUN+KC+Mao/hAQumzjSwHkupgWXtLKemZIuy7E4pPsclwNtNDv/ploCXI+4ESHR2NU6dO4fjx47h8+TLS09MxZMgQbN++vRC0Vj2RkZEcwyMoKAjp6ekKyXB2dubMelSrVk1m3I7cePToEdavX4+DBw/K1MHExARDhw7FiBEjYGdnp/BDMz4+Hrdu3cK1a9fw9OlTCWfS7GhoaOC3335DxYoV4eTkJGEw5NZndHQ03r59KzGDZGxsDC0tLYl2is40MRjZ0dDQgKamJjQ1NSEQCMSO0iKRSPx3Ju03xdcxhJbtb9ArXxeGtTpIXGfZoRVH3uc3M0ZKIcvOBWPbzRCIsn3zfB4wrLELZraXnGYPCwtDQEAAjh8/jn///ZczPcvn8/H69WtUqFChMFQvMNmny9PS0vDs2TPcuXMH9+7dQ1BQEL58+aKQPA0NDTg5OcHFxQVOTk5wdHSEnp5evt+o09PTERkZiW/fviExMVFmv3w+HxoaGhCJRCV6upyheng8nvjBnfMQCATF5lpmZiZCQkLw+vVrvH79Gi9fvkRwcDA+fPggl3FrVrUpDNtOBP7fcZXzGeFXxN9b01swnxEFkff5zZZpShnLzgVjy40QiXIRQVw+s31lfPjwAcePH8fx48dx9+5dmfKaNGmClJQUPHz4sEhNied2XZkIhUKEhIQgJETyM1UlIpGIzR6oiYI+OIvag1yeJbbiQGhoKEaPHo2goCCF244YMQIdR83B2INPAfzyEcmC5UAqHNjMSCkiPVOEinPPc2ZEsiAiZER/QsrbO3CKf4Fnz54WvoKMEo+GhgYsLS2ho6NTZB7GilzT0NDIlz8Oo3BIS0vDlClTsGHDBrnbzJo1C4sXLwaPx2NxRlQAmxlhSLDvTijHEBGJREj9EIS0r8+R/O4uMn/8ciz8qR71GDnQ0NCAgYGB2K9C3oenUChEWFgYQkJC8tyKq6uri1q1asHDwwMVK1aEtrZ2gR/kKSkp6NevH65cucLpq169ejh9+jQsLS1V+bExSjHa2tr4+++/ERERgWPHjuVZf/Xq1ZgyZYr4PL/JIBkFhxkjpYjQmCRkxn2HwNgKSa9uIObiBlBaEvRcG0KY+AO/JiSL/ESZmKy31Cw/EEXR19eHpaUlrK2tYWtrC0tLS85DX9lv1qmpqTh+/Dj27t2Lz58/y9SrTZs2GD9+PDw9PeWeQk9KSkJAQAD8/Pxw6dKlXD8PbW1tTkRUbW1thT87WXz79g3t27fH06fcmbXOnTvjwIED0NPTU1pfDEZ20tPTsWfPHixduhShoaG51uXz+di+fTsGDRokcU3eZJAM5cKMkVJEGXN9/Li+CxlRn6BhbAlK+xX9MvnNfwAAk+ZDITA0R8XMj/j45D98+/YtT5nlypVDly5dVDpFzuPx8ObNGzx8+BAPHjzA3bt38eXLF4UMEG1tbdSpU4eTx8Xa2jp/H6SCvHnzBv/88w92794tEXE0Cz09PQwYMABjx47NM1ZHFpmZmbhy5Qr279+PgIAAmbKBX06KzZs3h7e3N7p168aJiKosXr58CU9PTwkn4LFjx2Lt2rXQ0NBQep8MRmpqKnbu3Inly5fL5YCupaUFf39/dOnSpRC0Y8gNFQPi4uIIAMXFxalblWJNWoaQ7IduJIBH+DUFwjmsus8nlxlnKC1DSCKRiJ4/f06rVq2iVq1akZaWltQ2urq69O3bN6XqGRMTQ2fOnKFZs2ZRs2bNSE9PT2rfuR02NjbUrVs3+uuvv+jOnTuUmpqqVB3zQigU0vnz56ldu3a56uns7EyrVq2i2NhYueSKRCK6d+8ejR8/nqysrPL8HKpXr06rVq2iL1++qHS8V69eJWNjY4n+V61aRSKRSKV9M0onSUlJtHbtWrKzs5P59y8QCDjnBgYGFBgYqG7VSxXyPr+ZMVLKWHr2JelVair1h2s72JeWnn0ptV1iYiKdPXuWxo0bR7/99hun3ZgxY/Ktj1AopODgYNq+fTsNHjyYKlasqLDhwefzqWbNmjRmzBjy8/OjkJAQtT0AExISyNfXl1xdXXPVuVmzZnT8+HHKzMyUS+67d+9o/vz5VKFChTw/DycnJ5oxYwY9f/5cxaP9hZ+fH2lqanJ00NLSIn9//0Lpn1G6SEhIoFWrVuVqjDdo0IAuXLhAffv2FZeZm5vT/fv31a1+qYMZIwyZTNx8msDjS/yA/zx8V24ZHz58oI0bN1Lnzp3JzMyMPn78KFe7xMREunr1Ki1evJjat29PpqamChsfJiYm5OnpSYsWLaLAwEBKSEjI70ehND58+ECTJ0+WOjuQdWhra9PgwYPpyZMncsmMjIyk9evXU7169eT6TIYPH07//vsvCYVCFY/2FyKRiJYtWyZVl3///bdQdGCUHuLi4mjp0qVkbm4u83fQtGlTCgwMFL+M9OnThwCQvb09BQcHq3kEpRNmjDByxdvbh/MjNjIyyrestLQ0io6OligXiUQUGhpKBw4coLFjx1KtWrVIQ0NDYePD1dWVBg0aRNu2baOXL18W2sM2L0QiEQUGBlLnzp2Jx5O+9JV1I1yyZAlFRUXlKTMxMZH8/PzI09Mzz89KW1ubunXrRidOnCj0ZaiMjAwaNWqUhE7Ozs7sps/IF5lCEd1+H00Bj7/S7ffRlCn8ZVDExsbS/Pnzc31xadWqlVQDuFevXvTbb79RaGhoYQ+H8f/I+/xmDqyllHnz/oS//0GxE6ijo2O+ZWlpacHc3Bzp6el4/PgxJ5y6PE6w2dHV1YW7uzsnj4uFhUW+dVMFycnJOHDgANavX4/nz5/LrFe/fn1MmDABXbt2haamZFTHLLIcUf38/HDixIk8HVGbNWsmdkQ1MTEpyFDyRVJSEvr06YPTp09zymvVqoUzZ87A1pbFY2AohrT4HhaaaagQeQPnDu1CfHy81Hbt27fHnDlzUL9+fanXa9SogfXr18PKykolejOUBzNGSikVKlRAv379sHv3bgD5M0aioqIk8rikpiqWSMrR0ZGTx6V69eq5PrjVyZcvX7Bx40Zs3boVsbGxUutoamqiV69eGD9+POrWrStTFhEhKCgI+/fvh7+/P75//55r39WqVYOPjw/69OkDBweHAo2jIERGRqJjx4548OABp7xdu3Y4cuQIDAwM1KQZo7hy4UU4Ru1/BPr/c2HST8Q/OIHPj8/hYXqK1DadO3fGnDlzUKdOnVxlT58+nQWpKyYwY6QUM3fuXOzbtw9CoRBCPTPc+RAjM8CPSCRCcHAwx/h49+6dQv0JBALUrFmTs722IDMyhQER4fbt21i3bh2OHz8uczuxlZUVRo0ahREjRuQ6M/Dhwwf4+flh//79eX5+jo6O6Nu3L7y9vVG1atUCjUMZvH37Fu3atZMIfT9kyBBs2rSpyBqRjKKLUERYcDpYbIhkxIYhfNd4UGaa1Prdu3fHnDlzUL16dbnkM0Ok+MCMkVLM22RdmNdsg+9B53E/io8+2+6KQx83cNLH/fv3xYbHnTt3ZE6VysLc3Jwz61GnTp1iE/QqLS0Nhw4dwrp16/Do0SOZ9WrXro0JEyagZ8+eMoOHRUVF4dChQ/Dz88s1zw/wKwtvjx494O3tjcaNGxeZvCG3b99Gp06dEBMTwylftGgRZs+ezW76jHxxPySWszQjMLWDpqUT0sOzG+o8tO7YBX8vW4gqVaoUvpKMQoEZI6WUrKlRzTrdgYeXwNPQROLLa3gZ9gqd1r6CMPqTwonYqlSpwjE+KlSoUOweUuHh4di8eTM2b94sc+lEQ0MD3bp1w/jx49GgQQOpY0xKSsKpU6ewf/9+XLx4MdcAbVpaWujYsSO8vb3Rvn17pUZEVQbHjx+Ht7c3ZwlOIBBgx44d6N+/vxo1YxR3vidwl3V5PB70XBv9MkZ4fOhXaQZjj54YM6YDqlSxV5OWjMKAGSOlkOxTowJja+hWcMfP67sUkqGvrw8PDw+x4VGvXj2YmpqqRuFC4MGDB1i3bh0OHz4sM7Ovubk5hg8fjlGjRkldXsrMzERgYCD8/Pxw/PjxXB1RAaBZs2bw8fFRmyOqPKxbtw6TJk0CZcunaWhoiGPHjqF169Zq1IxRErAy1JEoM6zdCXH/HYRuubowazUSfG09qfUYJQtmjJRCck6NmjYbjJQPQYBQ+kMYAFxcXDizHm5ubhAIivefT0ZGBo4dO4b169fjzp07Muu5ublhwoQJ8Pb2hq6uLudaliOqn58f/P39ERkZmWuf1apVg7e3N/r06VOk/WVEIhH++OMP/P3335xyOzs7nDt3Tu41ewYjN9xdzGBrrIOIuFSx3whfoAkj9y6I++8g0r69xm/dp8Ldpb1a9WSonuL9NGHki5xTo5qmttC2/Q1pX1/+KtAQQNu6PNq1bIr+v7dB/fr1S9R2zaioKGzduhUbN26UufWYx+Ohc+fOGD9+PJo1ayaxFJPliOrn54e3b9/m2p+DgwO8vb2LjCNqXqSmpqJfv344evQop9zNzQ3nzp0r0kYUo3ihwedhXsfKGLX/ESdNp0H1doi7cxjC+Ci82jkN47RDsHLlSrZbqwTDo+zzr0WU+Ph4GBsbIy4uDkZGRupWp9hz50MM+mzjOlImvrwGYeIPaNtXgrZNOfAEWjg4zKNEZa98+vQp1q9fDz8/P6SlSffWNzY2xpAhQzB27Fi4uLhwrkVFReHw4cPw8/PLdSYlS06PHj3g4+NTpBxR8yImJgadO3fGf//9xylv0aIFjh8/rpIEewyGtDgjCWdXIvbFDfG5i4sLdu3ahaZNm6pDRUY+kff5zYyRUohQRGi04ipnajQ7PAA2xjq4Nb2F1G2+xQmhUIiTJ09i/fr1+Pfff2XWc3V1xfjx49G/f3/O21dycjJOnjwJPz8/XLx4EZmZmTJlaGlpoUOHDmJHVB2d4rXOHRISAk9PT7x584ZT7uPjgx07dkBLS0tNmjFKA0IR4X5ILL4npMLKUAcpn5+jZYvmEvXGjx+PZcuWFZudeaUdZowwciVrNw0AjkGSZXps8qmFdm7Fd2nmx48f2LFjB3x9ffHp0yeZ9Tw9PTFhwgS0bt1aPHuRmZmJq1evYv/+/Thx4gQSExNz7atp06ZiR9Ti6sQbFBQELy8viR1Es2bNwuLFi4vdrihG8YeIULVqVbx8+VLiWvny5bF79240bNhQDZoxFIEZI4w8kTY1mhVnpLgaIsHBwfjnn3+wd+9eJCcnS61jYGCAgQMHYty4cfjtt98A/LrxPXz4EH5+fjh48GCejqhVq1YVO6I6OTkpfRyFyZkzZ9CrVy/O58Xn87Fp0yYMHz5cjZoxSjubNm3C6NGjpV7j8XiYPHkyFi1aJOFYzig6MGOEIRc5p0ZlRWAtyohEIpw/fx7r1q3D5cuXZdYrW7Ysxo0bh0GDBol9Hz5+/Ch2RM25PJETBwcHcUTUatWqKXUM6mLLli0YPXo0J6aMnp4eDh8+DC8vLzVqxmAACQkJsLe3R0JCgsw6rq6u2LNnD+rVq1eImjHkRe7nt4oS9SkVlrWXIY24uDhat24dlS9fPtfsti1btqRTp05RZmYmERFFRUXRhg0bqH79+nlmDDY2NqahQ4fStWvXiky2YGUgEolo5syZEuO1srKiBw8eqFs9BkPM2LFj8/yd8vl8mj59OqWkpKhbXUYO5H1+M2OEUex49+4djR8/ngwNDWXenHR1dWn48OH0/PlzIiJKSkqigwcPUocOHUggEOR6Y9PS0qIuXbrQsWPHSuTNLS0tjby9vSXG7erqSh8/flS3egwGh+Dg4DyNkayjcuXKFBwcrG6VGdmQ9/nN4owwigVEhCtXrmDdunU4d+4cJyJodhwdHTF27FgMGTIEJiYmuHr1KlatWoXjx4/L5Yjq7e2N7t27F1tH1Lz4+fMnunbtimvXrnHKGzZsiJMnT8LcvORs5WaUDCpVqoQWLVrg6tWrUq/b2Niga9euaNiwIRo0aABnZ+dC1pChDJgxwijSJCUlYd++fVi/fj1evXols17jxo0xfvx4dO7cGc+ePcOSJUtw8OBBRERE5Crfzc0NPj4+JcIRNS++fPkCT09Pid0J3bt3x759+4rdVmRG6WHMmDEyjZHExESMHj2aJdEr5jAHVkaR5NOnT/D19cX27dvx8+dPqXW0tLTQt29fjBs3DiYmJjhw4AD8/Pzw+vXrXGXb29ujb9++8PHxKTGOqHnx9OlTtG/fXiLi7OTJk7Fq1apiE5SNUTrJzMyEi4sLvn79KvV62bJlcf/+fTazVwRhDqyMYodIJKLr169T165dic/ny1wXtrGxoYULF1JwcDBt3LiRGjRokOdaspGREQ0ZMoSuXr0qdmQtLVy6dEnCv4bH49G6devUrVqpJFMootvvoyng8Ve6/T6aMoUidatULFi0aJH477d///5kamrK+Ztu3rw5paenq1tNRg7kfX6zmRGG2klNTcWBAwewfv16PH36VGY9d3d3jBw5ElpaWjh06BDOnz+fa0RUTU1NeHl5wcfHB15eXqViGSLnVu3XN05j+PBhnM9JR0cHfn5+6Nq1qxo1LZ2UxNg+hUVkZCQcHR3B4/Hw6dMnvHz5Em3btoVQKBTXGTt2LP755x81asnICYszwijyhIWFYdOmTdiyZQuio6Ol1hEIBOjWrRsaNGiAR48e4fjx47nGHACAJk2aiB1RzczMVKF6kST7g46IEHfbH3G3/Dh1zM3NcerUKTRo0EBNWpZesqIeZ91ws269/P+Pblvcox4XBn379oWuri527NgBAPD19cW4ceM4dbZs2cKC9RUhmDHCKJIQEe7evYv169fj6NGjMmc2LCws0LlzZ/D5fJw5cwbh4eG5yq1SpYrYEbU0etNnf9CRMBOxlzYi8dklTp2yZcvi/Pnz4qizjMIjKx9U9hmR5Hf3EPffARjU9IJB5SawszApEfmgVMnt27dhZGQENzc3AL/uJyNGjMC2bdvEdQQCAQIDA9GkSRN1qcnIBjNGGEWK9PR0HDlyBOvWrcODBw9k1qtUqRIqVaqEly9f5hkRNcsRNSsiamnNn5L9QSdMSUTUqZVIC33EqaPvUBHvHlyHrY21mrQs3UjLlB3hNx1pX3/tbOLrGMCgamtsXz4LPVrUUYeKxZb09HS0atUKN2/eFJdZWFggKCioVL6YFDXkfX6zrb0MlRIZGYktW7Zg06ZNMrfZ8ng8VK9eHUKhEM+fP891C6+RkRG6d+8Ob29vNG3aFBoaGqpSvdhwPyQW4XGpyEyMRcSeiRAmxnKu65Z3h1nHaQhNEoAtAqiH7wmpnPOM2DCxIQIAotRExD84gV6tArCrXTuMGTMGnp6ebJeTHGhpaeHYsWOoW7euOClmdHQ0OnXqhP/++4+ThZtRdGF/6QyV8OjRIwwYMABOTk6YN2+eVENEX18f5cqVg4aGBp48eYLnz59LlaWpqYnff/8dR44cQUREBHbs2IEWLVowQ+T/+Z6QiozoLwjfLWmI6NfwhGWX2eBr6Ug8EBmFh5Uh13lalBIPTSsXiXpEhPPnz6NDhw5wcnLCypUrERsbK1GPwcXS0hInT56Enp6euOzZs2fo378/J+8So+jCjBGG0sjMzMSRI0fQqFEj1K5dG3v37kV6erpEPWNjY+jo6CApKQkfPnyQ6TfSuHFjbNmyBREREThx4gS6d+/OsnNKIezVI4TvmwJREvehpWnhDLPWo8Dj/zLacj4QGYWHu4sZbI11kLWQqG1fCbYD18PaeyW0naTHugkLC8P06dNhaWmJevXq4eDBg+zBmgvVq1fH3r17OWUnTpzAwoUL1aQRQxGYzwijwMTExGDbtm3YsGGDzKBEAKCtrY20tLRcZVWuXBk+Pj7o27cvW++VA39/fwwYMEDC6ONp6cJ++DZo6JuAB8DGWIc5R6qZLCdjAMh+0+UBSHhyATEXffOUIRAIUKNGDXh7e6NNmzaoVKlSqfWVksWCBQswf/58TtmRI0fQvXt39ShUymEOrAyV8/z5c6xfvx779+9Haqr0JQA+n5/n25ydnZ3YEbV69eoSN9ecsTPcXcxK/UOViLB69WpMmzZN6nWLzjOgX7GR+E2cbRstGuQWZyTkZgBGjx6tkDwLCwtMnz4dU6ZMYUbJ/yMSidCzZ08cO3ZMXKanp4f//vsPNWrUUJ9ipRTmwMpQCUKhEGfOnMH69etl5orIjixDxMjICN26dYOPj0+ujqgsSJQkQqEQEyZMwIYNG6Re16vYGPoVGwH4NSNSmj+rokY7N1u0rmwj3bh2G4XIyEgsWLBAbnkxMTG4desWatSogZYtWzKDBL9egPbs2YP379+LgygmJyejc+fOePDgAaysrNSsIUMabGaEIRc/f/7Ezp074evri5CQkHzJ0NTURPv27eHt7Y0OHTrk6f+RM0hUFqX5bT85ORl9+vTBqVOnpF43NjbGwcv3ka6pz2aRiiFEhFGjRmHLli0Kt3V1dcWYMWPQv39/GBsbq0C74sWnT59Qt25dREVFicsaNWqEwMBAaGlpqVGz0gVbpmEohTdv3uCff/7B7t27kZSUlC8ZjRo1go+PD3r06CF3RFRpQaKyUxr9IKKiotCmTRs8efJEZh22Nl78EQqF6NmzJ44fP56v9vr6+ujXrx/GjBkjDg5WWrl16xZatGiBjIwMcdnQoUOxdetWNotUSMj7/Ga7aUoZ2X+UshCJRDh//jw8PT1RsWJFbNiwQWFDpHLlyliyZAlCQkJw8+ZNjBgxQqHQ7FmxM9KjPiH2yhaI0rlGCQEIj0vF/ZDSse3x3bt3qFq1aq6GiJubGzNESgAaGhrw8/NDs2bN8tU+KSkJmzdvRtWqVdGsWTMcOXJErt99SaRRo0bYuHEjp2z79u3w9c3bWZhRuDBjpBQRGhqKwYMHy7yekJCADRs2oHLlymjfvj0uXLigkHw7OztMmTIFjx8/xosXLzBr1iyUKVMmX7p+T0gFCTMRc3YNEh6exrdtI5D6VTIYWmmInREYGIiqVasiMjIy13o5tzUyii86OjoICAhA9erVOeWy3uZlJYH8999/0bNnT5QpUwYLFizIM61CSWTo0KES+WsmTZqEK1euqEkjhjTyZYxs2LABZcqUgY6ODurVq4f79+/nWn/t2rVwdXWFrq4uHB0dMWnSJJm7Lxiq4fbt23B3dxdHKMzOx48fMXnyZDg4OGDs2LF5hmHPjqGhIQYNGoQrV67g8+fPWL16NWrUqFHgKVArQx3E3T6E9MgPAABhYgyiApZAlJEmUa8ks3TpUrRu3TrPLdE1atRAzZo1C0krRmFgbGyM8+fPw8Xlf8HRJkyYgL/++ksiqmjW/dTZ2VmqYfLt2zfMnz8fTk5O6N27N27evIlisEKvNNasWYOWLVuKz7OWwt6/f69GrRgcSEH8/f1JS0uLdu7cSS9fvqRhw4aRiYkJRUZGSq3v5+dH2tra5OfnRyEhIXTx4kWytbWlSZMmyd1nXFwcAaC4uDhF1WUQ0f79+0lLS4sAkJeXFxERiUQiCgwMpE6dOhGPxyP8WvmQ69DU1KROnTrR4cOHKTk5WSU63713n8Djc/q1/H0WOU8/Q87Tz1CZ6WfIY+kVyhSKVNK/uklPT6c2bdrI/Z0cOnRI3SozVMS7d+/I0tKSANCKFSuIiCgsLIz69Okj9W9BR0eHPD09qWzZsrn+zVSrVo02b95MCQkJah5h4RATE0PlypXjfAaVKlVizxUVI+/zW2FjxN3dncaMGSM+FwqFZGdnR8uWLZNaf8yYMdSiRQtO2eTJk6lhw4Zy98mMkfwhFAppzpw5nB9f586daevWreTm5qaQAQKAGjVqRJs2baLo6GiV6p2cnEw2NjacvvWrNOcYImWmn6Hzz7+pVA91IRQKady4cXJ/L2ZmZpSamqputRkqJCgoiAwMDGjHjh2c8sDAQKpUqZLUv4vy5cvTokWLyMvLK9cXDmNjY5owYQK9efNGTaMrPF6+fEmGhoac8Xt5eVFmZqa6VSuxqMQYSUtLIw0NDTpx4gSnvH///tSpUyepbfz8/MjY2Jju3btHREQfPnygihUr0pIlS2T2k5qaSnFxceLjy5cvzBhRkKSkJOrevbvCBkfOo1KlSrRkyRIKCQkpFL3T09OpRo0aHB0EekbkMMFfbIx4LL1SYg2RlJQU6tmzp8T3oK+vL/M7mjJlirrVZhQCV65coQsXLkiUp6Wl0cqVK2X+jXTr1o1u3rxJf/zxB5mZmeX6e2/dujWdPHmyRD+cT58+LWGczZgxQ91qlVhUYoyEhYURALp9+zanfOrUqeTu7i6z3bp160hTU5MEAgEBoJEjR+baz7x586T+UJgxIh9hYWFUp06dfBsgtra2NHnyZHr06BGJRIW3DBIdHU01a9aU0Of4iQC6/T6aAh5/pdvvo0vs0kxMTAw1btxYYvyOjo65fl/BwcHqVp1RSOT2e/zy5YtUQxYA6enp0bJly+jnz5+0c+dOqlWrVq5/U87OzrRs2TL6/v17IY6u8Fi+fLnEmPfv369utUokRcYYuXbtGllbW9O2bdvo2bNndPz4cXJ0dKSFCxfK7IfNjOSfR48ekb29vcIGiKGhIQ0cOJAuX76slreily9fkouLi9SbYmkgJCSEKlasKDH+Ro0a5fq9NWrUSN2qM4oYly9fJldXV6l/L66urnT58mUSiUR0584d8vHxEfuTSTu0tbWpf//+4pntkoJIJKK+fftKjPX+/fvqVq3EUWSWaRo1akR//PEHp2zfvn2kq6tLQqFQrn6Zz8j/yBSKZM4SnDhxgnR1deU2QAQCAXXs2JEOHTqkMkdUeTh9+rTEOm7W4evrqza9CougoCAJHxkANHToUDIwMJD6uZQvX54A0O7du9WtPqMIkpaWRsuXLyc9PT2pfz89evSgL1++EBFRZGQkLV26NM8ZuDp16tCuXbvUeq9QJsnJyRIzyHZ2dhQWFqZu1UoUKnVgHTt2rPhcKBSSvb29TAfWWrVq0bRp0zhlBw4cIF1dXbnfwJkx8ovzz7+Rx9IrYt+JLP+JM0++0LBhwxSaCeHxeLR8+XK1jkckEtHy5ctzda6LiIhQq46q5uzZsxJr/Xw+n/766y+Zb7cjRoygI0eOkLGxMSUlJal7CIwizOfPn2X6junr69PKlSspLS2NiIgyMjLoxIkT1KpVq1zvHebm5jRt2rRC8yNTJV+/fiVbW1vO+Nzd3SklJUXdqpUYVGaM+Pv7k7a2Nu3evZuCg4Np+PDhZGJiIn5o9OvXj+MMNG/ePDI0NKSDBw/Sx48f6dKlS1SuXDnq2bOn0gdTkjn//BuVyWaEOE07TbaD1pNRnc7EE2grvCyTdYwePZoyMjIKfTwpKSnk4+OTq24NGjQodL0Kk61bt5KGhgZnzHp6enTy5Enq2rWr1M/E2dmZ4uPjKTMzk9atW6fuITCKCRcvXqQKFSpI/ZuqVKkSBQYGcuq/fv2axo8fT0ZGRrm+0HTo0IEuXLgg9yx3UeTu3bukrc29h/br169Q/eVKMiozRoiI/vnnH3JyciItLS1yd3enu3fviq81bdqUBgwYID7PyMig+fPnU7ly5UhHR4ccHR1p9OjR9OPHD7n7K+3GSKZQxJkRsew6hzQtnOQ2ODQ0NKhMmTLUtGlT8vHxoVmzZtHmzZvp3Llz9OLFC/GbUWERFhZG7u7ueeqdFVOhpCESiSS2XAMgS0tLun//vlTnuqwj+0OD3SwZipCamkpLliyRuZTbu3dv+vr1K6dNQkICbdq0Kc9QAOXLl6c1a9ZQbGysmkZXMPbu3SsxplWrVqlbrRKBSo2Rwqa0GyO330dzlmYsu0o+yLIOTU1Nql27Ns2ePZtu3bpFYWFhRWqb3v3798nOzk4uI+r169fqVlfppKWlUb9+/STGWqFCBXr//j1duXKF+Hy+1M8je3wfBiO/hIaGUpcuXaT+jRkYGNDq1aspPT2d00YkEtG///5LPXr0EO+KlHbo6urS0KFD6fHjx+oZXAGYOnWqxMzP2bNn1a1WsYcZIyWIgMdfOcaI45TjxNPK9nbD1yDd8u70x/KNRdqH4MePHzR48GDy8PCQ6rCZ/XB1dVW3ukrn58+f1LJlS4mx1q9fn6KioujTp09kYWEh9fMoW7ZsqYmUySgczp07JxGRNOuoXLkyXbt2TWq7sLAwmjdvXp6/4YYNG9KBAwcKfeY1v2RmZpKnpydnDEZGRmzrfAFhxkgJIufMiPP0M2RQw5O07SuRWZvR5DDOj5ynn6Hb71UbGVWZiEQi8Y4QaUdOp+fizpcvX6hq1aoS4+zatSslJydTSkpKrrFh/v33X3UPgVECSUlJoUWLFpGOjo7Uvztvb2/69k16gMG0tDTy9/eXGhsn+2FtbU1z586VWAIqivz8+VPCcbx8+fLFdvmpKCDv85tl7S0GuLuYwdZYB9lTz5m1Hgkbn1UwrNkeAj1j2BrrwN3FTG06KsqCBQtyTVLVuXPnQtRGtTx//hweHh54/vw5p3zixIk4fPgwdHV1MW7cOAQFBUltP2HCBDRp0qQwVGWUMnR0dDBnzhwEBwejU6dOEtf9/Pzg6uqKtWvXIjMzk3NNS0sLvXr1wo0bN/D06VOMGDECenp6EjIiIyOxaNEiODs7o3v37rh27VqRTdJnbGyM06dPw8TERFz2/v179OrVS2L8DCVTOLZRwSjtMyNE/9tNUybHDElxzNPy9u1bCb+IGjVqiH1JrKysipSfS0G4cuWKxI4EHo9Ha9asEdfZtm2bzLfK8uXLF+mlN0bJ4vTp0zIT7FWtWpVu3LiRa/sfP37Q2rVr6bfffst1tqRy5cq0YcMGio+PL6SRKcalS5ck7lETJ05Ut1rFErZMUwKRFWekOBkiIpGInJ2dOT9yLS0tiomJod27dxMAGjJkiLrVVAp79+4lTU1Nzli1tbXpyJEj4jr379+XGQGTx+PRrVu31DgCRm5BBksqKSkpNH/+fIntrllHv379KDw8PFcZQqGQLl26RJ06dZLpkA38ivw8ZsyYIumXsXbtWgl9cyYqZOQNM0ZKKMX95vjHH39I/MB37txJRL9uYLVr16ZTp06pWcuCIRKJaPHixRLjNDMzo5s3b4rrff/+PdeolywBnnopCcZ/Qfjw4QN5eXlJ/ds0MjKidevWyRWjKDQ0lGbMmCHTOTvraNGiBR07dkwtcY+kIRKJaPDgwRwdNTU12QuCgsj7/OYRFdHFu2zEx8fD2NgYcXFxMDIyUrc6jHzy4sULVKtWjbNe3LBhQ9y6dUt8fu/ePVSrVg26urrqULHAZGZmYvTo0di2bRun3MXFBefPn4erq6u4Xrt27RAYGChVjqurKx4/flxsP4fizoUX4Ri1/xGy/lIpMwM8gabYb2uTTy20c7NVl3qFyunTpzF+/HiEhoZKXKtevTo2bNiAhg0b5iknNTUVhw8fxoYNG3D//n2Z9RwcHDBixAgMGzYM1tbWBVG9wKSlpaFFixa4ffu2uMzKygoPHjyAk5OTGjUrPsj7/GbGCKNQEAqFcHJywrdv38RlOjo6iIiIgLGxsRo1Ux6JiYno1asXzp07xymvU6cOzpw5w7mxzpgxAytWrJAqh8/n47///oOHh4dK9WVIRygiNFpxFeFxqeKyz3/3BEgEvq4RNPSMoWtkgg51XWFlZQkLCwtYWv76N/v/TU1NoaGhocaRKI+UlBQsX74cK1asQFpamsT1gQMHYsWKFbCyspJL3oMHD7Bhwwb4+/tLlQcAmpqa6NGjB8aMGYP69euDx+NJradqIiMjUadOHXz9+lVcVrNmTdy8eRP6+vpq0ak4wYwRRpFi9OjR2LRpE6fswIED6NOnj5o0Ui4RERHo0KEDHj58yCn38vLCoUOHODetY8eOoXv37jJlTZ8+HcuXL1eZrozcufMhBn223RWfizLS8WVNV4Xl8Pl8mJmZyTRWpJUV1Yfbpk2b0LZtW4hEIowfPx7nz5+XqGNsbIwlS5Zg5MiRchth0dHR2LlzJzZt2iR15iWLGjVqYOzYsejTp4/UHTuq5tGjR2jUqBFSUlLEZT169MChQ4fUZiQVF5gxwigyPHjwAPXq1eMsz7Ro0ULmEkVx4/Xr1/D09JS4mY4YMQK+vr4QCATislevXsHd3R2JiYlSZVWuXBkPHz6Ejo6OKlVm5MLJJ2GY4P9EfJ6ZEIOwjQMKpW9dXV25jJasf83MzDh/X6pi3rx5WLhwIVq0aIEhQ4ZAIBBg6tSp+Pz5s0TdmjVrYsOGDahfv77c8oVCIc6dO4cNGzbg4sWLMuuZmppi0KBBGDVqFMqXL5+vseSXw4cPo1evXpyyRYsWYc6cOYWqR3GDGSOMIkF6ejocHBwQFRUlLtPV1UVERESJ+C5v3ryJzp0748ePH5zypUuXYsaMGZy3poSEBLi7u+P169dSZWloaODOnTuoW7euSnVm5E7OmZHM+GjEXtqA9KhQCOOjcmlZ+PB4PJiamso0WqQZMAYGBgq/zX/58gVlypSBSCQC8MsoyIq9sXfvXqSnp0u0GTx4MJYvXw5LS0sIRYT7IbH4npAKK8NfMZE0+NJ1ePfuHTZt2oRdu3bh58+fMnXy9PTEmDFj0K5du0JbDvvzzz+xaNEiTtnx48fRpUuXQum/OMKMEUaRYNCgQdi9ezen7OjRo+jWrZt6FFIiR44cQb9+/Thr3pqamti1axe8vb05dYkIPXr0wLFjx8RlPB6PM1s0e/ZsLF68WPWKM3Ily2ckIi4VOW+OP2/uR9xtf6nt9PX14ejoCHNzc+jp6UEoFCImJgZRUVGIjo6W+sBWB9ra2nIZLVn/Nzc3h6amJjp16oTTp09LyHNzc4NQKMSrV68krpmamqLvmGkI0qmFiIQMcbmtsQ7mdaycqxNwUlISDh48CF9fXzx9+lRmPRcXF4waNQqDBw+Gubm5gp+GYohEInTr1g0BAQHiMn19fdy5cwdVq1ZVad/FFWaMMNTOjRs30LRpU05Zu3btpK43FyeICH///TemTJnCKTcyMsKJEyfQokULiTYrV67E9OnTZcqsWrUqHjx4AG1tbaXry1CcrN00ALgGCRFiA7ci4aHkQzknBgYGqF+/Pho3bozGjRujcuXKSExMRHR0tNhAyf7/nGU5Z9vUSVZE0txmKrS0tCAQCJCcnCx5zaY8zFqPgrbdr91kiuxKIiLcvn0bGzZswNGjR5GRkSG1no6ODvr06YMxY8agdu3aeY4pvyQmJqJBgwaciMplypTBgwcPYGFhobJ+iyvMGGGolZSUFNjb23NuqPr6+oiIiICBgYEaNSsYQqEQkydPxvr16znlDg4OOH/+PNzc3CTaBAYGok2bNuIp7pwIBALcu3cPtWrVUonOjPxx4UU4FpwO5uyqsTXWwVyvijj01yzs3btXIXm6urrYv38/unaVzxk2MzMTMTExeRotWf9GRUXJ3JlSNODBoHpbmLUdDR6PDx4AG2Md3JreQuaSTU4iIiKwbds2bNmyBWFhYTLreXh4YMyYMejRo4dKDPyQkBDUrVsXMTEx4rKmTZvi8uXL0NTUVHp/xRlmjDDUSs+ePXHkyBFO2enTp9GhQwc1aVRwUlJS4O3tjRMnTnDKq1WrhnPnzsHe3l6izefPn1G7dm1ER0eLy7S1tTkPjXnz5mH+/Pkq05uRf2T5OmRmZqJHjx6c6frcqFKlCnbu3Al3d3eV6UpESE5OlmvWJevf2NjYQs0To1+1NSzaT+CUHRzmgfrlFFteycjIwKlTp+Dr64vr16/LrGdpaYmhQ4di5MiRSo8Lcv36dbRu3ZqTs2bkyJESuwZLO8wYYaiNCxcuwNPTk1PWuXNnuW/cRZHo6Gh07NgRd+/e5ZS3bt0aR48elfp3mZqaiiZNmuDBgwfiMgMDA85Omho1auDevXvQ0tJSnfIMlZCamooOHTrkuSusadOmuHjxYpFcghMKhfjx40eeRkt0dDRevnyJ1NTUvIXmhMcDiMDT1IHdiO0Q6JtwLq/rXQOda0ga8vLy8uVLbNy4EXv37pW5S43P56Njx44YO3YsWrZsqbTtuJs3b8aoUaM4ZRs3bpQoK80wY4ShFhISEuDg4ID4+HhxmZGREb59+1ZkYyjkxYcPH+Dp6Yl3795xygcMGIBt27bJnJYdPnw4JxKrlpYWx4lRU1MTDx48QPXq1VWjOEPlJCYmolWrVrh3716u9Zo3b45169YVWyfHd+/ewc3NLU8nXD09PdSpUwf16tWDiXNlbHzJA19HH3G3/SEwtYNh9bYSbfIzMyKN+Ph47N27Fxs2bJC5Yw34Fd149OjRGDBggFICLo4ZMwYbN24UnwsEAly6dAnNmzcvsOySgNzPb6UFoFchLDdN8UFaLosLFy6oW618c+/ePbK0tJQY059//kkikey8QNu3b5eazyP7+aJFiwpxJAxVERMTQ1WrVs017woA4vP5NHr0aIqOjla3ygohEomoTZs2UhM5Vq5cmQYPHkxbtmyhJ0+ecPLKZApF5LH0ikSm8ewZxz2WXlF6fi2RSESBgYHUtWvXXJP06evr08iRI+n58+cF6i89PZ2aNWvGkW1ubk4fPnxQ0oiKNyxRHqPQOXbsmMQPvkePHupWK9+cPHmSdHV1OePR0NCg7du359ruwYMHEhlPK1SowDmvVasWpaenF9JIGKomPDycypUrx/mOZWW9NTMzI19f3yKTEC4vjh49SgDI2tqaOnXqREuWLKErV67IdT8+//wblfl/wyOnIVJm+hmVJx38/PkzzZ49m6ysrHI1FJs0aUKHDh3K928yKiqKXFxcODLd3NwoPj5eySMqfjBjhKFSvn//zjmPjY0lPT09zo/RxMSEkpKS1KRhwfD19ZV4q9LX16dz587l2i4qKoqcnJw47SpWrCiR+bOgb2OMokdISAjZ29uLv+cVK1bQli1bZGardXNzo8DAQHWrnSe3bt2i0NDQXGcCc6MoZD9OTU0lPz8/ql+/fq5GiZ2dHc2fP5++fVNct+fPn5OBgQFHXufOnUkoFKpgRMUHZowwVEqLFi0oJiZGfN68eXOJH/bVq1fVqGH+EAqFNG3aNImx2NjY0MOHD3Ntm5mZSa1ateK0s7KyIlNTU07Z0qVLC2k0jMImODiYzM3NCYB4Bi02NpYmTpxIAoFA6gOwa9eu9PHjRzVrrloyhSK6/T6aAh5/pdvvo5W+NKMIjx49oiFDhkjMemY/BAIB9erVi27cuCGXEZZVJyAgQELWnDlzVD2kIg0zRhgq4+PHjwSAJk6cSEREe/bskfgB+vj4qFlLxUlNTaXevXtLjKVSpUoUGhqaZ/sZM2ZILOk0adKEU1a3bt1iMz3PyB9BQUFkaGhIR48e5ZQHBwdL9b3IWtKZM2cOJSYmqknr0kdMTAytXr2aypYtm+tsSdWqVWnz5s2UkJAgU9apU6foxIkTRES0ePFiCRn+/v6FNKqiBzNGGCpjzZo14uWGW7duSayNm5ubU3JysrrVVIjY2Fhq2rSp1LXk2NjYPNsfP35cou2AAQMkHjgvX74shNEw1M2///5L//33n0S5SCSikydPSviXZB0ODg504MCBfC+JMBRHKBTSuXPnyMvLi3g8nkyjxMjIiMaPH0+vX7+WkHHu3DkCfjmlC4VC6tWrF6etrq4uBQUFqWF06ocZIwyV0bhxY850Zs4f7c2bN9WtokKEhoZS5cqVJcbRq1cvSk1NzbP9q1evyNDQkNO2W7duEsszK1euLITRMIoDqamptHz5cgkfg6yjYcOGeS4LMpTPhw8f6I8//iAzM7NcZ0tat25NAQEBlJmZSUREd+7cEV/r2bMnRUVFUa1atSQMzfDwcDWPsPBhxghDJUREROT69jB48GB1q6gQjx49IhsbG4lxTJ06VS7Hs/j4eKpUqRKnbbVq1ah9+/acMg8PD/GNi8HIIiwsjPr37y/1t8Tj8Wjo0KEUGRmpbjVLHcnJybRz504JgyLn4eTkRMuWLaNbt25xymvVqkV3794la2trTnn9+vXlesEpSTBjhKEStm7dKvOHKRAIaNSoUbR27Vo6deqUXH4W6uTChQsSb6Z8Pp98fX3lai8Siah79+6c9qamprRq1SpOmY6OjtSpXQYjizt37pC7u7vU35WxsTGtWbOG0tLS1K1mqUMkEtGdO3fIx8eHtLS0ZN77NDQ0JMqsra1py5YtEu0GDhxYqpbhmDHCUAmenp65vilkHTVr1izSxsiOHTskbiC6uroUEBAgt4ycRgePx6O9e/eSsbExp3zNmjUqHAmjpCAUCmn37t1SZ+oAkKurK50/f17dapZaIiMjaenSpeTo6CjXPRAAaWlp0eDBgyXK//77b3UPp9BgxghD6cTFxeX6dpB19O7du8jGFxGJRDRv3jwJnS0sLOju3btyywkMDJSIQzJ//nwJY61Ro0ZseYahEHFxcTRt2jTS1NSU+vvq0KEDvX37Vt1qlloyMjLoxIkTEtv4cztyLvfw+Xy6ePGiuodSKDBjhKF0Dh48mOsPjsfj0YoVK4rsFGR6ejoNHDhQQu/y5cvTu3fv5Jbz+fNniUBWHTp0oG3btknMtCgil8HIztu3b6lDhw5Sf2uampo0bdo0dk9UM8HBwRKRV2UdWfFnsg4TExMKfvW6yMRfURXMGGEonZ49e8r8oRkbG+cZnVSdxMXFUevWrSX09vDwkIgmmxupqakSa/vlypWjZ8+eSeSeWb9+vQpHxCgtnD9/nlxdXaX+7mxsbGjXrl2lPsqnOkhLS5PpfCzryDnbpWPhSI4T/NUWmbYwYMYIQ6mkpKSQvr6+1B9YxYoV6c2bN+pWUSZfv36l6tWrS+j9+++/K7ycNHz4cInZjydPnkgYOk2bNmUPCIbSSE9PpzVr1kgYvFmHu7u7QsuMjIIRExMjkRwvv4eOS21ymnqyUHP2FCbyPr95REQo4sidgpihMs6cOYOOHTtKlHt5eeHAgQNF9nt5+fIlPD098eXLF075uHHj8Pfff0NDQ0NuWTt37sSQIUM4ZX5+fkhMTMSIESPEZfr6+nj27BnKli1bMOUZjBx8//4ds2fPxo4dOyDt1t2vXz8sX74cdnZ2atCu9PDy5UvcvXsXYWFhEkdUVJTC8ozcu8K0+WAAAA+AjbEObk1vAQ0+T8maFz7yPr+ZMcKQi1atWiEwMJBTNnToUGzZsgV8Pl9NWuXOtWvX0KVLF8TFxXHKV69ejcmTJ4PHk/+HHhQUhEaNGiEtLU1cNn78eEyaNAlVq1ZFYmKiuHzjxo0YNWpUwQfAYMjg4cOHmDBhAv777z+JawYGBpg9ezYmTZoEbW1tNWhXuklLS8O3b9+kGiphYWH4+OkLvn39ApBI3MawVgeYthrBuScdHOaB+uXM1TEEpcKMEUaBEYoI90Ni8SbkMwa3qc15E+vRowcOHz6sRu1yx8/PD4MGDUJGRoa4TEtLC3v37kWvXr0UkhUdHY3atWvj8+fP4rJGjRrhypUraN++Pa5evSoub9myJS5dulRkDTRGyYGIcPDgQUybNg1hYWES18uVK4c1a9agY8eOChneDNVy8kkYxh14hJjTq5D89jZMGveDsUd3iXrretdA5xr2atBQucj7/GZ3TIZULrwIR6MVV9Fn212MHDKQY4i4urrCz89PjdrJhoiwbNky+Pj4cAwRU1NTXLlyRWFDRCgUok+fPhxDxMbGBocPH8aOHTs4hoiBgQF27NjBDBFGocDj8dC3b1+8efMGc+bMkZgF+fDhAzp37ox27drh1atXatKSkRMrQx3w+XxYeE2Cjc8qqYZIVr3SBLtrMiS48CIco/Y/QnhcKpJe30La52f/u8jTwPglvtDU1FSfgjLIzMzE6NGjMWvWLE65s7Mz/vvvPzRu3FhhmXPnzsWVK1fE5wKBAEePHkVKSgqmTp3KqbtmzRo4OzvnT3kGI5/o6+tj0aJFePXqFbp27Spx/dKlS6hatSomTpyInz9/Fr6CDA7uLmawNdYBX6AFbdvfJK7zANga68DdxazwlVMjzBhhcBCKCAtOB4MACJPjEHNpI+e6SaM+2PeWB6GoaK3uJSUloUuXLti8eTOnvFatWrh79y4qVaqksMyAgAAsW7aMU7ZmzRrUr18fgwYNQnJysri8TZs2GDp0aP6UZzCUgIuLC44dO4bAwEC4ublxrgmFQqxbtw4VKlTA1q1bIRQK1aQlQ4PPw7yOlQH8Mjyyk3U+r2PlEuG8qgjMGGFwuB8Si/C4VABA7KVNoJR48TVNq7Iwqtcd4XGpuB8Sqy4VJYiMjETz5s1x5swZTrmnpyf+/fdf2NjYKCzzzZs36N+/P6fM29sbY8eOha+vL27cuCEuNzIywvbt29m6PKNI0KJFCzx+/Bi+vr4wNTXlXIuOjsaIESNQt25d3Lx5U00aMtq52WKTTy3YGHOXYmyMdbDJpxbaudmqSTM1osr9xcqCxRkpPAIefyXn6WfIotN0if3wBtXbiYPzBDz+SkREnz59Uqu+r1+/lhoBcejQoZSRkZEvmQkJCVS5cmWOvGrVqlFSUhK9ffuWdHV1Odd27typ5FExGMohOjqaRo8eLZG6IOvo3bs3ff78Wd1qlloyhSIWgfX/YTMjDA5WhjoQJv1A7OVNEtcSn15AfNApcT0iQpcuXRAdHV3YagIA/vvvPzRo0AAhISGc8sWLF2Pr1q0QCAQKyyQiDB48GMHBweIyExMTHD9+HNra2hg0aBBSUlLE19q3b4+BAwfmewwMhioxNzfHhg0b8PjxYzRr1kziur+/P1xdXbFw4ULO3zWjcNDg81C/nDk617BH/XLmpW5phkOhmEYFhM2MFB4ZmUIyrdwo14iB5XvOpEyhiG7evEkAaM6cOYWu59GjR0lbW5ujl0AgoL179xZI7urVqyXGe+bMGSIi+uuvvyRyS3z9+lUZw2EwVI5IJKKjR4+Ss7Oz1N+1s7MzHTlypMjmlmIUT1g4eEa+OHDgAPcmxdcgLevynDINgYDOnz9PgwYNIuBXXpqfP38Wmo5///038Xg8jk6GhoZ0+fLlAsm9du0aaWhocOTOmzePiIhevXpFOjo6nGsFNXxKMqVh+rm4kpycTAsXLpRYbsw6mjVrRk+fPlW3mowSAjNGGAoTHh5OZmZm3Lf/ZgPJcYI/aVqW4ZTr6emRnp6e+HzJkiUq108oFNLEiRMlbp729vYFvnl++fKFLC0tOXLbt29PQqGQMjMzqV69epxrnTp1Ym+QMjj//Bt5LL0i9i8qqQnAijufP3+mPn36SDVI+Hw+jRo1iqKjo9WtJqOYw3LTMBSC/t//4+TJk+Iy93r18NfeU4hJzgA/5ScmeHeU8M/IwsLCAqGhodDX11eJfikpKejXrx+OHTvGKXdzc8P58+fh4OCQb9lpaWlo2rQp7t27Jy4rW7YsgoKCYGpqipUrV2L69Onia2ZmZnj58mW+dumUdLJi1OS8qWSthJfanQJFmFu3bmH8+PF4/PixxDVTU1MsXLgQI0eOzJcPFoPBIrAyFMLPz49jiGhra2PP7t1o9JsVOtewR8f6VXDp0iUYGxtLbR8dHY1t27apRLeYmBi0atVKwhBp2bIlbt26VSBDBAAmTpzIMUR0dXVx4sQJmJqaIjg4GHPnzuXU9/X1ZYaIFLLHqMki/ftHRJ1YiqS3d0DCDCw4HVzkYtSUdho1aoQHDx5g69atsLCw4Fz78eMHxo0bhxo1akjkpmIwlEphTNMUFLZMo1rCwsLIxMSEM027evVqIiL6+fMnHT16lIYMGUL29va5Orba2dlRamqqUnX78OED/fbbbxJ99evXj9LS0gosf9euXRKy9+/fT0REGRkZVKdOHc61rl27suUZGdx+H81ZmnGefoYMa3f639S/rhEZ1PSirUcusM+wiPLjxw+aOHEiCQQCqb/xLl260MePH9WtJqMYwXxGGHIhEomoQ4cOnBtOgwYNKDMzk4iIgoODqWXLlrkaIdmPzZs3K023+/fvk5WVlUQfs2fPVsrD7OHDhxI7csaNGye+vmTJEs41CwsLioyMLHC/JZWsGDVZh9PUk8TXNZL6d1KhQgVasGABffjwQd1qM6QQHBxMbdu2lfrdaWtr0+zZsykxMVHdajKKAcwYYcjF7t27OTcaHR0devPmDaeOSCSiw4cPk4ODQ57GSJkyZSg9Pb3Aep0+fZrjIAuANDQ0aMuWLQWWTfQrGFTOLY4NGzYUz7Y8e/aMNDU1OdcPHz6slL5LKjlnRuyGbSG+nkmefzMNGzakzZs3U2xsrLqHwMiGSCSiU6dOUbly5aR+b/b29rR//342y8XIFWaMMPLk69evZGxszLnB/P333zLrJyQk0IwZMyQe0jmPPXv2FEivTZs2SUSM1NfXp7NnzxZIbhaZmZnUunVrjnwbGxv69u3Xbo/09HSqWbMm53rPnj2V0ndJJlMoIo+lV6hMjtkRq+7zSMtWcqkt56GlpUVdu3algIAApSzBMZRDamoqLV++nAwMDKR+bw0aNKCgoCB1q8koojBjhJErIpGIPD09OTeVRo0akVAozLPt69evqU2bNjIfKhUrVpRLTk6EQiHNmDFDQp61tbVSb3azZs3iyBcIBHTz5k3x9QULFnCuW1lZUVRUlNL6L8mcf/6Nykw/wzFInP//3Nijp9zLfUZGRjR8+HC6c+cOe/MuInz79o369+8v9fvi8Xg0ZMgQtozJkIAZI4xc2bFjB+dmoqurS+/evZO7vUgkomPHjpGjo6PUm9ORI0cU0ictLY28vb0l5Li6uirVYS4gIECij3Xr1omvP378WMJ57/jx40rrvzQgK87IuWdhNGTIELkNkqzDwsKCRo0aRe/fv1f30BhEdPfuXXJ3d5dpRP71119sZoshhhkjDJl8/vyZjIy4joXr16/Pl6zExESaNWsWaWlpceRVr16dMjKFckXh/PHjBzVv3lzixtaoUSOKiYkpyFA5vHnzRmLcffv2Fb95p6WlUbVq1SSuMxRHVgTW9PR0ateuncIGSdbB/EuUR0Gi5AqFQtq9ezfZ2NhI/Z5cXV3p3LlzKtSeUVxgxghDKiKRSGKJpWnTpvlaVsnO27dvJR4yrv0X5xmF89OnT1SlShWJm1mPHj0oJSWlQDplR1om3qpVq3J2BMydO5dz3cbGhkWgVAHx8fESPjmKHsy/pGAoK0pufHw8TZs2TaYfmZeXF719+1ZFo2AUB1jWXoZUtm/fjkuXLonP9fX1sXPnTvD5BftTqFChAs6dO4eAgABY2f0KQhZyZR8oW4DfiLhUjNr/CBdehAMAnjx5gvr16+Ply5ccWVOmTIG/vz90dHQKpFMWRIQhQ4ZwMvEaGxvj+PHj4oixDx8+xNKlSznttmzZAnNzc6XowPgfhoaGOHv2LJydnXOtZ25ujpo1a4LHk8xkmp6ejuPHj+P333+HnZ0dxowZg7t373L+3hjSyYqSGx6XyinP+fuUB0NDQ6xYsQIvX75Ex44dJa6fPXsWVapUwbRp0xAfH19g3RklF2aMlCI+ffqEyZMnc8pWrlyJsmXLKkU+j8dDh46d4Dx8M4wb9EZ65Eekfn4mvp71mFhwOhgXLl5CkyZN8O3bN0779evXY/Xq1QU2jrLz999/4/Dhw5yy/fv3o3z58gB+hYMfMGAAhEKh+Hr//v3RqVMnpenA4GJra4vz58/D1NRUZp2YmBg8fvwYPXr0wNy5c1G5cmWZ9TZu3Ij69evD1dUVCxcuxMePH1WlerFGWpRcyszAj+u7kJkcBwD5ipJboUIFnDp1ChcuXEDFihU51zIyMrBq1Sr89ttv2LVrF0QiUUGHwSiBMGOklJA1O5CYmCgua968OUaOHKnUfu6HxOJ7CmDcoDd0nKsh+fVNztsqAXh36ww6dPBCQkKCuFxHRwfHjh3DuHHjlKrP9evXMW3aNE7Z4LF/wLO9l/h8wYIFnNkZOzs7rF27Vql6MCSpVKkSTp48CS0trVzrHT58GJs2bcK0adPw4MEDTJgwAVZWVlLrvnv3DvPmzUO5cuXQqFEjbNmyBT9+/FCF+sWS+yGxEjMicbf9EX/vGL5tG4mE51fw7WcK7ofE5kt+27Zt8ezZM6xZs0YiD0lkZCQGDx4MDw8P3L17N99jYJRQ8rMG5OvrS87OzqStrU3u7u507969XOv/+PGDRo8eTTY2NqSlpUUVKlRQKGYE8xkpOJs2beKs5RoYGFBISIjS+8mKwmnWdoy4L22nqmQ7cB05TTtNxo0kd8yYm5vT7du3la7Lly9fJCK46pStTU7TTonXx+/duycR00RZ8UwY8nHo0CHO59+mTRtycXGR6oPQvHlzev36NWVkZNDZs2epd+/epKOjw/xL5CRnlFy7oZsIfA3O56XtVI02BNwocF+RkZE0bNgw4vF4Ur+Xfv36UVhYmBJGxSjKqMyB1d/fn7S0tGjnzp308uVLGjZsGJmYmMjcX56WlkZ16tSh9u3b061btygkJISuX79OT548kbtPZowUjI8fP5K+vj7nRqDMsO3Zuf0+mhwnHyMNAzNOf5bd5pF+1dYSN6SyZctKRHxVBqmpqeTh4cHpS2BsTQ7jD4rjXjhNOU6OLuU5dQYPHqx0XRh589dff4m/g/Xr11NSUhLNmDFDao4ULS0tmjdvntjBOS4ujnbu3EnNmzeX+eDLbviOHj261MYvyRkl19xrMoEv+RlramnRwoULlWK8PXz4kBo2bCj1+9DX16elS5cq1VmdUbRQmTHi7u5OY8aMEZ8LhUKys7OjZcuWSa2/adMmKlu2bIFChDNjJP8IhUKJbbOtWrVS2Y04Uygip3bDuG9a9pVJu4zk7gl3d3eVBUkaNWoUpy+eQItsB67n3IiN3Lty6jg4ONDPnz9Vog8jd0QiEU2YMIEAbtj958+fU4MGDaQ+yH777Te6evUqR87nz59p2bJlEjunpB2lMT+OtCi5tkM2kpZ9JamfUZkyZejGjYLPkohEIjpw4IDMZJtly5algICAUmkglnRUYoykpaWRhoYGnThxglPev39/6tSpk9Q2np6e5O3tTcOGDSMrKyuqUqUKLVmyRJyITRqpqakUFxcnPr58+cKMkXzi6+vL+dEbGhpSaGioyvr7+fMnGRqbcmckTCVvQJ06daKkpCSV6JAz3w4AMveaTA4T/Mmm/xqy6DyDLHssJID7Fn3x4kWV6MOQj8zMTOratavEw08oFNLWrVslMktnHf3796fv379z2ohEIgoKCqIJEyZITbaY8yhN8UukRcl1mnaKjD16yPx8mjRpQl+/fi1w34mJiTR37lyJBJVZR+vWrenly5dKGCWjqKASYyQsLIwASKzvT506ldzd3aW2cXV1JW1tbRo8eDAFBQWRv78/mZmZ0fz582X2M2/ePKl/qMwYUYz3799LJJvbtm2bSvvMGasDAi2J73H06NG5GqMF4dGjRxI+BIa1vMi4YV9OmYahOed8+PDhKtGHoRjJyckyDYKIiAipUXoBkJmZGW3fvl1qvBzmXyKJrDgjnb2HyvxseDweeXp60qtXrwrcf0hICHXr1k1qPxoaGjR+/PhSYRiWBoqMMVKhQgVydHTkPHz++usvsrGxkdkPmxkpOEKhkJo0acL5kbdt21al06CRkZESvik5jxUrVqhMh+joaCpTpgynP237SuT0xwkyazdepk429o4UHx+vEp0YyufSpUtUvnx5qd9l48aN6eXLlzKjizL/kv8h7TOSFoVY2lG/fn06evRogTN0BwYGkpubm9Q+LCwsaPPmzZSZmVmgaLEM9VJklmmaNGlCLVu25JSdO3eOAMj95sF8RhRn3bp1nB+2kZERff78WaV9Zq35y3rjPHDggMr6zszMpLZt23L6tLa2ploz/KnM9DNk3n6iTN0uXrqsMr0YinPkyBFat24dXb9+XebbcXJyMs2ZM0dq5E+BQJPsm/Ulx8nHco0uyvxLpPPkyZM8M3NnHba2tjR//vwC7YrJyMggX19fMjU1ldpH2YpVqPKwNQWOFstQDyp1YB07dqz4XCgUkr29vUwH1pkzZ5KzszNn+nTt2rVka2srd5/MGFGMt2/fkq6uLucHvXPnTpX2+enTJ4n8NFmHiYkJXb9+XaX9z5kzJ8cDSUA3btwQr4/ruNSSqluHXgNUqhdDccLCwsjY2Fj8HTk6OpKXlxfNmjWL/P396dWrV+KZ1uDgYIkZQPHfgIktWfVcKN49VWb6GakPMOZfIsnixYvlMkYAkLa2Nk2aNKnAO2Kio6NpzJgxElvtsw69io3JftTOPL9PRtFCpVt7tbW1affu3RQcHEzDhw8nExMTioiIICKifv360YwZM8T1P3/+TIaGhjR27Fh68+YNnTlzhqysrGjx4sVKHwzj1wxBzm107du3V/k086BBg6TeQJycnFTukHby5EmJfteuXSu+vvbgOam62dg7UUJCgkp1Y+SPbdu25foA1NHRoTp16tDgwYNp7dq1NG3aNOlv1hoCsh+9R/wA81h6JdcpfuZf8ouMjAyqW7euXMYIn8+nCRMmKG2p89mzZ1ITZwIgg2ptxLMj8nyfDPWj0kR5//zzDzk5OZGWlha5u7vT3bt3xdeaNm1KAwYM4NS/ffs21atXj7S1tals2bJ57qbJCTNG5GfNmjWcH6+xsbFSvOBz49GjR1JvHDVq1FB5UKO3b9/mmomXiKhly5ZS9VP1bA0jf4hEIoqJiZHLdyHnwRNwd2kYefTgTO87Tz9Dt9/Ll/ywtPuXvHr1Kk+DLPvh4OBAJ0+elCkvNTVV7r5FIhEt8d1FGkb/m6niaeqQ/Zi9+f4+GepB3uc3j6joZ5aKj4+HsbEx4uLiJEIMM/7HmzdvUKNGDaSm/i/c8549e9C/f3+V9fn9+3dUrFhRIuR227ZtceTIERgaGqqs76SkJHh4eODFixfisqpVq+LOnTviBHhXrlxB69atpbZPSUlRWjI+hvzEx8fjy5cv+Pr1K758+cI5ssqSkpLy34GGJngCLfC19WA/bAt4Am64+XW9a6BzDXuFRH758gV+fn7Yt28fJ+GiNCpUqAAfHx/4+PgoLe+TulizZg2mTJmiUJuuXbti/fr1sLfnfsZr165FlSpVZP4ec3LySRjG7buH+AcnEH/3CLTtK8G612KJevn5PhmFh7zPb2aMlBCEQiEaN26MO3fuiMs6dOiAU6dOSc16qgzevXuH5s2bIywsjFPet29f7N69G5qamirpFwCICH379oW/v7+4zNjYGEFBQeIEeEQEd3d3BAUFSZXx6tUriaRejIKRlJSUp6Ghquyt9k4uSC7fCgbVWoGnoYXMhChomtpJ1Ds4zAP1y+UvGzMR4dGjR9i3bx8OHjyI79+/51q/YcOG6NevH3r27JlrUsCiilAoRPPmzXHz5k1xmUAgQGZmZq7tDA0NsWzZMowcORIaGhoAgEmTJmHHjh24desWqlWrlmffdz7EoM+2XzlsUj8/R+ShOXCachw8vganXkG+T4bqYcZIKWP16tWYOnWq+NzU1BQvXryAnZ3kzVgZ3LlzBx07dkRMTAynvHnz5ggMDFSZAZTF33//LZGB+PTp0+jQoYP4/NixY+jevbtMGefOnYOnp6fKdFQ3QhH9SlyYkAorQx24u5hBg5//7yUlJQVfv37N1dBQR1K6du3aYdy4cWjdpi2arLqOiLhUSLup8QDYGOvg1vQWBfocssjMzMSlS5ewb98+BAQEcGYkc6KlpYUOHTqgf//+8PT0zDM5YFHiw4cPqF69OpKSkqCvr48bN26gW7duCA0NzbNtvXr1sHXrVlSrVg29e/fGoUOHYG9vj3v37knMnOREKCI0WnEVEXGpiDy6ACkfHsBxgj/4OgYAlP99MlQDM0ZKEa9evULNmjWRlpYmLtu/fz+8vb1V0t+JEyfQt29fiZuvoaEhwsLCVLo0AwD//vsvWrZsCaFQKC6bO3cuFi5cKD7PzMxE5cqV8e7dO5lyfH19MWbMGJXqqi4uvAjHgtPBnAyttsY6mNexMtq52UrUT0tLQ1hYWK6GRnR0tMr1tra2hoODAxwdHSEQCHD06FGp9QwNDTFw4ECMGTMGrq6u4vILL8Ixav8jAOAYJFmPqk0+taSOv6DEx8fj2LFj2LdvH65fv47cbqvm5ubo1asX+vXrh3r16qnccFcGmzdvxqhRo9CsWTNcu3YN0dHR6NGjB65fv86px+PxJMYuEAgwZcoUXLt2Dffv3wcAVK9eHTdu3Mjzfn7hRTgGLNiK70fnAwDsR+6EwNhK5d8nQ3kwY6SUkJmZiYYNG4p/5ADQuXNnnDhxQiU3uX/++QcTJkyQerNdu3YtJkyYoPQ+sxMWFoZatWpxpsfbtWuHM2fOiKeDAWDHjh0YOnRorrImT56Mv/76S2W6qousB3LWN0TCTAiTYiGMj0ZmfBQ6V9CGXkYcx/CIjIxUuV4WFhZwdHQUGxtZR9a5vb09tLW1xfWXLVuGWbNmcWS4urpi7Nix6N+/v8x7gaKGmLIpif4lRIS2bduiTp06WLp0KQAgIyMDkydPhq+vL6cun8+HSCTKU2abNm1w5syZXJdz09PTUda1EsJCPwIAbAf7QsuyTKF+n4yCIffzWzX+s8qF7aaRzfLlyzke7WZmZhQeHq70foRCIU2ePFmmJ72jo6NC3vL5IS0tTSITr4uLC8XExHDqJScnk4WFRZ7e/126dFGpvuogKxFa1k4Ds9YjCTzpcRuUeZiamlK1atXIy8uLRowYQYsXL6Y9e/bQ1atX6e3bt5ScnKzQOEQiEVWsWPHXLgoej7y8vOjChQtSw73L+hzUHbEzP/FLtmzZUmTjl3z+/FnqDrRt27ZJDZKWMxWFtGPIkCG57j5avXo1p/6yXSdYBNZihkq39hY2zBiRzosXLyQCjR08eFDp/aSkpFCPHrKTaAGgHTt2KL3fnIwePZrTp46ODj169Eii3qJFi+R6gFavXl3lOhc2EiniO0wpsKFhZGREVapUoXbt2tHQoUNpwYIFtHPnTrp8+TK9evWKEhMTlT6OBw8ekJGREU2aNInevXundPmFjaLxS7p161as4pfcunWLrK2tpb6k5PX3tWjRIqkyIyIiJLbtnzt3rpBHxigozBgp4WRkZFCdOnU4P9SuXbsqPcZBTEwMNWrUKNebScWKFSkjI0Op/eZkz549Ev3u2bNHot7Pnz9lZgTNeRgaGpaYmBBZBDz+yjFGrHovyfPBZ2NjQ9WqVSNPT08aMWIErVq1ik6fPk0vX75U22/u/fv3JTYgXUmNX/L582eqXbt2vgzeffv2ScgbPHiwRD1VvGwxVAszRko4S5ZwHzIWFhYUGRmp1D5CQkLEU+XZDwMDA875kSNHlNpvTqRl4h09erTUur1791boJhgdXbICJuWcGbEfvZt0nKuRtqMbga+h0Gejr69PTk5OVKNGDWrZsiXNnz+/yD8QixslLT9OcnIy9e3bV6G/MwCkqalJV69eFct58OCBVENty5YtahwdIz8wY6QE8+zZM4k12sOHDyu1j6CgIKnTrjmT0dWuXVulD6iYmBhycXHh9Fm/fn2p09evX7/O800z53H//n2V6a4OsnxGyuSIUuk8/QzZDdlEmuZ5T5tLO9zd3Uuc4VaUUNS/pFGjRkXWvyQuLo68vLwU/hszNjamFy9ekEgkIo/69aXWWbVqlbqHx1AQeZ/ffDCKFRkZGRg4cCAyMjLEZT169ECPHj2U1se5c+fQpEkTzg4LPp+PdevW4dmzZ5y6S5YsUdnWRKFQCG9vb4SEhIjLrKyscOTIEalxGvr06cPZ5cPn/+/P28TEBLq6uhJtPn78qGSt1YsGn4d5HSsD+N921iy0LBxh238Nmnn+rpDMNm3aIDAwEObmLLCUquDxeKhduzbWrl2LsLAwnD17Fr1795YZIfjWrVsYMWIEbGxs0L17d5w8eRLp6emFrLV0jIyMcObMGZw7d06h3Y9xcXFo3749xsxeirvZgjfmrMMomTBjpJixfPlyPHr0SHxuaWmJDRs2KE3+tm3b0KlTJyQnJ4vL9PT0cPLkSaSlpSE8PFxc3rRpU7Rp00ZpfedkwYIFuHDhgvhcQ0MDhw8flhos6eTJk3j8+LH4POf2wrZt2+Lu3buwteVuBcxu6JQU2rnZYpNPLdgYcx9kNsY62DK4Ia6ePY5//vlH7gi5VlZWePr0qdjQE4oIdz7E4OSTMNz5EAOhiPKQwFAEgUCA9u3b4+DBg4iMjMTOnTvRvHlzqUZ/eno6jh07ht9//x12dnYYM2YM7t69m2uck8LC09MT9+/f58SBycLU1BTGxsYS5Z8/f8amFfNkynweEi7zGqOYUxjTNAWFLdP84smTJyQQCDjTlkePHlWKbJFIRLNnz5aYFrWysqL79+/Tz58/yczMjHPt9u3bSulbGqdOnZLQZc2aNVLrRkdHSywpdevWjXO+cuVKIvq1Fp29fNiwYSobg7rJa3vrnTt3yMHBQe5p9N9++40GTZhJtWb4c5Z/PJZeYancC4Hi6l/y8+dPat++vdR7y5YtW2jevHnk4eFBfP7/tqDztQ2Ir2so0cayVlu2rbeYwXxGShhpaWlUo0YNzg+zd+/eSpPdr18/qQ+frJvZnDlzONc6duyolL6l8e7dOzI2Nub016tXL5m+KX369OHUrV69ukRMlMDAQCL6tU05u19Jy5YtVTaO4sD379+pdevWiq3v8/ikW64uWXaZLU7lXmb6GWaQFBLF0b8kMzOTZs6cKaGbpqYmbd++nYiIzj94S8ZNBpC+W0viG5gT+P978dKr3JQAkO5v9VmW3mIGM0ZKGPPmzeP8iK2trZXiUPjz509q2bKlxE2iQYMGYvmRkZGkr68vvsbj8ejp06cF7lsaiYmJ5ObmxtGlSpUqMrd5Hj16lFNXIBDQkydPJMb048cPcZvsswFly5ZVyTiKE5mZmfTnn39K/A2Ym5uToaHk22nWoeNSSzw7Uub/Z0jYW2vhUtzilxw8eJB0dXUldBs3bhwdvR8i/ntynHqSLDrPIOMm/UnfrQU5TTtN5p7jScelNgU8/qoW3Rn5gzmwliAeP36MJUuWcMq2bNlSYIfCr1+/onHjxggMDOSUd+vWDVeuXBHLX7p0KSele58+feTKuqkoRIRhw4bhxYsX4jIjIyOcOHECBgYGEvWjoqIwatQoTtmff/6JatWqcfxqypYtCxMTE/G5i4uL+P+fPn3KMwNpSUdDQwMLFizAuXPnYGZmJi6vVKkSwsPDsWfPHtR0byDRTr9SE/H/CUB4XCruh8QWhsqM/6e4+Zf07t0bt27dgqOjI6f8n3/+wdLx/SBM+ZXRmc/XgH7FRjCp3xMWXpPB4/FgUK0NzNuOhpWhdKdeRvGGGSNFnPT0dAwYMIDzwPT29kbnzp0LJPfZs2fw8PDA8+fPOeWTJk3C4cOHxTtPPn36hE2bNomvCwQCTkI6ZbJ+/XocPHiQU7Zv3z5UqFBBav0xY8YgKipKfF6rVi3MmDEDISEhnOyxtWvX5rTLngNEKBTiy5cvylC/2OPp6YlHjx6hTp06AIDw8HDo6+ujf//+mLflMOyGb4VR/V7QMDAHT6ANgYlkXpDvCbIz1zJUi5GREQYNGoSrV6/i06dPWLZsGSpXriy1bkxMDDZu3Ij69evD1dUVCxcuLLSdZbVq1cKDBw/QqFEjTvmju7cQtW8yMqJCpbbjAXB0coa7i5nU64ziDTNGijiLFi3iGAw2NjZYv359gWQGBgaicePGCAsLE5fxeDz8/fffWLNmDWdL7IIFCzhbBocOHYpy5coVqH9p3Lx5E3/88QenbM6cOejUqZPU+ocPH8aRI0fE55qamtizZw80NTXx8OFDTt3cjBGgZO6oyS/Ozs64desWRo0ahW/fvonfmq0MdaBpagfTJv1g7jUJlJkOgZGlRHv21lo0cHR0xIwZM/DixQsEBQVhwoQJsLKyklr33bt3mDdvHsqVK4fGjRtj69atHGNeFVhbWyMwMBDDhw/nlKf9iED4vj+Q/OY/TnnWPM+8jpWhwS/6WY4Z+aAw1owKSmn1GXnw4AFpaHCjZp46dapAMvfs2SOxI0dbW1vqrpxXr15xPNx1dHTo61flr9eGhYVJ7IZp27YtZWZmSq0fERFB5ubmnPpLly4VX58+fTrn2uXLlznt9+7dy7m+bds2pY+pJLBv3z5KSkoiov8FU3MYuZP4ur/yhThNOc58RooRRdW/ZOPGjRL3JABk3KAPOU07xXZsFXOYA2sxJzU1lapUqcL5cfbv3z/f8kQikdQEcmZmZnTr1i2pbbp3786pO3Xq1Hz3L4u0tDRq0KABp58yZcpIZOLNPo4uXbpw6tetW5eTG6dVq1ac6zll3bp1i3N95syZSh9XSeTE/fekZV2OABBfW59jiLDdNMWLopYf5/r161Izbddr3pYuPwlhRm4xhhkjxZyc2+Ds7OzyvTUvIyODhg4dKvFDd3FxodevX0ttExQUxKlrZGSkknDgY8eO5e7QkJGJNws/Pz+JWZ2XL1+Kr4tEIjI1NeWMMSffvn3jyFDWFumSTEamkNp0+p9xKjBzYHFGSghFJX5JSEgIVa9eXaLPKlWq0Pv375XeH6NwYMZIMebevXuc5REAdPbs2XzJSkhIIE9PT4kfeJ06dSgiIkJmuzZt2nDqy0rzXRByLpcAoN27d8us/+3bN46hAfwvmFkWHz9+5Fzv3r27hByRSMSZpnZ3d1f62EoS559/I+f2Izmfq0GZarTw1AupwdQYxZOiEL8kMTGRevToIXUG98qVK0rrh1F4MGOkmJKSkkKVKlXi/BAHDRqUL1nh4eFUq1YtiR92hw4dKDExUWa7a9eucepbWlpSfHx8focklcePH0usW48aNUpmfZFIRB07duTU9/DwkPAryRl3ZNmyZVLlZf+MLSwslDq2ksT559/IutdiAo9rHOtXasKWZkow6vQvEYlEtGTJEonlIw0NDVq7di3LHF3MYMZIMWXatGmcH6CDgwMnYJe8BAcHk7Ozs8SNY+TIkRz/ipyIRCKqnyNj5tq1awswIkmkZeL18PDI9Ua2Z88eieUcaUtMOZe3Ll68KFVezqyiyja2SgKZQhG5LzxHhrW8SN+N64djWKczc1otJajLv+TUqVNSg+4NGjSIUlNTlTQ6hqphxkgx5M6dOxLLMxcuXFBYzo0bNySWM7JmCfK6QeTMCePo6KjUH75QKJRYNrKyssp1l87Xr18lwsPLylOTc3lJlp9LTl8VVUWULc7cfh8t9guxGbiONC2cSNOqLGkYW5NJ04Hiayw8d+mhsP1LXr58SeXLl5eQ7eHhQd++sVm54gAzRooZycnJ5OrqyvnBDR06VGE5hw4dIi0tLY4cTU1N2r9/f55thUIhVa1aldN2x44d+RmOTHKGHdfQ0KDr16/LrC8SiSSMl0aNGknd9isSiThbfp2dnWXKXbNmDUdmQECAMoZXLBGJRPT9+3cKCgqiY8eO0Zo1a2jixInk0aIdadmUJ76uEem41CaHCf7kMMGf7IZuJstuc8XGCAvPXfooTP+S2NhYiZcM4JdT/71791QwOoYyYcZIMWPKlCkSMxKKjFckEtHq1aslfrDGxsZ09epVuWTk3KlSsWLFXJd0FOX06dMS+v3111+5ttmxYwenvq6uLr17905q3dDQUE7drl27ypQbEBAg10xLSSA9PZ1CQkLo+vXrtHfvXlq0aBENGzaM2rRpQ66urlJzhXCWZGp1IKepJzmZerMf0mZG8soYzCg5FIZ/SUZGhsQ9Evi1m27Pnj0qHB2joDBjpBhx69YtibXYnIG6ciMzM5PGjRsn8UN1dHSk58+fyyUjPT2dypUrx2l/5MiR/A5JAkUz8RIRffr0iYyMjDht1q9fL7P+sWPHOHWXLFkis+7Tp085dceOHVug8RVVAgMDOUkOFTn4fD6V6TiWysgwQmT5jJx//o08ll7h1GXbf0sHqvYv2bNnD2lra0vImjx5slJfnBjKgyXKKyYkJydj0KBBnGRVI0aMQKtWreRu36NHD/zzzz+c8mrVquHOnTtwc3OTS86OHTvw4cMH8Xnt2rXRrVs3udrmRVJSErp27Yq4uDhxWZUqVbB9+3apCb0AgIgwdOhQxMfHi8uaNm2KMWPGyOwnrzDw2cmeLA8ouSHhW7RogatXr8LWVjKPTG4YGhri7Nmz2LR0FoD/hePOQlZ47gsvwjFq/yOEx3Fz1ETEpWLU/ke48CJc0SEwihGqzo/Tv39/3LhxA3Z2dpzyNWvWwMvLS+Vh7BkqpFBMowJSkmdGJk6cyLHwnZ2d5d7Z8f37d/Lw8JB4S2jdurVCn1VSUhLZ2tpyZOTHcVYaIpGI+vbty5FtZGREb968ybXdli1bOG309fXzdIRr27Ytp01UVFSu9bNHfKxUqZLCYytOfPnyhcqWLSvXjIiNjQ1nRk3emY6MTCHVmXuCbAdvIKuei8i673K5ZlIYJRtV+Jd8+/ZN6r2vfPnynCCIDPXDlmmKATdu3JCYygwMDJSr7bt376R6mQ8cOJDS09MV0mPlypUcGU2bNlXaXv5169ZJ6JiXs2hISAgZGBhw2mzcuDHXNiKRiCwtLcX1nZyc8tTN3d1dXF9HR6dYxy+Q5aORkZFBhw4dktiuLevQ1tam8PBwjmyRSEQxsT/owIXbtGCzP81dtZGWLV9OEyZMoB49elDDhg3JxcWFtLS5/gLaTtXk9jFhlA6U6V+SkpIikUoCABkaGhY4hxdDeTBjpIiTmJgo4aMxevRoudrevXtXah6HefPmKfxA/fnzJ5mZmXHk3L59Oz9DkuDmzZsSCbBmzZqVaxuhUEgtWrTgtGnZsiUJhcJc233+/JnTpkuXLnnq17t3b06b4rpVUNrMRe05x2jQhJnk4OAglxGSddSpU4cmTZpEvXr1osaNG1P58uVJT09PIRlZh8DMniw6TSNr7xXkOPEQ233D4KAM/5ILFy5Irc/j8Wjx4sXF+gWjpMCMkSJOTodTFxcXSkhIyLNdQECAxO4HDQ0N2r59e770mDNnDkdWx44d8yUnJ9++fSMbGxuO7DZt2sjMxJvFhg0bOG0MDAwoNDQ0z/5OnDjBaSdP+PqcAdJkJQwsypx//o3jYGo7ZCMZVG9HPIGkk19hHzwtXbId7Et8fZNff6dGVqRbvh4NHDOFDh8+TK9fv87z74FROshv/JJXr17lWrdHjx65RptmqB5mjBRhcoZbB0DXrl3Ls52vr69EUDQDAwM6f/58vvSIiIjg7LTg8XhKCf6VlpZGDRs25Ojp7OycZ6K9Dx8+SLyFb926Va4+cxpV586dy7PNtm3bOG327t0rV19FhUyhiDMjYtzIWy1Gh6amJjk7O1M9Dw8yq9KIDGt1IJMm/cm8/SRymnaK7IZtIQ1DS6ltdXV1qW7dujRkyBBat24dXbt2TWbGZkbJR1H/kjp16uRZp3r16hQSEqLuoZVa5H1+C8AoVBITEzF48GBO2bhx49CsWTOZbUQiEWbMmIFVq1Zxym1sbHDu3DnUrFkzX7osW7YMSUlJ4vM+ffqgWrVq+ZKVnT/++AP//fef+FxbWxvHjx+Hubm5zDYikQiDBg1CcnKyuKxNmzYYOnSoXH0qspMmi7Jly3LOi9uOmvshsZxdKzqOVRCXS31FEQgEsLW1ha2tLezs7DhH9jIzMzPw+b825mXtpgF+PQkAQNPMHrbeKxDhPxuZP7m7aVJSUvDgwQM8ePCAU+7g4IBq1aqJjxo1aqBSpUpKHB2jKMLj8VC7dm3Url0bq1evxqVLl7Bv3z4EBAQgNTVVon5QUFCeMp8+fYq6devi6NGjaNq0qSrUZiiDQjKOCkRJmhkZPXo0x2ovV65crtOIqampEr4NwK/dH/IsX8giNDSUE6lVIBAoJU33vn37JHTduXNnnu1yOroaGRnR58+f5epTJBJx3qIcHBzkapczw++AAQPkaldUCHj8leMn4jTtNAnM7H+Nh6dBfH1TgqZiyzUaGhp06dIlioyMzNNPRxaydt/4XX0s1zR8zsPa2pplbC3lKOJfIusQCAS0ceNG5kdSyLBlmiJIYGAg58fB4/Hoxo0bMuvHxsZSkyZNJH5UTZs2LXDa7kGDBnFkjhw5skDyiIiePHki4c8yYsSIPNu9fftWop08BkwWX7584bTt3LmzXO0yMjJIQ0ND3K5x48Zy91kUyJ47Juuw/H0WmTQbSA7jD/6/gXKKDl25R4cOHaLp06dT3bp1SVNTM9ebto+PT4F1k7W7JyoqimrWrCn3A6R169YUERFRYH0YJYcs/5IKFSrkyygZPnw4JaeksgjBhYS8z28eUbZoW0WU+Ph4GBsbIy4uDkZGRupWJ18kJCSgatWq+PTpk7hs4sSJ+Pvvv6XW//TpEzw9PfHq1StOee/evbF7925oa2vnW5dXr17Bzc0NIpEIAKCjo4P379/D3t4+3zJ//PiBOnXqcIIW1atXD//++2+uugqFQjRt2pSzrNO+fXucOXNGZkC0nJw8eRK///67+HzhwoWYO3euXG3LlSsn1tnBwQFfvnyRq11RQCgiNFpxFRFxqZD2I+YBsDHWwa3pLcSByWJjY2FoaIjIyEg8evQIjx8/Fv+bfewXL15EmzZtVKL3z58/0b59e9y5cyfXetbW1rhy5Qrc3NwgFBHuh8Tie0IqrAx14O5ixgm2xihdfPnyBa1atcLbt2/z1d7Q2Q3GHadDQ98UAGBrrIN5HSujnZtiwQEZeSPv85v5jBQSU6dO5RgiFSpUwJIlS6TWffToEby8vBAREcEpnzZtGpYtWyZen88vf/75p9gQAX75rBTEEBGJRPDx8eEYIlZWVjh69GieRtO6des4hoiJiQm2bt0qtyEC/Pq8siOPv0gWLi4uYr3DwsKQmpoKHR0dudurEw0+D/M6Vsao/Y/AAzgGiawIqWZmZgB+GV4ODg7o1KmT+Fp0dLTYOLl+/Tpat26t0PcgLyYmJrh06RI6d+6Mq1evyqwXGRmJatWqoWm7zvhRsTN+almKr7GHR+nl/fv3aNmyJT5//pxvGQmfXiB5z2RYdp0NbZvy4gjBm3xqsb8pdVEo8zQFpLgv01y6dElieUbWNtLz589L5BLh8/nk6+urFF2CgoIkfDPy2uWSF/Pnz5fwO5Bnd9CrV68kAh/lZ0eLl5cXR4Yi0/rDhg3jtH39+rXC/aub4poLJjk5WeK7k3nw+KRfpTnZDd8qjuZaZvqZIj9GhnL5+fMntW/fnsqWLUvm5uYScYwUPfg6huQ48TCLEKxC2G6aIkJ8fDyGDBnCKZs8eTIaNmwoUXfHjh0YMWIEhEKhuExXVxf+/v6cN9iCMGvWLM751KlTc93lkhfnzp3DggULOGUrVqzIdXcQ8Gt5ZuDAgRwP+U6dOsHHx0dhHbLvpLGzs4O1tbXcbaXtqHF1dVVYB3XSzs0WrSvbFLtlDF1dXRw/fhw+Pj44cuSIuFwgEEBPT4+TlwgkQtLLa0h6fRMOo3ZDQ98EPAALTgejdWWbIj9WhnIwNjbG2bNnxedEhNTUVMTFxSE+Ph5xcXHiI/t5fHw83n2JxMUb95Ae+QFZ84imrUaAr633SxaA8LhU3A+JRf1y+b8nMvIHM0ZUzJQpUzhr8a6urli0aBGnDhFh/vz5WLhwIafc0tISp0+fRr169ZSiy/Xr13Hp0iWO/AkTJuRb3ocPH+Dt7c1J8tezZ09Mnjw5z7Z//fUX7t27Jz43MzPDli1bFF4W+PbtG2c5S5ElGkAyYV5eibqKKhp8XrG8gWppaeHAgQPQ09PDnj17APxaxnn79i2m/LkEu7duBKWniOvruTYCX1sfAHt4MH5tBdbV1YWuri5sbGxyrXvySRielX2C1K+vEBWwBAZurWBQpZlEve8JkluIGaqHGSMq5MKFC9i+fbv4nM/nY/fu3dDV1RWXpaenY/jw4eIbcRbly5fHhQsXUK5cOaXoQkQSsyKzZ8+GoaFhvuQlJyeja9eu+Pnzp7iscuXK2LFjR54GRXBwsISDqa+vb543E2nkJ75IdnLOjBRXY6Q4IxAIsHPnTujr62Pjxo3g8XgwNTVF5yGTcJlfG/H3TyDh4WlQZjqManXA9+OLkPr5GfhaeuBp6aLPcVPYW5rB0NAQhoaGMDIyEv8/55H9mpmZGSwtLfNWkFEisDL85Qum41AJdgP/AV9PujNlVj1G4cKMERXx8+dPiYBdf/zxBzw8PMTn8fHx6NatG65cucKp5+HhgVOnTin1RnnmzBnO7gUnJyeMHDkyX7KICMOHD8ezZ8/EZYaGhjh+/DgMDAxybZuZmYkBAwYgPT1dXNa1a1f07t07X7oo2xgpboHPSgp8Ph++vr4wMDAQG+ZWhjrQ0DWCadMBMKr7O1I/PYO2fUVY9ZiP+Psn8PPGXiAlHp/iIvHpnWL96evr48yZM3kuJzJKDu4uZrA11kFEXCo0DEwlrmftPnN3MSt85Rgo2LYMhkwmT56MsLAw8XmlSpU4vhVhYWFo3LixhCHSpUsXBAYGKtUQEYlEmD17Nqds/vz5+d4e7OvrCz8/P07Z3r175fK1WLlyJSdqooWFBTZt2pTvXRsFNUbMzMw4s0NsZkR98Hg8LF++XLxcmfXw4AHQ0DOGfqXG/1+PD+N63WDrvRLaporPphkbG+PKlSvMECllZO0+A/632ywLWbvPGIUHM0ZUwNmzZ7Fr1y7xedbyTNaW0RcvXsDDw4MzswAA48ePx5EjR6Cnp6dUfQ4ePIjnz5+LzytWrIh+/frlS9atW7ckfEJmzpzJifMhi+fPn2P+/Pmcso0bN8LKyipfugBcYyQrdLki8Hg8zuzIx48fOT4wjMKFx+Nh+PDhAPJ+eGjbuWL/mWvo0aOH3PI1NTVx4cIFzgwlo/TQzs0Wm3xqwcaYuxRjY6zDtvWqG5Xv61ECxWlrb2xsLNnZ2XG2j82cOVN8/erVq2RsbCyxxeyvv/5SSZji9PR0Klu2LKevI0eO5EuWtEy8rVu3livzanp6ukTkzZ49e+ZLj+z6ZJfXoUOHfMnp0qULRw5L1Fa0yGvrskgkoi1btkhsE5d1mJiY0LBhw+j69ev5DnnPKN7IihDMUD4sHLya6N+/P+fGV6VKFUpNTSUiov3790uE4tbS0qJDhw6pTJ9NmzZx+qtdu3a+jJ709HRq1KgRR5aTkxNFRUXJ1X7BggWctlZWVnK3lcWZM2c4MufNm5cvOZMnT+bIefDgQYH0YigfeR4ez58/Vzj3jaOjI02fPp2eP3+uhlExGCUfZoyogVOnTkkE/woKCiKRSERLly6VuBGamprmmpumoCQlJZGtrS2nz4sXL+ZL1vjx4zlytLW1KSgoSK62jx8/lghOdPz48XzpkZ2cBs7JkyfzJcfX15cjR5XGIUO1JCUl0dChQ/MVAKtatWq0YsUK+vLli7qHwWCUGJgxUsjExMRILGHMmTOHMjIyaMSIERI3vjJlytCrV69UqtOKFSs4fTZt2jRfsyJ+fn4S+u/YsUOutmlpaVStWjVO2759+yqsgzQ6derEkfv169d8yTl37hxHzvLly5WiH0N9HDx4kAwNDTnfa5MmTcjHx0ciwnHOg8fjUbNmzWjbtm3048cPdQ+FwSjWMGOkkPH29ubc0FxcXCg2NpY6dOggcbOrXbs2hYeHq1Sfnz9/kqmpKaff27dvKyzn6dOnEhl1hw8fLnf7uXPnctra2NgUOPx8Fvb29mK51tbW+fa5efXqVb7Hxyi6vH//nurUqSP+XrN8ihITE8nPz488PT05WZulHVpaWtS1a1c6fvy4eLmVwWDIDzNGCpETJ05I3MS8vLw4N8Kso3379pSQkKBynebMmcPpt2PHjgrL+PHjB5UrV44jx93dXe6bclBQkMTNPr9LKTmJiIiQ+FzzS0pKCkdWq1atlKIjQ/2kpaXRlClTCAC5ublJXI+MjKR//vmH6tWrl+cyjomJCQ0dOpQ5vjIYCsCMkUIiKiqKrKys5FqTHjZsGGVkZKhcp4iICM5UNI/Ho6dPnyokQygUSszqWFpa0ufPn+Vqn5qaSlWqVOG079evX36GI5WzZ89yZM+dO7dA8rLPspQrV05JWjKKCmfPnqWyZcvmOnv27t07WrBgAVWoUCHP37KjoyNNmzaNnj17VoijYDCKH8wYKSR69+4tlyGyZMkSlWzdlUZOZ9P8+GjkdA7l8/kUGBgod/uZM2dy2tva2lJsbKzCeshi4cKFHPkBAQEFkpd9p5BAICgUo5FRuHz9+lWu71UkEtH9+/dpwoQJcr1oVK1alZYvXy63oc5glCaYMVIIHD16VC5DZP78+YWmU2hoKGlpaXEerO/fv1dIxrlz54jH43HGsHLlSrnb37t3j/h8Pqf9mTNnFB1KrnTu3Jkjv6A7IHJuyQ4JCVGOooxiTUZGBl24cIH69esnl+Nr06ZNmeMrg5ENZoyomO/fv5OlpaVcxgjwKzjYsWPHKD09XaV6DRo0iNPvyJEjFWr/4cMHMjEx4cjo3r273LM6KSkpVLFiRU77QYMG5WcoueLo6CiWb2VlVeBZp/nz53N0vnr1qpI0ZZQUEhMT6cCBA+Tl5SWX42uXLl3o6NGjlJKSom7VGQy1wYwRFdOjRw+5DZHsD015t8Tmh+DgYM6MhI6ODoWFhcndPikpiapXr87RuVKlShQfHy+3jKlTp3LaOzg4KP0t8fv375w+2rVrV2CZe/bs4cjcvn27EjRllFS+f/9Ovr6+5OHhkefv3tjYmIYMGULXrl1jjq+MUoe8z+985abZsGEDypQpAx0dHdSrVw/379+Xq52/vz94PJ5ceUyKMocPH8aRI0fkrl+hQgVs2bIFoaGhGDx4sMr0mjt3LkQikfh83LhxsLOzk6stEWHkyJF4+vSpuCwrE2/2RHK5cfv2baxevZpTtn37dpiYmMjVXl4KmhxPGix7L0MRLC0tMWbMGNy5cwfv37/HwoUL8dtvv0mtGxcXhx07dqB58+ZwdnbGtGnTJPJSMRilHkWtHH9/f9LS0qKdO3fSy5cvadiwYWRiYkKRkZG5tgsJCSF7e3tq3Lgxde7cWaE+i9LMSEREBJmbm8s1E1K/fn06fvy4XLlbCsqDBw84fRsZGSkUzyNnFFJAsSipSUlJErsQhg0blp+h5MnixYvzracsvn79ypHZp08fJWjKKE2IRCJ68OABTZw4kaytrfO8P7i5udGyZcvo06dP6ladwVAZKlumcXd3pzFjxojPhUIh2dnZ0bJly2S2yczMpAYNGtD27dtpwIABxc4YycqLceLRF2raxivPm0ynTp3o1q1bhapjmzZtODosWrRI7rb//fefRLj2GTNmKNT/pEmTOO2dnJxU9n3lTGynjJu5UCgkbW1tscx69eopQVNGaSUjI4MuXrxI/fr1IwMDgzzvGU2aNKGtW7cqdccZg1EUUIkxkpaWRhoaGnTixAlOef/+/alTp04y2/3555/0+++/ExHJZYykpqZSXFyc+Pjy5YvajJHsGUMtOk6VeTPR0tKioUOHqjzEuzSuXbvG0cXS0lLuwGrh4eES+WtatWql0GzOjRs3JHbfXL58Ob/DyRMnJydxPxYWFkrbMp3d8dbKykopMhmMpKQkOnjwIHl5eUkY/dLuI7///jtzfGWUGFTiMxIdHQ2hUAhra2tOubW1NSIiIqS2uXXrFnbs2IFt27bJ3c+yZctgbGwsPhwdHRVRU2lceBGOUfsfITwuFcLEH4i9vFmijomJCWbOnInQ0FBs27YNFStWLFQdiQgzZ87klM2ePRsGBgZ5ts3IyEDPnj0RHh4uLnNycsLBgwehoaEhV/9JSUkYNGgQiEhcNmrUKLRq1UrOEShGdHQ0Pn/+LD6vXbs2eDyeUmS7uLiI///9+3ckJiYqRS6jdKOnp4fevXvjzJkzCA8Px4YNG1C/fn2pddPT0xEQEIDu3bvDxsYGQ4YMwbVr1zi+YAxGSSRfDqzykpCQgH79+mHbtm2wsLCQu93MmTMRFxcnPr58+aJCLaUjFBEWnA7+9bpChJhLGyBKTfhfBb4ATu2GIyT0E5YuXQpbW9tC1xEAzpw5g7t374rPnZycMHLkSLnaTp06FTdv3hSfa2tr49ixYwp/Vx8+fBCflylTBitXrpS7vaKownk1C+bEylA1FhYWGD16NG7fvo0PHz5g0aJFcHV1lVo3Li4OO3fuRIsWLeDk5ISpU6fi6dOnHMOfwSgpKGSMWFhYQENDA5GRkZzyyMhI2NjYSNT/8OEDQkND0bFjRwgEAggEAuzduxenTp2CQCDgPMSyo62tDSMjI85R2NwPiUV4XCoAgNKSIIyP+t9FvgZsB6wFr3onvIrOKHTdshCJRJg9ezanbP78+dDW1s6z7cGDB7Fu3TpO2YYNG1CnTh25+79+/Tr++ecfTtmuXbvkmpXJL48ePeKcM2OEUVwpW7Ys5syZg1evXiEoKAiTJk2Seh8FgLCwMKxevRo1atRA1apVsXz5cs4MIYNR3FHIGNHS0kLt2rURGBgoLhOJRAgMDJQ67VixYkU8f/4cT548ER+dOnVC8+bN8eTJE7Utv8jD94RU8f/5Ogaw6fcXDOt2AfgaMGkyAFpWZSTqFTYHDx7E8+fPxecVK1ZEv3798mz3/PlzDB06lFM2bNgwDBkyRO6+ExMTMWjQIE7ZuHHj0KxZM7ll5IecMyO1atVSmuzsyzQA8PHjR6XJZjBkwePxULt2baxZswZfv37FpUuXMGDAAJlG/cuXLzFz5kw4OzujSZMm2Lp1K2JjYwtZawZDuSi8TDN58mRs27YNe/bswatXrzBq1Cix3wAA9O/fX+zDoKOjAzc3N85hYmICQ0NDuLm5QUtLS7mjUSJWhjqcc56GAGYthsB20D8wqttZZr3CIj09HX/++SenbNGiRRAIBLm2+/nzJ7p06YLk5GRxWd26dSVmOPJi2rRpCA0NFZ+XK1cOy5YtU0hGfshujJiZmcHZ2VlpsnPOjDBjhFHYaGhooHXr1ti9ezciIyPh7++PDh06yPxd37x5EyNGjICNjQ1+//13HD16FKmp6ntBYjDyi8LGSK9evbB69Wr8+eefqFGjBp48eYILFy6InVo/f/7McYgsrri7mMHWWAc5XSO1LJzA42uAB8DWWAfuLmbqUA87d+7kPCxr166Nbt265dpGJBKhX79+nOUxCwsLHDt2TK6lnSyuXLmCTZs2ic95PB527doFfX19BUagODExMRwDSJnOq4DkzAhbpmGoEz09PfTq1QunT59GeHg4Nm7ciAYNGkitm5GRgZMnT6JHjx6wtrbG4MGDcfXqVQiFwkLWmsHIHzwqBt5Q8fHxMDY2RlxcXKH6j2TtpgF+7bvLIuvxt8mnFtq5Fb7janJyMsqXL88x+i5evIg2bdrk2m7RokWc2RQ+n4/Lly+jRYsWcvcdHx+PqlWrctarJ02ahDVr1igwgvxx+fJlzhhnzJih9NkYCwsLxMTEAAAqV66Mly9fKlU+g1FQQkJCcODAAezfvx+vX7/Ota6dnR369OkDHx8fVK9eXanGO4MhD/I+v1W6m6a4087NFpt8asHGmLsUY2OsozZDBAB8fX05hkizZs3QunXrXNucP38e8+bN45QtW7ZMIUMEAP744w+OIfLbb79h8eLFCsnIL6rcSZNF9qWakJAQtnOBUeRwcXHB7NmzERwcjIcPH+bq+Prt2zf89ddfqFmzJtzc3LBs2TJ8+vSpkDVmMORA1QFPlEFRicAa8Pgr3X4fTZlC5QTZyg8/fvwgU1NTTqCk27dv59rmw4cPEm26deumcLCwCxcucGTw+fw8+1Ym3bt35/T/8eNHpffRq1cvTh/h4eFK74PBUDaZmZl0+fJlGjBgABkaGuYZ8bVRo0a0efNmiomJUbfqjBIOy9pbQpk9ezbnptKxY8dc6yclJVGNGjU4bSpWrKhQJl6iX0aQvb09R87UqVMLMhSFcXFxEfdtamqqtMir2ZkxYwZnjP/995/S+2AwVElycjIdOnSIOnbsmGfEV01NTerUqRMdPnyYkpOT1a06owSi0qy9DPUQGRmJtWvXis95PB6WLFkisz4RYdSoUXjy5Im4zMDAACdOnJA7E28WkydPRlhYmPi8YsWKWLhwoUIyCsKPHz84DqXKdl7Ngu2oYRR3dHV10bNnT5w6dQoRERHYtGkTGjZsKLVuRkYGTp06hZ49e8La2hqDBg1CYGAgc3xlFDrMGClGLF26FElJSeLzvn37omrVqjLrb9q0CXv37uWU7d69W+GQ9WfPnsWuXbvE53w+H3v27IGOTuFta84Z7EyZ8UWywwKfMUoS5ubmGDlyJG7duoWPHz9i8eLFqFSpktS6CQkJ2L17N1q1agUnJyf88ccfePz4MfObYhQKzBgpJnz69AmbN/8vN45AIMCCBQtk1r9z5w4mTpzIKZs2bVqe239z8uPHDwwbNoxTNn36dLi7uyskp6AUhvMqwAKfMUouWY6vL1++xKNHjzB58mSZaSyyHF9r1aqFKlWqYOnSpZxt9QyG0imURaMCwnxGiAYOHMhZ6x05cqTMuuHh4WRnZ8ep36JFC8rIyFC43379+nHkVKlShVJTUwsylHzRs2dPjh7v379XST/p6emkoaHBSe3OYJRUMjMz6cqVKzRw4EC5HF8bNmxImzZtoujoaHWrzigmyPv8ZnFGigGvXr2Cm5ubOHOnrq4u3r9/Dzs7O4m6GRkZaNWqFW7cuCEuc3R0xMOHD2FpaalQvydPnsTvv/8uPtfQ0MC9e/dUNiuRG+XLlxcHazMxMUFsbKzKYiaULVtWvDzj6OjIcoAwSgUpKSk4c+YM9u/fj/PnzyMjQ3beLU1NTbRr1w4+Pj7o2LEjdHV1C1FTRnGCxRkpQcydO5eTQnzcuHFSDRHg1xJKdkNES0sLx44dU9gQiYmJwYgRIzhls2bNUosh8vPnT07U2Fq1aqk0eFP2pZqvX78iLS1NZX0xGEUFXV1d9OjRAydPnkR4eDg2bdqERo0aSa2bkZGB06dPo1evXrC2tsbAgQNx5coV5vjKyDfMGCniBAUF4dixY+JzIyMjTJs2TWpdf39//P3335yyDRs2oG7dugr3O27cOE525mrVqmHOnDkKy1EGqszUK43sTqxExIJEMUodWY6vN2/eREhICJYsWYLKlStLrZuQkIA9e/agdevWcHR0xJQpU/Do0SPm+MpQCGaMFHFmzZrFOZ86dSrMzc0l6r148UIi6+7QoUMlsvPKw7Fjx3Dw4EHxuUAgwJ49e9SW2LCwnFezYDtqGIz/UaZMGcyaNQsvXrzA48ePMWXKFJkzs+Hh4VizZg1q166NypUrY8mSJez3w5ALZowUYa5du4bLly+Lz62srCR2yABAXFwcunbtysnEW6dOHYUz8QJAVFQURo0axSmbO3cuatSoobAsZVHYMyNsRw2DIQmPx0ONGjWwevVqfP78GVeuXMGgQYNk+gG8fv0ac+bMQdmyZdGwYUNs2rQJ0dHRhaw1o7jAjJEiChFJzIrMnj0bBgYGnDKRSIT+/fvj3bt34rKsTLz5iQMyZswYREVFic9r1qyJmTNnKixHmWSfGTEyMpKYuVA2LPAZg5E7GhoaaNmyJXbu3ImIiAgcOXIEnTt3hqamptT6t2/fxujRo2Fra4uOHTvi0KFDnJcnBoNt7S2inDx5krOlzsnJSeqW2sWLF0vki7ly5Uq++jx06JBEqOhnz54VdCgF4ufPnxydmjVrpvI+o6KiJPL4MBiMvImJiaHNmzdT48aN89wmbGBgQAMGDKBLly5RZmamulVnqAgWDr4YIxQKMXv2bE7Z/Pnzoa2tzSm7cOEC5s6dyylbunQpWrZsqXCfkZGRGD16tESfuUV4LQweP37MOS+M3Tzm5uacGSg2M8JgyIeZmRlGjBiBGzduIDQ0FEuXLkWVKlWk1k1MTMSePXvQpk0bODg4YPLkyXj48CFzfC2tFI5tVDBK28zI/v37JRLb5QxY9vHjR4lMvF27ds1X8jiRSERdunThyKpTp06+gqQpm9WrV3P0OnDgQKH0W61aNXGfxsbGhdIng1ESEYlE9OTJE/rjjz8kkm1KO1xdXWnRokX04cMHdavOUAJsZqSYkp6ejj///JNTtnjxYggEAvF5SkoKunbtih8/fojLKlasiF27duUr/sbBgwdx4sQJ8bmWlhb27NnD6VNdFPZOmiyy+43ExcVxPmsGgyE/PB4P1atXx6pVq/Dp0ydcvXoVgwcPlun4+ubNG8ydOxflypVDgwYNsHHjRub4WgpgxkgRY8eOHZxlgdq1a6Nr167ic5KRiff48eP5ik4bHh6OsWPHcsoWLVokM6ZAYZPdGDE0NET58uULpV+2o4bBUD4aGhpo3rw5duzYgcjISBw5cgS///67TMfXO3fuYMyYMWLHV39/f+b4WkJhxkgRIjk5GYsWLeKULV26lDPbsXnzZuzZs4dTZ9euXTIzceYGEWHEiBGct34PDw9MmTJFYVmqID4+Hm/fvhWf16pVC3x+4fzJslgjDIZq0dHRQffu3XHixAlERERgy5YtaNKkidS6mZmZOHPmDPr06QNra2sMGDAAly5dQmZmZiFrzVAVzBgpQvj6+iI8PFx83qxZM7Ru3Vp8fufOHUyYMIHTZurUqejevXu++tu3bx9Onz4tPtfR0cHu3buhoaGRL3nKJvvsD1B4SzQA297LYBQmZmZmGD58OP7991+EhoZi2bJluTq+7t27F23btoWDgwMmTZqEoKAg5vhazGHGSBHh58+fWL58Oacs+6xIZGQkunfvzkle1bx5cyxdujRf/YWFhWH8+PGcsiVLlsDV1TVf8lRBTn+RWrVqFVrfbJmGwVAPzs7OmDFjBp4/f44nT55g6tSpsLe3l1o3MjISa9euRd26dVGpUiUsWrSIk8eKUXxgxkgRYfXq1Zzlko4dO6J+/foAfk1R9urVC9++fRNfd3BwgL+/f76cTIkIw4YNQ1xcnLisYcOGErMu6kZdzqvArxDY2WHLNAxG4ZLl+Lpy5Up8/vwZ165dw5AhQ2BsbCy1/ps3b/Dnn3+ifPnyqF+/PjZs2MAJ4Mgo4hTCzp4CU9K39kZERJC+vr54axuPx+MEG5s8eTJn65uWlhbdu3cv3/3t2LGDI09XV5fevn2rjKEolYoVK3ICJAmFwkLt39bWVtx/+fLlC7VvBoMhnZSUFDp69Ch16dKFtLS0ct0mLBAIyMvLiw4cOEBJSUnqVr1UIu/zmxkjRYDx48dzfkDe3t7ia/7+/hI/sC1btuS7r0+fPpGRkRFH3rp165QxDKUSHx9PPB5PrGPjxo0LXYeGDRtyotGyKJEMRtEiNjaWtm7dSk2bNs0zfom+vj7169ePLly4UCRiKJUWmDFSTAgNDeVY9wKBgN6/f09ERC9evODMmACgwYMH5yuwGdGv4EOtW7fmyGvSpEmhzzjIw40bNzh6Tpw4sdB16NevH0eHT58+FboO6iRTKKLb76Mp4PFXuv0+mjKF+fu7YzAKg0+fPtHy5cupatWqeRom1tbWNGHCBLp//36+76cM+WBBz4oJ8+fPR3p6uvh86NChKFeuHOLi4tClSxckJSWJr9WuXRsbNmzIV2AzANi2bRsnC7C+vj527dpVaNtlFUGd/iJZlGYn1gsvwtFoxVX02XYXE/yfoM+2u2i04iouvAjPuzGDoQacnJwwffp0PHv2DE+fPsW0adPg4OAgtW5kZCTWrVsHd3d3VKxYEQsXLmSOr2qm6D2FShHBwcHYu3ev+FxXVxdz586FSCTCgAEDOJl4zc3N852JFwBCQ0Ml4oesXLlS5Rlw80tRMEZK6/beCy/CMWr/I4THpXLKI+JSMWr/I2aQMIo81apVw4oVK/Dp0ydcu3YNQ4cOlen4+vbtW8ybN0/s+Orr68scX9UAM0bUyJ9//gmRSCQ+HzduHOzs7LB8+XKcPHlSXM7n83Hw4EE4Ozvnqx+RSIQhQ4YgMTFRXNaiRQuMHDky/8qrmEePHon/r6+vj99++63QdSiNgc+EIsKC08HIHrGBRMJfx/+fLzgdDKGIxXRgFH34fD6aNWuGbdu2ISIiAseOHUPXrl2hpaUltf7du3cxbtw42NrawsvLCwcOHODMTjNUBzNG1ERQUBCOHTsmPjcyMsL06dNx6dIlzJkzh1N38eLFnOBnirJ582ZcvXpVfG5gYIAdO3YUyeUZAEhKSsLr16/F5zVq1FBLILbSuExzPySWMyMiTE3E96ML8PPfX1F/CUB4XCruh8SqSUMGI3/8X3vnHRfF8f7xz93BHSBdQRApigUVu2JNTAz2iC1qbEGjWGKvYPsSY0HsRo01loiCJaLB3jXGrqBSNHZRimKhSb17fn/448Jyd3BwHef9eu1Ld3Z25plhd+dzM8/MmJiYoHfv3vjzzz+RlJSEzZs346uvvpIbVywW4+jRoxg0aBAqV66MIUOG4Pjx42zFVw2in63RZ8CsWbM459OnT0daWhoGDBjAWUmwV69eCAgIKHM+T548wfTp0zlhy5cvl1lHQ5+Iiori9BjpYogGAKpUqcL5BfU5iJHX6Z+ECEnE+HApFIlbxyH76W2kXT+AjJhzMvEYDEPExsYGI0aMwLlz5/DixQsEBwejQYMGcuNmZmYiJCQEXbp0gZOTEyZOnIjr16+zFV/VDBMjOuDcuXMcR1J7e3uMGjUKffr0wbt3//3irF27NrZv315mh1WJRIJhw4ZxNpbq0KED/Pz8ym68FtAHfxHgUxdv4d6Rz2GYxs5chI8PLiPh97FIjzwMcfp/u6W+PfYrchIeAADsLcrmu8Rg6BvOzs6YMWMG7ty5g7t378Lf3x/Ozs5y475+/Rq//vorWrRogdq1a2PevHl49OiRli0up2hlbo+KlKepvRKJhFq2bMmZZrZq1SoaNmyYzJz4mJgYlfJavXo1J01LS0t68eKFmkqiOX744QeO3dHR0TqzpXPnzhxbMjIydGaLpjl//jx5tWghLat9v/kkdKzJKb/A3JaaBOxh03wZ5RqxWEznz58nPz8/sra2LnGqcIsWLejXX3+l5ORkXZuud7CpvXpKREQErl69Kj13cXGBQCDAtm3bOPG2bduGunXrljmfhw8fygzvrFy5UqHi1ycK94yYmZnBw8NDZ7Z8Dk6sd+/eRbdu3fDVV1/h+rVrAABT9+Ywq9YYdr1mQ2BuK40rzniHzKPByMvN0ZW5DIbG4fP5aNeuHTZt2oSkpCQcOHAAffr0gUgkkhv/2rVrmDBhAqpUqYKuXbti165dzPG1lDAxokFyc3M5jphisRizZ8/mxBkyZAimTJnCCZs2bRr69u1b5nzFYjGGDRuGrKwsaViXLl0wbNiwMqepLTIzMxEXFyc915XzagHlWYw8f/4cvr6+aNSoEY4ePSoN5/F4WLE0GA5WJjCyqAS7XrMBgbH0+oO7tzFq1Cg2Zs74LBCJROjVqxf279+PpKQkbNmyBV9//bXc4XOxWIxjx45h8ODBsLe3x+DBg3Hs2DHm+KoM2umoUQ1DHaa5ffs2NWzYkLKzs4mIaOfOnZyuvRo1apCTkxMn7Ouvv1Z5qeLly5dz0rSysqKXL1+qo0ga559//uHYPn78eJ3a8+eff8oMqRk6b968ocmTJyvc12Po0KFExF2Bde7SdTLxli9fruOSMBi6Iz4+npYsWUINGzYscRjHzs6Oxo8fT1evXv3sVnxly8HrAVu2bCEANGXKFMrJyaHq1atzHtB69epxzqtWrarymGNcXByZmJhw0t2xY4eaSqR51qxZw7F9+/btOrUnMjKSY8+ECRN0ao8qZGRk0IIFC2T2Jip8iEQihcveT506lROXz+fT8ePHtVwKBkP/uHfvHgUEBJCzs3OJwqRGjRoUGBiol5uTagImRvSAn376SfoADhgwQGZvhMLnQqGQrl69qlJ++fn51KKQAyIA6t69u0Ep8aFDh3LsL7x7sS748OGDTH0aGrm5ubRhwwZycHAo8UM5bdo0henk5+dTp06dZHrdHjx4oMXSMBj6i1gspgsXLtDIkSPJxsamxPfNy8uLVq9eTUlJSbo2XWMwMaIHFJ01U9yxYcMGlfMLDg7mpGljY0MJCQlqKIn2KLzJlampqV7srmlra8vpzTIUJBIJ7du3j2rWrKnUM2hlZUVv374tNs13797JpFe7dm368OGDlkrFYBgG2dnZFB4eTt999x2JRKJi3z2BQECdO3emnTt3Unp6uq5NVytMjOiYvLw8MjU1VaoR+Oabb1TuvYiJiZHxAdi1a5eaSqMdPn78SAKBQGp/y5YtdW0SERE1a9ZMapOZmZnB9DQ9e/aMxo0bp1SPCABavHixUunGxcXJDPV07dqV8vPzNVwiBsMw+fDhA/3+++/Uvn174vF4xb6HZmZmNHDgQDpy5Ajl5ubq2nSVYWJEx0RHRyvVABgbG1NcXJxKeeXl5XEaTADUq1cvg2k0C7hy5QqnDGPHjtW1SURE1K9fP45dhtalmp+fTxcuXKCqVasqfA6dnJzo48ePSqd55MgRmY/qjBkzNFgKBqN8EB8fT0uXLqVGjRqV2D7Y2dnRuHHj6MqVKwb3PS+ArTOiYwpv9KYIHo+HU6dOqbyOxpIlS3Dz5k3pecWKFbF+/foyr9yqK/Rl5dWiGPoeNXw+HxEREXj58qXCOPPmzYOpqanSaXbt2hWLFy/mhC1ZsgS7du0qs50MxudA1apVMW3aNERGRiI6OhozZ85UuAnqmzdvsHbtWrRq1Qo1a9ZEYGAg/v33Xy1brCW0JI5UwhB7RiZNmlSi6t26davK+dy9e5eMjY056e7Zs0cNJdA+RVehvXPnjq5NIiKijRs3cuwKCQnRtUlKI5FIaNq0acU+h3Xq1CmTb45EIqFBgwZx0hKJRHT9+nUNlKR0FJ6WfPlRClsxlqHXiMViunjxIo0aNUopx9fmzZvTqlWrDKKXlg3T6Jgvv/yy2Idp0qRJKueRm5tLjRs35qTbt29fNVivGxo0aCAth4mJiV44rxIRnTp1ilPH8+fP17VJSqFIiHTv3p1q1KghPT948GCZ8/j48aPMEGGVKlV06jh97F4CtVx0mlz9D0uPlotO07F7huXMzfg8yc7OpoMHD1Lfvn1LdHzl8/nUqVMn+uOPP+Q6vuqDKGfDNDpEIpEgMjJS4fX27dtj+fLlKucTFBTEycfOzg7r1q1TOV1dkJ2djZiYGOl5w4YNYWRkpEOL/sMQh2mICDNmzMCyZcs44d27d8e+ffvQr18/AEDr1q3h4+NT5nxMTU1x8OBBODg4SMMSEhLQq1cvZGdrf2ff49GJGBNyG4mp3LyTUrMxJuQ2jkcnat0mBqM0iEQi9OjRA3v37kVycjK2bt2Kb775Ru6wu0QiwYkTJ/DDDz/A3t4eAwcOxJEjR5CXl4fj0YloG3wWAzZfxcSwKAzYfBVtg8/q7TvAxIgGePz4MdLT0+Vec3V1xYEDB8Dnq1b1UVFRmD9/Pids/fr1sLOzUyldXXH37l2IxWLpub74iwCf9g8q/PfSdzFCRJg+fbpCISISiaTbDQQHB6vsW+Tk5ITw8HAIhUJp2LVr1zB69GitLhkvlhDmRcSicI4kzkPum2fSsHkRsRBLtGcTg6EKVlZWGDZsGE6fPo34+HgsW7YMjRo1khs3KysLoaGh+Pbbb1GpsgP6+frhWWwk5x3UZ1HOxIgGUOS8ampqiiNHjsDKykql9HNzc+Hr68vZ72DAgAHo06ePSunqkqLOq02aNNGRJbIYGxvDxcVFeq7P+9MUCJGiPW+FhQjwqedp6tSpaNu2rVrybdmyJTZt2sQJ27FjB1atWqWW9JXh+tN3Mj0iadfDkbhtAt6f/R3i3Cwkpmbj+tN3WrOJwVAXTk5OmDp1KiIjIxETE4NZs2YpdHxNe/8O6bePIClkOhI2+SEz9jwA6LUoZ2JEAygSI9u3b0e9evVUTn/BggW4e/eu9Lxy5cpYs2aNyunqEn2dSVNA4aGa+Ph45Obm6tAa+SgrRIBPM7mWLFmi1vx9fX3lbvp48uRJteajiNfpXCGS9z4RHy7tBkiCtBvhSNjyEz4+vCYTj8EwNOrWrYuFCxfiyZMn+PvvvzF69GjY2trKjZv/IQng/dfUE6CXopyJETUhlhCuPH6LQ1GvEHH8lMz1KVOmSMfpVeHWrVtYtGgRJ2zjxo2oWLGiymnrksJiRCQSqUW0qZPCu/cSEZ4/f65Da2QpTojs379f7tbnqg4VyiM4OBgdO3aUnkskEvTv3x8PHz5Ue15Fsbcw4Zx/uBQCSP7rPRSnv8GbA/OxYsZIxMfHa9weBkPT8Pl8tG3bFuvXr0diYiIOHTqENh27g2f035Apz0gEE/fmMvfqmyhnYkQNFHYUGrvlHOLuRnGut2vXDsHBwSrnk5OTA19fX45vxZAhQ9CjRw+V09Yl2dnZiI6Olp43aNAAxsbGxdyhfQqLEUC/hmpKEiKFfTk0jZGREcLCwlCzZk1p2IcPH+Dj44PU1FSN5u1VzRaOViYo8ICx7TAGFRp0lIl38dRR1K1bF6tWrWJbuzPKDUKhED4+Plj62zZUHReCil0nQehUBzyhKQRC2TWEiop3XcPEiIoU9t4niRhvwhcChVzoKto7Ys+ePWqZGTJv3jzOjBNHR0esXr1a5XR1zb179ziNgr4N0QD6O6OGiDBt2jS9ECIF2NjY4NChQ7C0tJSG3b9/HwMHDuQIaXUj4PMQ2L0uAIAHQGBijkpdJsCsVmuZuBkZGZg8eTK8vLw4CwYyGIaOVzVbONnbwtStEcTpbyF0rMW5zgPgaGUCr2ryh3V0BRMjKlDUe//DhR3ITbj/XwS+ERx6z0QlO3uV87p+/bpM78rmzZthY2Ojctq6Rt/9RQD97BkpECIrVqzghOtSiBRQp04dhIaGcmbqHD16FLNnz9Zovp09HbF+cBM4WP33q8+q9fcK40dGRqJFixaYMGEC0tLSNGobg6ENBHweJrWtjOQ9cyFOew2h3X9OrgVvY2D3uhDw9WuFbiZGVKCw9z7l5yH7ZQznuq33SGRYVVfZUSg7Oxu+vr6QSCTSsGHDhqFbt24qpasvFHX41Ucxom89I4qEiI+Pj86FSAFdu3ZFUFAQJyw4OBi7d+/mhN29excpKSlqy7ezpyMu+bdHqF9LrP6+Ef6cM7DYZ0oikWDNmjWoU6cO9u/fr9XpyIZIYf+4K4/f6t2sjM+d9PR0LJ/6I/LefvKLMq7030xABysTrB/cBJ09HXVlnkL0Y1UpA6WwAxDPyBgOAxbj7Yk1yIw+iwqe3jBv1EUmXlkIDAzE/fv/9bhUrVpVphEyZAr3jAiFQr1zXgU+LShXoUIFZGZmAtCtGClOiOzbt08vhEgBM2bMwN27dzkCZPjw4ahVqxaaNWsGAFi6dCnq16+PGTNmqC1fAZ+HVu7/OXX7+fnJ9MAVJSEhAX379kXXrl2xbt06uLm5qc2e8sLx6ETMi4jlTKF2tDJBYPe6etnAfW5kZ2ejZ8+euHHjhjRsmV832LjUgr3Fp6EZfesRKYBHBvAzIC0tDVZWVkhNTeWMQ+uaK4/fYsDmqzLhmQ/+gWn1ZuAbf5rBEOrXkvNhLFUeV66gbdu2nF6R48ePo1OnTmUzWs/IycmBhYUF8vLyAHzqFdHXMfwGDRrg3r17AD75Rbx7p/2pcUSEqVOnYuXKlZxwfRQiBWRlZeHLL7/k/F2dnJxw48YNiMViVKtWDc7Oznj48CEEAoFGbEhLS4OjoyM+fvyoVHxTU1P8/PPPmDx5st45U+uKAv+4og1GQdOmr7+4Pxfy8/PRr18/hIeHS8P4fD4yMjJKtQmmulG2/WbDNCpQ1Hu/gAq124BvLFLZUSgrKwtDhw7lCBE/P79yI0QAIDo6WipEAP0coimg8FDN+/fv8f79e63mb4hCBPjUsIeHh3OWjH/16hV69+6N5cuXIz8/H0+fPsXx48c1ZoOlpWWpptZnZWXB398fTZs2xZUrVzRml6Egb3XbpNBZeL1/Ht6d34aM6DOYvuEg0jMydWbj5wwRYeTIkRwhAnzyddOlECkNTIyoQFHv/cKow1Fozpw5nO2iXVxcZJb4NnQMwXm1AF06sRqqECmgatWqMkvGX716lbNC62+//aZRG/z8/Ep9z71799C6dWuMHj1a6+JTnyi6uq04Nws5L+4h6/ENpF37EylHViJ63U+wsrSAu7s7fHx8MHPmTISEhCAyMhJZWVk6tL58UzBsu23bNplrdevW1YFFZaNMYqRgPNXExAQtWrTA9evXFcbdvHkzvvjiC9jY2MDGxgbe3t7Fxjc05HnvA6o7Cl26dEmm4fn999/1aphKHTAxUjKKhEiPHj0MQogU0LJlS2zcuFHh9WPHjmnUF6dVq1aoU6dOme7duHEjPDw8sHv3brkOrkRUrr5rRSnq95b/9iUgM2DzqR6ePHmCiIgILF68GEOGDEGTJk1QoUIF1KhRAz169MCsWbOwa9cuREVF6WQzxfJGUFCQQh9CffS/U0hptwMOCwsjoVBIW7dupZiYGPLz8yNra2tKTk6WG3/gwIG0bt06ioyMpLi4OBo6dChZWVnRy5cvlc5T2S2IdYk6t2rOyMjgbPEOgMaMGaNGa/WHpk2bSstobGxM2dnZujZJIREREZy/yZIlSzSep0QiocmTJ8tsHd6jRw/KycnReP7qIjc3l27cuEGrV68mOzs7hVuiT58+XaN2LF++vNgt2QFQ9erVqU2bNmRrayv3eocOHejhw4ecdN+/f08VK1akBw8eaNR+XXH5UQq5+h+WHvb9fiG+mVWJdVnSwefzqWbNmtSzZ0+aPXs27d69m+7cuaPX3wF9Yv369cXWb0hIiK5NVLr9LrUY8fLyorFjx0rPxWIxValShYKCgpS6Pz8/nywsLGjHjh1K52kIYkSdTJgwgfNAubm5UXp6uq7NUjs5OTkkFAql5WzSpImuTSqWmJgYzt9l9OjRGs1PIpHQpEmTDF6IXL58mSpWrKhU42Rra0sfP37UmC2vX78mY2NjhfmfPn1aGjc9PZ2mTp1KAoFAJp5IJKL58+dLG824uDipkFH0w8yQyRdLqOWi0+RWSJC4+h+mygODCQJufRoZGalFpNSqVYt69epFc+bModDQULp79y4TKYUIDQ0lHo9XbD3evn1b12ZqRozk5OSQQCCg8PBwTvgPP/xAPj4+SqWRlpZGJiYmFBERoTBOdnY2paamSo/4+PhyK0aKiozz58/LPFDnzp3TjXEa5vbt25xy+vn56dqkYsnMzOTY26lTJ43lVV6ESAEPHjygli1bKtUQbd++XaO29OvXT2He1apVo7dv33LiR0ZGkpeXl9z4Hh4edOHCBTp37pw0rHnz5pSRkaHRMuiCY/cSyM3/sIwgqdRtisL6rFmzJrVr145at25NlSpVUlmkCAQC8vDwoD59+tD//vc/2rNnD927d88g3wlVOHbsWImij8/na1TYK4tGxMirV68IAF2+fJkTPn36dPLy8lIqjTFjxlD16tUpKytLYZzAwEC5lVvexMirV69o6NCh0vP09HSqVq0ap8zjx4/XoYWaZfPmzZyybtiwQdcmlYiDgwPnQ6tOCob6wm/HU/+ho8qNECkgPz+fgoODOb1h8o7mzZtr1I6TJ09K87KxsaHKlStz8u/SpQuJxWIZ29etW0eWlpZybW7UqBHn/Ntvv6W8vDyNlkMXHLuXQC0XneaIkZaLTlPXvkOK/ZsaGRlRt27daN26dXTkyBFas2YNjR49mr788kule81KSr9OnTr03XffUWBgIO3du5diYmIoNzdX11Wmdi5dukSmpqYl1kmNGjV0bSoR6akYCQoKIhsbG7pz506x8T6XnpGC8b6bN28SEdFPP/3EeZjc3d3L5S+sAkaPHs0p7/Xr13VtUom0bt1aaq+xsTHl5+erJd2Cj7zLjAiyaNZD5sPSs2dPgxYihYmJiaFmzZoV+yHV5LMgFovJzc2NAFBgYCCdP39eZigmMDBQ7r0JCQnUv39/pRrIkSNHkkRSdt8xfUWef1xWVhY1adJEqXoxNTWlfv36UXh4OGVnZ5NEIqGkpCQ6c+YM/frrrzRq1Chq27Yt2djYqCxSjI2NqV69etSvXz+aN28e7d+/n2JjYw1WpOTl5dHChQvJ39+fZs6cSePGjVNYdmVHKzSN3g3TLF26lKysrOjGjRulyZKIyq/PSKdOnQgANWzekuZtCOM8SDwejy5evKhrEzVK8+bNOb9siust0xcGDx7M+Tu9ePFC5TQLur8VCZFW7TuXGyFSQG5uLs2fP1+h/0bhHkNNMH/+fKpQoQKlpKQQEdGKFStkbDh8+LDC+48dOybTiynvWLhwoUbLoU88efKErK2tSyUWhg4dqtAPRCKRUEJCAp06dYpWrVpFfn5+1Lp1a7KyUt1x1tjYmDw9Pal///70yy+/0J9//kn37983uN6sBQsWKCzjzJkzdW0eEWnYgXXcuHHSc7FYTE5OTsU6sAYHB5OlpSVduXKltNkRUfkUI6mpqWRk9N+HmCfkdrtNnjxZ1yZqlNzcXBKJRNLyNmrUSNcmKcXcuXM5f6fz58+rlF6BY6Cr/2Gy6z1X5oNiVrMlef1yTKXZWfpMVFQUNWjQQKbcJiYmUqGgCeLj4zkzdyQSiUyPh7W1NT169EhhGpmZmdS1a9cSG77SOOsbOocOHVJKDHh7e9O1a9fKlIdEIqFXr17RyZMnaeXKlTRixAhq1aqVwiG00hxCoZAaNGhAAwYMoPnz59OBAwfowYMHausBjYqKotOnT6ulxywtLU1mxldhPzN9mElDpEExEhYWRiKRiLZv306xsbE0cuRIsra2pqSkJCIiGjJkCAUEBEjjL168mIRCIe3fv58SExOlR2lmh5RHMTJz6QaFL4SRrROFX1f8ESwPREZGcso8fPhwXZukFNu2bePYvXXrVpXSKzxl8lPPSE9p2qY1W5LLtHBy9T9Mlx9prmHWNTk5OTR37lyZoZLgJUvUNl1eHkV/kaenp1O9evU4NjRo0IAyMzNl7k1OTqYffvhBqQbOyMiITp48qVbb9Rl/f/9i68PZ2VkjU6AlEgnFx8fT8ePHafny5fTjjz9SixYtyMLCQmWRIhKJqGHDhjRw4EBauHAhHTx4kB4+fFhqkfL27VsSCATUpk0bOnHihEqiZPHixRwbe/bsSRKJRNp7qw8zaYg0KEaIiNasWUMuLi4kFArJy8uLrl69Kr3Wrl078vX1lZ67urrK/eMqGpOVR3kTI/liCVVs2F7xg1+1Hjl3/JFCQnbR5cuXKS0tTdcmq50tW7Zwyvzbb7/p2iSluHDhAsfuuXPnqpTewciX3KmSQ1aQaa02HCHi6n+YDkYqvy6PoXLjxg2qW7fuf++BrSO5zPiL4yh57F6CRm148OCBTOM1ePBgTqNx4MCBUvszWFhYUFRUlEZt1xfy8vLoyy+/LLY+KlSoQNu2bdOKT41EIqEXL17QsWPHaNmyZTRs2DDy8vIic3NzlUWKiYkJNW7cmAYPHkxBQUF06NAhevTokYwDdGHatWsnvb9FixZ05MiRUtdDRkaGzOykW7duSa/Vr19fL2bSEGlYjGib8iZGLsYlEk9UQamHvV+/fnJ/mRk6Y8aM4ZSzrF222ubFixccuwcNGqRSekUXk3L8cR3xzazJaewfnPDy3DNSmKysLPpu2E8EHp8AkP13P0vroGBaqaYFSXh4uMx7uGbNGul1sVhMkZGRtGTJEvL29uYMNxZ3VKlSRepjpM5FEvWRhIQEmVlK8o7vv/+ePnz4oBMbxWIxPXv2jI4cOUJLliwhX19fatasGZmZmaksUkxNTalJkyY0ZMgQWrx4MUVERNCTJ09ILBbL9U9q2rQpHTp0SGlRUnTxvm+//ZZz/dWrV5qosjKhbPvNdu3VAb9sCEPgmAElxhs0dgZ2rlkMHk8/t3xWhcLbCBgZGSE9PR0mJiYl3KV7xGIxzMzMkJubC+DTEuOXL18ue3oSQtvgs0hKzQYByPuQhISNI2Dq3hx2ff4HPo8HBysTXPJvr7dbf6uTgvp4FhuJlCMrYWzrBLvec/Dx/t8wq9UGfCNjrdTHrFmzEBQUJD03MjLC2l2H4FCrocxW7FlZWbh06RJOnjyJU6dO4c6dOwrTrVevHn7etB/LL7zi7PXiaGWCwO51y9Wut+fOnYO3t7d0o8+hQ4fi4MGD+PDhAyeem5sbQkND0bJlSx1YKYtEIsHz588RGxuLmJgY6REbG6vyHjtmZmZwcHBQuO1Bw4YN8b///Q89e/YEny+7W4tYQvg77hV6tWuCD2/fSMOvXbsGLy8vlWzTFMq230yM6IC+P/hh/84tJcbr0qs/9v6xBebm5lqwSnvk5eXBwsICOTk5AD69gFFRUbo1qhTUrl1buoGhg4MDEhMTVUqvYGt2AMjP/ICXawcDAGy/GQnLZj6f1dbsVx6/xYDNVwEAkrxspP69C0YVnfDu+FoIKtjAosm3MG/cBXsndEQr94oas0MsFqNz5844ffq0NExgbgtH39UQmNsUKx6Sk5Nx+vRpqTgp+nyYuNSHfd9fwDMyloYVyKry9rcOCgrCrFmzAHzaodvCwgKDBg3CpUuXOPEEAgHmzZuHgIAACAQCXZhaIhKJBM+ePeMIlJiYGMTFxal9jx1PT0/MnTsXffr0kdbH8ehEzIuIxYMze/H+zCZp3KZtvsLNS+fUmr86YWJETyEiuLq6Ij4+Xqn4tWvXxt69e9GgQQMNW6Y97t69i4YNG0rPhw0bhq1bt+rQotLRuXNnnDhxQnqemZkJMzMzldIs+NC8evMB8Su/AwDwBMZYt+cYxvT5RqW0DYlDUa8wMSyKE5YUMh05r+Kk5zxjEbr0/h6/LpwLd3d3jdmSkpKCeg0a4XXiK2mYqGo9VP5+IfgCIwAliwciQkxMDE6dOoUTJ07i1NlzkOTlwKzOl6jUfRoyY86D8nNh7vmN1np9tIlEIoGPjw+OHz+Ojx8/QigUIj8/HwsXLsQvv/wi7TUp4KuvvsLOnTtRtWpVHVlcesRiMZ4+fcrpQSkQKQU/uMpKnTp1MGfOHFjV+xLjQu9Akp+LVxtHQJzxThrHYdBSbAsYpLciVun2W8PDRWqhPPmMFF0CvfAhdKxFQseaMuEikYjWr19fbhZQ2rp1K6d8a9eu1bVJpaKov0t0dLRa0s0XS+jSv685adepU6dc+gwpQsaHZuhqhe8Lj8ej3r170z///KMRW/LFEvL8aZ3M3iuVfGZIfVhaLjqttL/H5Ucp5DI1nCp/v4gsW35HFbtNIYH5p6mZAnNbsvn6R3KetLfc+Qe9ffuWOnfuLBP+999/k4uLi8zf1dbWVmYtK0MkPz+f/v33XwoPD6cFCxbQgAEDqEGDBsTn80vvKFupKlXsNplsvLkLRZq4Niz1c6htlG2/ZQelGBpDIpFg6tSpcq+ZN+oCh0FL0OinNeg/YjzHTyQnJwdjxoxB//79kZqaqi1zNcatW7c4502bNtWRJWWjevXqnPOnT5+qJV0Bn4c2Ne04vSxxcXGYMmWKWtI3BLyq2cLRykQ6bGFsXx2VByyCqXtzmbhEhAMHDqBNmzZo3bo1Dhw4ALFYrDZbrj99h3QLV9h2GPMpQGAEm6+Ho0KdLz/lDyAxNRvXn75TnEghXqdng2dkDBPXBrBpNxQkzpP+whVnvMP7c1vxasOPWBU8HykpKWorh66xtbXFnj17ZMLbtm2LqKgofPfdd5zwd+/eoVevXhgzZozKPhq6RCAQoGbNmujZsydmz56N3bt3Y9WqVaAyDEZkp7zE2yMrkXbtT4hcGgC8T023VZsBpX4O9RUjXRvwuZCamgpfX1+cO8cd2+PxeJj6czDa+gws5BjXCT/2/RZDhgzB69evpXH37duHmzdvYs+ePWjeXPbjbCgUFiMCgYAzZGMIVKtWjXOuyBmtrFSoUAEfP36Unm/cuBEdO3ZE79691ZqPPiLg8xDYvS7GhNz+JEh4PJi4NICJSwPkpcQj7UY4cu5fQF4ut/v7ypUr6NOnD9zd3TFp0iQMGzYMFSpUUMmW1+mf/AAsGnaEODUZpjVbQJyegqRd/rBo3AVmtdqAZ2QsjVcS9hZcB+3sF3dl4kiyM7B382oc3rUZfn5+mDp1KpydnVUqhz6gqHvexsYGe/fuxe+//46JEydynvsNGzbg77//RmhoKOrXr68tUzVGSkoKBg8eXKIYsbGxgZubm/RIN7bBocd5MLKqDCNLe/BFZsj7kISPDy7BxNlTep+yz6G+wnxGNIxYQthz8gqmjx6ChOeyjdbmzZsxYsQIufcmJSVh0KBBOHv2LCfc2NgYixcvxuTJkw1upk1+fj4sLS2lv3jq16+Pu3dlP8r6TGRkJJo0aSI9nzhxIlatWgUASEhIQH5+PlxcXMqcfrVq1fDs2TNOmI2NDe7cuVMuGiZlKPChkTfjpLEdH+vWrcNvv/2Gt2/fyr3fxsYGY8aMwbhx4+DoWLax9MLOtIVJObICmdFnwTe1hHl9b2xZFIC+35T846DozCkiQk78PaRe2YfsZ5Fy7zEyMsLgwYPh7+8PDw+PMpXDULh//z4GDBgg48wuEomwfPly/PTTTwb3vSuAiODj44PDhw/D0tIS1apVg5ubm/TfwoeVlRXnXkXPYVFC/Vpq1Km7rDAHVj3geHQiJixaj0f7l4LyZFWrm5sbnjx5UuwLJhaLERQUhMDAQBlnr27dumH79u2oVKmS2m3XFPfu3eM44w4dOhTbtm3ToUXKkZ+fDyOjTx2JqampsLa2ll7z8fHBwYMHERoainHjxuHWrVsyvSelwdPTEzExMTLh7dq1w5kzZ/R2toG6EUsI15++w+v0bJnptADw8eNH/PHHH1ixYgUePnwoNw2hUIhBgwZh6tSpqFevXqnzLyweCpBkZyBh63iI0/+bWunt7Y3Ro0fDx8cHxsbGson9P4VnThVOMzfpEVKv7kPWv5fl/nLm8Xjo1asXAgICDLpXtCRycnIQEBAgFfeF8fHxwe+//25Q37sCMjIy8PDhQ1SrVo3z7VAGRc9hATxArx2flW2/mc+IhjgenYiB4+fgYeh8uUIEAAYOHFii0hcIBJgzZw7OnTsHJycnzrUjR46gUaNG+Pvvv9Vmt6YxVH+RlStXonfv3ti3bx+MjY1hY2MjvRYdHY3vvvsOgwYNQnZ2NlxdXVXKS9HwwoULFzhrX5R3BHweWrlXRI9GTmjlXlHmQ2tmZobRo0cjLi4O4eHhaNu2rUwaubm52LZtGzw9PdGlSxecOXNG6TH7giEj4L+ptwDANzFHpa4TOXFPnz6N7777Di4uLpg7dy5evHghN83Ono5YP7gJHKy4QzautT3x5/59uH//PoYPHy4jaAr8Y7y8vODt7V2qchgSIpEIK1euxJEjR2BnZ8e59tdff6Fhw4YyPcWGgLm5ORo3blxqIQIofg4Lnwd2r6uXQqRUaM6HVn0Y2myawpufVZ0YRpV6BMj1kL55q3R7B7x584a6desmkw6fz6f58+erbTMnTTJ+/HiO7ZcvX9a1SUrx5s0bMjX9tJlhhQoVFK662bhxY5Xz+vrrrxV61QsEAoOpM11w9epV6tu3b7EzFho1akQ7d+5Uehv5Y/cSpO9z4aXpewwarjAPPp9P3bp1o4iICLnvZUkrsMbHx9OUKVOoQgXFKzU3b96c/vzzz2KXHjdkEhISqEOHDnJnUQUEBCj99ysvKHoONb0isaqw5eB1SNHpiTbeo2ReKCMbR/rn4ZtSpy2RSGj58uVyt17/5ptvKDExUQMlUh+tW7fmfLANadrq6NGjFTYMBcfAgQNVzufbb78tNg83NzedLaFtKDx58oQmTJhQbGNetWpVWrJkiVJ1KU88ZGZmUu3atUt8JpydnWn+/PmUkFD6RiMlJYV+/vlnmd1ZCx+1a9emrVu3Uk5OTlmqSq8Ri8W0dOlSud87Ly+vYndVLo8Y4jYCTIzokKKbn7n6Hya7XnNIVMWDKnaZSADIsmVflTY/u3btGlWrVk3mBbW3t9fbHULz8/M5+z7Uq1dP1yaVivv375fY8CxYsEDlfIpuZS/v+P7778vNujOa5N27dxQUFESOjo4K69Lc3JwmT55Mz549K3X6165dk9ltuLherd69e9PJkydL3ZuRkZFBK1euJCcnp2JFz6pVqygjI6PU5dB3bty4QTVq1JAps4WFBYWEhOjaPEYxsHVGdEjRKXwAYFarJSoPXooK9b0hdKyFCh5t5cZTFi8vL0RGRsrM0X/9+jU6deqEWbNmIT8/v8zpa4L79+9zpu4Zir9IAbVr10b37t2LjVOnTh2V81FmSmpYWBh27Nihcl7lHRsbGwQEBODZs2fYvn273CmiGRkZWLlyJdzd3TFgwADcvHlT6fS9vLwwe/ZspeKKxWKkp6cDQKlnhVSoUAGTJk3CkydP8Pvvv6NWrVoyceLj4zFp0iS4urpi/vz5ePfOsNedKEyzZs1w+/Zt+Pr6csLT09MxePBg+Pr6Ij09HWIJ4crjtzgU9QpXHr+FWEI6sphRWpgY0QBFF24qgMfjgcfjoVKXiXCpWRde1WxVysfKygp79+7F+vXrIRKJpOFEhKCgILRr106hI50uMFTn1cIoWrSugLp166qcR3FLy589exbXr1/Hnj17kJGRodZFvsozQqEQvr6+uHPnDk6cOIGOHTvKxBGLxQgLC0Pz5s3x1VdfISIiQmYGmzzmzJnDmeotjzZt2uD27ds4efIkOnToUOYpqkKhED/++CNiY2Oxf/9+ue/Q27dv8b///Q+urq6YNm0aEhISypSXvmFhYYHt27dj9+7dMrMy/vjjD3h4NkSj8b9hwOarmBgWhQGbr6Jt8Fkcj1Zt7yiGdmBiRAOU5P0stHPFzz711OL9zOPxMHr0aFy7dg21a9fmXLt8+TIaNWqEv/76S+V81EF5ECNffvmlQruNjIzUsldKQc+ISCTCwIEDOddOnTqF5s2bo1+/fhg3btxnM81XXfB4PHTs2BEnTpzAnTt34OvrK3cq7oULF+Dj44O6deti06ZNxa4EamxsjJ07d3J+EBTl9u3biIuLU3i9tAgEAvTp0wc3btzAyZMn0b59e5k4GRkZWL58OapVqwY/Pz+F058NjYK1SIru8pvw4imiN0xE6rX9IPokIpNSszEm5DYTJIaAdkaNVMPQfEYK0Lb3c3p6Ovn6+sodT544cSJlZ2drJF9ladOmDcd51VDHtnfv3i23juvWrauW9H/55RcSCoV07NgxSk5O5vgkVKtWjfmKqJlXr15RQEAAWVtbK/THsLOzo59//plev36tMJ2VK1eW6DcydepUysvL00g5rl69Sj179lSYN5/Pp379+tHt26Wbxaev5Obm0uzZs4nH48mU1cS1EblMDS/THkIM9cIcWPUEXXg/79ixQ+4sgiZNmtDDhw81nr88ijqvqqvh1gW5ubnk7OwsU799+vRRS/pr1qyhv/76S3resWNHTj5XrlxRSz4MLunp6bR69Wpyc3NT2KCbmJjQqFGj6P79+zL3i8Vi+uqrrziNv729vUwa3t7elJKiuc3wYmNjydfXl4yMjBSWo1OnTnT+/PlyIWzX7AwngXlFrlNyg44ykwjK2waEhgITI585cXFx1KBBA7ne56GhoVq3JzY2lmPHkCFDtG6DOlm2bJlM3c6dO1ctaRedoll0l+OJEyeqJR+GfPLy8mjv3r3k5eWlsDHn8Xjk4+NDFy9e5DToz549IwsLCwJA9evXp/j4eGrYsKHM/dWqVaOoqCiNluPZs2c0fvx46fo48o5WrVrRoUOHDHqtkoORL6nqhN1kWrMlASAj26pU8dupZNG8J9l2Gkv23y8kpzHb6MCtF7o29bOEiREGffz4UWa7+4LDz89Pq2t87Ny5k5P/ypUrtZa3Jvjw4YO00Sk4du/erZG83r9/T0KhUJqPg4ODQSxwZ+hIJBL6+++/qUePHnKHAgqO5s2b0549e6TDL9u2bZO+Y0REHh4e1KVLF5n7zMzMaM+ePRovx+vXr2nOnDnFDkPVq1evVAvB6RMF6zq5zIgg244/kePQX8llRgRZtuzLKaPIxJQ8PT2pd+/e5O/vT1u2bKELFy5QYmJiuegh0leYGGFI2bt3L1laWsr9AMXExGjFhkmTJnHyvnjxolby1SRTpkzhlEmTv3SL+gKcOXNGY3kxZHnw4AGNHj2aTExMFDborq6utGrVKkpNTaUePXrQli1biIioevXqZGxsTEOHDpW7Jom/v79WxGVqaiotWbKEHBwcFJbBzc2N1q5dSx8/ftS4PeqiYMVrtyLDMq7+h8m2wxgCFAtJ6bCOuTk1btyY+vXrR7Nnz6YdO3bQ5cuX6c2bN0yoqAgTIwwOjx8/pubNm8u8hKampvT7779r/IX74osvOF3c6enpGs1PGzx//lzauPB4PI1+wPfs2cP5u40YMUJjeTEU8/r1a5o3bx7Z2dkpbNisrKxo3Lhx0mX7PT09OT2SlSpVkrmnU6dO9O7dO62UISsrizZu3Eju7u4Ky2BnZ0cLFy6k9+/fa8UmVTl2L4Hc/t9ZtbAYcfM/THa9ZpFQpFhEFnf069fPoFaJ1keYGGHIkJOTQ1OnTpX70g0aNIjS0tI0kq9YLCZzc3NpXh4eHhrJRxf07//9p6ETZ1eNOihnZmZynJJtbGzK5fLfhkJWVhZt3ryZPDw8FDZkRkZGNGTIEJmVkgcOHEiNGzeWie/u7k737t3TWhny8vIoNDRUrk9LwWFpaUn+/v56v80EUfGzFy9dukQ2NjZKixA+n09Lly5lvSJqgIkRhkIOHz5MFStWlHkBa9asqZFpf3FxcTLCpzxw7F4Cef607lMPk3vzUk/dzs3NLdXHbuDAgZx6jIiIKKvpDDUhFospIiKCM4tGmaNDhw5yl/2vUKEC/fnnn1otg0QioaNHj3J6L4seIpGIxowZQ48fP9aqbaWluNmLsbGx5OrqqtTf59dff9VhKcoXTIwwiiU+Pl7ux0coFNLatWvlNpLv378vk9d9SEgIJ48VK1aoowg6paBb2NX/MImcPcm8ybfkPHm/tKtYGUHy6tUr8vb2psjISKXyjIiIkPmFzdAfbt68SQMGDFB6r5oGDRpQYGCg3PizZ8/WyQyXS5cuFbtRo0AgoIEDB9Ldu3e1bps6ePXqVbE9QYUPHx8f+ueff3RtssHDxAijRPLy8mju3LlyZwr06tVLZgx79+7dFBwcXOp8Jk+ezEn7woUL6iqCTihwmJNugth7Lpm4NSLw+CSs7E4WjbuS+3czKDbufok9H7Vq1SIej0dDhw6l+Pj4YuPm5ORwuporVKjAxrP1kOfPn9OUKVNkZlvJO5ycnGjTpk1yeyq7deumM5+Nu3fv0qBBg4oVVt26daNLly7pxD5VSE1NpW+++UbpXqy2bdvS4cOH2ZBNGWFihKE0p0+fpsqVK8u8hK6urpwFtmbOnEkCgaDUH6B27dpx0tWUb4q2KJhKWHC4zPiLjO2ry/2Q2draUpcuXWjevHl04sQJmcZl1KhR0rimpqY0Z86cYuvHz8+Pk35YWJiGS8soCykpKfTll18q1dhZWFjQ9u3b5f5ir+JanXYfv6yz1UMfP35MY8aMIZFIpND+L774go4ePWpQjXVOTg4NGjRIaUECgDw9PemPP/4wyOnPuoSJEUapSEpKog4dOsi8gEZGRhQcHExisVjafVu1alWlV5AUi8WcX4i1atXScEk0z8HIl1wxMjWcIFC82mXRo06dOjRs2DDauHEj/fzzzzLX7e3tacOGDXKXDT979iwnbo8ePbRfAYxiuXv3rozTakmHQCCgtWvXyvUj4QlNqdaQXzS2jYQyJCYmkr+/f7G9PQ0bNqTQ0FCNLXevbsRiMfn7+3PKMH36dFqwYEGxs6VcXFxo1apVBrudhbZhYoRRasRiMQUFBcntmu3cuTNVqVKF00WrzJj2gwcPOOkMGDBACyXRLEV7RqpOCCWLpt1J6FiTwFdelCgjWop2D+fn55Ojo6M0jrGxkEIuxmhtqwFG8Tx+/JiaNGlCxsbGZfqb9xsxnqzbDSPw+DLXrNoMoCN3Xuq0fO/fv6dFixbJXea+4HB3d6cNGzZQVlaWTm1VljVr1kiHqgMDA4no04KR69atK1ZU2traUmBgIL1580a3BdBzlG2/eURE0HPS0tJgZWWF1NRUma2jGernn3/+wYABAxAfH19svKVLl2LatGnFxgkNDeXsPLts2TJMnTpVLXbqCrGE0Db4LJJSs1H05aH8XOQmP4bo3WN4VXiHa9eu4sWLFyrl1759eyxbtgyNGzcGAEyaNAmrV6+WXq/YZSLMG3SAo5UJArvXRWdPR5XyY6iOWCzGq1ev8OTJE7nHmzdvFN5rVrcdKtT5Cm+PLIckO4NzzaZOKzy+fAw21laaLkKxZGVlYdu2bVi6dCmePXsmN46DgwOmTJmCUaNG6f13+88//8SgQYMwefJkBAUFScPz8/Oxf/9+LF68GHfu3JF7r6mpKUaMGIGpU6fC1dVVWyYbDMq230yMMOTy7t07DBs2DH/99ZfCOEZGRrh48SJatWqlMM60adOwfPly6fm5c+fw1VdfqdNUnXA8OhFjQm4DAEeQ8P7/3/WDm0hFQUJCAq5du4arV6/i6tWruHHjRrFb0suDx+NhyJAhWLhwIfZfvIPJg76VXjNxa4zK/efLzZuhn6Snp+Pp06d4/PixVKDcjn6Am9H3kf8hGaIqtWHdfjheh84E5eVw7nV1r4mTRw+jVq1aOrL+P/Ly8rBnzx4sXrwYMTExcuNYW1tj7NixmDhxIuzs7LRsofJcunQJ58+fx5w5c2SuERFOnjyJ4OBgnDt3Tu79AoEA33//Pfz9/VG/fn1Nm2swMDHCUBkiwowZM7Bs2TKFcVxcXBAZGQlbW1u517/++mucP39eev7hwwdYWen2V526OB6diHkRsUhMzZaGKdM7kZ+fj+joaOzbtw+LFi0qVZ4mJiawbdELyVFnIU5N/hTI46Pq2B0QVLABD4CDlQku+beHgM8rNi2GfnEo6hUmhkWBJGKIM94h4+5JpP4TKjeupaUldu/ejW7dumnZSvlIJBIcOXIEQUFBuHLlitw4pqamGD58OKZNm6a3PQj5+fkwMjIqNs6NGzcQHByMAwcOQFHz2bVrV/j7++OLL74Aj/d5v4dKt9+aHS1SD8xnRPu8ePGCRo0apdTYd/fu3eV60ovFYs6eODVr1tRBSTRLcYssFcfHjx+pSZMmZfcpMfpvdgPPWET2feex7dINnMK+SE5jthPPSPEMFuDTFgQLFizQq1ksEomEzp8/T507d1Zot5GREf3www9a2xdLUzx48ID8/Pw4m1gWPVq2bEnh4eEGvSuyqjCfEUaZiYiIwPfff4+PHz8qfc/y5csxZcoUTtjDhw85Xcnff/89QkPl/9L7nCAi/PDDDwgJCSk2nlAoRMWKFVGpUiVUqlQJFStWRAZMcflVLiDOR9bzKJjX+xrmDTuDLzTh3Lv6+0bo0chJk8VgqJnCvkgSImRGn8W7M5tAOZnF3tenTx9s374d5ubmAD49X/rwazwyMhKLFy/G/v37IZFI5Mbp2bMnAgIC0KJFCy1bpz4SExOxatUqrF+/Hunp6XLjeHh4YMaMGRg0aBCEQqGWLdQtbJiGoRLJyckICwtDSEgIbt68WWJ8IyMjXLp0ifNRCQ0Nw8CBA6TnwUuWYMb06Rqx15C4ePEi1q1bJxUaRQVHwb/m5uYyjcqVx28xYPPVEvMI9WuJVu4VNVUEhoYo6ouUn5aCt8d/RfbT28XeV69ePRw8eBA1atTAwYMH4erqKnV41jUPHz7E0qVLsWPHDuTm5sqN8/XXX2PmzJnw9vbWCyFVFj58+IANGzZg1apVSE5OlhvHyckJkydPxsiRI2FhYaFlC3UDEyMMtXH//n2EhIQgJCQEz58/VxjP1dUVkZGRsLSyxtqzj7AwcDbeXN4nvV5n+FKsmDSIOVeqQHEzeQAwn5FyQFFfJCKC0cNzSDy5CVmZGQrvs7a2RlhYGG7cuIFNmzbhxo0bqFy5srbMLpGEhASsWLECGzZsQGam/N6epk2bIiAgAL169YJAINCyheohOzsbf/zxB5YuXYpHjx7JjVPg1DthwgTY29tr2ULtwsQIQ+1IJBJcvnwZISEh2Lt3L96/fy8Tp9XXnZDZbjJSs/KRHDYL2c/vSq85TwyDwMSczfZQkdLM5GEYJmIJ4frTd3idng17CxN4VbPFy/gXGD58OM6cOaPwPj6fjyZNmuDmzZto3bo1zp49C5FIpEXLS+bdu3dYt24dVq9ejbdv38qNU6tWLfj7+2Pw4MEGO6whFosRHh6O4OBghb3LJiYmGDZsGKZNm4bq1atr2ULtwMQIQ6Pk5OTg6NGjCAkJweHDhzndrzbt/WDRzAcvV38Pyf+PdxtZO8Jp1Gb2y11NlHUmD8OwISJs2LAB06dPV9i7UJgff/wRW7Zs0cuhj8zMTGzZsgXLli3Dy5cv5cZxcnLC1KlT4efnJ/WJMTSICOfOncPixYtx6tQpuXH4fD769u0Lf39/vRleUxdsNg1Da7x79442bNhIFm71P3mR843IpsNoMrarRgLLTys1mnl8wWZ7qJmyzuRhGD6PHz+W2fNJ0bF69Wpdm1ssOTk5tG3bNvLw8ChxtVNlt6HQV27dukX9+/cnPl92hd2Co2PHjnTmzBm9miWlCmw2DUOrFDhW5qcmI+3mIaTfOgKQGHwza1Tx2wjKy4KRRSVpfDbbg8FQDYlEgrVr1yIgIKDYRfR4PB5OnDiBDh06aNG60iORSHDo0CEEBQXhxo0bcuNUqFABI0eOxJQpU1C1alUtW6g+Hj9+jGXLlmHbtm3IycmRG6dZs2bw9/c3aP8ZQPn2m69FmxjlmNfpn4YLjKwqw6JxN4DEAADJx1RQTiZHiACAvYWJTBoMBkN5+Hw+JkyYgDt37qB169YK4xERevTogX///VeL1pUePp+PXr164dq1azh9+jS8vb1l4mRmZmLlypWoXr06hg8fjgcPHpSYbn5+vibMVQl3d3esX78ez58/x6xZs2BtbS0T5+bNm+jbty/q1KmDzZs3KxQt5QUmRhhqobC4MLZ1gkVTHxjZOsG201gYWXG9xR2tPjnkMRgM1alatSo6d+5cbJysrCw0b94ciYmJWrKq7PB4PHzzzTc4deoUrl+/jt69e8v4vOTl5WHr1q2oU6cOvvvuO9y6dUtheqNHj8arV680bXaZqFy5MhYuXIgXL15g2bJlqFKlikychw8fYuTIkXBzc0NwcDBSU1M518USwpXHb3Eo6hWuPH4LsUTvBzvkwoZpGGqhpCmnBfDAZnswGOqAiBAWFoaAgAClN2O0tLREZGSkwc3cuH//PpYsWYKdO3cq7Ono0KEDZs6cia+++oojXtq2bYv4+HicOHECHh4e2jK5TOTk5GDXrl1YsmSJwl4fS0tLjBkzBhMnTsSdt9B7R3Y2TMPQKgI+D4Hd6wL4b4ppUWzMjJkQYTDURHx8PG7dugVjY2Ol70lLS4Onp6fCzd70FQ8PD2zduhVPnjzBxIkTYWZmJhPn1KlTaN++PVq1aoWDBw9KV30VCoV48eIF2rRpo3DfHH1BJBLhxx9/RGxsLMLDw+WuTJuWlobg4GC4uLqh7+BhePH0Med6Umo2xoTcxvFo/e8FKwzrGWGoFXlTTq1NjTGsjRvGta/JpvMyGGqGiBAbG4tDhw7h0KFDuH79eon38Pl8rFy5Ej+NHYcbz95z1jMxhHc0JSUFa9aswZo1a+SudwQAdevWhb+/P7Zv3y4VX6ampti7dy++/fZbufdok7t372L8+PFwcXGBq6sr3NzcpP+6uLhAJBKBiHDx4kUEBwfj2LFjClLiwaxWK1h/OQTGFZ3/P0R/llBg64wwdIa8BZt0/UIwGJ8Lr169QkREBA4ePIizZ88iLy9PYdxKTTrC7OvR4Bl9WlhM37r4SyI9PR2bNm3CihUrkJCQoNQ9AoEAGzduxPDhwzVsXcnMmjULQUFBcq85OjpyBIqRkRH++ecfXLx4EWKxWCa+ww8rIXKsyQnTh20hmBhhMBiMz5zU1FQcP34chw4dwl9//SV3oTShQ03Y9ZoFI0s7g13FNycnBzt37kRwcLDCJdiLMn/+fMyePVunC8Ll5eWhXbt2Kg8fCR1rw/GH5TLh+rCEAvMZYTAYjM8cKysr9O/fH7t378a7d++wf/9+mfU5cpMeImnnNEhy/3M+nxcRa1CzMkQiEUaMGIH79+9jz549Sq1iOnfuXIwdO1ZuL4OmISI8f/4cJ0+eRJMmTcqWCI8P48ru4IkqwPqLwXKjGNISCqxnhMFgMD4j/n6QjG5DxiD9Rrg0zMZ7FCybdufE04cu/rIikUjQu3dvHDp0qMS4vXv3xq5du2Biov6Gm4iQmJiImJgYREdHc/7NyFC86WFxGBsb48cff8R1yy/xnm8FcW42eMYiTg+PIfqMGGnRJgaDwWDomHdZ+bBtPxwihxp4e+xXmHl8AYsmsg6dBQsZGhppaWkYOnSoUkIEAA4cOICOHTvi0KFDsLGxAVA2v7eUlBSO4Cj4vyIH29IiFAoxYsQIBAQEwNnZWbphpkBoInfDzMDudXUuREoDEyMMBoPxGVHQdV+hbjsY27nC2KaKXL8JQ+riL+Dff/+Fj4+PUiuzFubvv//GF198gePHjyP6g6DYtTtSU1NlBEd0dDRev36t7uIA+DQE5efnB39/f84QW2dPR6wf3ETGVgcDc0IugA3TMBgMxmdESQsU6lMXf2khIiQkJODff//FgwcPOP8+ffq0RP+QSpUdIfx2LowruUCSm428ty+Ql/ICeW+eIzflOcw/JiIlWbX1O4yNjVG7dm14enqiXr168PT0xK5du7B//35OPBMTE4wcORIzZsyAk5NiJ1R9n73IZtMwGAwGQy4FXfwA5HbxG9psGmXIzc3FkydPpOKksFBJTk6WxuObmMOuz/+QGXMOGVGK1vYoGT6fjxo1asDT05MjPGrWrMlZqI6IUL16dTx79gzAJxEyevRozJgxA46Ohv83YGKEwWAwGAqRt0Choa0zoi4+fPiAP8/dgP/WE8h/9wr5aW9gZFkJqZf3KHV/tWrVOIKjXr168PDwUMopNjo6GvXr14epqSnGjBmD6dOnw8HBQdUi6Q3MgZXBYDAYCuns6YgOdR30uotfW1hbW6NStbowr5crDct+cU9GjAgsKqFB/Xpo36qZVHjUqVMH5ubmZc777NmzmD59OqZNmwZ7e/uSbyinMDHCYDAYnykCPs9gp++qm6IOu8Z2brBo2h3GlVxhXMkFwkou4JuYY52apzyPHTsWAoFAbekZKkyMMBgMBuOzx6uaLRytTKSOvQJTC9h6j5JeL3Ds9apmq9Z8mRD5RJlWYF23bh3c3NxgYmKCFi1alLgx0759+6TjZ/Xr18fRo0fLZCyDwWAwGJqguJ3HDXXtDkOi1GJkz549mDJlCgIDA3H79m00bNgQnTp1UjjH+vLlyxgwYACGDx+OyMhI9OzZEz179kR0dLTKxjMYDAaDoS4K1u5wsOIO2ThYmZTLGUb6RKln07Ro0QLNmzfH2rVrAXxadtfZ2Rnjx49HQECATPz+/fsjMzMThw8floa1bNkSjRo1woYNG5TKk82mYTAYDIa20Pe1OwwJjcymyc3Nxa1btzBz5kxpGJ/Ph7e3t8JdB69cuYIpU6Zwwjp16oSDBw8qzCcnJwc5OTnS87S0tNKYyWAwGAxGmWGOvdqnVMM0KSkpEIvFqFy5Mie8cuXKSEpKkntPUlJSqeIDQFBQEKysrKSHs7NzacxkMBgMBoNhQJTJgVXTzJw5E6mpqdIjPj5e1yYxGAwGg8HQEKUapqlUqRIEAgFn6VwASE5OVrhinIODQ6niA582BhKJRKUxjcFgMBgMhoFSqp4RoVCIpk2b4syZM9IwiUSCM2fOoFWrVnLvadWqFSc+AJw6dUphfAaDwWAwGJ8XpV70bMqUKfD19UWzZs3g5eWFVatWITMzE8OGDQMA/PDDD3ByckJQUBAAYOLEiWjXrh2WL1+Obt26ISwsDDdv3sSmTZvUWxIGg8FgMBgGSanFSP/+/fHmzRv873//Q1JSEho1aoTjx49LnVRfvHgBPv+/DpfWrVtj9+7dmDNnDmbNmoWaNWvi4MGD8PT0VF8pGAwGg8FgGCxs114Gg8FgMBgaQdn2Wy9n0zAYDAaDwfh8YGKEwWAwGAyGTmFihMFgMBgMhk5hYoTBYDAYDIZOYWKEwWAwGAyGTmFihMFgMBgMhk5hYoTBYDAYDIZOYWKEwWAwGAyGTmFihMFgMBgMhk4p9XLwuqBgkdi0tDQdW8JgMBgMBkNZCtrtkhZ7Nwgxkp6eDgBwdnbWsSUMBoPBYDBKS3p6OqysrBReN4i9aSQSCRISEmBhYQEej6e2dNPS0uDs7Iz4+Hi2540GYfWsPVhdawdWz9qB1bN20GQ9ExHS09NRpUoVzia6RTGInhE+n4+qVatqLH1LS0v2oGsBVs/ag9W1dmD1rB1YPWsHTdVzcT0iBTAHVgaDwWAwGDqFiREGg8FgMBg65bMWIyKRCIGBgRCJRLo2pVzD6ll7sLrWDqyetQOrZ+2gD/VsEA6sDAaDwWAwyi+fdc8Ig8FgMBgM3cPECIPBYDAYDJ3CxAiDwWAwGAydwsQIg8FgMBgMnVLuxci6devg5uYGExMTtGjRAtevXy82/r59++Dh4QETExPUr18fR48e1ZKlhk1p6nnz5s344osvYGNjAxsbG3h7e5f4d2H8R2mf6QLCwsLA4/HQs2dPzRpYTihtPX/48AFjx46Fo6MjRCIRatWqxb4fSlDael61ahVq164NU1NTODs7Y/LkycjOztaStYbJxYsX0b17d1SpUgU8Hg8HDx4s8Z7z58+jSZMmEIlEqFGjBrZv365ZI6kcExYWRkKhkLZu3UoxMTHk5+dH1tbWlJycLDf+P//8QwKBgJYsWUKxsbE0Z84cMjY2pnv37mnZcsOitPU8cOBAWrduHUVGRlJcXBwNHTqUrKys6OXLl1q23PAobV0X8PTpU3JycqIvvviCevTooR1jDZjS1nNOTg41a9aMunbtSpcuXaKnT5/S+fPnKSoqSsuWGxalreddu3aRSCSiXbt20dOnT+nEiRPk6OhIkydP1rLlhsXRo0dp9uzZdODAAQJA4eHhxcZ/8uQJmZmZ0ZQpUyg2NpbWrFlDAoGAjh8/rjEby7UY8fLyorFjx0rPxWIxValShYKCguTG79evH3Xr1o0T1qJFCxo1apRG7TR0SlvPRcnPzycLCwvasWOHpkwsN5SlrvPz86l169a0ZcsW8vX1ZWJECUpbz+vXr6fq1atTbm6utkwsF5S2nseOHUvt27fnhE2ZMoXatGmjUTvLE8qIkRkzZlC9evU4Yf3796dOnTppzK5yO0yTm5uLW7duwdvbWxrG5/Ph7e2NK1euyL3nypUrnPgA0KlTJ4XxGWWr56J8/PgReXl5sLW11ZSZ5YKy1vUvv/wCe3t7DB8+XBtmGjxlqee//voLrVq1wtixY1G5cmV4enpi0aJFEIvF2jLb4ChLPbdu3Rq3bt2SDuU8efIER48eRdeuXbVi8+eCLtpCg9goryykpKRALBajcuXKnPDKlSvj/v37cu9JSkqSGz8pKUljdho6Zannovj7+6NKlSoyDz+DS1nq+tKlS/j9998RFRWlBQvLB2Wp5ydPnuDs2bMYNGgQjh49ikePHuGnn35CXl4eAgMDtWG2wVGWeh44cCBSUlLQtm1bEBHy8/MxevRozJo1SxsmfzYoagvT0tKQlZUFU1NTtedZbntGGIbB4sWLERYWhvDwcJiYmOjanHJFeno6hgwZgs2bN6NSpUq6NqdcI5FIYG9vj02bNqFp06bo378/Zs+ejQ0bNujatHLF+fPnsWjRIvz222+4ffs2Dhw4gCNHjmD+/Pm6No2hIuW2Z6RSpUoQCARITk7mhCcnJ8PBwUHuPQ4ODqWKzyhbPRewbNkyLF68GKdPn0aDBg00aWa5oLR1/fjxYzx79gzdu3eXhkkkEgCAkZERHjx4AHd3d80abYCU5Zl2dHSEsbExBAKBNKxOnTpISkpCbm4uhEKhRm02RMpSz3PnzsWQIUMwYsQIAED9+vWRmZmJkSNHYvbs2eDz2e9rdaCoLbS0tNRIrwhQjntGhEIhmjZtijNnzkjDJBIJzpw5g1atWsm9p1WrVpz4AHDq1CmF8Rllq2cAWLJkCebPn4/jx4+jWbNm2jDV4CltXXt4eODevXuIioqSHj4+Pvj6668RFRUFZ2dnbZpvMJTlmW7Tpg0ePXokFXsA8O+//8LR0ZEJEQWUpZ4/fvwoIzgKBCCxbdbUhk7aQo25xuoBYWFhJBKJaPv27RQbG0sjR44ka2trSkpKIiKiIUOGUEBAgDT+P//8Q0ZGRrRs2TKKi4ujwMBANrVXCUpbz4sXLyahUEj79++nxMRE6ZGenq6rIhgMpa3rorDZNMpR2np+8eIFWVhY0Lhx4+jBgwd0+PBhsre3pwULFuiqCAZBaes5MDCQLCwsKDQ0lJ48eUInT54kd3d36tevn66KYBCkp6dTZGQkRUZGEgBasWIFRUZG0vPnz4mIKCAggIYMGSKNXzC1d/r06RQXF0fr1q1jU3tVZc2aNeTi4kJCoZC8vLzo6tWr0mvt2rUjX19fTvy9e/dSrVq1SCgUUr169ejIkSNattgwKU09u7q6EgCZIzAwUPuGGyClfaYLw8SI8pS2ni9fvkwtWrQgkUhE1atXp4ULF1J+fr6WrTY8SlPPeXl59PPPP5O7uzuZmJiQs7Mz/fTTT/T+/XvtG25AnDt3Tu43t6BufX19qV27djL3NGrUiIRCIVWvXp22bdumURt5RKxvi8FgMBgMhu4otz4jDAaDwWAwDAMmRhgMBoPBYOgUJkYYDAaDwWDoFCZGGAwGg8Fg6BQmRhgMBoPBYOgUJkYYDAaDwWDoFCZGGAwGg8Fg6BQmRhgMBoPBYOgUJkYYDAaDwWDoFCZGGAwGg8Fg6BQmRhgMBoPBYOgUJkYYDAaDwWDolP8DvOIyz9FURx8AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Greedy rollouts over untrained policy\n", + "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", + "td_init = env.reset(batch_size=[3]).to(device)\n", + "policy = policy.to(device)\n", + "out = policy(td_init.clone(), phase=\"test\", decode_type=\"greedy\", return_actions=True)\n", + "actions_untrained = out['actions'].cpu().detach()\n", + "rewards_untrained = out['reward'].cpu().detach()\n", + "\n", + "for i in range(3):\n", + " print(f\"Problem {i+1} | Cost: {-rewards_untrained[i]:.3f}\")\n", + " env.render(td_init[i], actions_untrained[i])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Trainer\n", + "\n", + "The RL4CO trainer is a wrapper around PyTorch Lightning's `Trainer` class which adds some functionality and more efficient defaults" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using 16bit Automatic Mixed Precision (AMP)\n", + "GPU available: True (cuda), used: True\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "IPU available: False, using: 0 IPUs\n", + "HPU available: False, using: 0 HPUs\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/logger_connector/logger_connector.py:75: Starting from v1.9.0, `tensorboardX` has been removed as a dependency of the `lightning.pytorch` package, due to potential conflicts with other packages in the ML ecosystem. For this reason, `logger=True` will use `CSVLogger` as the default logger, unless the `tensorboard` or `tensorboardX` packages are found. Please `pip install lightning[extra]` or one of them to enable TensorBoard support by default\n" + ] + } + ], + "source": [ + "trainer = RL4COTrainer(\n", + " max_epochs=3,\n", + " accelerator=\"gpu\",\n", + " devices=1,\n", + " logger=None,\n", + ")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Fit the model" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "val_file not set. Generating dataset instead\n", + "test_file not set. Generating dataset instead\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "\n", + " | Name | Type | Params\n", + "--------------------------------------------------\n", + "0 | env | TSPEnv | 0 \n", + "1 | policy | AttentionModelPolicy | 710 K \n", + "2 | baseline | WarmupBaseline | 710 K \n", + "--------------------------------------------------\n", + "1.4 M Trainable params\n", + "0 Non-trainable params\n", + "1.4 M Total params\n", + "5.681 Total estimated model params size (MB)\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c15144babb9f45dba930de73d048e1f6", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Sanity Checking: | | 0/? [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Greedy rollouts over trained model (same states as previous plot)\n", + "policy = model.policy.to(device)\n", + "out = policy(td_init.clone(), phase=\"test\", decode_type=\"greedy\", return_actions=True)\n", + "actions_trained = out['actions'].cpu().detach()\n", + "\n", + "# Plotting\n", + "import matplotlib.pyplot as plt\n", + "for i, td in enumerate(td_init):\n", + " fig, axs = plt.subplots(1,2, figsize=(11,5))\n", + " env.render(td, actions_untrained[i], ax=axs[0]) \n", + " env.render(td, actions_trained[i], ax=axs[1])\n", + " axs[0].set_title(f\"Untrained | Cost = {-rewards_untrained[i].item():.3f}\")\n", + " axs[1].set_title(r\"Trained $\\pi_\\theta$\" + f\"| Cost = {-out['reward'][i].item():.3f}\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that even after just 3 epochs, our trained AM is able to find much better solutions than the random policy! 🎉" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "# Optionally, save the checkpoint for later use (e.g. in tutorials/4-search-methods.ipynb)\n", + "trainer.save_checkpoint(\"tsp-quickstart.ckpt\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "env", + "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.11.8" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/1-quickstart/index.html b/examples/1-quickstart/index.html new file mode 100644 index 00000000..998aed95 --- /dev/null +++ b/examples/1-quickstart/index.html @@ -0,0 +1,3735 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + RL4CO Quickstart Notebook - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/2-full-training/2-full-training.ipynb b/examples/2-full-training/2-full-training.ipynb new file mode 100644 index 00000000..236fc74d --- /dev/null +++ b/examples/2-full-training/2-full-training.ipynb @@ -0,0 +1,937 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Training: Checkpoints, Logging, and Callbacks" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "In this notebook we will cover a quickstart training of the Split Delivery Vehicle Routing Problem (SDVRP), with some additional comments along the way. The SDVRP is a variant of the VRP where a vehicle can deliver a part of the demand of a customer and return later to deliver the rest of the demand.\n", + "\n", + "\n", + "\n", + "\n", + "\"Open\n", + "\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installation\n", + "\n", + "Uncomment the following line to install the package from PyPI. Remember to choose a GPU runtime for faster training!\n", + "\n", + "> Note: You may need to restart the runtime in Colab after this\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install rl4co\n", + "\n", + "## NOTE: to install latest version from Github (may be unstable) install from source instead:\n", + "# !pip install git+https://github.com/ai4co/rl4co.git" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "from lightning.pytorch.callbacks import ModelCheckpoint, RichModelSummary\n", + "\n", + "from rl4co.envs import SDVRPEnv\n", + "from rl4co.models.zoo import AttentionModel\n", + "from rl4co.utils.trainer import RL4COTrainer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Main Setup" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Environment, Model and LitModule" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n" + ] + } + ], + "source": [ + "# RL4CO env based on TorchRL\n", + "env = SDVRPEnv(generator_params=dict(num_loc=20))\n", + "\n", + "# Model: default is AM with REINFORCE and greedy rollout baseline\n", + "model = AttentionModel(env,\n", + " baseline='rollout',\n", + " train_data_size=100_000, # really small size for demo\n", + " val_data_size=10_000)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Test greedy rollout with untrained model and plot" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tour lengths: ['29.45', '14.26', '21.15']\n" + ] + }, + { + "data": { + "image/png": "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ddWY5RtmO3ai7gwivPxgMBigFAK+Hirk605DE9w52mLqsKDcWIdZ/uED+u7tOvdai727RDNiNBoBAJGRkRJnQkRENLTc8sI6nC+twP1b/woA+Mna+9FcdwGHX/8IABASPx4LX1yP6565A5U5eRh3QzISfrUIz/3yPvx3eTUAYNrSW1B356148O57YDhbi5kr/wuBMaMx/4a70GG2DDhHo9EIjUbT6+susTeN1WpFTU0NfH19IZPJfrDfazAYEBkZiaqqKu55M4hYZ+dhrZ2DdXYO1rlvXik9hDAvDRaFT7Y9D1B64/bRCbaY/zTU4AtdMerNrQhSjcDN2jhM9Ovc4Larzu8d+xfymvQwdVgQNSIQP4+IxyiVz4ByE0LAaDQiLCzMbhPdy7lEMzJYuAGfc7DOzsNaOwfr7Byss3MMhTrzbhoiIiKSFJsRIiIiktSwbkZUKhXS09OhUqmkTsWtsc7Ow1o7B+vsHKyzcwyFOg/rOSNEREQkvWE9MkJERETSYzNCREREkmIzQkRERJJiM0JERESScvtmZNu2bYiKioJarUZSUhK+++67q8bv2LEDcXFxUKvVmDJlCjIzM52UqWtzpM7bt2/HnDlzEBAQgICAAKSmpl7z74UucfQz3SUjIwMymQyLFy8e3ATdhKN1bmhowKpVq6DVaqFSqTBhwgT++9EHjtb5+eefR2xsLLy8vBAZGYmHH34YJpNztrl3VV9//TUWLlyIsLAwyGQy7N69+5rnZGdnY/r06VCpVBg3bhzeeeedwU1SuLGMjAyhVCrFW2+9JU6ePCnuvfde4e/vL/R6fY/xBw8eFAqFQjz77LOioKBArF+/Xnh6eorjx487OXPX4midly5dKrZt2yby8vJEYWGhuPvuu4VGoxHV1dVOztz1OFrrLuXl5SI8PFzMmTNHLFq0yDnJujBH69zW1iZmzJghFixYIL755htRXl4usrOzRX5+vpMzdy2O1vn9998XKpVKvP/++6K8vFx88cUXQqvViocfftjJmbuWzMxMsW7dOrFz504BQOzateuq8WVlZcLb21usWbNGFBQUiK1btwqFQiH27t07aDm6dTMya9YssWrVKtvzjo4OERYWJp555pke42+77TZx88032x1LSkoSv/71rwc1T1fnaJ0v197eLnx9fcW77747WCm6jf7Uur29XaSkpIg33nhDLF++nM1IHzha51deeUVER0cLs9nsrBTdgqN1XrVqlZg/f77dsTVr1ojZs2cPap7upC/NyO9//3sxefJku2NLliwRaWlpg5aX216mMZvNyM3NRWpqqu2YXC5HamoqcnJyejwnJyfHLh4A0tLSeo2n/tX5ci0tLbBYLAgMDBysNN1Cf2v95JNPIjg4GCtXrnRGmi6vP3X+9NNPkZycjFWrViEkJATx8fHYtGkTOjo6nJW2y+lPnVNSUpCbm2u7lFNWVobMzEwsWLDAKTkPF1J8F3oM2m+WWF1dHTo6OhASEmJ3PCQkBEVFRT2eo9PpeozX6XSDlqer60+dL/eHP/wBYWFhV3z4yV5/av3NN9/gzTffRH5+vhMydA/9qXNZWRn279+PO++8E5mZmSgtLcUDDzwAi8WC9PR0Z6TtcvpT56VLl6Kurg7XXXcdhBBob2/H/fffj7Vr1zoj5WGjt+9Cg8GA1tZWeHl5/eB/ptuOjJBr2Lx5MzIyMrBr1y6o1Wqp03ErRqMRy5Ytw/bt2xEUFCR1Om7NarUiODgYr7/+OhITE7FkyRKsW7cOr776qtSpuZXs7Gxs2rQJL7/8Mo4ePYqdO3diz5492Lhxo9Sp0QC57chIUFAQFAoF9Hq93XG9Xo/Q0NAezwkNDXUonvpX5y7PPfccNm/ejK+++gpTp04dzDTdgqO1PnXqFE6fPo2FCxfajlmtVgCAh4cHiouLERMTM7hJu6D+fKa1Wi08PT2hUChsxyZOnAidTgez2QylUjmoObui/tT58ccfx7Jly3DPPfcAAKZMmYLm5mbcd999WLduHeRy/v/6h9Dbd6Gfn9+gjIoAbjwyolQqkZiYiKysLNsxq9WKrKwsJCcn93hOcnKyXTwA7Nu3r9d46l+dAeDZZ5/Fxo0bsXfvXsyYMcMZqbo8R2sdFxeH48ePIz8/3/a49dZbMW/ePOTn5yMyMtKZ6buM/nymZ8+ejdLSUluzBwAlJSXQarVsRHrRnzq3tLRc0XB0NYCC26z9YCT5Lhy0qbFDQEZGhlCpVOKdd94RBQUF4r777hP+/v5Cp9MJIYRYtmyZePTRR23xBw8eFB4eHuK5554ThYWFIj09nbf29oGjdd68ebNQKpXik08+EWfPnrU9jEajVG/BZTha68vxbpq+cbTOlZWVwtfXV6xevVoUFxeLzz//XAQHB4unnnpKqrfgEhytc3p6uvD19RUffvihKCsrE19++aWIiYkRt912m1RvwSUYjUaRl5cn8vLyBACxZcsWkZeXJyoqKoQQQjz66KNi2bJltviuW3sfeeQRUVhYKLZt28Zbewdq69atYvTo0UKpVIpZs2aJb7/91vba3LlzxfLly+3iP/74YzFhwgShVCrF5MmTxZ49e5ycsWtypM5jxowRAK54pKenOz9xF+ToZ7o7NiN952idDx06JJKSkoRKpRLR0dHi6aefFu3t7U7O2vU4UmeLxSI2bNggYmJihFqtFpGRkeKBBx4QFy5ccH7iLuTAgQM9/pvbVdvly5eLuXPnXnFOQkKCUCqVIjo6Wrz99tuDmqNMCI5tERERkXTcds4IERERuQY2I0RERCQpNiNEREQkKTYjREREJCk2I0RERCQpNiNEREQkKTYjREREJCk2I0RERCQpNiNEREQkKTYjREREJCk2I0RERCQpNiNEREQkqf8HgaPOLNtqJPsAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Greedy rollouts over untrained policy\n", + "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", + "td_init = env.reset(batch_size=[3]).to(device)\n", + "policy = model.policy.to(device)\n", + "out = policy(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True)\n", + "\n", + "# Plotting\n", + "print(f\"Tour lengths: {[f'{-r.item():.2f}' for r in out['reward']]}\")\n", + "for td, actions in zip(td_init, out['actions'].cpu()):\n", + " env.render(td, actions)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Training" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Callbacks \n", + "\n", + "Here we set up a checkpoint callback to save the best model and another callback for demonstration (nice progress bar). You may check other callbacks [here](https://lightning.ai/docs/pytorch/stable/extensions/callbacks.html)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# Checkpointing callback: save models when validation reward improves\n", + "checkpoint_callback = ModelCheckpoint( dirpath=\"checkpoints\", # save to checkpoints/\n", + " filename=\"epoch_{epoch:03d}\", # save as epoch_XXX.ckpt\n", + " save_top_k=1, # save only the best model\n", + " save_last=True, # save the last model\n", + " monitor=\"val/reward\", # monitor validation reward\n", + " mode=\"max\") # maximize validation reward\n", + "\n", + "# Print model summary\n", + "rich_model_summary = RichModelSummary(max_depth=3)\n", + "\n", + "# Callbacks list\n", + "callbacks = [checkpoint_callback, rich_model_summary]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Logging\n", + "\n", + "Here we will use Wandb. You may comment below lines if you don't want to use it. You may check other loggers [here](https://lightning.ai/docs/pytorch/stable/extensions/logging.html)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We make sure we're logged into W&B so that our experiments can be associated with our account. You may comment the below line if you don't want to use it." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# import wandb\n", + "# wandb.login()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "## Comment following two lines if you don't want logging\n", + "from lightning.pytorch.loggers import WandbLogger\n", + "\n", + "logger = WandbLogger(project=\"rl4co\", name=\"sdvrp-am\")\n", + "\n", + "\n", + "## Keep below if you don't want logging\n", + "# logger = None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Trainer\n", + "\n", + "The RL4CO trainer is a wrapper around PyTorch Lightning's `Trainer` class which adds some functionality and more efficient defaults" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The Trainer handles the logging, checkpointing and more for you. " + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using 16bit Automatic Mixed Precision (AMP)\n", + "Trainer already configured with model summary callbacks: []. Skipping setting a default `ModelSummary` callback.\n", + "GPU available: True (cuda), used: True\n", + "Trainer already configured with model summary callbacks: []. Skipping setting a default `ModelSummary` callback.\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "IPU available: False, using: 0 IPUs\n", + "HPU available: False, using: 0 HPUs\n" + ] + } + ], + "source": [ + "from rl4co.utils.trainer import RL4COTrainer\n", + "\n", + "trainer = RL4COTrainer(\n", + " max_epochs=2,\n", + " accelerator=\"gpu\",\n", + " devices=1,\n", + " logger=logger,\n", + " callbacks=callbacks,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Fit the model" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Failed to detect the name of this notebook, you can set it manually with the WANDB_NOTEBOOK_NAME environment variable to enable code saving.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[34m\u001b[1mwandb\u001b[0m: Currently logged in as: \u001b[33msilab-kaist\u001b[0m. Use \u001b[1m`wandb login --relogin`\u001b[0m to force relogin\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/wandb/sdk/lib/ipython.py:77: DeprecationWarning: Importing display from IPython.core.display is deprecated since IPython 7.14, please import from IPython display\n", + " from IPython.core.display import HTML, display # type: ignore\n" + ] + }, + { + "data": { + "text/html": [ + "wandb version 0.16.6 is available! To upgrade, please run:\n", + " $ pip install wandb --upgrade" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "Tracking run with wandb version 0.16.5" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "Run data is saved locally in ./wandb/run-20240428_182146-xcgdzio4" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "Syncing run sdvrp-am to Weights & Biases (docs)
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + " View project at https://wandb.ai/silab-kaist/rl4co" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + " View run at https://wandb.ai/silab-kaist/rl4co/runs/xcgdzio4/workspace" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "val_file not set. Generating dataset instead\n", + "test_file not set. Generating dataset instead\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n" + ] + }, + { + "data": { + "text/html": [ + "
┏━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┓\n",
+       "┃     Name                                    Type                   Params ┃\n",
+       "┡━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━┩\n",
+       "│ 0  │ env                                    │ SDVRPEnv              │      0 │\n",
+       "│ 1  │ policy                                 │ AttentionModelPolicy  │  694 K │\n",
+       "│ 2  │ policy.encoder                         │ AttentionModelEncoder │  595 K │\n",
+       "│ 3  │ policy.encoder.init_embedding          │ VRPInitEmbedding      │    896 │\n",
+       "│ 4  │ policy.encoder.net                     │ GraphAttentionNetwork │  594 K │\n",
+       "│ 5  │ policy.decoder                         │ AttentionModelDecoder │ 98.8 K │\n",
+       "│ 6  │ policy.decoder.context_embedding       │ VRPContext            │ 16.5 K │\n",
+       "│ 7  │ policy.decoder.dynamic_embedding       │ SDVRPDynamicEmbedding │    384 │\n",
+       "│ 8  │ policy.decoder.pointer                 │ PointerAttention      │ 16.4 K │\n",
+       "│ 9  │ policy.decoder.project_node_embeddings │ Linear                │ 49.2 K │\n",
+       "│ 10 │ policy.decoder.project_fixed_context   │ Linear                │ 16.4 K │\n",
+       "│ 11 │ baseline                               │ WarmupBaseline        │  694 K │\n",
+       "│ 12 │ baseline.baseline                      │ RolloutBaseline       │  694 K │\n",
+       "│ 13 │ baseline.baseline.policy               │ AttentionModelPolicy  │  694 K │\n",
+       "│ 14 │ baseline.warmup_baseline               │ ExponentialBaseline   │      0 │\n",
+       "└────┴────────────────────────────────────────┴───────────────────────┴────────┘\n",
+       "
\n" + ], + "text/plain": [ + "┏━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┓\n", + "┃\u001b[1;35m \u001b[0m\u001b[1;35m \u001b[0m\u001b[1;35m \u001b[0m┃\u001b[1;35m \u001b[0m\u001b[1;35mName \u001b[0m\u001b[1;35m \u001b[0m┃\u001b[1;35m \u001b[0m\u001b[1;35mType \u001b[0m\u001b[1;35m \u001b[0m┃\u001b[1;35m \u001b[0m\u001b[1;35mParams\u001b[0m\u001b[1;35m \u001b[0m┃\n", + "┡━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━┩\n", + "│\u001b[2m \u001b[0m\u001b[2m0 \u001b[0m\u001b[2m \u001b[0m│ env │ SDVRPEnv │ 0 │\n", + "│\u001b[2m \u001b[0m\u001b[2m1 \u001b[0m\u001b[2m \u001b[0m│ policy │ AttentionModelPolicy │ 694 K │\n", + "│\u001b[2m \u001b[0m\u001b[2m2 \u001b[0m\u001b[2m \u001b[0m│ policy.encoder │ AttentionModelEncoder │ 595 K │\n", + "│\u001b[2m \u001b[0m\u001b[2m3 \u001b[0m\u001b[2m \u001b[0m│ policy.encoder.init_embedding │ VRPInitEmbedding │ 896 │\n", + "│\u001b[2m \u001b[0m\u001b[2m4 \u001b[0m\u001b[2m \u001b[0m│ policy.encoder.net │ GraphAttentionNetwork │ 594 K │\n", + "│\u001b[2m \u001b[0m\u001b[2m5 \u001b[0m\u001b[2m \u001b[0m│ policy.decoder │ AttentionModelDecoder │ 98.8 K │\n", + "│\u001b[2m \u001b[0m\u001b[2m6 \u001b[0m\u001b[2m \u001b[0m│ policy.decoder.context_embedding │ VRPContext │ 16.5 K │\n", + "│\u001b[2m \u001b[0m\u001b[2m7 \u001b[0m\u001b[2m \u001b[0m│ policy.decoder.dynamic_embedding │ SDVRPDynamicEmbedding │ 384 │\n", + "│\u001b[2m \u001b[0m\u001b[2m8 \u001b[0m\u001b[2m \u001b[0m│ policy.decoder.pointer │ PointerAttention │ 16.4 K │\n", + "│\u001b[2m \u001b[0m\u001b[2m9 \u001b[0m\u001b[2m \u001b[0m│ policy.decoder.project_node_embeddings │ Linear │ 49.2 K │\n", + "│\u001b[2m \u001b[0m\u001b[2m10\u001b[0m\u001b[2m \u001b[0m│ policy.decoder.project_fixed_context │ Linear │ 16.4 K │\n", + "│\u001b[2m \u001b[0m\u001b[2m11\u001b[0m\u001b[2m \u001b[0m│ baseline │ WarmupBaseline │ 694 K │\n", + "│\u001b[2m \u001b[0m\u001b[2m12\u001b[0m\u001b[2m \u001b[0m│ baseline.baseline │ RolloutBaseline │ 694 K │\n", + "│\u001b[2m \u001b[0m\u001b[2m13\u001b[0m\u001b[2m \u001b[0m│ baseline.baseline.policy │ AttentionModelPolicy │ 694 K │\n", + "│\u001b[2m \u001b[0m\u001b[2m14\u001b[0m\u001b[2m \u001b[0m│ baseline.warmup_baseline │ ExponentialBaseline │ 0 │\n", + "└────┴────────────────────────────────────────┴───────────────────────┴────────┘\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Trainable params: 1.4 M                                                                                            \n",
+       "Non-trainable params: 0                                                                                            \n",
+       "Total params: 1.4 M                                                                                                \n",
+       "Total estimated model params size (MB): 5                                                                          \n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1mTrainable params\u001b[0m: 1.4 M \n", + "\u001b[1mNon-trainable params\u001b[0m: 0 \n", + "\u001b[1mTotal params\u001b[0m: 1.4 M \n", + "\u001b[1mTotal estimated model params size (MB)\u001b[0m: 5 \n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "07f138c5315e4403abbe0cfed220bfb3", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Sanity Checking: | | 0/? [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGdCAYAAADAAnMpAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAADDpUlEQVR4nOzdd3xT5eLH8c/Jatqm6d6DlraUTaHsISAoQ3HiVXHhvA7cet3rp/eq13Hde+t14UC5yl6C7L26oHTvldE0zTj5/ZESqG0RsG1aeN68+iI5OSd5TkfON8+UXC6XC0EQBEEQBC9ReLsAgiAIgiCc3kQYEQRBEATBq0QYEQRBEATBq0QYEQRBEATBq0QYEQRBEATBq0QYEQRBEATBq0QYEQRBEATBq0QYEQRBEATBq1TeLsDxkGWZ0tJSAgICkCTJ28URBEEQBOE4uFwuTCYTMTExKBTt13/0iDBSWlpKfHy8t4shCIIgCMJJKCoqIi4urt3He0QYCQgIANwno9frvVwaQRAEQRCOh9FoJD4+3nMdb0+PCCOHm2b0er0II4IgCILQw/xZFwvRgVUQBEEQBK8SYUQQBEEQBK8SYUQQBEEQBK8SYUQQBEEQBK8SYUQQBEEQBK8SYUQQBEEQBK8SYUQQBEEQBK8SYUQQBEEQBK8SYUQQBEEQBK864TDy22+/MWvWLGJiYpAkiQULFvzpMatXr2bYsGH4+PiQkpLCJ598chJFFQRBEAThVHTCYaShoYEhQ4bw5ptvHtf+hw4d4pxzzmHy5Mns3LmTu+66ixtuuIElS5accGEFQRAEQTj1nPDaNDNmzGDGjBnHvf8777xDUlISL730EgD9+vVj3bp1/Oc//2HatGkn+vKCIAiCIJxiOr3PyIYNG5g6dWqLbdOmTWPDhg3tHtPU1ITRaGzxJQiCIAjCqanTw0h5eTmRkZEttkVGRmI0GmlsbGzzmGeffZbAwEDPV3x8fGcXUxAEQRAEL+mWo2keeughDAaD56uoqMjbRRIEQRAEoZOccJ+RExUVFUVFRUWLbRUVFej1enx9fds8xsfHBx8fn84umiAIgiAI3UCn14yMGTOGFStWtNi2bNkyxowZ09kvLQiCIAhCD3DCYcRsNrNz50527twJuIfu7ty5k8LCQsDdxHL11Vd79r/55pvJy8vjH//4B1lZWbz11lt8++233H333R1zBoIgCIIg9GgnHEa2bt3K0KFDGTp0KAD33HMPQ4cO5fHHHwegrKzME0wAkpKS+OWXX1i2bBlDhgzhpZde4oMPPhDDegVBEARBAEByuVwubxfizxiNRgIDAzEYDOj1em8XRxAEQRCE43C81+9uOZpGEARBEITThwgjgiAIgiB4lQgjgiAIgiB4lQgjgiAIgiB4lQgjgiAIgiB4lQgjgiAIgiB4VadPBy/0fLXWBsyOphbbdCofQrT+XiqRIAiCcCoRYUQ4plprA49tXYjDJbfYrpIUPD18lggkgiAIwl8mmmmEYzI7mloFEQCHS25VWyIIgiAIJ0PUjJzi/tjEIppXBEEQhO5GhJFTWFtNLKJ5RRAEQehuRDPNKWp/XRnvZK5t1cTicMlkGyq8VCpBEARBaE3UjJyClpdkMT9ve7uPf5azCbVCyfDwXl1YKkEQBEFomwgjp5jdNSUtgkiojx8p+ghkl0xmfQVmRxMyLj7K3kCEbwAJuhAvllYQBEEQRBg55fxatNdze0b8AM7rNRiFJAHgkJ18cWALGyrycLpklhZnckPfcW0+T53NigsXchsjaQRBEAShI4kwcgopbajnkKkGgFi/IM7vNRipOYgAqBRKrkgZwZ6aEsyOJrZXF9Fgb8Jf7UOT08H6mhKWVxSwuDyPHfUV9AsI4Zyg0HZfr8BUI2pWBEEQhL9MhJFTSJnF6LmdER7vCSJjV3yOJElcnzSYESHRDAyJYUNFHhV2K89k/s7WukrWVhfTJDtRSRIOlwsAi60Rg93a7ut9dWAr4b4B9A2K6twTEwRBEE5pIoycso7UiDQ6HewxVrG+pgRwD6E63Pgi1bhH1ria7x8OIhIQrtYA0EsXwojwXkRoA6hsNLGh8hAllnqcuPgwaz3/Gnk+aoWyC85JEARBOBWJob2nkCg/vef29upCXM3B4odxF+JyuXiy/ziWn3Ep/XwDPPu5OBJEjuYCQlUq+gdF8UD62ZwV148hYXGcFd+PR4ZNJy0wEgCj3cq26sI2y+NyuSiyGJFdbb2CIAiCILiJMHIKifUPIinA3cejuKGehYV7cLlcJPkHMTw4mqf3rye3poRxgUHMCY+ml9b/qPqT1hbX1/B03h7u3rmShaUH2GeoBkApKTi31yDPftur3GHELjvZXFvKyzmbufD3Hwj96TUSfnmbT/P3dNo5C4IgCD2f5HJ1/4+tRqORwMBADAYDer3+zw84je2qKeat/b957kf6BpAeGs/W+gqePbCTZK0fU4JCUUgSdw+ayksHtvFe3q5Wz6OWJEJUamSFEqvTiclhAyDeV8/ZUYmMDY3ll7xtWGQnNoUKp1LDpppSrLITRXPEkZvrXFZOvIzJEWJOE0EQhNPN8V6/RZ+RU8yQ0DguThrK94d2AFDRaGJJ8X4A/BVK8qwWJrlCuD5tLH0Cw3k3YzqjQmK4edsSZFw4XS4kIEGjZUpwGP8ccR6hPv7srK/g4/w9NDmdbKgt5aNDu9ts3oEjIQRAKUmMConp5LMWBEEQejIRRk5BZ8f1I8YvkCXF+8kxVHq2jwkIZLmhFpPKj5ERiZ7t1yUNZnBgOOf//gMVTQ3ILhfhGh8AVpRkc2lyBkODoxgafGTUzPtZ6/l3zlYONDUesyyD9OH4qdQde4KCIAjCKUU005ziqhpNVDSaUEgS0X6B9F/6ETVNjZgvuhuNomUWrW6ycMmGBayuKuLC0EjPaJoZ8QOYGtsXndoHs93KsuIsFjfXtlTZbawy1mNy2HC286ukV2kYEBjG9Mgk5iYNJsFP/AwFQRBOB8d7/RZh5DTzSf5urt2yiDtSMnh16NRWjztkmW115dRZ6vgx/0hfEoUkEazxo85maTE6ZnbSUFKDY5ix9ltyzXWtAsnokGiKGk2UNZo9w4m1ChWpAcGcGZHANb0GtqhxEQRBEE4dIowI7Qr76VXMDjvmC+9BpWh7QJXL5eKXwr38r3BPm31DJOC8XoOZET8ASZIw2pu4bOPPLC7Pa7F/9Xl3EOrjiyzLrKgs4Kui/aytLqGgwYC9eap5laSgl5+e8WFxXJbQj7MjElG0Uy5BEASh5xBhRGjXm7nbmLdzOQ/3Hc0/B0085r4VFiNrynLZU1eKxW7DT61hSEgsE6JTiPRt+bNwumT+sWs1L+duASBVF0zOjJvafe6ddRV8XriXFRUF5JjraHQ6AHfQidbqGBkSzUWxfbgkri9alejeJAiC0NOIMHKKWlS0jx3VRZQ3GtEolPTWh3NRYnqLCc/asq2qkJ8KdlNjNRPhG8BrRblYZRnTBXehUChwuVwsLNjD2vIDNDrtJOvDmJMyolXgOB4fHtrF37ct4ebeQ3lj2FnHfVyRxcin+XtZVJ7HPkM1BkeT57EQjZb0wAjOjUnm6l4DCfXxO+FyCYIgCF1LhJFT1Kt7VzEivBeJuhCcLhcL8ndRaqnnyYxz8VG2XXtw0FjFi7uWc0HSEAaHxLK5Mp/3D2znl7pK/jnwDB7uN4bFRftZXLSPuWljCNP683P+bkqan/dkpnrPM9cT5uOLXu1z0udqtFn5b+F+fi49wPb6CqqaLJ4mIJ1STT99KGdHJXFt4iCSdcEn/TqCIAhC5xBh5DRhslm5b9MP3Dt4Kn0CI9rc573MddhkB/MGTPJse3bHYl7I348Tibrz7+SBzQs4K64fZ8f1A6DRYeO+jT8wt89oRhw1DNibHLLMgpIcvi3OZlNtKcUWk2dOEx+FkmT/ICZFJHBlrwGMCY31cmkFQRAEMenZaaLRaQfAX6Vpd588UzVTY/t67ssuGZVCyShdEIvrq7j0ty8JUSro27zeDICvSkNSQBh5pmpPGMmur2B+3nbKLAaCffyYmTCQsZG9W7zWqtIclhVnYrA1EqcL5rLkDJICwjrkXFUKBbPj+zI73n0usiyzrqaYLwr2s7a6iAMNdew/WMNbB3eglCTiffWMDY3l0oS+zIxKbrezriAIguBdIoz0YLLLxbd520jWhxPrH9TufkabFb1a67m/uCiTQnMdffz8WWOs4zdDDReEhLOnrpSEgBDPfnqNFoPNCkC11cwb+1ZzRnQq1/cdS1Z9OZ/nbCJQo2VAsHuG1S1VBXyXt505KSNICghjRWkWr+1dxVMZs9BrtHQ0hULBGeEJnBGe4NmWaazhk/w9LK/IJ9tUy5dF+/myaD8SEKn1JyM4kgtj+nB5Qj/8jhHgBEEQhK4jwkgP9tWBLZQ2GLh/yPF3EgXIM1UR5x9EldXMLclDeTl3CxW2JorMde0es6YslzCtjkt6DwMg2i+QA4Yqlpdke8LI8pIsxkclMy4qGYArUkayt7aU9RUHmR4/4CTP8sT004fy/OBJnvvlVjOf5e/ll7KD7DFU80tZHr+U5XHDtsUEqX0YHBjOOdHJXJ04kCitrkvKKAiCILQkwkgP9dWBLeypLeW+IVMJ/pORJXqNFqPd6rnfOyCcpcX70Wu0PDZ4Im8f3M6OBiM3/aETqNFmJV4XBECesZq+QS0nJ+sfHM23edsBcMhOCk21zIjr73lcIUn0DYoiz1j9V071L4nS6vhH39H8o+9oACwOG18VZrKgNJetdeWsrS7mt+piHtizBj+lir4BoUyNTOTqXgMYEBjutXILgiCcTkQY6WFcLhdfH9zKzppi7hk8hbDj+DTfOyCMrPpyT7+R6fH9WV2WQ0WjiTvWf8vogEBWGWrZUlfBzISBADQ67BwyVTMxOgUAo93aqqlFr9FiddqxOR1YHDZkXAS0sU95o7EjTr1D+Kk0XN97CNf3HgK4O8X+Wn6QbwqzWF9Twi5DJdvrK/h39iY0CgVJfkGcER7PFb36MyE0TkzGJgiC0AlEGOlhvjq4lc2V+dza/wy0SjUGm3uhOl+lGk3z0N6Ps9cTpPHjwqR0AKbEpvHi7uUsK85kUEgMC/J3YbA1clFiOgNDYjhgrGLrhp/4tGAfF8SlEabV8VPBboJ8fEkPi/fWqXYJlULBeTGpnBeT6tm2qaaUzwr2srqqkIPmerIP1fL+oV0okIj11TE6NJZL4tK4IDb1pIY9C4IgCC2JMNLDrCnLBeClPStabL+mz2jPyJbaJgsSkuexZH04N6SN46eCXSzI34WMizOiUpgW725SifUPYlJoLAsrC3lp328EKBSkBIZzx4DJnoutXq3FaLO2eE2jzYq2OQQpJAkFEqY29glUd3zn1c40KjSGUaExnvsHzXV8kr+HpRX57DdWM784i/nFWQCE+/gyLCiK82JSuDKhf6d01BUEQTjViTDSw7w7Yc6f7nPv4NYL4GWEJ5DRPOrkng3fEeffsn/I3IT+rKguZp3ZSN7Mm1sd31sfxt7a0hbbMuvL6a13D9tVKZQkBISQWV/hqU2RXS6y6suZHNPn+E6um0rWBfP0wDN4euAZAFRbLXxRuI+FZQfYVV/JkopDLKk4xG07lqFXaRgYGM70qCTmJg4ivhNWKK61NjT3AXKhkBToVD6EaP07/HUEQRC6iggjp6HBIbH8WrSXEK0f0X6BFJnr+L38AONColhWXcrKigIMljrqbRauTRsLwMToVFaX5vD9oR2Mi+xNVn0F26oKmTfwyNo2U2P78kn2BhIDQkgMCGVFSTY22dFqLpKeLkzrx119RnBXnxEAWB0OvivJ5vvibDbXlrGhpoT1NSU8vm8dvkoVqbpgzozoxdzEgQwJivyTZ2+f1WlneXEWCwv3tNiuQOLB9Gn0OmpYtiAIQk8iZmA9DVkddn4q2M3OmiJM9iYCNb6MCO/F2KgUoha+QVpACA8kDaSmqaFFLcvRk54F+fhxTpuTnmWztDgTo83qnvSsdwZJ+o6Z9KynkGWZZZX5fF2UydqqYgosRhxHrVCc6O9eofjy+H5MPc4VisstRl7ft4pqa0Obj2uVam4bMLHdWXgFQRC8QUwHL5yUc9bO59fyPDaeeVWLfhPCX7O9rpzPC/aysrKQHFMdVtm9QrECiWitPyNDo7k4No3ZcWmt1hgy2qz8a8di6mwWz7YwrQ6VJFHeaPJs81GqeGDI2cecAE8QBKEriTAinJRSi4m4X95iUGA4u86+ztvFOWUVWox8mr+HxeV57DVUY3TYPI+FarSkB0VybnQyVycOYHVJDkuK9wMQ5x/E3D5jiG+eE6baauaL3M1k1pcDkB4axy39z+j6ExIEQWiDCCPCSZuy+itWVhWy66y5DP4LfRyE42fwrFCc27xCcaPnMbUkEaRSEa/x5YPR5zM0pGWNlc3p4NGtCzHYGpGQeHbk+X86EZ4gCEJXEGFEOGkFDQYSf32HEcFRbJ56jbeLc1qyyQ4WlBzg8/w9rKoswCI7OfyHOlAfRlpACKkBwTw7aBIAPxza6ak9+Xu/8QwLS2j7iQVBELqQWLVXOGm9/AMZGxrL+poSck21pIpRGl1Oo1Dxt/i+jAwK59mdS5BlmUh9OGqNP0WNJr4rzuKHkhxGhsRwYWyfFvOb2GSnF0suCIJw4sTc1kKbPhg+A4Drty7ycklOb4EaX8C9QrHSaefx/uP4YPgMqs+7k4vj+vC3DT/xfXE22fUVnmOCmo8RBEHoKUQYEdrUTx9KRnAka6uLKbR0n7VlTjfBPn6e4brljUbWlh8E3NPYfzXqfC6JS+OSDQt449AenC4XQRpfUsXwXkEQehgRRoR2vZcxHYAbtojaEW86MybNc/u/BzbzQdbv7K4pIddQyYzQSPwVSrIaG/ioopjNDWYWlh6g0Wn3YokFQRBOjOjAKhzToCUfss9YTfmseUSIKce9wuVy8W3eNlaW5rT5eEVTEz/VVQIgAS5Aq1BxXkwKl8SnMSOqN/4qTdcVWBAEodnxXr9FzYhwTO9kTMMF3LhN1I54iyRJ/K13BrOThuKv8mn1eJzWl4jmfiKHP1lYZQc/lGRzyYafCP3pNS5a/wPb68q7sNSCIAjHT4ymEY5pXFgcqbpg/leaR73NSpBYldYrJEnirLh+TIrpw47qIoob6pFdLiJ8AxgenkBo9ib+mbkB51EVnY7m202ykx9LcknVhTAsOMpbpyAIgtAuUTMi/Kk3h56FjIubty3xdlFOe2qFkpERiVyUlM7s3kM5IzoFP5WGv8X1bRFEjqZA4pyo3jw9cEIXl1YQBOH4iDAi/KmzopLo5afnu5JszEdNWy50HwMCw0lrZz6YaVFJfD/2QjQKZReXShAE4fiIMCIcl1fSp+B0ubh9xzJvF0VoxxUJ/VFKUqvtoRptq8X3BEEQuhPxDiUclwti+xCj1fHfgv28M2yauLh1oBxDJUuL91NorsNga+SWfhNID4s/5jHZ9RXMz9tOmcVAsI8fMxMG8rf4vjy+bx3gbppJDwzDYrPwReF+yk3VvDdqFkkBYV1xSoIgCCdE1IwIx+3fgydhd8ncu2ult4tySrE5HcT5B3N58vDj2r/aauaNfatJC4rk0WEzmBKbxuc5m3A4mhigDwUgIyiC4b6+vJ8xnUH6UJbXVTJ3/Y8YbdbOPBVBEISTIsKIcNyu6DWAcB9fPji0G4cse7s4p4yBITFckDiEoX9SG3LYmrJcwrQ6Luk9jGi/QCbHpDEsLJ7lJdk83n8cV/cayLmhkUyKTmF8dAo7z7qOwYHh/Gas5fL1P3Ty2QiCIJy4kwojb775JomJiWi1WkaNGsXmzZuPuf8rr7xCWloavr6+xMfHc/fdd2O1ik9oPdEzAybQJDt5eO8abxfltJVnrKZvUMshuv2Do8kzVvO3+H58OHw6ZQ319GveR6FQsGPqXAbrgvi1qoi/bfjJG8UWBEFo1wmHkW+++YZ77rmHJ554gu3btzNkyBCmTZtGZWVlm/t/+eWXPPjggzzxxBNkZmby4Ycf8s033/Dwww//5cILXe+m5KEEqX1448B2ZFE74hVGu7XFKr0Aeo0Wq9OOzenAbG9CxkXAUfsoFAoe7TOcwf565hdnMXv9j11dbEEQhHadcBh5+eWXufHGG7n22mvp378/77zzDn5+fnz00Udt7r9+/XrGjRvHnDlzSExM5Oyzz+byyy//09oUoft6tN9YGp0Onslc7+2iCCdAoVBwaVQSw4Oj+L4khwt/F002giB0DycURmw2G9u2bWPq1KlHnkChYOrUqWzYsKHNY8aOHcu2bds84SMvL49ff/2VmTNntvs6TU1NGI3GFl9C93F36nACVGpeyNksake8QK/WtuqIarRZ0SrVaJQqdGofFEiY2tgnyMeXTWdexciQaBaU5nLB7993ZdEFQRDadEJhpLq6GqfTSWRkZIvtkZGRlJe3ve7FnDlz+L//+z/Gjx+PWq0mOTmZSZMmHbOZ5tlnnyUwMNDzFR9/fB37hK6hUCi4t89IzA47/8nd6u3inHZ668PIqm/595ZZX05vvXvYrkqhJCEghMz6Cs/jsstFVvM+CoWCDZOvZExoDD+VHmDWuu+6tPyCIAh/1OmjaVavXs2//vUv3nrrLbZv384PP/zAL7/8wtNPP93uMQ899BAGg8HzVVRU1NnFFE7QY/3G4qtUiaaaDmB12iky11FkrgOguqmBInMdtdYGAH48tJOPs498nydGp1JtNfP9oR2UWwysLs1hW1UhU2PTPPtMje3LuvIDbKjIo8xi4MsDW7DJDsZG9gbcgXLdpCsYGxrL/8oOMnPt/C48Y0EQhJZOaOaqsLAwlEolFRUVLbZXVFQQFdX2AlyPPfYYV111FTfccAMAgwYNoqGhgZtuuolHHnkEhaJ1HvLx8cHHp/XqpEL3oVAomJc8jBdyNvPuwR38PXmot4vUYxWYanl5zwrP/fl52wEYE5HE3LQxGGyN1DZZPI+HaXXMGzCJ+XnbWVmSTZCPH1f1GcWA4BjPPiPCe2G2W/m5YDdGm5U4XTB3DJiMvnl1X3D/DNdOmsOkNV+xqDyP6b99y+Iz/tYFZywIgtDSCYURjUZDRkYGK1as4IILLgBAlmVWrFjBvHnz2jzGYrG0ChxKpXuNDFc7C3sJPcO/Bk3ktQPbeGzfWhFG/oK0oEjenTCn3cfnpo1p85hHh8045vNOjkljckzaMfdRKBT8NvkKJq36kiUVhzh7zTcsnXjp8RVcEAShg5xwM80999zD+++/z6effkpmZia33HILDQ0NXHvttQBcffXVPPTQQ579Z82axdtvv83XX3/NoUOHWLZsGY899hizZs3yhBKhZ1IpFFyfNJiqpkb+W7DP28UR/oLVk+cwKTyeZZX5TFn9tbeLIwjCaeaEFxi59NJLqaqq4vHHH6e8vJz09HQWL17s6dRaWFjYoibk0UcfRZIkHn30UUpKSggPD2fWrFn885//7LizELzmpcFn8n7eLv6xezVX9Brg7eIIf8GqSXOYsuYrVlYWMHn1l6ya1H5tjSAIQkeSXD2grcRoNBIYGIjBYECv13u7OMIfXLvlFz7J38uCsRdyfmwfbxdH+IvOXvMNyyrzOSMsjlUTL2+zX5cgCMLxON7rt3iXEf6y14eehVKSuHPnij/fWej2lk68lOlRSfxWXczE1V+JuWQEQeh0IowIf5lOpWF2bBoFFiPLyg95uzhCB1g04W/MjOrNuppiJqz+UgQSQRA6lQgjQod4J2MaCiRu27HM20UROsgvEy7h3Ohk1teUMG7Vf0UgEYQeqNbaQKG51vN1eP6i7uaEO7AKQluCNFrOjenNz6UH+b26mHFhcd4uktABFo6fzQW/f89PpQcYs/ILNpx5pehDIgg9gMvlYmdNEe9m/o6LI11DlZLEExnnEOnbvfpfincVocO8nzEDCbh52xJvF0XoQAvGXcyFsalsritj1MrPRQ2JIHRzVqedtzPX8k7muhZBBMDpcvHSruUUmGq9VLq2iTAidJgIrT9TIxLZa6xme13baxUJPdMPYy9idmwaW+vKGbHiMxFIBKGbcrpk3tm/ll01xZ5tSiQ0iiMNIQa7lf/sWUFpg8EbRWyTCCNCh/pghHtW0Ju2LfZySYSONn/sBVwS15ft9RVkrPhUBBJB6IY2V+aT2byQpq9SzVWpo3hl7CW8NvYS/jHkLJICQgFodNr57tB2bxa1BRFGhA6V4KdnQlgc2+oqyDTWeLs4Qgf7dsz5XBbfj531lQxd/okIJILQzawpy/XcvrHfOMZHJaNRqpAkiWR9OHcNOpNgjR8A++rKqGo0eauoLYgwInS4D4e7a0du2LrIyyUROsNXo8/jioT+7DZUMWTZxyKQCEI30eiwccjk/hAY7RdI/6BoADZtsvL66+4mGa1SzYToFM8x++u7R5O6CCNCh0sNCGFEcBTra0o4ZK73dnGETvDFqFlc1WsAe43VDF72MQ4RSATB6xqdds/tKF89NTUyDz1Uy4QJpdx9dw0Oh7sza7TfkZE0Voe91fN4gxjaK3SKD4ZPZ8iyT7hh6yJWTLrc28UROsFnI89FKUl8kr+XwUs/YvfZ16ESw34FoVPl5NhYs8aKJHHUl4QkgcPlJPdAGOZqNcv3BnDfrkIAUlPVBAQoUKkkAE/tCYBO7eOV8/gjEUaETjE4KJLBgeGsqiqk1GIixi/A20USOsHHI85BQuLj/D0MXPIhe6ddLwKJIHSiF1808P77x+rncbgJxsVVd8i8/FgiZ51VRmio+++yvsnCuvKDACglBYNCYjq3wMdJvGsInea9jOm4gBvFyJpT2kcjZnJD0mCyzbUMWPKBaLIRhE50443H98Fuwv0H8Z+9mdXGXezbZ6O8wsG68oM8t2spFocNgIywePQa384s7nETYUToNKNCY0gLCGFReR61Nou3iyN0oveHz+DvvYeQY66j35L3sckObxdJEE5JI0ZoOftsX1TttGtIEpxzo4V+s6qRcbGkKAu73UWNtoLPczdR1+R+Lw718Wd272FdWPJjE2FE6FRvDzsbF3DTVjEr66nunYzp3NI7nQPmevov/lAEEkHoJLNn++No489LqYQxY3z44c1+TIvrj1JS0FCpASQCops8+6Xow7l/yFkEdpNaERB9RoRONjmiF0l+gSwozcVkbyKgm3SWEjrHWxnTUEoK3ji4nb6LPyBr+g0tZn4UBOHkrVvXyE03VZOZ6R4BI0ngap7tXaEAvV7Bt99GolEruSgpnamxabz0eT4A/dJ8mBSdypjI3iQ2T3zWnYiaEaHTvTp0Kk6Xi9u2t17Rt6esKCkcv9eHncUdKRkcajDQZ9H7WNv6CCcIwnFbs6aRvn2LmDChjKwsOzNm+LJgQaQniIA7lHzzTQSxsUfCv17ji29VFADzzh7A5SkjumUQAVEzInSBWTEpxPkG8FVRJu9lTEfb3NhZa23gsa0LcbiOdHhUSQqeHj6LEK2/t4ordIBXh05FKUn8J3craUveJ3vajZ6fuyAIx2fFCgu33FJNbq4DSYJzz/Xlww/DiYhw/y1NmqTlt9+suFzw2GNBnHWWX6vnOHDA/WEgPb1710qLmhGhS7w4ZDIOl8xdu1YAYJOdfHhoN0vrqnAeFe8dLhmzo6m9pxF6kJfTp3BfnxEUWoz0WfyeqCERhOO0ZEkDycmFTJ1azsGDDi64wI/KygQWLoz2BBGAp54KRpZh4kQtjz8e3OZzFRTYkSR3E053Jj6qCF3i0vh+3LljOR8d2sUAfSjPZW2i1GoGYERAIAFK8at4KnphyJkokPh3zmZSF79H9vQb8FNpvF0sQeiWfv21gdtuqyE/34FCARdf7Md774UREnLk/THHUMnS4v0UmuswSI288sU4rp4ZiVIptfmcZWVO/PQyz2xfRJnFQLCPHzMTBjI2sneL/VaV5rCsOBODrZE4XTCXJWeQFBDWqed7tO4dlYRTRoPDxsTweOwuF3fsXOEJIgBt/wkJp4rnh0zmwb6jKG400WfR+545DgRBcPv55wZ69SrgnHMqKCpycMkl/tTUJPDdd1EtggiAzekgzj+Yy5OHAzBxmoLgYGW7z11jsBOSZiQtKJJHh81gSmwan+dsYl9dqWefLVUFfJe3nXMSBvLI0BnE+Qfx2t5VGG3WzjnhNoiPo0KnMtqbeOPAdv6dvQmjve3mF4WII6e8ZwdNQoHEv7I2krLofXJm3IhO1JAIp7nvv2/grruqKS52olTC5Zf788474cdsUhkYEsPAE5g1tdFpIyhI5pLe7vAS7RfIAUMVy0uyGRDsfp7lJVmMj0pmXFQyAFekjGRvbSnrKw4yPX7AXzjD4ydqRoROdefOFTyy9zcM9iZc7ewjiSxyWvjnoIk81m8sZVYzqYvewyxqSITT1LffmomNLWD27ArKy51cdZWO+vpEvvwyssP7djQ1SATp1C229Q+OJs9YDYBDdlJoqqVfUJTncYUk0TcoyrNPVxBhROhUD6SNIlUXjPIYiUNkkdPH/w2cwJP9x1FubSDl13e7tBpYELztv/81ER1dwKWXVlJZ6WTuXB0GQyKffRaBTtfxl2OLRcZqUhER2bIZR6/RYnXasTkdmO1NyLgI0Ghb7WOwd93fpwgjQqfqqw9l+1lzuTg2rd19RDPN6eWJAeN5esAEKpospC5+XwQS4ZT36acmoqLyufLKKmpqnNxwQwAGQyIffxyBn1/nXYb37LGBSyIqrtNeosOIMCJ0Op1Kw9ejz+O19KmoJKlV+BBR5PTzaP+xPDNwApVNFlIWv0e9CCTCKejDD41EROQzd24VdXUyN98cgNGYyPvvh3dqCDlszx53U2hoQsv+ekabFa1SjUapQqf2QYGE6Q9/g0ablUB1y9qSziTCiNAlJEni9tQM1k6+ggitX4sA8scWnBJzfVcWTfCSR/qN5V8Dz6CqqZHURSKQCKeOd981EhaWzw03VGMwyMybp8dkSuTtt8PRarvuspud7Q4jtsiqFtsz68vprXcP21UplCQEhJBZX+F5XHa5yDpqn64gwkgHElOb/7nRobEsH38JCT5HFmj6Y03JJ7kbWVGS1dVFE7zgoX5jeH7QRKptjaQseles7iz0aG+8YSA0NJ+bb67GbJa56y53CHn99TA0mo653FqddorMdRSZ6wCobmqgyFznud78eGgnH2evByAvzwG4sPoa+P7QDsotBlaX5rCtqpCpRzWdT43ty7ryA2yoyKPMYuDLA1uwyY5Wc5F0JjG0t4OIqc2PT6PDxn9zN3JWUCgLayqocNhRqbT0CQiiwFRLo9O9ANS3edsJ1PgyPLyXl0ssdLZ/9B2NUlJw3+5VpC56n5zpNxLq03paa0Horl55pZ6nnqqnvl5Gq5W47z49zz4bgkrV8Z/3C0y1vLxnhef+/LztAIyJSGJu2hgMtkZqm9yhvrjYgUolcfvASczP287KkmyCfPy4qs8oz7BegBHhvTDbrfxcsBujzUqcLpg7BkxG34Wr+koul6u9EZfdhtFoJDAwEIPBgF6v93Zx2lRoruWfOxa32v7I0Okk6EK8UKLuaWlxJt8f2gFAtG8gX1QWMzAwnAXjLsIuO/lfwR4WF+8HIMI3gKcyzkUhxv6eFl7J2cLdu1YSrNaSM/1GwrQikAjdlyzL/Oc/Rp5+ug6DwYWvr8Qdd+h55pngTgkhJyMpqZDaWicGQ5LXynC81+/u8R0TTgsul4u1Zbme+3/vP57H+o/lp9JcdtdXolYouSBxCKn6CAAqG01kH9WOKZza7uozglfSp1Bnt5K6+D0qRTOn0A3Jssxzz9URHFzAfffVYrfDI48EYjb34rnnQrtNEAGor5cJCuo+5TmWnlFK4ZRgtDeSZaol32qhxOHko4J9GG1NBKl9uGLTQsDd0XVs1JF2ykJzrbeKK3jBnanDeT19KvX2Jvosfl8EEqHbkGWZZ56pIzCwgIceqsPphCeeCMJk6sUzz4SiUHS/y2lDg0x4ePtTxXcnos9IB5BdrnZnqvuzVrBCi5GCBgMTwuM7o2idyuywkWWs4WBDHYcaDBRZTJRZzVRaLdTarBjsTZgdNqyyA7sst5qB9ZfqUpRI+KvUFFqM2GQnGoUSrfLIbIHOo/rgCKeHeakZKCSJ23Yso8+i98macQNRWp23iyWcpmRZ5v/+r54XXzTQ0OBCp5N4+ulgHn44sFsGkMNkWcZuh7i4nnGZ7xml7Mbqmyy8nbmWfFNNm49/cWAztw+Y1KojkE128lL2Zp7a/zsuXFgvug/Jy30jKq0N5JhqOdhQT36DgeJGd7ioamqkzmbFaG+iwWHHKjtbdNT9I6UkoVEo8VOqCdX4EqzREubjS4SPH5m1JWgliRC1hhdHnEdqQAgu3HONHD7/PbUlnucKFZ1/T0u3pgxDKUncvH0paYveJ3PaDcT4BXi7WMJpRJZlHnusjldeMWKxuAgIkHj22WD+8Y/uHUIOKypyApCY2DMu8z2jlF2g1tqA2XFkYhidyudPR8E02G28vGclFY1Gz7bDceJwLUChuY7/7FnJP4acja/K/Yl/RUU+f9+2hLyGes9+9fYmgjUdN8GMLMsUNprIMdVyqKGeAouRkkYT5dYGqg+HC4cNi9OOTXbiPEYNjkpS4KNQ4q9SE+2rI1ijJdzHl2itjljfABL99ST7B5MaEEyExu+Yf6hfHdjC6uZ+I+vLc0kJGNWig2pOfQUbKw8B4KtUkx7a82qMhI7x9+ShSJLE37ctoe+SD8icdj2xft2zA7tw6nA4ZB55pI7XXzfS2OgiMFDixRdDuPtufY8IIYft3OmeY6RPH/Wf7Nk9iDDCyQ/LXVy8zxNEQnz8mJ00jPTQOFy42FFTzHd526m3NVJqMbCkeD8jI3tz184VzC/ORoHUotmiqslyzDBikx3kmuo4YK7jUIORIouRUquZCmsD1bZG6m1WzA47jU47NlmmdaOImwSoFQq0ChX+Kg3hPr6EanyJ0PoRrdUR7xdAol8gybog+uhCCOzAgARwZkwaa8sP4nTJbKjIo8BUw9jI3ujUPuyrK2NrVSGu5rJPjE7FRyl+RU9nN/VOR4nEDdsW02/Jh+yfdj1xIpAIncDhkHnggVreesuE1eoiKEjBs88Gc+edQd4u2knZv98dRgYN6hmrY4t3esDsaGrV7OBwyZgdTYTQOoxkGWtI8tPze/lBwB1c7hk0hXDfI9XII8J7Ee8fxFPbf8Uhy7yau5XN25fTJLurzv4YFh7avQaX5G4qOZ7+FocpkFArFPgqVQSoNMT5BhDqoyXSx58YXx0JfnqS/ANJ0QWT7B+MVuXdH3mkn55r+4zmo+wNyLgotRj4rnmo79EGBkczq9cgL5RQ6G6u7z0EhSRx3dZF9Fv8Afum30CCCCRCB7HZZO6/v5Z33zXS1AQhIQpeeCGEefMCvV20vyQ31wFAerqPl0tyfEQYOUHfFGVy2cafeSRtJA3NS6APDYv3BJEVFflkmWrQqTRUNVnYYbGwxVDNn3XD/KE0Bzi6v4WKkOb+FuE+vkT6+BHrG0CCn57ezbUWvfx6VrXhYSMiEtGptfxUsItDf+hro1P5MDEmlXPiB6LsgecmdI5rkwajlCTmbvmV/os/YN+06+nl37MvFoJ32Wwyd99dywcfGLHZIDRUwauvhvD3v58aQbew0I4kQUBAz3gfFWHkBGQZa7h2y68AvJ23iwtCwlFJEtF+evLM9TyXtZEPDu3y1GIEqDQocP1pEAF4YfAk7kkd0SPDxcnoFxxFv+Aoisx15JmqccoyIT5+DAiJQa3oGUPRhK51deIglJKCqzb/j/5LPmTf2deRqAvydrGEHsZqlbnrrho++siE3Q7h4QqefTaE668/NULIYWVlTnx8es6EkSKMHKcGh40L1v+ArbmZpdbeRE5jAzqFkrnbV1BtbyJM48uDfUdzda8BJPoHoVWqeG3vKnbXllLQ1IhZoWFjbRlKSWrRYVQlSdhk+bQJIkeL1wUTrwv2djGEHuKKXgNQIHHF5oUMWPohe8++niQRSITjYLXKzJtXw2efuUNIZKSS558P4ZprTs1RWjU1MgEBIoz0KFaH/ZiPu1wubty6mFxTXYu+Hr8b6zzDUmdGJjF/7IX4qY70XM431bC/zh0+hgeG8c8R55HXYOD9vF28n7eLOrsVJRKyy92BVRCEP3d5r/4oFHD5Rncg2XP2dSSLQCu0w2KRue22ar74wozDAdHRSl58MYQ5c07NEHKY0SjTq1fPucSffh/FjyK7ZBbk7+K1vavbfHxx0T7sspN383byVVFmq06nLiBcpeGaiFjS1Ao2VuRhtDVisDWyvCSLV/eu9BwxMToVhaQgRRfM84MnUTbrNr4efR7jwuKQcWGXxeRegnC8Lo3vz9ejz8fqdDBo6UfkmsRMvUJLZrPMVVdVEhiYzyefmImMVPL11+GUlvY65YMIQFOTi6iontPkfdoulOdyufgkZwMbK/OPuZ9OG8BrBVltTvIlAYEqDbNDI465mFuyPoy7Bp6Jpp1hqvkNBoLUPgR18DBab7E67PxUsJudNUWY7E3E+wdzaXIGiQGh7R6TXV/B/LztlFkMBPv4MTNhYKvlq1eV5rCsOBODrZE4XTCXJWeQFBDW2acjdGPfF2dzyYYF+ChU7DxrLmn69n/HhNOD0Sjz979XMX9+A04nxMcr+c9/wrj44tNnAkWLRcbfP5+rr9bx6acRXi2LWCjvT2yqzPcEEQUSI8N7cWXKSK5OHcWo8ESUSFgcDl4vyGx3tlEXUO+wYVe1HyKGhsZzx4DJ7QYRgET/wFMmiAB8lruJzPpyrk0by+PDZtI/OIr/7FlJXTtNUdVWM2/sW01aUCSPDpvBlNg0Ps/ZxL66Us8+W6oK+C5vO+ckDOSRoTOI8w/itb2rMNqsXXVaQjd0cVwa34+5kCbZQfqyj8k0tj0TsnDqq6938Le/lRMSks/XXzcQF6dkwYJICgt7nVZBBGDXLvdIz5SUnjHhGZymfUZcLhcrSrM896/vO5bh4b0898dG9kZWa7l5+zKczdsUSCjbqP2wu2R2mo38Mu5C1pUfpNxiACDaP5DxkSnEnGbDD21OBzuqi7h1wBn0CXQn8lm9BrO7toQ1ZblckDik1TFrynIJ0+q4pPcwAKL9AjlgqGJ5STYDgmMAWF6SxfioZMZFJQNwRcpI9taWsr7iINPjB3TR2Qnd0YVxffhx7IVcuP5Hhi77mG1Tr2FAYLi3iyV0kdpaBzfeWM2CBRZkGZKSVLzxRigzZ55eAeRoe/a4w0j//iKMdGtVVjOF5joAEnTBniBS4qhgZUUhr2XuZ2tdOaFqDRokotQaRkcmEejjh9MlI7tcOD1fMoMCw4n1D+LS5Axvnla3ILtcyLhQSS3bKtUKFQeNVW0ek2espm9QVItt/YOj+TZvOwAO2UmhqZYZcf09jyskib5BUe0uUCicXs6P7cPP4y7m/N9/IGP5p2ydeg0DRSA5pVVXO7jhhmoWLnSHkORkFW++Gcq0aadvCDksO9sdRoYM6Rmzr8JpGkaMtkbP7VT9kfa0RNsAHJFGNFXnkOycilpWITts+CoVjA2JYk7ikNNy+O2J0KrU9A4I49eivUT76dFrtGyuKiDPWE2Eb9srrxrtVvR/aKbSa7RYnXZsTgcWhw0ZFwFt7FN+1LpAwunt3JgUFo67mFm/f+8OJFOuZlCQd9vLhY5XWeng+uur+PXXRmQZUlNVvP12GFOm+Hm7aN3GoUPu2Vd79+45l/ieU9IOdHT/jaP7MYyxnck63x+wDfmJvF1OXGWpEFJJjkvJ+orfuKrGjkrtwFfjQq+FQF+JIF8lwzX9eEn7FCoRVAC4Lm0Mn+Zs4oHNC1AgkaALZkR4LwrNYsSD0LlmxiTzv/EXc+667xm+4jM2T7mKIUGR3i6W0AHKyx1cd10Vixc34nJBWpqad98NY+JE3z8/+DRTXOxApaJHfXg+LcNItF8g/iofGhxN7K4todbaQIjWn2eD7mQ88/mJn1g+eCUf9vsIi099i2MdLgmTS8IElLgkUDhZ3xDCa9/r8FEoCdNoCVMqCVSqiNb6c2GvAVycMMgTVFwuFwsL9rC2/ACNTjvJ+jDmpIwg0vfUmf0v3DeA+4ZMpcnpwOq0E6jx5b3MdYRp264Z0au1rTqiGm1WtEo1GqUKhSShQMLUxj6B6lOn46/QMWZEJ7NowiXMWDufEcs/Y9OUqxkaLAJJT1Vc7OD66ytZtsyKy+XuB/Huu2GMHy9CSHsqK2X8/HrOhGdwmo6mUSuUjItyDxt1uGRe37eaPGM1GS53n4+37e8Tu3smZ++7B6WsosX0IpILFLL7S+kEJKYZr+T8mBRS/ANBdpLdaOY3Yy3fVBZx2ZbFqL9/Ae33LxK98A0yln7IS9mbUPgEMK1XOipJyWt7V2GXna0L2sP5KFUEanxpsNvYX1fGkNC4NvfrrQ8jq768xbbM+nJ6693DdlUKJQkBIWTWV3gel10uso7aRxCOdnZUEkvP+BsyLkat+IxttWXeLpJwggoLHUyZUkpCQiFLl1oZMEDNxo0x7NsXL4LIn6ivdxIU1LMu76ftPCMmm5V/7VxM7VHNNGFaf14aOgelU8OVm98EoCxwP78MehZZant4bwABlFKKDh3vZa7DJjuYN2ASZoeN36uL+SBrA3VOB5VOJ6WNJmxOOyZny+ARpFThp9IQ7RdAH10I6UERjA2NZWRoNBpFz6u82ldXissFUX56KhtNfH9oB2qFkvsHn4VSoeDHQzupt1m4Nm0s4B7a+9S2X5gU04dxkb3Jqq/gm4PbmDdwomc0zZaqAj7J3sCVqSNJDAhlRUk226oLeCrjXPQa8cYktG1lRQFnr/0GBRK/n3klI0KivV0k4U/k59uYO7eaNWvcNaGDB2v44IMwRowQtaDHS6PJY8gQDVu2tP0BsCsd7/W7513pOkiARsvdg6bw+r7VVDaaAKi2NhDcEE+5PhsZGV+FhgTTICYXXMeKxA/afJ4QQiijjFRSyTNVMzW2LwA6lYZpUb1pajKzq6aYx4bNpKrRzKNbf+aeQVMotFrYUFPCLkMVOfXl1Nht7K6vYltdBV8VZXqeX6NQEKTWEucbQKoumCFBEYwLi2V0aEy3DSqNDjs/5u+ivsmCn0rDsLB4Lkgc4lmF12Br/EMI1DFvwCTm521nZUk2QT5+XNVnlCeIAIwI74XZbuXngt0YbVbidMHcMWCyCCLCMZ0Z2YvlZ1zG1N++ZuzKL1g3+QpGhcb8+YFClzt40MbcuVWsW9cEwNCh7hAybJgIISdClmXsdoiN7Z7Xh/b0rNJ2sAjfAB4bOoMtVQWsLT9AaYOBpNoMygOz6dXfxAz5HPd+fmdxd5OFHzRf4ZJaViQVUEAf+jCAAQxSXIdend7icb1ai6G5r4PR7h7FE+WnJy0okrOikgB4L3MdADf1G4/FYWNjTRnra0rYZajkgLmOkkYTewxVbK+v4JviI/OjHA4qMb46UnUhDAkKZ0xILGNDY9GqvPejHR7eq8W8LX80N21Mq22HJzw7lskxaUyOSfvL5RNOL5MiElg58TLOXPM141f9l98mz2FMaKy3iyU0y8mxce21Vaxf7w4hGRkaPvoonMGDfbxcsp6poMA9kiYpqWdd3ntWaTuBRqli3FGTaVUwkSi+ZH/oWh7lFs9+X/IxE1wH2eLagkuSUaHiMi7jYR7mNm5jNavZl3Efa21v8BD3cgu3oDiJLjl+Kg1nRvbizMjWF3Orw8HG2lI21JSwo76SA+ZaShrN7DdWs7O+kvlHBRW1pCBI7UOMbwApuiAGB4YzLiyOMaEx+Kl6zthzQegIZ4QnsHri5Uxe8xVnrPovqyfNYVyY96uwT2eZmTauvbaSTZvcc2KMHKnho48iGDBAvD/9FTt3uhd+TUvrWd/H0z6M/FEkkfjjz3rWt9iuQcNC6WdS7P0wqepwSA7u4z760Y+VrKSeei7Kv49Ncd8xj3k8wAPcyI2Mt19BYPP8GHq1u0nBaLMSeFTzgtFmJf44lkHXqlRMikhgUkRCq8dssoPNNWWsqylmV30VueZaii0mMk017DJU8n1JjmdftaQgUO1DtK+OFF0QQwIjGB0aw/iwOPxFUBFOUePD41k9aQ6TVn/JpNVfsmri5YwPj/d2sU47e/c2ce21VWzd6g4hY8b48NFH4fTtK957OsL+/e7v68CBPWf2VRBhpE396Md2tiMjt6jd0DuDmbX/QeYPfpRxjGUIR6Y2DyKIy6xzuSBnDnUD1vIqr/IKr/Be9CeM9pvG9aQTrY1Gr9aSVV9OfPOS540OO4dM1UyMTvlLZdYoVIwPj2/zzdUmO9hSW8766hJ21FeQ01yjkmOqZY+hih9Lcj37qiQFgWoNMdoAknVBDAoMZ0xoDBPC49GJoCL0cOPC4lg3+UrGr/ovk9Z8xcqJl3FGeOtwL3S8XbuauO66KrZvd18sx43z4eOPw0lNFe8rHenAAXfNSHp6z2rmOqnRNG+++SYvvPAC5eXlDBkyhNdff52RI0e2u399fT2PPPIIP/zwA7W1tfTq1YtXXnmFmTNnHtfrnexomromCz8c2sm+ulJsspNwrY5r+oz+09VjH6p5kR+TX+Tqba9xfsgEzohOwWBrZGHBHorMdfRJVLO/rI6mBjV6jZZb+p9BUkAYB41VvLh7ORclpjMoJIY36v/LN6ovORD+O0gwghHMLX2E3AIbc/uMIUyr46eC3ZQ01PFkxrmoFV2/3LNDltlWV8666mJ3UDHVUtxootZmpekPw41VkoRe7UO0Vkdyc9PPqJAYzgiLazWDqiB0Z1tqShm76r+4cLH8jMvarG0UOsa2bVauv77as3jbGWf48Mkn4SQliRDSGaZMKWXVKiuy3PvPd+4Cx3v9PuEw8s0333D11VfzzjvvMGrUKF555RXmz59PdnY2ERGtp1622WyMGzeOiIgIHn74YWJjYykoKCAoKIghQ1ovmvZXTuZoDXYb/9yxiD5BkUyMTiFAraWy0US4Vke4b0CbxxweYto/NpBbE2dwdsFNJBZORCFJ6NVaUvTh9NaH8cOhncxJGcGaslwaHXbMDitPZcxCr9GyraqQnwp2UWNtIMI3gIuS0rGGlDKPeWxmM7igd8MgRuXNIdiYSEpgOHOSRxDp1/0mPXPIMjvqyvm9poTt9RVkm9xNP7W2Rqx/CCpKSUKv8iFa60/v5hqV0aExnBEWf0qtSCycOrbWljF25RfIuFg64dI2+2kJJ2/zZis33FDFnj12JAkmTdLy8cfh9OrVs5oPepr+/YvIz3dgsSR5uyhAJ4aRUaNGMWLECN544w3APYwoPj6e22+/nQcffLDV/u+88w4vvPACWVlZqNUn90t4MmHkh0M7OWis4v4hZx3363x/aAd7a0t5IuMcfPElgQTuy/wQi9POnQMnA/DsziUk6kK4PGUE4J5866HNC5gc0+dPV48txR1KFrIQBw6CCOJO7uRRHkXVw1rMZFlmp6GStdXF7KhzB5Uii5EamxWr7Gix7+GgEqn1I9nfHVRGhsQwMSKOEI1YT0Lwnu115Yxe8TlOl4slZ/yNqZGJ3i5Sj7dhgzuE7N/vDiFTpmj5+OMI4uJ61ntcTxUZmQ9ARUWiV8txWKfMM2Kz2di2bRsPPfSQZ5tCoWDq1Kls2LChzWN+/vlnxowZw2233cZPP/1EeHg4c+bM4YEHHkCpbLtZoqmpiaamphYnc6J21xTTPziadzPXkmuoJEjjx8ToVCYco2/G0avHppJKFlkdunpsDDH8wA9YsfIwD/Me7/EUT/Esz3Ipl/IarxFE0AmfqzcoFAqGBUcxLDiq1WOyLLPbUMW66mK211eQZaqhyGKiwGIky1TLL+V5nn2VkkSASkOkj7tGZaA+jFGhMUwMiydMK4KK0LmGBUexecrVjFr5GdN++5ZFE2ZzdlT3qN7uadata+TGG6vJynKHkGnTfPnoo3BiYkQI6Uomk4tevXre9/yESlxdXY3T6SQysuU6D5GRkWRlZbV5TF5eHitXruSKK67g119/5cCBA9x6663Y7XaeeOKJNo959tlneeqpp06kaK1UWc2sKctlalxfZsQPIN9Uyzd521ApFIyJbPvN5ujVY8/kTPawhwqfog5fPVaLlpd5mRd5kXd5l6d5ms/5nC/4golM5C3eoh/9Tv7kvUyhUJAeHEl6G+uByLLMflMNv1UVuYOKsYZCi5HCRiPZ5loWHRVUFEgEqDVE+vjR2z+IgYFhjAiJYWJ4HJHtrHMjCCcqPTiSLVOuZsSKz5ix9jv+N/5iZkQne7tYPcaqVY3cfHM1OTnuEDJzpi8ffhhOVFTPuyCeCpqaXERHd33/w7+q039bZFkmIiKC9957D6VSSUZGBiUlJbzwwgvthpGHHnqIe+65x3PfaDQSH39iQ/BcQC9dCBcmpgOQoAuh1FLPmrLcdsPI0a7hGl7lVX5VLUBJ+51z/woFCm5p/reCFdzN3axmNf3pT1/68jIvM4NjTwTW0ygUCgYGhjMwMLzVY7Isk2mqYV11Mdvqysk01lDYaKK40USOuY7FFYeOPA8SOpWaSK0/Sf6BDNCHMTIkmjPC4onxa7tPkCC0Z3BQJNumzmX48k85d933LBx3MTNjRCA5luXLLdx8czUHDzpQKOC883x5//1wIiJECPGWhgYZWYaEhJ73MzihEoeFhaFUKqmoqGixvaKigqio1tX1ANHR0ajV6hZNMv369aO8vBybzYZG07pHtY+PDz4+f21YUqBGS7RfYMuy+Aayo7qo3WOOXj12KENRo2aTYgNnKsd1+uqxU5jCbnZzkIOecDKTmUQQwUM8xB3ccVKTqPUkCoWCAYHhDGgnqOSa6/itusgTVAosRkobzRww17G0Iv/I8zQHlQitH4l+QQwMDGV4cDQTw+OJ64YdhYXuYWBgONumXkPG8k+Z9fv3LBh3IbNiUr1drG5n8eIGbr21hkOH3CHkwgv9eP/9MEJDe94F8FRzeMRSSkrP6yR8Qr89Go2GjIwMVqxYwQUXXAC4LxIrVqxg3rx5bR4zbtw4vvzyS2RZRtG8NklOTg7R0dFtBpGOkqwPp+IPTScVjUZCfPzbPaa3Poy9taWe+4kkUqTMb3P12PQwd03N4dVjJ8f06Zhyk8xSlmLEyN3czX/5L3dzNw/zMNdyLS/wAn6cfn0pFAoFafpQ0vSh3NjG47mmWn6rKmLrUUGlrLGBg+Z6llfme/aTcK8bFOHjR6J/IP31oYwIiWZieAIJIqic9gYEhrPjrGsZtuxjzv/9BxaMu4jzRCAB4H//a2DevBoKCtwhZPZsP957L4zgYBFCuou9e91hpF+/njds+qSG9l5zzTW8++67jBw5kldeeYVvv/2WrKwsIiMjufrqq4mNjeXZZ58FoKioiAEDBnDNNddw++23k5uby3XXXccdd9zBI488clyveTKjafJNNTy/aymzEgYzPDyBfFMNn+du4srUkYyKcA95+rPVY29vup/vgj5giWEjZwe5m2q6evVYGZlneZb/8B9qqEGJkulM5y3eIgExN8LxOGiuY211EVtq3UElv8FAVZOFBqedo3/5JcBfpSbCx49efkcFlbB4Eo9jhlzh1JFlrGHoso9pkp18P+ZCLozrmA8bPdGCBQ3ccUc1RUVOlEqYPdufd98NIzCw5/VLONXde281L79s5MCBOJKTu0cg6bShvQBvvPGGZ9Kz9PR0XnvtNUaNGgXApEmTSExM5JNPPvHsv2HDBu6++2527txJbGws119//TFH05zsyfzR7poSfszfSWWjiTCtjqmxfVuMpvkkewM1TQ3cO3iqZ1t2fQXz87ZTZjHg0Nfy3uDbeIzH+D/+z7PPqtJslhZnelaPvax3BknNtSed6Xu+50Ee5AAHABjGMF7jNcYxrtNf+1SV32Dgt6pCttSVs99YTX6DkaqmBsyO1kHFT6km3MePRH89/QJCGR4SxcTwBJKbZ9MVTi05phrSl32C1elg/pgLuDju9Fqk8fvvzdx5Zw0lJe4Qctll/rz1Vjh6/andXNyTXXhhOQsWWHA6Ez0tEd7WqWGkq51sGPmrZGTUqMkgwz1hWTexgx3MYx4b2IALF/HE8zRPcw3XeLtop5RCi5G1VUVsri1jv7GaQw0GKpssNDhsyEftdziohPn40ssvkH76UIYHR3JGWAIpuqBu86YgnLhcUy1Dln2M1eng69Hn87f4vt4uUqf7+msT995bS2mpE5UK5szR8eabYeh04ve4uxs5spgdO2zY7d1neLoIIx0kkUSqqcaMuUtf93hUUsk85vEjP+LAgR49t3Eb/8f/9bhJ1HqaEouJ36qK2FxXyn5jDYcaDFRY3TUq8lF1KhLgq1QR5uNHLz89fZtrVCaExZOmCxZBpQc4aK5j8NKPaHQ6+Gr0LC6N7//nB/VAX3xh4v77aykvd4eQq64K4I03QvHzE7+jPUViYiH19U7q67vH7KsgwkiHuZzL+ZqvqaCCCFpPd98d2LDxKI/yDu9gwoQaNbOZzWu8Rhid33wktFRuNbOmuUZln6GaQw31VFgtmJrnqTman1JFqMaXBD89ffWhZARFMiE8nv4BoSKodCOHzPUMXPohjU4Hn488lyt6HXu25Z7kk0+MPPBALZWVMmo1zJ0bwGuvhaLVit+/niYo6BBBQQry87vP0gYijHSQn/mZ8zmff/Nv7uf+Ln3tk/EBH/AkT1JCCRIS4xnPW7zFQAZ6u2gCUGlt4LeqIjbVlrHXWMUhs4HypgZM9tZBxfeooJIWEEJGcBQTwmIZqA8XQcULChoMDFjiXh7is5HncmUPDyTvv2/k4Ydrqa6W0Wjg+usD+M9/QvHxEb9bPZVGk8eQIRq2bInzdlE8RBjpIE6cqFEzgQmsYU2XvvZf8Ru/cQd3sItdAPShDy/wAudxnpdLJrSn2mrht+piNtWWstdQRV5DPeXWBkwOG84//JlqFSpCfbTE++rpqw9hWFAU48PiGBIogkpnKrQY6b/4AyxOOx+PmMk1iYO8XaQT9tZbBh5/vI6aGhkfH7jpJj0vvhiCRiN+b3oyWZZRKvO54AI/fvyx7Xm/vEGEkQ4UQwyNNFJHXZe/9l91iEPcyq0sZSkyMuGEcz/3cy/3nvKTqJ1Kam0W1lYVs7G2lD2GKvLMBsqtDRgdTW0EFSUhGl/i/QJICwhhaFAk48PiSA+KRCWCyl9WaDEyYPEHmJ12Pho+g2uTBnu7SMfl9dfreeKJeurq3CHk1lv1/PvfIahU4nfiVJCXZyM5uZi779bz8svdp3lehJEOdD7n8zM/Y8CAnp45MZYZM/dxH5/yKVasaNFyDdfwIi+iQ6zz0pPV26ysrS5mY00Je41VHDDXU97oDiqOP/x5+xwOKr4BpAUEk94cVIYFR4mgcgKKLUb6L/kQk8PGBxnTub73EG8XqU0ul4tXXjHw1FN1GAwutFqJ22/X869/BYsQcor54YcGLr64gnfeCePvf+8+1ykRRjrQ53zO1VzNO7zD3/l7l79+R5KReYmXeIEXqKIKBQrO5mze4i2S6D49sIWOYbRZWVddwsbaUnYbKjlorqfMasZgbzuoBGu0xPkG0EcXwtDgCMaFxTEiOFoElTaUWkz0XfIBJoeNdzOmcVPvdG8XyUOWZV580cg//1mH0ejC11firrv0PP10MEql+Fmeiv75zzoefbSOdeuiGTeu4yfgPFkijHQgK1Z88WUa01jM4i5//c7yMz9zP/eTQw4AQxjCa7zGGZzh5ZIJXcHssLGuupiNNe6gcsBUT6knqMgt9j0cVGJ9dfTRhZAeFMHY0FhGhkajUZy+w8hLLSb6LfkAo8PG20PP4uaUYV4tjyzLPPecgeeeq8dkcuHnJ3HvvYE8+aSY7+ZUd+21lXzyiRmTKbFbzQkjwkgHCyMMBQqyrIcwO5pw4qROqiXMFY5O5UOItv01b7q7vezlVm5lHetw4SKWWJ7kSW7gBm8XTfCSBoeN9dUlbKgpYZehigPmOkob3UHF/oegolEoCFZrifUNIFUXTHqwO6iMDo05LYJKudVM30UfYHA08ebQs7jVC4FElmWeecbACy/UYza78PeX+Mc/gnj00UARQk4TZ55ZyurVVmS5+0x4BiKMdLgpTGGlayUj8y+lLDCLssAsHMomLtv8H0JsUTw9fFaPDiQA1VRzB3fwHd9hx04AAdzMzTzDM2joHuscCN5ncdjYUFPWHFQqOWCqo8Rqot7WdlAJUmuJ8dWRqgthSFA4Y0NiGRMai1Z16gSVSmsDaYvfp97exGvpU7k9NaNLXleWZZ58sp6XXjJgsbgICJB48MEgHnzw1AwhtdYGzI6mFtt6+ofBjtK/fxH5+Q4slu7V3C7CSAdYxzqWs5xVrGI963HgAJfkflByIbkUXLv+A1SyD48MnU6CLqTLytaZHDh4gid4kzcxYECFigu4gDd5s9tO/CZ0D1aHg421payvKWZnfRUHzLWUNJqpt1uxyS2DilpSEKT2IcY3gBRdEOlBkYwJjWFMaAx+qp4XfqutFvosfp86u5VX0qdwZ+rwTnstWZZ55JE6Xn3VSGOjC71e4pFHgrnvPv0pGULAHUQe27qwVROiSlKcEh8G/6rIyHwAKioSvVqOPzre6/ep89Gkgx3gABOYgAIF8tErkUhHsluoOQGV7OOF0nUuFSr+2fzvMz7jMR7jO77je75nNKN5i7dIJ93bxRS6Ia1KxaSIBCZFtF5R2iY72FhTyvqaEnbVV5FjqqWk0USmqYZdhkq+L8nx7KuWFASqfYjx1ZGiC2ZwYDhjQmMYHxbXbYNKmNaPnOk3krb4fe7auQJZdnF32ogOfQ2HQ+ahh+p44w0jVquLwECJZ54J4a67Tt0QcpjZ0bovE4DDJWN2NBHC6R1GTCYXiYk995Lec0veyZJJZi5z+YzP2nxckpVEG/p1cam63tXN/37nd+7kTjawgaEMJZlknuM5ZjPb20UUegiNQsUZ4QmcEd52UNlSW87v1SXsrK8gp7lGJdtUy25DFT8cFVRUh4OKVkeyLoghQRGMColmQng8Oi8HlTCtH7kzbyR10fvcs3slG/eWMkVOPOHn0aiVjE2PoU+iu7bV4ZD5xz9qefttE1ari+BgBc8/H8wddwR17Al0Uw12G2vKctt9vAdU8Hc6q9VFdLTS28U4aSKMtENC4l3eJZdcNrIRJ84Wj7sUTiKNfbxUuq43jnFsZSuFFHIbt7GIRVzCJYQQwj3cw0M8JCZRE06aRqFiXFgc48JaT2PtkGW21JWxvrqEHfUVZDfXqOSYa9ljrGJB6ZGLlEqS0Kt9iNbqSNEFMSgwnDEhsYwPi0Wv0XZK2Z0umRu2LuasyEQuj+9HiMaP3Bk30uund/jWmUWD3c6ZjsQTfFY763eWkhgTxP331/Luu0aamiA0VMFLL4Vw662BnXEq3VK11cwre1ZSZW1/sdLlJVlcmzYWhSR1Ycm6D5NJxuWChISee0nvuSXvAho0/MRPZJBBMcWtAknUaRRGDksggYUsxIKFB3iAj/iIR3mUp3maOczhFV7psRPDCd2TSqFgTKi70+sfOWSZHXXl/F5Twva6crLNdRRbTBw017HPWM1PpQc8+yoliUCVD1Faf3rrghgcGM6o0BjOCIsn6C8ElYIGI5/k7+GT/D38WJLDO8OmEerjx9NM4FHW8ov6IGqNghkkH9fzNTTasdngk7dV/P3SfGw2CAmRePTRIB59NPiky9kT2WUnb+xd7QkiEtA7IAy9RkuRuY7qpgYANlcVEOUXyDkJp8caXE1NLtatsxISoiA2VkVWlrtTb0qK2sslO3miA+txyCKLEYygwdWAq7nPiM4aypwtr3n2OZU6sJ4IGZnXeZ1neZYKKlCg4EzO5C3eIpVUbxdPOI3Jssz2+gp+rylhR10FWaYaii0mamxWrLKjxb5KSUKv8iFS60eyLohB+nBGh8YwITyOEI3fMV9nafkhpq391vM8IRpfPht5DoVrTVRZLDzvtxETNp4ZOIFH+o095nNZrTJnz8ph/So1TqdEWJjEyJE+rFhhJS5OxYEDrZu4TmUbKvL4JGcjAJG+AcwbMIkI3wDA3TSzofIQn+VsxAVolWqeH3UBWmXPvSAfr4ULGzjvvArPfYUCZBlSUlQMHepDbKySlBQ1N9ygx8fHu7VFYjRNB1vOcqa5piFLMrggtXI8k3Nu8Tx+uoaRoy1iEfdyL5lkAjCQgbzCK0xhipdLJggtybLMbkMV66qL2VZfTraplkKLkVqblUZn66ASoNIQpfUnyd/d9DMyJJqJYfGEaf1468B25u1Y5llzWQJcwATimWFJxtdPxbM+66lssvBU/3E8PmB8q/JYLDK3317D55+bsNtBp5dJ6+8kZ5+GhgYXsgxhYQqqqhI7+1vTrTy/cyl5pmoA7h98FimB4a32+TRnI+sr8gC4KnUU46OO1EDJsovMTDvr11vJzbXz0ENBBAf33H4Vh9XXO4mIKMBub/3Y4X7Msgy5ufFery0Ro2k62EDLCM6ruY0F8a+DBFHGtBaPG21WL5Ws+5jR/C+TTG7lVtawhqlMJZpoHuVRbuZm0a9E6BYUCgXpwZGkB0e2ekyWZfYaq1hXXcL2+goyjTUUWYwUWIxkmWpZVJ535HmQUCkUHP2J7vDtdRSxV1vFjQwhd/qNpC35gCf2/060r44bm6eOt1hkbrmlmi+/NONwQFSUgqQ0K7u3qdi+SdWiY2ZbF57uwuGQaWhw0dDgwmJx325sdDX/L9PY6L5vtbrvu/+Hpib37aYmF01N7uYHm8193253sacyHIc9AoWsZK/exuDBVZSXO8nKsvPkk8FMnKhlVESiJ4zklNdh3Wth/fomfv/dyvr1VszmI9/DSy/VkZHR88NIUJCSiy7y5/vvG3C0zM7IMiiVcN11Oq8HkRMhakaOQ6G5lv/sWYHFYeeHIY9Rrc/j7L33klh3ZKZFvdqHB9KnEaYVi84dVkstd3EX3/ANNmz4489N3MS/+BdaOqczoSB0JlmWyTTVsK66mK115WQZa9haV45VdrZ9gAuQYKA+jAfSRvFU5nryzfV8OXI6dUt68eCDddTVycTEKLjoIh0LFjRQXHz46tKyet3HBz77LKL5Qn7kon74Yn7kf5ov6DI2m/u2zea+uNvtYLe77zsc4HC4tzmd7vtOpwunExwOd62C0+m+uMmyC5fLfdvlOvLVmSQJXLiQJPdtjVpBUpIKm81FSYkTq9VdgMRkqKiz4bRL2M0qXC4JpfJIWQ/z9ZUwGBJRq0+NTq5LlliYPr281XZJgpAQBbm58d2iFkg003QQu+zk8a0LqW2yAKDys/JWxvX8o+Y5BtRMZEdNERaH+yNLL10ID6VPQzpNe3S3x4GDZ3iGV3mVeupRoWIWs3iDN4ghxtvFE4S/JPnXd8lrqG+5UXKC1gR+9eBrBL86iNtNiNmHJwr9Gef7PttKf2be7OtRqaCxsfPKd/hifvhLoQCFQmr+3/0pWqmUPP+rVEf+V6sl1GpQqdz/q9USGo37S60GHx/3bR+fI19a7ZH/tVoJX1/3/35+Er6+Cnx93dv8/CT8/RX4+irQ6cDfX4FGI7V4/3xq2y+UWgzu2xnnEOV3ZBRRWZmD336z8va3Raz5QcMfw9sfvwdTpmhZtuzUeb9xOl3ExBRQWdl67pVvv43gkku6xwdjEUY6yObKfD7MXg9Aoi6EuwdPYYRyGGMYw3u8h8lm5fldSz29ve8dPJU+gWKW0vb8l//yKI+STz4AIxjBm7zJCDp2cihB6CwVVLCDHexjH9mubD7YW4jL1wi+Bnfw8DWA1nxkgkQXjC+DO/dBvzpINGvJGrKO6upd7NhxEWo17N1r43//s1BdLbuPc7W+sEoSfPhhWIuLuvv2n1/Ue6plxZl8d2gHAH0CI7htwMQWHVTzjNW8vGcFtaVK/ndnf8zl2nZrbDIyNLz4YihnnOFzykwQ99BDtTz/fL3nnJVKmD7dl4ULo7rNz1+EkQ7y2t5V7KsrA+DeQVPoExTJbdzGClaQRRYAmyoP8VH2BgDGRSZzdZ9RXVrGnmgLW7iN29jCFgASSeRf/IvLudzLJRNOVzIyBznITnayn/0c4ACFFFJOOTXUYMZME02tD2zyg0Y9NAaitAUQ7aNnsC6GwBwl1x3YxQTDPnxcdpwKJR+lOlk++mz+secZ/KVa+mZMa/FUv/9u5e/zCtm3U4VC4UKWW15QnM4kFIrucZHpCg12G09sW4jJ7v6+B6i1jIlMIsTHj5z6SnbUFONq7qUzXJfK/AfiWL688ZhNSEolxMermDBBy1VX6ZgyRdtjw8mGnfWMHVrrue+jhQO5CcTFdZ/uoKIDawc53DyjVihJba7xiCCCbLLZyU7SSWdAcMxR+zd4pZw9zQhGsJnNlFLKbdzGQhYyhzncxm3cyZ08wiOoxK+n0EGaaGIPe9jNbrLIIo88iiiiggrqqaeBBvfaU3+gQIEvvujRk0YaMcSQRBJ96MMgBtHL1pe5v69iZEg0f4vvy8ioGBSFv8C6h5Fr9yABO0K0PDUCFsbbuVFxE//lTXaxHavcevryceO03PFwIznZMmsW+bFtgxqFApzNXVLsdnffkdOFv1rDrf0n8ureVViddkx2K0uLM1vtlxYYyTUDhnLtr0ruvLOat94ytXjcxwd27Yrliy8aWLTIQmamnc8/N/P552YUCoiLUzJunJY5c3TMnOnb7cOJy+Vic2UB75dvgqNqlZuaXDz7UiX/fiYKf//ufQ5/JGpG/sTT23+luKEeCYlXxs5Gq1SznvWMYxzf8i2XcAmVjSYe27oQgIHBMdw+cFKXlvFUYMXKQzzE+7xPAw1o0HAZl/EqrxJEkLeLJ3Rj9dSzne3sZS/ZZJNPPiWUUEUVBgw00thyfalmKlT4408QQUQQQRxxJJNMX/oymMEMYtDxd7R2WLBveRhz3ocEN5ip9YG3+8G7/aHIH5AgkEDqqENCYufG5YCL9NFntXqq9+bvwmyxo/NTM2VYf/7973o++siE0wlmcyJ+fj3rItMRyi0GFuTvZldNMfJRY5f0ai1nRKcyPb4/asWRzpqvvWbgrrtqPPcnTtSyalXL/iJFRQ4+/tjEL780sG+fnYYG9/NKEsTGKhkzRsvll+uYNcsXlar7fM8b7E28m7mObEMFhiIt31yR3uJxSXIRHqng3bcjOP98P68314iakQ6SFBBGcUM9LlxsqDjE5Jg+jGQkGjSUUALA7+UHj9o/1FtF7dG0aPkP/+ElXuId3uEZnuEzPuNzPmcSk3iTN+lHx68FJJYk775kZIooYic72cc+csmlgALKKKOGGkyYaKLJU01/NB980KEjhhiiiCKBBFJIoR/9SCedVFI7Zph51TZMm+dhq95IaBPsjYJ3Rkp8l+TC9od319d5Ham5k6Ws9MclqWms2ItvZPuzhiYnq3n33XCefDKYrCz7aRlEAKL8Arm5/wTqmywcNFZjkx0EanzpExiBStF6xMgddwTSu7eKSy6pxGp1ceaZvq32iY9X8fjjwTz+uHtW2/Jydzj53/8s7NljY/78BubPb0CSICpKyejRPlx6qT8XX+zvtXBil528tm81+SZ30Gqsb30Jd7kkKitkLrywgpkzffnww3Ciorr/pV7UjPyJQnMt/9yxGAAfpYrr+oxhSGgcgVIgya5k3qj4jg8PraLWtwSNU8t7A28nyOfYMzYKx2cZy7iHe9jLXgD60Y+XeIkZzOiQ5xdLknuPAweZZLKLXexnP3nkUUghFVRQRx1mzNhpPbGGAgVatOjRE0ooMcSQSCKppDKQgQxlKFFEdW7hZRn2vgK7XwZLCTLwQV94oz/sCWv7kEACKaccLVospTvILHOPO/Wz5dN39IVIR11Qj64ZuemSIZ17Lqe4XbuauOeeGt56K4y0tBNbRLG62sHHH5tZuLCB3bttGAxHak4iIpSMGqXhkkt0/O1v/mg0XRNOVpZk803eNsDdfyYiaygPXNveJdw9rvz110OZN897axmJDqwd6IOs39lSVUCj2kidXwnOwGpWxn2KTWrCx+GPVeNun4y0x1GuLury8p3qcsnlVm5lJSuRkYkkkod4iNu5/S99uj06aP6RmFH35Jkxs5Od7GEPWWSRTz7FFFNJJQYMWLC0WucJQIkSP/wIIohwwokjjt70pg99GMxghjAEHV4crmguhA33QMFCkG2g0EDi+TD6ZRbotnIRF7VZS6OQlUzJvYLZu+8BYIR+M3JoOkju311b2Q72NB5p929otONyIcJIN1Nf7+DTT8389JOFHTts1Ncf+RATHq5g+HAfZs/25/LLdfj6dnw4cblcPLHtFyoajQA8mH42S7/UcPPN1a32lRQuVFqZf/87mDtuCfVqp2fRTNOBrk4dxU/BH/O/yA/dG456vzkcRCSXxAzVVC+U7tSXSirLWIYRI3dxF1/yJXdxFw/zMNdxHc/zPH6I2qiuUE4529nOPvaRQw4FFFBKKdVUY8RIE01t9s/QoMEff8IJJ4oo4oknmWRPs0lf+nbfDssHv4VtT0J9c8dJ/zgYdC8MvMMz9/YFxPEar3E7t7c6XFY4ydh/HmaLHaXLAQkpniAC4BPZD3VOCXWOllMCaNTen7BKOCIoSMWddwZx551BABiNMl98YeLHHxvYvt3GokWNLFrUyPXXVxMaqiAjQ8NFF+m44godOt1fDye1TRZPEAnx8SffVMP+Qj/35HDN16TDa9T0nlzDmNsLGDdmBApFO9V13Uw3/evvXjRKFXdEXMr/aA4jbYRMl+TiAi7o0nKdbvTo+YiP+IAPeJZneZmXeYM3eJu3mcEM3uRNEji9FhLrKDIyueSyk51kkkkuuZ5mk1pq2x3WKiHhgw8BBNCLXsQQQwIJ9KEPAxhAOunEEdfzlgGwGWHzQ5D7OdhN7vAQPQlGvwThw9o8ZB/7Wm1TyApSqoeR5EgBP0jVZCKr+rfYxyWpyIipYWNVtCekaNRKxqafOhN0tWdNaS5rynKpaXLP0xTtF8i5CYMYGNL+uW+rKuSngt3UWM1E+AZwUVI6g0KOrOjscrlYWLCHteUHaHTaSdaHMSdlBJG+HVurrtcruPXWQG691d0EYrHIfPmlme+/b2Dr1iaWLrWydKmVm2+uJjhYwdChGi680J+rrw5Arz+xvwenS2ZR0ZHfr9qmBr4+uI11mYm4XJGAexK7+HgVdzxnIzvWvVr1H9dZ6s5EM80JuJ/7eYmX2u0wV0ut+ITexb7jOx7kQQ7i7kScQQav8zpjGPOnx54uzTRWrOxhD7vYRTbZHOSgp9mkjjosWNoc1qpEiRYtQQQRRhixxJJEEmmkMZCBpJNOMKfYkvblv8Omf0DFBsAFPsGQdj0MfwpUbf9ty8hMZzrLWEYKKQxiED/xk6eGaD7zmc1sAA6s/y8GTQpIrT8HJvmWEdL/3E47te5oV00xCklyr8Trgg2Vh1hanMmjQ6cT4x/Uav+Dxipe3LWcC5KGMDgkls2V+SwpzuSRodOJbd5/cdF+FhftY27aGMK0/vycv5sSSz1PZpzbYsRNZ7NaZb75xsz8+Q1s2dLUYqbUoCAFQ4aoOe88f+bO1RES0n69gFOWeTdrHbtqils9Nv+aQdQd8kdSuJh3r5bnn4rmu+ItrGseVPH3fhMYFhbf8Sd3AkQzTSf4J/9kOcvZw54Wbd5KlExjmggiXjC7+d92tjOPeWxkI2MZSwIJPM3TXM3V7R57sjm8iSbe4z0mMYlBDDrZoneIWmrZwQ72sIcccjjEIUoo8TSbtDesVY0aP/wIIYR+9Gs1rHUgA/HhNJnQQnbAzudh3xvQ2LzWR+gQGPFPSDjHs9vidYfYf9A9ikEhSWh9lASFqHh25I3sDtzIJCaxghXYsDGFKaxnPWGEcT7nA+AwV7QbRHDJFJr80ZsrUen+fAZng7mJD7/fw5Wz+hMR0nPfd4aExrW4f0HiENaU5ZJnqmkzjKwoyWZASDTT4ty1S+cnDiGzvpzVpTlckToSl8vFipIsZiYMJL35ua9NG8N9G39gZ3URIyISO/uUPLRaBddco+eaa9wXYJtN5rvvGvj22wY2bWrit9+aWLOmiXvvrUWvlxg8WMOsWX7MnRtARMSR35Ef8ne2GUQineHUHfJHoZK5+KPd+KRClWMSmyrzAfeAi/5BndyZuwOJMHICNGj4lm8ZzOAWYcTpcjKx6WxqaRAjMLxkGMNYz3rKKed2bmcBC7iGa7iDO7iN23iKp1r0SSizGPgg6/d2n29zZUGbNSPrWMe1XMsBDnAzN/M2b3fK+cjIFFDQYlhrIYWUUUYtte0Oa5WQ0KBBh45YYokiil70IoUU+tOfdNLpTe+e12zSGQwHYcNdULQYXA5QaiHlShj9Ivi1Xs0XIDFWz7RxSciyi0JrKTPV0ynWHWDOvvv5vN/zKBQSWrQsZCFnczZXciVq3NOX1x78DUhsuyySAqdKT8nepfQafWWnnG53J7tktlUVYnM66B3Qdj+HPFM1U2P7ttjWPzjac7GutjZgtFvpd9RF2FelISkgjDxTdZeGkT/SaBTMmRPAnDkBgHul4wULLHz9tZmNG5v4/fcm1q1r4oEH6tDpJAYO1HDWdB8K0w/hEwJKScHU2L4sKd4PwPf/CUDtI3PdBwW4elkx2uHF3cuxNy/aOCaiN1pVz1m1V4SRE5RKKu/wDnOZe9RWiV07VDzmXCiGhHpZFFHMZz42bDzCI7zDO/yLf/ECLzCb2bzGazgtGl7YtZwGRxtTezdbVpKJv1rDjPgBABgx8iAP8jZvo8Rd1VtM608rx8OGjf3sZze7ySSTgxz0zAZaRx0NNPzpsNZUUtsc1hqBWBfpT+V8BtufBqO7XR1dIqQ/CH1v9HRIbY9SocDfV81udjPafzSNNPJYzfMEbT2TfepqBvUJx2pzsHWrkesLP8Apy8wPzWbSiHhqGwCf1s8vORtROQz4uEz4B7pHC7lcLjbuLmNPThWNVgchgVrGZ8SRFOvun/Dh93sA+GKh+8IUF6njb9P7tnrunqCkoZ7ndy7FLjvxUaq4uf8EYvzbHopqtFnRq1tORKdXazHYrO7H7e4VB/WaP+yjObJPd6FSKZg9W8fs2e6fuSzLLFzYyFdfmVm/3srmzU1s3NgEpKPSyiSkygyZF0X/9AZWba9h/88RjLvrEK5eFZ7nbJLdza0xfoGcnzjYG6d10k77MCK7ZBYW7GFTZT5Gu5VAjS9jI5OYGT+w3ZnrruZqPmr4mt/83P0NIo2paB0BOJAx2a2eMLKqNIdlxZkYbI3E6YK5LDmDpHYSv9CxNGh4ofnfe7zH//F/fMVXfM3X9JIHkKG5klBHPBE+OsZE9SZBF4LJbmVbVSF76koB+Cl/F0NCYtnuv44buZFKKgE8tWKHF/s7mhGjZ1hrNtmeZpPDw1obaWxzWKsKlWdYazLJnmGtfenLIAYxhCGiGfCvsNa6+4Ic/BocDSApIW6au0NqyIATeqr/8T8u4AJcuPiar7k09FI+D95HbmEdg/qE87/VB1EpFVw4NRUfjZLd2VXMX5rD7EF+BDblUGtyUVjtIjImEpdSS0TCEJauzycqzJ+0gb0B2L6/gm37Kpg6phcRIX7sPVDNTysPcM35AwjWa5lzTj++/CWT2Wf3ITTIt0evVxPpG8Cjw2bQ6LCzvbqQT7I3cu/gqe0GklOVQqHg/PP9Of989/VDlmUe+WQ3333dRPmeAPL3abn57zUoFNGoNFHo4xrpd35Fq+fpHxzN9Wlj8FOd2Lwq3nbah5HFRZmsKTvAtWmjifYLpMBUy6e5G/FVajgzNq3V/k5Z5pOcjfSuvZiNI9dgUzUSV3uk38DH2Ru5bcBE8s01fJe3nTkpI0gKCGNFaRav7V3FUxmzWqV2oXPd1PxvNau51TmPTP+95A97kBBrDB+p32Gm6sgMmGMie7MgfxeLivbRoDZwkTybTaxAQmrVJJJFFgMYQDXVmDBhxdpm5+bDzSaRRHqGtR5uNhnCEPrQp/sOa+3pSla6Q0j1dsAF2jAYdA8MfRRO4s16Q+AK/s0taNCwmtWMZjQAIYFaquoaKakwUV5t4eZLh6BSumtBJo6I50BRPeXqkQweEM6hnSVkFZQRK5diV+uJiwpg8qgEFqzIZeKIePx91WzdV8GIgVH0TXI3FZ6REUdRmZHt+yuYMroXvlr374vWR4W/b8+pim+LSqF0d2AFegWEkG+uYWVpNlemjmy1r16jxWhvWcPh/hDpfk/Vq90zrRpt7g+Wnn1sVuJ1QZ10Bp1DoVCQPtFJbaq7M+pdAyejrglj0SILL79s4I57A0nrPZhCcx3768pokh0oJQV3Dpzs5ZKfnNP+HTDPVEV6aKxnaFiYVseWqgIOmWpa7etyufg4ZwNbqgrQ4Mew/IvYmPJf9NYj7ctljQZe3L0MndqH8VHJjItKBuCKlJHsrS1lfcVBpsef2CcxoWNMYhLPFX/JVxUrWZfyMSXBe7lAOo8ZzOB6rieJJEoppTA+n18D36U4aB+HJ5VpK2Q4cJBHHnr0JJFENNGeZpOjh7UKXcxhgx1PQ+Y7YK0GJAjLgFHPQeyUk37a78I+4uM+zxJIIDvZSS96eR5zz3UJVXWN2B1O3v56Z8siOWXqTUeaBfX+GlQ0YUeBw2YlJtwflwtqDVZUSgUNjXZiIlpO8BYboaOqrvGky99TuFzgkFvXHgL0Dggjq768Rb+RzLpyTx+TMK0/erWWrPpy4nXukV6NDjuHTNVMjE7p/MJ3sNijaoe2VhdyVWo0t98eyO23H94eRqG5lh017sk2Y/x6bm3SaR9GegeEs678ABUWI5F+eorMdRwwVnFJ76Gt9t1RU8yWqgLA/cZzn+ZOLnF9yaV90tGpUlhbfgAXUG9rpN7WyKyEIzUmCkmib1AUecbWs+UJXcdsb0LfFMHMfQ9wR/p4NgQs5TVe8wy9BFAqlSj0KmgjgPxRJpkkttcpUehatfvcM6SWrgCXE1T+7mG5o/4N2pMfpi0jcx7n8UvfXxhYPp71Ub8SQEDLlzZY0Qf4YLM78fdVc8m01rWqWk3LYaUahUyjJGEs3Yt/TPpJl68n+/HQTgaExBDi40eT08HmynxyDBXc0fzp/uPs9QRp/LgwKR2AKbFpvLh7OcuKMxkUEsOWqgIKzLWeWhRJkpgS25dfi/YS4RtAmFbHTwW7CfLxJd3LQ1xPxvCwXnybt50mp4Pfy/PoHxRNRviRuZQMtkY+y9nkuT+hBwauw077MDI9vj9Wp50ntv0PSZJwuVycnziEURFJrfZdXZrjuZ0RlsDFCSNIIolcZTbXhM7kt/ID+Cs1NDhtzXu1bMfVa7SUN8+gJ3iHVnmkSruhUeaGgBu4nuv5F/9iOMMZzGBC5FAe2vwzNdRQGLWJ2qRt7GY3KlSt5uMopliEEW+SZch6H3Y+B+Z89zZ9irsZJu2av/z0NmwMZzh72MPEogu5K/c5AqJaBpHCMiPVdY0M6xdJgL+ahkY7CoVEoK79odHGBhuSyt200FBfilGdiiS5m3t8NEr8fdWUVpqJP+q1SirNRIW5+xMom/uI9IBpoo7JZLfySfYGDLZGfFVqYv2DuGPgZPoHRwPuWUelo95Hk/Xh3JA2jp8KdrEgfxcRvgHc0n+CZ44RgGlx/bA5HXyRuxmLw0ZKYDh3DJjcpXOMdBStSs3UmL78UrQXFy7ey1pHr+IQ+gRGUm+zsLOm2DN6JtTHn1FeHC30V532YWRbVQGbK/O5Pm0sMf5BFJnr+DZvG0EaX8ZE9vbsZ3XYyTa4OwspJMnzy9+HPmxiE4ff9sZFJbO0xD1t9CFTFelhopq+O+kXFOUZGreiNJvh4QkoJAWP8Ihnn3WVB2hw2NASwOXW67iJj9jDHj7lUz7hE2qoQYkSJ07Pys1CF7OUw8b74ND34LSCpIaEWTD6ZQjqmE+H1VQziEGUU84VXMGVBU9jke00NNqRZRcWq538EiOb95TROy6Q/smhSBLEhOv4eeUBJmTEERyopcFiJ6+4npSEYE+YUCkVZFXpiYoEg8nKlkOF9OkV4un/MWJgFOt3lhIU4EN4iB/7DlRTVdfIzDPc70l+WjUqpYL8EgM6Pw0qpYSPpue9nV/dZ/QxH793cOslNjLCE1rUDvyRJEmclziY83rYaBKAHEMlS4v3U2iuw2Br5JZ+Ezi310BqmsxsbJ4/pMBcS4G5tsVxSkmi3tbIM9sXMTNhIGOPunZBzxhM0fN+ezvY94d2Mi2+v2f8eax/EDVNDSwq2t8ijFg8tR3gq9Rgsrvbf6uoYjvb2W7bi1apJjEg1LNfva1l+67RZiVQLTqvelPfoEiifPWUNxrJN9Xwzv61XJCYTox/IFaHnXUVB/nx0E7P/hOjUwEYxCBe5EWe4zmWspSP+ZiFLERDz+qx3uMV/gqbH4baXe77vlEwYB6kPwCKjns7yySTEYyggQae4Ame5EkWc4j8EiPvfrsLhSTh46MkPNiXySMTGJAS6hl9d+HUVNZtL2HJ7/k0Njnw91UTG6lr0dE0KMCHqIRUsJZjalITFuzHlNFHLrBD+0XQZHOyZmsRFquD0EAt55+ZQrDe/f6hUEhMHhnPxt1lrN9ZSmxEzx3aKxxhczqI8w9mXGQy72SuBUAhKZjbZwx9g6JYUZJNUUOdZ38fhQq7y8nYyGSmxKaRVV/O5zmbCNRoGRDsnlJ/S1VBjxhMcdqHEZvsQPGH5hSF1HrkhK/yyEXHhYusevdMjR/zMddxHZ8bfqZf6ABKLfWe/WqbLJ7bsst9zOSYPp1wFsLxkiSJOSkjeHXvKpwumV21JeyqLSFA7YPFYcfpOjJb6aiIRPoEtpy3Q4WKmc3/ZGQxeVhXcFhgyxOQ/SHY6gAJIsbC6H9D1LgOf7llLPP8fD/lU88svtPHJzF9fOvm2z/SqJWcOSqBM0cde52kjIFxbNtais5PyZixyS0ekySJMekxjDnG+jSD+oQzqE/4cZyR0FMMDIlpc10eSZIYE9mb0RFJVDSaMNga0SiUbK0qYH99uafPTLRfIAcMVSwvyfaEkeUlWT1iMMVp/046OCSWX4v2sqe2hGqrmR3VRSwvzvJMJQzuTlZfH9xCit79h29x2KhsNPH9oR2EWxL4V+knyC54o89tPKF5yHNcnrGaDRV5lFkMfHlgCzbZ0ar6TOh6aUGR3NJ/Qov+IyZ7U4sgMjayN1enjmp3rhlABJHOVrUdFk6GjwNgz4vuTqn9b4O59XDB750SRN7jPaYxDQUKVrHqmMsJdARJtiErTpNp94W/TJIkovz0pAVFkqQPI99cS98/TPnePzjaM1DCITspNNW2mJG2uw6mOO1rRi5LHs5PBbv58sAWTPYmAjW+TIhO4dyEI3NPGGyN1DZZmBSdygFjFeDumrq5Mp8VJdkE+/hxXcgV7Gz6gR1Rv2JU1nFP1bP0C47i54LdGG1W4nTB3DFgMvqjxr4L3jMoJJZ/jTifjZV5bKkqaP6koSI1MIKJ0ameYYFCF5Nl2Psa7HkJGppnuA3qBxlPQvLfOvWlH+AB/s2/0aNnO9tJJvnPD/qLFK4mZEX3qSoXehaj3drmbLNWpx2b04HFYUPGRUAb+3S3wRSnfRjRqtRcmpzBpckZ7e4zN829AqzsktlcVcDu2hLsLtnTJ6TW2sDaUjMXlz7PD0Mf42DEBr4NfYqVyuVMjmk9xE/oHvzVGqbE9mVKrGhr9zpzkXtYbsHPINtAoYGk2TDmJdAdu7mjI1zMxfzAD8QTz252E0RQp73W2PRYxqa75zVSOhuxqbtXR0JB8IbTPoycCIWk4KZ+4/ksZxObq/I92+Xm/iUKVNyc+Sqrh77MGtUqRjKSzWwW1fmC0J6872DrE1DvHuGEXywMvgcG3vWn68R0BAcORjOabWxjOMPZwIYunQ1X4WpqexVf4bTR1giaP5sTJbu+gvl526lsNLGkaH/zMibuLgBGmxWtUs3vFXksbR45+En2Rq7rO8YzgqY7DqYQV8kTpFYoub7vWB4fNpNJ0akkBoQS7x/MkNA4buk3gf8bfh6/q35jNrPZxjb60hcr3WuBJkHwKpsZ1t0OHwfC8kvAkAXRE+HCLXBlsTuMdEEQqaeeJJLYxjZmM5stbOnyafnVkgMkCXPVwS59XaH7ODyC5vLk4ce1f7XVzBv7VpMWFMnYyN5oFEo+z9nEvuY1tTLrywnV+vNd3nbOTRhEjF8gSknBa3tXYbRZPYMpeuu7V42ciOQnKdY/iMtTRrT7+Hzmcwu38A7v0Jve7Gd/p1b9CkfUNVn44dBO9tWVYpOdhGt1XNNndIth1390+JNGmcVAsI9fjx2r361VbHDPDVKxAXCBJggG3Qsj/g9UXbsIYC65ZJCBCRMP8ADP8VyXvv5hGrX7LdhUkYsuvPP7qAjdzx9H0FRbGygyu4fvVje5b/urNIRo/fnx0E521RYTptVxSe9hVFvNbK0qIMI3gF8L91HVaGZbVSHhvjrPCBqNUsXHWevxUapYXLwPm9PZLQdTiDDSid7mbcIJ52mepje92cteYmh/qJ7w1zXYbbywaxl9giK5feAkAtRaKhtN+B9jUbTDnzTOiE7l+r5je/RY/W5HdsCuF9ydUhvdw+EJGQwjnoFes7xSpN/4jbM4Czt23ud9buAGr5QDwDcgBBqgscHktTII3cv8Q9uP3M5z3x4TkcTctDEYbI3UNzV65sAK0+qYN2ASH2dvoLzRSL2tkTmpI/gydwsXJbpH0IwI74XZbuWHQztZWZJNr4DQbjmYQoSRTvZ//B/hhHMHd9CHPuxgB6mkertYp6wlxfsJ9vFj7lEzO4Zpdcc4AtaU5Xo+aUDPHqvfbRgOwsZ7oGgRyHZQaiF5jrtDql/Unx/fST7jM+YyFxUqlrGMKZz8wnkdITB6AMUHirA5e/a07kLHOVafkblpY3hs68IWH4DSgiK5InUEb+xbwxPDZrY5gmZyTBq1TRZyDJU8lD6t08/hZIgwcpRFRfvYUV1EeaMRjUJJb304FyWmE+WnP+Zx26oK+algNzVWMxG+AVyUlO5ZBRhgnmse5WUKXg5/kJH2Sdxc8Cx3JV5ApO+xn1c4cbtriukfHM27mWvJNVQSpPFjYnTqMReQyjNWtzlW/9vmTyWHx+rPiOvveby7jtX3upwvYMf/gSHXfV/XC4Y8AP3+3iX9QI7lcR7naZ5Gh47NbKYf/bxaHgBtYAS4CnCi/vOdBeEUJsLIUXIMlUyK6UOiLgSny8WC/F28unclT2aci4+y7W/VQWMVH2T9zgVJQxgcEsvmynze3r+WR4ZO96xfs6Q4k4aiCF71/Yh5gVfyavIdVGcZeWvgLT1y8aburMpqZk1ZLlPj+jIjfgD5plq+yduGSqFoMb3/0U6lsfpeYa2FzQ/Aga/A0QCSEmLPdteChAz88+O7wBzm8BVfEU00u9lNGN2nr4/kcuCURFOfcHz0ai1GW8tBEYdH0GiUKhSShAIJUxv7dLcRNEcTo2mOcufAyYyN7E2MfxDxumDm9hlNbZOl1aJER1tRks2AkGimxfUn2i+Q8xOHkKAL9qzw63K5WFGSxcyEgdwUfAlrFb/hVFv5ou8jvFL/cVed2mnDBSToQrgwMZ0EXQhnRKcwPiqZNWW53i7aqadkJfw4Ej4Lg6wP3E0x6Q/DtQ1wzpJuEUQcOBjDGL7iKwYzmHzyu1UQAZBkMfGZcPx668M8y5EclnnU6BiVQklCQAiZ9RWex7vrCJqjiTByDI1OO8AxOz/mmdqu4s8zuavvq60NGO1Wz3S8oxjFLmknfg49DwXexlu81UmlPz0FarRE+wW22BbtG0jdUesE/dGffdLQqX165CeNTuGwwZbH4bMI+GUKVG2FsGEwcxlcUw0j/wmq7jG9uREjKaSwkY3MYhY72NEtFzZUylYxJfxpzOq0U2SuazWCptbaALiXI/k4e71n/4nRqVRbzXx/aAflFgOrS3PYVlXI1NgjE2xOje3LuvIDPWo5EtFM0w7Z5eLbvG0k68M9zS1tMdqs6P9wQdKrtRiaL1xGu3uW1qObAfrSl4eL3uHfcbdzm/9tVFHFEzzR8SdxGkrWh1Pxh6aTikYjIT7+7R7TWx/G3trSFtva+6RxuGPZabfwYV0mbLgbSpa714hR+UHadTDq36Btf8i0txRQQDrp1FPP3dzNy7zs7SK1SyFbcUnd73sodI0CUy0v71nhud/WCJqjF109PIJmft52VpZkE+Tjx1V9Rnk628ORETQ9aTkSEUba8dWBLZQ2GLh/yFmd8vwBciCPFr3Dv/pew5M8STXVvM7rnfJap5OpsX15ftdSfi3cx/DwBPJNNawtP+BZ1RLcnzTqbRauTRsLuD9prC7N4ftDOxgX2Zus+gq2VRUyb+DEFs/7SfYGEgNCSAwIZUVJdrf/pPGXyTJkfwA7nwVTvnubPhmGPgppc71ZsmPawAYmMxkbNt7kTW7lVm8X6ZhU2GiSFFjNtWh1Id4ujtDF0oL+v707j4+qOh8//rkzk5nJvpA9BAIJhCVAZDUoIkpFXHCpP1GsC1Jbl6qV2lbUiksVa9VaFbXVVq1fFOquoFhAcQNFlrCGJWQhARKykEy2yWTm3t8fEwYCSUgCmZvMPG9eo8ydc2eeuRlynzn3nOfE8Y9Js9p8/MhyJMfv8+Do6e0+75TE9F61HIkkI614J/cntlYe4N5RU4m0tF+MKcxsxdZ0XPd9k53w5p6QsAB3Jmpz2Ak/Jiu1Oewkh0SRTz4ZZPAiL1JOOe/wzml+N/4lJbQPtw09hw8Lslm2byvR1hCuHjiGCbFHl373l28aXVZ/yF2cLP89cDW4y5X3uwTOfBYieva09CUsYRazMGBgKUu5iIv0DumkAprHsNsObMM6+Bx9gxFCJ11KRhYuXMhf//pXSkpKGDVqFC+88ALjx48/6X6LFy/m2muv5bLLLuOjjz7qykt3K03TWLx3PdkVxcwdef5J61MADAx1DyaaesxiazmHSxjYXJkz2hpMWICVnVUlnpVgG5xN5NeUMzkhDStWdrKTcYxjMYspp5wv+ELWszkFI/skMbJPUpuP+8s3jU7b9zn8NA8qNrvvB8bB8Psh8z4w9PzvLY/zOA/yIEEE8QM/MIIReofUIZagEGiChhqZJi78V6fPeEuWLGHu3LnMnz+fjRs3MmrUKKZNm8ahQ4fa3a+goIB7772XSZMmdTnY7vbO3vX8eKiAOekTsRoDqHY0UO1owOFyetq8vmsNH+Zne+6fn5TO9sMHWVGcQ0l9NZ8WbqGwtpJzm8cSKIrC+UlD+KxoG5sritlfV8Xru9cSYQn0jD8wYWIDGziP81jJSsYxDidOhOh2Tjv88Ad4MwqWXwQVWyA2Cy79Fq4vgdEP9opEZDazeZAHiSWWPPJ6TSICENbca9foaNI5EiH0o2ia1qnSfxMmTGDcuHG8+OKLAKiqSnJyMnfeeSf33Xdfq/u4XC7OOeccbr75Zr799luqqqo61TNis9kIDw+nurqasLDuKxT262/fbnX7jYPP9IwNeGbLSvpYglt8u3YXPdtMhb2u1aJnmqbxaeFWvi3Jpd7pIC08hlmp44hrpZjaTGbyX/5LGmlsZStW/Gy2hvCO8mxYOxdKvgZNhYBQSPsFTHgSzL2nGJ+KyhSm8A3fMJShbGRjr/s343Q42LxlC9bGQoaf9XO9wxHitOro+btTX3kcDgcbNmxg3rx5nm0Gg4GpU6eydu3aNvd79NFHiY2NZc6cOXz77bcnfZ3GxkYaGxs992027xSWam8Q0RG/Gzn1hG1jYvoxJqZfm/soisKMlJHMSBl50udfwhJiiGEhC2WBPXF6qSpsfwG2PAN1Re5t4UNgzHxIu0bf2LqgnnpGMYpccpnGND7js155edNkNoPmQlVkeq/wX51KRsrLy3G5XMTFxbXYHhcXx86dO1vd57vvvuNf//oX2dnZHX6dBQsW8Mgjj3QmNJ/yIi8STTSP8AgDGMB2tssCe6Lraovd68QUfAJqIxjMMOBK94DU0P56R9clxRQzilFUUslt3Nbr6/UYNCl8Jvxbt36NqKmp4frrr+fVV18lOrrjld/mzZtHdXW151ZUVNSNUfZMD/MwL/ACVVQxmMHsYpfeIYneJv99eDcD3k6GvHfd9UAmPA03N8DP3u+1ich61jOIQVRSyTM80+sTEXDXGpHCZ8KfdapnJDo6GqPRSGlpaYvtpaWlxMefuBLn3r17KSgo4NJLjy4Vrqqq+4VNJnbt2kVqauoJ+1ksFiwW+Yf5G35DH/pwHdcxkpF8x3eMY5zeYYmezFELP90Pu9+EJhtggPhzIOtpiOn9n533eZ+ZzATgAz7gCq7QOaLTw6DacZrCT95QCB/VqZ4Rs9nMmDFjWLXqaLU4VVVZtWoVWVknTpccMmQIW7duJTs723ObMWMGU6ZMITs7m+Tk1pdJFkddy7UsZzkuXGSRxRd8oXdIoicqXQsfnw1vhLnHhSgGGHEP3FwDM772iUTkGZ7hKq4igADWsc5nEhEAo9YIGHE6HHqHIoQuOj1nb+7cudx4442MHTuW8ePH89xzz1FXV8fs2bMBuOGGG0hKSmLBggVYrVYyMloulhUREQFwwnbRtgu4gLWs5WzOZjrTWcQiruVavcMSelOdsPlp2P481B90b4saAWP/DCkz9I3tNLuN23iFV+hDHzazmSTariPTGwUYVBoUhZrSHUQmZ+odjhBe1+lkZObMmZSVlfHQQw9RUlJCZmYmy5cv9wxq3bdvHwZD7xvR3tONYxxb2MJoRjOLWVRQwW/4jd5hCT3Y8t3rxBR9BmoTGC2Qei2c+TQE+9ZAZxWVC7mQFaxgEIPIJpsg2q+K3BtZzO4F/OoqiiQZEX6p03VG9OCtOiO9wQEOkEEGhznMfObzMA/rHZLwlj2LYOMjUL3HfT+kH4z6Awy9DXzwC4AdO2dwBjvZybmcyypW9cqpux1RsXctBVVmwptySTtzpt7hCHHadEudEaG/RBLJI49hDOMRHqGMMhayUO+wRHexV8G6P0Du2+CsA8UISVPd03L79J4qo51VQgkjGUkZZcxhDq/xmt4hdavwpJFwOIcml6J3KELoQpKRXiiCCE/J65d4iTLK+C//1TsscTodWA0//gHK1gMaWPpAxl0w+iEw+XY9ii1sIYss6qnnCZ5gHvNOvlMvZ7IGAyouKXwm/JQkI72UFSs55DCBCbzLu5zP+axghc92Y/sFpwOyn4AdL4G9DFCgzxkwYQH0vUDv6LxiKUu5nMvR0FjMYs80Xn+gaE2oim8nmkK0RZKRXsyEiZ/4iWlMYyUrGcMYfuInTPJj7V0O57jXidm/EjQnGANh8E1w5l/B2vFigb3di7zIXdyFGTNf8zUTmKB3SF5lUO24pAqr8FNy1urlDBhYwQqu5VoWs5ghDGEb23rdYmF+R1Vh178hewHU5Lm3haXCGQ/AoBt9ckBqe+7mbp7neSKIIJts+tM7q8OeCnfhsyi9wxBCF5KM+Ih3eIdoonmRFxnAAHLIkQX2eqL6Q/Dj793l2V0NoJgg+SLI+htEDNY7Oq9TUZnBDJaxjAEMYAtbCCFE77B0YdQaaVIC9A5DCF1IMuJDXuAFYohhPvMZwAC2spW+9NU7LAGw73N3mfaKbPd9ayxk3gdn3A8G//xn6MDBWMayla1MZCLf8q1fj3ky0QSKQn1lEUFRUp1a+Bf//C3owx7iIaKJ5g7uIJ101rOeoQzVOyz/5LTDhvmw8zVorAQUiD0Txv8FEs/ROzpdlVPOCEZQQgnXcR3/x//pHZLuAkxGAGwHd0oyIvyOJCM+6HZupw99mMUsMsnkG77xu8GAuirPhh9+BwdXg6ZCQAgMvRXGLQBrhM7B6S+HHMYxjjrqeJiHmc98vUPqEYJCIjjcAPV11XqHIoTXSTLio2Yykz704UIu5CzOYhnLmMY0vcPyXaoKOxbC5r9CXZF7W3i6uy7IoFn6xtaDrGAFF3ERKir/4T9cz/V6h9RjRCQOZf/eEpqcqt6hCOF1koz4sKlM5Qd+8Cyw9xZvcR3X6R3WaVdpr6PW2dhiW4jJQpQ1uPtfvLYYfrgXCj4CtREMAZByhXtAaqj/zQhpzz/5J7dyKwEEsIpVnIN/X6o6njUiCbSDOOXXsvBD8qn3cUcGCJ7BGfyCX1BJJXdyp95hnTaV9jr+tP5TnFrLb5MmxcBjYy/tvoQk/0NY/yc4vN19PygRRvwWRvzO76bldsQf+SNP8RRhhLGRjaSSqndIPZKiNeGSwmfCD0ky4gcGMYjd7CaDDO7iLsoo41Ee7fD+uvY8nESts/GERATAqanUOhuJ4jTG6KiF9Q/A7jfAYQMMED8JznwGYsedvtfxMT/n53zABySTzBa2yJTzdihqI6oUPhN+SJIRP5FIIvnkM4xhPMZjlFPOS7x00v1063noSUp/dF+KKV0DqGAOh4zfwtjHwOyfNTE6womTMzmTDWxgLGNZy1qpDnwSBtWOyxSqdxhCeJ38ZvAj4YSzl72MZCQv8zJllPEu77Zo8xqvYcDAzdwMeLnnwRsaq2DPWzD0V2BsZ1Ey1QlbnoVtz0H9Qfe2yAx3AjLgci8E2rtVUcUIRlBMMVdx1QmfM9E6o2bHqUgVVuF/JBnxM1as7GQnE5jAe7zHeZzHSlZiwMArvMJt3EYIIVzLtQQSqHe4p5fLAf+7HA5+DaYgGDLnxDa2fPhhLuxbBmoTGCyQeo37UkxwotdD7o32sIcxjKGGGu7jPhawQO+Qeg2j5gAMOO21mKzS6yb8h4y080MGDPzIj0xjGl/xFaMZzSIWcTu3A1BLLR/zsc5RnmaaBt/8Cg5+Cyiw7e/ubUfsWQRL0mHxQPfMmKAEmPgC3FwP578jiUgHfcM3ZJBBLbW8xmuSiHRSgBFQFKr3b9Y7FCG8SnpG/JQBA8tZznVcx9u8zS/4hecxI0b+xb+4hmt0jPA02/gY7Hnz6P3KrVC8CvLfg9xF4KwFxQiJ50PWs9BnpH6x9lL/4T/cxE2YMLGCFZzP+XqH1OtYA4OodkJd1SH66B2MEF4kyYifu53bWcISXLg821y4WMUq9rMfevClmv11VSza81Obj9c7He6/7Pk/d1n2433+M/f/LVGQcR+Mng8mmcnQFQ/xEI/xGCGEsI51sgRBF4X26UdpaRP2RofeoQjhVZKM+LHNbOZCLkRDO+ExBYW3eItZ/EqHyE5ur62Mv2/7ikaXs802b+1ex/1xVoJXz26jhQLnvQ1pPtQDpIMjvWsJJLCFLUQTrXdIvVZw7BAo2YJTM+odihBeJWNG/FQppZzP+dRRh8qJs2VUVF7jNVytzKTRm93ZxMs7vvUkIhHmQM5NGMQVKaMYF90fs8H9i9xk24V5xWWgtZWwKEdLt4tOc+Ikiyze5m1GMYoCCiQROUUmsxlw4VLameklhA+SnhE/ZcdOJJFUUIHS/Of4pGQve/nTvtcIpl+rz1FUe5h+Id6fhvhjWQE1TXYABoXFclfGuZiNRz/K5Q01fPTNE8wufApDK4nWUSpsewFG/g4Uycs7w4aNkYykkEJmMIMP+RCDfLc5LQyqQwqfCb8jvz38VH/6s6f5z9/4G+dyrqcglZHmLmINvo5/p83neDv3J3ZXH/JGuC2sLc3z/H1m6pijiYijBnb+i+jPz+WXhU9iQEVDaeeZmntGSr7v3oB9TCGF9Kc/hRRyD/fwMR9LInIaKapdkhHhd6RnxM+lkcbdzX9qqWUlK/lUXcoi12IaA+oojtqCKbqCGSFTiQ0M4VBDDWtL8zjYYMOpqfxr5/c8Pm4GJoP3rnFXNtYDEBZgJTkk0r1xw6Ow4WFAg+SLOHzeu8w7YEdTDIyLSuCXA4ZBY2XLm70SXA0QOcxrsfd2a1nLFKbgwMFCFnqmg4vTx6jacRjD9A5DCK+SZER4hBDC5VxOzKERGPdMYV/kJtYN+j/eGvIAVysjOaN5hsT5Sen8beuX5NrKqHI0sKmimHEx3luh1qi4ezscqhOXqmI0GCD5QncyMvohGPsI1TUVaAe/AMBgskBQnPsmumwJS5jFLAwYWMYypjNd75B8klFrBMWI0+FoHkMihO+TvlVxgvXl+1BQ6H94NN84fmC8Mp4LuIAlLEFDw2Qwcmn/EZ72G8r2eTW+/iHuCgx2l5ONFc0DUGPHw4D/517ETlNZc8ylnJQQqdhwqh7nca7hGqxY2cQmSUS6kUlxgaJQV7ZH71CE8BpJRsQJahzuwaEGFIaH9GcZy5jIRK7hGhaxCIC0sBhPe1vzYFJvOSchzfP3xbnr2V1V6r6TNgtq95H/9W/55mAuAAEGIxNiB3g1Pl8zm9k8yIPEEks++WSQoXdIPs1iCQCgpqJA30CE8CJJRsQJLM0DQlU0qhwNWLDwB/4AwNmcDUC5vfaE9t4yJCKeIRHuSy61zkae2bqKxzZ+xj/qInAoFmL2vu6pnTKt71CCA6SruytUVCYzmTd4g2EMo5BCYonVOyyfFxzu/mzb6+t0jkQI75FkRJwgPeLo2IpV+3cBUEklAH2ai1R/eWC3p82QcO+OxTAoCr8eOonUY3pniuuq2Hh4P2vDzybEVUtGzUYmJwzi4n4j2nkm0ZZ66kknnW/4hmlMYytbsSIzPLwhou8I0DSaXCdvK4SvkGREnGBSfBqG5imxK/fn8GnhVj5Xl7sfbArgo4LNfH3QfT3bpBg4K36g12MMMpmZO+I8rh80nuTgSM/2D2OuQUXhFtunXJs6FoPS3tRe0ZpiikkmmVxyuZ3bWc5ymbrrRSZrGKDhQnr0hP+Q2TTiBJGWIC7ul8Gn+7aiAUv3beXrsM0QofDHHz9qUZV1RspIQgL0+cZsMhg5Oz6Ns+PTqGtqpNHlJCjAjKF2EdaDq6GmAMJkvEhnrGc9k5iEHTvP8Axzmat3SH5J0Ry4pNaI8CPydUe06uJ+GUxPHu65bzfVYdAMnkREAWb0H8kFST1jQbTgAAtR1mCsxgCY+IJ745q79A2ql3mf9zmTM2miiY/4SBIRHRnURil8JvyK9IyIVimKwuUpoxgfk8LXB3fznsmOQTMRbQ1hVFQS5yQMIj6ohxZm6pMBoQOh6HNwOsAk3d0n8wzPcC/3Ekgg3/Edoxmtd0h+zaDacZoiT95QCB8hPSOiXYnB4VybNg5rIIQbQ3h83AyuTh3TcxORI8Y8ApoLNvxJ70h6vNu4jXu5lz70IZdcSUR6AINqR1Pku6LwH/JpFx1STz1heCcBuX/dx1Q0njitcXLCIGaljWt1nw1l+/i4cAsV9lpiA0O5csAURgSEQs4/YMJf0DSNTwu38m1JLg2uJlLDopmVNo64wB6eVHUjFZULuZAVrGAQg8gmmyCC9A5LAAGKk0bFgL3qINaIBL3DEaLbSTIiOsSOnSSSvPJa8zKnoTbXCQE4UFfNc9u+ZEx066sH77WV8drO77l8wChGRiWx7lABL+/4lscGzaHPjudg7xK+MI/gywO7uCk9i2hrMJ8UbOH5bV/x8JhLCPDiujo9hR07Z3AGO9nJFKawkpUyY6YHCTC5Z4FVHcwhXpIR4QckGfFDqqbyaeFWfjxUgK3JTrg5kIlxA7goOQOljamwTTQRao/hzzs+52B9NZGWIC7ql8HEuJbTer86sJsVxTlUOxroGxLJNaljGBAa3an4Qs0tB+4tL9pBjDWEweGtF9xatX8Xw6MSmNbXveDdZSmjyKkq4Qvrz5mlvIC2/k+s6v8kF/XLILNPXwBmp2dx7w8fkF1exLjYlE7F19uVUMJIRlJGGXOYw2u8pndI4jhBwWEctkND7WG9QxHCK+SrkB9aXpTD1wdzuTZtLA+PuZgrUzL5ojiHr44pZHY8VVPhYALpEXE8OHo65yel89buH9l++ICnzU9lhbyXt5GL+2XwwBnT6RscwfPbvsLm6Hq5eKfq4sdDBUyMS20zUcqrKWdIRHyLbcMiE9hbb4OkqVC9B7XhEEOPaRNoMjMgNJq8mvIux9YbbWELAxlIGWU8wROSiPRQobHpADik8pnwE5KM+KG8mjIy+yQxIiqJaGsIY2L6MSwigfyailbb27GjKRohSjD/b+BoEoLCmZKYzujoZFY2V2gFWLl/J2fHp3JWfCqJweFclzYes8HEmtK9XY41u6KYBqeDiXFt1wuxOeyEHVfrJCzASrXDDhNfQENhUtWXhB3X4xJmbm7jJ5aylNGMppFGlrCEeczTOyTRhuCYFNA0nJp0Xgv/IMmIHxoYGsPOqlJK620AFNUeJtdWRkZU69emCykEINbacrDnsMgE8mzungWn6mJfTWWL3geDojAkIt7Tpiu+L9nL8KgEIixdHFgZMYja8OFMPrwSnPVdjqO3e5EXmcEMTJhYwxqu5mq9QxInoWhOXAaL3mEI4RWSdvuhC5OHYXc1MX/DUhRFQdM0LksZ1ebqtvvYB0C0oU+L7WFmK3ZXEw6Xk3qnAxXthPEeYWYrJQ22LsVZYa8jp6qUW4dNarddmNl6wsrB7rEw7licZzxI1OprKP/pYZj8wtE2DjvJIRFdiq03uZu7eZ7niSCCbLLpT3+9QxIdoGhS+Ez4D+kZ8UMbygpZd6iAOekTefCM6dw0OIsVxTmsLc1rtX0RRQBEqX1afby7rCndS2iAhRFRie22Gxgazc6qkhbbcg6XMLB54GzkoKvZEzQEU/67nscbnE3k15R72vgiFZVLuITneZ4BDKCIIklEehGDakdVJBkR/kGSET/0fn4205KHMS42haTgCM6MG8D5SUP4vGhHq+0PchAAa2NEi+02hx2rMQCz0URIgAUDCjXHjcGwOeyEd2HtGlXTWFOaR1bcQIxKy4/p67vW8GF+tuf++UnpbD98kBXFOZTUV/Np4RYKays5N3Ew4K4mW9P3UiIcpeze9BL766p4ffdaIiyBZEYndzq23sCBg0wyWcYyJjKRXHIJIUTvsEQnGFU7miFA7zCE8ApJRvyQQ3V6VuU9wqAoaMfU9jhWCe5eh8OVLbfnVJUwMMzds2AyGOkXGkVOVanncVXT2HlMm87YWVVCZWM9Z8WduCJwZWM91Y4Gz/3UsBh+mX4W35bk8tjGz9lYXsRtwyaRFBzhaXPGWY9RZwyldtdbPLFpOY2uJu4aPsUna4yUU05/+rOVrVzHdXzP91JDpBcyag7AgNPuv2OdhP+QMSN+aGRUEp8VbSPKGkRCUDhFtYdZWbyTifFHT/wf5mdT5ahndvpEyigDDWrrNd7P38RZcQPZWVXKhrJ9/CZjsmefqUlDeGPXWlJCo0gJ7cOq/btwqM4TapF0xLDIBP4xaVarj/1u5NQTto2J6ceYmNaLogEoARaC+57H6MKPGT3kZYjO7HRMvUEOOYxjHHXU8TAPM5/5eockuijAqIKiUH1wO30GtF55WAhfIcmIH7omdSwfF27h7dyfqGlqJNwcyKSENC7pl+FpU+1ooLLR/Y2sggoUReHO4VN4N28jX+7fRYQliOsHT2B45NHxHONi+lPbZOeTwi3YHHb6hkRy1/AphJkDvf4eWzXx71D4sXs13xnf6B3NabeCFVzERaiovMVb/IJf6B2SOAUWayC4oO7wAfq0PbNdCJ+gaJrWet98D2Kz2QgPD6e6upqwMP9dS0Qv4xjHZjbjwKF3KKfu3ZFweBvceBgs4XpHc9r8k39yK7cSQAArWME5nKN3SOIUHd63kbwyjTBHLoOyZuodjhBd0tHzt1xIFidVTTVmzHqHcXpM+AugwY/36h3JafNH/siv+TWhhLKDHZKI+IjQ+GGgaTSp8mta+D75lIuTqqWWQHrIpZZT1W86WKNhzyJQVb2jOWU/5+c8xVMkk0whhaSSqndI4jQxma2AikuRwmfC90kyIk6qgQaCCdY7jNMn425wNUDOy3pH0mVOnIxlLB/wAWMZSx55RBChd1jiNDOoDil8JvyCJCPipOzYCSVU7zBOn8z7wGCGTQv0jqRLqqhiAAPYwAau4ip+4idMMhbdJymqXZIR4RckGREn1UQT4fjOYE8MJki5HOr3Q+lavaPplD3soR/9KKaY+7iPd3n35DuJXsuo2lEVHxmvJUQ7JBkRJ+XCRSSReodxek38u/v/a+7RN45O+JqvySCDWmp5jddYQO/s2REdZ9TsoJhwOnxgJpsQ7ZBkRLSrAXel02h8bA2XoHiIHgNl66ChTO9oTupN3mQKU9DQWMEK5jBH75CEF5gUFygK9qp9eociRLeSZES0q5BCAOKJ1zmSbnDms4AGa+fqHUm7HuIhbuImgglmM5s5n/P1Dkl4idnsHgtkK83VORIhupckI6JdPp2MJJ4DgfGQ926PneZ7HdfxGI+RQAL55DOUoXqHJLwoKNS9UnZDnU3nSIToXl1KRhYuXEhKSgpWq5UJEyawbt26Ntu++uqrTJo0icjISCIjI5k6dWq77UXPUkwxAEkk6RxJNxn1e1AbYevTekfSghMnWWTxNm8zilEUUOB7l8rESYUljQCgqWfmykKcNp1ORpYsWcLcuXOZP38+GzduZNSoUUybNo1Dhw612n716tVce+21fPXVV6xdu5bk5GQuuOAC9u/ff8rBi+53kIMAJJOscyTdJOO3YLTClmf1jsTDho000viBH5jBDDay0Xcq4IpOsYb0AU3FSYDeoQjRrTqdjDz77LPccsstzJ49m2HDhvHKK68QFBTEv//971bbL1q0iNtvv53MzEyGDBnCa6+9hqqqrFq16pSDF92vhBIA+tNf50i6icEAA6+GhlLY/6Xe0VBIIf3pTyGF3MM9fMzHGORqql9TtCZURWqNCN/Wqd9yDoeDDRs2MHXq0SXcDQYDU6dOZe3ajtVrqK+vp6mpiaioqDbbNDY2YrPZWtyEPspwzzSJJVbnSLpR1t8ABX74na5hrGUt6aRTTTULWciz9JzeGqEfRW3EJYXPhI/rVDJSXl6Oy+UiLi6uxfa4uDhKSko69Bx//OMfSUxMbJHQHG/BggWEh4d7bsnJPnqJoBeooAIFxbe/nVujIPZMqMiGWn0uHy5hCWdzNi5cLGMZt3O7LnGInseo2tEMsj6N8G1ePcM8+eSTLF68mA8//BCrte1Mf968eVRXV3tuRUVFXoxSHKuKKv8oNX6kCNra33r9pR/nca7hGqxY2cQmpjPd6zGInsug2dEUGTMifFunzjLR0dEYjUZKS0tbbC8tLSU+vv2pn08//TRPPvkkK1euZOTIke22tVgsWCzyTaAnsGHDgh/8LGLHQXAyFH4MqtNdMt4LZjObN3iDWGLZylbfvhwmusREE42KAbutHGuYzKgSvqlTPSNms5kxY8a0GHx6ZDBqVlZWm/s99dRTPPbYYyxfvpyxY8d2PVrhdbXUYsVPrlef8QCoTbDxz93+Uioqk5nMG7zBMIZRSKEkIqJVAc2/pW0l2/QNRIhu1OnLNHPnzuXVV1/lzTffJCcnh9tuu426ujpmz54NwA033MC8efM87f/yl7/wpz/9iX//+9+kpKRQUlJCSUkJtbW1p+9diG5TTz3BBOsdhncMuQVMQbD9xW59mXrqSSedb/iGaUxjK1v9J+ETnWYNcq+YXW+r0DkSIbpPp5ORmTNn8vTTT/PQQw+RmZlJdnY2y5cv9wxq3bdvHwcPHvS0f/nll3E4HFx11VUkJCR4bk8/3bOKTInWNdJIGGF6h+EdBgOkXQ+NFbBvWbe8RDHFJJNMLrnczu0sZ7lvDw4Wpyw8fhAADodT50iE6D6Kpmma3kGcjM1mIzw8nOrqasLC/OTE2EOYMJFFFt/yrd6heIfDBm9EQuQQ+H/bPZsr7XXUOhs990NMFqKsnesxWs96JjEJO3ae4Rnm0rPXxBE9g9PhYPOWLQQ2FjDsrKv0DkeITuno+dsPpkmIU+HCRRRt14TxOeYwSDgHDq4GWwGEpXC4qpCvV8/jgDmBLaFjADApBh4be2mHE5L3eZ+ZzATgIz7iMi7rpjcgfI3JbAbNiUsKnwkfJv3Dok311APQhz46R+JlE593/3/1jfD1HCLeG8QVh95h8uGVniZOTW3RU9KeZ3iGq7gKM2bWsU4SEdFpBs0hhc+ET5OeEdGmAgoAiCOu/Ya+RHVBzV73ejUl30DpGhTNiYpCgzGo0093K7fyD/5BH/qwhS0kktgNQQtfZ1DtqIbOf/6E6C0kGRFt2sc+AOJpv4aMT9BU2Pp32Po3qCvC02mouQcNqhho6MTJQEVlGtNYyUoGMYhssglCTiaiawyqHacpQu8whOg2koyINu3HXRo9iSSdI/GCqp3ww7EDSk9cs91uCOzQU9mxcwZnsJOdnMu5rGKVzJgRp8SoNQIGnA47JrP3LtecjoHbQnSEJCOiTUeSkWT8YG2gyGFw7n/g65vdvSStJCMNHUhGSihhJCMpo4w5zOE1XuuGYH2HnOw6JsCg0qAo1JTsILLfaK+8ZqW9jj+t/xSndvTfQmcHbgvRUZKMiDaV4i77P4ABOkfiJYOvh7CB8MWl7im+msvzkAEVu7H9ZGQLW8gii3rqeYInmMe8dtv7OznZdZzFYgUNaiuLvZaM1DobW/xs4OjA7Sh/KYQovEb6jkWbyigDIBo/Wg8j/iy4ciOEpYFi9Gw2oLV7mWYpSxnNaOzYWcISSUQ6oL2TnWgpONI98LnR3qBzJEJ0D0lGRJsqqURB8b/xDqEpcMU6SDofDcWz+fgBrDVN7pPmC7zADGZgwsQa1nA1V3szWuEHwhOGg6bR5PKzf4vCb8gnW7SpiioC8NOly81hNEz9iOz4KzybHMf0lAC8sv0bZtXfzF3cRTjh7GIXE5jg7UiFHzBZgwAVp2LWOxQhuoUkI6JNNmyY8c9ffqqm8vLONbwS+XNWR5wHwABHMVEW97VyFZVPhv6Fd4JeJ8nVjyKK6E9/PUMWPk5Rm1Cl8JnwUTKAVbSphhoC6dh0Vl+zsbyIXdXuAbyfJN/GaGM9l7CPS8dfxkH7YcYylgPWPOKqBzEn9xmCRwdzzBUdIU47g2aXZET4LOkZEW1qoMFvC3V9fXCP5++z07MIG3MfyqG12A99y0zrZRyw5DGqYgqXbXmYkvoa9trK9AtW+AWDakdTLF57vV6whqrwIdIzItrUSCNh+OYqyc/zPF/yJSOP+ZNKKkaMqJrKnurmmUTWYDIiE9EiLqYxKJpta39GTKbGF6Z59C+J49O6HVSbItlTkU9aeKzO76oH0DTY/QYknAthbU8J32sr48OCza0+tr+2in4hfrQ4YwcZ1UaalO7/la1pGuvKClhauLXVxwtqKuTnI047SUZEm5poIpxwvcPoFutYx8d8zDKW4cRd8t2ChaEMZZSWye5EF6ENMdSHBHKH8gVLlaUsjC7n0n3w/hcACwBIP/KEeUf+ooBiAoMJjGb3GjfGQAgIhoBQCAgDSziYo8AaBdZosMZCUBwEJkBwIpgjwNBLOy1r8t2F4wwBMPJ3kHk/mENbNFlbmsd/dv+ISuvfvN/c8wOKQeHMWD+pb9NBJsUJikJdeSHB0V0cn1S8AtbNg4y7IG2W+3N6DE3T+KAgm/8V57T5FItyfyLAYCQrbmDXYhCiFZKMiDa5cBGFb34DuoRLWMQiTyIC7p6gbLLZrGxGG6h5xoAM0AZyhXIF1vPOpcjVj2QtCRrK2LjrY/IO7SDYWcOI4ED6mjRwVIGjBppqwFkPrgZwHIaGUlCbmgupdaT7W3HXOTGYwGAGowVMgWAKAlMImMPAHA6WSLBEgSUagmIhMA4C491JjTXW+0mNo9r9f7UJsp+CnFdhwlMw+EYwGMmtPsSbu39Eaz4GYQEWBoXHogG7qw5R62xEA97c9QMx1hBSw2K8G38P5XK5MJrcg8lLDhQQ1GSmqakJp9NJUlISFksHL99UbIbyDe4VqdfPh7EPQ9p1nqTkh0P5LRKR5OAI0sJicGoq2yoPcNjhrnPyn90/khgUQf9Q3/z9ILxPkhHRqnrqAYjBN08G05iGAQNqK2XfNUUDDQyqkbP3zOa3lju4IiWTYycWHTaG8X/KUOr6DERBYcL4GWDpRFVKhw3q9kP9QXei0nAI7OVgr3AnL41V0GRzJzVNdc1Jjc3dRm1yry7cSuytUozu3hpjABiOS2oCQpt7aiLcSY21D1hjIDAWguIhKNHdY2Pq4Kwqh+2YOyo0VsA3c2DbczDxBT6vVD2JyDnxaVyTOhZjc8LkVF0s3ruBb0tyUdFYXrSDO4ZP7uAB9T0Oh4Pc3FwaGxtRVRWM7mUZqppCqDpwwNMuJiam48kIuD8PmgtqC2H1Tc1JySNoqbP4omiHp9m1qWM5N3Gw576qqbyTu55vmn8+K/bn8MshZ53y+xQCJBkRbcgnH4BYfG8cRD75/I2/EUAAjZxY7dOIkWgthskb7yWiIYHl7OBQfQ2TEtIIM1vJOVzC/4pzqGuuFHpGdF/PlN8OM4e5b5FDT+3NOOuh7mBzUlPSnNSUQUO5O6lxVLkThCNJjbPefWs83NxT42xei6cDFEPzJagAd0+N0dqc2IRAQIi7p6aptvV9D2+HpedyduhYSmKvQwsdwDVpYzEqR3tuTAYj16aObf4GXs/WygNUNdYTYfHPQdQGg+FoItIGo8lESEhIF1+huYeudh+svgnnugdJCb+I0vCzGRge3yIRATAoBq5OHcPG8iJqnY1sLC+iwekgsKOJqhDtkGREtGof+wBIIEHnSE6dispSlvIKr7CGNVTjvpRgauXjb8TIAAbwleErtsfZ+KAgG4CNFUVsrCg6oX2MNYRrU8d2a/ztMgVBeKr7dipUJ9SXNCc1B6H+kDuxaayAxkp38uKobk5qao9egmqoAbXYvb+m0uYlqOaE54ya9WTWrKchIApjcYp7DE1DqTvBiUjHWLWLh+pKaHQ1ARBcMLdFWf62L3G1c+nrpLNCtDbuduG1TmMsJiA54mcU9v19G01dRBS9ibbpLRTPvPKTPL/L3mLNpWP3MdUXc1P9P7nh4KvUhA6Fgkj3z91+CGLGw/RlBBiMZEQl8sOhfFyaSrm9juQQSUbEqZNkRLTqyIq9iSTqHEnXVFHFi7zIf/kvOeR4xobEEcclXMLd3E0wwQxnuGcfI0YyyGAFK4ghhr7JEBxg5sP8za2ul5IRmcgNgycQZvaBWiwGE4T0dd9OxbaFsOZOWjspurcoVBkjqIg9j7SwaPelqLr94GpsTnZqMboaCWg+YSoumntk2ivi0pECL621UVp/WDnyn3aet814Oru9veeCPrVrqKjbSm3QsOOSMkAxYq36CtUUgqHF2KB23quj2p2QtEPFQGB9IdTudCeR5gj3JbtmTvWYBSTb/bkI0XGSjIhWHcB9Tbof/XSOpOPWs57neI5VrKKEEsCdYAxjGFdxFb/hNy0G5Gpo9KUvxRRjwEAWWSxjWYvpzGfHpzEhdgAby/ex11aOU3URYQlifEwK8UG+Oe35lDhrm8ckHBkYbABUsEZTn/5r5tcnUWMKJ9YawiNjLz3hZKZqKo+u/5Ryex0AC8Zd5tcr+CpASmMj27dvb1H3Q9U0Dql2/tl/Hg+ccWHrU22LvoDNT8EFH7gvoQFseQZ+/GPL3pHmMSSqKRScdZhwobrq0RImoUx8HvqM8jRtcDrYetj9u8FiMBFt7eolIiFakmREAPA93/MszxJOOJFE8h3fAe4TfDnlRBJJP/r1qJ4SBw7+w394kzfZwAYacI/0DyOM6Uzn1/yaS7m0zYX+FBQu53Je5EWmM513ebfVirMBBiMTYgcwQaaanpzD5j7RKSZ3QtJnpHuK78CrCTaaSdyyil3VpRyy1/JRwWYuTxnlSUhUTeOD/M2eRGRYRLxfJyJHWCwWEhMT2b9/v2ebAuxyVre904Gv4YsZoDog730YcnMrjZoTxeYkx+isodKSyJfhk1kVeSFT+43g8qgRHOmPaXA28fqutTS63InmhNgULEY5hYjTQz5JAoCd7OQDPsCAASNGz2WN27nd0yaAACqpJAT9vg3tYx9/4298wifkk4+GhoJCf/pzCZfwW35LKh0fP3Ev99Kf/tzN3f67KODpZDS7LzsMuAIyfgtxWS0uQ1yYPMxTZv+L4h1srihmdHQyGrCxfB+lDTWA+2Q7LXmY9+PvoeLi4igpP4TL3giKARWNPFdN640P/QifT3eP48HgLkJ3JBlpqj+mV6R5YKy1D6ReA2MeYn99Iyu2fw3A/4pzWHeogJFRSThUF9kVxdibx/JYDCamJg3ptvcr/I+i9YKavzabjfDwcKqrqwkLk67x7lBLLfHEU0ddq48bMDCd6SxlqVfjUlH5gi94iZf4ju+oogoAK1YyyeQGbuBmbsaC98pki3a4Gt2zdqxt15/4cv8uluRtaPdprkkdy5TjZnP4sx2HD/Jl/nay1AgA8pxVrGw6BMAtQ85ibExzEbSKzfDJJHDWtZwldcZDkLcYqne77xutkHwxjH0EooZzrK8O7GbJ3vVtDoW1GEzcOmwSwyJ7/+B20f06ev6WnhEBQAgh3MzNvMRLuDh+tL07GXmO57wSiw0bL/ESi1nMdrZ7emliiOEaruFO7mQiE0/pNVRN5dPCrfx4qABbk51wcyAT4wZwUXIGSjuD8nZVlfJu3kYO1lcTaQnion4ZTDyuEuVXB3azojiHakcDfUMiuSZ1DANCo08p3l7DaHHf2nFeUjpxQaF8vm8He2yHWjw2ODyW6cnD5UR3jP8V5/B+/iYAxpscGM1x0HjIs7LY67vWYjGaGGGogaVT3DOdjp+uvelR96Wz+LPdVXH7TW/z9aYkDiY5OIL/7d/Jlor9nrowAQYj42P6c0HfocQH+WZlZqEfSUaExx3cwQu8cMJ2Awbu5V7SSOu2184mm+d4jv/xPw5yEHAPPk0nnau4iju5k2hO3wl9eVEOXx/MZXb6mSQEhVNYU8mbe34g0GjmvKT0Vvcpt9fy4vbVnJMwiDlDJrKzqoS3dv9IuNnK8Ej3WJqfygp5L28js9LGMSA0mlUHdvL8tq94ZMylhJllxdUjhkcmMjwykdJ6GyUN7kJp8UFhxAVKz+exNpUXeRIRgPKGvcSZ4+jHYazGWOyuJpyaynub32dY0Z8xOqpbrxsTGAez9oPReOJjrUgLjyUtPBabw05FYy0KCnGBYQSa5FKm6B6SjAiPdNI5j/P4mq89vSMKCtFE8wAPnNbXcuJkEYv4N/9mPes9FV9DCeUCLuAWbuFKrmxz8OmpyqspI7NPEiOikgCItobwU1kh+TUVbe7z9cE9RFtD+H8DRwOQEBRObnUZK/fv8iQjK/fv5Oz4VM6Kd49buS5tPNsqD7CmdC8XJg9v87n9VVxQGHEyK6lVmqaxbN82z/2L+2VwTlAQBbs3ExMYwVNjruCNXWs5VPwNvy98DIN24vRzj4ZSOLwVojM7FUOY2SpJtPAKSUZEC7Mdv+JL85ee+xoajzmeJMR86oNWiynm7/ydj/mYvexFRUVBIZlkLuIi7uEeBuOdcQIDQ2P4riSX0nobcUFhFNUeJtdWxv8beEab++TZyhkSEd9i27DIBP6btxFw11/YV1PJ9L5HB14aFIUhEfHk2cq7540In1VUd5iiusMA9AuJ5NJ+I9BUlUZLFQ5DOZb9K5hz4E0MBUsw4K7jonnKnx0/4sMAe97qdDIihLdIMiI8Ku11fL/eRdC4SOoth0GD2Jo0srdYqRxb16VplitYwUIW8g3fcBj3L1YLFsYyll/wC27hFqx4/5vXhcnDsLuamL9hKYqioGkal6WManf6rq3JfsK3xDCzFburCYfLSb3TgYpGaCttjlyKEKKj9tdVef4+LiYFRVFQjEYUzUlTbRmsvwFTxFA2J17L3iYXTsXMRZEhhDSWgC0PaovcSwIAoELR55D1jC7vRYiTkWREAHC4sZ63c39C1SDjwAWsG7AEgLNzZ+PSNMrsNR1KRmqp5RVe4R3eYStbacI9FTCaaM/Yj3M4p1vfS0dsKCtk3aEC5qRPJDE4gqLaw/w3bwMR5kBZGv0U3L/uYyoaT5yRNTlhELPSxrW6z4ayfXxcuIUKey2xgaFcOSDTc/kM3JcrPi3cyrcluTS4mkgNi2ZW2ji/Gl9ybHE4S1MJAQYnXLkR+mSyftda1pUVAHDW6IsICY44uqOz3p2U1O4Da4wM3BY9liQjgkMNNTyzZSVVzcuDp5eey7qUJYTYY4iuSwHgrd3r+EPmz1otfb6NbTzHcyxnuaeMvAEDgxnMlVzJ3dzd4xbcez8/m2nJwxgXmwJAUnAEFY11fF60o81kJCzAis3RspS2zWHHagzAbDRhUBQMKNS00iY8wD+uu8/LnIZ6zCWCA3XVPLftS8ZEt17Jd6+tjNd2fs/lA0YxMiqJdYcKeHnHtzxwxoUkNZ9UvyjO4csDu7gpPYtoazCfFGzh+W1f8fCYSwgwdGxAZm8Uf0yytbF8n6eux/CJl3u2O1xOtjVXRDUpBvocv2CjKQgi0t03YPm+7TJwW/RI3TM6UPQaLk3lpR3feBIRi8FEVng6KHBJ5Q2YmldVLWus5bWda9z74GIRiziP8wghhBGM4F/8i2qqOZ/zeYd3aKKJHHJ4nMd7XCIC4FCdGI5bw8OgKJ5pjK0ZGBbNzqqSFttyqkoYGOb+9mcyGOkXGkVOVanncVXT2HlMG18XarYSbg703LZU7ifGGsLg8NY/A6v272J4VALT+g4jISicy1JG0S8kktUH3PUwNE1j1f6dXNQvg8w+fekbHMns9CyqGhvILj9x4UJfkhLah8TmKbR7beWs3L+zRUl4l6rydu5P1DsdAIyN6Y/1JLNdjh24HW0NYUxMP4ZFJHR44HZCUDhTEtMZHZ3Myv27PG2OHbidGBzOdWnjMRtMrCndeyqHQPgRSUb83NbKAxysd5eVjg8M48/jZnDlUPcAzGuSJvHwmEsINwdSb6rirci/M9CVhhkzv+AXfMVXRBLJLdzCNrZRQw0rWck1XNNts2BOl5FRSXxWtI2tlfspt9eyqbyIlcU7yexzdKG4D/OzeX3XGs/9yQmDKLfX8n7+Jkrqq1l9YDcbyvYx9ZhvlFOThvBdSS5rS/M4WF/N27k/4VCdJ3Rp+wOn6uLHQwVMjEtt8xJAXk3rg4LzatwDfsvtddia7Aw9pk2gycyA0GhPG1+lKArTj5mB9W7eRh7ftJxPC7fwfv4mHlj/CWsP5QPuXpGf9T15RdSBoTHsrCqltN49hunIwO2MqLbrurQ1cPvIoOwjA7eP/RnJwG3RWXKZxs+tKc3z/P2qgWcQZrZygAIA6qnnr4GP8o9xr2JTqkABo2biDM5gFrO4lVsJIkifwE/RNalj+bhwC2/n/kRNUyPh5kAmJaRxSb8MT5tqRwOVjfWe+9HWEH4z/FzezdvIl/t3EWEJ4vrBEzxd1QDjYvpT22Tnk8It2Bx2+oZEctfwKb6xsm8nZVcU0+B0MDGunUHBDjthx13CCguwUt18qcvW1LzeUCuDgqsd7a8+6wvGx6ZwsL6az4q2Ay1n2BxhUBRmp2fRNzjypM8nA7dFTyXJiJ8ra14LxKQYPCfVI4vkzWIWJkyEK+GkVIxl2IGfcYEylbtHnKdbvKeL1RTAzNQxzEwd02abm9KzTtiWHhHHg6Pbrl4JMCUxnSmJrV9/9yffl+xleFQCEZbembD2FJeljKJvcCT/259DwTGXUxQgIyqR6cnDSQ2L6dBzycBt0VNJMuLnjl0x1aWpGBQjgxjEYAZzP/dzJVfS1GhgXs7H7vaRbY+4F+KICnsdOVWl3DpsUrvtwsxWbE3HDfhtshPe/C07LMDdo2RzuGd+eNo47CSHRJzeoHuwMTH9GBPTjwN1VZTZazEoCknBEUQdP2D1JGTgtuipevaFfdHtjnTtqmj8VFYIwGQms4td3MiNhBLKD83XpQH6hpy8K1iINaV7CQ2wMCIqsd12A0NbGRR8uISBzVNCo63BhAVYW7RpcDaRX1PuaeNPEoMjGNWnLyOikjqdiIAM3BY9lyQjfu6chKPrzbyXt+mEAWfbKg94rlcrwNlx3bc+jfANqqaxpjSPrLiBGJWWv2Je37WGD/OzPffPT0pn++GDrCjOoaS+mk8Lt1BYW8m5zSv2KorC+UlD+KxoG5sritlfV8Xru9cSYQkkMzrZm2/LJ8jAbdFTyWUaPzcwNJphkQnsOHyQOmcjf9n8P1LDYkgMCqewtoJ9tUcHy2XFDSQm8NTLwgvftrOqhMrGes5q5URU2VjvKVgOkBoWwy/Tz+Ljws18VLCZ2MBQbhs2yVNjBGBa36E4XE7+b8866p0O0sJjuGv4FJ+uMdJdZOC26KkU7diJ6z2UzWYjPDyc6upqwsL8p+qitzQ4HTy/bXW7UyVHRCXy66GT5AQgxGn0aeEWlh6zGB5AXGAYj469pM19pGKt6E06ev6WnhFBoMnM3JHn8+3BXFYf3EPpMdPxkoMjOTdxMFlxA07ochdCnLrEoHB+e8wMNWM7ZdmlYq3wVZKMCAACDEbOS0pnSuJgyu11NLgchJgsRFqC2l2zQghxagyK0mKmUHuOrVgL7mm/OVUlrD6wm+sGjT+hYi3A7PQs7v3hA7LLizyzaIToaSQZES0oiiLjQoTwokMNNfzhxw8JMBgYGBrNFSmZbS5KmVdT7lmj5ohhkQlsrigGTl6xVpIR0VNJv7sQQuhkQGg0Nw3O4q6Mc5mVNo5yex1/3bICu7Op1fZSsVb4KklGhBBCJxlRiYyJ6Uff4EiGRyZyZ8a51DubWF++T+/QhPAquUzj4z4v2s6m8iJKGmyYDUYGhsVwZUom8UHtj6yXEftCeF+QyUxcYKhnmYbjScVa4aukZ8TH7a4+xLmJg7lv1AXcnXEeLlXl79u+pNHlbHOfIyP2z4ofyIOjp5PZpy8v7/iW/XVVnjZHRuxfN2g892VegMVg4vltX9GkurzwroTwTXZXE2X22jYHtErFWuGrJBnxcXdnTGFi3EASgyNIDonkpsFnUtlYT2FtZZv7HDtiPyEonMtSRtEvJJLVB3YDnDBiv29wJLPTs6hqbCC7vMhbb02IXu+9vI3sriql3F7LXlsZr+z4FgMK42L6A1KxVvgPuUzjZxpc7oFxwSZzm21kxL4Q3nG4sZ7Xdq2hrqmRkAALaWEx3Jd5AaHNl12kYq3wF5KM+BFV0/hv3gZSw2Ja/PI6nozYF8I7bhl6druP/27k1BO2HVnBty2KojAjZSQzUkaecnxCeItcpvEj7+T+xIG6am4ZcpbeoQghhBAekoz4iXdyf2Jr5QHmjjyfSEtQu207M2K/RRvH0TZCCCFER0ky4uM0TeOd3J/IrijmnpHnEW09eXVVGbEvhBDCmyQZ8XHv7F3Pj4cKmJM+EasxgGpHA9WOBhzHTO2VEftCCCH0JANYfdzXB/cA8MzWVS223zj4TCbGDQRkxL4QQgh9KZqmaXoHcTI2m43w8HCqq6sJC5MKn0IIIURv0NHzd5cu0yxcuJCUlBSsVisTJkxg3bp17bZ/9913GTJkCFarlREjRvDZZ5915WWFEEII4YM6nYwsWbKEuXPnMn/+fDZu3MioUaOYNm0ahw4darX9mjVruPbaa5kzZw6bNm3i8ssv5/LLL2fbtm2nHLwQQggher9OX6aZMGEC48aN48UXXwRAVVWSk5O58847ue+++05oP3PmTOrq6li6dKln25lnnklmZiavvPJKh15TLtMIIYQQvU+3XKZxOBxs2LCBqVOPVgU0GAxMnTqVtWvXtrrP2rVrW7QHmDZtWpvtARobG7HZbC1uQgghhPBNnUpGysvLcblcxMXFtdgeFxdHSUlJq/uUlJR0qj3AggULCA8P99ySk2W6qBBCCOGremSdkXnz5lFdXe25FRXJSrBCCCGEr+pUnZHo6GiMRiOlpaUttpeWlhIfH9/qPvHx8Z1qD2CxWLBYLJ0JTQghhBC9VKd6RsxmM2PGjGHVqqMFtFRVZdWqVWRlZbW6T1ZWVov2ACtWrGizvRBCCCH8S6crsM6dO5cbb7yRsWPHMn78eJ577jnq6uqYPXs2ADfccANJSUksWLAAgLvvvpvJkyfzzDPPcPHFF7N48WLWr1/PP//5z9P7ToQQQgjRK3U6GZk5cyZlZWU89NBDlJSUkJmZyfLlyz2DVPft24fBcLTDZeLEibz99ts8+OCD3H///QwaNIiPPvqIjIyM0/cuhBBCCNFrSTl4IYQQQnSLbi0HL4QQQghxukgyIoQQQghdSTIihBBCCF1JMiKEEEIIXUkyIoQQQghdSTIihBBCCF1JMiKEEEIIXUkyIoQQQghdSTIihBBCCF11uhy8Ho4UibXZbDpHIoQQQoiOOnLePlmx916RjNTU1ACQnJyscyRCCCGE6KyamhrCw8PbfLxXrE2jqioHDhwgNDQURVFO2/PabDaSk5MpKiqSNW+6kRxn75Fj7R1ynL1DjrN3dOdx1jSNmpoaEhMTWyyie7xe0TNiMBjo27dvtz1/WFiYfNC9QI6z98ix9g45zt4hx9k7uus4t9cjcoQMYBVCCCGEriQZEUIIIYSu/DoZsVgszJ8/H4vFoncoPk2Os/fIsfYOOc7eIcfZO3rCce4VA1iFEEII4bv8umdECCGEEPqTZEQIIYQQupJkRAghhBC6kmRECCGEELry+WRk4cKFpKSkYLVamTBhAuvWrWu3/bvvvsuQIUOwWq2MGDGCzz77zEuR9m6dOc6vvvoqkyZNIjIyksjISKZOnXrSn4s4qrOf6SMWL16Moihcfvnl3Rugj+jsca6qquKOO+4gISEBi8XC4MGD5fdHB3T2OD/33HOkp6cTGBhIcnIy99xzD3a73UvR9k7ffPMNl156KYmJiSiKwkcffXTSfVavXs3o0aOxWCykpaXxxhtvdG+Qmg9bvHixZjabtX//+9/a9u3btVtuuUWLiIjQSktLW23//fffa0ajUXvqqae0HTt2aA8++KAWEBCgbd261cuR9y6dPc6zZs3SFi5cqG3atEnLycnRbrrpJi08PFwrLi72cuS9T2eP9RH5+flaUlKSNmnSJO2yyy7zTrC9WGePc2NjozZ27Fjtoosu0r777jstPz9fW716tZadne3lyHuXzh7nRYsWaRaLRVu0aJGWn5+vffHFF1pCQoJ2zz33eDny3uWzzz7THnjgAe2DDz7QAO3DDz9st31eXp4WFBSkzZ07V9uxY4f2wgsvaEajUVu+fHm3xejTycj48eO1O+64w3Pf5XJpiYmJ2oIFC1ptf/XVV2sXX3xxi20TJkzQfv3rX3drnL1dZ4/z8ZxOpxYaGqq9+eab3RWiz+jKsXY6ndrEiRO11157TbvxxhslGemAzh7nl19+WRs4cKDmcDi8FaJP6OxxvuOOO7Tzzjuvxba5c+dqZ511VrfG6Us6koz84Q9/0IYPH95i28yZM7Vp06Z1W1w+e5nG4XCwYcMGpk6d6tlmMBiYOnUqa9eubXWftWvXtmgPMG3atDbbi64d5+PV19fT1NREVFRUd4XpE7p6rB999FFiY2OZM2eON8Ls9bpynD/55BOysrK44447iIuLIyMjgyeeeAKXy+WtsHudrhzniRMnsmHDBs+lnLy8PD777DMuuugir8TsL/Q4F/aKhfK6ory8HJfLRVxcXIvtcXFx7Ny5s9V9SkpKWm1fUlLSbXH2dl05zsf74x//SGJi4gkfftFSV471d999x7/+9S+ys7O9EKFv6MpxzsvL48svv+S6667js88+Izc3l9tvv52mpibmz5/vjbB7na4c51mzZlFeXs7ZZ5+Npmk4nU5uvfVW7r//fm+E7DfaOhfabDYaGhoIDAw87a/psz0jond48sknWbx4MR9++CFWq1XvcHxKTU0N119/Pa+++irR0dF6h+PTVFUlNjaWf/7zn4wZM4aZM2fywAMP8Morr+gdmk9ZvXo1TzzxBC+99BIbN27kgw8+YNmyZTz22GN6hyZOkc/2jERHR2M0GiktLW2xvbS0lPj4+Fb3iY+P71R70bXjfMTTTz/Nk08+ycqVKxk5cmR3hukTOnus9+7dS0FBAZdeeqlnm6qqAJhMJnbt2kVqamr3Bt0LdeUznZCQQEBAAEaj0bNt6NChlJSU4HA4MJvN3Rpzb9SV4/ynP/2J66+/nl/+8pcAjBgxgrq6On71q1/xwAMPYDDI9+vToa1zYVhYWLf0ioAP94yYzWbGjBnDqlWrPNtUVWXVqlVkZWW1uk9WVlaL9gArVqxos73o2nEGeOqpp3jsscdYvnw5Y8eO9UaovV5nj/WQIUPYunUr2dnZntuMGTOYMmUK2dnZJCcnezP8XqMrn+mzzjqL3NxcT7IHsHv3bhISEiQRaUNXjnN9ff0JCceRBFCTZdZOG13Ohd02NLYHWLx4sWaxWLQ33nhD27Fjh/arX/1Ki4iI0EpKSjRN07Trr79eu++++zztv//+e81kMmlPP/20lpOTo82fP1+m9nZAZ4/zk08+qZnNZu29997TDh486LnV1NTo9RZ6jc4e6+PJbJqO6exx3rdvnxYaGqr95je/0Xbt2qUtXbpUi42N1f785z/r9RZ6hc4e5/nz52uhoaHaO++8o+Xl5Wn/+9//tNTUVO3qq6/W6y30CjU1NdqmTZu0TZs2aYD27LPPaps2bdIKCws1TdO0++67T7v++us97Y9M7f3973+v5eTkaAsXLpSpvafqhRde0Pr166eZzWZt/Pjx2g8//OB5bPLkydqNN97Yov1///tfbfDgwZrZbNaGDx+uLVu2zMsR906dOc79+/fXgBNu8+fP937gvVBnP9PHkmSk4zp7nNesWaNNmDBBs1gs2sCBA7XHH39cczqdXo669+nMcW5qatIefvhhLTU1VbNarVpycrJ2++23a4cPH/Z+4L3IV1991erv3CPH9sYbb9QmT558wj6ZmZma2WzWBg4cqL3++uvdGqOiadK3JYQQQgj9+OyYESGEEEL0DpKMCCGEEEJXkowIIYQQQleSjAghhBBCV5KMCCGEEEJXkowIIYQQQleSjAghhBBCV5KMCCGEEEJXkowIIYQQQleSjAghhBBCV5KMCCGEEEJXkowIIYQQQlf/H+SoQJCzlqOhAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Greedy rollouts over trained model (same states as previous plot)\n", + "policy = model.policy.to(device)\n", + "out = policy(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True)\n", + "\n", + "# Plotting\n", + "print(f\"Tour lengths: {[f'{-r.item():.2f}' for r in out['reward']]}\")\n", + "for td, actions in zip(td_init, out['actions'].cpu()):\n", + " env.render(td, actions)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Test function\n", + "\n", + "By default, the dataset is generated or loaded by the environment. You may load a dataset by setting `test_file` during the env config:\n", + "\n", + "```python\n", + "env = SDVRPEnv(\n", + " ...\n", + " test_file=\"path/to/test/file\"\n", + ")\n", + "```\n", + "In this case, we test directly on the generated test dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "val_file not set. Generating dataset instead\n", + "test_file not set. Generating dataset instead\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'test_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=31` in the `DataLoader` to improve performance.\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "a30f0c12c3964a608e2f6e55a8fdb18b", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Testing: | | 0/? [00:00┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n", + "┃ Test metric DataLoader 0 ┃\n", + "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n", + "│ test/reward -7.363526344299316 │\n", + "└───────────────────────────┴───────────────────────────┘\n", + "\n" + ], + "text/plain": [ + "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n", + "┃\u001b[1m \u001b[0m\u001b[1m Test metric \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m DataLoader 0 \u001b[0m\u001b[1m \u001b[0m┃\n", + "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n", + "│\u001b[36m \u001b[0m\u001b[36m test/reward \u001b[0m\u001b[36m \u001b[0m│\u001b[35m \u001b[0m\u001b[35m -7.363526344299316 \u001b[0m\u001b[35m \u001b[0m│\n", + "└───────────────────────────┴───────────────────────────┘\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "[{'test/reward': -7.363526344299316}]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "trainer.test(model)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Test generalization to new dataset\n", + "\n", + "Here we can load a new dataset (with 50 nodes) and test the trained model on it" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "# Test generalization to 50 nodes (not going to be great due to few epochs, but hey)\n", + "env = SDVRPEnv(generator_params=dict(num_loc=50))\n", + "\n", + "# Generate data (100) and set as test dataset\n", + "new_dataset = env.dataset(50)\n", + "dataloader = model._dataloader(new_dataset, batch_size=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plotting generalization\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tour lengths: ['11.84', '12.49', '12.20']\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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YaH/VV1d3VJv4ZShsXN9OGo1zbHR2HnOzc1VzGazMm3aNCU9PV2ZO3euEh0drfzf//1fS72FU4LGzvPTTz+tmM1m5bvvvlMyMzOVhQsXKu3bt1cuu+yylnoLpwTV1dXKpk2blE2bNimA8sYbbyibNm1ScnJyFEVRlEceeUSZMmWKf/yB0t4HH3xQSUtLU9577z21tPdEeeedd5SkpCRFr9crAwYMUNasWePfN2zYMGXq1Km1xv/4449Kp06dFL1er3Tv3l35448/mtniU5PGzHPbtm0VoM7r6aefbn7DT0Ea+5k+FNUZOXYaO8+rVq1SBg4cqBgMBiUlJUV5/vnnFUmSmtnqU4/GzLPH41GmT5+utG/fXjEajUpiYqJy++23KxUVFc1v+CnE0qVL6/3OPTC3U6dOVYYNG1bnmNTUVEWv1yspKSnK559/3qQ2Coqirm2pqKioqKiotBynbc6IioqKioqKyqmB6oyoqKioqKiotCiqM6KioqKioqLSoqjOiIqKioqKikqLojojKioqKioqKi2K6oyoqKioqKiotCiqM6KioqKioqLSoqjOiIqKioqKikqLojojKioqKioqKi2K6oyoqKioqKiotCiqM6KioqKioqLSoqjOiIqKioqKikqL8v8bTUJEf9JJxQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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XS26XAoEAoFAMFhovm+fTtJsUDgjNTU1AAQHB/ezJQKBQCAQCLpLTU0Nrq6unb4/KBRYrVYr+fn5uLi4IEnS6XfoItXV1QQHB5OTkyOUXXsRMc99h5jrvkHMc98g5rlv6M15lmWZmpoaAgIC2jTRPZlBERlRKBQEBQX12vH1er34ovcBYp77DjHXfYOY575BzHPf0FvzfKqISDMigVUgEAgEAkG/IpwRgUAgEAgE/cqwdkY0Gg0rV65Eo9H0tylDGjHPfYeY675BzHPfIOa5bxgI8zwoElgFAoFAIBAMXYZ1ZEQgEAgEAkH/I5wRgUAgEAgE/YpwRgQCgUAgEPQrwhkRCAQCgUDQrwx5Z+T1118nLCwMrVbLlClT2LVr1ynHf/XVV8TGxqLVahkzZgyrV6/uI0sHN92Z53feeYeZM2fi7u6Ou7s78+fPP+2/i6CF7n6nm/n888+RJIlLLrmkdw0cInR3nisrK7n99tvx9/dHo9EwYsQIcf3oAt2d55dffpmYmBgcHR0JDg7mnnvuwWAw9JG1g5PffvuNCy+8kICAACRJ4rvvvjvtPomJiUyYMAGNRkNUVBTvv/9+7xopD2E+//xzWa1Wy//73//kI0eOyLfccovs5uYmFxUVdTj+999/l5VKpfzCCy/IR48elR999FHZwcFBPnToUB9bPrjo7jxfe+218uuvvy7v379fTk5OllesWCG7urrKubm5fWz54KO7c91MRkaGHBgYKM+cOVO++OKL+8bYQUx357mxsVGeOHGivHjxYnnr1q1yRkaGnJiYKCclJfWx5YOL7s7zJ598Ims0GvmTTz6RMzIy5F9//VX29/eX77nnnj62fHCxevVq+ZFHHpG//fZbGZBXrVp1yvHp6emyTqeT7733Xvno0aPyq6++KiuVSnnNmjW9ZuOQdkYmT54s33777fa/LRaLHBAQID/77LMdjr/qqqvkCy64oM22KVOmyH/84x971c7BTnfn+WTMZrPs4uIif/DBB71l4pDhTObabDbL06dPl9999135hhtuEM5IF+juPL/55ptyRESEbDQa+8rEIUF35/n222+Xzz333Dbb7r33XnnGjBm9audQoivOyP333y+PHj26zbalS5fKCxcu7DW7huwyjdFoZO/evcyfP9++TaFQMH/+fLZv397hPtu3b28zHmDhwoWdjhec2TyfTH19PSaTCQ8Pj94yc0hwpnP95JNP4uPjw0033dQXZg56zmSef/jhB6ZNm8btt9+Or68vcXFx/P3vf8disfSV2YOOM5nn6dOns3fvXvtSTnp6OqtXr2bx4sV9YvNwoT/uhYOiUd6ZUFpaisViwdfXt812X19fUlJSOtynsLCww/GFhYW9Zudg50zm+WQeeOABAgIC2n35BW05k7neunUr//3vf0lKSuoDC4cGZzLP6enpbNy4kWXLlrF69WrS0tK47bbbMJlMrFy5si/MHnScyTxfe+21lJaWcs455yDLMmazmT/96U88/PDDfWHysKGze2F1dTUNDQ04Ojr2+GcO2ciIYHDw3HPP8fnnn7Nq1Sq0Wm1/mzOkqKmp4frrr+edd97By8urv80Z0litVnx8fPjPf/5DQkICS5cu5ZFHHuGtt97qb9OGFImJifz973/njTfeYN++fXz77bf8/PPPPPXUU/1tmuAsGbKRES8vL5RKJUVFRW22FxUV4efn1+E+fn5+3RovOLN5bubFF1/kueeeY/369YwdO7Y3zRwSdHeuT5w4QWZmJhdeeKF9m9VqBUClUpGamkpkZGTvGj0IOZPvtL+/Pw4ODiiVSvu2kSNHUlhYiNFoRK1W96rNg5EzmefHHnuM66+/nptvvhmAMWPGUFdXxx/+8AceeeQRFArxfN0TdHYv1Ov1vRIVgSEcGVGr1SQkJLBhwwb7NqvVyoYNG5g2bVqH+0ybNq3NeIB169Z1Ol5wZvMM8MILL/DUU0+xZs0aJk6c2BemDnq6O9exsbEcOnSIpKQk++uiiy5i7ty5JCUlERwc3JfmDxrO5Ds9Y8YM0tLS7M4ewLFjx/D39xeOSCecyTzX19e3cziaHUBZtFnrMfrlXthrqbEDgM8//1zWaDTy+++/Lx89elT+wx/+ILu5ucmFhYWyLMvy9ddfLz/44IP28b///rusUqnkF198UU5OTpZXrlwpSnu7QHfn+bnnnpPVarX89ddfywUFBfZXTU1Nf53CoKG7c30yopqma3R3nrOzs2UXFxf5jjvukFNTU+WffvpJ9vHxkZ9++un+OoVBQXfneeXKlbKLi4v82Wefyenp6fLatWvlyMhI+aqrruqvUxgU1NTUyPv375f3798vA/JLL70k79+/X87KypJlWZYffPBB+frrr7ePby7t/etf/yonJyfLr7/+uijtPVteffVVOSQkRFar1fLkyZPlHTt22N+bPXu2fMMNN7QZ/+WXX8ojRoyQ1Wq1PHr0aPnnn3/uY4sHJ92Z59DQUBlo91q5cmXfGz4I6e53ujXCGek63Z3nbdu2yVOmTJE1Go0cEREhP/PMM7LZbO5jqwcf3Zlnk8kkP/HEE3JkZKSs1Wrl4OBg+bbbbpMrKir63vBBxKZNmzq85jbP7Q033CDPnj273T7x8fGyWq2WIyIi5Pfee69XbZRkWcS2BAKBQCAQ9B9DNmdEIBAIBALB4EA4IwKBQCAQCPoV4YwIBAKBQCDoV4QzIhAIBAKBoF8RzohAIBAIBIJ+RTgjAoFAIBAI+hXhjAgEAoFAIOhXhDMiEAgEAoGgXxHOiEAgEAgEgn5FOCMCgUAgEAj6FeGMCAQCgUAg6FeEMyIQCAQCgaBf+X9rz+EOzaghfgAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Greedy rollouts over trained policy (same states as previous plot, with 20 nodes)\n", + "init_states = next(iter(dataloader))[:3]\n", + "td_init_generalization = env.reset(init_states).to(device)\n", + "\n", + "policy = model.policy.to(device)\n", + "out = policy(td_init_generalization.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True)\n", + "\n", + "# Plotting\n", + "print(f\"Tour lengths: {[f'{-r.item():.2f}' for r in out['reward']]}\")\n", + "for td, actions in zip(td_init_generalization, out['actions'].cpu()):\n", + " env.render(td, actions)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Loading model\n", + "\n", + "Thanks to PyTorch Lightning,[ we can easily save and load a model to and from a checkpoint](https://lightning.ai/docs/pytorch/stable/common/checkpointing_basic.html)! This is declared in the `Trainer` using the model checkpoint callback. For example, we can load the last model via the `last.ckpt` file located in the folder we specified in the `Trainer`. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Checkpointing" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/core/saving.py:188: Found keys that are not in the model state dict but in the checkpoint: ['baseline.baseline.policy.encoder.init_embedding.init_embed.weight', 'baseline.baseline.policy.encoder.init_embedding.init_embed.bias', 'baseline.baseline.policy.encoder.init_embedding.init_embed_depot.weight', 'baseline.baseline.policy.encoder.init_embedding.init_embed_depot.bias', 'baseline.baseline.policy.encoder.net.layers.0.0.module.Wqkv.weight', 'baseline.baseline.policy.encoder.net.layers.0.0.module.Wqkv.bias', 'baseline.baseline.policy.encoder.net.layers.0.0.module.out_proj.weight', 'baseline.baseline.policy.encoder.net.layers.0.0.module.out_proj.bias', 'baseline.baseline.policy.encoder.net.layers.0.1.normalizer.weight', 'baseline.baseline.policy.encoder.net.layers.0.1.normalizer.bias', 'baseline.baseline.policy.encoder.net.layers.0.1.normalizer.running_mean', 'baseline.baseline.policy.encoder.net.layers.0.1.normalizer.running_var', 'baseline.baseline.policy.encoder.net.layers.0.1.normalizer.num_batches_tracked', 'baseline.baseline.policy.encoder.net.layers.0.2.module.0.weight', 'baseline.baseline.policy.encoder.net.layers.0.2.module.0.bias', 'baseline.baseline.policy.encoder.net.layers.0.2.module.2.weight', 'baseline.baseline.policy.encoder.net.layers.0.2.module.2.bias', 'baseline.baseline.policy.encoder.net.layers.0.3.normalizer.weight', 'baseline.baseline.policy.encoder.net.layers.0.3.normalizer.bias', 'baseline.baseline.policy.encoder.net.layers.0.3.normalizer.running_mean', 'baseline.baseline.policy.encoder.net.layers.0.3.normalizer.running_var', 'baseline.baseline.policy.encoder.net.layers.0.3.normalizer.num_batches_tracked', 'baseline.baseline.policy.encoder.net.layers.1.0.module.Wqkv.weight', 'baseline.baseline.policy.encoder.net.layers.1.0.module.Wqkv.bias', 'baseline.baseline.policy.encoder.net.layers.1.0.module.out_proj.weight', 'baseline.baseline.policy.encoder.net.layers.1.0.module.out_proj.bias', 'baseline.baseline.policy.encoder.net.layers.1.1.normalizer.weight', 'baseline.baseline.policy.encoder.net.layers.1.1.normalizer.bias', 'baseline.baseline.policy.encoder.net.layers.1.1.normalizer.running_mean', 'baseline.baseline.policy.encoder.net.layers.1.1.normalizer.running_var', 'baseline.baseline.policy.encoder.net.layers.1.1.normalizer.num_batches_tracked', 'baseline.baseline.policy.encoder.net.layers.1.2.module.0.weight', 'baseline.baseline.policy.encoder.net.layers.1.2.module.0.bias', 'baseline.baseline.policy.encoder.net.layers.1.2.module.2.weight', 'baseline.baseline.policy.encoder.net.layers.1.2.module.2.bias', 'baseline.baseline.policy.encoder.net.layers.1.3.normalizer.weight', 'baseline.baseline.policy.encoder.net.layers.1.3.normalizer.bias', 'baseline.baseline.policy.encoder.net.layers.1.3.normalizer.running_mean', 'baseline.baseline.policy.encoder.net.layers.1.3.normalizer.running_var', 'baseline.baseline.policy.encoder.net.layers.1.3.normalizer.num_batches_tracked', 'baseline.baseline.policy.encoder.net.layers.2.0.module.Wqkv.weight', 'baseline.baseline.policy.encoder.net.layers.2.0.module.Wqkv.bias', 'baseline.baseline.policy.encoder.net.layers.2.0.module.out_proj.weight', 'baseline.baseline.policy.encoder.net.layers.2.0.module.out_proj.bias', 'baseline.baseline.policy.encoder.net.layers.2.1.normalizer.weight', 'baseline.baseline.policy.encoder.net.layers.2.1.normalizer.bias', 'baseline.baseline.policy.encoder.net.layers.2.1.normalizer.running_mean', 'baseline.baseline.policy.encoder.net.layers.2.1.normalizer.running_var', 'baseline.baseline.policy.encoder.net.layers.2.1.normalizer.num_batches_tracked', 'baseline.baseline.policy.encoder.net.layers.2.2.module.0.weight', 'baseline.baseline.policy.encoder.net.layers.2.2.module.0.bias', 'baseline.baseline.policy.encoder.net.layers.2.2.module.2.weight', 'baseline.baseline.policy.encoder.net.layers.2.2.module.2.bias', 'baseline.baseline.policy.encoder.net.layers.2.3.normalizer.weight', 'baseline.baseline.policy.encoder.net.layers.2.3.normalizer.bias', 'baseline.baseline.policy.encoder.net.layers.2.3.normalizer.running_mean', 'baseline.baseline.policy.encoder.net.layers.2.3.normalizer.running_var', 'baseline.baseline.policy.encoder.net.layers.2.3.normalizer.num_batches_tracked', 'baseline.baseline.policy.decoder.context_embedding.project_context.weight', 'baseline.baseline.policy.decoder.dynamic_embedding.projection.weight', 'baseline.baseline.policy.decoder.pointer.project_out.weight', 'baseline.baseline.policy.decoder.project_node_embeddings.weight', 'baseline.baseline.policy.decoder.project_fixed_context.weight']\n", + "val_file not set. Generating dataset instead\n", + "test_file not set. Generating dataset instead\n" + ] + } + ], + "source": [ + "# Environment, Model, and Lightning Module (reinstantiate from scratch)\n", + "model = AttentionModel(env,\n", + " baseline=\"rollout\",\n", + " train_data_size=100_000,\n", + " test_data_size=10_000,\n", + " optimizer_kwargs={'lr': 1e-4}\n", + " )\n", + "\n", + "# Note that by default, Lightning will call checkpoints from newer runs with \"-v{version}\" suffix\n", + "# unless you specify the checkpoint path explicitly\n", + "new_model_checkpoint = AttentionModel.load_from_checkpoint(\"checkpoints/last.ckpt\", strict=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can load both the model and environment from the checkpoint!" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tour lengths: ['9.12', '7.16', '9.55']\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Greedy rollouts over trained model (same states as previous plot, with 20 nodes)\n", + "policy_new = new_model_checkpoint.policy.to(device)\n", + "env = new_model_checkpoint.env.to(device)\n", + "\n", + "out = policy_new(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True)\n", + "\n", + "# Plotting\n", + "print(f\"Tour lengths: {[f'{-r.item():.2f}' for r in out['reward']]}\")\n", + "for td, actions in zip(td_init, out['actions'].cpu()):\n", + " env.render(td, actions)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Additional resources\n", + "\n", + "[**Documentation**](https://rl4co.readthedocs.io/) | [**Getting Started**](https://github.com/ai4co/rl4co/tree/main#getting-started) | [**Usage**](https://github.com/ai4co/rl4co/tree/main#usage) | [**Contributing**](#contributing) | [**Paper**](https://arxiv.org/abs/2306.17100) | [**Citation**](#cite-us)\n", + "\n", + "Have feedback about this notebook? Feel free to contribute by either opening an issue or a pull request! ;)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "env", + "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.11.8" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/2-full-training/index.html b/examples/2-full-training/index.html new file mode 100644 index 00000000..e671af70 --- /dev/null +++ b/examples/2-full-training/index.html @@ -0,0 +1,4469 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Training: Checkpoints, Logging, and Callbacks - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/2b-train-simple.py b/examples/2b-train-simple.py new file mode 100644 index 00000000..d7734b14 --- /dev/null +++ b/examples/2b-train-simple.py @@ -0,0 +1,69 @@ +import torch + +from lightning.pytorch.callbacks import ModelCheckpoint, RichModelSummary +from lightning.pytorch.loggers import WandbLogger + +from rl4co.envs import TSPEnv +from rl4co.models.zoo import AttentionModel +from rl4co.utils.trainer import RL4COTrainer + + +def main(): + # Set device + device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + + # RL4CO env based on TorchRL + env = TSPEnv(generator_params=dict(num_loc=20)) + + # Model: default is AM with REINFORCE and greedy rollout baseline + # check out `RL4COLitModule` and `REINFORCE` for more details + model = AttentionModel( + env, + baseline="rollout", + train_data_size=100_000, # really small size for demo + val_data_size=10_000, + ) + + # Example callbacks + checkpoint_callback = ModelCheckpoint( + dirpath="checkpoints", # save to checkpoints/ + filename="epoch_{epoch:03d}", # save as epoch_XXX.ckpt + save_top_k=1, # save only the best model + save_last=True, # save the last model + monitor="val/reward", # monitor validation reward + mode="max", + ) # maximize validation reward + rich_model_summary = RichModelSummary(max_depth=3) # model summary callback + callbacks = [checkpoint_callback, rich_model_summary] + + # Logger + logger = WandbLogger(project="rl4co", name="tsp") + # logger = None # uncomment this line if you don't want logging + + # Main trainer configuration + trainer = RL4COTrainer( + max_epochs=2, + accelerator="gpu", + devices=1, + logger=logger, + callbacks=callbacks, + ) + + # Main training loop + trainer.fit(model) + + # Greedy rollouts over trained model + # note: modify this to load your own data instead! + td_init = env.reset(batch_size=[16]).to(device) + policy = model.policy.to(device) + out = policy( + td_init.clone(), env, phase="test", decode_type="greedy", return_actions=True + ) + + # Print results + print(f"Tour lengths: {[f'{-r.item():.3f}' for r in out['reward']]}") + print(f"Avg tour length: {-torch.mean(out['reward']).item():.3f}") + + +if __name__ == "__main__": + main() diff --git a/examples/2d-meta_train.py b/examples/2d-meta_train.py new file mode 100644 index 00000000..1f3fb8d4 --- /dev/null +++ b/examples/2d-meta_train.py @@ -0,0 +1,80 @@ +from lightning.pytorch.callbacks import ModelCheckpoint, RichModelSummary +from lightning.pytorch.loggers import WandbLogger + +from rl4co.envs import CVRPEnv +from rl4co.models.zoo.am import AttentionModelPolicy +from rl4co.models.zoo.pomo import POMO +from rl4co.utils.trainer import RL4COTrainer +from rl4co.utils.meta_trainer import ReptileCallback + +def main(): + # Set device + device_id = 0 + + # RL4CO env based on TorchRL + env = CVRPEnv(generator_params={'num_loc': 50}) + + # Policy: neural network, in this case with encoder-decoder architecture + # Note that this is adapted the same as POMO did in the original paper + policy = AttentionModelPolicy(env_name=env.name, + embed_dim=128, + num_encoder_layers=6, + num_heads=8, + normalization="instance", + use_graph_context=False + ) + + # RL Model (POMO) + model = POMO(env, + policy, + batch_size=64, # meta_batch_size + train_data_size=64 * 50, # equals to (meta_batch_size) * (gradient decent steps in the inner-loop optimization of meta-learning method) + val_data_size=0, + optimizer_kwargs={"lr": 1e-4, "weight_decay": 1e-6}, + ) + + # Example callbacks + checkpoint_callback = ModelCheckpoint( + dirpath="meta_pomo/checkpoints", # save to checkpoints/ + filename="epoch_{epoch:03d}", # save as epoch_XXX.ckpt + save_top_k=1, # save only the best model + save_last=True, # save the last model + monitor="val/reward", # monitor validation reward + mode="max", # maximize validation reward + ) + rich_model_summary = RichModelSummary(max_depth=3) # model summary callback + + # Meta callbacks + meta_callback = ReptileCallback( + num_tasks = 1, # the number of tasks in a mini-batch, i.e. `B` in the original paper + alpha = 0.9, # initial weight of the task model for the outer-loop optimization of reptile + alpha_decay = 1, # weight decay of the task model for the outer-loop optimization of reptile. No decay performs better. + min_size = 20, # minimum of sampled size in meta tasks (only supported in cross-size generalization) + max_size= 150, # maximum of sampled size in meta tasks (only supported in cross-size generalization) + data_type="size_distribution", # choose from ["size", "distribution", "size_distribution"] + sch_bar=0.9, # for the task scheduler of size setting, where lr_decay_epoch = sch_bar * epochs, i.e. after this epoch, learning rate will decay with a weight 0.1 + print_log=True # whether to print the sampled tasks in each meta iteration + ) + callbacks = [meta_callback, checkpoint_callback, rich_model_summary] + + # Logger + logger = WandbLogger(project="rl4co", name=f"{env.name}_pomo_reptile") + # logger = None # uncomment this line if you don't want logging + + # Adjust your trainer to the number of epochs you want to run + trainer = RL4COTrainer( + max_epochs=15000, # (the number of meta_model updates) * (the number of tasks in a mini-batch) + callbacks=callbacks, + accelerator="gpu", + devices=[device_id], + logger=logger, + limit_train_batches=50 # gradient decent steps in the inner-loop optimization of meta-learning method + ) + + # Fit + trainer.fit(model) + + +if __name__ == "__main__": + main() + diff --git a/examples/3-creating-new-env-model/3-creating-new-env-model.ipynb b/examples/3-creating-new-env-model/3-creating-new-env-model.ipynb new file mode 100644 index 00000000..fedbb33b --- /dev/null +++ b/examples/3-creating-new-env-model/3-creating-new-env-model.ipynb @@ -0,0 +1,941 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# New Environment: Creating and Modeling\n", + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this notebook, we will show how to extend RL4CO to solve new problems from zero to hero! 🚀\n", + "\n", + "\"Open\n", + "\n", + "### Contents\n", + "\n", + "1. [Environment](#environment-creation)\n", + "2. [Modeling](#modeling)\n", + "3. [Training](#training-our-model)\n", + "4. [Evaluation](#evaluation)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Problem: TSP\n", + "\n", + "We will build an environment and model for the Traveling Salesman Problem (TSP). The TSP is a well-known combinatorial optimization problem that consists of finding the shortest route that visits each city in a given list exactly once and returns to the origin city. The TSP is NP-hard, and it is one of the most studied problems in combinatorial optimization." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Installation" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "## Uncomment the following line to install the package from PyPI\n", + "## You may need to restart the runtime in Colab after this\n", + "## Remember to choose a GPU runtime for faster training!\n", + "\n", + "# !pip install rl4co" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "from typing import Optional\n", + "import torch\n", + "import torch.nn as nn\n", + "\n", + "from tensordict.tensordict import TensorDict\n", + "from torchrl.data import (\n", + " BoundedTensorSpec,\n", + " CompositeSpec,\n", + " UnboundedContinuousTensorSpec,\n", + " UnboundedDiscreteTensorSpec,\n", + ")\n", + "\n", + "from rl4co.utils.decoding import rollout, random_policy\n", + "from rl4co.envs.common import RL4COEnvBase, Generator, get_sampler\n", + "from rl4co.models.zoo import AttentionModel, AttentionModelPolicy\n", + "from rl4co.utils.ops import gather_by_index, get_tour_length\n", + "from rl4co.utils.trainer import RL4COTrainer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Environment Creation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will base environment creation on the `RL4COEnvBase` class, which is based on [TorchRL](https://github.com/pytorch/rl). More information in [documentation](https://rl4co.readthedocs.io/en/latest/_content/api/envs/base.html)!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Reset\n", + "\n", + "The `_reset` function is used to initialize the environment to an initial state. It returns a TensorDict of the initial state." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict:\n", + " # Initialize locations\n", + " init_locs = td[\"locs\"] if td is not None else None\n", + " if batch_size is None:\n", + " batch_size = self.batch_size if init_locs is None else init_locs.shape[:-2]\n", + " device = init_locs.device if init_locs is not None else self.device\n", + " self.to(device)\n", + " if init_locs is None:\n", + " init_locs = self.generate_data(batch_size=batch_size).to(device)[\"locs\"]\n", + " batch_size = [batch_size] if isinstance(batch_size, int) else batch_size\n", + "\n", + " # We do not enforce loading from self for flexibility\n", + " num_loc = init_locs.shape[-2]\n", + "\n", + " # Other variables\n", + " current_node = torch.zeros((batch_size), dtype=torch.int64, device=device)\n", + " available = torch.ones(\n", + " (*batch_size, num_loc), dtype=torch.bool, device=device\n", + " ) # 1 means not visited, i.e. action is allowed\n", + " i = torch.zeros((*batch_size, 1), dtype=torch.int64, device=device)\n", + "\n", + " return TensorDict(\n", + " {\n", + " \"locs\": init_locs,\n", + " \"first_node\": current_node,\n", + " \"current_node\": current_node,\n", + " \"i\": i,\n", + " \"action_mask\": available,\n", + " \"reward\": torch.zeros((*batch_size, 1), dtype=torch.float32),\n", + " },\n", + " batch_size=batch_size,\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Step\n", + "\n", + "Environment `_step`: this defines the state update of the TSP problem gived a TensorDict (td in the code) of the current state and the action to take:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "def _step(self, td: TensorDict) -> TensorDict:\n", + " current_node = td[\"action\"]\n", + " first_node = current_node if td[\"i\"].all() == 0 else td[\"first_node\"]\n", + "\n", + " # Set not visited to 0 (i.e., we visited the node)\n", + " # Note: we may also use a separate function for obtaining the mask for more flexibility\n", + " available = td[\"action_mask\"].scatter(\n", + " -1, current_node.unsqueeze(-1).expand_as(td[\"action_mask\"]), 0\n", + " )\n", + "\n", + " # We are done there are no unvisited locations\n", + " done = torch.sum(available, dim=-1) == 0\n", + "\n", + " # The reward is calculated outside via get_reward for efficiency, so we set it to 0 here\n", + " reward = torch.zeros_like(done)\n", + "\n", + " td.update(\n", + " {\n", + " \"first_node\": first_node,\n", + " \"current_node\": current_node,\n", + " \"i\": td[\"i\"] + 1,\n", + " \"action_mask\": available,\n", + " \"reward\": reward,\n", + " \"done\": done,\n", + " },\n", + " )\n", + " return td" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### [Optional] Separate Action Mask Function\n", + "\n", + "The `get_action_mask` function simply returns a mask of the valid actions for the current updated state. This can be used in `_step` and `_reset` for larger environments with several constraints and may be useful for modularity" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "def get_action_mask(self, td: TensorDict) -> TensorDict:\n", + " # Here: your logic \n", + " return td[\"action_mask\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### [Optional] Check Solution Validity\n", + "\n", + "Another optional utility, this checks whether the solution is feasible and can help identify bugs " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def check_solution_validity(self, td: TensorDict, actions: torch.Tensor):\n", + " \"\"\"Check that solution is valid: nodes are visited exactly once\"\"\"\n", + " assert (\n", + " torch.arange(actions.size(1), out=actions.data.new())\n", + " .view(1, -1)\n", + " .expand_as(actions)\n", + " == actions.data.sort(1)[0]\n", + " ).all(), \"Invalid tour\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Reward function\n", + "\n", + "The `_get_reward` function is used to evaluate the reward given the solution (actions)." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "def _get_reward(self, td, actions) -> TensorDict:\n", + " # Sanity check if enabled\n", + " if self.check_solution:\n", + " self.check_solution_validity(td, actions)\n", + "\n", + " # Gather locations in order of tour and return distance between them (i.e., -reward)\n", + " locs_ordered = gather_by_index(td[\"locs\"], actions)\n", + " return -get_tour_length(locs_ordered)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Environment Action Specs\n", + "\n", + "This defines the input and output domains of the environment - similar to Gym's `spaces`. \n", + "This is not strictly necessary, but it is useful to have a clear definition of the environment's action and observation spaces and if we want to sample actions using TorchRL's utils\n", + "\n", + "> Note: this is actually not necessary, but it is useful to have a clear definition of the environment's action and observation spaces and if we want to sample actions using TorchRL's utils" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "def _make_spec(self, generator):\n", + " \"\"\"Make the observation and action specs from the parameters\"\"\"\n", + " self.observation_spec = CompositeSpec(\n", + " locs=BoundedTensorSpec(\n", + " low=self.generator.min_loc,\n", + " high=self.generator.max_loc,\n", + " shape=(self.generator.num_loc, 2),\n", + " dtype=torch.float32,\n", + " ),\n", + " first_node=UnboundedDiscreteTensorSpec(\n", + " shape=(1),\n", + " dtype=torch.int64,\n", + " ),\n", + " current_node=UnboundedDiscreteTensorSpec(\n", + " shape=(1),\n", + " dtype=torch.int64,\n", + " ),\n", + " i=UnboundedDiscreteTensorSpec(\n", + " shape=(1),\n", + " dtype=torch.int64,\n", + " ),\n", + " action_mask=UnboundedDiscreteTensorSpec(\n", + " shape=(self.generator.num_loc),\n", + " dtype=torch.bool,\n", + " ),\n", + " shape=(),\n", + " )\n", + " self.action_spec = BoundedTensorSpec(\n", + " shape=(1,),\n", + " dtype=torch.int64,\n", + " low=0,\n", + " high=self.generator.num_loc,\n", + " )\n", + " self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,))\n", + " self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Data generator\n", + "\n", + "The generator allows to generate random instances of the problem. Note that this is a simplified example: this can include additional distributions via the `rl4co.envs.common.utils.get_sampler` method!" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "torch.Size([32, 20, 2])\n" + ] + } + ], + "source": [ + "class TSPGenerator(Generator):\n", + " def __init__(\n", + " self,\n", + " num_loc: int = 20,\n", + " min_loc: float = 0.0,\n", + " max_loc: float = 1.0,\n", + " ):\n", + " self.num_loc = num_loc\n", + " self.min_loc = min_loc\n", + " self.max_loc = max_loc\n", + " self.loc_sampler = torch.distributions.Uniform(\n", + " low=min_loc, high=max_loc\n", + " )\n", + "\n", + " def _generate(self, batch_size) -> TensorDict:\n", + " # Sample locations\n", + " locs = self.loc_sampler.sample((*batch_size, self.num_loc, 2))\n", + " return TensorDict({\"locs\": locs}, batch_size=batch_size)\n", + " \n", + "# Test generator\n", + "generator = TSPGenerator(num_loc=20)\n", + "locs = generator(32)\n", + "print(locs[\"locs\"].shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Render function\n", + "\n", + "The `render` function is optional, but can be useful for quickly visualizing the results of your algorithm!" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "def render(self, td, actions=None, ax=None):\n", + " import matplotlib.pyplot as plt\n", + " import numpy as np\n", + "\n", + " if ax is None:\n", + " # Create a plot of the nodes\n", + " _, ax = plt.subplots()\n", + "\n", + " td = td.detach().cpu()\n", + "\n", + " if actions is None:\n", + " actions = td.get(\"action\", None)\n", + " # if batch_size greater than 0 , we need to select the first batch element\n", + " if td.batch_size != torch.Size([]):\n", + " td = td[0]\n", + " actions = actions[0]\n", + "\n", + " locs = td[\"locs\"]\n", + "\n", + " # gather locs in order of action if available\n", + " if actions is None:\n", + " print(\"No action in TensorDict, rendering unsorted locs\")\n", + " else:\n", + " actions = actions.detach().cpu()\n", + " locs = gather_by_index(locs, actions, dim=0)\n", + "\n", + " # Cat the first node to the end to complete the tour\n", + " locs = torch.cat((locs, locs[0:1]))\n", + " x, y = locs[:, 0], locs[:, 1]\n", + "\n", + " # Plot the visited nodes\n", + " ax.scatter(x, y, color=\"tab:blue\")\n", + "\n", + " # Add arrows between visited nodes as a quiver plot\n", + " dx, dy = np.diff(x), np.diff(y)\n", + " ax.quiver(\n", + " x[:-1], y[:-1], dx, dy, scale_units=\"xy\", angles=\"xy\", scale=1, color=\"k\"\n", + " )\n", + "\n", + " # Setup limits and show\n", + " ax.set_xlim(-0.05, 1.05)\n", + " ax.set_ylim(-0.05, 1.05)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Putting everything together" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "class TSPEnv(RL4COEnvBase):\n", + " \"\"\"Traveling Salesman Problem (TSP) environment\"\"\"\n", + "\n", + " name = \"tsp\"\n", + "\n", + " def __init__(\n", + " self,\n", + " generator = TSPGenerator,\n", + " generator_params = {},\n", + " **kwargs,\n", + " ):\n", + " super().__init__(**kwargs)\n", + " self.generator = generator(**generator_params)\n", + " self._make_spec(self.generator)\n", + " \n", + " _reset = _reset\n", + " _step = _step\n", + " _get_reward = _get_reward\n", + " check_solution_validity = check_solution_validity\n", + " get_action_mask = get_action_mask\n", + " _make_spec = _make_spec\n", + " render = render\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "batch_size = 2\n", + "\n", + "env = TSPEnv(generator_params=dict(num_loc=20))\n", + "reward, td, actions = rollout(env, env.reset(batch_size=[batch_size]), random_policy)\n", + "env.render(td, actions)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Modeling\n", + "\n", + "Now we need to model the problem by transforming input information into the latent space to be processed. Here we focus on `AttentionModel`-based embeddings with an encoder-decoder structure. In RL4CO, we divide embeddings in 3 parts:\n", + "\n", + "- `init_embedding`: (encoder) embed initial states of the problem\n", + "- `context_embedding`: (decoder) embed context information of the problem for the current partial solution to modify the query \n", + "- `dynamic_embedding`: (decoder) embed dynamic information of the problem for the current partial solution to modify the query, key, and value (i.e. if other nodes also change state)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Init Embedding\n", + "\n", + "Embed initial problem into latent space. In our case, we can project the coordinates of the cities into a latent space." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "class TSPInitEmbedding(nn.Module):\n", + " \"\"\"Initial embedding for the Traveling Salesman Problems (TSP).\n", + " Embed the following node features to the embedding space:\n", + " - locs: x, y coordinates of the cities\n", + " \"\"\"\n", + "\n", + " def __init__(self, embed_dim, linear_bias=True):\n", + " super(TSPInitEmbedding, self).__init__()\n", + " node_dim = 2 # x, y\n", + " self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias)\n", + "\n", + " def forward(self, td):\n", + " out = self.init_embed(td[\"locs\"])\n", + " return out" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Context Embedding\n", + "\n", + "Context embedding takes the current context and returns a vector representation of it. In TSP, we can take the embedding of the first node visited (since we need to complete the tour) as well as the embedding of current node visited (in the first step we just have a placeholder since they are the same)." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "class TSPContext(nn.Module):\n", + " \"\"\"Context embedding for the Traveling Salesman Problem (TSP).\n", + " Project the following to the embedding space:\n", + " - first node embedding\n", + " - current node embedding\n", + " \"\"\"\n", + "\n", + " def __init__(self, embed_dim, linear_bias=True):\n", + " super(TSPContext, self).__init__()\n", + " self.W_placeholder = nn.Parameter(\n", + " torch.Tensor(2 * embed_dim).uniform_(-1, 1)\n", + " )\n", + " self.project_context = nn.Linear(\n", + " embed_dim*2, embed_dim, bias=linear_bias\n", + " )\n", + "\n", + " def forward(self, embeddings, td):\n", + " batch_size = embeddings.size(0)\n", + " # By default, node_dim = -1 (we only have one node embedding per node)\n", + " node_dim = (\n", + " (-1,) if td[\"first_node\"].dim() == 1 else (td[\"first_node\"].size(-1), -1)\n", + " )\n", + " if td[\"i\"][(0,) * td[\"i\"].dim()].item() < 1: # get first item fast\n", + " context_embedding = self.W_placeholder[None, :].expand(\n", + " batch_size, self.W_placeholder.size(-1)\n", + " )\n", + " else:\n", + " context_embedding = gather_by_index(\n", + " embeddings,\n", + " torch.stack([td[\"first_node\"], td[\"current_node\"]], -1).view(\n", + " batch_size, -1\n", + " ),\n", + " ).view(batch_size, *node_dim)\n", + " return self.project_context(context_embedding)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dynamic Embedding\n", + "\n", + "Since the states do not change except for visited nodes, we do not need to modify the keys and values. Therefore, we set this to 0" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "class StaticEmbedding(nn.Module):\n", + " def __init__(self, *args, **kwargs):\n", + " super(StaticEmbedding, self).__init__()\n", + "\n", + " def forward(self, td):\n", + " return 0, 0, 0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Training our Model" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n" + ] + } + ], + "source": [ + "# Instantiate our environment\n", + "env = TSPEnv(generator_params=dict(num_loc=20))\n", + "\n", + "# Instantiate policy with the embeddings we created above\n", + "emb_dim = 128\n", + "policy = AttentionModelPolicy(env_name=env.name, # this is actually not needed since we are initializing the embeddings!\n", + " embed_dim=emb_dim,\n", + " init_embedding=TSPInitEmbedding(emb_dim),\n", + " context_embedding=TSPContext(emb_dim),\n", + " dynamic_embedding=StaticEmbedding(emb_dim)\n", + ")\n", + "\n", + "\n", + "# Model: default is AM with REINFORCE and greedy rollout baseline\n", + "model = AttentionModel(env, \n", + " policy=policy,\n", + " baseline='rollout',\n", + " train_data_size=100_000,\n", + " val_data_size=10_000) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Rollout untrained model " + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Problem 1 | Cost: 11.545\n", + "Problem 2 | Cost: 8.525\n", + "Problem 3 | Cost: 12.461\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGdCAYAAADAAnMpAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAACtFklEQVR4nOzdd1gTWRcH4F/oqBRFkWLvBRsqdl07FixrF9C1YO9iW1exrKKu2Mta1oqKvQt2197B3rGggBQVkE5yvj/8yDImgQAJIXDe55lH5047E5LMyZ0794qIiMAYY4wxpiE6mg6AMcYYY/kbJyOMMcYY0yhORhhjjDGmUZyMMMYYY0yjOBlhjDHGmEZxMsIYY4wxjeJkhDHGGGMaxckIY4wxxjRKT9MBKEMikSA4OBgmJiYQiUSaDocxxhhjSiAixMTEwMbGBjo6ius/tCIZCQ4ORsmSJTUdBmOMMcayICgoCCVKlFC4XCuSERMTEwA/TsbU1FTD0TDGGGNMGdHR0ShZsqT0Oq6IViQjqbdmTE1NORlhjDHGtExGTSy4AStjjDHGNIqTEcYYY4xpFCcjjDHGGNMoTkYYY4wxplGcjDDGGGNMozgZYYwxxphGcTLCGGOMMY3iZIQxxhhjGsXJCGOMMcY0KtPJyOXLl+Hk5AQbGxuIRCIcOXIkw20uXboEe3t7GBoaokKFCti2bVsWQmWMMcZYXpTpZCQ2Nha1atXC2rVrlVr/7du36NSpE1q2bImAgABMmDABQ4cOxenTpzMdLGOMMcbynkyPTdOhQwd06NBB6fX//vtvlC1bFl5eXgCAqlWr4urVq1i+fDnat2+f2cMzxhhjLI9Re5uRGzduoE2bNoKy9u3b48aNGwq3SUxMRHR0tGBijDHGWN6k9mQkNDQUxYsXF5QVL14c0dHRiI+Pl7uNp6cnzMzMpFPJkiXVHSZjjDHGNCRXPk0zY8YMREVFSaegoCBNh8QYY4wxNcl0m5HMsrKywufPnwVlnz9/hqmpKYyNjeVuY2hoCENDQ3WHxhhjjLFcQO01I40aNcL58+cFZWfPnkWjRo3UfWjGGGOMaYFMJyPfv39HQEAAAgICAPx4dDcgIAAfPnwA8OMWy4ABA6TrjxgxAoGBgZg6dSqeP3+OdevWYd++fZg4caJqzoAxNRJLCDfeROJowCfceBMJsYQ0HRJjjOU5mb5Nc/fuXbRs2VI6P2nSJADAwIEDsW3bNoSEhEgTEwAoW7YsTp48iYkTJ2LlypUoUaIENm/ezI/1slzP73EI5h5/ipCoBGmZtZkRPJyqwdHOWoORMcZY3iIiolz/Uy86OhpmZmaIioqCqamppsNh+YDf4xCM9L6Pnz8cov//u97FnhMSxhjLgLLX71z5NA1jmiSWEOYefyqTiACQls09/jTTt2wkEgmioqLw/fv3bMfIGGN5idqfpmFM29x++0V6a4bEyYCOLkAESVI8KDEWksRYvA2Kw/J/PsO6AAkeQ09viomJgbW1Ne7cuYNChQpp+CwZYyz34GSEsZ+ExfzXRuSzz0wkfnz6IyEBAIlYumzK7szt19jYGMeOHYONjY0qwmSMsTyDb9Mw9hNLEyPp/ykl+cd/JGKI9I1QpP0Y6Bhnrd3Sjh07ULduXbnL+Kkdxlh+xjUjjP3EoWwRWJsZITQqAZSSKC3X0TeESW1HFKzSFMl39yPi1lGkpKQotU8dHR0sW7YMd+7cQbNmzdCkSRMULlwYAD+1wxhj/DQNY3KkPk3zcYMbUr6FAAD0zK1QYvhmAD+epimjF4WJEyfCz88v0/sXiUSws7ND6Wr2uBlnCcMS1aFnWvS/5f//l5/aYYxpM2Wv35yMMKaA3+MQdGlSA8nRkQAAfYtSqDt5i0yNxalTpzBx4kS8fPkyW8fTNSsOswY9YFKnI4AfCYmVmRGuTmsFXR1R+hszxlguxI/2MpZNjnbWKKQrkc6Xty6Mq9NaydRUdOzYEY8ePYKXl5fCD5udnR1EovQTCnGUcAwnAhASlYDbb79k7QQYY0xLcDLCWDoSEv5rx1HU3ERhDYWBgQEmTZqEV69ewc3NTSbx8PHxQWRkJE6cOIFp06ahcePG0NPTl9mPXmFbmbK0T/cwxlhexMkIYwoQEeLj46XzRkZG6az9g6WlJTZu3Ii7d++iadOm0vKrV6+icOHC6NSpExYtWoRr167hbEAgivdfBPNmrjAsaQfo6MLQtorsPk0yPi5jjGkzTkYYUyAxMVEwb2xsrPS29vb2uHz5Mnx8fFCyZElcvXpVZp1mVW1R1q4eCtVoA3FMJPSKlICOvqF0uQg/nqpxKFsky+fAGGPagJMRxhRIe4sGyFwyAvx4YqZPnz54/vw5WrVqJbNcV0eE8U2K4/PeP5DyLQSGxcv9t+3///VwqsaNVxljeR4nI4ylsXPnToSE/HiUN+0tGkB4myYqKgrh4eFK7bNAgQIYNGiQTPnXr1+xeLwrkiODAAAGlmWly6zMjPixXsZYvsGdnjGWRlBQECpUqIBJkyahZ8+egmXGxsb4+PEjVq5cia1bt2brUd7o6Gg4OjoiICBAWjbnt04oXbM2LE1+3JrhGhHGWH7B/Ywwlsbt27fRoEEDAD9qNOLi4qTLbGxsEB4ejuTkZHTo0AGnTp3K0jHi4uLg6OiIK1euCMrDwsJQrFixrAfPGGO5DPczwlgW1K1bF2ZmZgAgSEQAIDg4GMnJP8aq6d27d5b2n5CQgG7duskkItbW1pyIMMbyLU5GGEtDV1cXLVu2THcdfX19dOvWLdP7Tk5ORu/evXH27FmZZbVq1cr0/hhjLK/gZISxn7Ru3Trd5e3bt4e5uXmm9ikWi+Hi4oLjx4/LXc7JCGMsP+NkhLGftGnTJt3lmb1FI5FIMGTIEOzbt0/hOpyMMMbyM05GGPtJ5cqVYWNjI3eZoaEhunbtqvS+iAijR4/G9u3b012PkxHGWH7GyQhjPxGJRAprRxwdHZV+oouI4O7ujr///jvd9QwNDVGpUqVMx8kYY3kFJyOMyaGo3UhmbtF4eHhg2bJlGa5nZ2cHPT3u8ocxln/xNyBjcshLRoyMjODk5KTU9klJSWjXrh1at24NiUSCBw8eYOLEiXLX5Vs0jLH8jpMRxuSwtbVFlSpV8Pz5c2lZx44dYWJiotT2BgYGglF7V69erXBdTkYYY/kd36ZhTIGf241ktaOz+/fv4/Dhw9L5woULY/369dJ5TkYYY/kdJyOMKZD2Vo2xsTE6deqUpf3Mnj1bMO/u7o4RI0Zg8ODBADgZYYwxvk3DmALNmreAjo4OJBIJGv3SDsYFCmZ6Hzdu3MDJkyel80WLFsW4ceMAAKtWrUJISEimO1BjjLG8hmtGGJPD73EIOm+4D73iFQAADw2qouniC/B7HJKp/fxcKzJ9+nQUKlQIAFCwYMF0O0JjjLH8gpMRxn7i9zgEI73vIyQqAUala0GkbwTj8vUQGpWAkd73lU5ILl++jHPnzknnraysMHLkSME6qYkJY4zlZ5yMMJaGWEKYe/wp6P/zRmVqw6h8fSSFvpaWzT3+FGIJKdoFgB8dns2aNUtQ9vvvv6NAgQKqD5oxxrQcJyOMpXH77ReERCVI541sq0JHTx+fd0/Hl3MbIElJRkhUAm6//ZLufs6fP4/Lly9L50uUKAE3Nze1xc0YY9qMkxHG0giLSRDMJ4a+RuyTSwCAmHvHEbJzMpIjP8qsl5a8WpE//vgDRkZGKo+XMcbyAk5GGEvD0kSYMETf3A+QRDqfHBaIkO0TcPfsERDJv1Xj6+uLmzdvSufLlCmDQYMGqSdgxhjLAzgZYSwNh7JFYG1mBNH/54t1mwETe2H/IpScgD+njoGrqytiYmKEy4hknqCZPXs2DAwM1Bk2Y4xpNU5GGEtDV0cED6dqAAARAJGeAYq0HYli3X+HjpHwyZddu3ahTp06uHv3rrTs6NGjuHfvnnS+YsWKcHV1zZHYNUEsIdx4E4mjAZ9w401khg17GWNMHhEpqmvORaKjo2FmZoaoqCilh29nLDv8Hodg7vGngsasRSgKSedW4sn924J19fX1sWjRIowbNw729vZ49OiRdJm3tzecnZ1zLO6cJO81sjYzgodTNTjaWWswMsZYbqHs9ZuTEcYUEEsIt99+QVhMAixNjOBQtghIIsb8+fMxf/58mTYjtWvXRkBAgHS+WrVqePjwIXR1dXM4cvVL7Yvl5y+P1Ntb613sOSFhjHEywpg6Xbp0Cc7OzggODla4zr59+9CrV68cjCpniCWEposvCGpEJEkJEOnq/ZgAWJkZ4eq0VtDVESneEWMsz1P2+s1tRhjLgl9++QUPHjxA586d5S63tLREly5dcjiqnPFzXywAEHVtN4K3jEbs86uQECnVFwtjjKXiZISxLCpatCiOHTuGZcuWySwLCwtDy5Yt8e7du5wPTM1+7mMlOSoM0XePIeXLJ0QcXYTQHZMQ/y4g3b5YGGMsLU5GGMsGkUiksOrxxo0bqF27Ng4cOJDDUamXTF8s130ASYp0Pin0FcL2/oEFY5wFTxYxxpginIwwlg1JSUmYP3++wuVRUVHo1asXRowYgfj4+ByMTH1+7oulQOUm0LcoJbPenWv/ol69eujduzdevnyZs0EyxrQKJyOMZcM///yD9+/fS+cbN26MHTt2yIzGu2HDBtSvXx9PnjzJ6RBV7ue+WIzL1YX1kDUwLF1T7vr79+9HtWrVMHz48HQb/DLG8i9ORhjLooSEBCxYsEBQNn/+fLi6uuL+/fuwt7cXLHvy5Anq1auHDRs2KOxKXls42lljvYs9rMx+3LIRiXRg0X4s/nu4V0gsFmPjxo2oUKECpk+fjq9fv+ZgtIyx3I4f7WUsi1auXIkJEyZI53/55RdcvHhROp+YmIgZM2Zg+fLlMtv27NkTmzZtgrm5eQ5Eqj4/98WycuYY7N3rk+F2hQsXxvTp0zF27FgYGxvnQKSMMU3gfkYYU6PY2FiUL18enz9/lpZduXIFTZs2lVn31KlTGDhwICIiIgTlpUuXxp49e9CoUSO1x5tTAgICUKdOHaXXt7GxwZw5czBo0CDo6empMTLGmCZwPyOMqdHatWsFiUi7du3kJiIA0LFjRzx48AAtW7YUlL9//x7NmjWDp6cnJBKJ3G21Te3atdGhQwel1w8ODsawYcNQvXp1HDhwQOtvXzHGsoaTEcYyKSYmBkuWLBGUpfdEDfCjBuDs2bP4888/Bd3Di8Vi/P7772jXrh1CQkLUEm9Omz59eqa3efnyJXr16gUHBwecP39eDVExxnIzTkYYy6SVK1ciMjJSOu/k5AQHB4cMt9PV1cXMmTNx+fJllColfBT2/PnzqFWrFvz8/FQeb05r1qxZlm893b17F23atEG7du24jxLG8hFORhjLhG/fvsHLy0tQNm/evEzto3HjxggICECPHj0E5eHh4ejQoQPc3d2RlJSU7Vg1RSQSYcaMGUqvL68B69mzZ1GvXj306dMHr169UmV4jLFciJMRxjJh2bJl+Pbtm3S+R48eqF27dqb3U7hwYezfvx/r16+HkZGwR1MvLy80adIEr1+/zma0mtOpUydUr15d4fLy5ctjy5YtCAoKwvfv3+Ht7Y2yZcvKrLdv3z5UrVoVI0aM4D5KGMvDOBlhTEmRkZFYsWKFdF4kEmHu3LlZ3p9IJMKIESNw584dVKtWTbDs7t27sLe3x+7du7O8f03S0dHBtGnTFC5/+/YtLCwsUKJECejo6MDZ2RnPnz/H6tWrYWlpKVhXLBZjw4YNqFChAmbMmCFIBhljeQMnI4wp6a+//kJMTIx0vm/fvun++leWnZ0d7ty5g2HDhgnKY2Ji4OzsjEGDBuH79+/ZPk5O69u3L0qXLi13mUQiQZ8+fXD9+nVpmYGBAcaMGYM3b95g7ty5MDExEWwTHx+PRYsWoVy5cliyZEme6V6fMQaAtEBUVBQBoKioKE2HwvKp0NBQKlCgAAEgAKSjo0PPnz9X+XH27dtHZmZm0uOkTpUrVyZ/f3+VH0/dVq9eLT2HX3/9lSpXriw4ryJFitDTp0/lbhsWFkYTJkwgAwMDmdcDANna2tKmTZsoOTk5h8+KMaYsZa/fnIwwpoSJEycKLoQDBw5U27Hevn1LDRs2lLn4GhgY0KpVq0gikajt2KoWGxtLxYoVIwB08+ZNevfuHVlbWwvOq1SpUvTp0yeF+3j37h0NHDiQRCKR3KSkcuXKdODAAa16XRjLLzgZYUxFPn78SEZGRtKLn56eHr1580atx0xKSqIZM2bIvQB36dKFIiIi1Hp8Vfrzzz+pRo0a0mQhICCATE1NBedUo0YN+vr1a7r7efToEXXp0kVuQgKA6tevT+fPn8+BM2KMKYuTEcZUZNSoUYKLnpubW44d++zZs2RlZSX3FsWlS5dyLI7s+PLlC23btk1QduHCBZnbL7/88gslJCRkuL9r165Rs2bNFCYl7dq1o3v37qnrdBhjmaDWZGTNmjVUunRpMjQ0JAcHB7p161a66y9fvpwqVapERkZGVKJECZowYQLFx8crfTxORpimvHv3jvT19QW3St6/f5+jMXz+/JkcHR1lLro6Ojrk4eGhtW0m9u7dK1Pz06tXLxKLxRluK5FI6MSJE1SjRg2FSUmfPn3o5cuXOXAmjDFF1JaM+Pj4kIGBAW3ZsoWePHlCbm5uZG5uTp8/f5a7/q5du8jQ0JB27dpFb9++pdOnT5O1tTVNnDhR6WNyMsI0ZejQoYIL3JgxYzQSh1gspqVLl5Kenp7MRbdZs2b04cMHjcSVXStWrJA5n3Hjxind/iMlJYV27txJZcqUkZuQ6Onp0YgRIyg4OFjNZ8IYk0dtyYiDgwONHj1aOi8Wi8nGxoY8PT3lrj969Ghq1aqVoGzSpEnUpEkTpY/JyQjThNevX5Ourq70wmZkZKTxi9rt27epXLlyMhfdIkWK0JEjRzQaW1ZNnTpV5nwWL16cqX0kJCTQqlWrpI1lf56MjY1pxowZGbZLYYyplrLX70z1M5KUlIR79+6hTZs20jIdHR20adMGN27ckLtN48aNce/ePdy+fRsAEBgYiFOnTqFjx44Kj5OYmIjo6GjBxFhOmzdvHsRisXR+1KhRsLa21mBEQP369eHv74/+/fsLyr98+YJu3bph7NixSEhI0FB0WePp6QkXFxdB2bRp07Bz506l92FoaIixY8dK+ygpVKiQYHl8fDw8PT1Rrlw5LF26lPsoYSy3yUyG8+nTJwJA169fF5RPmTKFHBwcFG63cuVK0tfXl1YxjxgxIt3jeHh4yP11wzUjLKc8e/aMdHR0pO+9ggULKrwVqQkSiYS2bt0q6PskdapVqxY9e/ZM0yFmSmJiIrVr107mFoufn1+W9pdRHyUlSpSgzZs3a217G8a0hVpqRrLi0qVLWLhwIdatW4f79+/j0KFDOHnyZLpDrs+YMQNRUVHSKSgoSN1hMiYwd+5cSCQS6fzYsWNluinXJJFIhN9++w337t1DrVq1BMsePHiAunXrYuvWrSAiDUWYOQYGBjhw4ADq1q0rLUtJSUGPHj1w9+7dTO+vWLFiWL58OV68eIEBAwZAJBIJln/8+BFDhw5FjRo1cOjQIa15nRjLszKT4SQmJpKuri4dPnxYUD5gwADq0qWL3G2aNm1K7u7ugrKdO3eSsbGxUq3mibjNCMtZjx49EjzlYWJikqv79YiPj6exY8fKrQHo16+fVn1uQkNDZdrEFCtWjF69epWt/T569IicnJwUPnnj4OBAFy5cUNFZMMZSqaVmxMDAAHXr1sX58+elZRKJBOfPn0ejRo3kbhMXFwcdHeFhdHV1UxOhzByesRzh4eEheG9OnDgRFhYWGowofUZGRli1ahWOHDmCIkWKCJbt2bMHderUwZ07dzQUXeYUL14cp0+fRrFixaRl4eHhcHR0RFhYWJb3a2dnh2PHjuHq1ato2rSpzPLbt2+jVatWaN++Pfz9/bN8HMZYFmU2y/Hx8SFDQ0Patm0bPX36lIYNG0bm5uYUGhpKRESurq40ffp06foeHh5kYmJCe/bsocDAQDpz5gyVL1+eevfurfLMirHsunfvnuAXs7m5uVY9gfHhwwe5HYLp6enRX3/9pXRtpKbdvn2bChYsKDiHunXrUkxMTLb3LZFI6Pjx42RnZ6ewpqRv377Zro1hjKm507PVq1dTqVKlyMDAgBwcHOjmzZvSZS1atBCM25GcnExz5syh8uXLk5GREZUsWZJGjRqVqS94TkZYTunUqZPgovTnn39qOqRMS05OJg8PD0ED3NSpffv20h8OuZ2vr69Mvyrt2rWjxMRElew/JSWFduzYkW4fJSNHjtT449yMaTPuDp6xTLpx44bgYmRhYUHR0dGaDivLLl26RLa2tjIX2eLFi9OZM2c0HZ5Stm/fLhO/q6urSgfFS0hIoJUrVyrso6RAgQL0+++/07dv31R2TMbyi1zzNA1j2mL27NmC+enTp8PExERD0WRfixYt8ODBAzg5OQnKP3/+jPbt22PGjBlITk7WUHTKGTBgADw9PQVlO3fuxIwZM1R2DENDQ4wbNw5v3rzBnDlzZPooiYuLw8KFC7mPEsbUKYeSo2zhmhGmbpcvXxb8GraysqLY2FhNh6USEomEVq1aJbfPjYYNG1JgYKCmQ0yXRCKR+7TQypUr1XK8z58/0/jx4wVjEqWduI8SxpTHt2kYU5JEIqEWLVrkyIVOk/z9/aly5coyF1dTU1Pau3evpsNLV0pKCvXs2VMQt0gkUmvcb9++pQEDBsgM5pc6ValShQ4ePKjSW0aM5TWcjDCmpHPnzsn88s3MqNLaJCYmhn777Te5F1c3N7dcXRsUHx8vkzQaGBiovX+Qhw8fpttHSYMGDejixYtqjYExbcVtRhhTAhFh1qxZgrKZM2fCyMhIQxGpV6FChbB161bs2rVLpj3Mpk2bUL9+fTx69EhD0aXPyMgIR44cQY0aNaRlSUlJ6NatGx4+fKi249aoUQPHjh3DlStX0KRJE5nlt27dQsuWLeHo6Mh9lDCWRZyMsHzNz89PMMhjmTJlMHjwYA1GlDP69+8Pf39/1KtXT1D+9OlTODg4YP369bmyU0Jzc3P4+vqiZMmS0rLo6Gg4Ojri/fv3aj1206ZNceXKFRw/fhx2dnYyy0+fPg17e3v069cPr1+/VmssjOU1nIywfIuIZJ6gmTVrFgwMDDQUUc4qX748rl27hsmTJwvKExISMGrUKPTs2RNfv37VUHSK2dra4vTp0yhcuLC0LCQkBI6OjoiMjFTrsUUiETp37oyAgABs374dpUuXllnHx8cHVatWxahRoxAaGqrWeBjLKzgZYfnWsWPHBIOwVahQAQMGDNBgRDnPwMAAS5cuxalTpwRdsAPAoUOHULt2bVy7dk1D0SlWtWpVHD9+XHA77fnz53ByckJcXJzaj6+rq4sBAwbgxYsXWLFiBYoWLSpYnpKSgvXr16N8+fL4448/EBUVpfaYGNNmnIywfEkikcjUinh4eEBPT09DEWlWhw4d8ODBA7Ru3VpQ/uHDB7Ro0QILFiyAWCzWUHTyNWnSBD4+PoKxr27cuIF+/fohJSUlR2IwNDTE+PHjERgYCA8PD7l9lCxYsADlypWDl5cXEhISciQuxrROTrSmzS5+moap2t69ewVPRFStWpVSUlI0HZbGicViWrhwIenq6so8NdKyZUv69OmTpkOUsWHDBrlPBmnikdvPnz/TuHHj0u2j5J9//uE+Sli+wY/2MqZASkoKVa1aVXCR2Ldvn6bDylWuX79OpUuXlrmYFi1alE6cOKHp8GR4eHjIxDpnzhyNxRMYGEiurq4K+yipWrUqHTp0iPsoYXkeJyOMKbBz507BhaFmzZpaM5ptTvr69Sv16tVL7sV04sSJlJCQoOkQpSQSCbm5ucnEuWHDBo3G9eDBA5nBF9NO3EcJy+s4GWFMjuTkZKpQoYLggnDkyBFNh5VrSSQS2rBhAxkZGclcSO3t7enly5eaDlEqOTlZpnMyHR0dOnr0qKZDo8uXL1Pjxo0VJiWOjo7k7++v6TAZUznu9IwxOXbs2CHoA6JevXro0qWLBiPK3UQiEYYNG4a7d++ievXqgmX379+Hvb09vL29NRSdkJ6eHnx8fNCoUSNpmUQiQZ8+fXD9+nUNRgY0a9YMV69exbFjx2ReR+BHfzd16tRB//798ebNGw1EyJhmcTLC8o2kpCTMmzdPUDZv3jyIRCINRaQ9qlevjjt37mDEiBGC8u/fv8PV1RUDBw7E9+/fNRTdfwoUKIDjx4+jcuXK0rKEhAQ4OTnh2bNnGozsR2Ln5OSEBw8eKOyjZM+ePahSpQrGjBmTbh8lCQkJSEpKUme4jOUoTkZYvrFlyxZBL52NGjWCo6OjBiPSLsbGxli/fj0OHDgAc3NzwbIdO3bA3t4e9+/f10xwaVhYWOD06dOwtraWln358gWOjo4IDg7WYGQ/KNNHydq1a1G+fHnMmjVLbh8lwcHB6NmzJxITE3MqbMbUK4duG2ULtxlh2RUfH0+2traC+/Tnzp3TdFha6927d3LbQBgYGNCKFStyxVMiAQEBZGpqKoivRo0a9PXrV02HJhAVFUWzZ8+mggULym1PYmFhQV5eXoLBG58+fUoAqHPnzrmqITFjP+MGrIylsXLlSsEXfIsWLXLFBVObJScn08yZM+U+vtq5c2cKDw/XdIh04cIFMjAwEMT2yy+/5MoL+OfPn2ns2LEK+ygpWbIkbdmyhZKTk8nf319a3rFjxzw7yjTTfpyMMPZ/sbGxVLx4ccEX++XLlzUdVp5x/vx5srKykrl42tjY5IrHVvfu3SuTMPXq1SvXPs4dGBhILi4u6fZR8nO/Kh06dOCEhOVKnIww9n9LliwRfHG3bdtW0yHlOZ8/f6YOHTrIXDhFIhHNmjVL4z2OrlixQia2cePG5erasYz6KPl5at++PSckLNfhZIQxIoqOjiYLCwvBl/bNmzc1HVaeJBaLycvLS+5thqZNm9L79+81Gt/UqVNl4lq8eLFGY1JGRn2UpJ3atWtHcXFxmg6ZMSnuZ4QxAKtWrRIMK9+5c2c0aNBAgxHlXTo6Opg0aRKuX7+O8uXLC5ZdvXoVtWvXxuHDhzUUHeDp6QkXFxdB2bRp07Bz504NRaSc1D5Kjh49KrePkrTOnDmDrl27Ij4+PoeiY0w1OBlheda3b9+wdOlSQdnP/Yww1atXrx7u378PZ2dnQfnXr1/x66+/YvTo0Rq5WOro6OCff/5Bu3btBOWDBw/G6dOnczyezBCJROjQoQO6du2a4bpnz55Fly5dEBcXlwORMaYanIywPGv58uX49u2bdP7XX39FnTp1NBdQPmJqaoqdO3di27ZtKFiwoGDZunXr0KBBA410QmZgYIADBw6gbt260rKUlBT06NEDd+/ezfF4lPXmzRs0a9YMCxcuVGr9c+fOwcnJSZCQiCWEG28icTTgE268iYRYQuoKl7FMExFRrn9HRkdHw8zMDFFRUTA1NdV0OEwLREZGomzZsoiJiQHw45flw4cPYWdnp+HI8p8XL16gb9++CAgIEJQbGxtj1apVGDJkSI73gvv582c0btwYgYGB0rJixYrh+vXrqFChQo7GkpFv375h1KhRuHjxYrq9ssrTsmVLHD9+HFfeRmPu8acIiUqQLrM2M4KHUzU42lmnswfGskfZ6zcnIyxPmjFjBhYtWiSd79u3L/bs2aPBiPK3xMRETJ06FatWrZJZ1qdPH2zYsAFmZmY5GtPr16/RuHFjhIeHS8vKly+Pa9euoXjx4jkai7KCg4Nx9+5d3L17F/fu3cPdu3cRFhaW7jY16jVCVLPJEBkYCcpT07/1LvackDC14WSE5VthYWEoW7astIpaR0cHT58+FYxXwjTj+PHjGDRokKBRMQCULVsWe/bsyfHGxXfu3EHLli0RGxsrLatbty4uXbqEQoUK5WgsWUFE+PTpkyA5uXv3LiIiIgTrGZa0g2VPD+gYGAvKRQCszIxwdVor6OrwGE1M9ZS9fnObEZbnLF68WHCv3MXFhRORXCJ1oLgWLVoIyt++fYumTZti8eLFkEgkORZP/fr1ceDAAejp6UnL7t27hx49emjFQHQikQglSpRAt27dMH/+fPj6+iIsLAzv37/HwYMHMWDkRBiVqYPk8PcI2+8BSaKwUSsBCIlKwO23XzRzAoz9H9eMsDwlODgY5cuXR0LCj3vjurq6ePHihcyjpkyzxGIxFixYgLlz58okH23btsWOHTtgZWWVY/Hs2LEDAwcOFJS5urpi+/btWj2q89GATxjvE4CET88ReWo59MytYFC8AgpUagRDq//axqzsWxtda9tqMFKWV3HNCMuXFi5cKE1EAGDQoEGciORCurq6mD17Ni5duoQSJUoIlp09exa1atXCmTNnciyeAQMGwNPTU1C2c+dOzJgxI8diUAdLkx/tRFIiPyDlyyckBN5D9I29SA4LlLseY5rCyQjLMz58+IBNmzZJ5w0MDDBr1iwNRsQy0qxZMzx48ADdunUTlIeFhaF9+/aYOnVqjt0umTZtGsaOHSsoW7x4sdxGt9rCoWwRWJsZIfnLJ0G5XpEfCaAIP56qcShbRAPRMfYfTkZYnvHnn38KLlxubm4oVaqUBiNiyihSpAgOHTqENWvWwNDQULDsr7/+QrNmzQSP4KqLSCTC8uXL0bNnT0H5hAkTsG/fPrUfXx10dUTwcKqG5MiPgnJ9ixLSp2k8nKpx41WmcZyMsDwhMDAQW7dulc4bGRnh999/12BELDNEIhFGjx6NW7duoUqVKoJlt2/fRp06deDj46P2OHR1dbFz505BA1sigqurKy5evKj246uDo501LFL+e7pGx9gUusamsDIz4sd6Wa7ByQjLE+bNm4eUlBTp/MiRI2FjY6PBiFhW1KpVC3fv3sWQIUME5dHR0ejXrx+GDBkieAxXHYyMjHDkyBHUqFFDWpaUlIRu3brh4cOHaj22OiQnJyP043vpfKVKlbDHrSGuTmvFiQjLNTgZYVrvxYsXgsHOChQogOnTp2swIpYdBQsWxObNm7Fnzx6YmJgIlm3ZsgX16tVTe1Jgbm4OX19fwW2+6OhoODo64v379+lsmfsEBgYKEvXGdWuiUXkLvjXDchVORpjW+/nx0LFjx8LS0lKDETFVSO1C3sHBQVD+/PlzODg4YN26dVBnzwS2trbw8/ND4cKFpWUhISFwdHSU6bQtN3vx4oVgnvvcYbkRJyNMqz1+/FjQlsDExARTpkzRYERMlcqVK4crV65g6tSpgvLExESMHj0aPXr0wJcv6uuwq2rVqjhx4gSMjP579PX58+cyg9DlZj8nIz+3yWEsN+BkhGm1OXPmCH4dT5gwARYWFhqMiKmagYEBFi9eDD8/P5kar8OHD6N27dq4evWq2o7fuHFj+Pj4QEfnv6/LGzduoF+/foLbH7nV8+fPBfNcM8JyI05GmNby9/fHwYMHpfPm5uaYNGmSBiNi6tS+fXs8ePAAbdu2FZQHBQWhRYsWmD9/PsRisVqO3bVrV6xfv15QduzYMYwaNUqtt4pUIW3NiJ6eHsqVK6fBaBiTj5MRprVmz54tmJ88eTLMzc01EwzLEVZWVvDz88PixYsF48lIJBLMnj0bbdq0wadPn9LZQ9YNGzYMHh4egrJNmzZh3rx5ajmeqqStGSlfvjz09fU1GA1j8nEywrTSrVu3cOLECem8hYUFxo8fr8GIWE7R0dHB1KlTceXKFZQpU0aw7NKlS6hVq5bgvaFKHh4ecHNzE5TNmTMHGzduVMvxsisyMlLQ2JZv0bDcipMRppV+rhWZNm2azGOgLG9r2LAh/P390bt3b0F5ZGQknJycMGHCBCQmJqr0mCKRCOvWrYOTk5OgfOTIkTh27JhKj6UK/CQN0xacjDCtc/XqVcEgasWLF8fo0aM1GBHTFHNzc/j4+GDTpk0wNjYWLFu5ciUaNWqEly9fqvSYenp68PHxQaNGjaRlEokEffr0wfXr11V6rOz6ufEqP0nDcitORpjW+XnwuxkzZqBAgQIaioZpmkgkwtChQ3H37l3Y2dkJlvn7+8Pe3h47duxQ6TELFCiA48ePC2oaEhIS4OTkhGfPnqn0WNnBNSNMW3AywrTKhQsXcOnSJem8ra0thg8frrmAWK5RrVo13L59GyNHjhSUx8bGYuDAgXB1dUVMTIzKjmdhYYHTp0/D2vq/LtW/fPkCR0dHBAcHq+w42cF9jDBtwckI0xpEJFMrMnPmTEGHVCx/MzY2xrp163Dw4EGZJ6u8vb1hb2+Pe/fuqex4pUuXhq+vL0xNTaVlHz58gKOjI759+6ay42RV2ts0FhYW3AcPy7U4GWFa4/Tp04J78qVLl5YZUI0xAPj1118REBCAJk2aCMpfv36NRo0aYdmyZYIhBLKjVq1aOHLkCAwMDKRljx49Qvfu3VXegDYzkpOT8ebNG+k836JhuRknI0wryKsVmTVrluACwFhapUuXxqVLl/DHH39AJPpvULjk5GRMnjwZTk5OCA8PV8mxWrZsiZ07dwqOc+nSJbi6uqos6cmsnwfI41s0LDfjZIRphePHj+Pu3bvS+fLly2PAgAEajIhpAz09PcyfPx/nz5+HjY2NYNmpU6dQq1YtXLhwQSXH6t27N5YvXy4o279/PyZMmKCRXlq58SrTJpyMsFxPIpHI1Ip4eHhwT5JMaS1btkRAQAA6deokKA8JCUGbNm0wc+ZMlYwzM378eJlB/VavXo0lS5Zke9+ZxckI0yacjLBc7+DBg3j48KF0vkqVKujfv78GI2LaqFixYjh+/DiWL18uSGSJCAsXLkSLFi3w/v37bB/H09MTLi4ugrLp06er/PHijHAfI0ybcDLCcjWxWCwzHsjcuXOhq6uroYiYNhOJRJgwYQJu3ryJihUrCpZdv34dtWvXFgy+mBU6Ojr4559/0K5dO0H5kCFD4Ofnl619ZwYPkMe0CScjLFfz8fERdCJVs2ZN9OzZU4MRsbwg9RFfV1dXQfm3b9/Qs2dPjBgxAvHx8Vnev4GBAQ4cOIC6detKy1JSUtCzZ09B2yd1SpuM8AB5LLfjZITlWikpKZg7d66gbO7cudDR4bctyz4TExPs2LEDO3bsQMGCBQXLNmzYAAcHBzx58iRb+z958qSgRiI2NhYdO3bE69evs7xfZURGRiIiIkI6z+1FWG7H3+os19q5cydevXolna9bty66du2qwYhYXuTq6irtNj6tx48fo379+ti4cWOWn4YpXrw4Tp8+jWLFiknLwsPD4ejoiM+fP2cr7vRw41WmbTgZYblSUlIS5s2bJyibN2+eoB8HxlSlYsWKuH79OiZMmCAoj4+Px/Dhw9GnT58s96haoUIFnDx5UlD78ubNG3Tq1Anfv3/PRtSKceNVpm2ylIysXbsWZcqUgZGRERo0aIDbt2+nu/63b98wevRoWFtbw9DQEJUqVcKpU6eyFDDLH7Zu3Yp3795J5xs2bIgOHTpoLiCW5xkaGmL58uU4ceIEihYtKli2f/9+1K5dGzdu3MjSvuvXr48DBw5AT09PWnbv3j306NEDSUlJ2YpbHq4ZYdom08nI3r17MWnSJHh4eOD+/fuoVasW2rdvj7CwMLnrJyUloW3btnj37h0OHDiAFy9eYNOmTbC1tc128CxvSkhIwJ9//ikomz9/PteKsBzRqVMnPHjwAC1bthSUv3//Hs2aNYOnp2eWelV1dHTEP//8Iyg7c+YMhg4dqvJO0TgZYVqHMsnBwYFGjx4tnReLxWRjY0Oenp5y11+/fj2VK1eOkpKSMnsoqaioKAJAUVFRWd4H0x6rVq0iANKpefPmJJFINB0Wy2dSUlLozz//JF1dXcH7EQC1bt2agoODs7TfRYsWyexv2rRpKo29cuXK0n1bWFiodN+MZYay1+9M1YwkJSXh3r17aNOmjbRMR0cHbdq0UVh9eezYMTRq1AijR49G8eLFYWdnh4ULF0IsFis8TmJiIqKjowUTyx/i4uKwYMECQRnXijBN0NXVxcyZM/Hvv/+iVKlSgmXnz59HrVq1stRvyNSpUzF27FhB2eLFi7Fq1apsxZuKB8hj2ihTyUhERATEYjGKFy8uKC9evDhCQ0PlbhMYGIgDBw5ALBbj1KlTmDVrFry8vGSq4dPy9PSEmZmZdCpZsmRmwmRabN26dYKnDNq0aYPmzZtrMCKW3zVp0gQBAQHo3r27oDw8PBwdOnSAu7t7ptp9iEQiLF++HL169RKUT5gwAfv27ct2vDxAHtNGan+aRiKRwNLSEhs3bkTdunXRp08fzJw5E3///bfCbWbMmIGoqCjpFBQUpO4wWS4QExODxYsXC8rmz5+voWgY+0/hwoVx8OBBrFu3DoaGhoJlXl5eaNKkSab6DtHV1cWOHTvQokULaRkRwdXVFRcvXsxWrNxehGmjTCUjRYsWha6urszz8Z8/f4aVlZXcbaytrVGpUiVB991Vq1ZFaGiowl8ThoaGMDU1FUws71u9erWgo6ZOnTqhYcOGGoyIsf+IRCKMHDkSt2/fRtWqVQXL7t69C3t7e+zevVvp/RkZGeHIkSOoUaOGtCwpKQndunUTjMWUWZyMMG2UqWTEwMAAdevWxfnz56VlEokE58+fR6NGjeRuk/qLIW3r85cvX8La2hoGBgZZDJvlNVFRUVi6dKmg7Od+RhjLDWrWrIk7d+5g6NChgvKYmBg4Oztj0KBBSvcfYm5uDl9fX0GblOjoaDg6OmZ50D7uY4Rppcy2jPXx8SFDQ0Patm0bPX36lIYNG0bm5uYUGhpKRESurq40ffp06fofPnwgExMTGjNmDL148YJOnDhBlpaW9Oeff6q8NS7TXh4eHoKnC7p3767pkBjLkI+PD5mamso8HVO5cmXy9/dXej9Pnz6lwoULC/ZRpUoVioiIyHRMTZo0ke5DT08vW08yMpZdyl6/M52MEBGtXr2aSpUqRQYGBuTg4EA3b96ULmvRogUNHDhQsP7169epQYMGZGhoSOXKlaMFCxZQSkqK0sfjZCRvi4yMFHyhi0QievjwoabDYkwpgYGB1KBBA5mExMDAgFavXq30Y+nXrl0jIyMjwT4aNWpEsbGxmYqnaNGi0u0rVaqUlVNiTGXUmozkNE5G8rYZM2YIvoD79Omj6ZAYy5SkpCSaNm2aTEICgLp27ap0DceRI0dIR0dHsH2XLl0oOTlZqe0jIiJktmVMk9TSzwhjqhYeHi7oX0FHRwdz5szRXECMZYG+vj4WLVqEM2fOyHR9cPToUdSuXRuXL1/OcD9du3bF+vXrBWXHjh3DqFGjlOqllRuvMm3FyQjTqMWLFyM2NlY67+zszA3umNZq27YtHjx4gHbt2gnKP378iJYtW2Lu3LnpdvgIAMOGDYOHh4egbNOmTUo16ObGq0xbcTLCNCY4OBhr166Vzuvq6mL27NkajIix7CtevDh8fX2xZMkSwcB4EokEc+bMQatWrfDx48d09+Hh4QE3NzdB2Zw5c7Bx48Z0t+OaEaatOBlhGuPp6YmEhATp/G+//YYKFSpoMCLGVENHRwdTpkzBtWvXUK5cOcGyy5cvo1atWjh27JjC7UUiEdatWwcnJydB+ciRI9PdjpMRpq04GWEa8eHDB8GvPH19fcyaNUuDETGmeg4ODrh//z769u0rKP/y5Qu6du2KcePGCRLytPT09ODj4yPow0kikaBPnz64fv263G3S3qaxsLBA0aJFVXAWjKkfJyNMIxYsWCDogdfNzQ2lS5fWYESMqYeZmRl2796Nf/75BwUKFBAsW716NRo2bChTo5GqQIECOH78uKCGIyEhAZ07d8azZ88E6/IAeUybcTLCclxgYCC2bNkinTc0NMTvv/+uwYgYUy+RSITBgwfj7t27qFmzpmDZgwcPYG9vj61bt8p9YsbCwgKnT5+GtbW1tOzr169wdHTEp0+fpGVv374VDJDHyQjTJpyMsBw3f/58wZfmyJEjYWtrq8GIGMsZVatWxa1btzB69GhBeVxcHAYPHgwXFxdER0fLbFe6dGn4+voKxun68OEDOnTogG/fvgHgJ2mYduNkhOWoly9fYseOHdL5AgUKYPr06RqMiLGcZWRkhDVr1uDw4cMoXLiwYNnu3bthb2+PO3fuyGxXq1YtHDlyRDCm16NHj9CtWzckJCRw49U8Qiwh3HgTiaMBn3DjTSTEkoz7l8kLOBlhOWru3LmCQRPHjBkj00kUY/lBt27d8ODBAzRr1kxQ/ubNGzRu3BhLly4VfFYAoGXLlti5cydEIpG07N9//8WAAQNk2pBwzYj28XscgqaLL6DfppsY7xOAfptuouniC/B7HKLp0NRORMp066dh0dHRMDMzQ1RUlKCakmmXJ0+eoEaNGtL74oUKFcLbt2+5xT/L11JSUjB//nz8+eefMsmHo6Mjtm/fDktLS0H5ypUrMWHCBEGZtbU1QkJ+XLT09PQQFxcHfX19tcbOVMfvcQhGet/Hzxfk1LRzvYs9HO2sf94s11P2+s01IyzHzJkzR9BAb8KECZyIsHxPT08Pc+fOxYULF2TaTvn5+aFWrVo4d+6coHz8+PGYOnWqoCw1EQGAcuXKcSKiRcQSwtzjT38MKESElJgI6bLUb8y5x5/m6Vs2nIywHBEQEIADBw5I583MzDBp0iQNRsRY7tKiRQsEBATIdHQWGhqKdu3aYcaMGUhOTpaWe3p6wsXFRe6++BaNdrn99gs+BL7GtyveCN7ohlDvqSD6r5aMAIREJeD22y+aC1LNOBlhOeLnbt4nT54s03iPsfyuaNGiOHr0KFauXCloqEpEWLRoEZo3b453794B+NHL6z///CMzDg4AwbYs9woNDcXKlSsxoEtrBG8egajrPkj5FgpxdBgSPjySWT8sRn4HeXkBtxlhanf79m00aNBAOm9hYYHAwED+WzKWDn9/f/Tt2xcvX74UlJuZmWHTpk3o1asXACAmJgY1atTA+/fvpesYGBjg2rVrqFevXo7GzBQjInz9+hWPHz/G3r17cfbsWbx+/VrhaMyFajvCov0YQdket4ZoVN4iJ8JVGWWv33oKlzCmIj/XikydOpUTEcYyUKdOHdy7dw9jxozB9u3bpeVRUVHo3bs33NzcsGLFCpiYmKBz586CQSeTkpLQsWNHXL9+ncd7ykHJyckICgrCmzdvEBgYKJ1ev36Nly9fIi4uTom9iGBUuhaMStVKUwJYmRnBoWwRtcWuaZyMMLW6du0aTp8+LZ23tLSU6fCJMXURSwi3335BWEwCLE1+fJnr6ogy3jCXKFSoELZt24Y2bdpg5MiR+P79u3TZpk2bcO3aNezdu1fuKMDh4eFwdHTEtWvX+PH5HEBEWLp0aZZ7kzYuWAiGdbujkF0b6Jr8V/uR+m71cKqmVe/dzOLbNEytWrVqhYsXL0rnly9fLvNIImPq4Pc4BHOPP0VI1H/32a3NjODhVE0rH5F89eoV+vXrh3v37gnKjYyMYGZmhs+fP8vdrm7durh06RIKFSqUE2Hme+vWrcOECRMEjY0z0r17d+zduxfnX0TkqfcsoPz1m5MRpjYXL15Eq1atpPM2NjZ48+YNjIyMNBgVyw/yap8NSUlJmDFjBpYtW6ZwnWrVquHly5eCIRfatWuH48ePc8NWNfn8+TP27t0Lb29vub3npmf+/PmYOXOmtCM7ba/N+xn3M8I0iogwa9YsQdnMmTM5EWFql7bPBkmi8B69tvfZYGBgAC8vL5w8eVJhHz1lypTBP//8Iyg7c+YMhg4dqrCxJMu879+/w9vbGx06dICtrS3Gjx+fqUREX18fO3fuxB9//CHoUVdXR4RG5S3QtbYtGpW30OpEJDM4GWFqcebMGVy7dk06X6pUKQwZMkSDEbH84vbbLwiJSkD8m7v49PdgxL/1FyzPC302dOzYEQ8ePBDUPKby9fVFUFAQFi5cKCjfuXMnZsyYkVMh5kkpKSnw9fWFs7MzihcvDldXV/j5+UEsFmdqP+bm5jhz5ozCfmLyI05GmMrJqxWZNWsWDA0NNRQRy0/CYhIQE+CHsIPzIEn4jvDDC5AYFih3PW1mY2ODM2fOwNHRUVBORPjjjz9w5swZDB48WLBs8eLFWLVqVU6GqfWICLdu3cK4ceNgY2ODjh07Yvfu3Uo+GSOrdOnSuHbtGn755RfVBqrlOBlhKnfixAlBdWW5cuUwcOBADUbE8guJRIID65fgy+k1wP97sKTkBEQcXSJzi8LSRPtvGerq6sp0IZ/q0qVLOHr0KJo2bSoonzBhAvbt25cT4Wm1V69eYc6cOahUqRIaNmyI1atXIzw8XKltdXV10a9fPyxevFhQXrduXdy8eRPVqlVTR8hajR/tZSolkUhkakU8PDx4nAymdgkJCfjtt9+wd+9e4QKRCMYVGkjvy+e1PhueP38u/b9IJBIkXZGRkbh69SpKlCghffyXiODq6opixYqhZcuWOR5vbhYWFiZtiHr79u1Mb1+oUCEMGzYM48aNQ+nSpXH06FHpMicnJ+zZswcFCxZUZch5BteMMJU6dOgQHjx4IJ2vUqUKnJ2dNRgRyw8iIyPRtm1bmURE36IUQITk/9+myYt9Nrx48UL6/4oVK+Lvv/+WaSj+8eNHQVlSUhK6deuGhw8f5licuVVsbCx27dqFjh07wsbGBuPGjct0ImJra4slS5YgKCgIXl5eKF26NABIb+WMGTMGhw8f5kQkHVwzwlRGLBbDw8NDUDZnzhzo6upqKCKmLG1+nPDNmzfo0KEDXr16JShv3t4JT8MTERH5AYkfn4BSkmBtYarVfTb8LDIyEhER/43wWqVKFQwfPhxNmjRBnz598PTpU+myhIQEQc1JdHQ0HB0dcePGDenFM79ISUnB2bNnsWvXLhw5cgSxsbFZ2k+tWrXg7u6O3r17y31sOiEhAV5eXpg4caLgiRkmi5MRpjJ79+4VfPnVqFFDOn4Gy720uXOwGzduoEuXLoILMvBjyIF58+bBxsYGAEApSXCvDYzq30prkixlpK0VAYDKlSsDAOzs7HDnzh1MnDgRGzdulC7/ud1MSEgIHB0dcfXqVVhYaNeYJ5lFRLhz5w68vb2xd+9ehIWFZXlfjo6OmDx5Mlq3bp1uktG3b18YGxtn+Tj5Cd+mYSqRkpKCOXPmCMrmzp0LHR1+i+VmqZ2DpU1EACA0KgEjve/D73GIhiLL2MGDB9GqVStBIqKjo4P169dj8eLF+Pfff/Hly3+P7wY/uZ2nEhFAcTICAAUKFMCGDRuwb98+mJmZKdzH8+fP4eTklOWnQ3K7169fY+7cuahcuTIaNGiA1atXK0xE9PQU/z7X19fHb7/9hocPH8LX1xdt2rTJsLaDExHl8ZWCqYS3t7egmtze3h7dunXTXEAsQ2k7B0sV8+A0om7sg0Tyo9+E3Ng5GBFh2bJl6NWrFxIS/kuiChYsiOPHj2PEiBEAIPPEyLlz53I0zpyQtvEq8OM2zc969eqFgIAANGrUSOF+bty4gX79+gl6bdVm4eHhWLNmDRo2bIiKFStizpw5MrfxUhkZGUnb08g7f3Nzc8yYMQPv3r3D1q1bUaNGDbXGnm+RFoiKiiIAFBUVpelQmBxJSUlUtmxZwo/+pAgAnThxQtNhsQxcfx1BpaedkE5WA5aRSM+QAJBhSTuyHbmVSk87QddfR2g6VKnk5GQaPXq04L0GgKytren+/fvS9ZKSkqhIkSKCdUQiEUVE5J5zUYWuXbsKzjE8PFzhuklJSTRjxgwSiUQyr1/q5ObmRhKJJAfPQHW+f/9Ou3btoo4dO5Kurq7CcwRABgYGVK5cOTIwMFC4TpkyZWjlypUUExOj6VPTaspevzkZYdm2YcMGwYe4QYMGWvuFlp8c8f8oTURsR+8kHWNTwd9Rx6gQFe06nY74f9R0qET042LTuXNnmYuGnZ0dffjwQbDu6dOn5V5g9u/fr6Ho1aNKlSrSc7OwsFBqm3PnzpGVlZXCi7CHh4d6g1ah5ORk8vX1JRcXFypYsGC6CYhIJCJ7e3uqXbt2uus5ODjQvn37KDk5WdOnlydwMsJyREJCApUsWVLwYT5z5oymw2JKSK0ZKTXlKBmWqkm6ppZyv5w793TW+K/D4OBgqlu3rkxsbdq0oW/fvsmsP3ToULnnMmzYMA1Erx5JSUmkp6cnPbfGjRsrve3nz5+pQ4cOCi/I69atU2Pk2SORSOj27ds0fvx4srSU/55NO9WsWZNcXFzSTUJEIhF17dqVrly5wj+kVIyTEZYjVq9eLfhQN2vWjD/MWiJFLKGGC8+Rab0fVf2mDXtTEcexJNI3lPmyrlChAt2+fVsjcT5+/JhKlSolE9OgQYMoKSlJZn15t2hSp3LlymngDNTjxYsXMq9HZojFYlq6dKkgoUk7bd68WU2RZ83r169p7ty5VKlSpQwTkJIlS9LEiRNp+vTpMreQ005GRkY0fPhwev78uaZPL8/iZISpXWxsrEx176VLlzQdlkCKWELXX0fQEf+PdP11BKWIOVFKa9KfK6R/uyLtRlHpaSfIZujfZGBVQeaLW09Pjzw9PSklJSXH4jt//jyZmZnJxDJ//nyFSa+iWzSp05s3b3IsfnU6evSo4LwWL16cpf3cuXNH4QXb09NTxVFnTlhYGK1evZoaNmyYYQJibm5Obm5udPDgQZoxYwYVLlxY4bpFixalOXPmUFhYmEbPLz/gZISp3dKlS2WqzHMT30fB1HDhOUEjzYYLz5Hvo2BNh5Yr3Lx5kwwN/6sFKfbrH9LXyWGeL/UcNEpuY8dffvmFgoKC1B7f9u3bSV9fX3BsfX192rlzZ7rbKbpFkzpt2LBB7bHnhCVLlgjO68iRI1neV1RUFPXo0UPu69W3b1+Kj49XYeTpi42Npd27dyvdELVHjx506NAhun//Pg0aNCjdRqmVKlWiDRs2UFxcXI6dT37HyQhTq5iYGCpatKjgg37jxg1NhyXl+yiYyqRJQlKnMv+f8ntC8unTJ7K2thZWyx86I1ODdP78ebKxsZH5Ui9cuDAdOHBALbFJJBKaM2eO3F++Fy9eTHfbpKQksrCwSPcC1qtXL7XEndOGDBkiOK9nz55la38SiYT++usvuQlo1apV6enTpyqKXFZycjKdPn2aXF1dM2yImpoQb968mb58+ULnzp1Lt/0LAGrevDkdPXqUxGKx2s6Byafs9VtE9FOXfLlQdHQ0zMzMEBUVBVNTU02HwwB4enri999/l8537NgRJ0+e1GBE/xFLCE0XX5B25JUY8hJfzm6AjlFB6BgWhI5RQZiammG0Yy0UKVwY5ubmgsnIyAiJiYmIiorC58+fBZONjQ2mTZum1V07JyQkoEWLFjLjb3z8+FHuCLCRkZFwc3PD4cOHZZYNGTIEK1asQKFChVQSW1JSEoYNG4bt27cLysuUKYNTp06hatWq6W5/5swZtG/fPt11ihQpgrCwMK0fpqBp06a4du0agB+ddcXFxalkQMojR46gR48ekEgkgnJjY2OsXr0agwcPVsn7n4hw7949eHt7w8fHB58/f053/Ro1asDFxQX9+vWDlZUV9u3bh6VLlyIgIEDu+jo6OujZsycmT54MBweHbMfLskbp63dOZEbZxTUjucu3b99k7sfevXtX02FJ/dx/RrFf/8jwl5Yyk56eHnXq1ImGDx9O06ZNI09PT1q/fj3t2bOHfH196caNG/Ts2TMKCQnJ0WrtzJBIJOTq6ipzbiKRKN1HGSUSCW3cuJEKFCggs23FihXpzp072Y7t69ev1KpVK5n916tXj0JCQpTaR9pbND/f4smt79esSlszWalSJZXu28/Pj3R0dOS+dn369JH7BJOy3rx5Q/PmzVOqIWqJEiVo6tSp9ODBAyL68d3z119/UYkSJRRuU7BgQRo/fjwFBgaq6uVg2aDs9ZvHpmGZtmLFCnz9+lU6361bN9StW1eDEQmFxQi7NhfHflPJflNSUjJV+2NoaChT65J2MjMzS3e5kZGRymtgli9fjp07d8qUW1paptsVtkgkgpubG5o3b47+/fvj/v370mWvXr1Co0aN8Oeff8Ld3T1LNQ7v379Hp06d8OTJE0F5165dsWvXLqVGO01OTsbhw4fRtGlTTJs2DRcuXMDy5culyw8ePAgfHx/s378fZ8+ezVXv2cySN0CeKrVv3x579uxB3759Zcaz2bt3L27fvg0fHx+laxzCw8Oxb98+7Nq1Czdu3Eh3XTMzM/Tq1QsuLi5o1qwZdHR0EBQUBHd3d2zcuBExMTFyt7O2tsa4ceMwfPhwFC5cWLkTZbkGJyMsU758+YJly5YJyubOnauhaOSzNBEOnw6RDkQGxqCk+ByNIzExUXp7JysMDAzSTVYymn5OZk6fPo0pU6bIPVbqgHIZqVy5Mm7cuIFZs2bhr7/+kl6oUlJSMH36dPj5+WHnzp0oUaKE0ud57949dO7cGaGhoYLycePGYdmyZUonN+Hh4Th27BgaN24MAPDz8xMsr1GjBn799Vfcvn0bZ86cUTq+3Ci9MWlUpXfv3ggNDcX48eNllr19+xZNmjTBggUL4O7uLncMqri4OBw7dgze3t44ffp0ul3NGxgYoFOnTnBxcUHHjh2l3bPfv38fXl5e2Lt3L8Risdxt7ezs4O7ujn79+skdOZdpiRypp8kmvk2Te/z++++CKtHevXtrOiQZqf1n/NyAtdSUo1Ri3B4q3n8RmVd2UMmtm9w8GRgYkKWlJVWqVIlq1qypsD8JAFS/fn26fv06PX36lIKDgykuLi7D/mJU0bj1+PHjMrd+RCIRLV++PNvvg58beP7cS6s227Jli+Dc1NknyNSpU9N9n7Vr145CQ0OJ6L+GqAMGDKBChQpl+B5t0aIFbdq0ib58+SI9nlgsppMnT1LLli3T3bZt27bk5+fH/RrlctyAlalceHg4ypYti9jYWAA/Gog9fvw4w0aFmpA6Gi3w45srVWo9wXoXe9hIwjFjxgycOnUqW8fS09ODra0tLC0tYW5uDmNjYxARoqKi8O3bN+kUHR2drePkNGVqZvT09LB//37cuXNHZvshQ4Zg5cqVCm+xrFu3DmPHjhU0lDQ2NsauXbvQvXv3bMfv4uKCXbt2SefDwsJQrFgxhevPmDED5ubmcHFxkduQNzeZNm0alixZIp2/evUqmjRpopZjSSQS/Pbbb3Jv76WysLBA8+bNcePGDZkarp/Z2dlJG6KWKlVKWp6QkIBdu3Zh2bJlePr0qdxt9fT00K9fP0yePBm1atXK2gmxHKXs9ZuTEaa0KVOmYOnSpdJ5FxeXdL+gNM3vcQjmHn8qfaoGAKzNjODhVA2OdtbSskuXLmHatGkyT5dkR6FChWBvb4969eqhfv36qFevHsqUKYOYmBhBgpKZSduSGQDQ1dWFra0trKyspG1kzMzM8ODBA5kExtzcHOvXr0fz5s2lSV122sz06tULBw4ckM5n9P1x9uxZtGvXDiKRCG3atMHAgQPRrVs3pdqr5LRu3brh6NGj0vnw8HAULVpUbcdLTk5G586ds3x7y9bWFs7OznB2dkbNmjUFyyIjI/H3339j9erVCm9pmpmZYfjw4Rg7dmymbgEyzeNkhKlUSEgIypUrJx2yXVdXF8+fP0eFChU0HFn6xBLC7bdfEBaTAEsTIziULQJdHdkLHBHh0KFD+P333/Hy5UvBskqVKmH69Om4c+cO7t69iwcPHiApKSnTsZibmwuSk/r166NEiRJKX3DFYjGio6MzlcA8e/YM4eHhmY41N9DX189Wm5k+ffrgxIkT0v0lJiam26ZAIpGgWrVqgvYYhQoVQq9evTBgwAA0b95cbtuIVMq+11ShatWqeP78OYAfjypHRkaq5ThpxcTEoFmzZnjw4IFS65uamkobosp77d68eYPly5dj69atiIuLk7uPUqVKYeLEiRgyZAhMTEyyfQ4s53EywlRq3LhxWL16tXR+yJAh2Lx5swYjUo/k5GRs3boVc+bMQUhICIAfVcNfvnyRfhkmJibi8ePH0uTkzp07ePLkicIGdumxtLSUJiepCUrx4sVVci7v3r3DkiVLUKRIERQpUgTXr1/HwYMH5a47ZMgQ2NrayiQzaW81RUVFqSSunCISiQRPgrRp0waF5fQrk3Y6ePCgTAPtVGXKlIGrqytcXV1RsWJFwTJla+FUITk5GQUKFJA2CG3cuLG0vxF1iIuLw/Hjx+Ht7Q1fX1+l3ucFChTA33//DVdXV5llN27cgJeXFw4dOiTzpE6qunXrwt3dHT179kz3KS+W+3EywlQmKCgIFSpUkNYG6Ovr49WrVyhdurSGI1Of2NhYrFy5EosXL0Z0dDSOHz+Ozp07K1w/Li4OAQEBuHv3rjRBefHihcIv2/SUKFFCUHtSt25dFClSJDunAwBwcHAQ3BoxMDCQ/k3v3bsHe3v7dLcXi8VK32Z6+fIl7t27l6UaJG3QuHFjDBgwAH369MHNj/EY6X0fP/+l07ZPUmVC8vLlS8HTM4MGDcKWLVtUtn/gx9/6woUL2LVrFw4ePIjv37+nu76urq7cJCW13ZCRkRGOHTuGpUuX4vr16wr307lzZ7i7u6N58+Za3bEg+w8nI0xlRowYgQ0bNkjnR44ciXXr1mkwopwTGRmJhQsXQk9PD4sXL87UttHR0bh//740Obl79y4CAwOzFEf58uUFtSf29vaZqra+c+eOoE8IOzs7/PXXX+jcuTPEYjFCQkJgZWWVpdgUiYiIwNChQwVtG9Lq27cvevXqpfStp9xYM2NoaIiCFRtAt0pL6BayAEgCQ6v/bl2KAFiZGeHqtFYqu2Vz7NgxdO3aVTq/ePFiTJ06Ndv7JSL4+/tLe0RNrRlUREdHR9D4uGzZsggPD5dJXIoXLw4DAwMEBQXJ3Y+hoSEGDBiAiRMn5srG8Cx7OBlhKvH27VtUqlRJWiVsaGiIN2/e5PqnDVQtNjZWJQ0ZIyMjce/ePcEtnk+fPmV6PyKRCFWqVBG0QalduzaMjY3lrj948GBs3bpVOr9u3TqMHDkSGzduxKhRo5CYmKiW7tF9fHzg6uoqt4+JSpUqYffu3Up3PpaZmplv377h3Llz0ie/fr5lox4iiPQMULz/IhhaC2/j7HFriEblLVRylL/++kuQfBw5ckSQnGTW27dvsXv3bnh7e0vboShia2uL/v37w9nZGcHBwejSpYvgb9u0aVPExcUJOsVTxMLCAqNGjcLo0aNVdmuS5T7cHTxTiUGDBgme7R8/frymQ8pzgoOD6dixYzR79mzq0KGDzACEyk66urpUq1YtGjp0KP3999907949SkxMpMjISDIyMpKuV6hQIYqOjpYef/Xq1So/J4lEQosWLcowZn19fVq8eLFaBjCrWLGi9DhlypShlJQU+vr1K719+5b8/f3p4sWLdPjwYdq6dSstX76cPDw8qFq1apl6zS1tSpJR6doE3f+6ntctVIRshm0S9HFzxP+jys5LFQPkRURE0Lp166hJkyYZnqOpqSkNHjyYLly4QCkpKYL9bN++XWb98uXLK+xKHgCVLVuW1q1bR7Gxsap6SVguxqP2smx7+fKlYAhvY2NjpccIYVknkUjo/fv3dODAAZo+fTq1bt2azMzMspSgGBoaUsmSJQVlI0eOVGv8ycnJNGLECJlYbGxsaMCAAXLjbN26NX38qLoLNhFRqVKlpPuvXLlyhut/+vQp3RFjdXR0qE6dOjR27Fjy8fGhoKAgWvbPXhLpGQrWExkYU3HnvwTJyPXXESo7r7QJhJ6eHiUlJSm1XVxcHO3du5ecnJzS7QAvNUns1q0b7d+/P8Nxljw9PTP1nixZsiRduXJFFS8F0wKcjLBsc3Z2FnyJTJkyRdMh5VtisZhevnxJu3fvpokTJ1KzZs2UGmpd3mRkZERNmzalCRMm0K5du+jFixcqq5mIjo6WO5x7zZo1KSgoiIiIzpw5Q9bW1jLrFClShA4fPqySOIiILC0tpfuuVatWhuv/nCgVKFCAWrVqRbNnz6bTp0/LfP8cOHBAZjA+HWNTshq4QpqElJl2ghouPEcpYtX1EpqZAfJSUlLo7Nmz9Ntvv5GJiUmG741mzZrRhg0bKDIyMsM4kpOTac+ePWRvb69wfyKRSPB3SJvYzZs3T6amheU9nIywbHny5AmJRCLpl0ehQoUoPDxc02GxNFJSUujx48e0bds2Gj16NDVo0IAMDQ0zvODIm8zMzKhVq1Y0bdo02r9/P7179y7T3Wx/+vSJateuLbPv9u3by3x2w8PDqUuXLnJjGTZsGH3//j3br4+pqal0nw0aNEh33Zs3b5K1tTX16NGDli9fTnfu3Em3xmH79u0ytyJ0CxUh68FrBYlImWknyPdRcLbPJVVERITgmE5OTjLrSCQSun//Pk2aNElu0vfzVK1aNVq4cCG9e/dOqRiio6Np2bJlgponRdPKlStJLBaTp6enoJY1dfrll19UXiPGchdORli29OrVS/ClMXPmTE2HxJSQmJhI9+/fpw0bNpCbm5vggpzZqWjRouTo6EizZs2io0ePUnCw4ovqw4cP5Q7r7ubmpvCiLpFI6O+//yZjY2OZ7SpXrkz37t3L1muRNjFr3rx5uuvGxMQonXytXbtWJl5LmxJUe/IOwa2ZhgvPqTQRISK6du2a4Lhpayvfvn1LCxYsoKpVq2b4t7WxsSF3d3fy9/dX+ryDgoJoypQp6d4y/LmmyMDAgC5cuEBERDdu3KAyZcrIbGNhYUHHjx9X6evEcg9ORliW+fv7y/xqTjuQFdMO79+/F/x6NzExIRcXF6pWrZqg1iszk42NDXXt2pXmz59Pfn5+FBERQWfOnJF7C8DT01OpC93Tp0/l1qjo6+vTkiVLsnQLSSKRCPbVrl27rLyEMuQ1yq1cuTIFBQVRilhC119H0BH/j3T9dYRKb82k+nmAvBUrVtD69eupadOmGf7tTE1NadCgQXT+/PlM3R4JCAggV1fXdNuZVKtWjf755x8KDQ2lGjVqyBz3wYMHRET09etXmR86qdP48eMpISFB5a8Z0yxORliW/Vx9Pm/ePE2HxLJg5syZgr/jrFmzpMtiYmLo33//JS8vL+rbty9VqFAhyzUoP08GBga0Z8+eTMWakJBAkydPlru/rDRujY+PF+yjS5cumdr+ZxKJRGbEauBHW5TPnz9na9+Z8fMIuvJuffyc0HXt2pX27dtHcXFxSh9HIpGQn58ftWnTJt39t2rVik6dOiVIGD9+/ChzC8fa2lp6G0gikdDGjRvl1ojVqVOHXrx4ofLXjWkOJyMsS27fvi34cihSpAi/7looMTFR0HBQV1dX2oBUkS9fvtDZs2dp4cKF9Ouvv8o8hZOZqXLlyuTs7EwrVqygq1evKv0Yp6oat379+lWwfa9evZTe9mdisZjGjh0rE1OjRo3UXmN4/fp18vf3p5SUFDp37pxS7TQAUNOmTenvv/+miIjMPcWTkJBAW7duJTs7O4X71tXVpf79+6d7G+3p06dUuHBhmfdE2niePHki9zgFCxak7du3Z/k1Y7mLWpORNWvWUOnSpcnQ0JAcHBzo1q1bSm23Z88eAkBdu3bN1PE4Gck5jo6Ogi+GRYsWaToklgWpn7XUqXv37lnaT2hoKJ04cYLmzJlDnTt3puLFi2cpOdHR0aEaNWrQ4MGDad26dXTnzh2FVfKqaNwaGhoq2M7V1TVL55+cnEy//fab3BqBmJiYLO1TWRKJhLZt20Y6OjpKtf2pUqUKLViwgN6+fZvpY3358oU8PT3TbfBqYmJCkydPpvfv3yu1z2vXrgn6t0lN4NImpnFxcXIfAwdALi4ugv5wmHZSWzLi4+NDBgYGtGXLFnry5Am5ubmRubl5hlWVb9++JVtbW2rWrBknI7nUz43jLC0tVfJUA8t5zZo1E/wtz549q5L9RkZGUqNGjbJcY5J20tfXp3r16tGIESNo8+bN9ODBA0pOTiaiHxfi9evXK2zcev/+/XTjfPfunWAbNze3TJ9rYmIi9ezZU+b4Tk5OGfa9kR3v3r2jhQsXKtUBm6WlJbVq1Yrq1atH+/fvz/SxAgMDady4cek+Jl6iRAlaunQpffv2LdP7P3LkiMxTR05OTtK/c6oDBw6Qubm5zLErVKhAd+/ezfRxWe6htmTEwcGBRo8eLZ0Xi8VkY2NDnp6eCrdJSUmhxo0b0+bNm2ngwIGcjORSrVq1EnwRLFu2TNMhsSx4+PCh4O9YqVIllfQjEhgYSFWqVJG5YHTv3p0ePXpEPj4+NHnyZGrRogUVKlQoSwmKsbExNW7cmMaNG0c7d+6kEydOUK1ateQmMn/99ZfC83r+/Llg/bFjxyo8r7dv38o0tI2NjZXbX0rfvn2V7mQsMyIjI+nvv/+WSSLTmwwMDKT/r1ixYqYapd66dYt69eqVbk+ptWvXJm9v72yf74YNG2T27ebmJvOav3v3jho3biz3b71s2bJMP2rOcge1JCOJiYmkq6src+92wIAB6TYQmz17NnXr1o2ISKlkJCEhgaKioqRTUFAQJyNqdvHiRcEXgI2NTaYavLHcY+TIkYK/5fLly7O9z9u3b8vtvGrSpElyL4JisZiePn1KO3bsoLFjx1KjRo1kquyVnQoVKiT3sWEA1KZNG/r06ZPM8R88eCBYz93dXe55SSQSat++vaCmJSoqipo3by5zrKFDh6q0k674+Hjav38/de3aVeaR2MxOmzdvzvB4YrGYjh49mmHC06FDBzp//rxKL/4eHh4yx/Hw8JBZLzk5mWbOnCn3aa+OHTtSWFiYymJiOUMtycinT58IAF2/fl1QPmXKFHJwcJC7zZUrV8jW1lbaYZYyyYi8Ny4nI+ojkUhkHg1cs2aNpsNiWRAVFSWolTA2Ns52I8sjR47I3C7R0dHJ9Jg2SUlJFBAQQJs2baLhw4eTvb19ht2SKzOZmJjQP//8I7h43rp1S7DOH3/8ITemEydOEACaO3cuEf3oVKx+/fpyky5VXJxTUlLo/PnzNHjwYKXagTRp0iTdHk6BH7dREhMTFR4zLi6O/v77b6pUqZLCfRgYGNDgwYPp8ePH2T5HeSQSCbm5uckcd8OGDXLXP3/+vNz2K9bW1tJ+S5h2yBXJSHR0NJUpU4ZOnTolLeOakdzn9OnTgg98yZIl+Xl/LbVmzRrB33LIkCHZ2t/KlStlfqUWKFCAjh49qpJ44+Pj6datW7R27Vr67bffyM7OLt1bB+lNxsbG1KFDB5o7dy4tXrxYsOzPP/+UOXZiYqL0Al23bl0KCQmR+3THnDlzspWISCQSCggIIHd3d7K1tc3wPKpUqUJ//vknBQYGEhHRjBkz0l1/xYoVco8bFhZGHh4e6Q68WLhwYfr999/T7dBOVZKTk8nJyUkmqT1y5IjC+Dt27CgTs0gkopkzZ8q0O2G5U664TZPaeZaurq50EolEJBKJSFdXl16/fq3UcbnNiPpIJBJycHAQfNg3btyo6bBYFkgkEplGj1ntxTQlJYUmTJggcyEoXrw43blzR8WRC8XExNCVK1do+fLl1L9//3R/0Ss7dezYkc6dO0dfv36VHmfZsmWCdeT1Durl5ZXl83j//j15enpS9erVM4zP2tqaJk2aRPfu3ZNJfDZv3qxwOwsLC5lG5s+fP6fhw4ene1usbNmytHr16hxvoB4bGyvTANrIyIiuXbsmd32xWEzLli2TexurcePGSndhzzRHrQ1Yx4wZI50Xi8Vka2srtwFrfHw8PXr0SDB17dqVWrVqRY8ePUq3ajEtTkbU59ixY4IPeLly5dTSQI+p36VLlwR/y4zGY1EkNjaWunXrJvPlX7Vq1Sw9NqoKX79+pfPnz9OiRYuoZ8+eVLp06SwnJhUrVqTu3bune7EWiUQKbyGk58uXL7Rhwwa5bU5+nkxMTGjgwIF09uzZdNui/Px3TTvNnz+fiH4kopcvX1b4SHTa98SBAwc0OkBdREQEVa5cWaaG5unTpwq3uXv3rtyO+czNzengwYM5GD3LLLU+2mtoaEjbtm2jp0+f0rBhw8jc3JxCQ0OJiMjV1ZWmT5+ucHt+mib3EIvFMt1wb9u2TdNhsSzq3bu34G+ZlY6jPn/+LFNTBvwY0Cy3DQkQFhZGR48eVdmjxqmTrq5upj4H8fHxdODAAerWrZvgCRd5k56eHjk5OZGPj4/SHcF9/PhRYTITFhZGe/fulfs3S5tYde/ena5evZprnkh59+6dTJuQUqVKpdvTbnR0NLm4uMg9xxEjRnCD+1xKrZ2erV69mkqVKkUGBgbk4OBAN2/elC5r0aIFDRw4UOG2nIzkHgcOHBB8oCtXrsz3YbVUcHCwoDFokSJFMt0XxrNnz6hs2bIyX/Surq5K12Jqip+fH1lZWaksIRGJRFS1alUaNmwYbdy4kfz9/QU1hmKxmC5cuEBDhgxJd+C41Klx48a0bt26LI18LRaL5fa30rp1a7m3llInIyMjGjlyJL18+VKVL7XKPHjwQKYRb40aNQS30uTZvn273H5R7Ozs1NYAl2UddwfP0pWSkiJzLzuz44mw3GPevHmCv2Xa0VyV8e+//8p03w2AZs+enWt+TWckLCyMOnfuLPfCXLNmTZowYQL98ssvGY7nkt7FvWbNmlSnTh25r9XP088NUbMjve7Zf56KFStG8+bNy1Lik9MuXLggU5vUokWLDBPpFy9eUJ06dWTO3djYmDZu3Kg179n8gJMRlq7du3fL/KpQRcdYLOclJycLntIQiURKNw4nItq1a5fMBUFPT4+2bt2qvqDVRCKR0Nq1a+U2eKxatapMo1VVT0WLFqUJEybQ3bt3VXpBbNmypVLJz8aNG7XudsXevXtlntjq1atXht9HCQkJNH78eLmvRa9evTKsYWE5g5MRplBycrLMEwrcCEx7HTp0SPC37NChg1LbSSQSWrBggcwXuampqcq6j9cURSMAZzTp6OhQlSpVqFq1almuQSlcuDC1bduWZsyYQQcPHqQPHz5kKTGRSCR09uxZat++fbrHa9GiBR0/flyrf0ysXLlS5rzGjh2r1Ot2/PhxsrCwkNm+TJkydOPGDZn1U1JS6N9//1XHaTA5OBlhCm3btk3woa1Tpw5Xa2qxn4d5P378eIbbJCUl0dChQ2W+wEuWLEmPHj3KgajV688//8xUAqGrq0sDBgygtWvXUvfu3TNsiJrZydLSkjp16kQeHh504sQJaYN/eRITE2nHjh1Us2bNdOPt27ev2h+zzklTp06VOU9lB+r8+PEjtWjRQu7r5OnpKUjUXr16RZaWljnStwrjZIQpkJSUROXKlcv0xYvlTj+PwVK6dOkMH9uMioqidu3ayXxx16lTR27X6tro95kzBedmbi6/jYdIJKL27dtTr169lGqI2qBBA5o8eTItWLCAXFxcqEqVKnK7LldmKlmyJHXv3p0WLlxIZ86cocDAQFq8eHGGHaMVrdOGtvkpN1K6NhGLxeTq6ipzvso+FZaSkkLz5s2T22lemzZtKCQkhIiIDh8+LK1R4gb76sfJCJNr48aNMl+uXCuivX7umCy9ASuJiIKCguT+4u7YsSPFxMTkUNTq5fsomKyb9RKcn1kl2S7elZ0qV65M8+bNU9gOJyoqii5evEhLliyh3r17y30iKbuTToEfiZJx+fpUZtoJKjPtBPk+ynu/7JOSkmQSZT09PfL19VV6H1euXKGSJUvKvIbFihUjX19fQa3ZzJkz1Xg2jIiTESZHQkKCzIf09OnTmg6LZdH3798Fv+YNDAzo8+fPCtf39/cnGxsbmS/pESNG5JlfiL6PgqnMtBNkUtcpUxf7n6fixYvThAkT6M6dO1lK1iMiIsjPz4/+/PNP6tatm1LdwCuadAsVoQLVWhBEOmQ1YBmV/n8y0nDhOUoR570fEtHR0VS3bl3Ba1CwYMFM3ZKKjIyU23Ff6t827XxmEh2WeZyMMBmrV68WfAibNm3KtSJa7Oduwp2dnSk5OVlumw9fX1/BAHqp05IlS/LMeyBFLKGGC89R6WknqFCt9Bt9Kprq1atHvr6+aknOgoOD6ciRI9S3b18qUqRIpmMzsKlCpaedEEzXX0eoPM7cIDQ0lMqXLy9Ts/Hq1Sul95H6ZJWhoWG6r6uFhQV9+PBBjWeTvyl7/dYByxfi4+OxcOFCQdn8+fMhEok0FBHLDiLC2rVrBWWjRo3CihUrsHnzZkH5pk2b0LlzZ3z//l1aZmhoiH379mHKlCl55j1w++0XhEQlgFKSkfzlU5b2cffuXSxfvhzh4eEqjS0hIQEnT57E9OnT4ePjgy9fvsisIxKJoK+vr3AfZg16yJSFxSSoNM7conjx4vDz80OxYsWkZeHh4XB0dMTnz5+V2odIJMKoUaNw+/ZtVK1aVeF6kZGR6Nu3L5KTk7MdN8s6TkbyifXr1yMkJEQ637p1a/zyyy+aC4hly+3bt+Hv7y+dr1WrFqysrDB79mxcvHgRACCRSPD7779j2LBhEIvF0nUtLCxw/vx59OrVK8fjVheJRIILFy8i0m81Pq5xQWLQ43TXb9iwIdasWQMfHx8UL15csOzMmTOoWbMmTpw4ke24IiIiMH/+fJQuXRpubm54/vy5zDpmZmaYPn06Pn78iISEBLx8+RJzlv0Nk3pdYViiOkT6RgAAw1I1ZLa1NDHKdoy5VYUKFXDq1CkULFhQWvbmzRt06tRJkFhnpEaNGpg/fz50dXUVrnP9+nXMnDkzW/GybMqZiprs4ds02RMTE0PFihUTVE1ev35d02GxbBgwYIDg7/n3338L+qMICgqivn37ylRJV6hQIdd2D54Vjx49omnTpsltsPjzpFfElsyaOtO+88K2B58/f5Y7VD0AGjVqVJY6EXv16hWNGjVKbjfuqVOZMmVoxYoVFB0dLbN96i2nMtNOUKkpR8lm6N+C2zN5uc3Iz3x9fQVDHQCgdu3aKTVEwYULF6hx48ZK3wo7evRoDpxR/sJtRpiUp6en4AOnbKdYLHcKDw8X3Ac3NTWlf/75R/A3/nkQMuDH+Cja0EV4RoKCgmjJkiXp9sOROukUNCeTul3IasByKj31uMILuEQiodWrV8ttX1CtWjV68OCBUrFdu3aNunfvnu7jvvXr16e9e/dm2C4ltTFumZ/aieTlp2kU2b59u8zr6OLikm5Hb+/evSNXV1e5baUUTebm5hobmTqv4mSEEdGP1+7nxnJ5qaOk/GjJkiWCv6ebm5tMzdfPU69evbSum/C0vn79Sps3b6aWLVtm2K+HSN+IClZvSZa95lKpKUczdQF/9OgR1ahRQ2afBgYGtHz5crkXv5SUFDpw4AA1bNgw3bi6dOlC//77b6YaDPs+CpY2yk2dGi48l68SkVSLFi2SeU2nTp2a4XaxsbG0Z88ecnJykqlhUZQs5vaBIbUJJyOMiIjmzp0r+KBldsRklruIxWKZfiy6d++e7pfrlClTtLKr8ISEBDp8+DD16NEjwycidHV1qWPHjrR79246fOt1ti7g8fHxCsc8ad++vbTzrO/fv9Pq1atlOhFMOxkaGtKwYcPo2bNnWX4dUsQSuv46go74f6TrryPyxa0ZeSQSCY0dO1bmNV6xYoXS+4iIiKD169dTs2bN0n0/jRs3joj4tVcFTkYYffnyRaZXSWWrm1nudOrUKcHfs3bt2ul+qRobG9OcOXO0pmdVsVhM//77Lw0bNkypkXEbNmxIq1evlulfRRUXkVOnTpGlpaXMMS0sLKh3797pxle0aFHy8PBIt98XlnkpKSnUq5ewQzuRSER79+7N9L7evXtHnp6ecmvCANDvXhu5VkoFOBlhNPOnLrF79eql6ZBYNnXu3FnwN7Wyssrwgp1ac9CjRw968eKFpk9BrsePH9P06dOpVKlSGZ5LxYoVae7cuZnqcyKrQkNDFTZuVRTb+vXrKTY2Vu2x5Vfx8fEy49AYGBjQhQsXsrzPhw8f0vTp0wWdAooMCpDNsI35vr1Odil7/RYRESGXi46OhpmZGaKiomBqaqrpcLRCeHg4ypUrJ30ETiQS4fHjx6hWrZqGI2NZ9e7dO5QrVw6pH9lChQop/Yhju3bt4O7ujjZt2uSafkU+ffqEPXv2wNvbGw8ePEh3XUtLS/Tt2xcuLi6oV69ejp0DEeHChQsYN24cnj59qnC9pk2bwt3dHU5OTtDR4R4T1O3bt29o3rw5Hj16JC0zNTXF5cuXUatWrSzvd9++fZg6bRriilZF5OOr0DEpCpsBXhDpGUjXEQGwMjPC1WmtoKuTOz5LuZmy12/+1ORRS5YsEVyo+vfvz4mIltuwYQPS/naIjY1Nd319fX0MHDgQDx48wOnTp9G2bVuNJyJRUVHYsmULWrdujZIlS2LKlCkKE5GCBQvCxcUFvr6++PTpE1auXIn69evnyDkkJydj9+7dqFu3Ltq0aZNuImJgYICePXuiS5cunIjkEHNzc/j6+qJUqVLSsujoaHTo0AHv37/P8n4DAgLw/t07xIt1ULzvAki+R+LrpW0gcYp0HQIQEpWA229lO65j2aD+Sprs49s0mRMSEiLo30BXVzdP9S2RHyUkJFDRokWVulVgbm5O06dPzzXtRBITE+nIkSPUs2dPpRqidujQgXbt2kXfv3/P8VijoqJo6dKl6fZbouiJDEdHRwoNDc3xmPOzp0+fyrTdqVy5MkVEZK2b/LR99ehb/Pce0CtsTdZD1glu2Rzx/6jis8mbuDv4fMzT0xPx8fHS+YEDB6JixYoajIhlh1hC8Fy7FREREemuV6ZMGaxcuRJBQUHw9PSEjY1NDkUoSyKR4MqVKxgxYgSsrKzQrVs3HDhwAImJiXLXb9CgAVatWoXg4GCcOnUK/fv3F/S8qW5BQUGYMmUKSpYsCXd3dwQFBcmsY2VlhYULF+Lz5884deoULC0tBcv9/PxQo0YNnDx5MqfCzveqVq2KEydOwMjov55oX7x4AScnJ8TFxWVqX0SE+/fvS+eTI/97D1ByIvTMhH/vvNz7rUbkTG6UPVwzorygoCAyMDD4L7vX1+dOfLRYaj8ThrZVFf5Sd3BwoH379uWKkXefPHlCM2bMoNKlS2dYg1OhQgWaM2eORmvt7t+/T87Ozun2P1G9enXaunUrJSQkCLYNDQ2lDh06yN1m9OjRWt2vi7Y5cuQI6ejoCP4GTk5OmfpMfPjwQeF7QKeAGRmWqE5GpWuScdm6VH3kan7MV0n8NE0+NWLECMGHaMSIEZoOiWVRag+c1r+tkvsF2ahle7py5YrGR9399OkTLV26NMPHjIEfI6+OHTuWbt26pbG4JRIJnTp1ilq1apVurG3atCFfX99045RIJLRq1Sq5t5+qV69ODx8+zMEzy982bNgg8zdwc3NT+n125MgR5W6DNh/AT9NkAicj+dDbt29JX19f+qExNDSkoKAgTYfFsiB1bJLS005QoVqOgi9DA9uqZOu2QaNjk3z79o22bNlCrVu3zrBH1AIFCpCzszOdOnWKkpKSNBIv0Y92N1u2bKHq1aun2x7ExcWF/P39M7Xvhw8fyt2voaEhrVy5UuMJY37h4eEh8zfw8PBQatvZs2dnmIiUaD2QE5FM4mQkHxo8eLDgg5PaiyDTPtdfR0gbyln/tpIK1mxH0NEjkZ4hlZywV7rs+uusNdTLisTERDp69Cj16tWLjIyM0v3S1tXVJUdHR/L29qaYmJgci1GeyMhIWrBgQbp9spiamtKUKVOylbzHxcXRmDFj5O6/Q4cO3Lg1B0gkEnJzc5N5/Tds2JDhtj/34fPzNGjMZL41kwXcz0g+8/r1a1SpUkU6VLyxsTECAwNhZWWl4chYVhwN+ITxPgGCMnHCdySFvoZxmdrSspV9a6NrbVu1xSGRSHD9+nXs2rUL+/btw5cv6T/O6ODgAGdnZ/Tp0wfFixdXW1zKCAwMxPLly7FlyxaFjRlLliyJCRMmYOjQoSr7bjl16hQGDRqEsLAwQbmlpSW2bt2Kjh07quQ4TL6UlBT06NEDx44dk5bp6Ojg0KFD6Nq1q8LtbG1tERwcLHfZ9OnTsXDhQo0/Gq+NuJ+RfGbu3LnSRAQARo8ezYmIFpPXUl/XqJAgEVG0nio8e/YMM2fORPny5dGsWTP8/fffChOR8uXLw8PDAy9fvsStW7cwbtw4jSYiN2/eRK9evVCxYkWsWbNGbiJib2+P3bt3482bN5g0aZJKf+R07NgRDx8+RIcOHQTlYWFh6NSpE8aNG4eEhASVHY8J6enpYc+ePWjUqJG0TCKRoG/fvrh+/brcbUJDQxUmIu7u7pyI5ACuGckDnj59Cjs7O2mHWAULFsTbt29RrFgxDUfGskosITRdfAGhUQmQ9wFVRy+QwcHB8PHxgbe3N/z9/dNdt1ixYujTpw9cXFzg4OCg8S9qsViM48ePY+nSpbh27ZrC9Tp16gR3d3e0aNFC7TETEVavXo2pU6fKPNJsZ2eH3bt3o0aNGmqNIT+LjIxE06ZN8fz5c2lZ4cKFce3aNVStWlWw7qlTp9CpUyeZfYwfPx7Lly/X+Ptbm3HNSD4yZ84cQc+c48eP50REy+nqiODh9KPH3J+/BlPnPZyqZTsRiY6OxrZt29C2bVuUKFECkydPVpiIGBsbo3///jh58iQ+ffqE1atXo0GDBhr9oo6Li8P69etRpUoVdO/eXW4iYmBggKFDh+LJkyc4ceIEfvnllxyJWSQSYdy4cbhz5w6qV68uWPb48WPUr18fq1atghb8HtRKFhYW8PPzg7W1tbTs69evcHR0xKdPnwTrpu1fJNXo0aM5EclJam67ohLcgFWxgIAAmYZ4kZGRmg6LqUhqPyOqHDk0MTGRjh07Rr17986wIaqOjg61b9+edu7cqfGGqGmFhobSrFmzyMLCQmHsRYoUoT/++INCQkI0HS43btWgBw8ekKmpqeA1r1GjBn39+lW6Tvfu3QXLhw8fzk9AqQg/TZNPdO3aVfAhmjt3rqZDYiqWIpbQ9dcRdMT/I11/HZGlFv0SiYSuXr1KI0eOpCJFimT4CGP9+vVpxYoVueJCntazZ8/Izc0t3W7ly5cvT2vXrtVId/IZOXHiBBUrVkwmZktLSzp58qSmw8uzLly4IOgMEgA1b9GCLj75SEf8P5KV7X9dvw8ZMoTEYrGmQ84zOBnJB+7cuSPzS5BfI5bW06dPaebMmVS2bNkME5By5crR7Nmz6cWLF5oOW0AikdClS5cyfPSycePGdPDgQUpJSdF0yOkKCQkhR0dHuecwbtw4io+P13SIedLevXtl+sQpULkp2Y71ls636dKbExEV42QkH/i5K2pPT09Nh8RygeDgYFq2bBnZ29tnmIAULVqURo8eTTdu3Mh11dLJycnk4+ND9erVUxi/SCSiX3/9la5du6bpcDNFLBbTihUrZH6tp95CePTokaZDzJNWrlwp83obV2xIAKhgtV+o9JSj3KmZinEyksddv35d8IEqVqxYrrqnz3JWdHQ0bdu2jdq2bSszRofMl6+xMfXr149Onjyp0R5RFYmOjqbly5enO76NsbExjR49ml69eqXpcLPlwYMHVK1aNZnzMzQ0pNWrV+e6BFHbpYglZN28j8zrbWBViUpNOUpl/t8mizs3Ux1lr996YFpp1qxZgvnp06ejUKFCGoqGaUJycjJOnz4Nb29vHDt2TDBS8890dHTQpk0buLi4oFu3bjAxMcnBSJXz6dMnrFq1Chs2bEBUVJTcdYoXL44xY8Zg5MiRsLCwyOEIVa9mzZq4e/cupkyZgrVr10rLExMTMXbsWPj6+mLr1q0yIwSzrLn99gv0GzqjYGQYYp9cBADoFy8Pyz7zIdLRBQEIiUrA7bdf0Ki89r+/tAknI1ro33//xfnz56Xz1tbWGDlypAYjYjmFiHDjxg3s2rULe/fuRWRkZLrr16tXD87Ozujbt2+u7QTv4cOH8PLywu7du5GSkiJ3napVq2Ly5MlwdnYWDBefFxgbG2PNmjVwdHTEoEGDEBERIV126tQp1KhRA9u2bZPpRI1lXlhMAkQiHVh0GA9x7DfomhSFheMYiHR0ZdZjOYuTES1DRDK1Ir///juMjY01FBHLCc+fP8euXbuwe/duBAYGprtuuXLl4OzsDGdnZ1SuXDmHIswcIsLZs2exdOlSnD17VuF6LVu2xOTJk9GhQwfo6OTtbpE6d+6MR48e4bfffsPp06el5WFhYejYsSPGjRuHxYsX57lkLCel9lgs0tWDZY9ZgK6+3H5E1NWzMVOMe2DVMmfPnkW7du2k8yVLlsSrV69gaGiowaiYOoSGhkp7RL13716661pYWKBv375wdnZGw4YNc21HTUlJSdizZw+8vLzw6NEjuevo6uqid+/emDx5MurWrZvDEWqeRCLBqlWrMG3aNCQlJQmW1ahRA7t374adnZ2GotNumujZOL9T9vrNyYgWISI0atQIt27dkpZt2LABw4YN02BUTJViYmJw+PBh7Nq1C+fOnYNEIlG4rrGxMbp27QpnZ2e0b98e+vr6ORhp5nz9+hUbN27EqlWrFI4BYmJiAjc3N4wfPx6lSpXK4QhznwcPHqB///54+vSpoNzIyAh//fUXRo8enWuTztzM73EIRnr/6HE17cUv9ZVc72IPRztrme1Y1nAykgedOHECTk5O0vmyZcvixYsXufoixDKWnJyMM2fOwNvbG0ePHlWqIaqzszO6d++eKxuipvXu3TusWLECmzdvRmxsrNx1bG1tMWHCBLi5ucHMzCyHI8zd4uPj4e7ujnXr1sks69y5M/755x9u3JoFfo9DMPf4U4RE/dc2xNrMCB5O1TgRUTGlr99qfaZHRfjR3h8dP9WpU0fwONq2bds0HRbLIolEQtevX6fRo0dT0aJFM+wPpG7durR8+XIKDtaOPhBu375NvXv3Tvcx49q1a9POnTspMTFR0+HmeseOHZP7PilevDj5+vpqOjytpIqejVnGuJ+RPObgwYOCL6FKlSpRcnKypsNimfT8+XOaNWsWlStXLsMEpGzZsvTHH3/Qs2fPNB22UsRiMR07doyaN2+e7nk5OjrSuXPnuA+NTAoODqZ27drJfU3Hjx/PPbeyXImTkTxELBaTnZ2d4Mtn9+7dmg6LKSkkJIRWrFiRbk+iqZOFhQWNHDmSrl27pjUX67i4ONqwYQNVrlxZ4Xnp6+vToEGDuGfRbBKLxbRs2TK5PbfWrFmTHj9+rOkQGRPgZCQP2bNnj+BLp3r16jx+Qi4XExNDO3bsoHbt2mXYI6qRkRH16dOHjh07plW3LMLCwmjOnDlyB35LnQoXLkwzZsygT58+aTrcPMXf35+qVq0q9720Zs0arUlkWd7HyUgekZycLPOL88CBA5oOi8mRlJREJ0+epH79+lGBAgXSTUB0dHSobdu2tG3bNq17X7948YJGjBhBRkZG6d5iWrVqFQ9RoEaxsbE0cuRIua9/586dKSwsTNMhMsbJSF6xfft2mUZ/XCuSe0gkErpx4waNGTNGqYao9vb2tGzZMq1piJpKIpHQlStXqGvXrjIjn6adHBwcaN++fdyeKQcdPXpUYeNWPz8/TYfH8jlORvKApKQkmYaOx44d03RYjH7UDsyePZvKly+fYQJSpkwZmjlzJj19+lTTYWdacnIy7du3jxwcHBSen0gkoq5du9KVK1f49oCGBAcHU9u2beX+fSZMmEAJCQmaDpHlU5yM5AGbNm2S+dXJX/aaExoaSitXrqT69etnmIAUKVKERo4cSVevXtXKv1lMTAytWrWKypYtm25blxEjRtCLFy80HS6jH41bvby8FDZuffLkiaZDZPkQJyNaLiEhgUqVKiX4QuEq15wXExNDO3fuJEdHR9LV1c2wIWrv3r21riFqWsHBwTRjxgwqXLiwwvMsVqwYzZkzh9sk5FL+/v5UpUoVue/PtWvXamVyzLQXJyNabs2aNYIvkiZNmvCXSA5JTk6mU6dOUf/+/TNsiCoSiahNmza0detWrX5/Pnr0iAYNGkT6+voKz7VSpUq0YcMGiouL03S4LAOxsbE0YsQIuX9HJycnTiRZjuFkRIvFxcWRtbW14Avk4sWLmg4rT5NIJHTz5k0aO3Zsuo+qpk516tQhLy8vrX5kVSKR0NmzZ8nR0THdc23evDkdO3aMG05roSNHjpCFhYXM39TKyopOnz6t6fBYPsDJiBZbtmyZ4IujVatWmg4pz3r58iV5eHhQhQoVMkxASpcuTb///rvW33tPSkqinTt3Uq1atRSeq46ODvXp04du376t6XBZNn369Elh49aJEydy41amVpyMaKnv37+TpaWl4Avj2rVrmg4rT/n8+TOtWrUq3SdEUqfChQvTiBEj6MqVK1pfM/Dt2zdasmQJlShRQuH5FixYkMaPH0+BgYGaDpepUGrjVnm34WrVqqX1CTbLvTgZ0VKLFi0SfFE4OjpqOqQ84fv37+Tt7U0dOnTIsCGqoaEh9erVi44ePaq1DVHTev/+PU2aNIlMTEwUnrO1tTUtWrSIvnz5oulwmRrdv39fYePWdevWcbs0pnKcjGihqKgoKlKkiOBLgqvJsy61IaqzszMVLFgww4aorVu3pi1bttC3b980HbpK3Lt3j/r165du8lWjRg3atm1bnki6mHJiY2Np+PDhct8PXbp04catTKU4GdFC8+bNk/liYJkjkUjo1q1bNHbsWJnbXfKm2rVr09KlS+njx4+aDl0lxGIxnThxglq2bJnuebdt25ZOnz7Nv4TzscOHDyts3HrmzBlNh8fyCGWv3yIiIuRy0dHRMDMzQ1RUFExNTTUdjlp8/foVZcuWRVRUlLQsICAAtWrV0mBU2uP169fYtWsXdu3ahVevXqW7bunSpdG/f384OzujevXqORSheiUkJGDXrl3w8vLCs2fP5K6jp6eH/v37Y9KkSfy+YgCA4OBgDBgwAOfPn5dZNmnSJCxcuBCGhoYaiIzlFUpfv3MkNcqm/FAz8scffwh+nfTs2VPTIeV6YWFhtHr1amrQoIFSDVGHDx9Oly9f1vqGqGlFRETQ/Pnz060FMjMzo6lTp1JQUJCmw2W5kFgspqVLl8pt3Fq7dm2tHMaA5R5qvU2zZs0aKl26NBkaGpKDgwPdunVL4bobN26kpk2bkrm5OZmbm1Pr1q3TXV+evJ6MhIeHU6FChQTtFx4/fqzpsHKl79+/065du6hjx45KNUTt2bMnHTlyJM89vvjq1SsaNWoUGRsbKzz/UqVK0fLlyyk6OlrT4TItoKhxq7GxMa1fv55v6bEsUVsy4uPjQwYGBrRlyxZ68uQJubm5kbm5OX3+/Fnu+v3796e1a9eSv78/PXv2jH777TcyMzPL1D36vJ6MTJkyRfDh79+/v6ZDylWSk5PJ19eXXFxclGqI2qpVK/rnn3/yTEPUtK5du0a//vpruiPn1q1bl3x8fHjkXJZp6TVu7dq1K4WHh2s6RKZl1JaMODg40OjRo6XzYrGYbGxsyNPTU6ntU1JSyMTEhLZv3670MfNyMhISEiL4daurq8sDj9GPhqi3b9+m8ePHK9UQtVatWvTXX3/lyVsRKSkpdPDgQWrUqFG6r0Hnzp3p0qVL/AuWZdvhw4dlnuwDfjwCzo1bWWYoe/3WU9yaRFZSUhLu3buHGTNmSMt0dHTQpk0b3LhxQ6l9xMXFITk5GUWKFFG4TmJiIhITE6Xz0dHRmQlTqyxatAjx8fHS+QEDBqBSpUoajEiz3rx5I22I+vLly3TXLVWqlLQhqp2dXQ5FmHPi4uKwbds2LFu2DG/evJG7jqGhIQYMGIBJkyahSpUqORwhy6u6desGBwcHmcatISEhaNeuHSZPnowFCxZw41amOpnJcD59+kQA6Pr164LyKVOmkIODg1L7GDlyJJUrV47i4+MVruPh4SH3l19eqxkJCgoiQ0ND6fnp6enly54vUxuiNmzYMMMaEHNzcxo2bBj9+++/eaohalqhoaH0xx9/yP1lmjpZWFjQ7NmzKTQ0VNPhsjxMLBbTkiVLFDZuffbsmaZDZLmcWm7TZDcZ8fT0pMKFC9ODBw/SXS8hIYGioqKkU1BQUJ5MRkaOHCn4cA8fPlzTIeWY2NhY2r17t9INUXv06EGHDx/Ocw1R03ry5AkNGTKEDAwMFL4WFSpUoHXr1lFsbKymw2X5yL1796hSpUpyG7f+/ffffGuQKaSWZCQxMZF0dXXp8OHDgvIBAwZk2EHXX3/9RWZmZnTnzp3MHJKI8mabkXfv3gl+bRgYGNCHDx80HZZaJScn0+nTp8nV1VWphqgtW7akzZs309evXzUdutpIJBK6cOECderUKd3Xo0mTJnT48GFKSUnRdMgsn/r+/TsNGzaMG7eyTFFrA9YxY8ZI58ViMdna2qbbgHXx4sVkampKN27cyOzhiChvJiNDhgwRfJjHjh2r6ZDUQiKR0J07d2jChAlUvHjxDG/D1KxZk5YsWZInG6KmlZSURLt37yZ7e3uFr4WOjg717Nkzy58bxtTh0KFDChu3nj17VtPhsVxGrY/2Ghoa0rZt2+jp06c0bNgwMjc3l967dnV1penTp0vXX7RoERkYGNCBAwcoJCREOsXExKj8ZLTFq1evBLcmjIyMKDg4WNNhqdSbN29o3rx5VLly5QwTkJIlS9K0adPo4cOHmg5b7aKiosjLy4tKlSql8PUoUKAAjRkzhl6/fq3pcBmT6+PHj9SqVSu57193d3ce64hJqbXTs9WrV1OpUqXIwMCAHBwc6ObNm9JlLVq0oIEDB0rnS5cuLfcN6+HhofTx8loy4urqKngtJk+erOmQVCIsLIzWrFmT4SOoqQ1R3dzc6NKlS3m2IWpaQUFBNGXKFDI1NVX4mhQvXpwWLFhAkZGRmg6XsQyl17i1Tp063LiVEREPlJdrPX36lHR0dKQf2oIFC2r1KJmxsbG0Z88e6tSpE+np6aWbgBgYGNCvv/5Khw4dytMNUdPy9/cnFxeXdF+batWq0ZYtW/LNa8Lylrt373LjVqYQJyO5VO/evQUf2BkzZmg6pExLSUmhM2fO0IABAwTd2CuafvnllzzfEDUtiURCvr6+1Lp163Rfl9atW9OpU6f4y5ppve/fv5Obm5vc93m3bt0oIiJC0yEyDeFRe3Ohhw8fCkZLNTU1xdu3b9PtAC63ICLcv38f3t7e8PHxQWhoaLrr16hRAy4uLujXrx9KliyZQ1FqVmJiIvbs2QMvLy88fvxY7jq6urro27cvJk+ejDp16uRwhIyp16FDh+Dm5oYvX74Iym1sbLBjxw60bt1aQ5ExTeFRe3Ohbt26CX4xzJkzR9MhZejNmzc0f/58pRqilihRgqZOnZphPzJ5TWRkJC1cuJCsrKwUvjYmJibk7u6e5x/fZkxR41aRSERTpkzhxq35DNeM5DL37t1DvXr1pPOFCxfG27dvYWZmpsGo5IuIiMD+/fvh7e2N69evp7uumZkZevXqBRcXFzRr1gw6Ojo5FKXmBQYGYsWKFfjnn38QFxcnd52SJUti/PjxGDp0aK78WzOmDhKJBEuXLsXMmTORkpIiWGZvb4/du3ejcuXKWd6/WEK4/fYLwmISYGliBIeyRaCrI8pu2EwNlL1+Z2psGpZ1s2fPFsxPmTIlV12c4uLicPz4cezatQu+vr4yXyBpGRgYoFOnTnBxcUHHjh1hZGSUg5Fq3q1bt+Dl5YWDBw9CIpHIXadOnTpwd3dHr169oK+vn8MRMqZZOjo6mDp1Klq3bo3+/fsLxpm6f/8+7O3tsWLFCgwdOhQiUeaSCL/HIZh7/ClCohKkZdZmRvBwqgZHO2uVnQPLWVwzkgNu3LiBxo0bS+eLFSuGwMBAFCpUSINRAWKxGBcuXMCuXbtw6NAhxMTEpLt+ixYt4OzsjJ49e6Jw4cI5FGXuIJFIcPz4cSxduhRXr15VuF7Hjh0xefJktGzZMtNfsozlRbGxsZgwYQI2b94ss6x79+7YtGkTLCwslNqX3+MQjPS+j58vWqmftPUu9pyQ5DLKXr85GckBbdu2xblz56TzS5cuxeTJkzUSCxHB399f2hA1JCQk3fXt7OykDVFLlSqVQ1HmHvHx8di+fTuWLVuGV69eyV3HwMAALi4umDRpEqpXr57DETKmHQ4ePAg3Nzd8/fpVUK5s49YUsQQNZh3Cpw+BSPnyCclfg2Hq0AO6xiYAfiQkVmZGuDqtFd+yyUU4GcklLl++jBYtWkjnrays8ObNGxQoUCBH43j79i12794Nb29vPH/+PN11bW1t4ezsDGdnZ9SsWTOHIsxdwsLCsG7dOqxduxYRERFy1ylcuDBGjRqFMWPGwMrKKocjZEz7fPz4EQMGDMDFixcF5SKRCO7u7vjzzz8RFxeHly9f4tWrV4J/n794idjvwtrb4s5LYFSimqBsj1tDNCqvXE0LUz9uM5ILEBFmzZolKPv9999zLBGJjIyUNkS9du1auuuamppKG6I2b948XzVETevFixdYtmwZtm/fjsTERLnrlCtXDhMnTsSgQYNQsGDBHI6QMe1VokQJnD17FgsXLsS8efOkbdOICH/99ReWLVsGsVis9P6Swt/JJCNhMQkK1ma5GScjanT+/HlcvnxZOl+iRAm4ubmp9Zjx8fE4fvw4vL294efnh+TkZIXr6uvrSxuidurUKd81RE1FRLhy5Qq8vLxw7Ngxhes1bNgQ7u7u6NatG3R1dXMwQsa0T1JSEgIDA2VqOe7evauwfVpmEhEAEEeHy5RZmuTP7zFtx8mImhAR/vjjD0HZH3/8oZYLvlgsxsWLF7Fr1y4cPHgww4aozZs3lzZE1YYO19QlJSUFhw4dwtKlS3Hnzh2564hEInTr1g3u7u6CRsiMsR/fPe/fv5e5pfLq1Su8e/dO4dNmWaajC+Ny9VCgYgPoFbGFvsV/HSqmthlxKJt/v9O0GScjanLq1CncunVLOl+mTBkMGjRIZfsnIgQEBMDb2xt79uzJsCFq9erVpQ1RS5curbI4tFFMTAy2bNmC5cuX4/3793LXMTY2xqBBgzBhwgRUrFgxhyNkLPcgIgQHB8ttxxEYGIikpKQciaNu3boYNW8V5l/+0QA2bWPH1OaqHk7VuPGqluJkRA2ISKZfEQ8PDxgYGMhdPyYmBiYmJkrt+927d9i9ezd27dqFp0+fpruura0t+vfvL22Imt8fNf306RNWr16NDRs24Nu3b3LXKVasGMaOHYuRI0eiaNGiORsgYxpCRIiMjJSbcLx+/RqxsbEqOY5IJEKpUqVQpEgRfPv2DW/fvlVqu7p16+LixYswMTGBTSnZfkasuJ8RrcdP06jB4cOH8euvv0rnK1WqhCdPnkBPTzb3u3jxIhYtWoTTp08r3F9qQ9Rdu3al28cF8KMhas+ePaUNUbltA/Do0SN4eXlh9+7dCtvQVKlSBZMnT4aLi0u+bTvD8r7o6Gi5t1RevnypMEHPCmtra1SsWBGVKlVCxYoVUbFiRSQmJuLy5cs4cOAAwsNl23pkpG7duti9ezcqVarEPbBqEX6aRkMkEoncWpGfE5GUlBTMnz8f8+fPR4cOHWT2Ex8fjxMnTsDb2xu+vr5KNUR1dnZG586d+WKKH7/0zp07h6VLl+LMmTMK1/vll18wefJkdOzYMd8+QcTylvj4eLx+/Vpu0vH582eVHadIkSLSZCPtvxUqVJDW9L579w7e3t6YMWMGXrx4kan9GxkZISHhv9qPe/fuoU6dOli5ciWGDBnCj+/mMZyMqNj+/fsFI7ZWq1YNffr0Eazz8eNH9O/fH1euXAEAaRsOsViMS5cuSRuiRkdHp3usZs2awcXFJd83RE0rKSkJPj4+8PLywsOHD+Wuo6uri169emHy5MmC8YIY0xbJycl4+/atTMLx8uVLBAUFqew4BQsWlJtwVKxYUWGvqV+/fsXGjRuxc+fODGtyLSwskJSUJNPofurUqZg+fTrc3d2xZcsWaXlcXBzc3Nzg5+eHjRs38vdeXqKGQfpUTltG7U1JSaEqVaoIRqrcv3+/YJ1jx45RkSJFBOsMGjSI3N3dycbGJsORcatVq0YLFy6kd+/eaegsc6evX7/S4sWL030NCxUqRBMnTuTXjmkFsVhM7969ozNnztDatWtp/Pjx1LFjR6pQoQLp6upm+F2h7GRoaEjVqlWjbt260ZQpU2jTpk106dIlCg4OJolEolSsiYmJdPjwYerRowcZGBhkeLyePXvS0aNHKTExkcqWLStdVrRoUTp16pRg3/v37ydzc3OZ/dja2tKFCxfU8dIzFVL2+s3JiArt2LFD8GGpVasWicViIiJKSEig8ePHZ+nLwsbGhtzd3cnf31/pL4f84u3btzRhwgQqVKiQwtfP1taWFi9eTF+/ftV0uIwJSCQSCgkJoX///Zc2bdpEU6dOpW7dulH16tXJ0NBQZQmHrq4uVahQgTp06EDjx4+nNWvW0JkzZ+jt27eUkpKS5divXbtGI0eOlPmBJW9q3rw5bdq0SfA5TElJIX19fenyjx8/yj3Whw8fqEWLFjL7FIlENH36dEpMTMzSOTD142QkhyUlJVH58uUFH5SjR48SEdHLly/J3t4+U18epqamNGjQIDp//nyWvyzysjt37lCfPn3S/YVYs2ZN2rFjB39RMY2LjIykmzdv0o4dO2jWrFnUp08fsre3TzeJzspUsmRJat26NY0YMYKWLVtGx48fpxcvXqj0M/Dy5UuaPXs2lStXLsN4qlSpQgsWLFBYG/np0ycSiUQ0e/ZsSk5OTve4KSkptHDhQtLT05M5Tr169ejFixcqO0emOspev/lpmmxKbdW9a8dWrJ03RVpev3593Lp1C3v27MHw4cPx/fv3DPelr6+Pjh07ShuiGhsbqzN0rSORSHDy5El4eXnh33//Vbhe+/bt4e7ujtatW+f7x5lZzvn+/TtevXolt+FoZGSkyo5jaWkptx1H+fLl1TbUREREBPbu3Qtvb2/cvHkzw/j69esHV1dX2Nvbp/sZfPXqFT58+JDhIHlp3blzB/3798fr168F5QUKFMCqVaswePBg/tznIjxQXg7we/zjeffgyBh82jRM0DXx4cOHcezYMWzdulWpfRUuXBh3795FuXLl1BWu1kpISMDOnTvh5eWlsEW+vr4++vfvj0mTJuXbwf2Y+iUmJuLNmzdyH43NqOPBzDAzM0OlSpVkko6KFSvCzMxMZcdJT0JCAk6cOIGdO3fi1KlT0nFk5DE2Nka3bt3g6uqKtm3byu3GQJW+f/+O8ePHCxq3purRowc3bs1FOBlRM7/HIRjpfR8EIOb+SXw5u166TN+yLIoX0MHHd28ytc86dergzJkz3NnW/0VEREhHzg0LC5O7jrm5OUaMGIGxY8fCxsYmhyNkeVFKSgrev38vN+F4//49VPWVWaBAAWmC8XPSUbRoUY38updIJLh69Sp27tyJ/fv3IyoqSuG6IpEIrVq1gqurK3799VelO25Upf3792PYsGEyfaSUKFECO3fuxC+//JLjMTEhTkbUSCwhNF18ASFRCZAkJyJ4oxvE37/8t4KOLiDJ3IBPqapXr46zZ8/C2jr/9iT46tUrLF++HNu2bUN8fLzcdcqUKYOJEydi8ODBKFSoUA5HyLSdRCLBp0+f5N5SCQwMTLdfn8zQ19dH+fLlZRKOSpUqwcbGJtfcTnj27Bm8vb2xa9cuhUMkpKpRowZcXV3Rv39/2Nra5lCEigUFBcHV1VXm1q1IJMK0adMwb9486Ovrayg6xp2eqdHtt1+kXRGLv0dCx9hUmIz8PxExMi4AczNTmJiYSCdT04zn4+LiNHFaGkVEuH79OpYuXYqjR48q/PVZv359uLu749dff1V7VTDTbkSE8PBwhV2cK0p0M0tHRwelS5eW246jVKlSufZ9+vnzZ/j4+GDnzp24d+9euuva2Nigf//+cHV1zXW3QUuWLInz589j8eLF8PDwkN5OIiIsWrQI586dw+7du3mMqVyOa0ay4GjAJ4z3CZDOE0kQ438K0bcPo3DLITAuUwsifSOs6l8XXWtr/pdDbiYWi3H48GF4eXml2zCuS5cucHd3R9OmTXPNr0mWO3z79k1hw9H0bjNklq2trdxbKuXKlYOhoaHKjpNd6XWVHhcXh6NHj2Lnzp04c+YMxGLFNbgFCxZEjx494OrqipYtW2rF0BK3b99G//798eaN8BZ5wYIFsWrVKgwaNIi/P3IY14yokaWJsLt1kUgHpvadYVKnI0QiHYXrsf/ExsZi69atWL58OQIDA+WuY2RkhIEDB2LixImoXLlyDkfIcpO4uDi8fv1abi1HVsY5UaRo0aKCWylpuzgvWLCgyo6jLqmN6gWDyJnoo2vxb3hx9RQOHjyY7pN9Ojo6aNeuHVxdXdG1a1etOOe0HBwc4O/vj3HjxmHbtm3S8tjYWAwZMgR+fn7YsGEDChcurLkgmVxcM5IFqW1GQqMSIO/FE+HHKJJXp7XiwZt+EhISgjVr1mD9+vX4+vWr3HWKFi2K0aNHY9SoUbC0tMzhCJmmJCUlITAwUG4Nx8ePH1V2HBMTE4VdnGvzRSpto3oASAp/h9jHFxD79F+Iv6f/aLG9vT1cXV3Rt29fWFlZqT/YHLBv3z4MGzZMpnasRIkS8Pb2RosWLTQUWf7CDVjVLPWDD0CQkKSmHutd7Hk46zSePHkCLy8v7Nq1C0lJSXLXqVixIiZPnowBAwZwHyt5lFgsxocPH+SOqfLu3TtIJBKVHMfIyAgVKlSQm3RYWlrmuar6tI3qASDi5ArEPj6X7jalSpWCs7Mz+vTpAwsLCwQHByMkJETmXysrK2zcuFErbtP87MOHD3B1dcXly5cF5SKRCNOnT8fcuXO5cauacTKSA+RViVqbGcHDqRonIvjRgOzixYtYunQpfH19Fa7XrFkzuLu7o3Pnzjxybh5ARAgJCZF7S+XNmzcKk9HM0tPTQ7ly5eTWcJQoUSJfvZduvIlEv03/tbn6ubuBVPoGBihbpgzMzc2RmJiIkJAQhIeHK2wwbm5ujnv37ml1/0disRiLFy/G7NmzZdrI1K9fH7t370aFChU0FF3ex8lIDkmvsVh+lZycjH379mHp0qUICAiQu46Ojg569uyJyZMnw8HBIWcDZCoRGRkprdVIm3S8evUKsbGxKjmGSCRCqVKl5CYcZcqU4V+1//dzo/qU2K/4tHYgQNmraTp+/Dg6d+6czehyh/Qat65evRq//fZbnqsxyw24AWsO0dURoVF5+UNp5zdRUVHYvHkzVqxYofAef8GCBTFkyBBMmDABZcuWzeEIWWbFxMTIbcPx8uVLhW1+ssLKykphF+dGRtwQPCM/N5bXK1gYpg16QMfYFJL4aMTcPwlKylyXAaVLl0ZISAju3bsHOzu7XPXEUFak17h18ODB8PX15catGsQ1IyzbgoKCsHLlSmzcuBExMTFy17G2tsa4ceMwfPhw/rDnMvHx8Xjz5o3cpCM0NFRlxylcuLDCLs410XtnXpJRo3pJfAzEAUfw9c6xLPWvoqenBzs7O9SpUwf29vawt7dHrVq1tO5pm1R79+7F8OHDZRq3lixZEjt37uTGrSrEt2mY2t2/fx9eXl7Yu3evwv4K7OzsMHnyZPTr10/rf1lps+TkZLx7905uDUdQUJDKujgvWLCg3EdjK1asCAsLrkFUJ2Ua1deyAP78809s3Lgx3bFmlCESiVC5cmVpclKnTh3UqVNHa35svH//Hq6urrhy5YqgXCQSYcaMGZgzZ47c24BisVgrG/NqCicjTC0k/2vv3qOaPu8/gL9DMOEiFzlIAI3cmaisiB74ofNn62HTau08+626apV5HNWVdlXE1WodtnbiHDBahqV2tXYtSq1HPa31sFqsx1pRWwGrIioXL0wTh5eSoVzz/P7wkDbyDZIYEhLer3P4wy9P8v3wEMknz+Xz6PUoKSlBTk4ODhw4YLJdcnIyMjIy8Itf/ILzsDai1+vR0NAgmXDU19c/9JtPF4VCgcjISMl1HEFBQfx921FvF9XX1dVh7dq1+PDDD62WiHYJCwszJCddiYpKpbLqPayls7MTGzZsQGZmZrcPVAkJCSgqKuq2uDU9PR2ZmZk2O7DQ0TEZIatqbW1FUVERcnJyUFVVJdnG1dUVTz/9NNLT0xEXF2fbAAcIIQS0Wq3klEpNTQ1aWloe/CS9IJfLERoaKrmOQ61W85NhP2bOovozZ85gzZo12L17t9F1hUKB0tJSVFVVoaKiAuXl5Th58iRaW1stiik4ONgoOYmPj4dare43ieuxY8cwd+7cbgUYBw8ejPz8fKSkpBhijYyMRGxsLHbt2tVv4u/PmIyQVdy4cQOFhYXIz8+HVquVbOPt7Y3FixfjD3/4A4YPH27jCJ3TrVu3JEc4Lly4YHJdjiXUarXkCEdYWBgUCoXV7kP92/Hjx7F69Wp88cUPtUn279+P5ORkw7/b29tRXV1tSE7Ky8tRUVHRY0XXnvj5+RklJ2PHjkVkZKTdtmTrdDq88MILeP/997t9b/bs2SgsLIS7uzs8PT2h1+uxceNGrFixwg6ROhYmI/RQamtrkZeXhy1btpg8uG/EiBFYunQpFi1axN+LBZqbm02eqdLY2Gi1+wQEBEieGhsREQEPDw+r3Ycc34EDB7Bq1SocO3YMy5cvR3Z2do/t9Xo9amtrDclJ19fNmzd7fJwpgwcPNqw96UpSYmJibHrYYE+LW1euXIm0tDQA98oTlJaW4tFHH7VZbI6IyQhZ5OjRo8jOzsauXbtMziXHx8cjIyMDv/71r1nn4QFaW1tRV1cnOcpx9epVq93Hx8fHZIlzzm2TOYQQ+PTTT/HRRx+hqKjIosdfuXLFaPSkvLzc4te7m5sbYmNjjUZRxowZ06dbvi9duoRnnnkGhw8f7rGdSqVCeXk5goOD+ywWR8dkhHqts7MTn3zyCbKzs3HkyBGT7WbMmIGMjAxMnjyZc6U/0tHRgUuXLkmOcFy6dMlqJc7d3d0lk43o6Gj4+/vzd0JWpdfrrTplotFoUFFRYTTNU19fb9Fzubq6YtSoUUZTPI888ohVt4h3dnYiKysLa9eu7fF044kTJ+LLL7/kBzMTmIzQA925cwdbt27F3/72N9TU1Ei2USgUWLBgAdLT0xETE2PjCPsPvV6Pq1evSp6pUldXh/b2dqvcZ9CgQQgPD5fcGhscHDygSpyT87t16xYqKyuNRlGqq6st2uEjk8kQHR1tNMUzduxY+Pn5PVSMR48exbx580yeLg4Ay5YtQ25u7kPdx1kxGSGTtFotCgoKsGnTJty4IX2ap5+fH9LS0pCWltZvt+VZmxACjY2NklMqNTU1JtfOmEsmkyE0NFRylCMkJMSm8+NE/c1///tffPfdd0ZTPKdPn7Z4a3pISEi3hbJBQb07O6ylpQWbNm3C+vXrTf6t7LJjxw489dRTFsXozJiMUDdnz55Fbm4uPvjgA5Nb9CIiIpCeno6UlBSHra74IN9//73JEuf3L1p7GMHBwZJTKuHh4SwAR2SG1tZWnD592miK5+TJkxZvZQ8MDDRKTuLj4xESEmKY6hRCYMuWLVi7dq3Joy3uN3jwYHzzzTcYOXKkRTE5KyYjBODef6pDhw4hOzsbe/fuNdluwoQJyMjIwJNPPukUNSTu3r2LmpoayYTj+vXrVruPv7+/5AhHZGQkBg8ebLX7EJGxjo4OnDt3zmgXT2VlJZqamix6viFDhhglJ0OHDsU333yDHTt2mDzw836jRo3CsWPH+H//R5iMDHAdHR3YuXMnsrOzceLECck2MpkMv/rVr7B8+XIkJSXZOMKH19bWhvr6eslRjitXrljtPl5eXpIJR1RU1EPPRxOR9ej1etTV1RlN8ZSXl1u8Vd7T0xNxcXEICwszTB/1tHYEAH7zm99g27ZtaO8U+KDsIi7dvIMQPw/MTwqFwnXgrfliMjJA6XQ6w8m5ly9flmzj4eGBhQsXYunSpd1KHfc3nZ2duHLliuQIx8WLF3tc5W4OpVJpSDDuTzpUKhV3qhA5KCEEGhoajJKT8vJy/Pvf/7bo+QYNGgR/f380NzebHIV5YvEqnBkyAfofvbu6yIDUSWF4efooi+7rqJiMDDANDQ148803sXnzZpPrHlQqFV544QUsWbKkXx1aJoSARqPptkulq8R5W1ubVe7j6uqKsLAwyXUcw4cP504VogHk+vXr3arJ1tbWWufJZS4IeOo1uIfFdfvW4v8dWAkJk5EB4uTJk8jJycH27dtNrjaPiYnB8uXLMW/evD4tFPQgN27ckJxSuXDhgsUlpe8nk8mgVqu7VRuNiopCaGgoawEQkUm3b982bDXuSlSqq6strhUk91HBJ/H/4DV2uuGaiwyoXvf4gJmy6e37N/cQOiAhBD7//HPk5ORg//79Jts99thjyMjIwLRp02z2qV+n05kscW5piWgpgYGBklMqERERcHd3t9p9iGjg8PX1xaOPPmpU4r25uRnfffed0SjK6dOne1VbqPN7LfQdxiO7egF8UHYRiyaFWzt8h8ZkxIG0trZi+/btyM3NxalTpyTbyOVyzJkzB8uXL0d8fHyfxNHS0oLa2lrJAmAajcZq9xkyZIjklEpkZCRHyIjIJjw9PZGUlGS0yL+trQ1nzpwxWoNy8uRJ3L17t9vjFQGh3a5dummdmkXOhMmIA7h16xbefvttvPnmm7h27ZpkGy8vL6SmpuLFF1/EiBEjHvqeHR0duHjxouTC0cuXL1tUIVGKp6enyRLn/WldCxFRF4VCYTjQb9GiRQDuLbZfv+0LvLFjP9o0NWi7Xof26/VQBkZ3e3yIHw+ovB+TkX6svr4eeXl5ePfdd9Hc3CzZZtiwYVi6dClSU1PNPhBNr9ejoaFBckqlrq7O4oqH91MoFIiIiJBMOIKCgrhThYgcnlwux0tP/xzvVXVAP/oxAPem1O//++YiA+Ynhdohwv6NyUg/dPz4ceTk5GDnzp0mF07FxcUhIyMDs2fP7nFRphAC169fl5xSqampsbiC4f1cXFwQFhYmOcoxYsQIpyikRkTUE4WrC1InheHtQ/cOAJT6oJU6KWzALF41B5ORfkKv12Pv3r3Izs7GV199ZbKdr68vdu7ciSlTphi90G/fvi05pXLhwgWLKxJKGT58uOQIR1hYGBQKhdXuQ0TkiLq27b7zVT3rjJiBW3ttpFMvcLz+Jq7rWhDg5YaEMD/IXWS4e/cu/vnPfyI3Nxfnz59/4PMsWbIEU6ZM6ZZ0WFphUMrQoUMlt8ZGRkbCw4NznURED9LWoWcFVrDOSL9ScvoaXv20Cte+/2FKxF/egpjbZSjZ8b5VE4ne8vb2ljymPioqCr6+vjaPh4iInA/rjPQTJaev4fcflqMr42u/0YCmb/fg8ukDONFhncqipri7u5sscT506FAuHCUion7BomSkoKAAf/3rX6HRaPDII48gPz8fCQkJJtt//PHHWLNmDS5evIioqCj85S9/wfTp0022dxadeoFXP60yJCLfl+3A7UMfALDeYJSrq6vJnSrBwcEscU5ERP2e2cnIRx99hPT0dBQWFiIxMRF5eXmYOnUqzp07h4CAgG7tjxw5gqeffhpZWVl44oknsG3bNsyaNQvl5eUYM2aMVX6I/up4/U2jqRnl8FF42ETExcUFWVlZiI2NRXR0NEJCQuDqygEuIiJyXGZ/bM7NzUVqaioWLlyIUaNGobCwEB4eHtiyZYtk+zfeeAPTpk3DihUrEBMTg3Xr1iE+Ph5///vfHzr4/u66znjbrHL4aAzyD7n3Dxc5XP2GYVBAOHyG9L64l16vh1arxeOPP46IiAgmIkRE5PDMeidra2vDiRMn8PLLLxuuubi4IDk5GWVlZZKPKSsrQ3p6utG1qVOnYs+ePSbv09raitbWVsO/rbk11ZYCvIwPpZPJZPCdvABt2jp4jZ0Ouce9ImXbU/8HI/1cJM90OX/+PHQ6ndHz5ObmYsaMGZgyZYrNfhYiIqK+YlYy0tjYiM7OTqhUKqPrKpUK1dXVko/RaDSS7Xs6wyQrKwuvvvqqOaH1SwlhfgjycYPm+xbD5IxHZCI8IhMBADIAgT4/bPNNSEjotvamq2hZV2LSlaTk5OQgMTERnp6etv2hiIiIrKxfjvG//PLLRqMpTU1NUKvVdozIMnIXGTJnjsLvPyyHDMarRbr2sWTOHAW5i+ldLTKZDCqVCiqVCpMmTerLcImIiOzCrDUj/v7+kMvl0Gq1Rte1Wi0CAwMlHxMYGGhWewBQKpXw9vY2+nJU08YE4a1n4hHoYzxlE+jjhreeice0MUF2ioyIiKh/MGtkRKFQYNy4cSgtLcWsWbMA3FtQWVpaiueff17yMUlJSSgtLcXSpUsN1/bv3290HLOzmzYmCD8fFShZgZWIiGigM3uaJj09HSkpKRg/fjwSEhKQl5eH5uZmLFy4EACwYMECDBs2DFlZWQCAF198EZMnT0ZOTg5mzJiB4uJifPvtt9i8ebN1f5J+Tu4iQ1JE73fNEBERDRRmJyNz5szBf/7zH/zpT3+CRqNBXFwcSkpKDItUL1++bFRoa8KECdi2bRteeeUVrFq1ClFRUdizZ4/T1xghIiKi3uHZNERERNQnevv+zVrhREREZFdMRoiIiMiumIwQERGRXTEZISIiIrtiMkJERER2xWSEiIiI7IrJCBEREdkVkxEiIiKyKyYjREREZFdml4O3h64isU1NTXaOhIiIiHqr6337QcXeHSIZ0el0AAC1Wm3nSIiIiMhcOp0OPj4+Jr/vEGfT6PV6XL16FV5eXpDJZFZ73qamJqjValy5coVn3vQh9rPtsK9tg/1sG+xn2+jLfhZCQKfTITg42OgQ3fs5xMiIi4sLhg8f3mfP7+3tzRe6DbCfbYd9bRvsZ9tgP9tGX/VzTyMiXbiAlYiIiOyKyQgRERHZ1YBORpRKJTIzM6FUKu0dilNjP9sO+9o22M+2wX62jf7Qzw6xgJWIiIic14AeGSEiIiL7YzJCREREdsVkhIiIiOyKyQgRERHZldMnIwUFBQgNDYWbmxsSExNx/PjxHtt//PHHGDlyJNzc3BAbG4t9+/bZKFLHZk4/v/POO5g0aRKGDBmCIUOGIDk5+YG/F/qBua/pLsXFxZDJZJg1a1bfBugkzO3n27dvIy0tDUFBQVAqlYiOjubfj14wt5/z8vLwk5/8BO7u7lCr1Vi2bBlaWlpsFK1jOnToEGbOnIng4GDIZDLs2bPngY85ePAg4uPjoVQqERkZia1bt/ZtkMKJFRcXC4VCIbZs2SLOnDkjUlNTha+vr9BqtZLtv/76ayGXy8XGjRtFVVWVeOWVV8SgQYPEqVOnbBy5YzG3n+fOnSsKCgpERUWFOHv2rPjtb38rfHx8RENDg40jdzzm9nWX+vp6MWzYMDFp0iTxy1/+0jbBOjBz+7m1tVWMHz9eTJ8+XRw+fFjU19eLgwcPisrKShtH7ljM7eeioiKhVCpFUVGRqK+vF//6179EUFCQWLZsmY0jdyz79u0Tq1evFrt27RIAxO7du3tsX1dXJzw8PER6erqoqqoS+fn5Qi6Xi5KSkj6L0amTkYSEBJGWlmb4d2dnpwgODhZZWVmS7WfPni1mzJhhdC0xMVEsXry4T+N0dOb28/06OjqEl5eXeP/99/sqRKdhSV93dHSICRMmiH/84x8iJSWFyUgvmNvPb731lggPDxdtbW22CtEpmNvPaWlpYsqUKUbX0tPTxcSJE/s0TmfSm2Tkj3/8oxg9erTRtTlz5oipU6f2WVxOO03T1taGEydOIDk52XDNxcUFycnJKCsrk3xMWVmZUXsAmDp1qsn2ZFk/3+/OnTtob2+Hn59fX4XpFCzt69deew0BAQFYtGiRLcJ0eJb08yeffIKkpCSkpaVBpVJhzJgxWL9+PTo7O20VtsOxpJ8nTJiAEydOGKZy6urqsG/fPkyfPt0mMQ8U9ngvdIiD8izR2NiIzs5OqFQqo+sqlQrV1dWSj9FoNJLtNRpNn8Xp6Czp5/u99NJLCA4O7vbiJ2OW9PXhw4fx7rvvorKy0gYROgdL+rmurg4HDhzAvHnzsG/fPtTU1OC5555De3s7MjMzbRG2w7Gkn+fOnYvGxkb87Gc/gxACHR0dWLJkCVatWmWLkAcMU++FTU1NuHv3Ltzd3a1+T6cdGSHHsGHDBhQXF2P37t1wc3OzdzhORafTYf78+XjnnXfg7+9v73Ccml6vR0BAADZv3oxx48Zhzpw5WL16NQoLC+0dmlM5ePAg1q9fj02bNqG8vBy7du3CZ599hnXr1tk7NHpITjsy4u/vD7lcDq1Wa3Rdq9UiMDBQ8jGBgYFmtSfL+rlLdnY2NmzYgC+++AI//elP+zJMp2BuX9fW1uLixYuYOXOm4ZperwcAuLq64ty5c4iIiOjboB2QJa/poKAgDBo0CHK53HAtJiYGGo0GbW1tUCgUfRqzI7Kkn9esWYP58+fjd7/7HQAgNjYWzc3NePbZZ7F69Wq4uPDztTWYei/09vbuk1ERwIlHRhQKBcaNG4fS0lLDNb1ej9LSUiQlJUk+Jikpyag9AOzfv99ke7KsnwFg48aNWLduHUpKSjB+/HhbhOrwzO3rkSNH4tSpU6isrDR8Pfnkk3jsscdQWVkJtVpty/AdhiWv6YkTJ6KmpsaQ7AHA+fPnERQUxETEBEv6+c6dO90Sjq4EUPCYNauxy3thny2N7QeKi4uFUqkUW7duFVVVVeLZZ58Vvr6+QqPRCCGEmD9/vli5cqWh/ddffy1cXV1Fdna2OHv2rMjMzOTW3l4wt583bNggFAqF2Llzp7h27ZrhS6fT2etHcBjm9vX9uJumd8zt58uXLwsvLy/x/PPPi3Pnzom9e/eKgIAA8frrr9vrR3AI5vZzZmam8PLyEtu3bxd1dXXi888/FxEREWL27Nn2+hEcgk6nExUVFaKiokIAELm5uaKiokJcunRJCCHEypUrxfz58w3tu7b2rlixQpw9e1YUFBRwa+/Dys/PFyNGjBAKhUIkJCSIo0ePGr43efJkkZKSYtR+x44dIjo6WigUCjF69Gjx2Wef2Thix2ROP4eEhAgA3b4yMzNtH7gDMvc1/WNMRnrP3H4+cuSISExMFEqlUoSHh4s///nPoqOjw8ZROx5z+rm9vV2sXbtWRERECDc3N6FWq8Vzzz0nbt26ZfvAHciXX34p+Te3q29TUlLE5MmTuz0mLi5OKBQKER4eLt57770+jVEmBMe2iIiIyH6cds0IEREROQYmI0RERGRXTEaIiIjIrpiMEBERkV0xGSEiIiK7YjJCREREdsVkhIiIiOyKyQgRERHZFZMRIiIisismI0RERGRXTEaIiIjIrpiMEBERkV39PyGXe5RCNUlsAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Greedy rollouts over untrained model\n", + "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", + "td_init = env.reset(batch_size=[3]).to(device)\n", + "policy = model.policy.to(device)\n", + "out = policy(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True)\n", + "actions_untrained = out['actions'].cpu().detach()\n", + "rewards_untrained = out['reward'].cpu().detach()\n", + "\n", + "for i in range(3):\n", + " print(f\"Problem {i+1} | Cost: {-rewards_untrained[i]:.3f}\")\n", + " env.render(td_init[i], actions_untrained[i])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Training loop" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using 16bit Automatic Mixed Precision (AMP)\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "IPU available: False, using: 0 IPUs\n", + "HPU available: False, using: 0 HPUs\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/logger_connector/logger_connector.py:75: Starting from v1.9.0, `tensorboardX` has been removed as a dependency of the `lightning.pytorch` package, due to potential conflicts with other packages in the ML ecosystem. For this reason, `logger=True` will use `CSVLogger` as the default logger, unless the `tensorboard` or `tensorboardX` packages are found. Please `pip install lightning[extra]` or one of them to enable TensorBoard support by default\n", + "val_file not set. Generating dataset instead\n", + "test_file not set. Generating dataset instead\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "\n", + " | Name | Type | Params\n", + "--------------------------------------------------\n", + "0 | env | TSPEnv | 0 \n", + "1 | policy | AttentionModelPolicy | 710 K \n", + "2 | baseline | WarmupBaseline | 710 K \n", + "--------------------------------------------------\n", + "1.4 M Trainable params\n", + "0 Non-trainable params\n", + "1.4 M Total params\n", + "5.682 Total estimated model params size (MB)\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "e355955596da4bda95ed46208d002f10", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Sanity Checking: | | 0/? [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Greedy rollouts over trained policy (same states as previous plot)\n", + "policy = model.policy.to(device)\n", + "out = policy(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True)\n", + "actions_trained = out['actions'].cpu().detach()\n", + "\n", + "# Plotting\n", + "import matplotlib.pyplot as plt\n", + "for i, td in enumerate(td_init):\n", + " fig, axs = plt.subplots(1,2, figsize=(11,5))\n", + " env.render(td, actions_untrained[i], ax=axs[0]) \n", + " env.render(td, actions_trained[i], ax=axs[1])\n", + " axs[0].set_title(f\"Untrained | Cost = {-rewards_untrained[i].item():.3f}\")\n", + " axs[1].set_title(r\"Trained $\\pi_\\theta$\" + f\"| Cost = {-out['reward'][i].item():.3f}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that solutions are way better than with the untrained model, even just after 3 epochs! 🚀" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "env", + "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.11.8" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/3-creating-new-env-model/index.html b/examples/3-creating-new-env-model/index.html new file mode 100644 index 00000000..bea57b0a --- /dev/null +++ b/examples/3-creating-new-env-model/index.html @@ -0,0 +1,4916 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + New Environment: Creating and Modeling - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..8df0f647 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,30 @@ +# 🧩 Examples and Tutorials + +This is a collection of examples and tutorials for using the RL4CO library. + +The root directory is made of quickstarts and contains the following: + + +## ⚡️ Quickstarts + +This is the root directory of the examples. The following quickstarts are available: +- [`1-quickstart.ipynb`](1-quickstart.ipynb): here we train a model on a simple environment - it takes less than 2 minutes! +- [`2-full-training.ipynb`](2-full-training.ipynb): similar to the previous notebooks but with a more interesting environment, with checkpointing, logging, and callbacks. + + - [`2b-train-simple.py`](2b-train-simple.py): here we show a simple script that can be called with `python 2b-train-simple.py`. This is simplified and _does not use Hydra_ - for those who prefer a simpler setup. Note that we also made a Hydra tutorial [here](advanced/1-hydra-config.ipynb). +- [`3-creating-new-env-model.ipynb`](3-creating-new-env-model.ipynb): here we show how to extend RL4CO to solve new problems and create new models from zero to hero! + + +## 📁 Folders Index + +### Modeling +Under the [`modeling/`](modeling) directory, here are some additional examples for modeling and inference. + +### Datasets +Under the [`datasets/`](datasets) directory, here are some additional examples for using your custom data to train/evaluate your models + +### Advanced +Under the [`advanced/`](advanced) directory, here are some additional examples for advanced topics. + +### Other +Under the [`other/`](other) directory, here are some additional examples for other topics. diff --git a/examples/advanced/1-hydra-config/1-hydra-config.ipynb b/examples/advanced/1-hydra-config/1-hydra-config.ipynb new file mode 100644 index 00000000..a02d31bc --- /dev/null +++ b/examples/advanced/1-hydra-config/1-hydra-config.ipynb @@ -0,0 +1,430 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Hydra Configuration\n", + "\n", + "\"Open\n", + "\n", + "[Hydra](https://hydra.cc/docs/intro/) makes it extremely convenient to configure projects with lots of parameter settings like the RL4CO library. \n", + "\n", + "While you don't need Hydra to use RL4CO, it is recommended to use it for your own projects to make it easier to manage the configuration of your experiments.\n", + "\n", + "Hydra uses config files in `.yaml` format for this. These files can be found in the [configs/](../../../configs/) folder, where the subfolders define configurations for specific parts of the framework which are then combined in the [main.yaml](../../../configs/main.yaml) configuration. In this tutorial we will have a look at how to use these different configuration files and how to add new parameters to the configuration." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from hydra import compose, initialize\n", + "from omegaconf import OmegaConf\n", + "\n", + "ROOT_DIR = \"../../\" # relative to this file" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# context initialization\n", + "with initialize(version_base=None, config_path=ROOT_DIR+\"configs\"):\n", + " cfg = compose(config_name=\"main\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Hydra stores the configurations in a dictionary like object called OmegaConf" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "omegaconf.dictconfig.DictConfig" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(cfg)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The different subfolders in the configs folder are represented as distinct keys in the omegaconf" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['mode',\n", + " 'tags',\n", + " 'train',\n", + " 'test',\n", + " 'compile',\n", + " 'ckpt_path',\n", + " 'seed',\n", + " 'matmul_precision',\n", + " 'model',\n", + " 'callbacks',\n", + " 'logger',\n", + " 'trainer',\n", + " 'paths',\n", + " 'extras',\n", + " 'env']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "list(cfg.keys())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Keys can be accessed using the dot notation (e.g. `cfg.model`) or via normal dictionaries:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "print(cfg.model == cfg[\"model\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The dot notation is however more convenient especially in nested structures" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "print(cfg.model._target_ == cfg[\"model\"][\"_target_\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For example, lets look at the model configuration (which corresponds the [model/default.yaml](../../../configs/model/default.yaml) configuration). " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "generate_default_data: true\n", + "metrics:\n", + " train:\n", + " - loss\n", + " - reward\n", + " val:\n", + " - reward\n", + " test:\n", + " - reward\n", + " log_on_step: true\n", + "_target_: rl4co.models.AttentionModel\n", + "baseline: rollout\n", + "batch_size: 512\n", + "val_batch_size: 1024\n", + "test_batch_size: 1024\n", + "train_data_size: 1280000\n", + "val_data_size: 10000\n", + "test_data_size: 10000\n", + "optimizer_kwargs:\n", + " lr: 0.0001\n", + "\n" + ] + } + ], + "source": [ + "print(OmegaConf.to_yaml(cfg.model))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we want to change parts of the configuration, it is generally a good practice to make the changes via the command line when executing the respective python script (in the case of RL4CO for example [rl4co/tasks/train.py](../../../rl4co/tasks/train.py)). For example, if we want to use a different model configuration, we can do something like:\n", + "\n", + "```bash\n", + "python train.py model=pomo model.batch_size=32\n", + "```\n", + "\n", + "Here we use the model/pomo.yaml configuration for the model and also change the batch size during training to 32. \n", + "\n", + "> Note: check out the see [override syntax documentation](https://hydra.cc/docs/1.1/advanced/override_grammar/basic/) on the Hydra website for more!" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "generate_default_data: true\n", + "metrics:\n", + " train:\n", + " - loss\n", + " - reward\n", + " val:\n", + " - reward\n", + " - max_reward\n", + " - max_aug_reward\n", + " test: ${metrics.val}\n", + " log_on_step: true\n", + "_target_: rl4co.models.POMO\n", + "num_augment: 8\n", + "batch_size: 32\n", + "val_batch_size: 1024\n", + "test_batch_size: 1024\n", + "train_data_size: 1280000\n", + "val_data_size: 10000\n", + "test_data_size: 10000\n", + "optimizer_kwargs:\n", + " lr: 0.0001\n", + "\n" + ] + } + ], + "source": [ + "with initialize(version_base=None, config_path=ROOT_DIR+\"configs\"):\n", + " cfg = compose(config_name=\"main\", overrides=[\"model=pomo\",\"model.batch_size=32\"])\n", + " print(OmegaConf.to_yaml(cfg.model))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "It is also possible to add new parameters to a config using the `+` prefix. Using `++` will add a new parameter if it does not exist and _overwrite_ it if it does. " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "generate_default_data: true\n", + "metrics:\n", + " train:\n", + " - loss\n", + " - reward\n", + " val:\n", + " - reward\n", + " - max_reward\n", + " - max_aug_reward\n", + " test: ${metrics.val}\n", + " log_on_step: true\n", + "_target_: rl4co.models.POMO\n", + "num_augment: 8\n", + "batch_size: 32\n", + "val_batch_size: 1024\n", + "test_batch_size: 1024\n", + "train_data_size: 1280000\n", + "val_data_size: 10000\n", + "test_data_size: 10000\n", + "optimizer_kwargs:\n", + " lr: 0.0001\n", + "num_starts: 10\n", + "\n" + ] + } + ], + "source": [ + "with initialize(version_base=None, config_path=ROOT_DIR+\"configs\"):\n", + " cfg = compose(config_name=\"main\", overrides=[\"model=pomo\",\"model.batch_size=32\",\"+model.num_starts=10\"])\n", + " print(OmegaConf.to_yaml(cfg.model))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Likewise, we can also remove unwanted parts of the configuration. For example, if we do not want to use any experiment configuration, we can remove the changes to the configuration made by [experiments/base.yaml](../../../configs/experiment/base.yaml) using the `~` prefix:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "generate_default_data: true\n", + "metrics:\n", + " train:\n", + " - loss\n", + " - reward\n", + " val:\n", + " - reward\n", + " - max_reward\n", + " - max_aug_reward\n", + " test: ${metrics.val}\n", + " log_on_step: true\n", + "_target_: rl4co.models.POMO\n", + "num_augment: 8\n", + "\n" + ] + } + ], + "source": [ + "with initialize(version_base=None, config_path=ROOT_DIR+\"configs\"):\n", + " cfg = compose(config_name=\"main\", overrides=[\"model=pomo\",\"~experiment\"])\n", + " print(OmegaConf.to_yaml(cfg.model))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you can see, parameters like \"batch_size\" were removed from the model config, as those were set by the experiment config base.yaml. Through the hashbang\n", + "```\n", + "# @package _global_\n", + "```\n", + "in the [configs/experiments/base.yaml](../../../configs/experiment/base.yaml), this configuration is able to make changes to all parts of the configuration (like model, trainer, logger). So instead of adding a new key to the omegaconf object, configurations with a ```# @package _global_``` hashbang typically alter other parts of the configuration. \n", + "\n", + "Another example of such a configuration is the debug/default.yaml, which sets all parameters into a lightweight debugging mode:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "generate_default_data: true\n", + "metrics:\n", + " train:\n", + " - loss\n", + " - reward\n", + " val:\n", + " - reward\n", + " test:\n", + " - reward\n", + " log_on_step: true\n", + "_target_: rl4co.models.AttentionModel\n", + "baseline: rollout\n", + "batch_size: 8\n", + "val_batch_size: 32\n", + "test_batch_size: 32\n", + "train_data_size: 64\n", + "val_data_size: 1000\n", + "test_data_size: 1000\n", + "optimizer_kwargs:\n", + " lr: 0.0001\n", + "\n" + ] + } + ], + "source": [ + "with initialize(version_base=None, config_path=ROOT_DIR+\"configs\"):\n", + " cfg = compose(config_name=\"main\", overrides=[\"debug=default\"])\n", + " print(OmegaConf.to_yaml(cfg.model))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Summary\n", + "\n", + "- Reference config files using the CLI flag ```=``` (e.g. ```model=am```)\n", + "- Add parameters (or even entire keys) to the config using the \"+\" prefix (e.g. ```+model.batch_size=32```)\n", + "- Remove parameters (or even entire keys) to the config using the \"~\" prefix (e.g. ```~logger.wandb```)\n", + "- The ```# @package _global_``` hashbang allows global access from any config file\n", + "- Turn on debugging mode using ```debug=default```" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "rl4co", + "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.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/advanced/1-hydra-config/index.html b/examples/advanced/1-hydra-config/index.html new file mode 100644 index 00000000..b63a4f77 --- /dev/null +++ b/examples/advanced/1-hydra-config/index.html @@ -0,0 +1,3592 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Hydra Configuration - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/advanced/2-flash-attention-2/2-flash-attention-2.ipynb b/examples/advanced/2-flash-attention-2/2-flash-attention-2.ipynb new file mode 100644 index 00000000..f04ab213 --- /dev/null +++ b/examples/advanced/2-flash-attention-2/2-flash-attention-2.ipynb @@ -0,0 +1,410 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Using Flash Attention 2 ⚡" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this notebook we will compare [Flash Attention 2](https://github.com/Dao-AILab/flash-attention) with the [`torch.nn.functional.scaled_dot_product_attention`](https://pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html) function and a simple implementation." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Installation\n", + "\n", + "Follow instructions here:\n", + "https://github.com/Dao-AILab/flash-attention" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "## Uncomment the following line to install the package from PyPI\n", + "## You may need to restart the runtime in Colab after this\n", + "## Remember to choose a GPU runtime for faster training!\n", + "\n", + "# !pip install rl4co" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/botu/.local/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "import torch\n", + "import torch.utils.benchmark as benchmark\n", + "\n", + "\n", + "# Simple implementation in PyTorch\n", + "from rl4co.models.nn.attention import scaled_dot_product_attention_simple\n", + "# PyTorch official implementation of FlashAttention 1\n", + "from torch.nn.functional import scaled_dot_product_attention\n", + "# FlashAttention 2\n", + "from rl4co.models.nn.flash_attention import scaled_dot_product_attention_flash_attn\n", + "\n", + "from rl4co.envs import TSPEnv\n", + "from rl4co.models.zoo.am import AttentionModel\n", + "from rl4co.utils.trainer import RL4COTrainer\n", + "from rl4co.models.common.constructive.autoregressive import GraphAttentionEncoder\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Testing differences with simple tensors" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "True\n", + "tensor(0.0005, device='cuda:0', dtype=torch.float16) tensor(1.2159e-05, device='cuda:0', dtype=torch.float16)\n", + "tensor(0.0005, device='cuda:0', dtype=torch.float16) tensor(6.3777e-06, device='cuda:0', dtype=torch.float16)\n" + ] + } + ], + "source": [ + "bs, head, length, d = 64, 8, 512, 128\n", + "\n", + "query = torch.rand(bs, head, length, d, dtype=torch.float16, device=\"cuda\")\n", + "key = torch.rand(bs, head, length, d, dtype=torch.float16, device=\"cuda\")\n", + "value = torch.rand(bs, head, length, d, dtype=torch.float16, device=\"cuda\")\n", + "\n", + "# Simple implementation in PyTorch\n", + "out_simple = scaled_dot_product_attention_simple(query, key, value)\n", + "\n", + "# PyTorch official implementation of FlashAttention 1\n", + "out_pytorch = scaled_dot_product_attention(query, key, value)\n", + "\n", + "# FlashAttention 2\n", + "out_flash_attn = scaled_dot_product_attention_flash_attn(query, key, value)\n", + "\n", + "\n", + "print(torch.allclose(out_simple, out_pytorch, atol=1e-3))\n", + "print(torch.allclose(out_flash_attn, out_pytorch, atol=1e-3))\n", + "\n", + "print(torch.max(torch.abs(out_simple - out_pytorch)), torch.mean(torch.abs(out_simple - out_pytorch)))\n", + "print(torch.max(torch.abs(out_flash_attn - out_pytorch)), torch.mean(torch.abs(out_flash_attn - out_pytorch)))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Testing Graph Attention Encoders with Flash Attention 2" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "GraphAttentionEncoder(\n", + " (init_embedding): TSPInitEmbedding(\n", + " (init_embed): Linear(in_features=2, out_features=128, bias=True)\n", + " )\n", + " (net): GraphAttentionNetwork(\n", + " (layers): Sequential(\n", + " (0): MultiHeadAttentionLayer(\n", + " (0): SkipConnection(\n", + " (module): MultiHeadAttention(\n", + " (Wqkv): Linear(in_features=128, out_features=384, bias=True)\n", + " (out_proj): Linear(in_features=128, out_features=128, bias=True)\n", + " )\n", + " )\n", + " (1): Normalization(\n", + " (normalizer): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", + " )\n", + " (2): SkipConnection(\n", + " (module): Sequential(\n", + " (0): Linear(in_features=128, out_features=512, bias=True)\n", + " (1): ReLU()\n", + " (2): Linear(in_features=512, out_features=128, bias=True)\n", + " )\n", + " )\n", + " (3): Normalization(\n", + " (normalizer): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", + " )\n", + " )\n", + " (1): MultiHeadAttentionLayer(\n", + " (0): SkipConnection(\n", + " (module): MultiHeadAttention(\n", + " (Wqkv): Linear(in_features=128, out_features=384, bias=True)\n", + " (out_proj): Linear(in_features=128, out_features=128, bias=True)\n", + " )\n", + " )\n", + " (1): Normalization(\n", + " (normalizer): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", + " )\n", + " (2): SkipConnection(\n", + " (module): Sequential(\n", + " (0): Linear(in_features=128, out_features=512, bias=True)\n", + " (1): ReLU()\n", + " (2): Linear(in_features=512, out_features=128, bias=True)\n", + " )\n", + " )\n", + " (3): Normalization(\n", + " (normalizer): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", + " )\n", + " )\n", + " (2): MultiHeadAttentionLayer(\n", + " (0): SkipConnection(\n", + " (module): MultiHeadAttention(\n", + " (Wqkv): Linear(in_features=128, out_features=384, bias=True)\n", + " (out_proj): Linear(in_features=128, out_features=128, bias=True)\n", + " )\n", + " )\n", + " (1): Normalization(\n", + " (normalizer): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", + " )\n", + " (2): SkipConnection(\n", + " (module): Sequential(\n", + " (0): Linear(in_features=128, out_features=512, bias=True)\n", + " (1): ReLU()\n", + " (2): Linear(in_features=512, out_features=128, bias=True)\n", + " )\n", + " )\n", + " (3): Normalization(\n", + " (normalizer): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n", + " )\n", + " )\n", + " )\n", + " )\n", + ")" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "env = TSPEnv(generator_params=dict(num_loc=1000))\n", + "\n", + "num_heads = 8\n", + "embed_dim = 128\n", + "num_layers = 3\n", + "enc_simple = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers,\n", + " sdpa_fn=scaled_dot_product_attention_simple)\n", + "\n", + "enc_fa1 = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers,\n", + " sdpa_fn=scaled_dot_product_attention)\n", + "\n", + "enc_fa2 = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers,\n", + " sdpa_fn=scaled_dot_product_attention_flash_attn)\n", + "\n", + "# Flash Attention supports only FP16 and BFloat16\n", + "enc_simple.to(\"cuda\").half()\n", + "enc_fa1.to(\"cuda\").half()\n", + "enc_fa2.to(\"cuda\").half()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "def build_models(num_heads=8, embed_dim=128, num_layers=3):\n", + " enc_simple = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers,\n", + " sdpa_fn=scaled_dot_product_attention_simple)\n", + "\n", + " enc_fa1 = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers,\n", + " sdpa_fn=scaled_dot_product_attention)\n", + "\n", + " enc_fa2 = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers,\n", + " sdpa_fn=scaled_dot_product_attention_flash_attn)\n", + "\n", + " # Flash Attention supports only FP16 and BFloat16\n", + " enc_simple.to(\"cuda\").half()\n", + " enc_fa1.to(\"cuda\").half()\n", + " enc_fa2.to(\"cuda\").half()\n", + " return enc_simple, enc_fa1, enc_fa2" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Times for problem size 10: Simple 0.633, FA1 0.511, FA2 0.554\n", + "Times for problem size 20: Simple 0.646, FA1 0.535, FA2 0.565\n", + "Times for problem size 50: Simple 0.663, FA1 0.547, FA2 0.580\n", + "Times for problem size 100: Simple 0.664, FA1 0.547, FA2 0.580\n", + "Times for problem size 200: Simple 0.670, FA1 0.509, FA2 0.585\n", + "Times for problem size 500: Simple 0.669, FA1 0.512, FA2 0.582\n", + "Times for problem size 1000: Simple 1.088, FA1 0.555, FA2 0.609\n", + "Times for problem size 2000: Simple 3.626, FA1 1.292, FA2 0.790\n", + "Times for problem size 5000: Simple 20.332, FA1 5.748, FA2 2.943\n", + "Times for problem size 10000: Simple 80.337, FA1 20.701, FA2 10.230\n" + ] + } + ], + "source": [ + "threads = 32\n", + "sizes = [10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000]\n", + "\n", + "times_simple = []\n", + "times_fa1 = []\n", + "times_fa2 = []\n", + "\n", + "# for embed_dim in [64, 128, 256]:\n", + "for embed_dim in [128]:\n", + " # Get models\n", + " enc_simple, enc_fa1, enc_fa2 = build_models(embed_dim=embed_dim)\n", + "\n", + " for problem_size in sizes:\n", + "\n", + " with torch.no_grad():\n", + " # initial data\n", + " env = TSPEnv(generator_params=dict(num_loc=problem_size))\n", + " td_init = env.reset(batch_size=[2])\n", + " # set dtype to float16\n", + " td_init = td_init.to(dest=\"cuda\", dtype=torch.float16)\n", + "\n", + " t_simple = benchmark.Timer(\n", + " setup='x = td_init',\n", + " stmt='encode(x)',\n", + " globals={'td_init': td_init, 'encode': enc_simple},\n", + " num_threads=threads)\n", + "\n", + " t_fa1 = benchmark.Timer(\n", + " setup='x = td_init',\n", + " stmt='encode(x)',\n", + " globals={'td_init': td_init, 'encode': enc_fa1},\n", + " num_threads=threads)\n", + " \n", + " t_fa2 = benchmark.Timer(\n", + " setup='x = td_init',\n", + " stmt='encode(x)',\n", + " globals={'td_init': td_init, 'encode': enc_fa2},\n", + " num_threads=threads)\n", + " \n", + " times_simple.append(torch.tensor(t_simple.blocked_autorange().times).mean())\n", + " times_fa2.append(torch.tensor(t_fa2.blocked_autorange().times).mean())\n", + " times_fa1.append(torch.tensor(t_fa1.blocked_autorange().times).mean())\n", + "\n", + " print(f\"Times for problem size {problem_size}: Simple {times_simple[-1]*1e3:.3f}, FA1 {times_fa1[-1]*1e3:.3f}, FA2 {times_fa2[-1]*1e3:.3f}\")\n", + "\n", + " # eliminate cache\n", + " torch.cuda.empty_cache()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1kAAAHFCAYAAAAAOjMiAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/OQEPoAAAACXBIWXMAAA9hAAAPYQGoP6dpAACnKklEQVR4nOzdd3gUVfvG8e/upickEAi9E3oLXVEQFEGsvAgiiIAiNrC8WLFjL6iA5hULigoqFrCLBUEQC6H3EkroNZAlPdmd3x+R/Ii03WQ3s5Pcn+viMtmceebOyT6Sw+zOsRmGYSAiIiIiIiI+YTc7gIiIiIiISFmiRZaIiIiIiIgPaZElIiIiIiLiQ1pkiYiIiIiI+JAWWSIiIiIiIj6kRZaIiIiIiIgPaZElIiIiIiLiQ1pkiYiIiIiI+JAWWSIiIiIiIj6kRZaIiIiIiIgPaZElIiIiIiLiQ+VikfWf//yHSpUqMWDAALOjiIiIiIhIGVcuFll33XUXH3zwgdkxRERERESkHAgyO0Bp6NGjB/Pnzy/WsW63mz179lChQgVsNptvg4mIiIiIiGUYhsGxY8eoWbMmdvvpr1eZvshasGABL730EkuXLmXv3r3Mnj2bfv36FRmTmJjISy+9xL59+2jbti2vvfYanTt3LpV8e/bsoU6dOqVyLhERERERCXw7d+6kdu3ap/266YusjIwM2rZty4033kj//v1P+vrMmTMZO3YsU6ZMoUuXLkycOJE+ffqwceNGqlatCkBCQgL5+fknHfvTTz9Rs2ZNr/Lk5OSQk5NT+LlhGABs376d6Ojosx7vcrnYunUrDRs2xOFw+HS8t7XLEyvMjRkZ/XlOX9YuSa3iHqteLX1WmRf1qn/qqFetwyrzol71T51A69VAez46nU7q169PhQoVzjjO9EVW37596du372m//sorrzBq1ChuuOEGAKZMmcJ3333Hu+++y4MPPgjAihUrfJbnueeeY/z48Sc9fvDgQbKyss56vNvtJjc3lwMHDpzxEmJxxntbuzyxwtyYkdGf5/Rl7ZLUKu6x6tXSZ5V5Ua/6p4561TqsMi/qVf/UCbReDbTnY3p6OsBZ30Zk+iLrTHJzc1m6dCnjxo0rfMxut9OrVy/+/PNPv5xz3LhxjB07tvBzp9NJnTp1aNSokcdXspKTk4mPj/d4Fe/peG9rlydWmBszMvrznL6sXZJaxT1WvVr6rDIv6lX/1FGvWodV5kW96p86gdargfZ8dDqdHo0L6EXWoUOHcLlcVKtWrcjj1apVY8OGDR7X6dWrFytXriQjI4PatWvz2Wefce65555ybGhoKKGhoSc97nA4PP7B2u12v433tnZ5YoW5MSOjP8/py9olqVXcY9Wrpc8q86Je9U8d9ap1WGVe1Kv+qRNovRpIz0dPMwT0IstXfvnlF7MjiIiIiIhIORHQi6wqVargcDjYv39/kcf3799P9erVTUp1MpfLRV5eXuHHbreb7Oxsjy+Vejre29rliRXmxp8Zg4ODA/b7FhERESlvAnqRFRISQocOHZg7d27hbd3dbjdz585lzJgx5ob7R3p6Ort27Sq8C6FhGOTn55OSkuLRvlrejPe2dnlihbnxZ0abzUbt2rWJioryaV0RERER8Z7pi6z09HSSk5MLP9+2bRsrVqwgNjaWunXrMnbsWIYPH07Hjh3p3LkzEydOJCMjo/Bug6XF5XLhcrlOemznzp1ERkZSpUoVbDYbhmGQm5tLSEiIx4ssT8d7W7s8scLc+CujYRgcOnSInTt30qhRoyJXtI5fPfv3c9cXfFm7JLWKe6y3x3kz3p/zbmVWmRczclqhV0taR71qHVaZF/Wqf+oEWq8G2vPR0xw24/glGJPMnz+fnj17nvT48OHDmTZtGgCvv/564WbECQkJTJ48mS5duvg1V2JiIomJibhcLjZt2kRSUtJJVwncbjf5+fnUqVOHsLCwwsfz8/MJCvJ8/erNeG9rlydWmBt/ZczOzmbnzp0EBQUVub2p2+0mNTWV2NhYv9xq1le1S1KruMd6e5w34/0571ZmlXkxI6cVerWkddSr1mGVeVGv+qdOoPVqoD0f09PT6dSpE2lpaWe887jpi6xA53Q6iYmJITU19aSJzM7OJiUlhQYNGhQusgzDICcnh9DQUI+vZHk63tva5YkV5safGbOzs9m2bRv16tUrsuC3wq1mS1or0G41W5JMZZ1V5kW3hfZPHfWqdVhlXtSr/qkTaL0aaM9Hp9NJbGzsWRdZgf3P/gHkVLeNdDgc2Gy2wj8nOtVjZ+LNeG9rlydWmBt/ZDxe81TPUyvcaraktQLtVrMlyVTWWWVedFto/9RRr1qHVeZFveqfOoHWq4H0fPT4e/NzDhERERERkXJFiyw5JZvNxpdffun38/To0YO7777b7+cRERERESktWmSVUwcPHuS2226jbt26hIaGUr16dfr06cOiRYsA2Lt3L3379jU5pYiIiIiI9eg9WeXU1VdfTW5uLu+//z4NGzZk//79zJ07l8OHDwME1GbPIiIiIlI+GYZBRm5g3L7dG7qS5UOGYZCZm09mruuf/3r6x5vxpx7rzU0ijx49ysKFC3nhhRfo2bMn9erVo3PnzowbN44rr7wSKPpywe3bt2Oz2fj000/p1q0b4eHhdOrUqfDW9h07diQqKoq+ffty8ODBwvOMGDGCfv36MX78eOLi4oiOjubWW28lNzf3tNlycnK49957qVWrFpGRkXTp0oX58+cX6+chIiIiItb28eKd3PzlThZvSzU7ild0JctDp9uM2DCMwj+Zufm0fPwnU/KtHd+biBDPfpyRkZFERUUxe/ZsunTpQmho6CnHnfi9ATz++OO8+uqr1K1bl5EjRzJkyBAqVKjAxIkTiYiIYNCgQTz66KO88cYbhTXmzp1LWFgY8+bNY/v27dx4443ExsbyzDPPnHQegNGjR7N+/Xo+/vhjatasyezZs7nkkktYtWoVjRs3Pu33dPz4QN6RwJ8Zj8/hv5+nVtg0saS1Am3TxJJkKuusMi/a4NQ/ddSr1mGVeVGv+qdOIPXq+r1Onvp+A7n5blbsOELnBrFeZfIHT78/LbJO48TNiAG2bNly2s2Ic3JyAMg28VJmdnYOdne+x+PfeustRo8ezZtvvklCQgLnn38+AwcOpHXr1oVjcnNzyc7OLvz+7rzzTi644AIAbrvtNoYPH873339Phw4dABg2bBjTp08nOzsbKHgShoSEkJiYSEREBI0aNeKRRx7h4Ycf5uGHH8Zutxc21/HNdKdNm8bGjRupWbMmAGPGjOGHH37g7bff5sknnzzj95Sf7/n3bxZ/ZczJySE/P5+UlJRTbkacnJzst00TfVG7JLWKe6y3x3kz3p/zbmVWmRczclqhV0taR71qHVaZF/Wqf+oESq9m5rm545td5Oa7SagaRLdqeWzevNmr78Uf0tPTPRqnRdZpjB49mtGjRxduRtyoUaPTbkYcGhpKWFgYoaEGa564mJycXEJDQ7zYjNiz8WcaGx7s8GrvpWuvvZZ+/fqxcOFC/vrrL+bMmcOrr77K22+/zYgRIwAICQn55/squNLVoUOHwo1ua9eufdJjtWrV4uDBg4WfOxwO2rZtS2zs//+rQ/fu3UlPT+fgwYPUq1evcN+DsLAwNm3ahMvlom3btkWy5uTkEBcXV2ST3VPNDRDwmxGD/zIGBQVpM+IA2DSxJJnKOqvMizY49U8d9ap1WGVe1Kv+qRMIvWoYBvd8tordzjyqR4fyYI9qNGncOCCej06n06NxWmR5yJPNiG02G5GhwTgMF2GhwR4vsjwd781YT4SHh9O7d2969+7NY489xk033cQTTzzBDTfcAHDSRsshIf+/uDv+Lw7/fsztdp9yY+Z/f3xi3eMfZ2Rk4HA4WLp06UlzHRUV5dH3rM2ItRmxP4/TBqclZ5V50Qan/qmjXrUOq8yLetU/dczu1U+X7OSrlXtx2G1MGpRATN6hgHk+ajNi8VqLFi3IyMjwac2VK1eSlZVV+Plff/1FVFQUderUOWlsu3btcLlcHDhwgPj4+CJ/dLdDERERkbJv0/5jPPbVGgDGXtyEjvUrmZyoeLTIKocOHz7MhRdeyPTp01m1ahXbtm3js88+48UXX+Sqq67y6blyc3MZOXIk69at4/vvv+fxxx9nzJgxp3ztbZMmTbjuuusYNmwYs2bNYtu2bSxevJjnnnuO7777zqe5RERERCSwZOW6GD1jGdl5bro1rsJtFzQyO1Kx6eWC5VBUVBRdunTh1VdfZcuWLeTl5VGnTh1GjRrFQw895NNzXXTRRTRu3Jju3buTk5PD4MGDeeKJJ047/r333uPpp5/mnnvuYffu3VSpUoVzzjmHyy+/3Ke5RERERCSwPP71GjYfSCeuQiivDkrAbrcR4De5PC0tssqh0NBQnnvuOZ577rnTjjnxNuP169c/6bbjPXr0OOmxESNGFN4040Tjx49n/PjxpzzPv/fACg4OPuN4ERERESl7Zi/fxadLdmG3waRrE6gSdeothqxCLxcUERERERHTbDmYzsOzC96HdedFjenaqIrJiUpOV7I85MlmxOD9hrPejLfChrunUhp5rTA32ozYP7UCadPEkmYq66wyL9rg1D911KvWYZV5Ua/6p05p92pGdi6jZywjM9fFOQ1juf2ChqX2u0xxeJrDZgTyb6UmOnEz4k2bNpGUlHTazYjr1q1buJcUFGw4GxTk+frVm/He1i5PrDA3/sqYk5PDjh07CAoKOuVmxLGxsX7bNNEXtUtSq7jHenucN+P9Oe9WZpV5MSOnFXq1pHXUq9ZhlXlRr/qnTmn36keb3Hy/6RgxYXb+d2UdKkcEnXJcoDwf09PT6dSpE2lpaSftoXsiLbLO4vhmxKmpqafdjLhBgwaFG8AWbBic4/GGs96M97Z2eWKFufFnxuzsbLZt26bNiLXBaUCzyrxog1P/1FGvWodV5kW96p86pdmr7/6ygucXHARg2oiOdGt88ssEA+356HQ6iY2NPesiK7D/2T+AeLIZ8Ym83XDWm/FW2HDXLFaYG21G7PtaZm+a6MtMZZ1V5kUbnPqnjnrVOqwyL+pV/9QpjV5NOZzJ5D8PAXB7j0b0aFbN53n8QZsRi4iIiIhIwMnJd3HnJyvIzDPoUK8iYy9uYnYkn9MiS0RERERESs3zP2xgzR4nFULtTLymLUGOsrckKXvfkYiIiIiIBKQf1+7jvUXbAbj3/KrUrBhubiA/0XuyRERERETE73YdyeS+z1YCMPL8+nSpY/57rPxFV7LkJD169ODuu+/2Sa3t27djs9lYsWKFT+qZbdq0aVSsWNHsGCIiIiKWkudyc8fHy3Fm55NQpyL3lsH3YZ1Ii6xyaMSIEUXuinj8T3JystnRaNasGaGhoezbt6/I46dbrI0YMYJ+/fr5JUv9+vWZOHFikccGDRrEpk2b/HK+E82aNYvevXtTuXLlMrVIFRERkfJpwo8bWb7jKNFhQbw2uB0hQWV7GaKXC3rI5XKdtMOzy+XCMIzCP8BJ/z0bb8Z7W/tMLrnkEt59990ij8XFxRU5hy/O402933//naysLAYMGMC0adN44IEHPK7jy7n5d90Ta4aFhREWFlas83iTMT09nfPOO4+BAwdy8803n3X+jn/9389TK+xMX9Japb0zvSfjA213+kBhlXkxI6cVerWkddSr1mGVeVGv+qeOP3p13oYDvLlgKwDP929NzZhQj88TaM9HT3NoM+LTSExMJDExEZfLxaZNm0hKSiIqKqrIGLfbTX5+PnXr1iU0NBQMA/IyyXe5CPLiPv7ejD/t2OAI8HDvpZtvvpmjR4/y6aefnvLrffr0oU2bNrz00ksAfPTRRyQmJrJ582YiIiLo0aMHL774IlWrVgXgyJEjjB07lrlz55Kenk6tWrW47777GDZsGCkpKTRv3pyPPvqIKVOmkJSURHx8PJMnT6ZLly4n5apevTrnn38+9913HytXriz8WkRERJGx3bp1o1u3bjz77LNFHp8zZw7du3dn165dPPjgg8ydOxe73U7Xrl2ZMGEC9erVKzIHXbt2ZdKkSeTl5TFgwABeeuklgoOD6dOnDwsXLixSOzMzkw8//JD777+fvXv3Fj7+1ltvMWnSJHbt2kX9+vV54IEHGDJkSJHsiYmJzJkzh19++YWaNWvy3HPPcfnll5/1Z3V8/v7880/atm172nE5OTns2LGDoKCgIruhW2Fn+pLWKu2d6T0ZH2i70wcKq8yLGTmt0KslraNetQ6rzIt61T91fN2rBzPyGf31Tpw5bq5sHsPtXap4dZ5Aez6mp6fTqVMnbUZcXKNHj2b06NE4nU5iYmJo1KjRSROZnZ1NSkoKoaGhhIWFQW4GthcbmZLXGLcbQiI9Gnt8M7ewsLBTfv34hm8nfv3pp5+madOmHDhwgHvuuYfbbruN7777DoBnnnmGjRs38v3331OlShWSk5PJysoiLCysYPEJPPnkk7z00ks0btyYRx55hBEjRrB582aCggqegseOHWP27Nn89ddfNGvWjFtuuYWkpCS6desGwN9//02XLl34+eefadmyJSEhIYSEhJCcnIzT6WTq1Knk5ORQo0YN7HY7V111Feeccw4LFiwgKCiIZ555hn79+rFy5UpCQkJwOBwsWLCAWrVqMW/ePJKTk7n22mvp0KEDo0aNYvbs2SQkJDBq1ChGjRoFFFzFCg4OLvwYYPbs2dx33328+uqr9OrVi2+//ZZbbrmFBg0a0LNnz8L5e+6553j++ed59tlneeutt7jxxhvZvn07sbGxZ/xZHZ+/wufYGQQFBVGvXr0i46ywM31Ja5XmzvSejg+03ekDhVXmxYycVujVktZRr1qHVeZFveqfOr7s1XyXm0emJuHMcdOyZjTPX9uF0H9eJujpeQLt+eh0Oj0ap0WWh061y7TD4SjyniZPryT5g7fn//bbb6lQoULh53379uWzzz4rUs/2T72RI0cWPt6oUSMmT55Mp06dyMjIICoqip07d9KuXTs6deoEQIMGDYrmAu69997CKzfjx4+nZcuWbNmyhWbNmgEwc+ZMGjduTKtWrQC49tpreffdd+nevTtA4VWzKlWqUKNGjcL64eHhhYur7OxsQkNDmTFjBm63m6lTpxae/7333qNixYr89ttv9O7dG4BKlSqRmJiIw+GgefPmXHbZZfz666/cfPPNVK5cGYfDQXR0dJHzHa93/L8vv/wyI0aMYPTo0QA0bdqUv//+m5dffpkLL7yw8LgRI0YwZMgQsrOzefbZZ3nttddISkrikksuOePP6cTz2c7w8z3+9VM9T62wM31Ja5XGzvTejg+k3ekDiVXmxYycVujVktZRr1qHVeZFveqfOr7q1Vd/SWZJyhGiQoNIHNKeiNDgYp0nkJ6PnmbQIsuXgiMwxu0mOzubsLCwM/5SfJxhGB6PP+PY4IhTH3QaPXv25I033ij8PDLy9FfBli5dyhNPPMHKlSs5cuQIbrcbgB07dtCiRQtuu+02rr76apYtW0bv3r3p168fXbt2LVKjTZs2hR8fX7QcOHCgcJH17rvvMnTo0MIxQ4cO5YILLuC1114rshj0xMqVK0lOTj7puOzsbLZs2VL4ecuWLYs0So0aNVi9erVX51q/fj0333xzkcfOO+88Jk2aVOSxE7//yMhIoqOjOXDggFfnEhEREbGKhZsPkji/4KZqz/VvTf0qnr3iqqzQIsuXbLaCl+y5HRAS5tmVJcPwfLw3Y88iMjKS+Pj4s47LyMigT58+9OnThxkzZhAXF8eOHTvo06cPubm5QMFVsJSUFL7//nt+/vlnLrroIkaPHs2ECRMK6xx/mR38/9WZ44u1devW8ddff7F48eIiN7twuVx88sknhS/X81R6ejodOnRgxowZJ30tLi7ulJmO5zqeyddK81wiIiIiZjrgzOa/M1dgGDCkS12uaFvT7Eilzvx3j0lA27BhA4cPH+b555+nW7duNGvW7JRXYOLi4hg+fDjTp09n4sSJvPXWWx6fY+rUqXTv3p2VK1eyYsWKwj9jx45l6tSpAISEhAAn39ElJCTkpMfat2/P5s2bqVq1KvHx8UX+xMTEeJzrVLX/rXnz5ixatKjIY4sWLaJFixYen0dERESkrHC5De76ZAWH0nNpVr0Cj11ePn8n0iJLzqhu3bqEhITw2muvsXXrVr7++mueeuqpImMee+wxvvrqK5KTk1m7di3ffvstzZs396h+Xl4eH374IYMHD6ZVq1ZF/tx00038/fffrF27lqpVqxIeHs6cOXPYv38/aWlpQMFeVqtWrWLjxo0cOnSIvLw8rrvuOqpUqcJVV13FwoUL2bZtG/Pnz+fOO+9k165dHn/v9evXZ8GCBezevZtDhw6dcsx9993HtGnTeOONN9i8eTOvvPIKs2bN4t577/X4PKeSmprKihUrWLduHQAbN25kxYoVJ+0fJiIiIhJI/jd/C39uPUxEiIPXh7QnLNj891GZQYssOaO4uDimTZvGZ599RosWLXj++eeLvAwQCq74jBs3jjZt2tC9e3ccDgeffPKJR/W//vprDh8+zH/+85+Tvta8eXOaN2/O1KlTCQoKYvLkybz55pvUrFmTq666CoBRo0bRtGlTOnXqRN26dVm0aBEREREsWLCAunXr0r9/f5o3b87IkSPJzs4+4602/+3JJ59k+/btNGrUqMjLDE/Ur18/Jk2axIQJE2jZsiVvvvkm7733Hj169PD4PKfy9ddf065dOy677DKg4EYg7dq1Y8qUKSWqKyIiIuIvK/dmMfnXgvdhPd2vFfFVo85yRNml92SVQ9OmTTvj1+fPn1/k88GDBzN48OAij524vdojjzzCI488cspa9evXP2kT3YoVKxZ57EwvyTt+JQfgpptu4qabbiry9bi4OH766aciNwUBqF69Ou+///5p655qDiZOnFjk83POOafIXl1QcJfAESNGFHnstttu47bbbjvtuU61CfHRo0dPO/505xEREREJVIfSc3hhwX7cBgzsUJv+7WubHclUupIlIiIiIiLF5nYb3Pv5alKzXDSuGsX4q1qaHcl0WmSJiIiIiEixTVmwhYWbDxHqsDH52rZEhOjFclpkiYiIiIhIsSzZnsrLP20C4LYuVWhSzbv9TcsqLTM95HK5TnrvkMvlwjCMwj9w6vffnIk3472tXZ5YYW78mfH4c/Dfz1OXy4Xb7T7rreiLw5e1S1KruMd6e5w34/0571ZmlXkxI6cVerWkddSr1mGVeVGv+qeON8cfycxlzMfLcbkNrmxTnYsbhfm8VwPt+ehpDpsRyL+VmigxMZHExERcLhebNm0iKSmJqKiid0hxu93k5+dTt25dQkNDCx/Pz88nKMjz9as3472tXZ5YYW78lTEnJ4cdO3YQFBSE3f7/F6jdbjepqanExsYWedwXfFm7JLWKe6y3x3kz3p/zbmVWmRczclqhV0taR71qHVaZF/Wqf+p4erxhGDwxdx9/78qkVnQwky6rSfaxoz7v1UB7Pqanp9OpUyfS0tLOeNdqLbLOwul0EhMTQ2pq6kkTmZ2dTUpKCg0aNCi8q51hGOTk5BAaGorNZjtrfW/Ge1u7PLHC3PgzY3Z2Ntu2baNevXqFz0Uo+NeW5ORk4uPjcTh8u0+FL2uXpFZxj/X2OG/G+3Percwq82JGTiv0aknrqFetwyrzol71Tx1Pj5/6+zae/WEjIUF2vrjlHJpWi/RLrwba89HpdBIbG3vWRVZg/7N/AHE4HCf9YB0OBzabrfDPiU712Jl4M97b2uWJFebGHxmP1zzV89Rut5/ycV/wZe2S1Crusd4e5814f867lVllXszIaYVeLWkd9ap1WGVe1Kv+qXO241fsPMqLPxa8D+vRy1vQuk4lXC6X33o1kJ6PHn9vfs4hIiIiIiJlRFpWHmM+Wka+2+DS1tUZ2qWu2ZECkhZZIiIiIiJyVoZh8MDnq9h1JIs6seE8f3WbgH8FkVm0yJKT9OjRg7vvvtsntbZv347NZmPFihU+qWe2adOmUbFiRbNjiIiIiJS6D/9KYc7afQQ7bCQOaU90WLDZkQKWFlnl0IgRI4q8l+z4n+TkZLOj0axZM0JDQ9m3b1+Rx0+3WBsxYgT9+vXzS5b69eszceLEIo8NGjSITZs2+eV8x+Xl5fHAAw/QunVrIiMjqVmzJsOGDWPPnj1+Pa+IiIjI6azZncbT364HYFzf5rSpXdHcQAFOi6xy6pJLLmHv3r1F/jRo0MDUTL///jtZWVkMGDCA999/39QspxMeHk7VqlX9eo7MzEyWLVvGo48+yrJly5g1axYbN27kyiuv9Ot5RURERE7lWHbB+7ByXW4ublGNG86rb3akgKdFlg8ZhkFmXiZZ+Vlk5mV6/Meb8acb6+2d+ENDQ6levXqRP6e7W8qHH35Ix44dqVChAtWrV2fIkCEcOHCg8OtHjhzhuuuuIy4ujvDwcBo3bsx7771XpMbWrVvp2bMnERERtG3blj///POk80ydOpUhQ4Zw/fXX8+677xb52vEFYLt27bDZbPTo0YMnnniC999/n6+++gq73U5ERATz588HYOfOnVxzzTVUrFiR2NhYrrrqKrZv315Y7/gVsAkTJlCjRg0qV67M6NGjycvLAwpeMpmSksJ///vfIncDPNXLBd944w0aNWpESEgITZs25cMPPyzydZvNxjvvvEP//v2pXLkyTZo04euvvz7NTwZiYmL4+eefueaaa2jatCnnnHMOr7/+OkuXLmXHjh2nPU5ERETE1wzD4KHZa9h+OJNaFcN5aYDeh+UJ3cLdh7Lyszjn43NMOfffQ/4mIjjCL7Xz8vJ46qmnaNq0KQcOHGDs2LGMGDGC77//HoBHH32UdevW8cMPP1ClShWSk5PJysoqUuPhhx9mwoQJNG7cmIcffpjBgweTnJxcuDHvsWPH+Oyzz/j7779p1qwZaWlpLFy4kG7dugGwePFiOnfuzC+//ELLli0JCQkhJCSE9evX43Q6effdd8nOzqZmzZrk5eXRp08fzj33XBYuXEhQUBBPP/00l1xyCatWrSIkJASAefPmUaNGDebNm0dycjKDBg0iISGBUaNGMWvWLNq2bcvNN9/MqFGjTjs3s2fP5q677mLixIn06tWLb7/9lhtuuIHatWvTs2fPwnHjx4/nhRde4KmnnuKtt97iuuuuIyUlhdjYWI9+BmlpadhsNr0fTERERErVJ0k7+WblHoLsNiYPbkfFiBCzI1mCFlnl1LfffktUVFTh53379uWzzz475dgbb7yx8OOGDRsyefJkOnXqRHp6OlFRUezYsYN27drRsWNHoOC9TP927733ctlllwEFC46WLVuSnJxMs2bNAPjkk09o3LgxLVu2BODaa69l6tSphYusuLg4ACpXrkz16tUL64aHh5OTk0P16tXJzs4mJCSEGTNm4Ha7eeeddwr/peW9996jYsWKzJ8/n969ewNQqVIlXn/9dRwOB82aNeOyyy5j7ty5jBo1itjYWBwOR+HVu9OZMGECI0aM4Pbbbwdg7Nix/PXXX0yYMKHIImvEiBEMHjyY7Oxsnn32WV577TUWL17MJZdcctrax2VnZ/PAAw8wePDgM256JyIiIuJL6/c6eeLrtQDc16cpHepVMjmRdWiR5UPhQeH8NfgvcnJyCA0N9ehSqmEYHo8/09jwoHCvsvbs2ZM33nij8PPIyMjTjl26dClPPPEEK1eu5MiRI7jdbgB27NhBixYtuO2227j66qtZtmwZvXv3pl+/fnTt2rVIjTZt2hR+XKNGDQAOHDhQuMh69913GTp0aOGYoUOHcsEFF/Daa69RoUIFr763lStXkpycfNJx2dnZbNmypfDzli1bFnmJZI0aNVi9erVX51q/fj0333xzkcfOO+88Jk2aVOSxE7//yMhIoqOji7zk8nTy8vK45pprMAyjyM9LRERExJ8ycvIZ89EycvLd9Ggax6huDc2OZClaZPmQzWYjIjgCu8tOWHCYx4ssT8d7M/ZsIiMjiY+PP+u4jIwM+vTpQ58+fZgxYwZxcXHs2LGDPn36kJubCxRcBUtJSeH777/n559/5qKLLmL06NFMmDChsE5w8P/f4vN49uOLtXXr1vHXX3+xePFiHnjggcJxLpeLTz755Iwv1zuV9PR0OnTowIwZM0762vErYv/OdDzX8Uy+VpxzHV9gpaSk8Ouvv+oqloiIiJSax79Zx5aDGVSLDuXlgW2x2/U+LG/oxhdyRhs2bODw4cM8//zzdOvWjWbNmp3yCkxcXBzDhw9n+vTpTJw4kbfeesvjc0ydOpXu3buzcuVKVqxYUfhn7NixTJ06FaDwfVQul6vIsSEhISc91r59ezZv3kzVqlWJj48v8icmJsbjXKeq/W/Nmzdn0aJFRR5btGgRLVq08Pg8p3J8gbV582Z++eUXKleuXKJ6IiIiIp76OdnJ7OV7sNtg8rXtqBwVanYky9GVLA+5XK6TfuF2uVwYhlH4Bzjpv2fjzXhva3ta73RfMwyDOnXqEBISwuTJk7n11ltZs2YNTz31VJExjz32GB06dKBly5bk5OTw7bff0rx585Pm5VRzlJuby4cfflj4Pq0TjRw5kldeeYU1a9bQtGlTwsPD+eGHH6hVqxZhYWHExMRQr149fvzxRzZs2EBUVBRVq1ZlyJAhvPTSS1x11VWMHz+e2rVrk5KSwqxZs7j//vupXbv2Kefg3/nq16/PggULGDRoEKGhoVSpUuWkMffee2/hDTN69erFN998w6xZs/j5559Pqn2q7/9UP4O8vDwGDhzIsmXL+Oabb8jPz2fv3r0AxMbGFi44T/Xz+vfz1OVy4Xa7z7pYLA5f1i5JreIe6+1x3oz357xbmVXmxYycVujVktZRr1qHVeZFveqfOhv3pvH6X4cAuOuixnSsV9Ev/eTp+EB7PnqaQ4us00hMTCQxMbFwIrds2VLkRhFQ8HK3/Px8cnJyijyen5/v1bm8Ge9t7VM5/ot4dnb2Kb9+/ImcnZ1NhQoVeOutt3j88cd57bXXSEhI4JlnnmHgwIHk5OSQnZ2N3W5n3LhxpKSkEB4eTteuXZk2bRrZ2dmFc3N8LFD439zcXL744gsOHz5M3759T8rToEEDmjVrxltvvcULL7zAhAkTeO6553j88cc577zz+PHHH7n++uuZN28enTt3Jj09nTlz5tC9e3d+/PFHHn30Ua6++mqOHTtGzZo16dGjByEhIWRnZ59yDo438fHHHn74Ye644w7i4+PJyckhMzOz8Bbvx8dccsklvPTSS0yYMIG7776b+vXr8+abb3LOOecUqZ2bm0tOTk6Rn19eXt4pfwYpKSmFt3hv165dka8d//7+7XjtlJQU7Pb/v0DtdrtJTU0lOTm5yOO+4MvaJalV3GO9Pc6b8f6cdyuzyryYkdMKvVrSOupV67DKvKhXfV8nO9/NXd/uIiffIKFGGL1quti8ebNfzuvp+EB7Pqanp3s0zmb46rJIGeV0OomJiSE1NfWk98RkZ2eTkpJCgwYNCAsLA7y7kYW3472tXZ5YYW78mTE7O5tt27ZRr169wuciFCwck5OTiY+PP+0+aMXly9olqVXcY709zpvx/px3K7PKvJiR0wq9WtI66lXrsMq8qFd9X2fc7DV8umQXlcIcfHfneVSL8Xx7IH/1aqA9H51OJ7GxsaSlpZ3x/fK6kuUhh8Nx0g/W4XAUblT771+aT/XYmXgz3tva5YkV5sYfGY/XPNXz1G63n/JxX/Bl7ZLUKu6x3h7nzXh/zruVWWVezMhphV4taR31qnVYZV7Uq76r89WK3Xy6ZBc2G9zfvSrVYiICplcD6fnoaQYtskREREREyrFthzJ4aFbBNjajezSiXU2TA5UB5r+wUURERERETJGd52L0jGVk5Lro0iCWOy88+xY/cnZaZImIiIiIlFPPfr+edXudxEaGMOnadji0H5ZPaJHlA7p3iJhNz0ERERHx1ver9/LBnykAvHJNW6rHhJ3lCPGUFlklcPyNb7m5uSYnkfLu+HMwEN4QKiIiIoFvx+FMHvh8FQC3XtCIHk2rmpyobNGNL0ogKCiIiIgIDh48SHBwMHa7vfA23YBXt3D3ZLy3tcsTK8yNvzK63W4OHjxIREQEQUFqaRERETmz3Hw3d3y8jGM5+XSoV4l7ejcxO1KZo9/ISsBms1GjRg22bdtGSkrBpVbDMMjPzycoKMjjRZan472tXZ5YYW78mdFut1O3bt2A/d5FREQkcLwwZwMrd6UREx7M5MHtCHboxW2+pkVWCYWEhNC4cePCl2u5XC5SUlKoV6+exxuxeTre29rliRXmxp8ZQ0JCAmIXdBEREQlsP6/bz9TftwEwYWBbalUMNzlR2aRFlg/Y7XbCwgreKOhyuQo/93SR5el4b2uXJ1aYGytkFBERkbJr99Es7v1sJQAjz2/AxS2qmZyo7NI/fYuIiIiIlHF5Ljd3fLSMtKw82taO4YFLmpkdqUzTIktEREREpIx7+adNLNtxlAphQbw+pD0hQVoG+JNmV0RERESkDJu/8QBTftsCwItXt6FObITJico+LbJERERERMqofWnZjP204H1Yw86tR9/WNUxOVD5okSUiIiIiUgblu9zc+clyUjNyaVEjmocubW52pHJDiywRERERkTJo8tzNLN6WSmSIg8Tr2hMWrLsblxYtskREREREyphFWw7z2rxkAJ7t35oGVSJNTlS+aJ8sD7lcLlwul0fj3G63R2O9He9t7fLECnNjRkZ/ntOXtUtSq7jHqldLn1XmRb3qnzrqVeuwyryoV09f51BGLmN/WIlhwDUda3N56+p+6aGSHOfp+EB7Pnqaw2YYhuHnLJaUmJhIYmIiLpeLTZs2kZSURFRU1FmPc7vdpKamEhsbi91+9guF3oz3tnZ5YoW5MSOjP8/py9olqVXcY9Wrpc8q86Je9U8d9ap1WGVe1Kunlpfv4sE5O1l7yEX9iiFMvLwWYV7crj3QejXQno/p6el06tSJtLQ0oqOjTztOi6yzcDqdxMTEkJqaesaJPM7lcpGcnEx8fDwOx9lf9+rNeG9rlydWmBszMvrznL6sXZJaxT1WvVr6rDIv6lX/1FGvWodV5kW9emqvzd3MxF+3EB5s58vbuxJf9ewXCXyRw1+9GmjPR6fTSWxs7FkXWXq5oIccDofHP1i73e638d7WLk+sMDdmZPTnOX1ZuyS1inuserX0WWVe1Kv+qaNetQ6rzIt6tai/tx5m8ryC/bDGX9mSpjViSjWHv3o1kJ6PHn9vfs4hIiIiIiJ+djg9hzs/WY7bgF6Nori6fS2zI5VrWmSJiIiIiFiY221wz2cr2e/MoVFcJKPPiTM7UrmnRZaIiIiIiIW9tXAr8zceJDTIzmvXJhAerF/xzaafgIiIiIiIRS1NSeWlHzcC8MSVLWlavYLJiQS0yBIRERERsaSjmbnc+fEKXG6DK9rW5NpOdcyOJP/QIktERERExGIMw+Dez1ax+2gW9StH8Ox/WmGz2cyOJf/QIktERERExGLeW7SdX9bvJ8Rh5/Uh7akQFmx2JDmBFlkiIiIiIhaycudRnvthPQAPX9acVrWKtx+W+I8WWSIiIiIiFuHMzmPMx8vIcxlc0rI6w86tZ3YkOQUtskRERERELMAwDB78YhU7U7OoXSmcFwa00fuwApQWWSIiIiIiFjD97x18v3ofQXYbrw9pT0y43ocVqLTIEhEREREJcGv3pPHUt+sAeLBvMxLqVDQ3kJyRFlkiIiIiIgEsPSefMR8tJzffzUXNqjLy/AZmR5Kz0CJLRERERCRAGYbBw7NXs+1QBjVjwpgwsK3eh2UBWmSJiIiIiASoT5fs5KsVe3DYbUwe3I5KkSFmRxIPaJElIiIiIhKANu47xuNfrwXgnt5N6Fg/1uRE4iktskREREREAkxmbj6jP1pGdp6b7k3iuLV7I7MjiRe0yBIRERERCTCPf7WW5APpVK0QyivXtMVu1/uwrESLLBERERGRADJr2S4+W7oLuw0mXduOKlGhZkcSL2mRJSIiIiISILYcTOeRL9cAcNdFTTi3UWWTE0lxaJElIiIiIhIAcvLd3PHxCjJzXXRtVJkxF8abHUmKSYssEREREZEA8Obiw2zcn06VqBAmDkrAofdhgSuXsNT1ZqfwmhZZIiIiIiIm+3bVXr7f5MRmg1cHJVA1OszsSAHB9tMj1Pt5JLZl08yO4pUgswOIiIiIiJRn2w9l8PA/78O67YKGdGscZ3KiALF8OvYl7wDgjqpuchjvaJHlIZfLhcvl8mic2+32aKy3472tXZ5YYW7MyOjPc/qydklqFfdY9Wrps8q8qFf9U0e9ah1WmZey0quZufnc/OES0nNctKwaypgLGpSofpnp1T3LsH87FhtwoOVNVGx0MQTAc9LT789mGIbh5yyWlJiYSGJiIi6Xi02bNpGUlERUVNRZj3O73aSmphIbG4vdfvZXY3oz3tva5YkV5saMjP48py9rl6RWcY9Vr5Y+q8yLetU/ddSr1mGVeSkLvWoYBi8uPMC8relUCnPw5PkRNKpZpdz3qiM7lfo/Dic46wDHanZjZfP7ia1csnnxlfT0dDp16kRaWhrR0dGnHadF1lk4nU5iYmJITU0940Qe53K5SE5OJj4+HofD4dPx3tYuT6wwN2Zk9Oc5fVm7JLWKe6x6tfRZZV7Uq/6po161DqvMS1no1Wl/bOep7zbgsNv4YEQHKuUfVq+68rBP/w+2HX9gVG5M3vA5JO86EDDPR6fTSWxs7FkXWXq5oIccDofHP1i73e638d7WLk+sMDdmZPTnOX1ZuyS1inuserX0WWVe1Kv+qaNetQ6rzIuVezVpeyrP/bARgIcubc45jaqwefMR9epPD8GOPyCkArZrP8IRWQm7/VDAPB89/t78nENERERERE5wwJnN7TOWke82uKJtTW48r77ZkQLDio/h7ykFH/d/E+KamJunBLTIEhEREREpJXkuN7fPWMbBYzk0rVaBF65ujc2m/bDYsxy+vbvg4wsegGaXmRqnpLTIEhEREREpJc98t54lKUeoEBrElOs7EBGid++QcQhmXg/52dDkErjgQbMTlZgWWSIiIiIipeCrFbuZ9sd2AF4ZlECDKpHmBgoE7nz4bASk7YTYRvCfNyEA7iJYUtb/DkREREREAtz6vU4e+GIVAGN6xnNxi2omJwoMtl8eh+0LISQKrv0IwiuaHckntMgSEREREfGjtKw8bp2+lOw8N90aV+G/F1v3hg6+FL19Dva/3yj4pN8bULWZuYF8SIssERERERE/cbsNxs5cQcrhTGpVDGfyte1w2HWjC/auonrSswUfd7sXWlxpbh4f0yJLRERERMRPEuclM3fDAUKC7EwZ2oFKkSFmRzJfxmHsn12P3ZWDEd8Lej5kdiKf0yJLRERERMQP5m88wCu/bALg6ata0bp2jMmJAoArHz6/AVvaTnKjauPu9xbYzd9k2Ne0yBIRERER8bGdqZnc9ckKDAMGd67LNZ3qmB0pMPzyOGz7DSM4kl3nv1hmbnTxb7oxv4iIiIiID2Xnubh1+lLSsvJoWzuGJ65sYXakwLD6c/jzdQDcV75ObnAjkwP5j65kiYiIiIj4iGEYPPLlGtbucRIbGcIbQzsQGlT2Xg7ntX2r4asxBR+f/19ocZW5efxMiywRERERER+Z8fcOPl+6C7sNXh/cjpoVw82OZL7MVPjkOsjPgkYXwYWPmp3I77TIEhERERHxgeU7jjD+m7UA3H9JM7rGVzE5UQBw5cPnN8LRFKhUH65+p0ze6OLftMgSERERESmhQ+k53DZ9GXkug0taVueW7g3NjhQYfn0Sts6D4AgYNAMiYs1OVCq0yBIRERERKYF8l5sxHy1jnzObRnGRvDSwDTabNhxmzSxYNKng46teh+qtzM1TirTIEhEREREpgRd/3MhfW1OJDHHw5vUdqBAWbHYk8+1fC1+NLvi4653Q6mpz85QyLbJERERERIrp+9V7eWvBVgBeHNCW+KoVTE4UADJT4ZMhkJcJDXtCryfMTlTqtMgSERERESmG5APHuO+zlQDc3L0hl7WpYXKiAOB2wRc3wZHtULEuDHi3XNzo4t+0yBIRERER8dKx7Dxu/nApGbkuzmkYy/19mpodKSDY5j8LW+ZCUHi5utHFv2mRJSIiIiLiBcMwuO+zVWw9mEH16DBeH9KeIId+ra6wcy72Ra8WfHLV61CjjbmBTKRng4iIiIiIF95auI05a/cR7LDxv6HtqRIVanYk8x1YR42/nyr4+Nwx0HqAuXlMFmR2ABERERERq1i+J5MJP+8F4PErWtK+biWTEwWArCPYP70eW34WRv3u2HqNNzuR6XQlS0RERETEA3uOZvH8b/txG3B1+9pc16Wu2ZHM53bBF6OwHdlGXkQN3FdPBYeu42iRJSIiIiJyFjn5LsZ8vIK0HDcta0TzzH9aacNhgPnPQfLPGEFh7Dr/eYiobHaigKBlpoiIiIjIWTzx9TpW7kojKsRO4pAEwoLL323JT7Lua1jwEgDGZRPJCW9mcqDAoStZIiIiIiJn8GnSTj5evAObDR7sXo06sRFmRzLfgQ3w5W0FH59zO0aba8zNE2B0JUtERERE5DRW70rjka/WAHDXhfF0rG2YnCgAZKfBJ0MgNx3qd4OLnzQ7UcDRlSwRERERkVM4kpHLrdOXkpvv5qJmVRndo5HZkczndsOsmyF1C0TXhgHvgSPY7FQBR4ssEREREZF/cbkN7vxkObuPZlGvcgSvDErAbteNLvjtedg0BxyhcO10iIozO1FA0iJLRERERORfXv15Ews3HyIs2M6UoR2ICdfVGjZ8B7+9UPDxFZOgZjtz8wQwLbJERERERE7w09p9vD4vGYAXrm5D8xrRJicKAAc3waxbCj7ufAskDDY3T4DTIktERERE5B/bDmVwz6crARjRtT5XJdQyOVEAyHb+c6OLY1DvPOjzjNmJAp4WWSIiIiIiQGZuPrd+uJRjOfl0rFeJhy5tbnYk87ndMPsWOLwZomvBwGm60YUHtMgSERERkXLPMAwe+GI1G/cfI65CKP+7rj0hQfpVmQUvwcbvC250MehDiKpqdiJL0DNHRERERMq9dxdt55uVewiy2/jfde2pGh1mdiTzbZwD858t+PjyV6BWB3PzWIgWWSIiIiJSri3elsqz368H4KFLm9OpfqzJiQLA4WSYNarg4043Qbuh5uaxGC2yRERERKTc2u/M5vYZy3C5Da5KqMkN59U3O5Lp7Hnp2D8dCjlOqHsu9HnO7EiWo0WWiIiIiJRLuflubp+xjEPpOTStVoHn+rfGZivnGw4bbmr89SS2Q5ugQg0Y+D4EhZidynK0yBIRERGRcunZ79ezNOUIFUKDmHJ9ByJCgsyOZDrb769SYfdvGI4QuOZDqFDN7EiWVOYXWTt37qRHjx60aNGCNm3a8Nlnn5kdSURERERMNnv5Lqb9sR2AVwcl0KBKpLmBAsGmn7D9c6MLo++LUKeTyYGsq8wv14OCgpg4cSIJCQns27ePDh06cOmllxIZqUYSERERKY/W7XEybtZqAO64MJ5eLXS1hsNb4IubsGFwJL4/0e2GmZ3I0sr8lawaNWqQkJAAQPXq1alSpQqpqanmhhIRERERU6Rl5nHr9KVk57np3iSOu3s1MTuS+XKOwSdDICcNo3Zn9rcba3aiQqnZqXy791sMwzA7ildMX2QtWLCAK664gpo1a2Kz2fjyyy9PGpOYmEj9+vUJCwujS5cuLF68uFjnWrp0KS6Xizp16pQwtYiIiIhYjdttMPbTFexIzaR2pXAmDUrAYS/vN7ow4Mvb4eAGiKqOe8A0cASbnQqAXFcuY38by/s73mfi8olmx/GK1y8XdLvd/PbbbyxcuJCUlBQyMzOJi4ujXbt29OrVy+sFTEZGBm3btuXGG2+kf//+J3195syZjB07lilTptClSxcmTpxInz592LhxI1WrFuw4nZCQQH5+/knH/vTTT9SsWROA1NRUhg0bxttvv33GPDk5OeTk5BR+7nQ6AXC5XLhcrrN+Py6XC7fb7dFYb8d7W7s8scLcmJHRn+f0Ze2S1CruserV0meVeVGv+qeOetU6rDIvxcn52q/JzN1wgJAgO4mDE4gOc3h1fFnsVduiidjXf41hD8Y94D1cEXG43Wmm96phGDz111OsOLiCCEcEVza4MiCekx7Pq+HhtbesrCxefvll3njjDVJTU0lISKBmzZqEh4eTmprKmjVr2LNnD7179+axxx7jnHPO8Tq0zWZj9uzZ9OvXr/CxLl260KlTJ15//XWgYJFXp04d7rjjDh588EGP6ubk5HDxxRczatQorr/++jOOfeKJJxg/fvxJjyclJREVFXXWc7ndblJTU4mNjcVuP/uFQm/Ge1u7PLHC3JiR0Z/n9GXtktQq7rHq1dJnlXlRr/qnjnrVOqwyL97mTNqVwWO/7MMAxp4XR+/G0X4/pxm1vakTufdPav/2X2wY7O34IGnx/wmYXv1+3/e8l/IeNmyMqTGG82ufHxDPx/T0dDp16kRaWhrR0ad/Dnl8JatJkyace+65vP3221x88cUEB598GTElJYWPPvqIa6+9locffphRo0YVL/0/cnNzWbp0KePGjSt8zG6306tXL/7880+PahiGwYgRI7jwwgvPusACGDduHGPH/v/rUJ1OJ3Xq1KFRo0ZnnMjjXC4XycnJxMfH43A4fDre29rliRXmxoyM/jynL2uXpFZxj1Wvlj6rzIt61T911KvWYZV58SbnjtRMJsz8EwMY3KkOoy9t6fdzmlXb4zqp27B/+Tg2DNzthlG17/1ULUEOX/bqn3v/5P0d7wNwd7u7OSfonIB5Ph5/ldvZeLzI+umnn2jevPkZx9SrV49x48Zx7733smPHDk9Ln9ahQ4dwuVxUq1b0ji/VqlVjw4YNHtVYtGgRM2fOpE2bNoXv9/rwww9p3br1KceHhoYSGhp60uMOh8PjH6zdbvfbeG9rlydWmBszMvrznL6sXZJaxT1WvVr6rDIv6lX/1FGvWodV5sWTnFm5LkZ/tIK0rDza1qnIE1e1LNH3VSZ6NScdPrsestOgVkfsl02AE8aa2aspzhQeWPgAbsPNlY2uZFiLYSQnJwfM89HTDB4vss62wDpRcHAwjRo18ni8P51//vm43W6zY4iIiIhIKTMMg4e/XM26vU4qR4bwxnXtCQ0y/xd1UxkGfD0GDqyDqGow6EMIOvkCgxmO5R7jzl/vxJnrpE1cGx479zFsWPPGJMV6YeOcOXP4/fffCz9PTEwkISGBIUOGcOTIEZ+Fq1KlCg6Hg/379xd5fP/+/VSvXt1n5xERERGRsmf63zuYtWw3dhu8NrgdNSuGmx3JfIsmwdrZYA+Caz6A6JpmJwLA5Xbx4MIH2Zq2lWoR1ZjUcxKhjsBY/BVHsRZZ9913X+HrEVevXs0999zDpZdeyrZt24q8n6mkQkJC6NChA3Pnzi18zO12M3fuXM4991yfnUdEREREypalKUd48pu1ADxwSTO6xlcxOVEASJ4Lc/+5wVvfF6Cu9zeq85fJyyezYNcCQh2hTLpwElXCrf3z8voW7gDbtm2jRYsWAHzxxRdcfvnlPPvssyxbtoxLL73Uq1rp6ekkJycXqb1ixQpiY2OpW7cuY8eOZfjw4XTs2JHOnTszceJEMjIyuOGGG4oTXURERETKuIPHcrh9xlLyXAZ9W1Xn5u4NzY5kvtRt8PmNYLih3VDoONLsRIW+3fot7655F4CnznuKlpWLd2OSQFKsRVZISAiZmZkA/PLLLwwbNgyA2NhYj++4cdySJUvo2bNn4efHr4QNHz6cadOmMWjQIA4ePMhjjz3Gvn37SEhIYM6cOSfdDMPftE9WYLPC3GjvHf/U0t471mGVeVGv+qeOetU6rDIvp8uZ73Iz5qOl7Hfm0Cgukuf7t/LZ+/Mt26u5Gdg/uQ5b9lGMmu1xX/IinGZOSrtXVx1YxeOLHgdgZKuR9K7bu0iNQHs++nyfrBNdeeWV5Obmct555/HUU0+xbds2atWqxU8//cSYMWPYtGmT14EDTWJiIomJibhcLjZt2qR9sgKcFeZGe+/4p1ag7Ofhi0xlnVXmRb3qnzrqVeuwyrycLufbSYf4Ym0a4UE2Jl1em7oVQ/x+zkCqfVIdw6Dmn48SveNn8kMrsb3P++RHnP5iRWn26tYDW3lxz4scyTtCh4oduL/J/dht9pPGBdLz0dN9soq1yNqxYwe33347O3fu5M4772TkyILLjf/9739xuVxMnjy5+MkDjNPpJCYmhtTUVO2TFcCsMDfae8c/tQJhPw9fZSrrrDIv6lX/1FGvWodV5uVUOb9bvZc7P1kJwOuDE+jbyrc3SrNir9r+fB37L49h2INwD/0S6nX1Sw5vj8vMzWTYd8NIzkimUUwj3u/zPlEhJ1/QCLTno9PpJDY21nebEZ+obt26fPvttyc9/uqrrxannCVon6zAZ4W50d47/qmlvXeswyrzol71Tx31qnVYZV5OzLl5/zEenLUGgFu6N+TytrX8fs5ArV1YZ/sCmPsEALY+z+Fo2M2vOTw9zjAMnkl6huSMZGJCYnjtwteICY/xeR5/8Pk+Wady4MABDhw4cNLrXNu0aVOSsiIiIiIiHjuWncctHy4lM9fFuQ0rc1+fpmZHMt/RHf9/o4u2Q6DzKLMTFZq2dhrfbfsOO3Ze6v4SdaLrmB3J54q1yFq6dCnDhw9n/fr1HH+1oc1mwzAMbDZbwLwxTURERETKNsMwuPezlWw9lEGNmDBeG9KOIIf5790xky0/G/unN0FWKtRsB5e/CrbA2NR3wa4FvLq04NVvN9S7gc7VO5ucyD+Ktci68cYbadKkCVOnTqVatWrYAuSHJiIiIiLly1sLt/Hj2v2EOOz877r2VImy7ga2PmEYVE96Dtv+1RBRBQZNh+Aws1MBsPXoVh5Y8AAGBlfHX02f2D5mR/KbYi2ytm7dyhdffEF8fLyv84iIiIiIeGT5nkwm/LwXgMevbEG7upVMTmQ+2+IpxKTMwbA5sA2cBjG1zY4EQFpOGnf8egfpeem0r9qeBzs9yPat282O5TfFWmRddNFFrFy5slwtsrRPVmCzwtxo7x3/1NLeO9ZhlXlRr/qnjnrVOqwyLzsPp/Pcb/txG3B1+1oM6lDL75kDvle3L8T+82MF9S4aj61uV/Bzz3lyXL47n3t/u5cdx3ZQI7IGE7pPwI7do/ME2vPRr/tkHTp0iOHDh9O5c2datWpFcHBwka9feeWV3pYMONony1qsMDfae8c/tbT3jnVYZV7Uq/6po161DivMS26+m3t+2M3mw7nEx4bw8qW1CA3yf9ZA7tWgjL3U/2kEQTlHOVD9Qg51exp7Me7G549enZYyje/2fUeoPZSnWzxN/cj6Hp8n0J6Pft0n65tvvuH666/H6XSeXLCM3fhC+2RZgxXmRnvv+KeW9t6xDqvMi3rVP3XUq9ZhhXl5aPYaZi7ZRYUQO1+N7kq9Kmf/h3BfCNhezcvCPu1SbPtW4q7Wmo3nTaZRs1YB0atfJn/JE389AcDL3V/moroXeXWeQHs++nWfrDvuuIOhQ4fy6KOPUq3a6XeMLku0T1bgs8LcaO8d/9TS3jvWYZV5Ua/6p4561ToCeV5mJu1g5pJd2GzwwAXVqFclqnz3qmHAD/fCvpUQHotxzXRsB7MDoleXH1jO04ufBuD2hNvp3aB3sc4TSM9Hj/8/VJzihw8f5r///W+5WWCJiIiIiPlW7TrKo1+tBeDuixrTsVaEyYkCwOK3YOXHYHPAwGlQMTD2nNqbvpe7591Nvjufi+tdzC1tbjE7Uqkq1iKrf//+zJs3z9dZREREREROKTUjl9umLyM3302v5lW5/YKGZkcy3/bfYc64go97PwUNLzA3zz+y8rO4a95dpGan0rRSU54+72nsNvPfT1WaivVywSZNmjBu3Dh+//13WrdufdKNL+68806fhBMRERERcbkN7vx4ObuPZlG/cgQvX5OA3V7O92lN2wWfDgfDBa0Hwjm3m50IKNgc+tFFj7I+dT2xYbFMvnAyEcHl74pjsRZZ77zzDlFRUfz222/89ttvRb5ms9m0yBIRERERn3nl5438nnyI8GAHU67vQEx4cJm60ZrX8rJh5lDIPATVWsMVk8EWGIvOd9a8w4/bfyTIHsSrPV6lZlRNsyOZoliLrG3btvk6h4iIiIjISX5au4/EeVsAeP7q1jSrfva7PZdphgHfjYU9yyG8Elw7HUIC40rR4tTFJG5OBOCRLo/Qvlp7kxOZp1iLrPJImxEHNivMjTY49U8tbXBqHVaZF/Wqf+qoV60jkOZl26EMxn66EoARXetxeevqhbnKa6/akt7BvmIGhs2Ou/9UiK5TZMNhs3p1w+ENTN4yGYDBTQfTr1G/M9bw9DyB9HwEP2xG/Pzzz3PXXXcRHh5+1rF///03hw4d4rLLLvMoRCDSZsTWYoW50Qan/qmlDU6twyrzol71Tx31qnUEyrxk5bm567td7DiaR8uqYbxwSU2CTngfVnns1fADy6k7bzQ2w8WBhDtIbTbU5xmLc7wzz8mDax7kYO5BWkW34pFmj+CwnflW59qM+B/Dhg3jhx9+YODAgVxxxRV07NiRuLg4APLz81m3bh2///4706dPZ8+ePXzwwQd0797dN9+NibQZsTVYYW60wal/ammDU+uwyryoV/1TR71qHYEwL4ZhcNfMlXy3eh9xUaF8PfpcqkaHmZ7T1F517sb+zoXYMg7ibvEfjP7vnPJ9WKXdq3nuPG795VaWHlhKtdBqfHTZR1SOqOyz8wTC8/FEPt+M+IMPPmDlypW8/vrrDBkyBKfTicPhIDQ0lMzMTADatWvHTTfdxIgRIwgLCztLRWvRZsSBzwpzow1O/VNLG5xah1XmRb3qnzrqVeswe17eWbiV71bvI8hu439D21OjUuQpx5WbXs3Lhs9HQMZBqNYKe79ECDr9r/Gl2avPJT3H0gNLiQyO5IEmD1A5orLPe9Xs5+OJPM3g1Xuy2rZty9tvv82bb77JqlWrSElJISsriypVqpCQkECVKlWKFVZEREREBOCvrYd57ocNADx8WXM61Y81OZHJDAO+vwd2L4WwijBoOoScetFZ2mZumMnMjTOxYePZ856lZlb5vJPgqRTrxhd2u52EhAQSEhJ8HEdEREREyqt9admM+WgZLrfBVQk1GdG1vtmRzLfkXVg+HWx2GPAuxDYwOxEASfuSeH7x8wDc2f5OLqh9AZs3bzY5VeAw/91jIiIiIlLu5ea7uX3GUg6l59KsegWe698aW4Ds/WSaHX/BDw8UfHzRYxB/kbl5/rHr2C7Gzh9LvpFP3wZ9GdlqpNmRAo4WWSIiIiJiuqe/W8eyHUepEBbElKEdiAgp5zsNOffCp8PAnQct+sF5d5udCICMvAzu+PUOjuYcpUXlFjzZ9Ukthk9BiywRERERMdWsZbv44M8UACYOSqB+lcB4z5Fp8nPg0+shfT9UbQFXJZ7yToKlzW24eWjhQyQfTaZKeBUm95xMWFDZutmdr2iRJSIiIiKmWbfHyUOzVwNw54XxXNS8msmJAsAP98OuJAiLKbjRRejZ92otDf9b8T9+3fkrIfYQJvWcRLVI/axOp0SLrOTkZH788UeysrKAgj0NREREREQ8kZaZx63Tl5Kd56Z7kzju6tXE7Eimsy2bBkunATa4eipUbmRyogJzts/hzVVvAvB418dpE9fG5ESBrVgvdj18+DCDBg3i119/xWazsXnzZho2bMjIkSOpVKkSL7/8sq9zms7lcuFyuTwa53a7PRrr7Xhva5cnVpgbMzL685y+rF2SWsU9Vr1a+qwyL+pV/9RRr1pHac2L221w1yfL2ZGaSe1K4bw6sDUYbjw9bVns1dADK7HNL7jRhbvnwxgNL8TjCfFRxlMdvyF1A4/+/igAw5oP47L6l51U31+9Gmh96mkOm1GMy0/Dhg3jwIEDvPPOOzRv3pyVK1fSsGFDfvzxR8aOHcvatWu9DhxoEhMTSUxMxOVysWnTJpKSkoiKOvulWrfbTWpqKrGxsdjtZ79Q6M14b2uXJ1aYGzMy+vOcvqxdklrFPVa9WvqsMi/qVf/UUa9aR2nNy/QVqUxfcYQQh41XLq1FfOVQr44va71qzzhAvR+HE5qbirN2T/ac91yx3ofl6149mneUB9c8yOHcwyTEJPBg0wdx2E7ekNdfvRpofZqenk6nTp1IS0sjOjr6tOOKtciqXr06P/74I23btqVChQqFi6ytW7fSpk0b0tPTSxQ+kDidTmJiYkhNTT3jRB7ncrlITk4mPj7eox2hvRnvbe3yxApzY0ZGf57Tl7VLUqu4x6pXS59V5kW96p866lXrKI15mbfxIKM+XIphwAtXt2JA+9pe1yhTverKxfbBFdh3JeGu0hTjxp8gtIIpGU883oWLUb+MYuXBldSPrs8Hl3xAdMipfx/2V68GWp86nU5iY2PPusgq1ssFMzIyiIiIOOnx1NRUQkO9+1cIq3A4HB7/YO12u9/Ge1u7PLHC3JiR0Z/n9GXtktQq7rHq1dJnlXlRr/qnjnrVOvw5LzsOZzL205UYBlzXpS6DOtUrdq0y0atuN3xzB+xKwhUcBddMxxFR0dSMdrsdu93OU38/xcqDK6kQXIHXLnyNSuGVfHpeT8cHUp96/L0Vp3i3bt344IMPCj+32Wy43W5efPFFevbsWZySIiIiIlLGZeW6uGX6UpzZ+STUqchjV7QwO5K5DAN+egRWf4ZhD2JP12cC5kYXH238iC+Tv8Rus/PSBS9RP6a+2ZEspVhXsl588UUuuugilixZQm5uLvfffz9r164lNTWVRYsW+TqjiIiIiFicYRg8PHs16/c6qRwZwhtD2xMaZP6VCVP9MRn+SgTAuOI1MsLbmxyowMqjK3l5U8GN7O7pcA/n1TrP5ETWU6wrWa1atWLTpk2cf/75XHXVVWRkZNC/f3+WL19Oo0aBsfoWERERkcAx/a8UZi3fjd0Grw1pR42YcLMjmWvFR/DzYwUf934ao80gc/P8I8WZwqvJr+I23FzV6Cqub3G92ZEsqVhXsgBiYmJ4+OGHfZlFRERERMqgpSlHePLbdQA82LcZXRtVMTmRyTb9CF+NKfj43DHQ9Q6vb9XuD8dyj3H3/LvJcGXQpkobHjv3MWzFuMOhlGCRlZ2dzapVqzhw4ABut7vI16688soSBxMRERER6ztwLJvbZywlz2VwaevqjOrW0OxI5tqZBJ8OB8MFbQbBxU+ZnQgAl9vFAwseYJtzG5VDKvPKBa8Q4ggxO5ZlFWuRNWfOHIYNG8ahQ4dO+prNZguYzcJERERExDx5LjdjPlrOfmcO8VWjeHFA2/J9ZeTgRvhoIORnQXwvuCoRAmDvJ4BJyyexcPdCQh2h3NfkPqqEl/OrjSVUrJ/qHXfcwcCBA9m7dy9ut7vIHy2wRERERATghR82sHhbKpEhDqYM7UBUaLFfRGV9abvhw/6QdQRqdYCB74Mj2OxUAHyz5RveW/MeAOPPHU+jSN1joaSKtcjav38/Y8eOpVq1ar7OIyIiIiJlwDcr9/DO79sAmDCwLfFVo0xOZKKsIzD9anDugsrxMOQzCA2M+Vh9cDVP/PEEAKNaj+KS+peYG6iMKNY/JwwYMID58+eXqzsJulwuj67SuVwur67oeTPe29rliRXmxoyM/jynL2uXpFZxj1Wvlj6rzIt61T911KvW4Yt52bT/GA98sQqAm7s1oHeLqj6fZ8v0al4W9o+uxXZwPUZUddxDPoewiifd6MKMXj2QeYC75t1FrjuXHrV7cFub2wKuVwOtTz3NYTMMw/C2eGZmJgMHDiQuLo7WrVsTHFz0Uuedd97pbcmAk5iYSGJiIi6Xi02bNpGUlERU1Nn/xcHtdpOamkpsbCx2D15j6814b2uXJ1aYGzMy+vOcvqxdklrFPVa9WvqsMi/qVf/UUa9aR0nnJSPXxZ3f7ma3M4+EGuE8c3ENHHbfvw/LEr3qzqfWogepsHshruAodlw0hZyKjX1Tu4QZc9w5PL7ucbZkbKFOeB2eafkM4Y7wgOvVQOvT9PR0OnXqRFpaGtHR0acdV6xF1tSpU7n11lsJCwujcuXKRd7AaLPZ2Lp1a/FSByCn00lMTAypqalnnMjjXC4XycnJxMfH43CcfYM9b8Z7W7s8scLcmJHRn+f0Ze2S1CruserV0meVeVGv+qeOetU6SjIvbrfB7R8t5+f1B6geE8bXo7tSOdI/d6gL+F41DGzf3Y19+YcYjlDc130B9br6pnYJMxqGwcOLHub77d8TExLDjL4zqF2hdoly+KtXA61PnU4nsbGxZ11kFevlgg8//DDjx4/nwQcfDIgVZWlwOBwe/2DtdrvfxntbuzyxwtyYkdGf5/Rl7ZLUKu6x6tXSZ5V5Ua/6p4561TqKOy9TFiTz8/oDhDjsTBnagarR/t1wOKB79denYfmHYLNjGzAVR8NuvqtdwjrvrnmX77d/j8Pm4JUer1CvYj2f5PBXrwZSn3r8vRWneG5uLoMGDSo3CywRERERObOFmw/y8k8bAXjiypYk1KlobiAzLX4bFrxU8PFlL0PzK8zNc4IFuxYwcelEAB7s/CCda3Q2N1AZVaxV0vDhw5k5c6avs4iIiIiIBe06ksmdHy/HbcA1HWszuHMdsyOZZ+1s+P6+go97PAQdbzQ3zwm2Ht3K/Qvux8BgYJOBDGo6yOxIZVaxXi7ocrl48cUX+fHHH2nTps1JN7545ZVXfBJORERERAJbdp6L26Yv40hmHq1qRfPkVa3K74bDW3+DWTcDBnQcCRfcb3aiQmk5adzx6x1k5GXQoVoHxnUeV35/TqWgWIus1atX065dOwDWrFlT5Gv6YYmIiIiUH098vZbVu9OoGBHMG9d1ICzY/PfNmGLvSvjkOnDlQvMr4dKXIEB+L85353Pvb/ey49gOakbW5JUerxAcIBshl1XFWmTNmzfP1zlERERExGI+WbyDT5J2YrPB5GvbUSc2wuxI5kjdBtMHQO4xqHc+9H8b7IGz2Hx5ycv8tfcvwoPCmXzhZGLDYs2OVObpzhUiIiIi4rWVO4/y2FdrAbjn4iZ0bxJnciKTpB+AD/8DGQegWmsY/BEEh5mdqtCszbOYvn46AM+e/yxNY5uanKh88PhKVv/+/Zk2bRrR0dH079//jGNnzZpV4mAiIiIiEphSM3K5bfpScl1uejWvxu094s2OZI6cYzBjABzZBhXrwtDPISzG7FSFlh9YzlN/PQXA7Qm306teL5MTlR8eL7JiYmIK328VExM4Tx4RERERKT0ut8GdHy9nT1o29StH8MqgttjtgfHeo1KVnwszhxa8FyuiMgydDRWqm52q0N6Mvdw9727y3flcXO9ibmlzi9mRyhWPF1nvvfceTz75JPfeey/vvfeePzOJiIiISICa8NNGfk8+RHiwgzev70h0WDm8gYLhhi9vha3zITgSrvsMqgTO1bxsVzaPzH+E1OxUmlZqytPnPY3dpncJlSavZnv8+PGkp6f7K4uIiIiIBLA5a/bxxvwtALwwoA1Nq1cwOZEJDAPbTw/Bmi/AHgSDPoRaHcxOVcgwDP639X9sPLKR2LBYJl84mYjgcnpDEhN5dXdBwzD8lUNEREREAtiWg+nc+9lKAG48rwFXtq1pciJzxK7/APuqtwo+6fcGxF9kbqB/eXv12/yZ+idB9iBe7fEqNaPK58/JbF5fN9Q+WCIiIiLlS0ZOPrd+uJT0nHw6149l3KXNzI5kCtuKGVRd9b+CT/o8C22uMTfQv8xNmcv//sn3cOeHaV+tvcmJyi+v98lq0qTJWRdaqampxQ4UqFwuFy6Xy6Nxbrfbo7Hejve2dnlihbkxI6M/z+nL2iWpVdxj1aulzyrzol71Tx31qnX8e14Mw+C+z1ay+UA6VSuEMvnattgxTJ+3Uv/5bfoR+7d3F5z7nDug863gw3OX9PvZdGQT434fB0Dfqn25ssGVZeLv1UDrU09z2AwvXgNot9uZOHHiWe8uOHz4cE9LBqzExEQSExNxuVxs2rSJpKQkoqKiznqc2+0mNTWV2NhY7PazXyj0Zry3tcsTK8yNGRn9eU5f1i5JreIeq14tfVaZF/Wqf+qoV63j3/PyxdqjvJ10GIcNXrykJi2rhZsdESjdn1/4oVXUmTcGuyuH/TUu4vD5T2F3+Haz4ZJ8P2l5aYxbM46DuQdpHd2aW6rcQlzluDLRq4HWp+np6XTq1Im0tDSio6NPO87rRda+ffuoWrWqT0JagdPpJCYmhtTU1DNO5HEul4vk5GTi4+NxeNB83oz3tnZ5YoW5MSOjP8/py9olqVXcY9Wrpc8q86Je9U8d9ap1nDgvSSlHGfbeElxug8cub87wc+uZHa9Qqf38Dm7APu1SbNlHcTfqxYZ2jxPfpFnA9GqeK49b597K0gNLqRNVh/d7v8/BnQfLTK8GWp86nU5iY2PPusjy6uWC5fn9WA6Hw+MfrN1u99t4b2uXJ1aYGzMy+vOcvqxdklrFPVa9WvqsMi/qVf/UUa9ah91u50B6HnfNXInLbdAvoSY3nNcg4H4X9PvPL20XfDQQso9CrY4YA97DnrInoHr12cXPsvTAUiKDI3ntoteIjYjlsP1wmerVQOpTj783b4rq7oIiIiIiZV+ey+COj5dzKD2XZtUr8Fz/NgG3wPK7zFSYfjU4d0OVJgV7YYVEmp2qiJkbZvLppk+xYeOFbi/QqGIjsyPJP7y6kuV2u/2VQ0REREQCxJtJh1i+00mFsCCmDO1AeIj5VxBKVW4mfHwtHNwAFWrC0FkQEevTG12U1OK9i3l+8fMA3NX+Li6oc4HJieRE5r97TEREREQCxqzlu/l2gxOAiYMSqF8lsK7e+J0rHz6/AXb+DWExMPQLqFjH7FRF7Dy2k3t+u4d8I59LG1zKja1uNDuS/IsWWSIiIiICwNKUVB6evQaAO3o24qLm1UxOVMoMA769CzbNgaAwGPwJVGthdqoiMvIyuPPXOzmac5SWlVsyvuv48vdSTgvQIktERERE2HE4k5s/WEquy+DcOhHccWG82ZFK369PwfLpYLPDgHehXlezExXhNtyMWziO5KPJVAmvwqSekwgLCjM7lpyC15sRi4iIiEjZkpaVx43vJ3E4I5eWNaJ5oHtlHPZydnXkrymw8OWCjy+fCM0uMzXOqSSuSGTeznmE2EOY1HMS1SLL2ZVGC9GVLBEREZFyLM/lZsxHy0g+kE616FDeur49YcHl7FfENV/AnAcLPu75CHQYbm6eU5izbQ5vrXoLgMe7Pk6buDYmJ5IzKWcdJCIiIiLHGYbB41+vZeHmQ4QHO5g6vBPVY8rZy8+2zINZtwAGdBoF3e81O9FJ1h1ex6OLHgVgRMsRXNnoSpMTydlokSUiIiJSTk39fRsf/b0Dmw0mXZtAq1oxZkcqXXtWwMyh4M6DFv2g7wsQYDeROJR1iDt/vZNsVzbn1zqfu9vfbXYk8YAWWSIiIiLl0M/r9vPM9+sBeKhvc3q3rG5yolJ2eAvMGAC56dCgO/R/C+yBtR9YriuXu+fdzf7M/dSPrs+L3V/EEWAZ5dS0yBIREREpZ9buSeOuT5ZjGDC4cx1u6tbA7Eil69h+mN4fMg5C9dYwaAYEhZqdqgjDMHjyzydZeXAlFUIq8NqFr1EhpILZscRDWmSJiIiIlCP7ndmMnLaEzFwX58VX5smrWpWvfZaynQVXsI5sh4r14LovICza7FQnmb5+Ol9t+Qq7zc6E7hOoH1Pf7EjiBS2yRERERMqJzNx8Rr6fxD5nNo3iIvnfdR0IdpSjXwfzc2DmdbBvFURUgetnQ4XAuw36H7v/YMKSCQDc2/FeutYKrP265OzKUVeJiIiIlF9ut8Hdn6xgzW4nsZEhvDuiEzHhwWbHKj1uF8y6GbYtgJAoGPo5VG5kdqqTpDhTuHfBvbgNN/3i+zG0+VCzI0kxaJElIiIiUg68MGcDP63bT4jDzlvXd6Be5UizI5UewyjYB2vdl2APhkHToWY7s1OdJCM/g7vm38Wx3GO0jWvLo+c8Wr5eylmGaJElIiIiUsZ9sngHby7YCsCLA9rQsX6syYlK2cKXYXHBRr78Zwo06mlunlNwuV1MSp7Edud2qkVUY2LPiYQ4QsyOJcUUZHYAq3C5XLhcLo/Gud1uj8Z6O97b2uWJFebGjIz+PKcva5ekVnGPVa+WPqvMi3rVP3XUq+ZZtOUwj3y5BoA7ejbiijbVz/g9W2VePM1pW/4B9l+fAsDd5zmMFv+BUn4ee2LSskksT1tOqCOUiRdMpFJIpVL9e7Gkx/urVwPt+ehpDpthGIafs1hSYmIiiYmJuFwuNm3aRFJSElFRUWc9zu12k5qaSmxsLHb72S8UejPe29rliRXmxoyM/jynL2uXpFZxj1Wvlj6rzIt61T911Kvm2Hk0l/9+v5v0XDcXNIjiwe5Vz/ryM6vMiyc5o3YvoNbvD2Az3BxqPpxDbW/3+zmL4/t93/NeynsA3NXwLs6PO7/Ytcparwba8zE9PZ1OnTqRlpZGdPTp70qpRdZZOJ1OYmJiSE1NPeNEHudyuUhOTiY+Ph6H4+ybxXkz3tva5YkV5saMjP48py9rl6RWcY9Vr5Y+q8yLetU/ddSrpS81I5erp/zFjtRM2tWtyIwbOxEa7Ns5NNNZc+78C/v0/tjys3G3HYJxxWtQwvc3+WNupq2dxsTlEwG4uubVPHTBQ+pVH+TxF6fTSWxs7FkXWXq5oIccDofHP1i73e638d7WLk+sMDdmZPTnOX1ZuyS1inuserX0WWVe1Kv+qaNeLT05+S5u/2g5O1IzqV0pnLeHdSQizPP391hlXk6b88B6+GQw5GdDk0uwX/kaOHzza68v5+bNlW/y+orXAbi59c30Cu+lXvVhHn/w+Hvzcw4RERERKUWGYTDui9UkbT9ChdAg3h3RiSpRoWbHKj1Hd8KH/SE7DWp3hgHv+WyB5SuGYfD68tcLF1hjEsZwe9vbdSfBMiSwnnEiIiIiUiKv/5rMrOW7cdhtJF7XnibVKpgdqfRkpsL0/nBsD1RpCkNmQkiE2amKMAyDV5e9yntrCt6DNbbDWG5odUPA3NhBfEOLLBEREZEy4puVe3j5500APHFlS7o3iTM5USnKzYCProFDmyC6Flw/CyIC61b1hmHwYtKLTF8/HYAHOj3A0BbabLgs0iJLREREpAxYtuMI93y2EoAbz2vA9efUMzlRKXLlwWc3wK4kCKsIQ7+AmNpmpyrCbbh59u9nmblxJgCPnvMo1zS9xuRU4i9aZImIiIhY3M7UTG7+YAm5+W4ualaVhy9rbnak0mMY8M2dsPlHCAqHIZ9C1cD6/l1uF0/+9SSzNs/Cho3xXcfzn8b/MTuW+JEWWSIiIiIW5szOY+T7SRxKz6V5jWgmD26Hw15+bqBg+/VJWPkR2Bww8D2o28XsSEXku/N5bNFjfLP1G+w2O0+f9zRXNLrC7FjiZ1pkiYiIiFhUvsvNmI+Ws2l/OlUrhDJ1eEciQ8vPr3eVNn6Mffmkgk+umARN+5ob6F/y3Hk8tPAh5myfg8Pm4Pluz3NJg0vMjiWloPx0oYiIiEgZYhgG479Zx4JNBwkLtvPO8I7UrBhudqxSY1vzBdX+2cSXix6D9tebmuff8lx53LfgPubumEuQPYgJ3SdwUb2LzI4lpUSLLBERERELmvbHdj78KwWAiYMSaFO7ormBSlPyXGxf3Q6Au/PN2M8fa3KgonJcOYydP5YFuxYQbA/m1R6vckGdC8yOJaVIiywRERERi/l1w36e+nYdAA/2bcYlrWqYnKgU7V4GM6/H5s7DWbcXkb2fhQDaxDcrP4u7593NH3v+INQRyuSek+laq6vZsaSU2c0OICIiIiKeW7/XyR0fLcdtwDUda3NL94ZmRyo9h7fAjIGQl4HR4AL2dnkcbIHz62xmXiZj5o7hjz1/EB4UTuJFiVpglVOB86wUERERkTM64Mxm5LQkMnJdnNuwMk/3a40tgK7i+NWxffDhfyDzENRoi3vg+xiOELNTFUrPTee2X25j8b7FRARF8EavN+hSI7DudCilR4ssEREREQvIynVx0wdL2JOWTcMqkUwZ2oGQoHLyq1x2GkwfAEdToFIDuO5zCI02O1UhZ66TW36+hWUHllEhuAJv9X6LDtU6mB1LTKT3ZImIiIgEOLfbYOynK1i1K42KEcG8O6ITMRHBZscqHXnZ8Ml1sH81RMbB9bMgqiq4XGYnAyAtJ42bf76ZdYfXERMaw5sXv0nLyi3NjiUm0yJLREREJMBN+GkjP6zZR7DDxptDO1C/SqTZkUqH2wWzb4btCyGkAgz9AmID5z1oqdmpjPppFJuObKJSaCXe7v02TWObmh1LAoAWWSIiIiIB7NMlO/nf/C0APN+/DV0aVjY5USkxDPjhflj3FThC4NoZUKOt2akKHco6xE0/3sSWtC1UDqvMO73fIb5SvNmxJEBokSUiIiISoP7ccpiHZ68GYEzPeK7uUNvkRKVowUuQ9A5gg/+8CQ0DZ5+p/Zn7ueWXW9ju3E7V8Kq80+cdGsQ0MDuWBJBy8m5JEREREWvZejCdW6cvJc9lcFnrGoy9uInZkUrPkvdg3jMFH/d9EVr1NzfPCQ7mHOSmn25iu3M7NSJrMO2SaVpgyUl0JUtEREQkwBzJyGXk+0tIy8ojoU5FXr6mLXZ7OblV+/pv4buxBR93uxe63GxunhPsOraLx9c9zsHcg9SKqsW7fd6lZlRNs2NJANKVLBEREZEAkpvv5tbpS9l2KINaFcN5e1hHwoIdZscqHdsXwec3guGGdtfDhY+YnahQijOFkT+P5GDuQepWqMu0S6ZpgSWnpStZIiIiIgHCMAwemr2av7elEhUaxNQRHYmrEGp2rNKxfy18PBhcOdD0Urh8IgTIRstbj25l5E8jOZR1iFphtZh68VSqR1Y3O5YEMC2yRERERALEG79t4fOlu7Db4PUh7WhWPXA23PWroztg+tWQkwZ1zoEB74IjMH5N3XRkE6N+GkVqdiqNKzbmgYYPEBcRZ3YsCXB6uaCIiIhIAPh+9V5enLMRgCeubEmPplVNTlRKMg7Dh/3h2F6Iaw6DP4bgcLNTAbD+8HpG/jiS1OxUmsc25+2L3yYmOMbsWGIBWmSJiIiImGzFzqP8d+YKAEZ0rc+wc+ubmqfU5GbARwPh8GaIrl2w2XBErNmpAFh9cDUjfxrJ0ZyjtK7Smrd7v03F0IpmxxKLCIzrsBbgcrlwuVwejXO73R6N9Xa8t7XLEyvMjRkZ/XlOX9YuSa3iHqteLX1WmRf1qn/qqFdPb8/RLG56P4mcfDcXNKnCuEuamJqp1ObFlYf902HYdi/FCK+Ee8hnEFUd/PCz9taKgysY/etoMvIyaBvXlsSeiUQFRalXfXicp+MDpU+P8zSHzTAMw89ZLCkxMZHExERcLhebNm0iKSmJqKiosx7ndrtJTU0lNjYWu/3sFwq9Ge9t7fLECnNjRkZ/ntOXtUtSq7jHqldLn1XmRb3qnzrq1VPLyHVzzw+72X4kl/qVQni5by0iQ8ztj1KZF8NNjb+fJGb7D7gdoezomUh2ldYBkXOtcy3PbXyOHHcOLSq04MGmDxLuCPfrOX1Zu6z1aiD06YnS09Pp1KkTaWlpREef/j2TWmSdhdPpJCYmhtTU1DNO5HEul4vk5GTi4+NxOM5+u1VvxntbuzyxwtyYkdGf5/Rl7ZLUKu6x6tXSZ5V5Ua/6p4569WT5Lje3TF/O/E0HqRIVwuzbzqVmRfPfi1Qa82L75XHsf76GYXPgHjQDGvf2uoY/cv619y/unn832a5sulTvwsQeEwkP+v+fiXrVd8d5Ot7sPv03p9NJbGzsWRdZermghxwOh8c/WLvd7rfx3tYuT6wwN2Zk9Oc5fVm7JLWKe6x6tfRZZV7Uq/6po14t6qnvNjB/00FCg+y8M7wTdSqf/RUzpcWv8/LHa/DnawDYrnodR7O+xS7ly5wLdy3k7nl3k+vO5fxa5zOx50RCHSffPl+96rvjPB0fSH93ePy9+TmHiIiIiPzLB39uZ9of2wF4dVACCXUqmpqn1KycCT/9s8FwrycgYYipcY6bt2Med827i1x3Lj3r9GRSz0mnXGCJeEqLLBEREZFSNH/jAZ74ei0A9/VpyqWta5icqJQk/wJf3V7w8Tm3w3l3mxrnuJ+2/8TY+WPJc+dxcb2LebnHy4Q4QsyOJRanRZaIiIhIKdm47xhjPlqO24Cr29fm9h6NzI5UOnYthZnDwJ0PrQZA72fAZjM7Fd9t/Y77F9xPvpHPpQ0u5cXuLxJsDzY7lpQBWmSJiIiIlIKDx3K4cVoS6Tn5dGkQy3P9W2MLgIWG3x3aXLAXVl4GNOwJ/d6AALhL3FfJXzFu4ThchourGl3Fs+c/S5BdtysQ39AzSURERMTPsvNcjPpgCbuPZtGgSiRThnYgJMj8hYbfOffCh/0h8zDUSIBBH0KQ+S/F+3zT5zz555MYGAxoMoBHz3kUu60c/Dyk1GiRJSIiIuJHbrfBPZ+tZMXOo8SEBzN1eEcqRZq/0PC7rKMwYwCk7YDYhnDd5xBawexUfLzhY579+1kABjcbzLjO48rHFUUpVVpkiYiIiPjRq79s4rtVewmy25gytAMN4wLnVu1+k5cNnwyB/WsgqhpcPxui4sxOxftr32fCkgkADG8xnHs63qMFlviFFlkiIiIifvLF0l289msyAM/2b825jSqbnKgUuF3wxUhIWQSh0QVXsCrVNzsV76x+h0nLJgEwqvUo7mh3hxZY4jdaZImIiIj4weJtqTw4axUAt/VoxDUd65icqBQYBnx3D2z4FhwhcO1HUKONyZEMpqycwv9W/g+A2xNu59Y2t2qBJX6lRZaIiIiIj20/lMEtHy4hz2XQt1V17uvd1OxIpeO3F2Dpe4AN+r8NDbqZGscwDCYvn8w7q98B4K72d3FT65tMzSTlgxZZIiIiIj6UlpnHjdOSOJKZR5vaMbxyTQJ2ezm4apI0FeY/V/DxZROgZT9T4xiGwYQlE/hg3QcA3NfxPoa1HGZqJik/tMgSERER8ZHcfDe3Tl/K1kMZ1IwJ451hHQkPcZgdy//WfV3wMkGACx6ATuZeLXIbbp77+zk+2fgJAA91eYjBzQabmknKFy2yRERERHzAMAwe/XINf249TGSIg3eGd6JqdJjZsfxv++/wxU2AAR1GQI9xpsZxG26e/PNJvtj8BTZsPHbuYwxoMsDUTFL+aJElIiIi4gNvLdjKzCU7sdvgtSHtaFEz2uxI/rdvNXw8GFw50OxyuPRlMPGGEi63i8f+eIyvt3yN3WbnqfOe4spGV5qWR8ovLbJERERESmjOmn08P2cDAI9c1oILm1UzOVEpOLIdpl8NOU6o2xWufgcc5v1qme/O56HfH+KHbT/gsDl4rttz9G3Q17Q8Ur5pkSUiIiJSAqt3pXH3zOUYBlx/Tj1uOK++2ZH8L+MQfNgf0vdD1ZYw+GMIDjctTp4rjwcWPsDPKT8TZAvixQte5OJ6F5uWR0SLLBEREZFi2puWxcj3k8jOc9O9SRyPX9Gi7O+/lJMOMwZC6haIqQNDv4DwiqbFyXXlcv/C+5m/az7B9mBe6fEKPer0MC2PCGiRJSIiIlIsGTn5jJy2hAPHcmhSLYrXh7QjyGE3O5Z/5efCp9fDnmUQHgtDZ0F0DdPi5Lhz+O9v/2XRnkWEOkKZ2HMi59c637Q8IsdpkSUiIiLiJZfb4K5PlrNur5MqUSFMHd6J6LBgs2P5l9sNX42GLb9CcARc9xnENTEtTlZ+Fi9sfIHVztWEOcJ47aLXOKfGOablETmRFlkiIiIiXnr2+/X8sv4AIUF23hrWkTqxEWZH8r+fH4XVn4I9CK75EGp3NC1KRl4GY34dw2rnaiKCIki8KJGO1c3LI/JvWmSJiIiIeGH6XylM/X0bAC8PbEv7upVMTlQKFk2GP18v+PiqRGjcy7Qox3KPcdsvt7Hy4ErCHeG8cdEbtK/e3rQ8IqeiRZaIiIiIhxZsOsjjX68FYOzFTbiibU2TE5WCFR8XXMUCuPgpaHutaVHSctK49edbWXN4DRVCKvBQ44doG9fWtDwip6NFloiIiIgHNu8/xugZy3C5Df7TrhZ3XBhvdiT/2/RTwfuwAM4dA+fdaVqUI9lHuPnnm9mQuoGKoRWZctEUHIcdpuUROZMyfgscERERkZI7lJ7Dje8ncSwnn071K/H81a3L/q3ady+Bz4aD4YI2gwquYpnkUNYhbvzxRjakbiA2LJZ3+7xLs9hmpuURORstskRERETOIDvPxc0fLGFnahZ1YyN48/qOhAaV7SsoIc7t2D++FvIyodFFBe/Dspvza+OBzAPc+OONJB9NJi48jvcueY/GlRqbkkXEU3q5oIiIiMhpGIbB/Z+vYtmOo0SHBfHuiE7ERoaYHcu/nHuoM/8ubFmpULM9XPMBOMy5Pf2+jH2M/HEkO47toFpENab2mUq96HqmZBHxhq5kiYiIiJzGxF828/XKPQTZbbwxtAPxVaPMjuRfBzdh//BKgjP3YcTGF+yFFWrO97w7fTcj5oxgx7Ed1IqqxbRLpmmBJZahK1kiIiIip/Dl8t1MmrsZgKf7teK8+ComJ/KzzT/D5zdiy3GSF1ED+3Wf44g053ve4dzByJ9Gsi9jH3Uq1GFq76nUiKphShaR4tCVLBEREZF/WbI9lfs/XwXALd0bcm3nuiYn8iPDgD8T4aNrIMeJUecctvd+Fyqa8z1vTdvKDXNuYF/GPupH12faJdO0wBLL0SJLRERE5AQ7Dmdy84dLyXW56d2iGg9cUobvYpefA1+NgR8fAsMN7Ybivv5LXGGxpsTZfGQzN865kQNZB4ivGM97l7xH1YiqpmQRKQm9XFBERETkH2lZedz4fhKpGbm0qhXNxGsTsNvL6K3a0w/CzKGw8y+w2aH3M3DObeB2mxJnY+pGRv00iiM5R2haqSlv9X6LWJMWeyIlpUWWiIiICJDncjN6xjKSD6RTPTqMd4Z1IiKkjP6qtG81fDwY0nZCaAwMfBfie5kWZ+2htdz88804c520rNySNy9+k5jQGNPyiJRUGf0/h4iIiIjnDMPg8a/X8nvyIcKDHbwzvCPVY8LMjuUf67+FWTdDXgbENoTBMyGuiWlxVh5cya0/30p6Xjpt4towpdcUKoRUMC2PiC9okSUiIiLl3tTft/HR3zuw2WDy4Ha0qlUGr6IYBiycAL8+XfB5gwtg4DSIMO8leUv3L+X2X24nMz+T9lXb879e/yMyONK0PCK+okWWiIiIlGu/rD/AM9+vB+DhS5tzcYtqJifyg7ws+Go0rPmi4PPON0OfZ03bZBjg771/c8evd5CVn0WX6l2YfOFkIoIjTMsj4ktaZImIiEi5lXw4h/vmrMQwYEiXuow8v4HZkXzPuQc+GQJ7loM9CC59CTreaGqkRbsXcde8u8hx5XBezfOY2HMiYUFl9OWZUi5pkSUiIiLl0r60bJ6Yu5esPBfdGldh/JUtsdnK2J0Edy+Fj4dA+j4IrwTXfAgNupka6bedv/Hf+f8lz53HBbUv4OUeLxPqCDU1k4ivaZElIiIi5c6x7Dxunr6MQ5ku4uMieX1Ie4IdZWz70NWfF7xEMD8b4prB4E8g1twrdXNT5nLvgnvJd+fTq24vXuz+IsEmvmRRxF+0yBIREZFy40hGLtP+2M60P7aTlpVHTKidt4d1ICa8DP2i73bDvGcKbnIB0OQS6P82hEWbGmvOtjk8uPBBXIaLvvX78ky3Zwi2l6F5FzlBmV9kHT16lF69epGfn09+fj533XUXo0aNMjuWiIiIlKJ9adm8s3ArHy3eQWauC4AGVSK4u0sl6saWoZst5KTD7Ftgw7cFn593F1z0ONgdpsb6Zss3PLLoEdyGmysbXcmTXZ/EYXImEX8q84usChUqsGDBAiIiIsjIyKBVq1b079+fypUrmx1NRERE/CzlcAZTftvKF0t3ketyA9CiRjSje8ZzcfM4tm5JNjmhDx3dUbDB8P414AiBK1+DtteanYrZm2fz+B+PY2BwdeOreezcx7DbythLM0X+pcwvshwOBxERBf9ClZOTg2EYGIZhcioRERHxp437jjFlwTa+XbUH9z9/7XeuH8vtPRtxQZM4bDYbLpfL3JC+lPInzBwKmYcgsipcOwPqdDY7FTM3zOTpvwv25RrUdBAPdXlICywpF0x/li9YsIArrriCmjVrYrPZ+PLLL08ak5iYSP369QkLC6NLly4sXrzYq3McPXqUtm3bUrt2be677z6qVKnio/QiIiISSJbvOMrjc/dy6WuL+HplwQKrR9M4Pr3lXD699Vx6NK1a9u4guOxDeP+KggVW9TZw87yAWGB9uO7DwgXW9S2u5+EuD2uBJeWG6VeyMjIyaNu2LTfeeCP9+/c/6eszZ85k7NixTJkyhS5dujBx4kT69OnDxo0bqVq1KgAJCQnk5+efdOxPP/1EzZo1qVixIitXrmT//v3079+fAQMGUK1aGdxoUEREpBwyDIPfkw/xv3lb+HPrYQBsNri0dQ1uu6ARrWrFmJzQT1z58PNj8FdiwectroJ+b0BIpLm5gKmrpzJx2UQARrYayV3t7yp7i1uRMzB9kdW3b1/69u172q+/8sorjBo1ihtuuAGAKVOm8N133/Huu+/y4IMPArBixQqPzlWtWjXatm3LwoULGTBgwCnH5OTkkJOTU/i50+kEwOVyefSyApfLhdvt9vglCN6M97Z2eWKFuTEjoz/P6cvaJalV3GPVq6XPKvOiXvVPHX/0qttt8PP6A7zx2xZW7y74+zrYYaNng0juubQN8dWiC2v4MlNAyHZinzUS25a5ALi7P4DR/T6w2cHkn/Vbq97if6v+B8AtrW/h1ja34na7S5TpVNSr/qkTaH+vBlqfeprDZgTQG5RsNhuzZ8+mX79+AOTm5hIREcHnn39e+BjA8OHDOXr0KF999dVZa+7fv5+IiAgqVKhAWloa5513Hh9//DGtW7c+5fgnnniC8ePHn/R4UlISUVFRZz2f2+0mNTWV2NhY7PazXxL3Zry3tcsTK8yNGRn9eU5f1i5JreIeq14tfVaZF/Wqf+r4slfz3Qbzt6Xz6aoj7EjLAyDUYaNvk2j+0yIaR46zTPdq8LEd1F54H6HO7bgdoezt8jjH6l7ks/rFnRfDMPhk1yfM2jMLgMG1B9O/1smvUvIV9ap/6gTa36uB1qfp6el06tSJtLQ0oqNPvy2C6VeyzuTQoUO4XK6TXtpXrVo1NmzY4FGNlJQUbr755sIbXtxxxx2nXWABjBs3jrFjxxZ+7nQ6qVOnDo0aNTrjRB7ncrlITk4mPj4eh+Pstyb1Zry3tcsTK8yNGRn9eU5f1i5JreIeq14tfVaZF/Wqf+r4olfz3PD50t28tXAru49mA1AhLIjrz6nLiK71qRwZUvZ7det87HNHYcs+ihFdE+OaGVSv0ZbqPjxFcebFMAxeXfZq4QJrbPuxDGsxzIepTqZe9U+dQPt7NdD69Pir3M4moBdZvtC5c2ePX04IEBoaSmho6EmPOxwOj3+wdrvdb+O9rV2eWGFuzMjoz3P6snZJahX3WPVq6bPKvKhX/VOnuMdn5cM7i1J4d1EKh9ILXtJfJSqEG89vwNBz6hEdVnRD2zLZq4YBSe/ADw+A4YLanbANmoGjgn/eY+7NvBiGwQtJLzBj/QwAHuz8INc1v84vuf5NveqfOoH292og9amnGQJ6kVWlShUcDgf79+8v8vj+/fupXt2X/2YjIiIigSY1I5epC7fy/h8ppOcWvKenVsVwbrmgIdd0rENYsPm/cJUKVx78cD8sebfg8zbXwhWTIDjM3FyA23Dz9F9P89mmzwB47NzHGNhkoMmpRMwX0IuskJAQOnTowNy5cwvfk+V2u5k7dy5jxowxN5yIiIj4xd60LN5esI2PF+8gK6/gTeaN4iK5rUc8VyXUJNhh/vsySk1mKnw6DLYvBGzQ6wk4766C2yeazOV28cSfT/Bl8pfYsDG+63j+0/g/ZscSCQimL7LS09NJTv7/3da3bdvGihUriI2NpW7duowdO5bhw4fTsWNHOnfuzMSJE8nIyCi826CIiIiUDdsOZTBl/hZmLd9FnqvgvlytakbTr2k4wy9MIDjY9F9bSteB9fDxtXBkO4REwdVToeklZqcCIN+dzyOLHuG7rd9ht9l55vxnuLzh5WbHEgkYpv/fasmSJfTs2bPw8+M3nRg+fDjTpk1j0KBBHDx4kMcee4x9+/aRkJDAnDlzSn2fK93CPbBZYW50q1n/1Aq0W82WJFNZZ5V5Ua/6p86Zjl+/18kbv23lhzX7cP9zz+MuDWK57YKGnNugIlu2bMEwfN9/Af2c3PwT9lk3YctNx6hYD/egGVC1RYlvz+6Js81LnjuPh35/iJ93/EyQLYhnz3+W3vV6l/o8qlf9UyfQ/l4NtD615C3cA0liYiKJiYm4XC42bdqkW7gHOCvMjW41659agXar2ZJkKuusMi/qVf/UOdXxa/dnMXP1URbvyiwc16V2BIPaVKJF1bBindfyvWoYxG6YTtzKRGwYZMa1Z/f5z+EKrVhqEc40L3nuPF5NfpWkI0k4bA7uib+HTrGdSi2bpzmteM5A7lV/HFfWb+GuRdZZOJ1OYmJiSE1N1S3cA5gV5ka3mvVPrUC71WxJMpV1VpkX9ap/6hw/vlGjRvyx7QhvzN/K4u1HALDb4NLW1bm1e0Oa14g+5XHlolfzs7F9Nxb7qk8AcLcfjnHJC+AIKdUYp5uXHFcO9/x2D7/v+Z0QewgvX/Ay3Wp1K9VsnuS06jkDrVcD5e/VQOtTp7NgHz5L75MVSHQL98BnhbnRrWb9UyvQbjVbkkxlnVXmRb3q+zout8GiHZnc9/Ni1u4t2Gcm2GFjQIfa3NK9EfWrRPrsvJbs1WP7YeZQ2LUYbA645HnsnUeZdoOLf89LVn4Wd8+/mz/3/kmYI4xJF06ia82upmQ7kXrVP3UC7e/VgOlTysgt3EVERMTa8lxuvly+mzfmb2HroQwAwoMdDOlSl5u6NaBGTLjJCQPA3pXw8RBw7oKwGBg4DRpdaHaqQpl5mYz5dQxJ+5IIDwon8aJEOlU35yWCIlahRZaIiIj4XFaui5lJO3h74TZ2H80CICrEzg3nNeCG8xsSG1m6L4ELWOu+gtm3Ql4mVG4Mgz+BKvFmpyqUnpvO7XNvZ/mB5UQGR/JGrzdoV7Wd2bFEAp4WWSIiIuIzzuw8PvwzhXd/38bhjFwA4iqEcuN59elSOZe2LRoHxEt+TGcY8NuLMP/Zgs8bXQQD3oXwiqbGOpEz18mYX8ew6tAqKgRXYMrFU2gT18bsWCKWoEWWiIiIlNih9BzeW7SND/5I4VhOPgC1K4Vz6wWNGNChNsF22Lx5s8kpA0RuJnx1O6ydXfD5ObfDxU+BI3B+LTuWd4zHfnmM9anriQmN4a2L36JF5RZmxxKxjMDp5gCnfbICmxXmRvt5+KdWoO3nUZJMZZ1V5kW96l2dPUezePv3bXy6ZBfZeW4AGleN4tYLGnJ56+oEOewlylHmetW5G/vModj2rcSwB2NcOgGj3fXHA5VejjPYn76fJ9Y/wY6sHVQKrcSbvd6kScUmAde76lX/1Am0Xg20vzu0T1YJaZ8sa7HC3Gg/D//UCrT9PEqSqayzyryoVz2rszMtl89WH2XulmO4/vlNokmVUK5tXYlz6kZg/9dd8dSrEHZ4DbUX3k9Q9mHyQyuy+7znyQqA9zdlubLYcGwDa51rWeNcw9aMrRgYVAyuyGPNHqNORB2zI56SetU/dQKtVwPt7w7tk+Uj2ifLGqwwN9rPwz+1Am0/j5JkKuusMi/q1TPXyYmoylu/b2fO2v0c/w3i3Iax3NajEV0bxmI7zS3Hy3uv2lZ9iu3bu7C5cjCqtsA96COoWNev5zyd7PxsVh5cSdL+JBbvW8y6w+vIN/KLjKkXXo9XL3yVhpUampLRE+pV/9QJtF4NtL87tE+Wj2mfrMBnhbnRfh7+qRVo+3mUJFNZZ5V5Ua+eLGl7KhPm7mPJ7m2Fj13cohq392hEu7qV/JrD0r3qdsPc8bBoYsHnTS/D1v9NHKEV/HO+U8h15RYsqvYVLKpWHVxFnjuvyJiakTXpVL0TnWt0pkNcB47tOUbDSg3Vq6V8Tu2T5ds8/qB9skRERKREDMNg/saDJM5LZknKEQDsNriybU1u6xFP0+qlt1CwpJxj8MUo2PRDwefd7oGej4CfX/KU585j7aG1/L33b5L2JbHi4ApyXDlFxlSNqErn6p3pXL0znap3onaF2oVfc7lcHOOYXzOKlHVaZImIiEgRLrfBD2v2kjhvC+v3OgEIcdi4OL4C916eQIM4La7O6sh2+HgwHFgHjlC4KhHaDPTLqfLd+aw/vJ7F+xaTtC+JZQeWkZWfVWRMbFhs4YKqc/XO1Iuud9qXdopIyWmRJSIiIgDk5ruZvXwXU37byrZDGQBEhDgYek49RpxbF+f+ndSNjTA5pQVs/x1mXg9ZqRBVHa79CGp38Fl5t+FmY+pGFu9bzOJ9i1m2fxnpeelFxlQMrUin6p0KF1UNYxpqUSVSirTIEhERKecyc/P5ZPFO3l64lb1p2QBUjAhmRNf6jOhan4oRIbhcLpz7TQ5qBUunwXf3gDsfarYrWGBF1yxRSbfhJvlocsF7qvYuZsn+JThznUXGVAiuQIfqHehSvQudqneicaXG2G3m34lNpLzSIktERKScSsvM44M/t/PeH9tJzcgFoGqFUG7u3pDBnesSGapfEzzmyoefHoa/pxR83rJ/wUsEQ7y/8mcYBtuc21i8t+BK1ZJ9SziSc6TImMjgSNpXbV/wEsAanWhWqRkOu/k3BRCRAvq/p4e0GXFgs8LcaNNE/9QKtE0TS5KprLPKvJSHXj2UnsO7i7Yz4+8dpOcUPF43NpxbujfkP+1qERr0/xsI+ypjme7VrKPYZ92Ibet8ANw9HsI4/x6w2TzaYNgwDHam7yRpXxJJ+5NYsm8Jh7IPFRkT5gijXdV2dKpW8BLA5rHNCbKf8Guc4fkmqWejXjXnnNqM2Ld5/EWbEZeQNiO2FivMjTZN9E+tQNs0sSSZyjqrzEtZ7tUDGS4+X3uUnzYfI/efHYTrVwxhUJuKdK8fhcN++vfslLUNTkuS6UQhzhRqLbyX0GM7cDvC2HPueNJr9zjrcQdzDrLGuaZwA+DDuYeLfD3YFkyTCk1oFd2KltEtiY+MJ9geXKyM3lKvmnNObUbs2zz+os2IfUSbEVuDFeZGmyb6p1agbZpYkkxlnVXmpSz26q9L1jFnh5tvVu3D5S74a79dnRhuu6ARPZvGYT/D4spXGctkr275FfsXN2LLcWLE1MZ9zQyo3vqUQ/dn7mfJviUk7S+4WrU7fXeRrwfZg2hTpQ0dq3WkU7VOtIlrQ6gj1PtMPqBeNeec2ozYt3n8RZsR+5g2Iw58Vpgbq2+a6HYb5Lnd5LsMcvLcpOcapGW7cDgKXu4CcPxfbY7/841B4Qen/brL5eZwlpsKx3Kx/5OzsN6//hno33XzXS72pbsIOZKNw+E4bY7jjxz/PN/lYkdaPhzKxGF3YGD8f+1/ncMwCv4lLeVIHnn70rH/874H4181j5/K5XKx41Au6WFObHY7breB2yj4ntwGuA0Dt1FwPvcJjxmFj515jPuExwzDKKzvSc1THm+c6vgT65883uBfNU8x5t81XW6DzMxMIhYeBc78S70nN0GznaWGV7VOGGMYFORc5CzyuC/PdxLDICMzk8g/nIUFPL0T3NlGZebms2T7kcLnZ7fGVbi9RzznNIz1+m5zZW2D02JnMoyC9179+BAYbqhzDrZB03FExRUOOZR1iCX7lhTeATDFmVKkhMPmoGWVloV7VSVUTSA8KNzzDH5mhb9Twfp/r/qrdlnr1UB6PmozYpEA4HIb5Lnc5LsNcnLzOJKVz960bAxs5Lnc/3zdIN/tLvjvP2PzXAULmeOPn1gn3+X+1zEnjvv/r+W7DHLzXRxJcxK+JKPg2H/quNwFxx1fMJ2qdkHdfx7757/uU1733u7DGUs5+5DT2lHM43Z6OX6XF2N3n31IuZRtdgAPZZ19iIXO2btFNUb3jKdtnYp+O0e5kJ8L398Dyz4o+DxhKFz+Ckfzs0hK+ZnFewv2qtqStqXIYXabneaxzQv3qmpfrT2RwZEmfAMiUhq0yJKAcuKVkrx//cKfd5oFSMFVlXx27MpgS84+XNgKFivHFwmnWcAcP09+4QLjhMdOu+g5Oc+psrn++T5O/WLckiwkiiv97EP85Pg/lNsKP7f96/N/PjCMgq+d5uvHryKcXK/gKpPd7ih47HTn+/fjFFxxcgQFYTsxx+nOA+S78gkOCipIc5rz/PPN4MrPJyQkBIe9YKzdZsP+z39tJ3xst/Gvz08Yby/4L5zhePvx40/8uifn++ex0+SznXhOj7+HU2Sw//94DDf79u2jRvUaZ3xdfeHVz7Pw5MXunlT696vm3e6CnNWrV/f69f+eZTp5kNttnHBOm+e1PBjjNtxUzD/KhZ1aBsS/AltaxiH4dBikLMLpcLC0y40srhjH4u+HsOnIppOGN63UlM41Cq5Uta/WnuiQs7/tQETKBi2yygDD8OxqSOGi5XSLlVNcGTnTwiTvhCsfp691/PgznPesV0q8sc8XU+pXwQ4bQXY7QXYbQQ4bQQ47wfaC/wY5bATb7UUed9htBP/ztSC7veD4wmNOHHf8a/8/zm6Do6mHqVGtKiHBDoLtdhz/HBfsKMhwqtrHHy8496kz2nCzdUsyjeMbExT0/7+4FWezS5fLxebNm2ncuHGx3pNVnGO9Pc6b8SX5fsoyl8vF5rB0GjeuHtDz4nK52ByRQePGNUv1fR6bN/vnnAW1M31aszz6v/buPjiq6uAf+Pfeu++bbDYJkJAQAzUBrGN9qEaax+po5SfMr2VEpDrI+DY4tH1E7YuO0860oNXWah/n+TlNba0ttI4jtvOrbQexDg+FgSJiykMBi0KiCAGS8BKSzSabze655/ljs5u7m93sbrKvyffT7mTvveece+51D9lvzt27A2f+gQNvPoBW4cH7tTX4yGKG3vkO0DlapsHdEPny32urroXb5s5bf4kovxiyisTBU5fwjdf+B35/AFI5NRpWdBn5EPNUZQwCY4PBaBgQw36UOB1R20yaOhpqDAEm3I5JGw07xnVRdaJCUWw7xnIjZSIhKXp/igyFkvnz5+f4jZtAY2N9Ft64hWcqlAkFKyKiQuYL+nDw3MHQFwB/8g7+5T0FUaoACM9GScx1zY18T1VTVRMq7ZX57DIRFRCGrCKhS4muvvDnGJLfn19TlQSzFDFBwzAjkjBkxAkm8UJIZMYjUUhJMnsSdzYnxTfwxTBzIMTEZnmIiCj7/MKPQ+cO4f2u0GeqDl84jKAeHC2gKJgDE66btxRNc76I66qvwyzHrPx1mIgKGkNWkVhY7cKf/qMZZ0934PJ5c2E1mxIHH1VJ6Xa8RERE04WUEgE9gMHAIHxBH3xBH84Pnsf2M9vxyaef4ND5QxjWh6PqzFYsaPL04LohP66bfztmf/m/AC0331VFRMWNIatIOK0mXFVbBtvgOTTMKinY2RoiIqLJCOrBSAjyBX3w+r043n8c58+ex5A+FFofCG0bDI4GpnB4GgwM4mL/ReA4MCSG4AuMlhNy/CtBZtpnoqm6CYvLF6Lpvc2Yc+afUBQN+L/PAU0P5ugMENFUwJCVIiEEhEh+mZ4QArqup1Q23fLptj2dFMO5yUcfs7nPTLY9mbYmWpdjNfeK5bxwrCZvR5c6/MIfFW5iQ094eSgYCkYDwwPovtQNc6cZQ2IoUs/43Bf0jZlNijg6qe5HsagW2E12OM1O1FvqcdPlN2Hx7MWod9VD6ToE9Y01UPo7Ie3lEKs2A3NvCF3zPU1wrOZnn9kYq7msn63fq4X2eky1H4qMvXctAQBaWlrQ0tICIQSOHz+O1tZWlJSUJK2n6zp6enpQUVGR0q1/0ymfbtvTSTGcm3z0MZv7zGTbk2lronWLeaxKKaFDhy71kS9Rjl4e76cOPfQFxTHLxp+ptJuonfHaFbrAwOAAHA4HVEWFgtHPXCoj/wv9X4n64t+45YCRW80rScuE1423H2NbUkp4+71wlbqgqmryvsS2laDMmL4ZykldwuPxwF3mjtpnouOKe/wJjkvqEud7zsPmsiEgAxjShzAkhuDX/aM/9SH4hT/htvBzX9CHYTkMv+5P92WbNhUqrJoVNtUGM8xwmB2wqlbYNBtsqi2yLfJzZJtFsSAwGMCMshmwm+ywqTbYtND2cBlNCV0NEjtWS0/9N2bvfwqq8MPvmovTN/wnAqVzsn6shaYYfqcC/L2arXYK7fdqob0evV4vmpqa0NfXB5cr8dcyMGQl4fF4UFZWhp6ennFPZJgQAu3t7WhoaEj5ttCplk+37emkGM5Nqn2UUiKoBxGUQQT0AIL66M/IQwbjrzeuk0EMB4fR2d0Jd6UbOvSo+nHrygCCIn77xnaDehABEcBwYBhms3n0jV/MRwGVmBWxbxCNxxwIBGCxWMa8OY4ntt3h4eFQ3Zg31PHKRhYl4Pf7YbPaovo9Xh+H/cOw2qxj24ztrwR8Qz6YrebR0CFDYUNIERVexmwzlI96YLQMUSGxaTbYTXY4zA7YTfbIw2FywGayjT7XbBjoHUBddR2cZmdU2UgdQxsWNTSmc/J79fLPwPT356Hu+SkAQDb8H+i3/wqwTc/vtSqG36lAfvqZzX1mqu3JtjPR+tkaq4X2evR4PKioqEgasni5YIo0TUv5P6yqqlkrn27b04mqqlBUBUHECRwJgkpABJIHmnjtGIJG+Hmi/RjbHfANQDumjRuSgjKY/GDTlc3vP87kH7SHkhdJyJejeul83VCev5pIVVSoUKEoCjRFG/nCYHX0gdHn4TLhGSZN1aAgpnyceuG6420LtwsJDHgHUFIauiog/KW84RmwyE9IhP4vx5YxbktQ3theeD+xZeOtD5fXpY4h/xCsFiukYmgnTlljG8Yy8con6me4bFAEoapq/H4m2E+ycxBmUkyRAGMMMg6TI27AiVfOqlpx/ux5LPzMQjitzkiIUpXU/rI8mbvAZvP3qqb7YX5zLZSPtoZW/PvDUJY8CU2d3r9ni+X9Rj76mc19ZqrtybYz0frZGquF9HpMtQ8MWdOMLkOX7AT0AIQUCOrByM+AHoDQo9cZA4TQRfRyuIyhXLh+ZDm8j5F9Rq2TIv4+Y9tLsM/Y+gE9ALm/CCZmJxAGNEWDSTXBpJpgVs2R5ybFFLU+atvI9qHBIbhdbpg1c6R8uFxs+Xj1zdpIWSV6mwoVZ0+fxZy6OdBULeoNHQDETpKPt13XdXSc7sCcOXMSXgqQqD1d13H69GnU1tZC1dSk5cOEEDh75ixqamvG9D9eX3Vdx9mzZ1FTUwMlyd07hRDo7OxEXW0dNC0UMDQlfmiJBKCRbWmFoSR1C00xfNUCkJ9+ZnOfwWAQ7e3tk25bCIG23jbMKZ1T0P/90tJ3GvX/vQ5K73FAswDL/x/wb3fnu1dENAUwZBWJ9kvteOHAC/B4PbCetMYNHMaAEht2wmV0qef7UHJuTKgwBJO4wWKc8knLGoKPMdSEQ0l3Zzfm1s2F1WSNG2TihSZN1Sb8hjmbb9yEECjtK0XjzMm3LYSAy+NCY1X6bQkhUN5fjsbZ6dUVQqBtoA2NNanVE0KgbbANjbXJywsh0OZLvW2ibJq2388nAsDgBWDw4sgj/Lwnsk79eCdsgxcgnTOh3PUacNnifPeaiKYIhqwi0R/ox54ze0ILfZltO/wX8Ng3+ZqqRS+PlAmvDwcA47Zw+fD6RPXNqjlqdkZTtNH2lNH6xnLG8rHLilTQ8WkHGi9vhNVsjQSe8F/2C0HkTXpskJAS0IOhhwiEfgb8gD4wuhy1XQB6IKVlJTgMd1cnlItuALphe9BQJzjOsjD0IXpZFQHM9Q9B3WkFDB/sDwl/RksZuy5qfeinCqB+yA91txUwBsp49WPWqZC4zOeDutcxsi3xfozrVClR5/NBfc+R8n7qBgahvu8cZz/hskDNMKC01QGOCsBeDtjdIz/LAZvhudkGIkpC6oCvF/D3AgPG4DT2oQ5eRGP/OWgBb9JmFQBD7kaY7/3/0Crqs30URDSNMGQVictKL8PGL2zEhXMXMKdmzujMx0iQMYYdY8BIJdQU4mVFSek6EBgMPYa9EEMDCHi7UX5RhQaZIJyksRw3wIwXRpKHFVUE0BDwQ1X06PCSxRsZqACqs9S2AiBT8UABYJ9EXccE6zmzVF4B4AKAUykUNtkTBDB34mBmLwesLqAA7rJENCHDg/Fnl6ICVM9IaLqABYM9UFL8t1IBoBmXHBWAozLuQy+pwkm1EQ1l0+8OgkSUXQxZRaLSXokVDSvQJtvQOLeILkEKDgPD3pEwNBB6JHo+3rbY54HoOwpoAObl5whTpiDNAaeaANUc+qmZEiwbHpp5zLJUNPQPDqHE5YZqsgCqZmjDHL087n7GLgsoOHO2E7W1tdCMn1GK+jhT+JP7cuw6w3qhC3SePYvZNTXQomaFxpaNXSd0HZ2dnZg9uxpaOHQkKGtsVw/Xq64e+zmwOP3VhUBXdxeqq6qhRh3v2H3pIojzpz/BzBITVH9f6C/wvkuhx5DhudSBoA/o9wH9nUiLogK2sjgBzB0dxuJtM1nT2xfReEQg6hK80fAUvU4duIDLPd1Qhz2h132KoibJLaWh0OScEROYKgBHaJ2wlePk+X7UX3ENNGdF6N+5BKQQkG1tEz92IqIEGLJodFZoeAAIDIT+whj3+chyoueRMGWoo2fhTnmxzE5IiwNBXYHJaoOSYkiAqhmCSYLlBOEl+fLYMCOg4WTHGdTP+ww0s3X8MKNqMZegTYwuBM6OfCYLmQ7mQmBQtgGXZ6BtIeBV2oCJ9FMIeE3p15VCoN/ShuoU60kh4GlrQ1UK5aUQuORsw4zxyuo6MNyfOID5Lhm29UZvCwyOXD41spwusyNO+HKPH8zCs2cFcvktZYmuA/6+6IA0MrukDFxAddcJqAcCgM+wfSi1a9gVAGbjCs0SCUZRs03O6HXCVoET3X2Y99lroFlTmLcWAsP+tlD9aX6HQCLKH4asYiElEPSH/iredxoQQxOYCfKOBKOY54Ec3Gdas4Te2FmcoYfZAVhKAIsj8XOLEzA7x3nuBMx2QFGgC4GPC/2uZUJguN8GzMhC4KHio47MRNnKgPI0PwsS9I8Tznqjg5px21BfKJyFx33/2fT2q6iJA1iy2TSTJb19FRMpR2Y0ZfTMZtQ6w89wHeM6IUIzPL5eIDxTGrf+eG0n2CYErD0fAR+fCr0ejDNOA2NnnBJdwqwCcCc8CeNflgdHJYS9HB0XBlG34N+glc4M/VufSmgXAkFPG2dgiaioMGQVi0/3QPvtcszP9n7C4cXiiH5uKRkJQMbnxsAU57lxWTMn3zcRpcZkBUqrQo906Drg9yQJZ73xZ9SCvpHZs57QI11mJ1S7G/MUK9QdI4Er7UASr+x49RNtQ5y2R3+qkJgv5chlaknazhANyNq/7xO6nDp8WZ5hZkm3l+PCoMSMyxZAdc6MDlF2d/JZIyEwJNtCf1TgH5qIaIpjyEqREAJCJP/QrRACuq6nVDat8pot8kFeGZkVMgahUKCR8QKPeXT2R1oM66JClDP0AfxsXQqU4vmYePPpnfd8yEcfs7nPTLY9mbYmWjdrY3USfcoJS2noUXZZevUCvpHw1RsJYUokqPVGQpsSCWrhn31QIIHAAJTAAIphLiLm3pEFRUIZvbtl7E8gwTYgqNmglVZBcc6AtMfOOFVAOioBeyXgrATsFXFnjYQQuNDeDndDw9grBiSS/jvPsVo8iuW88PdqdtoptLFaaK/HVPuhyNhv7CQAQEtLC1paWiCEwPHjx9Ha2oqSkpKk9XRdR09PDyoqKhJ+qeqEyutBYHgAFz0+lM+YlVLb00m65z0f8tHHbO4zk21Ppq2J1s3aWJ1En6YkXUANeKEN90Px92Kgpwuu0lIokVkPBTL2VvuGgCDH3CrfuA0YEzIM5aQhZMS2LSNfOxAdRgAFupTo7e1DmdsNVdUM5WDoU/z6MvYYosrFhCRDOaFLXLrUg/KKypHXzNigNFGZej1Oth2O1eJRLOeFv1ez006hjdVCez16vV40NTWhr68PLpcrYTmGrCQ8Hg/KysrQ09Mz7okME0Kgvb0dDfH+0jfJ8um2PZ0Uw7nJRx+zuc9Mtj2ZtiZal2M194rlvHCsZqcdjtXiUSznhWM1O+0U2lgttNejx+NBRUVF0pDFywVTpGlayv9hVVXNWvl0255OiuHc5KOP2dxnJtueTFsTrcuxmnvFcl44VrPTDsdq8SiW88Kxmp12Cm2sFtLrMeVjy3I/iIiIiIiIphWGLCIiIiIiogxiyCIiIiIiIsoghiwiIiIiIqIMYsgiIiIiIiLKIIYsIiIiIiKiDGLIIiIiIiIiyiCGLCIiIiIiogxiyCIiIiIiIsoghiwiIiIiIqIMYsgiIiIiIiLKIIYsIiIiIiKiDDLluwPFQggBIURK5XRdT6lsuuXTbXs6KYZzk48+ZnOfmWx7Mm1NtC7Hau4Vy3nhWM1OOxyrxaNYzgvHanbaKbSxWmivx1T7wZCVQEtLC1paWhAMBgEAhw4dQklJSdJ6uq7j0qVL8Hq9UNXkE4XplE+37emkGM5NPvqYzX1msu3JtDXRuhyruVcs54VjNTvtcKwWj2I5Lxyr2Wmn0MZqob0evV4vAEBKOW45RSYrMc2dPn0adXV1+e4GEREREREViI6ODsyZMyfhdoasJHRdx9mzZ1FaWgpFUVKq09TUhNbW1pT3kWp5j8eDuro6dHR0wOVypdz+dJHuec+HfPQxm/vMZNuTaWuidTlWc68YxinAsZqtdjhWiwfHan72ybE6VqGNUykl+vv7UVNTM+7MGi8XTEJV1XFTajyapqX1Iki3vMvlKogXWaFJ9zzmQz76mM19ZrLtybQ10bocq7lXDOMU4FjNVjscq8WDYzU/++RYTayQxmlZWVnSMvm/sHEKeuihh7JanuIrhvOYjz5mc5+ZbHsybU20Lsdq7hXLOeRYzU47HKvFo1jOIcdqdtrhWJ08Xi5YRDweD8rKytDX11cwSZ6IxuJYJSoOHKtEha9YxylnsoqI1WrFhg0bYLVa890VIhoHxypRceBYJSp8xTpOOZNFRERERESUQZzJIiIiIiIiyiCGLCIiIiIiogxiyCIiIiIiIsoghiwiIiIiIqIMYsgqQLt378by5ctRU1MDRVHwpz/9KWq7lBI/+MEPMHv2bNjtdixZsgRtbW356SzRNJGJcdnT04M1a9bA5XLB7XZj7dq18Hq9OTwKoqknV2Pz8OHDuOGGG2Cz2VBXV4fnnnsu24dGVLQKaVz+4Q9/wMKFC2Gz2XDVVVdh27ZtGT/eeBiyCtDAwACuvvpqtLS0xN3+3HPP4cUXX8QvfvEL7N+/H06nE0uXLsXQ0FCOe0o0fWRiXK5Zswb/+te/sH37dmzduhW7d+/GunXrcnUIRFNSLsamx+PBrbfeivr6ehw4cADPP/88Nm7ciJdffjnrx0dUjAplXL777rtYvXo11q5di4MHD2LFihVYsWIFPvjgg+wdfJikggZAvvnmm5FlXddldXW1fP755yPrent7pdVqla+//noeekg0/UxkXB49elQCkK2trZEyb7/9tlQURZ45cyZnfSeayrI1Nn/+85/L8vJy6ff7I2WeeOIJuWDBgiwfEVHxy+e4vPPOO+WXv/zlqP4sXrxYfu1rX8voMcbDmawic+LECXR1dWHJkiWRdWVlZVi8eDH27duXx54RTV+pjMt9+/bB7Xbj2muvjZRZsmQJVFXF/v37c95noukgU2Nz3759uPHGG2GxWCJlli5dimPHjuHSpUs5OhqiqSGX43Lfvn1R+wmXycV7ZoasItPV1QUAqKqqilpfVVUV2UZEuZXKuOzq6sKsWbOitptMJlRUVHDsEmVJpsZmV1dX3DaM+yCi1ORyXCYqk4txy5BFRERERESUQQxZRaa6uhoA0N3dHbW+u7s7so2IciuVcVldXY1z585FbQ8Gg+jp6eHYJcqSTI3N6urquG0Y90FEqcnluExUJhfjliGryMybNw/V1dXYsWNHZJ3H48H+/fvR3Nycx54RTV+pjMvm5mb09vbiwIEDkTJ/+9vfoOs6Fi9enPM+E00HmRqbzc3N2L17NwKBQKTM9u3bsWDBApSXl+foaIimhlyOy+bm5qj9hMvk5D1z1m+tQWnr7++XBw8elAcPHpQA5AsvvCAPHjwoT548KaWU8tlnn5Vut1v++c9/locPH5a33XabnDdvnvT5fHnuOdHUlYlxuWzZMrlo0SK5f/9++fe//102NjbK1atX5+uQiKaEXIzN3t5eWVVVJe+55x75wQcfyC1btkiHwyF/+ctf5vx4iYpBoYzLvXv3SpPJJH/605/KDz/8UG7YsEGazWZ55MiRrJ8DhqwCtHPnTglgzOO+++6TUoZuffn9739fVlVVSavVKm+55RZ57Nix/HaaaIrLxLi8ePGiXL16tSwpKZEul0s+8MADsr+/Pw9HQzR15GpsHjp0SH7xi1+UVqtV1tbWymeffTZXh0hUdAppXP7+97+X8+fPlxaLRV555ZXyrbfeytpxGylSSpn9+TIiIiIiIqLpgZ/JIiIiIiIiyiCGLCIiIiIiogxiyCIiIiIiIsoghiwiIiIiIqIMYsgiIiIiIiLKIIYsIiIiIiKiDGLIIiIiIiIiyiCGLCIiIiIiogxiyCIioinn/vvvx4oVK8Ytc9NNN+Gb3/xmTvqTqs2bN8Ptdue7G0RENEkMWURElDf3338/FEWBoiiwWCxoaGjAU089hWAwmO+u5cVdd92F48eP57sbREQ0SaZ8d4CIiKa3ZcuWYdOmTfD7/di2bRseeughmM1mfPe73x1Tdnh4GBaLJQ+9zA273Q673Z7vbhAR0SRxJouIiPLKarWiuroa9fX1+MY3voElS5bgL3/5C4DRy/6eeeYZ1NTUYMGCBQCAI0eO4Etf+hLsdjsqKyuxbt06eL3eMW0/+eSTmDlzJlwuF77+9a9jeHg4YT/8fj8ee+wx1NbWwul0YvHixdi1a1dke/hSvq1bt2LBggVwOBxYtWoVBgcH8dvf/hZz585FeXk5HnnkEQghEu7n0KFDuPnmm1FaWgqXy4VrrrkG//jHP6L2ETZ37tzITJ/xEdbR0YE777wTbrcbFRUVuO222/Dpp5+mctqJiCiLOJNFREQFxW634+LFi5HlHTt2wOVyYfv27QCAgYEBLF26FM3NzWhtbcW5c+fw4IMPYv369di8eXNUPZvNhl27duHTTz/FAw88gMrKSjzzzDNx97t+/XocPXoUW7ZsQU1NDd58800sW7YMR44cQWNjIwBgcHAQL774IrZs2YL+/n6sXLkSt99+O9xuN7Zt24ZPPvkEd9xxB66//nrcddddcfezZs0aLFq0CC+99BI0TcM///lPmM3muGVbW1sjgU0IgVWrVkXKBgKByHnYs2cPTCYTnn76aSxbtgyHDx+e0jN+RESFjiGLiIgKgpQSO3bswDvvvIOHH344st7pdOKVV16JhIZf/epXGBoawu9+9zs4nU4AwM9+9jMsX74cP/nJT1BVVQUAsFgs+M1vfgOHw4Err7wSTz31FB5//HH88Ic/hKpGX8hx6tQpbNq0CadOnUJNTQ0A4LHHHsNf//pXbNq0CT/60Y8AhILNSy+9hMsvvxwAsGrVKrz66qvo7u5GSUkJPvvZz+Lmm2/Gzp07E4asU6dO4fHHH8fChQsBIBLg4pk5c2bk+aOPPorOzk60trYCAN544w3ouo5XXnklMru1adMmuN1u7Nq1C7feemsqp52IiLKAIYuIiPJq69atKCkpQSAQgK7ruPvuu7Fx48bI9quuuipqVubDDz/E1VdfHQlYAHD99ddD13UcO3YsErKuvvpqOByOSJnm5mZ4vV50dHSgvr4+qg9HjhyBEALz58+PWu/3+1FZWRlZdjgckYAFAFVVVZg7dy5KSkqi1p07dy7h8X7729/Ggw8+iFdffRVLlizBV7/61ag243n55Zfx61//Gu+++24keB06dAjt7e0oLS2NKjs0NISPP/543PaIiCi7GLKIiCivbr75Zrz00kuwWCyoqamByRT9q8kYprLF6/VC0zQcOHAAmqZFbTMGqNjL+hRFibtO1/WE+9q4cSPuvvtuvPXWW3j77bexYcMGbNmyBbfffnvc8jt37sTDDz+M119/HZ/73Oei+nzNNdfgtddeG1PHOANGRES5x5BFRER55XQ60dDQkHL5K664Aps3b8bAwEAkgO3duxeqqkZujAGEZnp8Pl/kbn3vvfceSkpKUFdXN6bNRYsWQQiBc+fO4YYbbpjkESU3f/58zJ8/H9/61rewevVqbNq0KW7Iam9vx6pVq/C9730PK1eujNr2+c9/Hm+88QZmzZoFl8uV9T4TEVHqeHdBIiIqKmvWrIHNZsN9992HDz74IDLTc88990QuFQRCt3tfu3Ytjh49im3btmHDhg1Yv379mM9jAaHQs2bNGtx777344x//iBMnTuD999/Hj3/8Y7z11lsZ67vP58P69euxa9cunDx5Env37kVrayuuuOKKuGWXL1+ORYsWYd26dejq6oo8wudhxowZuO2227Bnzx6cOHECu3btwiOPPILTp09nrM9ERJQ+zmQREVFRcTgceOedd/Doo4+iqakJDocDd9xxB1544YWocrfccgsaGxtx4403wu/3Y/Xq1VGf9Yq1adMmPP300/jOd76DM2fOYMaMGfjCF76Ar3zlKxnru6ZpuHjxIu699150d3djxowZWLlyJZ588skxZbu7u/HRRx/ho48+ityMI0xKCYfDgd27d+OJJ57AypUr0d/fj9raWtxyyy2c2SIiyjNFSinz3QkiIiIiIqKpgpcLEhERERERZRBDFhERERERUQYxZBEREREREWUQQxYREREREVEGMWQRERERERFlEEMWERERERFRBjFkERERERERZRBDFhERERERUQYxZBEREREREWUQQxYREREREVEGMWQRERERERFl0P8Cm3MBR/mgg4sAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Plot results\n", + "import matplotlib.pyplot as plt\n", + "\n", + "\n", + "fig, ax = plt.subplots(1, 1, figsize=(10, 5))\n", + "ax.plot(sizes, times_simple, label=\"Simple\")\n", + "ax.plot(sizes, times_fa1, label=\"FlashAttention 1\")\n", + "ax.plot(sizes, times_fa2, label=\"FlashAttention 2\")\n", + "\n", + "# fancy grid\n", + "ax.grid(True, which=\"both\", ls=\"-\", alpha=0.5)\n", + "ax.set_xscale(\"log\")\n", + "ax.set_yscale(\"log\")\n", + "ax.set_xlabel(\"Problem size\")\n", + "ax.set_ylabel(\"Time (ms)\")\n", + "ax.legend()\n", + "\n", + "# Instead of 10^1, 10^2... show nuber\n", + "ax.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f\"{x:.0f}\"))\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using FlashAttention can speed up inference even at small context lengths (number of nodes in the graph). Difference can be of several times for large graphs between different implementations!" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "env", + "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.10.12" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/advanced/2-flash-attention-2/index.html b/examples/advanced/2-flash-attention-2/index.html new file mode 100644 index 00000000..6d1bed84 --- /dev/null +++ b/examples/advanced/2-flash-attention-2/index.html @@ -0,0 +1,3541 @@ + + + + + + + + + + + + + + + + + + + + + + + Using Flash Attention 2 ⚡ - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/advanced/3-local-search/3-local-search.ipynb b/examples/advanced/3-local-search/3-local-search.ipynb new file mode 100644 index 00000000..cba53c00 --- /dev/null +++ b/examples/advanced/3-local-search/3-local-search.ipynb @@ -0,0 +1,185 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Local Search\n", + "\n", + "In this notebook, we will show how to improve the solution at hand using local search and other techniques. Here we solve TSP and use 2-opt to improve the solution. You can check how the improvement works for other problems in each Env's `local_search` method. \n", + "\n", + "Note that this notebook is based on [`1-quickstart`](../1-quickstart.ipynb) and we use the checkpoint file from it. If you haven't checked it yet, we recommend you to check it first.\n", + "\n", + "\"Open" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Installation\n", + "\n", + "We use LocalSearch operator provided by PyVRP. See https://github.com/PyVRP/PyVRP for more details.\n", + "\n", + "Uncomment the following line to install the package from PyPI. Remember to choose a GPU runtime for faster training!\n", + "\n", + "> Note: You may need to restart the runtime in Colab after this\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install rl4co[routing] # include pyvrp" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "\n", + "from rl4co.envs import TSPEnv\n", + "from rl4co.models.zoo import AttentionModel" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Environment, Policy, and Model from saved checkpoint" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/sanghyeok/NCO/rl4co/.venv/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n", + "/home/sanghyeok/NCO/rl4co/.venv/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n", + "/home/sanghyeok/NCO/rl4co/.venv/lib/python3.10/site-packages/lightning/pytorch/core/saving.py:188: Found keys that are not in the model state dict but in the checkpoint: ['baseline.baseline.model.encoder.init_embedding.init_embed.weight', 'baseline.baseline.model.encoder.init_embedding.init_embed.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.num_batches_tracked', 'baseline.baseline.model.decoder.context_embedding.W_placeholder', 'baseline.baseline.model.decoder.context_embedding.project_context.weight', 'baseline.baseline.model.decoder.project_node_embeddings.weight', 'baseline.baseline.model.decoder.project_fixed_context.weight', 'baseline.baseline.model.decoder.pointer.project_out.weight']\n" + ] + } + ], + "source": [ + "# RL4CO env based on TorchRL\n", + "env = TSPEnv(num_loc=50) \n", + "\n", + "checkpoint_path = \"../tsp-quickstart.ckpt\" # checkpoint from the ../1-quickstart.ipynb\n", + "\n", + "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", + "\n", + "# Model: default is AM with REINFORCE and greedy rollout baseline\n", + "model = AttentionModel.load_from_checkpoint(checkpoint_path, load_baseline=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Testing with Solution Improvement" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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rFl48MEHsXnzZnTs2NF8PwUREZEDYIYSEZG9M3kfRFvgHk5ERMQsqB+2GxERWWwfRCIiIiIiInJe7CASERERERERAHYQiYiIiIiI6C52EImIiIiIiAgAO4hERERERER0FzuIREREREREBIAdRCIiIiIiIrqLHUQiIiIiIiICwA4iERERERER3cUOIhEREREREQEAXGxdQF0IIQAA+fn5Nq6EiIhspSoDqjKB6oYZSkREpmSoQ3QQCwoKAAChoaE2roSIiGytoKAAPj4+ti7DYTBDiYioSl0yVCYc4FKsTqfDH3/8AS8vL8hksno9R35+PkJDQ3H16lV4e3ubuULHxrYxjO1iHNvGMLaLceZoGyEECgoKEBISArmcMyTqihlqWWwbw9guxrFtDGO7GGftDHWITxDlcjkeeOABszyXt7c3f+mMYNsYxnYxjm1jGNvFuIa2DT85NB0z1DrYNoaxXYxj2xjGdjHOWhnKS7BEREREREQEgB1EIiIiIiIiuqvRdBBVKhXmzp0LlUpl61LsDtvGMLaLcWwbw9guxrFtHBv//Yxj2xjGdjGObWMY28U4a7eNQyxSQ0RERERERJbXaD5BJCIiIiIiovtjB5GIiIiIiIgAsINIREREREREd7GDSERERERERACcrIO4dOlStGzZEmq1GpGRkTh69Oh9z9+wYQPatWsHtVqNTp06YceOHVaq1PpMaZsvvvgC/fr1g6+vL3x9fREdHV1rWzoqU39nqqxbtw4ymQwjR460bIE2ZGrb3LlzB1OnTkVwcDBUKhXatGnjlP+nTG2XxYsXo23btnBzc0NoaCimTZuG0tJSK1VrHQcOHMCwYcMQEhICmUyGzZs31/qY/fv3o1u3blCpVGjdujVWr15t8Trp/pihxjFDDWOGGscMNYwZWpNdZqhwEuvWrRNKpVKsXLlSnD59Wjz//POiSZMm4ubNmwbPP3TokFAoFGLBggXizJkz4q233hKurq7it99+s3Lllmdq24wbN04sXbpUnDx5Upw9e1Y8++yzwsfHR1y7ds3KlVuWqe1SJT09XTRv3lz069dPjBgxwjrFWpmpbVNWViZ69OghBg8eLA4ePCjS09PF/v37RWpqqpUrtyxT2+W7774TKpVKfPfddyI9PV3s3r1bBAcHi2nTplm5csvasWOHmD17tti4caMAIDZt2nTf89PS0oS7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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Greedy rollouts over trained model (same states as previous plot)\n", + "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", + "td_init = env.reset(batch_size=[3]).to(device)\n", + "model = model.to(device)\n", + "out = model(td_init.clone(), phase=\"test\", decode_type=\"greedy\", return_actions=True)\n", + "actions = out['actions']\n", + "\n", + "# Improve solutions using LocalSearch\n", + "improved_actions = env.local_search(td_init, actions, rng=0)\n", + "improved_rewards = env.get_reward(td_init, improved_actions)\n", + "\n", + "# Plotting\n", + "import matplotlib.pyplot as plt\n", + "for i, td in enumerate(td_init):\n", + " fig, axs = plt.subplots(1,2, figsize=(11,5))\n", + " env.render(td, actions[i], ax=axs[0]) \n", + " env.render(td, improved_actions[i], ax=axs[1])\n", + " axs[0].set_title(f\"Before improvement | Cost = {-out['reward'][i].item():.3f}\")\n", + " axs[1].set_title(f\"After improvement | Cost = {-improved_rewards[i].item():.3f}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can see that the solution has improved after using 2-opt." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/advanced/3-local-search/index.html b/examples/advanced/3-local-search/index.html new file mode 100644 index 00000000..bddb628e --- /dev/null +++ b/examples/advanced/3-local-search/index.html @@ -0,0 +1,3235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Local Search - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/advanced/README.md b/examples/advanced/README.md new file mode 100644 index 00000000..825e7b45 --- /dev/null +++ b/examples/advanced/README.md @@ -0,0 +1,9 @@ +# Advanced + +Collection of advanced examples and tutorials - which at the moment are a bit mixed together. + + +## Index + +- [`1-hydra-config.ipynb`](1-hydra-config.ipynb): here we show how to use Hydra to configure your training and testing scripts. +- [`2-flash-attention-2.ipynb`](2-flash-attention-2.ipynb): this notebook shows the effects of different SDPA (Scaled Dot-Product Attention) implementations on the training of a model. \ No newline at end of file diff --git a/examples/advanced/index.html b/examples/advanced/index.html new file mode 100644 index 00000000..a816f406 --- /dev/null +++ b/examples/advanced/index.html @@ -0,0 +1,2385 @@ + + + + + + + + + + + + + + + + + + + + + + + Advanced - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ + + + + + + + + +

Advanced

+

Collection of advanced examples and tutorials - which at the moment are a bit mixed together.

+

Index

+
    +
  • 1-hydra-config.ipynb: here we show how to use Hydra to configure your training and testing scripts.
  • +
  • 2-flash-attention-2.ipynb: this notebook shows the effects of different SDPA (Scaled Dot-Product Attention) implementations on the training of a model.
  • +
+ + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/datasets/1-test-on-tsplib/1-test-on-tsplib.ipynb b/examples/datasets/1-test-on-tsplib/1-test-on-tsplib.ipynb new file mode 100644 index 00000000..1d5e8634 --- /dev/null +++ b/examples/datasets/1-test-on-tsplib/1-test-on-tsplib.ipynb @@ -0,0 +1,637 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Model on TSPLib\n", + "\n", + "In this notebook, we will test the trained model's performance on the TSPLib benchmark. We will use the trained model from the previous notebook.\n", + "\n", + "[TSPLib](http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/) is a library of sample instances for the TSP (and related problems) from various sources and of various types. In the TSPLib, there are several problems, including *TSP, HCP, ATSP*, etc. In this notebook, we will focus on testing the model on the TSP problem.\n", + "\n", + "\n", + "\n", + "\"Open\n", + "\n", + "\n", + "## Before we start\n", + "\n", + "Before we test the model on TSPLib dataset, we need to prepare the dataset first by the following steps:\n", + "\n", + "**Step 1**. You may come to [here](http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/tsp/) to download the *symmetric traveling salesman problem* data in TSPLib dataset and unzip to a folder;\n", + "\n", + "Note that the downloaded data is `gzip` file with the following file tree:\n", + "```\n", + ".\n", + "└── ALL_tsp/\n", + " ├── a280.opt.tour.gz\n", + " ├── a280.tsp.gz\n", + " ├── ali535.tsp.gz\n", + " └── ... (other problems)\n", + "```\n", + "We need to unzip the `gzip` file to get the `.tsp` and `.opt.tour` files. We can use the following command to unzip them to the same folder:\n", + "```bash\n", + "find . -name \"*.gz\" -exec gunzip {} +\n", + "```\n", + "\n", + "After doing this, we will get the following file tree:\n", + "```\n", + ".\n", + "└── ALL_tsp/\n", + " ├── a280.opt.tour\n", + " ├── a280.tsp\n", + " ├── ali535.tsp\n", + " └── ... (other problems)\n", + "```\n", + "\n", + "**Step 2**. To read the TSPLib problem and optimal solution, we choose to use the `tsplib95` package. Use `pip install tsplib95` to install the package." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installation\n", + "\n", + "Uncomment the following line to install the package from PyPI. Remember to choose a GPU runtime for faster training!\n", + "\n", + "> Note: You may need to restart the runtime in Colab after this\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install rl4co[graph] # include torch-geometric\n", + "\n", + "## NOTE: to install latest version from Github (may be unstable) install from source instead:\n", + "# !pip install git+https://github.com/ai4co/rl4co.git" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Install the `tsplib95` package\n", + "# !pip install tsplib95" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/cbhua/.local/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "import os\n", + "import re\n", + "import torch\n", + "\n", + "from rl4co.envs import TSPEnv, CVRPEnv\n", + "from rl4co.models.zoo.am import AttentionModel\n", + "from rl4co.utils.trainer import RL4COTrainer\n", + "from rl4co.utils.decoding import get_log_likelihood\n", + "from rl4co.models.zoo import EAS, EASLay, EASEmb, ActiveSearch\n", + "\n", + "from math import ceil\n", + "from einops import repeat\n", + "from tsplib95.loaders import load_problem, load_solution" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load a trained model" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/cbhua/miniconda3/envs/rl4co-user/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n", + "/home/cbhua/miniconda3/envs/rl4co-user/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n", + "/home/cbhua/miniconda3/envs/rl4co-user/lib/python3.10/site-packages/lightning/pytorch/core/saving.py:177: Found keys that are not in the model state dict but in the checkpoint: ['baseline.baseline.model.encoder.init_embedding.init_embed.weight', 'baseline.baseline.model.encoder.init_embedding.init_embed.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.num_batches_tracked', 'baseline.baseline.model.decoder.context_embedding.W_placeholder', 'baseline.baseline.model.decoder.context_embedding.project_context.weight', 'baseline.baseline.model.decoder.project_node_embeddings.weight', 'baseline.baseline.model.decoder.project_fixed_context.weight', 'baseline.baseline.model.decoder.logit_attention.project_out.weight']\n" + ] + } + ], + "source": [ + "# Load from checkpoint; alternatively, simply instantiate a new model\n", + "# Note the model is trained for TSP problem\n", + "checkpoint_path = \"../tsp-20.ckpt\" # modify the path to your checkpoint file\n", + "\n", + "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", + "\n", + "# load checkpoint\n", + "# checkpoint = torch.load(checkpoint_path)\n", + "\n", + "lit_model = AttentionModel.load_from_checkpoint(checkpoint_path, load_baseline=False)\n", + "policy, env = lit_model.policy, lit_model.env\n", + "policy = policy.to(device)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load tsp problems\n", + "\n", + "Note that in the TSPLib, only part of the problems have optimal solutions with the same problem name but with `.opt.tour` suffix. For example, `a280.tsp` has the optimal solution `a280.opt.tour`. " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Load the problem from TSPLib\n", + "tsplib_dir = './tsplib'# modify this to the directory of your prepared files\n", + "files = os.listdir(tsplib_dir)\n", + "problem_files_full = [file for file in files if file.endswith('.tsp')]\n", + "\n", + "# Load the optimal solution files from TSPLib\n", + "solution_files = [file for file in files if file.endswith('.opt.tour')] " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# Utils function\n", + "def normalize_coord(coord:torch.Tensor) -> torch.Tensor:\n", + " x, y = coord[:, 0], coord[:, 1]\n", + " x_min, x_max = x.min(), x.max()\n", + " y_min, y_max = y.min(), y.max()\n", + " \n", + " x_scaled = (x - x_min) / (x_max - x_min) \n", + " y_scaled = (y - y_min) / (y_max - y_min)\n", + " coord_scaled = torch.stack([x_scaled, y_scaled], dim=1)\n", + " return coord_scaled " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test the greedy\n", + "\n", + "Note that run all experiments will take long time and require large VRAM. For simple testing, we can use a subset of the problems. " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# Customized problem cases\n", + "problem_files_custom = [\n", + " \"eil51.tsp\", \"berlin52.tsp\", \"st70.tsp\", \"eil76.tsp\", \n", + " \"pr76.tsp\", \"rat99.tsp\", \"kroA100.tsp\", \"kroB100.tsp\", \n", + " \"kroC100.tsp\", \"kroD100.tsp\", \"kroE100.tsp\", \"rd100.tsp\", \n", + " \"eil101.tsp\", \"lin105.tsp\", \"pr124.tsp\", \"bier127.tsp\", \n", + " \"ch130.tsp\", \"pr136.tsp\", \"pr144.tsp\", \"kroA150.tsp\", \n", + " \"kroB150.tsp\", \"pr152.tsp\", \"u159.tsp\", \"rat195.tsp\", \n", + " \"kroA200.tsp\", \"ts225.tsp\", \"tsp225.tsp\", \"pr226.tsp\"\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_3883036/2632546508.py:5: DeprecationWarning: Call to deprecated function (or staticmethod) load_problem. (Will be removed in newer versions. Use `tsplib95.load` instead.) -- Deprecated since version 7.0.0.\n", + " problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx]))\n", + "/tmp/ipykernel_3883036/2632546508.py:43: DeprecationWarning: Call to deprecated function (or staticmethod) load_solution. (Will be removed in newer versions. Use `tsplib95.load` instead.) -- Deprecated since version 7.0.0.\n", + " solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour'))\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Problem: eil51 Cost: 493 Optimal Cost: 426 \t Gap: 15.73%\n", + "problem: eil51 cost: 493 \n", + "problem: berlin52 cost: 8957 \n", + "Problem: st70 Cost: 806 Optimal Cost: 675 \t Gap: 19.41%\n", + "problem: st70 cost: 806 \n", + "Problem: eil76 Cost: 693 Optimal Cost: 538 \t Gap: 28.81%\n", + "problem: eil76 cost: 693 \n", + "Problem: pr76 Cost: 132292 Optimal Cost: 108159 \t Gap: 22.31%\n", + "problem: pr76 cost: 132292 \n", + "problem: rat99 cost: 2053 \n", + "Problem: kroA100 Cost: 30791 Optimal Cost: 21282 \t Gap: 44.68%\n", + "problem: kroA100 cost: 30791 \n", + "problem: kroB100 cost: 30347 \n", + "Problem: kroC100 Cost: 28339 Optimal Cost: 20749 \t Gap: 36.58%\n", + "problem: kroC100 cost: 28339 \n", + "Problem: kroD100 Cost: 27600 Optimal Cost: 21294 \t Gap: 29.61%\n", + "problem: kroD100 cost: 27600 \n", + "problem: kroE100 cost: 28396 \n", + "Problem: rd100 Cost: 10695 Optimal Cost: 7910 \t Gap: 35.21%\n", + "problem: rd100 cost: 10695 \n", + "problem: eil101 cost: 919 \n", + "Problem: lin105 Cost: 21796 Optimal Cost: 14379 \t Gap: 51.58%\n", + "problem: lin105 cost: 21796 \n", + "problem: pr124 cost: 75310 \n", + "problem: bier127 cost: 177471 \n", + "problem: ch130 cost: 8169 \n", + "problem: pr136 cost: 135974 \n", + "problem: pr144 cost: 71599 \n", + "problem: kroA150 cost: 40376 \n", + "problem: kroB150 cost: 37076 \n", + "problem: pr152 cost: 94805 \n", + "problem: u159 cost: 64768 \n", + "problem: rat195 cost: 4465 \n", + "problem: kroA200 cost: 44181 \n", + "problem: ts225 cost: 210475 \n", + "Problem: tsp225 Cost: 6212 Optimal Cost: 3919 \t Gap: 58.51%\n", + "problem: tsp225 cost: 6212 \n", + "problem: pr226 cost: 98849 \n" + ] + } + ], + "source": [ + "# problem_files = problem_files_full # if you want to test on all the problems\n", + "problem_files = problem_files_custom # if you want to test on the customized problems\n", + "\n", + "for problem_idx in range(len(problem_files)):\n", + " problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx]))\n", + "\n", + " # NOTE: in some problem files (e.g. hk48), the node coordinates are not available\n", + " # we temporarily skip these problems\n", + " if not len(problem.node_coords):\n", + " continue\n", + "\n", + " # Load the node coordinates\n", + " coords = []\n", + " for _, v in problem.node_coords.items():\n", + " coords.append(v)\n", + " coords = torch.tensor(coords).float().to(device) # [n, 2]\n", + " coords_norm = normalize_coord(coords)\n", + "\n", + " # Prepare the tensordict\n", + " batch_size = 2\n", + " td = env.reset(batch_size=(batch_size,)).to(device)\n", + " td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2)\n", + " td['action_mask'] = torch.ones(batch_size, coords_norm.shape[0], dtype=torch.bool)\n", + "\n", + " # Get the solution from the policy\n", + " with torch.no_grad():\n", + " out = policy(\n", + " td.clone(), \n", + " decode_type=\"greedy\", \n", + " return_actions=True,\n", + " num_starts=0\n", + " )\n", + "\n", + " # Calculate the cost on the original scale\n", + " td['locs'] = repeat(coords, 'n d -> b n d', b=batch_size, d=2)\n", + " neg_reward = env.get_reward(td, out['actions'])\n", + " cost = ceil(-1 * neg_reward[0].item())\n", + "\n", + " # Check if there exists an optimal solution\n", + " try:\n", + " # Load the optimal solution\n", + " solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour'))\n", + " matches = re.findall(r'\\((.*?)\\)', solution.comment)\n", + "\n", + " # NOTE: in some problem solution file (e.g. ch130), the optimal cost is not writen with a brace\n", + " # we temporarily skip to calculate the gap for these problems\n", + " optimal_cost = int(matches[0])\n", + " gap = (cost - optimal_cost) / optimal_cost\n", + " print(f'Problem: {problem_files[problem_idx][:-4]:<10} Cost: {cost:<10} Optimal Cost: {optimal_cost:<10}\\t Gap: {gap:.2%}')\n", + " except:\n", + " continue\n", + " finally:\n", + " print(f'problem: {problem_files[problem_idx][:-4]:<10} cost: {cost:<10}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test the Augmentation" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_3883036/2898406631.py:13: DeprecationWarning: Call to deprecated function (or staticmethod) load_problem. (Will be removed in newer versions. Use `tsplib95.load` instead.) -- Deprecated since version 7.0.0.\n", + " problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx]))\n", + "/tmp/ipykernel_3883036/2898406631.py:56: DeprecationWarning: Call to deprecated function (or staticmethod) load_solution. (Will be removed in newer versions. Use `tsplib95.load` instead.) -- Deprecated since version 7.0.0.\n", + " solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour'))\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Problem: eil51\t Cost: 457\t Optimal Cost: 426\t Gap: 7.28%\n", + "problem: eil51\t cost: 457\t\n", + "problem: berlin52\t cost: 8256\t\n", + "Problem: st70\t Cost: 777\t Optimal Cost: 675\t Gap: 15.11%\n", + "problem: st70\t cost: 777\t\n", + "Problem: eil76\t Cost: 652\t Optimal Cost: 538\t Gap: 21.19%\n", + "problem: eil76\t cost: 652\t\n", + "Problem: pr76\t Cost: 124939\t Optimal Cost: 108159\t Gap: 15.51%\n", + "problem: pr76\t cost: 124939\t\n", + "problem: rat99\t cost: 1614\t\n", + "Problem: kroA100\t Cost: 27694\t Optimal Cost: 21282\t Gap: 30.13%\n", + "problem: kroA100\t cost: 27694\t\n", + "problem: kroB100\t cost: 28244\t\n", + "Problem: kroC100\t Cost: 25032\t Optimal Cost: 20749\t Gap: 20.64%\n", + "problem: kroC100\t cost: 25032\t\n", + "Problem: kroD100\t Cost: 26811\t Optimal Cost: 21294\t Gap: 25.91%\n", + "problem: kroD100\t cost: 26811\t\n", + "problem: kroE100\t cost: 27831\t\n", + "Problem: rd100\t Cost: 9657\t Optimal Cost: 7910\t Gap: 22.09%\n", + "problem: rd100\t cost: 9657\t\n", + "problem: eil101\t cost: 781\t\n", + "Problem: lin105\t Cost: 18769\t Optimal Cost: 14379\t Gap: 30.53%\n", + "problem: lin105\t cost: 18769\t\n", + "problem: pr124\t cost: 72115\t\n", + "problem: bier127\t cost: 154518\t\n", + "problem: ch130\t cost: 7543\t\n", + "problem: pr136\t cost: 128134\t\n", + "problem: pr144\t cost: 69755\t\n", + "problem: kroA150\t cost: 35967\t\n", + "problem: kroB150\t cost: 35196\t\n", + "problem: pr152\t cost: 88602\t\n", + "problem: u159\t cost: 59484\t\n", + "problem: rat195\t cost: 3631\t\n", + "problem: kroA200\t cost: 42061\t\n", + "problem: ts225\t cost: 196545\t\n", + "Problem: tsp225\t Cost: 5680\t Optimal Cost: 3919\t Gap: 44.93%\n", + "problem: tsp225\t cost: 5680\t\n", + "problem: pr226\t cost: 94540\t\n" + ] + } + ], + "source": [ + "# problem_files = problem_files_full # if you want to test on all the problems\n", + "problem_files = problem_files_custom # if you want to test on the customized problems\n", + "\n", + "# Import augmented utils\n", + "from rl4co.data.transforms import (\n", + " StateAugmentation as SymmetricStateAugmentation)\n", + "from rl4co.utils.ops import batchify, unbatchify\n", + "\n", + "num_augment = 100\n", + "augmentation = SymmetricStateAugmentation(num_augment=num_augment)\n", + "\n", + "for problem_idx in range(len(problem_files)):\n", + " problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx]))\n", + "\n", + " # NOTE: in some problem files (e.g. hk48), the node coordinates are not available\n", + " # we temporarily skip these problems\n", + " if not len(problem.node_coords):\n", + " continue\n", + "\n", + " # Load the node coordinates\n", + " coords = []\n", + " for _, v in problem.node_coords.items():\n", + " coords.append(v)\n", + " coords = torch.tensor(coords).float().to(device) # [n, 2]\n", + " coords_norm = normalize_coord(coords)\n", + "\n", + " # Prepare the tensordict\n", + " batch_size = 2\n", + " td = env.reset(batch_size=(batch_size,)).to(device)\n", + " td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2)\n", + " td['action_mask'] = torch.ones(batch_size, coords_norm.shape[0], dtype=torch.bool)\n", + "\n", + " # Augmentation\n", + " td = augmentation(td)\n", + "\n", + " # Get the solution from the policy\n", + " with torch.no_grad():\n", + " out = policy(\n", + " td.clone(), \n", + " decode_type=\"greedy\", \n", + " return_actions=True,\n", + " num_starts=0\n", + " )\n", + "\n", + " # Calculate the cost on the original scale\n", + " coords_repeat = repeat(coords, 'n d -> b n d', b=batch_size, d=2)\n", + " td['locs'] = batchify(coords_repeat, num_augment)\n", + " reward = env.get_reward(td, out['actions'])\n", + " reward = unbatchify(reward, num_augment)\n", + " cost = ceil(-1 * torch.max(reward).item())\n", + "\n", + " # Check if there exists an optimal solution\n", + " try:\n", + " # Load the optimal solution\n", + " solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour'))\n", + " matches = re.findall(r'\\((.*?)\\)', solution.comment)\n", + "\n", + " # NOTE: in some problem solution file (e.g. ch130), the optimal cost is not writen with a brace\n", + " # we temporarily skip to calculate the gap for these problems\n", + " optimal_cost = int(matches[0])\n", + " gap = (cost - optimal_cost) / optimal_cost\n", + " print(f'Problem: {problem_files[problem_idx][:-4]}\\t Cost: {cost}\\t Optimal Cost: {optimal_cost}\\t Gap: {gap:.2%}')\n", + " except:\n", + " continue\n", + " finally:\n", + " print(f'problem: {problem_files[problem_idx][:-4]}\\t cost: {cost}\\t')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test the Sampling" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_3883036/2154301274.py:9: DeprecationWarning: Call to deprecated function (or staticmethod) load_problem. (Will be removed in newer versions. Use `tsplib95.load` instead.) -- Deprecated since version 7.0.0.\n", + " problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx]))\n", + "/tmp/ipykernel_3883036/2154301274.py:53: DeprecationWarning: Call to deprecated function (or staticmethod) load_solution. (Will be removed in newer versions. Use `tsplib95.load` instead.) -- Deprecated since version 7.0.0.\n", + " solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour'))\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Problem: eil51\t Cost: 482\t Optimal Cost: 426\t Gap: 13.15%\n", + "problem: eil51\t cost: 482\t\n", + "problem: berlin52\t cost: 8955\t\n", + "Problem: st70\t Cost: 794\t Optimal Cost: 675\t Gap: 17.63%\n", + "problem: st70\t cost: 794\t\n", + "Problem: eil76\t Cost: 673\t Optimal Cost: 538\t Gap: 25.09%\n", + "problem: eil76\t cost: 673\t\n", + "Problem: pr76\t Cost: 127046\t Optimal Cost: 108159\t Gap: 17.46%\n", + "problem: pr76\t cost: 127046\t\n", + "problem: rat99\t cost: 1886\t\n", + "Problem: kroA100\t Cost: 29517\t Optimal Cost: 21282\t Gap: 38.69%\n", + "problem: kroA100\t cost: 29517\t\n", + "problem: kroB100\t cost: 28892\t\n", + "Problem: kroC100\t Cost: 26697\t Optimal Cost: 20749\t Gap: 28.67%\n", + "problem: kroC100\t cost: 26697\t\n", + "Problem: kroD100\t Cost: 27122\t Optimal Cost: 21294\t Gap: 27.37%\n", + "problem: kroD100\t cost: 27122\t\n", + "problem: kroE100\t cost: 28016\t\n", + "Problem: rd100\t Cost: 10424\t Optimal Cost: 7910\t Gap: 31.78%\n", + "problem: rd100\t cost: 10424\t\n", + "problem: eil101\t cost: 837\t\n", + "Problem: lin105\t Cost: 19618\t Optimal Cost: 14379\t Gap: 36.44%\n", + "problem: lin105\t cost: 19618\t\n", + "problem: pr124\t cost: 74699\t\n", + "problem: bier127\t cost: 170255\t\n", + "problem: ch130\t cost: 7985\t\n", + "problem: pr136\t cost: 129964\t\n", + "problem: pr144\t cost: 70477\t\n", + "problem: kroA150\t cost: 37185\t\n", + "problem: kroB150\t cost: 35172\t\n", + "problem: pr152\t cost: 97244\t\n", + "problem: u159\t cost: 59792\t\n", + "problem: rat195\t cost: 4325\t\n", + "problem: kroA200\t cost: 42059\t\n", + "problem: ts225\t cost: 205982\t\n", + "Problem: tsp225\t Cost: 5970\t Optimal Cost: 3919\t Gap: 52.33%\n", + "problem: tsp225\t cost: 5970\t\n", + "problem: pr226\t cost: 103135\t\n" + ] + } + ], + "source": [ + "# problem_files = problem_files_full # if you want to test on all the problems\n", + "problem_files = problem_files_custom # if you want to test on the customized problems\n", + "\n", + "# Parameters for sampling\n", + "num_samples = 100\n", + "softmax_temp = 0.05\n", + "\n", + "for problem_idx in range(len(problem_files)):\n", + " problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx]))\n", + "\n", + " # NOTE: in some problem files (e.g. hk48), the node coordinates are not available\n", + " # we temporarily skip these problems\n", + " if not len(problem.node_coords):\n", + " continue\n", + "\n", + " # Load the node coordinates\n", + " coords = []\n", + " for _, v in problem.node_coords.items():\n", + " coords.append(v)\n", + " coords = torch.tensor(coords).float().to(device) # [n, 2]\n", + " coords_norm = normalize_coord(coords)\n", + "\n", + " # Prepare the tensordict\n", + " batch_size = 2\n", + " td = env.reset(batch_size=(batch_size,)).to(device)\n", + " td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2)\n", + " td['action_mask'] = torch.ones(batch_size, coords_norm.shape[0], dtype=torch.bool)\n", + "\n", + " # Sampling\n", + " td = batchify(td, num_samples)\n", + "\n", + " # Get the solution from the policy\n", + " with torch.no_grad():\n", + " out = policy(\n", + " td.clone(), \n", + " decode_type=\"sampling\", \n", + " return_actions=True,\n", + " num_starts=0,\n", + " softmax_temp=softmax_temp\n", + " )\n", + "\n", + " # Calculate the cost on the original scale\n", + " coords_repeat = repeat(coords, 'n d -> b n d', b=batch_size, d=2)\n", + " td['locs'] = batchify(coords_repeat, num_samples)\n", + " reward = env.get_reward(td, out['actions'])\n", + " reward = unbatchify(reward, num_samples)\n", + " cost = ceil(-1 * torch.max(reward).item())\n", + "\n", + " # Check if there exists an optimal solution\n", + " try:\n", + " # Load the optimal solution\n", + " solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour'))\n", + " matches = re.findall(r'\\((.*?)\\)', solution.comment)\n", + "\n", + " # NOTE: in some problem solution file (e.g. ch130), the optimal cost is not writen with a brace\n", + " # we temporarily skip to calculate the gap for these problems\n", + " optimal_cost = int(matches[0])\n", + " gap = (cost - optimal_cost) / optimal_cost\n", + " print(f'Problem: {problem_files[problem_idx][:-4]}\\t Cost: {cost}\\t Optimal Cost: {optimal_cost}\\t Gap: {gap:.2%}')\n", + " except:\n", + " continue\n", + " finally:\n", + " print(f'problem: {problem_files[problem_idx][:-4]}\\t cost: {cost}\\t')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "rl4co-user", + "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.10.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/datasets/1-test-on-tsplib/index.html b/examples/datasets/1-test-on-tsplib/index.html new file mode 100644 index 00000000..937f181f --- /dev/null +++ b/examples/datasets/1-test-on-tsplib/index.html @@ -0,0 +1,4090 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Test Model on TSPLib - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+ +
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/datasets/2-test-on-cvrplib/2-test-on-cvrplib.ipynb b/examples/datasets/2-test-on-cvrplib/2-test-on-cvrplib.ipynb new file mode 100644 index 00000000..0f6f3f1d --- /dev/null +++ b/examples/datasets/2-test-on-cvrplib/2-test-on-cvrplib.ipynb @@ -0,0 +1,537 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Model on VRPLib\n", + "\n", + "In this notebook, we will test the trained model's performance on the VRPLib benchmark. We will use the trained model from the previous notebook.\n", + "\n", + "[VRPLIB](http://vrp.galgos.inf.puc-rio.br/index.php/en/) is a collection of instances related to the CVRP, which is a classic optimization challenge in the field of logistics and transportation. \n", + "\n", + "\"Open\n", + "\n", + "## Before we start\n", + "\n", + "To use the VRPLib, we strongly recomment to use the Python `vrplib` tool:\n", + "\n", + "[VRPLib](https://github.com/leonlan/VRPLIB) is a Python package for working with Vehicle Routing Problem (VRP) instances. This tool can help us easily load the VRPLib instances and visualize the results." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installation\n", + "\n", + "Uncomment the following line to install the package from PyPI. Remember to choose a GPU runtime for faster training!\n", + "\n", + "> Note: You may need to restart the runtime in Colab after this\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install rl4co[graph] # include torch-geometric\n", + "\n", + "## NOTE: to install latest version from Github (may be unstable) install from source instead:\n", + "# !pip install git+https://github.com/ai4co/rl4co.git" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Install the `tsplib95` package\n", + "# !pip install vrplib" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The autoreload extension is already loaded. To reload it, use:\n", + " %reload_ext autoreload\n" + ] + } + ], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "import os\n", + "import re\n", + "import torch\n", + "import vrplib\n", + "\n", + "from rl4co.envs import TSPEnv, CVRPEnv\n", + "from rl4co.models.zoo.am import AttentionModel\n", + "from rl4co.utils.trainer import RL4COTrainer\n", + "from rl4co.utils.decoding import get_log_likelihood\n", + "from rl4co.models.zoo import EAS, EASLay, EASEmb, ActiveSearch\n", + "\n", + "from tqdm import tqdm\n", + "from math import ceil\n", + "from einops import repeat" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load a trained model" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/cbhua/miniconda3/envs/rl4co-user/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n", + "/home/cbhua/miniconda3/envs/rl4co-user/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n", + "/home/cbhua/miniconda3/envs/rl4co-user/lib/python3.10/site-packages/lightning/pytorch/core/saving.py:177: Found keys that are not in the model state dict but in the checkpoint: ['baseline.baseline.model.encoder.init_embedding.init_embed.weight', 'baseline.baseline.model.encoder.init_embedding.init_embed.bias', 'baseline.baseline.model.encoder.init_embedding.init_embed_depot.weight', 'baseline.baseline.model.encoder.init_embedding.init_embed_depot.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.num_batches_tracked', 'baseline.baseline.model.decoder.context_embedding.project_context.weight', 'baseline.baseline.model.decoder.project_node_embeddings.weight', 'baseline.baseline.model.decoder.project_fixed_context.weight', 'baseline.baseline.model.decoder.logit_attention.project_out.weight']\n" + ] + } + ], + "source": [ + "# Load from checkpoint; alternatively, simply instantiate a new model\n", + "# Note the model is trained for CVRP problem\n", + "checkpoint_path = \"../cvrp-20.ckpt\" # modify the path to your checkpoint file\n", + "\n", + "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", + "\n", + "# load checkpoint\n", + "# checkpoint = torch.load(checkpoint_path)\n", + "\n", + "lit_model = AttentionModel.load_from_checkpoint(checkpoint_path, load_baseline=False)\n", + "policy, env = lit_model.policy, lit_model.env\n", + "policy = policy.to(device)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Download vrp problems" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " 0%| | 0/37 [00:00 torch.Tensor:\n", + " x, y = coord[:, 0], coord[:, 1]\n", + " x_min, x_max = x.min(), x.max()\n", + " y_min, y_max = y.min(), y.max()\n", + " \n", + " x_scaled = (x - x_min) / (x_max - x_min) \n", + " y_scaled = (y - y_min) / (y_max - y_min)\n", + " coord_scaled = torch.stack([x_scaled, y_scaled], dim=1)\n", + " return coord_scaled " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test the greedy" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Problem: A-n53-k7 Cost: 1371 Optimal Cost: 1010 \t Gap: 35.74%\n", + "Problem: A-n54-k7 Cost: 1426 Optimal Cost: 1167 \t Gap: 22.19%\n", + "Problem: A-n55-k9 Cost: 1333 Optimal Cost: 1073 \t Gap: 24.23%\n", + "Problem: A-n60-k9 Cost: 1728 Optimal Cost: 1354 \t Gap: 27.62%\n", + "Problem: A-n61-k9 Cost: 1297 Optimal Cost: 1034 \t Gap: 25.44%\n", + "Problem: A-n62-k8 Cost: 1818 Optimal Cost: 1288 \t Gap: 41.15%\n", + "Problem: A-n63-k9 Cost: 2166 Optimal Cost: 1616 \t Gap: 34.03%\n", + "Problem: A-n63-k10 Cost: 1698 Optimal Cost: 1314 \t Gap: 29.22%\n", + "Problem: A-n64-k9 Cost: 1805 Optimal Cost: 1401 \t Gap: 28.84%\n", + "Problem: A-n65-k9 Cost: 1592 Optimal Cost: 1174 \t Gap: 35.60%\n", + "Problem: A-n69-k9 Cost: 1641 Optimal Cost: 1159 \t Gap: 41.59%\n", + "Problem: A-n80-k10 Cost: 2230 Optimal Cost: 1763 \t Gap: 26.49%\n", + "Problem: B-n51-k7 Cost: 1270 Optimal Cost: 1032 \t Gap: 23.06%\n", + "Problem: B-n52-k7 Cost: 994 Optimal Cost: 747 \t Gap: 33.07%\n", + "Problem: B-n56-k7 Cost: 931 Optimal Cost: 707 \t Gap: 31.68%\n", + "Problem: B-n57-k7 Cost: 1422 Optimal Cost: 1153 \t Gap: 23.33%\n", + "Problem: B-n57-k9 Cost: 1889 Optimal Cost: 1598 \t Gap: 18.21%\n", + "Problem: B-n63-k10 Cost: 1807 Optimal Cost: 1496 \t Gap: 20.79%\n", + "Problem: B-n64-k9 Cost: 1150 Optimal Cost: 861 \t Gap: 33.57%\n", + "Problem: B-n66-k9 Cost: 1746 Optimal Cost: 1316 \t Gap: 32.67%\n", + "Problem: B-n67-k10 Cost: 1368 Optimal Cost: 1032 \t Gap: 32.56%\n", + "Problem: B-n68-k9 Cost: 1737 Optimal Cost: 1272 \t Gap: 36.56%\n", + "Problem: B-n78-k10 Cost: 1706 Optimal Cost: 1221 \t Gap: 39.72%\n", + "Problem: E-n51-k5 Cost: 690 Optimal Cost: 521 \t Gap: 32.44%\n", + "Problem: E-n76-k7 Cost: 1019 Optimal Cost: 682 \t Gap: 49.41%\n", + "Problem: E-n76-k8 Cost: 1031 Optimal Cost: 735 \t Gap: 40.27%\n", + "Problem: E-n76-k10 Cost: 1156 Optimal Cost: 830 \t Gap: 39.28%\n", + "Problem: E-n76-k14 Cost: 1335 Optimal Cost: 1021 \t Gap: 30.75%\n", + "Problem: E-n101-k8 Cost: 1265 Optimal Cost: 815 \t Gap: 55.21%\n", + "Problem: E-n101-k14 Cost: 1567 Optimal Cost: 1067 \t Gap: 46.86%\n", + "Problem: F-n72-k4 Cost: 425 Optimal Cost: 237 \t Gap: 79.32%\n", + "Problem: F-n135-k7 Cost: 4219 Optimal Cost: 1162 \t Gap: 263.08%\n", + "Problem: M-n101-k10 Cost: 1388 Optimal Cost: 820 \t Gap: 69.27%\n", + "Problem: M-n121-k7 Cost: 1746 Optimal Cost: 1034 \t Gap: 68.86%\n", + "Problem: M-n151-k12 Cost: 1906 Optimal Cost: 1015 \t Gap: 87.78%\n", + "Problem: M-n200-k16 Cost: 2509 Optimal Cost: 1274 \t Gap: 96.94%\n", + "Problem: M-n200-k17 Cost: 2339 Optimal Cost: 1275 \t Gap: 83.45%\n" + ] + } + ], + "source": [ + "for instance in instances:\n", + " problem = vrplib.read_instance(os.path.join(path_to_save, instance+'.vrp'))\n", + "\n", + " coords = torch.tensor(problem['node_coord']).float()\n", + " coords_norm = normalize_coord(coords)\n", + " demand = torch.tensor(problem['demand'][1:]).float()\n", + " capacity = problem['capacity']\n", + " n = coords.shape[0]\n", + "\n", + " # Prepare the tensordict\n", + " batch_size = 2\n", + " td = env.reset(batch_size=(batch_size,)).to(device)\n", + " td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2)\n", + " td['demand'] = repeat(demand, 'n -> b n', b=batch_size) / capacity\n", + " td['visited'] = torch.zeros((batch_size, 1, n), dtype=torch.uint8)\n", + " action_mask = torch.ones(batch_size, n, dtype=torch.bool)\n", + " action_mask[:, 0] = False\n", + " td['action_mask'] = action_mask\n", + "\n", + " # Get the solution from the policy\n", + " with torch.no_grad():\n", + " out = policy(td.clone(), decode_type='greedy', return_actions=True)\n", + "\n", + " # Calculate the cost on the original scale\n", + " td['locs'] = repeat(coords, 'n d -> b n d', b=batch_size, d=2)\n", + " neg_reward = env.get_reward(td, out['actions'])\n", + " cost = ceil(-1 * neg_reward[0].item())\n", + "\n", + " # Load the optimal cost\n", + " solution = vrplib.read_solution(os.path.join(path_to_save, instance+'.sol'))\n", + " optimal_cost = solution['cost']\n", + "\n", + " # Calculate the gap and print\n", + " gap = (cost - optimal_cost) / optimal_cost\n", + " print(f'Problem: {instance:<15} Cost: {cost:<10} Optimal Cost: {optimal_cost:<10}\\t Gap: {gap:.2%}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test the Augmentation" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Problem: A-n53-k7 Cost: 1123 Optimal Cost: 1010 \t Gap: 11.19%\n", + "Problem: A-n54-k7 Cost: 1305 Optimal Cost: 1167 \t Gap: 11.83%\n", + "Problem: A-n55-k9 Cost: 1199 Optimal Cost: 1073 \t Gap: 11.74%\n", + "Problem: A-n60-k9 Cost: 1534 Optimal Cost: 1354 \t Gap: 13.29%\n", + "Problem: A-n61-k9 Cost: 1187 Optimal Cost: 1034 \t Gap: 14.80%\n", + "Problem: A-n62-k8 Cost: 1474 Optimal Cost: 1288 \t Gap: 14.44%\n", + "Problem: A-n63-k9 Cost: 1820 Optimal Cost: 1616 \t Gap: 12.62%\n", + "Problem: A-n63-k10 Cost: 1505 Optimal Cost: 1314 \t Gap: 14.54%\n", + "Problem: A-n64-k9 Cost: 1582 Optimal Cost: 1401 \t Gap: 12.92%\n", + "Problem: A-n65-k9 Cost: 1332 Optimal Cost: 1174 \t Gap: 13.46%\n", + "Problem: A-n69-k9 Cost: 1305 Optimal Cost: 1159 \t Gap: 12.60%\n", + "Problem: A-n80-k10 Cost: 2044 Optimal Cost: 1763 \t Gap: 15.94%\n", + "Problem: B-n51-k7 Cost: 1073 Optimal Cost: 1032 \t Gap: 3.97%\n", + "Problem: B-n52-k7 Cost: 815 Optimal Cost: 747 \t Gap: 9.10%\n", + "Problem: B-n56-k7 Cost: 792 Optimal Cost: 707 \t Gap: 12.02%\n", + "Problem: B-n57-k7 Cost: 1219 Optimal Cost: 1153 \t Gap: 5.72%\n", + "Problem: B-n57-k9 Cost: 1744 Optimal Cost: 1598 \t Gap: 9.14%\n", + "Problem: B-n63-k10 Cost: 1611 Optimal Cost: 1496 \t Gap: 7.69%\n", + "Problem: B-n64-k9 Cost: 931 Optimal Cost: 861 \t Gap: 8.13%\n", + "Problem: B-n66-k9 Cost: 1427 Optimal Cost: 1316 \t Gap: 8.43%\n", + "Problem: B-n67-k10 Cost: 1122 Optimal Cost: 1032 \t Gap: 8.72%\n", + "Problem: B-n68-k9 Cost: 1382 Optimal Cost: 1272 \t Gap: 8.65%\n", + "Problem: B-n78-k10 Cost: 1437 Optimal Cost: 1221 \t Gap: 17.69%\n", + "Problem: E-n51-k5 Cost: 606 Optimal Cost: 521 \t Gap: 16.31%\n", + "Problem: E-n76-k7 Cost: 816 Optimal Cost: 682 \t Gap: 19.65%\n", + "Problem: E-n76-k8 Cost: 892 Optimal Cost: 735 \t Gap: 21.36%\n", + "Problem: E-n76-k10 Cost: 943 Optimal Cost: 830 \t Gap: 13.61%\n", + "Problem: E-n76-k14 Cost: 1160 Optimal Cost: 1021 \t Gap: 13.61%\n", + "Problem: E-n101-k8 Cost: 1042 Optimal Cost: 815 \t Gap: 27.85%\n", + "Problem: E-n101-k14 Cost: 1302 Optimal Cost: 1067 \t Gap: 22.02%\n", + "Problem: F-n72-k4 Cost: 286 Optimal Cost: 237 \t Gap: 20.68%\n", + "Problem: F-n135-k7 Cost: 1570 Optimal Cost: 1162 \t Gap: 35.11%\n", + "Problem: M-n101-k10 Cost: 1037 Optimal Cost: 820 \t Gap: 26.46%\n", + "Problem: M-n121-k7 Cost: 1283 Optimal Cost: 1034 \t Gap: 24.08%\n", + "Problem: M-n151-k12 Cost: 1407 Optimal Cost: 1015 \t Gap: 38.62%\n", + "Problem: M-n200-k16 Cost: 1811 Optimal Cost: 1274 \t Gap: 42.15%\n", + "Problem: M-n200-k17 Cost: 1812 Optimal Cost: 1275 \t Gap: 42.12%\n" + ] + } + ], + "source": [ + "# Import augmented utils\n", + "from rl4co.data.transforms import (\n", + " StateAugmentation as SymmetricStateAugmentation)\n", + "from rl4co.utils.ops import batchify, unbatchify\n", + "\n", + "num_augment = 100\n", + "augmentation = SymmetricStateAugmentation(num_augment=num_augment)\n", + "\n", + "for instance in instances:\n", + " problem = vrplib.read_instance(os.path.join(path_to_save, instance+'.vrp'))\n", + "\n", + " coords = torch.tensor(problem['node_coord']).float()\n", + " coords_norm = normalize_coord(coords)\n", + " demand = torch.tensor(problem['demand'][1:]).float()\n", + " capacity = problem['capacity']\n", + " n = coords.shape[0]\n", + "\n", + " # Prepare the tensordict\n", + " batch_size = 2\n", + " td = env.reset(batch_size=(batch_size,)).to(device)\n", + " td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2)\n", + " td['demand'] = repeat(demand, 'n -> b n', b=batch_size) / capacity\n", + " td['visited'] = torch.zeros((batch_size, 1, n), dtype=torch.uint8)\n", + " action_mask = torch.ones(batch_size, n, dtype=torch.bool)\n", + " action_mask[:, 0] = False\n", + " td['action_mask'] = action_mask\n", + " \n", + " # Augmentation\n", + " td = augmentation(td)\n", + "\n", + " # Get the solution from the policy\n", + " with torch.no_grad():\n", + " out = policy(\n", + " td.clone(), decode_type='greedy', num_starts=0, return_actions=True\n", + " )\n", + "\n", + " # Calculate the cost on the original scale\n", + " coords_repeat = repeat(coords, 'n d -> b n d', b=batch_size, d=2)\n", + " td['locs'] = batchify(coords_repeat, num_augment)\n", + " reward = env.get_reward(td, out['actions'])\n", + " reward = unbatchify(reward, num_augment)\n", + " cost = ceil(-1 * torch.max(reward).item())\n", + "\n", + " # Load the optimal cost\n", + " solution = vrplib.read_solution(os.path.join(path_to_save, instance+'.sol'))\n", + " optimal_cost = solution['cost']\n", + "\n", + " # Calculate the gap and print\n", + " gap = (cost - optimal_cost) / optimal_cost\n", + " print(f'Problem: {instance:<15} Cost: {cost:<10} Optimal Cost: {optimal_cost:<10}\\t Gap: {gap:.2%}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test the Sampling" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Problem: A-n53-k7 Cost: 1191 Optimal Cost: 1010 \t Gap: 17.92%\n", + "Problem: A-n54-k7 Cost: 1328 Optimal Cost: 1167 \t Gap: 13.80%\n", + "Problem: A-n55-k9 Cost: 1286 Optimal Cost: 1073 \t Gap: 19.85%\n", + "Problem: A-n60-k9 Cost: 1631 Optimal Cost: 1354 \t Gap: 20.46%\n", + "Problem: A-n61-k9 Cost: 1230 Optimal Cost: 1034 \t Gap: 18.96%\n", + "Problem: A-n62-k8 Cost: 1505 Optimal Cost: 1288 \t Gap: 16.85%\n", + "Problem: A-n63-k9 Cost: 1840 Optimal Cost: 1616 \t Gap: 13.86%\n", + "Problem: A-n63-k10 Cost: 1590 Optimal Cost: 1314 \t Gap: 21.00%\n", + "Problem: A-n64-k9 Cost: 1643 Optimal Cost: 1401 \t Gap: 17.27%\n", + "Problem: A-n65-k9 Cost: 1381 Optimal Cost: 1174 \t Gap: 17.63%\n", + "Problem: A-n69-k9 Cost: 1451 Optimal Cost: 1159 \t Gap: 25.19%\n", + "Problem: A-n80-k10 Cost: 2170 Optimal Cost: 1763 \t Gap: 23.09%\n", + "Problem: B-n51-k7 Cost: 1187 Optimal Cost: 1032 \t Gap: 15.02%\n", + "Problem: B-n52-k7 Cost: 884 Optimal Cost: 747 \t Gap: 18.34%\n", + "Problem: B-n56-k7 Cost: 853 Optimal Cost: 707 \t Gap: 20.65%\n", + "Problem: B-n57-k7 Cost: 1314 Optimal Cost: 1153 \t Gap: 13.96%\n", + "Problem: B-n57-k9 Cost: 1744 Optimal Cost: 1598 \t Gap: 9.14%\n", + "Problem: B-n63-k10 Cost: 1698 Optimal Cost: 1496 \t Gap: 13.50%\n", + "Problem: B-n64-k9 Cost: 1045 Optimal Cost: 861 \t Gap: 21.37%\n", + "Problem: B-n66-k9 Cost: 1506 Optimal Cost: 1316 \t Gap: 14.44%\n", + "Problem: B-n67-k10 Cost: 1254 Optimal Cost: 1032 \t Gap: 21.51%\n", + "Problem: B-n68-k9 Cost: 1510 Optimal Cost: 1272 \t Gap: 18.71%\n", + "Problem: B-n78-k10 Cost: 1514 Optimal Cost: 1221 \t Gap: 24.00%\n", + "Problem: E-n51-k5 Cost: 613 Optimal Cost: 521 \t Gap: 17.66%\n", + "Problem: E-n76-k7 Cost: 882 Optimal Cost: 682 \t Gap: 29.33%\n", + "Problem: E-n76-k8 Cost: 952 Optimal Cost: 735 \t Gap: 29.52%\n", + "Problem: E-n76-k10 Cost: 1015 Optimal Cost: 830 \t Gap: 22.29%\n", + "Problem: E-n76-k14 Cost: 1185 Optimal Cost: 1021 \t Gap: 16.06%\n", + "Problem: E-n101-k8 Cost: 1189 Optimal Cost: 815 \t Gap: 45.89%\n", + "Problem: E-n101-k14 Cost: 1420 Optimal Cost: 1067 \t Gap: 33.08%\n", + "Problem: F-n72-k4 Cost: 344 Optimal Cost: 237 \t Gap: 45.15%\n", + "Problem: F-n135-k7 Cost: 3130 Optimal Cost: 1162 \t Gap: 169.36%\n", + "Problem: M-n101-k10 Cost: 1221 Optimal Cost: 820 \t Gap: 48.90%\n", + "Problem: M-n121-k7 Cost: 1538 Optimal Cost: 1034 \t Gap: 48.74%\n", + "Problem: M-n151-k12 Cost: 1688 Optimal Cost: 1015 \t Gap: 66.31%\n", + "Problem: M-n200-k16 Cost: 2252 Optimal Cost: 1274 \t Gap: 76.77%\n", + "Problem: M-n200-k17 Cost: 2260 Optimal Cost: 1275 \t Gap: 77.25%\n" + ] + } + ], + "source": [ + "# Parameters for sampling\n", + "num_samples = 100\n", + "softmax_temp = 0.05\n", + "\n", + "for instance in instances:\n", + " problem = vrplib.read_instance(os.path.join(path_to_save, instance+'.vrp'))\n", + "\n", + " coords = torch.tensor(problem['node_coord']).float()\n", + " coords_norm = normalize_coord(coords)\n", + " demand = torch.tensor(problem['demand'][1:]).float()\n", + " capacity = problem['capacity']\n", + " n = coords.shape[0]\n", + "\n", + " # Prepare the tensordict\n", + " batch_size = 2\n", + " td = env.reset(batch_size=(batch_size,)).to(device)\n", + " td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2)\n", + " td['demand'] = repeat(demand, 'n -> b n', b=batch_size) / capacity\n", + " td['visited'] = torch.zeros((batch_size, 1, n), dtype=torch.uint8)\n", + " action_mask = torch.ones(batch_size, n, dtype=torch.bool)\n", + " action_mask[:, 0] = False\n", + " td['action_mask'] = action_mask\n", + " \n", + " # Sampling\n", + " td = batchify(td, num_samples)\n", + "\n", + " # Get the solution from the policy\n", + " with torch.no_grad():\n", + " out = policy(\n", + " td.clone(), decode_type='sampling', num_starts=0, return_actions=True\n", + " )\n", + "\n", + " # Calculate the cost on the original scale\n", + " coords_repeat = repeat(coords, 'n d -> b n d', b=batch_size, d=2)\n", + " td['locs'] = batchify(coords_repeat, num_samples)\n", + " reward = env.get_reward(td, out['actions'])\n", + " reward = unbatchify(reward, num_samples)\n", + " cost = ceil(-1 * torch.max(reward).item())\n", + "\n", + " # Load the optimal cost\n", + " solution = vrplib.read_solution(os.path.join(path_to_save, instance+'.sol'))\n", + " optimal_cost = solution['cost']\n", + "\n", + " # Calculate the gap and print\n", + " gap = (cost - optimal_cost) / optimal_cost\n", + " print(f'Problem: {instance:<15} Cost: {cost:<10} Optimal Cost: {optimal_cost:<10}\\t Gap: {gap:.2%}')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "rl4co-user", + "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.10.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/datasets/2-test-on-cvrplib/index.html b/examples/datasets/2-test-on-cvrplib/index.html new file mode 100644 index 00000000..33eaa864 --- /dev/null +++ b/examples/datasets/2-test-on-cvrplib/index.html @@ -0,0 +1,3949 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Test Model on VRPLib - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/datasets/README.md b/examples/datasets/README.md new file mode 100644 index 00000000..599971e8 --- /dev/null +++ b/examples/datasets/README.md @@ -0,0 +1,9 @@ +# Datasets + +Collection of examples for training and testing with custom datasets. + + +## Index + +- [`1-test-on-tsplib.ipynb`](1-test-on-tsplib.ipynb): here we show how to test a model on the TSPLIB dataset. +- [`2-test-on-cvrplib.ipynb`](2-test-on-cvrplib.ipynb): here we show how to test a model on the CVRPLIB dataset. \ No newline at end of file diff --git a/examples/datasets/index.html b/examples/datasets/index.html new file mode 100644 index 00000000..9622ed43 --- /dev/null +++ b/examples/datasets/index.html @@ -0,0 +1,2385 @@ + + + + + + + + + + + + + + + + + + + + + + + Datasets - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ + + + + + + + + +

Datasets

+

Collection of examples for training and testing with custom datasets.

+

Index

+ + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/index.html b/examples/index.html new file mode 100644 index 00000000..d938b351 --- /dev/null +++ b/examples/index.html @@ -0,0 +1,2449 @@ + + + + + + + + + + + + + + + + + + + + + + + 🧩 Examples and Tutorials - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ + + + + + + + + +

🧩 Examples and Tutorials

+

This is a collection of examples and tutorials for using the RL4CO library.

+

The root directory is made of quickstarts and contains the following:

+

⚡️ Quickstarts

+

This is the root directory of the examples. The following quickstarts are available:

+
    +
  • 1-quickstart.ipynb: here we train a model on a simple environment - it takes less than 2 minutes!
  • +
  • 2-full-training.ipynb: similar to the previous notebooks but with a more interesting environment, with checkpointing, logging, and callbacks.

    - 2b-train-simple.py: here we show a simple script that can be called with python 2b-train-simple.py. This is simplified and does not use Hydra - for those who prefer a simpler setup. Note that we also made a Hydra tutorial here. +- 3-creating-new-env-model.ipynb: here we show how to extend RL4CO to solve new problems and create new models from zero to hero!

    +
  • +
+

📁 Folders Index

+

Modeling

+

Under the modeling/ directory, here are some additional examples for modeling and inference.

+

Datasets

+

Under the datasets/ directory, here are some additional examples for using your custom data to train/evaluate your models

+

Advanced

+

Under the advanced/ directory, here are some additional examples for advanced topics.

+

Other

+

Under the other/ directory, here are some additional examples for other topics.

+ + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/modeling/1-decoding-strategies/1-decoding-strategies.ipynb b/examples/modeling/1-decoding-strategies/1-decoding-strategies.ipynb new file mode 100644 index 00000000..774195e8 --- /dev/null +++ b/examples/modeling/1-decoding-strategies/1-decoding-strategies.ipynb @@ -0,0 +1,679 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5f35f43a-a799-4e5b-8c6b-51e08932b61b", + "metadata": {}, + "source": [ + "# RL4CO Decoding Strategies Notebook\n", + "\n", + "This notebook demonstrates how to utilize the different decoding strategies available in [rl4co/utils/decoding.py](../../rl4co/utils/decoding.py) during the different phases of model development. We will also demonstrate how to evaluate the model for different decoding strategies on the test dataset. \n", + "\n", + "\"Open\n" + ] + }, + { + "cell_type": "markdown", + "id": "866f4981-7358-4086-9044-6df6a4ba8fea", + "metadata": {}, + "source": [ + "### Installation" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "7538da3e-67df-4c72-9acb-345a3bc9fba1", + "metadata": {}, + "outputs": [], + "source": [ + "## Uncomment the following line to install the package from PyPI\n", + "## You may need to restart the runtime in Colab after this\n", + "## Remember to choose a GPU runtime for faster training!\n", + "\n", + "# !pip install rl4co" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "4380f62f-bde8-4fc5-aa1a-072d5be58a32", + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "\n", + "from rl4co.envs import TSPEnv\n", + "from rl4co.models.zoo import AttentionModel, AttentionModelPolicy\n", + "from rl4co.utils.trainer import RL4COTrainer\n", + "from rl4co.utils.ops import batchify" + ] + }, + { + "cell_type": "markdown", + "id": "566e2f04-0576-4789-ac25-706ef3ebb7ca", + "metadata": {}, + "source": [ + "### Setup Policy and Environment" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "40c9a2ac-a2cc-4a90-a810-75a092fa4890", + "metadata": {}, + "outputs": [], + "source": [ + "%%capture\n", + "# RL4CO env based on TorchRL\n", + "env = TSPEnv(generator_params=dict(num_loc=50)) \n", + "\n", + "# Policy: neural network, in this case with encoder-decoder architecture\n", + "policy = AttentionModelPolicy(env_name=env.name, \n", + " embed_dim=128,\n", + " num_encoder_layers=3,\n", + " num_heads=8,\n", + " )\n", + "\n", + "# Model: default is AM with REINFORCE and greedy rollout baseline\n", + "model = AttentionModel(env, \n", + " baseline=\"rollout\",\n", + " batch_size = 512,\n", + " val_batch_size = 64, \n", + " test_batch_size = 64, \n", + " train_data_size=100_000, # fast training for demo\n", + " val_data_size=1_000,\n", + " test_data_size=1_000,\n", + " optimizer_kwargs={\"lr\": 1e-4},\n", + " policy_kwargs={ # we can specify the decode types using the policy_kwargs\n", + " \"train_decode_type\": \"sampling\",\n", + " \"val_decode_type\": \"greedy\",\n", + " \"test_decode_type\": \"beam_search\",\n", + " }\n", + " ) " + ] + }, + { + "cell_type": "markdown", + "id": "fdfa0c33-0f09-4316-84f9-25f6e8f8dfc0", + "metadata": {}, + "source": [ + "### Setup Trainer and train model" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "38e7840f-c3b7-4f47-b694-f00db7f25896", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Using 16bit Automatic Mixed Precision (AMP)\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "IPU available: False, using: 0 IPUs\n", + "HPU available: False, using: 0 HPUs\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/logger_connector/logger_connector.py:75: Starting from v1.9.0, `tensorboardX` has been removed as a dependency of the `lightning.pytorch` package, due to potential conflicts with other packages in the ML ecosystem. For this reason, `logger=True` will use `CSVLogger` as the default logger, unless the `tensorboard` or `tensorboardX` packages are found. Please `pip install lightning[extra]` or one of them to enable TensorBoard support by default\n", + "val_file not set. Generating dataset instead\n", + "test_file not set. Generating dataset instead\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "\n", + " | Name | Type | Params\n", + "--------------------------------------------------\n", + "0 | env | TSPEnv | 0 \n", + "1 | policy | AttentionModelPolicy | 710 K \n", + "2 | baseline | WarmupBaseline | 710 K \n", + "--------------------------------------------------\n", + "1.4 M Trainable params\n", + "0 Non-trainable params\n", + "1.4 M Total params\n", + "5.681 Total estimated model params size (MB)\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "4c79576d702f4301861fafabaae2d86c", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Sanity Checking: | | 0/? [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGzCAYAAAD9pBdvAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAADKRklEQVR4nOyddVwUzxvHP3dHd0hjAIrdimCLhYHd3V+7FRu7u7u7E0WxA8VAxVbEIqSUzrvn9wc/Vtc74FDgDpj367Uv2JnZnWd3b3c/O/PMMwIiIjAYDAaDwWAoCKGiDWAwGAwGg1G4YWKEwWAwGAyGQmFihMFgMBgMhkJhYoTBYDAYDIZCYWKEwWAwGAyGQmFihMFgMBgMhkJhYoTBYDAYDIZCYWKEwWAwGAyGQmFihMFgMBgMhkJhYoTByGUEAgFmz56taDMYDAZDaWFihKEwdu/eDYFAwC0qKiqwsrJCv379EBgYqGjzlJqGDRvyzt3vi6qqqlz7eP36NVxcXKCjowMjIyP07t0bYWFhvDKzZ8/OsB6BQIC7d+9yZfv16yezTJkyZTK148CBAxAIBNDR0ZGZf/ToUTg6OsLAwADGxsZo0KABLly48Nd2AoBEIsGmTZtQpUoVaGpqwtjYGM7Oznj27Bmv3IIFC9CmTRuYmZllKipPnTqF5s2bw9LSEurq6rC2tkanTp3w4sULmeVjYmIwefJk2NjYQF1dHVZWVujUqRPi4+O5MvJe4xs3bmR67AsWLODVfeXKFdStWxdaWlowNDREp06d8OnTJ16Z7O7z8ePHaN26NczNzaGjo4NKlSph7dq1EIvFvHIlSpSQub+hQ4fKPE+MwoOKog1gMObOnQsbGxskJibi/v372L17N+7cuYMXL15AQ0ND0eYpJdOnT8egQYN4aXFxcRg6dCiaNWuW5fbfvn1D/fr1oa+vj4ULFyI2NhbLly+Hn58ffHx8oKamBgDo0KEDSpYsKbX9tGnTEBsbi5o1a/LS1dXVsX37dl6avr5+hnbExsZi8uTJ0NbWlpm/bt06jB49Gq1atcLixYuRmJiI3bt3o3Xr1jhx4gQ6dOjwV3YOGDAABw4cQJ8+fTBy5EjExcXB19cXoaGhvHIzZsyAubk5qlatCk9PzwyPw8/PD4aGhhgzZgyKFCmCkJAQ7Ny5Ew4ODvD29kblypW5slFRUWjQoAG+ffuGIUOGoGTJkggLC8Pt27eRlJQELS0tAPJf47Jly2Lfvn1SNu3btw+XL1/mlT1//jzatm2LatWqYfHixYiOjsaaNWtQt25d+Pr6wsTEJNv7fPz4MWrXro1SpUrBzc0NWlpauHjxIsaMGQN/f3+sWbOGt48qVapgwoQJvDR7e/sMzy2jkEAMhoLYtWsXAaCHDx/y0t3c3AgAHTlyREGWZY/Y2NhM8wGQu7t7rtuxb98+AkAHDhzIsuywYcNIU1OTPn/+zKVduXKFANCWLVsy3fbLly8kEAho8ODBvPS+ffuStrZ2tmx2c3Oj0qVLU8+ePWVuW6pUKapZsyZJJBIuLSoqinR0dKhNmzZ/ZeeRI0cIAJ08eTJL+wICAoiIKCwsLNvXMSQkhFRUVOi///7jpQ8bNowMDAzo48ePcu8rnexc45IlS1KpUqV4aeXKlaOSJUtSUlISl/b06VMSCoU0fvz4v9rn4MGDSU1NjSIiInjp9evXJz09PV5a8eLFqVWrVlnWwyh8sG4ahtJRr149AIC/vz8v/c2bN+jUqROMjIygoaGBGjVq4OzZs1z+z58/IRKJsHbtWi4tPDwcQqEQxsbGoN8mqB42bBjMzc259du3b6Nz584oVqwY1NXVUbRoUYwbNw4JCQk8G/r16wcdHR34+/ujZcuW0NXVRc+ePQEASUlJGDduHExMTKCrq4s2bdrg27dvMo/xzZs3+PLly1+eIdkcPHgQ2traaNu2bZZlT5w4gdatW6NYsWJcWpMmTWBvb4+jR49muu2hQ4dARNxx/4lYLEZ0dHSWNrx//x6rVq3CypUroaIiu5E2OjoapqamEAgEXJqenh50dHSgqan5V3auXLkSDg4OaN++PSQSCeLi4jLcR4kSJbI8jowwNTWFlpYWfv78yaX9/PkTu3btwpAhQ2BjY4Pk5GQkJSXJvU95r7GPjw8+fPjAO/bIyEi8evUK7du351q+AKBy5cooW7YsDh8+nO19AmnXSENDAwYGBrx0CwuLDK9RcnJypuedUfhgYoShdKT3XxsaGnJpL1++hKOjI16/fo0pU6ZgxYoV0NbWRrt27XDq1CkAgIGBASpUqIBbt25x2925cwcCgYB7EKdz+/ZtTvQAwLFjxxAfH49hw4Zh3bp1aN68OdatW4c+ffpI2ZeamormzZvD1NQUy5cvR8eOHQEAgwYNwurVq9GsWTMsXrwYqqqqaNWqlcxjLFu2rMx9/y1hYWG4cuUK2rVrl2GXRzqBgYEIDQ1FjRo1pPIcHBzg6+ub6fYHDhxA0aJFUb9+fam8+Ph46OnpQV9fH0ZGRhgxYgRiY2Nl7mfs2LFo1KgRWrZsmWFdDRs2xKVLl7Bu3Tp8+vQJb968wYgRIxAVFYUxY8Zk287o6Gj4+PigZs2amDZtGvT19aGjowNbW9ssRZg8/Pz5E2FhYfDz88OgQYMQHR2Nxo0bc/l37txBYmIiSpYsiU6dOkFLSwuampqoU6cOnj59mum+s3ONDxw4AAA84ZAuemQJBC0tLQQFBSEkJCRb+wTSrlF0dDT+++8/vH79Gp8/f8bmzZtx8uRJTJ06VWo/165dg5aWFnR0dFCiRAmpbhxGIUXBLTOMQkx6N42XlxeFhYXR169f6fjx42RiYkLq6ur09etXrmzjxo2pYsWKlJiYyKVJJBKqXbs2r9l4xIgRZGZmxq2PHz+e6tevT6amprRp0yYiIoqIiCCBQEBr1qzhysXHx0vZt2jRIhIIBLyujL59+xIAmjJlCq/s06dPCQANHz6cl96jRw+ZzfsAqEGDBnKcJflYt24dASAPD48syz58+JAA0N69e6XyJk2aRAB45/l3Xrx4QQBo8uTJUnlTpkwhNzc3OnLkCB06dIg7V3Xq1KGUlBRe2fPnz5OKigq9fPmSiDLu4vn+/Ts1btyYAHBLkSJF6N69e5keY0Z2PnnyhACQsbExmZmZ0caNG+nAgQPk4OBAAoGALl68KHN/8nbTlC5dmrNTR0eHZsyYQWKxmMtfuXIlV7+DgwMdOHCANm7cSGZmZmRoaEhBQUEZ7lvea5yamkpmZmbk4ODASxeLxWRgYECNGzfmpYeHh5O2tjYBoEePHmVrn+l5I0eOJFVVVe7YRSIRd7/9jqurKy1ZsoROnz5NO3bsoHr16mX4e2IULpgYYSiMdDHy51KiRAny9PTkyqWLh3nz5lFYWBhvmTNnDgGgb9++ERHR4cOHCQC9efOGiIhq1qxJM2bMoI4dO1KPHj2IiOjMmTMEgJ48eSLTrtjYWAoLC6ObN28SADp9+jSXl/6C/V2gEBEtXLiQV286Pj4+eeIz4uTkRCYmJlIvfVncunUrQ5+cmTNnEgD68eOHzG2nTp1KAOjZs2dy2bVgwQICQIcOHeLSkpKSqFSpUjRy5EguLSMxEhMTQ8OHD6e+ffvSsWPHaOfOnVSxYkUyNzen9+/fZ1hvRnamHzsAun//Pq+eIkWKUJ06dWTuT14xcu/ePbp06RJt3LiRatasSRMmTKDk5GQuf+7cuZygiomJ4dK9vb0JAE2fPj3Dfct7jT09PQkAT2ynk+6PNWXKFHr37h09evSInJ2dOSFx+/btbO+TiGjVqlXUunVr2rNnDx05coTatWtHKioqdOrUqUxtlUgk1Lx5c1JRUeF9fDAKH0yMMBRGuhjZsGEDXblyhY4fP04tW7YkHR0dunHjBlfuwYMHMkXL70u6sAgMDCQAtG3bNoqNjSUVFRXy9PSkNWvWUNGiRYmIaOLEiaSnp8f7Yv38+TP17duXDA0Npfa9Z88erlzfvn1JRUWFty0R0X///UdCoVDqRREVFfXXYiQpKYmCg4N5S2pqqlQ5f39/AsB7uWfG37aMSCQSKl68OFWoUEHuY4iPjyehUEgDBw7k0hYvXkyGhoY8h8eMxIiLiwu1bt2alxYREUFGRkbUpUsXmXVmZmf6sdvY2Ejl9e/fn1RVVWW+7P/GgTUyMpLMzMxowoQJXNqyZcsIAPXv31+qvI2NDTVq1EjmvrJzjfv06UMikYhCQkKk8pKSkmjgwIEkFAq533ezZs1o6NChBIB8fX2zvc9FixaRubk5T1wRETVs2JAsLS2zFE+XLl0iALRv374sj41RcGFDexkKx8HBgfNfaNeuHerWrYsePXrg7du30NHRgUQiAQBMnDgRzZs3l7mP9GGdlpaWsLGxwa1bt1CiRAkQEZycnGBiYoIxY8bg8+fPuH37NmrXrg2hMM1lSiwWo2nTpoiMjISbmxvKlCkDbW1tBAYGol+/flz96airq3Pb5ib37t1Do0aNeGkBAQFSTpUHDx4EIN2XnxEWFhYAgODgYKm84OBgGBkZQV1dXSrv7t27+Pz5MxYtWiRXPQC4GB6RkZEA0oa1zp8/H8OHD0d0dDTn6BobGwsiwqdPn6ClpQVTU1N8/PgRly5dwtatW3n7NDIyQt26daVih8hjp6WlJQDAzMxMKs/U1BQpKSmIi4vLdDiyvBgaGsLZ2RkHDhzA8uXL5ar/x48fMvcl7zVOSEjAqVOn0KRJE5l1qKmpYfv27ViwYAHevXsHMzMz2Nvbo0ePHhAKhTKHR2e1z40bN8LZ2VkqTkybNm0wfvx4fPr0SeZ+0ylatCgAcL8RRuGEiRGGUiESibBo0SI0atQI69evx5QpU2BrawsAUFVVRZMmTbLcR7169XDr1i3Y2NigSpUq0NXVReXKlaGvr49Lly7hyZMnmDNnDlfez88P7969w549e3hOpVeuXJHb7uLFi0MikcDf3x+lS5fm0t++fSv3Pv6kcuXKUjb8PgIonYMHD8LOzg6Ojo5y7dfKygomJiZ49OiRVJ6Pjw+qVKkic7v04GQ9evSQqx4gLbhXeHg4F7/ix48fiI2NxdKlS7F06VKp8jY2Nmjbti1Onz6N79+/A4BU4CwASElJQWpqarbttLS0hLm5ucygekFBQdDQ0ICurq7cx5cVCQkJiIqK4tarV68OABnWn1GAOHmv8dmzZxETE5OlaDEzM+OEhVgsxo0bN1CrVi2Zgeey2uf3798zvEYAMrxO6Xz8+BEAuN8Io5Ci6KYZRuElozgjREQODg5kZmZGCQkJRJTW5GtkZCTTwS80NJS3vm3bNgJApUuXprFjx3LpLVq0IHt7e6m+8efPnxMA2r17N5cmkUioVatWBIB27drFpWfUneDr65stB9bXr19L+Z38DekOmTNnzsywzIcPH+jDhw+8tKFDh5KmpiZ9+fKFS/Py8iIAMh0Pk5OTydjYmOrVqyezjoSEBIqOjpZKT+/2SY/pERcXR6dOnZJaGjVqRBoaGnTq1CnOlyM0NJSEQiE1bNiQF2fk69evpKOjQy4uLtm2k4hozJgxBIAuX77MpYWFhZGenh61bNlS5jZZddN8//5dKi0gIIB0dXWlbKlcuTLp6elRWFgYl5buk7F06VKp/chzjdNp06YNaWlpSXWZZMbixYsJAB0/fvyv9lmhQgUyMjKi8PBwLi01NZWqV69Ourq6nM9MRESEVDdjcnIy1alTh9TU1Cg4OFhumxkFDyZGGAojMzFy7Ngx3ovx5cuXZGhoSMbGxjRlyhTaunUrzZs3j1q2bEmVKlXibfvmzRuuP/zEiRNc+qJFiwgAqaur83wikpOTyc7OjooUKUILFiygdevWUcOGDaly5cpyixEiou7duxMA6tmzJ23YsIE6dOhAlSpVytXRNBMmTJDpOPs7xYsXp+LFi/PSvnz5QsbGxmRnZ0dr166lhQsXkqGhodSIpXTOnTtHAGjz5s0y6wgICCADAwMaNmwYrVmzhtasWUMtW7YkAOTi4iLlY/MnGZ3XQYMGEQBq1KgRrVu3jhYuXEjW1tYkEono5s2b2baTKC0YmYWFBenq6pK7uzutXLmS7O3tSVNTk54+fcoru3fvXpo3bx7nENuoUSOaN28ezZs3jz59+sSVMzU1pe7du9OSJUto69atNGnSJDIyMiINDQ26e/cub5/Xrl0jkUhEpUuXppUrV5K7uzvp6uqSvb29zBe+PNeYKO1lr6qqSt26dcuwzL59+6hdu3a0cuVK2rp1K3Xp0oUA0KBBg/56n/v37ycAZGdnR0uWLKG1a9eSk5MTAaD58+dz5Xbt2kV2dnbk5uZGmzdvpoULF1KFChUIAC1cuDDTY2MUfJgYYSiMzMSIWCwmOzs7srOz476m/P39qU+fPmRubk6qqqpkZWVFrVu3lvlFZ2pqSgB4X6x37twhADK/ml+9ekVNmjQhHR0dKlKkCA0ePJiePXuWLTGSkJBAo0ePJmNjY9LW1iZXV1f6+vVrrokRsVhMVlZWVK1atUzLyRIjRGnDX5s1a0ZaWlpkYGBAPXv2lOmgSETUrVs3UlVVlYqymc6PHz+oV69eVLJkSdLS0iJ1dXUqX748LVy4kDeaJCMyOq8pKSm0bt06qlKlCuno6JCOjg41atSIrl279ld2puPv70/t27cnPT090tTUJGdnZ/Lx8ZEq16BBgwydpq9fv86Vc3d3pxo1apChoSGpqKiQpaUldevWjZ4/fy6z/itXrpCjoyNpaGiQkZER9e7dW2bLgLzXmIho8+bNBIDOnj2bYZkHDx5Q/fr1ydDQkDQ0NKhy5cq0efNmXstTdvdJlOaE2qBBAypSpAipqalRxYoVpQTho0ePyNXVlaysrEhNTY10dHSobt26dPTo0SyPjVHwERD9FpaSwWAwGAwGI49hEVgZDAaDwWAoFCZGGAwGg8FgKBQmRhgMBoPBYCgUJkYYDAaDwWAoFCZGGAwGg8FgKBQmRhgMBoPBYCiUfBEOXiKRICgoCLq6uhAIBIo2h8FgMBgMhhwQEWJiYmBpaZnpnF75QowEBQVxkykxGAwGg8HIX3z9+hXW1tYZ5ucLMZI+cdXXr1+hp6enYGsYDAaDwWDIQ3R0NIoWLZrlBJT5Qoykd83o6ekxMcJgMBgMRj4jKxcL5sDKYDAYDAZDoTAxwmAwGAwGQ6EwMcJgMBgMBkOhMDHCYDAYDAZDoTAxwmAwGAwGQ6EwMcJgMBgMBkOhMDHCYDAYDAZDoTAxwmAwGAwGQ6EwMcJgMBgMBkOhMDHCYDAYDAZDoWRbjNy6dQuurq6wtLSEQCDA6dOns9zmxo0bqFatGtTV1VGyZEns3r37L0xlMBgMxu+IJQRv/wiceRoIb/8IiCWkaJMYjL8i23PTxMXFoXLlyhgwYAA6dOiQZfmAgAC0atUKQ4cOxYEDB3D16lUMGjQIFhYWaN68+V8ZzWAwGIWdSy+CMefcKwRHJXJpFvoacHctB5cKFgq0jMHIPgIi+mspLRAIcOrUKbRr1y7DMm5ubrhw4QJevHjBpXXr1g0/f/7EpUuXZG6TlJSEpKQkbj191r+oqCg2UR6DwSj0XHoRjGH7n+DPh3f6VGSbelVjgoShFERHR0NfXz/L93eu+4x4e3ujSZMmvLTmzZvD29s7w20WLVoEfX19bilatGhum8lgMBj5ArGEMOfcK54QIYkYcW/ucGlzzr1iXTaMfEWui5GQkBCYmZnx0szMzBAdHY2EhASZ20ydOhVRUVHc8vXr19w2k8FgMPIFPgGRXNcMESEpLABhpxYi/MxiRD04CQIQHJUIn4BIxRrKYGSDbPuM5AXq6upQV1dXtBkMBoOhdARGRCEh4AkS/B8i/v0DCIQipP4MBgD8vLETIm196FRojNCYxCz2xGAoD7kuRszNzfH9+3de2vfv36GnpwdNTc3crp7BYDDyPSEhIfDw8MD58+dxyfMyEuLjAAA61V2RGv6FEyMAEOGxBiJNPZjqOirKXAYj2+S6GHFycoKHhwcv7cqVK3BycsrtqhkMBiNfIpFI4Ovri/Pnz+PChQt4+PChVBlNu5owch4ESknC90NTkfzdPy2DJAg/swSScc0BO/acZeQPsi1GYmNj8eHDB249ICAAT58+hZGREYoVK4apU6ciMDAQe/fuBQAMHToU69evx+TJkzFgwABcu3YNR48exYULF3LuKBgMBiOfExsbCy8vL1y4cAEXLlxAcHBwhmVt7MtB3HIShEIRSF0Lpp1nI2T/ZK6FRJKSiDaurXHnzh2ULVs2rw6Bwfhrsj2098aNG2jUqJFUet++fbF7927069cPnz59wo0bN3jbjBs3Dq9evYK1tTVmzpyJfv36yV2nvEODGAwGIz8REBCACxcu4Pz587h+/TqSk5Oz3MbMzAw+Pj54Fa3KizOS8iMYYQcnIyX2B1e2aNGiuHfvHqytrXPtGBiMzJD3/f1PcUbyCiZGGAxGQePTp0/o0aNHpmEO/kRdXR03b95ErVq1AKQN8/UJiERoTCJMdTWg+vMznBs1RExMDLdN+fLlcfv2bRgaGub0ITAYWaI0cUYYDAaDIU2JEiVw584d7N27FxYW8gUo27NnDydEAEAkFMDJzhhtq1jByc4YNapXw+nTp6GmpsaVefnyJVxdXTMMpcBgKANMjDAYDIaCEAqF6NWrF2bNmpVl2dmzZ6Nr165ZlnN2dsb+/fshEAi4tLt376Jbt25ITU39J3sZjNyCiREGg8FQEN++fUPr1q0xbNiwTMt1795dLsGSTufOnbF+/Xpe2tmzZzFs2DDkg555RiGEiREGg8HIY4gIW7duRfny5aVCH/yJo6Mjdu7cyWvpkIfhw4dj5syZvLTt27dnS9QwGHkFEyMMBoORh3z8+BGNGzfGf//9h+joaF6ek5MTjI2NufVixYrh9OnT0NDQ+Ku65syZg8GDB/PS5s+fL9VqwmAoGiZGGAwGIw8Qi8VYs2YNKlasiOvXr/PytLS0sHr1aty+fRulS5cGAOjo6ODcuXNSc3tlB4FAgI0bN0rNrD569GgcPXr0r/fLYOQ0TIwwGAxGLvP69WvUq1cPY8eORXx8PC/P2dkZfn5+GDNmDEQiEYoWLQqhUIjDhw+jUqVK/1y3iooKDh48iHr16nFpRIRevXrh6tWrUuX/tI/ByAuYGGEwGIxcIiUlBYsWLUKVKlWk4ono6upi69at8PLygq2tLZderFgxLF++HK1atcoxOzQ1NXH27FlUrFiRZ1v79u3x5MkTLk0ikaBXr17MyZWR57CgZwwGg5ELPH36FAMGDICvr69UXqtWrbB582aZkVEDAgJQokSJbDusykNQUBBq166Nz58/c2mmpqa4d+8e7OzscO3aNTRu3Bjnz5/PUTHEKLywoGcMBoOhAJKSkjBz5kzUrFlTSogYGRlh//79OHfuXIYh2m1sbHJFiACApaUlPD09eU6yoaGhaNasGb5//47t27cDABYsWMBaRxh5CmsZYTAYjBziwYMHGDBgAF69eiWV16lTJ6xfv/6fHFJzCh8fHzRq1IjnH1KpUiW8ffsWSUlJANLmFGvQoIGiTGQUEFjLCIPBYOQR8fHxmDhxImrXri0lRMzMzHDixAkcO3ZMKYQIADg4OODEiRNQUfk1cfvz5885IQIACxcuVIRpjEIKEyMMBoPxD9y8eROVK1fGihUrIJFIeHl9+vTBq1ev0KFDBwVZlzEuLi7YtWtXhvmXL1/Go0eP8tAiRmGGiREGg8H4C2JiYjB8+HA0bNgQHz584OVZW1vDw8MDe/bsgZGRkYIslA0Rwc/PD8uXL8fu3bshFGb8GmCtI4y8QiXrIgwGg8H4HU9PTwwZMgRfvnyRyhs6dCiWLFmitP5t586dQ//+/REZGZll2VOnTuHVq1coV65cHljGKMywlhEGg8GQk8jISPTr1w8uLi5SQsTW1hbXr1/Hpk2blFaIAECbNm3w9u1bDBo0SK7yixcvzmWLGAwmRhgMBkMuTp06hfLly2PPnj28dIFAgHHjxuH58+do2LChYozLJkWKFMG2bdvg7e2NqlWrZlr24MGDCAgIyCPLGIUVJkYYDAYjE0JDQ9G1a1d06NABISEhvLyyZcvi7t27WLlyJbS1tRVk4d/j6OiIhw8fYv369dDX15dZRiwWY9myZXlsGaOwwcQIg8FgyICIcPDgQZQrV05qUjmRSITp06fD19cXTk5OCrIwZxCJRBgxYgTevXuHfv36ySyzc+dOBAcH561hjEIFEyMMBoPxB4GBgWjTpg169uyJiIgIXl6VKlXw8OFDzJ8/H+rq6gqyMOcxNTXFrl27cPv2bakJ+pKSkrBq1SqIJQRv/wiceRoIb/8IiCVKHzOTkU9gEVgZDAbj/xARduzYgQkTJiA6OpqXp6amhlmzZmHy5MlQVVVVkIV5Q2pqKjZs2ICZM2ciJiYGAKCppY3y4/chLEWNK2ehrwF313JwqWChKFMZSg6LwMpgMBjZICAgAM2aNcPgwYOlhIijoyN8fX0xffr0Ai9EAEBFRQVjxozB27dv0bNnTwBAQnwc3t84wSsXEpWIYfuf4NIL1oXD+DeYGGEwGIUaiUSCdevWoUKFCvDy8uLlaWpqYuXKlbhz506hjLVhYWGBPXv3oeyg5VA1LoaYR2chSU7g8tOb1eece8W6bBj/BBMjDAaj0PL27VvUr18fo0eP5k0aBwANGzbE8+fPMW7cOIhEIgVZqHh8AiIRb1wG5v3WQLdWJ8S9usnLJwDBUYnwCcg6iBqDkREsAiuDwSh0pKamYsWKFXB3d+dNDgcAurq6WLZsGQYPHpxpqPTCQmhMIgBAEheJ6HuHoGJgjsRPT6FVpi60y9SVKsdg/A1MjDAYjELF8+fPMWDAADx+/Fgqr0WLFtiyZQuKFi2qAMuUE1NdDQBASmQQKCURKWGfkBL2CaomxWWWYzD+Bib7GQxGoSA5ORmzZ89G9erVpYSIoaEh9uzZgwsXLjAh8gcONkaw0NdA6o9AXrqqoSUAQIC0UTUONso1ISAjf8FaRhgMRoHn4cOHGDBgAF68eCGV16FDB2zYsAHm5uY5Vp9YQvAJiERoTCJMddNe1CKhIMf2n5eIhAK4u5ZDlxNBvHQVIyukH5G7a7l8e3wM5YCJEQaDUWBJSEiAu7s7VqxYAYlEwsszNTXFhg0b0KlTpxyt89KLYMw59wrBUb98KPJ7PA6XChYooxWHh7+lqRpawjyfHxdDeWBihMFgFEhu376NgQMH4v3791J5vXr1wurVq2FsbJyjdV56EYxh+5/gz0Gu6fE4NvWqlm9f3D+CP3P/Gxib4MhI53zd4sNQLpjPCIPBKFDExMRg5MiRqF+/vpQQsbKywvnz57Fv374cFyJiCWHOuVeQkASxL68j/PwKpAe4zu/xOFJSUngz91YoWxpOdsZMiDByDNYywmAwCgxXrlzB4MGD8fnzZ6m8wYMHY9myZRnOTvuv+ARE4uNTb/y4sQspoR8BAJp2DtAuWw8APx6Hk13OCqHcJiAgAGKxmFsvVaqUAq1hFESYGGEwGPmenz9/YsKECdi5c6dUno2NDbZt24bGjRvnWv3Pnj3D8GFjEOrNDwj2884BaJWuDYHwV9C0/BiP488WJnt7ewVZwiiosG4aBoORrzlz5gzKlSsnJUQEAgHGjBkDPz+/XBMiX758Qd++fVG1alU8/UOIAIBQXRPiuJ+8tPwYj+NPMcJaRhg5DWsZYTAY+ZKwsDCMHj0ahw8flsorXbo0du7cidq1a+dK3T9//sSiRYuwZs0aqQiuACBQUYNxy3HQKlMXAkGaX4UAgHk+jcfx7t073jprGWHkNEyMMBiMfAUR4ciRIxg1ahTCw8N5eSKRCJMmTYK7uzs0NHK+BSIpKQkbN27E/PnzERmZwVwsAiHMe6+AmqnNr6T//82v8Tj+bBmxs7NTkCWMggoTIwyGElGQgmXlBkFBQRg2bBjOnj0rlVepUiXs3LkT1atXz/F6JRIJjhw5gmnTpuHTp0+Zlu0yYDi+2JXlxRnJ7/E4fhcj1tbW0NLSUqA1jIIIEyMMhpJQEINl5RREhF27dmH8+PGIiori5amqqmLmzJlwc3ODmppajtd9/fp1TJo0SeZcNn9StGhR7FyzGBqaWgVGVCYmJuLLly/cOuuiYeQGTIwwGEpAQQ6W9a98/vwZgwcPxpUrV6TyatasiZ07d6JChQo5Xu+LFy/g5uYGDw8PubdZtWoVtLW1ASDfDd/NCH9/fy5eCsCcVxm5AxtNw2Bkg4SEhBzdX1xcHO5538fwWcsQcWUzQg5OwY9b+7j8/B4s61+QSCTYsGEDypcvLyVENDQ0sGzZMty7dy/Hhci3b98wcOBAVK5cOVtCpFmzZujQoUOO2qIM/Om8ysQIIzdgLSMMhhzcvXsXs2bNwuLFi1GzZs1sby+RSBAQEIDnz5/zlj+/OtMhIm4URn4OlvW3vHv3DoMGDcLt27el8urXr4/t27fn+EsxKioKS5cuxapVq7ItOtXU1LB+/XrumhUkWIwRRl7AxAiDkQn379+Hu7s7Ll++DDMzM7mcI6OiouDn58cTHX5+foiNjZWrzpSwz4i8shkCkQq0SteGumUZCISifBksK7ukpqZi1apVmDVrFhIT+cero6ODJUuWYOjQoRAKc65RNzk5GVu2bMHcuXOlRucAgL6+PkqUKIFnz55luI9JkyYV2BYDFmOEkRcwMcJgyODRo0dwd3fnNdO3bNmS9xJMTU3Fhw8fpFo7ZIUilx8BhFr60K/VEd+PzkLMozMQaRtCs5QjPpcbhJTyrlBVVf2H/SsvL168wIABA/Dw4UOpvGbNmmHr1q0oXrx4jtVHRDh+/DimTp0Kf39/qXx1dXWMGTMG1atXR//+/TPcT7FixTBt2rQcs0vZ+L2bRigUwtbWVoHWMAoqApLVRqxkREdHQ19fH1FRUdDT01O0OYwCjK+vL2bPni1z6OjEiRNhZWXFiY6XL19Kfb1nB0NDQ1SuXBkVK1bEhUA1JOhYQaVIMQhV0+JjpER8RfDe8aDkX10GRkZGaNOmDTp27IgmTZrkSiyNvCY5ORmLFy/G/PnzkZKSwsszMDDAqlWr0Ldv3xztArl16xYmTZoEHx8fqTyBQIDevXtj3rx5uHnzJgYMGIDU1NQM93Xq1Cm0a9cux2xTNiwtLREcHAwAsLW1lSncGIyMkPf9zcQIo8AjT+wOPz8/zJ49GydPnszx+lVUVFCmTBlUqlSJt1haWnIv2PTRNAB4I2oS3j9A6Ml5Mverq6uLVq1aoUOHDmjRogV0dHRy3PacJjlVgn3en/A5Mh7FjbRQXi0CQwYPhJ+fn1TZtm3bYtOmTbCwyLlRRK9fv8aUKVNkik0grQVmyZIlqFKlCpYvX45Jkybx8s3MzGBtbc0N823ZsiXOnz9fIH1FACA2Nha6urrcevPmzXHp0iUFWsTIb8j7/mbdNIwCTVaxO16+fIk5c+bg2LFjOVKfmZmZlOgoW7Ys1NXVM93OpYIFNvWqJmWrbY0GaGoWhwObVkptExMTg8OHD+Pw4cPQ0NCAi4sLOnToAFdXVxgYGOTI8eQkizxeYdvtAEgIkKQkIeruIUT7nARIwitnYmKCdevWoUuXLjn2kg8ODoa7uzt27NgBiUQilV+lShUsXboUTZs2hUQiwcSJE7FixQpeGTs7O1y+fBmenp54/Pgx1NXVsXbt2gIrRADmL8LIO5gYYRRYMovdMXDNGdgHeuLmpTMyR7NkhZqaGsqXL88THRUrVoSZmdlf2+tSwQJNy5lLteII0AgxgR8y/JoH0gJTnT59GqdPn4aKigoaN26Mjh07omfPnkoRLXORxytsuRUAAEj89goRF9cgNTJQqlyPHj2wZs0aFClSJEfqjYmJwbJly7BixQrEx8dL5RctWhQLFixAz549IRQKkZKSgoEDB2Lfvn28ctWqVYOHhwfMzMzQvHlzAICbm1uBD4vORtIw8gomRhgFErGEMOfcKxAASVIchOppgahSIgMRde8w4l7dRBBJfyFnhkAgwIYNG1C/fn3Y29vniiOpSCiQMXxXgH379qFWrVp48+ZNlvtITU3Fp0+fYGpqCk1NzRy3Mbskp0qw7XaaECEi/Ly5R0qIiHSMcGTvDnRs3y5H6kxJScG2bdswZ84chIaGSuXr6+tj+vTpGDVqFOd3ExcXh86dO+PixYu8so0bN8bJkye5JmZbW1u4uLhgypQpOWKrMsNijDDyCiZGGAUSn4BIBEclglKTEbR9GNTMS0GjRBUkvL+P1KjvgFAIiLMnRogIXl5eGDp0aJ43zevp6eH06dNwcHBAdHR0huX09fWxaNEiDBo0SGlG3ezz/oT0eG0CgQDGLqMQtHMEIBEDANQsy0DTtjr2e9zGM98nSEpKknvR1tbG8ePHYW5uDiDtGp06dQpTp06VepECaS1ao0aNwrRp02Bk9Gv23IiICLRq1QoPHjzgle/SpQv27t0r1c125MgRpRB6uQ3rpmHkFUyMMAok6TE5Yl9chTg2EgkfHiDhwwPoOXaCWbcFIJJAEh+FMY6GsNVMwtevX6WWoKAgKf+CkydPYv369Rg1alSeH1Pp0qWxf/9+tGnTJsMy0dHR8Pf3h1gsVhox8jmS3z2iamwNPcfOiHl4GpSSiOSgN0gOeoPTd4DT2divuro6vLy8OCFy9+5dTJo0Cd7e3jLL9+zZE/Pnz0eJEiV46V++fEHz5s2lWp1GjhyJNWvWyIxpUlgc6X8XI6qqqjk6tJrB+B0mRhgFElNdDZBEjOj7x3npmjZpQcsEAiFE2oao4+iYYVTT1NRUBAUFSYmUu3fvonPnztxLMC9xdXXFnDlz4O7uLjOfiLBixQp4enpi3759qFKlSt4aKIPiRtI+KwZ1ukO/Vkckh35EpOcGpIR/kbFlxggEAhw8eBB169bF27dvMXXqVJw6dUpmWWdnZyxdulRmwLqXL1+iefPmCAzkdxvNnz8f06ZNK9DOqfLwe+uSra0tVFTYK4ORO7ChvYwCiVhCKNN9Oj4cXcSlqVuVhVnPpRAIBBAgbVr3O27O+W42VYlEgo4dO+L06dOZllNVVcXs2bMxefJkhb5EklMlKDPzIjKaWofEKYh5eAoJD47KHbfF2NgYPXv2xKdPn3D+/HmZI2QqVqyIpUuXonnz5jJFxd27d9G6dWv8/PmTSxMKhdi8eTMGDx4slx0FmcjISBgb/xLqrq6umTpRMxiykPf9zSbKYxRIBCCkPuF/Kes5duaECAC4u5bLd0IESHth7t27F2XLluXSZs6ciSFDhvDKpaSkYPr06ahfvz4+fPiQ12ZyqKkIMbieTYb5ApEqJk12w8uXL9GiRQu59hkREYG1a9fi7NmzUkLE0tISu3btgq+vL1xcXGQKkXPnzqFJkyY8IaKuro4TJ04UaiFy+fJl7n/mL8LIS5gYYRRILly4gE8ffvkAqJqUgKZd2gR35voa2NSrGlwq5FwwrbxGV1cXp0+fhr6+PoC0OBlbtmzB+fPnpYYXe3t7o3Llyti8efNfDWPOCaa2LIf/6tvgT+0nFAD/1bfB1JblYGtri7Nnz6Jdu3b/FOiMiHD9+nUcOnQIISEhUvm7du1C+/btea0w+vr6uHz5coGOpCoP7u7u6NmzJ37+/JmpGCEihf2WGAUUygdERUURAIqKilK0KYx8gEQiIUdHR0JaMFMCQLNXbaHTvt/o3odwShVLFG1ijnH+/HkSCAT07NkzLi0sLIw6derEO/70xcXFhQIDAxVmb1KKmLbf8qeZp/1o+y1/SkoRc3lisZj69+9PBgYG9PPnTxo5ciQJBAKZx5GdpVKlSjRhwgS6ePEizZkzRyrfwsKCnj9/rrBzokz06dOHAJC1tTW1atWKd568vLzo6dOnNH36dGrXrh2JxeKsd8go9Mj7/mZihFHguH79Ou8hamdnRykpKYo2K9eYP38+xcbG8tIkEgnt37+f9PX1pV6+RkZGdOTIEQVZKxuxWEyDBg0iAKSurs6l79y5k7S1tTMUGra2tmRlZfXXQqVUqVIUEBCguANXMubNm5fhubKwsOD+37lzp6JNZeQTclWMrF+/nooXL07q6urk4OBADx48yLT8qlWryN7enjQ0NMja2prGjh1LCQkJctfHxAgjMz5+/Mhbb9asGe8humXLFgVZljdIJBm39Hz58oUaN24s8+XSvXt3ioiIyENLZSORSGjo0KE8296+fUudO3fO8MVYr1497rkjkUjo3bt3tGHDBmrXrh3p6enJLUaMjY2pW7dutGPHDvry5YuCz4TiOXLkSJbnzMrKipKSkhRtKiOfkGti5PDhw6SmpkY7d+6kly9f0uDBg8nAwIC+f/8us/yBAwdIXV2dDhw4QAEBAeTp6UkWFhY0btw4uetkYoSRESkpKWRra8v9/h49eiT1NZeYmKhgKxWLWCymtWvXkoaGhtSLxdLSkjw9PRVmm0QioeHDh0vZJRKJZL4IdXV1CQDdv38/w32mpKTQ3bt3afbs2eTo6Jitrp7SpUvTyJEj6ezZsxQdHZ2HZ0I58PX1zfIcrVixQtFmMvIRuSZGHBwcaMSIEdy6WCwmS0tLWrRokczyI0aMIGdnZ17a+PHjqU6dOnLXycQIIyPev39PAKhRo0aUkpJCHTt25D04ly9frmgTlYbXr19TzZo1Zb5gRowYIdXVk9tIJBIaPXq0XCLBwsKCtm3bRikpKXTu3Dk6d+5clvsPDQ2lGjVq/HUXjoqKCtWtW5fmzJlD3t7eBbqrL52YmJhMz4mBgUGhFGmMvydXxEhSUhKJRCI6deoUL71Pnz7Upk0bmdscOHCA9PX1uSZVf39/KlOmDC1YsCDDehITEykqKopbvn79ysQIQybnz5/nHpTdunXjfQUbGhqyB+cfJCcn0+zZs2W2PJQqVSrTFoecRCKR0Lhx47IUBDo6OjRv3rxsC6WAgAAqVaqU1P7Gjh1LHz9+pG3btlGXLl3I2NhYbnGir69P7du3p40bN9KHDx9y6cwonsx8cKZPn65o8xj5jFwRI4GBgQSA7t27x0ufNGkSOTg4ZLjdmjVrSFVVlVRUVAgADR06NNN63N3dZd4ITIww/mTFihUZPjjd3d0VbZ7S8vDhQypTpozUORMKhTRjxgxKTk7OtbolEglNnDhRrpaJGzduZHv/z5494zlbpi+LFy+W8q8Ri8X06NEjWrhwITVq1IjU1NTkFic2NjY0ZMgQOnbsmFL43uQUDRs2lHm8GhoaGXbHMxgZoTRi5Pr162RmZkbbtm2j58+f08mTJ6lo0aI0d+7cDOthLSMMeRkyZEiGL4tmzZpR+/btqVWrVtSnTx+Kj49XtLlKRXx8PI0ZM0bmuatWrRq9fPkyx+uUSCTk5uYm9wtfQ0OD1qxZI/cw0ps3b0qNIBKJRHKP/oiNjaWLFy/SuHHjqEKFCnLbKRQKycHBgaZPn043btzI1w6eGd1Tw4cPV7RpjHyI0nTT1K1blyZOnMhL27dvH2lqasr9gGE+I4yMaNCggVxN/Y8fP1a0qUqLl5cXWVtbS503dXV1Wrly5V/Fk0gVS+jeh3BebBeJRELTp0+X+wX/+9KlS5csHZFPnTpF6urqvO00NTXl8i/JiKCgINq7dy/17t2bzM3N5bZXW1ubWrZsSatXr6aXL19mOuJJ2Vi+fLlMseXv769o0xj5EHnf39masEJNTQ3Vq1fH1atXuUiFEokEV69exciRI2VuEx8fLzXrpUgkAgAWwY/xz7x9+zbTfFVVVZw+fRrVqlXLI4vyH40bN4afnx9Gjx6Nffv2celJSUkYP348zp49i927d8s9Y+ulF8GYc+4VgqN+RTi10NeA7ZcLOLh5VZbbq6uro2rVqnBwcOCWkiVLZjpp3bZt2zB06FBeaHhDQ0OcP38etWvXlstuWVhYWKB3797o3bs3iAgvXrzAlStXcOXKFdy8eRMJCQkyt4uLi4OHhwc8PDwAAFZWVmjSpAmaNWuGJk2awNTU9K9tym3s7e2l0rp27QpbW1sFWMMoNGRX5Rw+fJjU1dVp9+7d9OrVKxoyZAgZGBhQSEgIERH17t2bpkyZwpV3d3cnXV1dOnToEH38+JEuX75MdnZ21KVLlxxXVozCRfrvIqNFIBDQ4cOHFW1mvuL48eMynTr19PRo9+7dWX7hX/QLohJu56n4H4tB3Z4ZXqcyZcpQnz59aMOGDfTw4cNsdXFIJBKZgbqsrKzoxYsX/3o6MiUhIYGuXr1KU6ZMoerVq2drCHHlypVp4sSJ5OnpqXTdh69fv5ay19fXV9FmMfIpuRr0bN26dVSsWDFSU1MjBwcHngd+gwYNqG/fvtx6SkoKzZ49m+zs7EhDQ4OKFi1Kw4cPpx8/fshdX16JEVlNywzlxcfHJ9MH/po1axRtYr4kODiYWrduLfOctmvXLkMnxlSxhBwXelFxt/NUbPK5X0KkXm9ue1VdI2rTpi0tWLCAvLy86OfPn39tZ2pqKo0YMUKmuPn8+fNf7/dvCQsLo8OHD9PAgQOpWLFicgsTdXV1atKkCS1ZsoR8fX0VHmY9KSmJhEIhZ5+Li4tC7WHkb+R9fwuIlL+vRN4piP+FjJqW3V3L5esJ1Qoy+/fvR+/evWXmTZkyBYsWLcpjiwoORIQdO3Zg3LhxiI2N5eWZmppi27ZtaNOmDS/d2z8C3bfdBwD8vL0fmrbVkRoXieSgd1CzsIe6hT1EukVweIgTnOyM8S8kJSWhT58+OHr0KC+9Vq1auHDhAoyN/23//woR4f3797h8+TKuXLmC69evIyYmRq5tTUxM0KRJEzRt2hRNmzaFtbV1LlsrTcmSJeHv7w8AuH79Oho2bJjnNjAKBvK+v9msvUgTIsP2P+EJEQAIiUrEsP1PcOlFsIIsY2TGmzdvZKb369cPCxcuzGNrChYCgQCDBg3Cs2fPULduXV5eaGgo2rZti4EDByI6OvpXekza/UMkQZT3UYQcmoafN/ZA3bocNIpXhoqeCQQCAVfub4mOjkbLli2lhEjLli1x9epVhQsRIO382dvbY+TIkThz5gwiIiJw584dzJo1C05OTpzfnCzCwsJw6NAhDBgwAEWLFkW5cuUwZswYnD9/Xm5B8y+IJQRTaxsAQLnK1VC3Xv1cr5PBKPRiRCwhzDn3CrKah9LT5px7BbFE6RuQCh2ynFdbtmyJrVu3ZursyJAfW1tb3LhxA0uWLIGamhovb+fOnahcuTJu3boFADDV1QAASJLiAZIA4hSk/ghC3OtbEKprc9ull/sbvn//jkaNGuHatWu89D59+uD06dPQ1tbOYEvFoqqqijp16mDOnDm4d+8eIiIicOrUKQwfPhwlS5bMdNvXr19j7dq1cHV1hZGREerXr4/58+fjwYMHEIvFOWrnpRfBqLvkGl7EagEAwmxdUG/pdfZBxsh1Cr0Y8QmIlGoRAYCYp5eQHPYJBCA4KhE+AZF5bxwjU/4UI46Ojjh69ChUVVUVZFHBRCQSYfLkyXj48CEqVarEy/v06RMaNmyIiRMnopKFFsz11CGJj+LyVU1KwLj5KAgEAgiQ1vXpYGP0V3b4+/ujTp06ePLkCS990qRJ2L17d7667vr6+mjXrh02bNiA9+/fIyAgAFu3bkXnzp1haGiY4Xapqam4ffs2Zs6cCUdHRxQpUgQdO3bEli1b8PHjx3+y6fcWYlUjS6gYWUOzlCNrIWbkCYXeZ+TM00CMOfyUWydxCsI9ViP+1U2oGJjDvM8qiDR1saZbFbStYpWjdTP+HolEAm1tbSQmpgnJMmXK4M6dO0rRRF+QSUpKwuzZs7F06VLeMFoAKF6yNNSajEZ0TBy+H5gMgbo2LPqugqqhJdLbqTb1qvZXPli+vr5o0aIFvn//zktfvnw5JkyY8LeHo5SIxWI8efKEG0J89+5dpKSkyLWtra0t52vi7OycqbDh1Skh1F1yjfswSwjwRWp0GHQrNwMACACY62vgjpszRELW6siQH3nf34VejPzudAcAoacWIOGdN7euYmgJ067zcXxim392umP8O2IJwScgEn5v3+O/Vk4AAEtLS3h7e6NYsWIKtq7wcPfuXfTp00f6a1yoAq0ydRH/6gZMOs6EVslaAAADLVUs7lBRbiGSfp1DYxLx9cVDTBveh+cvoaKigl27dqFXr145dkzKSmxsLG7dusWJk5cvX8q1nVAoRM2aNTlx4ujoKNXVlk76c5CI8OPadghUNaCiWwSqJsWhYV2OK3dosCN7DjKyhbzv72wFPSuIONgYwUJfAyFRiSAAulVbIeH9g7Q+bwCpP4IQtHkAZn9sjn79+qJt27bQ0tJSrNGFlN9HPCV8fAwAEGloY8a6fUyI5DF16tTBs2fPMGHCBGzduvVXhiQV8a9uQMu+NidEAEBTVYSm5czl2vfv1znuzR2En18OiFO5fC0tLRw/fhwtWrTIseNRZnR0dNCyZUu0bNkSABAYGAgvLy9cuXIFXl5eUq1F6UgkEjx48AAPHjzA/PnzoaOjg4YNG3LipEyZMpxvFed8nBSHmEdnuH1o2dfmiZF/dT5mMDKi0PuMiIQCuLum3WwCAJolqsDQeZBUucuXPdGjRw9YWFhg0KBBuH37Nosgm4f8OeIpJTIQEKnCpMNMLPVJYP3ZCkBHRwdbtmzBsm0HIdQ24NLVrcrCuM1kXll5/a5+v84xvh4IP7OEJ0T0DAxx7dq1QiNEZGFlZYW+ffti//79CA4OxrNnz7B8+XI0a9YMGhoZOwfHxsbi/PnzGDNmDMqVK4dixYphwIABOHToEFST04Zvi3/z9wHAu67AvzkfMxiZUejFCAC4VLDApl7VYK6fdqPpVneFdsUmMstGR0djx44dqF+/Puzs7DB79mxuPD4jd5A14ik57BPUzUtCpGcCgI14UiSlatSH5YAN0CpdB0JNPZi0mwahSLrRNauv6t+vc/w7b0Re3gj8dtVFuiaw6bcCNWo65PAR5F8EAgEqVaqECRMmwNPTEz9+/ICXlxfc3NxQtWrVTLf99u0bdu3ahR49eqBVrTII2zsGUXcP8sqItPTT6sG/OR8zGFnBxMj/calggTtuzjg02BFru1fFhcN7UMvRMdNtAgICMGfOHJQsWRL16tXDtm3bEBUVlek2jOwja8STODYCSYGvEbRjOKIenUHQjzg24klBmOpqQKSljyJtp8Ci31qIdGQ7TWb1Vf37dda0qwkN2xpcnmqRYjDvtQw/1U3Zdc4EDQ0NNG7cGIsXL8aTJ08QGhrKi1mSGfHB/oh7dZOXlhwagJTQjyCSwN21HHNeZeQahd5n5HdEQgHPOevUyZOoUaMGgoKCstz2zp07uHPnDkaPHo127dqhT58+aNq0KVRU2Cn+V/78oo7/4IPE//uMUEoSflzdhrhXt/Co1kY42TkrwsRCze9+VwK9IlL56SMxsvqq/v06C0QqMKjbA+E/QyDS1INJp1kQaehIlWNkjomJCbp164Zu3bqBiPD27VvOEfb69etS0XX/JOH9fSS8vw8DoyLY960ZQv7vb2JlxUYWMnIW1jKSCRYWFjh58mSGHuiySExMxOHDh7F48WI8e/YsF60rPPz5RS1JioNATZOXlhz8FuO7u2DOnDlITk7OS/MKPX/6Xf1O+ro8X9V/Xmc1UxukxkRAr2Y7TojIKseQD4FAgDJlymDUqFE4e/YsIiMjcevWLS5myZ+zq//Oz8hwHDx4EP3794e1tTXKly+PsWPH4sKFC1kKGgZDHgr90F552LNnD/r16ydX2QYNGmD27NlsLoccJD0GQvqIJwBIjQ5FpOdGJHx8JFW+fPny2LFjB2rVqiWV9+PHDwiFQujr6+ey1YWPf53fSdZ1Dt47Acmh/jBpNw3aJR1YrItc5OfPn+jWrRs8PT2ztZ2qqipq167NjdKpXr16puHuGYULNjdNDtK3b1+MHTtWrrJlypSBYxa+JozsIevLW0XPFCad3FHEdSKEmvwf+MuXL+Hk5IRx48YhLi6Ol/fq1St07txZ7iBSDPn53e9qTbcqODTYEXfcnOWOLSLrOqtblALEqQg7tRDxHx4wv4VcxMDAALq6ury0lStXomPHjjAwMMhwu5SUFNy8eRMzZsxArVq1YGJigs6dO2Pr1q0ICAjIZasZBQXWMiInqampcHFxwdWrV7MsW7lyZRw7dgylSpXKA8sKDxl9eY+pY4ZzWxbh4MGDUtuUKFECW7duRdOmTQEAR44cQbdu3fDff/9h06ZNbA4bJeT36xz74hoiLqwEAKioqOL48WNo27atgi0suDRo0ICba0hVVRVJSUkQCAQQi8V4/Pgxrly5gsuXL8Pb21tuQW9nZ4dmzZqhadOmaNSoUabChlHwkPv9TfmAqKgoAkBRUVEKtSM8PJxsbW0JaeMNM110dXXpyJEjCrW3IJIqltC9D+F02vcb3fsQTqliCZd3/vx5sra2lnk9+vXrRxEREbRs2TIubcWKFQo8EkZmpF/nDadu8q6jqqoqnTp1StHmFVhKly7NnWsrK6sMy8XExND58+dpzJgxVK5cObmeiQBIKBSSo6MjzZw5k27fvk3Jycl5eHQMRSDv+5uJkWzi5+dH2travBvMysqKRo8eLfPmGz58OCUkJCja7EJDVFQUDR8+XOa1MDMzIycnJ25dIBDQ6dOnFW0yIxPEYjHp6enxrqOKigqdPHlS0aYVSAwNDbnzXLVqVbm3+/r1K+3atYt69OhBpqamcosTXV1dcnV1pbVr19Lr169JIpFkXRkjX8HESC5y8uRJqZtq3rx5dPLkSdLX15fKq1atGn348EHRZhcqbt++zfvKy2jR0tKiR48eKdpcRiY0btxY6rqpqKjQ8ePHFW1agSIpKYl3jps3b/5X+xGLxeTr60tLly6lpk2bkoaGhtzipGjRojRgwAA6dOgQhYWF5fARMhQBEyO5jLu7u9SNdObMGfL396fq1atL5enp6bGHZx6TkJBA06ZNI5FIlOkD0MLCgr5+/apocxkZMGXKFJnXTSQS0dGjRxVtXoEhMDCQd3779OmTI/uNj4+ny5cv06RJk6hKlSpyCxOBQEDVqlUjNzc38vLyYi3M+RQmRnIZsVhM7dq1k2pyfPnyJSUmJtLIkSNl3mCjRo2ixMRERZtfqPD19SULC4tMH3yVK1emmJgYRZvKkIGslsjfBQnzzcoZfH19eed24sSJuVLP9+/f6eDBg9SvXz+ysrKSW5xoampS8+bNafny5fTs2TPWpZNPYGIkD4iOjqby5cvzbpiSJUtSZGQkEREdO3ZMqr8bANWoUYM+fvyoYOsLB2/evKHmzZvL9bBr3bo1paamKtpkxh98+/Yt0+smEono0KFDijYz33Pp0iXeeV26dGmu1ymRSOjVq1e0Zs0aatWqlZQ/XmaLmZkZ9erVi/bs2UOBgYG5bivj72BiJI/48OEDz+kLADVr1oxSUlKIiOj9+/dUtWpVqRtJX1+fOeHlIikpKTR16lRSVVWV++EGgMaOHato0xkyyKplSygU0oEDBxRtZr5m7969vHO6e/fuPLchKSmJbt68STNmzKBatWqRUCiU+94tX748jR07ljw8PCg2NjbPbWfIhomRPOTKlStSN83vTZwJCQk0bNiwDF9+SUlJCrS+4BIeHk4HDhygnj17krGxsdwPtQ0bNhBR5sOIGXlL27Zts7xuQqGQ9u/fr2hT8y3Lly/nnU8PDw9Fm0SRkZF0/Phx+u+//+QOqwCA1NTUqGHDhrRgwQLy8fFhLZ4KRN73Nwt6lkOsWrUK48eP56Xt378fPXv25NaPHDmCwYMHIyYmhlfOwcEBR44cQYkSJfLC1EKJWCzGw4cP4eHhAQ8PDzx+/DjDskKhEHM27MOFH2Z/HdqckbMsWLAAM2bMkJlXunRplChRApqamtDR0cHChQuznKGWAQQFBSEsLAyVK1cGALi5uWHp0qVc/uPHj1GtWjVFmScTf39/bqK/a9eu4efPn3JtZ2RkhMaNG3Mh69mzNu+Q9/3NxEgOQUTo168f9u7dy6VpaGjg9u3bqFHj11To79+/R+fOnaUm0TMwMMCePXvQpk2bPLO5MBMSEoKLFy/Cw8MDly9fRnR0NC9foKYJ817LoGZS4lfa//9u6lWNCZI85sqVK2jWrJnMPBcXF1y8eDGPLcr/xMXFwdjYGMOHD8ecOXMwevRo7N69m8v/+vUrrK2t4e/vj0ePHqFr166KM1YGqampePToESdOvL29kZqaKte2pUqV4oRJo0aN2FxVuQgTIwogMTER9evXx8OHD7k0a2trPHz4EObm5lxaQkICxo0bhy1btkjtY8KECVi0aBFUVVXzxGZG2twa9+7dg4eHBy5cuICXL18CAER6JrDovRIiHUOurABgk7UpgB8/fsDIyAgAoKurC1VVVURGRnL5V69ehbOzs6LMy7dUqlQJfn5+sLKygqamJj58+MDl7d27F3v27MHVq1exdetWDB48WIGWZk1MTAxu3ryJy5cv48qVK3jz5o1c24lEItSqVYsTJw4ODuz5m4MwMaIgAgMDUaNGDYSEhHBptWvXxrVr16Curs4re+jQIQwZMkRqCm5HR0ccOXIExYoVyxObGb/w9o9A5+VnkfDxERI+PoIkOREm7aYi8spmaJepCy17JwDAocGOcLIzVrC1hQt7e3u8f/8ee/bsQWRkJMaNG8flVa9eHT4+PhAK2dyf2WHgwIHYuXNnpmW0tbURHBwsNYmesvP161d4eXnh8uXL8PLyQnh4uFzb6erqolGjRtx8OqVKlWJzWP0DTIwoEG9vbzRs2BDJyclc2qBBg7B161apH/Xbt2/RuXNn+Pn58dKNjIywZ88etG7dOk9sZqRx5mkgxhx+yq2L46MQdmYxkr74ASJVmHWeA43ilbCmWxW0rWKlOEMLIb169UJiYiKOHTuG5ORklClTBp8+feLyDx48iO7duyvOwHzIli1bMHTo0EzLDB48GFu3bs2xOsUSgk9AJEJjEmGqqwEHG6Ncb2WUSCR49uwZN9HfnTt3kJSUJNe2xYoVQ9OmTdGsWTM0btwYxsbsIyQ7MDGiYHbt2oUBAwbw0jZs2IDhw4dLlU1ISMDo0aOxfft2qbxJkyZhwYIFrNkwj/D2j0D3bfe59fDzKxD38jq3LlDThFn3RTg5sxdrGcljjh07BmdnZ+5lcOjQIfTo0YPLt7GxwevXr6VaIBkZ8+TJE1SvXj3TMg8fPuT5vf0LGc28ndeO4QkJCbh9+zbnb/KnD19GCAQCVKtWjevSqVOnDvu9ZQETI0rA6NGjsW7dOm5dRUUFXl5eaNCggczy+/fvx3///Yf4+Hheeu3atXH48GFYWlnn+RdFYUMsIdRdcg0hUYkgAKnRYQjZPxnimDCujIqWPp49uo9yZcsozlAGJBIJHBwceCOjVq9ejTFjxijQqvxFSkoKdHV1M2wlqFKlCp48eZIj3RSXXgRj2P4n+POFowyO4d+/f4eXlxcnToKCguTaTktLC/Xr1+fESYUKFViXzh8wMaIEpKSkoHnz5rh+/deXdZEiRfDo0SMUL15c5javX79G586dOSfKdPQMDGHRdhISzStxaWyoae6Q/tAE0oIWpER8RcgBN0gSfo24KVasGO7evQtra2sFWckA0hxXmzRpwq0bGxvD39+fjY7IBo6Ojnjw4IHMvI0bN2LYsGH/XEe6yA+KiEHCJ19olXTg5SuTYzgR4dWrV5wwuXHjhtQHYkZYWFigSZMmaNq0KZo0aQILC/ZsZmJESQgPD0fNmjV5fdtVqlTBnTt3oK2tLXOb+Ph4jBw5Ert27ZLK03PsBIN6vSEQipTii6Kg8mdzclLwO4Qeng5JcgJXpmzZsrh9+zbrQ1YwLi4u8PT05NanTZuGBQsWKNCi/MWoUaOwfv16qXQtLS0EBQXliLDz9o9A1403EXZ6ERI/PoKeU1cY1u8tVU4ZHcOTk5Ph7e3NjdJ59OgR5H1tVqxYkWs1qV+/PrS0tHLZWuWDiREl4vnz53BycuKp6y5duuDw4cOZNunt2bMHw4YNQ0JCAi9d3bocTDrOgkhDR6m+KAoafzraxXz0hWvrVjzHZAcHB1y9ehU6OjoKtLRw8+zZM1StWpV7QWhqauL9+/ewsmIOxvKwb98+9OnTRyq9f//+mY60kUgkiIyMRFhYGEJDQ3nLn2nfgoIRF8OP5aNfpwf063TnPQPzg2N4ZGQkrl27xomT3z80M0NNTQ116tThRulUrVq1UIz+YmJEyThx4gQ6derES1u4cCGmTp2a6XYHLt5F/97dkRLxlUvTKF4Fpl3mQCAUcWnK+EVREDl58iQ6d+4MiUTCpTVt2hTnzp1jjmwKpE+fPti3bx+3PmjQIGzbtk2BFuUf3rx5g7Jly0qle3t7w9HRkVu/d+8eZs2axQmM8PBwiMXiv65Xz6EDDBr254mR/PYcIyIuKuzly5dx7do1qQCKGWFsbMyLCptR131+h4kRJWTWrFmYN28ety4QCHD27NlMh++eeRqIUXvvI/LKRsS9uAaRtiEMGw2EJCURGkXLQ8XIGgKBIF98URQUduzYgUGDBvHSOnfujEOHDkEkEmWwFSM3+fz5M+zt7blWK6FQCD8/P5QrV07Blik/EokEhoaGvJdoxYoV8ezZM6mW2/Xr12P06NFyd1NkhE6VFjBqNpzbf0Fp4U1NTcXDhw95UWHlFWz29va8qLCy3nWKGBb9rzAxooRIJBK0b98eZ8+e5dJ0dXXh4+ODMmVkj8xIH2pKRIjz84KKgRnUrcoh7NQCJPg/hFBLH+rW5TC4U0v0atccVatWhYqKSl4dUqFl6dKlcHNz46UNGTIEmzdvZt70CmLSpElYvnw5t+7q6sq71xgZ4+zszHO0X7t2LUaNGiWz7PHjx9GzZ09ed2V20C7fCMatxkEgSOuiKMi+b9HR0bhx4wYnTt6+fSvXdiKRCI6OjryosF5vwpRiWHR2YWJESYmOjoajoyNev37Npdnb2+PBgwcwMDCQKv/nUNN0JClJCD0+B0lfnvPKa2trw8nJCfXq1UO9evVQq1atQuk0lRdMnjwZy5Yt46Ux50nFERkZCTs7O97kabdu3UK9evUUZ1Q+4fdJ8jQ0NBAUFARDQ0Opcl+/fsXOnTuxfv16uSOa/k6dJi2R2mAMQmJTuLT88EL9V4gIGzduRFxcHMLCwvDmzRt4e3sjIiJCru21dHQBi/LQKFEVGiWqQMXQEgKBIF8IOSZGlJj379/DwcGB99Bs0aIFzp07J7OZ/8+hpulQUjxCjsxAcvC7DOtSVVVF9erVUbduXdSrVw9169bl5vhg/BtEhEGDBkk5+a1YsUJqBmdG3rBs2TJMnjyZW3d0dMS9e/dYa1UWHD16DF27dgEAtGjfFeeOH+Ka/1NTU3HhwgVs27YNFy9e5PlLZYSKiorUpHUuLi44c+YMRCqq+a6rISe4evUqmjZtynVxqaiowNzcHJqamoiPj0dISIjcXTp6NdvD0HkgAOXv4mJiRMnx9PREy5YteTe2m5sbFi9eLLN8RpELx9e3wNyhXfHixQu56y5fvjzq1auHJk2aoEOHDuxB/Q+kpqaic+fOOH36NC999+7d6Nu3r2KMKsQkJibC3t4eX7/+cvg+fvw4OnbsqECrlJtLL4Ixbd91+C7tCQAw67kUNuWr4b+qOnh/+yx27dqF4OBgufdnbGyMyMhInl9JgwYN4OHhUehbaWW1pv4Nxq4ToVOuIS9NWZ1/5X5/Uz4gKiqKAFBUVJSiTclRli9fTkhr7OCWgwcPSpVLSUkhIqJUsYTufQin077f6N6HcEoVS4iIKCgoiOzs7KT2ldlSq1YtevnyZZ4eb0ElISGBGjZsyDu/IpGIzpw5o2jTCiW7d+/mXYtSpUpRcnKyos1SSi76BVEJt/NUbPI5EmoZkIqRNRVp40YaJapm+vwQCARUqVIlqfRKlSqRSCTipTk4OFB0dLSiDzVHyehZnBXBwcFUtGjRbD2rZS1WI/dTcbfzvOW077dcPuq/Q973N2sZUSBEhD59+mD//v1cmoaGBu7cucPNF5GSkoJJkyZh9erVme7r06dPqFu3LgIDAzMtp6Ghgfnz52Ps2LFs5EcOEh0djUaNGuHJkydcmrq6Ojw9PTMM/8/IHcRiMapWrcqbfDKnIokWJNL90dJbWwO3DIY47gcoJTHDbaysrDBw4EAMGDAAL1684I0ETG8hTEn55Q9SqVIlXL9+vUB1DWc1vw4R4du3b3j9+rXUEhYWlsmeM0bNsgx0yjeCJDUZ4uhQGDX5T6pMfm8ZYWJEwSQkJKBevXq8+TWKFi2KR48ewdTUFAcOHEDfvn3x+fPnLIM4vX79GvXr18/UsczY2BiLFi3CgAEDmBjJYUJDQ1GvXj28e/fLh0dPTw83btxA1apVFWhZ4ePixYto2bIlt25qaooPHz5AV1dXgVYpF39OChm0cyRSwj5JlROJRGjVqhUGDx4MFxcXbrRe+mSgOjo6mDx5MhYuXIjExF8vaHt7e9y6dQtmZma5fix5xe/z6xBJkBoZhJSIr9xiiUgEf/ZHbGxsjtTXuHFjTJ02HdPvi/E9OklqXh+g4PiMFPzwb0qOpqYmTp8+zbthv379ik6dOiE5ORnLly+HWCyWK4BT2bJl4enpmekFj4iIwJAhQ1CjRg3cunUrR46BkYapqSkuX77ME43R0dFwcXHB+/fvFWhZ4cPFxQXOzs7cemhoKFasWKFAi5SP0Bh+C4hBPX54dpG+GQzq9cY2jwc4c+YMWrduzQsb8P37d5QuXRrbt2/HsmXLeEKkRIkSuHr1aoESImIJYc65V78EARGCdo1E2KkF+HlrL+JeXsf7l89yRIi0atUK9+7dg5eXFxo7N8LsNuUB/BoGnU76urtrOaUUItmBiRElwNraGidOnICqqiqXdvv2bTRu3BhPnz4FAGzdupXX/JkR1apVw4ULF6CpqZlpuadPn6JBgwbo2rUrvnz58k/2M35RvHhxXL58mdcsHRoaiqZNm2bZhcbIOQQCATdUNZ3ly5cjJCREQRYpH6a6Grx1zZI1oWJkDa3SdWDaZS6s/tsG/dpdUcauhMztq1atip07d2LYsGGIiYnh0i0sLODl5VXgJpH0CYjkdc0IhCKoGlrKta1QKETJkiXRunVrDBkyRGYZgUCATp064cmTJzh//jycnJy4PJcKFtjUqxrM9fnXzFxfQ6mH9WYH1k2jRGzbti3DHyqQvVEBly5dQps2bTgBU716dejq6uLGjRtSZTU0NODm5obJkycXem/3nMLHxwfOzs6Ii4vj0sqXL49bt24VqP5zZad79+44fPgwtz5s2DBs3LhRgRYpD7JiGJE4FQJRWutHVs3/7969Q7169RAaGsqlFSlSBDdv3iyQkW/PPA3EmMNPeWlBO0YgJfzzrwSRKkrYlkStapVQtmxZbilVqhQ0NNKExIEDB9CrVy9uE6FQiB49emDq1KlZnjcWgVXBFBYxAgAjRozI8GHZuHFjeHl5yb2v48ePo2vXrpBIJOjTpw92796NkydPYsKECfj8+bNUeWtrayxbtgxdu3Zlw31zAC8vL7Rs2ZLXouXo6AgvL68MZ2xm5CwfP35EmTJluGsgEonw6tUr2NvbK9gy5SCjGEZZBdP69OkT6tWrh2/fvnFp+vr6uH79eoH1j/rTxwYAvm7oC03batAq5QRV46JQ0TfF4f/qZOpI2rlzZxw/fhyqqqro168f3NzcYGdnl9vmKwzmM5JPSExMxJkzZzBlyhQ0aNAAu3btyrDs1atX5Q4nDACdOnXC9u3bAQAGBgYQCATo2LEjXr9+jXnz5km1gnz79g3du3dHvXr1eKNCGH9HkyZNcPDgQZ6wu3//Pjp06CAVSvv9+/f/PN8HQxpbW1veKBqxWIxp06Yp0CLl4m+a/4OCgtCkSROeENHW1oaHh0eBFSIA4GBjBAt9DZ7fhkCkgqQvL6BRvDLUDC1gaagNB5uMWz4TEhJw48YNjBo1Cv7+/ti6dWuBFiLZIjfHF+cUBTXOCBGRRCKhHTt2kK6urlzjy8eOHZvtOlavXk2zZs2SSv/69Sv17NkzwzgCgwYNopCQkJw4zELNli1bpM5v165dKTU1lSvTsWNHunr1qgKtLLiEhoZK3V/e3t6KNkupkDduRlhYGJUrV453LtXV1QvNbzc9LkuJ/8f2EGkbEgDSr92dSridp4t+QZluHx4eTsHBwXlkrXIg7/ubiREl4dOnT+Ts7JylGDEwMKC4uLhs7z8oKOOb5O7du1SjRg2Z9enp6dHy5cspKSnpXw6v0LNw4UKpczt06FCSSCQUFhZGqqqq1LBhQ0WbWWCZP38+79zXq1ePJBL5AlUx0vjx4wdVrcoPhqaiokLnzp1TtGl5ykW/IHJc6EXF3c6TUF077eNNpErbzt1WtGlKCRMj+RCxWEzr1q0jTU3NTAXJjh07cqXuXbt2kZmZmcw6S5UqRefPn8/xegsLEomExo8fL3VeZ86cSWvXruXWb99mD7TcIDY2liwsLHjn/uzZs4o2K98QGxtLtWvX5p0/oVBIR44cUbRpCiG9JUlNXZ07H40bN2YCVwZMjORj3r17R05OThmKkRo1auRa3VFRUeTm5kZqamoy63ZxcaHXr1/nWv0FGbFYTH379pU6p/r6+tz/zZo1U7SZBZZt27bxznvZsmW5qRYYGZOQkECNGzeW+t3u3LlT0aYpFIlEInVOZE3nUdhhYiSfk5qaSosXL85QFPj4+ORq/e/fv6c2bdrIrFtFRYXGjh1LP378yFUbCiIpKSkZntf05cGDB4o2s0CSkpJCZcuW5Z3rbdu2KdospSY5OZlcXV2lfqPr1q1TtGkKJyEhQeq8mJubs+fiHzAxUkB4/vy5VD8tAOrfv3+e1O/p6Sn1AE9fihQpQlu2bOE5YjKyJj4+nqpUqZKhGHF1dVW0iQWWM2fO8M61paXlX/lgFURu3rzJW09NTaWuXbtK/T4XLVqkIAuVix8/fsi8f0eMGKFo05QKJkYKEElJSTRr1izebJgaGhoUFh7xVzNHZpfk5GRau3YtGRgYyLz5KleuTDdu3MiVugsK8fHx5OHhQSNHjiRbW9tMW0YAkK+vr6JNLpBIJBKqW7cu71wvWLBA0WYpnIcPH1Lx4sVJLBYTUVqXYv/+/aV+l9OnT1ewpcpDcHCwzHtXIBDQw4cPFW2e0sDESAHk4cOHvFaK4i2H8qaQdlzoleXQsn8hLCyMhg0bRkKhUOZN2LlzZ/r06VOu1Z+f+fHjB40ePVpqevWMlo4dOyra5ALLvXv3eOdaT0+PwsLCFG2WQmnZsiUBoJs3b5JEIqFRo0ZJ/SZHjx7NHDR/IyAgIMP7t3r16qzF+P/I+/5mQc/yETVq1MCTJ0/Qsd9QAAIE3j/HC5QVEpWIYfuf4NKL4Fypv0iRIti4cSN8fX3RsGFDqfxjx46hTJkycHd354VBZ6QFnVuzZg18fX3RoEGDLMufOHECL1++zAPLCh9OTk7o0KEDtx4dHY358+cr0CLFcv/+fXh4eAAA9u3bhxkzZmDdunW8MgMHDsSqVatYZObfSEhIyDDv8ePH2LRpUx5ak/9hYiSfoaqmjkD7TjDrsQiUmozEz8+4vHRZMufcK4glJHsHOUClSpVw7do1nDhxAiVKlODlJSYmYu7cuShTpgwOHTrEoor+QcWKFXH9+nUcOnSIN7uvLBYuXJhHVhU+Fi5cCJFIxK1v3LgRHz9+VKBFimP27Nnc/7t27ZL63XXr1g1btmyBUMheF7/z+yzFspg+fTqCg3Pnw7Ag8le/rg0bNqBEiRLQ0NBArVq14OPjk2n5nz9/YsSIEbCwsIC6ujrs7e05Jc7IHukzR0qS4iGO+4n4N3d4L3wCEByVCJ+AyFy1QyAQoEOHDnj9+jUWLFggM7R8jx49UK9ePTx+/DhXbclvCAQCdOvWDW/evMGUKVN4szX/zuHDh/H+/fs8tq5wULp0ad6klCkpKZgxY4YCLVIMd+/ehaenJ7cuFot5+a6urti7dy9PuDHSyEqMREdHY8KECXlkTf4n22LkyJEjGD9+PNzd3fHkyRNUrlwZzZs3583c+DvJyclo2rQpPn36hOPHj+Pt27fYtm1bll+FDNmExiQiNTYSER6rAXEKYp9dQtjxORAnxEiVyws0NDQwbdo0vHv3Dr1795bKv3v3LmrWrIlBgwbh+/fveWJTfkFHRweLFi3Cixcv0KJFC6l8iUTCWkdyEXd3d96EhYcOHcKjR48UaFHe4+7unmGenZ0d9u3bl6FYLuxkJUaAtN/UlStX8sCaAkB2nVEcHBx4Q5fEYjFZWlpmONxr06ZNZGtrS8nJydmtioM5sP7izrtQ0ijBH+qrWqQ4FZtwkufMeu9DuELsu3fvHtWsWVOmU5euri4tW7aMhZaXgUQiobNnz5KNjQ3vnIlEInr/wT9PRk0VRtzd3Xnn29nZudA4ad68eTNLR2odHR3q2LEj7dmzhyIjIxVtslLh4eGR4Xlr0qQJNW3alAwNDalUqVKUkJCgaHMVRq44sCYnJ+Px48do0qQJlyYUCtGkSRN4e3vL3Obs2bNwcnLCiBEjYGZmhgoVKmDhwoVSzYG/k5SUhOjoaN7CSOPemT1I/OTLrQtU1FCkzSQIVNTS1gFY6GtkOnNkbuLk5IT79+9j9+7dMDc35+XFxMRg0qRJqFChAs6fP8/8SX5DIBDA1dUVr169wty5c6GpqQkgrdm8To8x6L7tPsYcforu2+6j7pJrueakXNiYMGECTE1NufVr167xui0KMpm1iqQTGxuLc+fO4fXr16yr5g9+d2CtVasWL8/e3h6XL19GREQEPDw8EBsbm9fm5TuyJUbCw8MhFothZmbGSzczM0NISIjMbT5+/Ijjx49DLBbDw8MDM2fOxIoVKzL1Xl+0aBH09fW5pWjRotkxs8Dy5MkTTP9j+nPDRgOhZlICALiprd1dy0EkVJzXu1AoRN++ffHu3TtMmTIFampqvPz379/D1dUVLVq0wOvXrxVkpXKioaGBmTNn4vXr16jTtBUAIPTxJaRGh3NlcnvUVGFCV1dX6qXs5uaW6cdSQeD69eu4ceNGluU6duyI169fY9GiRdDT08t9w/IR6d00M2fOxLVr16Curs7leXl5AUj7yChZsiSKFCmiEBvzE7nuHi2RSGBqaoqtW7eievXq6Nq1K6ZPn47NmzdnuM3UqVMRFRXFLV+/fs1tM5WeuLg4dO/eHSkpKVyaYVkn6FRtya2b62tgU69qcKlgoQgTpdDV1cWiRYvw6tUrtG3bVirf09MTlSpVwrhx4/Djxw8FWKi8WBctBnGjcTDtOh+qBhaI9jkBACAiri142ik/JKdKFGpnQWDw4MEoVaoUt/78+XMcOHBAgRblLkSEWbNmZVqmSpUquHHjBo4fPw5bW9s8six/kZqaiq1bt2Lu3LnQ0tJC3bp1ubx3797hy5cvCrQu/5EtMVKkSBGIRCIpR8Tv379LNcmnY2FhAXt7e14TX9myZRESEoLk5GSZ26irq0NPT4+3FHbGjh2Ld+/ecesWFhZ4feMMDg9xwppuVXBosCPuuDkrjRD5HTs7O5w+fRqXL19GuXLleHmpqalYvXo17O3tsWXLlgL/RSov6aOmNEtUgUX/dVA1LorEry8R8+Q8VyYyLgWOi66yFpJ/RFVVVcpReObMmXI5KOZHrl69ijt37sjMMzMzw44dO/Do0SO54uEUZrp164bBgwdz67+7LwBp55khP9kSI2pqaqhevTrvJEskEly9ehVOTk4yt6lTpw4+fPgAieTXF9y7d+9gYWEh1XzPkM3x48exfft2bl0gEGDfvn0wMzWBk50x2laxgpOdsUK7ZuShadOmePbsGdatWwdDQ0NeXnh4OIYOHYrq1avj5s2bCrJQefh9NJRApAI1Uxt8PzIDUXcOQpL8Ky8yLpl12eQAHTt25PX7f/nyBevXr1egRblDRq0iampqmDJlCt6/f48BAwYw/xA5+PP91bhxY956elcNQz6y3U0zfvx4bNu2DXv27MHr168xbNgwxMXFoX///gCAPn36YOrUqVz5YcOGITIyEmPGjMG7d+9w4cIFLFy4ECNGjMi5oyjAfPnyhae+AWDSpElSP/z8goqKCkaOHIn3799jxIgRUoGUnj17hoYNG6JLly749OmTYoxUAkx1NXjrqsZFoVOxCSSJMYj1kx4qmNuB7go6AoEAy5Yt46UtWLAAkZG5G68nLxBLCN7+ETjzNBCrdx2TGmzQqVMnvHnzBosWLYKurq6CrMz/VKtWDQYGBty6l5cXc9LPBtkWI127dsXy5csxa9YsVKlSBU+fPsWlS5c4p9YvX77wos4VLVoUnp6eePjwISpVqoTRo0djzJgxmDJlSs4dRQFFLBajV69e+PnzJ5dWvXp1zJs3T3FG5RDGxsZYv349nj59ikaNGknlHzt2DGXLlsWsWbMKZWh5BxsjWOhrcE7JQg0dGDcfAaPmo5Dg/xAk+dWdlVeB7go69erVg6urK7f+8+dPLFq0SIEW/TuXXgSj7pJr6L7tPkYf8sWUGTO5vKpVq+LmzZs4duwYbGxsFGhlwUAkEsHZ2ZlbDw0NxYsXLxRoUf5CQPlAukVHR0NfXx9RUVGFyn9k/vz5mDnz18NDW1sbT548gb29vQKtynmICKdPn8aECRMQEBAglW9lZYWlS5eie/fuhWpujEsvgjFs/xMuzD9JxAjcOgSSuB/QLu8MPcdOUDX45au1plsVtK3Cggn+C69evULFihW5bmV1dXW8e/cOxYoVU7Bl2Sf99yNJTQZEqkj4+Ahhx+dApG0Ig/p9sGfRRLSqbK1oMwsUmzZtwvDhw7n1lStXYty4cQq0SPHI+/5mkw0oKd7e3rw5IwBg3bp1BU6IAGlN5O3bt8erV6+wcOFCXlRMAAgMDETPnj1Rt27dQhUh06WCBTb1qgYj7bQImPFv7kAc9R2UmozYZ5cQcXEtr/yfXTuM7FOuXDmuyxlIi3n0+wdBfkEsIUzZcQkRV7fh24Y+SAp6i2jvo9Bz7AzLwVugW6kp5nu8ZV17OcyfTqzMb0R+mBhRQqKiotCjRw/eyJIuXbqgX79+ijMqD9DQ0MDUqVPx9u1bmaHl7927BwcHBwwYMCDDuDYFDZcKFrg/tQkMtVQR9eAEL0/foT0AxQe6K2jMmTOHCzoHpM1k++zZs0y2UB6SkpJw+PBh1HSqi2erByDm0RlIEmMR8/gsjFtPgGGDvhCqa7GuvVyiZMmSvFa0mzdvZjhqlMGHiRElZMSIETznzWLFimHz5s2FpovCysoKe/fuhbe3NxwcHHh5RIRdu3bB3t4ey5YtQ1JSkoKszDvUVIToZB6BlNBfs8qqFikODdsaShPoriBhZWWFsWPHcutEpPQ+bv7+/nBzc0PRokXRvXt3+Prc4+UnvL8PoYaO1HZ5NYdVYUEgEPBaR+Li4vDgwQMFWpR/YGJEydi/fz8v4JJQKMT+/fulhsIWBhwdHeHt7Y09e/bIDC0/efJkVKhQAefOnSvwXuvXj+7grevV6giBQKB0ge4KCm5ubjA2NubWL126hGvXruVZ/f7+/lmWSUlJwcmTJ9GsWTOULFkSS5cuRVhYmHRBkQo07Z1AyQlSWaxrL+dhXTV/B3NgVSL8/f1RtWpVxMT8moF31qxZmDNnjgKtUg5iYmKwcOFCrFy5UmazZ7NmzbBq1SqpoGoFgcePH6NGjRrcupmFFTacuQNLI1042BixFpFcYs2aNbwWkurVq8PHx0dqOHpOc+7cOUyYMIEX5PB3vnz5gm3btmHHjh28kYt/omFsBc2KzaFdsTFEWvq8PAHSIjbfcXNmv58c5s8goLVr18bdu3cVaJFiYQ6s+YyUlBT07NmTJ0ScnJwU5jz3e2wCb/8IhTu6/R5avl27dlL5ly9fRqVKlTB27NgCF1p+6dKlvHW3SRPQsWaJfBHoLj8zdOhQ3pDXx48f48iRI7lWn0Qiwdy5c9GmTRupgFpisRjnz5+Hq6srbGxsMH/+fJlCREVFBZ06dcKVK1dw4toD6NfqABUZQgRgXXu5hZmZGSpVqsSt33/wAF5PPyn8Gar05N7EwTmHvFMQ52emT5/Om4JaT0+PPn78qBBbLvoFkeNCLyrudp5bHBd60UW/IIXYI4srV65Q+fLlZU7fbWxsTJs2baLU1FRFm/nPfPjwgYRCIXdshoaGFBMTo2izCg0HDx7k/bZsbGwoMTExx+uJioqidu3acfU0bNiQiIgCAwNp7ty5VLRo0QynqwdAxYsXp/nz51NQEP8ezQ/3ckGkQ5//eNfHpOPMQnve5X1/MzGiBNy4cYMEAgHvx3vw4EGF2HLRL4hK/PbgSl9K/H9RppspJSWF1q9fT4aGhjIf0JUqVaLr168r2sx/YtiwYbxjmj59uqJNKlSIxWKqXr067xqsXr06R+t4+/YtlS1blldH5cqVqUOHDiQSiTIUIEKhkFxdXenChQuZCu9UsYTufQin077f6N6HcEoVS3LUfgafi35BZNppNu9a6VZvo5TP0LxA3vc38xlRMJGRkahcuTK+ffvGpfXp0wd79uzJc1vEEkLdJdcQHPXLw56IAIkYApGK0vYzR0REYPbs2di0aZPMifY6deqEZcuWoUSJEnlv3D8QGhqK4sWLcxO2qaur48uXLzA1NVWwZYWLq1ev8pwSjY2N4e/vD319/Uy2ko8LFy6gZ8+eiIqKknsbCwsLDB48GIMGDULRokX/2QZGzpH+DA0M+4Gva7oDklQAgGqRYrAcuFFpn6G5CfMZUUL+1H1EhMGDB/OEiJ2dncIm6EqfKZZIAklSHJLDvyLs5Dz8uJ42kkNZYxMYGxtj3bp1ePr0KS8cczrHjx9HmTJlMHPmTC60vLL5xMhi/fr1vJlj+/fvz4SIAmjcuDGaN2/OrUdEREj58WQXIsKCBQvg6uoqtxBp3rw5Tp48ic+fP2POnDlMiCgh6c9QoZom1K3KcOkp4V+QGhuptM9QZYC1jOQhc+fO5c2YuX37dt4keCoqKrh7965UbI3sIBaLER0djaioKJlLZnkh4ZGIiPwJSk6AapFiSI0KBaUkABDAvNcy7uZS5rDjRIQzZ85g/PjxGYaW7zFyKm5JSiMk+leMEgt9Dbi7llOaIbKxsbEoVqwY54wrFArx9u1blCxZUsGWFU6ePXuGqlWrch8UmpqaeP/+Payssn8fxMbGol+/fjhx4kSWZU1MTDBgwAAMHjwYdnZ22a6LkbeceRqIMYefAgCiH55Bgv9DqJeoDG372lAxtORiRSnzMzSnkff9rZKHNhVqvn79Cnd3d9SpUweNGzfGmzdvMGbMGF6ZefPm/ZMQAQAPDw907tz574OBCUUwbNQfKT+/IyX8wv8TCRGX1sKi3xoIRKpKHZtAIBCgXbt2cHFxwerVqzF//nzeRHuBgYFYNnUk1C3LwLDJEKhbpIXXD4lKxLD9T5QmZseOHTt4o4I6duzIhIgCqVy5Mnr37o29e/cCABISEjB79mxs27ZNZnmxhOATEInQmESY6mpwQ7A/fPiAdu3a4eXLl3LVO2TIEMybN6/QBDzM75jqaoBIgsSPT5Dw8REgEEC/Viep66fMz1BFwVpG8ogVK1Zg4sSJcHBwwM2bN+Hk5ISnT59y+Y0aNcKVK1cgEon+ua6rV6+ibdu22Z7ttnjx4tBpMQFx+rYQJ8UjaMdwiGPCuXyDuj1RpmX/fNXfGRQUhKlTp3IvkT8x6TgTWiVrAVCe2AspKSkoWbIkvnz5wqU9fPiQF2uEkfd8+fIF9vb2nNAXCoXw8/OTim1z6UUw5px7xfO9stDXQCvD71gxdQRvFm55GDhwIDZt2gRVVdV/PgZG7hEXF4c9e/ZiwuzFSAz7AoGqOiwGbOBNZqksz5i8hPmMKBmHDx8GAPj4+KBx48Y8IWJkZIS9e/fmiBAB0vq4L1++DA0N+dV327Zt4evri+UjOgEAROpaMGo+glfm570j6FdOJV/dRJaWltizZw/u37+PcpWr8fJE+mbQLFGVW1eW/twjR47whIizszMTIkpAsWLFMGrUKG5dIpFIhYlPnyn3TyfwN577MHNYr2wLESCtlax///5ITU39a9sZuce3b98wdepUFC1aFCNGDEdiWNq9a1Cvj5QQAVh8l4xgLSN5wPv37zOdbffkyZNo3759jtTl7++Pffv2Yf/+/XKFlFZVVcWyZcswevRorinx9y+7sLPLEP/6Jle+du3auH37dq5HocwNTj35isGzVuPnzd0Qx0bCuOVYJH59CXVzO2iWdICKXppzaF725xIRrwmXiFC5cmX4+flxaZcuXeI5UDIUR2RkJOzs7Hii4tatW6hXrx7EEkKdxVd5vkiS5EREXFyD+De3pfalpaUFc3PzLBdTU1Ooq6vnxeExsoGPjw9Wr16NY8eOSQnF0pWqwaDLIoTEpHBpyuaXllcwnxElIrOojS4uLmjWrNk/7T8yMhJHjx7Fvn37cO/evaw3+D82NjY4cuQIatasybepggWaljOHT0Ak3jVbg9EdGyH6Z5r/wr1797Bp0yaMGDFC1i6VGnN9LehUcIaWvRPiXt2EdoXGUC1SHN8PTkHklc1QNSkBzZK1EFZTFZJKFnkiuB49eoTv37+jdevWANKEx+9CpHLlyv/8+2DkHEZGRpg2bRomT57MpU2ePBn37t2DT0AkPr3yRUpoADRKVEHCJ1+IoyOgYmgJwyb/QaRtCJGOIdb1b4QWtcpCR0d64jqGcpOamopTp05h9erVGT5rVVVVcfzAHpQtV16m3xAjA3InzEnOkt+DnmUUKfT3pVixYtS6dWv6/PmzXPtMSkqiU6dOUYcOHUhNTS3L/f+5dOzYkX78+CFXXXv37uVtq6OjQ1++fPmHM6IYUsUSclzoJRXUrUjbKVLnx8zMjAYOHEinT5+m2NjYXLNp3759pKenR2/fviUiooYNG/LsOHDgQK7Vzfg7EhISpCKiHj9+nE77fiOL/msJAKkYWRMAUrcsQ2bdFpJx6wnc7+207zdFHwIjm/z48YOWLVtGxYoVy/LZ6u7urmhzlQoWgVVJ8PPzk0scWFpa0p07dzLdl0QiIW9vbxo+fDgZGRlluj+BQEBNmjSRermpqanR+vXrSSKRPwqjRCKhZs2a8fbTqlWrbO1DWUiPMPunIDGo2zPDc6mhoUEtW7akzZs307dvOfsicXd3JwBUtmxZ8vLykgrxnZKSkqP1MXKG3bt3865VqVKl6NbrYLIaukPmb6hIu6ncb+3eh3BFm8+Qk3fv3tHIkSNJW1tbrud4+fLlc2W6gPyMvO/v/Nfxn884dOhQlmWcnZ3x5MkT1KlTR2Z+QEAA5s2bh9KlS8PJyQkbN25EZKRsJ8sKFSpgyZIl+PLlC65cucKLOmpnZwdvb2+MGDEiW0MFBQIBtmzZAi0tLS7twoULuTppWG7hUsECm3pVg7k+37m3dIt+qO/SRuY2iYmJ8PDwwNChQ2FtbY3q1atj9uzZePz4sVQgu+zy/v17AMDr16/RsmVLXt6ECROgosJ6UpWRXr168SZDe//+PZ5fPQkLE2OpsurFKkLLvjYESPMbcLAxykNLGX9LVFQUli1bhu3bt8s1MlEgEGD79u3Mv+dvyRtt9G/k15YRiURCtra2mSrpadOmyZxX4sePH7R161aqW7dulmrczMyMxo0bR76+vlKtFY0bNyYA1KVLl38+f6tWreLVa2JiQuHh+fMrT9Z8HfHx8VSzZs1sdXdZWlqSm5sbJScn/5UdDg4OMverpqZGHh4edPnyZTp79ixdunQph88A41+5ePGi1H143PstAb/NMyUQkkX/tYV2XpKCQHh4OC1ZsoTMzMwyfRaMHTtW0aYqJaybRgnw8fHJ8IdrYGBA586d45VPTk6ms2fPUqdOnUhdXT3TH76mpiZ1796dLl68mGlTfsWKFWnTpk050qWSmpoq9fLs06fPP+9XmQgMDCQrKyu5hIhQKKShQ4dSaGjoX9eX0SR/vy8qKip0+fLlHDxKRk4gkUjI2dmZd61mz55NWjq63LpOZRc2U24B4OTJk6SpqZnhPVqiRIlc9S3LzzAxogSMHz9e5g+3WrVq9PHjRyJKe6A9ePCARo4cSUWKFMn0pSQQCKhRo0a0a9cuuc/FmzdvcvSYnj9/TioqKjy7PD09c7QORfPo0aNMHzwAyMLCgp4+ffpP9URERMglevbu3ZtDR8bIaR49esT/SNDSJmMTcwJA2jq6tPvqUzZTbj5GIpHQ0qVLpWZV/3NhHwsZw8SIghGLxTK/sAcPHkwJCQn06dMnmj9/PpUuXTrLl1HZsmVp4cKFco+0yW1mzJhR4L8Kjh07luV1adWq1T85tN6/fz/LOhYuXJiDR8XIDbp168ZvMdNIaxkp3nIoaw3JxyQnJ9OgQYOk7kl9fX3eer9+/RRtqlLDxIgC+N0PYcPBs7wfrIaGBm3cuJG2b99ODRo0yPIlZGJiQqNHj6ZHjx4p3aiVxMREKlOmDM/ecePG8coEBwfne6/yuXPnZnmd9PX1aceOHX91jfbv35/pvocOHap0154hzU4Pb4KQ31oo0jel4hNPMT+RfMqPHz84f7vfl/Lly1NAQAAZGxsTkOYnFBERoWhzlRomRvKYi35B5LjQixu+p1O1Ja9Jv3nz5qShoZHpy0ddXZ26dOlC58+f/2uHyLzi9u3b/K9BoZAePHjA5ffp04e8vLwUaOG/I5FIpL56M/Llad68ebZbrtKH9cpa2rRpI9OxmaFcpMeu0a3uyrt+alZlqfj/nVYdF3qxbpp8hL+/v9THVvo9/vPnTyIi6tChAwGgY8eOKdha5YcN7c1D/pyPQiJORdyr/4dQF6kgODgYnp6eSExMlLl9/fr1sX37dnz//h1HjhxBq1atlH5SrLp162L48OHcukQiwaBBg5CcnIy7d+9i7969uHjxogIt/HcEAgF27tzJi1A7d+5crF69Gpqamryynp6eqFChArZu3Sr3cN8PHz7ITK9VqxYOHTqUY3MVMXIPn4BIBEclQr92NwjU0oa+C1TVoVXKEUQEgnLMd8SQj3v37qFWrVp48+YNL3348OE4f/489PX1AQANGjRA+/bt0bFjR0WYWSBhYuQfEUsIc869QvrrJ+HzMwRtHQxK+v+4dLHsya1Kly6N+fPnIyAgADdv3sTAgQO5H3p+YdGiRbC2tubW/fz8sHjxYowcORIA4OHhoSjTcgxNTU2cOXMGVlZpc9XY2NhgzJgxeP78OerXr88rGxMTg//++w9NmzbFp0+fstx3eoyR3ylZsiTOnTvHi+nCUF5CY9I+MERa+jCo0w16Dh1gOXQX9Gt15MXySS/HUF4OHToEZ2dnhIf/mqlcIBBg9erVWL9+PS/mj4uLC9avX5+teE2MzGFi5B9J/zJKR6SpC3F0mMyyxsbGGDlyJB48eIDXr19j+vTpvKBk+Q09PT1s2rSJl+bu7s7NSPz69Wu5XsrKjoWFBc6ePQtNTU0UL14cQJpouH79OtavXw9tbW1e+atXr6JChQrYsGEDJBJJhvv9s2XExMQEly5dgomJSc4fBCNXMNX9FTxPz6EDDBsNgIqW9GRgv5djKBdEhLlz56JHjx5ISvo1yaG2tjbOnDmDMWPGSIkOe3t7WFpa5rWpBRomRv6RP7941ExtoVqk+K8EkQq0StfBtFU7ERQUhHXr1sHBwaHAKOrWrVuja9euGebn966adKpVq4Z9+/bxxKNQKMSIESPg5+cHZ2dnXvm4uDiMHDkSzs7OMmdPjoyM5EXR1dLSwoULF2BnZ5drx8DIeRxsjGChr4GM7mYWdTVniI6O/udox7JISkpCnz594O7uzku3srLCnTt34OrqmuN1MmTDxMg/IuuLR6diY6hbl4NR85GwHrkfJu2morVrG6ipqSnAwpwnNDQUo0ePRrt27VCzZk14eXllWLagiBEA6NixI0xNTaXSbWxs4OXlhc2bN0vNxHrz5k1UqlQJa9asgUQigVhC8PaPwA6PXzN+ikQiHD16VGr2ZIbyIxIK4O5aDgCkBEn6urtrOTZbqwzS74UzTwPh7R8BsSRjsfH06VPY29tj8uTJuH//fqYtjvISHh6OJk2aYP/+/bz0atWqwcfHB1WqVPnnOhjyI6DckJs5THR0NPT19REVFQU9PekmUEUilhDqLrmGkKhEzm+EiLiWDwEAc30N3HFzLlAPpJMnT6JXr15ISEjItJyWlhYiIyMLzXwNnz9/xuDBg3HlyhWpvPLVHKDScDh+qhZB7MvriDi/AgAw2n0Z1syemNemMnKQSy+CMefcK16XrYW+Btxdy8GlgoUCLVNO/uZ81atXD3fu3AEAWFpaol27dujQoQPq168vl8O/WELwCYhEaEwi4kO/YubwXlKtlm3btsWBAwekul4Zf4+8728mRnKA9NE0APD7yUyXHpt6VSuQD6SHDx/C1dUV379/z7Tc5cuX0bRp0zyySvEQEXbu3Inx48cjOjqalydQUYNBvV4QJ8Uj+t5h6NfuBsN6vQrsb6Qw8fvLzlQ3rWumIH2A5BTpz8s/XzxZPS8vXbqEFi1aSKUbGhqiTZs2aN++PZo1ayY10i29znTxk/D5GcJPLYQkiT/53cSJE7F48WI2ii2HYWIkjymsX0afP39Gq1at8PLlywzLjBs3DitXrsxDq5SDb9++4b///pM5qkioqQcN2xoo0mochAJBgWw9YzD+JL0l+ffn5M/b+yGOjQSEQgiEImhrqqOHow3UVFWhoqIC1f//VVFRwbx58xAbG5vh/rW0tNCiRQt06NABrVq1gr6+Pk/8xD6/jAjPDYBEzG0jFImwaeNGDBkyJDcPvdDCxIgCKKxfRlFRUejSpQsuX74sM7906dJS4/YLC0QE9xWbsGDGZN6XmJp5KZj3WgaB6NdwwUODHeFkJz0FPYNRUPD2j0D3bfd5aUE7hiMl/EuO16Wqqgpn58Z4p1UWKVbVAIEQQVuH8O5Dgbo2yvScBb9tkwrFs1oRyPv+Vskwh5FtREJBoXyZ6Ovr4/z58xg1ahS2bNkilf/27Vt8/PgRtra2CrBOsQgEAlRv0hYWATqIvLwRCR8eQKRvBtOu83hCBGCxKBgFH1m/cUlSfK7UlZKSAk/PSwAuARBA3boc9Jy64OetvYBEDBV9M5h0ckd8kWLwCYgslM9uZYKJEUaOoKqqik2bNqFkyZKYPHmy1DC8ixcvYsSIEQqyTrGY6mpARdcYJh1mIP71TYi0jSDS0JFZjsEoyMj6jVMGgSFzAm1dfZBlRWjaVoOGTTWo6BaBUEMHcc+vwKTDDIi0DQCwDwFlgIkRRo4hEAgwceJE2NraSo20KcxiJD0WRUhUIrTLNZTKTx9xxWJRMAo6v98L6Z8r5n1WIGjHCAAEwzo9ULRyXezuVx0kESMlJQWpqalITU3Fz58/0blzZ6SkpGS4f4FAgBo1asDFxQUuLi4QG9uh965HvDK6lZtDp2ITCIS/HFXZh4DiYWKEkeN06NABN2/e5I20uXbtGm68CkRUMgqVPw3wKxbFsP1PIIDsEVcsFgWjMCDrXlDVN4NOuYaIfXYJP27sQhXtKNjZdpLyL1i4cKFMIWJiYoLmzZvDxcUFzZo140UwFktISvwA4IQI+xBQHpgDKyPX+HOkjWnnOdC0rQ6gcIw0+pPCOuKKwfiTP++FpMA3CNn/K9aOjY0NDh48CEdHRwDAjx8/YGNjg6ioKIhEIjg5OXGtH1WrVoVQmHH8zsIaekFZYKNpGErBCe+36NWjOxI/+UK3ehsYNUkbPldYHwSFdcQVg/Env98LJjrqGOhajzfqTiQSYe7cuXBzc8OWLVvw5MkTtGjRAo0bN4aBgUG26mIfAoqDiRGGwkmPKRAUGYuIK5uQ+Pk5rP/bxuUX1Oi0DAYj+yxduhRubm5S6Y0aNcK+ffu4mbP/FvYhoBjkfX+zuWkYuQY3o7FQBIFQBBVtfSRHBnH5BCA4KhE+AZEZ74TBYBQKevfuLTP66fXr11GpUiWcPn36n/afHnqhbRUrONkZMyGiZDAxwsg10ofLRXsfRayvB5IC3+DnjV2QpCTJLMdgMAovFhYWcHFxkZkXGRmJ9u3bY9iwYVnOh8XInzAxwsg1THU1EPv8Cn7e3selJbz3Rszjc1LlGAwGo3///pnmb968GTVq1ICfn18eWcTIK5gYYeQaYa+8EeG5jpemYVsdejXbAUjzGbFgw+oYDMb/cXV1hbFx5pFQX716hZo1a2L9+vVSwRUZ+RcmRhi5woMHD9C9W1dAIuHS1CxKwaTtFAhEKiy+BoPBkEJNTQ09e/bMslxSUhJWrlyJPXv25IFVjLyAiRFGjvPu3Tu0atUK8fG/5pzQMLaCaafZEKqlTe9trq9R6Ib1MhiMrMmsq0ZFRQWnTp1CZGQkPn78iH79+uWdYYxchUVgZeQoISEhaN68OSIiIrg0U1NT3Ll7E+ECAzasjsFgZEqVKlVQtWpV+Pr6SuWlpqZi7969aNu2rQIsY+QmrGWEkWNER0ejZcuW+PTpE5emo6MDDw8PlCppx4bVKQCxhODtH4EzTwPh7R8BsYT1sTOUn99bR/T19XkRVk+dOoVVq1YpwixGLsKCnjFyhOTkZLRs2RJXr17l0lRUVODh4YGmTZsq0LLCC4s6ycivREREwNLSEsnJyVi6dCmSk5MxY8YMLl8kEuHGjRuoW7euAq1kyAMLesbIMyQSCfr3788TIgCwa9cuJkQURPp8HL8LEQAIiUrEsP1PcOlFsIIsYzCyxtjYGG3atIGxsTGGDRuGqVOnomXLlly+WCxG165dERoaqkArGTkJEyOMf2by5Mk4ePAgL23p0qXo1auXgizKGfJrF4dYQphz7hVvUrDEb69Aqclc2pxzr/LN8TAKJ/3798e4ceOgo6MDoVCIffv2oXjx4lx+UFAQevToAbFYrEArGTkFc2Bl/BMrV67EihUreGljx47FxIkTM9gif5Cfuzi4MPz/Rxwfhe8Hp0Cgqg5Nu5rQsq+NQNsa8AmIhJNd5jEdGAxF0axZM143jJGREY4dO4Y6deogJSUFAHD16lXMnj0b8+bNU5SZjByCtYww/ppDhw5hwoQJvLSuXbtixYoVEAjyr4Nqfu/i+D28PqWmIObJeYAkoOQExL++hfAzi/FtXQ+MG9wT+/fvx8+fPxVnLIORASoqKlI+BjVr1sTq1at5afPnz8fFixfz0DJGbsDECOOvuHr1Kvr27ctLa9SoEfbs2cPzfM9vyOriiH54GolfX+SbLo708PrJ3/0RvHccEj89lSpDqcl4cN0TvXv3hqmpKVq2bInt27cjLCwsj61lMLLHsGHD0KNHD15ar1698PnzZwVZxMgJ8u9bg6Ewnj59ivbt23NNpQBQqVIlnDp1Curq6gq07N/5s4sj2ucUflzbjtCjsxD/4UG+mGm4qrUuxI+OInjveAjVtKBfuxu0KzaFUFO2J3tKSgouXryIwYMHw9zcHM7OztiwYQOCgoJklmcwFIlAIMCWLVtQtmxZLi0yMhKdO3dGUlJSJlsylJm/EiMbNmxAiRIloKGhgVq1asHHx0eu7Q4fPgyBQIB27dr9TbUMJSAgIAAtWrRATEwMl1a8eHFcvHgR+vr6CrQsZ/i9iyP+nTd+3NgJIK0lIezkAsT6eUmVUyZevHiBOrWd8O3qXkAihm61ltC0rY4iLcfAeuQ+mHVbAN2qrWBkYiZze4lEguvXr2PkyJGwsrJC7dq1sWLFCgQEBOTxkTAYGaOjo4MTJ05AW1ubS3v48KFUtzEj/5BtMXLkyBGMHz8e7u7uePLkCSpXrozmzZtnOcTq06dPmDhxIurVq/fXxjIUS3h4OFxcXBASEsKlGRkZ4dKlS7C0tFSgZTnH7zMIqxhaQKRt+CuTJIjwWI2oByeUbqbh1NRULFq0CNWrV8eTJ08AAPpGxrCt6cyVEQhFsKlUC0f3bkNYSBDu3LmD8ePH80Yo/Im3tzcmTpwIW1tbVK9eHQsWLMCbN29y/XgYjKwoW7Ystm3bxkvbsGEDDh06pCCLGP8EZRMHBwcaMWIEty4Wi8nS0pIWLVqU4TapqalUu3Zt2r59O/Xt25fatm2brTqjoqIIAEVFRWXXXEYOERsbS7Vq1SIA3KKpqUn37t1TtGk5SqpYQo4LvaiE23kq7naerIbuJKGmHu+4AdD4CRNIIpEo2lwiInr9+rXUtQFA06ZNo1SxhO59CKfTvt/o3odwShVL2yyRSOjRo0c0depUsre3l9qPrKVcuXI0c+ZMevr0qdKcB0bhZMSIEbzfpra2Nr169UrRZjH+j7zv72yJkaSkJBKJRHTq1Cleep8+fahNmzYZbjdr1ixq164dEZFcYiQxMZGioqK45evXr0yMKJCUlBRq1aoV74YXCoV09uxZRZuWK1z0C6ISbuc5QWLWa7nMF3K/fv0oJSVFYXampqbSihUrSENDQ8o2oVBInz9/zvY+JRIJ+fn50Zw5c6hSpUpyCRM7OzuaNGkS3b9/nwkTRp6TmJhINWvW5P0my5YtSzExMYo2jUG5JEYCAwMJgNTX8KRJk8jBwUHmNrdv3yYrKysKCwsjIvnEiLu7u8yHHhMjeY9EIqEBAwZIXYtt27Yp2rRc5aJfEDku9KLi/xckKsbFZP4mXV1dKT4+Ps/t+/DhA9WtWzdDgZDd1seMeP/+PS1evFjqYZ/RYm1tTaNHj6YbN25QampqjtjAYGTFp0+fyNDQkPdb7NGjBxPHSoBSiJHo6GgqUaIEeXh4cGmsZSR/MXPmTKkXzpw5cxRtVp7wexfHwNGTM3wB161bl378+JEnNonFYlq/fj1paWllKgo8PT1zvO7Pnz/T6tWrqV69eiQQCLIUJqampjRkyBDy9PSk5OTkHLeHwfidCxcuSP0GN27cqGizCj1K0U3j6+tLAEgkEnGLQCAggUBAIpGIPnz4IFe9zGdEMWzatEnq5h4yZEih/Np48eJFpi/eSpUqUVBQUK7aEBAQQM7OzlmKgJIlS5JYLM5VW4KDg2nz5s3UtGlTEolEWdpkYGBAffr0oTNnzlBCQkKu2sYovMyYMYP3u1NTUyMfHx9Fm1WoyRUxQpTmwDpy5EhuXSwWk5WVlUwH1oSEBPLz8+Mtbdu2JWdnZ/Lz86OkpCS56mRiJO85deoUCYVC3o3dpk0bhfpIKBKJREKlS5fO9IVrY2ND79+/l9r258+f/1z31q1bSUdHR66ukpUrV/5TfdklIiKCdu3aRa1btyY1NbUs7dPR0aGuXbvSkSNHWL8+I0dJTU2VEuzFixeniIgIRZtWaMk1MXL48GFSV1en3bt306tXr2jIkCFkYGBAISEhRETUu3dvmjJlSobbs9E0ys/t27elnCJr165NcXFxijZNoUyfPl2uroknT57wthszZgw9fvz4r+sNCQmhJUuWUNu2bcnExCTT+jU1NSkyMvJfD/WviYqKokOHDlGnTp2y7EoCQBoaGtS2bVvau3dvnnV1MQo2379/J0tLS97vrFWrVrneWsiQTa6JESKidevWUbFixUhNTY0cHBzo/v37XF6DBg2ob9++GW7LxIjyIEtcvHz5kgwMDHg3cpkyZdiXBf3qdpTny//69evcdnZ2duTk5JQjD0OxWExNmjTJsO4BAwb8cx05RVxcHJ08eZJ69epF+vr6WZ43VVVVcnFxoa1bt1JoaKiizWfkY27fvi3VfbhgwQJFm1UoyVUxktcwMZI7DBgwgBvlRET09etXKlq0KO8GtrS0pE+fPinQSuVBIpGQra2tXIJEVVWVTp06Re/evePSdu3a9c82zJs3L9N6/6UFJjdJSkoiDw8PGjhwIBkbG2d5/oRCITVs2JDWrVtH3759U7T5jHzI8uXLpX5TV69eVbRZhQ4mRhiZ8vHjRxKJRLRixQoiIvrx4wdVqFCBd/Pq6enR8+fPFWypcjF5csajamS9UH9vxTAxMfmnrojTp09L1VGyZEnu/1q1auXcgeYiKSkpdO3aNRoxYgRZWFjIdS4dHR1p2bJl9PHjR0Wbz8gnSCQSat++vVQ3amBgoKJNK1QwMcLIlOHDh3NdMPHx8VS/fn3eTaumpsbramCk8eDBgwxfmEWKFCFzc/NMX6qjRo36q3r9/PykHFjbtWtHgYGBnNPo3r17c/hocx+xWEx3796lCRMmUIkSJeQSJlWrVqV58+axKJuMLPn58yfZ2dnxfj9169ZlQ83zECZGGBkSEhLCc1CtUaMG72YVCAR09OhRRZuplEgkEqmurD/FRpkyZTJtLXn69Gm26gwPDycbGxvefipUqEDR0dFERNSvXz8yNjbO90NmJRIJPX78mKZNm5blyKX0pWzZsjRjxgx68uSJ3EPOw8LCmLNsIcLX11fKIX/ixImKNqvQwMQII0OmTp2a6QN+7dq1ijZRqRk7dix3rho0aCAl5AYOHJjp+a1bt67cL87k5GSpoYpGRkbk7+/PlXn27Bm5ubnl1uEqjJcvX9LcuXOpcuXKcgkTW1tbmjhxInl7e2fqLBwYGEhFixZl/gOFiB07dkj9Xk6ePKloswoFTIwwZPLz50/S05Oe+C19KYgvtZzmzp07BKT5gERFRVGfPn3keln+vuzbt0+uukaNGsXbTiQSyXyJFvR4He/fv6clS5bInBBQ1mJlZUUjR46k69evS4Wll0gkXJfXmDFjFBLOn5H3/DmthZ6entyBNxl/DxMjDJksWbIk04d4hQoVaMKECeTp6cke0hkgFovJwsKC1q9fT0RpAs/KyipbYsTc3DzL3/O2bduktlu3bl1eHKJS8+XLF1qzZg3Vr19frrD0JiYmNHjwYLp06RIXaLF69eq8rp5Hjx4p+KgYuU18fLzU5I9VqlRhz7lchokRhhQJCQlZOlimLxoaGrRs2bJCGfpdHlavXs1zgrtx44ZcL8bfl3HjxmW4/9u3b5Oqqiqv/ODBg9n1+IOQkBDasmULNWvWjFRUVLI85wYGBtS7d2+qUqUKL11FRYXmzJlTaCMMFxbevXsn1TI8aNAgRZtVoGFihCHF5s2b5XpJtmjRgueTwJBGliiYOHEi7zxqa2tTkSJFMjzPIpGI/Pz8pPbz+fNnMjU15ZWtW7eu3NMnFFYiIiJo9+7d1KZNG1JXV8921xkAcnBwoDdv3ij6UBi5yIkTJ6Sue07EAGLIhokRBo+UlJQsA3ZZW1vTiRMn2Nf3X5KQkCAVq6V169a0evXqDLtxGjZsSBKJhJsh+Mi992RfriKvTNGiRen79++KPrx8RXR0NB0+fJg6d+5M2tra2RIkmpqatG7dOhY+vAAzYcIEqZbg7I5yY8gHEyMMHocPH87w4auiokKTJk0q8E6QecHTp0+luld27dpFiYmJtGXLFqkhugDIbelGclzoRcUmnyOtMvWkXox/znXDyB7x8fF0+vRp6t27t1xh6dOXpk2b0tevX3n7SheNp32/0b0P4ZQqZsI9P5KcnEx16tThXe+SJUv+86SWDGmYGGFwSCQSqT7y35v/ZXUVMP6eP52Edf/X3n3HNXW9fwD/JIEQQLYiiBQEpYqoFCcqUpW6EVsHqAytq2pbkbrHj/q1WtyjdWsRJ36lWhdSrHVXpQ6s1lUUxcEQlaWsJPf3h19uvQSQYJKbhOf9euWl5+Tk3icXyH1yzrnnmpmxK4eWlpYy27Zt46xFIqpjzTiG/5ex7KJ4Vc7MJet5fjf65dq1awprTlT1sLS0ZHbt2sUwDMMcvf6U6bDwN8Zp+mH20WHhb8zR6095flekJh4/fqxw48mBAwdSz7CKVff8LWAYhoGWy8vLg4WFBXJzc2Fubs53OFpPJmeQlPoCWflFsDWT4MWdJPTr24fTpm7duliyZAnCwsIgEAh4ilQ/yWQydO3aFWfOnGHrfHx8cOLECYhEIrbNzz/vw8jwmXidfg/GTTqg8J8LnO1YeAeimf8YnJ3eDSIh/Yze1927d+Hr64uMjAylX9ulV3+kug2F0NiMU1/2U1kX7IVeHvYqiJJo0vHjx9GjRw/I5XK2bsWKFQgPD+cvKD1T3fM3JSN6JuFGOuYduon03CK27sV/ZyE/9S+2PHbsWHz//fewtrbmI8RaITU1FS1btkRBQQFbt2jRIkybNo0tn7/3HEEbz6Pw/iW8PL4J0pwMgHnzoWjcuD3qfTYbAoEQu8d0gLerjcbfgz65d+8efH198eTJkxpvQ2hqBTPP3rDsPIxTLwBgZyGhpFFLlJaW4tGjR3BxcalW+wULFmDOnDls2cDAACdPnkSnTp3UFWKtQsmIDigqKoJEIlHZ9hJupGP8jit4+wda/OQWMnZMBQC4NG2OndGb0aFDB5Xtk1QuOjoan3/+OVs2NDTEn3/+iVatWgEADiQ/waTYZAAAwzAoTLmI50dXQ2RqCbvgpRAamQAAVgV5IsDTQePx65MnT57g2bNnKCkpQWlpKfvv2/+v7N97GTn4b9IDFN6/jJKMf2Ds1hH1/KdAYCDm7IOSRtV5u3e3bh0jgAGyXxXD1kyCdo2s35n0de3aFc+fP0dAQAAGDBgALy+vSnuA5XI5+vXrh6NHj7J1Dg4O2LDvN0jFZtXeJ6kYJSNa7Nq1a1i2bBk8PT0RERGhkm3K5Aw6fHsAj9MeQpqTAWlOOkzcOuLlyWgUPbwGK58QNPl4IM7N+oT+qDSEYRh89tln+OWXX9i6Fi1aICkpCRKJBOfvPcfQTdyhGWluFhhGDkNLO7aOTnL8OpD8BGP+sw7P9i9g6wxtXWA3LIpNGAFKGlWlot7dt9lbSBDp717lsNjvv/+O7t27s+WGDRuif//+GDBgAHx9fSEWcxPJ58+fw8vLC2lpaWydxMkTtkPmQSAUVWufpGKUjGgZhmGQmJiIpUuX4rfffgMA3L9/H40aNar2NqRSKR49eoT79+/j3r17uH//Pvu4+08K8vNyOe0tuoSi9NlDWHX9HAZmb05mdGLTrGfPnsHDwwNZWVls3ZQpU7BkyRLI5Aw6L/odGblFqOiPkLr/tUPcicsY0tsXTPErtq5Oyx6w6f01px39bb2/inp3y6vOPB2GYdC5c2f88ccfCs+Zm5ujT58+CAgIQO/evWFhYQEASEpKQqdOnSGVlrJtLToOhaXPcJob9B6qe/420GBMtVJxcTF2796NZcuW4caNG2x9+/btK0xEcnNzFRKNsvLDhw8hk8mqvW+m+DXq9Z/KqcvKr/jbBlGPevXqYcuWLfD392frli1bhn79+sHX1xeR/u4Yv+MKBADnA7jswy/S350SER4VFRVh4TdjOImIoW0jWPmNY8tlSWO7RjQH633I5AzmHbrJ+Tt4/usaSHMyIHudAwAQmVpBYCCGQCDE8CMG6N7MDiKRECKRCEKhkH2UTRSvSF5eHmJjYxEbGwtDQ0N07doVAQEB6NvPHw17f4EHh35g2+b+EQsjh6YwdmkNAYB5h27iE3c7+ptUA0pGlFT+SpXKxhJfvnyJDRs2YPXq1UhPT1d43s3NDZs3b1bo5Xjx4oXqYi14rlBna6a6OSqkevr164cxY8Zg06ZNAN58awsNDcVff/2FXh72WBfspdAtbUfdwlohPDwcV69eZcsCsTHqBcyA0NDoTfl/9ZQ0vr+k1BcKQzPFT26h9NkDtlyKVPb/rwHsvYH3UlpaisTERCQmJmLixIkwrN8YhvWc39ong+LHN2Hs0hoMgPTcIiSlvqAeMDWgZEQJFY1llh9LTE1NxcqVK7Flyxa8evWqsk1h+/bt2L59u0riMjU1hYuLCx5LzSAzrQeRpR0MLe1hWNeRbUPf3vi1fPlyHD9+HPfv3wcApKWlYdKkSdi6dSt6edjjE3e7aiW5RHN27NiBDRs2cOoaD5qKEut/54VQ0qg6FfbaMnLFOjUqzUz53/8EgFAEm55fok5LP04b6l1WD0pGqqmyscyM3CKM33EF4a0E+OOXGMTFxXGuWVcVBwcHuLi4wNXVFS4uLpyHra0tBAIBGyNAXf7apk6dOti+fTt8fHzY34+YmBj4+/tj4MCBEAkF9G1Li/z9998YN24cp27SpElYtvxbShrVhO9eW2dXN7ywbg6JaxuIjM0hEBnA0MZRoR3fceormsBaDWUTDct3ITKMHIUpfyIvaR+KH//9XvswMTFRSDLKEg9nZ+dqXwJcnd4bwp/Zs2dj4cKFbNnGxgbXr1+HvT39bLRFQUEB2rVrh1u3brF1HTp0wKlTpxSuwiCqU9mE7jenKAZgGICRo/jpHTw7sAjyVy/fa38SiQTdunVDnz590KdPH3zg5EwTytWArqZRofKXYMqLXyP3/H+Rf+1XMEX5NdqmgYEB1q5di+bNm8PFxQX169dX2Uqo1Z3XQjSvpKQEHTp04MxD6NOnDw4fPkwr4WoBhmEQHByMXbt2sXXW1ta4evUqPvjgAx4jqx0q6919mwCAtOAF6pxZhdt/XVZq+yKL+qjbrAMmhAzC1JEDYWxsXK3909U0NVfd87dQgzHprLfHCF+e+AmPVg9D3sU4MEX5sOk/Hda9voZ520/RunM3NGrUqFonFalUitu3b6Njx46ws7NT6YmorMs/wNMB3q42lIhoEbFYjB07dsDIyIiti4+Px8aNG3mMipTZsGEDJxERCATYuXMnJSIaUjah286i8p5gOwsJNn3hh6sXz2LEiBHv3qhAiDpefdFg9Do4jNsMY98xiE6zwql7OdXev52FhBIRNaOekWp4u2ckL2k/Xp7Ywj5n1X0MzNsEAPh3nYHCwkLcuXMHt2/fxq1bt9jH3bt3UVJSwr5WIBDg5MmT6NKli2bfEOHdqlWrOPe/MDExQXJyMpo0acJfULXc5cuX0bFjR87f6Jw5czB//nweo6qdqrsCK8MwWLlyJaZMmfKOuXoCOEyIhoFZ3f+Vqh5yod5l1aFhGhV6eyyz5PljPN38BfucxPkj2AXOr9ZYolQqRWpqKpuc3L59GyUlJYiOjqax6FpGLpejR48eOH78OFvXvn17nD17FgYGNK9c016+fInWrVsjNfXfS0e7deuGxMTEKtesINohMTERgYGByMnJqfB5iUsb1B/8rUI9LVSnfjRMo0IioQCR/u4AAENrBxhY/ttVV/ToOuTFr6t1pYqBgQGaNGmC/v37Y/r06YiOjsbOnTspEamFhEIhoqOj2dUfAeDixYuIioriMaraiWEYjBw5kpOI2NvbY9euXZSI6IgePXogKSkJzZo149Qb2jhCYGAEoaQOKvreTZfpag9KRqqpbCzR3tIYxq5t/31CJkWocz6NJRKlOTo6Yu3atZy6efPm4dKlSzxFVDstW7YMBw4cYMsikQixsbGoX78+j1ERZTVp0gQXLlxA37592TqTpj5wGP8TCu9fRmn2Q4XX0GW62oOSESX08rDH2endMP+rUE59+nXF+x8QUh1Dhw5FYGAgW5ZKpQgJCUFhYSGPUdUeZ86cwYwZMzh1CxYsoHlcOsrc3BwHDhzAtOnTAQDyonyUvngCpigfhff+ZNsJ8GbJA1oEUntQMqIkkVCAL4L6oU6dOmxdfHy8WhY6I/pPIBBg7dq1aNCgAVt3+/ZthRMkUb2srCwEBQVx7vfUr18/TJ06tYpXEW0nEomwKCoK0xetASMtQWHKRQBAYcqbZIQWgdROlIzUgJGRET755BO2nJ6ezlk3ghBlWFtbIzo6mlO3evVqHDt2jKeI9J9MJsOwYcPw9OlTts7JyQkxMTEQCuljUR9ETZuA6LUrUXr/TRJS/PQ2ZK9z6TJdLUV/dTX09rgkABw5coSnSIg+6NGjB7788ktO3YgRI1R640Tyr//85z+cK5nEYjH27t0La2vqttcnnrYGKHyW9qbAyPG5Uy7OTu9GiYgWomSkhvr06cMpUzJC3teiRYvw4YcfsuWnT59i4sSJPEaknxITExXWDlmxYgXatm1bySuIrjp06BCnfOfPUzQ0o6UoGakhe3t7tG7dmi0nJSUhMzOTx4iIrjMxMcGOHTs464zExsZi9+7dPEalXx4/fozhw4dzLvMMCgrC+PHjeYyKqMvBgwc55YSEBJSWlvIUDakKJSPvofxQzdGjR3mKhOiLNm3aYO7cuZy6CRMm4PHjxzxFpD9KS0sRGBiI7Oxstu7DDz/Exo0b6b5Aeujly5c4c+YMpy43Nxfnzp3jKSJSFUpG3kO/fv045cOHD/MUCdEns2bNQrt27dhyTk4ORowYQVdsvacZM2bgjz/+vQzf2NgYcXFxMDMz4zEqoi5Hjx7lXClVhj6ntRMlI++hdevWnIWREhMTOfe1IKQmDAwMsH37dpiYmLB1x48fx48//shjVLpt3759WL58Oadu/fr18PDw4Ckiom7l54uUoWREO1Ey8h6EQiF69+7NlvPz83H27FkeIyL6ws3NDcuWLePUTZ8+Hbdu3eIpIt2VkpKCkSNHcupGjx6N0NDQSl5BdF1paWmlw+Z37tzBP//8o+GIyLtQMvKeaKiGqMu4ceM4yW5RURGCg4Op900JhYWFGDx4MPLy8tg6T09PrF69mseoiLqdOXMGubm5lT5PVz9qH0pG3tMnn3wCQ0NDtky/5ERVBAIBtmzZwln74sqVK3RLeyVMmjQJycnJbNnc3Bx79+6FsbExf0ERtSt/FU15lQ3hEP5QMvKezM3N4ePjw5bv3r1LXYBEZezt7bFx40ZO3cKFC3H+/HmeItId27dvx6ZNmzh10dHRaNy4MU8REU1gGOadycjp06er7DkhmkfJiAqUH6qh3hGiSgMHDuTMb5DL5QgNDUVBQQGPUWm3v//+G1988QWnLjw8HJ999hlPERFNuXnzJlJTU6tsI5VKkZiYqKGISHVQMqICtDQ8UbfVq1fjgw8+YMspKSmYMmUKjxFpr4KCAgwaNAivX79m67y9vbFo0SIeoyKaUjYEY2ZmpvDZ3KVLF9ja2gKg+X3ahpIRFXBzc0OTJk3Y8qlTp5Cfn89jRETfWFhYICYmhrM414YNGyjxLYdhGIwdOxa3b99m62xsbLBnzx6IxWIeIyOacurUKcyZMwcPHjxQuN/TgAEDkJqaiqVLl+Ly5csVrkNC+EHJiIq8nYGXlpbSHVeJyn388ceIiIjg1I0aNQrPnj3jKSLts379es7y+QKBADt37oSjoyOPURFNio2Nxfz58yu86aFAIICJiQm++eYbXLx4EVKplIcISUUoGVERGqohmvDdd99xFurKzMzEuHHjOPdaqa0uXbqE8PBwTt2cOXPQs2dPfgIivLCwsGD/X9XfhampKYyMjDQREqkGSkZUpEuXLqhTpw5bjo+Pp+W7icpJJBLs2LGDczn5/v37sW3bNh6j4t/Lly8xePBgzhos3bt3R2RkJI9REb6VT0boHkTai5IRFRGLxejRowdbzsjIwJUrV3iMiOirVq1aKaw18tVXX+HBgwf8BMQzuVyOsLAwzvu3t7fHzp07IRKJ+AuMEFJtlIyoEA3VEE2ZMmUKOnfuzJbz8/MRFhZWKyfkLV26lLOIlUgkwp49ezj3jSK1E/WM6A5KRlSoT58+nDJdOkbURSQSYdu2bZyhwdOnT2PFihU8RqV5p0+fxqxZszh1Cxcu5CxESGovSkZ0ByUjKmRnZ4c2bdqw5UuXLiEjI4PHiIg+a9SoEVatWsWpmz17Nv766y+eItKszMxMBAUFcXqD/P39af0VQnQQJSMqVn6oprI7RxKiCiNHjkRAQABbLikpQXBwMIqLi3mMSv1kMhmGDRuG9PR0ts7Z2RkxMTEQCuljjbxBPSO6g/5qVYzu4ks0SSAQYOPGjeyqkgBw/fp1zJ07l8eo1G/evHn4/fff2bJYLEZcXBysrKx4jIpoO0pGtBclIyrm5eXFmTh37NgxuuU7UStbW1ts3ryZU7d06VKcPn2ap4jU69dff8V3333HqVu5ciVat27NU0REW9H6O7qDkhEVEwqFnKGa/Px8nDlzhseISG3g7++P0aNHs2WGYRAaGoq8vDweo1K9R48eYfjw4ZyTzNChQxVuikcIQMM0uoSSETUoP2+EhmqIJixfvhwuLi5s+eHDh5g0aRKPEalWSUkJhgwZgufPn7N1TZs2xcaNG+kkQ4iOo2REDT755BPOCpm03gjRBDMzM2zbto0zgXPr1q3Yv38/j1GpzvTp03HhwgW2bGJigri4OM7lzYS8jXpGdEeNkpE1a9bA2dkZEokE7du3R1JSUqVtN23aBB8fH1hZWcHKygp+fn5VttcHZmZm8PX1Zcv//PMP7t69y2NEpLbo1KkTZsyYwakbO3aszl9i/vPPP2PlypWcuvXr16N58+b8BER0AiUjukPpZGTPnj2IiIhAZGQkrly5glatWqFnz57IysqqsP3JkycxdOhQnDhxAufPn4ejoyN69OiBJ0+evHfw2oxWYyV8iYyMxEcffcSWs7OzMXr0aJ2dzJeSkoLPP/+cUzdmzBiEhITwFBEhRNWUTkaWL1+OMWPGYOTIkXB3d8f69ethYmKCn376qcL2O3fuxIQJE+Dp6YmmTZti8+bNkMvlOH78+HsHr80oGSF8EYvF2L59O+eOpEeOHMGmTZt4jKpmCgsLMWjQIM5EXE9PT6xevZrHqIiuoJ4R3aFUMlJSUoLLly/Dz8/v3w0IhfDz88P58+ertY3Xr1+jtLQU1tbWlbYpLi5GXl4e56FrmjRpAjc3N7Z86tQpnXwfRDc1b94cUVFRnLrJkycjJSWFp4hq5uuvv8a1a9fYsoWFBeLi4iCRSHiMiugKSkZ0h1LJSHZ2NmQymcINqOrXr1/tMenp06ejQYMGnISmvO+//x4WFhbsw9HRUZkwtcbbvSNSqRTHjh3jMRpS23z99dfo1q0bW379+jVCQ0MhlUp5jKr6tm3bprB+SnR0NFxdXXmKiBCiLhq9miYqKgqxsbHYv39/ld9sZs6cidzcXPbx6NEjDUapOjRUQ/gkFAqxdetWWFhYsHXnz5/HokWLeIyqem7cuKGwdkhERAQ+/fRTniIiuoh6RnSHUslI3bp1IRKJkJmZyanPzMyEnZ1dla9dunQpoqKikJiYiJYtW1bZ1sjICObm5pyHLvLx8YGZmRlbPnLkCORyOY8RkdrG0dERa9as4dR9++23uHz5Mk8RvVt+fj4GDRqEwsJCtq5jx44Kw06EvAslI7pDqWRELBajdevWnMmnZZNRvb29K33d4sWLMX/+fCQkJHDuaqvvxGIxevTowZazsrK0+iRA9NOwYcMwZMgQtiyVShESEsI52WsLhmEwZswY3Llzh62rW7cu9uzZw1m7hxCiX5QepomIiMCmTZsQExODW7duYfz48Xj16hVGjhwJAAgNDcXMmTPZ9osWLcLcuXPx008/wdnZGRkZGcjIyEBBQYHq3oUWK3/jPBqqIZomEAiwbt062Nvbs3W3bt3i/J1qi7Vr12LPnj1sWSAQYOfOnWjYsCGPURFdRT0jukPpZCQwMBBLly7F//3f/8HT0xPJyclISEhgJ7WmpaVxbuu9bt06lJSUYNCgQbC3t2cfS5cuVd270GK9e/fmlGlpeMIHa2trREdHc+pWrVqF3377jaeIFP3555+YPHkyp27u3Lmc3kVClKGra+vURgJGB35aeXl5sLCwQG5urk7OH2nXrh3+/PNPtvz06VPOt1RCNOXLL7/kzCFxcHDA9evXYWVlxWNUwIsXL+Dl5YWHDx+ydX5+fkhISIBIJOIxMqLL9uzZg6CgILa8ZcsWhQX0iHpV9/xN96bRgPJDNUePHuUpElLbLV68mLP+zZMnT/Dll1/yGNGbeWdhYWGcRKRBgwbYuXMnJSLkvdAwje6gZEQD6C6+RFuYmJhgx44dnJP8rl27EBsby1tMS5Ys4fxNiEQi7NmzB7a2trzFRPSDDnT8k/+hZEQDPvroI86lz8eOHUNxcTGPEZHarG3btpg7dy6nbvz48bzcL+r06dOYPXs2py4qKgqdO3fWeCxE/1HPiPaiZEQDhEIhp3ekoKAAZ86c4TEiUtvNmjUL7dq1Y8s5OTkYOXKkRtfByczMRFBQEGQyGVsXEBCAb775RmMxEP1GwzS6g5IRDXnXUM3r1681GQ6p5QwNDbF9+3YYGxuzdceOHcPatWs1sn+ZTIahQ4dyrrxr1KgRtm7dSicMoiAnJ6dGtzGQybjJtVxOwzbaipIRDfHz8+Ms2nT48GE2a9+7dy+WL1/OV2iklnJzc8OyZcs4dVOnTsXt27fVvu/IyEicOHGCLYvFYuzduxeWlpZq3zfRLTI5g+PJ91HX1g5de/XHhg0bkZaW9s7XJdxIx38O3+TULYi/hYQb6ZW8gvCJkhENMTMzw8cff8yW7927h7t372Lz5s0ICgrSmZuXEf3yxRdfoFevXmy5qKgIwcHBKC0tVds+jx49igULFnDqVq1ahdatW6ttn0Q3JdxIR+dFv+ObhHTIG3XAyV8P4YsvxsHJyQnu7u6YPHkyEhISFFYTTriRjvE7ruDl6xJOfW5hKcbvuEIJiRaiZESNpFIpJ8koP1QzYsQIjBkzBnK5nLqmCS8EAgG2bNkCa2trtu7y5cuYP3++WvaXlpaG4OBgTt2wYcMwbtw4teyP6K6yhCI9twiMrBR1PuoLiAzY52/duoWVK1eid+/esLa2Rs+ePbF8+XJcv/E3vj34NxgAKDdnhMGbz9l5h25CRkM2WsXg3U3I++jWrRsKCgrQsmVLzt1TAeDChQvs/ykZIXxp0KABNmzYgMGDB7N1CxcuRJ8+fdChQweV7aekpARDhgzBixcv2LpmzZphw4YN9PtPOGRyBvMO3URZulDw1zG8SKx8PlNRURESExORmJgI4BuIzOrCuJEXYCDmNhQIwABIzy1CUuoLeLvaqOstECVRMqJGBgYGWLt2Lby8vHD16tUq2wqF1ElF+DNo0CCEhIRg+/btAN5MMA0JCUFycjJMTU1Vso9p06bh4sWLbNnExARxcXGoU6eOSrZP9EdS6guk5xaxZUZaUkVrRbL8bBT8lQihWT2YNPOFqbsvhBJTGFo5sG2y8ouq2ALRNDoDqpmHh4fCOgoVoW+GhG8//PADHB0d2XJKSgqmTJmi9HZKS0tx7do1Tl1cXBxWrVrFqdu4cSPc3d1rFizRa+UTBYGk+gmxs6sbzL0DYRe2Eg3H/4R6/afCpHE7SBo2h8jUkm1nayZRVbhEBSgZ0YCZM2eiRYsWVbahZITwzcLCAjExMZy69evXIz4+XqntxMfHY/r06Wz5n3/+UbgfyLhx4zB8+PCaB0v0WvlEwfTDzqg3MLLS9l5eXvjuu+9w8+ZNpNy9DXf/MZDYNa7wc1UAwN5CgnaNrBU3RHhDyYgGiMVibNmypcqhGBqmIdqga9euiIiI4NSNGjUK2dnZ1d7G1q1b8euvv+LixYsoLCzEoEGDkJ+fzz7v5eWFlStXqipkoofaNbKGvYUEZamEUGwM6cunCu3q1q2LefPmsSv5NmvWDCKhAJH+b3rcyqciZeVIf3eIhPQFUJvQGVBD2rZtq/Ah/zbqGSHaYsGCBWjevDlbzsjIwLhx46p1n49nz56xC/rNnz8fX331Ff766y/2eQsLC+zduxcSCXWRk8qVTygYaSnyLh+ExKkVhKb/9mhkZ2cjMjISDRs2xPTp0/H48WMAQC8Pe6wL9oKdBff3zM5CgnXBXujlQXdN1zYCRgfuJFTdWxBru9evX6NVq1ZISUlReG7RokWYNm0aD1ERoig5ORnt2rXjrDcSExOD0NDQKl+3atUqhIeHV/r8/v37MWDAABVFWTWZnEFS6gtk5RfB1uxNtzx9G9YtCTfSMe/QTTzJegFGLoPI2AxmeQ9wc8PXFd66wMDAAIMHD8bkyZPRtm1b+h3QAtU9f1MyomGnT5+Gr6+vQv2SJUtqNFmQEHWJiorCzJkz2bKZmRmuX78OJyenSl/j6empMHm1zDfffIOlS5eqPM6KlJ3E3r4iw95Cgkh/d/pWrGMqSiimTvkGK1asqPJ1nTp1wuTJkzFgwADOXaqJZlX3/E3DNBrWpUsXjB8/XqGehmmItpk6dSo6derElvPz8xEWFlbpzfSSk5MrTUSAN/cX2bBhA5KSkhRWzFSltxfLeltGbhGtvqmDREIBvF1tEODpAG9XG4iEAsyfPx/Ozs5Vvu7cuXMYNGgQGjdujBUrViAvL08zAZMaoZ4RHuTl5cHDwwOPHj1i65YtW1blnBJC+HD//n20atUKBQUFbN3SpUsrvLNueHi4wuW7FTEwMMDixYsRHh5eYRJ+/vx5FBcXw9LSkn2Ym5tXa5K3TM6g86Lf2UTk9T8X8eK39TAwt4WBhS0MzG1hY+eANeN6wqWRMz744AOav6KjEhMT0bNnz2q379u3L3bs2EH3P9IwGqbRcgkJCejduzdbXrFiRZVj7YTwZcuWLRg9ejRbFovFuHTpEudy9ZKSEjg4OLzzqhtXV1fs3r0bbdu2rbRNUlISfH19UVT0b8+GQCCAubk5J0Gp6JFdYoCNFzIglJhCaFQHhfcvIef0tipjql+/PpydneHk5MR5lNWZmZm96xARnowYMULhcvS3GRsbIzg4GBMnTkSrVq00GBkpQ8mIDggLC8O2bW8+KEdN/Rajxn1JE6yI1mEYBgMGDMDBgwfZupYtWyIpKQlGRkYA3kxM/eyzz6rcTnBwMNauXVutk/vu3bsxbNiwGscsEBvDomMgZHnPkX/lUI23AwBWVlac5KR8wmJtbU3DrDx5/vw53N3dkZWVVeHztra2OHjwINq3b6/hyEgZSkZ0wH/P/o3gXp1R+ioHVt3HwrxNf5pkR7RSVlYWPDw88OzZM7Zu+vTpiIqKAgAEBARwkpW31alTB2vXrkVISIhS+4yIiHjnJMXyBAIBTFt8AkufEIjqWCHn9HYU3DwJWX42IJcpta3qMjU1VehNefthZ2dH6wip0Z49exAUFFTp8xKJBNu3b8egQYM0GBUpQ8mIliubZFdw+yyyD0TBym8czFv7s4vy0LXwRNscPHgQAQEBbFkgEODUqVNwc3ODg4MDZDLFk32bNm2we/duNG7cuMptMwyD1NRUnD17FmfPnsW5c+dw8+ZNpeLz8fHBsuUr8PWxHGTkFuHtDzZGLoOs4AVkeVmoU5qD0BYmeJSWhocPH7KPt4eFVEksFuODDz6ocAjIyckJDRs2hIEB3SasphiGQUBAAA4d+rcHTCQSKfw+RkVFYdq0adSLpWGUjGix8pPsnu1fCIGhERhpKQSGYggMxKhjaoIwHzeYmphAIpHA2Ni40kdFz0skEvo2RlRu9OjR2LJlC1t2dnbGmDFjKrz/0tSpU/Hdd99BLBYrPCeVSnHt2jVO8pGeXrOrXJydnbFkyRIMHDgQAoGATfQBcBKSqhJ9hmGQlZXFSU4ePHjAKavragyhUIiGDRtWOmeFJtm+2+PHj+Hu7o78/HyYmZnh2LFjGDBgADIyMjjtRo0ahXXr1sHQ0JCnSGsfSka02Pl7zzF00wW2LCt4iez4FShKvaLS/RgZGdUokanp8xKJhL516Ln8/Hy0atUKqampbJ2lpSVycnLYcv369bFt2zb06NGD87qLFy+yyceFCxfw6tWr94rF1NQUs2bNQkREhMLJWh3rjOTk5CgkKG+XlVkyX1k0yfbd1q1bhwkTJqB3796Ij49HWloa+vXrh+vXr3PadevWDT///DNdVaMhlIxosQPJTzApNplTl310NV79lchPQCpUPnmpKplRRSJkZGRECdB7ysrKwowZMzBo0CD4+flV2JNRJuFGOqb8+F/8vTECYBTXG+nVqxdiYmIglUpx7tw5NvlITk6udH2SihgZGaFdu3YQCAQ4ffq0wvNhYWFYuHAhGjRoUOk2NL365qtXr5CWllZpwpKenl6tJfVromySbUXzVtQ5yTYtLQ2zZs1CeHg42rRpo/LtK0Mul+Pjjz9Gv3792NWs8/LyEBQUhKNHj3LaNmvWDEeOHEGjRo34CLVWoWREi5XvGQGA7MPL8OrvEzxFpLsEAkGlSYu6eoUMDQ31LgEaPHgw4uLiYGVlhU8//RSBgYHo2rUrpzu7bPiDAfDyVAzyLuzlbMO9Q1fUs7HCP39dxtNHD5Xav42NDTp16oTOnTujc+fO8PLygpGREcaOHYtNmzax7Tp27IhVq1bxfuKriZKSEjx69KjCIaCHDx/i0aNHkEqlatn325NsK0pY3meSrbe3Ny5cuMCueBoQEMDbHJg7d+6gsLAQnp6ebJ1UKkV4eDjWrFnDaVuvXj0cOHAA3t7eGo6ydqFkRIuVzRl5e5IdI5OCkRaDKS0BIy2GjUSATcNboqS4CEVFRSgsLKz08a7nK2tDakYoFGqk16d8AqROSUlJCpc/2tjYYODAgRgyZAg6+3TBx8tOs8Me8uJXeLLpC8hfvazR/ho3bozOnTuzCciHH35YYYLXtGlT3LlzB46Ojli8eDECAwP1LhEsI5PJ8PTp00rnrGjrJNsff/wRX331FVt2cnLCV199hVGjRmnNUAjDMFi9ejUmT57M6Z0yMjJCTEwMAgMDeYxOv1EyouVqMslOlRiGQXFxcbUTGlUkRMXFxWp7P/pOJBKpLNmp7LmgoCAkJydXuH8rm3oo/aAtTJv6wKihOyAQ4NHywWCk7/6ZikQieHl5sclHp06dYGdn987XZWVloVGjRpg+fTqmTJkCExMTZQ+bXqlokm35pEWdk2wdHBwqnLdiamoKHx8fhSEoU1NTjBw5El9//TWaNGlS4XY1PZR26NAhDB06VGG+0oIFCzBz5ky9TXT5RMmIDqhtN/OSy+WcBEjVCU9Fz5eUlPD9tvWOqI41TD7shOInt1CSoXgHaoGhBEYOzSBp6A77Dz/ChRXjYG5WR+n9PHr0CAKBAA0bNlRF2LVCRZNs305Y1DnJtjICgQB9+/ZFeHg4unXrxp7w+fr8u3r1Kvr164enT59y6keMGIENGzZUOWeKKI+SER1Bt7hWL5lMxklS1N0DVFRUhNLSUr7ftmYJhOxkVoGhBHUDZsLEtTX79O4xHeDtasNXdOQtZZNsKxoGevDggVon2QKAh4cHwsPDUbdVV4TH3UL5PWmqZ/jx48fw9/dX6An8+OOP8fPPP8Pa2lpt+65tKBkhhCdSqbTSpKWm83ve9XxFC45pjEAEgIGhjSPqDZ4HQ/O6nKdXBXkiwNOBn9iIUt6eZFtRwqKqSbYGJhYw9eyNOh/1gUEda8gK85G1NxKmzXxRx90XDg3scHZ6N7V+MSsoKMDQoUNx+PBhTr2bmxuOHDnyzoX6SPVQMkJILVJaWvrevTu7du3CixcvqrE3AcT2jSFxagWJkyeMHJpBlpcFA2sHCASKV2RQz4j+KD/J9uHDhzh48CAuXrxYsw0KDVCnpR8MLO2RczL6f3UiGLu0xtzJExAxKoi9/5E6yGQyREREYPXq1Zx6Gxsb/PLLL+jcubPa9l1bUDJCCKm2S5cuVXkn3aZNm6J79+6wauKFhOfWeFby7qt7BADsLCRq/4ZL+JObm4vmzZvjyZMn72xraGiIpk2bwrKBC66/NodhPScY1nWCgWV9ZGyfgpL0uwqvsba2xtChQxEWFoY2bdqobYLpjz/+iEmTJnHWwhGLxYiOjn6vGzYSSkYIIdXEMAy6d++OEyf+XefGwcEB3bt3Zx8ODv8Os7w9z+lB9ius+O0fCMDPVWGEX+VvDwC8mbDq6uoKDw8P9tGiRQs0adIEhoaGCussyUsKkRk7CyXp/1S5L3d3d4SFhSE4OLjKxe5qKj4+HoGBgSgoKODUz5s3D3PnzqUrbWqIkhFCSLUcPXoUw4YNQ7du3djkw83NrdofvrXtqjDyRmJiIkaNGsVJOjw8PNCsWbMqL8OuaJ0lACjNfoSCG8fx6u/fISuofLhQKBTik08+QVhYGAYMGABjY2OVvadr166hX79+ePz4Mac+ODgYmzdvVuuQkb6iZIQQUi3p6emwtbWFSCSq8TboqrDap7S0tMaL8VW1zhIjl2GM6yv8feoQ9u/fX+VCb+bm5ggMDERYWBg6duyokt6Lp0+fwt/fH1eucO8V5uPjg/3798PGhuY/KYOSEUIIIVqrOj1qubm52Lt3L7Zu3Ypz585Vub3GjRsjLCwMISEhcHJyeq/YXr16heHDh+PAgQMK+zhy5Ajc3Nzea/u1CSUjhBBCtJoyPWopKSnYtm0btm3bhocPq773UdeuXREWFoaBAweiTh3lF9wD3lxpM23aNCxfvpxTb21tjf3796NLly412m5tQ8kIIYQQvSOXy3Hq1CnExMQgLi5OYWn3t5mammLQoEEICwuDr69vjW4GuH79enz55ZectXwMDQ2xefNmhIaG1ug91CaUjBBCCNFrBQUF2LdvH7Zu3cq5GqwiTk5OCA0NRWhoqNILmv36668YPHgw8vPzOfVz587FvHnz6EqbKlAyQgghpNZ4+PAhtm/fjpiYGKSkKN4z6W2dOnVCWFgYhgwZAgsLi2pt//r16+jXrx/S0tI49UOHDsVPP/0EiURS49j1GSUjhBBCah2GYfDHH38gJiYGe/bsqfJOxhKJBJ9++inCwsLg5+f3zivKMjIy0L9/f/z555+c+k6dOmH//v2oV6+eSt6DPqFkhBBCSK1WWFiIAwcOYOvWrTh27BhnhdXyGjRogODgYISFhcHd3b3Sdq9fv0ZISAj27dvHqXdxccGRI0fQtGlTlcWvDygZIYQQQv7n6dOn2LFjB2JiYnDz5s0q27Zt2xZhYWEICgqqcF0RuVwOPz8/hXkqlpaW2LdvH7p27arS2HUZJSOEEEJIOQzD4NKlS4iJicGuXbvw8uXLStsaGhqif//+CAsLQ69evTiLvO3ZswdBQUEKrzEwMMDGjRsxcuRItcSva6p7/lb+OidCCCFERwkEArRt2xY//vgj0tPTERcXB39//wrni5SWluLnn39G//790bBhQ0yePBnXrl0DADRs2LDC7UulUnz++eeYNWtWlcNChIt6RgghhNR6mZmZ2LVrF2JiYtiEozKtWrVCjx49sGTJkirbDRkyBFu3blXp/XN0DQ3TEEIIITVw7do1xMTEYMeOHXj27Nl7batDhw44cOAAbG1tVRSdbqFhGkIIIaQGWrVqheXLl+PJkyc4ePAgBg4cCLFYXKNtXbhwAe3bt3/npNnajnpGCCGEkHd4/vw5YmNjERMTo7DOSHVYWFggLi4OXbt1r1V3uKZhGkIIIUTFioqK4Ofn9867CFdEZGAAJ/+vIXPrxtaVv1OxvqFhGkIIIUSF8vPz0adPnxolIgAgk0pxf/9yvDwZDYZ5c6VNRm4Rxu+4goQb6aoMVedQMkIIIYS8Q3Z2Nrp16/bOG/JVR97Fn5H9SxQYWSnKhibmHboJmVzrByrUxoDvAAghhBBtZ25ujkOHDuHly5d4+fIlcnJyOP9W9v+cnBzk5uYqbE8gNgGEb07BDID03CIkpb6At6viiq+1ASUjhBBCyDuIxWLY2dnBzs5O6dfuu5yGr386iRe/rkHhvSSI7ZrAptdECATciatZ+UWqClfnUDJCCCGEqJG9pSkMzGxQb+Bc5F86CNMW3SEQGSq0szWT8BCddqA5I4QQQogatWtkDXsLCYQCAczbBkAkqcN5XoA3V9W0a2TNT4BaoEbJyJo1a+Ds7AyJRIL27dsjKSmpyvZ79+5F06ZNIZFI0KJFC8THx9coWEIIIUTXiIQCRPq7A3iTeLytrBzp767X6428i9LJyJ49exAREYHIyEhcuXIFrVq1Qs+ePZGVlVVh+z/++ANDhw7FqFGjcPXqVQwYMAADBgzAjRs33jt4QgghRBf08rDHumAv2Flwh2LsLCRYF+ylt+uMVJfSi561b9+eveMhAMjlcjg6OuKrr77CjBkzFNoHBgbi1atXOHz4MFvXoUMHeHp6Yv369RXuo7i4GMXFxWw5Ly8Pjo6OtOgZIYQQnSaTM7QCawWU6hkpKSnB5cuX4efn9+8GhEL4+fnh/PnzFb7m/PnznPYA0LNnz0rbA8D3338PCwsL9uHo6KhMmIQQQohWEgkF8Ha1QYCnA7xdbfQ6EVGGUslIdnY2ZDIZ6tevz6mvX78+MjIyKnxNRkaGUu0BYObMmcjNzWUfjx49UiZMQgghhOgQrby018jICEZGRnyHQQghhBANUKpnpG7duhCJRMjMzOTUZ2ZmVroQjJ2dnVLtCSGEEFK7KJWMiMVitG7dGsePH2fr5HI5jh8/Dm9v7wpf4+3tzWkPAMeOHau0PSGEEEJqF6WHaSIiIhAWFoY2bdqgXbt2WLlyJV69eoWRI0cCAEJDQ+Hg4IDvv/8eADBp0iT4+vpi2bJl6Nu3L2JjY3Hp0iVs3LhRte+EEEIIITpJ6WQkMDAQz549w//93/8hIyMDnp6eSEhIYCeppqWlQSj8t8OlY8eO2LVrF+bMmYNZs2ahSZMm+OWXX+Dh4aG6d0EIIYQQnaX0OiN8qO51yoQQQgjRHmpZZ4QQQgghRNUoGSGEEEIIrygZIYQQQgivKBkhhBBCCK8oGSGEEEIIrygZIYQQQgivKBkhhBBCCK8oGSGEEEIIr7Tyrr3lla3LlpeXx3MkhBBCCKmusvP2u9ZX1YlkJD8/HwDg6OjIcySEEEIIUVZ+fj4sLCwqfV4nloOXy+V4+vQpzMzMIBAIVLbdvLw8ODo64tGjR7TMvBrRcdYcOtaaQcdZM+g4a4Y6jzPDMMjPz0eDBg04960rTyd6RoRCIRo2bKi27Zubm9MvugbQcdYcOtaaQcdZM+g4a4a6jnNVPSJlaAIrIYQQQnhFyQghhBBCeFWrkxEjIyNERkbCyMiI71D0Gh1nzaFjrRl0nDWDjrNmaMNx1okJrIQQQgjRX7W6Z4QQQggh/KNkhBBCCCG8omSEEEIIIbyiZIQQQgghvKJkhBBCCCG80vtkZM2aNXB2doZEIkH79u2RlJRUZfu9e/eiadOmkEgkaNGiBeLj4zUUqW5T5jhv2rQJPj4+sLKygpWVFfz8/N75cyH/UvZ3ukxsbCwEAgEGDBig3gD1hLLHOScnBxMnToS9vT2MjIzg5uZGnx/VoOxxXrlyJT788EMYGxvD0dERkydPRlFRkYai1U2nT5+Gv78/GjRoAIFAgF9++eWdrzl58iS8vLxgZGSExo0bY+vWreoNktFjsbGxjFgsZn766Sfm77//ZsaMGcNYWloymZmZFbY/d+4cIxKJmMWLFzM3b95k5syZwxgaGjLXr1/XcOS6RdnjPGzYMGbNmjXM1atXmVu3bjEjRoxgLCwsmMePH2s4ct2j7LEuk5qayjg4ODA+Pj5MQECAZoLVYcoe5+LiYqZNmzZMnz59mLNnzzKpqanMyZMnmeTkZA1HrluUPc47d+5kjIyMmJ07dzKpqanMr7/+ytjb2zOTJ0/WcOS6JT4+npk9ezazb98+BgCzf//+Ktvfv3+fMTExYSIiIpibN28yP/zwAyMSiZiEhAS1xajXyUi7du2YiRMnsmWZTMY0aNCA+f777ytsP2TIEKZv376cuvbt2zPjxo1Ta5y6TtnjXJ5UKmXMzMyYmJgYdYWoN2pyrKVSKdOxY0dm8+bNTFhYGCUj1aDscV63bh3j4uLClJSUaCpEvaDscZ44cSLTrVs3Tl1ERATTqVMntcapT6qTjEybNo1p3rw5py4wMJDp2bOn2uLS22GakpISXL58GX5+fmydUCiEn58fzp8/X+Frzp8/z2kPAD179qy0PanZcS7v9evXKC0thbW1tbrC1As1Pdb/+c9/YGtri1GjRmkiTJ1Xk+N88OBBeHt7Y+LEiahfvz48PDywcOFCyGQyTYWtc2pynDt27IjLly+zQzn3799HfHw8+vTpo5GYaws+zoU6cdfemsjOzoZMJkP9+vU59fXr18ft27crfE1GRkaF7TMyMtQWp66ryXEub/r06WjQoIHCLz/hqsmxPnv2LLZs2YLk5GQNRKgfanKc79+/j99//x3Dhw9HfHw8UlJSMGHCBJSWliIyMlITYeucmhznYcOGITs7G507dwbDMJBKpfjiiy8wa9YsTYRca1R2LszLy0NhYSGMjY1Vvk+97RkhuiEqKgqxsbHYv38/JBIJ3+Holfz8fISEhGDTpk2oW7cu3+HoNblcDltbW2zcuBGtW7dGYGAgZs+ejfXr1/Mdml45efIkFi5ciLVr1+LKlSvYt28fjhw5gvnz5/MdGnlPetszUrduXYhEImRmZnLqMzMzYWdnV+Fr7OzslGpPanacyyxduhRRUVH47bff0LJlS3WGqReUPdb37t3DgwcP4O/vz9bJ5XIAgIGBAe7cuQNXV1f1Bq2DavI7bW9vD0NDQ4hEIrauWbNmyMjIQElJCcRisVpj1kU1Oc5z585FSEgIRo8eDQBo0aIFXr16hbFjx2L27NkQCun7tSpUdi40NzdXS68IoMc9I2KxGK1bt8bx48fZOrlcjuPHj8Pb27vC13h7e3PaA8CxY8cqbU9qdpwBYPHixZg/fz4SEhLQpk0bTYSq85Q91k2bNsX169eRnJzMPvr374+uXbsiOTkZjo6OmgxfZ9Tkd7pTp05ISUlhkz0AuHv3Luzt7SkRqURNjvPr168VEo6yBJChe76qDC/nQrVNjdUCsbGxjJGREbN161bm5s2bzNixYxlLS0smIyODYRiGCQkJYWbMmMG2P3fuHGNgYMAsXbqUuXXrFhMZGUmX9laDssc5KiqKEYvFTFxcHJOens4+8vPz+XoLOkPZY10eXU1TPcoe57S0NMbMzIz58ssvmTt37jCHDx9mbG1tme+++46vt6ATlD3OkZGRjJmZGbN7927m/v37TGJiIuPq6soMGTKEr7egE/Lz85mrV68yV69eZQAwy5cvZ65evco8fPiQYRiGmTFjBhMSEsK2L7u0d+rUqcytW7eYNWvW0KW97+uHH35gPvjgA0YsFjPt2rVjLly4wD7n6+vLhIWFcdr/97//Zdzc3BixWMw0b96cOXLkiIYj1k3KHGcnJycGgMIjMjJS84HrIGV/p99GyUj1KXuc//jjD6Z9+/aMkZER4+LiwixYsICRSqUajlr3KHOcS0tLmW+//ZZxdXVlJBIJ4+joyEyYMIF5+fKl5gPXISdOnKjwM7fs2IaFhTG+vr4Kr/H09GTEYjHj4uLCREdHqzVGAcNQ3xYhhBBC+KO3c0YIIYQQohsoGSGEEEIIrygZIYQQQgivKBkhhBBCCK8oGSGEEEIIrygZIYQQQgivKBkhhBBCCK8oGSGEEEIIrygZIYQQQgivKBkhhBBCCK8oGSGEEEIIr/4fVWefHjT4D54AAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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/BlSqVSurlgsBpDWOTq30vft4cOHvPFQHj58CJlMpnDfMyIihISEoGbNmlxZaGgoDh48iIMHD8rVr1WrFqpXr44nT57wylNSUnD8+HE0btw4RwkQU0wpuWWGYeRkNs4IEZGzszOZm5tTUlISERE1btyYTExM6NOnT3J1IyMjedPbtm0jAFShQgWaOHEiV966dWsqX748AaBbt25x5c+ePSMAtHv3bq5MJpNR27ZtCQDt2rWLK89sPAk/P79cdWANCAiQu8SSGydOnCAANHv2bK5MKpVS/fr1ycTEhNfR9+3bt/T27dss1yeVSqlt27ako6PDi+vn95Yo7TKHsbExVatWjStLSkpS2E9l2rRpmY4TkpqaSqamptSgQYNM40of2+LixYtc2ZcvX8jAwIDatGnDlYWGhmY6zoi1tTV3eUvZ+z527FgCQNeuXePVnThxolzfmIyyG2fExMSE17+DiKhfv36ko6NDUVFRWe7Txo0bCQCtWbOGKztx4oTcq2fPngSA9u7dS1evXpVbj6enJwGgHTt2KIyTYYjYZRqmkElvJt69ezdGjhyJjRs3on79+qhatSqGDx8Oe3t7fP78GT4+Pvj48SNvaPD0W3Zfv36NpUuXcuUNGzbE+fPnoampyRvls2LFinBwcMDUqVMRFhYGAwMDHD9+PNtLHRnVqFEDvXv3xqZNmxATE4N69erhypUrePv2rcL6lSpVQqNGjXD9+vVcvjNpOnbsiKZNm8LDwwNfv35F9erVcfLkSdy+fRtbtmyBpqYmV7dp06YAftwyDQATJkxAcnIyatSoAbFYjIMHD8LX1xd79uxB6dKluXrTp09HUFAQmjZtCisrK4SEhGDLli1ISEjAunXruHoRERGoWbMmevfuzd2e6u3tDS8vL7Rq1QodO3aU2wdvb29ERUXJjS2S0axZs3D06FFuZFFDQ0P8+++/EIvFvL9tqVKlMHHiRKxcuRJisRh16tTByZMncevWLRw4cIA3wqgy933s2LHYtWsX2rdvj3HjxsHW1hY3btzAoUOH0Lx5c9StW5er+/79e+zbtw9AWisHACxevBhAWktc//79AaRdDlq0aBHGjBmD7t27o2XLlrh16xb279+PJUuWwMTEhFunra0tevbsiapVq0JLSwu3b9/G4cOHUaNGDd7tu506dZL7W6S3hLRu3RolSpSQm3/gwAFo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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "batch_instance = 0\n", + "for i, actions in enumerate(actions_stacked[batch_instance].cpu()):\n", + " reward = rewards_stacked[batch_instance, i]\n", + " _, ax = plt.subplots()\n", + " \n", + " env.render(td[0], actions, ax=ax)\n", + " ax.set_title(\"Reward: %s\" % reward.item())" + ] + }, + { + "cell_type": "markdown", + "id": "0d3387ca", + "metadata": {}, + "source": [ + "### Final notes" + ] + }, + { + "cell_type": "markdown", + "id": "633b4ce9", + "metadata": {}, + "source": [ + "For evaluation, we can also use additional decoding strategies used during evaluatin, such as sampling N times or greedy augmentations, available in [rl4co/tasks/eval.py](../../rl4co/tasks/eval.py)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/modeling/1-decoding-strategies/index.html b/examples/modeling/1-decoding-strategies/index.html new file mode 100644 index 00000000..c91cb5e7 --- /dev/null +++ b/examples/modeling/1-decoding-strategies/index.html @@ -0,0 +1,4269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + RL4CO Decoding Strategies Notebook - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/modeling/2-transductive-methods/2-transductive-methods.ipynb b/examples/modeling/2-transductive-methods/2-transductive-methods.ipynb new file mode 100644 index 00000000..bec38e9c --- /dev/null +++ b/examples/modeling/2-transductive-methods/2-transductive-methods.ipynb @@ -0,0 +1,436 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Transductive Methods\n", + "\n", + "In this notebook, we will showcase how to use the Efficient Active Search (EAS) algorithm to find better solutions to existing problems!\n", + "\n", + "> Tip: in [transductive RL](https://en.wikipedia.org/wiki/Transduction_(machine_learning)) we train (or finetune) to solve only specific ones.\n", + "\n", + "\"Open" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installation\n", + "\n", + "Uncomment the following line to install the package from PyPI. Remember to choose a GPU runtime for faster training!\n", + "\n", + "> Note: You may need to restart the runtime in Colab after this\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install rl4co[graph] # include torch-geometric\n", + "\n", + "## NOTE: to install latest version from Github (may be unstable) install from source instead:\n", + "# !pip install git+https://github.com/ai4co/rl4co.git" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2023-08-22 16:29:17.903805: I tensorflow/core/util/port.cc:110] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", + "2023-08-22 16:29:17.923169: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX512F AVX512_VNNI AVX512_BF16 FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "2023-08-22 16:29:18.249479: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n" + ] + } + ], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "import torch\n", + "\n", + "from rl4co.envs import TSPEnv, CVRPEnv\n", + "from rl4co.models.zoo.am import AttentionModel\n", + "from rl4co.utils.trainer import RL4COTrainer\n", + "from rl4co.utils.decoding import get_log_likelihood\n", + "from rl4co.models.zoo import EAS, EASLay, EASEmb, ActiveSearch\n", + "\n", + "import logging" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:196: UserWarning: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n", + " rank_zero_warn(\n", + "/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:196: UserWarning: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n", + " rank_zero_warn(\n", + "/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/core/saving.py:164: UserWarning: Found keys that are not in the model state dict but in the checkpoint: ['baseline.baseline.model.encoder.init_embedding.init_embed.weight', 'baseline.baseline.model.encoder.init_embedding.init_embed.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.num_batches_tracked', 'baseline.baseline.model.decoder.context_embedding.W_placeholder', 'baseline.baseline.model.decoder.context_embedding.project_context.weight', 'baseline.baseline.model.decoder.project_node_embeddings.weight', 'baseline.baseline.model.decoder.project_fixed_context.weight', 'baseline.baseline.model.decoder.logit_attention.project_out.weight']\n", + " rank_zero_warn(\n" + ] + } + ], + "source": [ + "# Load from checkpoint; alternatively, simply instantiate a new model\n", + "checkpoint_path = \"last.ckpt\" # model trained for one epoch only just for showing the examples\n", + "\n", + "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", + "\n", + "# load checkpoint\n", + "# checkpoint = torch.load(checkpoint_path)\n", + "\n", + "model = AttentionModel.load_from_checkpoint(checkpoint_path, load_baseline=False)\n", + "policy = model.policy.to(device)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# env = CVRPEnv(generator_params=dict(num_loc=50))\n", + "# policy = AttentionModel(env).policy.to(device)\n", + "\n", + "env = TSPEnv(generator_params=dict(num_loc=50))\n", + "\n", + "td = env.reset(batch_size=3).to(device)\n", + "\n", + "out = policy(td, return_actions=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "env.render(td.cpu(), out[\"actions\"].cpu())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## EAS\n", + "\n", + "We perform few iterations of EASLay for demonstration" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:196: UserWarning: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n", + " rank_zero_warn(\n", + "/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:196: UserWarning: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n", + " rank_zero_warn(\n", + "INFO:rl4co.models.rl.common.base:No metrics specified, using default\n", + "INFO:rl4co.models.zoo.eas.search:Setting up Efficient Active Search (EAS) with: \n", + "- EAS Embedding: False \n", + "- EAS Layer: True \n", + "\n" + ] + } + ], + "source": [ + "logging.basicConfig(level=logging.DEBUG)\n", + "\n", + "env.generator.num_loc = 200\n", + "\n", + "dataset = env.dataset(batch_size=[2])\n", + "# eas_model = EASEmb(env, policy, dataset, batch_size=2, max_iters=20, save_path=\"eas_sols.pt\") # alternative\n", + "eas_model = EASLay(env, policy, dataset, batch_size=2, max_iters=20, save_path=\"eas_sols.pt\")\n", + "\n", + "eas_model.setup()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:rl4co.models.common.constructive.autoregressive.policy:Instantiated environment not provided; instantiating tsp\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Plot initial solution\n", + "td_dataset = next(iter(eas_model.train_dataloader()))\n", + "td_dataset = env.reset(td_dataset).to(device)\n", + "out = policy(td_dataset, return_actions=True)\n", + "\n", + "env.render(td_dataset.cpu(), out[\"actions\"].cpu())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Perform search \n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:rl4co.utils.trainer:gradient_clip_val is set to None. This may lead to unstable training.\n", + "Using 16bit Automatic Mixed Precision (AMP)\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "IPU available: False, using: 0 IPUs\n", + "HPU available: False, using: 0 HPUs\n", + "INFO:rl4co.models.zoo.eas.search:Setting up Efficient Active Search (EAS) with: \n", + "- EAS Embedding: False \n", + "- EAS Layer: True \n", + "\n", + "DEBUG:fsspec.local:open file: /home/botu/Dev/rl4co-rebuttal/notebooks/dev/lightning_logs/version_181/hparams.yaml\n", + "DEBUG:fsspec.local:open file: /home/botu/Dev/rl4co-rebuttal/notebooks/dev/lightning_logs/version_181/hparams.yaml\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0]\n", + "INFO:rl4co.models.rl.common.base:Instantiating optimizer \n", + "\n", + " | Name | Type | Params\n", + "------------------------------------------------\n", + "0 | env | TSPEnv | 0 \n", + "1 | policy | AttentionModelPolicy | 710 K \n", + "------------------------------------------------\n", + "710 K Trainable params\n", + "0 Non-trainable params\n", + "710 K Total params\n", + "2.841 Total estimated model params size (MB)\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "75a65a8984b34ad780ce54612a4eaa01", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Sanity Checking: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:432: PossibleUserWarning: The dataloader, val_dataloader, does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` (try 32 which is the number of cpus on this machine) in the `DataLoader` init to improve performance.\n", + " rank_zero_warn(\n", + "/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:432: PossibleUserWarning: The dataloader, train_dataloader, does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` (try 32 which is the number of cpus on this machine) in the `DataLoader` init to improve performance.\n", + " rank_zero_warn(\n", + "/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/loops/fit_loop.py:280: PossibleUserWarning: The number of training batches (1) is smaller than the logging interval Trainer(log_every_n_steps=50). Set a lower value for log_every_n_steps if you want to see logs for the training epoch.\n", + " rank_zero_warn(\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "f94c336fc12c4d59b8cccb01fd176037", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Training: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/botu/Dev/rl4co-rebuttal/notebooks/dev/../../rl4co/models/zoo/eas/nn.py:22: UserWarning: nn.init.xavier_uniform is now deprecated in favor of nn.init.xavier_uniform_.\n", + " torch.nn.init.xavier_uniform(self.W1)\n", + "/home/botu/Dev/rl4co-rebuttal/notebooks/dev/../../rl4co/models/zoo/eas/nn.py:23: UserWarning: nn.init.xavier_uniform is now deprecated in favor of nn.init.xavier_uniform_.\n", + " torch.nn.init.xavier_uniform(self.b1)\n", + "INFO:rl4co.models.rl.common.base:Instantiating optimizer \n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/trainer/connectors/logger_connector/result.py:212: UserWarning: You called `self.log('step', ...)` in your `training_step` but the value needs to be floating point. Converting it to torch.float32.\n", + " warning_cache.warn(\n", + "INFO:rl4co.models.zoo.eas.search:0/20 | Reward: -15.52 \n", + "INFO:rl4co.models.zoo.eas.search:1/20 | Reward: -15.32 \n", + "INFO:rl4co.models.zoo.eas.search:2/20 | Reward: -15.30 \n", + "INFO:rl4co.models.zoo.eas.search:3/20 | Reward: -15.28 \n", + "INFO:rl4co.models.zoo.eas.search:4/20 | Reward: -15.01 \n", + "INFO:rl4co.models.zoo.eas.search:5/20 | Reward: -15.01 \n", + "INFO:rl4co.models.zoo.eas.search:6/20 | Reward: -15.01 \n", + "INFO:rl4co.models.zoo.eas.search:7/20 | Reward: -15.01 \n", + "INFO:rl4co.models.zoo.eas.search:8/20 | Reward: -15.01 \n", + "INFO:rl4co.models.zoo.eas.search:9/20 | Reward: -15.01 \n", + "INFO:rl4co.models.zoo.eas.search:10/20 | Reward: -15.01 \n", + "INFO:rl4co.models.zoo.eas.search:11/20 | Reward: -15.01 \n", + "INFO:rl4co.models.zoo.eas.search:12/20 | Reward: -15.01 \n", + "INFO:rl4co.models.zoo.eas.search:13/20 | Reward: -15.01 \n", + "INFO:rl4co.models.zoo.eas.search:14/20 | Reward: -15.01 \n", + "INFO:rl4co.models.zoo.eas.search:15/20 | Reward: -15.01 \n", + "INFO:rl4co.models.zoo.eas.search:16/20 | Reward: -15.01 \n", + "INFO:rl4co.models.zoo.eas.search:17/20 | Reward: -15.01 \n", + "INFO:rl4co.models.zoo.eas.search:18/20 | Reward: -14.84 \n", + "INFO:rl4co.models.zoo.eas.search:19/20 | Reward: -14.74 \n", + "INFO:rl4co.models.zoo.eas.search:Best reward: -14.74\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "9e6619ed6eae4a0ab770ebb08d266915", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:rl4co.models.zoo.eas.search:Saving solutions and rewards to eas_sols.pt...\n", + "`Trainer.fit` stopped: `max_epochs=1` reached.\n" + ] + } + ], + "source": [ + "from rl4co.utils.trainer import RL4COTrainer\n", + "\n", + "trainer = RL4COTrainer(\n", + " max_epochs=1,\n", + " gradient_clip_val=None,\n", + ")\n", + "\n", + "trainer.fit(eas_model)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load actions\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Load\n", + "actions = torch.load(\"eas_sols.pt\")[\"solutions\"][0].cpu()\n", + "actions = actions[:torch.count_nonzero(actions, dim=-1)] # remove trailing zeros\n", + "state = td_dataset.cpu()[0]\n", + "\n", + "env.render(state, actions)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Even with few iterations, the search method can clearly find better solutions than the initial ones!" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "env", + "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.11.6" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/modeling/2-transductive-methods/index.html b/examples/modeling/2-transductive-methods/index.html new file mode 100644 index 00000000..a7fd687f --- /dev/null +++ b/examples/modeling/2-transductive-methods/index.html @@ -0,0 +1,3625 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Transductive Methods - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/modeling/3-change-encoder/3-change-encoder.ipynb b/examples/modeling/3-change-encoder/3-change-encoder.ipynb new file mode 100644 index 00000000..b13cea60 --- /dev/null +++ b/examples/modeling/3-change-encoder/3-change-encoder.ipynb @@ -0,0 +1,520 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Encoder Customization\n", + "\n", + "In this notebook we will cover a tutorial for the flexible encoders!\n", + "\n", + "\"Open" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installation\n", + "\n", + "Uncomment the following line to install the package from PyPI. Remember to choose a GPU runtime for faster training!\n", + "\n", + "> Note: You may need to restart the runtime in Colab after this\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install rl4co[graph] # include torch-geometric\n", + "\n", + "## NOTE: to install latest version from Github (may be unstable) install from source instead:\n", + "# !pip install git+https://github.com/ai4co/rl4co.git" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Imports " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from rl4co.envs import CVRPEnv\n", + "\n", + "from rl4co.models.zoo import AttentionModel\n", + "from rl4co.utils.trainer import RL4COTrainer" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## A default minimal training script\n", + "\n", + "Here we use the CVRP environment and AM model as a minimal example of training script. By default, the AM is initialized with a Graph Attention Encoder, but we can change it to anything we want." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n", + "/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n", + "Using 16bit Automatic Mixed Precision (AMP)\n", + "GPU available: True (cuda), used: True\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "TPU available: False, using: 0 TPU cores\n", + "IPU available: False, using: 0 IPUs\n", + "HPU available: False, using: 0 HPUs\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Encoder: GraphAttentionEncoder\n" + ] + } + ], + "source": [ + "# Init env, model, trainer\n", + "env = CVRPEnv(generator_params=dict(num_loc=20))\n", + "\n", + "model = AttentionModel(\n", + " env, \n", + " baseline='rollout',\n", + " train_data_size=100_000, # really small size for demo\n", + " val_data_size=10_000\n", + ")\n", + " \n", + "trainer = RL4COTrainer(\n", + " max_epochs=3, # few epochs for demo\n", + " accelerator='gpu',\n", + " devices=1,\n", + " logger=False,\n", + ")\n", + "\n", + "# By default the AM uses the Graph Attention Encoder\n", + "print(f'Encoder: {model.policy.encoder._get_name()}')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/callbacks/model_checkpoint.py:630: Checkpoint directory /datasets/home/botu/Dev/rl4co/notebooks/tutorials/checkpoints exists and is not empty.\n", + "val_file not set. Generating dataset instead\n", + "test_file not set. Generating dataset instead\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "\n", + " | Name | Type | Params\n", + "--------------------------------------------------\n", + "0 | env | CVRPEnv | 0 \n", + "1 | policy | AttentionModelPolicy | 694 K \n", + "2 | baseline | WarmupBaseline | 694 K \n", + "--------------------------------------------------\n", + "1.4 M Trainable params\n", + "0 Non-trainable params\n", + "1.4 M Total params\n", + "5.553 Total estimated model params size (MB)\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "3db02ec8f6dc4913a26462bbc1a851e8", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Sanity Checking: | | 0/? [00:00 Note: while we provide these examples, you can also implement your own encoder and use it in RL4CO! For instance, you may use different encoders (and decoders) to solve problems that require e.g. distance matrices as input" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# Before we init, we need to install the graph neural network dependencies\n", + "# !pip install rl4co[graph]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n", + "/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n", + "Using 16bit Automatic Mixed Precision (AMP)\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "IPU available: False, using: 0 IPUs\n", + "HPU available: False, using: 0 HPUs\n" + ] + } + ], + "source": [ + "# Init the model with different encoder\n", + "from rl4co.models.nn.graph.gcn import GCNEncoder\n", + "from rl4co.models.nn.graph.mpnn import MessagePassingEncoder\n", + "\n", + "gcn_encoder = GCNEncoder(\n", + " env_name='cvrp', \n", + " embed_dim=128,\n", + " num_nodes=20, \n", + " num_layers=3,\n", + ")\n", + "\n", + "mpnn_encoder = MessagePassingEncoder(\n", + " env_name='cvrp', \n", + " embed_dim=128,\n", + " num_nodes=20, \n", + " num_layers=3,\n", + ")\n", + "\n", + "model = AttentionModel(\n", + " env, \n", + " baseline='rollout',\n", + " train_data_size=100_000, # really small size for demo\n", + " val_data_size=10_000, \n", + " policy_kwargs={\n", + " 'encoder': gcn_encoder # gcn_encoder or mpnn_encoder\n", + " }\n", + ")\n", + " \n", + "trainer = RL4COTrainer(\n", + " max_epochs=3, # few epochs for demo\n", + " accelerator='gpu',\n", + " devices=1,\n", + " logger=False,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/callbacks/model_checkpoint.py:630: Checkpoint directory /datasets/home/botu/Dev/rl4co/notebooks/tutorials/checkpoints exists and is not empty.\n", + "val_file not set. Generating dataset instead\n", + "test_file not set. Generating dataset instead\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "\n", + " | Name | Type | Params\n", + "--------------------------------------------------\n", + "0 | env | CVRPEnv | 0 \n", + "1 | policy | AttentionModelPolicy | 148 K \n", + "2 | baseline | WarmupBaseline | 148 K \n", + "--------------------------------------------------\n", + "297 K Trainable params\n", + "0 Non-trainable params\n", + "297 K Total params\n", + "1.191 Total estimated model params size (MB)\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "81c30fe25912497bb53cfb492810c655", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Sanity Checking: | | 0/? [00:00 Tuple[Tensor, Tensor]:\n", + " \"\"\"\n", + " Args:\n", + " td: Input TensorDict containing the environment state\n", + " mask: Mask to apply to the attention\n", + "\n", + " Returns:\n", + " h: Latent representation of the input\n", + " init_h: Initial embedding of the input\n", + " \"\"\"\n", + " init_h = self.init_embedding(td)\n", + " h = None\n", + " return h, init_h" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "rl4co", + "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.11.6" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/modeling/3-change-encoder/index.html b/examples/modeling/3-change-encoder/index.html new file mode 100644 index 00000000..f960bef4 --- /dev/null +++ b/examples/modeling/3-change-encoder/index.html @@ -0,0 +1,3669 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Encoder Customization - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+ +
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/modeling/README.md b/examples/modeling/README.md new file mode 100644 index 00000000..e42b1884 --- /dev/null +++ b/examples/modeling/README.md @@ -0,0 +1,10 @@ +# Modeling + +Collection of examples on models and related topics. + + +## Index + +- [`1-decoding-strategies.ipynb`](1-decoding-strategies.ipynb): here we show how to use different decoding strategies at inference time, such as greedy evaluation, beam search, and various sampling methods including top-k and nucleus sampling. +- [`2-transductive-methods.ipynb`](2-transductive-methods.ipynb): here we show how to use transductive methods (i.e. online / test time optimization) such as EAS. +- [`3-change-encoder.ipynb`](3-change-encoder.ipynb): here we show how to change the encoder of a model. diff --git a/examples/modeling/index.html b/examples/modeling/index.html new file mode 100644 index 00000000..b509aa40 --- /dev/null +++ b/examples/modeling/index.html @@ -0,0 +1,2386 @@ + + + + + + + + + + + + + + + + + + + + + + + Modeling - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ + + + + + + + + +

Modeling

+

Collection of examples on models and related topics.

+

Index

+
    +
  • 1-decoding-strategies.ipynb: here we show how to use different decoding strategies at inference time, such as greedy evaluation, beam search, and various sampling methods including top-k and nucleus sampling.
  • +
  • 2-transductive-methods.ipynb: here we show how to use transductive methods (i.e. online / test time optimization) such as EAS.
  • +
  • 3-change-encoder.ipynb: here we show how to change the encoder of a model.
  • +
+ + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/other/1-mtvrp/1-mtvrp.ipynb b/examples/other/1-mtvrp/1-mtvrp.ipynb new file mode 100644 index 00000000..449df935 --- /dev/null +++ b/examples/other/1-mtvrp/1-mtvrp.ipynb @@ -0,0 +1,647 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# MTVRP: Multi-task VRP environment\n", + "\n", + "\"Open\n", + "\n", + "\n", + "This environment can handle _any_ of the following variants:\n", + "\n", + "\n", + "| VRP Variant | Capacity (C) | Open Route (O) | Backhaul (B) | Duration Limit (L) | Time Window (TW) |\n", + "|-------------|--------------|----------------|--------------|--------------------|------------------|\n", + "| CVRP | ✔ | | | | |\n", + "| OVRP | ✔ | ✔ | | | |\n", + "| VRPB | ✔ | | ✔ | | |\n", + "| VRPL | ✔ | | | ✔ | |\n", + "| VRPTW | ✔ | | | | ✔ |\n", + "| OVRPTW | ✔ | ✔ | | | ✔ |\n", + "| OVRPB | ✔ | ✔ | ✔ | | |\n", + "| OVRPL | ✔ | ✔ | | ✔ | |\n", + "| VRPBL | ✔ | | ✔ | ✔ | |\n", + "| VRPBTW | ✔ | | ✔ | | ✔ |\n", + "| VRPLTW | ✔ | | | ✔ | ✔ |\n", + "| OVRPBL | ✔ | ✔ | ✔ | ✔ | |\n", + "| OVRPBTW | ✔ | ✔ | ✔ | | ✔ |\n", + "| OVRPLTW | ✔ | ✔ | | ✔ | ✔ |\n", + "| VRPBLTW | ✔ | | ✔ | ✔ | ✔ |\n", + "| OVRPBLTW | ✔ | ✔ | ✔ | ✔ | ✔ |\n", + "\n", + "\n", + "It is fully batched, meaning that _different variants can be in the same batch_ too!\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning_utilities/core/imports.py:14: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html\n", + " import pkg_resources\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/pkg_resources/__init__.py:2832: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('sphinxcontrib')`.\n", + "Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages\n", + " declare_namespace(pkg)\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/fabric/__init__.py:41: Deprecated call to `pkg_resources.declare_namespace('lightning.fabric')`.\n", + "Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/pkg_resources/__init__.py:2317: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('lightning')`.\n", + "Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages\n", + " declare_namespace(parent)\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/__init__.py:37: Deprecated call to `pkg_resources.declare_namespace('lightning.pytorch')`.\n", + "Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/pkg_resources/__init__.py:2317: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('lightning')`.\n", + "Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages\n", + " declare_namespace(parent)\n" + ] + } + ], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "from rl4co.envs.routing.mtvrp.env import MTVRPEnv\n", + "from rl4co.envs.routing.mtvrp.generator import MTVRPGenerator" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's now generate some variants! By default, we can generate all variants with the `variants_preset` variable" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['VRPLTW', 'OVRP', 'VRPLTW', 'OVRPLTW', 'OVRPL', 'VRPB', 'OVRPTW', 'OVRPB']" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Single feat: generate a distribution of single-featured environments\n", + "generator = MTVRPGenerator(num_loc=50, variant_preset=\"all\")\n", + "env = MTVRPEnv(generator, check_solution=False)\n", + "\n", + "td_data = env.generator(8)\n", + "env.get_variant_names(td_data)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "all: {'O': 0.5, 'TW': 0.5, 'L': 0.5, 'B': 0.5}\n", + "single_feat: {'O': 0.5, 'TW': 0.5, 'L': 0.5, 'B': 0.5}\n", + "single_feat_otw: {'O': 0.5, 'TW': 0.5, 'L': 0.5, 'B': 0.5, 'OTW': 0.5}\n", + "cvrp: {'O': 0.0, 'TW': 0.0, 'L': 0.0, 'B': 0.0}\n", + "ovrp: {'O': 1.0, 'TW': 0.0, 'L': 0.0, 'B': 0.0}\n", + "vrpb: {'O': 0.0, 'TW': 0.0, 'L': 0.0, 'B': 1.0}\n", + "vrpl: {'O': 0.0, 'TW': 0.0, 'L': 1.0, 'B': 0.0}\n", + "vrptw: {'O': 0.0, 'TW': 1.0, 'L': 0.0, 'B': 0.0}\n", + "ovrptw: {'O': 1.0, 'TW': 1.0, 'L': 0.0, 'B': 0.0}\n", + "ovrpb: {'O': 1.0, 'TW': 0.0, 'L': 0.0, 'B': 1.0}\n", + "ovrpl: {'O': 1.0, 'TW': 0.0, 'L': 1.0, 'B': 0.0}\n", + "vrpbl: {'O': 0.0, 'TW': 0.0, 'L': 1.0, 'B': 1.0}\n", + "vrpbtw: {'O': 0.0, 'TW': 1.0, 'L': 0.0, 'B': 1.0}\n", + "vrpltw: {'O': 0.0, 'TW': 1.0, 'L': 1.0, 'B': 0.0}\n", + "ovrpbl: {'O': 1.0, 'TW': 0.0, 'L': 1.0, 'B': 1.0}\n", + "ovrpbtw: {'O': 1.0, 'TW': 1.0, 'L': 0.0, 'B': 1.0}\n", + "ovrpltw: {'O': 1.0, 'TW': 1.0, 'L': 1.0, 'B': 0.0}\n", + "vrpbltw: {'O': 0.0, 'TW': 1.0, 'L': 1.0, 'B': 1.0}\n", + "ovrpbltw: {'O': 1.0, 'TW': 1.0, 'L': 1.0, 'B': 1.0}\n" + ] + } + ], + "source": [ + "# Here is the list of presets and their probabilities of being generated (fully customizable)\n", + "env.print_presets()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can change the preset to generate some specific variant, for instance the VRPB" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "vrpb selected. Will not use feature combination!\n" + ] + }, + { + "data": { + "text/plain": [ + "['VRPB', 'VRPB', 'VRPB', 'VRPB', 'VRPB', 'VRPB', 'VRPB', 'VRPB']" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Change generator\n", + "generator = MTVRPGenerator(num_loc=50, variant_preset=\"vrpb\")\n", + "env.generator = generator\n", + "td_data = env.generator(8)\n", + "env.get_variant_names(td_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Greedy rollout and plot" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import torch\n", + "from rl4co.utils.ops import gather_by_index\n", + "\n", + "\n", + "# Simple heuristics (nearest neighbor + capacity check)\n", + "def greedy_policy(td):\n", + " \"\"\"Select closest available action\"\"\"\n", + " available_actions = td[\"action_mask\"]\n", + " # distances\n", + " curr_node = td[\"current_node\"]\n", + " loc_cur = gather_by_index(td[\"locs\"], curr_node)\n", + " distances_next = torch.cdist(loc_cur[:, None, :], td[\"locs\"], p=2.0).squeeze(1)\n", + "\n", + " distances_next[~available_actions.bool()] = float(\"inf\")\n", + " # do not select depot if some capacity is left\n", + " distances_next[:, 0] = float(\"inf\") * (\n", + " td[\"used_capacity_linehaul\"] < td[\"vehicle_capacity\"]\n", + " ).float().squeeze(-1)\n", + "\n", + " # # if sum of available actions is 0, select depot\n", + " # distances_next[available_actions.sum(-1) == 0, 0] = 0\n", + " action = torch.argmin(distances_next, dim=-1)\n", + " td.set(\"action\", action)\n", + " return td\n", + "\n", + "\n", + "def rollout(env, td, policy=greedy_policy, max_steps: int = None):\n", + " \"\"\"Helper function to rollout a policy. Currently, TorchRL does not allow to step\n", + " over envs when done with `env.rollout()`. We need this because for environments that complete at different steps.\n", + " \"\"\"\n", + "\n", + " max_steps = float(\"inf\") if max_steps is None else max_steps\n", + " actions = []\n", + " steps = 0\n", + "\n", + " while not td[\"done\"].all():\n", + " td = policy(td)\n", + " actions.append(td[\"action\"])\n", + " td = env.step(td)[\"next\"]\n", + " steps += 1\n", + " if steps > max_steps:\n", + " print(\"Max steps reached\")\n", + " break\n", + " return torch.stack(actions, dim=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cost: 17.503389358520508\n", + "Problem: OVRPLTW\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cost: 18.86773109436035\n", + "Problem: CVRP\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cost: 15.39835262298584\n", + "Problem: VRPB\n" + ] + } + ], + "source": [ + "# NOTE: if we don't select ovrpbltw, the below does not work and there is still some\n", + "# minor bug in either masking or variant subselection\n", + "\n", + "generator = MTVRPGenerator(num_loc=50, variant_preset=\"all\")\n", + "env.generator = generator\n", + "td_data = env.generator(3)\n", + "variant_names = env.get_variant_names(td_data)\n", + "\n", + "td = env.reset(td_data)\n", + "\n", + "actions = rollout(env, td.clone(), greedy_policy)\n", + "rewards = env.get_reward(td, actions)\n", + "\n", + "for idx in [0, 1, 2]:\n", + " env.render(td[idx], actions[idx])\n", + " print(\"Cost: \", - rewards[idx].item())\n", + " print(\"Problem: \", variant_names[idx])\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Train MVMoE on Multiple Problems" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "single_feat selected. Will not use feature combination!\n" + ] + } + ], + "source": [ + "from rl4co.utils.trainer import RL4COTrainer\n", + "from rl4co.models.zoo import MVMoE_POMO\n", + "\n", + "device_id = 0\n", + "device = torch.device(f\"cuda:{device_id}\" if torch.cuda.is_available() else \"cpu\")\n", + "generator = MTVRPGenerator(num_loc=50, variant_preset=\"single_feat\")\n", + "env = MTVRPEnv(generator, check_solution=False)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n", + "Using 16bit Automatic Mixed Precision (AMP)\n", + "GPU available: True (cuda), used: True\n", + "TPU available: False, using: 0 TPU cores\n", + "IPU available: False, using: 0 IPUs\n", + "HPU available: False, using: 0 HPUs\n", + "/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/logger_connector/logger_connector.py:75: Starting from v1.9.0, `tensorboardX` has been removed as a dependency of the `lightning.pytorch` package, due to potential conflicts with other packages in the ML ecosystem. For this reason, `logger=True` will use `CSVLogger` as the default logger, unless the `tensorboard` or `tensorboardX` packages are found. Please `pip install lightning[extra]` or one of them to enable TensorBoard support by default\n", + "Missing logger folder: /home/botu/Dev/rl4co/examples/other/lightning_logs\n", + "val_file not set. Generating dataset instead\n", + "test_file not set. Generating dataset instead\n", + "LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n", + "\n", + " | Name | Type | Params\n", + "--------------------------------------------------\n", + "0 | env | MTVRPEnv | 0 \n", + "1 | policy | AttentionModelPolicy | 3.7 M \n", + "2 | baseline | SharedBaseline | 0 \n", + "--------------------------------------------------\n", + "3.7 M Trainable params\n", + "0 Non-trainable params\n", + "3.7 M Total params\n", + "14.868 Total estimated model params size (MB)\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "bac126d9831c49da91319e21e79150e1", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Sanity Checking: | | 0/? [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cost: 17.188127517700195\n", + "Problem: OVRPLTW\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cost: 14.578388214111328\n", + "Problem: CVRP\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cost: 12.24499797821045\n", + "Problem: VRPB\n" + ] + } + ], + "source": [ + "# Greedy rollouts over trained model (same states as previous plot)\n", + "policy = model.policy.to(device)\n", + "out = policy(td.to(device).clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True)\n", + "actions_mvmoe = out['actions'].cpu().detach()\n", + "rewards_mvmoe = out['reward'].cpu().detach()\n", + "\n", + "for idx in [0, 1, 2]:\n", + " env.render(td[idx], actions_mvmoe[idx])\n", + " print(\"Cost: \", -rewards_mvmoe[idx].item())\n", + " print(\"Problem: \", variant_names[idx])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Getting gaps to classical solvers\n", + "\n", + "\n", + "We additionally offer an optional `solve` API to get solutions from classical solvers. We can use this to get the gaps to the optimal solutions." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "# PyVRP - HGS\n", + "pyvrp_actions, pyvrp_costs = env.solve(td, max_runtime=5, num_procs=10, solver=\"pyvrp\")\n", + "rewards_pyvrp = env.get_reward(td, pyvrp_actions)" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([-17.1881, -14.5784, -12.2450]) tensor([-17.5034, -18.8677, -15.3984]) tensor([-12.6954, -11.9107, -9.9261])\n", + "Gap to HGS (NI): 50.47%\n", + "Gap to HGS (MVMoE): 27.05%\n" + ] + } + ], + "source": [ + "def calculate_gap(cost, bks): \n", + " gaps = (cost - bks) / bks\n", + " return gaps.mean() * 100\n", + "\n", + "# Nearest insertion\n", + "actions = rollout(env, td.clone(), greedy_policy)\n", + "rewards_ni = env.get_reward(td, actions)\n", + "\n", + "print(rewards_mvmoe, rewards_ni, rewards_pyvrp) \n", + "print(f\"Gap to HGS (NI): {calculate_gap(-rewards_ni, -rewards_pyvrp):.2f}%\")\n", + "print(f\"Gap to HGS (MVMoE): {calculate_gap(-rewards_mvmoe, -rewards_pyvrp):.2f}%\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With only two short epochs, we can already get better than NI!" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "env", + "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.11.8" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/other/1-mtvrp/index.html b/examples/other/1-mtvrp/index.html new file mode 100644 index 00000000..ee0b82fd --- /dev/null +++ b/examples/other/1-mtvrp/index.html @@ -0,0 +1,3996 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + MTVRP: Multi-task VRP environment - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/other/2-scheduling/2-scheduling.ipynb b/examples/other/2-scheduling/2-scheduling.ipynb new file mode 100644 index 00000000..ffe6782b --- /dev/null +++ b/examples/other/2-scheduling/2-scheduling.ipynb @@ -0,0 +1,829 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Solving the Flexible Job-Shop Scheduling Problem (FJSP)\n", + "\n", + "The following notebook explains the FJSP and explains the solution construction process using an encoder-decoder architecture based on a Heterogeneous Graph Neural Network (HetGNN)\n", + "\n", + "\"Open" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: torch_geometric in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (2.5.0)\n", + "Requirement already satisfied: tqdm in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (4.66.1)\n", + "Requirement already satisfied: numpy in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (1.26.3)\n", + "Requirement already satisfied: scipy in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (1.11.4)\n", + "Requirement already satisfied: fsspec in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (2023.12.2)\n", + "Requirement already satisfied: jinja2 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (3.1.3)\n", + "Requirement already satisfied: aiohttp in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (3.9.1)\n", + "Requirement already satisfied: requests in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (2.31.0)\n", + "Requirement already satisfied: pyparsing in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (3.1.1)\n", + "Requirement already satisfied: scikit-learn in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (1.4.1.post1)\n", + "Requirement already satisfied: psutil>=5.8.0 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (5.9.7)\n", + "Requirement already satisfied: attrs>=17.3.0 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from aiohttp->torch_geometric) (23.2.0)\n", + "Requirement already satisfied: multidict<7.0,>=4.5 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from aiohttp->torch_geometric) (6.0.4)\n", + "Requirement already satisfied: yarl<2.0,>=1.0 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from aiohttp->torch_geometric) (1.9.4)\n", + "Requirement already satisfied: frozenlist>=1.1.1 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from aiohttp->torch_geometric) (1.4.1)\n", + "Requirement already satisfied: aiosignal>=1.1.2 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from aiohttp->torch_geometric) (1.3.1)\n", + "Requirement already satisfied: async-timeout<5.0,>=4.0 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from aiohttp->torch_geometric) (4.0.3)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from jinja2->torch_geometric) (2.1.3)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from requests->torch_geometric) (3.3.2)\n", + "Requirement already satisfied: idna<4,>=2.5 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from requests->torch_geometric) (3.6)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from requests->torch_geometric) (1.26.18)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from requests->torch_geometric) (2023.11.17)\n", + "Requirement already satisfied: joblib>=1.2.0 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from scikit-learn->torch_geometric) (1.3.2)\n", + "Requirement already satisfied: threadpoolctl>=2.0.0 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from scikit-learn->torch_geometric) (3.3.0)\n" + ] + } + ], + "source": [ + "! pip install torch_geometric" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "import torch\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from IPython.display import display, clear_output\n", + "import time\n", + "import networkx as nx\n", + "import matplotlib.pyplot as plt\n", + "from rl4co.envs import FJSPEnv\n", + "from rl4co.models.zoo.l2d import L2DModel\n", + "from rl4co.models.zoo.l2d.policy import L2DPolicy\n", + "from rl4co.models.zoo.l2d.decoder import L2DDecoder\n", + "from rl4co.models.nn.graph.hgnn import HetGNNEncoder\n", + "from rl4co.utils.trainer import RL4COTrainer" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "generator_params = {\n", + " \"num_jobs\": 5, # the total number of jobs\n", + " \"num_machines\": 5, # the total number of machines that can process operations\n", + " \"min_ops_per_job\": 1, # minimum number of operatios per job\n", + " \"max_ops_per_job\": 2, # maximum number of operations per job\n", + " \"min_processing_time\": 1, # the minimum time required for a machine to process an operation\n", + " \"max_processing_time\": 20, # the maximum time required for a machine to process an operation\n", + " \"min_eligible_ma_per_op\": 1, # the minimum number of machines capable to process an operation\n", + " \"max_eligible_ma_per_op\": 2, # the maximum number of machines capable to process an operation\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "env = FJSPEnv(generator_params=generator_params)\n", + "td = env.reset(batch_size=[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualize the Problem\n", + "\n", + "Below we visualize the generated instance of the FJSP. Blue nodes correspond to machines, red nodes to operations and yellow nodes to jobs. A machine may process an operation if there exists an edge between the two. \n", + "\n", + "The thickness of the connection between a machine and an operation node specifies the processing time the respective machine needs to process the operation (thicker line := longer processing).\n", + "\n", + "Each operation belongs to exactly one job, where an edge between a job and an operation node indicates that the respective operation belongs to the job. The number above an operation-job edge specifies the precedence-order in which the operations of a job need to be processed. A job is done when all operations belonging to it are scheduled. The instance is solved when all jobs are fully scheduled.\n", + "\n", + "Also note that some operation nodes are not connected. These operation nodes are padded, so that all instances in a batch have the same number of operations (where we determine the maximum number of operations as num_jobs * max_ops_per_job). " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "jupyter": { + "source_hidden": true + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Create a bipartite graph from the adjacency matrix\n", + "G = nx.Graph()\n", + "proc_times = td[\"proc_times\"].squeeze(0)\n", + "job_ops_adj = td[\"job_ops_adj\"].squeeze(0)\n", + "order = td[\"ops_sequence_order\"].squeeze(0) + 1\n", + "\n", + "num_machines, num_operations = proc_times.shape\n", + "num_jobs = job_ops_adj.size(0)\n", + "\n", + "jobs = [f\"j{i+1}\" for i in range(num_jobs)]\n", + "machines = [f\"m{i+1}\" for i in range(num_machines)]\n", + "operations = [f\"o{i+1}\" for i in range(num_operations)]\n", + "\n", + "# Add nodes from each set\n", + "G.add_nodes_from(machines, bipartite=0)\n", + "G.add_nodes_from(operations, bipartite=1)\n", + "G.add_nodes_from(jobs, bipartite=2)\n", + "\n", + "# Add edges based on the adjacency matrix\n", + "for i in range(num_machines):\n", + " for j in range(num_operations):\n", + " edge_weigth = proc_times[i][j]\n", + " if edge_weigth != 0:\n", + " G.add_edge(f\"m{i+1}\", f\"o{j+1}\", weight=edge_weigth)\n", + "\n", + "\n", + "# Add edges based on the adjacency matrix\n", + "for i in range(num_jobs):\n", + " for j in range(num_operations):\n", + " edge_weigth = job_ops_adj[i][j]\n", + " if edge_weigth != 0:\n", + " G.add_edge(f\"j{i+1}\", f\"o{j+1}\", weight=3, label=order[j])\n", + "\n", + "\n", + "widths = [x / 3 for x in nx.get_edge_attributes(G, 'weight').values()]\n", + "\n", + "plt.figure(figsize=(10,6))\n", + "# Plot the graph\n", + "\n", + "machines = [n for n, d in G.nodes(data=True) if d['bipartite'] == 0]\n", + "operations = [n for n, d in G.nodes(data=True) if d['bipartite'] == 1]\n", + "jobs = [n for n, d in G.nodes(data=True) if d['bipartite'] == 2]\n", + "\n", + "pos = {}\n", + "pos.update((node, (1, index)) for index, node in enumerate(machines))\n", + "pos.update((node, (2, index)) for index, node in enumerate(operations))\n", + "pos.update((node, (3, index)) for index, node in enumerate(jobs))\n", + "\n", + "edge_labels = {(u, v): d['label'].item() for u, v, d in G.edges(data=True) if d.get(\"label\") is not None}\n", + "nx.draw_networkx_edge_labels(G, {k: (v[0]+.12, v[1]) for k,v in pos.items()}, edge_labels=edge_labels, rotate=False)\n", + "\n", + "nx.draw_networkx_nodes(G, pos, nodelist=machines, node_color='b', label=\"Machine\")\n", + "nx.draw_networkx_nodes(G, pos, nodelist=operations, node_color='r', label=\"Operation\")\n", + "nx.draw_networkx_nodes(G, pos, nodelist=jobs, node_color='y', label=\"jobs\")\n", + "nx.draw_networkx_edges(G, pos, width=widths, alpha=0.6)\n", + "\n", + "plt.title('Visualization of the FJSP')\n", + "plt.legend(bbox_to_anchor=(.95, 1.05))\n", + "plt.axis('off')\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Build a Model to Solve the FJSP\n", + "\n", + "In the FJSP we typically encode Operations and Machines separately, since they pose different node types in a k-partite Graph. Therefore, the encoder for the FJSP returns two hidden representations, the first containing machine embeddings and the second containing operation embeddings:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# Lets generate a more complex instance\n", + "\n", + "generator_params = {\n", + " \"num_jobs\": 10, # the total number of jobs\n", + " \"num_machines\": 5, # the total number of machines that can process operations\n", + " \"min_ops_per_job\": 4, # minimum number of operatios per job\n", + " \"max_ops_per_job\": 6, # maximum number of operations per job\n", + " \"min_processing_time\": 1, # the minimum time required for a machine to process an operation\n", + " \"max_processing_time\": 20, # the maximum time required for a machine to process an operation\n", + " \"min_eligible_ma_per_op\": 1, # the minimum number of machines capable to process an operation\n", + " \"max_eligible_ma_per_op\": 5, # the maximum number of machines capable to process an operation\n", + "}\n", + "\n", + "env = FJSPEnv(generator_params=generator_params)\n", + "td = env.reset(batch_size=[1])" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "torch.Size([1, 60, 32])\n", + "torch.Size([1, 5, 32])\n" + ] + } + ], + "source": [ + "encoder = HetGNNEncoder(embed_dim=32, num_layers=2)\n", + "(ma_emb, op_emb), init = encoder(td)\n", + "print(ma_emb.shape)\n", + "print(op_emb.shape)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The decoder return logits over a composite action-space of size (1 + num_jobs * num_machines), where each entry corresponds to a machine-job combination plus one **waiting**-operation. The selected action specifies, which job is processed next by which machine. To be more precise, the next operation of the selected job is processed. This operation can be retrieved from __td[\"next_op\"]__" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([[ 0, 4, 10, 15, 21, 27, 33, 39, 45, 49]])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# next operation per job\n", + "td[\"next_op\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "torch.Size([1, 51])\n" + ] + } + ], + "source": [ + "decoder = L2DDecoder(env_name=env.name, embed_dim=32)\n", + "logits, mask = decoder(td, (ma_emb, op_emb), num_starts=0)\n", + "# (1 + num_jobs * num_machines)\n", + "print(logits.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "def make_step(td):\n", + " logits, mask = decoder(td, (ma_emb, op_emb), num_starts=0)\n", + " action = logits.masked_fill(~mask, -torch.inf).argmax(1)\n", + " td[\"action\"] = action\n", + " td = env.step(td)[\"next\"]\n", + " return td" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualize solution construction\n", + "\n", + "Starting at $t=0$, the decoder uses the machine-operation embeddings of the encoder to decide which machine-**job**-combination to schedule next. Note, that due to the precedence relationship, the operations to be scheduled next are fixed per job. Therefore, it is sufficient to determine the next job to be scheduled, which significantly reduces the action space. \n", + "\n", + "After some operations have been scheduled, either all the machines are busy or all the jobs have been scheduled with their currently active operation. In this case, the environment transitions to a new time step $t$. The new $t$ will be equal to the first time step where a machine finishes an operation in the partial schedule. When an operation is finished, the machine that has processed it is immediately ready to process the next operation. Also, the next operation of the respective job can then be scheduled.\n", + "\n", + "The start time of an operation is always equal to the time step in which it is scheduled. The finish time of an operation is equal to its start time plus the processing time required by the machine on which it is being processed.\n", + "\n", + "The figure below visualises this process. " + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAnYAAAHWCAYAAAD6oMSKAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAClyUlEQVR4nOzdeVxU9frA8c8MMOz7jgguGIJopGaallqZe9pyvVlahrfS6qem4ZKVZmWWeS27ZeVKlldvuZTerloappSGa5ooigriwjrsMAzM/P4gJkaQdWZAet6vl76YM9/5Ps85Z2Ce+Z5zvkeh1+v1CCGEEEKIm56yuRMQQgghhBCmIYWdEEIIIUQrIYWdEEIIIUQrIYWdEEIIIUQrIYWdEEIIIUQrIYWdEEIIIUQrIYWdEEIIIUQrIYWdEEIIIUQrIYWdEEIIIUQrIYWdEEJUERsbi0Kh4Ouvv27uVIQQosGksBNC3NCFCxd44YUXuOWWW3BwcMDBwYHw8HCef/55fvvtN7PHX7hwIVu3bq22/Oeff2b+/Pnk5OQ0qL/Y2Fgeeugh/Pz8UKlU+Pj4MHLkSDZv3myahBth/fr1vP/++80WXwjRukhhJ4So0fbt24mIiGDdunXcd999LF26lA8++IChQ4fy3XffERkZSXJysllzqK2we/311xtU2M2bN4+BAwdy8uRJnn32WT755BOio6MpKCjg4YcfZv369aZLvAGksBNCmJJ1cycghGh5kpKSePTRRwkODmb37t34+/sbPf/OO+/w8ccfo1TeHN8Nv/76axYsWMAjjzzC+vXrsbGxMTwXHR3Nzp070Wq1Fs2psLAQR0dHi8YUQvwF6IUQ4jrPPPOMHtAfOHCg3q85fvy4/sknn9S3b99eb2trq/f19dU/9dRT+szMTKN28+bN0wP6s2fP6p988km9q6ur3sXFRT9hwgR9YWGhoR1Q7d+TTz5peP31/y5cuHDD3Dp37qz38PDQ5+Xl1bkeP/74ox7Qb9y4Uf/mm2/q27Rpo7e1tdXfc889+rNnzxq1/emnn/SPPPKIvm3btnqVSqUPDAzUT5s2TV9UVGTU7sknn9Q7Ojrqz507px86dKjeyclJP2rUKH3//v2rrUdwcHDdG1sIIW5ARuyEENVs376dkJAQ7rjjjnq/5vvvv+f8+fM89dRT+Pn58fvvv/PZZ5/x+++/c+DAARQKhVH7MWPG0L59e95++22OHDnCypUr8fHx4Z133gFg3bp1/OMf/6BXr14888wzAHTs2BFHR0cSExP597//zdKlS/Hy8gLA29u7xrzOnj3L6dOniYqKwtnZud7rs2jRIpRKJS+99BK5ubm8++67PP744xw8eNDQ5quvvqKoqIjJkyfj6enJr7/+yocffkhqaipfffWVUX9lZWUMHjyYfv368d577+Hg4ICfnx+5ubmkpqaydOlSAJycnOqdoxBCVNPclaUQomXJzc3VA/rRo0dXe06tVuszMjIM/6qOTF0/SqXX6/X//ve/9YD+p59+MiyrHHGLiooyavvggw/qPT09jZY5Ojrqn3zyyWr9Ll68uM5RukrffPONHtAvXbq0zrZ6/Z8jdmFhYXqNRmNY/sEHH+gB/YkTJwzLalrnt99+W69QKPTJycmGZU8++aQe0M+ePbta++HDh8sonRDCZG6OE2SEEBaTl5cH1DxyNGDAALy9vQ3/PvroI8Nz9vb2hp9LSkrIzMykd+/eABw5cqRaX5MmTTJ6fNddd5GVlWWIbyqV/TVktA7gqaeeQqVSGeUHcP78ecOyqutcWFhIZmYmd955J3q9nqNHj1brc/LkyQ3KQQghGkoKOyGEkcoCqKCgoNpzn376Kd9//z1ffPFFteeys7OZOnUqvr6+2Nvb4+3tTfv27QHIzc2t1j4oKMjosbu7OwBqtbrJ61CVi4sLAPn5+Q16XX3yS0lJYcKECXh4eODk5IS3tzf9+/cHqq+ztbU1gYGBDc5fCCEaQs6xE0IYcXV1xd/fn5MnT1Z7rvKcu4sXL1Z7bsyYMfz8889ER0cTGRmJk5MTOp2OIUOGoNPpqrW3srKqMb5er2/aClync+fOAJw4caJBr6srv/LycgYNGkR2djazZs2ic+fOODo6cvnyZSZMmFBtnW1tbW+aq4iFEDcvKeyEENUMHz6clStX8uuvv9KrV68626vVanbv3s3rr7/Oa6+9Zlh+9uzZJuVx/QUXdS2vyS233EJoaCjffPMNH3zwgckuTjhx4gSJiYnExMTwxBNPGJZ///33DeqnIesihBB1ka+PQohqZs6ciYODA1FRUaSlpVV7/vpRtcrRreuXN3XiXUdHxxonIa6c/62+ExS//vrrZGVl8Y9//IOysrJqz+/atYvt27c3KLea1lmv1/PBBx80qB9HR8caD1ULIURjyIidEKKaTp06sX79esaOHUtoaCiPP/44t956K3q9ngsXLrB+/XqUSqXhnDEXFxfuvvtu3n33XbRaLW3atGHXrl1cuHChSXn06NGDH374gX/+858EBATQvn177rjjDnr06AHA3LlzefTRR7GxsWHkyJE3nPD373//OydOnOCtt97i6NGjjB07luDgYLKystixYwe7d+9u8J0nOnfuTMeOHXnppZe4fPkyLi4ubNq0qcHnCPbo0YONGzcyffp0br/9dpycnBg5cmSD+hBCCIPmuyBXCNHSnTt3Tj958mR9SEiI3s7OTm9vb6/v3LmzftKkSfpjx44ZtU1NTdU/+OCDejc3N72rq6v+b3/7m/7KlSt6QD9v3jxDu8rpTjIyMoxev2bNmmpTmJw+fVp/99136+3t7Q0TFFd644039G3atNErlcp6T32ye/du/ahRo/Q+Pj56a2trvbe3t37kyJH6b775xtCmcrqTr776yui1Fy5c0AP6NWvWGJadOnVKf9999+mdnJz0Xl5e+qefflp//Pjxau0qJyiuSUFBgf6xxx7Tu7m5yQTFQogmU+j1Jj5TWQghhBBCNAs5x04IIYQQopWQwk4IIYQQopWQwk4IIYQQopWQwk4IIYQQopWQwk4IIYQQopWQwk4IIYQQopWQCYotRKfTceXKFZydneUWQkIIIW5qer2e/Px8AgIC5B7ILYwUdhZy5coV2rZt29xpCCGEECZz6dIlwx1oRMsghZ2FODs7AxW/BC4uLs2cjRBCCNF4eXl5tG3b1vDZJloOKewspPLwq4uLixR2QgghWgU5tajlkQPjQgghhBCthBR2QgghhBCthBR2QgghhBCthBR2QgghhBCthBR2QgghhBCthBR2QgghhBCthBR2QgghhBCthBR2QgghhBCthBR2QgghhBCthBR2QgghhBCthBR2QgghhBCthBR2QgghhBCthBR2QgghhBCthBR2QgghhBCthHVzJ/BXc+zYMZycnOrVVqPRYGtra+aMLKc51qe5t2Fzx6/KkrlYKlZL2r51uZlyra/6rJOXlxdBQUFmzyUlJYXMzEyzx2koS62/EJWksLOw/v3717+xQgl6nfmSsTClAnR6y8a0UkC5hWNWpVAo0OubMYEqLJmLUgk6C7x1LRXHFBQKJfpW9PsM9XtP2dvbcfr0GbMWNykp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r8qSuVgqVkvavnW5mXKtr/qsk5eXl9mLmqCgIM4kJJCZmWnWOI1hifUXoioZsbMQ+XYjhBCitZDPtJZLLp4QQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglpLATQgghhGglrJs7ASGEEEK0TuXl5Wi12uZO46ZmY2ODlZVVvdtLYSeEEEIIk9Lr9Vy7do2cnJzmTqVVcHNzw8/PD4VCUWdbKeyEEEIIYVKVRZ2Pjw8ODg71KkhEdXq9nqKiItLT0wHw9/ev8zVS2AkhhBDCZMrLyw1FnaenZ3Onc9Ozt7cHID09HR8fnzoPy8rFE0IIIYQwmcpz6hwcHJo5k9ajclvW53xFKeyEEEIIYXJy+NV0GrItpbATQgghhGig2NhYFApFi7tARM6xE0IIIYRFXM4pRl1YarF47o4q2rjZ17v9hAkTyMnJYevWrWbLqaSkhBkzZrBhwwY0Gg2DBw/m448/xtfX1yT9S2FnYceOHcPJyam50zArjUaDra1tq49pDrIeN1dMU6ia982wDvXJ0cvLi6CgIAtldPNISUkhMzOz2eI39365nFPMPe/FoinTWSymrbWSPS8NaFBxZ24vvvgi//3vf/nqq69wdXXlhRde4KGHHiIuLs4k/UthZ2H9+/dv7hTMTqkEneV+b5stpjnIejQhpkKJTn/zbbyqed8M61CfHB3s7Ug4fUaKuypSUlII6xxGUXFRs+XgYO9AwumEZtsv6sJSixZ1AJoyHerC0kYVdhqNhujoaDZs2EBeXh49e/Zk6dKl3H777Ubt4uLimDNnDomJiURGRrJy5UoiIiJq7DM3N5dVq1axfv167rnnHgDWrFlDWFgYBw4coHfv3g1fyetIYWdh06d70qmTXXOnYTYpKaW8/XYGQyJuobO/j0Vinr6azo6TicyZ401QkMoiMc3h118LWbMm56Zfj8r3wBQvL+52tMzo9E+FBSzLzGTZiFcI8Qy2SExT+PH8ARbvW8WyEa9wKfeq4eeWug7nspKZsv1N3hhoy7BO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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "env.render(td, 0)\n", + "# Update plot within a for loop\n", + "while not td[\"done\"].all():\n", + " # Clear the previous output for the next iteration\n", + " clear_output(wait=True)\n", + "\n", + " td = make_step(td)\n", + " env.render(td, 0)\n", + " # Display updated plot\n", + " display(plt.gcf())\n", + " \n", + " # Pause for a moment to see the changes\n", + " time.sleep(.4)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "if torch.cuda.is_available():\n", + " accelerator = \"gpu\"\n", + " batch_size = 256\n", + " train_data_size = 2_000\n", + " embed_dim = 128\n", + " num_encoder_layers = 4\n", + "else:\n", + " accelerator = \"cpu\"\n", + " batch_size = 32\n", + " train_data_size = 1_000\n", + " embed_dim = 64\n", + " num_encoder_layers = 2" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n", + "/Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n", + "/Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages/lightning/pytorch/trainer/connectors/accelerator_connector.py:551: You passed `Trainer(accelerator='cpu', precision='16-mixed')` but AMP with fp16 is not supported on CPU. Using `precision='bf16-mixed'` instead.\n", + "Using bfloat16 Automatic Mixed Precision (AMP)\n", + "GPU available: False, used: False\n", + "TPU available: False, using: 0 TPU cores\n", + "IPU available: False, using: 0 IPUs\n", + "HPU available: False, using: 0 HPUs\n", + "/Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages/lightning/pytorch/trainer/connectors/logger_connector/logger_connector.py:67: Starting from v1.9.0, `tensorboardX` has been removed as a dependency of the `lightning.pytorch` package, due to potential conflicts with other packages in the ML ecosystem. For this reason, `logger=True` will use `CSVLogger` as the default logger, unless the `tensorboard` or `tensorboardX` packages are found. Please `pip install lightning[extra]` or one of them to enable TensorBoard support by default\n", + "val_file not set. Generating dataset instead\n", + "test_file not set. Generating dataset instead\n", + "\n", + " | Name | Type | Params\n", + "--------------------------------------------\n", + "0 | env | FJSPEnv | 0 \n", + "1 | policy | L2DPolicy | 81.2 K\n", + "2 | baseline | WarmupBaseline | 81.2 K\n", + "--------------------------------------------\n", + "162 K Trainable params\n", + "0 Non-trainable params\n", + "162 K Total params\n", + "0.649 Total estimated model params size (MB)\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "812cd22f33dd469cb501b27936cc1105", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Sanity Checking: | | 0/? [00:00 + + + + + + + + + + + + + + + + + + + + + + + + + Solving the Flexible Job-Shop Scheduling Problem (FJSP) - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/other/3-data-generator-distributions/3-data-generator-distributions.ipynb b/examples/other/3-data-generator-distributions/3-data-generator-distributions.ipynb new file mode 100644 index 00000000..82e1e221 --- /dev/null +++ b/examples/other/3-data-generator-distributions/3-data-generator-distributions.ipynb @@ -0,0 +1,372 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Generating data in RL4CO\n", + "\n", + "RL4CO allows for easily generating data from different distributions for CO problems\n", + "\n", + "\"Open\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generating different distributions for TSP" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/botu/anaconda3/envs/rl4co/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + }, + { + "data": { + "text/plain": [ + "Text(0.5, 0.98, 'TSP with 100 locations, uniform distribution')" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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Gqv6ptjPzDS2VDUazc3N+PGPf4zTTjsNBQUF6NOnDx588ME4OQacnGdTpkzBH/7wB9TU1KCgoABnnXUWli5dmjQmQoi/0NAgxCW6deuGlpaWpLQqO5iKq1UaUHl5OWpqarBq1aroa2vWrEEkEsH+/fuxdevW6OurV6/GkCFDUn5Op06d8PjjjwMALr/8cixYsAALFizAd7/73eg1LS0t+Na3voUOHTrgwQcfxLBhwzBnzhw89dRTjn9fIm+//TYA4Pzzz497vX///sjJyYn+vbW1Fe+8807SdQAwYMAA1NbW4tChQ7a+e+/evbjooovwxhtvYNKkSbj//vtx9OhRjBkzBr///e+j17W0tOCyyy7DjBkz0L9/f8yZMwe33norGhsbsWXLluh1jzzyCM477zzcd999mDVrFtq0aYMrr7wyTvFdsGABCgoKMGTIkOg9/8///E/LMU6fPh2TJ09Gly5dMGfOHFxxxRV48skn8c1vfhMnTpyIu/bAgQMYNWpUtNanb9++mDZtGv785z9Hr5k/fz5uueUWVFdX4+GHH8aMGTPQr18/vPnmm7bunVN+9KMfYfPmzbj33nsxceJE/OlPf8KUKVMsrx86dGh0PY0cOTJ6zwDx52cyc+ZMLF68GHfccQdmzZoV9fC3tLTgkksuwWmnnYYHHngA3bt3x5QpU/D8889j1KhROP/88zF79my0a9cOP/jBD7Bz5860v9EwDIwdOxYLFizA97//ffz85z/Hv/71L1x77bUZ78+7776Lyy67DMeOHcN9992HOXPmYMyYMVi7di2Akyma9913HwDgpptuit6PoUOHRj+joaEBl1xyCfr164eHH34YF198cdrvvP/++7F48WJMmzYNt9xyC5YtW4YRI0bgyJEjGccbi8jYYjEMA2PGjMHcuXMxatQoPPTQQ+jTpw/uvPNO3H777UnXr1mzBpMmTcL48ePxwAMP4OjRo7jiiivQ0NBga5yEEJcxCCGOmTx5smG1jPbs2WN06tTJAGD07dvXuPnmm42XXnrJOHjwYNK11157rVFSUmJ89tlnxmeffWbs2LHDmDVrlhGJRIxzzjkn4xg6d+4c/fftt99uDB061DjllFOMxx9/3DAMw2hoaDAikYjxyCOPxH1nt27dov/+7LPPDADGvffem3J8AIz77rsv7vXzzjvP6N+/f9rxpRqv1T2b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hChDhgxBXV0dfve730VTqXJycnDRRRfhoYcewokTJzLWZxQXFwNASgXCK4YPH46KiopoByyTxx9/HMXFxRg9enT0tXHjxuGtt96KMza2bduGFStW4Morr7T93Zdeeik2bNiAdevWRV9rbm7GU089he7du6O6uhoAcMUVV2Dfvn2YN29e0meY3tTc3FxEIpE4D29dXV3KE8BLSkqE7vmIESOQn5+PX/3qV3Fe22eeeQaNjY1x90aUxA49+fn5qK6uhmEYaQ0pK3r16hXXAQ0AnnrqKU883aLPz2suvfRSfPHFF3FzuqWlxfK0+1j279+f9JppbJtpgyUlJQDkrdsXXnghTtl/5ZVXUF9fj0suuST6Wq9evbB+/fq4NMfXX389qQ2unbFdeumlaGlpSVpXc+fORSQSift+Qog+8MA+QlxiwYIF+O1vf4vLL78c/fv3R35+Pt577z08++yzKCwsjPazl4FpRGzbti3uoLqhQ4fiz3/+MwoKCuLOm0hFUVERqqur8bvf/Q5nnHEGKioqUFNTg5qamqzHt2vXrmgbUtMw+PnPfw7gpKfymmuuiY5h5syZmDx5Mq688kp861vfwurVq/Hiiy/i/vvvR0VFRfQzJ02ahPnz52P06NG44447kJeXh4ceegidO3fGj3/8Y9tjvOuuu7Bw4UJccskluOWWW1BRUYHf/OY32LlzJ1599dVo2tkPfvADvPDCC7j99tuxYcMGDBkyBM3NzVi+fDkmTZqEsWPHYvTo0XjooYcwatQoXH311fj000/x6KOP4vTTT8c777wT9739+/fH8uXLo4cy9ujRA1/72teSxtepUyf85Cc/wYwZMzBq1CiMGTMG27Ztw2OPPYYLLrgg5aGRmfjmN7+JyspKDBo0CJ07d8Z7772HefPmYfTo0XERoUgkgmHDhuFvf/tb2s+74YYboqe6jxw5Eps3b8Ybb7yBjh072h6bXUSfn9d8+9vfxqBBg3DXXXehrq4O1dXV+J//+R+hWp377rsPq1atwujRo9GtWzd8+umneOyxx3DqqadGi9579eqF8vJyPPHEE2jXrh1KSkrwta99zbIGJRMVFRUYPHgwrr/+euzduxcPP/wwTj/9dNx4443Ra2644Qa88sorGDVqFK666irU1tbixRdfjCvOtju2b3/727j44otxzz33oK6uDueeey7+8pe/4LXX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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "from rl4co.envs.routing import TSPEnv, TSPGenerator\n", + "from rl4co.envs.common.distribution_utils import Cluster, Mix_Distribution, Mix_Multi_Distributions, Gaussian_Mixture, Mixed\n", + "\n", + "# Instantiate the environment and generator\n", + "generator = TSPGenerator(num_loc=100)\n", + "env = TSPEnv(generator=generator)\n", + "\n", + "# Simple plot\n", + "fig, axs = plt.subplots(1, 3, figsize=(10, 3))\n", + "td = env.generator(3) # generate 3 instances\n", + "for i in range(3):\n", + " axs[i].scatter(td[\"locs\"][i][:, 0], td[\"locs\"][i][:, 1])\n", + " axs[i].set_xticks([]); axs[i].set_yticks([])\n", + "fig.suptitle(\"TSP with 100 locations, uniform distribution\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Generating data with different sizes" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0.98, 'TSP with 1000 locations, uniform distribution')" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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M3z4cMlz6NWrl+fff/nLX5iJEycyPXv2ZFasWMEwDMNUVFQwBoOBee2117y+My4uzvPv3377jQHAPP3007znB4D529/+5vX6qFGjmNGjR4ueH9/5Cl2zefPmMUFBQbx/69GjBzNr1iyvc+WeD8MwzPLlyxkAzM8//yzrmEKsWrWKAcAUFRUxDMMwZ86cYcxmM3P11Vcz7e3tnvdlZGQwAJh3332XYRiGaWtrYxISEpi4uDimqqrK65gul8vz3w0NDT7fuWbNGgYAs337ds9rL7/8std5sImLi2PuuOMOz78ffvhhBgCzY8cOz2t1dXVMQkICEx8f7znvbdu2MQCYIUOGMM3NzZ73vvbaawwA5tChQwzDMMz+/fsZAMynn34qeq1oefrpp3mfAe61Jr+Ney3OnDnDWCwW5pFHHvG8Rn7Ltm3bfL7nt99+8/oszf1jGIa54oorGADMG2+84XWeRUVFDACmR48eXuP5iSeeYAAwI0aMYFpbWz2vz549mzGbzUxTU5PodRk5ciTjdDq9jvn1118zALzGKsMwPmM1MjKSmTdvnujxp02b5nMchjl37fr37+/zPPJdV3JdXnnlFc9rzc3NzMiRI5mePXsyLS0tDMPw30+hYwqdG7nWq1at8rxGvqeiosLz2oEDBxij0cj84Q9/8LxG7v9dd93ldcyZM2cyMTExPt+lo6MTOPTUKR0dlfTq1QsHDhzA/fffj6qqKrzxxhuYM2cOevbsiaVLl3qlNQFAfX09evTogR49emDgwIFYtGgRxo8fL5g6QZgwYQJOnz6NX375BYB752LixImYMGECduzYAcC9y8EwjOCOBi3333+/z3cLqTwpQazo1Gq1orGx0fM+gL82gaSksd9Lc0xasrKy0NLSgocfftirAPuee+5BRESEJz1p//79KCoqwsMPP+xTI8BOG2KnlDU1NaG8vNyTbkfSXuSyefNmjB07FpdffrnntbCwMNx7770oLi5GXl6e1/vnzp3rdY3Ic0LuLdmx+N///tcpKSdJSUlez26PHj1w8cUXK3r2aO8fwWKxYO7cubzHuvnmm712cy699FIA7loudqH2pZdeipaWFpw8eVLwvEpLS5GTk4M77rjD65iTJk1CUlKS5O+KiorCDz/8gFOnTkm+V4g77riDKsURcNeU3XfffZ5/m81m3HfffThz5gz27t2r+BykINfpzjvvhN1u97w+fPhwTJo0CZs3b/b5DN+8VVFRgdraWr+dp46Ojji6o6GjowFOpxMrVqxAaWkpfvnlF/zrX/9Cjx498H//93945513vN5rtVqxZcsWbNmyBdu3b8evv/6K7Oxs9O/fX/Q7iAG2Y8cO1NfXY//+/ZgwYQImTpzocTR27NjhkcxVitVq9UnViY6ORlVVleJjcgkJCUFLSwvv35qamjxGEPl/PunfpqYmr/fQHpOWkpISAMDFF1/s9brZbEb//v09fydpb1L9BiorK/HQQw956lh69OiBhIQEAFBU/0DOkXt+gFsNjf0bCP369fP6NymOJ/c2ISEBf/nLX/D2228jNjYW11xzDZYvX674/OTCPT9yjkqePdr7R+jTp4+go8o9L+IgXHTRRbyvi50v+d7ExESfv/HdSy4vvfQScnNzcdFFF2Hs2LFYsmSJbEeMPHc09O7dGzabzeu1QYMGARCuKdMCofsHuJ/v8vJy1NfXe70u9Xzr6OgEHt3R0NHREIPBgEGDBuFPf/oTtm/fDqPRiI8++sjrPUFBQUhPT0d6ejomTJhAlZcNuBf8hIQEbN++Hbt27QLDMBg/fjwmTJiAX3/9FSUlJdixYwcuu+wyVRKoQUFBij9Li9PpRHt7u0ctiNDS0oKKigqP8pbdbofFYkFpaanPMchr5L20x+wsbrnlFqxcuRL3338/vvjiC3z99dfIzMwEAC/5YX8idG/Zu26vvPIKDh48iEWLFqGxsRF//vOfMXToUJw4cUL29wn1URESFqA5P38h5ogKnVdnnO8tt9yCY8eO4d///jd69+6Nl19+GUOHDsVXX31FfQy5TrcUcu+zv+jM50dHR4cf3dHQ0fET/fv3R3R0NK+RrBSSJrVjxw6MHDkS4eHhGDFiBCIjI5GZmYl9+/Zh4sSJoseQaqIXCEaOHAkA+Omnn7xe/+mnn+ByuTx/NxqNGDZsmM/7ALfKU//+/REeHi7rmLTExcUBgCdVjdDS0oKioiLP3wcMGAAAyM3NFTxWVVUVvvnmGzz++ON45plnMHPmTEyaNIl3F0vO/YmLi/M5P8DdwI79G+QybNgwPPXUU9i+fTt27NiBkydP+igN0UAiylyVJ+5ugj+gvX+Bhnxvfn6+z9/47iUfTqcTDz74IL788ksUFRUhJiYGzz77rOfvWo7xU6dO+ewcENlqUowt5z7TnpvQ/QPcz3dsbKzPTouOjk7XQ3c0dHRU8sMPP/gsxIC7S3ZFRQVVOgQtEyZMQHFxMT7++GNPKpXRaMRll12Gf/7zn2htbZWszyC9ATqz83RaWhrsdjtWrFjh9fqKFSsQGhqKadOmeV676aab8OOPP3o5EL/88gu2bt2Km2++WdExaUhPT4fZbMa//vUvr4joO++8g5qaGs/xUlJSkJCQgGXLlvlcU/I5EmnlRlb5OiQT44nm/kydOhV79uzBrl27PK/V19fjrbfeQnx8PFXOP5va2lq0tbV5vTZs2DAYjUZFneuJE7Z9+3av8/vPf/4j+1hyob1/gcbpdGLkyJH4z3/+45WStmXLFp+aGi7t7e0+aWw9e/ZE7969ve6PzWbTLN2tra0Nb775puffLS0tePPNN9GjRw+MHj0aAP99bm9v5+3QTntu7OvEHgu5ubn4+uuvMXXqVKU/SUdHJ4Do8rY6Oir54IMP8NFHH2HmzJkYPXo0zGYzjhw5gnfffRdWqxWLFi3S7LuIE/HLL794GtUB7q6+X331FSwWi1e/CT5CQkKQlJSEjz/+GIMGDYLdbkdycrJkjQENJSUlnu7pxDH4+9//DsAdobz99ts957B06VLMmzcPN998M6655hrs2LEDH374IZ599lmv4s8HH3wQK1euxLRp0/Doo4/CZDLhn//8J3r16oVHHnnE63fRHpOGHj164IknnsAzzzyDyZMnY/r06fjll1/w+uuvY8yYMR6pXKPRiBUrVuC6667DyJEjMXfuXDidTvz88884fPgw/ve//yEiIgITJ07ESy+9hNbWVvTp0wdff/01ioqKfL6XGG9PPvkkZs2aBZPJhOuuu443evv4449jzZo1mDJlCv785z/DbrfjP//5D4qKivD555/LTqHbunUr5s+fj5tvvhmDBg1CW1sbPvjgAwQFBeHGG2/0vI/Ixm7btk20u/zVV1+Nfv364e6778Zjjz2GoKAgvPvuu+jRoweOHz8u69zkQnv/OoPnn38e06ZNw+WXX4677roLlZWV+Pe//42hQ4fi7Nmzgp+rq6tD3759cdNNN2HEiBEICwtDVlYWfvzxR7zyyiue940ePRoff/wx/vKXv2DMmDEICwvDddddp+hce/fujRdffBHFxcUYNGgQPv74Y+Tk5OCtt97yyAMPHToU48aNwxNPPIHKykrY7XasXbvWx2mVe24vv/wypkyZgvHjx+Puu+/2yNtGRkb69P7R0dHponSS2pWOznmFmFTrwYMHmccee4xJSUlh7HY7ExwczDidTubmm29m9u3b5/VeIm+rhp49ezIAmNOnT3te27lzJwOAmTBhgs/7ufK2DMMw33//PTN69GjGbDZ7yWcKnZ+QTCkXImfJ978rrrjC5/1vvfUWc/HFFzNms5kZMGAA8+qrr3pJwhJ+/fVX5qabbmIiIiKYsLAw5tprr2Xy8/N5z4H2mFyEJDozMjKYwYMHMyaTienVqxfzwAMP+MjYMoz7HkyaNIkJDw9nbDYbM3z4cObf//635+8nTpxgZs6cyURFRTGRkZHMzTffzJw6dYpXanjp0qVMnz59GKPR6HVOXHlbhmGYwsJC5qabbmKioqIYq9XKjB07ltm4caPXe8h94crWciVFjx07xtx1113MgAEDGKvVytjtdubKK69ksrKyvD73yCOPMAaDgTly5Ij4RWUYZu/evcyll17KmM1mpl+/fsw///lPQXnbadOm+Xz+iiuu8Hp2aOVtCTT374orrmCGDh3q81lyfV5++WWv14WuJ/ldP/74o8gVcfP5558zQ4YMYSwWC5OUlMR88cUXvGOV/Xw0Nzczjz32GDNixAjPczZixAjm9ddf9/rM2bNnmTlz5jBRUVFekrlC583+G1fedujQocxPP/3EjB8/nrFarUxcXByTkZHh8/nCwkImPT2dsVgsTK9evZhFixYxW7Zs8Tmm0LnxydsyDMNkZWUxqampTEhICBMREcFcd911TF5entd7hO6/0JjW0dEJHAaG0aukdHR0dHToGTt2LOLi4vDpp5929qno6Ojo6HRhdEdDR0dHR4ea2tpa9OjRAzk5OR4ZXR0dHR0dHT50R0NHR0dHR0dHR0dHR3N01SkdHR0dHR0dHR0dHc3RHQ0dHR0dHR0dHR0dHc3RHQ0dHR0dHR0dHR0dHc3RHQ0dHR0dHR0dHR0dHc3RHQ0dHR0dHR0dHR0dHc3RHQ0dHR0dHR0dHR0dHc3RHQ0dHR0dHR0dHR0dHc3RHQ0dHR0dHR0dHR0dHc3RHQ0dHR0dHR0dHR0dHc3RHQ0dHR0dHR0dHR0dHc3RHQ0dHR0dHR0dHR0dHc3RHQ0dHR0dHR0dHR0dHc0JpnmTy+XCqVOnEB4eDoPB4O9z0tHREYFhGNTV1aF3794wGs+fWIE+j+jodA30OURHR0cttPMIlaNx6tQpXHTRRZqdnI6Ojnp+/fVX9O3bt7NPgxp9HtHR6Vroc4iOjo5apOYRKkcjPDzcc7CIiAhtzkxHR0cRtbW1uOiiizzj8nxBn0d0dLoG+hyio6OjFtp5hMrRIFuUERER+uDW0ekinG+pA/o8oqPTtdDnEB0dHbVIzSPnT3Kmjo6Ojo6Ojo6Ojs55g+5o6Ojo6Ojo6Ojo6OhoDlXqlI6Ojo7O+U+7i8GeokqcqWtCz3ArxibYEWQ8v9JndHR0dHTOH3RHw490hUW93cVg97EK7CqsAMBgfP9YjBsQoxsXfqAr3G8d/3I+3+PM3FI88988lNY0eV5zRlrx9HVJmJzs7MQz69rIueeBfD7O52fxfES/3urprGuo9ntb2lz4YFcxSiobEGcPxe3j42EOvjASggJxT3RHw090hUU9M7cUj39xCNUNrZ7XMrYVIirUhBduGKYbFxpCc7/1her8pjPGtJpnhv3Z4vJ6vJqV7/OespomPPDhPqy4LSXg88H5MB7k3PNAPh9832W3mTBzZB+kJzm65LU8n+kK6/n5TmddQ/6xYsb1I3tjEsVYeX5zHlbuKIKLOffas5uP4J4JCXhiapKic+oqc1+g7omBYRhG6k21tbWIjIxETU2NKqWHrnJxxdDiHDNzS/HAh/vAvbDkKIFY1DNzS3H/h/tE3/NGJxgXbM6H54EGoftNWJCeiMSeYVi66YgmA1qr8Rhozqfz5j6bVfXNmLd6v+A99sdYUrMI8H1WCAMAR6QVOxemBWz8Sf22rjA3yJnHAznnS803gPRzcj6NRTadcd7+vrf+ftbPt7GkFL7fuSWvTNVYeX5zHt7cXiT42fsmync2uorTqsU9oR2PfnM0+BZqrQwtf7H5YCmeWp+LyvoWz2tyz7HdxeDyF7cKLvCBWNTbXQxSX9iKslpxI6NXuBn//P0olJ9tDvgEpLWh0ZlbsmL3Wwylk6xuJPgXvmfTaIBXRItLVKgJe5+apNkzp2YRoDFE+VhzzziMHxAj91R5ERuPUr/t3okJ2HCgtFPXCpp53G4z46lpQ9AzwopHPslBWW2z4HvJnA9A8LrQzGG0843Uc3K+jEUugT5vf6/nao1O7jMzOi4ae0uqupTdFQibiO86OiIsaGpzeWV0CGGA71hpaXNh8OKvROd9owH4eekU6jSqrhCEBrS7J7Tj0S+pU7TRtM7ctuci5LmWyjzHPUWVor+b6TjmnqJKzRZ1vnOQcjIA4HRdC259+wfPvwM1AQkNNvI8yDU0MnNLsWTDYa+F3hFhwZLpQ/3+W6TutxgM3AP6mf/mYVKS47zczTmfoDHkhJ5NscUGAKobWpGxtQAPpSdqcp7P/DeP11GQembEPivFmbomzXZ0hYynSUkO0d8GgHceVrJWqPktNPN4RX0LFnxyQPJYZM5f+NlBZB05jerGc4YPuS4AqAxO2vlGn1u0wZ/rudQ6KPWsKwmIyDm+Vsi9hnLHreB1FHD8heCOlQ92FUteSxfjft/dE/pLHl/JvO6vAGqg7VTNHQ050TRycZdsOIxwq0kysu6vi7754CnR7TEG9BM2jYEPuBd1f6H02IGYgKQGGyDP0BBKESurbcb9H+6jTmkRerb4XgfORSXzT5+l+t1CBMLx1KGvoVFqpAPAyh2FeOB3A2QVCfI9X2oWATWOb3F5vU+US27wQcp4ejg9UdH50ThYWu6g+2N+/mzfCZ/XymqaBFNc+eY8Oeelzy3qob3eQu9rdzHYXViBXcfKARgwfkAMxvV33wulwQRAeUCE9vhaIuca8s3TUSEmzE2Nx/y0RE0DK2z4xkpJZQPVZ2nfRzuvv5ddhNhwC4rL67Fmz3Evh0mrYLDa51oumjkaRN3o8c8PybrpDNxGoVRkffPBUx1pTb7RILX5kU+tz5V8H82EnZlbiqUbD1N9b89wK9W5KXGsaI7Nhz8mIK5aw6Ce4ZoZGu0uBo9/cUj0c49/cUjytwhNbpcnxuKn4iov5zEq1AQAVNuxctiSV6YbAyJIOXxi40NoUS7tMPJen5OCqcOdqox0ADjb3I5xz2fhuZl0QgtCzs+UZAfV9/EFNZQsDAYANkuw6mJxmojdquxi2efHPgbfPOyPHXSlc6hcxNZKvjlPyXn5M6h1oUN7vfnexy/GUoCoUBPmXhavOJighXFN64RqEdylvYbF5fVYlpXv87uqG1vxalY+Vn1f7CNio3bO5sJeh+PsoVSfoX0f7ThcuumI4N/ImqW2JlDNc60ETRwNOYWHNHAXBK3SmvjYU1Tp5byIwX5Q5BaLEkjuGzGUhFCTuzk2wQ5HhJV6d4WNllEwPrUGNa4L99x2F1ZIGvzVDa3YXViB1MRY3r8LGaHVja3YeLCU93j+4N3sYoxNsHd6CmFXhG8shFmCwDBAfUu75zW+8UGzKM9fsw8ZGIVWmnCgBJX1rdRpD0KR/3cpjfGlGw8jxGT0+h4lCwMD4Gxzm+DfaIMPNBE7dtqQUtjzsJIddJrfomYO1RLunDc2wQ5npBVlNU3UhmagnKbzFTFjemyCHVGhJsF5X2g9FxNjqW5o5XXq+eAzTrU0rsWMX62KlqWeWXIN1+w5LvpMVzf4zq1aO9Hsdfj28fF4dvMRyRqN28fHUx1by3FIE0AVg2YeMRqAqnp56WdCqBYCJhO9ll4l+eHP/DcPG3Po0praFRoJch5U8qBk5pYi9YWtmL1yNx5am4PZK3dj/ho6JwMAnr4uiSrnkHtNiQOWmetrALMJMhqwZLoy2TWC2gFMnEPubVFvyp07N/d2tDRC79Nq21Ur1DzHFyLtLgavZR3F/Txj4Wxzu5eTAfCPD5pF2cUAD67ej+Lyes3OXexe0kT+adYP4tSwf+/YBDvsNrOicxaCbeyKQTtnRIWYVAUcyDzc7mKwZIO88Sv1W9pdDHYVVuC5TXmoa/ZPUEEJ5NoGGQ2emg4anBRBre5MZm4pLn/Rey2//MWtnjG1Ja9MNLjEwHc9dz+XdJkNUrCf9V2FFVifcxLZBXTrnpzjc1Frg7BhP7PccU/+PWtMP6qaCq69F2uzUJ8HDSQQ0e5iYA424p4JCaLvv2dCAnWqLDHutUhUIzWBSqGZR1wMMG/1fln3WghVjoY/DTWyIDzxpXhqDEC3CApB62XG2MwYm2D3RCq4kS4a+9BuM0tGOmlqGJ5cl4t1+05gV2GFoDEzOdmJN25L8aT6yEWN993S5sLKHcLOoVpibRbsKqzAUer6CP6hrfW2q1pKa5qw+1hFZ59Gl4A487SRP8A7QEHGhRyHec2e43BEqF8IpIxZmsi/HH+T/XuDjAb8fUayjLOlR+pa0s4Zl3fsLsq9zgZ4G84ZW/MV7zjw/Ra20flOdjHqm9t5Ptk5sK/t5GQnHk4fRPW5WWP6dctCcLZhLrRObj54ijeIQYzpzQdP4Zn/5ol+j80chHCLyev4bjEWdZFg9rPOdYYytik3MPmOz71WLW0uSRtEblBscrITK25LgSPSe45wRFqx4rYUxMfSpR8BnLlV40ebO3c/MTUJ901M8An8GA3ypW3FHC4lrPq+iOoeCI2FyclOLJ+TIhnU0iIAqip1KhCGWl0T/5Y+l686vC65OYTEy5T6HUs7Fm+pmgAxnpo2RHLLUa7aCVvNhbv9OznZiUlJDvz7m3y8vfMYzlIunFGhJrhcDNpdjKJFikatQQkGAJGhJjzy6QFZBoZQClhXzF2e99E+vHBj926mqFSeFfBNNZHjMJfVNmNB+iAsyzoKA7x337j/pkHo+crKK5N5JGH4Uh2nDnfivhMJojvBSpC6lu50I4ukkbW3pArL54zyKdaWgoHbcAbcz4gcJ5RLz3Arp6FhA5ZlHVUVNCMpIP+4aQTK65tRXtcsmm8t55jcXYl+MXSGGe37LiRoUn425pzCn9bu5/082VXk1oTyUd/Sjlvf+cHr+HLXFb65BnDvlND0gZAL9/h8zezYEv9clKZXE3uEjLlYmwUwAOVn3WNFDuQal5/VJrVH6PiA29l45OrBijqDc9PyJiU5sOK2FE1KDaobWqnqhsXGQrTNLGqraZVKr8rR6EqG2vu7SvD+rhLZOYRBRgMWTxuCB1fzTzqA23OdOtyJ7IJyVTn6lfUtksa73GtKVEu4eaRs2cTXvvEtsBKjuqHVZ/KUA60KgxzIZOz+jfT3IDrU5FH54NIVc5erG+ly/C9UtNolJeOoSmTB5CM+NpR3IXCwxtOidbmiCzGB7/lqdzFYl3NS1jnRwJ03npiahBF9o7Dwi0PUwRoxokJMkik4QUYDZo/tJ+kAlNY0Idpmwc6Fadh9rALzPtpHXbvxatZRrNlzHE1tynYbiOFeVd+suP+N0HEBt/FG6sHaXQze3llEXU8hZnBy14xKSgOL9n0XCjSSsfuPV0k64QxAXbsJnCvSzZg1UpbRfFNKH2QXVvDONZOSHLj8xa2aZ4yw5zK+a0UztwHK7L8go1t5KzO3FI9+dkC2NC+BzK3+WsPZKWvEUUjqHYk7UxOog69iRv7OhWme46oJSEjV2EiNheY2F9X3ZKkUq1HlaPjTUCMNkSpkGgpyJVozc0sFb7LdZsLfZyRj6vDeAIBdherSWpZuOoK3dxaJGu9yryl5iLgOELkOkaEmxRMV+1ry7ZgIDbiLorWPovWS0XyHzfM3DBM8T9rdrM6gu+rfa7VLSiLWSzeJpz7wfW78gBjR5z1tcC+Mez5L0BARE3yQIz4h97y5TB3eG81tLqpeD1LMTY2nehbjY21UxztT14QgowGpA2Pxwo3D8EBH4SzNXKWmQJsBMH2Ek0q4Q4xQcxAaWDVCDp6gDEmVeODDfYI7YlGhJrxwwzAAvn00+I7p+VwIXUqs1vU6XRma2qfHPz+I6kb1jrcQ89fmyHq/1RyEf9w0whPZZ881uzgOiBbclNIHL940AgBUOzFK7T810rzcuVWJOALt8dUUw0srHY7y2JXtLgbLvy2kdvDYCN0D2p4d/7h5BNX3rMs5iUXTxGuLxVDlaNDcZCUpB+SnLJ2RjKWb5G0x0SqLtLsYZGzNF42+uVwMjF6fV/8oSzlCo+OiJbcuaRByQJQc4y+fHIDVRNcxPTO3FG/vKFT8nXwsSB+ES+KjvSSQpRCbENhRilljLlKVguEPtFT+Ot/QYpfUGWmFy8Xg1S2/UM8d3AWMRN74MAcb8dxMfuNYSvBB611gKRU7R2SI6u8IswRjfhpdI8LYMLrizKOn65CdXw4XwyD3ZC2mJPfCrmMVqGo4ZwQaDADjhxTMj386oXomb2hpx4L0QYiPDRUNvJDcdK7BEmoOwtRkB567YbgnBYMmmONetwqwknKO1eL+ny/QqZ7JczLsNjOq6lv8Jhjy4e7j+HD3cc96xZ5zaB3qyUN7oWeEFe/vKpF872f7TiJtcE9E2yyKnRha5Uw+1OxYC82tWq3hNClrNIFsOqXD/ciAAVOHOxFkNOD6kb2p1QbJuYrdA9qeHWDc87uQ6iChsl46TUsMVY4GO2IjBM0Dxd0yc0RasXhaEqJtZkxNduAdmdrrUoaau5N0nuRArm5s89IsHt8/Fhnb1BnRYo4Q8aDVOhla09DS7hW9A/gHnJrceiEMANb+eJw61/gP4+MwJdkp2lPBp2dGqAktbS6f39jZdKXUxEChxS5pY6s7b1ouUmpwbIQMSLvNjKUzkn0WIeLcqm3wyIfYeWsh03rLJX3pI1mUg3/5tkIs55lLwyzBGJsQjR+LqzRJ+eJDC4lqMi/tXJgmeW1IbnrG1nysyi5GdWMrGlra8dm+k8gurPAERPicW+86knq8m12EGkpjubspTmk9Xzo77JB5q4V3pLSCbz2lTXvLPHwaC9LpAgGA28i9g1KSlQuNcqZY89v3sosUOzjcHT61bRW46eY0KWs0gWx6pcN9eMOY4pkfaB0NmntAOxa2/nxa0smQe0w+VPfRIJXr89fsk10ATC5RxuxRiLZZOF1d8xTn7xGElEXkGsPkoRo3IEZUU5sWPkfIH0a6P+EOOEC406na7ymtaaKedImTwTfRCV3jmo77ee1wJ3bml3vlizsiLJg9th9a212qnUy5aCm3er6gJp3NZglCfXO77PFpt5mom+yxmZzshKuj4SdJh6qob8HSTXkwGuG1IC7ZcFi1Eg0Xo8E9d4qd97m6iaOKv4eMbxrKVequn21uw9aff1N1jEAgFMziNiglRaNb8sp4m5GJRUjVGlKLpw3pVqmXWqdyE6N2hVGb4l0x+AxYOWlva/YcR1SIiarWycUAq74vpjqu3WbySvUUS+cDhOsSpo9wYsOBUsXX0G4z4bvHrvTs/m0+WIoHVwsHuMUQE9ChSVkjY/+97CLemg05Bjm533LWPal7ANCPBTn1gmrGlyYN+6Qq1wnEECDwXbDM3FLe/Fly/LmXxaFvdChV8Qz3wijdtmMvKC/cMEywEY9cyAPZ1fo50MKVgvPnRHyiSrrA3ClQ5Gm3mfHM9KF4bvMR0SjF3pIq7HkyHXtLqnwmn/UKC3h7hZtxpk7Z1vuaPccxPy2xWxkLNOIMXKJCTLjzsnis/fG4bEnSCGswnpqahMgQs2yVNaG5im08AtBsvuDiYoBoCh15OdKRXORGxbuiwII/YRsVfA1K/77pCKYNc+CnkipZEVItAk9LNx2B0WjoNqISWuXrGwAsn3POgScRZ7nCBXLhOq9y0t60DmKQ1JzvHruSdz3kQ6wuQa0CXmV9K/aWVGH8gBhsPngK89fQrw9sYmxmL4eFL+NFTgdvvppbOXMgcVhiwy2eFDCh3bO7U+OR3uGUSK1TNE0S5dRAR4VKi4GIobphH0B/Y4gREBViwoL0Qdi5ME12F9//7CpBr3CraOMTrt46QU2hKfs3Ku1NwYVErAMhE+xPU/VMXZPf03zWHzgl+Z5rh7uLPLnXsrK+BX9a4/s6GzLJf7CrmHdSVWpATUjsobwYv7ZZcX+Y8xka45nN32cMRbg1WNFiW9vUhr98esCnUZcUNP1ulmw4jMc/Vy6HTQPNuFNj/E8f4RRNkeDqs2vZlEoMA9yKco4IbRt2yYVcW7EGpRsPlYk+m9yAjVaBp1IFzdXOZ2gaw9Gs3XddHu8p1GUfmwgX+BsypslY6iyevi4J5mAjxg+IwYyRfTB+QIzoXODvYOmZuiZk5pbiwdX7FcvnV9S3YG9Jleh7ZEmi84wxufdt6aYjeGhtDl7NykdUqAmRnGfUGWnFG7elYPF1Q0XvARuasTBjZG/QUt3Qii0qZNk1cTTkLmQ1ja1YlnXU58Rpc9vmr92P6SPcDorQReTLX1NjDJfXNWPzQbfHrkWOL+COWLe7GL8b6Xelxvs0ymGj1nHqGW71WyTTAHcUgkap5/N9J1VPdGTQcw3PsQl2aqUXwoL0QQi1qNs07I51GnJ/858+zlHdrwCQ1/WWptiurLZZcfTTQtltlmbcqTH+39xexHs9hDoqb8krw+JpQwKyO/v8DcOQ/fhV+OiPl8oem1pgNLjFO7RqUEqeey0DTwy0abh1viDWGO6N21Lw3PXSjsLmQ2WijXBfnzNKssmZGsiYltsFXiuMBuBfs0chMsQs2vCQTSCCpbFhFskGijRIrS9y5ktyVbhjbNaYixSdW01DK2oaWrEgfRBemzUSa+4Z5xOQp0WqSaKclFh2x3QlaJI6JXfLkn1z2NvFcgyMDQdKeZs+RXdI0vLdGDXG8NJNR2A0aFsQRiLW/k43mJTkwJPTks41ygmzAIw7n5pE7l/KPOKz7S8FV/lAaquuV4QFgEF2YeoMSkUGrYvoiRQdEQOYm5pAnevuiLBgftpAvJetzgCJlRndvxCQW5siV5lIaGtaaF7iQ010hwYpfXM5yi80MqtiPP7FIaq0HnZPH3/zcPogzxzPlsgNpDntYtzplnmnajRpUErWAa2DC91NwY7bGI6bfy+F1PWaOrw3MmBQXCMgBN+Ydjs2KZi3OnDPtosBnt7g3axQStbV3wGxqFATwGiTni1lb8mdL9k1G85Iq+xGpNxjyRGakEJsLLS7GGq7Xa0SpiY7Gkpbq5fWNCFj6zlZMrm5bdE2CxZPS/Iqmqqsb8XSTUeQmVvqs7U/Oi4ajgjlRr0/gkJn6pr8mm5gt5lQVut+QMYm2DFjZB+kDoxFamKsZzt0S14Z3uLZ9heDu3NEcuuFDsEAWDJ9KJZMp4/QRIWYZHve/uDxLw6h3cVgftpAaiNqyfShCDIacPv4eHXRr+5TngFAfcdnGqQec/a8xJcelJlbKkuKUA4GgPp5Ye/a8p0nG6HoFg3VDa3I2Frg+R6plDGtdnzF4NadkN8X6FSTM3VNqhuUklTf0XHR2FVY4Rdlsu62M0oUvLgpP7TXgV0/yTeupg53OwBa7WyIZWJMHe7EnZfFafNFlHAzCKR2e/0dLJ17WYJqoQmhlHo+lMyXSzcdwYM8qdty4aZSAtLzuxhCY0HJjpnSeUSTHQ1AWO5Rilez8nGxIxyTO9SC5EgxZuWV4d3sYtHIGrdb9iXx0dh40H85q38YH4cYm4U68t0z3Ko64ihGZX0rFnycA4A/KqE0t5JPau5vG4W3NYmBPjnZiQXpiVTGpMHgPit3bxGTXxqd0UAMrYfSEyXFAEgDLnJdzMFGXDWkJ7bknVH03eXdqLMveRa7Aq9m5ePAiWrk/FrjtVPmiLBSywFGh5pQJcPoJmOfZofmoasSPakNxeUNWLPnuNe8yTfWz8msFshWoVr1fRHmpw0MSIoEDXyGDTt69/XhUqz58Vc0tdJ1vlU67/YMtyLOrrzYnpiU00c4ccXL2/x2bbtbkb4QtNehZ7hVsmEbrQgOgdzreycm+CgwSSkJXT3UiVXfS/fJ8BdSsq5aN85jE2oOwvy0gditomEyjSQsFzKfLPzsID7bd0Lxdyslu6C8Q9aabn5XArHbF607RGVfKZ1HNHM0AO+JPrvgN2o5UPLwbskrw9lm+oV5XQ5/Tr5QZK2spsmvTgbgllcdPyAGiT1tmL9GuGiJu00q5KiRSNeO/HLUqFS74JNSlGM42G0mzBzZx0f5IDO3VFJZp6ah1fPd89MSsWbPr5IOZVVDG6/D2BkQQ2tyshNv8NynqFAT5l6WgAd+NwB7S6qwPudkh1RzC7IUOhlA9zIQuooRS+CTWZWT9nfH+Dis+r6Yuu+BI9KKa4b2wnsUBsV73xdj2TfCzrqYbOqq7+Wn81U3tHq23zsT9rwppNdf09iC974vkTR4yLEWTxuiKN2BREdHx0Xj2c1HFO14OzqkP9/aXuS31Jju1k9DDBqDOCrEhB+OVeC1b8TliKXSG7mwnYm/Th7i8+wCwK7CCl4xEjWy31yUtAoApNNnZo1RJ6MtBKlXc1HmyE4b5sC+49WyHDkhtuSV4fNOcDIAIGNbgeDfxOZ3Mi+W1brbAthtZjgiQwQbgEaGmPHklCFYsjFPsHeRmiaNgMaOBnBum2Zsgh2f7ztJNTDcqQoFWJZ1lHqyDbMEy45w+zvH0WgAqjq298TyOIW8a24+XXF5PdbsOS7pHJFo3LXDndhx9DfUCDwsfFEJWsNh/pUDsWDSIN4H9fEvpJV1uN+9ZHoSb2dlPjrbySDnQCZYobzHLXllPlFJpXU9agf2+UhnG7Fas+ybAslUuwXpg9DPHoLK+hacqGqkjpxJFZkLRSB3H6tQPJ7Is97ZkM69fEGZxdOSsHST9A4tew6enOzENclOvLrlqOjizmXxtHNpo/dMSJCU8CRj+h83jfDUx42Oi8YVL2/z29pkgLwobndAqpN0dWOroBPPHlf/uGkE1ffNv3IgUgfGehl63OaMYrsnZK1R0rwYcLcEuHqo06tPGZ8sNy3ceVptvxcpqhpa8afVe/HdUbr+OulJDvxrdgpvEEIOXbntgJgsttC9IPNjtM3sZV9KqTUq2Q3iormjQSDpQLQa8quy5UV0Lh9oR+Zh5ZFif+BigHmr92NFh3b51OFOvMHT7CeyI/rNV3tAJqDM3FLeBk98RIaa8PtL+lJFxbhRCVrDIXVgLO9DtruQ3nBhf/e5LbvcLtcJXQj2BMu3UPAVoyqJHGkxsM9HuoIRqzWkGSS3mRYxIgD4bZHmi0DSFMMKQRZsf6VISGHvEPoAIFiMTluga7ME4x83D/dEA4l8qRxHI5pVG/jEVPe9fGtHEW/qG3tMpybGel6Xag6mBq3SKy4UtDKIybiCQVoAxRFp9QrQ8e3CbckrkxRXYK+xBoM8AYyrhzp9diDuPVHtI/5Cu9PBnqcD1Wh4c+5p6vfuK6mE0eA+z2uH91a8hna1HXYu3Pld6l6Uypgf2SjdDWLjN0cDIPn4g6i20+TKQO4prlZ4Vufg5uWSxzEy1ISahlbFg4ftZZ7Li87HquxiVDe2orqhFa9mHcXaH4973UAyCZ2qbsSS/+ZSf7812Ij1OaWyzper1S01WQpF1ncdK5fxrd7fPTnZicaWdiz45IDsY4jx0FWJeHvnMdnN26SIDfNWgGJvUS7deFjx88J9DrUY2OcjYxPssNvM543jSQOJPIWYg7B8ToqX0puQgaE1Z+qaPM/q0dO1sj/PngP8WU/GZUxcFH4+fdaznV9Z34q/bcxDU5tLNGWWBlJnwzb8Ym0WWTWC3MjuE1OT8MjVg7Hoi0PYfKgUDa3izWn5jiGHSGsQaprOfYfNHIShvSNwSbwdqQNjMa4/neb+hYYcY14N5WebBccCX7CIz9FxRFgkn2efQF7HH0LNQWhoEV7jhNbuzNxS3qCklPPCPV5Xjfh/sPs4Pth9HIC3sy2UaslHu4tBdoF826YzIPO7lvfCbjNh8bVD4YhQthvExW+OBrmp/WJCRYsiDQAiOdE+Gqo0MEa4kQEHK8qodCHliyJuySvj3Z0geXbL54xC/pmzHkdELkoalXG1umknS1/kP4DsiIic7qdSkInw/isG4P1dxaiHto7GI5/kYMn0oZic7ERmbimWbMiTLdXLB7nmcjp/XogEGQ34+4xkzWUjOxsyJxiNBswY2QeAskXaZglS5DwXlzfg8he3qorOzRrTDxsPnkLPcCsmJTkUCX/I5ceSap/XtOyA/MinBxBmzsXpunNrSWQI/ZLItwNnDjbiH7eMwIs3DRc0atgGzw7KdBA+nr9hBKJtZmTllWFdzklU1rdiT3EV9hRXYd3+k90yWMFvzFvR1NauuUHcM9yK8QNieMcCn1gK766FgueZBC8iQ0y4Z0ICXvvGdxdOaO2mUY3jg+94XT3iD5yzsfgK8IV2/DYfPIWn1ud2mviMXHqGWzW/F5X1rXBEWDWTxPaLo0G7RUke3rmp8bIlLbWYNMg24d2p8Ugb0surt8TyOSkdD5syh4Ytjyc1sOet2S+7F4BShLS6aSZLPsYPiJGVbhAVaoLLxaDdxSDIaNA8FWP6CCdSX9wqS+2HltO1zZ5JSyofWy4GAJtzy7BoWvdKl+IydbgT953Q/vp2BdjRayULw52XxWM5pcAG0GGMhJpk1b5xiQoJBgwGr11pskDvXJjmMZiPltVh+bf059YVqG9u93HcSOG+WHoKTf0UN7WSoGU++5NfHsKz1ycLKi8KFYteqAgb89oaw3xCLkK9CgD/RP5J8GJsQgzeuC2Cau1udzF4d+cxqmePq/LId7zzoaaOXHO+9YT0yXp9TgqmDnf/ruc35503aw/7Odx48JTmx9fy/mruaMjJ2XOwip3+s6tYsQfJHRRhlmBqCUoDgC/2n8SmQ6Ve0QVnpBUzRiiXlCPRLhqDIlBOBoFvh0JqshRiXP8YWapQ1Q2tuPWdH7yiCWRHRQ1GA3D35Qmq1VvE8lTJy29p0AWY79jdrbGWEE9MTUKIKQjLeCJ1chnqCMfhsjoNzko97Ai4EuPnsv6x+GLfSVmNUdvaGcXj4drhTl4hCj4jdldhxXnnaIgRYjKioYVfVYiBsvoprfPZqxpa8eSX/Cm2UnKkFxqBTuPh3n8hxxLwb+R/3kf78MKNw7ycfr61OzO3FI9/fog6Y2L22H4wdOQ4jO8fi3EDfNPwLpSaunmr9+HO4jhEhpjPGycD8J6H/HEvtDymJg37CHIGu91mxuJpbkMzyGjAzI6UAiXMGNEHa+4Z52nZvnTGUOrPMnBP2NwtzLKaJlW61SS1K1BeP80y4uxoPS8U4RJq7CJGkNGAF24YJvNsvRsAkR2VaBUdhV0M8Pk+frljuceRwp+O4fkQJQoECT3CNDlOV3EyokNNnghoZm4plm48TP1Z0mhq3IAY2Y1RaQMubJyRVrw+JwV7S6p4/04e/2f+m+dpHEV2JpUwc2RvRZ/zJw0tLlw7rBfvdbaZg2Qfz1+GsNjOLTt4caETyDQedld6NkJN1fw5p1c3umXjt+SVCa7dRH5eTlr28m2FyNhWgIxthXj0swPYklfm8x5/NhoOJAyAVd+XiMqFd2XaXQxcLgZRIcrtJzZyGhvSoqmjIWewV9W34MHV+/C3/x7GrsIKpA3upfh71x846el6PX5AjCZ5/2RBMBqUNWdeusm9CAfK66dZwP5x0wi/bKOT3hJyuq5zjZXJyU7MGdtP1XlcCEXEF0qUSC1aXIdABHFjbGZcObiH5PvI806i2nJ3b0nkSqhjrSPCguuG+6rY0XD7uH5YPG0IXv29O1Czc2Eaom1m0bmca8SSWi8ll7yrFZMSNh46zXtu9S3tuF+kSzIfnZnP3h2CF4H8jf3svvZFZm4pLn9xK2av3I2H1uZg9srduPzFrcjMLQ3InM52+tm0tLnwiEqxFZJi9FrWUa/vIGO+q47fCx0DgCe+OITUF77Bre/8oKi+VwitFS81dTTkpAOQh/Pd7GLMXrkbD67ehzBLsKKFqrK+1Stqo6Wn7WKULYRkEe5KXn95vX+6TJOmLwunDMbt4+idBa6xYugKF6mT8EcU4XxGi3GjRFqYlqgQEz7646XY9cRVOPBrjeT7qxtasftYheyoNt8u5ORkJ3YuTPPaxd3+1zT8xFM8TcPUYb1x94T+mDnqXDSU1nBjv484QXJ3Nr7MkZdfbIC71ktOYMMfPP75IWQXlPMaeFw609jvDsELpb/R0PG/+yYmwGamM4fKz3qvoyR4wHUkya59VX0zHBHeioVaIrRzlZlbikufy0K9iDKVHF7NykfqC27niezeNLe5cFOK8mwUtSjZXbxQEMrGUYPR4O5cr3VAWrMaDbnpAFzUdr3m9jjQIu+fjZJummfqmmT3E/EnWiw4XIm4qvoWLN2krriR3Lvx/WOpu8mfzyhT9+peqB3DU5J74SsZ2uu0kLvzwo3DkDowFrsKK6h30r4vLKcaJxHWYNw0ui8miSiQcXPClfRjECtqpp0ruO8jtV7vZRdh6aYjss6HBs/1v2GYV01ZeV2zX75PjOrGVtz69g9U/Sr8YexLyZsC3Sd4QSPTHhVqgiXY6GWYsZUm36NMlWZHjqXEXgwAFn2ZS/071MC2gfzV36Kslr+3R2dgAHDvxAF+6UZ+IRAZEozrhvfGhz8cp/4MwwBvbS/CqH7RmjobmjgagWraIgbfgqelBCPJy78rNR61ja34bN9JWefUmQNTqy7T/uoA+r+O7eUxCfYuMYEJQRwEmgVeiAXpiVj746+y1b26K5EKn4eKs/5Jo4vuaBpH7pWcSHXO8Wqq9z0zfShmpvSVdV5yI+bkWZ6S7PDsvLIdGrX9dfyh+gZ4C4iwAx6dGdcspVB4Gh0XrXmPGHOwUXIeWjxtSLcIXtDItD/PcU7ZPTbkBAINrH1WqZQ4Bjx9MFioWUu4EHsjEIXxgVyjb0rpi6wjp3kbnk5KcmDtj8c7pYFoV6emsQ1Tkp3YeKhUVlNlf4hIqHY0Ortpi9iCx1ZS2pJXhi9zTime6MkN+Cq3DN89diV2FpQLblmxz6mznTCtouX+/B2bc09jc+5pOCOt+P0lff0iHavFeUeGmjyF70p2qJyRVsxPS8T8tESvxW50XDT2llRhfc5JarWvCx21z9ueYv5CZrVU1rdi6aYjMHbUS8iJVGdTduVWEv2W+xki3/pudjHezS72icor7a/jr2AEu8fMlrwyn74gnT1cGAgvzuSaaOlk3JTShyrYFW3zX8pOV0NMpn3xtCREhpg9vWCmJDuxt6QKGw6ckp2Jwd5JVJsSp0W6MNcGOh/6W9BAfteLNw0HAEFVLa2zV/yFvxuc8nGmrgmtbfzqeUL4QwFTtaPRmQ81jRFNUgzGD4jBk9OSkLE1X3bPDgK5AXtLqjBjZG9Rg5hsx3Z250yaaLlUx8xAOZNlNU14a3sR7pmQgDV7SnC2Wd4AEYIsNEs35amKfBgNBjS2tMMRGYLX56TgbxsPezmboWZhSUwDvJ9TMoAzc0txxcvbqBoJdRc6O3ghBVvedVKSQ5acNg15pbVeHcS5cxvfeKXpR2O3mTBjRG+s+r7EJw2U+5v2FFWiuc2Fh9MTsWbPcd50E+7z6a9gBLvHjFCHZ3/W49DCtzj745o4I61IHRhL5Wh0h0JwNnwy7VX1zT7pvUpSoQF3TcC4/ufur9qUOJoGnAYAf5wQj7d3FAOQdvovlHvOwN0Xi7tmciEOphz53s6AgXsOHtYnEt8dpes6HhVqQk3HboSSOaT8bIviGp0u1UejMx9qu82MZ2cmUxlk7S4GuwsrsCq7WPX3ZuWV4V2R45BiGiV502KEmoNgNBiojZrF04bgztQE0eg4XwSSa+gGypkkA2mlRn0q/jA+DlOSnR5jzWiEqshHZX0LFnQoeDgjrfi/a5MQbbN4GXz/yy3zafQo5DgINpjqhs222HT1iBx7e9nlYjR1MgDg2c3nag24z47YeF08bQgeXL3f53hk9P99xjAs3ZTH+53kNz3+xSGfjveOCCsWpA9CfGyoqPPjL+eQBHi+zy/v0g4o4L0ean1N2EZlZIiZ6jPdoRCcC7t+KTO3FPNW79fMMR0dF+1pNgtIpxhqwfKOhnKj4+yCjfkmJTmwq7DCU690oUBbLzA52Ylwqwm3vv1DgM5MGVX1rdROBgA8d/0w5J85i1XZRbKcKLIbVN2gfBdVy7lDtaNBezJa56cCwKIpg306X/JF5rXezl+XI9yvwQBgw4FS/HXyEM2dsMYOz5S20DU23CLpZNAYuudrhGRKstMrCkIiH0s2HFat1FBW04R5q/djxW0pmMHqATN1uBPXdOS9l9U0orK+BfYwCyJDzF4LFE0RYXdptsXlfHjeiPH71Hr/FnqyxyIAwfFKCjT5IMZIZIi0ZK07l9d7QTtd24RlWUex4raUTmlKRrj/o72aKej4C/Z6qPaaRIWYvIwL9k5Su4tRVUPTHfCH87s9vxyDF3+FeyYk4ImpSaIphmrhBhmEmuoKpRJ2hV0+LWCvg2LZF+P6x/jd6VML7XmRBsRKhHbYAYnck9KKiELfX6WhSqlqR4O2aPC7x67E3pIqZOWV4R0NdhUA4NmvfobNGozJyU7BSN/0EU7V3aIJBrgdpgoRh4md36Z1NIkYoHuK6PLPY0Xyc+UYuudjVExIbYVM1hlbC1SpVYg5A0FGA2oaW/DS/34R3CmiKSLsrp3Cz6fnTW4/DLmQ52zJhsMADILjFRAu0CSNUdfnSKfaiJ2DmOMbCOewqzsZBoM74k1Qe02Wz0mBsUNqmGtUKa2h6U74y/l1MfCkTT8xNUm4NiTCgqY2F2oaWmXZH/OvHIDUgT14dw65anNCwcILxclgr4M1jS2i2Rf+dPoCzd2Xx+PtHcrsVnZAItxiUqTk6WLgDqR21CKqRXUfDXJzAd/GduwJzxxsxPgBMR5lIS2orG/BAx/uw/Ob83h1rEtrmvCmQidDaHqeQdnF9kxdk196aDAAKupbYLeZJI/7yKcHBJtKyTF0u1IvEFpmjeknWrfzUHoi3lCg+c9GTL9cTFc9M7dUUZ+C7oKaLtNyYGvoc7/PEqxpiyFVMADKaptl9SkiGKBN81CpLtPnk3OohDCLdEyOYeDppt7uYlSlsMTYzBjXUVvI1+0ZOLdD69O8kaf3SnfE33PnW9uLsOOX39DS5kJkiBl/nTzY3fjylhFYc884ZD9+lUc8RM7amdgrnPd+A97dx7MLyrFkw2FR++ZC8TNJbZbYmgoIj4nziYevSsTGg2WK7Nb5Vw7EzoVpnrE/bkCMKntbqBGkXDSRtxVTe+DmF2tdGMfAndOv1Y4FKRxe9OUhnwhhZKhJVm6sPz3smSP74N3sYtHjnq4VzvWXY+jK/R3RoSYwDIPqRm1z1+XQ2t7ularEB3cruri8Acs6djnk3CvavGx2ZPgfN4+gOvaFbsDxEajeM+z56a+Th3ieg1ibBY98ekDSsLeHmlDZRaWYCXwBAzWpBVvyynh32AKRq95Z3JUaDwCidXmEstomvJaVLzunmsuMkb2pdiOE0mm6804Gwd9zJwPg9lV7fNKUSJQ9qCMaLFdmP/90HXYVVvjcRyUp4C4GeHLqYCzfVtilC6Wl+DLnlOhu7pPrcpE2uBfMwUafMREbZsEjn+Ro2tjOn7S5GMU7cakDY32yK164YZiitVTLrArNwnZ83WrZnpU/iwW12CZk774YjfxpCDUNrViWdRRRocK7CdwOz2Si6UXZxTbERHdLSmsa8XB6InqGCzs+5LKwvVISEck/fZbqe8hkLRQpcEZa8fqcUZ77viA9EVUNrZ3qZABAxrZCXP7iVsEdHQLZir52eG+MTbDjztR4hFnl+d9y8rLJ4AUD0V2i7t4pfHKyE2/clqLZ7idh1EVRvPMTeQ5mjOwDo9FAtXvwh/Hx581OHztgAMiLsLJ5N7uYd0xpceyuyqQkByYlOajeu/jLQ3g166hqo47m+8hcvvGgu7P6tcN7C0bCuyOB2okXUnDbfPCUp3v2P24agQ/uGouoEOn5LGNbIWav3O21fgntktNQ09jaZZ2MJ6cOEb0m7nR1k2R9b0V9Cy59LguvZR3F+pyTnsDKjJF9kDowFkumDz2P5iX5Bq2YvUDWUm53+sgQOjtHi51BzTqDA775g2y6upIMW73h8he38r6HRKQNrP+mzY1tbKUzvF+5eQT+tvGIpKFDek9ESxhiUjmOUlSxBrhU9KzdxQheu86AT72JW0w2Oi4aK74twKrsYt7JWGoHx2Dwvka0g7K8vlnPsZaAXU/zbnYRajRYLPf/Wo37OtI4haC9hwk9bOdNTnBsmAXZBeXIPVmLycm9sPtYpVdTPZJPLtXYSaxWQyxXffbYfoiPtWHH0d+oZFml8Ie4CB/sxdsZaZWcO89SyJXK+U4haNQCuzuB2hnlQuaB+Wv2ezkhdpsZKXFR2Przb1TzBWkEuXzOKCzddETF/NI11xBnpBV3XZ6Ai+whHjVIvnVw5sg+VHW9VQ2tXq0L2OOBzE1Prz+M011UlYtk1IzvHyu7roKBuL3AZ7u5XAxufUdapUuLnUFNHQ0xumqueaQ1GK/fNhrj+rsjQVKStAzcD/RNKX18mvbx6cvTposZcE7GLv9MPXWhMm0H3i15ZViVXSx7svrbxsOIDDWh/Ow5Xf/zxZnkFrFuySvzWZxJ4zKxY4h+BwM8uHof3jCmyGrg1jPcivEDYqhSDrszpJ7mkrhoqkmRBik1L7n38N6JCe70zS7oaRjg1mJ/8KO9qOHsMlpNRswecxGuHuqWgH4p84hks0yp7XSxYES7i8Hzm39W/ZucLHER714JR3iLcdV0MWYv3uzGYFyDSEsJW6kAgy6LTc+kJAd1c0Ot4e50VNa3YOvPv7n/QfnQMAD++vlBxQ6sM9I9R2VsK1D0eTaRIcE+c4gaFk9zP+eTkhx4OD3RJ9jHVstTIiDENx5a2rXpzaU17ODiuAExVEENNlOSe6G5zcWbckcgGwGeYOvZ5o7dIuH50RFh0SSrImCOBu3iraT5lRopN4PRgLqmVtnNbj7bd1JSX15OuhgDINrmToOKjw2V+zMkEcpxlKKsttlLm1osatYVnUliGGVszceyrHyfa6CVcUiMV1oVtrEJdrS7GHcR4TUXe2RwHRF6jjUf5RpK7Unlncq5h5m5pZqp2vkDEhjho6nVhVXfl8AcbMTYBDs2HBBPM2Tzxnduw4VGGYek+GQX/KaooJ3L4mlDPOIibK7pUHPzROwYRrGuvtEA/Ov3oxAZYsb6nJPoGW7FpCQHb2BASolQzndmzB4l2VxVl8WmIzO31KcnTFdBzrqjZpds+ggnxvWPgSPCqvo6GBW0MR/RNxK/VjXy7j4u3ZSHAyeqsOFAqdd4igoxYW5qAuanDUSQ0YBnBXr/SMHtd8TXT6WrwA0uyt2J+yr3tKflgZiNJrfOp6nNhS15ZaoDFwFzNOTI4K74tgDvZhdTp0pYTUFoUCh9WNPQ6uX1Fpc3UH9WSl9eboSfGOpaFrEZAIRbgzVLMxCLmsWGCcvpSuHv1BMluzlyYBuvNClRfLsr7CJCHW+0LuwUc4pppUMBdOkGcrRj6s3tRQgxBcuaq747Wo7vjpZLputo3cMIAKIFZLu5Do5SOV8AmJLswLNfHeExgOJ9dlPKaho9jTzV4GKEfxtBl8WmIzO3NOApU10R0tPrkvhobDxIH0jggzZ7gs1frxmMmsYW3kaiRBWUS02juxb2YkcY0gb3wjs7xXdZxWD3O+qK8/T8KwcidWCsT8BmcrITC9ITvVLBaBGy0ZSIMXHtY6UETMNRjgzu/LREzL9yAPWxiZOhwOH2KpjefLDUozok97N8EmByI/zEmNKyiI0BUNuk3XanWIH5B7uKVR33iSmDYTMHqT5HPgJRDEfut5TsJAAqqT6dc2hd2CnluNBIh+4+Jp5myYVGIlVL5Cwob26Xr7UOiD+zagpYxaCdV9U4p5sOlfmcd3WjOwd87HNZqGls8cjOOiJDFH8Pl69yS7GrsEJQUpL2t2fllWl2Tucb7S4Gj39xqLNPo0vg3s0vUO1kKCEq1IQxCXYs3XRE1ufYNsZ/vi/WROzH3/2OlJLYK0xQwGF+WiIclCJCbIRsNCVBMSkbl5aArnw0MrhqImAhJiMaWuTn4KnxesUiSHIWOnYBoNIitkAVSKotMBeirqlV86ZcBrhlidXkadPCvt9CueoAcPmLW/XUB5loJRVtANArwgIXw3hSYoRS1cTqDTJzS/H453TGzBBHOE5UN6BOQ4dfaxpbleUuCz2zLW0uLFp3yC9RRPY4E+sU7C/J3WpOlE/L73l/Vwne31UiuFNEu6asyzmJRdO65+7o7mMVAZnvzxdWZdPvCIRZgjQRNACAF24Yhr0lVYpsA2Jj/FjM37enK0DWIZs5SLHdIjaeg4wGLJmuTMyAa5eqqZ/VYpc04F2pxGRw1UbAGlpcuHa406f5Fm2UXI2RzhdpkhOFnZrsNmiI1zgpyUEt7Umkzf52XRLsNm3lQMX4WqCJjlJOVDVqchwu6YN7+uW4bPiUYtiSqSRqISf1QccbKYnlBemJksdg4M47vfXtH/DQ2hwfGUkufPeQzFO0u2RHyupQ19S1u1qrgfvMZuaWYtzz3/glisgeZ5m5pbj8xa2YvXI37730p+Qug3NRPn98j9BO0dgEO+w26V5OlfWt3XYO2VVYIfszUaEmvD5HXQNXQlfz7eTs5mvhZESFBOONDidcbd1mqAYZDmEW/2RJOCKtuG9igmInQ0xdjmSJNLe5MDW5l+JzJNdfi/pZNccI7F5+B3wyuFr12dhZUI49i9I9ObSxYRbMX71P80g5Fz7PlCYKS15/J7sY72QXeyJZkSFmWVGZ6SOc+NPaHMXXT0kk473vta17+DLnlIZHc2M1GQOiODJrTD+q922hTGnoioX1XQEpieWLHeGCO2xRHTtb3HElR63Hn/2AzneyC35DRV0z5q/1zcfWClLDRKu8pKRhGi3sKJ/Q95C6jsSeYXhi3SFq1R6hnaIgowHXj+xN1Tyw+84h8kfn8tkpSE2MhdEIXmUxMZyRVvzjphEor2/uUEBrwbzV8o7hDwwAIjRWiqLBagry9IFRW1s3xBmODQfU9Uq7ZqgD2QXlOF3brMn9mH/lAKQO7IHRcdGYoELOf9aYfrw7jlrWtZHrr0WNo5pjdIqjwYdW0qjVDa3YW1LlcWR2FVZQFTGFW4MURx3FPFOphU5ooZzb0Y1WiqgQE56bOQxLN6kzfs42t8NuM+P6kb1x1eBeeOTTAzhdK54K0BXlPLkoTQmRy6tZR/GfXUWYObIP0jvUp7iTSGZuKZWBAHTPjuBsxFJixPr1TE52Im1wL3ywqxjFFfUAgJEXRcMRYcUjnx4A4DsXyElZ6woSztcNd+DH4uoup6YjV/tdLqTGRa7yEtc5zT9dp9m5ftWx4zA2wS7pBF+T7ETG1gK8tb2QKvAllLIQSdH0Dei+c4icPgREhGZcx/WV45iya0tTE2O9/rbC6B/nlhYSwGzTosBBJmW1zZ5nVm1a4fNf/YJQs3KxHwD4fN9JRIWaNHP6EnuFY/yAGOwqrFDVk4NPXVRJwTYfbGVEwN3rS6k6K/dYSugyjoaW0Rf2sWiPe1NKX2QePq1oQDS2tnskwPgMpHONx/IlVQTIQrmeMrrf5nLhl9N1mkxoVfUtWJVdjLEJdiyZrn0jsmuHOxXnbHYFDACiQ01uWdPDp33+Xlnf6rMz5dHvbnNh0bpcqu/pzh3BAXXNyPg+m3XkDGaNuUjUMKfNQ+3sKHF0qAlTkp34sbgqIN9nswShXqOcbS6OCAv+79ok/G1jnlc/IiHqm9vwwIf78HD6INnKS2zndFdhhWaOBl9NhdDzE2Q0YH7aQKzZUyJrh539zGXmlkquIVoYBucz4wbEeHYvxRBqjMrnMFbVt2DpJvp+R+xjZOWV4ZO9v1IFMrWqkSB1if4au1KQZ1aL2rpGltgPO7hpNABXDemJrLwzgMSxazSs2SHKpGrXgvzTZ736XrS7GCzZoH63nPtcZ+aWYt5qOufFX82Du4yjoWX0hX2s4vJ6qs9cPdSJS/vHKBoQRALs3okJPprQZAGalOTA2h9/pToeA6CivgV2mwlV9a2i53K2uR2vfSNfAk3oe0k0cOfCNKy4LQWL1uVqUmDuiLDgtVmjAADvZRfJVqLobMgQ+/v17t0jKdgpHACwaN0h6pz17ixxq6YZmdBnS2uaqGUCpRaPzowSGwDccknfgOrBv3X7JTAaDMjKK1PUNEuMpjYXjEYDsh+/ChlbCySblJLf/BalQpbQvRwdF62q9xIfZTVNuP/DfViQnoj4WJugyMCeokoqp4oNeebITo4UDM41Q+uOBBkNeOGGYZJFtGKOAt+uaXqSe6e0pLIBcfZQ3D4+HuZg4TJXcozxA2KwcMqQjrol4bXUEWHB9r+m4V/fHFXkCJOeXrE2i+DubaAor2v21C+pTV8kdknPMDP+OGEAfq06d/2DjAZkbC3Aquwi0VoULefLtT8ex/y0garXgoxtBcjYVgBHhBWzx/bDz2U1muxSs59r2lTfeybEY3Sc3W/Ngzvd0SA7AGU1jYqa9bHhRnLaXQzW7Dku+TkSQQ4yGngHhNSiRP7EpwlNDKSH0xNlD7KZI/tQp9poBTsaODnZicaWdtUa8QYAS6YP9Sx8seHK+20ECm5EjN2llOY+kmfi0U8PyIpQ3Z0a3227+kqlxADAkg2HedObtKqdEFo8yDx1qqoBVpMRTQFKySM4I61YPC1JdYokLZ6Ukv4xHoNpdFw05q/Zr5mBztZofyg9ERc7wqgcctrdAKF7ubekiuo3yNnNIYdjO7R8u3ByoqDc9UxO2t7STXkwGtFt55LJyU68cVsKlmw47OXYRYcG44ZRfQXTW4Xg2yl9e2cRtRFmDjbiuZnJgp3lAfcaaQ42InVgD1mORlSoCS/cMMxzHrsKK6gM1ghrsKbS92yWbjridX3IDs+rW44q6lLOADhd14LkPpG4Z2J/AP7p0UMDsY/GJtg1uYZltU2SQRYa/jA+DlM6VPDIc007Z6zcUYzRcXbsXJgmmPqphk5zNNpdDDK25vu0nVcK3xYPbfSIXZTD3TYtLq/H6h9KcLpOWVSfeOOrFDgM6UkOjEmwy4qGS0G7W5NdUI6xCXbVGvGOCAuWTB+KSUkO7CqswJm6JpSryGv0N+wdKL4BJ7cJmNxt8PSOIrruCM2kWFbbjIytBXiIozCltnZCLN1k88FTeGp9bsC12G8f1w8Gg8ETvQtk2iED3521aJtF010Abj3F5GQnGprb8ZdP1Te/s9vcKY58qay0xv7frx+G4xUNktFSIUp5duHkNIQFvO+BHCdFjsDBhQp7LS+rbULl2WbYbWY4IkN8DCixmjA1u6zc85GS9wfOqVVKjfXJQ3vh9nHxGMfqw9DuYpBdUE5zeXD9yN748Ifjmo5pNtzrE2Q0IHVgrCJHg0DGgFa1DGrP4+qkXgERm6FhCk/appw545n/5iFtsHKFKzE6xdHIzC3F418c0lTrmm+Lh/Yic4tySAQvM7cUy7LyVT/MDORJzLGNniCjAY2tLiz4OEflWZw7FxoythXg830n8OSUIarSDF65ZSTqmlpx+YtbZe0SBYqoEBPmXTkAsWEWnwWIL9fa36kzW38u67YdfWnH66tZR5HYMwzRNrNXd2aliOWhPr85j3en0t8YDcAHu8/txr69swhDnOEB+/6rBvfwMZ78UZ/CraeoatCmD9DMkX2wJa+Mt9aHViHOEWHFzFF9MD9tIPYUVeKr3FK8v6tE1nkwAJ744hAmJTmwJa+MuiGszRyEV24Z4XUP5Mw9ek8eN0FGA2oaW/BS5s9ez4HdZvIId/DVX5CAU9rgXli0jr+/lpJrLCUYQM6Z1DUILZH3TUzAE1OTvF6TG+F/f7d0toca+K6P2uLwnuHWLqH8V1xe72PTCBFhDcZtl8bh9e/8I5YhFiSLtdFnj5TWNPmk99HWRkoRcEfDX54owyOBRDsxs/MJCf54mCOtwaiR2GbjM3qUdIcUIyrEhJpG8doPwP3gqZWq/HB3Mb7K9S2cFnIytCw+p6G6sRXJfaKojXt/NQEjrNxRDMCAJ6clSb31gkOOITV/zT6vZ4imt4AQ0TYTLk2IQe7JGoRbTJ4I4eaDpZ3iZAC+46O0pimgKQLf/PwbMnNLFRu6ciFOjJr7yCYixCQYhV6WdRRRoSbUNPDPgdyFm52vL9fRAICqhlY8tGYv9h6voZ4z6lva4eI8BHLnHi0abZ3vCNkbbOEOPkjNjVSaJPsaj02wexyI2DALwMAjeUurmkeYnOzEvRMTsHJHkddcYADwxwnxvE5GZ0b4heA+g2qKw+02E8pqm/BedlGnCspEh5qoa/4MAF66aTia2/yTaitZrC0zvsCtIdJqZzSgDfv86Ymerm32aXBE2zBv6aYjPk27/CFj2dwu/bA5Iq0+N7WqvkXThlNzUxMCNiHxORlsuGPDEWnVrHESLXIitezmXP5i5Y4ibPRDT5GuDhmvNHANcSWCBVcM6oEwSzAq61vxVW4ZMrYV4tZ3fsDov2/xpEspZfG0IXj1lhHu///9SMy/cqDiY3UWpCEdQU4DUrkQBRa1zgxpXrpmz3HRWh9i5HB/i9DC3e5i4HIxiKKUluWy8dBp2evJU+tzva6/0saAna2U1lmosTfIZ2hrsbLyyryaR9769g+49R26pqB8ZOaW4q3tRT7zHAN3MIp9rK4Q4ZeC/QwKNV6N7mhQLPRsV9a3YsHHOZ0uJCOnvwqx5fwVpOGzF9mUn1WXpk5+K3ctkEtAdzT8qUHPt00nx3vmem7+mJyFJi2bJQizLrmIt0BNjjSZFCRS98DvBuDXyvoukVvoYtxGWWy4xSvyYzRCUjWEMP/KAUjsFY7YMAu+LyjH8m/lbVHSTALcHN7lc0Zh6aYjfnue56/dj+BgQ7fKrybjlfa+q+W7o7/xvl7d0IoHVyvfyYsKNeHO1ASvceyWVFWem9wZ8EnEqpWqFIIosNhtZpiDjWgRiQCS3QiAv6h21ph+osWVDNy7DAvSE7H2x18lVVY6q+iUdPcm17/dxSAyxIy7UuOxLuckdc1Qd+2nEcieN1KKbFo3BX28Ix0vyGjoEr19pOA+g0IpZHzpjl2Jm1L6UNlN4dZgLJ7mW3ejZSaE3WbC4mlDRJ+n2DD1wjta7IwG1NHwd2SF74LQSqtxHZVATs4RVhMW8cgR+iNSMX2EExNf2talmn3FhlswY2QfH2P+4asSsYxCujd1YA/P/TYaDNSOBq3evFBfh8XTkhBtM2NLXhk+3XsCdRoreHTH/OrJyU5cN9yB/x6k66CuFH+m6FU3tOKlzCNe6Q1jE+yw28yaSEUHEu6c7c9O2wDdztQLNwwDAMGiWto0hdZ2F7577ErsLakSzJfv7JQUdvEr9/dGh5rQ3OYSbGbW3ftpBGInxwB3fwepYK+ceg4ax6G6odUjiqHF7xSaD+9OjUdFfQu+VLHD7oiw8D6DfClkXgX8NY1YuulIl5kzHREWpA6MpXI06praMG/1PqwwniuE1zpIU1Xfinmr92OFkT8gmZlbiqdV7MpzUfOcBTR1KlDGO9/iuHNhGm5K6Sv6OW6+ZaDSd8h3ctEyUuGMtOLeiQl4c3uRYidDaGoMNQcpPzG4n4vM3FKvrefZK3dj7Y+/IjJE2BcmaRKj46Kxq7AC63NOwuViZNW0SPWsIIYG9z6U1TRh3up9qGlswf9dNxR7n5qkWX45Qei5uJDJzC31u5MB+L8O6M3tRdh88NziHGQ04PqRvf38rdrDN2eT+XRB+qCAn090qMmjULVzYRrW3DMOr80aiTX3jMPOhWmYnOyk7p2Usa0QV7y8DTWNLZgxso8nh5xAE+iJCjHhxpQ+Kn+VMGRu5JuDqhtaPU4GbQpYdyIQ9gYDelETtn0hBq1Bt+r7IrS7GMW/k6yfr8/xTWNyRlrxxm0pWHzdUPSN9u1gLYfZY8+pera7GM9avauwgjcdhzggjsiQLuNkAG75YbkqnOyUI6GUMaWIpTVl5pbi/g/3KVZL5UPNeArojoa/C2kJQhck64h4vQDhTF1TwNM4yOTCjurnnz6r6pghJiN+d3FP3DYuDmPi7Rj7XJai47A1/L0iiBEWzB7bD9UNrVjz43HZvQVIxK2qvoU3Pex07bnnRKhj5fQRTlzx8jav86JZVsXUFNi9XZZuOkKlOGIONuLm0X00Lx7uTvnVtA3JzheeWp+LazqiWQAwKckR8L44hCenDsG+45WSNVMEmmj42h/9q1rDR1VDq1dhKTciStM5m41YSgtVZLmxFTeM6ov/HT6tqgcUHwYDUFHXjGe/Ep+DIkNNsAYHeQWQtGq0dT4TCHsj1BwkuKMkhFZNQas7xsLouGjZu6VsR3RyshPXJAsrYY0fEKMq7TM+1gZAODNA6DntKmuf0QD8KW0gmttccDEMHBEWnK5tlnymhDJsJiU5kLE1H+9mF6NGZWsHvu9odzF4/ItDqo7LRoudUU0dDTEtavK3KcnuxVZo+ygyJBh3pSYgPtYGe6gZf3h3D/UkIXZB9hRVUkvMkoE+OdmJ1+ek+Cjc+AMSudIyJaGx1YWvcsuQ82s1fn9JX8VywlOSHYi2mb3SDIrLG7Bmz3FZizobMtEtnjZEsAkZWUijQk2wBBu9eqJEhpgwITGG17AXulVhlmDccklfTBJp1iTnHnB3wDYcoC/2o6U75VefD7nGcuDm2NPq4/uD0ppGaieDIBYN78x7JWSAKHFUxVJaaA2d8vpmvHTjcDy4WtugFMNAUvWPgdvg/OjuFBiNBs0bbZ3PsNNV/IVcJwOQntPHJtgRFWKisley8srwl09yBJ0MYmcJNaAlBr6YEta4/jE+n5cDe1dOTi+SrrL2RVhNeO2bc45WVKhJluPKnUfcMtfq2yYIfcfuwgrNWkdotTOqmaORmVuKJRvyvKMqEVYsme7OU+YabwaDeyIlRIWaMPeyBMxPG+j5QbsKK2Q5GYDwBaFdNKJCTV6OytThTmRglGRxaFSHYoLcG3wuqt+Meav3+yXyUlbThGXfKI9IvJtdjHezi2G3mfC364aiuLxBdSdL2k7bpHDzoz9eip+KqzzNs6obW2Wn2IRZgvAkTy0MQWk+9pm6Js0Nr+6YX91VIlha8lWHOgwx/NiGTyDz/j/56QT1e2m00zvzXhEtfW5QS+kYJAGD3ccqkDow1ut7aM9n/IAY3HciodPkkMvrmzFjpP9SuM5XJiU58OerBuJf3xR0uioT7ZweZDRgbmo8VRBPqgidrLNSvTukzueFG4bJzu4gv3d0XDSueHmb7F4kgcqAESLMEoyzzW0+Dh8RorBZglBP0ZCXPY/4SyGM/R27jtE1bKRBq51RTRwNkg/Gpay2SfDhJDsEd6fGIz3JgdFx0dhbUoWNB0/J7uAKeA8o0oGaPaBoF425lyX4DMCpw3vjDaPBx1liN/0hk0fG1nxZUX4GwLXDnYIpOlqg1XEr61sxf22O6uMsnjbEo8pD22n7myOnsSq7WNVvKattFlROUDMB9Ay3amp4ddf86q4SwdKS93eV4P1dJV7GO18xtb8bWNKk9UxJ7oU/jE+gMkLU3CtHhAVNbS7BPhZi2G0mVNU3+zTLsttMmD5CXQ3MvI/24YUbh1ErxXANxyemJmFE3yg89vlBKgNES2LDLLzrXnems9TC+JA7p89PS8Sq74sFA5c0Reh2mwnfPXYlzMHuUlyhdY/PAeG+PinJgTduS/EJJkeHmlDV0CqY2vz0dUnYW1IlGUzkUzXyp8odDUECt4k4R+YgI2CB4Fjncyz9sRPs9HFelY17owG4+/J4pA12aD6PqHY01OSDGQBszi3D6Di7T569nA6uxHDdkleG1Be+8UqxcURY8H/XJiEy1Cy5HRkVasL8NH69e5qOngDwUPogXOwI95ngbOYg1Atss67c0TlRsM7AGWn1kv6kNVi+zDmlyUQj5BAonQCiQkxwMYysDpxS2G1mPDszudvlV3dmapG/4aYIsOeS8rrmTteGB9xzHK18YVV9syLniMzVL2UeURT9H3VRFO/Ob2V9K977Xn4zPTbVja1e90jM0OEajsQw21tSFVAng6SWPvJJjte6p1VH3/OVzlYL4yI3Mkx2Efh+A3kWeXoUe1FZ34q9JVWCY1qoZmL6CCc2HCjlraXIfjyNSpKW/Xtpg4lltU0+zrJQYEbMntIKsebKJNNCiHOp4Ule18sfap+zxvTzskOV1tS4GODtHcUYHWfXfHdUtaOx+5jyfDDiyfLltsrp4EqcDP5dlWZqTfwXbhgm6r0FGQ1e3T9Jbj73M1xDIjbMgkc+yVE9MOZdOQD5p8/i6zx5udZdicXThnhdr9Fx0ZIGiwHKGrLxQRwbbsSmrKZR0fGqG1tx69s/wBFhFX1W5fCUhDb2hQrbsOsqBoJW8KUIEAOAdiEGfHOttYTW6Xf39pGf5ulkzdVvKUwx2n2s0u/PBvseCRk6bEMqUJFzPmdHyODRqqPv+UhXamA3/8oBSB3YQ1FkWOzZI7WuUggF1oQcsdKaJt4AgNjzNDnZibTBvfDBrmKUVDYgzh6K28fHe3ZSaOeVpRsPe/WGYTvLHsnbWndgZtmWX6iOqQQD3DWgtDW9fDg6HDaugI7dpqzhpxjxsd6qYGpravwhq6/a0dhVWKHFefhAFmZ2B1ehiBIAVVX2tNEfMdUEvt0OYkjsKqzwijYpZc2e49RNmroq0ZzI/96SKioNcrWwtzH57qNaaVq2QpZa5EroXUiQxfXxLw75zaCmxRlpxTVDe6mOlBOEUgTkpCE9d30yDpyo1rwWwGhw71JIocaImz7CPb+qMQL9HcX01GsUVngVVwv12whU5Pzuy+OwmdNd3BFpRWNrO+84kdO34UJDq/QUsmbwKS7SktgrXHBHQUw8hyCUSbGnqJLK0eDWBxBjfenGw7KeWbHniW89fXtnkccucrkYquJ2rm3DdW5qGlvwUubPfnXoya+irZHhEmoOwso/XIKahhbBnVca3IqecVS1sNz1Q2lNDaBNcz4+NKjR8N8US9vBNTu/XJFREhVqwvLZKRjH0U/nQ0w14f4P9/l4kGznRav8fS2cjMlDeyHzcOftiHCvRaCaKgFup3RLXhnvfayi2DGJCgkGAwOvJB05ns0cBHOwUXRbVQzffMvux+RkJ8ItJtz6zg8B+052A0bugq6Vo0HgPvPuZn4mqvEdbbPgialJaGlzYZWG5+ViINr8iaDGiHtzexFCzaaApMbRFmoK8eDqfV7jnMzn7JQCtZFzOXnn7+wswetzUryeT5eLER0j/jIaujpaNbADfOVfd+T/htcpG8ICwkEEoWDX9SN7+6gi8ilCya0f0mLXje95kmsXyf0+4ty0tblk14deMagHLh8Yi4yt+aJpUGx6RViwZPpQTEpy+NicNDS0tMPVzqiquX3oqkT8+apEAG4JcbFieK54EWFyspO3poYWre0y1Y7G+P6xyNhGP/CUEB9rw86FvrmBHnUqhVX21Q2tMBoNkk6G2IJCXuMOJjLQ7kqNR5+orhOhHtgzHOhER4M78dJGc+02M6rqW6gGLzcViy0UcPmLW0XvoxitLgb1EkW19S3tqG9ph91mwoi+UfippMqrY7hQ8RyhsbUdW/LKul26A5dyiui6UtxOxRBE2yySRW9jE+yapyvxRaBmjuwjqSADnFsArh7q1NTRIAhFwEk0lKhoKeXN7crV7+QQZFAXwecGE/hSR9RGzqNtJswY0Zv6Pi7dlIedC9M894Y25e5CVHMTQ84OoVBNAp/8a01jC76g6AoNiCtMCRnnlfUtHoVHqSwLOfVDWu+6sXt+ybWL5EKcmz99nCP7s/dfMQDjB8TgInsIdXT/lVtGepTnFk8bQp12z+bz/SdUzQvs9PxZYy4S3VmpbmgVtBf4Us4On6zGlxQy/FoLs6h2NMYNUJcPRkPPcKuozrPSKnvAV36SDyULChloZHvT36oytFyaYMfqPXTRU7lwJYu9/gb+iZc2MrN4WhLmraZTn3ht1ijEhvkakbsKK6juo1A0VE6EtKq+Fd/+8huWzxnlY9BuySsTTA2qaWjttrnVbPylQLUgPRHz0xKpUknaXQwythZoOre5U5R8d8/SkxxUjga5LmMT7HBEWDRJySQIRcC1rEFoaJHX1FMptZQRTFr4UkfUGvCV9a1Yf+CU9Bs74N4bOfK73QkaWdRQcxAWpA/CHZe5awn+OnmIaBqTEmOdT2GKdheslKLGhqZ+yB/1KuR5CmQvHanCdy7szIDJyU7clRpPlWpWfvbcfMpN86ZFSW8VNg9+uNdrB0bKrhJLjyR2c2ZuKd7NLpK8X/6S1TeqPQDJB1OK3WYWdRPEcodJO3tGxTB6f1cJZq/cjctf3IpMgWidFhGhruBkRIUE47HPDvrFyViQnojls0d56mrYiEn7kcgMJD43dbh7Uu0VIT74DQCe23wEYxPcygnjWWlxWXl0fTeCjaqHhVsVBMDSTb7nMinJAWsw/3eQx+SZ/+ahvSs8NJ0EMRa0yiw3GoDX54zCQ+mDvJ5BMoeszzmJXYUVaHcxaHcxeC3rKFKWfq26XwwXF+NOy9l80Huukfq9BngvnlvyytDUJs9ojwqhK0Rkz3fEwLoQlcDkwnbEAG0MeLlzMfveyH1mugtiawqhoaUdz24+gite3obM3FKPQXbtcLdE8saDp7zmAznGujPSKuggyDXOpdaByclO7FyYhjX3jMNrs0ZizT3jsHNhmma7bmy4z1NX3ilbzOmXNSnJQfU59phW+vvGxKsbb9w0LzEnizsn8UE7h/tTVl+9RYVz+WAOCSOQj+tHimufuxfm/T5OQGZuKS5/cStmr9yN5RqkbpGtcT5nQ8uIEPf+kUZ/gaC6sc0v8moAcLEjHFOH98aK21LgiPS+Xg6RiRc4F5mR+tzkZCdeuWWk6HkIDbzM3FKqiDHgmzahhtKaJmRs9d76dG9lCkeiaSaPCx0aY0EOGbNTcE2y08up2HzwlGcOeWhtDmav3I3Rf9+C4Uv+h1ez8lHTqG1UnM38Nfuw+aB3NHvWmIsEd/UA31QIuTst6UN6Ur2PrczWVdR7uhLEANHaGaaBvRbRBmm6UyE4QWhN4cJe99k2BZkPLn9xKzK25ssy1u9KjUdzm8vjqLCRY7zSrgPESeIG1tpdDLILtGnexvc8deWdsmiOuIsSp1zJ77OZg3DHZfEBnxeEgqhy5vDIEBMeTk+kdsrkoFlncKXa8JOSHLgkzo55a/aJem5/+eQAwq0mjOsfI1jQqwb21nja4F5eCiOj46I161DpYty5f7HhFqqCvvMB9vYdbb8RLrSfY29tisGe0Mlgo/kdkX5IAyQ5lvGxNllSul05YhQIhFID5HLfxAQYjfBp8sZHoJSuSADlDaMBLhfw1PpcQQlnrVIhUhN7ILuwgrqANJCpEUK4G/Spl4zWEmKASOXJM3A3QbQEB+HLHOkUKSWppzTpM90VsqZ8X1CO+z/ay5v6Stb9J744xCvgUVrTJFt96NnNP3v+m1trocR4lbsOuFM+87Equ1iVRCsbvuepszt3i8G9ZnJqWgju9FR5vS/unTgA5mBjwBsNvpNdjDEdfUfYyJnDqxtb8WpWPtb++Kvmc4dmjgbgrY7Q2NKOv0tU3hsNwKmqBlQ2tEjm4DW0tHf0K3B3laW9eWTHgMaAIBGES5/L8pp0okNNGNUvSrNFt6iiHkm9Iz2LRlcdrLRwc7vF62mEofkc7USdf/osdhVWeAqraO4dA3dneK3TZQB4LVa0UrpdOWIUKIix8OqWo4qaEAHAxz+dwFvbi7rk+PrLJwdEc3pvSumD1IGxiAwxewqylc5DlWebsXjaEMxbvZ+qAZ1W0VClkGar8xQUZPoDPmOfxtBfn3OSytG4c3wcb2G41O6E0uBOd2BLXhkWrTskWl8n1XxNDVwRASVNSeWsA5m5pZpLgz98VSL+dJVvXVtnd+4WQ6hf1vI5o7B00xEqpzzIaMCS6UnUheTshs9C84Iz0h243nhQnagGH3y1GkqClTT1QXLR1NEgZOaWYtG6XMkHz8UAj3x2UNaxaYsf5185EKkDY72ic1/lluL9XdIKH9xJp6qhFVt//k3WeYrx4e7j+HD3cU+0Q8rT9keU3R8EIgJPG0XJ2FaAjG0FcHY0N6LhrtR4zE8biLU/HvdrJJdKSldAtq670O5isPtYRUefHgaRlPUFfHTlsSNVOPjZvpP4rEPpxt6hUqSUpZuOwBlpxR8nJODzfSe86gOI4EK41YQHPtyL7Ud/83vPCimWTB/qXrCNBixad6hTewiJGftShj6toXj1UCcu7R/D67QsnjYEkSFmrM85yetIKA3uXMh0he7gfCICT18nw3gN8V0HhPpv+Ov3LvsmH4Od4T5GZ7uLQWSIGXNT4/FlzimvHVkpdUV/IdUvS0jGXMgpJ2UBj3xyQHI+5DZ8npTkQLjF1KGK6h6f4/rHYEPOSb84Gmp7NLFh4N7l06oHj+aORlcY3ACQ2CvM64KT/6ZxNAIF23Pk836jbSb8fUYyjEZDl7imUtA+1NyJcnRcNG8zLKEJVc5EXVbTRKU2AUDRQqAEmvvYnWORQlG5rhY1CzSV9a2qJW1La5qwcod3s78wSxBG94vCE+sO+rUuRQ4L0hO9arPSBvfCuOe/EUwv8zdSqUhChn67i0Fbu0vy2TUagNFx0TAHG72cllibBT8WV2LRulyvNBjaJrPdla5UX8Td8Z+c7MSC9ESqlKy5qfFeht7mg6U+aZbEeF66yX+/9/HPD3lS14lT49sHxISZI/sgvaMPyJa8MizZcNgrOOyIsGDGyN4+csJCmIMMaGmX96tmjemHZzfl8a77ZTVNmLfabXOxe+JIIeZkRIea8PwNw7zGIt/1+XzfCUwf4cSne+kkkpXA16NJqSpsVUMrMrbm46H0QarPS1NHoysNbj6jtyvmFDJwRzt2LkzzydWurG/F0k1HsHhaEh5OH4RV2UWa5VxyCbME46xEjwgxokJMcDFuhQ4xD5hvAHKlf4W0zcniKgcSUTKIyAtzUyImJztxd2o8dfG4P6hqaO12jbYA9/Mh5OR1lTF7oXG2uR0bD9EpsgWKxJ5hXv82Bxvx3MxkPNDxbPj7WYgKCcbc1ARPXZVQ1FMoGEKkkWnnbBcD7C2p8ko9zcwtxbw1/EX/fH09dM7RFeqLuLCNwPlpiViz51fR/P/oUBPmpyV6/v385jy8ub3I532lNU14cLX/AmOAO3//1rd/8KzNfKmoVfWteLejVuDcWPGVKRjVL9ojJ5yVVya6zspxMmzmIJiCjaKpz2Idzvmgqe+0dAQHCELB9tKaJt77pyVcu3dLXpmqHf1V2cXUcvBiaOpodIXBTYxGl4vx2WZm5xR2JYgy0bKsfN6HkzuJRFqDkZ7UE1lHftNMIcklV6iaA3siEoq0CQ1ArgMgNCDZ3UblwOBckSVtIRhtXwN/0t2KwdtdDJZsoCva70yn46GrBuLjH0/gdK1wUXU0ZadvHX6WbjqCa5KdXmNSjjiAM9KK5D4R+ObIGUXS4tWNbbjYEe4pwBdKVeFLzZg+womPfzohe4HnygqL7arKNZi6G3LmTn+JgHDhKoYtmZ4k6DgbADzPSsXZfPCU341UGsSMZfYz6XIB81b7rvWna70d5NFx0Vj706+yelQJUd/SDlCkewr1C+KDxqYtq232HKuzgu189WO0IjhiVDdqE/DU1NHobMOIGCCNre1eSk5s43dyshMPpw/yS8GvGlZlF1M/nDVNbfh83ylcN9yB/x4s08TwUttkhiAUadNiAKrtNnp3ajw255aJNjdipyw4IqyCxmQg6G7F4KSDqRQM3MptP5VU4qtc6S73ISYjGlvVN4qLCjXhhY4t8iHOCFG1oSYNvu98hajqFZc3YFnHPCt3DAkZAiSN6oNdxSipbMBF0aEY3Csc5fXNqKxvgT3MPW6r6psxb/V+VWOXGExLN/E7E3xRXTVRS66ssBRyDKbuBu3cGWMz49mZyQDg13TZGJsZo+OivV4TKxhmB+vaXQyeWp/rt3PTEvJMPrWev0aX64w8tT5XtZMhlbEgBI29SmvTkvd1RrBdKFiq1bloYddr6mgEyjAiEQhrcJCXYRLVUYDENUS5xm98bKhfz89mDpJdSKkkJeq/B8tgswSBYbwdBaHUIy0Ryp0kE8mT63LR2NIOR2SILOUnf5Ke5MCiaUnU0cmoUJPn93RWQVt3Qs6EZreZsf94jeT7okKCMXNUH1W1DVGhJsy9LAHz0wZ6JnIhI4HMQVo57ucbjggL7kxN8Fynix1hiuWJ+Z4HoV2Ep69Lwt0p/QG4DbPLX9yqeswKpaT4IwWCreEvd67s7ABfV4QmTdpuM2HXE1fB3NE89fU5ozB/zX6/NNetqG/BFS9v89ntp1EM21NUed7tjorVUhFnRIt0L7I2K0nIoLFXi8sbZB2rM8ZirwgLZo/t5+ndQp4frc5FC7teU0dDiXSbXMjwe+GGYd5Fc2EWPPJJDu9nuNvM/nKI5l05AJcNiMUjn+TIcjQswUY0y+zyS2BHA6JCTJibes4gInmQb35XgG+PaitVKZY7ycA9sS745AAA9yI6lVL5yR+wDXe+ok2hlK6aDoeVu63OrSmx+yFNpjs22pIzLivrW6h2P+amJmBsQoxiR2PmyN646ZKLPEWQbLhGgtgcxMWAc07JhcTssf180p0mJTmw8LMDHvUsWrjPg9A45QaSukJQQy6/v+Qiz3/LNRC6284nDTR9E56bOczjZADA1OG9kQGDIgOYuybwISQbKqUYJvd5UBIYU1ow3Nk4OlQlaQVfAN9Anlhq5DKJzBfusbQYi/ZQEyop7sWDvxsAS3AQ1uw57iUsQAIvWpwLt4mhUjTvo7F4WpJmhUnRHRFl9gDgqn+QAbqrsIK627K/isIH9QqH0WCgluAlKHUyuNQ0tmJZ1lFc7AjD5I785prGFs2dDLmU1TR1Wr2DlAa9WEoXcVCtwUZ89MdLUX622UclKzbMgu8LyrH8W/Xd6QnThju7ZYFnVX0z1YLtiLDgRDVd08P4WJuqAMi6nFNYl3NKsPaIbSRIzUFsGAAzR/VBZIgZa/Yc93KabGYj6lvOz9SrWp6d2S15ZbKdDO4CRzNOSSBJToOtrsKyb/Lx8U+/yjYQtDIELkSUNDOcOtyJBWfoU6uJUU+7C8LAV8GJDZ/RGxtmoTq23WbG32cM9ekTYbMESaYnVTe0elKx1RKoDIDF04bgztQE7CmqpHY0uPaAsATuECyV6AMHuH8n27ZQY1tGhZqwfHYKztQ1eYK0YvxcVottP//Gm755/4f78NBViaLp3wYAoRLPxvQRTk0CnprL23Jbvytl/pUDsWCSW1aLphGRnFw6fzWakdP12R9wF1x0/LcUBgChCtK95JwXQBf1kYKkzZHdBqnDSclSSkU/GZzr3cKWwyOqMI9+eoDagB3eNwIHT9RKvm9nQbmketeFRmZuKR6kbMz2+zEX4Z2ddKkr5XXN2HjwFGaNuQivZuUrHu80TYxo5yByDmRxdERYsCA90Uvh6KXMI12i+FMu63JOYtG0cwtvu4vB418ckn0cufnGJJCUsTUf/9lVLPv7ugJkZ2b5nBQqY8WA7rnzKQep1CQ+w15OarWjY7deTiBNSDhFyOi9eXRfquPedmk/TB3eG9d07OqR31RW24QFH+dIfn5HfgX1bxCDgdvpqapv8YvDQXYRSIqmHOOebQ+I7ZDSrkVsGW5AWRNDdpZOamJsR+8oaaR6u732TT6iQoJ507/Jd5qCjACE7b4NB0rx18lDupbqFKBdjlrqwFjPj6MpdKONApH3iRViLZ42BPln6mVFNRyRVlTVt2DppiNUn/EX7J0bdPw3zWdMwUYqxQbyWxmGwenaZlkTiRZOBuAekABUN+MB6J/Xez/4CS/fOAJTh59bFOT2Nvm1ki7fs7qbSdvSGqOh5iCYg4147Rv6DuHs8UjUypSmCEg1MaKdg3yVWJqxLCsfK25L8dzzJ6YmYUTfaB/NfC7+VswJMRnR7mKoZSYr672f3Yyt+bLOjU+THqAfpzS9CUjamothePuGdJaqGfnORV8ewh3j4/HaN8K/Reg66fgilJokZNjPGtOP6rjsiLqSHXt2yh8AQaP3X1vp5juyvnJ/L63hqqV0/vUje2NVdrFfxhJ3FwGAJ5AkxN2p8Z7+HkR+WmyHlJb4WJvPa2K2JV/tLDcYqmUJQnXH/MZdIxwdz7mUjauV2ITmjoYWeWGOCIvgdrBQPh2NV8vdZpaKdtAUMpJHffoIJ6+cW2chx+GbktyLSr2HQHpZKNkRUtKAh8AdkFJFdDTQPq/1ze14cPU+3HciAX+dPESRglZVA32fku5U4Lm7sILKGG1oaVdVZE12wRakD0J8bKgiVaSqhlbMX70Xfxif4PO8jU2wwxFhlZ26IyRVOnW4E9ckO5CxNZ93ESXfPPeyBNmpHnw4I634/SUXoc3FAGAwvn8sxiTYMfa5LLTIcBbIs9vuYrBKhgH28FWJ+NNV/JrtWtUhkCM/31Hjl7E1H6uyi72MLEekFZOH9lLdHFEp1Q2teO2bfBgMvkWuoeYg3DPBXXdUfrbZq/hThx6xaPayrKOI6tg1F0o5YUfUR8dFK9qtZ4/7hpY21Uav0LulbCN/BCsiQ8zUUtRyYcvb8zmLfO8fk2D3Mpa1quMSmpfEbEtSOytkt2jdNJgv/Xtsgh0bD56i+nyXU50C3A+12uLYpjYXtuSV+URrxBRHJic7JbesGlvbfY4rVojFfViKy+s78qlZnS5l5PPJ4eqkXpibmoCq+mb8bWOe7LoPOQvzgB7hAKQdDba8JwBFE4kSJ2NCYix+N6gHbh8f71W8J1VER4PcnMo3txfBagr2e7Fpdyrw3HUsMDVEZGFf++Nx7FyYhiCjQZEq0le5p/FV7mmf1IcgowGzx0pHiYTOjR09YgdUxibE4PU54T4yq8TxnpTkwNofj4v+Bnb3YLFuvlyDdRelE8iGPLt7iiqpo6QL0gfhofREwb9rVVdn75AzJfdsfloiLomzdzyD7vlkXP8YZGyV3hlxH49/rdMiksunpNPQ0o7/7Crx2tXTu4QLwxeYBCBZ72Ng/Tdfygk7or63pErxbj0Z91owvn8s7+ti/cOUBCtoIHPspCQHXt1yFBnb6HehpahpaMUDH+7DvRMTeCWmhd7PTntVazzTKEMK2Sc0douWTYNJ+rfRYPBK/6a1MYrL61Wfg+aORpDRgL/PSJbMcYsW2brmezBoFUdW3JaCx784xLs4Vje04v4P9+ENGd1UuQ/F/LREn4nLHyong3qFeY69cMoQZOf/RlVQyR0AUpEMR6QVwZTRsOWzUzBuQAx2FVZ4fv93j12JH4sr8X1BOd77vliwzkNN1GRHfjl25Jfj7Z1FqhZUoUWHZguRzds7jyn6fhq6p7Rt4KKxXIOe3Zfhh6JKfJ1Hv7PH1zNGrXT2mbom0QLFaJuFNxI2fYRTtKZj+ginZ4eErZIFBiivFw5iyN2dMRrg6RdAu5hHhgRjftpA0fdoFeV7atoQ0Zz4z/edwOJpQ7Bmz3HJYzkjrXhyymDMX5vj8zfufKs2bY+NlHy7jhu++2u3mXFpQrRkvU9VQysWpCdi7Y+/ShaSd4Xd56hQE8ZJGK98629URwoeCVZoJZDDnmNTB8Zq6miQ81u5Q9rJIO/n7hirCeRJCcxohdZNg7nPKW3w5tWsfE/zUqVo7mgAbpm4+05UCy58BgDPXj8Mf9uYx+tosB+McIsJZ+qaBHcMuA9R2uBeMEA83/txkTxrKfi8UX9MNEXlDbj8xa0+Gv2A8GLFNwCkJP4WTxuCReuk8+OdkVbUNLbwnhMj4DByv0tt1ETNgirUJwOQv/hr0cWUj0BNYF2N8QNiNF2IaCBjlmbrXQitFzDAHT1alpXPG1CZt3o/VtyW4hWVAtwO9IYDpaLHZRf1CQkZ8BWnLt14WNb5uxh3hHf8gBjqa3FXav+APe+OyBAA4oEralGCSy7Cs1/9TPVekrb30FWJ+M/3xZrmwwul3nVnhO5vZX0LdZpwfKwNOxemSabndoXd5xdYXcS5iNUTEnltfwjkkDmWVk1QLnKOxw0wqdkhlRKYUQJfEFRpKq4Q3OdUbKeLjRZzi1H6Lcp4YmoSXp+TAjtHhcoZacWK21IQbTOLXkDyYNz6zg9Y8MkBqgYwGVsLMO75byS16asbWpFBWWBFgz8mmk2HfJvt1XQ0I1yQnoi7UuN9rq2j49pyGwKtuC0Fjkgr73sjQ8yegiExUvpFYd7q/T7nVN3QKupksL9rftpAOCOVXysyITzz3zy0d8wy7S4GuworsD7nJHYVVnheZ0MmWr5zVxphjAoxqYrDL0gf5HMt+O5fd2Bc/xivvNtA0DPcKvhcyIErvlBV36L4uTAagNU/lIjmarOffQLNjir7HIV+N3HkM3NLPe9RkgJLDAyymItdj6hQk+RuBkDfLVuMqFATxibYNSsEbXMx1M8OOe4nP/2K52YO86TnaAX3OezOiN1fOfQMt3oc82uH9wYAbDx4ymedqRKxTbQiKtSE1+eMgiPCW+rWHmrCXanxiAwx+6yJ6/afxMrtx7Dws4OC14IYke0uRtBWUAqZY+et9k8TRCWQuYkY2YC8cbggfRB2LkzTdI3OzC3F5S9uxeyVu/HQ2hzMXrkbl7+4FS9lHkFTm/qgpgHCMtiTk514OH2Q6Oe1mFv8sqNB4G7VsyMC63Pk6arTICdavur7Iq9Ov2rwV18OLudyzH/FzoVpeFKgyzUXscKkf/yPLiL37S++es1ShJqDsPIPl3jphRMPWul1Yj/0NY0tvrsUISbMTY3H/LRESXUJNcxNjccyBXKpJDXqgd8NwCVx0T654d0xGhlkNOCFG4aJpsWIFWfKgVz/kRdFIfXFbzR7LrILyrElr0xW4yguLgY4XScdUOGqgNDuqJbVNCK7oByPf35IdHd4yYbDAAyKrw0JvNBEScUisWy0SE+de5m7eHdXYYVGqa7yS3VLa5oQbfNfoWxXSOPpbNQ+K9z0VbHa0ElJDizdpMwBlrN2zL0swUu6NiuvDOtyTqKyvhXvZhfj3exiQVUjMfhSSb2akNoseOTTA4K9GIR+lyPS3W/qipe3dRmBHMA7KCykDiWEAcCaPSW4JD7aq6hazZottNtUWtNELW9uAGAxGdHUKtx7SSxLgjbdV83c4ldHAxAufOns7UYtJUT91ZeDD+7EwHf+Qspc/L+VbpAo6bHR0NIOMPDpFLzithQsWndIlWDAG98V4DueRoTVja14NSsfq74vxgs3DENkiFnzxdwZacX8tERc7AgXlLB7q2OS4EtXmz7CiSte3uaTG96dCzonJzvxxm0pWLIhz2unkyzoACS3eAnRHR23hdIFp49wIvXFrZp2cw9k6hd3wqedS5duOiK6Mwx4942RC199kZjUo5znXa0Bzd450cIYNxqg2MA4U9eEGSP7YFKSA7uPVWDeR/s0S6Xq7HW1K6Dm/nLTV6VqQx9OT1S8vkSGmvCHcXH4YHeJaBZGqDkIl8RHe3or1TS24N3sYlXGKZevct2pl3y2wpLp9LYN+/rtLanyq2iKoeOEaOwtodrHyclOuFxMh4y4+Bgkc+Otb//geU2NEINWQVAGEHUy/jjBveO1Puckr3MktzWEEvzuaAgRqF0AMeROSEIGPCDfO1aL0LlLKXNxuTTBjoxtfjtN7DpWjtREbzWMyclONLa6qJoICcHnZLCp7hAUmJsar/g7+GA3yZKSR165o8hLOcZgAK4a0pNXKUMv6JSWm/73rFH409r9ovOF3WbC7ifSsfXn07wdgYkT2JWibHLhTvi0c6mUk6EGsfoiqfvKhW+eVWtAs3dOtDDGXQzw2jcFinbaztQ2eYzG1IGxeOHGYR4nWulz2T1FJPhRc3/Z+fc03ejlyDdzqW5opeqR0dDSjlvf/gFRISbceVk81v54XPP56/1dJXh/V4mPrdDuYhAZYsZdqfGeHRRCdKgJDODTn4F83h9ZK2zI2irlAInNTSS1S+n1VLNu+0NEiI93dhZj5Y5iz7+595hG/ljt3BJwR4O9iKjt1qsWqQmJfa7F5Q0d0rbCBjyNHK4/z51WmYuN0eDvVB3+4zsi/B95YwCsz6HTiqaBK+8L8O/YZeaW8hqzLgbYkndG8Fz1gk54euKQMbSnqBJjE+zYkleG//vvYcl5orK+FXtLqniN2664lU8gk7lYI0yhCT/IaMDiaUOoi5j9gVSBJK0UtVCg5MkpgxUVlBoNQMbsUV7nRbuwLpo6BA+tFc4vN3D+m/bUnt38M5Z9k4+XbxyOqcN7e4JUSzYc9loraI/ZXUUkhFASxLRZgnDvhP6elFuArhu9lkX9UlQ3tmKZSBNHLeA2EeRT7bp+ZG9M6pDDBiAYQAjE7lqYJRhhlmAvu4w7TwjNTVrsKKhZtwOV5sidv8pqmnD/h/uwID0R8bE29Ay3iq4fDNTPLQF1NLRU/lEDjYdGo0ZTyrphZIIiCypxUvrZQ1F+thkZ2wpRQzEp0XjnfOdOU+D4zH/zkDa4F/aWVHkmBtqH3WYOUpQ+RYwLbpRydFy0Zt0vxaiob4HdZkJVvfr8/uqGVriEdygBqJu8hHLwuxNCc4Sc+YFd8MftkBuICJJSZo3ph9rGFl5JQ6moHLsDOhslPY2iQ00wBxlxpk7Y4ekVYcErt4zULFcZEA+U8EnI0pAxOwVTh3sbGFKprgzgkRIWc2xINHdB+iDJPiZc3A1A9+O+E9V4YmpSx6ve1492DvGHCs75jBIp5IbmdizrkPEkAQqSTiRFVIgJNY3q15euADGcH//iEO9OXWW9O20rMsQskZIdmKyVs81tMAXBy2geHRftZeMIzU1a7SgoXbeLyxtUf7cSyL1gN4H1txhLwBwNoUWE2603NsyCRz7JEYzqqYUm+iMmB8fHq1n5WLPnVyyZ7p7sxRwqKUfCQZHjz3futMoz457P8jI8uMpVQihxMqJDTRgTb8drWflYlV3kFf0htQxKc0rlMHNkH7ybXazJztn8NfuQgVGYOrw3b4qHFpNXdy3oFBp3coMQ5XXNntQUNl35uoaYg7zELLhRuajQYNwxPh7NbS7sKqzwLKZZeWWiWuszRvaRnd5R1dDqlq2GcMOyJdOHInUgf4MwJbS7GCzZwL9jpWTMOjkpMNxxKpXqunTTEUxJdlB9V3xsqJcManF5A1b/UILTddI72W9uL0KbC3hnp/x5cO5l8bh6KH+jRR15AQq2gc2tE5NibmoClmnY7K6z4aZD8fFq1lGs2VOCJdOHCo6xQNWuVjW0YVlWPlbcluIx9GkMfq3XAznHa3cxVL16AoXY/dYi0yIgjgZNriO7W++S6UOpCz/lIhX9URqRLqttEu1WSRwqbtMcZ6QVs8b0Q3xsqNcAHdUvmjfHXOjcaSdGbnTTn9J8zW0ujPzb1+6icA6lNU14a3sRrhrcA9/8/JvfzgFwN74Zk2DXpH7GxcATieSqezgjrdTGiRjdsaBTS3WwpZuOYPm3BT4dr7vydeWOEW4kvaqhDctY3aBp04iUpg4KzVc00XOxWjYh/vVNviYppvOvHIjUgbGe75SqWXO5gAdX+641ZTVN1ApibBlUAsMw1GkuSpwMANhw4BSeulZPl+IiN1BIOGdg0zknJLtgftpAXOwIUy1wcr5RVtvssXn41kIyxvgcen/01aA1hsn8lH/6rKbfHxtmkX5TB3uKKjXpj+GIsKCuuc1vvb0AbTItAuJo0OQ6ciXWVtyWgsc/P6R5DuRLNwzHhIt7KD5XKYS6VRKHyhpsxJNTh+DXqgbE2UNx+/h4mIN925nILaCsPKtskfbndi+fg8H97h/8rPtO9KODjAa3ykthBeatVq/ywrcTI8c44aM7F3RqXRhXWd+Kd7KL8U6H7CORolS7lf+H8XGIs4cKpirxER1qAsNom89Nu0hX1rfAZglCQ3O7rN9M5qsQUxCW352C8nr+FCmuU1FV34ylm47IUph6fnOe6p1NMnYWTBrkOT+pmrXlc0YJ3kfy+w0iBpHQeM3MLfV7Lj3gTgvtzmmWfPhLzpwLN7tAC4GT8xEGwmshuy6U2DJEAlxrJ4PWGFbToJXqJCih3f2IDAn26lPWK9yMOZfGIT7W5qkb9qeTwaZLy9sC9CfIft/kZCfCLSbc+s4PIp+Qz5/W7scLNw4TXPTUXEwG8FIZ4vt7WW0znt18bnFb/m2hV3EVexGnLaAE6FOgxI8hP59bLWeb2xFmCUZ9c5vmiwNbIQpwX8/URG1UXvigMU7Y50abFtcd8GdaE3vRU5uuNyXZibEJdvx7W4FkesHcy+Jw9VD3+3cXVmg+l9FCFiK56Qtk8TYaDT7dyAH3os0tYOZDTIxi88FS2feDZuzQ7KJLSVqy53Pa8apFY0E5dOV0wM4gUEo+fDt7gRA4ocEfuwVy4SuSHh0XjXk8u4daIjYelO500fLNz6d9FDaFoN1d54r1GAxGXOwIBwAsyzoq+lu0fg7UZAT4rTM4G6U6veMGxKjqJM1HdWOrp/stzTn4G1JcRbpBCp2XFI7IENXnsvjaoVhzzzi8Nmsk5l8p3a1XK1wdq7mW5rXNEiQoOad1B1Q2DM4Nbu7vMXT8776JCYKd2rtrQac/xx2Zax//4pCn9kkJpLP0lrwySSfjvokJeHp6MsYPcDdhLK/XXnlODtGhJvTidBWOCqErAORbvDNzS3H/h/uo0p3YYhTsjsrtHfr1tDgjrXh9ju+45Rs7NLvotEGVu1PjqcdroAxdQldOB+wM/O14TUiMxeJpQ/DdY1f63HtS/KxmHVO7BhoA3H15vMqjuOc6tefC3mXIzC3tqA/1bxd1ofEQiJ2ud7OLqe032meF21/ldEeK/uNf8DddJcTYzPjX70d5bA41GCDcWZyWgOxoKNXpVaIeQYtQPl9n9vcoVaHJPDouWvWOhCPC6tlB2VVYEbAmZA0t7YqUW/gwALh2uAPLZqWI7gzIadSjhLtT47E5t0ywxuavk4fIzmO/kPH3uKMpcJRi7mUJACAZsY4KNeGvk4d4vdbZBmFVQys++uOlMBoMnmfOxTBezaeE4J57u4vB418ckvX9fKkNe4oqZRkeZOxckyydUqqlwZme5MCiaUlU4zWQOwzcxV9JbcyFhr/H2Y78cuzIL8fbO4t8djS0KH4mawTgDozImbOckW6ZUjlpnWJoNQ9ndaRL+dueEjOGaQMA14/sDYMBWLdfWW0bbZ2IUtuWXEOp56KivgUx4RbNerudF/K2YgNQKmVkcrITr88ZhflrhPXM5SKWz8c+185C7GHlW0y25JXhmf/mKTaY+Ry9sQl2OCIsfukBwgdbuSW74DdkbCuUfYzbx/XD4muH8ta8+OaSt6hq1COFlHEiJy2uOxAohRKlkM7SNAtWdUMrXt1y1KsouSs0KC0/2+yVAtXuYhQFgHYXVih22tiGuByjfEF6oseooxk7Whmc7Bovvu9sdzHYXViBXcfKARhQWtOoyfdKwU0Llduo9UJlbIJdUm3KZglCuCVY1domlA6opvg5OtSExdOGeI43KcmBhZ8dwGf76Brf/f6Si5BXWqfJjlqNhu0G1uWcDMicx02dZK+9ZZTj8kuVfbfkFE1PSnLIlm6Xw5m6JswY2QeTkhxYsiEXH+yWr3Ll7kOkPtMiYPK2QgOQRsVk6vDeyICBVx1EDUILHTnXp9fn4nSdf7f6uIg5QUp7DBApWTmSuVvyytDUJtE0QkPYyi1jE+z4fN9JaqOMGERLpifzOmd8181o8J8xazS41by4PVU2Hjzl43DoUchzeEQgZEbyAsFz17ufLVrjOGNbATK2FXgZe53tSBHjm69pKhexAJDbqFZ3DgC9SovdZsL8tERZ30Ozi05TS7V4mrgMemc8q1wHQkmj1u6MKciI7X9N8/RaKK9rlr0LwFeDQOAKudAev6qhFfNW78eKjuLyIKMBkZTpjQA0FSDQYn4ywF07WuHndCluI12+9V6LGlZaxNYI9txbXtfs17mDzLVBRgMMChszuxggWoNrF9CGfXKVlNhMHe7EG0bhbaCoEBNaXS5ZFfhiUa/JyU6EW01UqQX+gPuwKu0xEGMz47vHroQ52Egtmevvoik2fFFTOduK5MmZNaYfryEv9Fv8WSznYoB5q/dhhTGFNz3Lydoe16OQ3kxKcuDp9Yc7+zR8iLa5jWK5kXJi7D3c0Sfo4fRErNlz3CuaGh1qQku7vLlLLnabCWW1TXgt66jP9xsMviIWUaEmPH+DkGiG/EWLd3eEcgzePi5etvMttYsuJdxBEFpkSY2KGsxBBrS0S59EVIgJc1MTfCTQAbqid7Ua+OcTe4oqJdfE6oZW7C2p8mom+/bOItm7jVKZEeS19Tl0OxIEcr8A927A+QoD4LoRTrz3fYlfjm+zBOGPl/fHn69KlFzv/Snjz6W8rhnrc07y2iJye7QogW+ujbOHKj6eFumgAXU0AHjSCIizsaeoktrZYDsqZbVNyM7/DVuOnEFNY6ts6Ui7zSRZ3FKuUDJWC9gGjZpCpor6Fs+kSuPoBUoekA1f1JR2W5E0FmM3O2PLmWr9W3qFm/HMjGS4XIxkOt8jnx7gNR5JR3k+unsUMmNrAVWjMyVEhZp4u93SkJVX5tltk5MCRd7Dfj4dEVZPg1IyBtfvP4m/fHpAwZm5iQ41+RQOsqmsbxWU3uQzuMWONX5AjKz6LaHdEdoC+f49bNTfxUZsF31KsoNKippvkSXNBdVC42QAwPI5KYJqNnKl4y90lChcqk3blPpOOR2g2fcLoBcs6KpsOKBM3EYIdlCkvrkdn/z0K4Y4wz1NA8Wc7kBgNMBr94odVNSq1tgA91pW1dBKXYpw+/h4PLv5iKIAqxZpqAF3NNTmkpJIQWZuKT7fpzz3b+bIPpLOTWcUcPJ5o2qVTLiTqtiCE0jVFLvNhOdm8kdNaSJTAL9BxI4ia/1b/vn7UUgdGItdhRWig5YBFEWou2MUkpCZW+plkGsFe7JXaky8k12MMR0dpdWmQJ2ubcKyrKNYcVsKxibYkbE1H29tP6bgSG7sNhP+dl0y5q/dr/gYfAg9g+P6x8jKLRZKj1WqRigHoeBKxlY6R4nvu92BLm2c4VBzkGC/IbIWjBOZr5UY1hcytM9KeV0z2l2M59mW6hRP+518tYBKuoZfKPdL650EblCEHZiLDDFT3bvo0GBUNbRJvk8JXJuAnF+IOUiT45OZ+PkbhgHwzYgQmmvNwUbcMyFBlpS4ln29/OZokAFXVtuEyrPNsNvMOF7ZwJsPLDeKq0XUPT3Jt4Mzd5IYHRcNR4RV1VZXkAGgDFwJeqNqJx05C3UgJ7jF1w71Wz8TA4BV36trAsYH2eXy53XqblFIwH/9Bx6+aiD+dNW5Jm4rbkvBonW5imQWieGtxigBzj2fT3xxCAs/P+jVkEkJlfWteOJLeSpQNIilhbxwwzDRCB13x4bPYabZHYoKMcHFMF5GIRepOiducCUzt1TS+BNbZLUc+8TJUNpXJxDO2vkE7Y7j0k1HvJSj2l0MIkPM+OvkwR57JTbMgjtW7RENKBkNbsVHQNtawOLyemgr+N45+HsngR2Y++s1F1N9xsUYcFNKX3y274Rm5yFU7E9ekmpeLAQ3EMF1JOSUIjwx1R1sW7mjiGpng4F2fb384mjI7b4oN4qrJuoutIAIFVq3qCyIpnUyAPWRPy5KPNJALkhiDY7UnocWcqZ89Ay3ot3FoNxP6T1sLpSoFg3+2km7tH+sT6FmY0s7FnwiP02JbXizI+VKVNIYiKcnyaWuyT8Rui0dKWNcJic78cZtKT45x+y0RbH0WOIckBQmod2h6sZW3Pr2D4K73nJ3yGmDVGKLrJZzJEmDsAQbvXZJekVYMHtsPzS3ubCrsEKxs6ZlVPJ8QE4aFAlw3jsxARsOlPo8Q7PG9JM0yFwMsLekCjWNLZrWAvIFZDuLrqgCyIYE5miDRzWNrfhs3wlVqbSEP4yPQ5w9VDNJYS4R1mCs/MMlKD/bTBVEkWJUv2j0CDsZcJEjzR0NpYXE5GHZXVgh2V1RqQEmFCVSUmgdHWpC6sBYbDyoPgdxSnIv/GF8gqrInxByPVKtZDiNHbmUShe/riAHysUZaUVVfTMuf3FrQNLLuksUEvCfU5VdUO4zrtQ0t+RLQxybYMeHPxzvckpZWrA+5xSeFFBeEkpL2pJX5jNG2MY/byBKwprh2/VWorZE69ASOV2+3RItpb+Jw8nucVJc3oA1e457GZuOCCuWTPd1ntRIx1+o0O44kmvFl05SVtNEncZZVtOIl/73S5dZp7QgzBKMeyb0R2LPMCzd5OvIL56WhGibGWfqmpB/+mzAem6JYQ+zUNsMBs5/K713U5Kdfg0IltU2w2gweMmSA8K7uFy57fEDYjCuv7tprFzbXMsUbk0djZY2FxatE+9YKMW81fvwwo38efvk4uafrqM6FreBHd+OgdI0LEuwEVcN6aWJozE52SnqlSotVvvjhHjB1CShB5VGrUUsP5s8jvdMSMBb24sUL35dsa/C6Lhov/beYKO2E+f5hr+cqoxtBfh83wmvcU+cWCXOIt950nQKV0OkNRi1TW2dMgYq6ltEU/j40pLEjP97J7rnBe7fSe61JdiIZp5dZO6uNzr+W67aEq1RUNPYKrpb8n/XDpWUW7dZgnBJv2h8ly8tB0x6nAjVKZXVugUk3uBxntRIx1+oECf4vewiRdFmOWOtsr4loN3gA8HZ5ja8mnUUUSEm3HlZHMbEx6C8nj+qHsjmvmI4IqzUPdBIxsPDVyXi459+9Rnji6YOwdMbDgvukrCDpaRw31/wKZDyzUvTRzjx8U8nvNaijG0FiAo14bnrh2HpJnl2rpYp3Jo5Gpm5pR25z+oW3OrGVt5olJx0LPIQbH3kd1j9QwlKKhsQZw/F7ePjfZq5KU3ZKKttRqVGqlRCcmhslOSFv7OzGKMusmPqcHnpBlILF4libskrw5c5p7wGI3tx45PTtdvMWDojmWrxU5sLrzU788sDZux1tyikP3ewuBFuJV1ZhXbh/FVbwiZ1YAw2557263eIQWuc00itrtzh62Sw4XMy2MdgK/IoUVuidWjfzS7mVaViC01IUd/cjomDelA5GiQlU6rj+hNfHOKNMKqRjr9QCTIaEBtO16tFCWROiAoNXI+GQFPd2Ipl3xQgKrQEL9wwjNfg1HLuNgAIERFIEPoMmZuDjAZ3L6bPD1Epkb73fTGem5mMaJvFZ9yYggwep0UsWEqTvggeCXFa2HOWUCCntKZJsNC7uqFVVQ+6LiNv64++C+xolJzjk4dg+ggn0l751msxWrnjGGaP7Yf4WJvngcrKK1N8jnabWXVnRyE5NGKIc3cevnvsSuwtqUJ2QblkFMHFAA+u3oc3jPLTDaQWrvEDYjB+QAyeFOl+PTnZ6dNHoqK+BUs35cFohKSzwS7QK69rRsbWfNT4KRedBrkSykpwd+Ic1e2ikOwdLK1Rq+QltgsXCJU24mTQdBf2B7TGOY3UqtLFlo2chY/7XjW7WYB8oQm7zUxdQ7H7mHTH9aqGVuw+VoHUgb7pxXLztbsDWu2UCu3MTx/hxLOb/ZOf35WobuAPAAPaZR+Quhg5yoN8c7OcHmjVjR1NEm9L8UlPot0pDDIasHhaEq8xT87vXpmKT+Sz7OBWZ7QeALqIvK0/fjw7GjU2wS7r+FGhJtxySV/e7fmy2mafvNe6JuXGoxY3QEgObcVtKQCEG7ol9gqj/o4n1+UibXAvBBkNstINaBYusfdk5pbyphrRqIzJFRTwJwYAkSEmTRyNMEswzja3CU7IGbNTfHaguguTk524d6L8CZkGvjmFFrEUlLKaRg3PUpzOcDJoVJ8IgRIvkDPvct+rZDeLixyhCUdkiGQNBWk2uu3nM1TH3FXI72jo+KJFtH1BeiLW/virj7E5fYST1864UGHgtg/CLSafNCq12QeLpw3BnakJ2HjwlKzPCc3N4/rHyLrvQkEobsA1NswCMO4eQNn55YAB2HrktGBjRW6Gx5INh71qu6JCglHd6GsP8DlQgWw9QHBEWLqGvK0/f/yb3xUg71QPWcevbmjF2h9/pXq41MjWRoWaAIP2ykbkvJ/44pBEj4hE6mNW1Ldg3PNZuGN8QsCaO6npWBvIzuS0zE2NV6UEcndqPNKTHJ5iWb0juC/tLkbzBk9cvsotRd6pGqo5Zf6VA5A6sIdoCooSmdzzCSnVJzb+Fi/gRvikdgrsNjPKahp9VJsmJztxd2o83qFo2CdGVIgJNY38qjV86Rx8qoYMoKB3TFeaGbs2QUYDpo9wKgpekHv4wO8G4pI4u1eB7Zh4O654eVu3uxOlNU249Z1zOwXclOu0wb0w7vksWSn0RoO7oVyQ0SB7Dlk8bQjvnCRnh1zK7mH3bnv00wOy7FH2+YmJZ9DUV3WGCmVTmwtb8spU2yWqHQ1//vhvj5bj26PS+a1sGEC1Lj0N1Q2t2HrEf3nTQtKXxEhfs+e4rB4flfWt1AtadsFvqvN7lXasVbtDZreZUVXfotkCEBViwgs3DsOkJAfW/vir7MgYn4Gm51PzE4iIzfu7Sqjfm9grXNLhtof5Lwe8K0G62S9IH4T5aQM9zyo7tTM2zAJHhAWna5uFc5WhzEzmi/CJpWswcAdYiIwxdxymJzlUOxpzU+OxLCufKhrJHfPF5fWKAxfj++u7GbRk5pbiLYVOBuBOjbri5W1e89KHu0uQPqRnl9ht72y42Ql7S6pk1+kSiWCi4CdnJ+Kp9blIT3L41N4C51KfaOs1hKS8AWXBTwPcafHXdNQFAvwZIJOSHAi3mHiVoth0hgpljUjKnBx8745MlPz4C8WcEtou8zcM3Glgs8f288vxM7YV4vIXtyIzV3l0WWnHWqXGpgFuY+LvM5I9/+b+XQnLb/UuIJZ7rEVTz0U02l0MdhVWYH3OSU8Kz4yRfTB+gO+k0h3pan1DaOa24xUNATgTZTgjrVggY+eThlezjiL1hW+QmVuKzNxSXP7iVsxeuRsPrc3BrW//gKY2lycYwob8+48T4iW/IyrU5NNjJ9pmwl2p8YgMMaO9I4eMGBKOSOn7RAyizQdPYVdhBcpqGmG3mRXPC1GhJlwSZ8fyOaN8vt8RaRXMZR+bYEdsmAWrFDo5UaEm0U7hOudQE7RyRFo9Cmnc9ai6sRWf7euctb+rQa7tkg2HkV1Qjq8U2gxk7mevszRU1rdi3PPfCNoqk5OdWD4nhepY72YX47Wso1ifcxK7Cis884zS54grXsEHmUNvfecHZGwrRMa2Ajz66QFs4akdJk5YIC0F8puf+W+e53ooQfWOhpLiugtlu1GtwpZafi6r8dux5XZr56K0Y60SY5MdQZyc7MQKo2+ags0ShLPN8rpzOiOtGNf/3KKuJA/1obX7EWQAjB31MXq6lDBdqW+I3WZCWW2TaLO0dheDNXuOd8LZCRNhDcbT1yahd3SoJ8VIyU6cGGW1zYI1DjUdO7GRHJEMdiqA0WAQTGUxAHjhhmG8ynbvZBfjnexin3QN8t6y2iYs3XiYd14mv33+mv2a1LpUN7Ti1nd+8OkpILY7mZlb6tPgUC4v3DBMD0pQojRotXjaENw+Pj4gqVFdRbpdDSTwSVN8LQR77pe7E1FZ3yIo/QwA4wbEUNuo7F1GMs9EhphV7V4J2TQ0wjzczIfF04Zg3ur9is9FCVqk1Kt2NNwV90PwYIB/vA7wlR8lL9Uq9VTVt4iq5AjJhSoxNntFWLBk+lCfXMiMrflYlV2M6sZW2U4GwK8yJLcjtFv5i39sqHXmLjTGJthVq7hpRWV9KxZ8nANA2CEkxq2WEF13uY4BeUpfumm4z3n6S82LDzJvhJiCsPzuFF7t/b9OHoIQUzBW7jyGeta45F7nmsYWrMoulhSTIOkIuworJIM/WhfUl9U0Yd7qfbyqNWwyc0tVFaA7OHOcjjRKd0hjwy3YW1Ll19QoZ6QV1w534O2dxQHxNNy9FJKRV1oruWYFGrvNhNFx0V6vyVGOIrCln7lqnUpsVDLPzE2Nl/U5Lnw2DU0N6+NfHOpoGXGuDjAq1CRb/lcr1GQcaCJvG23rHnnK3Q0lnmy7i0HG1gKqehC2IU8mhrKaRoRbg1EnS8bW1wnakleGZVn5iufwjFnCErPEsFGb6kPO7fHPDyHcauLNy9TxJjIkGK/fOhr/O1wmq95CDUIOoT9SvRJ62BQ5BmLKWIHuR0PmDaPRt6Mtn5pcVIgJc1MTfGo/xBZiwDcI0hmpdzQBGZr+GHzcPq4fLom36zVcClG6QxprsyC7QF5tqFyuHe7E2xI9ZYRwRFjQ1OZCTQO/EAEfIaYgXJPsRLTN0uUcjcr6Vlzx8jafncEx8fLqNYj0c11TK2/2wFWDe+Cbn3+jPi8yttfnyFPCYhMVYvKSpyXOT3lds2QNK1/ArTODcGoyDjRxNORO8Gr04BdPG4L/HjiFnBP+SxuiJcRkRGOrcIOpCwXa++tODfCWb+OD2ytCrZQt6ZpLlJ1Gx0WrllyOoWj0pFWqjxxlnwuZPUWVkhNpTWMbjAYDpiQ7NXM0Fk8b4m4kuekIr4oUeY4e/fQADp6oQerAWIzrH4Pi8npNvp9NeV0zYsMtuDGlLz7bd0Ly/fOvHIjUgbGShih7J46v0SZBy14dXFEJoVSBmsZWLMs6iosdYZ5nnybthRsEKS7vnHoZqYAMTX8MPlLi7KK7JDriKJG2NRiAv3ySg9N12jTjFeLzfSdl71jeeVkcrh7q9CgVyelbwZb29ldjVDWU1jT59KEg3a7lFPN/uLsEmbllvLugSuwLIipht5lQVU/v2BHmpsZ7esF1Fbl+JdhtJlUyt6qLwQH5BpfVFKToe+w2E24fH4+SSu0XFCWxohdnDoNUkMloADJmjYSTomCxq0Jzf4kRIeVkAG5DhuyCkc9pMQDfyS7G7JW7Me75LNXHo3GuyKStFSRyrqYI/3xGjoCAVGGcAe7InyNC/D3OSCvuTE2AIzJEUqr2bHM7Xv+2ELe+/QNSln6Nd7O17fdBmnc+tDaHyskAgMReYdRiAmQn7v+uG4ofn0zHmnvG4dXfj8TiaUPw6i0jsOaecciYTVc4SQNbVIJ2h4IUHNI+C6RosivUywid867CCkXH4xbE68hDiYAHw8DvTgYgXxabAfDe9yWoaWzx6ltBI4RAKKttUixq0hmU1jThre1FuHdiAmxmOptxR/5voulISjcFZ3Y4/HI+Hmo2Yn5aoqY2Tmcxc2QfVTuqmjgatNXwUSHuDRSl+WUzR/bB3pIqQelXpZDzvodCEYVw38QETE/pi3smJIi+754JCbh2ZB/sXJjmXthvGaFK7STQGA1AVb34xKtEleFMXZPfOl1qUaRP41zJVciQQiuFh/MVOQICYgsm+feS6UOxZHqSqNQqSd+Tuytb09imuYy2kluudFeNOB0zR/XB3RP6Y2ZKX4wfEIOpw51YkD5I0TH5IM5zxtZ8arlrgP53rc85dS7tUuN6GbkIn7P8G+vkqV/TkY8Sg7wrw14bJic7sXNhGhZPG0L12b/99zBey8pHc5sLD6cnoleE9649sc+6EgyADQdK8TplAESsFpOB8t3a9CSH7OfIFGTslG7eRoPbltUyCJqe5FD1eU0cDRov+eGrEhXvZBDSkxx+ycMlcoRPThuK+yaKOw5hlmC8PicFT0x1/94npibhvokJPp6y0eB2Rsj7PAt7Sl88N5NfglVLDADCLOquN+AemPNW7xeNsitR9+gZbu2UTpdSkCg33yLPlqcl8neTk514fU6K4kgJFxpJvAsVml0K9r0RMiK48qJRoSafY0WGmrze05mKV4olVkOC/WKMzk8biEiNjA6ywNLKuWYXlGPdvhPIPVlDFcWsqG/x5D13JlGhwqkFcvpeGDr+xydEoaMMuQa5P3E3kvSdj2jgWxuCjAbcmZpAFeitanD30npobU6HupIBC9IH4bVZI7EgfRCsJnlj/sHf9RfdMdaK0pomBJuMvPM4m1DKXQ/a9xHImkOeozX3jMP8KwdKfq6msQ2LvjgYcBvHxQBpgx2yzlUMtWlTgEY1GoBwwSFbImzZN8oaFLEVitQaYORY/7hpBK8iyhNTkzCibzSeWs+p9g8xIX1IT6QOjEW0za3lzv7MI1cPxge7ilFS2YA4eyhuHx/P20QG8H9xpjPSillj+inoOCuMWLGjnEgi+15uPKi8yMof8DXaIvDlWJJne+pwJzIwilfVQql8YWcbTp0Bu5srTRM0QLz5oViTpRrOrmhn5i4r/b7qxjZNurayaXcx2F1YgdZ27a4CA1DJVAJAxrYC2ccn970zETO2xg2IoVZTEyvq15EPuwB3sCMCjggrTtdqM8aNBmDZzSOxZBO/pLIQf5+RjKWbjiiea0ivCjLPic2bYpyubcKyrKOefiFyz2VCYk8M7xulSk2NljO1TXjhhmGi33XfxP5UTTDlZtSw1xwSMC6raaT6bGf1WzlT1+Q517EJdny+74RiW/PvM5JVBz003SsTW/TXK2xuxzUw5PTtEDNWxg2I8ZwnKZIiF9NoBMxB3he2pqNJD3lwuIW75mAj7p7Qn/p3nZNgpVNoomVBeiLmpyVig4bNBKWKHSvPystpJfeys40DLkKLPI3e9dThvfEGT68MR4fO/qIvD8kqCO1q1yZQCDnhQveGK2NIxjHNljXbeVa6WHc2SuWn+fB3wWJUiAk1jfILKqUor2tGWzsDg8GdY98ZVDW0Cs6PQUaDpJFEhCzkqEsJPfs6bngVzkJNnnx9tY9KxuwURNvM1E6GAcBDVw3ENclOGI0GxXPN+7tK8P6uEp9+MituS/GRQxWDXIeVMtWv2MHCIKMBcy+Lw6rv/asAmF1QgX/cMgJv3JbiIzhDpJ8nJTk07RlkALB8Dr/6pNwaGykWTxuC2HALYsMs+MvH+3G6Tt3x2fYDWduUOIT3TUzA1OG9VZ0LoLGjAfC3WAfoFUHsNrPXTXR0ROeb21ye5llSF+2qwT0wvG801uw57hVtJ8YKAFz+4lZvQybCgtlj+6G2sRXv8GzzCxmZy+eMQrTNoniy16qAkT3pZOaWYummI9SfpY22cSMpBLvNTPc9ISa8cOMwz8CV6rURCP6cNhADeoYJ3jsavWti7Ak52jRqSgSh/iLdCaHrCLgLa8lrVfUtWLpJeAeVtiaAzFeBloHVArWNlAhiuz9aMTc1AcuyjmrqyJEC+q6A2C7k5GSnqJEkdwdDbIdV3w0RUTgTaCgpB3cOfAKmDnfKCqAyAJZ9U4CPfzqBp69LUj3XcGW3Jyc78cOxCllGPwN5zjnfznLf6FD6Ayjks30nkJ7UUzSYTc5Lq2DRHePjBI1se5h2LR2MBsAZGYKpw922W7PEbrLYbxOyH0iK9/w1+6jsrRibGUtnJGPqcG3mEk0dDbHoIo1BbQDwt+uGIibcbbgXl9djzZ7jXhF/Inkmxjc//4Zvfv4NjggLFqQnIj7Whp7hVoyOi8aKbwt4t9fKapuptt0IQp1myWQvNhgIGVvzNStgXDxtiMfJoDUYokJMWH5rCsAAt74j3RiHL5IC0Effl89JQWqiO185M7cU81b717Ch4cMfjuO5mcmChppUHQnXYOVztOWmQen52b4BC9pou9wmS9x7MznZibTBvfCf74vxzy2/nBfy1WrT7NQULJKFjWEYnK5tFiy8d0RaMT9tIC52hGnqyHUlzQSpeVDKSKJFaI4vrfGW+e6uOxw0wSFrsBEf/fFSRf14XAzw1vYijOoXrWjnme0g7FyYJtnVXghuoAsA1h/wbzoy386ylka3GEs2HPbs3gqt10LBIiWNYDccPIVxA2J4HXctFeHcdbD7cO8J8RS2MEsQXrpxOACDjxQwIJ76DUA0xZvgr7lDM0dDLMISGWKmMqgZAPPX7sfrc0bBEmzkbbhWVtOENyl1lYnz8PqcUahpbMHEl7ZprkzCXejKOiZ77oPNNc4zc0tlOTZiGOCO6qUnOagNBgOAF24chtSBsWh3MbLy09kTJQAs2ZAn+ZkYmxljWI1rpM7TaHDvNiz7Rn7Othwq61tEu3PTGnHZBb8JGg+0i1GMzYxnZybrEUkOcpxnuU2WuPemM/XOlUbh2L9BSTqNUlEG9sIGQLS2ZvG0JOwpqkRzmwv/uGkEYADO1DXjqXWHUN8JXW61RM4upJiRRAPN3PlOdjHeyS7utjscNMGhstpm/FxaiwirssJswG3gf/fYldSp3OzvZzsItF3thY7FLhDXQnGRj+tH9kbf6FCMHxCDcf29n9+eMh0NpSmOZbXNyNhagIfSE0Xfx+fQu1wMVTCVTWV9q6BtICeFHwDGJURjd1GV4N8ZSKewhVtNuCbZiSCjAW8Y6dOLgXPrQquLwYL0QT7ZPv6eKzRxNKRy2OW2cJ+/Zj8irMGimutymLd6f8Ai5+R7uN4z2zif1OEQaPmdpTVN+GBXMdWDH24Nwi2jL0JkyLmidjlbjmSifPyLQ9TdSSvqW3DFy9uo0loAtwM3Jj4GUaElopEImyUIwUaDaqlRvlz3dheDckpNdXa3Ve6gpSk0tttM2PXEVYICAt0VJdF2miZLBgC9IixwMQzW55zsSMVqDuhcQYgKNeG564f5pIFFdwQraLfJlabTKN0R4S5sQrU100c4eVPcZo256IJwMoDA7ULKcQqFOtpf6NA+z2pS7siau7ekyrN2yp2j2Dvhancl/SkeYjQAX3YEbjK2FfikadMEGtkwDHBTSl9kHTlNLRJBeJXT2FMIrkPf7mLgiLBQ9fniwmcbBBkNmD7CSRX0Nhgg6mQQpHZn2c+LnN1RvnWBne0Ta7MABqD8bLOnPEHruUy1o0GzTSm3hbuLcSuqaEVX2F1nRzHCrSa/RExpGxnWNbV7ol5RISbMTU3A/LSBWHFbCh7/gq5omYGvMyUFWfjuok1roSgyZxigVuWzQib997KLcGdqgupOnqWcBZ5GTem5mcN0J4MHNRLIM0f2wbvZxbzXnAHQ1ObCrW+fi3IZDeJzhSXYgOY27WeT6oZWGI3wpFGwF47/5ZbxbpMD7nMlBi6NYIHQ4iw3/eN3g2Jx3xUDfRYkvsVPyHkrq2nSbEdXCnK/F6Qnol+MTXaKCnHoFk8bgqWbjlBHEf2BHIOSGznvLmlUgRTSOFPXhBkj+8haO7mfB9Sfsz9/M1/WxgMf7lOsVgUAEwbF4sWbhnvmih1Hy6mblLKfZ9od3CCjAbPH9pM95wgJ4bS7GGw4QNdYV0uBCvb4p9kdFVoXTtc2Y1lWPu6dmIANB0r9Xuul2tGg2aasqG9BuDUYdU3aNrg63yAPrZxOsdcOd2LbL2dQL9KIhhBnl1+UVd3o1tZ+c3sh7pnQH9bgIAD+2X4lC986ygK6yrPNkhO30uaPfCzddARv7yzC9BFOxRMogYH3hChXTUnHzf8OK++Snp7kwJgEu881J4Wg3GdLKqLkDycD8E2jYDN1uBNvGPmNGKIrL0ewgG8RlpsGkNwnSvBv7MWv3cXg8he3arYzrZRomwkzR/bB2IQYuBhGtpMBwDNGr0l2Uhk2/lKEkmtQSikGXoj8f3vvHh5Vda+PvzPJzCQZkkkmUWYAIYEEJQx3RTBIS0wqgkK1tlXU03qhtpJ+NacXxUKljfVy2vMTW1CrCJ5TBbT1AgpymgBViSDKPQQLhAREMmAuJGFyJTO/PyZr2LNnX9bae+1JIPM+z3lO1cmePXuv9Vmf6/tGk6qavA8SZD+8dg827K+l/l7y91rvWVzV1Jq1l4IcUYtWtiohiOgqWZM3jx2EbUe/obp3sp6b2jqZKriZGXaNdxsZ4PeWBhjL/lc7FwBIVmSMqITqDjRoMyz9PcgQ4vDpFqrP3TzWTWW0iLG5Z2omVmyr1mRgWzu78bxGnRMWBBDsfXTarWj0dSoOj9KyWfEEywyQGqRYjXgMg/YXbNxfi/9hHNQkMJuAScPSYI03hz3zDLsNv/j7PmgNpo2gaFVzBv3+gGTA3dQa7CF+pGAkM8OWEKz0h8u2Ho1ooZBCXxHkbPB1hVVwWUASAYW5rjDGs5vHDpLdt0YyQrEGhQT9SZcnGlTVUnM5pZVepiBDKD6q5Z7FbXubKmrRfp4PeUXeiHSUKyREWdmqCOTmmeLMJiyZM5raBv3zoBevfVrDVMHVU/UR/60R+8ncM7si91jlhITloNX+GlEJ1d2r0V/5/vXgn5WnVT/jSIhH+dE6aqP1xC25sMabVRXa+wq+Oz5IGye+T6HxdDkSo3pPAP9DSWyQSBZn7vjBIZaqGCKxqaIWD63erbns7A8Au44H+2KFz9xsNukihLg3LwuAMftL6vDauL8WC2RYQgI9/7fqU7rA+MOK2pCivRiEflVNfVcIQnzxfNlhrNv7dcS1+6JzS9sTXjRjBNbMn4Jtj+YDAPKe2Yw7X9mBh9fuxZ2v7EDeM5uxqSKy2kZaFcQHPHGApP6GBcQhZUV/O6dJBdnlMO53L549CjurG7Bu79coP1qHJesPMp0fc8a5I1oPpe7Z7UjAg9OD6t9CuBwJIYearDutlL1iKAUZWqE2zzTT48btE4dQXesfu08qZup/935lhJ0jQTqL7TbhgoPf7Q+g/Egd/vR/X2LroTMMV6HD/OuVz5a2rm6UVnqpr6fH/opJBvRCd0WjNxR1TYBkbxnv7wgAuPe6YVi3r1Y2+24UmhgqQD+ZnhWK3md63PjJ9KxgWdPgG05NslAPg4tR2EOhptRKxMqG1RchdcCL2yomDUvDruONsSpHD0jJVy+kDK1W46tG0epKsaH9vF/zfgCkGbDk5jOEoHUu5OipCYQioqvKq1WdcvI7hX3PwmtfjM4tec/FhVeGssRSWVZvcwd++vpuvCTInOptYaNF0CEbTK06nG639ktdHnEFua6lg4vmitNuwfcnDYmY12HF+n21+PXMUapzTuQ8+PXMUZrFSXtbrwqgaxPOy06nmtVQ6pCRq+BqqRoFEGTMK630aprBoYHZBCy7c0JIs+PlT6olb45UsGlbmnjY37JKL5eWS92Bhh7VQa24b1omFs7KDdt4x77x4S9bjnDbTMJNce3wdOrFabfFwdfRHVV1YaHB2lRRq3u+gAYPTs/ChKFpzOVpsaqoUiuR2hB1APqCHaNBDnhhYEG0YYS9qOJDoL/SUhLwarmRMrRajK84EyflDEwalob/fGsvPtivLWNNWr0Iuv0BLFl/kPrvHYnxaG47z0xPLV5jcWYTHi7IQVF+NnZWN6D86DdhjGos1y7MdTElCpx2CxbNysWTGyuZaTonZ6ZhZ406s4sSxO+52x/AY+8cUPybx945EAocWDV39CAvO4M60Jg7Xr7N61KHeGZIa2sxQbrdit/dMho/X6ufnU5uLcgN+cr9exp76Q8EKzBOuxUlGw5xSZzSnvv35WWGEotq65BnF4NUUkluVjKtRzFeKpB4/D1jAgyCZXdODIn1Kflu5N8L9USUwKMI8Gp5Da7Jcur2RbjQ3Mz0uKmZhHjg1W01eHpjZVhLRHHhSNw/LUvT9UwIZiTfeOBaPH/H+FDJXFgloC3D+jq68eD0LENLtmIQg6VHeIsFJgSDm8Jcl+RzSetpv1Bqi6JljJB79i5HAl66eyKeuW2M5HcZBVJKdaWoc4eXzPWgtNKLac9uCbVdPFd2JGLgTY7VQ2+bxcUKHi03TrtFMotLUz4X229hiwKB0PY0tXVi8lNlmoMMILzVC0CPiBf9UGfhqIEA6PaBUnsBAfl9OQOTqe9BfG0ATG0+Db4uNLZ2atICqDjVzPw3A2xxYf8sfs87qupVHYyzrV3Y0dNmQrtueaxvFoeMiLn1d8SZTVg8O1fT+Wjq+b+SuR784cND3M5YHmuB9hoZyTbcOnEInrrVA0D/mUkTvJoAfFjhxaRhaaE2M7n2TSCYbHHalds31f47AUkqdfsD2F5VH/ruwlwXtj2ajzXzp4T8vc8eL8CPpg6TvI7eIEPuKaUlWfDS3cEgg8V3I3oiBOLfR54tSdTqXatL1h+UfV+04CbYV5jrwsryGua/u8njwocV9H1nBH/9uBrjhqSGyk2bKmqx4hPtQ7xL5ozGlOHpIcd3Z3VDmONbmOtCcoIFn1bV4bXyGln+d+KEf/SrGdh1vBEfVtQyK49qwUsfHcXGA0lRGb4U08FKVSVKK72KbVFSA5POHnYYsTKl2hC1VIbCyN8+y+NCSqJFkSrvwelZMJvBzK9OvqM/0lIS8Cj53jp+sCzNoVr5PCUhHvfmZSEzw67ayibXWqMFQoeB1QHJy85AQe5A6n1Am13X8i6E9iEj2YZHCnKwcls1VTsoLUW3GFrY584JmPzSkiz4wdVXoOO8P8Qlv/1YHdV1th+rQ15OBvWz4rG+J2c5qRiGWAdIL2VsqqhFyQZtLZnk7KLRgGIBj7XAuu5metxYPm8iHn1nvy6SnvMUziexBVOeLgtLIEhV7YlPoJRoMAF4cq4HJRsOyWbqhV0TasQM3f4Alm05gp++vgtNjJoeajCbgD//cAL+8GF4i11QUiATRfk5oXOFtYpP9EQAKP6+wlyXJlV0IbzNHbqrsNwCDS1lGqfdgrunDNMUaADAr97ej+QeZc/H3j6gKXJzpdiwZM5oAMC0Z7dIOr4pidYIJUU5kI2163hj6MVEI9D46DDdocgTJRsO4S9bjoZ0OGh7TeW4nYXsMGJDpMQZLf4uwiykVwV+gC0e5zoiDfGrPQF1apIFnef9EU7OAFscOs/78fi7FZqzCf2RlpJAK7OOEAUKWVxSJZPruW1qO4+lZUfw4t0TFZ89r1kSAqHDUFPnY/rbBl8nfjz+QtBPm+BQC2j0lN+F/fC0DHJaKLoJ9DCCNbZ2hbHuuR0JGH9FKuVfB+2e2rOSY9wRg6bSS8vSIx447q+QO3PU8B9Th+Emjzv0DtZRUrOrgXYt0IB13ZGAK5pMoOLgQdy+SZOwEfoEZrNJUZfqiVuCcxVK2kI/mZ6FN784aVhblD8ApCfbJPWRxHtSS2Vr4TsH0Chx78Jn60i0cvl9eitv3BTCtLBhPDnXg6bWTs3f6evoxj0rd+KelTuZFSYBoLhgJMofuwEAJJlCiOP7XNlhZqeVvBgtTAcXE4gOx6QnSyNafaQYlmhLhKztQ8LvysvJwG9vZmdmEUMqyBDibGuXZCb1XEc3Vn16HA0+7WuboC8y9xgNorqqBUKWECUU5rqQICOQSNNaBPClbzWbgPFXpGJ7VT3e3X0Sr31aw/T3JRsOIe+ZLSjtGd67ibKnVi0bKrTremxYo8peIO/tnqmZmu3lvT3tuzxsrbepnToBRoJRpWdFHKKbPK5Qm6sUNlXUhrVa3vnKDkx7doukHSRMYUnWOIkrBfHyx9X9tgWTQE9L8U0edxg7YMYA9ZZZNaixL7GABKU3eVyhSrjSd8mxokUbQhvbed6vOguVbrfio1/NUG1ndzkSsHzeBCQnWGSTz4St768fVxs6ewEA3uZ2Kjp7LZUtqSADCH+2epOtBHorb9wqGgApyU3AonUVqn22D07Pwo0eN6Y9u4XnLVAh3W7F3PGDQoO6Rsw1kBcTDU7vvoCzrV0RLCxSoHXO9LYPpfWCBocRuBiZe/SCRXVVCJYZILUZCJqKEs8g0B8A8p7drGk+gcDb3B7ag2qD2CwZVXKoL1mv/eBSsnvC90YoulntZWqSBUX5ObjSlYwl6w/qFi0j32syKesFpCVZMGX4hfUhN2xKfszK8hqslKjYAvJZ99qmdlnbWpjrQkrCQcXWsf7agkmgJSEgtT82VdQyETTIgYZ9iaaqJdUWJF6vYhbHaMxw0oLY2Mff2a/q8Nf7OsO6RADprolGXydKNkSnjZoGv3//YFhAIEf0wpu9lTzbhnP6xRtdKTbdlTeugUawJHco7LAUL/x0uxUlcz2YNdaN8iN1UV0QN3lc+Ky6HvW+zpDBd9qtXDLPBFIGSu7w6U3KOaO+W+1QY3HO9LQPXQqVgP7aX621UqA2AyQ08jwGd3kHgXqCDCF+8dY+7F/iUmRsA+gzqt3+AByJVtw2cRBe+NcxLvcohNjxuhDY0AcMJoV/Sk6Ix+0Th8Bui2Ni0ALURcmevm2MJIEFcYBWfFKFzV9+E3GdWhE7145j9XhUpf2XMFwBCKNs1RswX+rQchaQWTwyqynXhkOLtKR4/PYWD1wp6vTlNIKPckEpOdPvz8uMmHXsKwKaYmykrBxKvUdhS/WmilosWK39HRkBcdVBjvHPqIS0027V3Ya8ZM5o3UkKboGG3MInBvbe64ZhSFoSnHYr0uxWbNx/Co+/W8Hr6xVhQjDjJVUK5x1kANIHuBwlplA/YcuXp7Fim7H6F2QRGxXgqB1qWpwzLVlUrU5gX6o69df+ai2OQXFBTmi4Ts4WCY08j8FdHrMkRsDX2Y2/bD6CRwpHSiY4aDKqBFJOD08UF4yMmO8CgvbSbo3HPSt3Ul2nsbULy7YcxdKywxHvvaX9PFZ9WoObx2prx7svLxMbD3jD7JASBTXJRv+z0ovNX34je90AgsEDbaXobGsXHl67B7uON8aUwRnAehaQJByZF3SlJKD9fLeuc+HH12Xh1gmDVT9HY7sKc12KlQkTgs7747PD/RAWsbew66lU9eQgN+MoBi2Rg9J71DsTGS0odWrIVkN1wOVIxOLZuVR6TGKkJlnwzG1juNDscwk0aEpy/7P9eK9l7wMAOs77Df8etQNcaqCZ/PPG/bV4RQdrFss9zvK4QgPNRuDDnp5gqcxNo6+TuZqy6L0DSLSYw56rWmmZZkAuNckCW7w5LCPociTgjmuuUGSUihZe/rgaE4am9Ts9DVbHwARg7edfoSg/h1o07aNfzdDdWiTMQvW1A27Ftmr8/IYcVcY2JWgdoKVF8L2dQFF+tuR/X73zBNP1VpUr6wdppR8uzHXhN7NzqZ4ha2AWbBmhr2Rp/Q39sQWTgOYscNqtuGWcG699Gumn8Ohzz8ywq36G1nYl2yzMei3d/gDe23tK072rBRliViPCqvSzb2fjW3/cqvjcHYkWqvna1ERpunIguOcef/cAt4qwGM4kCxo4znIoVRmF9rqs0qvLTzObgLpzHfA2tVF9fuFNV/UQBAQwdXgGpghmk/SCS6BBKxjTm9BCf6gGYqAWzR4FlyOR6gCXcpD/r6IWRWv2cL8/ILhJ/jJvIurOdYS+b2d1A9MCDmpGmKgNrliBmGyc0kqvJgpkX0d3WI8yTWlZTewPCLY9SDlhQNBxjYYiuVrQ1R/7qycNS2MKRoWGGz3/W+2zu443cmktUstC8W7NpMW5jvOhg0yOsU0pWNfSz21CMPvJ+t6eK/038rIvC/v+TRW1zGyEWghBlMDKDGR0YKYFPNmNLlbQnAUlcz2aqW9pQBPo0Qo+0tIuC6tYO6sbDLNDT313DNLsVkk7oiTmHECQwIEmqXd9jrTTa/SeKy4YiZ99e4RiwKQVZ1raZW3w1BHpmDoiHSmJVjxXdljT9f0B4OcMfmVzexd+deNVmr5LDVwCjf5YliVL/g+3eqgzzlIOsl6OYzWMH5qKvOyMsH83OcuJJGscdfBF6H9ZNzQZYmT5LsX7WH8Qfj8k+zCleh/lnEBx5UnKCSMHk9FQcsr6a3/1ruONmhITLHboTEs75o4frLu1CAjPQnmb2tDg64RzgA2ulGB75OSnyrjt8bSkeDS20tFSKj0PtWCdtZ+b2MP512fh5Y+DlVnaV7hsaxWWba0K0YnnXzVQlYVGjFTKzCgtxDSZaomNvjZoC/BlN7rYoXYW8NbHIGAJ9GjtF20bkzC4McpHMwEo2VCJbY/mhyUptlfV40xLO2rqlHVxci5PphqCfn+/F7PH1kZ0NRi151KTLKEA6sOK2lCXA8/W6po6X4SkgtiuZGZop/tmxWuf1mDMYIchHRRcAo3+WJZNTbLgaYb+NbnI22h6tS1ffoNNFbURg0ezPC78Y7c6J/jtE4eE/lZJe0AJvKpJ3uYOLFon3Ycp1/tIhBa3V9WDpSRIDqbH363olYy0EP0tkNf6e1nskFC8SmtrkRByVYON+0+p7pfUJAuaWuX1H0wm4MfXZeI7uS5MGpaGCSX/hK9DfU/JPQ+aPnDWVlNhcDZhaJqmPmOhjg4LTKDPjNKC/B5AOsEiTmz0xUFb1oD5UofSXueljyGEWqAnzmbTUueu3nlC0WZIBTdG+WjiZBhL6yAJUhbPHoUFq9Uz7795twL5Vw2EtYeW3Ig9ZwIwe6wbszyuCPaq1KSgZpvQnmtJopK2bSl7JbYr0fStfR3dkoPqPMAl0OBNzdUbYB14kuMwlkJvZrvkBo+eum0s3t79teI9mU3AU7eNCf0zMdTLthzBqvIa7q0KNFBy+mmM3tu7v6Y6fAnTzsKZV+Lx9yrQ1d17K7u/BfJaZjSEByvr7IWSGKQebNyv3hJJMmcLFIb1AgHgtfIaXJvlhDXejD9+byweUjmY5RjLaPvA/3T7OMXrExTNyEZedkZYcEbsxI5j9Vjwxm5D7URaT8KnMNeF/9muX7umaMaIUBsXEBRxpUls9JVkwOLZo5CRbNMcMF9qkGpNkdrrRthYpUBP6mxypdhUkw5AuO9B2/ZptI9WWulFU1snU9cDOa/T7DY8UjBStUWo3teJKU+X4albxzAxB7IggOAclNQsVFPPcy8uGInMjCTU1LViqca2JrlnJLYrk7OccKUkcNPDoIER7dpcBPt4iTr1JrSwKjz+7gF0UmT+ejPbJe5fJ7DGm/HA9VmKfzv/+qxQ9oAgzmzCwwUjsWtxIdbMn4L/mDqM9y3rxpmWdllhIrEQICnzrtv7NbZX1aPbHwgTzfrV2wcMDTLMJvk9Q0TM+lt/NYvIpfhgVRNNE35WK6TWjBibKmrx0Ordqi1gZ1u7kGa3Yvm8CVC7pd+8W4F3d59Emt2G+Sp7t62rW5JlhrYPHCYovgOyNosLR4YJmhHEmU3Iy87AM98bE5zdUP5pmjA5Mw1fLCrETE+Qne3JuR7N17rwe64M/R7aZ7WzukGToxrH+aG4HQn4cV5WmEBqfwaL+CFPYd3URAveeOBabHs0XzbIkDqbTjd34GxPkKF2HyYEg+yBKeFVEJcjQTIjrUVQmQUry2vw2DvK9MxyONPSTt0i1ODrCp3f0U7Akd+29vMTuMnjxtrPTzD/XrMJePiGHMUqt9CulFZ60X6e/3wxzXfzBDd6276oFWE0GnxdmPL0ZjylMqfBO/J22i1YfPNouFIS8M+DtVj16XHVvxHfw6YK6agdCL6z+ddnYeEsecMkzAL/73b1748mzjS3Y/nWKtVMpN8fQMmGQ5pnZtKSLEyVLSHIQXL/tCxJtrH+3F/NwimeZrfgybnh+492NkcLaIgISNWAFiTbqjavU+/rRPFb+0LfOf/6LKzZ+ZUkhWRTa5dkGZzWFtWd64jKsLwePHzDyLDvnzXWjQdPZuGvHyuz99H+HhatlZvHDqLOGJMzkXf+4o5rhvY7WyGHjftrJSk9aXQMtII8+We+NyZiLpKApqLoSLLAbDKpVu8bW7vwxgPXwmwyUbV9XmgHNoahSWsbuJaAgYY50AgQR/xv22s02TN/ADjvp2tL/dv2amysOM38HTxQfvQbrhVRLhUNgpkeN7Y9mo8186fg+TvG440HrsX/y8/h+RXcwMscN/g6wzLkUuAVeZPM4FO3jsGtE4JZq++MpnOahP2fchkVgj//cIJikCEEz0wQD5gA/GHjl4rtGsRYPLR6T8QzoDWWKQnx+M2sUZrv0+VIwE+mZ8kGe3KZqf4Ccii6HOF7JzXJggG2C/mRBl8XSjYcith/Ylu0Zv4U2QwjLWirZKwVzMuTE5iTEd6mdqz4pBpxMhacHLy/e78yrOLCoh8i9w5Y16bwXRTNkKayZUVqkgVTJFpgFs7KxQvzJsBpt4T9+3S7FfflZaK4YCQGptD9HpZnRVPVv+GqywAYl3iL5uBoX8bG/adQtEae6QiI3BfABZuTmmiJ/EMJiD+XZrfgvrxMOBKtklVOgK6ieLa1C3dccwXVPdSd68DUEenUVayZHjcW3zya6trRAKnYs/gRYuZAIPqdNMcblIfclUF3t70VZABBgg656p8WcFUGBy5kujdV1OKXf98nu6lcKTa0n/crOnZGVkN4X1apr41Xf6RURpb22r94ay+WzBmtKvYDAL99vwKHvM2AKWhMnUlWnG3rCjHpCCNdoxQttSJa39/cfh6L1tEJTjrtFjw5N5wCsNHXgQWr98je7+LZo/ptkEH6qjvO+4OzAj184KQnloZxDOA7e0E728Dar08OWtZSNbmPpjZ5Biop1jIaTQHhDAvvYfnJWU68vfukblv4jIQiN8GssYNwY8+AdlmlF+/u/Rr1vs4QtbYrxYbighxkZtgVfw8NzbLZFPwcIF+9cTsSsHj2KJRsOKT9B1Ogv81ySSHYsqg8v6SmY5Bss+CuVz9T/a7ld02E2WRCaaUX7+09hQZfZ4jMQE7QkZ5Zim53ZNjpBsiFcKX0nXUiFKVlrSgpMQcajWFO7UH91BHpXGyg0ZA7V7WAe6ABqHMbExXf0kpvaGFJlbKX3TkRR8609AnxNCWo0ZCq8XgHEMle4Eqx4Y5rrkBwBESeLYnW0T/d3IGfvb4bjxTkqG7IBl8Xlv+rSva/ExrKgp5hJSPbI/oy2rvUS6Dpdiu2L7whbNal2x+QHTIFCBvHIdzo6X/K4HKtSYtnj5LtiZVjHOMJ2n7918qr0dhKP5BMMnJ+f4A7RSuB0Lmh0RQQthDJ8byrCWbKgUeLyvzrs1QPvjizCU1tweBCvGZON3dgadkRvHj3RMVAlIZm2R8Ifo5cRy4wM3pOrz/OcomhpWVRClNGpKsm79yOBEwZno7SSi9WSawxOSeNNhj82w66dmS/huHSyVlOw2wNK9bvq8WvZ45CnNmEwlwXHinIwcufHGNi1eMpckcDtyMB90zNxIpt1UzBAkniTBmebih9PiHoaPQFWTq1tsnxPFe5BxpqDEsmXFDxpeulduNKV7Khyo+8oJStkPuthO2KBBkDbHH49sjL8cXxRizdfDT0OSW2JHLtJesrZdkJyKJZxWETCmkohZmb/KsGYsrTZX3+PUUDZEv+4VZPxEA9y5Bpf9LPUKJd1ZOl5AHaTCRL1jo1yYI9JxoND9CPnD6H7VX1oWCAdoZFLuibM86N9ftqJYPBNLtNNfiY6XFj+bwJmg/BV7dVY8IVqZg1dpDsZ1gqUHIHKMuMhhBSlTSjWalu8gQdrf7MNKWlZVEKNMHwnHFudPsDePxd6QFouTVG24FwjsLRBoKCbM98j55mn+DyFBv3QMNui6MKEIQgNruprZOJFleOOTAocidNHcsLi2ePgjXerKmTgyRxiA0sWrOHa9cOIegg662jO4DiN/dqvh6vc5V7oMHqRNGU5i84sZujpmmgpQ1ILVshFXmLF9m5jm58cCCyL06tjEVT8g2Av3qu8L4cidY+H2REq71LSWdFqwNzKUPNMaSF1memlqE3oi3lbGuX6uAyDyzbehTLth4NSwqo6cvIBX21Te2S91wrEQzKtY9sqqhFyYZDYbaChV7cHwAeWr0HL/Uc2FLgEcyzzGgIIbWWaup8VNfSipXlNVip0LLTH6ClZVEOMz1u/GS6PLHAXz+uxhufSRMxEEitMd6txmfbpEkf5LCpohZPrDuI0y0dOr85EvFmE+zWOPgYdSXkqkJSoCGiKMrPwZqdXxlGCZvW067G0skhtS/T7DbuowHi58KrTU6vL8I90NDiRNH0UlvjzXjqVo+hcvNCsH6HmuESHj4ZA2zYIBFMqN2PWhauzkdnPFITLWhqU+bq1nJfv77xSg5XDLI5AWxaJbRwORKweHYuSjZUGtojaYs3ozDXFfbvyBo4cvoc1TX6U881r9aSDLstpEpL29JDwyQ1OcsJp93a6+KNYqQmxuNs23kqp4UkBX4yPSuiIiGsmPLS/altasdPX9+NF+ZNxKyxF6okUjacBBnfHpmBfx2uo7q+ki3kEcyT7LPSuhTbfam1xMJkpxc8+6ovNrDYSzWGrm5/AOv3KZ/RSkGGEOI1JuegOu0WzYk6mvYWtZZ2vVCaF1PCe3tPUd8TDXNgnNmEJXNymX7r8IwkHFNRMScQvk9xojxjgA0IBD/T4OuUnGslKJOgH9eKNJnEJq/5YL2+CPdAQ2sWiBYOCaNtt8bBEm+OmjEXw4Sg4fpg/ylJ54ZFLVMJalk42md6b14WlpYd5pbdJ/fFywl7+rYxaO3oxn/+fR+X6wHBNfLyf1yNKcODWVuzGYozM3qdA29zR9h7YlVMFZeGL3XozZgQWshf/H1fWCbLlZKAOycPRWZGkuzepFF+jjOb8N3xg0IDxX0GJhMelAgcpEB+o1SWVlyZ5NnKVbRmN5ZhAm70uFUDmF0nGqmvy8MWKn0uzmzCnHFuxaqTcJhVbi1F81yKxrxSX8XkLCe1UrMaQxfPmRqpNSbVyeFtbtfU5kJTnetN0WAl2K1xVH6DUEiTZk2zUvmyVHguT07QPKMGBN/Fsi1HNM+SpCTE4d68rB5ms2CSnvg1YtDM5DkYVea1gHugwcpqQgulaNzX2Y0fXz0E59q78Y/dJ7XctmbY4s2wxJnCVC2F2VAjsghyThntsy/Kz8aVrgHce8OdA2y6o+figuDszqufHON2XwBgiTeHbUa1PvXCXBd2VNXjZ2/sQnO7tkwNeU8sa6C/6mewJB7kgsOgQxd+qHib22X3Jk271uPvHkD+VQNh7alQ9bVAo6m1Cy9/XI3l8yYizW5F+dFvsGyrPJGDHMIqkzOv4nqPpNWpuMCnam9a2tnaLvTawknD0mQrYDRZbTLMCsBwR+4mjwsfVqhnQfvrjBcAmE10NlPN3vDINqv5OuJOjmAbo3YoJWt6UzRYCdNHXka1pnMGJjOvZdJyP+nJUrSonOG0syXpdisafR2Y9uwWxQq4HDZV1CrO0tLAbrPg/4k0hJSg5uv4/ZDUnOHpixhCb0vLakIbFdJE469RiNYZgY7zfogrqCQ7uHzeBJRsOMT98KEZYlN79iSjsqOqHq99Wo3SQ2d035crJUFX/6nbkYCiHt0Vp92q+36EONvaFXHwqs0H5eVk4L9uH4ufamSHIJkPFgeEh6jcxQhax5C0vQkN5kAKqmwC1sy9UJSzMNel2koTbZAAoWRDJbY9mq+rMkQc1DoD+rcBYGU53+QBANS1dKDbH5Bl45PbuwEEqxHf+uNWWYeBxjkTqugavS4+q2ZzRPvTjBcQdKZp2pmcdotionNTRS0X5qIA2Jy0yVlOuFJs8DZr2391LR1Yt/drSV+qL66FtCQL7p4yjCrQ0NoBY4034/uThlAliGiYuG6bOFiSlp6mZZFX0pkmiSD2rQtzXZK+TmmlFyUbpJnaePoihtDb0rCa0PRFE/TVaFwO5PDXQy0mBZpqEIsqcmmll0tVQ3hfcWYTM9WtVOTsciTquicpSBlbtfmgmR43Xrp7Ih575wB1C4TwedCuXdbS8KUG2iB5pseNGz3hBtMfCOCuFeq894C2maIGXyd++vpuvHT3xDA2mr7ShiDMYPOY6zn49Vnd15CC1h5uJZRsOIQV26o1HYhqLWQd5+kUfKPhxKUkxDOfJf1pxgugfw/XZqXLtjmzUuQqgVTnaVFa6UU75ZoTw2wKZ7wT+1J9bS2YEGyRnjJcmUqYR+uOI5EuaXlvXiaWlh2RteszrrwMb+8+qYnJjnfrmtJap/Wt1QIfnlpeXJXBhVBS5qVV2CXoi9G4GgIA9yADoMuQ0Kgiq6mDs0J4X+T7iwtGUv2tlDLv5CwnUpPoFFppodXYzvS4sWtRId544Frc5HGp/wEuPA/atUtKw/0xyCCgUaKWqoLWnWPLAGqdKXrsnQMozHVJ3mNfwIcVtfD7A3Cl0CnsyuE9lXahvgapc0Orw0gO3d+9X0kthnZ5coLhjtz3Jg2h/qwJ/VNXg/YdfFjhxcNr9+LOV3ZEqB/zTGqeZdDTIeex1nkeMXuReE8Q7Yy+ArstDv6eSqScujeP1p1ufwBrdp5Q/ZwrxYai/By8ePdEuEW2nXTjbf33N4o+nTDhIwbvZLncWqf1rWlkKEo2HJJVuGeFIRUNAqlssRZ+82hF49GiPtUC1jKWUqa+2x/AkvV8out0uxV/uNUjeV9rP1fe4KmJFiy/a6LkIFNppZfbEKVaVoSmhS/ObMKU4en4JcWA+gMCQTGjyREuNZC+2r9tr8HxhlYMcybhnqmZsMabZTM1d1wzVNN3kZki2gPgbGsX/rL5CB4pHBlRhm70dUa0dKlBSZNizjg3Xu7JuNPu0//dfhz/u/04UpMsIVvaV+0ZTwiDA3Ju6DnYicMAE6izrf9XUauqIq4VD07PwrevHMikgdTfZrwA0nqUwNT/Lm554ZnUXPXpcVw7PD3ibBSfN5OGpXGf75Hypa7PScf7+/kxHenBuY5uPLR6Dx48eRYLZ+VSd2GwYmd1A9V6uHPy0LCW8p3VDSit9AYFPxlfjNQa4rmu5JIILL51tLW8DA00pKDlB/Ki6FKDq8dpEQ6P6oUWSkwW8SstWLblCBeOaafdEqF6TUBz0J9t64LZZJItM9LChCBLVGNrF5XasRBGtPC98kk1Jg1Lw0yP2zByhEsVUu9jxbbqkOMt1Ru7tOwwUhWYM+RQdeYcrh6WynT4Pr/5CEYOHIBZYwdFGGDS0lVW6cW7e78Oy34p7elfzxwlGehOGJqmqbWxqSdAFzP0aQ1geCE1MR4JlnjD+O2F50Yph2HeunMdVO18pZVeyb5tFqQmWWA2mcLOCqfdgifnejBr7CB0+wNUZ6ArxYYlc0b3uxkvIJgMunMy2/ktdsB4J3zESVMp+6aH1lYJxJd6rvTfmDo8A58di8y09zb++nE1xg1Jw6yx6npqAF1SUPi5DyvoqrOZGfbQ/44zmzA5y4n/fGuvpt8kRbHOc13J+TIsvnW0tbyiHmho1dlYPHuUqjqwFjjtFiy+eXSI6/iD/ae4XTvdbsWSOaPx8zV09x2NPv1NFbXcVDOfunVMKMgQGwBaZ0JqPbBkI8lTevq2MQDAlBWhpTZVulc5CA8Y2gH9/g5WkTjggqNgEvxvWodv2dajzPcYgLxYnFCd9vHZucFsWlNbiE89zW6TrZZJZY1metzw+wPMs17kOSTEm/HGA9ei7lxHRACjl/lEC0wmE3578ygs6LHjRgQ6pZVeTM5y4r29+u345ckJmDoiXZWdbtqzW3T/lmduG6PoaNFQ7RYXjERRfna/tiVqtLVSEDpgvJOawuBXzr4ZLXK7bGuVJiY6Fswe40L50XpNgsCL11XgRo9LdV6SZfaANUEjDgS0VkTttrgIinWn3Yq549xw2q1o9HWqJgrmjh+EN784GdHRIaeVQcDiW0e70yLqgYaWH0iUZHmCmOKnbg1/cTwjz3pfJ57aeAjzr8/Eq9siVcCF9+JyJKC48MoQG1f5kTpsP1YHwpN8TaYTu4436qpw8Bx0S02yhATp5LI0NJB63iwOvTiQoMmKAMrtYzxa+IQHDMuAfn+FnmG5AILijsUFOVj7+VdRIY5Q0ymIM5vQ1NaJ//q/f4v2hRXfHT8Ihbku1T28qaJWc6Y8gKCWi9lkwtzxg8P+20yPG8k2C+56lW6AnhcaW7uQZrcxk0XYbXG4PvsybDqoXqVYt/cUbrhqoC5NH3GVUYmdbntVva71NsAWhz99f1zIBsg5WpsqakOVKCk8OD0LDxfkaL6PSwV6zu8zLe3clbvJdXkPA5tNwP/Lz8HSzXyShnqx4YD2CmK9r1O2RYckMMsqvZJMYOKkICuzk1xHgdZMvq+jO4Iqt8HXiVUUrKi3TxyCvJwMuFIS8IvvXIXPqxtCPuC1WU6YzSbUnevA9qp6ybODxbeOdqdFVAONbn8A/kBAkUZM/AP1UoIlJ8Th9klDsG5vbdjhI+fk8VYA9ja1Y8UnNXjg+iy88ol8VpZktTdV1EYwHC3bejTC6DkS4nHftOFMGSy+g25Butimtk7NWRqzCWiUeM4sh0VA1EApNxckdhLU2seUWvhon2FppTf0t2pUuv0dPNZmZoYd2x7Nx89X78LGitOc7kwatU3teK28GhnJNiYhwAZfJ1aW12BleY2imCAvx6RMsAaFqPMZQ2GrhjMt7Zg7fnBoL5CKz8nGNry16ytJPntfRzdVkAEEnZbg4awNclVGuWyr3taCku/KZygJaNYC0fPo7/ZET0WCnDtyiSGtuDw5gfsw8LI7J6Ag14X/3VFjeEUkGpDaRzSVCWFSMP+qgUw2k+yUxT3VZ6NandRASG/+sftkSAeOVGp+eeNV2FRRi1+/vV+1ksMSPAgDajnw7LSIWqBBs2ikdDbUFo5a1qGlvRurysOjSafdIkvdFWc24cm5HkkBEy0gG+Efu9SFBDdV1CryvgvR1H4ez5UdxqpPq/GMQjlNCN7sXRsP1GLDgVOanSF/AFiwejdeNEcyTtEeFqebOyLanISBRU2dD2t2ngjjJmdR/fY2tYX1W7K08K0sr8HkLGfovtRKw/0ZPNZmTZ0PpZVew4MMAjk6SdogQSwm6LRbcOv4wSjIdcEfCHBxTF4tr8E1gjVI0FvkA+R75So+fKD9cGStMup9jq4U9b9n0fPo7/ZFS0VCKnsrTAzJZdNZrsurJTslIR63TxqCI2d8+P0HWy+JIAOI3EcsCWaSFPzb9homW+LqmVkTk3iQeToj54JTEuKx5JbR+KqxDUvLDsu2b/9kepbsbKLY72Ft057pceMn04MJcGG3jdkEzBcQ2vBAVAIN2kUjNvI0BlbLImjwdWHB6j14UaLPGgBmjXXjwZNZiv2wLCCtHXIgEbnfz86hfba1K8Txr7YwaA/FyZlp2FnTqPq5v+2gE0k0maDI3CBuQ2E5LMRtTjTaICxsViUbDoVVt9yOBMy/PguvbqtWZZhR4tWOIRw8HN/nyo5wp0SmRS2jEKAUGnxdeLW8Bq+W13ClopRag6zVOb3gXalWwtQR6Xh790kmJyHBYsLPvpWNovwcpr2qNYPO0poQ7cHNix0sFQm5CpYwWVWQ68KkYU5mVjnhdXnYNxOA5vbzVOJzFxPELEpaq7nHG1qpPvcfU4fhJo8bjb4OWfG9Bav3hJx8I9Dcfh4lGw4iAJNi+/Yrn0QGGcL/LrbtLG3apB1TfP1AAHj542pMGJrGLdgwPNBgWTTiKoORhjMAZSdw4axcjBuSyl10T+5e9B74NA4t7aFIE2SwQCnIIL9d3IbCcliQayzbclQyO6AH4ha6YCtctWIrnPi+dhyrR152Bse7uvTAawiTFyWyFhCbQisEqAQtQ5VykMp2C4N5o9mntFSqtX6Py5GAKcPTVdsCxGjvCuC5siPIuTzIKAbQ016zfhcrCUSMIpsdUq2qjb4OlGw4ROWASQ0dL549CrVN7VTzomLa90nD0hTZpUyIZIkT42KhqmaZbTEhch9obTMb5qQjAriphw1SjsSBOPHr9p7Cwzfk4JVPjsHXGdnSqReNrcoCpgHQ+U5i207Tpq1FZkIPDA80WBZNyYZDuNHjjpp+hlq5edbYQbjR4w69sE8O14V66PoaaErnRgy68YJcG0phrgvPlR6mYghaue2Y4b+JbMIP9tfi3uuGUQ15LXhjN575nnx7Gy1l36UMmrLv7LFufLC/b4vJaREC1ALiVF/lGoCt/1afSZBK2pBg/vF3K7jd8+TMNBw5cy6sgqulUq0VxGnR+tuK1uzBMphgNkcy2BG7JD7EC3NdWD5vAorW7KHS0UhVYY8RI0aRrQ1SrarC85xltopkuZfPm6iaEBHTvm/cX6uYsCTf/sxtY7DnRGNEK0tfgCPRgiaF5AdZg4tnj4oI5lKTLMgbkYHtx+ojugOEdoGVklb43QNTbGhqi6S3l7rHyVlOKipYb3MH07B9b/lUUrZdrU37ktPRYKlK9IZ+htr9kRfW7Q/giXUHDboLPqB51rwH3YyAsA1lpseNvOwMqkCjqV05Q8ALZBMOSaPLoJxt65KkywXYdDwudcitTUeiBffmZWJouj0qgYbbkYCbx7qwYhu7WBNwQQjQKLtFHBM1ulMh5JI2RCBxytNlXCq3pBoqnDcRO3NGVKpNJuDh/JwQEx6g7bf5A5Cdz/M2teOnr++OmPEiopG0zqFSG60UYhTZ/CBHFrLjWD0+rarDa+U1ilnekg2VWDw7SNEs9y6EtO9Pb6xU3aMkEAcg2crSF/DCvIn44niDJDW+cA3O9LglgzkA+PRIHd7ecxKtnd24JtOJH12XGXpOWihpyXcHALS0n8eftyj7CAEAP7z6CgDG2KDeem9aEvKXnI4G60MQ62cYnYGXuj+pDPPO6gau7QxGgPZZC9WXP6uuxz8rzxh8Z+wIAFiy/iCSEyw409JhmKiRHjjtViaHUkq8iUXHoz+AVLGWbTmKVeXVONvWhbNtXXiu7Ag1ZbIW3OQZiJked9h+f+WTGk3XcqUkGGq3HEkWPPXdMSjZQEdVLackS2CNN+OpW8eE2n943G+DrwsrewbRtdIwsiAQAJZuPoI3v/gqbCh/1/FG3Dp+sKZh3ojv6Pn/4vaW2qZ2ZpFXYtvEGidyiFFkGwMplkc5kASTHEVzWk9w7Ui0otsfwP9V1KoGGSkJ8fjld65Ess2CX/x9X58LMkLtiCPSkZeTgStdyaprUBzMST3jf1aexvJ/HcUzPfpXWls4SbsZbWvT0s1H8Nr2Gtx7XZaGb4suTAgmUJQSGOl2KyYNS2O+Nq0NzhhgY762FEwBMT+oBJqbm+FwONDU1ISUlBSmL+j2BzDt2S3Ukeqa+VMiMg5ao101JCfEYe9vb4wonUplmG/yuPr0EJbbkYBtj+aH0WPKlYiNep79DWvmT5Gl91X6G1IhU9oXxMAL3ymBnv3Ym6C9byMHheVQNCMbedkZoX2ybu/XeHjtXubrpNut2PmbghBVNc+2JAITgEcKRlI7tzREEYAxdiEtyYIvFhVG9AdPe3aLIRUf8i0/mZ6F9ftqw36LGilFb0Kuiim245OGpenWUwIufRtCoHYOyrE8KuH5O8Zj7vjBoWuXVnrx3t5T4fT5KQlo6eiSpGu+mGACIhJeLK2+NM+YhQWSJG7uy8vEDVcNjBDHY0FqkgVNrV19LrgjMAFhA+ly95naU/FnIbKgtcGuFBuWzBkte37Q7kfDKxq0Q4dKfabC4ZbSSi/e3fM1c/lZCrdPHELVn1nb1N6ngwzxQJVSOw6gPXsQwwWQLHGc2YQX756Ix94+QFXxIhW7aPdIXiwwalBYDcu2HsWyrUd7hj5zUdeiTWeiZK4njAGkrbMbxW/t43mrCABY9Sldy9T9eZnU2W6hnfU2taFkwyFVJVs1NLZ24S+bD+Pa4RlhjolaK9AjBSND+iI7jtXh+c10Ku7kWpKZ5D5s9EgVc/m8iUizW3uouVt7qLkj7bhYhDGGSEidg64UG+6cPBRD0+1Y9N4BTdeta+lAtz8QomheJdFupdX57Wt4pGBkhP1Q6v8XBiEZA2x4Yl2F6newEHg47VaUzPVg1lg3tlfV63rOXee7+7JJQKI1DhOGpuHFu9MUE0Ck4v/KJ9X4r++Nxayx6vaetltISj5AC6JCb0vKvkolygCACVc4sKOqHlNGpEuye8htaq34zujwKF2vg2NCsBTa3H4+agtYHHGqteM4kiyGZBH78oY1AndcMzTMobRb4nHPqp2qf5dhD5YiY5SV0jByUJhmndY2tWvW0HlwehZu9LjCdFeMIrSgPZzzrxrIdF3hTNqJhlbJnmxWPL/5KAKCQIE4y7StQJOznHjz85O6nbe+bKPIvRWt2a3YKtGf2ypZIHsONnfoXtMlGw5hxbZqLJ6di5IN0U+K0MLBwRfJzKCbQwSi0ylR7+tEyYZKmM1Ax3l2OQAhfJ36/t5otHZ2h6QLPvrVDNVZs3Md5/HQ6t148GQWFs7KVb0+8cuXrK+Uta28GKiiJth3off6CFaV10hmfzdWnMbGitMYYIvHD64egkLBICHvTKczyRLW28bDwQkAMJlNoZdjtAEqLhgZpgyuRlkGGEP/SYRv1Ep8vQWW0iwtxAbYHEe5AXs+Rtv7yKtH8mKBUYFVcUEO1n7+lSGHoNNuwZNzPTCbTRHtcK6UBMNK9I5EC5rblK/7i7/vw5I5bD38ag5DWmI8MpJtOHLGR3U9pRmkbY/mU1HILpmTy3WGpK9CbaDcCOrJSw3RqIp6dSQkooX7pg3H0rLDklVD2mdDmyiJZrsrsR+PFORE4dt6H797vxLJNvoZ1b9+XI1xQ1JDNN1KmOlxI9lmwV2vfib7GR7dFWZNf6URcWYTHi4YiV2LC1FcMFL2c+c6gqI0d76yA9Oe3YJNFbXcM50NrV341h+3YlMPlRovB6epx6F1iITD7LY4LtcHghnBl+6eiIcLwnvyjMwGi2G3xeH+vEysmT8F2x7Nx8JZwQylyyFtmKJ9HqYlxeP+vEy8cf+1SIjn9+wJxAa47hxdq03oc7QW+VL2qiTAuwJgQnC/FOXnYNuj+VgzfwqKZozQdU23IwHFBSPx/B3jsWb+FHz+m0KYzSb87PXdEfvvdHM7zvYEGby3QOEo9WrF6ebgobyJkjKSOAxydiTBYkZj23nqIEMKZEn/7v3gMPvUEemYO34wpkpUsglI9k3OvhiBvurCCw/+GCIRjXOwt82ySWFxXrB52ZJ7xuVIwAvzJsDtSFBc43ZrHPz+ALpVot9ot7uS71mz8wRcKcq/4VJAbVM7th9TpzAXYtG6CtX3RlDno/Nd9PjIUatoiLFm5wmqzxGq0x/nZVJfmzZiF2bWeDk4xKFItMRh+f0TUefrQMYAG37x1l7dg2HigVUxotlm09rRHcEqM9Pjht8vTQ8ZbV7ws63BYDUl0cK9X1aKxYdVVIt2c9N+7lIBT0prKerPqSPSde2TxbNH4cd5WcziR6lJFtjizfA283ufednpSB9gUWS2YcmA0zgM7V182g20ZMlIVXzHsXoseGO3YSyAxQUjcaVrQJ8nzOhvbZW0uNSeC5kbI7M7RHxwweo9AJTpjpXE28xmk+Kgtq+zG3e9+pkq3Xo0E5wEROeiuGCkZNWmryI10aLRbrGFUw2+LmrbGg1B0KhWNAh2VjcwO39v76ITyrt94mDqrJcwszZpWBpSE/nQZ5JD1Gw2Ye74wTCbTLocDJKhKC4cqZj1q6nTnmVkhfDZkci52x9QpdwU37o4M5OWFI/UJP3vgdzfKgOG+KU464mDLGcOyDskAUpM7VcaZEgN0J9RTrTG4ZGCkWHaCoC+Z5qRbIt49zSD/Y2tXfjvHwQrIPflZSI5QX+O5/KUBKzfp16poM2A94bDwHoOxJlNyMvOwDPfGxOkfzTgnoamJ8GRaMWvb7wyqJmgswJmFPqbbaBFX38uLGvWabdi8exczBrrDqv8zRo7SLZaIZ7fIXNX4qphYa6L6qwlyV65qmhvBnaZGUmSz8Fu5d/FIIUEixn5V11G/fnl8yZqqqhPHZEON2M1l/a9BFXrrbL/Xey7aEGvVDRYF2YAQDOlGFtedgaevX1cKIKva+kIU52WunZtUzt2HW/EtJwMroJg5Hfq2Yi0gkybKmq5DG6yQJyVpHFU/IFgVvjU2Ta8u/frsL5Dp93a0+sOTbSDUvfHO+v5wjzpIUxWUa2Y2q88eIlKtnZ247myw1j7+YmwjJyeqomUE1Na6aX627pzHbDFm7kQWphNwGfH6pmej5od6g2HoeSDg0i0mJkHm+XWiJvDvNjv3z8Yxmo4MNmGAbZ4nOvgJwiqNwObmmTpl7aBBmR/6w2aE+JNaD/PN0++ePYoDEy2oYiSOrvR14kFq3fjRXPkuaNUraDBzuoGptlFuapobwZ2lycnYOqIdMnnUFrppdZI0YqOLj+2fvkN5l+fhVe3ySu6C/VIzGYTlm2tov4Op92KKcPT8cQtuUx+Ec17IfN4chTsvARBo1bR6PYHsL2qHuv2fq2ZOpIGLkdiWASfkUw3TFta6eWuOkxetJ6NKJWhICDP9N09X2PhO/s1f4deEAeFNjt5srENK8trIoabiFEFgtz/PCobQLBcySPz+cgN2YrUcXJ95HJZJrnMfUztN/gsyUzF83eMx+LZozRfyyvKyGmpmgizOkJbVn6kDu/tPUV1DWeilVsvsz8AVSVcMYR2SPgbtlfVo9sfCDGi8QLN0m3wdTHNkAghXiNq82K071pMnX66pYNrkFFcMDLi3li3+dnWLuoAt79BuL/1QC3IIDbhhXkTqLshMpJtSGfwB6Q6B4SQq1bQgCWxoFQVVavma4HbkQBXik3xmk77BUIfqecw0+PGrkWFeOOBa1E0IxsPfXs4nHYr1/skb+SD/bX48w/HK37ujmuCquSsz+s/pgwDELR3xZQD8GZT0J9Sgto8HqDsf7IgKhUNKRYTLRkdNXVoqfJOTV0r1bXf+oKuNYsG4mz05CynJuajohkjUFx4paTx6Euie8SBaaAciP7H7pOK/ey/e78S2x7NDylE//Wjo2jV0Rt+b14Wlz7OrMsGqH6GJcs00+PG8nkTsGhdRdi6jqn9BiHka+/2B7D8X1WaxO+k5hRYqibCwK+00qt53/1s9S6c6yUBL6FtlNPZ+eHVV3D7vuKCkci5fEAocaC277SyKMlx+ou1l1ZypEWXQmqSBT+amok3P/8Kp5vlK2VOuwU/+/YIFOVnh9kIuZ57OZD1nGyzoM5Hpy7enzDT48ZNnoH4sOK0Yd8RAEJ22pFkxV0r5Jl7CC5PTtDU0WGEppKWBKjUvdNqMrCgrasbP7x6CF7+uFr2mg2+IKGP0lkZZzZhyvB0mE0mnGlpx4+mDmPu/FAT+iTvJz05SNIjdz48V3YEaz//Ck/ckht6XjRYuvkI3vwi+HeZGXaqv/EHEFEJE2ucLFl/UPFdOe0WfPSrGbDG669HGF7RkIuaWBYjyRw8Odej2AMvzgAH24no1HO1ZqxostGllV5N5bu87Mtkgwy1SDSaIJGzUp+fEC0KbXBCoxpnNuFK1wDNQYYa+wYr1DLC5N+zqKaWbDgU0T62eHYsyBAjzmzCk3M9mv9eKiMnlREnbCxCkKwOAF37jjbIcHCaFSMgthEAni87gp9K/AZvUzuWbtbfeulKsYUY8WaNDQZzaSp2wSgWpTizCZOznPiwwrjM/4+uG4Y186dg16JCFBeOxJI5ypUy4hyVVnoxOcsZcjzT7DYsn0dvo8gzu+vVz/Dw2r1hDI0xBHH3tZmGXj/JGhea/5oyPF21Ap/W0+6mtcOBd2sjyayzQO7e5ar5aUkWTZ0JZ1u78PLH1fjJ9CzFPSGuVouxqaIW057dgjtf2YGH1+7Fc2VHkJpkoWYBXTx7FP50+ziqz55paQ+dKXKsqrVN7aH2pxfvnkj9/MnvpE2cA0EbQSph4udw14rPVOeGG3xd2HW8kfr7lGBoRYOXCB5wIXPwotkkq3otdM66/QEsWX9Qxzero7hgJNZ+fkJRcIo8A1akJQXZkrZX1Yc5q72lnKyEkg2VuNHjgsuRyO2a3uZ2zc8OUGffqKnz9ajuqldhxBUquYzwnHFurN9Xq7o2yTWkeMeVenL7O2aNdePBk1mKLEtqEB/WUhnxGz3uiGARAKY9uyUq++6FuybCbDLhw4pa/O/247qulZZkwdO3jQEA5D2zWXa98/hdxQUj8bNvj8Cu441Yt/drXJ6cgMJcF7U6uvDdsATsSjB6wP1/Pj2OqcMvtKzQVMq8Pc6GuModZBcahTS7TdO7J0O7MTG/4PqBKRgMtHYaU0Vs7ezGjqp65OVkUH2e7DGtM2K8ZyFIJYKl71+pHUeumg8AO6rqMf9vXzC/i/X7arHlF99G3rNbJKvZSqx6cmcsi6ZRRrJNE3HL2s+VWVUfe+cAdi0qDD0vb3M76lra8VzZEclnRH7nmp3HkZZkiWjvlENtUzseWbsbH+z3arLxvIJbQwMNWiOfkhCPu6cMQ03dOWw/Vo/G1gsZb7HjLl7MGXYbYAoOWgqd8uDLM2YWhDieRfnZESVw8YGo9aBrbO1C8Zt7AYQ7q9FkhqEtg5JsJK8hPCA4JHqi3qf5WlLtR2Knsig/RxB4tGJp2eGI3ysOWOSMV21Tu6QDLKXkS0OHGhPkksbCWbkYNyQ1ot2MFjSHhlTwsb2KbfBaC0IDgwLHVWugkWSJw4PfGo6i/ByUVnoNFdNKTbLgmZ5g5lt/3BoRaN9xzVCq65B3IxfIa2knjMaAu3ivzvS4kX/VQEx5erOscwREiqd6m9qxYPUevHj3RNzkcWt69ySL2Z9tRzTbit/4rAZ5ORlUg9VnWy9QjrK2Gull/ZHDTI8b9+dl4lVKdkaSVJRbW6SKSM5V4heYzSbmIINU7VZ/dlyxZVaqtYxGvJgGdS0duMnjZiJuofHRzrZ2YdmWo3i4ICd0z8+XHVZ8RoTSlxXv79de0eUV3BoaaNAa+eb288jLzsCvZ15FlckijsCmilr88h/7wl5qaqIF9+ZlYWh6kvhruECOm18OPA46obPacZ4Pjz0NBqbYMNSZhJ016uWzMy3tiDObsHj2KDzU02ssB3NPz6PShm/wdWli0SLvX6iYLgehQ7mpohYOiTma1J6M8EyPW1M1SSpwoKFDNaIn91LBrLGDQlWH0kov3tt7imp2IzXRAn8gKEDF6oQZ7bCK7Uq3PwC/P6CZd/2VH12NvOwMwyqgdlscpudk4O5rMzFlRLpsMONtasfSssOK6ujCg1oukJcK2GlAe1AOsMXBH4Cm7HdtUzteK68OZT8nZzmx63gj8zyR0FZ89KsZmpnR+rPtiKZCNQBsrDiNTRW11OcysSOk8rVkfSUVicri2cYRgxTkuqgDDbW1JZckuMnjkvw8DY430LULCW00r4RsyYZDWLGtOsRkR8MoSXtWrPq0GkX52QCAHcfq8dePjum+X17gzXppaKDBEg0teGM3nvle0KGjMZByBuVsWxeeKzuMARyVuIVgHdTlEREKDyDafkE9uD8vE6dbOrDxQC11BE1+ZxoFcw0hzzBCZKeprQtLyw7jStcA2XckDmbJIKbUvQhLlFqNlzhwoDVEl5rwlBbIJR5IkDh1RDp+MzsXy7YcUQ1Mz7Z14a4V6gJUUt9/5PQ5Xj9JEkK7oicjK6yKANrWbHFBDtZ+/pXi37V2dGNTxWnMHT8YAFSzh+e7AyE7JndQq11HS6WPpk3FbKKfn5GDkELd7UjALI2OlZBuXc+AbX+0Hb3VVvy79yvxp+/TnctCf2Cmx41kmwV3vao+RF5Z24w0u9WQgX/WTgS5taWUJFipQ8/qijS6pHHGgAu+B8v6V9tf3qb20LyIuDVayh+k9fmCVY0jqrY22jCC9dLQQEONXkuIs21dYRkrpcoGjUHhze6SmmjB8rsmhrU10ICX0jE5gGACl+sNsMUjPs4U0SP8xC252HOikZrqVxz50m7w+/IyqTPRLJBySIRrqabOh9WfncBpAcWy2SRvaITX0nt4l1V6MXVEekysjxIsLTRrP/+K+rokO/5IwUhkZiTJVk43VdRiyfqDhrVg/mbWKFyeYgv7fj0ZWT3ZNfL3wZbQHBTl52BHVT0WrJZW4Bbus+QEi+pBea7jPOy2OFjizGE2R3hQq7Wn0Vb6xGeHWpVVjvteK7xN7dQZYjmUVXqx+JbRmvVk+qPtoA2qnXZr2LkjN19Hi9qmdiCgfC7LZYjrfHS2ZdnWo1i29WhIa0qJZh2I3AOThqVh1/FGSX+KdVZDvLa6/QHsqKrHo28f0N2qJAR5Zle5kun+QPBFtOtfas5W6rImBOdFPvrVDNnnSDA5y0ldiY629hkNjGC9NCzQ6PYH8PsP2Ad5f/d+Jfz+YC+gnIPRGwq2Z9u6YDaZNNEv8qR+23LoNJfrlcwdjTnjB0cEc93+AB56g87gSDk2tBu8MNeFMYMdVEOi5Ltof6vQIWlq61Q9qJUcDeG19B7er5bX4JosJwpzXTGxPhWwtNCw2gNyTSEjnTiA2VRRy0U0Ugm57pSwQVKaBApJeDS1dkXYSD3ZNQLhXjabTYqHJdkbr++gmyXwdXQD6EZxQQ4yM+wRBzWtDo9S8CQVnKYmWWC3xsEnaosyoqIKwTVpWkTl8O7er/F4D/scmUksP1qHZVvVtVOc9v4p5kcbVN9xzRU9uiXBqihJHv565ii8Vl6tKPArh81fnsaccW5ZogpChSv2H1i1axp8nXho9W48eDILC2dJa4VI7QGzKfycc9otPQHLIADB6soL8yaiaM1uxfPQaQ8nqdFD960EoW/R0EqXjBQGbbSCuGTOVu293JI12gAAJmxJREFUCyuN4iSHVFKct/izUSDP4U+3jzOUJtuwQINM0rOAvMyHVkce8HrmFHipumrNaPNSOgYuOKt6rycUNhTitXJ5dcvIa0Q6NrRl2EZfBzVLFU3WQQqvfFKFrV9+w8WZONPSjps8blVObTWQ6giLinh/A+uwPO85qMJcFx5754Dua6rhTA+BBTmg/IGA+hBhT8Jj1lg3bvRIM7wIrzlpWBpVBVSqUkQrCPfx4W+oPkewZucJlD92QwRDzKL36J65XPAk204rM6RrdIuNnkpJg+/C4DCx05OznHh790nVNfLkXE+/tB20QfUL/7qgyvz27pOhdR9nNuHHeVlYsa2auWPgrS9OavMxNL6mv35cjXFDUiMY8uTagMVrscHXhYdW70H+rq8wf3o2Jmc5MWusG8swQbH61+C7QFKjRRuMFq4eBjZHohXlR+nsi/D9qyV4A0BINyjObKIWdiZdCQRSQZ0jIT6qs7RaIfQ1aJnTtMKwQIN3j2jYnAJlPyRBydzRqKlvxYpPjkVktVigJ6MtzEx5m9tR8sFBTaw5QLignZB96/OaBqwsr0azgk6FWracdvDqO7mX48W7r5Yc1F88O1cyWBSiZMMh1YFHOXavupYOqqzTli/ZHCAlXJ6cgF3HG3UFGcCF6ohc8BkT61OvUIhbaHjPQdkt8YYdoEKIbQCtujCxreJEgRLtspLwVXFBsFVKuJe7/QFqxXNWm+pt7sCyLUdDe7qs0kvVaqRku/oi7TcAfGvkZfiIMRAjkKJiVmsDe3B6VihL3d+gpU1ZXCEVOqgsoAkypOaL6ihFbqXwq7f34/cfHApL6Cq1AUthy7/rsOXfdWHUyvfnZeLdvV+r+ie8beTi2aNChAqNvs6Iiq0c5OyCWoJ36eYjeG17DZ65bQz1GUIqjUptrk0K/ldfQjR9DcMCjZo6H/drhuYUevohaTPcJxra8OfNR3QdQjzo5YhjsL2qXnOQAYQ7WULWpOdVfiNNtnyYk27w6tos+VkVNYEuIPgb/rz5CO645go8V3aEKrMvpK5bsa06Ku1zxIhNGpaGP3MQNAPCmUdoVcT7E2iTFKfOtmF7VT28ze1w2i269hRwwb68veekruvQQny/tOxSUoeiUquZ3CBjkKEtMyLIAILBHs38lN0W19MSxYbnyg5j1afVzM6KnO3qjXZaGgx1atcWEr9nIvAphXS7FSUUvfuXMrS0KUtVSImD+vi7B3TbFCGk5ov0JEl8Hd0Re09rFS3YSRIewCYnxOO2CYPx/v5a7rOUUshItmHu+MHYVFGLBavp5tTUfJqZHjf8/oBscH62tQs/fX03lt0xHskJ8YpiwsCFSuPkLGefTGzIwYQgi+h//2A86s4Z1yIlB0MCjW5/AGt2KguW6EGdryNkUGhe9KpPq3UviDnj3IovhUVgike1RyxuRbPoB6bYsGTO6IgIVnjvIy9PjujnFMNsAkYOTA6Jcol/K+3vI/3GRDlUbkhUDC1CQ1pAftGcce4IfQA9EJd4+yMNpRJoD99f/mOf7gqTFIwS+NILucwdTasZGWR88V9VWFVejbNtXT0MfUHWE/Feo93DIy9Pxp6vzmr6PaxBxiMFI2Wzb32RZclsAv62g/0clHrPaiQB/T3IIGCljQWkSQZmetxo6/KH2oR4QbxOeZHFGIGW9vP4H52CoSy4PDmBuTKplpUPzgqrdz/8fO1e6u8k+iB6/QGn3YJGH714oFYQP2bJnNHIyza2RUoOhgQaRorlAcEFOXVEOl68eyIee+cAlVCOXqzfV4tfzxwlGTywCkzxaPUQXmPHMToxsf/+wfiIhSZ172pqqgmWONyzcmfon8W/VUgzR4OmnvdTrMICJASr0JAWuARtJzyMQWzImw60h68RQQYAXD0sDf+sPG3MxXVAbqCUttXsxX9VSYpSSg3Y09oorUGGFmRmyFdb+yLLkp4ZDeF7VnO+TAiSpyTb4vFZTT3EQ879DSy0sUKIg4AT9fy7MsTrlDdZzMUKV4otJPRH48sUzchGXnaGqp9AOyvM8twvT07QndgYYIvD3HGDsOpTPoEc8S1+cPUQ/M+nx8Oq40rBGEuCXA8MCTSMzC4JW5i0GhQtkKNV1CIwNTnLqbnVg5TA/IEA1u39GjV1PqzcJs10IYa4H1Tu3tt6ggzx4DP5Z3EQIvytALBk/UGm30Syrms/P4Ftj+ZTL3QWoSEaJFnNeOU/rgmVFicNS8O3/riVm/GXcxRjCIfWPmleGOVK0dwSJIYJgF0DGYVUsE8qf2LQ2tuXP66iHrCnoSZXq3zyBsl4Sh2MfSkzrOe5mE3A/Ouzws4M2kDynlUXkj/Lth4NKbb3x3kvWtpYIZyJ1hCRQsYAG1Z/xjebL9d+zZMs5mLFkjmjEWc2wdvURvX5pja6Vi6evqgwUbizukHXtc51dIeCDClGMBbfkASoTW1deH7zBVY6NfFi1gS5HhgSaBiZXZrVw7RCDhgtBkUrxJExKzsOQZzZhFvHD2Z2ksmCaj/vx10r2IMr4XuhuffLB1jxwPUj8FVjK65IS8KKT46F6U+IP7/wnQNhAncs0MKRn2G3wZWSgNPNfJwLa3xcWBZQjddfCKfdCr/fj7Nt8g6l3RaHti5/iBowFnDIw6g+aRo0tHXijquv0B3EkrcbH8f+nqUqik2tXZLJC1p7qzS0Ldx/k7OcKNmgTk0ezSDDlWJDo68T057dInsw9mZmOCUhHrdPGoLBqYma6FEJAgHg5Y+rMWFoWugda3WWSP/5S4xq6pcCtPggD7+119BZBKUkk3her6bOh5c+qkJbV99nL9IDEgwX5rqwvaqemsHubztO4G87Tqg6xrx8UfEsCKvIoRJIMve+vEwU5rpCCU7qpEmPwROfGUrixVoS5Hpg5nYlASZnOeFKYWufocWr5TW485UdmPbsFmyqqI1qybxBVBFgYccRoyCXXTnWITHLQAMTIrMpNPd+uqUTnsEOPHHLaJhNkAwyhJ/XGmQIocaRP+3ZLbjzlR14eO1e3PXqZ2g/3x0KdIQw9fzfg9Oz4HbQK3UK3xXtAV80YwT+cscExSADCA7vFb+5N2z9xiCPmR43Ft88Ourfe3lygqb9KYbLkYBHCkZyY2chh8Lv3q9Et8DLJ4eeXDhD9gINePUf88bc8YOwYPXuiPsiB+OmitpQcOoS7ffUJEtENchpp2P4okFakgVfLCrEb28ZTU2TKQepd6z3jBOvl/4AtT0hBaOCDLstTjXYCxeVbcXSsiOyQUZqYjxSkyxamXG5gXy/XKVVDWlJ8dj5eAEAhM71dymZ7gjI/t+4vxbbq+qxbu/X2F5VH1rvQV9Uv4/ociSEOd+k6s4DxH/5sMKLyVlOWOPNoWtL+TVAkCnw/rzM4N/LbG2580ItySz1N3phSEUjzmzCnZOHGqp6SBbY8nkTVUvm1jgTOrv1P7QGX2fYADStIyr1ORpBGSFLQIbdhl/8fR8AbU6LOJtCe++llV7851t7o+Z4iKsuwgyP1Hoi8x0OEad3kIc7F2l2K65ypeCjw99Q0XWWH/0m1JZBO2tiiYtjrqwZlTm41MDjkGBBatIFsTPWVhwTgpWtRbNHweVIxOQsJz7Yz3ZwqkGq8qfU582a3efRf2wE3vziJFXlWI7JDUCEUvLEklIu+ko/uHoIrPHBnB0vqmXhO9bbFkZTKb7U0Nvtl0KotWBKtbAoIdEaj8WzR2HB6j1Rrd6J2zlJ739hrgs7qurx0Bu7mKhdG1vPy86N0YL8nVhoUFjpWDJHH3HM4tmj8OO8rIhq1EyPGy9RzgmrQbzn1ejvC3NdmPRkKfN1AfoE+Y5j9dyGxw2jt83MsBt1aQAXDpiSDZWq3OJyQYbbkYA7rhmKrm4/leLqcoHQD/lbGtTURWpTqDkHQDhLAKHxZIVcny7tgbjSwGFrKTT2OOy0xpesg4R4M9544NrQfEWjr4Oah1uIZVsvvGNXig2pSRY0tSozQywtO4xHCkYyfY9Sa10MFxDt3vt7r7twoLC04pC394dbPbqUuWkhDgaUDqabPC6qfUyCLL39x0ZA6SAXH6ZyTG5izRHaIEONHENIFNLo6+Dm/An1UvS2hfXF4NFoXGCgOmgoOY0alOy8GpuYFGqb2pFmt/W0llZEhXoWCLbmOO0W3Dp+MApyXWHtv2azSZN+xKpyPkQr4uS7OJH3wryJWLBmNzOBSLrdKhlkEJDExl82H1GVF6CBcJ8q0d8/X3aYKbgRCg3S2oIFb+zGM9/jM+NlSOsUQH/ADrDF4eEbsgGwi2SSA8aRZNVUvls8exQeLshBceFI6vYaAm9TO5aWHaYqYS4tOxxqk+n2B0IlPkeiFcvnTYgo9YvLdN3+AMqP1jHdH8HyO6Uz5jSl5d5wfUs2HMLG/afws9cj2yTkEEBQBMxsMmHu+MFoauvEgtV7dFdhvM0dOKsSZJDvX/v5CbhSbEzPTKm1LoYghCVqo9djapIFRfnZoX+Wa8VJk2jFEe9ZAi0tHDSQsq8zPW5sezQfa+ZPwfN3jMea+VNCwp40IEFWo68DSnGvCdrbJYRwJPLNc9EeoKR1gBZqdMdkD2+qqMVDEqrMWiF8x3JrUcu1+hNmetwof+wGFDMmgnhCzs7rEZk809IebC2dPYrLPdKi0deFleU1aGrr1NQhIQatdhArxC1As8a6sfzOCczXKZnrUU0CxplNeKRwJJbPY7++GFKsZFNHpGPu+MGhJEq3P4BVjAngd/d+zdyKebatK9SWqheGVTRomZXOdXRjyvAMjHKnRGTjUhMtVAtxe1W9prmFkg2HcKNIDZR205OMNG2G6XfvV8LvR0SW3S1o8ZGiGGMtqwp/n8uRgCky5XKaLFlvdPXWNrVj0boKzcbXCIVgmndc29SO4oIcLJUQH1RDf8w2siBarCzP3DZGsjxO04ojN9zPs61JiEaZVj2pbD6ZmVPK6pIgKyiWpe4s33tdFp4rO8x622F44a5JMJtM+LCiFv/Lga+f9gBlmUGhPYO8ze149kPtQ+BSEL9j8VrMGGDDf765B6dblDPaPMRmL2bEmU14uCAHV7oG9Cqzk9jO65mFImvd5dAuCKkFcpV41kDWBMBBube0QlzpnDV2EF4ym6jXwIPTs5i0aW70uFFccA6ryms0/S7afbqzuoH5+kRoUEsrJo+uC8MqGoRZiQYkOhdn45bfNZHy29iPa3GWgTgzLJUNMgB9+0Tl30m+6yGZYcYFq3ejqa0zImp9vuwIfsqQ2SdQU8skIL/ZwSE7yRNaWYaOnD6H18r5K4bTrq6mti5NWcf+mm1kgdA+FM3IVv8DCcgNL7odCYrDmlJZJal/p3TvUutCz75btK4C7+4JH3wUg1RPn9pQiRaVNqFnbhsDAKpButkELJ83EUX52borNWdaOjB1RDpu4lCaT020wB8IUA0wsgT29/YMXKqh4VwH9/ac339wYSCTvEsy83Pz2EHIy87A7+Z6VK8To9QOgocN0QOxndeSYBITuxCnMZqQqtCwVG7JZ2j3ll6I25GEfmZxwciIOUCn3YIX5k3Awln0w94b95/CNX8oxXNlR0JBQJI1jvrvTaDfp6WVXurrCvHPg8HKBMsgO6+uC8OUwXdWNyCR8kGTDSjOxnX7A0gVDfkKQbL2U4dnhPXWs0CpJ+7I6XNUsxtJNu2PUSpDsKmiVldfKY1appAiNiE+DlqHzPsSaN4VQdGMbOQMHED9jmmwbu8p/GZ2bmgNeZvaULLhEBp9nbID/zEBP3oQ+0B7QIuz0cJBumiIFAkRkY3WSe7Q4OsKqRZLUTwGbYi6OrJwhouGztkfANLsVi5zA4TFj4YYw9EzKwWZ7zrb1oW7VnxGxQNPG9gXF+SgKD8Haz//SvHeXI4EOO1WqmsSpNutqFfprfc2d2DZlqOSmXjh75QbSE1LsuDpfqqjIQdWG8IDcnZeSxUACHdItXRj8ILwGbLYg4EpNvz25lw4Eq3UFUM9kGtHIijKz9Z1Hjy9sRJ//ThSy0yt5ZKAZZ9uqqjVPDf72vbjuCbTiVljB4WSX4+9fYDq+evdL9wDDZZWHzVHq7TSqzoE+MQtuZgyIl2zAF5dSwe6/YFQFUG44JxJVizbqn6NgE6JYmHU2NTWyWw0yGA6jaq21lYsVhTNGIGcgcnIsNvw87V7ojawRgtLnBlzxw/G9qp6boFGva8zVJ4khizRGqc48B/LNoaDRqmU9oBePm8izGaT5LV6g4FHeMBpJXeQgnDwsTDXhWVbjlK3NSVa4kIzHKwsenpb2ohzTkOMIay4KH0XDZsbTeuA25GAovwcqnt74pag00SLxbNH4WRjK5UqsNx7FP9Owvyz/Vgd+rsyOA2iVUVWsvOsLSxyCcSQ08iB/YgF4mcoZw/EgnTt5/14/L0Kw++VNpFHdDHIuSPUaVPDxv21kkEGLaYOT8PrD0yl+i7W2TIxAgHgodV78JLZhJkeN5Pgtd79wjXQYGFQUHO0aB5qapIlVAV4cq5HkXlKDiUbDmHFtmrMGefG+n21ERtEDWZTUDyGB7zN7fivTV8yBRlFM0aguPBKqoWqheFCK/KyLws5Vd8dPyjq7FVqIEI2hbkubsI7ABsbkBEKnBczaJVK1cSShPNJcvuCJqAxEjwzqkLBzCfWVaj27Ash7GGmPUzEQ8p+f0CT7RX2l9PuE+JQL1i9WzITR8PmRhs8kL+lubduf0B1DgYIrme3I0GXqJ/c78zLyUBeDh86yksd0WKzU7LzNPNbxQU5yMywq9ooEmwu23IkYkbAlWJD+3k/d8e+USJ5KKzcllZ6sbK8JoIRKlrBEElEq9l1pXNHaT7P29SG364/qOsetx9rRNHq3RhxmR1Th2conlm89I2ENmPKiHTVajKPrgtugQbrEK6ao0XzUInAGhn0efDkWU3RZW1Tu+Tf0eiV8NRBajjXwbyQ8rIvCy3MzvN+/G17DY43tGKYMwn3TM0M8bvzHJIWZyiEkFqYhbl09JpS1zLyECAb7olb9PFsC3F5ckKEE1uY65Jt1+lth7evgEWpNM5sgmdwiuJeER4w4mfc6OuUJGUwIvDr9gckM828M6pkXkwLSNBD08Ik3tvd/oAmp9lujYs4vJToHAnizCaYzSbFcr8Ud7wYrAkAtXuLM5vw25tzVQOuxbNzqVTXaUDzO2O4ALEdIFoURkFOf0EInomo4ND7SBTl54T9Tn8ggLtWqGetWVGyoRI3eiKDeVIhIK2dLLDb4lR1R2hxX16m6vNTOnd++vruiNb9VI2iyUr4sCI4c7Fsa5WsHAHALzklpgJnSbpoBbdAgzbaKpqRjbzsDFWHSosY3sJZuUi0xGPpZuOEAo2Alj5f8aH/9MZKvPJJdVgA8IeNhzD/+iwsnJXLVe33/mlZWPFJMDCjWZiThqUxtbal261YMmc0ntp4yLAWL+EhHeTZnoCiNXs0B47kfTT6OjDt2S1UTixtBv9Sh5pSqThz+/TGSpRWnpG93qRhqeg478f2qnrJoEIKRggobqqojWhnWLb1KFKTLHjqu2Oiqg+ihAy7Ddur6nGmpR13XHMFnpNgTpPb25rtiozpl9PAEEKPUKoQNIEN7b1tqqhVDLjs1jj8ZPoIOBIt3G1ajLVOHXK29ifTsyI6GfSCnAVqQQYQtH2ORCt+feOVaPB1wjnABleKvoSTeJ2u2/u1puuoQSnIXbbliKbWUJogg2a+CYAqrTeNQrY4oDC6GnO2tQs/fX23JDkJz+SUeDZZSm9mYIoNS+aM5nIecgs0aI1dzsABVNkXLWV8AMi6zFihQL3g1edL/oY4XnIVGfLvuzgooxN8sL8Wy+dNQMmGQ6pZGGLgWeZn6n2dWPxeBX583TBck5mOOl8Haup8WLPzBHdmF29zO7ZX1aPLH0DRjGz8eYu2eY0AAM/gFElqUHEP/c7qBpRVevGqRJWnPyqG0yqV/uz1XZg4NFW1avnF8bP44vhepnsQBjT5Vw3EruONuqpMmypqZatkZ1u78NDq3XhwehZe/rg6quq+YqQmWfCLv+8LcwqksnZyGVatTq6vozvUC81a0dNyNshVDmkCGykIr1dT58NzZcrJLV9nN54rO4zURP4Mf8I5wxgioZS1fvnjaiyfNxFpditKK714b+8p1XlCpf3KkgVWSjTJVWO12CIj51Gk9v+milrV/aAHT8zOxZINB2V9Ctp2H57JV95Ysv5gROsnz3Y/8Zrw+6WErfnZE26BhtbAQAjhpqr+xqfYogNcULLVch+9geKCkVj7+YkI53zx7GCQ4W1up8r8C7Penef9eOUTZcfr5U+qmRUxlUCUSbc9mq9oBPXMhJxt68LSzUeRmnQcz9w2JqIkTFh7Tjfr23QlH8gbLFbIZdmJE/vYOwdUmYBoeswvNdA6q/+sPI1/Vp427D5IQDPl6bKwNcFaZer2B7CEonf377u+xo+uG4b1+2p7jSwhGEyEr3/C7lRcMFKVYEKPvS2t9OI/39rLXNFjbfGScuhSEy24Ny8zNPDNAj2EGkYw7JA5w/5WCaUBTda6ZEMltj2aj6kj0vGb2bmiNsuOiISayQTZ85S25YmmVRSIJD/QUvE2ch5FvP/1DizTYMkG+cQlS6DXlyuB3uaOiGoRD6Y/qSBMLlHtbeaX9OQWaNAyechFmVqM99nWLpRWeiUHRftCSwIBeblF+dkoys/GjmP12F5VDyCYhfr9B/RUtnZbHBbPHhX6zX/bHjlsJQbPIIPgTEu7YjaQZibEabfC7+/G2Tb5cunZ1q6wxS78viVzlAfpUnsoMZXugVeQoYYApJ06uc/2p97rvpYcEK+J2p5+XSWtDSF2VjdQ7ecGXyde62EectotmDtuMNbt+zpqa1IOJNhd+/kJbHs0X/HA1mNvpea2aCp65MCVqxgJh0DlHLqzbV14ruwIVn1aI9sTLYVoEmqwoD9WQmlAk7UW96yLbe6NHndYFVrpvKVhoKRpFV34zgHJmSst75mHgyqG0GEVJojrWtjnTFmhlJRhmW2Jxrkz//osvL/vlKZODKlASC/DmHhAfuP+U4odAgH0McE+oQiI3O20dXVLio0Q461FmI5IzLPcR2+AvNzSSi9++fd9WLb1KJZtrcLzm48yLcLWjm4sWL0nJAt/vKHVqFtWhNompTHwDb5OxSCDgCx2sRiXnBCa027FC/MmhigxxeugL60LJfTljAtPsIg99SYee+cAd0E4gkZfF177tAbfnzSE+Tm4HQkRIoR6wSLUdMc1Q5mdF7nfSK4jtd9ZQZPsIIkMYk/1Xq+3wPO5XUqgnRNQ+hwZbt5YoS6Udrq5Q3U90bSKyhE7aH3PcmelnoL5E7fkorTSi2nPbsGdr+zAw2v36mZT04N0uxUf/WoGdQBm5LmT3uOD/GZ2LpbMGQ0T2P0OOR+rMNeFhHhtrntxQU7o+XT7A1i0rkL1b3gI9nFVBldTmm6SMOp6jLfcYUjuY2BK38iUkuehNaASQmxohjmTONwhG5z2yJY1MXg7yXKLfabHjcWzR8Fpv7Dm6nsGgAHIBiIXA/papt8o9NXkgBhnW7uwjGKGR8t7I/t6/b5aPHB9JvVzWDx7FLY9mo8fXj2E+TtpoLSPN1XUYtqzW6g1O4RQsvdqQY5aewZJQO2gECAk30fjuPXlnm6An4rvpQQiCqn3c7TvniYQ0Hs2an3PYlXsNfOn4MuSm3qU0kdQXyc10RJq7dLrz4ihx/7X+zqx63gj9ed5nztOuwXP/TD4XHf+pgCzxgYderkgTwmuFJusj0VbMZdCZsaFGead1Q3U1XO9a5ZroAEoR1tSm5CH8ZYrMf3398fpuq4S3I4EPDg9C26KxUMCrMfeOcAlGyY0NPdMzdSVldCCJ+d6uA1sskBu8GzB6j0RG4aUmAFEGNdFs0dxvzeeMEG5zfBShBZj3BtY9Wm1qkM6OcsJV4qN+dpkX7/ySQ21nchItqG00ouXdYhGKUFuH6slTYoLcvDCvAlU9lEOcocbLXlAkFKYDjSO28VSYbxY7jMaoE0qqX2O5ZmqBQK8zkYt75m0hs0dPxhTR6TDGm/G1BHpKC68MixZp4TldwVJTYyo7um9Husz4XnuPHXrGNw6YXCoBU/8PcQPuS8vU/VaS+aMlvWx9Oxv4dpjuU6fEuwD1KMtcf85D6Mo9xDqfHRRnyPRguY2+V7+1CQL/nLHBJhNJtT5OsKGI389c1TPb26XHSyWo0rTizMt7bDGmzH/+izFPrskaxzaOru5GIUHp2dh1thBqp+jHdgMBALU0XlNnS/sn1loUYV9t8H5mL4JntzVFxuEdKNvfX4C7+49FbXvpqVMFGr3yCHObMKSOaO5abMoIWOADb/8+z6mvU0zw6TE3KJWhQ7Od3yFbY/mh/rbvU1tKNlwiGnoXc6u058ZbPtH7boXS4XxYrnPaEAoCqnnc1qeqdx6UhMcpQXP90wreux2JGDK8HTu1T0Tgp0fen0kLc9ETHOdMcCGX7y1l6lqIGxJkgMJ8qaOSMfkLKfknIWSjgaBlt8oZc9pr5Nut+pOenKvaLBynOvZLGqZX9pr35eXFbqe+PomAM/cNgbXj7wMeTkZoUyAUKhp6oh0uFISoj7ESX7fwlm5eHB6VkRlw2wKBgb/3w+ClR2WY1d8LdJzuHBWLtXfK5Ulhc70kjmjqe9pzc4TYdlk2symOLOk1ptpAqizOzRwpdiQmmShev4uR0K/Hugk++nZ28cZVqlLTbTghXkTwqpc2xfeQE09SmPjZnrceOnuidxnJwiI7UMAzAe+y5GAl+5Wn2GSC3ZZ9l3IPjoSqYMMXnZ9ao/qLS3UrmtETzfPNs7+WAlVA3lnSqB5Zlrevdx6Ep6NWmDUe541dhAenJ6l+L3EJvCsmpFneu918t9NAz0OsbDSk5edEZqroIHbkYCi/Bym75vpcWPXokK88cC1KJqRjaIZI/DG/ddi16JC1bOfdS3K2XOavQEAJRQdLGrgXtFgpbnVylpCk/mlzaoX5WfjStcAXeqc0SxXS0WnC2fl4hffuUpWGVxKfdTdQ62bZrfC29QWJhg0aViabi0BWtXTl+6eiF/+fR/OqYj1iCnftAp30ahhPjnXg5INhzSzl6UlWfDbW0aHxJdKK72KDFn35WWiMNfVb5XBxaCp1GnF8rsmIi87I+Lf35uXScX/TmvjSKZs5bZj+MPGL5nvUw1P3JJLXbUtmpGNnIEDIvayFlViLfuO1T7ysOtThqcrslOJP6/mpNDYjUd6KIEzBtjw0Bu70NR2XvE7/+u2sbhn1U7F7xWCVKEg8/39sRKqBOE7k1srNM9MeB010KynmR437s/LlNRSUrs2YNx7XjgrF+OGpGHRuoqwxICYVpdnNcVpt+IPt3pQmOvC2s9PaD5z544fxO2ZyPkuQuh9F3FmE/KyMyTPIrW/Y2ERk7PnansDIB0sfUiwj4CV41wr9RpNEMAir86qEisGz40nvFe1+xbCGm/G/dcPl7ymlt/Hg1qV5ntnetxo6/Kj+M29qtcTOix6tFtogiCz2aSZEvBpUfmTNuiK4QJI9UyseC+EWGtHSXtH6IBKoSg/B6s+rZEt39M6pELEmU24b9pwrCyv4Ua5nd5zMM/0uKnbAPOyMyT3sxa7oGXf0f6N027BU7cqtw6w2vWXFOggWZ0Fln387PfGSgY5wu9saGPTTyFVqJgdoYfcO2PVpODtfBbkupgDjWi851lj3bjRo2wTeMoILBLQ9dMGc1JQUwJnhdA2Sok59uaeU1rTi2ePQprdRmXP5a7jtFvw5FwPVZs8DUwBCuLn5uZmOBwONDU1ISUlRfWiZFAQkD4EpFpDpHQ0XCk23Dl5KDIz7Miw2wATUHeugzkIUFLg5LVIuv0BTHt2i2KAlZpkQWNrl6rjSu4N4CPYczFge1U97nxlh+rn1syfEnKYaJ65y5GgqAWgprwqt3bmjHPjzS9OMvdY8lB6Zd2PfQVa77vzvD9UqbsiLQlXDUxGQ1snLk+OrLw1+jqxYDWb7RFCTieB9u/Vriu+L4LUJAue+u4YlGyoVDy8nXYLdiwsCFUqeewBVmj5TrW/AYIB1PaFN4R+mxpY7Hq3P4BlW45iVXl1mGieVntKu4/V7pHW7g2wxeNP3x8bRk2px470NxsC8LG9wutIOZ8s64l2H/3p9nERs6F9AWo2jRbCM51cd8l6em0xIPjcedo4KfBaP33xnrReh3Y/GhJoANqceyNfZDQWCU2ABUgHD3dcM1RShbcvLm4joNVh0hLUark3qXfQ7Q+EiS9OHZ6BKRKME7zRH50EFuhNLBiVmJBUqE6y4N7rslCUnx0mMAewJWmM3gNSv6Uv3CerfewNe6r0nTQB2ABbHHYv/g51AEaDmA3hA73rqTf2Lk9I2bS0JItAoFYeSkkQkhhQo86+WJ7TpYpeDzSA/uMkC0HjpPTH50IDrUY3GhWrvoS+dtjSIpr3rXePGbVHaa6rZT33xh64WO6zr0MtM0yrSM+CmA3pO7jY94SUTQMQqvqsLK+RbXGkqTArtapdTM/pUkSfCDT6K2KBhHZoNbr96ZlfrPvxYr3v3oCW9dzXsvV96T77OqLtbF6se/FivW81XMp7Qu/aFj6bjAE2IIA+2UrWHxELNGK4aHEpG10euFj348V63zHEEA1E0+5drHvxYr3v/o7YmX5pgnY/cmediiEGvSCc1jHEEEMM/QUxuxfDpYrY2u7f4C7YF0MMMcQQQwwxxBBDDDHEEAs0YoghhhhiiCGGGGKIIQbuoGqdImMczc3Nht5MDDHEoA6yDynGq/oUYnYkhhj6BmI2JIYYYtALWjtCFWi0tLQAAK644gqdtxVDDDHwQktLCxwOR2/fBjVidiSGGPoWYjYkhhhi0As1O0LFOuX3+3Hq1CkkJyfDZIoxBcQQQ28iEAigpaUFgwYNgtl88XQ/xuxIDDH0DcRsSAwxxKAXtHaEKtCIIYYYYoghhhhiiCGGGGJgwcWTyoghhhhiiCGGGGKIIYYYLhrEAo0YYoghhhhiiCGGGGKIgTtigUYMMcQQQwwxxBBDDDHEwB2xQCOGGGKIIYYYYoghhhhi4I5YoBFDDDHEEEMMMcQQQwwxcEcs0IghhhhiiCGGGGKIIYYYuCMWaMQQQwwxxBBDDDHEEEMM3PH/A+bS5Y1QB4VAAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "generator = TSPGenerator(num_loc=1000)\n", + "env.generator = generator\n", + "\n", + "fig, axs = plt.subplots(1, 3, figsize=(10, 3))\n", + "td = env.generator(3) # generate 3 instances\n", + "for i in range(3):\n", + " axs[i].scatter(td[\"locs\"][i][:, 0], td[\"locs\"][i][:, 1])\n", + " axs[i].set_xticks([]); axs[i].set_yticks([])\n", + "fig.suptitle(\"TSP with 1000 locations, uniform distribution\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Changing distribution of the data to normal distribution. We can pass the arguments to it by using `loc_` + distribution name as well as its keyword arguments, including here the `mean` and `std` of the normal distribution" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0.98, 'TSP with 100 locations, normal distribution')" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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xz/+Ebt377b0epdccgk2btyITZs2xR77/PPP281cpiLyOxQWFgKQd33qZYB1v/nNbwC07UUDtJXg7tq1a0JFO6CtvHIyM8emwm9PRM7ihn1ELnj22Wfx/PPP47LLLsOgQYOQk5OD999/H0899RTy8vJw5513SnsvPYjYvn17wkZ1o0aNwt/+9jfk5uYm7DeRSn5+PsrLy/HSSy/hjDPOQElJCSoqKlBRUWH7+D7++ONYmV89MLj33nsBtI1gfvvb344dw9y5czFz5kxceeWV+NrXvoZ169bhueeew3333YeSkpLYa86YMQOLFi3CxIkTcfvttyM7OxsPPfQQunfvjh//+Memj/EnP/kJXnzxRUyYMAE//OEPUVJSgt///vfYtWsXXn755Vja2Xe+8x0888wzuO2227Bp0yaMHDkSTU1NWLVqFWbMmIEpU6Zg4sSJeOihhzB+/HhcffXV2Lt3Lx599FGcdtpp2Lp1a8L7Dho0CKtWrYptytinTx98+ctfbnd83bp1w09/+lPMmTMH48ePx+TJk7F9+3Y89thjuPDCC1NuGpnJxRdfjNLSUgwfPhzdu3fH+++/j4ULF2LixIkJM0KRSASjR4/G3//+d9PvkYrod+2kSZMm4ec//zmuvfZaDBs2DO+++y6ef/75jGuijPznf/4nnn32WYwfPx633HILCgsL8eSTT6JXr17tfvNkIr/DoEGDAAB33XUXpk2bhuzsbHz961+PdfLN2rVrFyZPnozx48ejsrISzz33HK6++uqEdVzf//738cADD+D73/8+LrjgAqxduzblZptmjk2F356IHOZJrSuiAEpXqnXr1q3aHXfcoZ1//vlaSUmJdtJJJ2llZWXalVdeqW3evDnhuXp5WztOPvlkDYD22WefxR5bv369BkAbOXJku+cnl7fVNE174403tEGDBmk5OTkJJSyNjk8vlZmJXqoy1f/iy3zqnnzySa1///5aTk6O1q9fP23BggUJpWN1n376qTZ16lStqKhI69ChgzZp0iRtx44dGY9H09qX3dQ0TauurtamTp2qderUScvLy9MGDx6svfbaa+3+9vDhw9pdd92l9enTR8vOztZKS0u1qVOnatXV1bHnLF68WDv99NO13NxcbcCAAdqSJUtSfl8ffPCBNmrUKC0/P18DEDum5PK2uoULF2oDBgzQsrOzte7du2s3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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "generator = TSPGenerator(num_loc=100, loc_distribution=\"normal\", loc_mean=0, loc_std=1)\n", + "env.generator = generator\n", + "\n", + "fig, axs = plt.subplots(1, 3, figsize=(10, 3))\n", + "td = env.generator(3) # generate 3 instances\n", + "for i in range(3):\n", + " axs[i].scatter(td[\"locs\"][i][:, 0], td[\"locs\"][i][:, 1])\n", + " axs[i].set_xticks([]); axs[i].set_yticks([])\n", + "fig.suptitle(\"TSP with 100 locations, normal distribution\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can pass a custom `loc_sampler` to the generator (we can make it ourselves!) to generate data from a custom distribution. In this case we use the mixture of three exemplar distributions in batch-level, i.e. Uniform, Cluster, Mixed following the setting in Bi et al. 2022 (https://arxiv.org/abs/2210.07686)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5, 0.98, 'TSP with 200 locations, mixed distribution')" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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+9uov+vNsdhrGo1Nr0Zj7dq1GD9+PLKzs5GXl4fp06dHrXXgu+e9d+9eXH/99cjLy0Nubi5uuOEGtLa26j8EgiCkIzFcRAThIwYOHIjOzk688sor+OEPf2jpGqriqpcGlJeXh9LSUqxfvx4//vGPAQAbN25EIBBAY2MjqqqqcOaZZwIANmzYgPHjx2tep0+fPuF0rhkzZuCyyy4DAJx11lnh93R2duKiiy7C+eefj1/+8pcoLy/HE088gUGDBuG2227j/m319fUAgN69e4dfUxXPc889N+q9I0eORDAYxLZt23DttdciFAph586duPHGG+OuO2rUKPzlL3/BkSNH0KNHD+bxHDhwABdccAFaW1vx4x//GL169cLvfvc7TJs2DW+88UbYMOrs7MSll16Kv/71r5g5cyZuv/12HDlyBGvWrEFlZSUGDRoEAHjqqacwbdo0XHPNNWhvb8fKlStx5ZVX4r333kNZWRmArlS8//qv/8KoUaNwyy23AED481rMnz8fDz/8MCZPnozbbrsNn376KZYsWYIPP/wQmzZtiopSNTU1YerUqbjssstw1VVX4Y033sC9996LYcOG4eKLLwbQlT734x//GFdccQVuv/12HDt2DDt37sQHH3yAq6++mvneRbJ3715cffXV+NGPfoRrr70Wv/zlL/H9738fv/3tb3H//feHjchHH30UV111FT799FMEg9q+sBtuuAFvvfUW7rrrLkyZMgUnn3wyPv74Yzz88MO46aabcMkllwDoMh7Gjh2LAQMG4L777kN2djZef/11/OAHP8Cbb74Zfnb19fWYOHEijh8/Hn7f0qVLkZmZyfTb/vKXv+Dyyy9HSUkJHn30UTQ0NOCGG27ASSedZPrZW2+9FW+88Qbmzp2LkpISNDQ0YOPGjdi1axfOOeccPPDAA2hubsaXX36JRYsWAUBcA4YFCxYgLS0Nd999N9ra2gzTpZqamnDJJZfgqquuwqxZs/D666/jtttuQ1pamua6MYJlbJGUl5fj4osvxqmnnor58+fj6NGj+M1vfoOxY8di69atcYXzV111FYqLi/Hoo49i69ateP7559G3b18sXLiQa5wEQXiIQhCEcObMmaPoLa/6+nqlT58+CgBlyJAhyq233qosX75cOXToUNx7f/jDHyrZ2dnKN998o3zzzTfK3r17lUceeUQJBALKWWedZTqGfv36hf991113KRMmTFD69u2rLFmyRFEURWloaFACgYDy1FNPRX3nwIEDw//+5ptvFADKQw89pDk+AMr//M//RL1+9tlnKyNHjjQcnx6TJ09WcnJylKampqjfkpKSovn+Pn36KDNnzowaa+x4FEVRnn76aQWA8sknnxh+/8CBA5Uf/vCH4X/fcccdCgBlw4YN4deOHDmiFBcXK0VFRUpnZ6eiKIrywgsvKACUX/3qV3HXDIVC4f9ubW2N+lt7e7tSWlqqTJo0Ker17OzsqHGovPjiiwoApaamRlEURfn666+VtLQ05d///d/DY1EURVm8eLECQHnhhRfCr1144YUKAOXll18Ov9bW1qYUFBQol19+efi16dOnK2eeeabW7bHEwIEDFQDKP/7xj/Br//d//6cAUDIzM5V9+/aFX3/22WcVAMq6devCrz300ENx66murk7Jz89XpkyZorS1tSlnn322csoppyjNzc3h93zve99Thg0bphw7diz8WigUUi644AJl8ODB4dfUZ/zBBx+EX/v666+V3NzcqHutx4gRI5TCwsKoNfyXv/xFARC1lhRFiVtLubm5ypw5cwyvX1ZWFncdRVGUdevWKQCUU089NW5eqX+LvI/q83/iiSfCr7W1tSkjRoxQ+vbtq7S3tyuKEj/HjK6pN7aamhoFgPLiiy+GX1O/p6GhIfzajh07lGAwqFx33XXh19TnfeONN0Zdc8aMGUqvXr3ivosgCHmh1CmCcJl+/fphx44duPXWW9HU1ITf/va3uPrqq9G3b18sWLAgKq0JAFpaWtCnTx/06dMHp512Gu6//36MGTNGNzVDZfz48Thw4AA+/fRTAF2RiwkTJmD8+PHYsGEDgK4oh6IouhENVm699da477bS5emRRx5BeXk5HnvsMeTl5YVfNypqzcjIwNGjR8PvA6BZKK2mpKnvYeX999/HqFGjMG7cuPBr3bt3xy233ILa2lpUVVUBAN5880307t0b//3f/x13jci0n0gveVNTE5qbmzF+/Phwqgwv5eXlaG9vxx133BEVAbj55puRk5MTl+LVvXv3qJqftLQ0jBo1Kup55eXl4csvv8SHH35oaUxalJSUYMyYMeF/n3/++QCASZMm4ZRTTol73Wz+FBQU4Omnn8aaNWswfvx4bN++HS+88AJycnIAAI2NjVi7di2uuuoqHDlyBAcPHsTBgwfR0NCAiy66CHv27MFXX30FoOsZjx49GqNGjQpfv0+fPrjmmmtMf1ddXR22b9+OH/7wh8jNzQ2/PmXKFJSUlJh+Pi8vDx988AH2799v+l49fvjDHzJHX7p164Yf/ehH4X+npaXhRz/6Eb7++mt89NFHlsdghnqfrr/+euTn54dfP+usszBlypSodDcVLbnS0NCAw4cPOzZOgiDEQoYGQXhAYWEhlixZgrq6Onz66af49a9/jT59+uD//b//h2XLlkW9NyMjA2vWrMGaNWuwfv16fPHFF9i0aRNOPfVUw+9QjYcNGzagpaUF27Ztw/jx4zFhwoSwobFhw4Zwy1yrZGRkhOs4VHr27Immpiau67z22mt48MEHcdNNN8WlXGVmZqK9vV3zc8eOHQsrWer/a7X+VVvmsipkKvv27cMZZ5wR9/rQoUPDfwe60tnOOOMM06Ll9957D6NHj0ZGRgby8/PD6WnNzc1c44ocH4C4MaalpeHUU08N/13lpJNOijuTIvZ53XvvvejevTtGjRqFwYMHY86cOdi0aZOl8alEGhMAwkr5ySefrPk6y/yZOXMmysrKsGXLFtx888343ve+F/7b3r17oSgK5s2bFzbU1f899NBDAICvv/4aQNc9HDx4cNz1tZ57LOr9tfr5//3f/0VlZSVOPvlkjBo1CvPnz+c20ouLi5nf279/f2RnZ0e9dvrppwPQr/kSgd48BbrW0sGDB9HS0hL1euycURs+8MoWgiC8gwwNgvCQQCCA008/Hf/93/+N9evXIxgM4ve//33Ue1JSUjB58mRMnjwZ48ePZ8r7BroUiuLiYqxfvx4VFRVQFAVjxozB+PHj8cUXX2Dfvn3YsGEDLrjgAt1ceBZEdEBas2YNrrvuOpSVlcUVpgJdhllnZ2dYMVRpb29HQ0NDuPNWfn4+0tPTUVdXF3cN9TXRXbp42LBhA6ZNm4aMjAw888wzeP/997FmzRpcffXVcZEsp9B7XpHfP3ToUHz66adYuXIlxo0bhzfffBPjxo0LK+giv5dlPHo0NDTgn//8JwCgqqoqqnhb/e+77747bKjH/u+0007j/RnCueqqq/DZZ5/hN7/5Dfr374/HH38cZ555Jv785z8zX4PXeDZD73BEswYPorEzNwiCkAMyNAhCEk499VT07NlTU0m2ipomtWHDBowYMQI9evTA8OHDkZubi9WrV2Pr1q2YMGGC4TWcPpH5gw8+wIwZM3Duuefi9ddf14wIjBgxAgDCSqXKP//5T4RCofDfg8Eghg0bFvc+9XtOPfVUrkJwoKt4X00/i+STTz4J/x3oKtb+9NNP0dHRoXutN998ExkZGfi///s/3Hjjjbj44ovDLXxjYb3v6vfHjrG9vR01NTXhv/OSnZ2N//iP/8CLL76Izz//HGVlZfjFL36he5iiF8yZMwdHjhzBo48+io0bN0YdHKdG/FJTU8OGeuz/1LkwcOBA7NmzJ+76Ws89FvX+Wv080GVIz549G3/84x9RU1ODXr164Re/+EX47yLX4P79++MiB7t37waAcDG2GjmI7VoWGx3jGZvePAW61lLv3r3jIi0EQfgfMjQIwmU++OCDuI0eALZs2YKGhgamdAtWxo8fj9raWrz22mvhVKpgMIgLLrgAv/rVr9DR0WFan5GVlQUgXukQwa5du1BWVoaioiK89957up7ZSZMmIT8/H0uWLIl6fcmSJcjKygp3awKAK664Ah9++GGUsfHpp59i7dq1uPLKK7nHeMkll2DLli2oqKgIv9bS0oKlS5eiqKgonId/+eWX4+DBg1i8eHHcNVQPbEpKCgKBQJRnuLa2VvME8OzsbKZ7PnnyZKSlpeHXv/51lKd32bJlaG5ujro3rDQ0NET9Oy0tDSUlJVAUxdCQcpM33ngDr732Gh577DHcd999mDlzJh588MGw0ty3b1/827/9G5599llN4/2bb74J//cll1yCzZs3Y8uWLVF/j40ualFYWIgRI0bgd7/7XVT625o1a8L1O3p0dnbGpcz17dsX/fv3j0r/y87OtpxaF8vx48fx7LPPhv/d3t6OZ599Fn369MHIkSMBfNfhbP369VFjXbp0adz1WMcWeZ8i53VlZSX+8pe/hDuFEQSRWFB7W4JwmVdeeQW///3vMWPGDIwcORJpaWnYtWsXXnjhBWRkZOD+++8X9l2qEfHpp59GHVQ3YcIE/PnPf0Z6enrUeRNaZGZmoqSkBK+99hpOP/105Ofno7S0FKWlpbbGduTIEVx00UVoamrCPffcE1e0PGjQoHDxcGZmJhYsWIA5c+bgyiuvxEUXXYQNGzbg1VdfxS9+8Yuo4tLZs2fjueeeQ1lZGe6++26kpqbiV7/6Ffr164ef/OQn3OO87777sGLFClx88cX48Y9/jPz8fPzud79DTU0N3nzzzXDa2XXXXYeXX34Zd911F7Zs2YLx48ejpaUF5eXlmD17NqZPn46ysjL86le/wtSpU3H11Vfj66+/xtNPP43TTjsNO3fujPrekSNHory8PHwoY3FxcbhQOpI+ffrgZz/7GR5++GFMnToV06ZNw6effopnnnkG5513nuahkWb8+7//OwoKCjB27Fj069cPu3btwuLFi1FWVhYVEQoEArjwwgs1z2pwkq+//hq33XYbJk6ciLlz5wIAFi9ejHXr1uH666/Hxo0bEQwG8fTTT2PcuHEYNmwYbr75Zpx66qk4cOAAKioq8OWXX2LHjh0AgJ/+9Kd45ZVXMHXqVNx+++3h9rYDBw6Mey5aPProoygrK8O4ceNw4403orGxMXwOybfffqv7uSNHjuCkk07CFVdcgeHDh6N79+4oLy/Hhx9+iCeeeCL8vpEjR+K1117DXXfdhfPOOw/du3fH97//fUv3rn///li4cCFqa2tx+umn47XXXsP27duxdOnScBvkM888E6NHj8bPfvYzNDY2Ij8/HytXrsTx48fjrscztscffxwXX3wxxowZg5tuuinc3jY3NzfubB6CIBIEj7pdEURCY9TedufOnco999yjnHPOOUp+fr7SrVs3pbCwULnyyiuVrVu3Rr1XbW9rh759+yoAlAMHDoRf27hxowJAGT9+fNz7Y9vbKoqi/OMf/1BGjhyppKWlRbXn1BufVjvSWNT2l3r/02rtunTpUuWMM85Q0tLSlEGDBimLFi2Kah2r8sUXXyhXXHGFkpOTo3Tv3l259NJLlT179hiORyW2va2iKEp1dbVyxRVXKHl5eUpGRoYyatQo5b333ov7bGtrq/LAAw8oxcXFSmpqqlJQUKBcccUVSnV1dfg9y5YtUwYPHqykp6crQ4YMUV588UXN+/XJJ58oEyZMUDIzM6Puh17r0cWLFytDhgxRUlNTlX79+im33XZbVItgRelqb6rVtjb2mT/77LPKhAkTlF69einp6enKoEGDlHvuuSeqdeyRI0cUAOHWwkYMHDhQKSsri3sdQFxrV3VePP744+HXYu/PZZddpvTo0UOpra2N+uw777yjAFAWLlwYfq26ulq57rrrlIKCAiU1NVUZMGCAcumllypvvPFG1Gd37typXHjhhUpGRoYyYMAAZcGCBcqyZcuY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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "loc_sampler = Mix_Distribution(n_cluster=3)\n", + "generator = TSPGenerator(num_loc=200, loc_sampler=loc_sampler)\n", + "env.generator = generator\n", + "\n", + "fig, axs = plt.subplots(1, 3, figsize=(10, 3))\n", + "td = env.generator(3) # generate 3 instances\n", + "for i in range(3):\n", + " axs[i].scatter(td[\"locs\"][i][:, 0], td[\"locs\"][i][:, 1])\n", + " axs[i].set_xticks([]); axs[i].set_yticks([])\n", + "fig.suptitle(\"TSP with 200 locations, mixed distribution\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generating different distributions for MCP\n", + "\n", + "In here we visualize the different weight and size distributions for MCP by passing the distribution name, which is automatically parsed:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkQAAAHHCAYAAABeLEexAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA0d0lEQVR4nO3de1hVZf7//9cGZIMoIDacDIHK8XzILEMtM5nQrLQ0syFDM50p0NQytfGUZSY1aZhp9pkxnbQyR62cMg1NpkQ0Tce0TMuUkYBSAQ8jIKzvH/3Yv3Z4AAT2xvv5uK51Xa573Xut91oX6ot73Wsvm2VZlgAAAAzm4eoCAAAAXI1ABAAAjEcgAgAAxiMQAQAA4xGIAACA8QhEAADAeAQiAABgPAIRAAAwHoEIAAAYj0AEoEKioqI0ZMgQV5ehH374QTabTW+88Yajbdq0abLZbLVy/FtuuUW33HKLY/3TTz+VzWbTihUrauX4Q4YMUVRUVK0cCzAJgQgw3O7duzVgwABFRkbKx8dHTZo00R/+8AfNnTvX1aXVqKysLE2bNk07d+50dSnluHNtwOXKy9UFAHCdzZs3q0ePHmratKmGDx+u0NBQZWZmasuWLXr55Zc1cuRIR999+/bJw8M9f4eaNGmSJkyYUKnPZGVl6emnn1ZUVJQ6dOhQ4c+tW7euktVV3oVqe/3111VaWlrjNQCmIRABBpsxY4YCAgK0bds2BQYGOm3Lzc11Wrfb7bVYWeV4eXnJy6tm/zk7ffq06tevL29v7xo9zsXUq1fPpccHLlfu+esegFrx3XffqXXr1uXCkCQFBwc7rf92DpHNZjvv8sMPPzj6ffPNNxowYICCgoLk4+OjTp066f33369QfXl5eRoyZIgCAgIUGBiohIQE5eXllet3rjlE69evV7du3RQYGKgGDRqoefPmeuqppyT9Mu/n+uuvlyQNHTrUUXfZvKRbbrlFbdq00fbt23XzzTerfv36js/+dg5RmZKSEj311FMKDQ2Vn5+f7rrrLmVmZl7wGpb59T4vVtu55hCdOnVKjz/+uCIiImS329W8eXO9+OKLsizLqZ/NZlNSUpJWr16tNm3ayG63q3Xr1lq7dm25mgDTMEIEGCwyMlLp6en66quv1KZNm0p99h//+Ee5tkmTJik3N1cNGjSQJO3Zs0ddu3ZVkyZNNGHCBPn5+Wn58uXq16+f/vnPf+ruu+8+7/4ty1Lfvn312Wef6c9//rNatmypVatWKSEh4aK17dmzR3fccYfatWun6dOny26368CBA/r8888lSS1bttT06dM1ZcoUjRgxQjfddJMkqUuXLo59HD16VL1799agQYP0wAMPKCQk5ILHnDFjhmw2m8aPH6/c3FzNmTNHsbGx2rlzp3x9fS9ac5mK1PZrlmXprrvu0saNGzVs2DB16NBBH3/8scaNG6cjR45o9uzZTv0/++wzrVy5Uo8++qgaNmyolJQU9e/fX4cPH1bjxo0rXCdw2bEAGGvdunWWp6en5enpacXExFhPPvmk9fHHH1tFRUXl+kZGRloJCQnn3VdycrIlyVqyZImjrWfPnlbbtm2tM2fOONpKS0utLl26WM2aNbtgbatXr7YkWcnJyY62s2fPWjfddJMlyVq0aJGjferUqdav/zmbPXu2Jcn66aefzrv/bdu2ldtPme7du1uSrAULFpxzW/fu3R3rGzdutCRZTZo0sQoKChzty5cvtyRZL7/8sqPtfNfwt/u8UG0JCQlWZGSkY73sOj377LNO/QYMGGDZbDbrwIEDjjZJlre3t1Pbrl27LEnW3Llzyx0LMAm3zACD/eEPf1B6erruuusu7dq1S8nJyYqLi1OTJk0qfFtLkjZu3KiJEydq5MiRGjx4sCTp2LFj2rBhgwYOHKgTJ07o559/1s8//6yjR48qLi5O+/fv15EjR867zw8//FBeXl565JFHHG2enp5OE73Pp+wW4HvvvVflCch2u11Dhw6tcP8HH3xQDRs2dKwPGDBAYWFh+vDDD6t0/Ir68MMP5enpqVGjRjm1P/7447IsSx999JFTe2xsrK6++mrHert27eTv76/vv/++RusE3B2BCDDc9ddfr5UrV+r48ePaunWrJk6cqBMnTmjAgAHau3fvRT//3//+V/fdd5+6du2ql156ydF+4MABWZalyZMn63e/+53TMnXqVEnlJ27/2qFDhxQWFua4/VamefPmF62prJ6HH35YISEhGjRokJYvX16pcNSkSZNKTaBu1qyZ07rNZtM111zjNJ+qJhw6dEjh4eFOYUz65dZb2fZfa9q0abl9NGrUSMePH6+5IoE6gDlEACRJ3t7euv7663X99dfr97//vYYOHap3333XEV7OpaioSAMGDJDdbtfy5cudnvQqCx9PPPGE4uLizvn5a665pnpP4v/j6+urtLQ0bdy4Uf/617+0du1avfPOO7r11lu1bt06eXp6Vmgf1e18Xx5ZUlJSoZqqw/mOY/1mAjZgGgIRgHI6deokSfrxxx8v2G/UqFHauXOn0tLSyk06vuqqqyT98ph4bGxspWuIjIxUamqqTp486TRKtG/fvgp93sPDQz179lTPnj310ksv6bnnntNf/vIXbdy4UbGxsdX+zdb79+93WrcsSwcOHFC7du0cbY0aNTrnU3KHDh1yXC/p/MHpXCIjI/XJJ5/oxIkTTqNE33zzjWM7gIvjlhlgsI0bN55zZKBs3suFbk8tWrRIr732mubNm6cbbrih3Pbg4GDdcssteu21184ZrH766acL1nb77bfr7Nmzmj9/vqOtpKSkQt+gfezYsXJtZV9wWFhYKEny8/OTpHMGlKpYsmSJTpw44VhfsWKFfvzxR/Xu3dvRdvXVV2vLli0qKipytK1Zs6bc4/mVqe32229XSUmJXnnlFaf22bNny2azOR0fwPkxQgQYbOTIkTp9+rTuvvtutWjRQkVFRdq8ebPeeecdRUVFnXdS8c8//6xHH31UrVq1kt1u15tvvum0/e6775afn5/mzZunbt26qW3btho+fLiuuuoq5eTkKD09Xf/973+1a9eu89Z25513qmvXrpowYYJ++OEHtWrVSitXrlR+fv5Fz2v69OlKS0tTnz59FBkZqdzcXL366qu68sor1a1bN0m/hJPAwEAtWLBADRs2lJ+fnzp37qzo6OhKXMH/X1BQkLp166ahQ4cqJydHc+bM0TXXXKPhw4c7+jz88MNasWKFevXqpYEDB+q7777Tm2++6TTJubK13XnnnerRo4f+8pe/6IcfflD79u21bt06vffeexo9enS5fQM4D5c+4wbApT766CProYceslq0aGE1aNDA8vb2tq655hpr5MiRVk5OjlPfXz8yfvDgQUvSeZeDBw86Pvfdd99ZDz74oBUaGmrVq1fPatKkiXXHHXdYK1asuGh9R48etQYPHmz5+/tbAQEB1uDBg60vv/zyoo/dp6amWn379rXCw8Mtb29vKzw83Lr//vutb7/91mn/7733ntWqVSvLy8vLaZ/du3e3Wrdufc6azvfY/VtvvWVNnDjRCg4Otnx9fa0+ffpYhw4dKvf5v/71r1aTJk0su91ude3a1fri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ggoHooMHD9ZkHQAAAC5T4UAUGRlZk3UAAAC4TJW/mFGS9u7dq8OHD6uoqMip/a677rqkogAAAGpTlQLR999/r7vvvlu7d+92mldU9sJXXu4KAADqkio9dv/YY48pOjpaubm5ql+/vvbs2aO0tDR16tRJn376aTWXCAAAULOqNEKUnp6uDRs26IorrpCHh4c8PDzUrVs3zZw5U6NGjdKXX35Z3XUCAIAaFjXhXy479g/P93HZsaUqjhCVlJSoYcOGkqQrrrhCWVlZkn6ZeL1v377qqw4AAKAWVGmEqE2bNtq1a5eio6PVuXNnJScny9vbWwsXLtRVV11V3TUCAADUqCoFokmTJunUqVOSpOnTp+uOO+7QTTfdpMaNG+udd96p1gIBAABqWpUCUVxcnOPP11xzjb755hsdO3ZMjRo1cjxpBgAAUFdc0vcQSVJmZqYkKSIi4pKLAQAAcIUqTao+e/asJk+erICAAEVFRSkqKkoBAQGaNGmSiouLq7tGAACAGlWlEaKRI0dq5cqVSk5OVkxMjKRfHsWfNm2ajh49qvnz51drkQAAADWpSoFo2bJlevvtt9W7d29HW7t27RQREaH777+fQAQAAOqUKt0ys9vtioqKKtceHR0tb2/vS60JAACgVlUpECUlJemZZ55RYWGho62wsFAzZsxQUlJStRUHAABQGyp8y+yee+5xWv/kk0905ZVXqn379pKkXbt2qaioSD179qzeCgEAAGpYhQNRQECA03r//v2d1nnsHgAA1FUVDkSLFi2qyToAAABc5pK+mPGnn35yvMy1efPm+t3vflctRQEAANSmKk2qPnXqlB566CGFhYXp5ptv1s0336zw8HANGzZMp0+fru4aAQAAalSVAtHYsWO1adMmffDBB8rLy1NeXp7ee+89bdq0SY8//nh11wgAAFCjqnTL7J///KdWrFihW265xdF2++23y9fXVwMHDuSLGQEAQJ1SpRGi06dPKyQkpFx7cHAwt8wAAECdU6VAFBMTo6lTp+rMmTOOtv/97396+umnHe82AwAAqCuqdMtszpw56tWrV7kvZvTx8dHHH39crQUCAADUtCoForZt22r//v1aunSpvvnmG0nS/fffr/j4ePn6+lZrgQAAADWt0oGouLhYLVq00Jo1azR8+PCaqAkAAKBWVXoOUb169ZzmDgEAANR1VZpUnZiY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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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1aqVZs2apcmTJyshIUF2u728TwcAAFRAFfqWmSR99913CgkJUYMGDTRs2DClp6dLkvbt26ecnBz17NnTHNu4cWPVr19fKSkpkqSUlBQ1b95cQUFB5piYmBg5nU4dPHjwksfMzs6W0+l0WQAAQNVVoQNRhw4dtHz5cq1du1aLFy/WkSNH1KVLF/3666/KyMiQ3W5XzZo1XbYJCgpSRkaGJCkjI8MlDBX0F/RdSmJiovz9/c0lNDS0dE8MAABUKBX6llmfPn3Mn1u0aKEOHTooLCxM77zzjry9vcvsuFOmTFF8fLy57nQ6CUUAAFRhFfoK0R/VrFlTN910kw4fPqzg4GBdvHhRp0+fdhmTmZlpzjkKDg4u9NRZwXpR85IKOBwO+fn5uSwAAKDqqlSB6MyZM/r+++9Vr149tW3bVtWrV9fGjRvN/rS0NKWnpysqKkqSFBUVpQMHDujEiRPmmPXr18vPz0+RkZHlXj8AAKiYKvQts4kTJ6p///4KCwvTTz/9pOnTp8vT01P33Xef/P39NXLkSMXHxysgIEB+fn4aO3asoqKidMstt0iSevXqpcjISD3wwAOaO3euMjIyNHXqVMXGxsrhcLj57AAAQEVRoQPRf//7X9133336+eefVbduXXXu3Fm7du1S3bp1JUl///vf5eHhoUGDBik7O1sxMTF6+eWXze09PT21evVqjRkzRlFRUfLx8dGIESM0c+ZMd50SAACogCp0IHr77bcv2+/l5aVFixZp0aJFlxwTFhamjz/+uLRLAwAAVUilmkMEAABQFghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ip0IEpMTNTNN98sX19fBQYGasCAAUpLS3MZEx0dLZvN5rI8+uijLmPS09PVr18/1ahRQ4GBgZo0aZJyc3PL81QAAEAFVs3dBVzO1q1bFRsbq5tvvlm5ubn661//ql69eunQoUPy8fExx40aNUozZ84012vUqGH+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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from rl4co.envs.graph import MCPEnv, MCPGenerator\n", + "from matplotlib import pyplot as plt\n", + "import torch\n", + "from collections import Counter\n", + "\n", + "generator = MCPGenerator(size_distribution=\"uniform\", weight_distribution=\"uniform\")\n", + "env = MCPEnv(generator=generator)\n", + "data = env.generator(100)\n", + "\n", + "sizes = torch.count_nonzero(data[\"membership\"], dim=-1).flatten().tolist()\n", + "size2cnt = Counter(sizes)\n", + "weights = data[\"weights\"].flatten().tolist()\n", + "weight2cnt = Counter(weights)\n", + "\n", + "# plot the size distributions and the weight distributions\n", + "plt.figure()\n", + "plt.bar(size2cnt.keys(), size2cnt.values())\n", + "plt.title(\"Size distribution\")\n", + "plt.xlabel(\"Size\")\n", + "plt.ylabel(\"Probability\")\n", + "plt.show()\n", + "\n", + "# Note: the size distributions are not perfectly uniform since there might be repeated items and are removed in post-processing\n", + "\n", + "plt.figure()\n", + "plt.bar(weight2cnt.keys(), weight2cnt.values())\n", + "plt.title(\"Weight distribution\")\n", + "plt.xlabel(\"Weight\")\n", + "plt.ylabel(\"Probability\")\n", + "plt.show()\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also pass a custom `sampler` to generate data:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkQAAAHHCAYAAABeLEexAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA9wElEQVR4nO3deVwW9f7//+clyKWigGiAGAJaaS64Z+SeJipZpmaau6YnQ00xj9JxQVsw7JgtpqfzTa1zNC2PWWmZaCqVuKQH1yI1FUvBcuFyObHO749+XJ+ucAECrgvncb/d5nZj3u/3NfOa60bxdOY9MxbDMAwBAACYWAVnFwAAAOBsBCIAAGB6BCIAAGB6BCIAAGB6BCIAAGB6BCIAAGB6BCIAAGB6BCIAAGB6BCIAAGB6BCIAhRISEqLhw4c7uwydOHFCFotFy5Yts7fFxsbKYrGUyf47deqkTp062de3bt0qi8Wi1atXl8n+hw8frpCQkDLZF2AmBCLA5A4cOKB+/fopODhYlSpVUu3atfXAAw/o9ddfd3Zpper06dOKjY1VcnKys0spwJVrA25V7s4uAIDzbN++XZ07d1adOnU0evRoBQQE6NSpU9qxY4deffVVjR8/3j42JSVFFSq45r+hpk+frmnTphXpM6dPn9bs2bMVEhKiZs2aFfpzGzduLGJ1RXej2v75z38qLy+v1GsAzIZABJjYCy+8IG9vb+3evVs+Pj4OfWfPnnVYt1qtZVhZ0bi7u8vdvXT/d3b16lVVqVJFHh4epbqfm6lYsaJT9w/cqlzzn3sAysSxY8fUqFGjAmFIkvz8/BzW/ziHyGKxXHc5ceKEfdx3332nfv36ydfXV5UqVVKrVq308ccfF6q+ixcvavjw4fL29paPj4+GDRumixcvFhh3rTlECQkJateunXx8fFS1alXVr19fzz77rKTf5v20bt1akjRixAh73fnzkjp16qTGjRtrz5496tChg6pUqWL/7B/nEOXLzc3Vs88+q4CAAHl6euqhhx7SqVOnbvgd5vv9Nm9W27XmEF25ckWTJ09WUFCQrFar6tevr5dfflmGYTiMs1gsGjdunNauXavGjRvLarWqUaNG2rBhQ4GaALPhDBFgYsHBwUpKStLBgwfVuHHjIn32X//6V4G26dOn6+zZs6pataok6dChQ2rbtq1q166tadOmydPTU++//7569+6t//znP3rkkUeuu33DMPTwww/rq6++0pNPPqm7775bH374oYYNG3bT2g4dOqQHH3xQYWFhmjNnjqxWq44ePaqvv/5aknT33Xdrzpw5mjlzpsaMGaP27dtLku677z77Ns6dO6cePXpowIABGjx4sPz9/W+4zxdeeEEWi0VTp07V2bNntWDBAnXt2lXJycmqXLnyTWvOV5jafs8wDD300EPasmWLRo0apWbNmunzzz/XlClT9NNPP+mVV15xGP/VV19pzZo1euqpp1StWjW99tpr6tu3r1JTU1WjRo1C1wnccgwAprVx40bDzc3NcHNzM8LDw42//vWvxueff25kZWUVGBscHGwMGzbsutuKj483JBnvvvuuva1Lly5GkyZNjF9//dXelpeXZ9x3333GnXfeecPa1q5da0gy4uPj7W05OTlG+/btDUnG0qVL7e2zZs0yfv+/s1deecWQZPz888/X3f7u3bsLbCdfx44dDUnG4sWLr9nXsWNH+/qWLVsMSUbt2rUNm81mb3///fcNScarr75qb7ved/jHbd6otmHDhhnBwcH29fzv6fnnn3cY169fP8NisRhHjx61t0kyPDw8HNr27dtnSDJef/31AvsCzIRLZoCJPfDAA0pKStJDDz2kffv2KT4+XhEREapdu3ahL2tJ0pYtWxQTE6Px48dryJAhkqTz58/riy++UP/+/XXp0iX98ssv+uWXX3Tu3DlFREToyJEj+umnn667zU8//VTu7u4aO3asvc3Nzc1hovf15F8C/Oijj4o9AdlqtWrEiBGFHj906FBVq1bNvt6vXz/VqlVLn376abH2X1iffvqp3NzcNGHCBIf2yZMnyzAMffbZZw7tXbt2Vb169ezrYWFh8vLy0g8//FCqdQKujkAEmFzr1q21Zs0aXbhwQbt27VJMTIwuXbqkfv366fDhwzf9/I8//qjHHntMbdu21fz58+3tR48elWEYmjFjhm677TaHZdasWZIKTtz+vZMnT6pWrVr2y2/56tevf9Oa8ut54okn5O/vrwEDBuj9998vUjiqXbt2kSZQ33nnnQ7rFotFd9xxh8N8qtJw8uRJBQYGOoQx6bdLb/n9v1enTp0C26hevbouXLhQekUC5QBziABIkjw8PNS6dWu1bt1ad911l0aMGKEPPvjAHl6uJSsrS/369ZPVatX777/vcKdXfvh45plnFBERcc3P33HHHSV7EP+/ypUrKzExUVu2bNH69eu1YcMGrVq1Svfff782btwoNze3Qm2jpF3v4ZG5ubmFqqkkXG8/xh8mYANmQyACUECrVq0kSWfOnLnhuAkTJig5OVmJiYkFJh3XrVtX0m+3iXft2rXINQQHB2vz5s26fPmyw1milJSUQn2+QoUK6tKli7p06aL58+frxRdf1N/+9jdt2bJFXbt2LfEnWx85csRh3TAMHT16VGFhYfa26tWrX/MuuZMnT9q/L+n6welagoODtWnTJl26dMnhLNF3331n7wdwc1wyA0xsy5Yt1zwzkD/v5UaXp5YuXap//OMfWrhwoe65554C/X5+furUqZP+8Y9/XDNY/fzzzzesrWfPnsrJydGiRYvsbbm5uYV6gvb58+cLtOU/4DAzM1OS5OnpKUnXDCjF8e677+rSpUv29dWrV+vMmTPq0aOHva1evXrasWOHsrKy7G3r1q0rcHt+UWrr2bOncnNz9cYbbzi0v/LKK7JYLA77B3B9nCECTGz8+PG6evWqHnnkETVo0EBZWVnavn27Vq1apZCQkOtOKv7ll1/01FNPqWHDhrJarfr3v//t0P/II4/I09NTCxcuVLt27dSkSRONHj1adevWVXp6upKSkvTjjz9q3759162tV69eatu2raZNm6YTJ06oYcOGWrNmjTIyMm56XHPmzFFiYqIiIyMVHByss2fP6s0339Ttt9+udu3aSfotnPj4+Gjx4sWqVq2aPD091aZNG4WGhhbhG/w/vr6+ateunUaMGKH09HQtWLBAd9xxh0aPHm0f88QTT2j16tXq3r27+vfvr2PHjunf//63wyTnotbWq1cvde7cWX/729904sQJNW3aVBs3btRHH32kiRMnFtg2gOtw6j1uAJzqs88+M0aOHGk0aNDAqFq1quHh4WHccccdxvjx44309HSHsb+/Zfz48eOGpOsux48ft3/u2LFjxtChQ42AgACjYsWKRu3atY0HH3zQWL169U3rO3funDFkyBDDy8vL8Pb2NoYMGWL897//velt95s3bzYefvhhIzAw0PDw8DACAwONgQMHGt9//73D9j/66COjYcOGhru7u8M2O3bsaDRq1OiaNV3vtvv33nvPiImJMfz8/IzKlSsbkZGRxsmTJwt8/u9//7tRu3Ztw2q1Gm3btjW++eab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x0RERCglJUUXLlwouwMBAAAuy6lniG6me/fu6tOnj0JDQ3Xs2DE9++yz6tGjh5KSkuTm5qa0tDT5+fk5fMbd3V2+vr5KS0uTJKWlpSk0NNRhjL+/v72vevXqBfabmZmpzMxM+7rNZivpQwMAAC7EpQPRgAED7D83adJEYWFhqlevnrZu3aouXbqU2n7j4uI0e/bsUts+AABwLS5/yez36tatq5o1a+ro0aOSpICAAJ09e9ZhTE5Ojs6fP2+fdxQQEKD09HSHMfnr15ubFBMTo4yMDPty6tSpkj4UAADgQspVIPrxxx917tw51apVS5IUHh6uixcvas+ePfYxX3zxhfLy8tSmTRv7mMTERGVnZ9vHJCQkqH79+te8XCb9NpHby8vLYQEAALcupwaiy5cvKzk5WcnJyZKk48ePKzk5Wampqbp8+bKmTJmiHTt26MSJE9q8ebMefvhh3XHHHYqIiJAk3X333erevbtGjx6tXbt26euvv9a4ceM0YMAABQYGSpIef/xxeXh4aNSoUTp06JBWrVqlV199VdHR0c46bAAA4GKcGoi++eYbNW/eXM2bN5ckRUdHq3nz5po5c6bc3Ny0f/9+PfTQQ7rrrrs0atQotWzZUl9++aWsVqt9G8uXL1eDBg3UpUsX9ezZU+3atXN4xpC3t7c2btyo48ePq2XLlpo8ebJmzpzJLfcAAMDOqZOqO3XqJMMwrtv/+eef33Qbvr6+WrFixQ3HhIWF6csvvyxyfQAAwBzK1RwiAACA0kAgAgAApkcgAgAApufSD2YEAPyfkGnrnbbvE3MjnbZvoCxwhggAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJgegQgAAJieUwNRYmKievXqpcDAQFksFq1du9bel52dralTp6pJkyby9PRUYGCghg4dqtOnTztsIyQkRBaLxWGZO3euw5j9+/erffv2qlSpkoKCghQfH18WhwcAAMoJpwaiK1euqGnTplq4cGGBvqtXr2rv3r2aMWOG9u7dqzVr1iglJUUPPfRQgbFz5szRmTNn7Mv48ePtfTabTd26dVNwcLD27NmjefPmKTY2Vm+99VapHhsAACg/3J258x49eqhHjx7X7PP29lZCQoJD2xtvvKF77rlHqampqlOnjr29WrVqCggIuOZ2li9frqysLC1ZskQeHh5q1KiRkpOTNX/+fI0ZM6bkDgYAAJRb5WoOUUZGhiwWi3x8fBza586dqxo1aqh58+aaN2+ecnJy7H1JSUnq0KGDPDw87G0RERFKSUnRhQsXyqp0AADgwpx6hqgofv31V02dOlUDBw6Ul5eXvX3ChAlq0aKFfH19tX37dsXExOjMmTOaP3++JCktLU2hoaEO2/L397f3Va9evcC+MjMzlZmZaV+32WylcUgAAMBFlItAlJ2drf79+8swDC1atMihLzo62v5zWFiYPDw89Je//EVxcXGyWq3F2l9cXJxmz579p2oGAADlh8tfMssPQydPnlRCQoLD2aFradOmjXJycnTixAlJUkBAgNLT0x3G5K9fb95RTEyMMjIy7MupU6f+/IEAAACX5dKBKD8MHTlyRJs2bVKNGjVu+pnk5GRVqFBBfn5+kqTw8HAlJiYqOzvbPiYhIUH169e/5uUySbJarfLy8nJYAADArcupl8wuX76so0eP2tePHz+u5ORk+fr6qlatWurXr5/27t2rdevWKTc3V2lpaZIkX19feXh4KCkpSTt37lTnzp1VrVo1JSUladKkSRo8eLA97Dz++OOaPXu2Ro0apalTp+rgwYN69dVX9corrzjlmAEAgOtxaiD65ptv1LlzZ/t6/nygYcOGKTY2Vh9//LEkqVmzZg6f27Jlizp16iSr1aqVK1cqNjZWmZmZCg0N1aRJkxzmFXl7e2vjxo2KiopSy5YtVbNmTc2cOZNb7gEAgF2xAtGWLVscgkxxderUSYZhXLf/Rn2S1KJFC+3YseOm+wkLC9OXX35Z5PoAAIA5FGsOUffu3VWvXj09//zzTDgGAADlXrEC0U8//aRx48Zp9erVqlu3riIiIvT+++8rKyurpOsDAAAodcUKRDVr1tSkSZOUnJysnTt36q677tJTTz2lwMBATZgwQfv27SvpOgEAAErNn77tvkWLFoqJidG4ceN0+fJlLVmyRC1btlT79u116NChkqgRAACgVBU7EGVnZ2v16tXq2bOn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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkQAAAHHCAYAAABeLEexAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8pXeV/AAAACXBIWXMAAA9hAAAPYQGoP6dpAABB/0lEQVR4nO3deVyVdf7//+cBZRHh4AZIIqCWiqmllh41lTJJaTFtsaxIzT464IKjljNmLhlmi0u5ZIvYpJXtpeOuaCouWZhLkZaGk4ItwnEFhev7Rz+unyesgMADXI/77XZu4/W+Xud9vd44Mzy9znVdx2YYhiEAAAAL83B3AwAAAO5GIAIAAJZHIAIAAJZHIAIAAJZHIAIAAJZHIAIAAJZHIAIAAJZHIAIAAJZHIAIAAJZHIAJQKg8//LAiIiJK/d6aNWuWbUN/Ijk5WTabTYcPHzbHunXrpm7dul2W49tsNk2cONHcnjhxomw2m37++efLcvyIiAg9/PDDl+VYQGVFIAKqkKVLl8pms+nDDz8ssq9169ay2WzasGFDkX0NGzZUx44dL0eLJXLmzBlNnDhRKSkp7m5FkrR161ZNnDhR2dnZ7m6liIrcG1AZEIiAKqRz586SpM2bN7uMO51O7d27V9WqVdOWLVtc9h05ckRHjhwx31tcr7zyitLT0/9ew3/hzJkzmjRpUrkEotWrV2v16tUles/WrVs1adKkEoeOs2fPavz48SV6T0n9WW/p6el65ZVXyvX4QGVXzd0NACg7oaGhioyMLBKIUlNTZRiG7r777iL7CrdLGoiqV6/+95p1My8vr3Kdv6CgQHl5efLx8ZGPj0+5HuuveHt7u/X4QGXAGSKgiuncubO+/PJLnT171hzbsmWLWrRooZ49e2rbtm0qKChw2Wez2dSpUydz7M0331Tbtm3l6+ur2rVrq1+/fjpy5IjLcS51DdEvv/yiBx98UAEBAQoMDFRcXJx2794tm82m5OTkIr3++OOP6t27t2rWrKl69epp9OjRys/PlyQdPnxY9erVkyRNmjRJNputyLU4l7Jv3z7deOON8vX1VYMGDfTUU0+5rLfQpa4hevHFF9WiRQvVqFFDtWrVUrt27bRkyRJJv133M2bMGElSZGSk2U/hdUk2m00JCQlavHixWrRoIW9vb61cudLcd6m+f/75Z91zzz0KCAhQnTp1NGLECJ07d87cf/jw4T/82V0851/1dqlriL7//nvdfffdql27tmrUqKEOHTpo+fLlLjUpKSmy2WxaunSppk6dqgYNGsjHx0c33XSTDh48WKQnoDLjDBFQxXTu3Fn/+c9/tH37dvMX/pYtW9SxY0d17NhROTk52rt3r1q1amXua9asmerUqSNJmjp1qp544gndc889euSRR/TTTz/pxRdfVJcuXfTll18qMDDwksctKCjQbbfdph07dmjo0KFq1qyZPv74Y8XFxV2yPj8/XzExMWrfvr2ee+45rV27Vs8//7waN26soUOHql69epo3b56GDh2qO++8U3369JEks+9LyczMVHR0tC5cuKDHH39cfn5+WrBggXx9ff/y5/bKK69o+PDhuuuuu8xg8tVXX2n79u26//771adPH3377bd66623NGPGDNWtW1eSzNAmSevXr9fSpUuVkJCgunXr/uVF5/fcc48iIiKUlJSkbdu2afbs2Tpx4oTeeOONv+z3YsXp7WJZWVnq2LGjzpw5o+HDh6tOnTpatGiRbr/9dr333nu68847XeqnTZsmDw8PjR49Wjk5OZo+fbr69++v7du3l6hPoEIzAFQp+/btMyQZU6ZMMQzDMM6fP2/4+fkZixYtMgzDMIKDg405c+YYhmEYTqfT8PT0NAYPHmwYhmEcPnzY8PT0NKZOneoy5549e4xq1aq5jMfFxRnh4eHm9vvvv29IMmbOnGmO5efnGzfeeKMhyVi4cKHLeyUZkydPdjnOtddea7Rt29bc/umnnwxJxpNPPlmstY8cOdKQZGzfvt0cO378uGG32w1JxqFDh8zxrl27Gl27djW377jjDqNFixZ/Ov+zzz5bZJ5CkgwPDw9j3759l9x38RqefPJJQ5Jx++23u9T94x//MCQZu3fvNgzDMA4dOlTkZ/dHc/5Zb+Hh4UZcXJy5Xfhz+uyzz8yxkydPGpGRkUZERISRn59vGIZhbNiwwZBkNG/e3MjNzTVrZ82aZUgy9uzZU+RYQGXFR2ZAFdO8eXPVqVPHvDZo9+7dOn36tHkXWceOHc0Lq1NTU5Wfn29eP/TBBx+ooKBA99xzj37++WfzFRISoiuvvPKSd6gVWrlypapXr67BgwebYx4eHoqPj//D9wwZMsRl+4YbbtD3339fuoVL+u9//6sOHTro+uuvN8fq1aun/v37/+V7AwMD9b///U87d+4s9fG7du2qqKioYtf//mczbNgwSb+tozz997//1fXXX+9y3VjNmjX16KOP6vDhw9q/f79L/YABA1yuubrhhhsk6W/9XQEVDYEIqGJsNps6duxoXiu0ZcsWBQUFqUmTJpJcA1Hhfxb+Yjxw4IAMw9CVV16pevXquby+/vprHT9+/A+P+8MPP6h+/fqqUaOGy3jhcX/Px8enyEc6tWrV0okTJ0q38P+vhyuvvLLIeNOmTf/yvY899phq1qyp66+/XldeeaXi4+OL3JH3VyIjI0tU//teGzduLA8PD5fnJZWHH3744ZI/k+bNm5v7L9awYUOX7Vq1aknS3/q7AioariECqqDOnTvr008/1Z49e8zrhwp17NhRY8aM0Y8//qjNmzcrNDRUjRo1kvTbdUA2m00rVqyQp6dnkXnL8mGKl5rfnZo3b6709HQtW7ZMK1eu1Pvvv6+5c+dqwoQJmjRpUrHmKM61Sn/GZrP96XahwgvPL5c/+rsyDOOy9gGUJwIRUAVd/DyiLVu2aOTIkea+tm3bytvbWykpKdq+fbt69epl7mvcuLEMw1BkZKSuuuqqEh0zPDxcGzZs0JkzZ1zOEv2du5H+KBD8WQ8HDhwoMl7c5yX5+fnp3nvv1b333qu8vDz16dNHU6dO1bhx4+Tj41Pifv7KgQMHXM4qHTx4UAUFBebF2IVnYn7/bKHfn8GRSvazCg8Pv+TP5JtvvjH3A1bDR2ZAFdSuXTv5+Pho8eLF+vHHH13OEHl7e6tNmzaaM2eOTp8+7XIdSZ8+feTp6alJkyYV+de/YRj65Zdf/vCYMTExOn/+vMsDAAsKCjRnzpxSr6MwWBX3QYi9evXStm3btGPHDnPsp59+0uLFi//yvb9fm5eXl6KiomQYhs6fPy/pt8BUkn7+yu9/Ni+++KIkqWfPnpKkgIAA1a1bV5s2bXKpmzt3bpG5StJbr169tGPHDqWmpppjp0+f1oIFCxQREVGi66CAqoIzREAV5OXlpeuuu06fffaZvL291bZtW5f9HTt21PPPPy/J9YGMjRs31lNPPaVx48bp8OHD6t27t/z9/XXo0CF9+OGHevTRRzV69OhLHrN37966/vrr9c9//lMHDx5Us2bN9Mknn+jXX3+VVPKzPdJvH0FFRUXpnXfe0VVXXaXatWvr6quv1tVXX33J+rFjx+o///mPbrnlFo0YMcK87T48PFxfffXVnx6rR48eCgkJUadOnRQcHKyvv/5aL730kmJjY+Xv7y9J5s/x3//+t/r166fq1avrtttuM8NISR06dEi33367brnlFqWmpurNN9/U/fffr9atW5s1jzzyiKZNm6ZHHnlE7dq106ZNm/Ttt98WmaskvT3++ON666231LNnTw0fPly1a9fWokWLdOjQIb3//vvy8ODfyrAgd97iBqD8jBs3zpBkdOzYsci+Dz74wJBk+Pv7GxcuXCiy//333zc6d+5s+Pn5GX5+fkazZs2M+Ph4Iz093az5/W33hvHbbfL333+/4e/vb9jtduPhhx82tmzZYkgy3n77bZf3+vn5FTlu4e3oF9u6davRtm1bw8vLq1i34H/11VdG165dDR8fH+OKK64wpkyZYrz22mt/edv9yy+/bHTp0sWoU6eO4e3tbTRu3NgYM2aMkZOT4zL/lClTjCuuuMLw8PBwmVOSER8ff8meft934Tr3799v3HXXXYa/v79Rq1YtIyEhwTh79qzLe8+cOWMMGjTIsNvthr+/v3HPPfcYx48fv+TP4o96+/1t94ZhGN99951x1113GYGBgYaPj49x/fXXG8uWLXOpKbzt/t1333UZ/7PHAQCVlc0wuCoOQPn56KOPdOedd2rz5s0uT8MGgIqEQASgzJw9e9blTqv8/Hz16NFDn3/+uTIzM//2XVgAUF64hghAmRk2bJjOnj0rh8Oh3NxcffDBB9q6dauefvppwhCACo0zRADKzJIlS/T888/r4MGDOnfunJo0aaKhQ4cqISHB3a0BwJ8iEAEAAMvj3koAAGB5BCIAAGB5XFRdDAUFBTp69Kj8/f3L/NH9AACgfBiGoZMnTyo0NPQvHzhKICqGo0ePKiwszN1tAACAUjhy5IgaNGjwpzUEomIofGz/kSNHFBAQ4OZuAABAcTidToWFhZm/x/8MgagYCj8mCwgIIBABAFDJFOdyF7deVB0RESGbzVbkFR8fL0k6d+6c4uPjVadOHdWsWVN9+/ZVVlaWyxwZGRmKjY1VjRo1FBQUpDFjxujChQsuNSkpKWrTpo28vb3VpEkTJScnX64lAgCASsCtgWjnzp06duyY+VqzZo0k6e6775YkJSYm6tNPP9W7776rjRs36ujRo+rTp4/5/vz8fMXGxiovL09bt27VokWLlJycrAkT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hfsL9/1ZjdPp1NmzZ+Xr61ukr9zcXOXm5prbTqfzb68VAABUXG4NRD179jT/3KpVK7Vv317h4eFaunTpJYPK5ZKUlKRJkya57fgAAODycvtHZhcLDAzUVVddpYMHDyokJER5eXnKzs52qcnKyjKvOQoJCSly11nh9l/VBAQE/GHoGjdunHJycszXkSNHymJ5AACggqpQgejUqVP67rvvVL9+fbVt21bVq1fXunXrzP3p6enKyMiQw+GQJDkcDu3Zs0fHjx83a9asWaOAgABFRUWZNRfPUVhTOMeleHt7KyAgwOUFAACqLrcGotGjR2vjxo06fPiwtm7dqjvvvFOenp667777ZLfbNWjQII0aNUobNmzQrl27NGDAADkcDnXo0EGS1KNHD0VFRenBBx/U7t27tWrVKo0fP17x8fHy9vaWJA0ZMkTff/+9xo4dq2+++UZz587V0qVLlZiY6M6lAwCACsSt1xD973//03333adffvlF9erVU+fOnbVt2zbVq1dPkjRjxgx5eHiob9++ys3NVUxMjObOnWu+39PTU8uWLdPQoUPlcDjk5+enuLg4TZ482ayJjIzU8uXLlZiYqFmzZqlBgwZ69dVXueUeAACYbIZhGO5uoqJzOp2y2+3Kycnh4zNAUsTjy93dQqkdnhZb7NrKus6SrBGoykry+7tCXUMEAADgDgQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeQQiAABgeaUKRBs2bCjrPgAAANymVIHolltuUePGjfXUU0/pyJEjZd0TAADAZVWqQPTjjz8qISFB7733nho1aqSYmBgtXbpUeXl5Zd0fAABAuStVIKpbt64SExOVlpam7du366qrrtI//vEPhYaGavjw4dq9e3dZ9wkAAFBu/vZF1W3atNG4ceOUkJCgU6dO6fXXX1fbtm11ww03aN++fWXRIwAAQLkqdSA6f/683nvvPfXq1Uvh4eFatWqV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LSsrSwEBAfL19S3Sj7e3t7y9vctkbQAAoOJz6xkiwzCUkJCgDz/8UOvXr1dkZKTL/rZt26p69epat26dOZaenq6MjAw5HA5JksPh0J49e3T8+HGzZs2aNQoICFBUVJRZc/EchTWFcwAAAGtz6xmi+Ph4LVmyRB9//LH8/f3Na37sdrt8fX1lt9s1aNAgjRo1SrVr11ZAQICGDRsmh8OhDh06SJJ69OihqKgoPfjgg5o+fboyMzM1fvx4xcfHm2d5hgwZopdeekljx47VwIEDtX79ei1dulTLly9329oBAEDF4dYzRPPmzVNOTo66deum+vXrm6933nnHrJkxY4ZuvfVW9e3bV126dFFISIg++OADc7+np6eWLVsmT09PORwOPfDAA3rooYc0efJksyYyMlLLly/XmjVr1Lp1az3//PN69dVXueUeAABIcvMZIsMw/rLGx8dHc+bM0Zw5c/6wJjw8XP/973//dJ5u3brpyy+/LHGPAACg6qswd5kBAAC4C4EIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYHoEIAABYnlsD0aZNm3TbbbcpNDRUNptNH330kct+wzA0YcIE1a9fX76+vurevbsOHDjgUvPrr7+qf//+CggIUGBgoAYNGqRTp0651Hz11Ve64YYb5OPjo7CwME2fPr28lwYAACoRtwai06dPq3Xr1pozZ84l90+fPl2zZ8/W/PnztX37dvn5+SkmJkbnzp0za/r37699+/ZpzZo1WrZsmTZt2qRHH33U3O90OtWjRw+Fh4dr165devbZZzVx4kQtWLCg3NcHAAAqh2ruPHjPnj3Vs2fPS+4zDEMzZ87U+PHjdccdd0iS3njjDQUHB+ujjz5Sv3799PXXX2vlypXauXOn2rVrJ0l68cUX1atXLz333HMKDQ3V4sWL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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from collections import Counter\n", + "from torch.distributions import Normal\n", + "\n", + "size_sampler = Normal(10, 2)\n", + "weight_sampler = Normal(5, 1)\n", + "\n", + "generator = MCPGenerator(size_sampler=size_sampler, weight_sampler=weight_sampler)\n", + "env = MCPEnv(generator=generator)\n", + "data = env.generator(100)\n", + "\n", + "sizes = torch.count_nonzero(data[\"membership\"], dim=-1).flatten().tolist()\n", + "size2cnt = Counter(sizes)\n", + "weights = data[\"weights\"].flatten().tolist()\n", + "weight2cnt = Counter(weights)\n", + "\n", + "# plot the size distributions and the weight distributions\n", + "plt.figure()\n", + "plt.bar(size2cnt.keys(), size2cnt.values())\n", + "plt.title(\"Size distribution\")\n", + "plt.xlabel(\"Size\")\n", + "plt.ylabel(\"Probability\")\n", + "plt.show()\n", + "\n", + "plt.figure()\n", + "plt.bar(weight2cnt.keys(), weight2cnt.values())\n", + "plt.title(\"Weight distribution\")\n", + "plt.xlabel(\"Weight\")\n", + "plt.ylabel(\"Probability\")\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Tl;dr: RL4CO allows for easily generating data for CO problems! 🚀" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "nipsreb", + "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.11.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/other/3-data-generator-distributions/index.html b/examples/other/3-data-generator-distributions/index.html new file mode 100644 index 00000000..160857dc --- /dev/null +++ b/examples/other/3-data-generator-distributions/index.html @@ -0,0 +1,3483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Generating data in RL4CO - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/other/README.md b/examples/other/README.md new file mode 100644 index 00000000..8a7f9e01 --- /dev/null +++ b/examples/other/README.md @@ -0,0 +1,9 @@ +# Miscellaneous Examples + +Collection of examples on other topics. + +## Index + +- [`1-mtvrp.ipynb`](1-mtvrp.ipynb): here we show how to use the Multi-Task Vehicle Routing Problem (MTVRP) environment, which includes 16 tasks that can be solved simultaneously. +- [`2-scheduling.ipynb`](2-scheduling.ipynb): provides a brief introduction to scheduling problems with RL4CO with the Flexible Job Shop Scheduling Problem (FJSP) environment. +- [`3-data-generator-distributions.ipynb`](3-data-generator-distributions.ipynb): here we show how to use the data generators and how to generate data from custom distributions. \ No newline at end of file diff --git a/examples/other/index.html b/examples/other/index.html new file mode 100644 index 00000000..f1f0784c --- /dev/null +++ b/examples/other/index.html @@ -0,0 +1,2386 @@ + + + + + + + + + + + + + + + + + + + + + + + Miscellaneous Examples - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ + + + + + + + + +

Miscellaneous Examples

+

Collection of examples on other topics.

+

Index

+
    +
  • 1-mtvrp.ipynb: here we show how to use the Multi-Task Vehicle Routing Problem (MTVRP) environment, which includes 16 tasks that can be solved simultaneously.
  • +
  • 2-scheduling.ipynb: provides a brief introduction to scheduling problems with RL4CO with the Flexible Job Shop Scheduling Problem (FJSP) environment.
  • +
  • 3-data-generator-distributions.ipynb: here we show how to use the data generators and how to generate data from custom distributions.
  • +
+ + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..84308df4 --- /dev/null +++ b/index.html @@ -0,0 +1,3069 @@ + + + + + + + + + + + + + + + + + + + + + + + + + RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + + + + + + + + + + + + + +
+
+ + + + + + + + + +

Home

+ +
+ +
+ +
+
+
+ + +
+
Loading...
+
+
+ AI4CO Logo +
+
+ + +
+
+
+ +

An extensive Reinforcement Learning (RL) for Combinatorial Optimization (CO) benchmark. Our goal is to provide a unified framework for RL-based CO algorithms, and to facilitate reproducible research in this field, decoupling the science from the engineering.

+

RL4CO is built upon:

+
    +
  • TorchRL: official PyTorch framework for RL algorithms and vectorized environments on GPUs
  • +
  • TensorDict: a library to easily handle heterogeneous data such as states, actions and rewards
  • +
  • PyTorch Lightning: a lightweight PyTorch wrapper for high-performance AI research
  • +
  • Hydra: a framework for elegantly configuring complex applications
  • +
+
+ RL4CO-Overview +
+ +

We offer flexible and efficient implementations of the following policies:

+
    +
  • Constructive: learn to construct a solution from scratch
      +
    • Autoregressive (AR): construct solutions one step at a time via a decoder
    • +
    • NonAutoregressive (NAR): learn to predict a heuristic, such as a heatmap, to then construct a solution
    • +
    +
  • +
  • Improvement: learn to improve a pre-existing solution
  • +
+
+ RL4CO-Policy-Overview +
+ +

We provide several utilities and modularization. For example, we modularize reusable components such as environment embeddings that can easily be swapped to solve new problems.

+
+ RL4CO-Env-Embedding +
+ +

Getting started

+

Open In Colab

+

RL4CO is now available for installation on pip! +

pip install rl4co
+

+

To get started, we recommend checking out our quickstart notebook or the minimalistic example below.

+

Install from source

+

This command installs the bleeding edge main version, useful for staying up-to-date with the latest developments - for instance, if a bug has been fixed since the last official release but a new release hasn’t been rolled out yet:

+
pip install -U git+https://github.com/ai4co/rl4co.git
+
+

Local install and development

+

If you want to develop RL4CO we recommend you to install it locally with pip in editable mode:

+
git clone https://github.com/ai4co/rl4co && cd rl4co
+pip install -e .
+
+

We recommend using a virtual environment such as conda to install rl4co locally.

+

Usage

+

Train model with default configuration (AM on TSP environment): +

python run.py
+

+
+

Tip

+

You may check out this notebook to get started with Hydra!

+
+
+ Change experiment settings + +Train model with chosen experiment configuration from [configs/experiment/](configs/experiment/) +
python run.py experiment=routing/am env=tsp env.num_loc=50 model.optimizer_kwargs.lr=2e-4
+
+Here you may change the environment, e.g. with `env=cvrp` by command line or by modifying the corresponding experiment e.g. [configs/experiment/routing/am.yaml](configs/experiment/routing/am.yaml). + +
+ +
+ Disable logging + +
python run.py experiment=routing/am logger=none '~callbacks.learning_rate_monitor'
+
+Note that `~` is used to disable a callback that would need a logger. + +
+ +
+ Create a sweep over hyperparameters (-m for multirun) + +
python run.py -m experiment=routing/am  model.optimizer.lr=1e-3,1e-4,1e-5
+
+
+ +

Minimalistic Example

+

Here is a minimalistic example training the Attention Model with greedy rollout baseline on TSP in less than 30 lines of code:

+
from rl4co.envs.routing import TSPEnv, TSPGenerator
+from rl4co.models import AttentionModelPolicy, POMO
+from rl4co.utils import RL4COTrainer
+
+# Instantiate generator and environment
+generator = TSPGenerator(num_loc=50, loc_distribution="uniform")
+env = TSPEnv(generator)
+
+# Create policy and RL model
+policy = AttentionModelPolicy(env_name=env.name, num_encoder_layers=6)
+model = POMO(env, policy, batch_size=64, optimizer_kwargs={"lr": 1e-4})
+
+# Instantiate Trainer and fit
+trainer = RL4COTrainer(max_epochs=10, accelerator="gpu", precision="16-mixed")
+trainer.fit(model)
+
+

Other examples can be found on our documentation!

+

Testing

+

Run tests with pytest from the root directory:

+
pytest tests
+
+

Known Bugs

+

Bugs installing PyTorch Geometric (PyG)

+

Installing PyG via Conda seems to update Torch itself. We have found that this update introduces some bugs with torchrl. At this moment, we recommend installing PyG with Pip: +

pip install torch_geometric
+

+

Contributing

+

Have a suggestion, request, or found a bug? Feel free to open an issue or submit a pull request. +If you would like to contribute, please check out our contribution guidelines here. We welcome and look forward to all contributions to RL4CO!

+

We are also on Slack if you have any questions or would like to discuss RL4CO with us. We are open to collaborations and would love to hear from you 🚀

+

Contributors

+

+ +

+

Citation

+

If you find RL4CO valuable for your research or applied projects:

+
@article{berto2024rl4co,
+    title={{RL4CO: an Extensive Reinforcement Learning for Combinatorial Optimization Benchmark}},
+    author={Federico Berto and Chuanbo Hua and Junyoung Park and Laurin Luttmann and Yining Ma and Fanchen Bu and Jiarui Wang and Haoran Ye and Minsu Kim and Sanghyeok Choi and Nayeli Gast Zepeda and Andr\'e Hottung and Jianan Zhou and Jieyi Bi and Yu Hu and Fei Liu and Hyeonah Kim and Jiwoo Son and Haeyeon Kim and Davide Angioni and Wouter Kool and Zhiguang Cao and Jie Zhang and Kijung Shin and Cathy Wu and Sungsoo Ahn and Guojie Song and Changhyun Kwon and Lin Xie and Jinkyoo Park},
+    year={2024},
+    journal={arXiv preprint arXiv:2306.17100},
+    note={\url{https://github.com/ai4co/rl4co}}
+}
+
+

Note that a previous version of RL4CO has been accepted as an oral presentation at the NeurIPS 2023 GLFrontiers Workshop. Since then, the library has greatly evolved and improved!

+
+

Join us

+

Slack

+

We invite you to join our AI4CO community, an open research group in Artificial Intelligence (AI) for Combinatorial Optimization (CO)!

+
+ AI4CO Logo +
+ + + + + + + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..5618cfe3a7328df8b0a67310ba68c1f607a37143 GIT binary patch literal 3291 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 3x more CPU. We may generally recommend using the :class:`TensorDictDatasetList` + + Note: + Check out the issue on tensordict for more details: + https://github.com/pytorch-labs/tensordict/issues/374. + """ + + def __init__(self, td: TensorDict): + self.data = td + + def __len__(self): + return len(self.data) + + def __getitems__(self, index): + # Tricks: + # - batched data loading with `__getitems__` for faster loading + # - avoid directly indexing TensorDicts for faster loading + return TensorDict( + {key: item[index] for key, item in self.data.items()}, + batch_size=torch.Size([len(index)]), + **td_kwargs, + ) + + def add_key(self, key, value): + self.data.update({key: value}) # native method + return self + + @staticmethod + def collate_fn(batch: Union[dict, TensorDict]): + """Equivalent to collating with `lambda x: x`""" + return batch diff --git a/rl4co/data/generate_data.py b/rl4co/data/generate_data.py new file mode 100644 index 00000000..a2122369 --- /dev/null +++ b/rl4co/data/generate_data.py @@ -0,0 +1,386 @@ +import argparse +import logging +import os +import sys + +from typing import List, Union + +import numpy as np + +from rl4co.data.utils import check_extension +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +DISTRIBUTIONS_PER_PROBLEM = { + "tsp": [None], + "vrp": [None], + "pctsp": [None], + "op": ["const", "unif", "dist"], + "mdpp": [None], + "pdp": [None], +} + + +def generate_env_data(env_type, *args, **kwargs): + """Generate data for a given environment type in the form of a dictionary""" + try: + # breakpoint() + # remove all None values from args + args = [arg for arg in args if arg is not None] + + return getattr(sys.modules[__name__], f"generate_{env_type}_data")( + *args, **kwargs + ) + except AttributeError: + raise NotImplementedError(f"Environment type {env_type} not implemented") + + +def generate_tsp_data(dataset_size, tsp_size): + return { + "locs": np.random.uniform(size=(dataset_size, tsp_size, 2)).astype(np.float32) + } + + +def generate_vrp_data(dataset_size, vrp_size, capacities=None): + # From Kool et al. 2019, Hottung et al. 2022, Kim et al. 2023 + CAPACITIES = { + 10: 20.0, + 15: 25.0, + 20: 30.0, + 30: 33.0, + 40: 37.0, + 50: 40.0, + 60: 43.0, + 75: 45.0, + 100: 50.0, + 125: 55.0, + 150: 60.0, + 200: 70.0, + 500: 100.0, + 1000: 150.0, + } + + # If capacities are provided, replace keys in CAPACITIES with provided values if they exist + if capacities is not None: + for k, v in capacities.items(): + if k in CAPACITIES: + print(f"Replacing capacity for {k} with {v}") + CAPACITIES[k] = v + + return { + "depot": np.random.uniform(size=(dataset_size, 2)).astype( + np.float32 + ), # Depot location + "locs": np.random.uniform(size=(dataset_size, vrp_size, 2)).astype( + np.float32 + ), # Node locations + "demand": np.random.randint(1, 10, size=(dataset_size, vrp_size)).astype( + np.float32 + ), # Demand, uniform integer 1 ... 9 + "capacity": np.full(dataset_size, CAPACITIES[vrp_size]).astype(np.float32), + } # Capacity, same for whole dataset + + +def generate_pdp_data(dataset_size, pdp_size): + depot = np.random.uniform(size=(dataset_size, 2)) + loc = np.random.uniform(size=(dataset_size, pdp_size, 2)) + return { + "locs": loc.astype(np.float32), + "depot": depot.astype(np.float32), + } + + +def generate_op_data(dataset_size, op_size, prize_type="const", max_lengths=None): + depot = np.random.uniform(size=(dataset_size, 2)) + loc = np.random.uniform(size=(dataset_size, op_size, 2)) + + # Methods taken from Fischetti et al. 1998 + if prize_type == "const": + prize = np.ones((dataset_size, op_size)) + elif prize_type == "unif": + prize = (1 + np.random.randint(0, 100, size=(dataset_size, op_size))) / 100.0 + else: # Based on distance to depot + assert prize_type == "dist" + prize_ = np.linalg.norm(depot[:, None, :] - loc, axis=-1) + prize = ( + 1 + (prize_ / prize_.max(axis=-1, keepdims=True) * 99).astype(int) + ) / 100.0 + + # Max length is approximately half of optimal TSP tour, such that half (a bit more) of the nodes can be visited + # which is maximally difficult as this has the largest number of possibilities + MAX_LENGTHS = {20: 2.0, 50: 3.0, 100: 4.0} + max_lengths = MAX_LENGTHS if max_lengths is None else max_lengths + + return { + "depot": depot.astype(np.float32), + "locs": loc.astype(np.float32), + "prize": prize.astype(np.float32), + "max_length": np.full(dataset_size, max_lengths[op_size]).astype(np.float32), + } + + +def generate_pctsp_data(dataset_size, pctsp_size, penalty_factor=3, max_lengths=None): + depot = np.random.uniform(size=(dataset_size, 2)) + loc = np.random.uniform(size=(dataset_size, pctsp_size, 2)) + + # For the penalty to make sense it should be not too large (in which case all nodes will be visited) nor too small + # so we want the objective term to be approximately equal to the length of the tour, which we estimate with half + # of the nodes by half of the tour length (which is very rough but similar to op) + # This means that the sum of penalties for all nodes will be approximately equal to the tour length (on average) + # The expected total (uniform) penalty of half of the nodes (since approx half will be visited by the constraint) + # is (n / 2) / 2 = n / 4 so divide by this means multiply by 4 / n, + # However instead of 4 we use penalty_factor (3 works well) so we can make them larger or smaller + MAX_LENGTHS = {20: 2.0, 50: 3.0, 100: 4.0} + max_lengths = MAX_LENGTHS if max_lengths is None else max_lengths + penalty_max = max_lengths[pctsp_size] * (penalty_factor) / float(pctsp_size) + penalty = np.random.uniform(size=(dataset_size, pctsp_size)) * penalty_max + + # Take uniform prizes + # Now expectation is 0.5 so expected total prize is n / 2, we want to force to visit approximately half of the nodes + # so the constraint will be that total prize >= (n / 2) / 2 = n / 4 + # equivalently, we divide all prizes by n / 4 and the total prize should be >= 1 + deterministic_prize = ( + np.random.uniform(size=(dataset_size, pctsp_size)) * 4 / float(pctsp_size) + ) + + # In the deterministic setting, the stochastic_prize is not used and the deterministic prize is known + # In the stochastic setting, the deterministic prize is the expected prize and is known up front but the + # stochastic prize is only revealed once the node is visited + # Stochastic prize is between (0, 2 * expected_prize) such that E(stochastic prize) = E(deterministic_prize) + stochastic_prize = ( + np.random.uniform(size=(dataset_size, pctsp_size)) * deterministic_prize * 2 + ) + + return { + "locs": loc.astype(np.float32), + "depot": depot.astype(np.float32), + "penalty": penalty.astype(np.float32), + "deterministic_prize": deterministic_prize.astype(np.float32), + "stochastic_prize": stochastic_prize.astype(np.float32), + } + + +def generate_mdpp_data( + dataset_size, + size=10, + num_probes_min=2, + num_probes_max=5, + num_keepout_min=1, + num_keepout_max=50, + lock_size=True, +): + """Generate data for the nDPP problem. + If `lock_size` is True, then the size if fixed and we skip the `size` argument if it is not 10. + This is because the RL environment is based on a real-world PCB (parametrized with data) + """ + if lock_size and size != 10: + # log.info("Locking size to 10, skipping generate_mdpp_data with size {}".format(size)) + return None + + bs = dataset_size # bs = batch_size to generate data in batch + m = n = size + if isinstance(bs, int): + bs = [bs] + + locs = np.stack(np.meshgrid(np.arange(m), np.arange(n)), axis=-1).reshape(-1, 2) + locs = locs / np.array([m, n], dtype=np.float32) + locs = np.expand_dims(locs, axis=0) + locs = np.repeat(locs, bs[0], axis=0) + + available = np.ones((bs[0], m * n), dtype=bool) + + probe = np.random.randint(0, high=m * n, size=(bs[0], 1)) + np.put_along_axis(available, probe, False, axis=1) + + num_probe = np.random.randint(num_probes_min, num_probes_max + 1, size=(bs[0], 1)) + probes = np.zeros((bs[0], m * n), dtype=bool) + for i in range(bs[0]): + p = np.random.choice(m * n, num_probe[i], replace=False) + np.put_along_axis(available[i], p, False, axis=0) + np.put_along_axis(probes[i], p, True, axis=0) + + num_keepout = np.random.randint(num_keepout_min, num_keepout_max + 1, size=(bs[0], 1)) + for i in range(bs[0]): + k = np.random.choice(m * n, num_keepout[i], replace=False) + np.put_along_axis(available[i], k, False, axis=0) + + return { + "locs": locs.astype(np.float32), + "probe": probes.astype(bool), + "action_mask": available.astype(bool), + } + + +def generate_dataset( + filename: Union[str, List[str]] = None, + data_dir: str = "data", + name: str = None, + problem: Union[str, List[str]] = "all", + data_distribution: str = "all", + dataset_size: int = 10000, + graph_sizes: Union[int, List[int]] = [20, 50, 100], + overwrite: bool = False, + seed: int = 1234, + disable_warning: bool = True, + distributions_per_problem: Union[int, dict] = None, +): + """We keep a similar structure as in Kool et al. 2019 but save and load the data as npz + This is way faster and more memory efficient than pickle and also allows for easy transfer to TensorDict + + Args: + filename: Filename to save the data to. If None, the data is saved to data_dir/problem/problem_graph_size_seed.npz. Defaults to None. + data_dir: Directory to save the data to. Defaults to "data". + name: Name of the dataset. Defaults to None. + problem: Problem to generate data for. Defaults to "all". + data_distribution: Data distribution to generate data for. Defaults to "all". + dataset_size: Number of datasets to generate. Defaults to 10000. + graph_sizes: Graph size to generate data for. Defaults to [20, 50, 100]. + overwrite: Whether to overwrite existing files. Defaults to False. + seed: Random seed. Defaults to 1234. + disable_warning: Whether to disable warnings. Defaults to True. + distributions_per_problem: Number of distributions to generate per problem. Defaults to None. + """ + + if isinstance(problem, list) and len(problem) == 1: + problem = problem[0] + + graph_sizes = [graph_sizes] if isinstance(graph_sizes, int) else graph_sizes + + if distributions_per_problem is None: + distributions_per_problem = DISTRIBUTIONS_PER_PROBLEM + + if problem == "all": + problems = distributions_per_problem + else: + problems = { + problem: distributions_per_problem[problem] + if data_distribution == "all" + else [data_distribution] + } + + # Support multiple filenames if necessary + filenames = [filename] if isinstance(filename, str) else filename + iter = 0 + + # Main loop for data generation. We loop over all problems, distributions and sizes + for problem, distributions in problems.items(): + for distribution in distributions or [None]: + for graph_size in graph_sizes: + if filename is None: + datadir = os.path.join(data_dir, problem) + os.makedirs(datadir, exist_ok=True) + fname = os.path.join( + datadir, + "{}{}{}_{}_seed{}.npz".format( + problem, + "_{}".format(distribution) + if distribution is not None + else "", + graph_size, + name, + seed, + ), + ) + else: + try: + fname = filenames[iter] + # make directory if necessary + os.makedirs(os.path.dirname(fname), exist_ok=True) + iter += 1 + except Exception: + raise ValueError( + "Number of filenames does not match number of problems" + ) + fname = check_extension(filename, extension=".npz") + + if not overwrite and os.path.isfile( + check_extension(fname, extension=".npz") + ): + if not disable_warning: + log.info( + "File {} already exists! Run with -f option to overwrite. Skipping...".format( + fname + ) + ) + continue + + # Set seed + np.random.seed(seed) + + # Automatically generate dataset + dataset = generate_env_data( + problem, dataset_size, graph_size, distribution + ) + + # A function can return None in case of an error or a skip + if dataset is not None: + # Save to disk as dict + log.info("Saving {} dataset to {}".format(problem, fname)) + np.savez(fname, **dataset) + + +def generate_default_datasets(data_dir, generate_eda=False): + """Generate the default datasets used in the paper and save them to data_dir/problem""" + generate_dataset(data_dir=data_dir, name="val", problem="all", seed=4321) + generate_dataset(data_dir=data_dir, name="test", problem="all", seed=1234) + + # By default, we skip the EDA datasets since they can easily be generated on the fly when needed + if generate_eda: + generate_dataset( + data_dir=data_dir, + name="test", + problem="mdpp", + seed=1234, + graph_sizes=[10], + dataset_size=100, + ) # EDA (mDPP) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "--filename", help="Filename of the dataset to create (ignores datadir)" + ) + parser.add_argument( + "--data_dir", + default="data", + help="Create datasets in data_dir/problem (default 'data')", + ) + parser.add_argument( + "--name", type=str, required=True, help="Name to identify dataset" + ) + parser.add_argument( + "--problem", + type=str, + default="all", + help="Problem, 'tsp', 'vrp', 'pctsp' or 'op_const', 'op_unif' or 'op_dist'" + " or 'all' to generate all", + ) + parser.add_argument( + "--data_distribution", + type=str, + default="all", + help="Distributions to generate for problem, default 'all'.", + ) + parser.add_argument( + "--dataset_size", type=int, default=10000, help="Size of the dataset" + ) + parser.add_argument( + "--graph_sizes", + type=int, + nargs="+", + default=[20, 50, 100], + help="Sizes of problem instances (default 20, 50, 100)", + ) + parser.add_argument("-f", action="store_true", help="Set true to overwrite") + parser.add_argument("--seed", type=int, default=1234, help="Random seed") + parser.add_argument("--disable_warning", action="store_true", help="Disable warning") + args = parser.parse_args() + + logging.basicConfig(level=logging.INFO) + + args.overwrite = args.f + delattr(args, "f") + generate_dataset(**vars(args)) diff --git a/rl4co/data/transforms.py b/rl4co/data/transforms.py new file mode 100644 index 00000000..6fb8807e --- /dev/null +++ b/rl4co/data/transforms.py @@ -0,0 +1,150 @@ +import math +from typing import Union +import torch + +from tensordict.tensordict import TensorDict +from torch import Tensor + +from rl4co.utils.ops import batchify +from rl4co.utils.pylogger import get_pylogger + + +log = get_pylogger(__name__) + + +def dihedral_8_augmentation(xy: Tensor) -> Tensor: + """ + Augmentation (x8) for grid-based data (x, y) as done in POMO. + This is a Dihedral group of order 8 (rotations and reflections) + https://en.wikipedia.org/wiki/Examples_of_groups#dihedral_group_of_order_8 + + Args: + xy: [batch, graph, 2] tensor of x and y coordinates + """ + # [batch, graph, 2] + x, y = xy.split(1, dim=2) + # augmnetations [batch, graph, 2] + z0 = torch.cat((x, y), dim=2) + z1 = torch.cat((1 - x, y), dim=2) + z2 = torch.cat((x, 1 - y), dim=2) + z3 = torch.cat((1 - x, 1 - y), dim=2) + z4 = torch.cat((y, x), dim=2) + z5 = torch.cat((1 - y, x), dim=2) + z6 = torch.cat((y, 1 - x), dim=2) + z7 = torch.cat((1 - y, 1 - x), dim=2) + # [batch*8, graph, 2] + aug_xy = torch.cat((z0, z1, z2, z3, z4, z5, z6, z7), dim=0) + return aug_xy + + +def dihedral_8_augmentation_wrapper( + xy: Tensor, reduce: bool = True, *args, **kw +) -> Tensor: + """Wrapper for dihedral_8_augmentation. If reduce, only return the first 1/8 of the augmented data + since the augmentation augments the data 8 times. + """ + xy = xy[: xy.shape[0] // 8, ...] if reduce else xy + return dihedral_8_augmentation(xy) + + +def symmetric_transform(x: Tensor, y: Tensor, phi: Tensor, offset: float = 0.5): + """SR group transform with rotation and reflection + Like the one in SymNCO, but a vectorized version + + Args: + x: [batch, graph, 1] tensor of x coordinates + y: [batch, graph, 1] tensor of y coordinates + phi: [batch, 1] tensor of random rotation angles + offset: offset for x and y coordinates + """ + x, y = x - offset, y - offset + # random rotation + x_prime = torch.cos(phi) * x - torch.sin(phi) * y + y_prime = torch.sin(phi) * x + torch.cos(phi) * y + # make random reflection if phi > 2*pi (i.e. 50% of the time) + mask = phi > 2 * math.pi + # vectorized random reflection: swap axes x and y if mask + xy = torch.cat((x_prime, y_prime), dim=-1) + xy = torch.where(mask, xy.flip(-1), xy) + return xy + offset + + +def symmetric_augmentation(xy: Tensor, num_augment: int = 8, first_augment: bool = False): + """Augment xy data by `num_augment` times via symmetric rotation transform and concatenate to original data + + Args: + xy: [batch, graph, 2] tensor of x and y coordinates + num_augment: number of augmentations + first_augment: whether to augment the first data point + """ + # create random rotation angles (4*pi for reflection, 2*pi for rotation) + phi = torch.rand(xy.shape[0], device=xy.device) * 4 * math.pi + + # set phi to 0 for first , i.e. no augmentation as in SymNCO + if not first_augment: + phi[: xy.shape[0] // num_augment] = 0.0 + x, y = xy[..., [0]], xy[..., [1]] + return symmetric_transform(x, y, phi[:, None, None]) + + +def min_max_normalize(x): + return (x - x.min()) / (x.max() - x.min()) + + +def get_augment_function(augment_fn: Union[str, callable]): + if callable(augment_fn): + return augment_fn + if augment_fn == "dihedral8": + return dihedral_8_augmentation_wrapper + if augment_fn == "symmetric": + return symmetric_augmentation + raise ValueError(f"Unknown augment_fn: {augment_fn}. Available options: 'symmetric', 'dihedral8' or a custom callable") + + +class StateAugmentation(object): + """Augment state by N times via symmetric rotation/reflection transform + + Args: + num_augment: number of augmentations + augment_fn: augmentation function to use, e.g. 'symmetric' (default) or 'dihedral8', if callable, + then use the function directly. If 'dihedral8', then num_augment must be 8 + first_aug_identity: whether to augment the first data point too + normalize: whether to normalize the augmented data + feats: list of features to augment + """ + + def __init__( + self, + num_augment: int = 8, + augment_fn: Union[str, callable] = 'symmetric', + first_aug_identity: bool = True, + normalize: bool = False, + feats: list = None, + ): + self.augmentation = get_augment_function(augment_fn) + assert not ( + self.augmentation == dihedral_8_augmentation_wrapper and num_augment != 8 + ), "When using the `dihedral8` augmentation function, then num_augment must be 8" + + if feats is None: + log.info("Features not passed, defaulting to 'locs'") + self.feats = ["locs"] + else: + self.feats = feats + self.num_augment = num_augment + self.normalize = normalize + self.first_aug_identity = first_aug_identity + + def __call__(self, td: TensorDict) -> TensorDict: + td_aug = batchify(td, self.num_augment) + for feat in self.feats: + if not self.first_aug_identity: + init_aug_feat = td_aug[feat][list(td.size()), 0].clone() + aug_feat = self.augmentation(td_aug[feat], self.num_augment) + if self.normalize: + aug_feat = min_max_normalize(aug_feat) + if not self.first_aug_identity: + aug_feat[list(td.size()), 0] = init_aug_feat + td_aug[feat] = aug_feat + + return td_aug diff --git a/rl4co/data/utils.py b/rl4co/data/utils.py new file mode 100644 index 00000000..f8a1e288 --- /dev/null +++ b/rl4co/data/utils.py @@ -0,0 +1,71 @@ +import os + +import numpy as np + +from tensordict.tensordict import TensorDict + +CURR_DIR = os.path.dirname(os.path.abspath(__file__)) +ROOT_PATH = os.path.dirname(os.path.dirname(CURR_DIR)) + + +def load_npz_to_tensordict(filename): + """Load a npz file directly into a TensorDict + We assume that the npz file contains a dictionary of numpy arrays + This is at least an order of magnitude faster than pickle + """ + x = np.load(filename) + x_dict = dict(x) + batch_size = x_dict[list(x_dict.keys())[0]].shape[0] + return TensorDict(x_dict, batch_size=batch_size) + + +def save_tensordict_to_npz(tensordict, filename, compress: bool = False): + """Save a TensorDict to a npz file + We assume that the TensorDict contains a dictionary of tensors + """ + x_dict = {k: v.numpy() for k, v in tensordict.items()} + if compress: + np.savez_compressed(filename, **x_dict) + else: + np.savez(filename, **x_dict) + + +def check_extension(filename, extension=".npz"): + """Check that filename has extension, otherwise add it""" + if os.path.splitext(filename)[1] != extension: + return filename + extension + return filename + + +def load_solomon_instance(name, path=None, edge_weights=False): + """Load solomon instance from a file""" + import vrplib + + if not path: + path = "data/solomon/instances/" + path = os.path.join(ROOT_PATH, path) + if not os.path.isdir(path): + os.makedirs(path) + file_path = f"{path}{name}.txt" + if not os.path.isfile(file_path): + vrplib.download_instance(name=name, path=path) + return vrplib.read_instance( + path=file_path, + instance_format="solomon", + compute_edge_weights=edge_weights, + ) + + +def load_solomon_solution(name, path=None): + """Load solomon solution from a file""" + import vrplib + + if not path: + path = "data/solomon/solutions/" + path = os.path.join(ROOT_PATH, path) + if not os.path.isdir(path): + os.makedirs(path) + file_path = f"{path}{name}.sol" + if not os.path.isfile(file_path): + vrplib.download_solution(name=name, path=path) + return vrplib.read_solution(path=file_path) diff --git a/rl4co/envs/__init__.py b/rl4co/envs/__init__.py new file mode 100644 index 00000000..1c43a7d1 --- /dev/null +++ b/rl4co/envs/__init__.py @@ -0,0 +1,77 @@ +# Base environment +from rl4co.envs.common.base import RL4COEnvBase + +# EDA +from rl4co.envs.eda import DPPEnv, MDPPEnv + +# Graph +from rl4co.envs.graph import FLPEnv, MCPEnv + +# Routing +from rl4co.envs.routing import ( + ATSPEnv, + CVRPEnv, + CVRPTWEnv, + DenseRewardTSPEnv, + MDCPDPEnv, + MTSPEnv, + MTVRPEnv, + OPEnv, + PCTSPEnv, + PDPEnv, + PDPRuinRepairEnv, + SDVRPEnv, + SPCTSPEnv, + SVRPEnv, + TSPEnv, + TSPkoptEnv, +) + +# Scheduling +from rl4co.envs.scheduling import FFSPEnv, FJSPEnv, JSSPEnv, SMTWTPEnv + +# Register environments +ENV_REGISTRY = { + "atsp": ATSPEnv, + "cvrp": CVRPEnv, + "cvrptw": CVRPTWEnv, + "dpp": DPPEnv, + "ffsp": FFSPEnv, + "jssp": JSSPEnv, + "fjsp": FJSPEnv, + "mdpp": MDPPEnv, + "mtsp": MTSPEnv, + "op": OPEnv, + "pctsp": PCTSPEnv, + "pdp": PDPEnv, + "pdp_ruin_repair": PDPRuinRepairEnv, + "sdvrp": SDVRPEnv, + "svrp": SVRPEnv, + "spctsp": SPCTSPEnv, + "tsp": TSPEnv, + "smtwtp": SMTWTPEnv, + "mdcpdp": MDCPDPEnv, + "mtvrp": MTVRPEnv, + "tsp_kopt": TSPkoptEnv, + "mcp": MCPEnv, + "flp": FLPEnv, +} + + +def get_env(env_name: str, *args, **kwargs) -> RL4COEnvBase: + """Get environment by name. + + Args: + env_name: Environment name + *args: Positional arguments for environment + **kwargs: Keyword arguments for environment + + Returns: + Environment + """ + env_cls = ENV_REGISTRY.get(env_name, None) + if env_cls is None: + raise ValueError( + f"Unknown environment {env_name}. Available environments: {ENV_REGISTRY.keys()}" + ) + return env_cls(*args, **kwargs) diff --git a/rl4co/envs/common/__init__.py b/rl4co/envs/common/__init__.py new file mode 100644 index 00000000..20b8afba --- /dev/null +++ b/rl4co/envs/common/__init__.py @@ -0,0 +1,2 @@ +from .base import RL4COEnvBase +from .utils import Generator, get_sampler diff --git a/rl4co/envs/common/base.py b/rl4co/envs/common/base.py new file mode 100644 index 00000000..d2f4aa55 --- /dev/null +++ b/rl4co/envs/common/base.py @@ -0,0 +1,403 @@ +import abc + +from os.path import join as pjoin +from typing import Iterable, Optional + +import torch + +from tensordict.tensordict import TensorDict +from torchrl.envs import EnvBase + +from rl4co.data.dataset import TensorDictDataset +from rl4co.data.utils import load_npz_to_tensordict +from rl4co.utils.ops import get_num_starts, select_start_nodes +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class RL4COEnvBase(EnvBase, metaclass=abc.ABCMeta): + """Base class for RL4CO environments based on TorchRL EnvBase. + The environment has the usual methods for stepping, resetting, and getting the specifications of the environment + that shoud be implemented by the subclasses of this class. + It also has methods for getting the reward, action mask, and checking the validity of the solution, and + for generating and loading the datasets (supporting multiple dataloaders as well for validation and testing). + + Args: + data_dir: Root directory for the dataset + train_file: Name of the training file + val_file: Name of the validation file + test_file: Name of the test file + val_dataloader_names: Names of the dataloaders to use for validation + test_dataloader_names: Names of the dataloaders to use for testing + check_solution: Whether to check the validity of the solution at the end of the episode + dataset_cls: Dataset class to use for the environment (which can influence performance) + seed: Seed for the environment + device: Device to use. Generally, no need to set as tensors are updated on the fly + batch_size: Batch size to use for the environment. Generally, no need to set as tensors are updated on the fly + run_type_checks: If True, run type checks on the TensorDicts at each step + allow_done_after_reset: If True, an environment can be done after a reset + _torchrl_mode: Whether to use the TorchRL mode (see :meth:`step` for more details) + """ + + batch_locked = False + + def __init__( + self, + *, + data_dir: str = "data/", + train_file: str = None, + val_file: str = None, + test_file: str = None, + val_dataloader_names: list = None, + test_dataloader_names: list = None, + check_solution: bool = True, + dataset_cls: callable = TensorDictDataset, + seed: int = None, + device: str = "cpu", + batch_size: torch.Size = None, + run_type_checks: bool = False, + allow_done_after_reset: bool = False, + _torchrl_mode: bool = False, + **kwargs, + ): + super().__init__( + device=device, + batch_size=batch_size, + run_type_checks=run_type_checks, + allow_done_after_reset=allow_done_after_reset, + ) + # if any kwargs are left, we want to warn the user + kwargs.pop("name", None) # we remove the name for checking + if kwargs: + log.error( + f"Unused keyword arguments: {', '.join(kwargs.keys())}. " + "Please check the base class documentation at https://rl4co.readthedocs.io/en/latest/_content/api/envs/base.html. " + "In case you would like to pass data generation arguments, please pass a `generator` method instead " + "or for example: `generator_kwargs=dict(num_loc=50)` to the constructor." + ) + self.data_dir = data_dir + self.train_file = pjoin(data_dir, train_file) if train_file is not None else None + self._torchrl_mode = _torchrl_mode + self.dataset_cls = dataset_cls + + def get_files(f): + if f is not None: + if isinstance(f, Iterable) and not isinstance(f, str): + return [pjoin(data_dir, _f) for _f in f] + else: + return pjoin(data_dir, f) + return None + + def get_multiple_dataloader_names(f, names): + if f is not None: + if isinstance(f, Iterable) and not isinstance(f, str): + if names is None: + names = [f"{i}" for i in range(len(f))] + else: + assert len(names) == len( + f + ), "Number of dataloader names must match number of files" + else: + if names is not None: + log.warning( + "Ignoring dataloader names since only one dataloader is provided" + ) + return names + + self.val_file = get_files(val_file) + self.test_file = get_files(test_file) + self.val_dataloader_names = get_multiple_dataloader_names( + self.val_file, val_dataloader_names + ) + self.test_dataloader_names = get_multiple_dataloader_names( + self.test_file, test_dataloader_names + ) + self.check_solution = check_solution + if seed is None: + seed = torch.empty((), dtype=torch.int64).random_().item() + self.set_seed(seed) + + def step(self, td: TensorDict) -> TensorDict: + """Step function to call at each step of the episode containing an action. + If `_torchrl_mode` is True, we call `_torchrl_step` instead which set the + `next` key of the TensorDict to the next state - this is the usual way to do it in TorchRL, + but inefficient in our case + """ + if not self._torchrl_mode: + # Default: just return the TensorDict without farther checks etc is faster + td = self._step(td) + return {"next": td} + else: + # Since we simplify the syntax + return self._torchrl_step(td) + + def reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: + """Reset function to call at the beginning of each episode""" + if batch_size is None: + batch_size = self.batch_size if td is None else td.batch_size + if td is None or td.is_empty(): + td = self.generator(batch_size=batch_size) + batch_size = [batch_size] if isinstance(batch_size, int) else batch_size + self.to(td.device) + return super().reset(td, batch_size=batch_size) + + def _torchrl_step(self, td: TensorDict) -> TensorDict: + """See :meth:`super().step` for more details. + This is the usual way to do it in TorchRL, but inefficient in our case + + Note: + Here we clone the TensorDict to avoid recursion error, since we allow + for directly updating the TensorDict in the step function + """ + # sanity check + self._assert_tensordict_shape(td) + next_preset = td.get("next", None) + + next_tensordict = self._step( + td.clone() + ) # NOTE: we clone to avoid recursion error + next_tensordict = self._step_proc_data(next_tensordict) + if next_preset is not None: + next_tensordict.update(next_preset.exclude(*next_tensordict.keys(True, True))) + td.set("next", next_tensordict) + return td + + @abc.abstractmethod + def _step(self, td: TensorDict) -> TensorDict: + """Step function to call at each step of the episode containing an action. + Gives the next observation, reward, done + """ + raise NotImplementedError + + @abc.abstractmethod + def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: + """Reset function to call at the beginning of each episode""" + raise NotImplementedError + + def _make_spec(self, td_params: TensorDict = None): + """Make the specifications of the environment (observation, action, reward, done)""" + raise NotImplementedError + + def get_reward(self, td: TensorDict, actions: torch.Tensor) -> torch.Tensor: + """Function to compute the reward. Can be called by the agent to compute the reward of the current state + This is faster than calling step() and getting the reward from the returned TensorDict at each time for CO tasks + """ + if self.check_solution: + self.check_solution_validity(td, actions) + return self._get_reward(td, actions) + + @abc.abstractmethod + def _get_reward(self, td, actions) -> TensorDict: + """Function to compute the reward. Can be called by the agent to compute the reward of the current state + This is faster than calling step() and getting the reward from the returned TensorDict at each time for CO tasks + """ + raise NotImplementedError + + def get_action_mask(self, td: TensorDict) -> torch.Tensor: + """Function to compute the action mask (feasible actions) for the current state + Action mask is 1 if the action is feasible, 0 otherwise + """ + raise NotImplementedError + + def get_num_starts(self, td): + return get_num_starts(td, self.name) + + def select_start_nodes(self, td, num_starts): + return select_start_nodes(td, self, num_starts) + + def check_solution_validity(self, td: TensorDict, actions: torch.Tensor) -> None: + """Function to check whether the solution is valid. Can be called by the agent to check the validity of the current state + This is called with the full solution (i.e. all actions) at the end of the episode + """ + raise NotImplementedError + + def replace_selected_actions( + self, + cur_actions: torch.Tensor, + new_actions: torch.Tensor, + selection_mask: torch.Tensor, + ) -> torch.Tensor: + """ + Replace selected current actions with updated actions based on `selection_mask`. + """ + raise NotImplementedError + + def local_search( + self, td: TensorDict, actions: torch.Tensor, **kwargs + ) -> torch.Tensor: + """Function to improve the solution. Can be called by the agent to improve the current state + This is called with the full solution (i.e. all actions) at the end of the episode + """ + raise NotImplementedError( + f"Local is not implemented yet for {self.name} environment" + ) + + def dataset(self, batch_size=[], phase="train", filename=None): + """Return a dataset of observations + Generates the dataset if it does not exist, otherwise loads it from file + """ + if filename is not None: + log.info(f"Overriding dataset filename from {filename}") + f = getattr(self, f"{phase}_file") if filename is None else filename + if f is None: + if phase != "train": + log.warning(f"{phase}_file not set. Generating dataset instead") + td = self.generator(batch_size) + else: + log.info(f"Loading {phase} dataset from {f}") + if phase == "train": + log.warning( + "Loading training dataset from file. This may not be desired in RL since " + "the dataset is fixed and the agent will not be able to explore new states" + ) + try: + if isinstance(f, Iterable) and not isinstance(f, str): + names = getattr(self, f"{phase}_dataloader_names") + return { + name: self.dataset_cls(self.load_data(_f, batch_size)) + for name, _f in zip(names, f) + } + else: + td = self.load_data(f, batch_size) + except FileNotFoundError: + log.error( + f"Provided file name {f} not found. Make sure to provide a file in the right path first or " + f"unset {phase}_file to generate data automatically instead" + ) + td = self.generator(batch_size) + + return self.dataset_cls(td) + + def transform(self): + """Used for converting TensorDict variables (such as with torch.cat) efficiently + https://pytorch.org/rl/reference/generated/torchrl.envs.transforms.Transform.html + By default, we do not need to transform the environment since we use specific embeddings + """ + return self + + def render(self, *args, **kwargs): + """Render the environment""" + raise NotImplementedError + + @staticmethod + def load_data(fpath, batch_size=[]): + """Dataset loading from file""" + return load_npz_to_tensordict(fpath) + + def _set_seed(self, seed: Optional[int]): + """Set the seed for the environment""" + rng = torch.manual_seed(seed) + self.rng = rng + + def to(self, device): + """Override `to` device method for safety against `None` device (may be found in `TensorDict`)""" + if device is None: + return self + else: + return super().to(device) + + @staticmethod + def solve( + instances: TensorDict, + max_runtime: float, + num_procs: int = 1, + **kwargs, + ) -> tuple[torch.Tensor, torch.Tensor]: + """Classical solver for the environment. This is a wrapper for the baselines solver. + + Args: + instances: The instances to solve + max_runtime: The maximum runtime for the solver + num_procs: The number of processes to use + + Returns: + A tuple containing the action and the cost, respectively + """ + raise NotImplementedError + + def __getstate__(self): + """Return the state of the environment. By default, we want to avoid pickling + the random number generator directly as it is not allowed by `deepcopy` + """ + state = self.__dict__.copy() + state["rng"] = state["rng"].get_state() + return state + + def __setstate__(self, state): + """Set the state of the environment. By default, we want to avoid pickling + the random number generator directly as it is not allowed by `deepcopy` + """ + self.__dict__.update(state) + self.rng = torch.manual_seed(0) + self.rng.set_state(state["rng"]) + + +class ImprovementEnvBase(RL4COEnvBase, metaclass=abc.ABCMeta): + """Base class for Improvement environments based on RL4CO EnvBase. + Note that this class assumes that the solution is stored in a linked list format. + Here, if `rec[i] = j`, it means the node `i` is connected to node `j`, i.e., edge `i-j` is in the solution. + For example, if edge `0-1`, edge `1-5`, edge `2-10` are in the solution, so we have `rec[0]=1`, `rec[1]=5` and `rec[2]=10`. + Kindly see https://github.com/yining043/VRP-DACT/blob/new_version/Play_with_DACT.ipynb for an example at the end for TSP. + """ + + def __init__( + self, + **kwargs, + ): + super().__init__(**kwargs) + + @abc.abstractmethod + def _step(self, td: TensorDict, solution_to=None) -> TensorDict: + raise NotImplementedError + + def step_to_solution(self, td, solution) -> TensorDict: + return self._step(td, solution_to=solution) + + @staticmethod + def _get_reward(td, actions) -> TensorDict: + raise NotImplementedError( + "This function is not used for improvement tasks since the reward is computed per step" + ) + + @staticmethod + def get_costs(coordinates, rec): + batch_size, size = rec.size() + + # calculate the route length value + d1 = coordinates.gather(1, rec.long().unsqueeze(-1).expand(batch_size, size, 2)) + d2 = coordinates + length = (d1 - d2).norm(p=2, dim=2).sum(1) + + return length + + @staticmethod + def _get_real_solution(rec): + batch_size, seq_length = rec.size() + visited_time = torch.zeros((batch_size, seq_length)).to(rec.device) + pre = torch.zeros((batch_size), device=rec.device).long() + for i in range(seq_length): + visited_time[torch.arange(batch_size), rec[torch.arange(batch_size), pre]] = ( + i + 1 + ) + pre = rec[torch.arange(batch_size), pre] + + visited_time = visited_time % seq_length + return visited_time.argsort() + + @staticmethod + def _get_linked_list_solution(solution): + solution_pre = solution + solution_post = torch.cat((solution[:, 1:], solution[:, :1]), 1) + + rec = solution.clone() + rec.scatter_(1, solution_pre, solution_post) + return rec + + @classmethod + def get_best_solution(cls, td): + return cls._get_real_solution(td["rec_best"]) + + @classmethod + def get_current_solution(cls, td): + return cls._get_real_solution(td["rec_current"]) diff --git a/rl4co/envs/common/distribution_utils.py b/rl4co/envs/common/distribution_utils.py new file mode 100644 index 00000000..ab8e1449 --- /dev/null +++ b/rl4co/envs/common/distribution_utils.py @@ -0,0 +1,292 @@ +import random + +import torch + + +class Cluster: + """ + Multiple gaussian distributed clusters, as in the Solomon benchmark dataset + Following the setting in Bi et al. 2022 (https://arxiv.org/abs/2210.07686) + + Args: + n_cluster: Number of the gaussian distributed clusters + """ + + def __init__(self, n_cluster: int = 3): + super().__init__() + self.lower, self.upper = 0.2, 0.8 + self.std = 0.07 + self.n_cluster = n_cluster + + def sample(self, size): + + batch_size, num_loc, _ = size + + # Generate the centers of the clusters + center = self.lower + (self.upper - self.lower) * torch.rand( + batch_size, self.n_cluster * 2 + ) + + # Pre-define the coordinates + coords = torch.zeros(batch_size, num_loc, 2) + + # Calculate the size of each cluster + cluster_sizes = [num_loc // self.n_cluster] * self.n_cluster + for i in range(num_loc % self.n_cluster): + cluster_sizes[i] += 1 + + # Generate the coordinates + current_index = 0 + for i in range(self.n_cluster): + means = center[:, i * 2 : (i + 1) * 2] + stds = torch.full((batch_size, 2), self.std) + points = torch.normal( + means.unsqueeze(1).expand(-1, cluster_sizes[i], -1), + stds.unsqueeze(1).expand(-1, cluster_sizes[i], -1), + ) + coords[:, current_index : current_index + cluster_sizes[i], :] = points + current_index += cluster_sizes[i] + + # Confine the coordinates to range [0, 1] + coords.clamp_(0, 1) + + return coords + + +class Mixed: + """ + 50% nodes sampled from uniform distribution, 50% nodes sampled from gaussian distribution, as in the Solomon benchmark dataset + Following the setting in Bi et al. 2022 (https://arxiv.org/abs/2210.07686) + + Args: + n_cluster_mix: Number of the gaussian distributed clusters + """ + + def __init__(self, n_cluster_mix=1): + super().__init__() + self.lower, self.upper = 0.2, 0.8 + self.std = 0.07 + self.n_cluster_mix = n_cluster_mix + + def sample(self, size): + + batch_size, num_loc, _ = size + + # Generate the centers of the clusters + center = self.lower + (self.upper - self.lower) * torch.rand( + batch_size, self.n_cluster_mix * 2 + ) + + # Pre-define the coordinates sampled under uniform distribution + coords = torch.FloatTensor(batch_size, num_loc, 2).uniform_(0, 1) + + # Sample mutated index (default setting: 50% mutation) + mutate_idx = torch.stack( + [torch.randperm(num_loc)[: num_loc // 2] for _ in range(batch_size)] + ) + + # Generate the coordinates + segment_size = num_loc // (2 * self.n_cluster_mix) + remaining_indices = num_loc // 2 - segment_size * (self.n_cluster_mix - 1) + sizes = [segment_size] * (self.n_cluster_mix - 1) + [remaining_indices] + for i in range(self.n_cluster_mix): + indices = mutate_idx[:, sum(sizes[:i]) : sum(sizes[: i + 1])] + means_x = center[:, 2 * i].unsqueeze(1).expand(-1, sizes[i]) + means_y = center[:, 2 * i + 1].unsqueeze(1).expand(-1, sizes[i]) + coords.scatter_( + 1, + indices.unsqueeze(-1).expand(-1, -1, 2), + torch.stack( + [ + torch.normal(means_x.expand(-1, sizes[i]), self.std), + torch.normal(means_y.expand(-1, sizes[i]), self.std), + ], + dim=2, + ), + ) + + # Confine the coordinates to range [0, 1] + coords.clamp_(0, 1) + + return coords + + +class Gaussian_Mixture: + """ + Following Zhou et al. (2023): https://arxiv.org/abs/2305.19587 + + Args: + num_modes: the number of clusters/modes in the Gaussian Mixture. + cdist: scale of the uniform distribution for center generation. + """ + + def __init__(self, num_modes: int = 0, cdist: int = 0): + super().__init__() + self.num_modes = num_modes + self.cdist = cdist + + def sample(self, size): + + batch_size, num_loc, _ = size + + if self.num_modes == 0: # (0, 0) - uniform + return torch.rand((batch_size, num_loc, 2)) + elif self.num_modes == 1 and self.cdist == 1: # (1, 1) - gaussian + return self.generate_gaussian(batch_size, num_loc) + else: + res = [self.generate_gaussian_mixture(num_loc) for _ in range(batch_size)] + return torch.stack(res) + + def generate_gaussian_mixture(self, num_loc): + """Following the setting in Zhang et al. 2022 (https://arxiv.org/abs/2204.03236)""" + + # Randomly decide how many points each mode gets + nums = torch.multinomial( + input=torch.ones(self.num_modes) / self.num_modes, + num_samples=num_loc, + replacement=True, + ) + + # Prepare to collect points + coords = torch.empty((0, 2)) + + # Generate points for each mode + for i in range(self.num_modes): + num = (nums == i).sum() # Number of points in this mode + if num > 0: + center = torch.rand((1, 2)) * self.cdist + cov = torch.eye(2) # Covariance matrix + nxy = torch.distributions.MultivariateNormal( + center.squeeze(), covariance_matrix=cov + ).sample((num,)) + coords = torch.cat((coords, nxy), dim=0) + + return self._global_min_max_scaling(coords) + + def generate_gaussian(self, batch_size, num_loc): + """Following the setting in Xin et al. 2022 (https://openreview.net/pdf?id=nJuzV-izmPJ)""" + + # Mean and random covariances + mean = torch.full((batch_size, num_loc, 2), 0.5) + covs = torch.rand(batch_size) # Random covariances between 0 and 1 + + # Generate the coordinates + coords = torch.zeros((batch_size, num_loc, 2)) + for i in range(batch_size): + # Construct covariance matrix for each sample + cov_matrix = torch.tensor([[1.0, covs[i]], [covs[i], 1.0]]) + m = torch.distributions.MultivariateNormal( + mean[i], covariance_matrix=cov_matrix + ) + coords[i] = m.sample() + + # Shuffle the coordinates + indices = torch.randperm(coords.size(0)) + coords = coords[indices] + + return self._batch_normalize_and_center(coords) + + def _global_min_max_scaling(self, coords): + + # Scale the points to [0, 1] using min-max scaling + coords_min = coords.min(0, keepdim=True).values + coords_max = coords.max(0, keepdim=True).values + coords = (coords - coords_min) / (coords_max - coords_min) + + return coords + + def _batch_normalize_and_center(self, coords): + # Step 1: Compute min and max along each batch + coords_min = coords.min(dim=1, keepdim=True).values + coords_max = coords.max(dim=1, keepdim=True).values + + # Step 2: Normalize coordinates to range [0, 1] + coords = ( + coords - coords_min + ) # Broadcasting subtracts min value on each coordinate + range_max = ( + (coords_max - coords_min).max(dim=-1, keepdim=True).values + ) # The maximum range among both coordinates + coords = coords / range_max # Divide by the max range to normalize + + # Step 3: Center the batch in the middle of the [0, 1] range + coords = ( + coords + (1 - coords.max(dim=1, keepdim=True).values) / 2 + ) # Centering the batch + + return coords + + +class Mix_Distribution: + """ + Mixture of three exemplar distributions in batch-level, i.e. Uniform, Cluster, Mixed + Following the setting in Bi et al. 2022 (https://arxiv.org/abs/2210.07686) + + Args: + n_cluster: Number of the gaussian distributed clusters in Cluster distribution + n_cluster_mix: Number of the gaussian distributed clusters in Mixed distribution + """ + + def __init__(self, n_cluster=3, n_cluster_mix=1): + super().__init__() + self.lower, self.upper = 0.2, 0.8 + self.std = 0.07 + self.Mixed = Mixed(n_cluster_mix=n_cluster_mix) + self.Cluster = Cluster(n_cluster=n_cluster) + + def sample(self, size): + + batch_size, num_loc, _ = size + + # Pre-define the coordinates sampled under uniform distribution + coords = torch.FloatTensor(batch_size, num_loc, 2).uniform_(0, 1) + + # Random sample probability for the distribution of each sample + p = torch.rand(batch_size) + + # Mixed + mask = p <= 0.33 + n_mixed = mask.sum().item() + if n_mixed > 0: + coords[mask] = self.Mixed.sample((n_mixed, num_loc, 2)) + + # Cluster + mask = (p > 0.33) & (p <= 0.66) + n_cluster = mask.sum().item() + if n_cluster > 0: + coords[mask] = self.Cluster.sample((n_cluster, num_loc, 2)) + + # The remaining ones are uniformly distributed + return coords + + +class Mix_Multi_Distributions: + """ + Mixture of 11 Gaussian-like distributions in batch-level + Following the setting in Zhou et al. (2023): https://arxiv.org/abs/2305.19587 + """ + + def __init__(self): + super().__init__() + self.dist_set = [(0, 0), (1, 1)] + [ + (m, c) for m in [3, 5, 7] for c in [10, 30, 50] + ] + + def sample(self, size): + batch_size, num_loc, _ = size + coords = torch.zeros(batch_size, num_loc, 2) + + # Pre-select distributions for the entire batch + dists = [random.choice(self.dist_set) for _ in range(batch_size)] + unique_dists = list( + set(dists) + ) # Unique distributions to minimize re-instantiation + + # Instantiate Gaussian_Mixture only once per unique distribution + gm_instances = {dist: Gaussian_Mixture(*dist) for dist in unique_dists} + + # Batch process where possible + for i, dist in enumerate(dists): + coords[i] = gm_instances[dist].sample((1, num_loc, 2)).squeeze(0) + + return coords diff --git a/rl4co/envs/common/utils.py b/rl4co/envs/common/utils.py new file mode 100644 index 00000000..413742d0 --- /dev/null +++ b/rl4co/envs/common/utils.py @@ -0,0 +1,109 @@ +import abc + +from typing import Callable, Union + +import torch + +from tensordict.tensordict import TensorDict +from torch.distributions import Exponential, Normal, Poisson, Uniform + +from rl4co.envs.common.distribution_utils import ( + Cluster, + Gaussian_Mixture, + Mix_Distribution, + Mix_Multi_Distributions, + Mixed, +) + + +class Generator(metaclass=abc.ABCMeta): + """Base data generator class, to be called with `env.generator(batch_size)`""" + + def __init__(self, **kwargs): + self.kwargs = kwargs + + def __call__(self, batch_size) -> TensorDict: + batch_size = [batch_size] if isinstance(batch_size, int) else batch_size + return self._generate(batch_size) + + @abc.abstractmethod + def _generate(self, batch_size, **kwargs) -> TensorDict: + raise NotImplementedError + + +def get_sampler( + val_name: str, + distribution: Union[int, float, str, type, Callable], + low: float = 0, + high: float = 1.0, + **kwargs, +): + """Get the sampler for the variable with the given distribution. + If kwargs are passed, they will be parsed e.g. with `val_name` + `_dist_arg` (e.g. `loc_std` for Normal distribution). + + Args: + val_name: Name of the variable + distribution: int/float value (as constant distribution), or string with the distribution name (supporting + uniform, normal, exponential, and poisson) or PyTorch Distribution type or a callable function that + returns a PyTorch Distribution + low: Minimum value for the variable, used for Uniform distribution + high: Maximum value for the variable, used for Uniform distribution + kwargs: Additional arguments for the distribution + + Example: + ```python + sampler_uniform = get_sampler("loc", "uniform", 0, 1) + sampler_normal = get_sampler("loc", "normal", loc_mean=0.5, loc_std=.2) + ``` + """ + if isinstance(distribution, (int, float)): + return Uniform(low=distribution, high=distribution) + elif distribution == Uniform or distribution == "uniform": + return Uniform(low=low, high=high) + elif distribution == Normal or distribution == "normal" or distribution == "gaussian": + assert ( + kwargs.get(val_name + "_mean", None) is not None + ), "mean is required for Normal distribution" + assert ( + kwargs.get(val_name + "_std", None) is not None + ), "std is required for Normal distribution" + return Normal(loc=kwargs[val_name + "_mean"], scale=kwargs[val_name + "_std"]) + elif distribution == Exponential or distribution == "exponential": + assert ( + kwargs.get(val_name + "_rate", None) is not None + ), "rate is required for Exponential/Poisson distribution" + return Exponential(rate=kwargs[val_name + "_rate"]) + elif distribution == Poisson or distribution == "poisson": + assert ( + kwargs.get(val_name + "_rate", None) is not None + ), "rate is required for Exponential/Poisson distribution" + return Poisson(rate=kwargs[val_name + "_rate"]) + elif distribution == "center": + return Uniform(low=(high - low) / 2, high=(high - low) / 2) + elif distribution == "corner": + return Uniform( + low=low, high=low + ) # todo: should be also `low, high` and any other corner + elif isinstance(distribution, Callable): + return distribution(**kwargs) + elif distribution == "gaussian_mixture": + return Gaussian_Mixture(num_modes=kwargs["num_modes"], cdist=kwargs["cdist"]) + elif distribution == "cluster": + return Cluster(kwargs["n_cluster"]) + elif distribution == "mixed": + return Mixed(kwargs["n_cluster_mix"]) + elif distribution == "mix_distribution": + return Mix_Distribution(kwargs["n_cluster"], kwargs["n_cluster_mix"]) + elif distribution == "mix_multi_distributions": + return Mix_Multi_Distributions() + else: + raise ValueError(f"Invalid distribution type of {distribution}") + + +def batch_to_scalar(param): + """Return first element if in batch. Used for batched parameters that are the same for all elements in the batch.""" + if len(param.shape) > 0: + return param[0].item() + if isinstance(param, torch.Tensor): + return param.item() + return param diff --git a/rl4co/envs/eda/__init__.py b/rl4co/envs/eda/__init__.py new file mode 100644 index 00000000..ce8f2f8c --- /dev/null +++ b/rl4co/envs/eda/__init__.py @@ -0,0 +1,2 @@ +from rl4co.envs.eda.dpp.env import DPPEnv +from rl4co.envs.eda.mdpp.env import MDPPEnv diff --git a/rl4co/envs/eda/dpp/__init__.py b/rl4co/envs/eda/dpp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/eda/dpp/env.py b/rl4co/envs/eda/dpp/env.py new file mode 100644 index 00000000..c8d89430 --- /dev/null +++ b/rl4co/envs/eda/dpp/env.py @@ -0,0 +1,260 @@ +import os +import zipfile + +from typing import Optional + +import numpy as np +import torch + +from robust_downloader import download +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.data.utils import load_npz_to_tensordict +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.utils.pylogger import get_pylogger + +from .generator import DPPGenerator +from .render import render + +log = get_pylogger(__name__) + + +class DPPEnv(RL4COEnvBase): + """Decap Placement Problem (DPP) as done in DevFormer paper: https://arxiv.org/abs/2205.13225 + + The environment is a 10x10 grid with 100 locations containing either a probing port or a keepout region. + The goal is to place decaps (decoupling capacitors) to maximize the impedance suppression at the probing port. + Decaps cannot be placed in keepout regions or at the probing port and the number of decaps is limited. + + Observations: + - locations of the probing port and keepout regions + - current decap placement + - remaining decaps + + Constraints: + - decaps cannot be placed at the probing port or keepout regions + - the number of decaps is limited + + Finish Condition: + - the number of decaps exceeds the limit + + Reward: + - the impedance suppression at the probing port + + Args: + generator: DPPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "dpp" + + def __init__( + self, + generator: DPPGenerator = None, + generator_params: dict = {}, + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = DPPGenerator(**generator_params) + self.generator = generator + + self.max_decaps = self.generator.max_decaps + self.size = self.generator.size + self.raw_pdn = self.generator.raw_pdn + self.decap = self.generator.decap + self.freq = self.generator.freq + self.num_freq = self.generator.num_freq + self.data_dir = self.generator.data_dir + + self._make_spec(self.generator) + + def _step(self, td: TensorDict) -> TensorDict: + current_node = td["action"] + + # Set available to 0 (i.e., already placed) if the current node is the first node + available = td["action_mask"].scatter( + -1, current_node.unsqueeze(-1).expand_as(td["action_mask"]), 0 + ) + + # Set done if i is greater than max_decaps + done = td["i"] >= self.max_decaps - 1 + + # The reward is calculated outside via get_reward for efficiency, so we set it to 0 here + reward = torch.zeros_like(done) + + td.update( + { + "i": td["i"] + 1, + "action_mask": available, + "reward": reward, + "done": done, + } + ) + return td + + def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: + device = td.device + + # Other variables + i = torch.zeros((*batch_size, 1), dtype=torch.int64, device=device) + + return TensorDict( + { + "locs": td["locs"], + "probe": td["probe"], + "i": i, + "action_mask": td["action_mask"], + "keepout": ~td["action_mask"], + }, + batch_size=batch_size, + ) + + def _make_spec(self, generator: DPPGenerator): + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(generator.size**2, 2), + dtype=torch.float32, + ), + probe=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + keepout=UnboundedDiscreteTensorSpec( + shape=(generator.size**2), + dtype=torch.bool, + ), + i=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(generator.size**2), + dtype=torch.bool, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=0, + high=generator.size**2, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + def _get_reward(self, td, actions): + """ + We call the reward function with the final sequence of actions to get the reward + Calling per-step would be very time consuming due to decap simulation + """ + # We do the operation in a batch + if len(td.batch_size) == 0: + td = td.unsqueeze(0) + actions = actions.unsqueeze(0) + probes = td["probe"] + reward = torch.stack( + [self._decap_simulator(p, a) for p, a in zip(probes, actions)] + ) + return reward + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor): + assert True, "Not implemented" + + def _decap_placement(self, pi, probe): + device = pi.device + + n = m = self.size # columns and rows + num_decap = torch.numel(pi) + z1 = self.raw_pdn.to(device) + + decap = self.decap.reshape(-1).to(device) + z2 = torch.zeros( + (self.num_freq, num_decap, num_decap), dtype=torch.float32, device=device + ) + + qIndx = torch.arange(num_decap, device=device) + + z2[:, qIndx, qIndx] = torch.abs(decap)[:, None].repeat_interleave( + z2[:, qIndx, qIndx].shape[-1], dim=-1 + ) + pIndx = pi.long() + + aIndx = torch.arange(len(z1[0]), device=device) + aIndx = torch.tensor( + list(set(aIndx.tolist()) - set(pIndx.tolist())), device=device + ) + + z1aa = z1[:, aIndx, :][:, :, aIndx] + z1ap = z1[:, aIndx, :][:, :, pIndx] + z1pa = z1[:, pIndx, :][:, :, aIndx] + z1pp = z1[:, pIndx, :][:, :, pIndx] + z2qq = z2[:, qIndx, :][:, :, qIndx] + + zout = z1aa - torch.matmul(torch.matmul(z1ap, torch.inverse(z1pp + z2qq)), z1pa) + + idx = torch.arange(n * m, device=device) + mask = torch.zeros(n * m, device=device).bool() + mask[pi] = True + mask = mask & (idx < probe) + probe -= mask.sum().item() + + zout = zout[:, probe, probe] + return zout + + def _decap_model(self, z_initial, z_final): + impedance_gap = torch.zeros(self.num_freq, device=self.device) + + impedance_gap = z_initial - z_final + reward = torch.sum(impedance_gap * 1000000000 / self.freq.to(self.device)) + + reward = reward / 10 + return reward + + def _initial_impedance(self, probe): + zout = self.raw_pdn.to(self.device)[:, probe, probe] + return zout + + def _decap_simulator(self, probe, solution, keepout=None): + self.to(self.device) + + probe = probe.item() + + assert len(solution) == len( + torch.unique(solution) + ), "An Element of Decap Sequence must be Unique" + + if keepout is not None: + keepout = torch.tensor(keepout) + intersect = torch.tensor(list(set(solution.tolist()) & set(keepout.tolist()))) + assert len(intersect) == 0, "Decap must be not placed at the keepout region" + + z_initial = self._initial_impedance(probe) + z_initial = torch.abs(z_initial) + z_final = self._decap_placement(solution, probe) + z_final = torch.abs(z_final) + reward = self._decap_model(z_initial, z_final) + return reward + + def _load_dpp_data(self, chip_file, decap_file, freq_file): + def _load_file(fpath): + f = os.path.join(self.generator.data_dir, fpath) + if not os.path.isfile(f): + self._download_data() + with open(f, "rb") as f_: + return torch.from_numpy(np.load(f_)).to(self.device) + + self.raw_pdn = _load_file(chip_file) # [num_freq, size^2, size^2] + self.decap = _load_file(decap_file).to(torch.complex64) # [num_freq, 1, 1] + self.freq = _load_file(freq_file) # [num_freq] + self.size = int(np.sqrt(self.raw_pdn.shape[-1])) + self.num_freq = self.freq.shape[0] diff --git a/rl4co/envs/eda/dpp/generator.py b/rl4co/envs/eda/dpp/generator.py new file mode 100644 index 00000000..d34b8e7c --- /dev/null +++ b/rl4co/envs/eda/dpp/generator.py @@ -0,0 +1,169 @@ +import os +import zipfile +from typing import Union, Callable + +import torch +import numpy as np + +from robust_downloader import download +from torch.distributions import Uniform +from tensordict.tensordict import TensorDict + +from rl4co.data.utils import load_npz_to_tensordict +from rl4co.utils.pylogger import get_pylogger +from rl4co.envs.common.utils import get_sampler, Generator + +log = get_pylogger(__name__) + + + +class DPPGenerator(Generator): + """Data generator for the Decap Placement Problem (DPP). + + Args: + min_loc: Minimum location value. Defaults to 0. + max_loc: Maximum location value. Defaults to 1. + num_keepout_min: Minimum number of keepout regions. Defaults to 1. + num_keepout_max: Maximum number of keepout regions. Defaults to 50. + max_decaps: Maximum number of decaps. Defaults to 20. + data_dir: Directory to store data. Defaults to "data/dpp/". + This can be downloaded from this [url](https://drive.google.com/uc?id=1IEuR2v8Le-mtHWHxwTAbTOPIkkQszI95). + chip_file: Name of the chip file. Defaults to "10x10_pkg_chip.npy". + decap_file: Name of the decap file. Defaults to "01nF_decap.npy". + freq_file: Name of the frequency file. Defaults to "freq_201.npy". + url: URL to download data from. Defaults to None. + + Returns: + A TensorDict with the following keys: + locs [batch_size, num_loc, 2]: locations of each customer + depot [batch_size, 2]: location of the depot + demand [batch_size, num_loc]: demand of each customer + capacity [batch_size]: capacity of the vehicle + """ + def __init__( + self, + min_loc: float = 0.0, + max_loc: float = 1.0, + num_keepout_min: int = 1, + num_keepout_max: int = 50, + max_decaps: int = 20, + data_dir: str = "data/dpp/", + chip_file: str = "10x10_pkg_chip.npy", + decap_file: str = "01nF_decap.npy", + freq_file: str = "freq_201.npy", + url: str = None, + **unused_kwargs + ): + self.min_loc = min_loc + self.max_loc = max_loc + self.num_keepout_min = num_keepout_min + self.num_keepout_max = num_keepout_max + self.max_decaps = max_decaps + self.data_dir = data_dir + + # DPP environment doen't have any other kwargs + if len(unused_kwargs) > 0: + log.error(f"Found {len(unused_kwargs)} unused kwargs: {unused_kwargs}") + + + # Download and load the data from online dataset + self.url = ( + "https://github.com/kaist-silab/devformer/raw/main/data/data.zip" + if url is None + else url + ) + self.backup_url = ( + "https://drive.google.com/uc?id=1IEuR2v8Le-mtHWHxwTAbTOPIkkQszI95" + ) + self._load_dpp_data(chip_file, decap_file, freq_file) + + # Check the validity of the keepout parameters + assert ( + num_keepout_min <= num_keepout_max + ), "num_keepout_min must be <= num_keepout_max" + assert ( + num_keepout_max <= self.size**2 + ), "num_keepout_max must be <= size * size (total number of locations)" + + def _generate(self, batch_size) -> TensorDict: + """ + Generate initial observations for the environment with locations, probe, and action mask + Action_mask eliminates the keepout regions and the probe location, and is updated to eliminate placed decaps + """ + m = n = self.size + # if int, convert to list and make it a batch for easier generation + batch_size = [batch_size] if isinstance(batch_size, int) else batch_size + batched = len(batch_size) > 0 + bs = [1] if not batched else batch_size + + # Create a list of locs on a grid + locs = torch.meshgrid( + torch.arange(m), torch.arange(n) + ) + locs = torch.stack(locs, dim=-1).reshape(-1, 2) + # normalize the locations by the number of rows and columns + locs = locs / torch.tensor([m, n], dtype=torch.float) + locs = locs[None].expand(*bs, -1, -1) + + # Create available mask + available = torch.ones((*bs, m * n), dtype=torch.bool) + + # Sample probe location from m*n + probe = torch.randint(m * n, size=(*bs, 1)) + available.scatter_(1, probe, False) + + # Sample keepout locations from m*n except probe + num_keepout = torch.randint( + self.num_keepout_min, + self.num_keepout_max, + size=(*bs, 1), + ) + keepouts = [torch.randperm(m * n)[:k] for k in num_keepout] + for i, (a, k) in enumerate(zip(available, keepouts)): + available[i] = a.scatter(0, k, False) + + return TensorDict( + { + "locs": locs if batched else locs.squeeze(0), + "probe": probe if batched else probe.squeeze(0), + "action_mask": available if batched else available.squeeze(0), + }, + batch_size=batch_size, + ) + + def _load_dpp_data(self, chip_file, decap_file, freq_file): + def _load_file(fpath): + f = os.path.join(self.data_dir, fpath) + if not os.path.isfile(f): + self._download_data() + with open(f, "rb") as f_: + return torch.from_numpy(np.load(f_)) + + self.raw_pdn = _load_file(chip_file) # [num_freq, size^2, size^2] + self.decap = _load_file(decap_file).to(torch.complex64) # [num_freq, 1, 1] + self.freq = _load_file(freq_file) # [num_freq] + self.size = int(np.sqrt(self.raw_pdn.shape[-1])) + self.num_freq = self.freq.shape[0] + + def _download_data(self): + log.info("Downloading data...") + try: + download(self.url, self.data_dir, "data.zip") + except Exception: + log.error( + f"Download from main url {self.url} failed. Trying backup url {self.backup_url}..." + ) + download(self.backup_url, self.data_dir, "data.zip") + log.info("Download complete. Unzipping...") + zipfile.ZipFile(os.path.join(self.data_dir, "data.zip"), "r").extractall( + self.data_dir + ) + log.info("Unzip complete. Removing zip file") + os.remove(os.path.join(self.data_dir, "data.zip")) + + def load_data(self, fpath, batch_size=[]): + data = load_npz_to_tensordict(fpath) + # rename key if necessary (old dpp version) + if "observation" in data.keys(): + data["locs"] = data.pop("observation") + return data diff --git a/rl4co/envs/eda/dpp/render.py b/rl4co/envs/eda/dpp/render.py new file mode 100644 index 00000000..fec5ecba --- /dev/null +++ b/rl4co/envs/eda/dpp/render.py @@ -0,0 +1,84 @@ +import torch +import numpy as np +import matplotlib.pyplot as plt + +from matplotlib import cm, colormaps + +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def render(self, decaps, probe, action_mask, ax=None, legend=True): + """ + Plot a grid of 1x1 squares representing the environment. + The keepout regions are the action_mask - decaps - probe + """ + import matplotlib.pyplot as plt + + settings = { + 0: {"color": "white", "label": "available"}, + 1: {"color": "grey", "label": "keepout"}, + 2: {"color": "tab:red", "label": "probe"}, + 3: {"color": "tab:blue", "label": "decap"}, + } + + nonzero_indices = torch.nonzero(~action_mask, as_tuple=True)[0] + keepout = torch.cat([nonzero_indices, probe, decaps.squeeze(-1)]) + unique_elements, counts = torch.unique(keepout, return_counts=True) + keepout = unique_elements[counts == 1] + + if ax is None: + fig, ax = plt.subplots(1, 1, figsize=(6, 6)) + + grid = np.meshgrid(np.arange(0, self.size), np.arange(0, self.size)) + grid = np.stack(grid, axis=-1) + + # Add new dimension to grid filled up with 0s + grid = np.concatenate([grid, np.zeros((self.size, self.size, 1))], axis=-1) + + # Add keepout = 1 + grid[keepout // self.size, keepout % self.size, 2] = 1 + # Add probe = 2 + grid[probe // self.size, probe % self.size, 2] = 2 + # Add decaps = 3 + grid[decaps // self.size, decaps % self.size, 2] = 3 + + xdim, ydim = grid.shape[0], grid.shape[1] + ax.imshow(np.zeros((xdim, ydim)), cmap="gray") + + ax.set_xlim(0, xdim) + ax.set_ylim(0, ydim) + + for i in range(xdim): + for j in range(ydim): + color = settings[grid[i, j, 2]]["color"] + x, y = grid[i, j, 0], grid[i, j, 1] + ax.add_patch(plt.Rectangle((x, y), 1, 1, color=color, linestyle="-")) + + # Add grid with 1x1 squares + ax.grid( + which="major", axis="both", linestyle="-", color="k", linewidth=1, alpha=0.5 + ) + # set 10 ticks + ax.set_xticks(np.arange(0, xdim, 1)) + ax.set_yticks(np.arange(0, ydim, 1)) + + # Invert y axis + ax.invert_yaxis() + + # Add legend + if legend: + num_unique = 4 + handles = [ + plt.Rectangle((0, 0), 1, 1, color=settings[i]["color"]) + for i in range(num_unique) + ] + ax.legend( + handles, + [settings[i]["label"] for i in range(num_unique)], + ncol=num_unique, + loc="upper center", + bbox_to_anchor=(0.5, 1.1), + ) diff --git a/rl4co/envs/eda/mdpp/__init__.py b/rl4co/envs/eda/mdpp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/eda/mdpp/env.py b/rl4co/envs/eda/mdpp/env.py new file mode 100644 index 00000000..1da98814 --- /dev/null +++ b/rl4co/envs/eda/mdpp/env.py @@ -0,0 +1,161 @@ +from typing import Optional + +import numpy as np +import torch + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.envs.eda.dpp.env import DPPEnv +from rl4co.utils.pylogger import get_pylogger + +from .generator import MDPPGenerator +from .render import render + +log = get_pylogger(__name__) + + +class MDPPEnv(DPPEnv): + """Multiple decap placement problem (mDPP) environment + This is a modified version of the DPP environment where we allow multiple probing ports + + Observations: + - locations of the probing ports and keepout regions + - current decap placement + - remaining decaps + + Constraints: + - decaps cannot be placed at the probing ports or keepout regions + - the number of decaps is limited + + Finish Condition: + - the number of decaps exceeds the limit + + Reward: + - the impedance suppression at the probing ports + + Args: + generator: DPPGenerator instance as the data generator + generator_params: parameters for the generator + reward_type: reward type, either minmax or meansum + - minmax: min of the max of the decap scores + - meansum: mean of the sum of the decap scores + + Note: + The minmax is more challenging as it requires to find the best decap location + for the worst case + """ + + name = "mdpp" + + def __init__( + self, + generator: MDPPGenerator = None, + generator_params: dict = {}, + reward_type: str = "minmax", + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = MDPPGenerator(**generator_params) + self.generator = generator + + assert reward_type in [ + "minmax", + "meansum", + ], "reward_type must be minmax or meansum" + self.reward_type = reward_type + + self._make_spec(self.generator) + + def _step(self, td: TensorDict) -> TensorDict: + # Step function is the same as DPPEnv, only masking changes + return super()._step(td) + + def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: + # Reset function is the same as DPPEnv, only masking changes due to probes + td_reset = super()._reset(td, batch_size=batch_size) + + # Action mask is 0 if both action_mask (e.g. keepout) and probe are 0 + action_mask = torch.logical_and(td_reset["action_mask"], ~td_reset["probe"]) + # Keepout regions are the inverse of action_mask + td_reset.update( + { + "keepout": ~td_reset["action_mask"], + "action_mask": action_mask, + } + ) + return td_reset + + def _make_spec(self, generator: MDPPGenerator): + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(generator.size**2, 2), + dtype=torch.float32, + ), + probe=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + keepout=UnboundedDiscreteTensorSpec( + shape=(generator.size**2), + dtype=torch.bool, + ), + i=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(generator.size**2), + dtype=torch.bool, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=0, + high=generator.size**2, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + def _get_reward(self, td, actions): + """We call the reward function with the final sequence of actions to get the reward + Calling per-step would be very time consuming due to decap simulation + """ + # We do the operation in a batch + if len(td.batch_size) == 0: + td = td.unsqueeze(0) + actions = actions.unsqueeze(0) + + # Reward calculation is expensive since we need to run decap simulation (not vectorizable) + reward = torch.stack( + [ + self._single_env_reward(td_single, action) + for td_single, action in zip(td, actions) + ] + ) + return reward + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor): + assert True, "Not implemented" + + def _single_env_reward(self, td, actions): + """Get reward for single environment. We""" + + list_probe = torch.nonzero(td["probe"]).squeeze() + scores = torch.zeros_like(list_probe, dtype=torch.float32) + for i, probe in enumerate(list_probe): + # Get the decap scores for the probe location + scores[i] = self._decap_simulator(probe, actions) + # If minmax, return min of max decap scores else mean + return scores.min() if self.reward_type == "minmax" else scores.mean() diff --git a/rl4co/envs/eda/mdpp/generator.py b/rl4co/envs/eda/mdpp/generator.py new file mode 100644 index 00000000..75767150 --- /dev/null +++ b/rl4co/envs/eda/mdpp/generator.py @@ -0,0 +1,178 @@ +import os +import zipfile +from typing import Union, Callable + +import torch +import numpy as np + +from robust_downloader import download +from torch.distributions import Uniform +from tensordict.tensordict import TensorDict + +from rl4co.data.utils import load_npz_to_tensordict +from rl4co.utils.pylogger import get_pylogger +from rl4co.envs.common.utils import get_sampler, Generator + +log = get_pylogger(__name__) + + +class MDPPGenerator(Generator): + """Data generator for the Multi Decap Placement Problem (MDPP). + + Args: + min_loc: Minimum location value. Defaults to 0. + max_loc: Maximum location value. Defaults to 1. + num_keepout_min: Minimum number of keepout regions. Defaults to 1. + num_keepout_max: Maximum number of keepout regions. Defaults to 50. + max_decaps: Maximum number of decaps. Defaults to 20. + data_dir: Directory to store data. Defaults to "data/dpp/". + This can be downloaded from this [url](https://drive.google.com/uc?id=1IEuR2v8Le-mtHWHxwTAbTOPIkkQszI95). + chip_file: Name of the chip file. Defaults to "10x10_pkg_chip.npy". + decap_file: Name of the decap file. Defaults to "01nF_decap.npy". + freq_file: Name of the frequency file. Defaults to "freq_201.npy". + url: URL to download data from. Defaults to None. + + Returns: + A TensorDict with the following keys: + locs [batch_size, num_loc, 2]: locations of each customer + depot [batch_size, 2]: location of the depot + demand [batch_size, num_loc]: demand of each customer + capacity [batch_size]: capacity of the vehicle + """ + def __init__( + self, + min_loc: float = 0.0, + max_loc: float = 1.0, + num_keepout_min: int = 1, + num_keepout_max: int = 50, + num_probes_min: int = 2, + num_probes_max: int = 5, + max_decaps: int = 20, + data_dir: str = "data/dpp/", + chip_file: str = "10x10_pkg_chip.npy", + decap_file: str = "01nF_decap.npy", + freq_file: str = "freq_201.npy", + url: str = None, + **unused_kwargs + ): + self.min_loc = min_loc + self.max_loc = max_loc + self.num_keepout_min = num_keepout_min + self.num_keepout_max = num_keepout_max + self.num_probes_min = num_probes_min + self.num_probes_max = num_probes_max + self.max_decaps = max_decaps + self.data_dir = data_dir + + # DPP environment doen't have any other kwargs + if len(unused_kwargs) > 0: + log.error(f"Found {len(unused_kwargs)} unused kwargs: {unused_kwargs}") + + + # Download and load the data from online dataset + self.url = ( + "https://github.com/kaist-silab/devformer/raw/main/data/data.zip" + if url is None + else url + ) + self.backup_url = ( + "https://drive.google.com/uc?id=1IEuR2v8Le-mtHWHxwTAbTOPIkkQszI95" + ) + self._load_dpp_data(chip_file, decap_file, freq_file) + + # Check the validity of the keepout parameters + assert ( + num_keepout_min <= num_keepout_max + ), "num_keepout_min must be <= num_keepout_max" + assert ( + num_keepout_max <= self.size**2 + ), "num_keepout_max must be <= size * size (total number of locations)" + + def _generate(self, batch_size) -> TensorDict: + m = n = self.size + # if int, convert to list and make it a batch for easier generation + batch_size = [batch_size] if isinstance(batch_size, int) else batch_size + batched = len(batch_size) > 0 + bs = [1] if not batched else batch_size + + # Create a list of locs on a grid + locs = torch.meshgrid(torch.arange(m), torch.arange(n)) + locs = torch.stack(locs, dim=-1).reshape(-1, 2) + # normalize the locations by the number of rows and columns + locs = locs / torch.tensor([m, n], dtype=torch.float) + locs = locs[None].expand(*bs, -1, -1) + + # Create available mask + available = torch.ones((*bs, m * n), dtype=torch.bool) + + # Sample probe location from m*n + probe = torch.randint(m * n, size=(*bs, 1)) + available.scatter_(1, probe, False) + + # Sample probe locatins + num_probe = torch.randint( + self.num_probes_min, + self.num_probes_max, + size=(*bs, 1), + ) + probe = [torch.randperm(m * n)[:p] for p in num_probe] + probes = torch.zeros((*bs, m * n), dtype=torch.bool) + for i, (a, p) in enumerate(zip(available, probe)): + available[i] = a.scatter(0, p, False) + probes[i] = probes[i].scatter(0, p, True) + + # Sample keepout locations from m*n except probe + num_keepout = torch.randint( + self.num_keepout_min, + self.num_keepout_max, + size=(*bs, 1), + ) + keepouts = [torch.randperm(m * n)[:k] for k in num_keepout] + for i, (a, k) in enumerate(zip(available, keepouts)): + available[i] = a.scatter(0, k, False) + + return TensorDict( + { + "locs": locs if batched else locs.squeeze(0), + "probe": probes if batched else probes.squeeze(0), + "action_mask": available if batched else available.squeeze(0), + }, + batch_size=batch_size, + ) + + def _load_dpp_data(self, chip_file, decap_file, freq_file): + def _load_file(fpath): + f = os.path.join(self.data_dir, fpath) + if not os.path.isfile(f): + self._download_data() + with open(f, "rb") as f_: + return torch.from_numpy(np.load(f_)) + + self.raw_pdn = _load_file(chip_file) # [num_freq, size^2, size^2] + self.decap = _load_file(decap_file).to(torch.complex64) # [num_freq, 1, 1] + self.freq = _load_file(freq_file) # [num_freq] + self.size = int(np.sqrt(self.raw_pdn.shape[-1])) + self.num_freq = self.freq.shape[0] + + def _download_data(self): + log.info("Downloading data...") + try: + download(self.url, self.data_dir, "data.zip") + except Exception: + log.error( + f"Download from main url {self.url} failed. Trying backup url {self.backup_url}..." + ) + download(self.backup_url, self.data_dir, "data.zip") + log.info("Download complete. Unzipping...") + zipfile.ZipFile(os.path.join(self.data_dir, "data.zip"), "r").extractall( + self.data_dir + ) + log.info("Unzip complete. Removing zip file") + os.remove(os.path.join(self.data_dir, "data.zip")) + + def load_data(self, fpath, batch_size=[]): + data = load_npz_to_tensordict(fpath) + # rename key if necessary (old dpp version) + if "observation" in data.keys(): + data["locs"] = data.pop("observation") + return data diff --git a/rl4co/envs/eda/mdpp/render.py b/rl4co/envs/eda/mdpp/render.py new file mode 100644 index 00000000..fbd4cd00 --- /dev/null +++ b/rl4co/envs/eda/mdpp/render.py @@ -0,0 +1,161 @@ +import torch +import numpy as np +import matplotlib.pyplot as plt + +from matplotlib import cm, colormaps + +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def render(self, td, actions=None, ax=None, legend=True, settings=None): + """Plot a grid of squares representing the environment. + The keepout regions are the action_mask - decaps - probe + """ + + import matplotlib.pyplot as plt + + from matplotlib.lines import Line2D + from matplotlib.patches import Annulus, Rectangle, RegularPolygon + + if settings is None: + settings = { + "available": {"color": "white", "label": "available"}, + "keepout": {"color": "grey", "label": "keepout"}, + "probe": {"color": "tab:red", "label": "probe"}, + "decap": {"color": "tab:blue", "label": "decap"}, + } + + def draw_capacitor(ax, x, y, color="black"): + # Backgrund rectangle: same as color but with alpha=0.5 + ax.add_patch(Rectangle((x, y), 1, 1, color=color, alpha=0.5)) + + # Create the plates of the capacitor + plate_width, plate_height = ( + 0.3, + 0.1, + ) # Width and height switched to make vertical + plate_gap = 0.2 + plate1 = Rectangle( + (x + 0.5 - plate_width / 2, y + 0.5 - plate_height - plate_gap / 2), + plate_width, + plate_height, + color=color, + ) + plate2 = Rectangle( + (x + 0.5 - plate_width / 2, y + 0.5 + plate_gap / 2), + plate_width, + plate_height, + color=color, + ) + + # Add the plates to the axes + ax.add_patch(plate1) + ax.add_patch(plate2) + + # Add connection lines (wires) + line_length = 0.2 + line1 = Line2D( + [x + 0.5, x + 0.5], + [ + y + 0.5 - plate_height - plate_gap / 2 - line_length, + y + 0.5 - plate_height - plate_gap / 2, + ], + color=color, + ) + line2 = Line2D( + [x + 0.5, x + 0.5], + [ + y + 0.5 + plate_height + plate_gap / 2, + y + 0.5 + plate_height + plate_gap / 2 + line_length, + ], + color=color, + ) + + # Add the lines to the axes + ax.add_line(line1) + ax.add_line(line2) + + def draw_probe(ax, x, y, color="black"): + # Backgrund rectangle: same as color but with alpha=0.5 + ax.add_patch(Rectangle((x, y), 1, 1, color=color, alpha=0.5)) + ax.add_patch(Annulus((x + 0.5, y + 0.5), (0.2, 0.2), 0.1, color=color)) + + def draw_keepout(ax, x, y, color="black"): + # Backgrund rectangle: same as color but with alpha=0.5 + ax.add_patch(Rectangle((x, y), 1, 1, color=color, alpha=0.5)) + ax.add_patch( + RegularPolygon( + (x + 0.5, y + 0.5), numVertices=6, radius=0.45, color=color + ) + ) + + size = self.size + td = td.detach().cpu() + # if batch_size greater than 0 , we need to select the first batch element + if td.batch_size != torch.Size([]): + td = td[0] + + if actions is None: + actions = td.get("action", None) + + # Transform actions from idx to one-hot + decaps = torch.zeros(size**2) + decaps.scatter_(0, actions, 1) + decaps = decaps.reshape(size, size) + + keepout = ~td["action_mask"].reshape(size, size) + probes = td["probe"].reshape(size, size) + + if ax is None: + _, ax = plt.subplots(1, 1, figsize=(6, 6)) + + grid = np.meshgrid(np.arange(0, size), np.arange(0, size)) + grid = np.stack(grid, axis=-1) + + xdim, ydim = grid.shape[0], grid.shape[1] + # ax.imshow(np.zeros((xdim, ydim)), cmap="gray") + + ax.set_xlim(0, xdim) + ax.set_ylim(0, ydim) + + for i in range(xdim): + for j in range(ydim): + x, y = grid[i, j, 0], grid[i, j, 1] + + if decaps[i, j] == 1: + draw_capacitor(ax, x, y, color=settings["decap"]["color"]) + elif probes[i, j] == 1: + draw_probe(ax, x, y, color=settings["probe"]["color"]) + elif keepout[i, j] == 1: + draw_keepout(ax, x, y, color=settings["keepout"]["color"]) + + ax.grid( + which="major", axis="both", linestyle="-", color="k", linewidth=1, alpha=0.5 + ) + # set 10 ticks + ax.set_xticks(np.arange(0, xdim, 1)) + ax.set_yticks(np.arange(0, ydim, 1)) + + # Invert y axis + ax.invert_yaxis() + + # # Add legend + if legend: + colors = [settings[k]["color"] for k in settings.keys()] + labels = [settings[k]["label"] for k in settings.keys()] + handles = [ + plt.Rectangle( + (0, 0), 1, 1, color=c, edgecolor="k", linestyle="-", linewidth=1 + ) + for c in colors + ] + ax.legend( + handles, + [label for label in labels], + ncol=len(colors), + loc="upper center", + bbox_to_anchor=(0.5, 1.1), + ) diff --git a/rl4co/envs/graph/__init__.py b/rl4co/envs/graph/__init__.py new file mode 100644 index 00000000..355a55c6 --- /dev/null +++ b/rl4co/envs/graph/__init__.py @@ -0,0 +1,4 @@ +from rl4co.envs.graph.flp.env import FLPEnv +from rl4co.envs.graph.flp.generator import FLPGenerator +from rl4co.envs.graph.mcp.env import MCPEnv +from rl4co.envs.graph.mcp.generator import MCPGenerator diff --git a/rl4co/envs/graph/flp/__init__.py b/rl4co/envs/graph/flp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/graph/flp/env.py b/rl4co/envs/graph/flp/env.py new file mode 100644 index 00000000..aa73b3f9 --- /dev/null +++ b/rl4co/envs/graph/flp/env.py @@ -0,0 +1,169 @@ +from typing import Optional + +import torch + +from tensordict.tensordict import TensorDict + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +from .generator import FLPGenerator + +log = get_pylogger(__name__) + + +class FLPEnv(RL4COEnvBase): + """Facility Location Problem (FLP) environment + At each step, the agent chooses a location. The reward is 0 unless enough number of locations are chosen. + The reward is (-) the total distance of each location to its closest chosen location. + + Observations: + - the locations + - the number of locations to choose + + Constraints: + - the given number of locations must be chosen + + Finish condition: + - the given number of locations are chosen + + Reward: + - (minus) the total distance of each location to its closest chosen location + + Args: + generator: FLPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "flp" + + def __init__( + self, + generator: FLPGenerator = None, + generator_params: dict = {}, + check_solution=False, + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = FLPGenerator(**generator_params) + self.generator = generator + self.check_solution = check_solution + self._make_spec(self.generator) + + def _step(self, td: TensorDict) -> TensorDict: + # action: [batch_size, 1]; the location to be chosen in each instance + selected = td["action"] + batch_size = selected.shape[0] + + # Update location selection status + chosen = td["chosen"].clone() # (batch_size, n_locations) + n_points_ = chosen.shape[-1] + + chosen[torch.arange(batch_size).to(td.device), selected] = True + + # We are done if we choose enough locations + done = td["i"] >= (td["to_choose"] - 1) + + # The reward is calculated outside via get_reward for efficiency, so we set it to zero here + reward = torch.zeros_like(done) + + # Update distances + orig_distances = td["orig_distances"] # (batch_size, n_points, n_points) + + cur_min_dist = ( + gather_by_index( + orig_distances, chosen.nonzero(as_tuple=True)[1].view(batch_size, -1) + ) + .view(batch_size, -1, n_points_) + .min(dim=1) + .values + ) + + # We cannot choose the already-chosen locations + action_mask = ~chosen + + td.update( + { + "distances": cur_min_dist, # (batch_size, n_points) + # states changed by actions + "chosen": chosen, # each entry is binary; 1 iff the corresponding facility is chosen + "i": td["i"] + 1, # the number of sets we have chosen + "action_mask": action_mask, + "reward": reward, + "done": done, + } + ) + return td + + def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: + self.to(td.device) + + return TensorDict( + { + # given information + "locs": td["locs"], # (batch_size, n_points, dim_loc) + "orig_distances": td[ + "orig_distances" + ], # (batch_size, n_points, n_points) + "distances": td["distances"], # (batch_size, n_points, n_points) + # states changed by actions + "chosen": torch.zeros( + *td["locs"].shape[:-1], dtype=torch.bool, device=td.device + ), # each entry is binary; 1 iff the corresponding facility is chosen + "to_choose": td["to_choose"], # the number of sets to choose + "i": torch.zeros( + *batch_size, dtype=torch.int64, device=td.device + ), # the number of sets we have chosen + "action_mask": torch.ones( + *td["locs"].shape[:-1], dtype=torch.bool, device=td.device + ), + }, + batch_size=batch_size, + ) + + def _make_spec(self, generator: FLPGenerator): + # TODO: make spec + pass + + def _get_reward(self, td: TensorDict, actions: torch.Tensor) -> torch.Tensor: + if self.check_solution: + self.check_solution_validity(td, actions) + + # The reward is (minus) the total distance from each location to the closest chosen location + chosen = td["chosen"] # (batch_size, n_points) + batch_size_ = td["chosen"].shape[0] + n_points_ = td["chosen"].shape[-1] + orig_distances = td["orig_distances"] + cur_min_dist = ( + gather_by_index( + orig_distances, chosen.nonzero(as_tuple=True)[1].view(batch_size_, -1) + ) + .view(batch_size_, -1, n_points_) + .min(1) + .values.sum(-1) + ) + return -cur_min_dist + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor) -> None: + # TODO: check solution validity + pass + + @staticmethod + def local_search(td: TensorDict, actions: torch.Tensor, **kwargs) -> torch.Tensor: + # TODO: local search + pass + + @staticmethod + def get_num_starts(td): + return td["action_mask"].shape[-1] + + @staticmethod + def select_start_nodes(td, num_starts): + num_loc = td["action_mask"].shape[-1] + return ( + torch.arange(num_starts, device=td.device).repeat_interleave(td.shape[0]) + % num_loc + ) diff --git a/rl4co/envs/graph/flp/generator.py b/rl4co/envs/graph/flp/generator.py new file mode 100644 index 00000000..adbc7de6 --- /dev/null +++ b/rl4co/envs/graph/flp/generator.py @@ -0,0 +1,74 @@ +import math + +from typing import Callable, Union + +import torch + +from tensordict.tensordict import TensorDict +from torch.distributions import Uniform + +from rl4co.envs.common.utils import Generator, get_sampler +from rl4co.utils.ops import get_distance_matrix +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class FLPGenerator(Generator): + """Data generator for the Facility Location Problem (FLP). + + Args: + num_loc: number of locations in the FLP + min_loc: minimum value for the location coordinates + max_loc: maximum value for the location coordinates + loc_distribution: distribution for the location coordinates + + Returns: + A TensorDict with the following keys: + locs [batch_size, num_loc, 2]: locations + orig_distances [batch_size, num_loc, num_loc]: original distances between locations + distances [batch_size, num_loc]: the current minimum distance rom each location to the chosen locations + chosen [batch_size, num_loc]: indicators of chosen locations + to_choose [batch_size, 1]: number of locations to choose in the FLP + """ + + def __init__( + self, + num_loc: int = 100, + min_loc: float = 0.0, + max_loc: float = 1.0, + loc_distribution: Union[int, float, str, type, Callable] = Uniform, + to_choose: int = 10, + **kwargs, + ): + self.num_loc = num_loc + self.min_loc = min_loc + self.max_loc = max_loc + self.to_choose = to_choose + + # Location distribution + if kwargs.get("loc_sampler", None) is not None: + self.loc_sampler = kwargs["loc_sampler"] + else: + self.loc_sampler = get_sampler( + "loc", loc_distribution, min_loc, max_loc, **kwargs + ) + + def _generate(self, batch_size) -> TensorDict: + # Sample locations + locs = self.loc_sampler.sample((*batch_size, self.num_loc, 2)) + distances = get_distance_matrix(locs) + max_dist = math.sqrt(2) * (self.max_loc - self.min_loc) + + return TensorDict( + { + "locs": locs, + "orig_distances": distances, + "distances": torch.full( + (*batch_size, self.num_loc), max_dist, dtype=torch.float + ), + "chosen": torch.zeros(*batch_size, self.num_loc, dtype=torch.bool), + "to_choose": torch.ones(*batch_size, dtype=torch.long) * self.to_choose, + }, + batch_size=batch_size, + ) diff --git a/rl4co/envs/graph/mcp/__init__.py b/rl4co/envs/graph/mcp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/graph/mcp/env.py b/rl4co/envs/graph/mcp/env.py new file mode 100644 index 00000000..3f0275e0 --- /dev/null +++ b/rl4co/envs/graph/mcp/env.py @@ -0,0 +1,193 @@ +from typing import Optional + +import torch + +from tensordict.tensordict import TensorDict + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.utils.pylogger import get_pylogger + +from .generator import MCPGenerator + +log = get_pylogger(__name__) + + +class MCPEnv(RL4COEnvBase): + """Maximum Coverage Problem (MCP) environment + At each step, the agent chooses a set. The reward is 0 unless enough number of sets are chosen. + The reward is the total weights of the covered items (i.e., items in any chosen set). + + Observations: + - the weights of items + - the membership of items in sets + - the number of sets to choose + + Constraints: + - the given number of sets must be chosen + + Finish condition: + - the given number of sets are chosen + + Reward: + - the total weights of the covered items (i.e., items in any chosen set) + + Args: + generator: MCPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "mcp" + + def __init__( + self, + generator: MCPGenerator = None, + generator_params: dict = {}, + check_solution=False, + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = MCPGenerator(**generator_params) + self.generator = generator + self.check_solution = check_solution + self._make_spec(self.generator) + + def _step(self, td: TensorDict) -> TensorDict: + # action: [batch_size, 1]; the set to be chosen in each instance + batch_size = td["action"].shape[0] + selected = td["action"] + + # Update set selection status + chosen = td["chosen"].clone() # (batch_size, n_sets) + chosen[torch.arange(batch_size).to(td.device), selected] = True + + # We are done if we choose enough sets + done = td["i"] >= (td["n_sets_to_choose"] - 1) + + # The reward is calculated outside via get_reward for efficiency, so we set it to -inf here + reward = torch.ones_like(done) * float("-inf") + + remaining_sets = ~chosen # (batch_size, n_sets) + + chosen_membership = chosen.unsqueeze(-1) * td["membership"] + chosen_membership_nonzero = chosen_membership.nonzero() + remaining_membership = remaining_sets.unsqueeze(-1) * td["membership"] + + batch_indices, set_indices, item_indices = chosen_membership_nonzero.T + chosen_items_indices = chosen_membership[ + batch_indices, set_indices, item_indices + ].long() + + batch_size, n_items = td["weights"].shape + + # We have batch_indices and chosen_items_indices + # chosen_items: (batch_size, n_items) + # for each i, chosen_items[batch_size[i], chosen_items_indices[i]] += 1 + chosen_items = torch.zeros(batch_size, n_items + 1, device=td.device) + chosen_items[batch_indices, chosen_items_indices] += 1 + chosen_items = chosen_items[:, 1:] # Remove the first column (invalid zeros) + + # chosen_item[i, j] > 0 means item j is chosen in batch i + covered_items = (chosen_items > 0).float() # (batch_size, n_items) + remaining_items = 1.0 - covered_items # (batch_size, n_items) + + # We cannot choose the already-chosen sets + action_mask = ~chosen + + td.update( + { + "membership": remaining_membership, # (batch_size, n_sets, max_size) + "weights": td["weights"] * remaining_items, # (batch_size, n_items) + "chosen": chosen, + "i": td["i"] + 1, + "action_mask": action_mask, + "reward": reward, + "done": done, + } + ) + return td + + def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: + self.to(td.device) + + return TensorDict( + { + # given information; constant for each given instance + "orig_membership": td["membership"], # (batch_size, n_sets, max_size) + "membership": td["membership"], # (batch_size, n_sets, max_size) + "orig_weights": td["weights"], # (batch_size, n_items) + "weights": td["weights"], # (batch_size, n_items) + "n_sets_to_choose": td["n_sets_to_choose"], # (batch_size, 1) + # states changed by actions + "chosen": torch.zeros( + *td["membership"].shape[:-1], dtype=torch.bool, device=td.device + ), # each entry is binary; 1 iff the corresponding set is chosen + "i": torch.zeros( + *batch_size, dtype=torch.int64, device=td.device + ), # the number of sets we have chosen + "action_mask": torch.ones( + *td["membership"].shape[:-1], dtype=torch.bool, device=td.device + ), + }, + batch_size=batch_size, + ) + + def _make_spec(self, generator: MCPGenerator): + # TODO: make spec + pass + + def _get_reward(self, td: TensorDict, actions: torch.Tensor) -> torch.Tensor: + if self.check_solution: + self.check_solution_validity(td, actions) + + membership = td[ + "orig_membership" + ] # (batch_size, n_sets, max_size); membership[i, j] = the items in set j in batch i (with 0 padding) + weights = td["orig_weights"] # (batch_size, n_items) + chosen_sets = td["chosen"] # (batch_size, n_set); 1 if chosen, 0 otherwise + + chosen_membership = chosen_sets.unsqueeze(-1) * membership + chosen_membership_nonzero = chosen_membership.nonzero() + + batch_indices, set_indices, item_indices = chosen_membership_nonzero.T + chosen_items_indices = chosen_membership[ + batch_indices, set_indices, item_indices + ].long() + + batch_size, n_items = weights.shape + + # We have batch_indices and chosen_items_indices + # chosen_items: (batch_size, n_items) + # For each i, chosen_items[batch_size[i], chosen_items_indices[i]] += 1 + chosen_items = torch.zeros(batch_size, n_items + 1, device=td.device) + chosen_items[batch_indices, chosen_items_indices] += 1 + chosen_items = chosen_items[:, 1:] # remove the first column + + # chosen_item[i, j] > 0 means item j is chosen in batch i + chosen_items = (chosen_items > 0).float() + # Compute the total weights of chosen items + chosen_weights = torch.sum(chosen_items * weights, dim=-1) + + return chosen_weights + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor) -> None: + # TODO: check solution validity + pass + + @staticmethod + def local_search(td: TensorDict, actions: torch.Tensor, **kwargs) -> torch.Tensor: + # TODO: local search + pass + + @staticmethod + def get_num_starts(td): + return td["action_mask"].shape[-1] + + @staticmethod + def select_start_nodes(td, num_starts): + num_sets = td["action_mask"].shape[-1] + return ( + torch.arange(num_starts, device=td.device).repeat_interleave(td.shape[0]) + % num_sets + ) diff --git a/rl4co/envs/graph/mcp/generator.py b/rl4co/envs/graph/mcp/generator.py new file mode 100644 index 00000000..99d5463f --- /dev/null +++ b/rl4co/envs/graph/mcp/generator.py @@ -0,0 +1,138 @@ +from typing import Callable, Union + +import torch + +from tensordict.tensordict import TensorDict +from torch.distributions import Uniform + +from rl4co.envs.common.utils import Generator, get_sampler +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def remove_repeat(x: torch.Tensor) -> torch.Tensor: + """ + Remove the repeated elements in each row (i.e., the last dimension) of the input tensor x, + and change the repeated elements to 0 + + Ref: https://stackoverflow.com/questions/62300404 + + Args: + x: input tensor + """ + + # sorting the rows so that duplicate values appear together + # e.g., first row: [1, 2, 3, 3, 3, 4, 4] + y, indices = x.sort(dim=-1) + + # subtracting, so duplicate values will become 0 + # e.g., first row: [1, 2, 3, 0, 0, 4, 0] + y[..., 1:] *= ((y[..., 1:] - y[..., :-1]) != 0).long() + + # retrieving the original indices of elements + indices = indices.sort(dim=-1)[1] + + # re-organizing the rows following original order + # e.g., first row: [1, 2, 3, 4, 0, 0, 0] + return torch.gather(y, -1, indices) + + +class MCPGenerator(Generator): + """Data generator for the Maximum Coverage Problem (MCP). + + Args: + num_items: number of items in the MCP + num_sets: number of sets in the MCP + min_weight: minimum value for the item weights + max_weight: maximum value for the item weights + min_size: minimum size for the sets + max_size: maximum size for the sets + n_sets_to_choose: number of sets to choose in the MCP + + Returns: + A TensorDict with the following keys: + membership [batch_size, num_sets, max_size]: membership of items in sets + weights [batch_size, num_items]: weights of the items + n_sets_to_choose [batch_size, 1]: number of sets to choose in the MCP + """ + + def __init__( + self, + num_items: int = 200, + num_sets: int = 100, + min_weight: int = 1, + max_weight: int = 10, + min_size: int = 5, + max_size: int = 15, + n_sets_to_choose: int = 10, + size_distribution: Union[int, float, str, type, Callable] = Uniform, + weight_distribution: Union[int, float, str, type, Callable] = Uniform, + **kwargs, + ): + self.num_items = num_items + self.num_sets = num_sets + self.min_weight = min_weight + self.max_weight = max_weight + self.min_size = min_size + self.max_size = max_size + self.n_sets_to_choose = n_sets_to_choose + + # Set size distribution + if kwargs.get("size_sampler", None) is not None: + self.size_sampler = kwargs["size_sampler"] + else: + self.size_sampler = get_sampler( + "size", size_distribution, min_size, max_size + 1, **kwargs + ) + + # Item weight distribution + if kwargs.get("weight_sampler", None) is not None: + self.weight_sampler = kwargs["weight_sampler"] + else: + self.weight_sampler = get_sampler( + "weight", weight_distribution, min_weight, max_weight + 1, **kwargs + ) + + def _generate(self, batch_size) -> TensorDict: + try: + batch_size = batch_size[0] + except TypeError: + batch_size = batch_size + + # Sample item weights + weights_tensor = self.weight_sampler.sample((batch_size, self.num_items)) + weights_tensor = torch.floor(weights_tensor) + weights_tensor = torch.clamp(weights_tensor, self.min_weight, self.max_weight) + + # Sample set sizes + set_sizes = self.size_sampler.sample((batch_size, self.num_sets)) + set_sizes = torch.floor(set_sizes).long() + set_sizes = torch.clamp(set_sizes, self.min_size, self.max_size) + max_size = set_sizes.max().item() + + # Create membership tensor + membership_tensor_max_size = torch.randint( + 1, self.num_items + 1, (batch_size, self.num_sets, max_size) + ) + + cutoffs_masks = torch.arange(self.max_size).view(1, 1, -1) < set_sizes.unsqueeze( + -1 + ) + # Take the masked elements, 0 means the item is invalid + membership_tensor = ( + membership_tensor_max_size * cutoffs_masks + ) # (batch_size, num_sets, max_size) + + # Remove repeated items in each set + membership_tensor = remove_repeat(membership_tensor) + + return TensorDict( + { + "membership": membership_tensor.float(), # (batch_size, num_sets, max_size) + "weights": weights_tensor.float(), # (batch_size, num_items) + "n_sets_to_choose": torch.ones(batch_size, 1) + * self.n_sets_to_choose, # (batch_size, 1) + }, + batch_size=batch_size, + ) diff --git a/rl4co/envs/routing/__init__.py b/rl4co/envs/routing/__init__.py new file mode 100644 index 00000000..7588b5f4 --- /dev/null +++ b/rl4co/envs/routing/__init__.py @@ -0,0 +1,24 @@ +from rl4co.envs.routing.atsp.env import ATSPEnv +from rl4co.envs.routing.atsp.generator import ATSPGenerator +from rl4co.envs.routing.cvrp.env import CVRPEnv +from rl4co.envs.routing.cvrp.generator import CVRPGenerator +from rl4co.envs.routing.cvrptw.env import CVRPTWEnv +from rl4co.envs.routing.cvrptw.generator import CVRPTWGenerator +from rl4co.envs.routing.mdcpdp.env import MDCPDPEnv +from rl4co.envs.routing.mdcpdp.generator import MDCPDPGenerator +from rl4co.envs.routing.mtsp.env import MTSPEnv +from rl4co.envs.routing.mtsp.generator import MTSPGenerator +from rl4co.envs.routing.mtvrp.env import MTVRPEnv +from rl4co.envs.routing.mtvrp.generator import MTVRPGenerator +from rl4co.envs.routing.op.env import OPEnv +from rl4co.envs.routing.op.generator import OPGenerator +from rl4co.envs.routing.pctsp.env import PCTSPEnv +from rl4co.envs.routing.pctsp.generator import PCTSPGenerator +from rl4co.envs.routing.pdp.env import PDPEnv, PDPRuinRepairEnv +from rl4co.envs.routing.pdp.generator import PDPGenerator +from rl4co.envs.routing.sdvrp.env import SDVRPEnv +from rl4co.envs.routing.spctsp.env import SPCTSPEnv +from rl4co.envs.routing.svrp.env import SVRPEnv +from rl4co.envs.routing.svrp.generator import SVRPGenerator +from rl4co.envs.routing.tsp.env import DenseRewardTSPEnv, TSPEnv, TSPkoptEnv +from rl4co.envs.routing.tsp.generator import TSPGenerator diff --git a/rl4co/envs/routing/atsp/__init__.py b/rl4co/envs/routing/atsp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/atsp/env.py b/rl4co/envs/routing/atsp/env.py new file mode 100644 index 00000000..90a6360c --- /dev/null +++ b/rl4co/envs/routing/atsp/env.py @@ -0,0 +1,173 @@ +from typing import Optional + +import torch + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.envs.common.utils import batch_to_scalar +from rl4co.utils.pylogger import get_pylogger + +from .generator import ATSPGenerator +from .render import render + +log = get_pylogger(__name__) + + +class ATSPEnv(RL4COEnvBase): + """Asymmetric Traveling Salesman Problem (ATSP) environment + At each step, the agent chooses a customer to visit. The reward is 0 unless the agent visits all the customers. + In that case, the reward is (-)length of the path: maximizing the reward is equivalent to minimizing the path length. + Unlike the TSP, the distance matrix is asymmetric, i.e., the distance from A to B is not necessarily the same as the distance from B to A. + + Observations: + - distance matrix between customers + - the current customer + - the first customer (for calculating the reward) + - the remaining unvisited customers + + Constraints: + - the tour starts and ends at the same customer. + - each customer must be visited exactly once. + + Finish Condition: + - the agent has visited all customers. + + Reward: + - (minus) the negative length of the path. + + Args: + generator: ATSPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "atsp" + + def __init__( + self, + generator: ATSPGenerator = None, + generator_params: dict = {}, + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = ATSPGenerator(**generator_params) + self.generator = generator + self._make_spec(self.generator) + + @staticmethod + def _step(td: TensorDict) -> TensorDict: + current_node = td["action"] + first_node = current_node if batch_to_scalar(td["i"]) == 0 else td["first_node"] + + # Set not visited to 0 (i.e., we visited the node) + available = td["action_mask"].scatter( + -1, current_node.unsqueeze(-1).expand_as(td["action_mask"]), 0 + ) + + # We are done there are no unvisited locations + done = torch.count_nonzero(available, dim=-1) <= 0 + + # The reward is calculated outside via get_reward for efficiency, so we set it to 0 here + reward = torch.zeros_like(done) + + td.update( + { + "first_node": first_node, + "current_node": current_node, + "i": td["i"] + 1, + "action_mask": available, + "reward": reward, + "done": done, + }, + ) + return td + + def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: + # Initialize distance matrix + cost_matrix = td["cost_matrix"] + device = td.device + + # Other variables + current_node = torch.zeros((*batch_size, 1), dtype=torch.int64, device=device) + available = torch.ones( + (*batch_size, self.generator.num_loc), dtype=torch.bool, device=device + ) # 1 means not visited, i.e. action is allowed + i = torch.zeros((*batch_size, 1), dtype=torch.int64, device=device) + + return TensorDict( + { + "cost_matrix": cost_matrix, + "first_node": current_node, + "current_node": current_node, + "i": i, + "action_mask": available, + }, + batch_size=batch_size, + ) + + def _make_spec(self, generator: ATSPGenerator): + self.observation_spec = CompositeSpec( + cost_matrix=BoundedTensorSpec( + low=generator.min_dist, + high=generator.max_dist, + shape=(generator.num_loc, generator.num_loc), + dtype=torch.float32, + ), + first_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + current_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + i=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(generator.num_loc), + dtype=torch.bool, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=0, + high=generator.num_loc, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + def _get_reward(self, td: TensorDict, actions: torch.Tensor) -> torch.Tensor: + distance_matrix = td["cost_matrix"] + + # Get indexes of tour edges + nodes_src = actions + nodes_tgt = torch.roll(actions, -1, dims=1) + batch_idx = torch.arange( + distance_matrix.shape[0], device=distance_matrix.device + ).unsqueeze(1) + # return negative tour length + return -distance_matrix[batch_idx, nodes_src, nodes_tgt].sum(-1) + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor): + assert ( + torch.arange(actions.size(1), out=actions.data.new()) + .view(1, -1) + .expand_as(actions) + == actions.data.sort(1)[0] + ).all(), "Invalid tour" + + @staticmethod + def render(td, actions=None, ax=None): + return render(td, actions, ax) diff --git a/rl4co/envs/routing/atsp/generator.py b/rl4co/envs/routing/atsp/generator.py new file mode 100644 index 00000000..89e381ca --- /dev/null +++ b/rl4co/envs/routing/atsp/generator.py @@ -0,0 +1,71 @@ +from typing import Union, Callable + +import torch + +from torch.distributions import Uniform +from tensordict.tensordict import TensorDict + +from rl4co.utils.pylogger import get_pylogger +from rl4co.envs.common.utils import get_sampler, Generator + +log = get_pylogger(__name__) + + +class ATSPGenerator(Generator): + """Data generator for the Asymmetric Travelling Salesman Problem (ATSP) + Generate distance matrices inspired by the reference MatNet (Kwon et al., 2021) + We satifsy the triangle inequality (TMAT class) in a batch + + Args: + num_loc: number of locations (customers) in the TSP + min_dist: minimum value for the distance between nodes + max_dist: maximum value for the distance between nodes + dist_distribution: distribution for the distance between nodes + tmat_class: whether to generate a class of distance matrix + + Returns: + A TensorDict with the following keys: + locs [batch_size, num_loc, 2]: locations of each customer + """ + def __init__( + self, + num_loc: int = 10, + min_dist: float = 0.0, + max_dist: float = 1.0, + dist_distribution: Union[ + int, float, str, type, Callable + ] = Uniform, + tmat_class: bool = True, + **kwargs + ): + self.num_loc = num_loc + self.min_dist = min_dist + self.max_dist = max_dist + self.tmat_class = tmat_class + + # Distance distribution + if kwargs.get("dist_sampler", None) is not None: + self.dist_sampler = kwargs["dist_sampler"] + else: + self.dist_sampler = get_sampler("dist", dist_distribution, 0.0, 1.0, **kwargs) + + def _generate(self, batch_size) -> TensorDict: + # Generate distance matrices inspired by the reference MatNet (Kwon et al., 2021) + # We satifsy the triangle inequality (TMAT class) in a batch + batch_size = [batch_size] if isinstance(batch_size, int) else batch_size + dms = ( + self.dist_sampler.sample((batch_size + [self.num_loc, self.num_loc])) + * (self.max_dist - self.min_dist) + + self.min_dist + ) + dms[..., torch.arange(self.num_loc), torch.arange(self.num_loc)] = 0 + log.info("Using TMAT class (triangle inequality): {}".format(self.tmat_class)) + if self.tmat_class: + while True: + old_dms = dms.clone() + dms, _ = ( + dms[..., :, None, :] + dms[..., None, :, :].transpose(-2, -1) + ).min(dim=-1) + if (dms == old_dms).all(): + break + return TensorDict({"cost_matrix": dms}, batch_size=batch_size) diff --git a/rl4co/envs/routing/atsp/render.py b/rl4co/envs/routing/atsp/render.py new file mode 100644 index 00000000..8ad0a903 --- /dev/null +++ b/rl4co/envs/routing/atsp/render.py @@ -0,0 +1,50 @@ +import torch +import numpy as np +import matplotlib.pyplot as plt + +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def render(td, actions=None, ax=None): + if ax is None: + # Create a plot of the nodes + _, ax = plt.subplots() + + td = td.detach().cpu() + + if actions is None: + actions = td.get("action", None) + + # If batch_size greater than 0 , we need to select the first batch element + if td.batch_size != torch.Size([]): + td = td[0] + actions = actions[0] + + locs = td["locs"] + + # Gather locs in order of action if available + if actions is None: + log.warning("No action in TensorDict, rendering unsorted locs") + else: + actions = actions.detach().cpu() + locs = gather_by_index(locs, actions, dim=0) + + # Cat the first node to the end to complete the tour + locs = torch.cat((locs, locs[0:1])) + x, y = locs[:, 0], locs[:, 1] + + # Plot the visited nodes + ax.scatter(x, y, color="tab:blue") + + # Add arrows between visited nodes as a quiver plot + dx, dy = np.diff(x), np.diff(y) + ax.quiver( + x[:-1], y[:-1], dx, dy, scale_units="xy", angles="xy", scale=1, color="k" + ) + + # Setup limits and show + ax.set_xlim(-0.05, 1.05) + ax.set_ylim(-0.05, 1.05) diff --git a/rl4co/envs/routing/cvrp/__init__.py b/rl4co/envs/routing/cvrp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/cvrp/env.py b/rl4co/envs/routing/cvrp/env.py new file mode 100644 index 00000000..6f47fe84 --- /dev/null +++ b/rl4co/envs/routing/cvrp/env.py @@ -0,0 +1,258 @@ +from typing import Optional + +import torch + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.data.utils import load_npz_to_tensordict +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.utils.ops import gather_by_index, get_tour_length +from rl4co.utils.pylogger import get_pylogger + +from .generator import CVRPGenerator +try: + from .local_search import local_search +except: + # In case some dependencies are not installed (e.g., pyvrp) + local_search = None +from .render import render + +log = get_pylogger(__name__) + + +class CVRPEnv(RL4COEnvBase): + """Capacitated Vehicle Routing Problem (CVRP) environment. + At each step, the agent chooses a customer to visit depending on the current location and the remaining capacity. + When the agent visits a customer, the remaining capacity is updated. If the remaining capacity is not enough to + visit any customer, the agent must go back to the depot. The reward is 0 unless the agent visits all the cities. + In that case, the reward is (-)length of the path: maximizing the reward is equivalent to minimizing the path length. + + Observations: + - location of the depot. + - locations and demand of each customer. + - current location of the vehicle. + - the remaining customer of the vehicle, + + Constraints: + - the tour starts and ends at the depot. + - each customer must be visited exactly once. + - the vehicle cannot visit customers exceed the remaining capacity. + - the vehicle can return to the depot to refill the capacity. + + Finish Condition: + - the vehicle has visited all customers and returned to the depot. + + Reward: + - (minus) the negative length of the path. + + Args: + generator: CVRPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "cvrp" + + def __init__( + self, + generator: CVRPGenerator = None, + generator_params: dict = {}, + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = CVRPGenerator(**generator_params) + self.generator = generator + self._make_spec(self.generator) + + def _step(self, td: TensorDict) -> TensorDict: + current_node = td["action"][:, None] # Add dimension for step + n_loc = td["demand"].size(-1) # Excludes depot + + # Not selected_demand is demand of first node (by clamp) so incorrect for nodes that visit depot! + selected_demand = gather_by_index( + td["demand"], torch.clamp(current_node - 1, 0, n_loc - 1), squeeze=False + ) + + # Increase capacity if depot is not visited, otherwise set to 0 + used_capacity = (td["used_capacity"] + selected_demand) * ( + current_node != 0 + ).float() + + # Note: here we do not subtract one as we have to scatter so the first column allows scattering depot + # Add one dimension since we write a single value + visited = td["visited"].scatter(-1, current_node, 1) + + # SECTION: get done + done = visited.sum(-1) == visited.size(-1) + reward = torch.zeros_like(done) + + td.update( + { + "current_node": current_node, + "used_capacity": used_capacity, + "visited": visited, + "reward": reward, + "done": done, + } + ) + td.set("action_mask", self.get_action_mask(td)) + return td + + def _reset( + self, + td: Optional[TensorDict] = None, + batch_size: Optional[list] = None, + ) -> TensorDict: + device = td.device + + # Create reset TensorDict + td_reset = TensorDict( + { + "locs": torch.cat((td["depot"][:, None, :], td["locs"]), -2), + "demand": td["demand"], + "current_node": torch.zeros( + *batch_size, 1, dtype=torch.long, device=device + ), + "used_capacity": torch.zeros((*batch_size, 1), device=device), + "vehicle_capacity": torch.full( + (*batch_size, 1), self.generator.vehicle_capacity, device=device + ), + "visited": torch.zeros( + (*batch_size, td["locs"].shape[-2] + 1), + dtype=torch.uint8, + device=device, + ), + }, + batch_size=batch_size, + ) + td_reset.set("action_mask", self.get_action_mask(td_reset)) + return td_reset + + @staticmethod + def get_action_mask(td: TensorDict) -> torch.Tensor: + # For demand steps_dim is inserted by indexing with id, for used_capacity insert node dim for broadcasting + exceeds_cap = td["demand"] + td["used_capacity"] > td["vehicle_capacity"] + + # Nodes that cannot be visited are already visited or too much demand to be served now + mask_loc = td["visited"][..., 1:].to(exceeds_cap.dtype) | exceeds_cap + + # Cannot visit the depot if just visited and still unserved nodes + mask_depot = (td["current_node"] == 0) & ((mask_loc == 0).int().sum(-1) > 0)[ + :, None + ] + return ~torch.cat((mask_depot, mask_loc), -1) + + def _get_reward(self, td: TensorDict, actions: TensorDict) -> TensorDict: + # Gather locations in order of tour (add depot since we start and end there) + locs_ordered = torch.cat( + [ + td["locs"][..., 0:1, :], # depot + gather_by_index(td["locs"], actions), # order locations + ], + dim=1, + ) + return -get_tour_length(locs_ordered) + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor): + """Check that solution is valid: nodes are not visited twice except depot and capacity is not exceeded""" + # Check if tour is valid, i.e. contain 0 to n-1 + batch_size, graph_size = td["demand"].size() + sorted_pi = actions.data.sort(1)[0] + + # Sorting it should give all zeros at front and then 1...n + assert ( + torch.arange(1, graph_size + 1, out=sorted_pi.data.new()) + .view(1, -1) + .expand(batch_size, graph_size) + == sorted_pi[:, -graph_size:] + ).all() and (sorted_pi[:, :-graph_size] == 0).all(), "Invalid tour" + + # Visiting depot resets capacity so we add demand = -capacity (we make sure it does not become negative) + demand_with_depot = torch.cat((-td["vehicle_capacity"], td["demand"]), 1) + d = demand_with_depot.gather(1, actions) + + used_cap = torch.zeros_like(td["demand"][:, 0]) + for i in range(actions.size(1)): + used_cap += d[ + :, i + ] # This will reset/make capacity negative if i == 0, e.g. depot visited + # Cannot use less than 0 + used_cap[used_cap < 0] = 0 + assert ( + used_cap <= td["vehicle_capacity"] + 1e-5 + ).all(), "Used more than capacity" + + @staticmethod + def load_data(fpath, batch_size=[]): + """Dataset loading from file + Normalize demand by capacity to be in [0, 1] + """ + td_load = load_npz_to_tensordict(fpath) + td_load.set("demand", td_load["demand"] / td_load["capacity"][:, None]) + return td_load + + def _make_spec(self, generator: CVRPGenerator): + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(generator.num_loc + 1, 2), + dtype=torch.float32, + ), + current_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + demand=BoundedTensorSpec( + low=-generator.capacity, + high=generator.max_demand, + shape=(generator.num_loc + 1, 1), + dtype=torch.float32, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(generator.num_loc + 1, 1), + dtype=torch.bool, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=0, + high=generator.num_loc + 1, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + def replace_selected_actions(self, cur_actions: torch.Tensor, new_actions: torch.Tensor, selection_mask: torch.Tensor) -> torch.Tensor: + """ + Replace selected current actions with updated actions based on `selection_mask`. + + Args: + cur_actions [batch_size, num_loc] + new_actions [batch_size, num_loc] + selection_mask [batch_size,] + """ + diff_length = cur_actions.size(-1) - new_actions.size(-1) + if diff_length > 0: + new_actions = torch.nn.functional.pad(new_actions, (0, diff_length, 0, 0), mode="constant", value=0) + elif diff_length < 0: + cur_actions = torch.nn.functional.pad(cur_actions, (0, -diff_length, 0, 0), mode="constant", value=0) + cur_actions[selection_mask] = new_actions[selection_mask] + return cur_actions + + @staticmethod + def local_search(td: TensorDict, actions: torch.Tensor, **kwargs) -> torch.Tensor: + assert local_search is not None, "Cannot import local_search module. Check if `pyvrp` is installed." + return local_search(td, actions, **kwargs) + + @staticmethod + def render(td: TensorDict, actions: torch.Tensor = None, ax=None): + return render(td, actions, ax) diff --git a/rl4co/envs/routing/cvrp/generator.py b/rl4co/envs/routing/cvrp/generator.py new file mode 100644 index 00000000..d6404781 --- /dev/null +++ b/rl4co/envs/routing/cvrp/generator.py @@ -0,0 +1,143 @@ +from typing import Callable, Union + +import torch + +from tensordict.tensordict import TensorDict +from torch.distributions import Uniform + +from rl4co.envs.common.utils import Generator, get_sampler +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +# From Kool et al. 2019, Hottung et al. 2022, Kim et al. 2023 +CAPACITIES = { + 10: 20.0, + 15: 25.0, + 20: 30.0, + 30: 33.0, + 40: 37.0, + 50: 40.0, + 60: 43.0, + 75: 45.0, + 100: 50.0, + 125: 55.0, + 150: 60.0, + 200: 70.0, + 500: 100.0, + 1000: 150.0, +} + + +class CVRPGenerator(Generator): + """Data generator for the Capacitated Vehicle Routing Problem (CVRP). + + Args: + num_loc: number of locations (cities) in the VRP, without the depot. (e.g. 10 means 10 locs + 1 depot) + min_loc: minimum value for the location coordinates + max_loc: maximum value for the location coordinates + loc_distribution: distribution for the location coordinates + depot_distribution: distribution for the depot location. If None, sample the depot from the locations + min_demand: minimum value for the demand of each customer + max_demand: maximum value for the demand of each customer + demand_distribution: distribution for the demand of each customer + capacity: capacity of the vehicle + + Returns: + A TensorDict with the following keys: + locs [batch_size, num_loc, 2]: locations of each customer + depot [batch_size, 2]: location of the depot + demand [batch_size, num_loc]: demand of each customer + capacity [batch_size]: capacity of the vehicle + """ + + def __init__( + self, + num_loc: int = 20, + min_loc: float = 0.0, + max_loc: float = 1.0, + loc_distribution: Union[int, float, str, type, Callable] = Uniform, + depot_distribution: Union[int, float, str, type, Callable] = None, + min_demand: int = 1, + max_demand: int = 10, + demand_distribution: Union[int, float, type, Callable] = Uniform, + vehicle_capacity: float = 1.0, + capacity: float = None, + **kwargs, + ): + self.num_loc = num_loc + self.min_loc = min_loc + self.max_loc = max_loc + self.min_demand = min_demand + self.max_demand = max_demand + self.vehicle_capacity = vehicle_capacity + + # Location distribution + if kwargs.get("loc_sampler", None) is not None: + self.loc_sampler = kwargs["loc_sampler"] + else: + self.loc_sampler = get_sampler( + "loc", loc_distribution, min_loc, max_loc, **kwargs + ) + + # Depot distribution + if kwargs.get("depot_sampler", None) is not None: + self.depot_sampler = kwargs["depot_sampler"] + else: + self.depot_sampler = get_sampler( + "depot", depot_distribution, min_loc, max_loc, **kwargs + ) if depot_distribution is not None else None + + # Demand distribution + if kwargs.get("demand_sampler", None) is not None: + self.demand_sampler = kwargs["demand_sampler"] + else: + self.demand_sampler = get_sampler( + "demand", demand_distribution, min_demand - 1, max_demand - 1, **kwargs + ) + + # Capacity + if ( + capacity is None + ): # If not provided, use the default capacity from Kool et al. 2019 + capacity = CAPACITIES.get(num_loc, None) + if ( + capacity is None + ): # If not in the table keys, find the closest number of nodes as the key + closest_num_loc = min(CAPACITIES.keys(), key=lambda x: abs(x - num_loc)) + capacity = CAPACITIES[closest_num_loc] + log.warning( + f"The capacity capacity for {num_loc} locations is not defined. Using the closest capacity: {capacity}\ + with {closest_num_loc} locations." + ) + self.capacity = capacity + + def _generate(self, batch_size) -> TensorDict: + + # Sample locations: depot and customers + if self.depot_sampler is not None: + depot = self.depot_sampler.sample((*batch_size, 2)) + locs = self.loc_sampler.sample((*batch_size, self.num_loc, 2)) + else: + # if depot_sampler is None, sample the depot from the locations + locs = self.loc_sampler.sample((*batch_size, self.num_loc + 1, 2)) + depot = locs[..., 0, :] + locs = locs[..., 1:, :] + + # Sample demands + demand = self.demand_sampler.sample((*batch_size, self.num_loc)) + demand = (demand.int() + 1).float() + + # Sample capacities + capacity = torch.full((*batch_size, 1), self.capacity) + + return TensorDict( + { + "locs": locs, + "depot": depot, + "demand": demand / self.capacity, + "capacity": capacity, + }, + batch_size=batch_size, + ) diff --git a/rl4co/envs/routing/cvrp/local_search.py b/rl4co/envs/routing/cvrp/local_search.py new file mode 100644 index 00000000..73deb7d4 --- /dev/null +++ b/rl4co/envs/routing/cvrp/local_search.py @@ -0,0 +1,215 @@ +from functools import partial +from multiprocessing import Pool +from typing import Tuple, Union + +import numpy as np +import torch + +from pyvrp import ( + Client, + CostEvaluator, + Depot, + ProblemData, + RandomNumberGenerator, + Solution, + VehicleType, +) +from pyvrp.search import ( + NODE_OPERATORS, + ROUTE_OPERATORS, + LocalSearch, + NeighbourhoodParams, + compute_neighbours, +) +from tensordict.tensordict import TensorDict + +from rl4co.utils.ops import get_distance_matrix +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +C = ( + 10**4 +) # Scaling factor for the data, to convert the float values to integers as required by PyVRP + + +def local_search( + td: TensorDict, + actions: torch.Tensor, + max_trials: int = 10, + neighbourhood_params: Union[dict, None] = None, + load_penalty: float = 0.2, + allow_infeasible_solution: bool = False, + seed: int = 0, + num_workers: int = 1, +): + """ + Improve the solution using local search for CVRP, based on PyVRP. + + Args: + td: TensorDict, td from env with shape [batch_size,] + actions: torch.Tensor, Tour indices with shape [batch_size, max_seq_len] + max_trials: int, maximum number of trials for local search + neighbourhood_params: dict, parameters for neighbourhood search + load_penalty: int, penalty for exceeding the vehicle capacity + allow_infeasible_solution: bool, whether to allow infeasible solutions + seed: int, random seed for local search + num_workers: int, number of workers for parallel processing + Returns: + torch.Tensor, Improved tour indices with shape [batch_size, max_seq_len] + """ + + # Convert tensors to numpy arrays + # Note: to avoid the overhead of device transfer, we recommend to pass the tensors in cpu + actions_np = actions.detach().cpu().numpy() + positions_np = td["locs"].detach().cpu().numpy() # [batch_size, num_loc + 1, 2] + demands_np = td["demand"].detach().cpu().numpy() # [batch_size, num_loc] + demands_np = np.pad(demands_np, ((0, 0), (1, 0)), mode="constant") # Add depot demand + distances = td.get("distances", None) # [batch_size, num_loc + 1, num_loc + 1] + if distances is None: + distances_np = get_distance_matrix(td["locs"]).numpy() + else: + distances_np = distances.detach().cpu().numpy() + + max_trials = 1 if allow_infeasible_solution else max_trials + + partial_func = partial( + local_search_single, + neighbourhood_params=neighbourhood_params, + load_penalty=load_penalty, + allow_infeasible_solution=allow_infeasible_solution, + max_trials=max_trials, + seed=seed, + ) + + if num_workers > 1: + with Pool(processes=num_workers) as pool: + new_actions = pool.starmap( + partial_func, zip(actions_np, positions_np, demands_np, distances_np) + ) + else: + new_actions = [ + partial_func(*args) + for args in zip(actions_np, positions_np, demands_np, distances_np) + ] + + # padding with zero + lengths = [len(act) for act in new_actions] + max_length = max(lengths) + new_actions = np.array( + [ + np.pad(act, (0, max_length - length), mode="constant") + for act, length in zip(new_actions, lengths) + ] + ) + return torch.from_numpy(new_actions[:, :-1].astype(np.int64)).to( + td.device + ) # We can remove the last zero + + +def local_search_single( + path: np.ndarray, + positions: np.ndarray, + demands: np.ndarray, + distances: np.ndarray, + neighbourhood_params: Union[dict, None] = None, + allow_infeasible_solution: bool = False, + load_penalty: float = 0.2, + max_trials: int = 10, + seed: int = 0, +) -> np.ndarray: + data = make_data(positions, demands, distances) + solution = make_solution(data, path) + ls_operator = make_search_operator(data, seed, neighbourhood_params) + + improved_solution, is_feasible = perform_local_search( + ls_operator, + solution, + int(load_penalty * C), # * C as we scale the data in `make_data` + remaining_trials=max_trials, + ) + + # Return the original path if no feasible solution is found + if not is_feasible and not allow_infeasible_solution: + return path + + # Recover the path from the sub-routes in the solution + route_list = [ + idx for route in improved_solution.routes() for idx in [0] + route.visits() + ] + [0] + return np.array(route_list) + + +def make_data( + positions: np.ndarray, demands: np.ndarray, distances: np.ndarray +) -> ProblemData: + positions = (positions * C).astype(int) + distances = (distances * C).astype(int) + + capacity = C + demands = np.round(demands * capacity).astype(int) + + return ProblemData( + clients=[ + Client(x=pos[0], y=pos[1], delivery=d) + for pos, d in zip(positions[1:], demands[1:]) + ], + depots=[Depot(x=positions[0][0], y=positions[0][1])], + vehicle_types=[ + VehicleType( + len(positions) - 1, + capacity, + 0, + name=",".join(map(str, range(1, len(positions)))), + ) + ], + distance_matrices=[distances], + duration_matrices=[np.zeros_like(distances)], + ) + + +def make_solution(data: ProblemData, path: np.ndarray) -> Solution: + # Split the paths into sub-routes by the zeros + routes = [ + arr[1:].tolist() for arr in np.split(path, np.where(path == 0)[0]) if len(arr) > 1 + ] + return Solution(data, routes) + + +def make_search_operator( + data: ProblemData, seed=0, neighbourhood_params: Union[dict, None] = None +) -> LocalSearch: + rng = RandomNumberGenerator(seed) + neighbours = compute_neighbours( + data, NeighbourhoodParams(**(neighbourhood_params or {})) + ) + ls = LocalSearch(data, rng, neighbours) + for node_op in NODE_OPERATORS: + ls.add_node_operator(node_op(data)) + for route_op in ROUTE_OPERATORS: + ls.add_route_operator(route_op(data)) + return ls + + +def perform_local_search( + ls_operator: LocalSearch, + solution: Solution, + load_penalty: int, + remaining_trials: int = 5, +) -> Tuple[Solution, bool]: + cost_evaluator = CostEvaluator( + load_penalty=load_penalty, tw_penalty=0, dist_penalty=0 + ) + improved_solution = ls_operator(solution, cost_evaluator) + remaining_trials -= 1 + if is_feasible := improved_solution.is_feasible() or remaining_trials == 0: + return improved_solution, is_feasible + + # print("Warning: Infeasible solution found from local search.", + # "This will slow down the search due to the repeated local search runs.") + + # If infeasible, run the local search again with a higher penalty + return perform_local_search( + ls_operator, solution, load_penalty * 10, remaining_trials=remaining_trials + ) diff --git a/rl4co/envs/routing/cvrp/render.py b/rl4co/envs/routing/cvrp/render.py new file mode 100644 index 00000000..74748e1c --- /dev/null +++ b/rl4co/envs/routing/cvrp/render.py @@ -0,0 +1,133 @@ +import torch +import numpy as np +import matplotlib.pyplot as plt + +from matplotlib import cm, colormaps + +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def render(td, actions=None, ax=None): + num_routine = (actions == 0).sum().item() + 2 + base = colormaps["nipy_spectral"] + color_list = base(np.linspace(0, 1, num_routine)) + cmap_name = base.name + str(num_routine) + out = base.from_list(cmap_name, color_list, num_routine) + + if ax is None: + # Create a plot of the nodes + _, ax = plt.subplots() + + td = td.detach().cpu() + + if actions is None: + actions = td.get("action", None) + + # if batch_size greater than 0 , we need to select the first batch element + if td.batch_size != torch.Size([]): + td = td[0] + actions = actions[0] + + locs = td["locs"] + scale_demand = td["capacity"][0] + demands = td["demand"] * scale_demand + + # add the depot at the first action and the end action + actions = torch.cat([torch.tensor([0]), actions, torch.tensor([0])]) + + # gather locs in order of action if available + if actions is None: + log.warning("No action in TensorDict, rendering unsorted locs") + else: + locs = locs + + # Cat the first node to the end to complete the tour + x, y = locs[:, 0], locs[:, 1] + + # plot depot + ax.scatter( + locs[0, 0], + locs[0, 1], + edgecolors=cm.Set2(2), + facecolors="none", + s=100, + linewidths=2, + marker="s", + alpha=1, + ) + + # plot visited nodes + ax.scatter( + x[1:], + y[1:], + edgecolors=cm.Set2(0), + facecolors="none", + s=50, + linewidths=2, + marker="o", + alpha=1, + ) + + # plot demand bars + for node_idx in range(1, len(locs)): + ax.add_patch( + plt.Rectangle( + (locs[node_idx, 0] - 0.005, locs[node_idx, 1] + 0.015), + 0.01, + demands[node_idx - 1] / (scale_demand * 10), + edgecolor=cm.Set2(0), + facecolor=cm.Set2(0), + fill=True, + ) + ) + + # text demand + for node_idx in range(1, len(locs)): + ax.text( + locs[node_idx, 0], + locs[node_idx, 1] - 0.025, + f"{demands[node_idx-1].item():.2f}", + horizontalalignment="center", + verticalalignment="top", + fontsize=10, + color=cm.Set2(0), + ) + + # text depot + ax.text( + locs[0, 0], + locs[0, 1] - 0.025, + "Depot", + horizontalalignment="center", + verticalalignment="top", + fontsize=10, + color=cm.Set2(2), + ) + + # plot actions + color_idx = 0 + for action_idx in range(len(actions) - 1): + if actions[action_idx] == 0: + color_idx += 1 + from_loc = locs[actions[action_idx]] + to_loc = locs[actions[action_idx + 1]] + ax.plot( + [from_loc[0], to_loc[0]], + [from_loc[1], to_loc[1]], + color=out(color_idx), + lw=1, + ) + ax.annotate( + "", + xy=(to_loc[0], to_loc[1]), + xytext=(from_loc[0], from_loc[1]), + arrowprops=dict(arrowstyle="-|>", color=out(color_idx)), + size=15, + annotation_clip=False, + ) + + ax.set_xlim(-0.05, 1.05) + ax.set_ylim(-0.05, 1.05) diff --git a/rl4co/envs/routing/cvrptw/__init__.py b/rl4co/envs/routing/cvrptw/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/cvrptw/env.py b/rl4co/envs/routing/cvrptw/env.py new file mode 100644 index 00000000..62005b9c --- /dev/null +++ b/rl4co/envs/routing/cvrptw/env.py @@ -0,0 +1,291 @@ +from typing import Optional + +import torch + +from tensordict.tensordict import TensorDict +from torchrl.data import BoundedTensorSpec, CompositeSpec, UnboundedContinuousTensorSpec + +from rl4co.data.utils import ( + load_npz_to_tensordict, + load_solomon_instance, + load_solomon_solution, +) +from rl4co.envs.routing.cvrp.env import CVRPEnv +from rl4co.utils.ops import gather_by_index, get_distance + +from ..cvrp.generator import CVRPGenerator +from .generator import CVRPTWGenerator +from .render import render + + +class CVRPTWEnv(CVRPEnv): + """Capacitated Vehicle Routing Problem with Time Windows (CVRPTW) environment. + Inherits from the CVRPEnv class in which customers are considered. + Additionally considers time windows within which a service has to be started. + + Observations: + - location of the depot. + - locations and demand of each customer. + - current location of the vehicle. + - the remaining customer of the vehicle. + - the current time. + - service durations of each location. + - time windows of each location. + + Constraints: + - the tour starts and ends at the depot. + - each customer must be visited exactly once. + - the vehicle cannot visit customers exceed the remaining customer. + - the vehicle can return to the depot to refill the customer. + - the vehicle must start the service within the time window of each location. + + Finish Condition: + - the vehicle has visited all customers and returned to the depot. + + Reward: + - (minus) the negative length of the path. + + Args: + generator: CVRPTWGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "cvrptw" + + def __init__( + self, + generator: CVRPTWGenerator = None, + generator_params: dict = {}, + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = CVRPTWGenerator(**generator_params) + self.generator = generator + self._make_spec(self.generator) + + def _make_spec(self, generator: CVRPTWGenerator): + if isinstance(generator, CVRPGenerator): + super()._make_spec(generator) + else: + current_time = UnboundedContinuousTensorSpec( + shape=(1), dtype=torch.float32, device=self.device + ) + current_loc = UnboundedContinuousTensorSpec( + shape=(2), dtype=torch.float32, device=self.device + ) + durations = BoundedTensorSpec( + low=generator.min_time, + high=generator.max_time, + shape=(generator.num_loc, 1), + dtype=torch.int64, + device=self.device, + ) + time_windows = BoundedTensorSpec( + low=generator.min_time, + high=generator.max_time, + shape=( + generator.num_loc, + 2, + ), # Each location has a 2D time window (start, end) + dtype=torch.int64, + device=self.device, + ) + # Extend observation specs + self.observation_spec = CompositeSpec( + **self.observation_spec, + current_time=current_time, + current_loc=current_loc, + durations=durations, + time_windows=time_windows, + ) + + @staticmethod + def get_action_mask(td: TensorDict) -> torch.Tensor: + """In addition to the constraints considered in the CVRPEnv, the time windows are considered. + The vehicle can only visit a location if it can reach it in time, i.e. before its time window ends. + """ + not_masked = CVRPEnv.get_action_mask(td) + current_loc = gather_by_index(td["locs"], td["current_node"]) + dist = get_distance(current_loc[..., None, :], td["locs"]) + td.update({"current_loc": current_loc, "distances": dist}) + can_reach_in_time = ( + td["current_time"] + dist <= td["time_windows"][..., 1] + ) # I only need to start the service before the time window ends, not finish it. + return not_masked & can_reach_in_time + + def _step(self, td: TensorDict) -> TensorDict: + """In addition to the calculations in the CVRPEnv, the current time is + updated to keep track of which nodes are still reachable in time. + The current_node is updeted in the parent class' _step() function. + """ + batch_size = td["locs"].shape[0] + # update current_time + distance = gather_by_index(td["distances"], td["action"]).reshape([batch_size, 1]) + duration = gather_by_index(td["durations"], td["action"]).reshape([batch_size, 1]) + start_times = gather_by_index(td["time_windows"], td["action"])[..., 0].reshape( + [batch_size, 1] + ) + td["current_time"] = (td["action"][:, None] != 0) * ( + torch.max(td["current_time"] + distance, start_times) + duration + ) + # current_node is updated to the selected action + td = super()._step(td) + return td + + def _reset( + self, td: Optional[TensorDict] = None, batch_size: Optional[list] = None + ) -> TensorDict: + device = td.device + td_reset = TensorDict( + { + "locs": torch.cat((td["depot"][..., None, :], td["locs"]), -2), + "demand": td["demand"], + "current_node": torch.zeros( + *batch_size, 1, dtype=torch.long, device=device + ), + "current_time": torch.zeros( + *batch_size, 1, dtype=torch.float32, device=device + ), + "used_capacity": torch.zeros((*batch_size, 1), device=device), + "vehicle_capacity": torch.full( + (*batch_size, 1), self.generator.vehicle_capacity, device=device + ), + "visited": torch.zeros( + (*batch_size, td["locs"].shape[-2] + 1), + dtype=torch.uint8, + device=device, + ), + "durations": td["durations"], + "time_windows": td["time_windows"], + }, + batch_size=batch_size, + ) + td_reset.set("action_mask", self.get_action_mask(td_reset)) + return td_reset + + def _get_reward(self, td: TensorDict, actions: torch.Tensor) -> torch.Tensor: + """The reward is the negative tour length. Time windows + are not considered for the calculation of the reward.""" + return super()._get_reward(td, actions) + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor) -> None: + CVRPEnv.check_solution_validity(td, actions) + batch_size = td["locs"].shape[0] + # distances to depot + distances = get_distance( + td["locs"][..., 0, :], td["locs"].transpose(0, 1) + ).transpose(0, 1) + # basic checks on time windows + assert torch.all(distances >= 0.0), "Distances must be non-negative." + assert torch.all(td["time_windows"] >= 0.0), "Time windows must be non-negative." + assert torch.all( + td["time_windows"][..., :, 0] + distances + td["durations"] + <= td["time_windows"][..., 0, 1][0] # max_time is the same for all batches + ), "vehicle cannot perform service and get back to depot in time." + assert torch.all( + td["durations"] >= 0.0 + ), "Service durations must be non-negative." + assert torch.all( + td["time_windows"][..., 0] < td["time_windows"][..., 1] + ), "there are unfeasible time windows" + # check vehicles can meet deadlines + curr_time = torch.zeros(batch_size, 1, dtype=torch.float32, device=td.device) + curr_node = torch.zeros_like(curr_time, dtype=torch.int64, device=td.device) + for ii in range(actions.size(1)): + next_node = actions[:, ii] + dist = get_distance( + gather_by_index(td["locs"], curr_node).reshape([batch_size, 2]), + gather_by_index(td["locs"], next_node).reshape([batch_size, 2]), + ).reshape([batch_size, 1]) + curr_time = torch.max( + (curr_time + dist).int(), + gather_by_index(td["time_windows"], next_node)[..., 0].reshape( + [batch_size, 1] + ), + ) + assert torch.all( + curr_time + <= gather_by_index(td["time_windows"], next_node)[..., 1].reshape( + [batch_size, 1] + ) + ), "vehicle cannot start service before deadline" + curr_time = curr_time + gather_by_index(td["durations"], next_node).reshape( + [batch_size, 1] + ) + curr_node = next_node + curr_time[curr_node == 0] = 0.0 # reset time for depot + + @staticmethod + def render(td: TensorDict, actions: torch.Tensor = None, ax=None): + render(td, actions, ax) + + @staticmethod + def load_data( + name: str, + solomon=False, + path_instances: str = None, + type: str = None, + compute_edge_weights: bool = False, + ): + if solomon: + assert type in [ + "instance", + "solution", + ], "type must be either 'instance' or 'solution'" + if type == "instance": + instance = load_solomon_instance( + name=name, path=path_instances, edge_weights=compute_edge_weights + ) + elif type == "solution": + instance = load_solomon_solution(name=name, path=path_instances) + return instance + return load_npz_to_tensordict(filename=name) + + def extract_from_solomon(self, instance: dict, batch_size: int = 1): + # extract parameters for the environment from the Solomon instance + self.min_demand = instance["demand"][1:].min() + self.max_demand = instance["demand"][1:].max() + self.vehicle_capacity = instance["capacity"] + self.min_loc = instance["node_coord"][1:].min() + self.max_loc = instance["node_coord"][1:].max() + self.min_time = instance["time_window"][:, 0].min() + self.max_time = instance["time_window"][:, 1].max() + # assert the time window of the depot starts at 0 and ends at max_time + assert self.min_time == 0, "Time window of depot must start at 0." + assert ( + self.max_time == instance["time_window"][0, 1] + ), "Depot must have latest end time." + # convert to format used in CVRPTWEnv + td = TensorDict( + { + "depot": torch.tensor( + instance["node_coord"][0], + dtype=torch.float32, + device=self.device, + ).repeat(batch_size, 1), + "locs": torch.tensor( + instance["node_coord"][1:], + dtype=torch.float32, + device=self.device, + ).repeat(batch_size, 1, 1), + "demand": torch.tensor( + instance["demand"][1:], + dtype=torch.float32, + device=self.device, + ).repeat(batch_size, 1), + "durations": torch.tensor( + instance["service_time"], + dtype=torch.int64, + device=self.device, + ).repeat(batch_size, 1), + "time_windows": torch.tensor( + instance["time_window"], + dtype=torch.int64, + device=self.device, + ).repeat(batch_size, 1, 1), + }, + batch_size=1, # we assume batch_size will always be 1 for loaded instances + ) + return self.reset(td, batch_size=batch_size) diff --git a/rl4co/envs/routing/cvrptw/generator.py b/rl4co/envs/routing/cvrptw/generator.py new file mode 100644 index 00000000..770f88fb --- /dev/null +++ b/rl4co/envs/routing/cvrptw/generator.py @@ -0,0 +1,162 @@ +from typing import Union, Callable + +import torch + +from torch.distributions import Uniform +from tensordict.tensordict import TensorDict + +from rl4co.envs.routing.cvrp.generator import CVRPGenerator +from rl4co.utils.ops import get_distance + + +class CVRPTWGenerator(CVRPGenerator): + """Data generator for the Capacitated Vehicle Routing Problem with Time Windows (CVRPTW) environment + Generates time windows and service durations for the locations. The depot has a time window of [0, self.max_time]. + The time windows define the time span within which a service has to be started. To reach the depot in time from the last node, + the end time of each node is bounded by the service duration and the distance back to the depot. + The start times of the time windows are bounded by how long it takes to travel there from the depot. + + Args: + num_loc: number of locations (customers) in the VRP, without the depot. (e.g. 10 means 10 locs + 1 depot) + min_loc: minimum value for the location coordinates + max_loc: maximum value for the location coordinates, default is 150 insted of 1.0, will be scaled + loc_distribution: distribution for the location coordinates + depot_distribution: distribution for the depot location. If None, sample the depot from the locations + min_demand: minimum value for the demand of each customer + max_demand: maximum value for the demand of each customer + demand_distribution: distribution for the demand of each customer + capacity: capacity of the vehicle + max_time: maximum time for the vehicle to complete the tour + scale: if True, the locations, time windows, and service durations will be scaled to [0, 1]. Default to False + + Returns: + A TensorDict with the following keys: + locs [batch_size, num_loc, 2]: locations of each city + depot [batch_size, 2]: location of the depot + demand [batch_size, num_loc]: demand of each customer + while the demand of the depot is a placeholder + capacity [batch_size, 1]: capacity of the vehicle + durations [batch_size, num_loc]: service durations of each location + time_windows [batch_size, num_loc, 2]: time windows of each location + """ + def __init__( + self, + num_loc: int = 20, + min_loc: float = 0.0, + max_loc: float = 150.0, + loc_distribution: Union[ + int, float, str, type, Callable + ] = Uniform, + depot_distribution: Union[ + int, float, str, type, Callable + ] = None, + min_demand: int = 1, + max_demand: int = 10, + demand_distribution: Union[ + int, float, type, Callable + ] = Uniform, + vehicle_capacity: float = 1.0, + capacity: float = None, + max_time: float = 480, + scale: bool = False, + **kwargs, + ): + super().__init__( + num_loc=num_loc, + min_loc=min_loc, + max_loc=max_loc, + loc_distribution=loc_distribution, + depot_distribution=depot_distribution, + min_demand=min_demand, + max_demand=max_demand, + demand_distribution=demand_distribution, + vehicle_capacity=vehicle_capacity, + capacity=capacity, + **kwargs, + ) + self.max_loc = max_loc + self.min_time = 0.0 + self.max_time = max_time + self.scale = scale + + def _generate(self, batch_size) -> TensorDict: + td = super()._generate(batch_size) + + batch_size = [batch_size] if isinstance(batch_size, int) else batch_size + + ## define service durations + # generate randomly (first assume service durations of 0, to be changed later) + durations = torch.zeros( + *batch_size, self.num_loc + 1, dtype=torch.float32 + ) + + ## define time windows + # 1. get distances from depot + dist = get_distance(td["depot"], td["locs"].transpose(0, 1)).transpose(0, 1) + dist = torch.cat((torch.zeros(*batch_size, 1), dist), dim=1) + + # 2. define upper bound for time windows to make sure the vehicle can get back to the depot in time + upper_bound = self.max_time - dist - durations + + # 3. create random values between 0 and 1 + ts_1 = torch.rand(*batch_size, self.num_loc + 1) + ts_2 = torch.rand(*batch_size, self.num_loc + 1) + + # 4. scale values to lie between their respective min_time and max_time and convert to integer values + min_ts = (dist + (upper_bound - dist) * ts_1).int() + max_ts = (dist + (upper_bound - dist) * ts_2).int() + + # 5. set the lower value to min, the higher to max + min_times = torch.min(min_ts, max_ts) + max_times = torch.max(min_ts, max_ts) + + # 6. reset times for depot + min_times[..., :, 0] = 0.0 + max_times[..., :, 0] = self.max_time + + # 7. ensure min_times < max_times to prevent numerical errors in attention.py + # min_times == max_times may lead to nan values in _inner_mha() + mask = min_times == max_times + if torch.any(mask): + min_tmp = min_times.clone() + min_tmp[mask] = torch.max( + dist[mask].int(), min_tmp[mask] - 1 + ) # we are handling integer values, so we can simply substract 1 + min_times = min_tmp + + mask = min_times == max_times # update mask to new min_times + if torch.any(mask): + max_tmp = max_times.clone() + max_tmp[mask] = torch.min( + torch.floor(upper_bound[mask]).int(), + torch.max( + torch.ceil(min_tmp[mask] + durations[mask]).int(), + max_tmp[mask] + 1, + ), + ) + max_times = max_tmp + + # Scale to [0, 1] + if self.scale: + durations = durations / self.max_time + min_times = min_times / self.max_time + max_times = max_times / self.max_time + td["depot"] = td["depot"] / self.max_time + td["locs"] = td["locs"] / self.max_time + + # 8. stack to tensor time_windows + time_windows = torch.stack((min_times, max_times), dim=-1) + + assert torch.all( + min_times < max_times + ), "Please make sure the relation between max_loc and max_time allows for feasible solutions." + + # Reset duration at depot to 0 + durations[:, 0] = 0.0 + td.update( + { + "durations": durations, + "time_windows": time_windows, + } + ) + return td diff --git a/rl4co/envs/routing/cvrptw/render.py b/rl4co/envs/routing/cvrptw/render.py new file mode 100644 index 00000000..74748e1c --- /dev/null +++ b/rl4co/envs/routing/cvrptw/render.py @@ -0,0 +1,133 @@ +import torch +import numpy as np +import matplotlib.pyplot as plt + +from matplotlib import cm, colormaps + +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def render(td, actions=None, ax=None): + num_routine = (actions == 0).sum().item() + 2 + base = colormaps["nipy_spectral"] + color_list = base(np.linspace(0, 1, num_routine)) + cmap_name = base.name + str(num_routine) + out = base.from_list(cmap_name, color_list, num_routine) + + if ax is None: + # Create a plot of the nodes + _, ax = plt.subplots() + + td = td.detach().cpu() + + if actions is None: + actions = td.get("action", None) + + # if batch_size greater than 0 , we need to select the first batch element + if td.batch_size != torch.Size([]): + td = td[0] + actions = actions[0] + + locs = td["locs"] + scale_demand = td["capacity"][0] + demands = td["demand"] * scale_demand + + # add the depot at the first action and the end action + actions = torch.cat([torch.tensor([0]), actions, torch.tensor([0])]) + + # gather locs in order of action if available + if actions is None: + log.warning("No action in TensorDict, rendering unsorted locs") + else: + locs = locs + + # Cat the first node to the end to complete the tour + x, y = locs[:, 0], locs[:, 1] + + # plot depot + ax.scatter( + locs[0, 0], + locs[0, 1], + edgecolors=cm.Set2(2), + facecolors="none", + s=100, + linewidths=2, + marker="s", + alpha=1, + ) + + # plot visited nodes + ax.scatter( + x[1:], + y[1:], + edgecolors=cm.Set2(0), + facecolors="none", + s=50, + linewidths=2, + marker="o", + alpha=1, + ) + + # plot demand bars + for node_idx in range(1, len(locs)): + ax.add_patch( + plt.Rectangle( + (locs[node_idx, 0] - 0.005, locs[node_idx, 1] + 0.015), + 0.01, + demands[node_idx - 1] / (scale_demand * 10), + edgecolor=cm.Set2(0), + facecolor=cm.Set2(0), + fill=True, + ) + ) + + # text demand + for node_idx in range(1, len(locs)): + ax.text( + locs[node_idx, 0], + locs[node_idx, 1] - 0.025, + f"{demands[node_idx-1].item():.2f}", + horizontalalignment="center", + verticalalignment="top", + fontsize=10, + color=cm.Set2(0), + ) + + # text depot + ax.text( + locs[0, 0], + locs[0, 1] - 0.025, + "Depot", + horizontalalignment="center", + verticalalignment="top", + fontsize=10, + color=cm.Set2(2), + ) + + # plot actions + color_idx = 0 + for action_idx in range(len(actions) - 1): + if actions[action_idx] == 0: + color_idx += 1 + from_loc = locs[actions[action_idx]] + to_loc = locs[actions[action_idx + 1]] + ax.plot( + [from_loc[0], to_loc[0]], + [from_loc[1], to_loc[1]], + color=out(color_idx), + lw=1, + ) + ax.annotate( + "", + xy=(to_loc[0], to_loc[1]), + xytext=(from_loc[0], from_loc[1]), + arrowprops=dict(arrowstyle="-|>", color=out(color_idx)), + size=15, + annotation_clip=False, + ) + + ax.set_xlim(-0.05, 1.05) + ax.set_ylim(-0.05, 1.05) diff --git a/rl4co/envs/routing/mdcpdp/__init__.py b/rl4co/envs/routing/mdcpdp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/mdcpdp/env.py b/rl4co/envs/routing/mdcpdp/env.py new file mode 100644 index 00000000..1f2f5dec --- /dev/null +++ b/rl4co/envs/routing/mdcpdp/env.py @@ -0,0 +1,354 @@ +from typing import Optional + +import torch + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.utils.ops import gather_by_index, get_tour_length + +from .generator import MDCPDPGenerator +from .render import render + + +class MDCPDPEnv(RL4COEnvBase): + """Multi Depot Capacitated Pickup and Delivery Problem (MDCPDP) environment. + One reference to understand the problem could be: Solving the multi-compartment capacitated location routing + problem with pickup–delivery routes and stochastic demands (https://doi.org/10.1016/j.cie.2015.05.008). + The environment is made of num_loc + num_depots locations (cities): + - num_depot depot + - num_loc / 2 pickup locations + - num_loc / 2 delivery locations + The goal is to visit all the pickup and delivery locations in the shortest path possible starting from the depot + The conditions is that the agent must visit a pickup location before visiting its corresponding delivery location + The capacity is the maximum number of pickups that the vehicle can carry at the same time + + Observations: + - locs: locations of the cities [num_loc + num_depot, 2] + - current_node: current node of the agent [1] + - to_deliver: if the node is to deliver [1] + - i: current step [1] + - action_mask: mask of the available actions [num_loc + num_depot] + - shape: shape of the observation + + Constraints: + - The agent cannot visit the same city twice + - The agent must visit the pickup location before the delivery location + - The agent must visit the depot at the end of the tour + + Finish Condition: + - The agent visited all the locations + + Reward: + - Min-sum: the reward is the negative of the length of the tour + - Min-max: the reward is the negative of the maximum length of the tour + - Lateness: the reward is the negative of the cumulate sum of the length of the tour + - Lateness-square: the reward is the negative of the cumulate sum of the square of the length of the tour + + Args: + generator: MDCPDPGenerator instance as the data generator + generator_params: parameters for the generator + dist_mode: distance mode. One of ["L1", "L2"] + reward_mode: objective of the problem. One of ["lateness", "lateness_square", "minmax", "minsum"] + problem_mode: type of the problem. One of ["close", "open"] + start_mode: type of the start. One of ["order", "random"] + """ + + name = "mdcpdp" + + def __init__( + self, + generator: MDCPDPGenerator = None, + generator_params: dict = {}, + dist_mode: str = "L2", + reward_mode: str = "lateness", + problem_mode: str = "close", + start_mode: str = "order", + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = MDCPDPGenerator(**generator_params) + self.generator = generator + self.dist_mode = dist_mode + self.reward_mode = reward_mode + self.problem_mode = problem_mode + self.start_mode = start_mode + self.depot_mode = generator.depot_mode + self._make_spec(self.generator) + + assert self.dist_mode in ["L1", "L2"], "Distance mode (L1/L2) not supported" + assert self.reward_mode in ["lateness", "lateness_square", "minmax", "minsum"], "Objective mode not supported" + assert self.problem_mode in ["close", "open"], "Task type (open/close) not supported" + assert self.start_mode in ["order", "random"], "Start type (order/random) not supported" + + def _step(self, td: TensorDict) -> TensorDict: + current_node = td["action"].unsqueeze(-1) + current_depot = td["current_depot"] + + num_depot = td["capacity"].shape[-1] + num_loc = td["locs"].shape[-2] - num_depot # no depot + pd_split_idx = num_loc // 2 + num_depot + + # Pickup and delivery node pair of selected node + new_to_deliver = (current_node + num_loc // 2) % (num_loc + num_depot) + + # If back to the depot + back_flag = (current_node < num_depot) & (td["available"].gather(-1, current_node) == 0) + + # Set available to 0 (i.e., we visited the node) + available = td["available"].scatter(-1, current_node.expand_as(td["action_mask"]), 0) + + # Record the to be delivered node + to_deliver = td["to_deliver"].scatter(-1, new_to_deliver.expand_as(td["to_deliver"]), 1) + + # Update number of current carry orders + current_carry = td["current_carry"] + current_carry += ((current_node < pd_split_idx) & (current_node >= num_depot)).long() # If pickup, add 1 + current_carry -= (current_node >= pd_split_idx).long() # If delivery, minus 1 + + # Update the current depot + current_depot = td["current_depot"] + current_depot = torch.where(back_flag, current_node, current_depot) + + # Update the length of current tour + current_length = td["current_length"] + prev_loc = gather_by_index(td["locs"], td["current_node"]) + curr_loc = gather_by_index(td["locs"], current_node) + current_step_length = self.get_distance(prev_loc, curr_loc) + + # If this path is the way between two depods, i.e. open a new route, set the length to 0 + current_step_length = torch.where( + (current_node < num_depot) & (td["current_node"] < num_depot), + 0, current_step_length + ) + + # If the problem mode is open, the path back to the depot will not be counted + if self.problem_mode == "open": + current_step_length = torch.where( + (current_node < num_depot) & (td["current_node"] >= num_depot), + 0, current_step_length + ) + + # Update the current length + current_length.scatter_add_(-1, current_depot, current_step_length) + + # Update the arrive time for each city + arrivetime_record = td["arrivetime_record"] + arrivetime_record.scatter_(-1, current_node, current_length.gather(-1, current_depot)) + + # Action is feasible if the node is not visited and is to deliver + action_mask = available & to_deliver + + # If reach the capacity, only delivery is available + current_capacity = td["capacity"].gather(-1, current_depot) + capacity_flag = current_carry >= current_capacity + action_mask[..., num_depot:pd_split_idx] &= ~capacity_flag # If reach the capacity, pickup is not available + + # If back to the current depot, this tour is done, set other depots to availbe to start + # a new tour. Must start from a depot. + action_mask[..., num_depot:] &= ~back_flag.expand_as(action_mask[..., num_depot:]) + + # If back to the depot, other unvisited depots are available + # if not back to the depot, depots are not available except the current depot + action_mask[..., :num_depot] &= back_flag.expand_as(action_mask[..., :num_depot]) + action_mask[..., :num_depot].scatter_(-1, current_depot, ~back_flag) + + # If this is the last agent, it has to finish all the left taks + last_depot_flag = torch.sum(available[..., :num_depot].long(), dim=-1, keepdim=True) == 0 + action_mask[..., :num_depot] &= ~last_depot_flag.expand_as(action_mask[..., :num_depot]) + + # Update depot mask + carry_flag = current_carry > 0 # If agent is carrying orders + action_mask[..., :num_depot] &= ~carry_flag # If carrying orders, depot is not available + + # We are done there are no unvisited locations + done = torch.count_nonzero(available, dim=-1) == 0 + + # If done, the last depot would be always available + action_mask[..., :num_depot].scatter_(-1, current_depot, action_mask[..., :num_depot].gather(-1, current_depot) | done) + + # The reward is calculated outside via get_reward for efficiency, so we set it to 0 here + reward = torch.zeros_like(done) + + # Update step + td.update( + { + "current_node": current_node, + "current_depot": current_depot, + "current_carry": current_carry, + "available": available, + "to_deliver": to_deliver, + "i": td["i"] + 1, + "action_mask": action_mask, + "reward": reward, + "done": done, + } + ) + return td + + def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: + device = td.device + locs = torch.cat((td["depot"], td["locs"]), -2) + + # Record how many depots are visited + depot_idx = torch.zeros((*batch_size, 1), dtype=torch.int64, device=device) + + # Pick is 1, deliver is 0 [batch_size, graph_size+1], i.e. [1, 1, ..., 1, 0, ...0] + to_deliver = torch.cat( + [ + torch.ones( + *batch_size, + self.generator.num_loc // 2 + self.generator.num_depot, + dtype=torch.bool, + device=device, + ), + torch.zeros( + *batch_size, self.generator.num_loc // 2, dtype=torch.bool, device=device + ), + ], + dim=-1, + ) + + # Current depot index + if self.start_mode == "random": + current_depot = torch.randint( + low=0, high=self.generator.num_depot, size=(*batch_size, 1), device=device + ) + elif self.start_mode == "order": + current_depot = torch.zeros((*batch_size, 1), dtype=torch.int64, device=device) + + # Current carry order number + current_carry = torch.zeros((*batch_size, 1), dtype=torch.int64, device=device) + + # Current length of each depot + current_length = torch.zeros((*batch_size, self.generator.num_depot), dtype=torch.float32, device=device) + + # Arrive time for each city + arrivetime_record = torch.zeros((*batch_size, self.generator.num_loc + self.generator.num_depot), dtype=torch.float32, device=device) + + # Cannot visit depot at first step # [0,1...1] so set not available + available = torch.ones( + (*batch_size, self.generator.num_loc + self.generator.num_depot), dtype=torch.bool, device=device + ) + action_mask = ~available.contiguous() # [batch_size, graph_size+1] + action_mask[..., 0] = 1 # First step is always the depot + + # Other variables + current_node = torch.zeros( + (*batch_size, 1), dtype=torch.int64, device=device + ) + i = torch.zeros((*batch_size, 1), dtype=torch.int64, device=device) + + return TensorDict( + { + "locs": locs, + "depot_idx": depot_idx, + "current_node": current_node, + "current_depot": current_depot, + "current_carry": current_carry, + "current_length": current_length, + "arrivetime_record": arrivetime_record, + "capacity": td["capacity"], + "lateness_weight": td["lateness_weight"], + "to_deliver": to_deliver, + "available": available, + "i": i, + "action_mask": action_mask, + }, + batch_size=batch_size, + ) + + def _make_spec(self, generator: MDCPDPGenerator): + """Make the observation and action specs from the parameters.""" + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(generator.num_loc + 1, 2), + dtype=torch.float32, + ), + current_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + to_deliver=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + i=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(generator.num_loc + 1), + dtype=torch.bool, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=0, + high=generator.num_loc + 1, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + def get_distance(self, prev_loc, cur_loc): + # Use L1 norm to calculate the distance for Manhattan distance + if self.dist_mode == "L1": + return torch.abs(cur_loc - prev_loc).norm(p=1, dim=-1) + elif self.dist_mode == "L2": + return torch.abs(cur_loc - prev_loc).norm(p=2, dim=-1) + else: + raise ValueError(f"Invalid distance norm: {self.dist_norm}") + + def _get_reward(self, td: TensorDict, actions) -> TensorDict: + """Return the rewrad for the current state + Support modes: + - minmax: the reward is the maximum length of all agents + - minsum: the reward is the sum of all agents' length + - lateness: the reward is the sum of all agents' length plus the lateness with a weight + Args: + - actions [batch_size, num_depot+num_locs-1]: the actions taken by the agents + note that the last city back to depot is not included here + """ + # Check the validity of the actions + num_depot = td["capacity"].shape[-1] + num_loc = td["locs"].shape[-2] - num_depot # except depot + + # Append the last depot to the end of the actions + actions = torch.cat([actions, td["current_depot"]], dim=-1) + + # Calculate the reward + if self.reward_mode == "minmax": + cost = torch.max(td["current_length"], dim=-1)[0] + elif self.reward_mode == "minsum": + cost = torch.sum(td["current_length"], dim=-1) + elif self.reward_mode == "lateness": + cost = torch.sum(td["current_length"], dim=(-1)) + lateness = td["arrivetime_record"][..., num_depot+num_loc//2:] + if self.reward_mode == "lateness_square": + lateness = lateness ** 2 + lateness = torch.sum(lateness, dim=-1) + # lateness weight - note that if this is 0, the reward is the same as the cost + # and if this is 1, the reward is the same as the lateness + cost = cost * (1 - td["lateness_weight"].squeeze()) + lateness * td["lateness_weight"].squeeze() + else: + raise NotImplementedError(f"Invalid reward mode: {self.reward_mode}. Available modes: minmax, minsum, lateness_square, lateness") + return -cost # minus for reward + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor): + assert True, "Not implemented" + + @staticmethod + def render(td: TensorDict, actions: torch.Tensor=None, ax = None): + return render(td, actions, ax) diff --git a/rl4co/envs/routing/mdcpdp/generator.py b/rl4co/envs/routing/mdcpdp/generator.py new file mode 100644 index 00000000..284e46a0 --- /dev/null +++ b/rl4co/envs/routing/mdcpdp/generator.py @@ -0,0 +1,126 @@ +from typing import Union, Callable + +import torch + +from torch.distributions import Uniform +from tensordict.tensordict import TensorDict + +from rl4co.utils.pylogger import get_pylogger +from rl4co.envs.common.utils import get_sampler, Generator + +log = get_pylogger(__name__) + + +class MDCPDPGenerator(Generator): + """Data generator for the Multi Depot Capacitated Pickup and Delivery Problem (MDCPDP) environment. + + Args: + num_loc: number of locations (customers) + min_loc: minimum value for the location coordinates + max_loc: maximum value for the location coordinates, default is 150 insted of 1.0, will be scaled + loc_distribution: distribution for the location coordinates + num_depot: number of depots, each depot has one vehicle + depot_mode: mode for the depot, either single or multiple + depod_distribution: distribution for the depot coordinates + min_capacity: minimum value of the capacity + max_capacity: maximum value of the capacity + min_lateness_weight: minimum value of the lateness weight + max_lateness_weight: maximum value of the lateness weight + latebess_weight_distribution: distribution for the lateness weight + + Returns: + A TensorDict with the following keys: + locs [batch_size, num_loc, 2]: locations of each customer + depot [batch_size, num_depot, 2]: locations of each depot + capacity [batch_size, 1]: capacity of the vehicle + lateness_weight [batch_size, 1]: weight of the lateness cost + """ + def __init__( + self, + num_loc: int = 20, + min_loc: float = 0.0, + max_loc: float = 1.0, + loc_distribution: Union[ + int, float, str, type, Callable + ] = Uniform, + num_depot: int = 5, + depot_mode: str = "multiple", + depot_distribution: Union[ + int, float, str, type, Callable + ] = Uniform, + min_capacity: int = 1, + max_capacity: int = 5, + min_lateness_weight: float = 1.0, + max_lateness_weight: float = 1.0, + lateness_weight_distribution: Union[ + int, float, str, type, Callable + ] = Uniform, + **kwargs + ): + self.num_loc = num_loc + self.min_loc = min_loc + self.max_loc = max_loc + self.depot_mode = depot_mode + self.num_depot = num_depot + self.min_capacity = min_capacity + self.max_capacity = max_capacity + self.min_lateness_weight = min_lateness_weight + self.max_lateness_weight = max_lateness_weight + + # Number of locations must be even + if num_loc % 2 != 0: + log.warn("Number of locations must be even. Adding 1 to the number of locations.") + self.num_loc += 1 + + # Check depot mode validity + assert depot_mode in ["single", "multiple"], f"Invalid depot mode: {depot_mode}" + + # Location distribution + if kwargs.get("loc_sampler", None) is not None: + self.loc_sampler = kwargs["loc_sampler"] + else: + self.loc_sampler = get_sampler("loc", loc_distribution, min_loc, max_loc, **kwargs) + + # Depot distribution + if kwargs.get("depot_sampler", None) is not None: + self.depot_sampler = kwargs["depot_sampler"] + else: + self.depot_sampler = get_sampler("depot", depot_distribution, min_loc, max_loc, **kwargs) + + # Lateness weight distribution + if kwargs.get("lateness_weight_sampler", None) is not None: + self.lateness_weight_sampler = kwargs["lateness_weight_sampler"] + else: + self.lateness_weight_sampler = get_sampler( + "lateness_weight", lateness_weight_distribution, min_lateness_weight, max_lateness_weight, **kwargs + ) + + def _generate(self, batch_size) -> TensorDict: + # Sample locations + locs = self.loc_sampler.sample((*batch_size, self.num_loc, 2)) + + # Sample depot + if self.depot_mode == "single": + depot = self.depot_sampler.sample((*batch_size, 2))[:, None, :].repeat(1, self.num_depot, 1) + else: + depot = self.depot_sampler.sample((*batch_size, self.num_depot, 2)) + + # Sample capacity + capacity = torch.randint( + self.min_capacity, + self.max_capacity + 1, + size=(*batch_size, 1), + ) + + # Sample lateness weight + lateness_weight = self.lateness_weight_sampler.sample((*batch_size, 1)) + + return TensorDict( + { + "locs": locs, + "depot": depot, + "capacity": capacity, + "lateness_weight": lateness_weight, + }, + batch_size=batch_size, + ) diff --git a/rl4co/envs/routing/mdcpdp/render.py b/rl4co/envs/routing/mdcpdp/render.py new file mode 100644 index 00000000..5711b1d7 --- /dev/null +++ b/rl4co/envs/routing/mdcpdp/render.py @@ -0,0 +1,120 @@ +from tensordict.tensordict import TensorDict + + +def render(td: TensorDict, actions=None, ax=None): + import matplotlib.pyplot as plt + markersize = 8 + + td = td.detach().cpu() + + # If batch_size greater than 0 , we need to select the first batch element + if td.batch_size != torch.Size([]): + td = td[0] + if actions is not None: + actions = actions[0] + + n_depots = td["capacity"].size(-1) + n_pickups = (td["locs"].size(-2) - n_depots) // 2 + + # Variables + init_deliveries = td["to_deliver"][n_depots:] + delivery_locs = td["locs"][n_depots:][~init_deliveries.bool()] + pickup_locs = td["locs"][n_depots:][init_deliveries.bool()] + depot_locs = td["locs"][:n_depots] + actions = actions if actions is not None else td["action"] + + if ax is None: + _, ax = plt.subplots(figsize=(4, 4)) + + # Plot the actions in order + last_depot = 0 + for i in range(len(actions)-1): + if actions[i+1] < n_depots: + last_depot = actions[i+1] + if actions[i] < n_depots and actions[i+1] < n_depots: + continue + from_node = actions[i] + to_node = ( + actions[i + 1] if i < len(actions) - 1 else actions[0] + ) # last goes back to depot + from_loc = td["locs"][from_node] + to_loc = td["locs"][to_node] + ax.plot([from_loc[0], to_loc[0]], [from_loc[1], to_loc[1]], "k-") + ax.annotate( + "", + xy=(to_loc[0], to_loc[1]), + xytext=(from_loc[0], from_loc[1]), + arrowprops=dict(arrowstyle="->", color="black"), + annotation_clip=False, + ) + + # Plot last back to the depot + from_node = actions[-1] + to_node = last_depot + from_loc = td["locs"][from_node] + to_loc = td["locs"][to_node] + ax.plot([from_loc[0], to_loc[0]], [from_loc[1], to_loc[1]], "k-") + ax.annotate( + "", + xy=(to_loc[0], to_loc[1]), + xytext=(from_loc[0], from_loc[1]), + arrowprops=dict(arrowstyle="->", color="black"), + annotation_clip=False, + ) + + # Annotate node location + for i, loc in enumerate(td["locs"]): + ax.annotate( + str(i), + (loc[0], loc[1]), + textcoords="offset points", + xytext=(0, 5), + ha="center", + ) + + for i, depot_loc in enumerate(depot_locs): + ax.plot( + depot_loc[0], + depot_loc[1], + "tab:green", + marker="s", + markersize=markersize, + label="Depot" if i == 0 else None, + ) + + # Plot the pickup locations + for i, pickup_loc in enumerate(pickup_locs): + ax.plot( + pickup_loc[0], + pickup_loc[1], + "tab:red", + marker="^", + markersize=markersize, + label="Pickup" if i == 0 else None, + ) + + # Plot the delivery locations + for i, delivery_loc in enumerate(delivery_locs): + ax.plot( + delivery_loc[0], + delivery_loc[1], + "tab:blue", + marker="x", + markersize=markersize, + label="Delivery" if i == 0 else None, + ) + + # Plot pickup and delivery pair: from loc[n_depot + i ] to loc[n_depot + n_pickups + i] + for i in range(n_pickups): + pickup_loc = td["locs"][n_depots + i] + delivery_loc = td["locs"][n_depots + n_pickups + i] + ax.plot( + [pickup_loc[0], delivery_loc[0]], + [pickup_loc[1], delivery_loc[1]], + "k--", + alpha=0.5, + ) + + # Setup limits and show + ax.set_xlim(-0.05, 1.05) + ax.set_ylim(-0.05, 1.05) diff --git a/rl4co/envs/routing/mpdp/__init__.py b/rl4co/envs/routing/mpdp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/mpdp/env.py b/rl4co/envs/routing/mpdp/env.py new file mode 100644 index 00000000..969d85c6 --- /dev/null +++ b/rl4co/envs/routing/mpdp/env.py @@ -0,0 +1,405 @@ +from typing import Optional + +import torch + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +from .generator import MPDPGenerator +from .render import render + +log = get_pylogger(__name__) + + +class MPDPEnv(RL4COEnvBase): + """Multi-agent Pickup and Delivery Problem (mPDP) environment. + The goal is to pick up and deliver all the packages while satisfying the precedence constraints. + When an agent goes back to the depot, a new agent is spawned. In the min-max version, the goal is to minimize the + maximum tour length among all agents. The reward is 0 unless the agent visits all the customers. + In that case, the reward is (-)length of the path: maximizing the reward is equivalent to minimizing the path length. + + Observations: + - locations of the depot, pickup, and delivery locations + - current location of the vehicle + - the remaining locations to deliver + - the visited locations + - the current step + + Constraints: + - the tour starts and ends at the depot + - each pickup location must be visited before its corresponding delivery location + - the vehicle cannot visit the same location twice + + Finish Condition: + - the vehicle has visited all locations + + Reward: + - (minus) the negative length of the path + + Args: + generator: MPDPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "mpdp" + + def __init__( + self, + generator: MPDPGenerator = None, + generator_params: dict = {}, + objective: str = "minmax", + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = MPDPGenerator(**generator_params) + self.generator = generator + self.objective = objective + self._make_spec(self.generator) + + def _step(self, td: TensorDict) -> TensorDict: + selected = td["action"][:, None] # Add dimension for step + + agent_num = td["lengths"].size(1) + n_loc = td["to_delivery"].size(-1) - agent_num - 1 + + new_to_delivery = (selected + n_loc // 2) % ( + n_loc + agent_num + 1 + ) # the pair node of selected node + + is_request = (selected > agent_num) & (selected <= agent_num + n_loc // 2) + td["left_request"][is_request] -= 1 + depot_distance = td["depot_distance"].scatter(-1, selected, 0) + + add_pd = td["add_pd_distance"][is_request.squeeze(-1), :].gather( + -1, selected[is_request.squeeze(-1), :] - agent_num - 1 + ) + td["longest_lengths"][is_request.squeeze(-1), :].scatter_add_( + -1, td["count_depot"][is_request.squeeze(-1), :], add_pd + ) + td["add_pd_distance"][is_request.squeeze(-1), :].scatter_( + -1, selected[is_request.squeeze(-1), :] - agent_num - 1, 0 + ) + remain_sum_paired_distance = td["add_pd_distance"].sum(-1, keepdim=True) + remain_pickup_max_distance = depot_distance[:, : agent_num + 1 + n_loc // 2].max( + dim=-1, keepdim=True + )[0] + remain_delivery_max_distance = depot_distance[ + :, agent_num + 1 + n_loc // 2 : + ].max(dim=-1, keepdim=True)[0] + + # Calculate makespan + cur_coord = gather_by_index(td["locs"], selected) + path_lengths = (cur_coord - td["cur_coord"]).norm(p=2, dim=-1) + + td["lengths"].scatter_add_(-1, td["count_depot"], path_lengths.unsqueeze(-1)) + + # If visit depot then plus one to count_depot\ + td["count_depot"][ + (selected == td["agent_idx"]) & (td["agent_idx"] < agent_num) + ] += 1 # torch.ones(td["count_depot"][(selected == 0) & (td["agent_idx"] < agent_num)].shape, dtype=torch.int64, device=td["count_depot"].device) + + # `agent_idx` is added by 1 if the current agent comes back to depot + agent_idx = (td["count_depot"] + 1) * torch.ones( + selected.size(0), 1, dtype=torch.long, device=td["count_depot"].device + ) + visited = td["visited"].scatter(-1, selected.unsqueeze(-1), 1) + to_delivery = td["to_delivery"].scatter(-1, new_to_delivery[:, :, None], 1) + + # Get done and reward + done = visited.all(dim=-1, keepdim=True).squeeze(-1) + reward = torch.zeros_like(done) + + td.update( + { + "visited": visited, + "agent_idx": agent_idx, + "cur_coord": cur_coord, + "to_delivery": to_delivery, + "depot_distance": depot_distance, + "remain_sum_paired_distance": remain_sum_paired_distance, + "remain_pickup_max_distance": remain_pickup_max_distance, + "remain_delivery_max_distance": remain_delivery_max_distance, + "i": td["i"] + 1, + "done": done, + "reward": reward, + } + ) + td.set("action_mask", self.get_action_mask(td)) + return td + + def _reset( + self, + td: Optional[TensorDict] = None, + batch_size: Optional[list] = None, + agent_num: Optional[int] = None, # NOTE hardcoded from ET + ) -> TensorDict: + device = td.device + + # NOTE: this is a hack to get the agent_num + # agent_num = td["agent_num"][0].item() if agent_num is None else agent_num + # agent_num = agent_num if agent_num is not None else td["agent_num"][0].item() + + depot = td["depot"] + depot = depot.repeat(1, agent_num + 1, 1) + loc = td["locs"] + left_request = loc.size(1) // 2 + whole_instance = torch.cat((depot, loc), dim=1) + + # Distance from all nodes between each other + distance = torch.cdist(whole_instance, whole_instance, p=2) + index = torch.arange(left_request, 2 * left_request, device=device)[ + None, :, None + ] + index = index.repeat(distance.shape[0], 1, 1) + add_pd_distance = distance[ + :, agent_num + 1 : agent_num + 1 + left_request, agent_num + 1 : + ].gather(-1, index) + add_pd_distance = add_pd_distance.squeeze(-1) + + remain_pickup_max_distance = distance[:, 0, : agent_num + 1 + left_request].max( + dim=-1, keepdim=True + )[0] + remain_delivery_max_distance = distance[:, 0, agent_num + 1 + left_request :].max( + dim=-1, keepdim=True + )[0] + remain_sum_paired_distance = add_pd_distance.sum(dim=-1, keepdim=True) + + # Distance from depot to all nodes + # Delivery nodes should consider the sum of distance from depot to paired pickup nodes and pickup nodes to delivery nodes + distance[:, 0, agent_num + 1 : agent_num + 1 + left_request] = ( + distance[:, 0, agent_num + 1 : agent_num + 1 + left_request] + + distance[:, 0, agent_num + 1 + left_request :] + ) + + # Distance from depot to all nodes + depot_distance = distance[:, 0, :] + depot_distance[:, agent_num + 1 : agent_num + 1 + left_request] = depot_distance[ + :, agent_num + 1 : agent_num + 1 + left_request + ] # + add_pd_distance + + batch_size, n_loc, _ = loc.size() + to_delivery = torch.cat( + [ + torch.ones( + batch_size, + 1, + n_loc // 2 + agent_num + 1, + dtype=torch.uint8, + device=device, + ), + torch.zeros( + batch_size, 1, n_loc // 2, dtype=torch.uint8, device=device + ), + ], + dim=-1, + ) + + # Create reset TensorDict + td_reset = TensorDict( + { + "locs": torch.cat((depot, loc), -2), + "visited": torch.zeros( + batch_size, + 1, + n_loc + agent_num + 1, + dtype=torch.uint8, + device=device, + ), + "lengths": torch.zeros(batch_size, agent_num, device=device), + "longest_lengths": torch.zeros(batch_size, agent_num, device=device), + "cur_coord": td["depot"] + if len(td["depot"].shape) == 2 + else td["depot"].squeeze(1), + "i": torch.zeros( + batch_size, dtype=torch.int64, device=device + ), # Vector with length num_steps + "to_delivery": to_delivery, + "count_depot": torch.zeros( + batch_size, 1, dtype=torch.int64, device=device + ), + "agent_idx": torch.ones( + batch_size, 1, dtype=torch.long, device=device + ), + "left_request": left_request + * torch.ones(batch_size, 1, dtype=torch.long, device=device), + "remain_pickup_max_distance": remain_pickup_max_distance, + "remain_delivery_max_distance": remain_delivery_max_distance, + "depot_distance": depot_distance, + "remain_sum_paired_distance": remain_sum_paired_distance, + "add_pd_distance": add_pd_distance, + }, + batch_size=batch_size, + ) + td_reset.set("action_mask", self.get_action_mask(td_reset)) + return td_reset + + @staticmethod + def get_action_mask(td: TensorDict) -> torch.Tensor: + """Get the action mask for the current state.""" + + visited_loc = td["visited"].clone() + + agent_num = td["lengths"].size(1) + n_loc = visited_loc.size(-1) - agent_num - 1 # num of customers + batch_size = visited_loc.size(0) + agent_idx = td["agent_idx"][:, None, :] + mask_loc = visited_loc.to(td["to_delivery"].device) | (1 - td["to_delivery"]) + + # depot + if td["i"][0].item() != 0: + mask_loc[:, :, : agent_num + 1] = 1 + + # if deliver nodes which is assigned agent is complete, then agent can go to depot + no_item_to_delivery = ( + visited_loc[:, :, n_loc // 2 + agent_num + 1 :] + == td["to_delivery"][:, :, n_loc // 2 + agent_num + 1 :] + ).all(dim=-1) + mask_loc[no_item_to_delivery.squeeze(-1), :, :] = mask_loc[ + no_item_to_delivery.squeeze(-1), :, : + ].scatter_(-1, agent_idx[no_item_to_delivery.squeeze(-1), :, :], 0) + + condition = (td["count_depot"] == agent_num - 1) & ( + (visited_loc[:, :, agent_num + 1 :] == 0).sum(dim=-1) != 0 + ) + + mask_loc[..., agent_num][condition] = 1 + + else: + return ( + torch.cat( + [ + torch.zeros( + batch_size, 1, 1, dtype=torch.uint8, device=mask_loc.device + ), + torch.ones( + batch_size, + 1, + n_loc + agent_num, + dtype=torch.uint8, + device=mask_loc.device, + ), + ], + dim=-1, + ) + > 0 + ) + action_mask = mask_loc == 0 # action_mask gets feasible actions + return action_mask + + def _get_reward(self, td: TensorDict, actions: torch.Tensor) -> torch.Tensor: + # Calculate the reward (negative tour length) + if self.objective == "minmax": + return -td["lengths"].max(dim=-1, keepdim=True)[0].squeeze(-1) + elif self.objective == "minsum": + return -td["lengths"].sum(dim=-1, keepdim=True).squeeze(-1) + else: + raise ValueError(f"Unknown objective {self.objective}") + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor) -> None: + assert True, "Not implemented" + + def _make_spec(self, generator: MPDPGenerator): + """Make the observation and action specs from the parameters.""" + max_nodes = self.num_loc + self.max_num_agents + 1 + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(max_nodes, 2), + dtype=torch.float32, + ), + current_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(max_nodes, 1), + dtype=torch.bool, + ), + visited=UnboundedDiscreteTensorSpec( + shape=(1, max_nodes), + dtype=torch.bool, + ), + lengths=UnboundedContinuousTensorSpec( + shape=(generator.max_num_agents,), + dtype=torch.float32, + ), + longest_lengths=UnboundedContinuousTensorSpec( + shape=(generator.max_num_agents,), + dtype=torch.float32, + ), + cur_coord=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(2,), + dtype=torch.float32, + ), + to_delivery=UnboundedDiscreteTensorSpec( + shape=(max_nodes, 1), + dtype=torch.bool, + ), + count_depot=UnboundedDiscreteTensorSpec( + shape=(1,), + dtype=torch.int64, + ), + agent_idx=UnboundedDiscreteTensorSpec( + shape=(1,), + dtype=torch.int64, + ), + left_request=UnboundedDiscreteTensorSpec( + shape=(1,), + dtype=torch.int64, + ), + remain_pickup_max_distance=UnboundedContinuousTensorSpec( + shape=(1,), + dtype=torch.float32, + ), + remain_delivery_max_distance=UnboundedContinuousTensorSpec( + shape=(1,), + dtype=torch.float32, + ), + depot_distance=UnboundedContinuousTensorSpec( + shape=(max_nodes,), + dtype=torch.float32, + ), + remain_sum_paired_distance=UnboundedContinuousTensorSpec( + shape=(1,), + dtype=torch.float32, + ), + add_pd_distance=UnboundedContinuousTensorSpec( + shape=(max_nodes,), + dtype=torch.float32, + ), + ## NOTE: we should have a vectorized implementation for agent_num + # agent_num=UnboundedDiscreteTensorSpec( + # shape=(1,), + # dtype=torch.int64, + # ), + i=UnboundedDiscreteTensorSpec( + shape=(1,), + dtype=torch.int64, + ), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=0, + high=max_nodes, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + @staticmethod + def render(td: TensorDict, actions: torch.Tensor=None, ax = None): + return render(td, actions, ax) \ No newline at end of file diff --git a/rl4co/envs/routing/mpdp/generator.py b/rl4co/envs/routing/mpdp/generator.py new file mode 100644 index 00000000..13f42932 --- /dev/null +++ b/rl4co/envs/routing/mpdp/generator.py @@ -0,0 +1,95 @@ +from typing import Union, Callable + +import torch + +from torch.distributions import Uniform +from tensordict.tensordict import TensorDict + +from rl4co.utils.pylogger import get_pylogger +from rl4co.envs.common.utils import get_sampler, Generator + +log = get_pylogger(__name__) + + +class MPDPGenerator(Generator): + """Data generator for the Capacitated Vehicle Routing Problem (CVRP). + Args: + num_loc: number of locations + min_loc: minimum location value + max_loc: maximum location value + loc_distribution: distribution for the locations + depot_distribution: distribution for the depot location. If None, sample the depot from the locations + min_num_agents: minimum number of agents + max_num_agents: maximum number of agents + + Returns: + A TensorDict with the following keys: + locs [batch_size, num_loc, 2]: locations of each customer and the depot + depot [batch_size, 2]: location of the depot + num_agents [batch_size]: number of agents + """ + def __init__( + self, + num_loc: int = 20, + min_loc: float = 0.0, + max_loc: float = 1.0, + loc_distribution: Union[ + int, float, str, type, Callable + ] = Uniform, + depot_distribution: Union[ + int, float, str, type, Callable + ] = None, + min_num_agents: int = 2, + max_num_agents: int = 10, + **kwargs + ): + self.num_loc = num_loc + self.min_loc = min_loc + self.max_loc = max_loc + self.min_num_agents = min_num_agents + self.max_num_agents = max_num_agents + + # Number of locations must be even + if num_loc % 2 != 0: + log.warn("Number of locations must be even. Adding 1 to the number of locations.") + self.num_loc += 1 + + # Location distribution + if kwargs.get("loc_sampler", None) is not None: + self.loc_sampler = kwargs["loc_sampler"] + else: + self.loc_sampler = get_sampler("loc", loc_distribution, min_loc, max_loc, **kwargs) + + # Depot distribution + if kwargs.get("depot_sampler", None) is not None: + self.depot_sampler = kwargs["depot_sampler"] + else: + self.depot_sampler = get_sampler("depot", depot_distribution, min_loc, max_loc, **kwargs) if depot_distribution is not None else None + + + def _generate(self, batch_size) -> TensorDict: + # Sample locations: depot and customers + if self.depot_sampler is not None: + depot = self.depot_sampler.sample((*batch_size, 2)) + locs = self.loc_sampler.sample((*batch_size, self.num_loc, 2)) + else: + # if depot_sampler is None, sample the depot from the locations + locs = self.loc_sampler.sample((*batch_size, self.num_loc + 1, 2)) + depot = locs[..., 0, :] + locs = locs[..., 1:, :] + + # Sample the number of agents + num_agents = torch.randint( + self.min_num_agents, + self.max_num_agents + 1, + size=(*batch_size, ), + ) + + return TensorDict( + { + "locs": locs, + "depot": depot, + "num_agents": num_agents, + }, + batch_size=batch_size, + ) diff --git a/rl4co/envs/routing/mpdp/render.py b/rl4co/envs/routing/mpdp/render.py new file mode 100644 index 00000000..1f49a2f9 --- /dev/null +++ b/rl4co/envs/routing/mpdp/render.py @@ -0,0 +1,114 @@ +import torch +import numpy as np +import matplotlib.pyplot as plt + +from matplotlib import cm, colormaps + +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def render(td, actions=None, ax=None): + # TODO: color switch with new agents; add pickup and delivery nodes as in `PDPEnv.render` + + import matplotlib.pyplot as plt + import numpy as np + + from matplotlib import cm, colormaps + + num_routine = (actions == 0).sum().item() + 2 + base = colormaps["nipy_spectral"] + color_list = base(np.linspace(0, 1, num_routine)) + cmap_name = base.name + str(num_routine) + out = base.from_list(cmap_name, color_list, num_routine) + + if ax is None: + # Create a plot of the nodes + _, ax = plt.subplots() + + td = td.detach().cpu() + + if actions is None: + actions = td.get("action", None) + + # if batch_size greater than 0 , we need to select the first batch element + if td.batch_size != torch.Size([]): + td = td[0] + actions = actions[0] + + locs = td["locs"] + + # add the depot at the first action and the end action + actions = torch.cat([torch.tensor([0]), actions, torch.tensor([0])]) + + # gather locs in order of action if available + if actions is None: + log.warning("No action in TensorDict, rendering unsorted locs") + else: + locs = locs + + # Cat the first node to the end to complete the tour + x, y = locs[:, 0], locs[:, 1] + + # plot depot + ax.scatter( + locs[0, 0], + locs[0, 1], + edgecolors=cm.Set2(2), + facecolors="none", + s=100, + linewidths=2, + marker="s", + alpha=1, + ) + + # plot visited nodes + ax.scatter( + x[1:], + y[1:], + edgecolors=cm.Set2(0), + facecolors="none", + s=50, + linewidths=2, + marker="o", + alpha=1, + ) + + # text depot + ax.text( + locs[0, 0], + locs[0, 1] - 0.025, + "Depot", + horizontalalignment="center", + verticalalignment="top", + fontsize=10, + color=cm.Set2(2), + ) + + # plot actions + color_idx = 0 + for action_idx in range(len(actions) - 1): + if actions[action_idx] == 0: + color_idx += 1 + from_loc = locs[actions[action_idx]] + to_loc = locs[actions[action_idx + 1]] + ax.plot( + [from_loc[0], to_loc[0]], + [from_loc[1], to_loc[1]], + color=out(color_idx), + lw=1, + ) + ax.annotate( + "", + xy=(to_loc[0], to_loc[1]), + xytext=(from_loc[0], from_loc[1]), + arrowprops=dict(arrowstyle="-|>", color=out(color_idx)), + size=15, + annotation_clip=False, + ) + + # Setup limits and show + ax.set_xlim(-0.05, 1.05) + ax.set_ylim(-0.05, 1.05) diff --git a/rl4co/envs/routing/mtsp/__init__.py b/rl4co/envs/routing/mtsp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/mtsp/env.py b/rl4co/envs/routing/mtsp/env.py new file mode 100644 index 00000000..2259be41 --- /dev/null +++ b/rl4co/envs/routing/mtsp/env.py @@ -0,0 +1,246 @@ +from typing import Optional + +import numpy as np +import torch + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.envs.common.utils import batch_to_scalar +from rl4co.utils.ops import gather_by_index, get_distance, get_tour_length + +from .generator import MTSPGenerator +from .render import render + + +class MTSPEnv(RL4COEnvBase): + """Multiple Traveling Salesman Problem environment + At each step, an agent chooses to visit a city. A maximum of `num_agents` agents can be employed to visit the cities. + The cost can be defined in two ways: + - `minmax`: (default) the reward is the maximum of the path lengths of all the agents + - `sum`: the cost is the sum of the path lengths of all the agents + Reward is - cost, so the goal is to maximize the reward (minimize the cost). + + Observations: + - locations of the depot and each customer. + - number of agents. + - the current agent index. + - the current location of the vehicle. + + Constrains: + - each agent's tour starts and ends at the depot. + - each customer must be visited exactly once. + + Finish condition: + - all customers are visited and all agents back to the depot. + + Reward: + There are two ways to calculate the cost (-reward): + - `minmax`: (default) the cost is the maximum of the path lengths of all the agents. + - `sum`: the cost is the sum of the path lengths of all the agents. + + Args: + cost_type: type of cost to use, either `minmax` or `sum` + generator: MTSPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "mtsp" + + def __init__( + self, + generator: MTSPGenerator = None, + generator_params: dict = {}, + cost_type: str = "minmax", + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = MTSPGenerator(**generator_params) + self.generator = generator + self.cost_type = cost_type + self._make_spec(self.generator) + + @staticmethod + def _step(td: TensorDict) -> TensorDict: + # Initial variables + is_first_action = batch_to_scalar(td["i"]) == 0 + current_node = td["action"] + first_node = current_node if is_first_action else td["first_node"] + + # Get the locations of the current node and the previous node and the depot + cur_loc = gather_by_index(td["locs"], current_node) + prev_loc = gather_by_index( + td["locs"], td["current_node"] + ) # current_node is the previous node + depot_loc = td["locs"][..., 0, :] + + # If current_node is the depot, then increment agent_idx + cur_agent_idx = td["agent_idx"] + (current_node == 0).long() + + # Set not visited to 0 (i.e., we visited the node) + available = td["action_mask"].scatter( + -1, current_node[..., None].expand_as(td["action_mask"]), 0 + ) + # Available[..., 0] is the depot, which is always available unless: + # - current_node is the depot + # - agent_idx greater than num_agents -1 + available[..., 0] = torch.logical_and( + current_node != 0, td["agent_idx"] < td["num_agents"] - 1 + ) + + # We are done there are no unvisited locations except the depot + done = torch.count_nonzero(available[..., 1:], dim=-1) == 0 + + # If done is True, then we make the depot available again, so that it will be selected as the next node with prob 1 + available[..., 0] = torch.logical_or(done, available[..., 0]) + + # Update the current length + current_length = td["current_length"] + get_distance(cur_loc, prev_loc) + + # If done, we add the distance from the current_node to the depot as well + current_length = torch.where( + done, current_length + get_distance(cur_loc, depot_loc), current_length + ) + + # We update the max_subtour_length and reset the current_length + max_subtour_length = torch.where( + current_length > td["max_subtour_length"], + current_length, + td["max_subtour_length"], + ) + + # If current agent is different from previous agent, then we have a new subtour and reset the length + current_length *= (cur_agent_idx == td["agent_idx"]).float() + + # The reward is the negative of the max_subtour_length (minmax objective) + reward = -max_subtour_length + + td.update( + { + "max_subtour_length": max_subtour_length, + "current_length": current_length, + "agent_idx": cur_agent_idx, + "first_node": first_node, + "current_node": current_node, + "i": td["i"] + 1, + "action_mask": available, + "reward": reward, + "done": done, + } + ) + + return td + + def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: + device = td.device + + # Keep track of the agent number to know when to stop + agent_idx = torch.zeros((*batch_size,), dtype=torch.int64, device=device) + + # Make variable for max_subtour_length between subtours + max_subtour_length = torch.zeros(batch_size, dtype=torch.float32, device=device) + current_length = torch.zeros(batch_size, dtype=torch.float32, device=device) + + # Other variables + current_node = torch.zeros((*batch_size,), dtype=torch.int64, device=device) + available = torch.ones( + (*batch_size, self.generator.num_loc), dtype=torch.bool, device=device + ) # 1 means not visited, i.e. action is allowed + available[..., 0] = 0 # Depot is not available as first node + i = torch.zeros((*batch_size,), dtype=torch.int64, device=device) + + return TensorDict( + { + "locs": td["locs"], # depot is first node + "num_agents": td["num_agents"], + "max_subtour_length": max_subtour_length, + "current_length": current_length, + "agent_idx": agent_idx, + "first_node": current_node, + "current_node": current_node, + "i": i, + "action_mask": available, + }, + batch_size=batch_size, + ) + + def _make_spec(self, generator: MTSPGenerator): + """Make the observation and action specs from the parameters.""" + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(generator.num_loc, 2), + dtype=torch.float32, + ), + num_agents=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + agent_idx=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + current_length=UnboundedContinuousTensorSpec( + shape=(1), + dtype=torch.float32, + ), + max_subtour_length=UnboundedContinuousTensorSpec( + shape=(1), + dtype=torch.float32, + ), + first_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + current_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + i=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(generator.num_loc), + dtype=torch.bool, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=0, + high=generator.num_loc, + ) + self.reward_spec = UnboundedContinuousTensorSpec() + self.done_spec = UnboundedDiscreteTensorSpec(dtype=torch.bool) + + def _get_reward(self, td, actions=None) -> TensorDict: + # With minmax, get the maximum distance among subtours, calculated in the model + if self.cost_type == "minmax": + return td["reward"].squeeze(-1) + + # With distance, same as TSP + elif self.cost_type == "sum": + locs = td["locs"] + locs_ordered = locs.gather(1, actions.unsqueeze(-1).expand_as(locs)) + return -get_tour_length(locs_ordered) + + else: + raise ValueError(f"Cost type {self.cost_type} not supported") + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor): + assert True, "Not implemented" + + @staticmethod + def render(td, actions=None, ax=None): + return render(td, actions, ax) diff --git a/rl4co/envs/routing/mtsp/generator.py b/rl4co/envs/routing/mtsp/generator.py new file mode 100644 index 00000000..1716ca41 --- /dev/null +++ b/rl4co/envs/routing/mtsp/generator.py @@ -0,0 +1,72 @@ +from typing import Callable, Union + +import torch + +from tensordict.tensordict import TensorDict +from torch.distributions import Uniform + +from rl4co.envs.common.utils import Generator, get_sampler +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class MTSPGenerator(Generator): + """Data generator for the Multiple Travelling Salesman Problem (mTSP). + + Args: + num_loc: number of locations (customers) in the TSP + min_loc: minimum value for the location coordinates + max_loc: maximum value for the location coordinates + loc_distribution: distribution for the location coordinates + min_num_agents: minimum number of agents (vehicles), include + max_num_agents: maximum number of agents (vehicles), include + + Returns: + A TensorDict with the following keys: + locs [batch_size, num_loc, 2]: locations of each customer + num_agents [batch_size]: number of agents (vehicles) + """ + + def __init__( + self, + num_loc: int = 20, + min_loc: float = 0.0, + max_loc: float = 1.0, + loc_distribution: Union[int, float, str, type, Callable] = Uniform, + min_num_agents: int = 5, + max_num_agents: int = 5, + **kwargs, + ): + self.num_loc = num_loc + self.min_loc = min_loc + self.max_loc = max_loc + self.min_num_agents = min_num_agents + self.max_num_agents = max_num_agents + + # Location distribution + if kwargs.get("loc_sampler", None) is not None: + self.loc_sampler = kwargs["loc_sampler"] + else: + self.loc_sampler = get_sampler( + "loc", loc_distribution, min_loc, max_loc, **kwargs + ) + + def _generate(self, batch_size) -> TensorDict: + # Sample locations + locs = self.loc_sampler.sample((*batch_size, self.num_loc, 2)) + + # Sample the number of agents + num_agents = torch.randint( + self.min_num_agents, + self.max_num_agents + 1, + size=(*batch_size,), + ) + + return TensorDict( + { + "locs": locs, + "num_agents": num_agents, + }, + batch_size=batch_size, + ) diff --git a/rl4co/envs/routing/mtsp/render.py b/rl4co/envs/routing/mtsp/render.py new file mode 100644 index 00000000..173301ae --- /dev/null +++ b/rl4co/envs/routing/mtsp/render.py @@ -0,0 +1,95 @@ +import torch +import numpy as np +import matplotlib.pyplot as plt + +from matplotlib import colormaps + +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def render(td, actions=None, ax=None): + def discrete_cmap(num, base_cmap="nipy_spectral"): + """Create an N-bin discrete colormap from the specified input map""" + base = colormaps[base_cmap] + color_list = base(np.linspace(0, 1, num)) + cmap_name = base.name + str(num) + return base.from_list(cmap_name, color_list, num) + + if actions is None: + actions = td.get("action", None) + # if batch_size greater than 0 , we need to select the first batch element + if td.batch_size != torch.Size([]): + td = td[0] + actions = actions[0] + + num_agents = td["num_agents"] + locs = td["locs"] + cmap = discrete_cmap(num_agents, "rainbow") + + fig, ax = plt.subplots() + + # Add depot action = 0 to before first action and after last action + actions = torch.cat( + [ + torch.zeros(1, dtype=torch.int64), + actions, + torch.zeros(1, dtype=torch.int64), + ] + ) + + # Make list of colors from matplotlib + for i, loc in enumerate(locs): + if i == 0: + # depot + marker = "s" + color = "g" + label = "Depot" + markersize = 10 + else: + # normal location + marker = "o" + color = "tab:blue" + label = "Customers" + markersize = 8 + if i > 1: + label = "" + + ax.plot( + loc[0], + loc[1], + color=color, + marker=marker, + markersize=markersize, + label=label, + ) + + # Plot the actions in order + agent_idx = 0 + for i in range(len(actions)): + if actions[i] == 0: + agent_idx += 1 + color = cmap(num_agents - agent_idx) + + from_node = actions[i] + to_node = ( + actions[i + 1] if i < len(actions) - 1 else actions[0] + ) # last goes back to depot + from_loc = td["locs"][from_node] + to_loc = td["locs"][to_node] + ax.plot([from_loc[0], to_loc[0]], [from_loc[1], to_loc[1]], color=color) + ax.annotate( + "", + xy=(to_loc[0], to_loc[1]), + xytext=(from_loc[0], from_loc[1]), + arrowprops=dict(arrowstyle="->", color=color), + annotation_clip=False, + ) + + # Legend + handles, labels = ax.get_legend_handles_labels() + ax.legend(handles, labels) + ax.set_title("mTSP") + ax.set_xlabel("x-coordinate") + ax.set_ylabel("y-coordinate") diff --git a/rl4co/envs/routing/mtvrp/__init__.py b/rl4co/envs/routing/mtvrp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/mtvrp/baselines/__init__.py b/rl4co/envs/routing/mtvrp/baselines/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/mtvrp/baselines/constants.py b/rl4co/envs/routing/mtvrp/baselines/constants.py new file mode 100644 index 00000000..e17b888b --- /dev/null +++ b/rl4co/envs/routing/mtvrp/baselines/constants.py @@ -0,0 +1,42 @@ +LKH_SCALING_FACTOR = 100_000 +ORTOOLS_SCALING_FACTOR = 100_000 +PYVRP_SCALING_FACTOR = 1_000 + + +ROUTEFINDER2LKH = { + "CVRP": "CVRP", + "OVRP": "OVRP", + "OVRPB": None, # Issue: don't know + "OVRPBL": None, # Issue: distance limits + "OVRPBLTW": None, # Issue: distance limits + "OVRPBTW": None, # Issue: service times don't work in VRPBTW + "OVRPL": "OVRP", + "OVRPLTW": "CVRPTW", + "OVRPMB": "VRPMPD", + "OVRPMBL": "VRPMPD", + "OVRPMBTW": "VRPMPDTW", + "OVRPMBLTW": "VRPMPDTW", # Issue: distance limits + "OVRPTW": "CVRPTW", + "VRPB": None, # Issue: don't know: linehaul after backhaul + "VRPBL": None, + "VRPBLTW": None, # Issue: service times don't work in VRPBTW + "VRPBTW": None, # Issue: service times don't work in VRPBTW + "VRPL": "DCVRP", + "VRPLTW": "CVRPTW", # I don't think that limits get respected + "VRPMB": "VRPMPD", + "VRPMBL": "VRPMPD", # I don't think that limits get respected + "VRPMBTW": "VRPMPDTW", + "VRPMBLTW": None, # Issue: don't know + "VRPTW": "CVRPTW", +} + +LKH_VARIANTS = [ + "CVRP", + "OVRP", + "CVRPTW", + "DCVRP", + "VRPB", + "VRPBTW", + "VRPMPD", + "VRPMPDTW", +] diff --git a/rl4co/envs/routing/mtvrp/baselines/lkh.py b/rl4co/envs/routing/mtvrp/baselines/lkh.py new file mode 100644 index 00000000..40946516 --- /dev/null +++ b/rl4co/envs/routing/mtvrp/baselines/lkh.py @@ -0,0 +1,214 @@ +import lkh +import numpy as np + +from tensordict import TensorDict +from torch import Tensor + +from .constants import LKH_SCALING_FACTOR, ROUTEFINDER2LKH +from .utils import scale + + +def solve( + instance: TensorDict, + max_runtime: float, + problem_type: str, + num_runs: int, + solver_loc: str, +) -> tuple[Tensor, Tensor]: + """ + Solves an AnyVRP instance with OR-Tools. + + Args: + instance: The AnyVRP instance to solve. + max_runtime: The maximum runtime for the solver. + problem_type: The problem type for LKH3. + num_runs: The number of runs to perform and returns the best result. + solver_loc: The location of the LKH3 solver executable. + + Returns: + A tuple containing the action and the cost, respectively. + """ + problem = instance2problem(instance, problem_type, LKH_SCALING_FACTOR) + action, cost = _solve(problem, max_runtime, num_runs, solver_loc) + cost /= -LKH_SCALING_FACTOR + + return action, cost + + +def _solve( + problem: lkh.LKHProblem, + max_runtime: float, + num_runs: int, + solver_loc: str, +) -> tuple[Tensor, Tensor]: + """ + Solves an instance with LKH3. + + Args: + problem: The LKHProblem instance. + max_runtime: The maximum runtime for each solver run. + num_runs: The number of runs to perform and returns the best result. + solver_loc: The location of the LKH3 solver executable. + + Returns: + A tuple containing the action and the cost, respectively. + """ + routes, cost = lkh.solve( + solver_loc, + problem=problem, + time_limit=max_runtime, + runs=num_runs, + ) + + action = routes2action(routes) + return action, cost + + +def instance2problem( + instance: TensorDict, + problem_type: str, + scaling_factor, +) -> lkh.LKHProblem: + """ + Converts an AnyVRP instance to an LKHProblem instance. + + Args: + instance: The AnyVRP instance to convert. + problem_type: The problem type for LKH3. + scaling_factor: The scaling factor to apply to the instance data. + + Returns: + The LKHProblem instance. + """ + num_locations = instance["demand_linehaul"].size()[0] + + # Data specifications + specs = {} + specs["DIMENSION"] = num_locations + specs["CAPACITY"] = scale(instance["vehicle_capacity"], scaling_factor) + + if not np.isinf(distance_limit := instance["distance_limit"]).any(): + specs["DISTANCE"] = scale(distance_limit, scaling_factor) + + specs["EDGE_WEIGHT_TYPE"] = "EXPLICIT" + specs["EDGE_WEIGHT_FORMAT"] = "FULL_MATRIX" + specs["NODE_COORD_TYPE"] = "TWOD_COORDS" + + # LKH can only solve VRP variants that are explicitly supported (so no + # arbitrary combinations between individual supported features). We can + # support some open variants with some modeling tricks. + lkh_problem_type = ROUTEFINDER2LKH[problem_type] + if lkh_problem_type is None: + raise ValueError(f"Problem type {problem_type} is not supported by LKH.") + + specs["TYPE"] = lkh_problem_type + + # Weird LKH quirk: specifying the number of vehicles lets (D)CVRP hang. + if lkh_problem_type not in ["CVRP", "DCVRP"]: + specs["VEHICLES"] = num_locations - 1 + + # Data sections + sections = {} + sections["NODE_COORD_SECTION"] = scale(instance["locs"], scaling_factor) + + demand_linehaul = scale(instance["demand_linehaul"], scaling_factor) + demand_backhaul = scale(instance["demand_backhaul"], scaling_factor) + sections["DEMAND_SECTION"] = demand_linehaul + demand_backhaul + + time_windows = scale(instance["time_windows"], scaling_factor) + sections["TIME_WINDOW_SECTION"] = time_windows + + service_times = scale(instance["durations"], scaling_factor) + sections["SERVICE_TIME_SECTION"] = service_times + + distances = instance["cost_matrix"] + backhaul_class = instance["backhaul_class"] + + if backhaul_class == 1: + # VRPB has a backhaul section that specifies the backhaul nodes. + backhaul_idcs = np.flatnonzero(instance["demand_backhaul"]).tolist() + sections["BACKHAUL_SECTION"] = backhaul_idcs + [-1] + + # linehaul = np.flatnonzero(demand_linehaul > 0) + # backhaul = np.flatnonzero(demand_backhaul > 0) + # distances[np.ix_(backhaul, linehaul)] = time_windows.max() + + elif backhaul_class == 2: + # VRPMPD has a pickup and delivery section that specifies the pickup + # and delivery quantities for each node, as well as the time windows. + # The regular time window section is redundant in this case. + data = [ + [ + 0, # dummy + time_windows[idx][0], + time_windows[idx][1], + service_times[idx], + demand_backhaul[idx], + demand_linehaul[idx], + ] + for idx in range(num_locations) + ] + sections["PICKUP_AND_DELIVERY_SECTION"] = data + + if instance["open_route"]: + # Arcs to the depot are set to zero as vehicles don’t need to return. + distances[:, 0] = 0 + + sections["EDGE_WEIGHT_SECTION"] = scale(distances, scaling_factor) + + # Convert to VRPLIB-like string. + problem = "\n".join(f"{k} : {v}" for k, v in specs.items()) + problem += "\n" + "\n".join(_format(name, data) for name, data in sections.items()) + problem += "\n" + "\n".join(["DEPOT_SECTION", "1", "-1", "EOF"]) + + return lkh.LKHProblem.parse(problem) + + +def _is_1D(data) -> bool: + for elt in data: + if isinstance(elt, (list, tuple, np.ndarray)): + return False + return True + + +def _format(name: str, data) -> str: + """ + Formats a data section. + + Args: + name: The name of the section. + data: The data to be formatted. + + Returns: + A VRPLIB-formatted data section. + """ + section = [name] + include_idx = name not in ["EDGE_WEIGHT_SECTION", "BACKHAUL_SECTION"] + + if name == "BACKHAUL_SECTION": + # Treat backhaul section as row vector. + section.append("\t".join(str(val) for val in data)) + + elif _is_1D(data): + # Treat 1D arrays as column vectors, so each element is a row. + for idx, elt in enumerate(data, 1): + prefix = f"{idx}\t" if include_idx else "" + section.append(prefix + str(elt)) + else: + for idx, row in enumerate(data, 1): + prefix = f"{idx}\t" if include_idx else "" + rest = "\t".join([str(elt) for elt in row]) + section.append(prefix + rest) + + return "\n".join(section) + + +def routes2action(routes: list[list[int]]) -> list[int]: + """ + Converts LKH routes to an action. + """ + # LKH routes are location-indexed, which in turn are 1-indexed. The first + # location is always the depot, so we subtract 2 to get client indices. + # LKH routes are 1-indexed, so we subtract 1 to get client indices. + routes_ = [[client - 1 for client in route] for route in routes] + return [visit for route in routes_ for visit in route + [0]] diff --git a/rl4co/envs/routing/mtvrp/baselines/ortools.py b/rl4co/envs/routing/mtvrp/baselines/ortools.py new file mode 100644 index 00000000..67b31c1a --- /dev/null +++ b/rl4co/envs/routing/mtvrp/baselines/ortools.py @@ -0,0 +1,248 @@ +from dataclasses import dataclass +from typing import Optional + +import numpy as np +import routefinder.baselines.pyvrp as pyvrp + +from ortools.constraint_solver import pywrapcp, routing_enums_pb2 +from tensordict import TensorDict +from torch import Tensor + +from .constants import ORTOOLS_SCALING_FACTOR + + +def solve(instance: TensorDict, max_runtime: float, **kwargs) -> tuple[Tensor, Tensor]: + """ + Solves an MTVRP instance with OR-Tools. + + Args: + instance: The MTVRP instance to solve. + max_runtime: The maximum runtime for the solver. + + Returns: + A tuple containing the action and the cost, respectively. + + Note: + This function depends on PyVRP's data converter to convert the MTVRP + instance to an OR-Tools compatible format. Future versions should + implement a direct conversion. + """ + data = instance2data(instance) + action, cost = _solve(data, max_runtime) + cost /= ORTOOLS_SCALING_FACTOR + cost *= -1 + + return action, cost + + +@dataclass +class ORToolsData: + """ + Convenient dataclass for instance data when using OR-Tools as solver. + + Args: + depot: The depot index. + distance_matrix: The distance matrix between locations. + duration_matrix: The duration matrix between locations. This includes service times. + num_vehicles: The number of vehicles. + vehicle_capacities: The capacity of each vehicle. + max_distance: The maximum distance a vehicle can travel. + demands: The demands of each location. + time_windows: The time windows for each location. Optional. + backhauls: The pickup quantity for backhaul at each location. + """ + + depot: int + distance_matrix: list[list[int]] + duration_matrix: list[list[int]] + num_vehicles: int + vehicle_capacities: list[int] + max_distance: int + demands: list[int] + time_windows: Optional[list[list[int]]] + backhauls: Optional[list[int]] + + @property + def num_locations(self) -> int: + return len(self.distance_matrix) + + +def instance2data(instance: TensorDict) -> ORToolsData: + """ + Converts an AnyVRP instance to an ORToolsData instance. + """ + # TODO: Do not use PyVRP's data converter. + data = pyvrp.instance2data(instance, ORTOOLS_SCALING_FACTOR) + + capacities = [ + veh_type.capacity + for veh_type in data.vehicle_types() + for _ in range(veh_type.num_available) + ] + max_distance = data.vehicle_type(0).max_distance + + demands = [0] + [client.delivery for client in data.clients()] + backhauls = [0] + [client.pickup for client in data.clients()] + service = [0] + [client.service_duration for client in data.clients()] + + tws = [[data.location(0).tw_early, data.location(0).tw_late]] + tws += [[client.tw_early, client.tw_late] for client in data.clients()] + + # Set data to None if instance does not contain explicit values. + default_tw = [0, np.iinfo(np.int64).max] + if all(tw == default_tw for tw in tws): + tws = None # type: ignore + + if all(val == 0 for val in backhauls): + backhauls = None # type: ignore + + distances = data.distance_matrix().copy() + durations = np.array(distances) + np.array(service)[:, np.newaxis] + + if backhauls is not None: + # Serve linehauls before backhauls. + linehaul = np.flatnonzero(np.array(demands) > 0) + backhaul = np.flatnonzero(np.array(backhauls) > 0) + distances[np.ix_(backhaul, linehaul)] = max_distance + + return ORToolsData( + depot=0, + distance_matrix=distances.tolist(), + duration_matrix=durations.tolist(), + num_vehicles=data.num_vehicles, + vehicle_capacities=capacities, + demands=demands, + time_windows=tws, + max_distance=max_distance, + backhauls=backhauls, + ) + + +def _solve(data: ORToolsData, max_runtime: float, log: bool = False): + """ + Solves an instance with OR-Tools. + + Args: + data: The instance data. + max_runtime: The maximum runtime in seconds. + log: Whether to log the search. + + Returns: + A tuple containing the action and the cost, respectively. + """ + # Manager for converting between nodes (location indices) and index + # (internal CP variable indices). + manager = pywrapcp.RoutingIndexManager( + data.num_locations, data.num_vehicles, data.depot + ) + routing = pywrapcp.RoutingModel(manager) + + # Set arc costs equal to distances. + distance_transit_idx = routing.RegisterTransitMatrix(data.distance_matrix) + routing.SetArcCostEvaluatorOfAllVehicles(distance_transit_idx) + + # Max distance constraint. + routing.AddDimension( + distance_transit_idx, + 0, # null distance slack + data.max_distance, # maximum distance per vehicle + True, # start cumul at zero + "Distance", + ) + + # Vehicle capacity constraint. + routing.AddDimensionWithVehicleCapacity( + routing.RegisterUnaryTransitVector(data.demands), + 0, # null capacity slack + data.vehicle_capacities, # vehicle maximum capacities + True, # start cumul to zero + "Demand", + ) + + # Backhauls: this assumes that VRPB is implemented by forbidding arcs + # that go from backhauls to linehauls. + if data.backhauls is not None: + routing.AddDimensionWithVehicleCapacity( + routing.RegisterUnaryTransitVector(data.backhauls), + 0, # null capacity slack + data.vehicle_capacities, # vehicle maximum capacities + True, # start cumul to zero + "Backhaul", + ) + + # Time window constraints. + if data.time_windows is not None: + depot_tw_early = data.time_windows[data.depot][0] + depot_tw_late = data.time_windows[data.depot][1] + + # The depot's late time window is a valid upper bound for the waiting + # time and maximum duration per vehicle. + routing.AddDimension( + routing.RegisterTransitMatrix(data.duration_matrix), + depot_tw_late, # waiting time upper bound + depot_tw_late, # maximum duration per vehicle + False, # don't force start cumul to zero + "Time", + ) + time_dim = routing.GetDimensionOrDie("Time") + + for node, (tw_early, tw_late) in enumerate(data.time_windows): + if node == data.depot: # skip depot + continue + + index = manager.NodeToIndex(node) + time_dim.CumulVar(index).SetRange(tw_early, tw_late) + + # Add time window constraints for each vehicle start node. + for node in range(data.num_vehicles): + start = routing.Start(node) + time_dim.CumulVar(start).SetRange(depot_tw_early, depot_tw_late) + + for node in range(data.num_vehicles): + cumul_start = time_dim.CumulVar(routing.Start(node)) + routing.AddVariableMinimizedByFinalizer(cumul_start) + + cumul_end = time_dim.CumulVar(routing.End(node)) + routing.AddVariableMinimizedByFinalizer(cumul_end) + + # Setup search parameters. + params = pywrapcp.DefaultRoutingSearchParameters() + + gls = routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH + params.local_search_metaheuristic = gls + + params.time_limit.FromSeconds(int(max_runtime)) # only accepts int + params.log_search = log + + solution = routing.SolveWithParameters(params) + action = solution2action(data, manager, routing, solution) + objective = solution.ObjectiveValue() + + return action, objective + + +def solution2action(data, manager, routing, solution) -> list[list[int]]: + """ + Converts an OR-Tools solution to routes. + """ + routes = [] + distance = 0 # for debugging + + for vehicle_idx in range(data.num_vehicles): + index = routing.Start(vehicle_idx) + route = [] + route_cost = 0 + + while not routing.IsEnd(index): + node = manager.IndexToNode(index) + route.append(node) + + prev_index = index + index = solution.Value(routing.NextVar(index)) + route_cost += routing.GetArcCostForVehicle(prev_index, index, vehicle_idx) + + if clients := route[1:]: # ignore depot + routes.append(clients) + distance += route_cost + + return [visit for route in routes for visit in route + [0]] diff --git a/rl4co/envs/routing/mtvrp/baselines/pyvrp.py b/rl4co/envs/routing/mtvrp/baselines/pyvrp.py new file mode 100644 index 00000000..1e889323 --- /dev/null +++ b/rl4co/envs/routing/mtvrp/baselines/pyvrp.py @@ -0,0 +1,109 @@ +import numpy as np +import pyvrp as pyvrp + +from pyvrp import Client, Depot, ProblemData, VehicleType, solve as _solve +from pyvrp.constants import MAX_VALUE +from pyvrp.stop import MaxRuntime +from tensordict.tensordict import TensorDict +from torch import Tensor + +from .constants import PYVRP_SCALING_FACTOR +from .utils import scale + + +def solve(instance: TensorDict, max_runtime: float, **kwargs) -> tuple[Tensor, Tensor]: + """ + Solves the AnyVRP instance with PyVRP. + + Args: + instance: The AnyVRP instance to solve. + max_runtime: The maximum runtime for the solver. + + Returns: + A tuple containing the action and the cost, respectively. + """ + data = instance2data(instance, PYVRP_SCALING_FACTOR) + stop = MaxRuntime(max_runtime) + result = _solve(data, stop) + + solution = result.best + action = solution2action(solution) + cost = -result.cost() / PYVRP_SCALING_FACTOR + + return action, cost + + +def instance2data(instance: TensorDict, scaling_factor: int) -> ProblemData: + """ + Converts an AnyVRP instance to a ProblemData instance. + + Args: + instance: The AnyVRP instance to convert. + scaling_factor: The scaling factor to use for the conversion. + + Returns: + The ProblemData instance. + """ + num_locs = instance["demand_backhaul"].size()[0] + + time_windows = scale(instance["time_windows"], scaling_factor) + pickup = scale(instance["demand_backhaul"], scaling_factor) + delivery = scale(instance["demand_linehaul"], scaling_factor) + service = scale(instance["service_time"], scaling_factor) + coords = scale(instance["locs"], scaling_factor) + capacity = scale(instance["vehicle_capacity"], scaling_factor) + max_distance = scale(instance["distance_limit"], scaling_factor) + + depot = Depot( + x=coords[0][0], + y=coords[0][1], + ) + + clients = [ + Client( + x=coords[idx][0], + y=coords[idx][1], + tw_early=time_windows[idx][0], + tw_late=time_windows[idx][1], + delivery=delivery[idx], + pickup=pickup[idx], + service_duration=service[idx], + ) + for idx in range(1, num_locs) + ] + + vehicle_type = VehicleType( + num_available=num_locs - 1, # one vehicle per client + capacity=capacity, + max_distance=max_distance, + tw_early=time_windows[0][0], + tw_late=time_windows[0][1], + ) + + matrix = scale(instance["cost_matrix"], scaling_factor) + + if instance["open_route"]: + # Vehicles do not need to return to the depot, so we set all arcs + # to the depot to zero. + matrix[:, 0] = 0 + + if instance["backhaul_class"] == 1: # VRP with backhauls + # In VRPB, linehauls must be served before backhauls. This can be + # enforced by setting a high value for the distance/duration from depot + # to backhaul (forcing linehaul to be served first) and a large value + # from backhaul to linehaul (avoiding linehaul after backhaul clients). + linehaul = np.flatnonzero(delivery > 0) + backhaul = np.flatnonzero(pickup > 0) + # Note: we remove the constraint that we cannot visit backhauls *only* in a + # a single route as per Slack discussion + # matrix[0, backhaul] = MAX_VALUE + matrix[np.ix_(backhaul, linehaul)] = MAX_VALUE + + return ProblemData(clients, [depot], [vehicle_type], [matrix], [matrix]) + + +def solution2action(solution: pyvrp.Solution) -> list[int]: + """ + Converts a PyVRP solution to the action representation, i.e., a giant tour. + """ + return [visit for route in solution.routes() for visit in route.visits() + [0]] diff --git a/rl4co/envs/routing/mtvrp/baselines/solve.py b/rl4co/envs/routing/mtvrp/baselines/solve.py new file mode 100644 index 00000000..f750fe6d --- /dev/null +++ b/rl4co/envs/routing/mtvrp/baselines/solve.py @@ -0,0 +1,83 @@ +from functools import partial +from multiprocessing import Pool + +from tensordict.tensordict import TensorDict +from torch import Tensor + +from .utils import process_instance + + +class NoSolver: + def solve(self, *args, **kwargs): + pass + + +try: + import rl4co.envs.routing.mtvrp.baselines.pyvrp as pyvrp +except ImportError: + pyvrp = NoSolver() +try: + import rl4co.envs.routing.mtvrp.baselines.lkh as lkh +except ImportError: + lkh = NoSolver() +try: + import rl4co.envs.routing.mtvrp.baselines.ortools as ortools +except ImportError: + ortools = NoSolver() + + +def solve( + instances: TensorDict, + max_runtime: float, + num_procs: int = 1, + solver: str = "pyvrp", + **kwargs, +) -> tuple[Tensor, Tensor]: + """ + Solves the AnyVRP instances with PyVRP. + + Args: + instances: The AnyVRP instances to solve. + max_runtime: The maximum runtime for the solver. + num_procs: The number of processes to use. + solver: The solver to use. + + Returns: + A tuple containing the action and the cost, respectively. + """ + + instances = process_instance(instances) + + if solver == "pyvrp" and isinstance(pyvrp, NoSolver): + raise ImportError( + "PyVRP is not installed. Please install it using `pip install -e .[solvers]`." + ) + if solver == "lkh" and isinstance(lkh, NoSolver): + raise ImportError( + "LKH is not installed. Please install it using `pip install -e .[solvers]`" + ) + if solver == "ortools" and isinstance(ortools, NoSolver): + raise ImportError( + "OR-Tools is not installed. Please install it using `pip install -e .[solvers]`." + ) + + solvers = {"pyvrp": pyvrp.solve, "ortools": ortools.solve, "lkh": lkh.solve} + if solver not in solvers: + raise ValueError(f"Unknown baseline solver: {solver}") + + _solve = solvers[solver] + func = partial(_solve, max_runtime=max_runtime, **kwargs) + + if num_procs > 1: + with Pool(processes=num_procs) as pool: + results = pool.map(func, instances) + else: + results = [func(instance) for instance in instances] + + actions, costs = zip(*results) + + # Pad to ensure all actions have the same length. + max_len = max(len(action) for action in actions) + actions = [action + [0] * (max_len - len(action)) for action in actions] + + return Tensor(actions).long(), Tensor(costs) diff --git a/rl4co/envs/routing/mtvrp/baselines/utils.py b/rl4co/envs/routing/mtvrp/baselines/utils.py new file mode 100644 index 00000000..9af2bdf5 --- /dev/null +++ b/rl4co/envs/routing/mtvrp/baselines/utils.py @@ -0,0 +1,36 @@ +import numpy as np +import torch + +from tensordict import TensorDict +from torch import Tensor + + +def process_instance(td: TensorDict) -> TensorDict: + """ + We simply transform the data to the format the current PyVRP API expects + """ + td_ = td.clone().cpu() + td_.set("durations", td["service_time"]) + cost_mat = torch.cdist(td_["locs"], td_["locs"]) + num_loc = cost_mat.shape[-1] + # note: if we don't do this, PyVRP may complain diagonal is not 0. + # i guess it is because of some conversion from floating point to integer + cost_mat[:, torch.arange(num_loc), torch.arange(num_loc)] = 0 + td_.set("cost_matrix", cost_mat) + backhaul_class = td.get("backhaul_class", torch.ones(td_.batch_size[0], 1)) + td_.set("backhaul_class", backhaul_class) + return td_ + + +def scale(data: Tensor, scaling_factor: int): + """ + Scales ands rounds data to integers so PyVRP can handle it. + """ + array = (data * scaling_factor).numpy().round() + array = np.where(array == np.inf, np.iinfo(np.int32).max, array) + array = array.astype(int) + + if array.size == 1: + return array.item() + + return array diff --git a/rl4co/envs/routing/mtvrp/env.py b/rl4co/envs/routing/mtvrp/env.py new file mode 100644 index 00000000..c4a32cc3 --- /dev/null +++ b/rl4co/envs/routing/mtvrp/env.py @@ -0,0 +1,503 @@ +from typing import Optional + +import torch + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.data.utils import load_npz_to_tensordict +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.utils.ops import gather_by_index, get_distance +from rl4co.utils.pylogger import get_pylogger + +from .generator import MTVRPGenerator + +log = get_pylogger(__name__) + + +class MTVRPEnv(RL4COEnvBase): + r"""MTVRPEnv is a Multi-Task VRP environment which can take any combination of the following constraints: + + Features: + + - *Capacity (C)* + - Each vehicle has a maximum capacity $Q$, restricting the total load that can be in the vehicle at any point of the route. + - The route must be planned such that the sum of demands and pickups for all customers visited does not exceed this capacity. + - *Time Windows (TW)* + - Every node $i$ has an associated time window $[e_i, l_i]$ during which service must commence. + - Additionally, each node has a service time $s_i$. Vehicles must reach node $i$ within its time window; early arrivals must wait at the node location until time $e_i$. + - *Open Routes (O)* + - Vehicles are not required to return to the depot after serving all customers. + - Note that this does not need to be counted as a constraint since it can be modelled by setting zero costs on arcs returning to the depot $c_{i0} = 0$ from any customer $i \in C$, and not counting the return arc as part of the route. + - *Backhauls (B)* + - Backhauls generalize demand to also account for return shipments. Customers are either linehaul or backhaul customers. + - Linehaul customers require delivery of a demand $q_i > 0$ that needs to be transported from the depot to the customer, whereas backhaul customers need a pickup of an amount $p_i > 0$ that is transported from the client back to the depot. + - It is possible for vehicles to serve a combination of linehaul and backhaul customers in a single route, but then any linehaul customers must precede the backhaul customers in the route. + - *Duration Limits (L)* + - Imposes a limit on the total travel duration (or length) of each route, ensuring a balanced workload across vehicles. + + The environment covers the following 16 variants depending on the data generation: + + | VRP Variant | Capacity (C) | Open Route (O) | Backhaul (B) | Duration Limit (L) | Time Window (TW) | + | :---------- | :----------: | :------------: | :----------: | :----------------: | :--------------: | + | CVRP | ✔ | | | | | + | OVRP | ✔ | ✔ | | | | + | VRPB | ✔ | | ✔ | | | + | VRPL | ✔ | | | ✔ | | + | VRPTW | ✔ | | | | ✔ | + | OVRPTW | ✔ | ✔ | | | ✔ | + | OVRPB | ✔ | ✔ | ✔ | | | + | OVRPL | ✔ | ✔ | | ✔ | | + | VRPBL | ✔ | | ✔ | ✔ | | + | VRPBTW | ✔ | | ✔ | | ✔ | + | VRPLTW | ✔ | | | ✔ | ✔ | + | OVRPBL | ✔ | ✔ | ✔ | ✔ | | + | OVRPBTW | ✔ | ✔ | ✔ | | ✔ | + | OVRPLTW | ✔ | ✔ | | ✔ | ✔ | + | VRPBLTW | ✔ | | ✔ | ✔ | ✔ | + | OVRPBLTW | ✔ | ✔ | ✔ | ✔ | ✔ | + + You may also check out the following papers as reference: + - ["Multi-Task Learning for Routing Problem with Cross-Problem Zero-Shot Generalization" (Liu et al, 2024)](https://arxiv.org/abs/2402.16891) + - ["MVMoE: Multi-Task Vehicle Routing Solver with Mixture-of-Experts" (Zhou et al, 2024)](https://arxiv.org/abs/2405.01029) + - ["RouteFinder: Towards Foundation Models for Vehicle Routing Problems" (Berto et al, 2024)](https://arxiv.org/abs/2406.15007) + + Tip: + Have a look at https://pyvrp.org/ for more information about VRP and its variants and their solutions. Kudos to their help and great job! + + Args: + generator: Generator for the environment, see :class:`MTVRPGenerator`. + generator_params: Parameters for the generator. + """ + + name = "mtvrp" + + def __init__( + self, + generator: MTVRPGenerator = None, + generator_params: dict = {}, + check_solution: bool = False, + **kwargs, + ): + if check_solution: + log.warning( + "Solution checking is enabled. This may slow down the environment." + " We recommend disabling this for training by passing `check_solution=False`." + ) + + super().__init__(check_solution=check_solution, **kwargs) + + if generator is None: + generator = MTVRPGenerator(**generator_params) + self.generator = generator + self._make_spec(self.generator) + + def _step(self, td: TensorDict) -> TensorDict: + # Get locations and distance + prev_node, curr_node = td["current_node"], td["action"] + prev_loc = gather_by_index(td["locs"], prev_node) + curr_loc = gather_by_index(td["locs"], curr_node) + distance = get_distance(prev_loc, curr_loc)[..., None] + + # Update current time + service_time = gather_by_index( + src=td["service_time"], idx=curr_node, dim=1, squeeze=False + ) + start_times = gather_by_index( + src=td["time_windows"], idx=curr_node, dim=1, squeeze=False + )[..., 0] + # we cannot start before we arrive and we should start at least at start times + curr_time = (curr_node[:, None] != 0) * ( + torch.max(td["current_time"] + distance / td["speed"], start_times) + + service_time + ) + + # Update current route length (reset at depot) + curr_route_length = (curr_node[:, None] != 0) * ( + td["current_route_length"] + distance + ) + + # Linehaul (delivery) demands + selected_demand_linehaul = gather_by_index( + td["demand_linehaul"], curr_node, dim=1, squeeze=False + ) + selected_demand_backhaul = gather_by_index( + td["demand_backhaul"], curr_node, dim=1, squeeze=False + ) + + # Backhaul (pickup) demands + # vehicles are empty once we get to the backhauls + used_capacity_linehaul = (curr_node[:, None] != 0) * ( + td["used_capacity_linehaul"] + selected_demand_linehaul + ) + used_capacity_backhaul = (curr_node[:, None] != 0) * ( + td["used_capacity_backhaul"] + selected_demand_backhaul + ) + + # Done when all customers are visited + visited = td["visited"].scatter(-1, curr_node[..., None], True) + done = visited.sum(-1) == visited.size(-1) + reward = torch.zeros_like( + done + ).float() # we use the `get_reward` method to compute the reward + + td.update( + { + "current_node": curr_node, + "current_route_length": curr_route_length, + "current_time": curr_time, + "done": done, + "reward": reward, + "used_capacity_linehaul": used_capacity_linehaul, + "used_capacity_backhaul": used_capacity_backhaul, + "visited": visited, + } + ) + td.set("action_mask", self.get_action_mask(td)) + return td + + def _reset( + self, + td: Optional[TensorDict] = None, + batch_size: Optional[list] = None, + ) -> TensorDict: + device = td.device + + # Create reset TensorDict + td_reset = TensorDict( + { + "locs": td["locs"], + "demand_backhaul": td["demand_backhaul"], + "demand_linehaul": td["demand_linehaul"], + "distance_limit": td["distance_limit"], + "service_time": td["service_time"], + "open_route": td["open_route"], + "time_windows": td["time_windows"], + "vehicle_capacity": td["vehicle_capacity"], + "capacity_original": td["capacity_original"], + "speed": td["speed"], + "current_node": torch.zeros( + (*batch_size,), dtype=torch.long, device=device + ), + "current_route_length": torch.zeros( + (*batch_size, 1), dtype=torch.float32, device=device + ), # for distance limits + "current_time": torch.zeros( + (*batch_size, 1), dtype=torch.float32, device=device + ), # for time windows + "used_capacity_backhaul": torch.zeros( + (*batch_size, 1), device=device + ), # for capacity constraints in backhaul + "used_capacity_linehaul": torch.zeros( + (*batch_size, 1), device=device + ), # for capacity constraints in linehaul + "visited": torch.zeros( + (*batch_size, td["locs"].shape[-2]), + dtype=torch.bool, + device=device, + ), + }, + batch_size=batch_size, + device=device, + ) + td_reset.set("action_mask", self.get_action_mask(td_reset)) + return td_reset + + @staticmethod + def get_action_mask(td: TensorDict) -> torch.Tensor: + curr_node = td["current_node"] # note that this was just updated! + locs = td["locs"] + d_ij = get_distance( + gather_by_index(locs, curr_node)[..., None, :], locs + ) # i (current) -> j (next) + d_j0 = get_distance(locs, locs[..., 0:1, :]) # j (next) -> 0 (depot) + + # Time constraint (TW): + early_tw, late_tw = ( + td["time_windows"][..., 0], + td["time_windows"][..., 1], + ) + arrival_time = td["current_time"] + (d_ij / td["speed"]) + # can reach in time -> only need to *start* in time + can_reach_customer = arrival_time < late_tw + # we must ensure that we can return to depot in time *if* route is closed + # i.e. start time + service time + time back to depot < late_tw + can_reach_depot = ( + torch.max(arrival_time, early_tw) + td["service_time"] + (d_j0 / td["speed"]) + ) * ~td["open_route"] < late_tw[..., 0:1] + + # Distance limit (L): do not add distance to depot if open route (O) + exceeds_dist_limit = ( + td["current_route_length"] + d_ij + (d_j0 * ~td["open_route"]) + > td["distance_limit"] + ) + + # Linehaul demand / delivery (C) and backhaul demand / pickup (B) + # All linehauls are visited before backhauls + linehauls_missing = ((td["demand_linehaul"] * ~td["visited"]).sum(-1) > 0)[ + ..., None + ] + is_carrying_backhaul = ( + gather_by_index( + src=td["demand_backhaul"], + idx=curr_node, + dim=1, + squeeze=False, + ) + > 0 + ) + exceeds_cap_linehaul = ( + td["demand_linehaul"] + td["used_capacity_linehaul"] > td["vehicle_capacity"] + ) + exceeds_cap_backhaul = ( + td["demand_backhaul"] + td["used_capacity_backhaul"] > td["vehicle_capacity"] + ) + + meets_demand_constraint = ( + linehauls_missing + & ~exceeds_cap_linehaul + & ~is_carrying_backhaul + & (td["demand_linehaul"] > 0) + ) | (~exceeds_cap_backhaul & (td["demand_backhaul"] > 0)) + + # Condense constraints + can_visit = ( + can_reach_customer + & can_reach_depot + & meets_demand_constraint + & ~exceeds_dist_limit + & ~td["visited"] + ) + + # Mask depot: don't visit depot if coming from there and there are still customer nodes I can visit + can_visit[:, 0] = ~((curr_node == 0) & (can_visit[:, 1:].sum(-1) > 0)) + return can_visit + + def _get_reward(self, td: TensorDict, actions: TensorDict) -> TensorDict: + # Append depot to actions and get sequence of locations + go_from = torch.cat((torch.zeros_like(actions[:, :1]), actions), dim=1) + go_to = torch.roll(go_from, -1, dims=1) # [b, seq_len] + loc_from = gather_by_index(td["locs"], go_from) + loc_to = gather_by_index(td["locs"], go_to) + + # Get tour length. If route is open and goes to depot, don't count the distance + distances = get_distance(loc_from, loc_to) # [b, seq_len] + tour_length = (distances * ~((go_to == 0) & td["open_route"])).sum(-1) # [b] + return -tour_length # reward is negative cost + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor): + batch_size, n_loc = td["demand_linehaul"].size() + locs = td["locs"] + n_loc -= 1 # exclude depot + sorted_pi = actions.data.sort(1)[0] + + # all customer nodes visited exactly once + assert ( + torch.arange(1, n_loc + 1, out=sorted_pi.data.new()) + .view(1, -1) + .expand(batch_size, n_loc) + == sorted_pi[:, -n_loc:] + ).all() and (sorted_pi[:, :-n_loc] == 0).all(), "Invalid tour" + + # Distance limits (L) + assert (td["distance_limit"] >= 0).all(), "Distance limits must be non-negative." + + # Time windows (TW) + d_j0 = get_distance(locs, locs[..., 0:1, :]) # j (next) -> 0 (depot) + assert torch.all(td["time_windows"] >= 0.0), "Time windows must be non-negative." + assert torch.all(td["service_time"] >= 0.0), "Service time must be non-negative." + assert torch.all( + td["time_windows"][..., 0] < td["time_windows"][..., 1] + ), "there are unfeasible time windows" + assert torch.all( + td["time_windows"][..., :, 0] + d_j0 + td["service_time"] + <= td["time_windows"][..., 0, 1, None] + ), "vehicle cannot perform service and get back to depot in time." + # check individual time windows + curr_time = torch.zeros(batch_size, dtype=torch.float32, device=td.device) + curr_node = torch.zeros(batch_size, dtype=torch.int64, device=td.device) + curr_length = torch.zeros(batch_size, dtype=torch.float32, device=td.device) + for ii in range(actions.size(1)): + next_node = actions[:, ii] + curr_loc = gather_by_index(td["locs"], curr_node) + next_loc = gather_by_index(td["locs"], next_node) + dist = get_distance(curr_loc, next_loc) + + # distance limit (L) + curr_length = curr_length + dist * ~( + td["open_route"].squeeze(-1) & (next_node == 0) + ) # do not count back to depot for open route + assert torch.all( + curr_length <= td["distance_limit"].squeeze(-1) + ), "Route exceeds distance limit" + curr_length[next_node == 0] = 0.0 # reset length for depot + + curr_time = torch.max( + curr_time + dist, gather_by_index(td["time_windows"], next_node)[..., 0] + ) + assert torch.all( + curr_time <= gather_by_index(td["time_windows"], next_node)[..., 1] + ), "vehicle cannot start service before deadline" + curr_time = curr_time + gather_by_index(td["service_time"], next_node) + curr_node = next_node + curr_time[curr_node == 0] = 0.0 # reset time for depot + + # Demand constraints (C) and (B) + # linehauls are the same as backhauls but with a different feature + def _check_c1(feature="demand_linehaul"): + demand = td[feature].gather(dim=1, index=actions) + used_cap = torch.zeros_like(td[feature][:, 0]) + for ii in range(actions.size(1)): + # reset at depot + used_cap = used_cap * (actions[:, ii] != 0) + used_cap += demand[:, ii] + assert ( + used_cap <= td["vehicle_capacity"] + ).all(), "Used more than capacity for {}: {}".format(feature, used_cap) + + _check_c1("demand_linehaul") + _check_c1("demand_backhaul") + + def load_data(self, fpath, batch_size=[], scale=False): + """Dataset loading from file + Normalize demand by capacity to be in [0, 1] + """ + td_load = load_npz_to_tensordict(fpath) + if scale: + td_load.set( + "demand_linehaul", + td_load["demand_linehaul"] / td_load["capacity_original"], + ) + td_load.set( + "demand_backhaul", + td_load["demand_backhaul"] / td_load["capacity_original"], + ) + return td_load + + @staticmethod + def render(*args, **kwargs): + """Simple wrapper for render function""" + from .render import render + + return render(*args, **kwargs) + + def select_start_nodes(self, td, num_starts): + """Select available start nodes for the environment (e.g. for POMO-based training)""" + num_loc = td["locs"].shape[-2] - 1 + selected = ( + torch.arange(num_starts, device=td.device).repeat_interleave(td.shape[0]) + % num_loc + + 1 + ) + return selected + + @staticmethod + def solve( + instances: TensorDict, + max_runtime: float, + num_procs: int = 1, + solver: str = "pyvrp", + **kwargs, + ) -> tuple[torch.Tensor, torch.Tensor]: + """Classical solver for the environment. This is a wrapper for the baselines solver. + Available solvers are: `pyvrp`, `ortools`, `lkh`. Returns the actions and costs. + """ + from .baselines.solve import solve + + return solve(instances, max_runtime, num_procs, solver, **kwargs) + + def _make_spec(self, td_params: TensorDict): + # TODO: include extra vars (but we don't really need them for now) + """Make the observation and action specs from the parameters.""" + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=self.generator.min_loc, + high=self.generator.max_loc, + shape=(self.generator.num_loc + 1, 2), + dtype=torch.float32, + device=self.device, + ), + current_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + device=self.device, + ), + demand_linehaul=BoundedTensorSpec( + low=-self.generator.capacity, + high=self.generator.max_demand, + shape=(self.generator.num_loc, 1), # demand is only for customers + dtype=torch.float32, + device=self.device, + ), + demand_backhaul=BoundedTensorSpec( + low=-self.generator.capacity, + high=self.generator.max_demand, + shape=(self.generator.num_loc, 1), # demand is only for customers + dtype=torch.float32, + device=self.device, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(self.generator.num_loc + 1, 1), + dtype=torch.bool, + device=self.device, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + low=0, + high=self.generator.num_loc + 1, + shape=(1,), + dtype=torch.int64, + device=self.device, + ) + self.reward_spec = UnboundedContinuousTensorSpec( + shape=(1,), dtype=torch.float32, device=self.device + ) + self.done_spec = UnboundedDiscreteTensorSpec( + shape=(1,), dtype=torch.bool, device=self.device + ) + + @staticmethod + def check_variants(td): + """Check if the problem has the variants""" + has_open = td["open_route"].squeeze(-1) + has_tw = (td["time_windows"][:, :, 1] != float("inf")).any(-1) + has_limit = (td["distance_limit"] != float("inf")).squeeze(-1) + has_backhaul = (td["demand_backhaul"] != 0).any(-1) + return has_open, has_tw, has_limit, has_backhaul + + @staticmethod + def get_variant_names(td): + ( + has_open, + has_time_window, + has_duration_limit, + has_backhaul, + ) = MTVRPEnv.check_variants(td) + instance_names = [] + for o, b, l_, tw in zip( + has_open, has_backhaul, has_duration_limit, has_time_window + ): + if not o and not b and not l_ and not tw: + instance_name = "CVRP" + else: + instance_name = "VRP" + if o: + instance_name = "O" + instance_name + if b: + instance_name += "B" + if l_: + instance_name += "L" + if tw: + instance_name += "TW" + instance_names.append(instance_name) + return instance_names + + def print_presets(self): + self.generator.print_presets() diff --git a/rl4co/envs/routing/mtvrp/generator.py b/rl4co/envs/routing/mtvrp/generator.py new file mode 100644 index 00000000..4c06796b --- /dev/null +++ b/rl4co/envs/routing/mtvrp/generator.py @@ -0,0 +1,436 @@ +from typing import Callable, Tuple, Union + +import torch + +from tensordict.tensordict import TensorDict +from torch.distributions import Uniform + +from rl4co.data.utils import save_tensordict_to_npz +from rl4co.envs.common.utils import Generator, get_sampler +from rl4co.utils.ops import get_distance +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def get_vehicle_capacity(num_loc: int) -> int: + """Capacity should be 30 + num_loc/5 if num_loc > 20 as described in Liu et al. 2024 (POMO-MTL). + For every N over 1000, we add 1 of capacity every 33.3 nodes to align with Ye et al. 2024 (GLOP), + i.e. 260 at 2K nodes, 350 at 5K nodes and 500 at 10K nodes. + Note that this serves as a demand scaler. + """ + if num_loc > 1000: + extra_cap = 1000 // 5 + (num_loc - 1000) // 33.3 + elif num_loc > 20: + extra_cap = num_loc // 5 + else: + extra_cap = 0 + return 30 + extra_cap + + +VARIANT_GENERATION_PRESETS = { + "all": {"O": 0.5, "TW": 0.5, "L": 0.5, "B": 0.5}, + "single_feat": {"O": 0.5, "TW": 0.5, "L": 0.5, "B": 0.5}, + "single_feat_otw": {"O": 0.5, "TW": 0.5, "L": 0.5, "B": 0.5, "OTW": 0.5}, # same training as Zhou et al. 2024 + "cvrp": {"O": 0.0, "TW": 0.0, "L": 0.0, "B": 0.0}, + "ovrp": {"O": 1.0, "TW": 0.0, "L": 0.0, "B": 0.0}, + "vrpb": {"O": 0.0, "TW": 0.0, "L": 0.0, "B": 1.0}, + "vrpl": {"O": 0.0, "TW": 0.0, "L": 1.0, "B": 0.0}, + "vrptw": {"O": 0.0, "TW": 1.0, "L": 0.0, "B": 0.0}, + "ovrptw": {"O": 1.0, "TW": 1.0, "L": 0.0, "B": 0.0}, + "ovrpb": {"O": 1.0, "TW": 0.0, "L": 0.0, "B": 1.0}, + "ovrpl": {"O": 1.0, "TW": 0.0, "L": 1.0, "B": 0.0}, + "vrpbl": {"O": 0.0, "TW": 0.0, "L": 1.0, "B": 1.0}, + "vrpbtw": {"O": 0.0, "TW": 1.0, "L": 0.0, "B": 1.0}, + "vrpltw": {"O": 0.0, "TW": 1.0, "L": 1.0, "B": 0.0}, + "ovrpbl": {"O": 1.0, "TW": 0.0, "L": 1.0, "B": 1.0}, + "ovrpbtw": {"O": 1.0, "TW": 1.0, "L": 0.0, "B": 1.0}, + "ovrpltw": {"O": 1.0, "TW": 1.0, "L": 1.0, "B": 0.0}, + "vrpbltw": {"O": 0.0, "TW": 1.0, "L": 1.0, "B": 1.0}, + "ovrpbltw": {"O": 1.0, "TW": 1.0, "L": 1.0, "B": 1.0}, +} + + +class MTVRPGenerator(Generator): + """MTVRP Generator. + Class to generate instances of the MTVRP problem. + If a variant is declared and Subsample is True, the generator will sample the problem based on the variant probabilities. + By default, we use Mixed-Batch Training as in Berto et al. 2024 (RouteFinder), i.e. one batch can contain multiple variants. + + Example presets: + - "all": Sample uniformly from 16 variants + - "single_feat": Sample uniformly between CVRP, OVRP, VRPB, VRPL, VRPTW (as done in Liu et al. 2024 (MTPOMO)) + - "single_feat_otw": Sample uniformly between CVRP, OVRP, VRPB, VRPL, VRPTW, OVRPTW (as done in Zhou et al. 2024 (MVMoE)) + - "cvrp": Only CVRP (similarly for other variants) + + Args: + num_loc: Number of locations to generate + min_loc: Minimum location value + max_loc: Maximum location value + loc_distribution: Distribution to sample locations from + capacity: Vehicle capacity. If None, get value based on `get_vehicle_capacity` + min_demand: Minimum demand value + max_demand: Maximum demand value + min_backhaul: Minimum backhaul value + max_backhaul: Maximum backhaul value + scale_demand: Scale demand values (by default, generate between 1 and 10) + max_time: Maximum time window value (at depot) + backhaul_ratio: Fraction of backhauls (e.g. 0.2 means 20% of nodes are backhaul) + distance_limit: Distance limit + speed: Speed of vehicle. Defaults to 1 + subsample: If False, we always sample all attributes (i.e., OVRPBLTW) + If true, we use the + **kwargs: Additional keyword arguments + """ + + def __init__( + self, + num_loc: int = 20, + min_loc: float = 0.0, + max_loc: float = 1.0, + loc_distribution: Union[int, float, str, type, Callable] = Uniform, + capacity: float = None, + min_demand: int = 1, + max_demand: int = 10, + min_backhaul: int = 1, + max_backhaul: int = 10, + scale_demand: bool = True, + max_time: float = 4.6, + backhaul_ratio: float = 0.2, + distance_limit: float = 3.0, + speed: float = 1.0, + prob_open: float = 0.5, + prob_time_window: float = 0.5, + prob_limit: float = 0.5, + prob_backhaul: float = 0.5, + variant_preset=None, + use_combinations=True, + subsample=True, + **kwargs, + ) -> None: + # Location distribution + self.num_loc = num_loc + self.min_loc = min_loc + self.max_loc = max_loc + if kwargs.get("loc_sampler", None) is not None: + self.loc_sampler = kwargs["loc_sampler"] + else: + self.loc_sampler = get_sampler( + "loc", loc_distribution, min_loc, max_loc, **kwargs + ) + + if capacity is None: + capacity = get_vehicle_capacity(num_loc) + self.capacity = capacity + self.min_demand = min_demand + self.max_demand = max_demand + self.min_backhaul = min_backhaul + self.max_backhaul = max_backhaul + self.scale_demand = scale_demand + self.backhaul_ratio = backhaul_ratio + + self.max_time = max_time + self.distance_limit = distance_limit + self.speed = speed + + assert not (subsample and (variant_preset is None)), ( + "Cannot use subsample if variant_preset is not specified. " + ) + if variant_preset is not None: + log.info(f"Using variant generation preset {variant_preset}") + variant_probs = VARIANT_GENERATION_PRESETS.get(variant_preset) + assert ( + variant_probs is not None + ), f"Variant generation preset {variant_preset} not found. \ + Available presets are {VARIANT_GENERATION_PRESETS.keys()} with probabilities {VARIANT_GENERATION_PRESETS.values()}" + else: + variant_probs = { + "O": prob_open, + "TW": prob_time_window, + "L": prob_limit, + "B": prob_backhaul, + } + # check probabilities + for key, prob in variant_probs.items(): + assert 0 <= prob <= 1, f"Probability {key} must be between 0 and 1" + self.variant_probs = variant_probs + self.variant_preset = variant_preset + if isinstance(variant_preset, str) and variant_preset != "all": + log.warning(f"{variant_preset} selected. Will not use feature combination!") + use_combinations = False + self.use_combinations = use_combinations + self.subsample = subsample + + def _generate(self, batch_size) -> TensorDict: + # Locations + locs = self.generate_locations(batch_size=batch_size, num_loc=self.num_loc) + + # Vehicle capacity (C, B) - applies to both linehaul and backhaul + vehicle_capacity = torch.full( + (*batch_size, 1), self.capacity, dtype=torch.float32 + ) + capacity_original = vehicle_capacity.clone() + + # linehaul demand / delivery (C) and backhaul / pickup demand (B) + demand_linehaul, demand_backhaul = self.generate_demands( + batch_size=batch_size, num_loc=self.num_loc + ) + # add empty depot demands + demand_linehaul = torch.cat( + [torch.zeros(size=(*batch_size, 1)), demand_linehaul], dim=1 + ) + demand_backhaul = torch.cat( + [torch.zeros(size=(*batch_size, 1)), demand_backhaul], dim=1 + ) + + # Open (O) + open_route = self.generate_open_route(shape=(*batch_size, 1)) + + # Time windows (TW) + speed = self.generate_speed(shape=(*batch_size, 1)) + time_windows, service_time = self.generate_time_windows( + locs=locs, + speed=speed, + ) + + # Distance limit (L) + distance_limit = self.generate_distance_limit(shape=(*batch_size, 1), locs=locs) + + # scaling + if self.scale_demand: + demand_backhaul /= vehicle_capacity + demand_linehaul /= vehicle_capacity + vehicle_capacity /= vehicle_capacity + + # Put all variables together + td = TensorDict( + { + "locs": locs, + "demand_backhaul": demand_backhaul, # (C) + "demand_linehaul": demand_linehaul, # (B) + "distance_limit": distance_limit, # (L) + "time_windows": time_windows, # (TW) + "service_time": service_time, # (TW) + "vehicle_capacity": vehicle_capacity, # (C) + "capacity_original": capacity_original, # unscaled capacity (C) + "open_route": open_route, # (O) + "speed": speed, # common + }, + batch_size=batch_size, + ) + + if self.subsample: + # Subsample problems based on given instructions + return self.subsample_problems(td) + else: + # Not subsampling problems, i.e. return tensordict with all attributes + return td + + + + def subsample_problems(self, td): + """Create subproblems starting from seed probabilities depending on their variant. + If random seed sampled in [0, 1] in batch is greater than prob, remove the constraint + thus, if prob high, it is less likely to remove the constraint (i.e. prob=0.9, 90% chance to keep constraint) + """ + batch_size = td.batch_size[0] + + variant_probs = torch.tensor(list(self.variant_probs.values())) + + if self.use_combinations: + # in a batch, multiple variants combinations can be picked + keep_mask = torch.rand(batch_size, 4) >= variant_probs # O, TW, L, B + else: + # in a batch, only a variant can be picked. + # we assign a 0.5 prob to the last variant (which is normal cvrp) + if self.variant_preset in list( + VARIANT_GENERATION_PRESETS.keys() + ) and self.variant_preset not in ( + "all", + "cvrp", + "single_feat", + "single_feat_otw", + ): + cvrp_prob = 0 + else: + cvrp_prob = 0.5 + if self.variant_preset in ("all", "cvrp", "single_feat", "single_feat_otw"): + indices = torch.distributions.Categorical( + torch.Tensor(list(self.variant_probs.values()) + [cvrp_prob])[ + None + ].repeat(batch_size, 1) + ).sample() + if self.variant_preset == "single_feat_otw": + keep_mask = torch.zeros((batch_size, 6), dtype=torch.bool) + keep_mask[torch.arange(batch_size), indices] = True + + # If keep_mask[:, 4] is True, make both keep_mask[:, 0] and keep_mask[:, 1] True + keep_mask[:, :2] |= keep_mask[:, 4:5] + else: + keep_mask = torch.zeros((batch_size, 5), dtype=torch.bool) + keep_mask[torch.arange(batch_size), indices] = True + else: + # if the variant is specified, we keep the attributes with probability > 0 + keep_mask = torch.zeros((batch_size, 4), dtype=torch.bool) + indices = torch.nonzero(variant_probs).squeeze() + keep_mask[:, indices] = True + + td = self._default_open(td, ~keep_mask[:, 0]) + td = self._default_time_window(td, ~keep_mask[:, 1]) + td = self._default_distance_limit(td, ~keep_mask[:, 2]) + td = self._default_backhaul(td, ~keep_mask[:, 3]) + + return td + + @staticmethod + def _default_open(td, remove): + td["open_route"][remove] = False + return td + + @staticmethod + def _default_time_window(td, remove): + default_tw = torch.zeros_like(td["time_windows"]) + default_tw[..., 1] = float("inf") + td["time_windows"][remove] = default_tw[remove] + td["service_time"][remove] = torch.zeros_like(td["service_time"][remove]) + return td + + @staticmethod + def _default_distance_limit(td, remove): + td["distance_limit"][remove] = float("inf") + return td + + @staticmethod + def _default_backhaul(td, remove): + # by default, where there is a backhaul, linehaul is 0. therefore, we add backhaul to linehaul + # and set backhaul to 0 where we want to remove backhaul + td["demand_linehaul"][remove] = td["demand_linehaul"][remove] + td["demand_backhaul"][remove] + td["demand_backhaul"][remove] = 0 + return td + + def generate_locations(self, batch_size, num_loc) -> torch.Tensor: + """Generate seed locations. + + Returns: + locs: [B, N+1, 2] where the first location is the depot. + """ + locs = torch.FloatTensor(*batch_size, num_loc + 1, 2).uniform_( + self.min_loc, self.max_loc + ) + return locs + + def generate_demands(self, batch_size: int, num_loc: int) -> torch.Tensor: + """Classical lineahul demand / delivery from depot (C) and backhaul demand / pickup to depot (B) generation. + Initialize the demand for nodes except the depot, which are added during reset. + Demand sampling Following Kool et al. (2019), demands as integers between 1 and 10. + Generates a slightly different distribution than using torch.randint. + + Returns: + linehaul_demand: [B, N] + backhaul_demand: [B, N] + """ + linehaul_demand = ( + torch.FloatTensor(*batch_size, num_loc) + .uniform_(self.min_demand - 1, self.max_demand - 1) + .int() + + 1 + ).float() + # Backhaul demand sampling + backhaul_demand = ( + torch.FloatTensor(*batch_size, num_loc) + .uniform_(self.min_backhaul - 1, self.max_backhaul - 1) + .int() + + 1 + ).float() + is_linehaul = torch.rand(*batch_size, num_loc) > self.backhaul_ratio + backhaul_demand = ( + backhaul_demand * ~is_linehaul + ) # keep only values where they are not linehauls + linehaul_demand = ( + linehaul_demand * is_linehaul + ) + return linehaul_demand, backhaul_demand + + def generate_time_windows( + self, + locs: torch.Tensor, + speed: torch.Tensor, + ) -> torch.Tensor: + """Generate time windows (TW) and service times for each location including depot. + We refer to the generation process in "Multi-Task Learning for Routing Problem with Cross-Problem Zero-Shot Generalization" + (Liu et al., 2024). Note that another way to generate is from "Learning to Delegate for Large-scale Vehicle Routing" (Li et al, 2021) which + is used in "MVMoE: Multi-Task Vehicle Routing Solver with Mixture-of-Experts" (Zhou et al, 2024). Note that however, in that case + the distance limit would have no influence when time windows are present, since the tw for depot is the same as distance with speed=1. + This function can be overridden for that implementation. + See also https://github.com/RoyalSkye/Routing-MVMoE + + Args: + locs: [B, N+1, 2] (depot, locs) + speed: [B] + + Returns: + time_windows: [B, N+1, 2] + service_time: [B, N+1] + """ + + batch_size, n_loc = locs.shape[0], locs.shape[1] - 1 # no depot + + a, b, c = 0.15, 0.18, 0.2 + service_time = a + (b - a) * torch.rand(batch_size, n_loc) + tw_length = b + (c - b) * torch.rand(batch_size, n_loc) + d_0i = get_distance(locs[:, 0:1], locs[:, 1:]) + h_max = (self.max_time - service_time - tw_length) / d_0i * speed - 1 + tw_start = (1 + (h_max - 1) * torch.rand(batch_size, n_loc)) * d_0i / speed + tw_end = tw_start + tw_length + + # Depot tw is 0, max_time + time_windows = torch.stack( + ( + torch.cat((torch.zeros(batch_size, 1), tw_start), -1), # start + torch.cat((torch.full((batch_size, 1), self.max_time), tw_end), -1), + ), # en + dim=-1, + ) + # depot service time is 0 + service_time = torch.cat((torch.zeros(batch_size, 1), service_time), dim=-1) + return time_windows, service_time # [B, N+1, 2], [B, N+1] + + def generate_distance_limit( + self, shape: Tuple[int, int], locs: torch.Tensor + ) -> torch.Tensor: + """Generates distance limits (L) and checks their feasibilities. + + Returns: + distance_limit: [B, 1] + """ + # calculate distance of all locations to depot + dist_to_depot = torch.cdist(locs, locs[:, 0:1, :], p=2) + assert ( + dist_to_depot * 2 < self.distance_limit # go back and forth + ).all(), "Distance limit too low, not all nodes can be reached from the depot." + return torch.full(shape, self.distance_limit, dtype=torch.float32) + + def generate_open_route(self, shape: Tuple[int, int]): + """Generate open route flags (O). Here we could have a sampler but we simply return True here so all + routes are open. Afterwards, we subsample the problems. + """ + return torch.ones(shape, dtype=torch.bool) + + def generate_speed(self, shape: Tuple[int, int]): + """We simply generate the speed as constant here""" + # in this version, the speed is constant but this class may be overridden + return torch.full(shape, self.speed, dtype=torch.float32) + + @staticmethod + def save_data(td: TensorDict, path, compress: bool = False): + save_tensordict_to_npz(td, path) + + @staticmethod + def print_presets(): + for key, value in VARIANT_GENERATION_PRESETS.items(): + print(f"{key}: {value}") + + @staticmethod + def available_variants(*args, **kwargs): + # remove 'all', 'single_feat' from the list + return list(VARIANT_GENERATION_PRESETS.keys())[3:] diff --git a/rl4co/envs/routing/mtvrp/render.py b/rl4co/envs/routing/mtvrp/render.py new file mode 100644 index 00000000..01a5aadd --- /dev/null +++ b/rl4co/envs/routing/mtvrp/render.py @@ -0,0 +1,145 @@ +import torch + +from tensordict.tensordict import TensorDict + +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def render( + td: TensorDict, actions=None, ax=None, scale_xy: bool = True, vehicle_capacity=None +): + import matplotlib.pyplot as plt + import numpy as np + + from matplotlib import cm, colormaps + + num_routine = (actions == 0).sum().item() + 2 + base = colormaps["nipy_spectral"] + color_list = base(np.linspace(0, 1, num_routine)) + cmap_name = base.name + str(num_routine) + out = base.from_list(cmap_name, color_list, num_routine) + + if ax is None: + _, ax = plt.subplots(dpi=100, figsize=(6, 6)) + + td = td.detach().cpu() + + if actions is None: + actions = td.get("action", None) + + if td.batch_size != torch.Size([]): + td = td[0] + actions = actions[0] + + locs = td["locs"] + scale_demand = td["capacity_original"] + demands_linehaul = td["demand_linehaul"] * scale_demand + demands_backhaul = td["demand_backhaul"] * scale_demand + # scale to closest integer + demands_linehaul = demands_linehaul.round().int() + demands_backhaul = demands_backhaul.round().int() + + if actions is None: + log.warning("No action in TensorDict, rendering unsorted locs") + else: + actions = torch.cat([torch.tensor([0]), actions, torch.tensor([0])]) + + # Depot + ax.scatter( + locs[0, 0], + locs[0, 1], + edgecolors=cm.Set2(2), + facecolors="none", + s=100, + linewidths=2, + marker="s", + alpha=1, + ) + + for node_idx, loc in enumerate(locs): + if node_idx == 0: + continue + delivery, pickup = demands_linehaul[node_idx], demands_backhaul[node_idx] + if delivery > 0: + ax.text( + loc[0], + loc[1] + 0.02, + f"{delivery.item()}", + horizontalalignment="center", + verticalalignment="bottom", + fontsize=10, + color=cm.Set2(0), + ) + # scatter delivery as downward triangle + ax.scatter( + loc[0], + loc[1], + edgecolors=cm.Set2(0), + facecolors="none", + s=30, + linewidths=2, + marker="v", + alpha=1, + ) + elif pickup > 0: + ax.text( + loc[0], + loc[1] - 0.02, + f"{pickup.item()}", + horizontalalignment="center", + verticalalignment="top", + fontsize=10, + color=cm.Set2(1), + ) + ax.scatter( + loc[0], + loc[1], + edgecolors=cm.Set2(1), + facecolors="none", + s=30, + linewidths=2, + marker="^", + alpha=1, + ) + else: + print("Error: no demand") + + color_idx = 0 + next_actions = torch.roll(actions, -1, 0) + for ai, aj in zip(actions, next_actions): + if ai == 0: + color_idx += 1 + from_loc = locs[ai] + to_loc = locs[aj] + # if any of from_loc or to_loc is depot, change color and linewidth + if ai == 0 or aj == 0: + color, lw, alpha, style = "lightgrey", 1, 0.5, "--" + else: + color, lw, alpha, style = out(color_idx), 1, 1, "" + ax.plot( + [from_loc[0], to_loc[0]], + [from_loc[1], to_loc[1]], + color=color, + lw=lw, + alpha=alpha, + linestyle=style, + ) + ax.annotate( + "", + xy=(to_loc[0], to_loc[1]), + xytext=(from_loc[0], from_loc[1]), + arrowprops=dict(arrowstyle="->", color=color, lw=lw, alpha=alpha), + size=15, + annotation_clip=False, + ) + + if scale_xy: + ax.set_xlim(-0.05, 1.05) + ax.set_ylim(-0.05, 1.05) + + # Remove the ticks + ax.set_xticks([]) + ax.set_yticks([]) + plt.show() diff --git a/rl4co/envs/routing/op/__init__.py b/rl4co/envs/routing/op/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/op/env.py b/rl4co/envs/routing/op/env.py new file mode 100644 index 00000000..fd1442b6 --- /dev/null +++ b/rl4co/envs/routing/op/env.py @@ -0,0 +1,262 @@ +from typing import Optional, Union + +import torch +import torch.nn.functional as F + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.utils.ops import gather_by_index, get_tour_length +from rl4co.utils.pylogger import get_pylogger + +from .generator import OPGenerator +from .render import render + +log = get_pylogger(__name__) + + +class OPEnv(RL4COEnvBase): + """Orienteering Problem (OP) environment. + At each step, the agent chooses a location to visit in order to maximize the collected prize. + The total length of the path must not exceed a given threshold. + + Observations: + - location of the depot + - locations and prize of each customer + - current location of the vehicle + - current tour length + - current total prize + - the remaining length of the path + + Constraints: + - the tour starts and ends at the depot + - not all customers need to be visited + - the vehicle cannot visit customers exceed the remaining length of the path + + Finish Condition: + - the vehicle back to the depot + + Reward: + - the sum of the prizes of visited nodes + + Args: + generator: OPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "op" + + def __init__( + self, + generator: OPGenerator = None, + generator_params: dict = {}, + prize_type: str = "dist", + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = OPGenerator(**generator_params) + self.generator = generator + self.prize_type = prize_type + assert self.prize_type in [ + "dist", + "unif", + "const", + ], f"Invalid prize_type: {self.prize_type}" + self._make_spec(self.generator) + + def _step(self, td: TensorDict) -> TensorDict: + current_node = td["action"][:, None] + + # Update tour length + previus_loc = gather_by_index(td["locs"], td["current_node"]) + current_loc = gather_by_index(td["locs"], current_node) + tour_length = td["tour_length"] + (current_loc - previus_loc).norm(p=2, dim=-1) + + # Update prize with collected prize + current_total_prize = td["current_total_prize"] + gather_by_index( + td["prize"], current_node, dim=-1 + ) + + # Set current node as visited + visited = td["visited"].scatter(-1, current_node, 1) + + # Done if went back to depot (except if it's the first step, since we start at the depot) + done = (current_node.squeeze(-1) == 0) & (td["i"] > 0) + + # The reward is calculated outside via get_reward for efficiency, so we set it to 0 here + reward = torch.zeros_like(done) + + td.update( + { + "tour_length": tour_length, + "current_node": current_node, + "visited": visited, + "current_total_prize": current_total_prize, + "i": td["i"] + 1, + "reward": reward, + "done": done, + } + ) + td.set("action_mask", self.get_action_mask(td)) + return td + + def _reset( + self, + td: Optional[TensorDict] = None, + batch_size: Optional[list] = None, + ) -> TensorDict: + device = td.device + + # Add depot to locs + locs_with_depot = torch.cat((td["depot"][:, None, :], td["locs"]), -2) + + # Create reset TensorDict + td_reset = TensorDict( + { + "locs": locs_with_depot, + "prize": F.pad( + td["prize"], (1, 0), mode="constant", value=0 + ), # add 0 for depot + "tour_length": torch.zeros(*batch_size, device=device), + # max_length is max length allowed when arriving at node, so subtract distance to return to depot + # Additionally, substract epsilon margin for numeric stability + "max_length": td["max_length"][..., None] + - (td["depot"][..., None, :] - locs_with_depot).norm(p=2, dim=-1) + - 1e-6, + "current_node": torch.zeros( + *batch_size, 1, dtype=torch.long, device=device + ), + "visited": torch.zeros( + (*batch_size, locs_with_depot.shape[-2]), + dtype=torch.bool, + device=device, + ), + "current_total_prize": torch.zeros( + *batch_size, dtype=torch.float, device=device + ), + "i": torch.zeros( + (*batch_size,), dtype=torch.int64, device=device + ), # counter + }, + batch_size=batch_size, + ) + td_reset.set("action_mask", self.get_action_mask(td_reset)) + return td_reset + + @staticmethod + def get_action_mask(td: TensorDict) -> torch.Tensor: + """Get action mask with 1 = feasible action, 0 = infeasible action. + Cannot visit if already visited, if depot has been visited, or if the length exceeds the maximum length. + """ + current_loc = gather_by_index(td["locs"], td["current_node"])[..., None, :] + exceeds_length = ( + td["tour_length"][..., None] + (td["locs"] - current_loc).norm(p=2, dim=-1) + > td["max_length"] + ) + mask = td["visited"] | td["visited"][..., 0:1] | exceeds_length + + action_mask = ~mask # 1 = feasible action, 0 = infeasible action + + # Depot can always be visited: we do not hardcode knowledge that this is strictly suboptimal if other options are available + action_mask[..., 0] = 1 + return action_mask + + def _get_reward(self, td: TensorDict, actions: torch.Tensor) -> torch.Tensor: + """Reward is the sum of the prizes of visited nodes""" + # In case all tours directly return to depot, prevent further problems + if actions.size(-1) == 1: + assert (actions == 0).all(), "If all length 1 tours, they should be zero" + return torch.zeros(actions.size(0), dtype=torch.float, device=actions.device) + + # Prize is the sum of the prizes of the visited nodes. Note that prize is padded with 0 for depot at index 0 + collected_prize = td["prize"].gather(1, actions) + return collected_prize.sum(-1) + + @staticmethod + def check_solution_validity( + td: TensorDict, actions: torch.Tensor, add_distance_to_depot: bool = True + ) -> None: + """Check that solution is valid: nodes are not visited twice except depot and capacity is not exceeded. + If `add_distance_to_depot` if True, then the distance to the depot is added to max length since by default, the max length is + modified in the reset function to account for the distance to the depot. + """ + + # Check that tours are valid, i.e. contain 0 to n -1 + sorted_actions = actions.data.sort(1)[0] + # Make sure each node visited once at most (except for depot) + assert ( + (sorted_actions[:, 1:] == 0) + | (sorted_actions[:, 1:] > sorted_actions[:, :-1]) + ).all(), "Duplicates" + + # Gather locations in order of tour and get the length of tours + locs_ordered = gather_by_index(td["locs"], actions) + length = get_tour_length(locs_ordered) + + max_length = td["max_length"] + if add_distance_to_depot: + max_length = ( + max_length + + (td["locs"][..., 0:1, :] - td["locs"]).norm(p=2, dim=-1) + + 1e-6 + ) + assert ( + length[..., None] <= max_length + 1e-5 + ).all(), "Max length exceeded by {}".format( + (length[..., None] - max_length).max() + ) + + def _make_spec(self, generator: OPGenerator): + """Make the observation and action specs from the parameters.""" + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(generator.num_loc + 1, 2), + dtype=torch.float32, + ), + current_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + prize=UnboundedContinuousTensorSpec( + shape=(generator.num_loc,), + dtype=torch.float32, + ), + tour_length=UnboundedContinuousTensorSpec( + shape=(generator.num_loc,), + dtype=torch.float32, + ), + visited=UnboundedDiscreteTensorSpec( + shape=(generator.num_loc + 1,), + dtype=torch.bool, + ), + max_length=UnboundedContinuousTensorSpec( + shape=(1,), + dtype=torch.float32, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(generator.num_loc + 1, 1), + dtype=torch.bool, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=0, + high=generator.num_loc + 1, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + @staticmethod + def render(td: TensorDict, actions: torch.Tensor=None, ax = None): + return render(td, actions, ax) diff --git a/rl4co/envs/routing/op/generator.py b/rl4co/envs/routing/op/generator.py new file mode 100644 index 00000000..bf33d512 --- /dev/null +++ b/rl4co/envs/routing/op/generator.py @@ -0,0 +1,149 @@ +from typing import Callable, Union + +import torch + +from tensordict.tensordict import TensorDict +from torch.distributions import Uniform + +from rl4co.envs.common.utils import Generator, get_sampler +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + +# From Kool et al. 2019 +MAX_LENGTHS = {20: 2.0, 50: 3.0, 100: 4.0} + + +class OPGenerator(Generator): + """Data generator for the Orienteering Problem (OP). + + Args: + num_loc: number of locations (customers) in the OP, without the depot. (e.g. 10 means 10 locs + 1 depot) + min_loc: minimum value for the location coordinates + max_loc: maximum value for the location coordinates + loc_distribution: distribution for the location coordinates + depot_distribution: distribution for the depot location. If None, sample the depot from the locations + min_prize: minimum value for the prize of each customer + max_prize: maximum value for the prize of each customer + prize_distribution: distribution for the prize of each customer + max_length: maximum length of the path + + Returns: + A TensorDict with the following keys: + locs [batch_size, num_loc, 2]: locations of each customer + depot [batch_size, 2]: location of the depot + prize [batch_size, num_loc]: prize of each customer + max_length [batch_size, 1]: maximum length of the path for each customer + """ + + def __init__( + self, + num_loc: int = 20, + min_loc: float = 0.0, + max_loc: float = 1.0, + loc_distribution: Union[int, float, str, type, Callable] = Uniform, + depot_distribution: Union[int, float, str, type, Callable] = None, + min_prize: float = 1.0, + max_prize: float = 1.0, + prize_distribution: Union[int, float, type, Callable] = Uniform, + prize_type: str = "dist", + max_length: Union[float, torch.Tensor] = None, + **kwargs, + ): + self.num_loc = num_loc + self.min_loc = min_loc + self.max_loc = max_loc + self.min_prize = min_prize + self.max_prize = max_prize + self.prize_type = prize_type + self.max_length = max_length + + # Location distribution + if kwargs.get("loc_sampler", None) is not None: + self.loc_sampler = kwargs["loc_sampler"] + else: + self.loc_sampler = get_sampler( + "loc", loc_distribution, min_loc, max_loc, **kwargs + ) + + # Depot distribution + if kwargs.get("depot_sampler", None) is not None: + self.depot_sampler = kwargs["depot_sampler"] + else: + self.depot_sampler = get_sampler( + "depot", depot_distribution, min_loc, max_loc, **kwargs + ) if depot_distribution is not None else None + + # Prize distribution + if kwargs.get("prize_sampler", None) is not None: + self.prize_sampler = kwargs["prize_sampler"] + elif ( + prize_distribution == "dist" + ): # If prize_distribution is 'dist', then the prize is the distance from the depot + self.prize_sampler = None + else: + self.prize_sampler = get_sampler( + "prize", prize_distribution, min_prize, max_prize, **kwargs + ) + + # Max length + if max_length is not None: + self.max_length = max_length + else: + self.max_length = MAX_LENGTHS.get(num_loc, None) + if self.max_length is None: + closest_num_loc = min(MAX_LENGTHS.keys(), key=lambda x: abs(x - num_loc)) + self.max_length = MAX_LENGTHS[closest_num_loc] + log.warning( + f"The max length for {num_loc} locations is not defined. Using the closest max length: {self.max_length}\ + with {closest_num_loc} locations." + ) + + def _generate(self, batch_size) -> TensorDict: + # Sample locations: depot and customers + if self.depot_sampler is not None: + depot = self.depot_sampler.sample((*batch_size, 2)) + locs = self.loc_sampler.sample((*batch_size, self.num_loc, 2)) + else: + # if depot_sampler is None, sample the depot from the locations + locs = self.loc_sampler.sample((*batch_size, self.num_loc + 1, 2)) + depot = locs[..., 0, :] + locs = locs[..., 1:, :] + + locs_with_depot = torch.cat((depot.unsqueeze(1), locs), dim=1) + + # Methods taken from Fischetti et al. (1998) and Kool et al. (2019) + if self.prize_type == "const": + prize = torch.ones(*batch_size, self.num_loc, device=self.device) + elif self.prize_type == "unif": + prize = ( + 1 + + torch.randint( + 0, 100, (*batch_size, self.num_loc), device=self.device + ).float() + ) / 100 + elif self.prize_type == "dist": # based on the distance to the depot + prize = (locs_with_depot[..., 0:1, :] - locs_with_depot[..., 1:, :]).norm( + p=2, dim=-1 + ) + prize = ( + 1 + (prize / prize.max(dim=-1, keepdim=True)[0] * 99).int() + ).float() / 100 + else: + raise ValueError(f"Invalid prize_type: {self.prize_type}") + + # Support for heterogeneous max length if provided + if not isinstance(self.max_length, torch.Tensor): + max_length = torch.full((*batch_size,), self.max_length) + else: + max_length = self.max_length + + return TensorDict( + { + "locs": locs_with_depot[..., 1:, :], + "depot": locs_with_depot[..., 0, :], + "prize": prize, + "max_length": max_length, + }, + batch_size=batch_size, + ) diff --git a/rl4co/envs/routing/op/render.py b/rl4co/envs/routing/op/render.py new file mode 100644 index 00000000..65ad40be --- /dev/null +++ b/rl4co/envs/routing/op/render.py @@ -0,0 +1,86 @@ +import torch +import numpy as np +import matplotlib.pyplot as plt + +from matplotlib import cm, colormaps + +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def render(td, actions=None, ax=None): + # Create a plot of the nodes + if ax is None: + _, ax = plt.subplots() + + td = td.detach().cpu() + + # Actions + if actions is None: + actions = td.get("action", None) + actions = actions.detach().cpu() if actions is not None else None + + # if batch_size greater than 0 , we need to select the first batch element + if td.batch_size != torch.Size([]): + td = td[0] + actions = actions[0] if actions is not None else None + + # Variables + depot = td["locs"][0, :] + customers = td["locs"][1:, :] + prizes = td["prize"][1:] + normalized_prizes = ( + 200 * (prizes - torch.min(prizes)) / (torch.max(prizes) - torch.min(prizes)) + + 10 + ) + + # Plot depot and customers with prize + ax.scatter( + depot[0], + depot[1], + marker="s", + c="tab:green", + edgecolors="black", + zorder=5, + s=100, + ) # Plot depot as square + ax.scatter( + customers[:, 0], + customers[:, 1], + s=normalized_prizes, + c=normalized_prizes, + cmap="autumn_r", + alpha=0.6, + edgecolors="black", + ) # Plot all customers with size and color indicating the prize + + # Gather locs in order of action if available + if actions is None: + log.warning("No action in TensorDict, rendering unsorted locs") + else: + # Reorder the customers and their corresponding prizes based on actions + tour = customers[actions - 1] # subtract 1 to match Python's 0-indexing + + # Append the depot at the beginning and the end of the tour + tour = np.vstack((depot, tour, depot)) + + # Use quiver to plot the tour + dx, dy = np.diff(tour[:, 0]), np.diff(tour[:, 1]) + ax.quiver( + tour[:-1, 0], + tour[:-1, 1], + dx, + dy, + scale_units="xy", + angles="xy", + scale=1, + zorder=2, + color="black", + width=0.0035, + ) + + # Setup limits and show + ax.set_xlim(-0.05, 1.05) + ax.set_ylim(-0.05, 1.05) diff --git a/rl4co/envs/routing/pctsp/__init__.py b/rl4co/envs/routing/pctsp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/pctsp/env.py b/rl4co/envs/routing/pctsp/env.py new file mode 100644 index 00000000..9032283d --- /dev/null +++ b/rl4co/envs/routing/pctsp/env.py @@ -0,0 +1,284 @@ +from typing import Optional + +import torch +import torch.nn.functional as F + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.utils.ops import gather_by_index, get_tour_length +from rl4co.utils.pylogger import get_pylogger + +from .generator import PCTSPGenerator +from .render import render + +log = get_pylogger(__name__) + + +class PCTSPEnv(RL4COEnvBase): + """Prize-collecting TSP (PCTSP) environment. + The goal is to collect as much prize as possible while minimizing the total travel cost. + The environment is stochastic, the prize is only revealed when the node is visited. + + Observations: + - locations of the nodes + - prize and penalty of each node + - current location of the vehicle + - current total prize + - current total penalty + - visited nodes + - prize required to visit a node + - the current step + + Constraints: + - the tour starts and ends at the depot + - the vehicle cannot visit nodes exceed the remaining prize + + Finish Condition: + - the vehicle back to the depot + + Reward: + - the sum of the saved penalties + + Args: + generator: OPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "pctsp" + _stochastic = False + + def __init__( + self, + generator: PCTSPGenerator = None, + generator_params: dict = {}, + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = PCTSPGenerator(**generator_params) + self.generator = generator + self._make_spec(self.generator) + + def _step(self, td: TensorDict) -> TensorDict: + current_node = td["action"] + + # Get current coordinates, prize, and penalty + cur_total_prize = td["cur_total_prize"] + gather_by_index( + td["real_prize"], current_node + ) + cur_total_penalty = td["cur_total_penalty"] + gather_by_index( + td["penalty"], current_node + ) + + # Update visited + visited = td["visited"].scatter(-1, current_node[..., None], 1) + + # Done and reward + done = (td["i"] > 0) & (current_node == 0) + + # The reward is calculated outside via get_reward for efficiency, so we set it to 0 here + reward = torch.zeros_like(done) + + # Update state + td.update( + { + "current_node": current_node, + "cur_total_prize": cur_total_prize, + "cur_total_penalty": cur_total_penalty, + "visited": visited, + "i": td["i"] + 1, + "reward": reward, + "done": done, + } + ) + td.set("action_mask", self.get_action_mask(td)) + return td + + def _reset( + self, td: Optional[TensorDict] = None, batch_size: Optional[list] = None + ) -> TensorDict: + device = td.device + + locs = torch.cat([td["depot"][..., None, :], td["locs"]], dim=-2) + expected_prize = td["deterministic_prize"] + real_prize = ( + td["stochastic_prize"] if self.stochastic else td["deterministic_prize"] + ) + penalty = td["penalty"] + + # Concatenate depots + real_prize_with_depot = torch.cat( + [torch.zeros_like(real_prize[..., :1]), real_prize], dim=-1 + ) + penalty_with_depot = F.pad(penalty, (1, 0), mode="constant", value=0) + + # Initialize the current node and prize / penalty + current_node = torch.zeros((*batch_size,), dtype=torch.int64, device=device) + cur_total_prize = torch.zeros(*batch_size, device=device) + cur_total_penalty = penalty.sum(-1) # Sum penalties (all when nothing is visited) + + # Init the action mask (all nodes are available) + visited = torch.zeros( + (*batch_size, self.generator.num_loc + 1), dtype=torch.bool, device=device + ) + i = torch.zeros((*batch_size,), dtype=torch.int64, device=device) + prize_required = torch.full( + (*batch_size,), self.generator.prize_required, device=device + ) + + td_reset = TensorDict( + { + "locs": locs, + "current_node": current_node, + "expected_prize": expected_prize, + "real_prize": real_prize_with_depot, + "penalty": penalty_with_depot, + "cur_total_prize": cur_total_prize, + "cur_total_penalty": cur_total_penalty, + "visited": visited, + "prize_required": prize_required, + "i": i, + }, + batch_size=batch_size, + ) + td_reset.set("action_mask", self.get_action_mask(td_reset)) + return td_reset + + @staticmethod + def get_action_mask(td: TensorDict) -> torch.Tensor: + """Cannot visit depot if not yet collected 1 total prize and there are unvisited nodes""" + mask = td["visited"] | td["visited"][..., 0:1] + mask[..., 0] = (td["cur_total_prize"] < 1.0) & ( + td["visited"][..., 1:].int().sum(-1) < td["visited"][..., 1:].size(-1) + ) + return ~(mask > 0) # Invert mask, since 1 means feasible action + + def _get_reward(self, td: TensorDict, actions: torch.Tensor) -> torch.Tensor: + """Reward is `saved penalties - (total length + penalty)`""" + + # In case all tours directly return to depot, prevent further problems + if actions.size(-1) == 1: + assert (actions == 0).all(), "If all length 1 tours, they should be zero" + return torch.zeros(actions.size(0), dtype=torch.float, device=actions.device) + + # Gather locations in order of tour (add depot since we start and end there) + locs_ordered = torch.cat( + [ + td["locs"][..., 0:1, :], # depot + gather_by_index(td["locs"], actions), # order locations + ], + dim=1, + ) + length = get_tour_length(locs_ordered) + + # Reward is saved penalties - (total length + penalty) + saved_penalty = td["penalty"].gather(1, actions) + return saved_penalty.sum(-1) - (length + td["penalty"][..., 1:].sum(-1)) + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor) -> None: + """Check that the solution is valid, i.e. contains all nodes once at most, and either prize constraint is met or all nodes are visited""" + + # Check that tours are valid, i.e. contain 0 to n -1 + sorted_actions = actions.data.sort(1)[0] + + # Make sure each node visited once at most (except for depot) + assert ( + (sorted_actions[..., 1:] == 0) + | (sorted_actions[..., 1:] > sorted_actions[..., :-1]) + ).all(), "Duplicates" + + prize = td["real_prize"][..., 1:] # Remove depot + prize_with_depot = torch.cat((torch.zeros_like(prize[:, :1]), prize), 1) + p = prize_with_depot.gather(1, actions) + + # Either prize constraint should be satisfied or all prizes should be visited + assert ( + (p.sum(-1) >= 1 - 1e-5) + | ( + sorted_actions.size(-1) - (sorted_actions == 0).int().sum(-1) + == (td["locs"].size(-2) - 1) + ) # no depot + ).all(), "Total prize does not satisfy min total prize" + + @property + def stochastic(self): + return self._stochastic + + @stochastic.setter + def stochastic(self, state: bool): + if state is True: + log.warning( + "Stochastic mode should not be used for PCTSP. Use SPCTSP instead." + ) + + def _make_spec(self, generator): + """Make the locs and action specs from the parameters.""" + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(generator.num_loc, 2), + dtype=torch.float32, + ), + current_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + expected_prize=UnboundedContinuousTensorSpec( + shape=(generator.num_loc), + dtype=torch.float32, + ), + real_prize=UnboundedContinuousTensorSpec( + shape=(generator.num_loc + 1), + dtype=torch.float32, + ), + penalty=UnboundedContinuousTensorSpec( + shape=(generator.num_loc + 1), + dtype=torch.float32, + ), + cur_total_prize=UnboundedContinuousTensorSpec( + shape=(1), + dtype=torch.float32, + ), + cur_total_penalty=UnboundedContinuousTensorSpec( + shape=(1), + dtype=torch.float32, + ), + visited=UnboundedDiscreteTensorSpec( + shape=(generator.num_loc + 1), + dtype=torch.bool, + ), + prize_required=UnboundedContinuousTensorSpec( + shape=(1), + dtype=torch.float32, + ), + i=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(generator.num_loc), + dtype=torch.bool, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=0, + high=generator.num_loc, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + @staticmethod + def render(td: TensorDict, actions: torch.Tensor = None, ax=None): + return render(td, actions, ax) diff --git a/rl4co/envs/routing/pctsp/generator.py b/rl4co/envs/routing/pctsp/generator.py new file mode 100644 index 00000000..332a5c9c --- /dev/null +++ b/rl4co/envs/routing/pctsp/generator.py @@ -0,0 +1,143 @@ +from typing import Callable, Union + +from tensordict.tensordict import TensorDict +from torch.distributions import Uniform + +from rl4co.envs.common.utils import Generator, get_sampler +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +MAX_LENGTHS = {20: 2.0, 50: 3.0, 100: 4.0} + + +class PCTSPGenerator(Generator): + """Data generator for the Prize-collecting Traveling Salesman Problem (PCTSP). + + Args: + num_loc: number of locations (customers) in the VRP, without the depot. (e.g. 10 means 10 locs + 1 depot) + min_loc: minimum value for the location coordinates + max_loc: maximum value for the location coordinates + loc_distribution: distribution for the location coordinates + depot_distribution: distribution for the depot location. If None, sample the depot from the locations + min_demand: minimum value for the demand of each customer + max_demand: maximum value for the demand of each customer + demand_distribution: distribution for the demand of each customer + capacity: capacity of the vehicle + + Returns: + A TensorDict with the following keys: + locs [batch_size, num_loc, 2]: locations of each city + depot [batch_size, 2]: location of the depot + demand [batch_size, num_loc]: demand of each customer + capacity [batch_size, 1]: capacity of the vehicle + """ + + def __init__( + self, + num_loc: int = 20, + min_loc: float = 0.0, + max_loc: float = 1.0, + loc_distribution: Union[int, float, str, type, Callable] = Uniform, + depot_distribution: Union[int, float, str, type, Callable] = None, + penalty_factor: float = 3.0, + prize_required: float = 1.0, + **kwargs, + ): + self.num_loc = num_loc + self.min_loc = min_loc + self.max_loc = max_loc + self.penalty_fctor = penalty_factor + self.prize_required = prize_required + + # Location distribution + if kwargs.get("loc_sampler", None) is not None: + self.loc_sampler = kwargs["loc_sampler"] + else: + self.loc_sampler = get_sampler( + "loc", loc_distribution, min_loc, max_loc, **kwargs + ) + + # Depot distribution + if kwargs.get("depot_sampler", None) is not None: + self.depot_sampler = kwargs["depot_sampler"] + else: + self.depot_sampler = get_sampler( + "depot", depot_distribution, min_loc, max_loc, **kwargs + ) if depot_distribution is not None else None + + # Prize distribution + self.deterministic_prize_sampler = get_sampler( + "deterministric_prize", "uniform", 0.0, 4.0 / self.num_loc, **kwargs + ) + self.stochastic_prize_sampler = get_sampler( + "stochastic_prize", "uniform", 0.0, 2.0, **kwargs + ) + + # For the penalty to make sense it should be not too large (in which case all nodes will be visited) nor too small + # so we want the objective term to be approximately equal to the length of the tour, which we estimate with half + # of the nodes by half of the tour length (which is very rough but similar to op) + # This means that the sum of penalties for all nodes will be approximately equal to the tour length (on average) + # The expected total (uniform) penalty of half of the nodes (since approx half will be visited by the constraint) + # is (n / 2) / 2 = n / 4 so divide by this means multiply by 4 / n, + # However instead of 4 we use penalty_factor (3 works well) so we can make them larger or smaller + self.max_penalty = kwargs.get("max_penalty", None) + if self.max_penalty is None: # If not provided, use the default max penalty + self.max_penalty = MAX_LENGTHS.get(num_loc, None) + if ( + self.max_penalty is None + ): # If not in the table keys, find the closest number of nodes as the key + closest_num_loc = min(MAX_LENGTHS.keys(), key=lambda x: abs(x - num_loc)) + self.max_penalty = MAX_LENGTHS[closest_num_loc] + log.warning( + f"The max penalty for {num_loc} locations is not defined. Using the closest max penalty: {self.max_penalty}\ + with {closest_num_loc} locations." + ) + + # Adjust as in Kool et al. (2019) + self.max_penalty *= penalty_factor / self.num_loc + self.penalty_sampler = get_sampler( + "penalty", "uniform", 0.0, self.max_penalty, **kwargs + ) + + def _generate(self, batch_size) -> TensorDict: + # Sample locations: depot and customers + if self.depot_sampler is not None: + depot = self.depot_sampler.sample((*batch_size, 2)) + locs = self.loc_sampler.sample((*batch_size, self.num_loc, 2)) + else: + # if depot_sampler is None, sample the depot from the locations + locs = self.loc_sampler.sample((*batch_size, self.num_loc + 1, 2)) + depot = locs[..., 0, :] + locs = locs[..., 1:, :] + + # Sample penalty + penalty = self.penalty_sampler.sample((*batch_size, self.num_loc)) + + # Take uniform prizes + # Now expectation is 0.5 so expected total prize is n / 2, we want to force to visit approximately half of the nodes + # so the constraint will be that total prize >= (n / 2) / 2 = n / 4 + # equivalently, we divide all prizes by n / 4 and the total prize should be >= 1 + deterministic_prize = self.deterministic_prize_sampler.sample( + (*batch_size, self.num_loc) + ) + + # In the deterministic setting, the stochastic_prize is not used and the deterministic prize is known + # In the stochastic setting, the deterministic prize is the expected prize and is known up front but the + # stochastic prize is only revealed once the node is visited + # Stochastic prize is between (0, 2 * expected_prize) such that E(stochastic prize) = E(deterministic_prize) + stochastic_prize = self.stochastic_prize_sampler.sample( + (*batch_size, self.num_loc) + ) * deterministic_prize + + return TensorDict( + { + "locs": locs, + "depot": depot, + "penalty": penalty, + "deterministic_prize": deterministic_prize, + "stochastic_prize": stochastic_prize, + }, + batch_size=batch_size, + ) diff --git a/rl4co/envs/routing/pctsp/render.py b/rl4co/envs/routing/pctsp/render.py new file mode 100644 index 00000000..7d0e3622 --- /dev/null +++ b/rl4co/envs/routing/pctsp/render.py @@ -0,0 +1,93 @@ +import torch + + +def render(td, actions=None, ax=None): + import matplotlib.pyplot as plt + import numpy as np + + from matplotlib import colormaps + + # Create a plot of the nodes + if ax is None: + _, ax = plt.subplots() + + td = td.detach().cpu() + + # Actions + if actions is None: + actions = td.get("action", None) + actions = actions.detach().cpu() if actions is not None else None + + # if batch_size greater than 0 , we need to select the first batch element + if td.batch_size != torch.Size([]): + td = td[0] + actions = actions[0] if actions is not None else None + + # Variables + depot = td["locs"][0, :] + customers = td["locs"][1:, :] + prizes = td["real_prize"][1:] + penalties = td["penalty"][1:] + normalized_prizes = ( + 200 * (prizes - torch.min(prizes)) / (torch.max(prizes) - torch.min(prizes)) + + 10 + ) + normalized_penalties = ( + 3 + * (penalties - torch.min(penalties)) + / (torch.max(penalties) - torch.min(penalties)) + ) + + # Represent penalty with colormap and size of edges + penalty_cmap = colormaps.get_cmap("BuPu") + penalty_colors = penalty_cmap(normalized_penalties) + + # Plot depot and customers with prize (size of nodes) and penalties (size of borders) + ax.scatter( + depot[0], + depot[1], + marker="s", + c="tab:green", + edgecolors="black", + zorder=1, + s=100, + ) # Plot depot as square + ax.scatter( + customers[:, 0], + customers[:, 1], + s=normalized_prizes, + c=normalized_prizes, + cmap="autumn_r", + alpha=1, + edgecolors=penalty_colors, + linewidths=normalized_penalties, + ) # Plot all customers with size and color indicating the prize + + # Gather locs in order of action if available + if actions is None: + print("No action in TensorDict, rendering unsorted locs") + else: + # Reorder the customers and their corresponding prizes based on actions + tour = customers[actions - 1] # subtract 1 to match Python's 0-indexing + + # Append the depot at the beginning and the end of the tour + tour = np.vstack((depot, tour, depot)) + + # Use quiver to plot the tour + dx, dy = np.diff(tour[:, 0]), np.diff(tour[:, 1]) + ax.quiver( + tour[:-1, 0], + tour[:-1, 1], + dx, + dy, + scale_units="xy", + angles="xy", + scale=1, + zorder=2, + color="black", + width=0.0035, + ) + + # Setup limits and show + ax.set_xlim(-0.05, 1.05) + ax.set_ylim(-0.05, 1.05) diff --git a/rl4co/envs/routing/pdp/__init__.py b/rl4co/envs/routing/pdp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/pdp/env.py b/rl4co/envs/routing/pdp/env.py new file mode 100644 index 00000000..dfa78904 --- /dev/null +++ b/rl4co/envs/routing/pdp/env.py @@ -0,0 +1,535 @@ +from typing import Optional + +import torch + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.envs.common.base import ImprovementEnvBase, RL4COEnvBase +from rl4co.utils.ops import gather_by_index, get_tour_length + +from .generator import PDPGenerator +from .render import render, render_improvement + + +class PDPEnv(RL4COEnvBase): + """Pickup and Delivery Problem (PDP) environment. + The environment is made of num_loc + 1 locations (cities): + - 1 depot + - `num_loc` / 2 pickup locations + - `num_loc` / 2 delivery locations + The goal is to visit all the pickup and delivery locations in the shortest path possible starting from the depot + The conditions is that the agent must visit a pickup location before visiting its corresponding delivery location + + Observations: + - locations of the depot, pickup, and delivery locations + - current location of the vehicle + - the remaining locations to deliver + - the visited locations + - the current step + + Constraints: + - the tour starts and ends at the depot + - each pickup location must be visited before its corresponding delivery location + - the vehicle cannot visit the same location twice + + Finish Condition: + - the vehicle has visited all locations + + Reward: + - (minus) the negative length of the path + + Args: + generator: PDPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "pdp" + + def __init__( + self, + generator: PDPGenerator = None, + generator_params: dict = {}, + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = PDPGenerator(**generator_params) + self.generator = generator + self._make_spec(self.generator) + + @staticmethod + def _step(td: TensorDict) -> TensorDict: + current_node = td["action"].unsqueeze(-1) + + num_loc = td["locs"].shape[-2] - 1 # except depot + + # Pickup and delivery node pair of selected node + new_to_deliver = (current_node + num_loc // 2) % (num_loc + 1) + + # Set available to 0 (i.e., we visited the node) + available = td["available"].scatter( + -1, current_node.expand_as(td["action_mask"]), 0 + ) + + to_deliver = td["to_deliver"].scatter( + -1, new_to_deliver.expand_as(td["to_deliver"]), 1 + ) + + # Action is feasible if the node is not visited and is to deliver + # action_mask = torch.logical_and(available, to_deliver) + action_mask = available & to_deliver + + # We are done there are no unvisited locations + done = torch.count_nonzero(available, dim=-1) == 0 + + # The reward is calculated outside via get_reward for efficiency, so we set it to 0 here + reward = torch.zeros_like(done) + + # Update step + td.update( + { + "current_node": current_node, + "available": available, + "to_deliver": to_deliver, + "i": td["i"] + 1, + "action_mask": action_mask, + "reward": reward, + "done": done, + } + ) + return td + + def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: + device = td.device + + locs = torch.cat((td["depot"][:, None, :], td["locs"]), -2) + + # Pick is 1, deliver is 0 [batch_size, graph_size+1], [1,1...1, 0...0] + to_deliver = torch.cat( + [ + torch.ones( + *batch_size, + self.generator.num_loc // 2 + 1, + dtype=torch.bool, + ).to(device), + torch.zeros( + *batch_size, + self.generator.num_loc // 2, + dtype=torch.bool, + ).to(device), + ], + dim=-1, + ) + + # Cannot visit depot at first step # [0,1...1] so set not available + available = torch.ones( + (*batch_size, self.generator.num_loc + 1), dtype=torch.bool + ).to(device) + action_mask = ~available.contiguous() # [batch_size, graph_size+1] + action_mask[..., 0] = 1 # First step is always the depot + + # Other variables + current_node = torch.zeros((*batch_size, 1), dtype=torch.int64).to(device) + i = torch.zeros((*batch_size, 1), dtype=torch.int64).to(device) + + return TensorDict( + { + "locs": locs, + "current_node": current_node, + "to_deliver": to_deliver, + "available": available, + "i": i, + "action_mask": action_mask, + }, + batch_size=batch_size, + ) + + def _make_spec(self, generator: PDPGenerator): + """Make the observation and action specs from the parameters.""" + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(generator.num_loc + 1, 2), + dtype=torch.float32, + ), + current_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + to_deliver=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + i=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(generator.num_loc + 1), + dtype=torch.bool, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=0, + high=generator.num_loc + 1, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + @staticmethod + def _get_reward(td, actions) -> TensorDict: + # Gather locations in order of tour (add depot since we start and end there) + locs_ordered = torch.cat( + [ + td["locs"][..., 0:1, :], # depot + gather_by_index(td["locs"], actions), # order locations + ], + dim=1, + ) + return -get_tour_length(locs_ordered) + + def check_solution_validity(self, td, actions): + # assert (actions[:, 0] == 0).all(), "Not starting at depot" + assert ( + torch.arange(actions.size(1), out=actions.data.new()) + .view(1, -1) + .expand_as(actions) + == actions.data.sort(1)[0] + ).all(), "Not visiting all nodes" + + visited_time = torch.argsort( + actions, 1 + ) # index of pickup less than index of delivery + assert ( + visited_time[:, 1 : actions.size(1) // 2 + 1] + < visited_time[:, actions.size(1) // 2 + 1 :] + ).all(), "Deliverying without pick-up" + + def get_num_starts(self, td): + """Only half of the nodes (i.e. pickup nodes) can be start nodes""" + return (td["locs"].shape[-2] - 1) // 2 + + def select_start_nodes(self, td, num_starts): + """Only nodes from [1 : num_loc // 2 +1] (i.e. pickups) can be selected""" + num_possible_starts = (td["locs"].shape[-2] - 1) // 2 + selected = ( + torch.arange(num_starts, device=td.device).repeat_interleave(td.shape[0]) + % num_possible_starts + + 1 + ) + return selected + + @staticmethod + def render(td: TensorDict, actions: torch.Tensor = None, ax=None): + return render(td, actions, ax) + + +class PDPRuinRepairEnv(ImprovementEnvBase): + """Pickup and Delivery Problem (PDP) environment for performing neural ruin-repair search. + The environment is made of num_loc + 1 locations (cities): + - 1 depot + - `num_loc` / 2 pickup locations + - `num_loc` / 2 delivery locations + + The goal is to search for optimal solutions to pickup and delivery problems by performing a ruin-and-repair neighborhood search on a given initial solution. + (see MDP described in https://arxiv.org/abs/2204.11399) + + The condition is that at each step, the visited solutions must be feasible, + maintaining the sequence of visiting the pickup location before its corresponding delivery location. + + Observations: + - locations of the depot, pickup, and delivery locations + - current solution to be improved + - historical decisions + - the current step + + Constraints: + - the tour starts and ends at the depot + - each pickup location must be visited before its corresponding delivery location + - the vehicle cannot visit the same location twice + + Finish Condition: + - None + + Reward: + - the immediate reduced cost over the current best-so-far solution + (see MDP described in https://arxiv.org/abs/2204.11399) + + Args: + num_loc: number of locations (cities) in the TSP + init_sol_type: the method type used for generating initial solutions (random or greedy) + td_params: parameters of the environment + seed: seed for the environment + device: device to use. Generally, no need to set as tensors are updated on the fly + """ + + name = "pdp_ruin_repair" + + def __init__( + self, + generator: PDPGenerator = None, + generator_params: dict = {}, + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = PDPGenerator(**generator_params) + self.generator = generator + self._make_spec(self.generator) + + def _step(self, td: TensorDict, solution_to=None) -> TensorDict: + # get state information from td + solution_best = td["rec_best"] + locs = td["locs"] + cost_bsf = td["cost_bsf"] + action_record = td["action_record"] + bs, gs = solution_best.size() + + # perform local_operator + if solution_to is None: + action = td["action"] + solution = td["rec_current"] + next_rec = self._local_operator(solution, action) + else: + next_rec = solution_to.clone() + new_obj = self.get_costs(locs, next_rec) + + # compute reward and update best-so-far solutions + now_bsf = torch.where(new_obj < cost_bsf, new_obj, cost_bsf) + reward = cost_bsf - now_bsf + index = reward > 0.0 + solution_best[index] = next_rec[index].clone() + + # reset visited_time + visited_time = td["visited_time"] * 0 + pre = torch.zeros((bs), device=visited_time.device).long() + arange = torch.arange(bs) + for i in range(gs): + current_nodes = next_rec[arange, pre] + visited_time[arange, current_nodes] = i + 1 + pre = current_nodes + visited_time = visited_time.long() + + # update action record + if solution_to is None: + action_record[:, :-1] = action_record[:, 1:] + action_record[:, -1] *= 0 + action_record[torch.arange(bs), -1, action[:, 0]] = 1 + + # Update step + td.update( + { + "cost_current": new_obj, + "cost_bsf": now_bsf, + "rec_current": next_rec, + "rec_best": solution_best, + "visited_time": visited_time, + "action_record": action_record, + "i": td["i"] + 1 if solution_to is None else td["i"], + "reward": reward, + } + ) + + return td + + def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: + device = td.device + + locs = torch.cat((td["depot"][:, None, :], td["locs"]), -2) + current_rec = self.generator._get_initial_solutions(locs).to(device) + obj = self.get_costs(locs, current_rec) + + # get index according to the solutions in the linked list data structure + bs = batch_size[0] + seq_length = self.generator.num_loc + 1 + visited_time = torch.zeros((bs, seq_length)).to(device) + pre = torch.zeros((bs)).to(device).long() + arange = torch.arange(bs) + for i in range(seq_length): + current_nodes = current_rec[arange, pre] + visited_time[arange, current_nodes] = i + 1 + pre = current_nodes + visited_time = visited_time.long() + + # get action record and step i + i = torch.zeros((*batch_size, 1), dtype=torch.int64).to(device) + action_record = ( + torch.zeros((bs, seq_length, seq_length // 2)) + if self.training + else torch.zeros((bs, seq_length // 2, seq_length // 2)) + ) + + return TensorDict( + { + "locs": locs, + "cost_current": obj, + "cost_bsf": obj.clone(), + "rec_current": current_rec, + "rec_best": current_rec.clone(), + "visited_time": visited_time, + "action_record": action_record, + "i": i, + }, + batch_size=batch_size, + ) + + @staticmethod + def _local_operator(solution, action): + # get info + pair_index = action[:, 0].view(-1, 1) + 1 + first = action[:, 1].view(-1, 1) + second = action[:, 2].view(-1, 1) + rec = solution.clone() + bs, gs = rec.size() + + # fix connection for pairing node + argsort = rec.argsort() + pre_pairfirst = argsort.gather(1, pair_index) + post_pairfirst = rec.gather(1, pair_index) + rec.scatter_(1, pre_pairfirst, post_pairfirst) + rec.scatter_(1, pair_index, pair_index) + + argsort = rec.argsort() + + pre_pairsecond = argsort.gather(1, pair_index + gs // 2) + post_pairsecond = rec.gather(1, pair_index + gs // 2) + + rec.scatter_(1, pre_pairsecond, post_pairsecond) + + # fix connection for pairing node + post_second = rec.gather(1, second) + rec.scatter_(1, second, pair_index + gs // 2) + rec.scatter_(1, pair_index + gs // 2, post_second) + + post_first = rec.gather(1, first) + rec.scatter_(1, first, pair_index) + rec.scatter_(1, pair_index, post_first) + + return rec + + def _make_spec(self, generator: PDPGenerator): + """Make the observation and action specs from the parameters.""" + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(generator.num_loc + 1, 2), + dtype=torch.float32, + ), + cost_current=UnboundedContinuousTensorSpec( + shape=(1), + dtype=torch.float32, + ), + cost_bsf=UnboundedContinuousTensorSpec( + shape=(1), + dtype=torch.float32, + ), + rec_current=UnboundedDiscreteTensorSpec( + shape=(self.generator.num_loc + 1), + dtype=torch.int64, + ), + rec_best=UnboundedDiscreteTensorSpec( + shape=(self.generator.num_loc + 1), + dtype=torch.int64, + ), + visited_time=UnboundedDiscreteTensorSpec( + shape=(self.generator.num_loc + 1, self.generator.num_loc + 1), + dtype=torch.int64, + ), + action_record=UnboundedDiscreteTensorSpec( + shape=(self.generator.num_loc + 1, self.generator.num_loc + 1), + dtype=torch.int64, + ), + i=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(3,), + dtype=torch.int64, + low=0, + high=self.generator.num_loc + 1, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + def check_solution_validity(self, td, actions=None): + # The function can be called by the agent to check the validity of the best found solution + # Note that the args actions are not used in improvement method. + + solution = td["rec_best"] + batch_size, graph_size = solution.size() + + assert ( + torch.arange(graph_size, out=solution.data.new()) + .view(1, -1) + .expand_as(solution) + == solution.data.sort(1)[0] + ).all(), "Not visiting all nodes" + + visited_time = torch.zeros((batch_size, graph_size), device=self.device) + pre = torch.zeros(batch_size, device=self.device).long() + arange = torch.arange(batch_size) + for i in range(graph_size): + visited_time[arange, solution[arange, pre]] = i + 1 + pre = solution[arange, pre] + + assert ( + visited_time[:, 1 : graph_size // 2 + 1] + < visited_time[:, graph_size // 2 + 1 :] + ).all(), "Deliverying without pick-up" + + @staticmethod + def get_mask(selected_node, td): + # return mask that is 1 if the corresponding action is feasible, 0 otherwise + + visited_time = td["visited_time"] + bs, gs = visited_time.size() + visited_time = visited_time % gs + arange = torch.arange(bs) + + visited_order_map = visited_time.view(bs, gs, 1) > visited_time.view(bs, 1, gs) + mask = visited_order_map.clone() + mask[arange, selected_node.view(-1)] = True + mask[arange, selected_node.view(-1) + gs // 2] = True + mask[arange, :, selected_node.view(-1)] = True + mask[arange, :, selected_node.view(-1) + gs // 2] = True + + bs, gs, _ = visited_order_map.size() + + return ~mask + + @classmethod + def _random_action(cls, td): + batch_size, graph_size = td["rec_best"].size() + selected_node = ( + (torch.rand(batch_size, 1) * graph_size // 2) % (graph_size // 2) + ).long() + mask = cls.get_mask(selected_node + 1, td) + logits = torch.rand(batch_size, graph_size, graph_size) + logits[~mask] = -1e20 + prob = torch.softmax(logits.view(batch_size, -1), -1) + sample = prob.multinomial(1) + action = torch.cat( + (selected_node, sample // (graph_size), sample % (graph_size)), -1 + ) + td["action"] = action + return action + + @classmethod + def render(cls, td: TensorDict, actions: torch.Tensor = None, ax=None): + solution_current = cls.get_current_solution(td) + solution_best = cls.get_best_solution(td) + return render_improvement(td, solution_current, solution_best) diff --git a/rl4co/envs/routing/pdp/generator.py b/rl4co/envs/routing/pdp/generator.py new file mode 100644 index 00000000..1c6dfd37 --- /dev/null +++ b/rl4co/envs/routing/pdp/generator.py @@ -0,0 +1,152 @@ +from typing import Callable, Union + +import torch + +from tensordict.tensordict import TensorDict +from torch.distributions import Uniform + +from rl4co.envs.common.utils import Generator, get_sampler +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class PDPGenerator(Generator): + """Data generator for the Pickup and Delivery Problem (PDP). + Args: + num_loc: number of locations (customers) in the PDP, without the depot. (e.g. 10 means 10 locs + 1 depot) + - 1 depot + - `num_loc` / 2 pickup locations + - `num_loc` / 2 delivery locations + min_loc: minimum value for the location coordinates + max_loc: maximum value for the location coordinates + init_sol_type: the method type used for generating initial solutions (random or greedy) + loc_distribution: distribution for the location coordinates + depot_distribution: distribution for the depot location. If None, sample the depot from the locations + + Returns: + A TensorDict with the following keys: + locs [batch_size, num_loc, 2]: locations of each customer + depot [batch_size, 2]: location of the depot + """ + + def __init__( + self, + num_loc: int = 20, + min_loc: float = 0.0, + max_loc: float = 1.0, + init_sol_type: str = "random", + loc_distribution: Union[int, float, str, type, Callable] = Uniform, + depot_distribution: Union[int, float, str, type, Callable] = None, + **kwargs, + ): + self.num_loc = num_loc + self.min_loc = min_loc + self.max_loc = max_loc + self.init_sol_type = init_sol_type + + # Number of locations must be even + if num_loc % 2 != 0: + log.warn( + "Number of locations must be even. Adding 1 to the number of locations." + ) + self.num_loc += 1 + + # Location distribution + if kwargs.get("loc_sampler", None) is not None: + self.loc_sampler = kwargs["loc_sampler"] + else: + self.loc_sampler = get_sampler( + "loc", loc_distribution, min_loc, max_loc, **kwargs + ) + + # Depot distribution + if kwargs.get("depot_sampler", None) is not None: + self.depot_sampler = kwargs["depot_sampler"] + else: + self.depot_sampler = get_sampler( + "depot", depot_distribution, min_loc, max_loc, **kwargs + ) if depot_distribution is not None else None + + def _generate(self, batch_size) -> TensorDict: + # Sample locations: depot and customers + if self.depot_sampler is not None: + depot = self.depot_sampler.sample((*batch_size, 2)) + locs = self.loc_sampler.sample((*batch_size, self.num_loc, 2)) + else: + # if depot_sampler is None, sample the depot from the locations + locs = self.loc_sampler.sample((*batch_size, self.num_loc + 1, 2)) + depot = locs[..., 0, :] + locs = locs[..., 1:, :] + + return TensorDict( + { + "locs": locs, + "depot": depot, + }, + batch_size=batch_size, + ) + + # for improvement MDP only (to be refactored by a combination of rollout and the random policy) + def _get_initial_solutions(self, coordinates): + order_size = self.num_loc // 2 + batch_size = coordinates.size(0) + + if self.init_sol_type == "random": + candidates = torch.ones(batch_size, self.num_loc + 1).bool() + candidates[:, order_size + 1 :] = 0 + rec = torch.zeros(batch_size, self.num_loc + 1).long() + selected_node = torch.zeros(batch_size, 1).long() + candidates.scatter_(1, selected_node, 0) + + for i in range(self.num_loc): + dists = torch.ones(batch_size, self.num_loc + 1) + dists.scatter_(1, selected_node, -1e20) + dists[~candidates] = -1e20 + dists = torch.softmax(dists, -1) + next_selected_node = dists.multinomial(1).view(-1, 1) + + add_index = (next_selected_node <= order_size).view(-1) + pairing = ( + next_selected_node[next_selected_node <= order_size].view(-1, 1) + + order_size + ) + candidates[add_index] = candidates[add_index].scatter_(1, pairing, 1) + + rec.scatter_(1, selected_node, next_selected_node) + candidates.scatter_(1, next_selected_node, 0) + selected_node = next_selected_node + + elif self.init_sol_type == "greedy": + candidates = torch.ones(batch_size, self.num_loc + 1).bool() + candidates[:, order_size + 1 :] = 0 + rec = torch.zeros(batch_size, self.num_loc + 1).long() + selected_node = torch.zeros(batch_size, 1).long() + candidates.scatter_(1, selected_node, 0) + + for i in range(self.num_loc): + d1 = coordinates.cpu().gather( + 1, selected_node.unsqueeze(-1).expand(batch_size, self.num_loc + 1, 2) + ) + d2 = coordinates.cpu() + + dists = (d1 - d2).norm(p=2, dim=2) + dists.scatter_(1, selected_node, 1e6) + dists[~candidates] = 1e6 + next_selected_node = dists.min(-1)[1].view(-1, 1) + + add_index = (next_selected_node <= order_size).view(-1) + pairing = ( + next_selected_node[next_selected_node <= order_size].view(-1, 1) + + order_size + ) + candidates[add_index] = candidates[add_index].scatter_(1, pairing, 1) + + rec.scatter_(1, selected_node, next_selected_node) + candidates.scatter_(1, next_selected_node, 0) + selected_node = next_selected_node + + else: + raise NotImplementedError() + + return rec.expand(batch_size, self.num_loc + 1).clone() diff --git a/rl4co/envs/routing/pdp/render.py b/rl4co/envs/routing/pdp/render.py new file mode 100644 index 00000000..2388f743 --- /dev/null +++ b/rl4co/envs/routing/pdp/render.py @@ -0,0 +1,142 @@ +import matplotlib.pyplot as plt +import torch + +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +# Only render the first instance +def render(td, actions=None, ax=None): + markersize = 8 + + td = td.detach().cpu() + # if batch_size greater than 0 , we need to select the first batch element + if td.batch_size != torch.Size([]): + td = td[0] + if actions is not None: + actions = actions[0] + + # Variables + init_deliveries = td["to_deliver"][1:] + delivery_locs = td["locs"][1:][~init_deliveries.bool()] + pickup_locs = td["locs"][1:][init_deliveries.bool()] + depot_loc = td["locs"][0] + actions = actions if actions is not None else td["action"] + + fig, ax = plt.subplots() + + # Plot the actions in order + for i in range(len(actions)): + from_node = actions[i] + to_node = ( + actions[i + 1] if i < len(actions) - 1 else actions[0] + ) # last goes back to depot + from_loc = td["locs"][from_node] + to_loc = td["locs"][to_node] + ax.plot([from_loc[0], to_loc[0]], [from_loc[1], to_loc[1]], "k-") + ax.annotate( + "", + xy=(to_loc[0], to_loc[1]), + xytext=(from_loc[0], from_loc[1]), + arrowprops=dict(arrowstyle="->", color="black"), + annotation_clip=False, + ) + + # Plot the depot location + ax.plot( + depot_loc[0], + depot_loc[1], + "g", + marker="s", + markersize=markersize, + label="Depot", + ) + + # Plot the pickup locations + for i, pickup_loc in enumerate(pickup_locs): + ax.plot( + pickup_loc[0], + pickup_loc[1], + "r", + marker="^", + markersize=markersize, + label="Pickup" if i == 0 else None, + ) + + # Plot the delivery locations + for i, delivery_loc in enumerate(delivery_locs): + ax.plot( + delivery_loc[0], + delivery_loc[1], + "b", + marker="v", + markersize=markersize, + label="Delivery" if i == 0 else None, + ) + + # Setup limits and show + ax.set_xlim(-0.05, 1.05) + ax.set_ylim(-0.05, 1.05) + + +def render_improvement(td, current_soltuion, best_soltuion): + coordinates = td["locs"][0] + real_seq = current_soltuion[:1] + real_best = best_soltuion[:1] + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6)) # Create two side-by-side axes + + for ax in [ax1, ax2]: # Plot on both axes + if ax == ax1: + ax.axis([-0.05, 1.05] * 2) + # plot the nodes + ax.scatter( + coordinates[:, 0], coordinates[:, 1], marker="H", s=55, c="blue", zorder=2 + ) + # plot the tour + real_seq_coordinates = coordinates.gather( + 0, real_seq[0].unsqueeze(1).repeat(1, 2) + ) + real_seq_coordinates = torch.cat( + (real_seq_coordinates, real_seq_coordinates[:1]), 0 + ) + ax.plot( + real_seq_coordinates[:, 0], + real_seq_coordinates[:, 1], + color="black", + zorder=1, + ) + # mark node + for i, txt in enumerate(range(real_seq.size(1))): + ax.annotate( + txt, + (coordinates[i, 0] + 0.01, coordinates[i, 1] + 0.01), + ) + ax.set_title("Current Solution") + else: + ax.axis([-0.05, 1.05] * 2) + # plot the nodes + ax.scatter( + coordinates[:, 0], coordinates[:, 1], marker="H", s=55, c="blue", zorder=2 + ) + # plot the tour + real_best_coordinates = coordinates.gather( + 0, real_best[0].unsqueeze(1).repeat(1, 2) + ) + real_best_coordinates = torch.cat( + (real_best_coordinates, real_best_coordinates[:1]), 0 + ) + ax.plot( + real_best_coordinates[:, 0], + real_best_coordinates[:, 1], + color="black", + zorder=1, + ) + # mark node + for i, txt in enumerate(range(real_seq.size(1))): + ax.annotate( + txt, + (coordinates[i, 0] + 0.01, coordinates[i, 1] + 0.01), + ) + ax.set_title("Best Solution") + plt.tight_layout() diff --git a/rl4co/envs/routing/sdvrp/__init__.py b/rl4co/envs/routing/sdvrp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/sdvrp/env.py b/rl4co/envs/routing/sdvrp/env.py new file mode 100644 index 00000000..57e9a423 --- /dev/null +++ b/rl4co/envs/routing/sdvrp/env.py @@ -0,0 +1,210 @@ +from typing import Optional + +import torch + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +from ..cvrp.env import CVRPEnv +from ..cvrp.generator import CVRPGenerator + +log = get_pylogger(__name__) + + +class SDVRPEnv(CVRPEnv): + """Split Delivery Vehicle Routing Problem (SDVRP) environment. + SDVRP is a generalization of CVRP, where nodes can be visited multiple times and a fraction of the demand can be met. + At each step, the agent chooses a customer to visit depending on the current location and the remaining capacity. + When the agent visits a customer, the remaining capacity is updated. If the remaining capacity is not enough to + visit any customer, the agent must go back to the depot. The reward is the -infinite unless the agent visits all the customers. + In that case, the reward is (-)length of the path: maximizing the reward is equivalent to minimizing the path length. + + Observations: + - location of the depot. + - locations and demand/remaining demand of each customer + - current location of the vehicle. + - the remaining capacity of the vehicle. + + Constraints: + - the tour starts and ends at the depot. + - each customer can be visited multiple times. + - the vehicle cannot visit customers exceed the remaining capacity. + - the vehicle can return to the depot to refill the capacity. + + Finish Condition: + - the vehicle has finished all customers demand and returned to the depot. + + Reward: + - (minus) the negative length of the path. + + Args: + generator: CVRPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "sdvrp" + + def __init__( + self, + generator: CVRPGenerator = None, + generator_params: dict = {}, + **kwargs, + ): + super().__init__(generator, generator_params, **kwargs) + + def _step(self, td: TensorDict) -> TensorDict: + # Update the state + current_node = td["action"][:, None] # Add dimension for step + + # Not selected_demand is demand of first node (by clamp) so incorrect for nodes that visit depot! + selected_demand = gather_by_index( + td["demand_with_depot"], current_node, dim=-1, squeeze=False + )[..., :1] + delivered_demand = torch.min( + selected_demand, td["vehicle_capacity"] - td["used_capacity"] + ) + + # Increase capacity if depot is not visited, otherwise set to 0 + used_capacity = (td["used_capacity"] + delivered_demand) * ( + current_node != 0 + ).float() + + # Update demand + demand_with_depot = td["demand_with_depot"].scatter_add( + -1, current_node, -delivered_demand + ) + + # Get done + done = ~(demand_with_depot > 0).any(-1) + + # The reward is calculated outside via get_reward for efficiency, so we set it to 0 here + reward = torch.zeros_like(done) + + # Update state + td.update( + { + "demand_with_depot": demand_with_depot, + "current_node": current_node, + "used_capacity": used_capacity, + "reward": reward, + "done": done, + } + ) + td.set("action_mask", self.get_action_mask(td)) + return td + + def _reset( + self, + td: Optional[TensorDict] = None, + batch_size: Optional[list] = None, + ) -> TensorDict: + device = td.device + + # Create reset TensorDict + reset_td = TensorDict( + { + "locs": torch.cat((td["depot"][..., None, :], td["locs"]), -2), + "demand": td["demand"], + "demand_with_depot": torch.cat( + (torch.zeros_like(td["demand"][..., 0:1]), td["demand"]), -1 + ), + "current_node": torch.zeros( + *batch_size, 1, dtype=torch.long, device=device + ), + "used_capacity": torch.zeros((*batch_size, 1), device=device), + "vehicle_capacity": torch.full( + (*batch_size, 1), self.generator.vehicle_capacity, device=device + ), + }, + batch_size=batch_size, + ) + reset_td.set("action_mask", self.get_action_mask(reset_td)) + return reset_td + + @staticmethod + def get_action_mask(td: TensorDict) -> torch.Tensor: + mask_loc = (td["demand_with_depot"][..., 1:] == 0) | ( + td["used_capacity"] >= td["vehicle_capacity"] + ) + mask_depot = (td["current_node"] == 0).squeeze(-1) & ( + (mask_loc == 0).int().sum(-1) > 0 + ) + return ~torch.cat((mask_depot[..., None], mask_loc), -1) + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor) -> None: + """Check that the solution is valid (all demand is satisfied)""" + + batch_size, graph_size = td["demand"].size() + + # Each node can be visited multiple times, but we always deliver as much demand as possible + # We check that at the end all demand has been satisfied + demands = torch.cat((-td["vehicle_capacity"], td["demand"]), 1) + + rng = torch.arange(batch_size, out=demands.data.new().long()) + used_cap = torch.zeros_like(td["demand"][..., 0]) + a_prev = None + for a in actions.transpose(0, 1): + assert ( + a_prev is None or (demands[((a_prev == 0) & (a == 0)), :] == 0).all() + ), "Cannot visit depot twice if any nonzero demand" + d = torch.min(demands[rng, a], td["vehicle_capacity"].squeeze(-1) - used_cap) + demands[rng, a] -= d + used_cap += d + used_cap[a == 0] = 0 + a_prev = a + assert (demands == 0).all(), "All demand must be satisfied" + + def _make_spec(self, generator): + """Make the observation and action specs from the parameters.""" + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(generator.num_loc + 1, 2), + dtype=torch.float32, + ), + current_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + demand=BoundedTensorSpec( + low=generator.min_demand, + high=generator.max_demand, + shape=(generator.num_loc, 1), # demand is only for customers + dtype=torch.float32, + ), + demand_with_depot=BoundedTensorSpec( + low=generator.min_demand, + high=generator.max_demand, + shape=(generator.num_loc + 1, 1), + dtype=torch.float32, + ), + used_capacity=BoundedTensorSpec( + low=0, + high=generator.vehicle_capacity, + shape=(1,), + dtype=torch.float32, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(generator.num_loc + 1, 1), + dtype=torch.bool, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=0, + high=generator.num_loc + 1, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) diff --git a/rl4co/envs/routing/spctsp/__init__.py b/rl4co/envs/routing/spctsp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/spctsp/env.py b/rl4co/envs/routing/spctsp/env.py new file mode 100644 index 00000000..4f99c070 --- /dev/null +++ b/rl4co/envs/routing/spctsp/env.py @@ -0,0 +1,31 @@ +from rl4co.utils.pylogger import get_pylogger + +from ..pctsp.env import PCTSPEnv + +log = get_pylogger(__name__) + + +class SPCTSPEnv(PCTSPEnv): + """Stochastic Prize Collecting Traveling Salesman Problem (SPCTSP) environment. + + Note: + The only difference with deterministic PCTSP is that the prizes are stochastic + (i.e. the expected prize is not the same as the real prize). + """ + + name = "spctsp" + _stochastic = True + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + @property + def stochastic(self): + return self._stochastic + + @stochastic.setter + def stochastic(self, state: bool): + if state is False: + log.warning( + "Deterministic mode should not be used for SPCTSP. Use PCTSP instead." + ) diff --git a/rl4co/envs/routing/svrp/__init__.py b/rl4co/envs/routing/svrp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/svrp/env.py b/rl4co/envs/routing/svrp/env.py new file mode 100644 index 00000000..4e14720b --- /dev/null +++ b/rl4co/envs/routing/svrp/env.py @@ -0,0 +1,255 @@ +from typing import Optional + +import torch + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.data.utils import load_npz_to_tensordict +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.utils.ops import gather_by_index, get_distance +from rl4co.utils.pylogger import get_pylogger + +from .generator import SVRPGenerator +from .render import render + +log = get_pylogger(__name__) + + +class SVRPEnv(RL4COEnvBase): + """Skill-Vehicle Routing Problem (SVRP) environment. + Basic Skill-VRP environment. The environment is a variant of the Capacitated Vehicle Routing Problem (CVRP). + Each technician has a certain skill-level and each customer node requires a certain skill-level to be serviced. + Each customer node needs is to be serviced by exactly one technician. Technicians can only service nodes if + their skill-level is greater or equal to the required skill-level of the node. The environment is episodic and + the goal is to minimize the total travel cost of the technicians. The travel cost depends on the skill-level of + the technician. The environment is defined by the following parameters: + + Observations: + - locations of the depot, pickup, and delivery locations + - current location of the vehicle + - the remaining locations to deliver + - the visited locations + - the current step + + Constraints: + - the tour starts and ends at the depot + - each pickup location must be visited before its corresponding delivery location + - the vehicle cannot visit the same location twice + + Finish Condition: + - the vehicle has visited all locations + + Reward: + - (minus) the negative length of the path + + Args: + generator: PDPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "svrp" + + def __init__( + self, + generator: SVRPGenerator = None, + generator_params: dict = {}, + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = SVRPGenerator(**generator_params) + self.generator = generator + self.tech_costs = self.generator.tech_costs + self._make_spec(self.generator) + + def _make_spec(self, generator): + """Make the observation and action specs from the parameters.""" + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(generator.num_loc + 1, 2), + dtype=torch.float32, + ), + current_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + skills=BoundedTensorSpec( + low=generator.min_skill, + high=generator.max_skill, + shape=(generator.num_loc, 1), + dtype=torch.float32, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(generator.num_loc + 1, 1), + dtype=torch.bool, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=0, + high=generator.num_loc + 1, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,), dtype=torch.float32) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + @staticmethod + def get_action_mask(td: TensorDict) -> torch.Tensor: + """Calculates the action mask for the Skill-VRP. The action mask is a binary mask that indicates which customer nodes can be services, given the previous decisions. + For the Skill-VRP, a node can be serviced if the technician has the required skill-level and the node has not been visited yet. + The depot cannot be visited if there are still unserved nodes and the technician either just visited the depot or is the last technician + (because every customer node needs to be visited). + """ + batch_size = td["locs"].shape[0] + # check skill level + current_tech_skill = gather_by_index(td["techs"], td["current_tech"]).reshape( + [batch_size, 1] + ) + can_service = td["skills"] <= current_tech_skill.unsqueeze(1).expand_as( + td["skills"] + ) + mask_loc = td["visited"][..., 1:, :].to(can_service.dtype) | ~can_service + # Cannot visit the depot if there are still unserved nodes and I either just visited the depot or am the last technician + mask_depot = ( + (td["current_node"] == 0) | (td["current_tech"] == td["techs"].size(-2) - 1) + ) & ((mask_loc == 0).int().sum(-2) > 0) + return ~torch.cat((mask_depot[..., None], mask_loc), -2).squeeze(-1) + + def _step(self, td: TensorDict) -> torch.Tensor: + """Step function for the Skill-VRP. If a technician returns to the depot, the next technician is sent out. + The visited node is marked as visited. The reward is set to zero and the done flag is set if all nodes have been visited. + """ + current_node = td["action"][:, None] # Add dimension for step + + # if I go back to the depot, send out next technician + td["current_tech"] += (current_node == 0).int() + + # Add one dimension since we write a single value + visited = td["visited"].scatter(-2, current_node[..., None], 1) + + # SECTION: get done + done = visited.sum(-2) == visited.size(-2) + reward = torch.zeros_like(done) + + td.update( + { + "current_node": current_node, + "visited": visited, + "reward": reward, + "done": done, + } + ) + td.set("action_mask", self.get_action_mask(td)) + return td + + def _reset( + self, td: Optional[TensorDict] = None, batch_size: Optional[list] = None + ) -> TensorDict: + device = td.device + + # Create reset TensorDict + td_reset = TensorDict( + { + "locs": torch.cat((td["depot"][:, None, :], td["locs"]), -2), + "techs": td["techs"], + "skills": td["skills"], + "current_node": torch.zeros( + *batch_size, 1, dtype=torch.long, device=device + ), + "current_tech": torch.zeros( + *batch_size, 1, dtype=torch.long, device=device + ), + "visited": torch.zeros( + (*batch_size, td["locs"].shape[-2] + 1, 1), + dtype=torch.uint8, + device=device, + ), + }, + batch_size=batch_size, + ) + td_reset.set("action_mask", self.get_action_mask(td_reset)) + return td_reset + + def _get_reward(self, td: TensorDict, actions: torch.Tensor) -> torch.Tensor: + """Calculated the reward, where the reward is the negative total travel cost of the technicians. + The travel cost depends on the skill-level of the technician.""" + # Check that the solution is valid + if self.check_solution: + self.check_solution_validity(td, actions) + + # Gather dataset in order of tour + batch_size = td["locs"].shape[0] + depot = td["locs"][..., 0:1, :] + locs_ordered = torch.cat( + [ + depot, + gather_by_index(td["locs"], actions).reshape( + [batch_size, actions.size(-1), 2] + ), + ], + dim=1, + ) + + # calculate travelling costs depending on the technicians' skill level + costs = torch.zeros(batch_size, locs_ordered.size(-2), device=self.device) + indices = torch.nonzero(actions == 0) + start = tech = 0 + batch = 0 + for each in indices: + if each[0] > batch: + costs[batch, start:] = self.tech_costs[tech] + start = tech = 0 + batch = each[0] + end = ( + each[-1] + 1 + ) # indices in locs_ordered are shifted by one due to added depot in the front + costs[batch, start:end] = self.tech_costs[tech] + tech += 1 + start = end + costs[batch, start:] = self.tech_costs[tech] + + travel_to = torch.roll(locs_ordered, -1, dims=-2) + distances = get_distance(locs_ordered, travel_to) + return -(distances * costs).sum(-1) + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor) -> None: + """Check that solution is valid: nodes are not visited twice except depot and required skill levels are always met.""" + batch_size, graph_size = td["skills"].shape[0], td["skills"].shape[1] + sorted_pi = actions.data.sort(1).values + + # Sorting it should give all zeros at front and then 1...n + assert ( + torch.arange(1, graph_size + 1, out=sorted_pi.data.new()) + .view(1, -1) + .expand(batch_size, graph_size) + == sorted_pi[:, -graph_size:] + ).all() and (sorted_pi[:, :-graph_size] == 0).all(), "Invalid tour" + + # make sure all required skill levels are met + indices = torch.nonzero(actions == 0) + skills = torch.cat( + [torch.zeros(batch_size, 1, 1, device=td.device), td["skills"]], 1 + ) + skills_ordered = gather_by_index(skills, actions).reshape( + [batch_size, actions.size(-1), 1] + ) + batch = start = tech = 0 + for each in indices: + if each[0] > batch: + start = tech = 0 + batch = each[0] + assert ( + skills_ordered[batch, start : each[1]] <= td["techs"][batch, tech] + ).all(), "Skill level not met" + start = each[1] + 1 # skip the depot + tech += 1 diff --git a/rl4co/envs/routing/svrp/generator.py b/rl4co/envs/routing/svrp/generator.py new file mode 100644 index 00000000..60110559 --- /dev/null +++ b/rl4co/envs/routing/svrp/generator.py @@ -0,0 +1,107 @@ +from typing import Union, Callable + +import torch + +from torch.distributions import Uniform +from tensordict.tensordict import TensorDict + +from rl4co.utils.pylogger import get_pylogger +from rl4co.envs.common.utils import get_sampler, Generator + +log = get_pylogger(__name__) + + +class SVRPGenerator(Generator): + """Data generator for the Skill Vehicle Routing Problem (SVRP). + Args: + num_loc: number of locations (customers) in the TSP + min_loc: minimum value for the location coordinates + max_loc: maximum value for the location coordinates + loc_distribution: distribution for the location coordinates + depot_distribution: distribution for the depot location. If None, sample the depot from the locations min_skill: minimum value for the technic skill + max_skill: maximum value for the technic skill + skill_distribution: distribution for the technic skill + tech_costs: list of the technic costs + + Returns: + A TensorDict with the following keys: + locs [batch_size, num_loc, 2]: locations of each customer + depot [batch_size, 2]: location of the depot + techs [batch_size, num_loc]: technic requirements of each customer + skills [batch_size, num_loc]: skills of the vehicles + """ + def __init__( + self, + num_loc: int = 20, + min_loc: float = 0.0, + max_loc: float = 1.0, + loc_distribution: Union[ + int, float, str, type, Callable + ] = Uniform, + depot_distribution: Union[ + int, float, str, type, Callable + ] = None, + min_skill: float = 1.0, + max_skill: float = 10.0, + tech_costs: list = [1, 2, 3], + **kwargs + ): + self.num_loc = num_loc + self.min_loc = min_loc + self.max_loc = max_loc + self.min_skill = min_skill + self.max_skill = max_skill + self.num_tech = len(tech_costs) + self.tech_costs = torch.tensor(tech_costs) + + # Location distribution + if kwargs.get("loc_sampler", None) is not None: + self.loc_sampler = kwargs["loc_sampler"] + else: + self.loc_sampler = get_sampler("loc", loc_distribution, min_loc, max_loc, **kwargs) + + # Depot distribution + if kwargs.get("depot_sampler", None) is not None: + self.depot_sampler = kwargs["depot_sampler"] + else: + self.depot_sampler = get_sampler("depot", depot_distribution, min_loc, max_loc, **kwargs) if depot_distribution is not None else None + + def _generate(self, batch_size) -> TensorDict: + """Generate data for the basic Skill-VRP. The data consists of the locations of the customers, + the skill-levels of the technicians and the required skill-levels of the customers. + The data is generated randomly within the given bounds.""" + # Sample locations: depot and customers + if self.depot_sampler is not None: + depot = self.depot_sampler.sample((*batch_size, 2)) + locs = self.loc_sampler.sample((*batch_size, self.num_loc, 2)) + else: + # if depot_sampler is None, sample the depot from the locations + locs = self.loc_sampler.sample((*batch_size, self.num_loc + 1, 2)) + depot = locs[..., 0, :] + locs = locs[..., 1:, :] + + locs_with_depot = torch.cat((depot[:, None, :], locs), dim=1) + + # Initialize technicians and sort ascendingly + techs, _ = torch.sort( + torch.FloatTensor(*batch_size, self.num_tech, 1) + .uniform_(self.min_skill, self.max_skill), + dim=-2, + ) + + # Initialize the skills + skills = ( + torch.FloatTensor(*batch_size, self.num_loc, 1).uniform_(0, 1) + ) + # scale skills + skills = torch.max(techs, dim=1, keepdim=True).values * skills + td = TensorDict( + { + "locs": locs_with_depot[..., 1:, :], + "depot": locs_with_depot[..., 0, :], + "techs": techs, + "skills": skills, + }, + batch_size=batch_size, + ) + return td diff --git a/rl4co/envs/routing/svrp/render.py b/rl4co/envs/routing/svrp/render.py new file mode 100644 index 00000000..88a3d752 --- /dev/null +++ b/rl4co/envs/routing/svrp/render.py @@ -0,0 +1,103 @@ +import torch + +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def render(td, actions=None, ax=None): + import matplotlib.pyplot as plt + import numpy as np + + from matplotlib import cm, colormaps + + num_routine = (actions == 0).sum().item() + 2 + base = colormaps["nipy_spectral"] + color_list = base(np.linspace(0, 1, num_routine)) + cmap_name = base.name + str(num_routine) + out = base.from_list(cmap_name, color_list, num_routine) + + if ax is None: + # Create a plot of the nodes + _, ax = plt.subplots() + + td = td.detach().cpu() + + if actions is None: + actions = td.get("action", None) + + # if batch_size greater than 0 , we need to select the first batch element + if td.batch_size != torch.Size([]): + td = td[0] + actions = actions[0] + + locs = td["locs"] + + # add the depot at the first action and the end action + actions = torch.cat([torch.tensor([0]), actions, torch.tensor([0])]) + + # gather locs in order of action if available + if actions is None: + log.warning("No action in TensorDict, rendering unsorted locs") + else: + locs = locs + + # Cat the first node to the end to complete the tour + x, y = locs[:, 0], locs[:, 1] + + # plot depot + ax.scatter( + locs[0, 0], + locs[0, 1], + edgecolors=cm.Set2(2), + facecolors="none", + s=100, + linewidths=2, + marker="s", + alpha=1, + ) + + # plot visited nodes + ax.scatter( + x[1:], + y[1:], + edgecolors=cm.Set2(0), + facecolors="none", + s=50, + linewidths=2, + marker="o", + alpha=1, + ) + + # text depot + ax.text( + locs[0, 0], + locs[0, 1] - 0.025, + "Depot", + horizontalalignment="center", + verticalalignment="top", + fontsize=10, + color=cm.Set2(2), + ) + + # plot actions + color_idx = 0 + for action_idx in range(len(actions) - 1): + if actions[action_idx] == 0: + color_idx += 1 + from_loc = locs[actions[action_idx]] + to_loc = locs[actions[action_idx + 1]] + ax.plot( + [from_loc[0], to_loc[0]], + [from_loc[1], to_loc[1]], + color=out(color_idx), + lw=1, + ) + ax.annotate( + "", + xy=(to_loc[0], to_loc[1]), + xytext=(from_loc[0], from_loc[1]), + arrowprops=dict(arrowstyle="-|>", color=out(color_idx)), + size=15, + annotation_clip=False, + ) diff --git a/rl4co/envs/routing/tsp/__init__.py b/rl4co/envs/routing/tsp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/routing/tsp/env.py b/rl4co/envs/routing/tsp/env.py new file mode 100644 index 00000000..743ea9e7 --- /dev/null +++ b/rl4co/envs/routing/tsp/env.py @@ -0,0 +1,606 @@ +from typing import Optional + +import torch + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.envs.common.base import ImprovementEnvBase, RL4COEnvBase +from rl4co.utils.ops import gather_by_index, get_distance, get_tour_length +from rl4co.utils.pylogger import get_pylogger + +from .generator import TSPGenerator + +try: + from .local_search import local_search +except ImportError: + # In case some dependencies are not installed (e.g., numba) + local_search = None +from .render import render, render_improvement + +log = get_pylogger(__name__) + + +class TSPEnv(RL4COEnvBase): + """Traveling Salesman Problem (TSP) environment + At each step, the agent chooses a city to visit. The reward is 0 unless the agent visits all the cities. + In that case, the reward is (-)length of the path: maximizing the reward is equivalent to minimizing the path length. + + Observations: + - locations of each customer. + - the current location of the vehicle. + + Constraints: + - the tour must return to the starting customer. + - each customer must be visited exactly once. + + Finish condition: + - the agent has visited all customers and returned to the starting customer. + + Reward: + - (minus) the negative length of the path. + + Args: + generator: TSPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "tsp" + + def __init__( + self, + generator: TSPGenerator = None, + generator_params: dict = {}, + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = TSPGenerator(**generator_params) + self.generator = generator + self._make_spec(self.generator) + + @staticmethod + def _step(td: TensorDict) -> TensorDict: + current_node = td["action"] + first_node = current_node if td["i"].all() == 0 else td["first_node"] + + # # Set not visited to 0 (i.e., we visited the node) + available = td["action_mask"].scatter( + -1, current_node.unsqueeze(-1).expand_as(td["action_mask"]), 0 + ) + + # We are done there are no unvisited locations + done = torch.sum(available, dim=-1) == 0 + + # The reward is calculated outside via get_reward for efficiency, so we set it to 0 here + reward = torch.zeros_like(done) + + td.update( + { + "first_node": first_node, + "current_node": current_node, + "i": td["i"] + 1, + "action_mask": available, + "reward": reward, + "done": done, + }, + ) + return td + + def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: + # Initialize locations + device = td.device + init_locs = td["locs"] + + # We do not enforce loading from self for flexibility + num_loc = init_locs.shape[-2] + + # Other variables + current_node = torch.zeros((batch_size), dtype=torch.int64, device=device) + available = torch.ones( + (*batch_size, num_loc), dtype=torch.bool, device=device + ) # 1 means not visited, i.e. action is allowed + i = torch.zeros((*batch_size, 1), dtype=torch.int64, device=device) + + return TensorDict( + { + "locs": init_locs, + "first_node": current_node, + "current_node": current_node, + "i": i, + "action_mask": available, + "reward": torch.zeros((*batch_size, 1), dtype=torch.float32), + }, + batch_size=batch_size, + ) + + def _make_spec(self, generator: TSPGenerator): + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(generator.num_loc, 2), + dtype=torch.float32, + ), + first_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + current_node=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + i=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(generator.num_loc), + dtype=torch.bool, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1), + dtype=torch.int64, + low=0, + high=generator.num_loc, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1), dtype=torch.bool) + + def _get_reward(self, td: TensorDict, actions: torch.Tensor) -> torch.Tensor: + if self.check_solution: + self.check_solution_validity(td, actions) + + # Gather locations in order of tour and return distance between them (i.e., -reward) + locs_ordered = gather_by_index(td["locs"], actions) + return -get_tour_length(locs_ordered) + + @staticmethod + def check_solution_validity(td: TensorDict, actions: torch.Tensor) -> None: + """Check that solution is valid: nodes are visited exactly once""" + assert ( + torch.arange(actions.size(1), out=actions.data.new()) + .view(1, -1) + .expand_as(actions) + == actions.data.sort(1)[0] + ).all(), "Invalid tour" + + def replace_selected_actions( + self, + cur_actions: torch.Tensor, + new_actions: torch.Tensor, + selection_mask: torch.Tensor, + ) -> torch.Tensor: + """ + Replace selected current actions with updated actions based on `selection_mask`. + + Args: + cur_actions [batch_size, num_loc] + new_actions [batch_size, num_loc] + selection_mask [batch_size,] + """ + cur_actions[selection_mask] = new_actions[selection_mask] + return cur_actions + + @staticmethod + def local_search(td: TensorDict, actions: torch.Tensor, **kwargs) -> torch.Tensor: + assert ( + local_search is not None + ), "Cannot import local_search module. Check if `numba` is installed." + return local_search(td, actions, **kwargs) + + @staticmethod + def render(td: TensorDict, actions: torch.Tensor = None, ax=None): + return render(td, actions, ax) + + +class TSPkoptEnv(ImprovementEnvBase): + """Traveling Salesman Problem (PDP) environment for performing the neural k-opt search. + + The goal is to search for optimal solutions to TSP by performing a k-opt neighborhood search on a given initial solution. + + Observations: + - locations of each customer + - current solution to be improved + - the current step + + Constraints: + - the tour must return to the starting customer. + - each customer must be visited exactly once. + + Finish condition: + - None + + Reward: + - the immediate reduced cost over the current best-so-far solution + + Args: + generator: TSPGenerator instance as the data generator + generator_params: parameters for the generator + k_max: the maximum k value for k-opt: + if k_max==2, the MDP in DACT(https://arxiv.org/abs/2110.02544) is used; + if k_max>2, the MDP in NeuOpt(https://arxiv.org/abs/2310.18264) is used; + """ + + name = "tsp_kopt" + + def __init__( + self, + generator: TSPGenerator = None, + generator_params: dict = {}, + k_max: int = 2, + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = TSPGenerator(**generator_params) + self.generator = generator + self.k_max = k_max + self.two_opt_mode = k_max == 2 + self._make_spec(self.generator) + + def _step(self, td: TensorDict, solution_to=None) -> TensorDict: + # get state information from td + solution_best = td["rec_best"] + locs = td["locs"] + cost_bsf = td["cost_bsf"] + bs, gs = solution_best.size() + + # perform loca_operator + if solution_to is None: + action = td["action"] + solution = td["rec_current"] + next_rec = self._local_operator(solution, action) + else: + next_rec = solution_to.clone() + new_obj = self.get_costs(locs, next_rec) + + # compute reward and update best-so-far solutions + now_bsf = torch.where(new_obj < cost_bsf, new_obj, cost_bsf) + reward = cost_bsf - now_bsf + index = reward > 0.0 + solution_best[index] = next_rec[index].clone() + + # reset visited_time + visited_time = td["visited_time"] * 0 + pre = torch.zeros((bs), device=visited_time.device).long() + arange = torch.arange(bs) + for i in range(gs): + current_nodes = next_rec[arange, pre] + visited_time[arange, current_nodes] = i + 1 + pre = current_nodes + visited_time = visited_time.long() + + # Update step + td.update( + { + "cost_current": new_obj, + "cost_bsf": now_bsf, + "rec_current": next_rec, + "rec_best": solution_best, + "visited_time": visited_time, + "i": td["i"] + 1 if solution_to is None else td["i"], + "reward": reward, + } + ) + + return td + + def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: + device = td.device + + locs = td["locs"] + current_rec = self.generator._get_initial_solutions(locs).to(device) + + obj = self.get_costs(locs, current_rec) + + # get index according to the solutions in the linked list data structure + bs = batch_size[0] + seq_length = self.generator.num_loc + visited_time = torch.zeros((bs, seq_length)).to(device) + pre = torch.zeros((bs)).to(device).long() + arange = torch.arange(bs) + for i in range(seq_length): + current_nodes = current_rec[arange, pre] + visited_time[arange, current_nodes] = i + 1 + pre = current_nodes + visited_time = visited_time.long() + + i = torch.zeros((*batch_size, 1), dtype=torch.int64).to(device) + + return TensorDict( + { + "locs": locs, + "cost_current": obj, + "cost_bsf": obj.clone(), + "rec_current": current_rec, + "rec_best": current_rec.clone(), + "visited_time": visited_time, + "i": i, + }, + batch_size=batch_size, + ) + + def _local_operator(self, solution, action): + rec = solution.clone() + + if self.two_opt_mode: + # get actions + first = action[:, 0].view(-1, 1) + second = action[:, 1].view(-1, 1) + + # fix connection for first node + argsort = solution.argsort() + pre_first = argsort.gather(1, first) + pre_first = torch.where(pre_first != second, pre_first, first) + rec.scatter_(1, pre_first, second) + + # fix connection for second node + post_second = solution.gather(1, second) + post_second = torch.where(post_second != first, post_second, second) + rec.scatter_(1, first, post_second) + + # reverse loop: + cur = first + for i in range(self.generator.num_loc): + cur_next = solution.gather(1, cur) + rec.scatter_( + 1, cur_next, torch.where(cur != second, cur, rec.gather(1, cur_next)) + ) + cur = torch.where(cur != second, cur_next, cur) + + rec_next = rec + + else: + # action bs * (K_index, K_from, K_to) + selected_index = action[:, : self.k_max] + left = action[:, self.k_max : 2 * self.k_max] + right = action[:, 2 * self.k_max :] + + # prepare + rec_next = rec.clone() + right_nodes = rec.gather(1, selected_index) + argsort = rec.argsort() + + # new rec + rec_next.scatter_(1, left, right) + cur = left[:, :1].clone() + for i in range( + self.generator.num_loc - 2 + ): # self.generator.num_loc - 2 is already correct + next_cur = rec_next.gather(1, cur) + pre_next_wrt_old = argsort.gather(1, next_cur) + reverse_link_condition = (cur != pre_next_wrt_old) & ~( + (next_cur == right_nodes).any(-1, True) + ) + next_next_cur = rec_next.gather(1, next_cur) + rec_next.scatter_( + 1, + next_cur, + torch.where(reverse_link_condition, pre_next_wrt_old, next_next_cur), + ) + # if i >= self.generator.num_loc - 2: assert (reverse_link_condition == False).all() + cur = next_cur + + return rec_next + + def _make_spec(self, generator: TSPGenerator): + """Make the observation and action specs from the parameters.""" + self.observation_spec = CompositeSpec( + locs=BoundedTensorSpec( + low=generator.min_loc, + high=generator.max_loc, + shape=(generator.num_loc, 2), + dtype=torch.float32, + ), + cost_current=UnboundedContinuousTensorSpec( + shape=(1), + dtype=torch.float32, + ), + cost_bsf=UnboundedContinuousTensorSpec( + shape=(1), + dtype=torch.float32, + ), + rec_current=UnboundedDiscreteTensorSpec( + shape=(self.generator.num_loc), + dtype=torch.int64, + ), + rec_best=UnboundedDiscreteTensorSpec( + shape=(self.generator.num_loc), + dtype=torch.int64, + ), + visited_time=UnboundedDiscreteTensorSpec( + shape=(self.generator.num_loc, self.generator.num_loc), + dtype=torch.int64, + ), + i=UnboundedDiscreteTensorSpec( + shape=(1), + dtype=torch.int64, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(self.k_max * 3,), + dtype=torch.int64, + low=0, + high=self.generator.num_loc, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + def check_solution_validity(self, td, actions=None): + # The function can be called by the agent to check the validity of the best found solution + # Note that the args actions are not used in improvement method. + + solution = td["rec_best"] + batch_size, graph_size = solution.size() + + assert ( + torch.arange(graph_size, out=solution.data.new()) + .view(1, -1) + .expand_as(solution) + == solution.data.sort(1)[0] + ).all(), "Not visiting all nodes" + + def get_mask(self, td): + # return mask that is 1 if the corresponding action is feasible, 0 otherwise + visited_time = td["visited_time"] + bs, gs = visited_time.size() + if self.two_opt_mode: + selfmask = torch.eye(gs).view(1, gs, gs).to(td.device) + masks = selfmask.expand(bs, gs, gs).bool() + return ~masks + else: + assert False, "The masks for NeuOpt are handled within its policy" + + def _random_action(self, td): + bs, gs = td["rec_best"].size() + + if self.two_opt_mode: + mask = self.get_mask(td) + logits = torch.rand(bs, gs, gs) + logits[~mask] = -1e20 + prob = torch.softmax(logits.view(bs, -1), -1) + sample = prob.multinomial(1) + td["action"] = torch.cat((sample // (gs), sample % (gs)), -1) + + else: + rec = td["rec_current"] + visited_time = td["visited_time"] + action_index = torch.zeros(bs, self.k_max, dtype=torch.long) + k_action_left = torch.zeros(bs, self.k_max + 1, dtype=torch.long) + k_action_right = torch.zeros(bs, self.k_max, dtype=torch.long) + next_of_last_action = torch.zeros((bs, 1), dtype=torch.long) - 1 + mask = torch.zeros((bs, gs), dtype=torch.bool) + stopped = torch.ones(bs, dtype=torch.bool) + + for i in range(self.k_max): + # Sample action for a_i + logits = torch.rand(bs, gs) + logits[mask.clone()] = -1e30 + prob = torch.softmax(logits, -1) + action = prob.multinomial(1) + value_max, action_max = prob.max(-1, True) ### fix bug of pytorch + action = torch.where( + 1 - value_max.view(-1, 1) < 1e-5, action_max.view(-1, 1), action + ) ### fix bug of pytorch + if i > 0: + action = torch.where( + stopped.unsqueeze(-1), action_index[:, :1], action + ) + + # Store and Process actions + next_of_new_action = rec.gather(1, action) + action_index[:, i] = action.squeeze().clone() + k_action_left[stopped, i] = action[stopped].squeeze().clone() + k_action_right[~stopped, i - 1] = action[~stopped].squeeze().clone() + k_action_left[:, i + 1] = next_of_new_action.squeeze().clone() + + # Process if k-opt close + if i > 0: + stopped = stopped | (action == next_of_last_action).squeeze() + else: + stopped = (action == next_of_last_action).squeeze() + k_action_left[stopped, i] = k_action_left[stopped, i - 1] + k_action_right[stopped, i] = k_action_right[stopped, i - 1] + + # Calc next basic masks + if i == 0: + visited_time_tag = ( + visited_time - visited_time.gather(1, action) + ) % gs + mask &= False + mask[(visited_time_tag <= visited_time_tag.gather(1, action))] = True + if i == 0: + mask[visited_time_tag > (gs - 2)] = True + mask[ + stopped, action[stopped].squeeze() + ] = False # allow next k-opt starts immediately + # if True:#i == self.k_max - 2: # allow special case: close k-opt at the first selected node + index_allow_first_node = (~stopped) & ( + next_of_new_action.squeeze() == action_index[:, 0] + ) + mask[ + index_allow_first_node, action_index[index_allow_first_node, 0] + ] = False + + # Move to next + next_of_last_action = next_of_new_action + next_of_last_action[stopped] = -1 + + # Form final action + k_action_right[~stopped, -1] = k_action_left[~stopped, -1].clone() + k_action_left = k_action_left[:, : self.k_max] + td["action"] = torch.cat((action_index, k_action_left, k_action_right), -1) + + return td["action"] + + @classmethod + def render(cls, td: TensorDict, actions: torch.Tensor = None, ax=None): + solution_current = cls.get_current_solution(td) + solution_best = cls.get_best_solution(td) + return render_improvement(td, solution_current, solution_best) + + +class DenseRewardTSPEnv(TSPEnv): + """ + This is an experimental version of the TSPEnv to be used with stepwise PPO. That is + this environment defines a stepwise reward function for the TSP which is the distance added + to the current tour by the given action. + """ + + def __init__( + self, generator: TSPGenerator = None, generator_params: dict = {}, **kwargs + ): + super().__init__( + generator, + generator_params, + check_solution=False, + _torchrl_mode=True, + **kwargs, + ) + + def _step(self, td): + last_node = td["current_node"].clone() + current_node = td["action"] + + first_node = current_node if td["i"].all() == 0 else td["first_node"] + + # # Set not visited to 0 (i.e., we visited the node) + available = td["action_mask"].scatter( + -1, current_node.unsqueeze(-1).expand_as(td["action_mask"]), 0 + ) + + # We are done there are no unvisited locations + done = torch.sum(available, dim=-1) == 0 + + # calc stepwise reward + last_node_loc = gather_by_index(td["locs"], last_node) + curr_node_loc = gather_by_index(td["locs"], current_node) + reward = get_distance(last_node_loc, curr_node_loc)[:, None] + + td.update( + { + "first_node": first_node, + "current_node": current_node, + "i": td["i"] + 1, + "action_mask": available, + "reward": reward, + "done": done, + }, + ) + return td + + def _get_reward(self, td, actions=None) -> TensorDict: + if actions is not None: + # Gather locations in order of tour and return distance between them (i.e., -reward) + locs_ordered = gather_by_index(td["locs"], actions) + return -get_tour_length(locs_ordered) + return -td["reward"] diff --git a/rl4co/envs/routing/tsp/generator.py b/rl4co/envs/routing/tsp/generator.py new file mode 100644 index 00000000..0c0dda04 --- /dev/null +++ b/rl4co/envs/routing/tsp/generator.py @@ -0,0 +1,99 @@ +from typing import Callable, Union + +import torch + +from tensordict.tensordict import TensorDict +from torch.distributions import Uniform + +from rl4co.envs.common.utils import Generator, get_sampler +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class TSPGenerator(Generator): + """Data generator for the Travelling Salesman Problem (TSP). + + Args: + num_loc: number of locations (customers) in the TSP + min_loc: minimum value for the location coordinates + max_loc: maximum value for the location coordinates + init_sol_type: the method type used for generating initial solutions (random or greedy) + loc_distribution: distribution for the location coordinates + + Returns: + A TensorDict with the following keys: + locs [batch_size, num_loc, 2]: locations of each customer + """ + + def __init__( + self, + num_loc: int = 20, + min_loc: float = 0.0, + max_loc: float = 1.0, + init_sol_type: str = "random", + loc_distribution: Union[int, float, str, type, Callable] = Uniform, + **kwargs, + ): + self.num_loc = num_loc + self.min_loc = min_loc + self.max_loc = max_loc + self.init_sol_type = init_sol_type + + # Location distribution + if kwargs.get("loc_sampler", None) is not None: + self.loc_sampler = kwargs["loc_sampler"] + else: + self.loc_sampler = get_sampler( + "loc", loc_distribution, min_loc, max_loc, **kwargs + ) + + def _generate(self, batch_size) -> TensorDict: + # Sample locations + locs = self.loc_sampler.sample((*batch_size, self.num_loc, 2)) + + return TensorDict( + { + "locs": locs, + }, + batch_size=batch_size, + ) + + # for improvement MDP only (to be refactored by a combination of rollout and the random policy) + def _get_initial_solutions(self, coordinates): + batch_size = coordinates.size(0) + + if self.init_sol_type == "random": + set = torch.rand(batch_size, self.num_loc).argsort().long() + rec = torch.zeros(batch_size, self.num_loc).long() + index = torch.zeros(batch_size, 1).long() + + for i in range(self.num_loc - 1): + rec.scatter_(1, set.gather(1, index + i), set.gather(1, index + i + 1)) + + rec.scatter_(1, set[:, -1].view(-1, 1), set.gather(1, index)) + + elif self.init_sol_type == "greedy": + candidates = torch.ones(batch_size, self.num_loc).bool() + rec = torch.zeros(batch_size, self.num_loc).long() + selected_node = torch.zeros(batch_size, 1).long() + candidates.scatter_(1, selected_node, 0) + + for i in range(self.num_loc - 1): + d1 = coordinates.cpu().gather( + 1, selected_node.unsqueeze(-1).expand(batch_size, self.num_loc, 2) + ) + d2 = coordinates.cpu() + + dists = (d1 - d2).norm(p=2, dim=2) + dists[~candidates] = 1e5 + + next_selected_node = dists.min(-1)[1].view(-1, 1) + rec.scatter_(1, selected_node, next_selected_node) + candidates.scatter_(1, next_selected_node, 0) + selected_node = next_selected_node + + else: + raise NotImplementedError() + + return rec.expand(batch_size, self.num_loc).clone() diff --git a/rl4co/envs/routing/tsp/local_search.py b/rl4co/envs/routing/tsp/local_search.py new file mode 100644 index 00000000..a8bd2908 --- /dev/null +++ b/rl4co/envs/routing/tsp/local_search.py @@ -0,0 +1,74 @@ +import concurrent.futures + +import numpy as np +import numba as nb +import torch +from tensordict.tensordict import TensorDict + +from rl4co.utils.ops import get_distance_matrix +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def local_search(td: TensorDict, actions: torch.Tensor, max_iterations: int = 1000) -> torch.Tensor: + """ + Improve the solution using local search, especially 2-opt for TSP. + Implementation credits to: https://github.com/henry-yeh/DeepACO + + Args: + td: TensorDict, td from env with shape [batch_size,] + actions: torch.Tensor, Tour indices with shape [batch_size, num_loc] + max_iterations: int, maximum number of iterations for 2-opt + Returns: + torch.Tensor, Improved tour indices with shape [batch_size, num_loc] + """ + distances = td.get("distances", None) + if distances is None: + distances_np = get_distance_matrix(td["locs"]).numpy() + else: + distances_np = distances.detach().cpu().numpy() + distances_np = distances_np + 1e9 * np.eye(distances_np.shape[1], dtype=np.float32)[None, :, :] + + actions_np = actions.detach().cpu().numpy().astype(np.uint16) + with concurrent.futures.ThreadPoolExecutor() as executor: + futures = [] + for dist, tour in zip(distances_np, actions_np): + future = executor.submit(_two_opt_python, distmat=dist, tour=tour, max_iterations=max_iterations) + futures.append(future) + return torch.from_numpy(np.stack([f.result() for f in futures]).astype(np.int64)).to(actions.device) + + +@nb.njit(nb.float32(nb.float32[:,:], nb.uint16[:], nb.uint16), nogil=True) +def two_opt_once(distmat, tour, fixed_i = 0): + '''in-place operation''' + n = tour.shape[0] + p = q = 0 + delta = 0 + for i in range(1, n - 1) if fixed_i==0 else range(fixed_i, fixed_i + 1): + for j in range(i + 1, n): + node_i, node_j = tour[i], tour[j] + node_prev, node_next = tour[i - 1], tour[(j + 1) % n] + if node_prev == node_j or node_next == node_i: + continue + change = ( + distmat[node_prev, node_j] + distmat[node_i, node_next] + - distmat[node_prev, node_i] - distmat[node_j, node_next] + ) + if change < delta: + p, q, delta = i, j, change + if delta < -1e-6: + tour[p: q + 1] = np.flip(tour[p: q + 1]) + return delta + else: + return 0.0 + + +@nb.njit(nb.uint16[:](nb.float32[:,:], nb.uint16[:], nb.int64), nogil=True) +def _two_opt_python(distmat, tour, max_iterations=1000): + iterations = 0 + min_change = -1.0 + while min_change < -1e-6 and iterations < max_iterations: + min_change = two_opt_once(distmat, tour, 0) + iterations += 1 + return tour diff --git a/rl4co/envs/routing/tsp/render.py b/rl4co/envs/routing/tsp/render.py new file mode 100644 index 00000000..5f703f90 --- /dev/null +++ b/rl4co/envs/routing/tsp/render.py @@ -0,0 +1,110 @@ +import matplotlib.pyplot as plt +import numpy as np +import torch + +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def render(td, actions=None, ax=None): + if ax is None: + # Create a plot of the nodes + _, ax = plt.subplots() + + td = td.detach().cpu() + + if actions is None: + actions = td.get("action", None) + + # If batch_size greater than 0 , we need to select the first batch element + if td.batch_size != torch.Size([]): + td = td[0] + actions = actions[0] + + locs = td["locs"] + + # Gather locs in order of action if available + if actions is None: + log.warning("No action in TensorDict, rendering unsorted locs") + else: + actions = actions.detach().cpu() + locs = gather_by_index(locs, actions, dim=0) + + # Cat the first node to the end to complete the tour + locs = torch.cat((locs, locs[0:1])) + x, y = locs[:, 0], locs[:, 1] + + # Plot the visited nodes + ax.scatter(x, y, color="tab:blue") + + # Add arrows between visited nodes as a quiver plot + dx, dy = np.diff(x), np.diff(y) + ax.quiver(x[:-1], y[:-1], dx, dy, scale_units="xy", angles="xy", scale=1, color="k") + + # Setup limits and show + ax.set_xlim(-0.05, 1.05) + ax.set_ylim(-0.05, 1.05) + + +def render_improvement(td, current_soltuion, best_soltuion): + coordinates = td["locs"][0] + real_seq = current_soltuion[:1] + real_best = best_soltuion[:1] + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6)) # Create two side-by-side axes + + for ax in [ax1, ax2]: # Plot on both axes + if ax == ax1: + ax.axis([-0.05, 1.05] * 2) + # plot the nodes + ax.scatter( + coordinates[:, 0], coordinates[:, 1], marker="H", s=55, c="blue", zorder=2 + ) + # plot the tour + real_seq_coordinates = coordinates.gather( + 0, real_seq[0].unsqueeze(1).repeat(1, 2) + ) + real_seq_coordinates = torch.cat( + (real_seq_coordinates, real_seq_coordinates[:1]), 0 + ) + ax.plot( + real_seq_coordinates[:, 0], + real_seq_coordinates[:, 1], + color="black", + zorder=1, + ) + # mark node + for i, txt in enumerate(range(real_seq.size(1))): + ax.annotate( + txt, + (coordinates[i, 0] + 0.01, coordinates[i, 1] + 0.01), + ) + ax.set_title("Current Solution") + else: + ax.axis([-0.05, 1.05] * 2) + # plot the nodes + ax.scatter( + coordinates[:, 0], coordinates[:, 1], marker="H", s=55, c="blue", zorder=2 + ) + # plot the tour + real_best_coordinates = coordinates.gather( + 0, real_best[0].unsqueeze(1).repeat(1, 2) + ) + real_best_coordinates = torch.cat( + (real_best_coordinates, real_best_coordinates[:1]), 0 + ) + ax.plot( + real_best_coordinates[:, 0], + real_best_coordinates[:, 1], + color="black", + zorder=1, + ) + # mark node + for i, txt in enumerate(range(real_seq.size(1))): + ax.annotate( + txt, + (coordinates[i, 0] + 0.01, coordinates[i, 1] + 0.01), + ) + ax.set_title("Best Solution") + plt.tight_layout() diff --git a/rl4co/envs/scheduling/__init__.py b/rl4co/envs/scheduling/__init__.py new file mode 100644 index 00000000..febb183c --- /dev/null +++ b/rl4co/envs/scheduling/__init__.py @@ -0,0 +1,4 @@ +from .ffsp.env import FFSPEnv +from .fjsp.env import FJSPEnv +from .jssp.env import JSSPEnv +from .smtwtp.env import SMTWTPEnv diff --git a/rl4co/envs/scheduling/ffsp/__init__.py b/rl4co/envs/scheduling/ffsp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/scheduling/ffsp/env.py b/rl4co/envs/scheduling/ffsp/env.py new file mode 100644 index 00000000..c74ef4c2 --- /dev/null +++ b/rl4co/envs/scheduling/ffsp/env.py @@ -0,0 +1,458 @@ +import itertools + +from math import factorial +from typing import Optional + +import torch + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.data.dataset import FastTdDataset +from rl4co.envs.common.base import RL4COEnvBase + +from .generator import FFSPGenerator + + +class FFSPEnv(RL4COEnvBase): + """Flexible Flow Shop Problem (FFSP) environment. + The goal is to schedule a set of jobs on a set of machines such that the makespan is minimized. + + Observations: + - time index + - sub time index + - batch index + - machine index + - schedule + - machine wait step + - job location + - job wait step + - job duration + + Constraints: + - each job has to be processed on each machine in a specific order + - the machine has to be available to process the job + - the job has to be available to be processed + + Finish Condition: + - all jobs are scheduled + + Reward: + - (minus) the makespan of the schedule + + Args: + generator: FFSPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "ffsp" + + def __init__( + self, + generator: FFSPGenerator = None, + generator_params: dict = {}, + **kwargs, + ): + super().__init__(check_solution=False, dataset_cls=FastTdDataset, **kwargs) + if generator is None: + generator = FFSPGenerator(**generator_params) + self.generator = generator + + self.num_stage = generator.num_stage + self.num_machine = generator.num_machine + self.num_job = generator.num_job + self.num_machine_total = generator.num_machine_total + self.tables = None + self.step_cnt = None + self.flatten_stages = generator.flatten_stages + + self._make_spec(generator) + + def get_num_starts(self, td): + return factorial(self.num_machine) + + def select_start_nodes(self, td, num_starts): + self.tables.augment_machine_tables(num_starts) + selected = torch.full((num_starts * td.size(0),), self.num_job) + return selected + + def _move_to_next_machine(self, td): + batch_size = td.batch_size + batch_idx = torch.arange(*batch_size, dtype=torch.long, device=td.device) + + time_idx = td["time_idx"] + machine_idx = td["machine_idx"] + sub_time_idx = td["sub_time_idx"] + + machine_wait_step = td["machine_wait_step"] + job_wait_step = td["job_wait_step"] + job_location = td["job_location"] + + ready = torch.flatten(td["done"]) + idx = torch.flatten(batch_idx) + # select minibatch instances that need updates (are not done) + idx = idx[~ready] + + while ~ready.all(): + # increment the stage-machine counter + new_sub_time_idx = sub_time_idx[idx] + 1 + # increment time if all machines-stage combinations have been candidates + step_time_required = new_sub_time_idx == self.num_machine_total + time_idx[idx] += step_time_required.long() + # in this case set the machine-stage counter to zero again + new_sub_time_idx[step_time_required] = 0 + # update machine-stage counter + sub_time_idx[idx] = new_sub_time_idx + # determine current machine candidate + new_machine_idx = self.tables.get_machine_index(idx, new_sub_time_idx) + machine_idx[idx] = new_machine_idx + + # decrease machine wait time by 1 if instance transitioned to new time step + machine_wait_steps = machine_wait_step[idx, :] + machine_wait_steps[step_time_required, :] -= 1 + machine_wait_steps[machine_wait_steps < 0] = 0 + machine_wait_step[idx, :] = machine_wait_steps + + # decrease job wait time by 1 if instance transitioned to new time step + job_wait_steps = job_wait_step[idx, :] + job_wait_steps[step_time_required, :] -= 1 + job_wait_steps[job_wait_steps < 0] = 0 + job_wait_step[idx, :] = job_wait_steps + # machine is ready if its wait time is zero + machine_ready = machine_wait_step[idx, new_machine_idx] == 0 + # job is ready if the current stage matches the stage of the job and + # its wait time is zero (no operation of previous stage is in process) + new_stage_idx = self.tables.get_stage_index(new_sub_time_idx) + job_ready_1 = job_location[idx, : self.num_job] == new_stage_idx[:, None] + job_ready_2 = job_wait_step[idx, : self.num_job] == 0 + job_ready = (job_ready_1 & job_ready_2).any(dim=-1) + # instance ready if at least one job and the current machine are ready + ready = machine_ready & job_ready + assert ready.shape == idx.shape + idx = idx[~ready] + + return td.update( + { + "time_idx": time_idx, + "sub_time_idx": sub_time_idx, + "machine_idx": machine_idx, + "machine_wait_step": machine_wait_step, + "job_wait_step": job_wait_step, + } + ) + + def pre_step(self, td: TensorDict) -> TensorDict: + batch_size = td.batch_size + batch_idx = torch.arange(*batch_size, dtype=torch.long, device=td.device) + sub_time_idx = td["sub_time_idx"] + # update machine index + td["machine_idx"] = self.tables.get_machine_index(batch_idx, sub_time_idx) + # update action mask and stage machine indx + td = self._update_step_state(td) + # perform some checks + assert (td["stage_idx"] == 0).all(), "call pre_step only at beginning of env" + assert torch.all(td["stage_machine_idx"] == td["machine_idx"]) + # return updated td + return td + + def _update_step_state(self, td): + batch_size = td.batch_size + batch_idx = torch.arange(*batch_size, dtype=torch.long, device=td.device) + + sub_time_idx = td["sub_time_idx"] + job_location = td["job_location"] + job_wait_step = td["job_wait_step"] + if len(td["done"].shape) == 2: + done = td["done"].squeeze(1) + else: + done = td["done"] + + # update stage + stage_idx = self.tables.get_stage_index(sub_time_idx) + stage_machine_idx = self.tables.get_stage_machine_index(batch_idx, sub_time_idx) + + job_loc = job_location[:, : self.num_job] + job_wait_time = job_wait_step[:, : self.num_job] + # determine if job can be scheduled in current stage + # (i.e. previous stages are completed) + job_in_stage = job_loc == stage_idx[:, None] + job_not_waiting = job_wait_time == 0 + # job can be scheduled if in current stage and not waiting + job_available = job_in_stage & job_not_waiting + # determine instance for which waiting is allowed. This is the case if either + # 1.) any of its jobs need to be scheduled in a previous stage, + # 2.) any of the jobs wait for an operation of the preceeding stage to finish + # 3.) the instance is done. + job_in_previous_stages = (job_loc < stage_idx[:, None]).any(dim=-1) + job_waiting_in_stage = (job_in_stage & (job_wait_time > 0)).any(dim=-1) + wait_allowed = job_in_previous_stages + job_waiting_in_stage + done + + job_enable = torch.cat((job_available, wait_allowed[:, None]), dim=-1) + job_mask = torch.full_like(td["action_mask"], 0).masked_fill(job_enable, 1) + assert torch.logical_or((job_mask[:, :-1].sum(1) > 0), done).all() + return td.update( + { + "action_mask": job_mask, + "stage_idx": stage_idx, + "stage_machine_idx": stage_machine_idx, + } + ) + + def _step(self, td: TensorDict) -> TensorDict: + self.step_cnt += 1 + batch_size = td.batch_size + batch_idx = torch.arange(*batch_size, dtype=torch.long, device=td.device) + + # job_idx is the action from the model + job_idx = td["action"] + time_idx = td["time_idx"] + machine_idx = td["machine_idx"] + + # increment the operation counter of the selected job + td["job_location"][batch_idx, job_idx] += 1 + # td["job_location"][:, :-1].clip_(0, self.num_stage) + # assert (td["job_location"][:, : self.num_job] <= self.num_stage).all() + # insert start time of the selected job in the schedule + td["schedule"][batch_idx, machine_idx, job_idx] = time_idx + # get the duration of the selected job + job_length = td["job_duration"][batch_idx, job_idx, machine_idx] + # set the number of time steps until the selected machine is available again + td["machine_wait_step"][batch_idx, machine_idx] = job_length + + # set the number of time steps until the next operation of the job can be started + td["job_wait_step"][batch_idx, job_idx] = job_length + # determine whether all jobs are scheduled + td["done"] = (td["job_location"][:, : self.num_job] == self.num_stage).all(dim=-1) + + if td["done"].all(): + pass + else: + td = self._move_to_next_machine(td) + td = self._update_step_state(td) + + if td["done"].all(): + # determine end times of ops by adding the durations to their start times + end_schedule = td["schedule"] + td["job_duration"].permute(0, 2, 1) + # exclude dummy job and determine the makespan per job + end_time_max, _ = end_schedule[:, :, : self.num_job].max(dim=-1) + # determine the max makespan of all jobs + end_time_max, _ = end_time_max.max(dim=-1) + reward = -end_time_max.to(torch.float32) + td.set("reward", reward) + + return td + + def _reset( + self, td: Optional[TensorDict] = None, batch_size: Optional[list] = None + ) -> TensorDict: + """ + Args: + + Returns: + - stage_table [batch_size, num_stage * num_machine] + - machine_table [batch_size, num_machine * num_stage] + - stage_machine_idx [batch_size, num_stage * num_machine] + - time_idx [batch_size] + - sub_time_idx [batch_size] + - batch_idx [batch_size] + - machine_idx [batch_size] + - schedule [batch_size, num_machine_total, num_job+1] + - machine_wait_step [batch_size, num_machine_total] + - job_location [batch_size, num_job+1] + - job_wait_step [batch_size, num_job+1] + - job_duration [batch_size, num_job+1, num_machine * num_stage] + """ + device = td.device + + self.step_cnt = 0 + self.tables = IndexTables(self) + # reset tables to undo the augmentation + # self.tables._reset(device=self.device) + self.tables.set_bs(batch_size[0]) + + # Init index record tensor + time_idx = torch.zeros(size=(*batch_size,), dtype=torch.long, device=device) + sub_time_idx = torch.zeros(size=(*batch_size,), dtype=torch.long, device=device) + + # Scheduling status information + schedule = torch.full( + size=(*batch_size, self.num_machine_total, self.num_job + 1), + dtype=torch.long, + device=device, + fill_value=-999999, + ) + machine_wait_step = torch.zeros( + size=(*batch_size, self.num_machine_total), + dtype=torch.long, + device=device, + ) + job_location = torch.zeros( + size=(*batch_size, self.num_job + 1), + dtype=torch.long, + device=device, + ) + job_wait_step = torch.zeros( + size=(*batch_size, self.num_job + 1), + dtype=torch.long, + device=device, + ) + job_duration = torch.empty( + size=(*batch_size, self.num_job + 1, self.num_machine * self.num_stage), + dtype=torch.long, + device=device, + ) + job_duration[..., : self.num_job, :] = td["run_time"] + job_duration[..., self.num_job, :] = 0 + + # Finish status information + reward = torch.full( + size=(*batch_size,), + dtype=torch.float32, + device=device, + fill_value=float("-inf"), + ) + done = torch.full( + size=(*batch_size,), + dtype=torch.bool, + device=device, + fill_value=False, + ) + + action_mask = torch.ones( + size=(*batch_size, self.num_job + 1), dtype=bool, device=device + ) + action_mask[..., -1] = 0 + + batch_idx = torch.arange(*batch_size, dtype=torch.long, device=td.device) + stage_idx = self.tables.get_stage_index(sub_time_idx) + machine_idx = self.tables.get_machine_index(batch_idx, sub_time_idx) + stage_machine_idx = self.tables.get_stage_machine_index(batch_idx, sub_time_idx) + + return TensorDict( + { + # Index information + "stage_idx": stage_idx, + "time_idx": time_idx, + "sub_time_idx": sub_time_idx, + "machine_idx": machine_idx, + "stage_machine_idx": stage_machine_idx, + # Scheduling status information + "schedule": schedule, + "machine_wait_step": machine_wait_step, + "job_location": job_location, + "job_wait_step": job_wait_step, + "job_duration": job_duration, + # Finish status information + "reward": reward, + "done": done, + "action_mask": action_mask, + }, + batch_size=batch_size, + ) + + def _make_spec(self, generator: FFSPGenerator): + self.observation_spec = CompositeSpec( + time_idx=UnboundedDiscreteTensorSpec( + shape=(1,), + dtype=torch.int64, + ), + sub_time_idx=UnboundedDiscreteTensorSpec( + shape=(1,), + dtype=torch.int64, + ), + batch_idx=UnboundedDiscreteTensorSpec( + shape=(1,), + dtype=torch.int64, + ), + machine_idx=UnboundedDiscreteTensorSpec( + shape=(1,), + dtype=torch.int64, + ), + schedule=UnboundedDiscreteTensorSpec( + shape=(generator.num_machine_total, generator.num_job + 1), + dtype=torch.int64, + ), + machine_wait_step=UnboundedDiscreteTensorSpec( + shape=(generator.num_machine_total), + dtype=torch.int64, + ), + job_location=UnboundedDiscreteTensorSpec( + shape=(generator.num_job + 1), + dtype=torch.int64, + ), + job_wait_step=UnboundedDiscreteTensorSpec( + shape=(generator.num_job + 1), + dtype=torch.int64, + ), + job_duration=UnboundedDiscreteTensorSpec( + shape=( + generator.num_job + 1, + generator.num_machine * generator.num_stage, + ), + dtype=torch.int64, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=0, + high=generator.num_machine_total, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + def _get_reward(self, td, actions) -> TensorDict: + return td["reward"] + + +class IndexTables: + def __init__(self, env: FFSPEnv): + self.stage_table = torch.arange( + env.num_stage, dtype=torch.long, device=env.device + ).repeat_interleave(env.num_machine) + + # determine the increment of machine ids between stages, i.e. [0,4,8] + # for instances with 4 machines and three stages + start_sub_ids = torch.tensor( + list(range(0, env.num_machine * env.num_stage, env.num_machine)), + dtype=torch.long, + device=env.device, + ).repeat_interleave(env.num_machine) + # generate all possible permutations of the machine ids and add the stage increment to it + # (num_permutations, total_machines) + permutations = torch.tensor( + list(itertools.permutations(list(range(env.num_machine)))), + dtype=torch.long, + device=env.device, + ).repeat(1, env.num_stage) + self.machine_table = permutations + start_sub_ids[None] + + if env.flatten_stages: + # when flatting stages, every machine in each stage is treated as a distinct entity (no shared embeddings) + # Therefore, all machine need a unique index which is the same as the machine table + self.stage_machine_table = self.machine_table + else: + # when we do not flatten the stages, machines of different stages with the same subtime index + # share an embedding. In this case, they need the same index (i.e. leave out the stage increment) + self.stage_machine_table = permutations + + def set_bs(self, bs): + self.bs = bs + + def get_stage_index(self, sub_time_idx): + return self.stage_table[sub_time_idx] + + def get_machine_index(self, idx, sub_time_idx): + pomo_idx = idx // self.bs + + return self.machine_table[pomo_idx, sub_time_idx] + + def get_stage_machine_index(self, idx, sub_time_idx): + pomo_idx = idx // self.bs + return self.stage_machine_table[pomo_idx, sub_time_idx] diff --git a/rl4co/envs/scheduling/ffsp/generator.py b/rl4co/envs/scheduling/ffsp/generator.py new file mode 100644 index 00000000..6b33b8b1 --- /dev/null +++ b/rl4co/envs/scheduling/ffsp/generator.py @@ -0,0 +1,65 @@ +import torch + +from tensordict.tensordict import TensorDict + +from rl4co.envs.common.utils import Generator +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class FFSPGenerator(Generator): + """Data generator for the Flow Shop Scheduling Problem (FFSP). + + Args: + num_stage: number of stages + num_machine: number of machines + num_job: number of jobs + min_time: minimum running time of each job on each machine + max_time: maximum running time of each job on each machine + flatten_stages: whether to flatten the stages + + Returns: + A TensorDict with the following key: + run_time [batch_size, num_job, num_machine, num_stage]: running time of each job on each machine + + Note: + - [IMPORTANT] This version of ffsp requires the number of machines in each stage to be the same + """ + + def __init__( + self, + num_stage: int = 2, + num_machine: int = 3, + num_job: int = 4, + min_time: int = 2, + max_time: int = 10, + flatten_stages: bool = True, + **unused_kwargs, + ): + self.num_stage = num_stage + self.num_machine = num_machine + self.num_machine_total = num_machine * num_stage + self.num_job = num_job + self.min_time = min_time + self.max_time = max_time + self.flatten_stages = flatten_stages + + # FFSP environment doen't have any other kwargs + if len(unused_kwargs) > 0: + log.error(f"Found {len(unused_kwargs)} unused kwargs: {unused_kwargs}") + + def _generate(self, batch_size) -> TensorDict: + # Init observation: running time of each job on each machine + run_time = torch.randint( + low=self.min_time, + high=self.max_time, + size=(*batch_size, self.num_job, self.num_machine_total), + ) + + return TensorDict( + { + "run_time": run_time, + }, + batch_size=batch_size, + ) diff --git a/rl4co/envs/scheduling/ffsp/render.py b/rl4co/envs/scheduling/ffsp/render.py new file mode 100644 index 00000000..992f3ad4 --- /dev/null +++ b/rl4co/envs/scheduling/ffsp/render.py @@ -0,0 +1,72 @@ +import torch +import numpy as np +import matplotlib.pyplot as plt + +from matplotlib import cm, colormaps +from tensordict.tensordict import TensorDict + +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def render(td: TensorDict, idx: int): + import matplotlib.patches as patches + import matplotlib.pyplot as plt + + # TODO: fix this render function parameters + num_machine_total = td["num_machine_total"][idx].item() + num_job = td["num_job"][idx].item() + + job_durations = td["job_duration"][idx, :, :] + # shape: (job, machine) + schedule = td["schedule"][idx, :, :] + # shape: (machine, job) + + total_machine_cnt = num_machine_total + makespan = -td["reward"][idx].item() + + # Create figure and axes + fig, ax = plt.subplots(figsize=(makespan / 3, 5)) + cmap = _get_cmap(num_job) + + plt.xlim(0, makespan) + plt.ylim(0, total_machine_cnt) + ax.invert_yaxis() + + plt.plot([0, makespan], [4, 4], "black") + plt.plot([0, makespan], [8, 8], "black") + + for machine_idx in range(total_machine_cnt): + duration = job_durations[:, machine_idx] + # shape: (job) + machine_schedule = schedule[machine_idx, :] + # shape: (job) + + for job_idx in range(num_job): + job_length = duration[job_idx].item() + job_start_time = machine_schedule[job_idx].item() + if job_start_time >= 0: + # Create a Rectangle patch + rect = patches.Rectangle( + (job_start_time, machine_idx), + job_length, + 1, + facecolor=cmap(job_idx), + ) + ax.add_patch(rect) + + ax.grid() + ax.set_axisbelow(True) + plt.show() + +def _get_cmap(color_cnt): + from random import shuffle + + from matplotlib.colors import CSS4_COLORS, ListedColormap + + color_list = list(CSS4_COLORS.keys()) + shuffle(color_list) + cmap = ListedColormap(color_list, N=color_cnt) + return cmap diff --git a/rl4co/envs/scheduling/fjsp/__init__.py b/rl4co/envs/scheduling/fjsp/__init__.py new file mode 100644 index 00000000..4eb6d9df --- /dev/null +++ b/rl4co/envs/scheduling/fjsp/__init__.py @@ -0,0 +1,2 @@ +NO_OP_ID = -1 +INIT_FINISH = 9999.0 diff --git a/rl4co/envs/scheduling/fjsp/env.py b/rl4co/envs/scheduling/fjsp/env.py new file mode 100644 index 00000000..dcf62608 --- /dev/null +++ b/rl4co/envs/scheduling/fjsp/env.py @@ -0,0 +1,508 @@ +import torch + +from einops import rearrange, reduce +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.envs.common.base import RL4COEnvBase as EnvBase +from rl4co.utils.ops import gather_by_index, sample_n_random_actions + +from . import INIT_FINISH, NO_OP_ID +from .generator import FJSPFileGenerator, FJSPGenerator +from .render import render +from .utils import calc_lower_bound, get_job_ops_mapping, op_is_ready + + +class FJSPEnv(EnvBase): + """Flexible Job-Shop Scheduling Problem (FJSP) environment + At each step, the agent chooses a job-machine combination. The operation to be processed next for the selected job is + then executed on the selected machine. The reward is 0 unless the agent scheduled all operations of all jobs. + In that case, the reward is (-)makespan of the schedule: maximizing the reward is equivalent to minimizing the makespan. + + Observations: + - time: current time + - next_op: next operation per job + - proc_times: processing time of operation-machine pairs + - pad_mask: specifies padded operations + - start_op_per_job: id of first operation per job + - end_op_per_job: id of last operation per job + - start_times: start time of operation (defaults to 0 if not scheduled) + - finish_times: finish time of operation (defaults to INIT_FINISH if not scheduled) + - job_ops_adj: adjacency matrix specifying job-operation affiliation + - ops_job_map: same as above but using ids of jobs to indicate affiliation + - ops_sequence_order: specifies the order in which operations have to be processed + - ma_assignment: specifies which operation has been scheduled on which machine + - busy_until: specifies until when the machine will be busy + - num_eligible: number of machines that can process an operation + - job_in_process: whether job is currently being processed + - job_done: whether the job is done + + Constrains: + the agent may not select: + - machines that are currently busy + - jobs that are done already + - jobs that are currently processed + - job-machine combinations, where the machine cannot process the next operation of the job + + Finish condition: + - the agent has scheduled all operations of all jobs + + Reward: + - the negative makespan of the final schedule + + Args: + generator: FJSPGenerator instance as the data generator + generator_params: parameters for the generator + mask_no_ops: if True, agent may not select waiting operation (unless instance is done) + """ + + name = "fjsp" + + def __init__( + self, + generator: FJSPGenerator = None, + generator_params: dict = {}, + mask_no_ops: bool = True, + check_mask: bool = False, + stepwise_reward: bool = False, + **kwargs, + ): + super().__init__(check_solution=False, **kwargs) + if generator is None: + if generator_params.get("file_path", None) is not None: + generator = FJSPFileGenerator(**generator_params) + else: + generator = FJSPGenerator(**generator_params) + self.generator = generator + self._num_mas = generator.num_mas + self._num_jobs = generator.num_jobs + self._n_ops_max = generator.max_ops_per_job * self.num_jobs + + self.mask_no_ops = mask_no_ops + self.check_mask = check_mask + self.stepwise_reward = stepwise_reward + self._make_spec(self.generator) + + @property + def num_mas(self): + return self._num_mas + + @property + def num_jobs(self): + return self._num_jobs + + @property + def n_ops_max(self): + return self._n_ops_max + + def set_instance_params(self, td): + self._num_jobs = td["start_op_per_job"].size(1) + self._num_mas = td["proc_times"].size(1) + self._n_ops_max = td["proc_times"].size(2) + + def _decode_graph_structure(self, td: TensorDict): + batch_size = td.batch_size + start_op_per_job = td["start_op_per_job"] + end_op_per_job = td["end_op_per_job"] + pad_mask = td["pad_mask"] + n_ops_max = td["pad_mask"].size(-1) + + # here we will generate the operations-job mapping: + ops_job_map, ops_job_bin_map = get_job_ops_mapping( + start_op_per_job, end_op_per_job, n_ops_max + ) + + # mask invalid edges (caused by padding) + ops_job_bin_map[pad_mask.unsqueeze(1).expand_as(ops_job_bin_map)] = 0 + + # generate for each batch a sequence specifying the position of all operations in their respective jobs, + # e.g. [0,1,0,0,1,2,0,1,2,3,0,0] for jops with n_ops=[2,1,3,4,1,1] + # (bs, max_ops) + ops_seq_order = torch.sum( + ops_job_bin_map * (ops_job_bin_map.cumsum(2) - 1), dim=1 + ) + + # predecessor and successor adjacency matrices + pred = torch.diag_embed(torch.ones(n_ops_max - 1), offset=-1)[None].expand( + *batch_size, -1, -1 + ) + # the start of the sequence (of each job) does not have a predecessor, therefore we can + # mask all first ops of a job in the predecessor matrix + pred = pred * ops_seq_order.gt(0).unsqueeze(-1).expand_as(pred).to(pred) + succ = torch.diag_embed(torch.ones(n_ops_max - 1), offset=1)[None].expand( + *batch_size, -1, -1 + ) + # apply the same logic as above to mask the last op of a job, which does not have a successor. The last job of a job + # always comes before the 1st op of the next job, therefore performing a left shift of the ops seq tensor here + succ = succ * torch.cat( + (ops_seq_order[:, 1:], ops_seq_order.new_full((*batch_size, 1), 0)), dim=1 + ).gt(0).to(succ).unsqueeze(-1).expand_as(succ) + + # adjacency matrix = predecessors, successors and self loops + # (bs, max_ops, max_ops, 2) + ops_adj = torch.stack((pred, succ), dim=3) + + td = td.update( + { + "ops_adj": ops_adj, + "job_ops_adj": ops_job_bin_map, + "ops_job_map": ops_job_map, + # "op_spatial_enc": ops_spatial_enc, + "ops_sequence_order": ops_seq_order, + } + ) + + return td, n_ops_max + + def _reset(self, td: TensorDict = None, batch_size=None) -> TensorDict: + self.set_instance_params(td) + + td_reset = td.clone() + + td_reset, n_ops_max = self._decode_graph_structure(td_reset) + + # schedule + start_op_per_job = td_reset["start_op_per_job"] + start_times = torch.zeros((*batch_size, n_ops_max)) + finish_times = torch.full((*batch_size, n_ops_max), INIT_FINISH) + ma_assignment = torch.zeros((*batch_size, self.num_mas, n_ops_max)) + + # reset feature space + busy_until = torch.zeros((*batch_size, self.num_mas)) + # (bs, ma, ops) + ops_ma_adj = (td_reset["proc_times"] > 0).to(torch.float32) + # (bs, ops) + num_eligible = torch.sum(ops_ma_adj, dim=1) + + td_reset = td_reset.update( + { + "start_times": start_times, + "finish_times": finish_times, + "ma_assignment": ma_assignment, + "busy_until": busy_until, + "num_eligible": num_eligible, + "next_op": start_op_per_job.clone().to(torch.int64), + "ops_ma_adj": ops_ma_adj, + "op_scheduled": torch.full((*batch_size, n_ops_max), False), + "job_in_process": torch.full((*batch_size, self.num_jobs), False), + "reward": torch.zeros((*batch_size,), dtype=torch.float32), + "time": torch.zeros((*batch_size,)), + "job_done": torch.full((*batch_size, self.num_jobs), False), + "done": torch.full((*batch_size, 1), False), + }, + ) + + td_reset.set("action_mask", self.get_action_mask(td_reset)) + # add additional features to tensordict + td_reset["lbs"] = calc_lower_bound(td_reset) + td_reset = self._get_features(td_reset) + + return td_reset + + def _get_job_machine_availability(self, td: TensorDict): + batch_size = td.size(0) + + # (bs, jobs, machines) + action_mask = torch.full((batch_size, self.num_jobs, self.num_mas), False).to( + td.device + ) + + # mask jobs that are done already + action_mask.add_(td["job_done"].unsqueeze(2)) + # as well as jobs that are currently processed + action_mask.add_(td["job_in_process"].unsqueeze(2)) + + # mask machines that are currently busy + action_mask.add_(td["busy_until"].gt(td["time"].unsqueeze(1)).unsqueeze(1)) + + # exclude job-machine combinations, where the machine cannot process the next op of the job + next_ops_proc_times = gather_by_index( + td["proc_times"], td["next_op"].unsqueeze(1), dim=2, squeeze=False + ).transpose(1, 2) + action_mask.add_(next_ops_proc_times == 0) + return action_mask + + def get_action_mask(self, td: TensorDict) -> torch.Tensor: + # 1 indicates machine or job is unavailable at current time step + action_mask = self._get_job_machine_availability(td) + if self.mask_no_ops: + # masking is only allowed if instance is finished + no_op_mask = td["done"] + else: + # if no job is currently processed and instance is not finished yet, waiting is not allowed + no_op_mask = ( + td["job_in_process"].any(1, keepdims=True) & (~td["done"]) + ) | td["done"] + # flatten action mask to correspond with logit shape + action_mask = rearrange(action_mask, "bs j m -> bs (j m)") + # NOTE: 1 means feasible action, 0 means infeasible action + mask = torch.cat((no_op_mask, ~action_mask), dim=1) + + return mask + + def _translate_action(self, td): + """This function translates an action into a machine, job tuple.""" + selected_job = td["action"] // self.num_mas + selected_op = td["next_op"].gather(1, selected_job[:, None]).squeeze(1) + selected_machine = td["action"] % self.num_mas + return selected_job, selected_op, selected_machine + + def _step(self, td: TensorDict): + # cloning required to avoid inplace operation which avoids gradient backtracking + td = td.clone() + td["action"].subtract_(1) + # (bs) + dones = td["done"].squeeze(1) + # specify which batch instances require which operation + no_op = td["action"].eq(NO_OP_ID) + no_op = no_op & ~dones + req_op = ~no_op & ~dones + + # transition to next time for no op instances + if no_op.any(): + td, dones = self._transit_to_next_time(no_op, td) + + # select only instances that perform a scheduling action + td_op = td.masked_select(req_op) + + td_op = self._make_step(td_op) + # update the tensordict + td[req_op] = td_op + + # action mask + td.set("action_mask", self.get_action_mask(td)) + + step_complete = self._check_step_complete(td, dones) + while step_complete.any(): + td, dones = self._transit_to_next_time(step_complete, td) + td.set("action_mask", self.get_action_mask(td)) + step_complete = self._check_step_complete(td, dones) + if self.check_mask: + assert reduce(td["action_mask"], "bs ... -> bs", "any").all() + + if self.stepwise_reward: + # if we require a stepwise reward, the change in the calculated lower bounds could serve as such + lbs = calc_lower_bound(td) + td["reward"] = -(lbs.max(1).values - td["lbs"].max(1).values) + td["lbs"] = lbs + else: + td["lbs"] = calc_lower_bound(td) + + # add additional features to tensordict + td = self._get_features(td) + + return td + + def _get_features(self, td): + # after we have transitioned to a next time step, we determine which operations are ready + td["is_ready"] = op_is_ready(td) + # td["lbs"] = calc_lower_bound(td) + + return td + + @staticmethod + def _check_step_complete(td, dones): + """check whether there a feasible actions left to be taken during the current + time step. If this is not the case (and the instance is not done), + we need to adance the timer of the repsective instance + """ + return ~reduce(td["action_mask"], "bs ... -> bs", "any") & ~dones + + def _make_step(self, td: TensorDict) -> TensorDict: + """ + Environment transition function + """ + + batch_idx = torch.arange(td.size(0)) + + # 3*(#req_op) + selected_job, selected_op, selected_machine = self._translate_action(td) + + # mark job as being processed + td["job_in_process"][batch_idx, selected_job] = 1 + + # mark op as schedules + td["op_scheduled"][batch_idx, selected_op] = True + + # update machine state + proc_time_of_action = td["proc_times"][batch_idx, selected_machine, selected_op] + # we may not select a machine that is busy + assert torch.all(td["busy_until"][batch_idx, selected_machine] <= td["time"]) + + # update schedule + td["start_times"][batch_idx, selected_op] = td["time"] + td["finish_times"][batch_idx, selected_op] = td["time"] + proc_time_of_action + td["ma_assignment"][batch_idx, selected_machine, selected_op] = 1 + # update the state of the selected machine + td["busy_until"][batch_idx, selected_machine] = td["time"] + proc_time_of_action + # update adjacency matrices (remove edges) + td["proc_times"] = td["proc_times"].scatter( + 2, + selected_op[:, None, None].expand(-1, self.num_mas, 1), + torch.zeros_like(td["proc_times"]), + ) + td["ops_ma_adj"] = td["proc_times"].contiguous().gt(0).to(torch.float32) + td["num_eligible"] = torch.sum(td["ops_ma_adj"], dim=1) + # update the positions of an operation in the job (subtract 1 from each operation of the selected job) + td["ops_sequence_order"] = ( + td["ops_sequence_order"] - gather_by_index(td["job_ops_adj"], selected_job, 1) + ).clip(0) + # some checks + # assert torch.allclose( + # td["proc_times"].sum(1).gt(0).sum(1), # num ops with eligible machine + # (~(td["op_scheduled"] + td["pad_mask"])).sum(1), # num unscheduled ops + # ) + + return td + + def _transit_to_next_time(self, step_complete, td: TensorDict) -> TensorDict: + """ + Transit to the next time + """ + + # we need a transition to a next time step if either + # 1.) all machines are busy + # 2.) all operations are already currently in process (can only happen if num_jobs < num_machines) + # 3.) idle machines can not process any of the not yet scheduled operations + # 4.) no_op is choosen + available_time_ma = td["busy_until"] + end_op_per_job = td["end_op_per_job"] + # we want to transition to the next time step where a machine becomes idle again. This time step must be + # in the future, therefore we mask all machine idle times lying in the past / present + available_time = ( + torch.where( + available_time_ma > td["time"][:, None], available_time_ma, torch.inf + ) + .min(1) + .values + ) + + assert not torch.any(available_time[step_complete].isinf()) + td["time"] = torch.where(step_complete, available_time, td["time"]) + + # this may only be set when the operation is finished, not when it is scheduled + # operation of job is finished, set next operation and flag job as being idle + curr_ops_end = td["finish_times"].gather(1, td["next_op"]) + op_finished = td["job_in_process"] & (curr_ops_end <= td["time"][:, None]) + # check whether a job is finished, which is the case when the last operation of the job is finished + job_finished = op_finished & (td["next_op"] == end_op_per_job) + # determine the next operation for a job that is not done, but whose latest operation is finished + td["next_op"] = torch.where( + op_finished & ~job_finished, + td["next_op"] + 1, + td["next_op"], + ) + td["job_in_process"][op_finished] = False + + td["job_done"] = td["job_done"] + job_finished + td["done"] = td["job_done"].all(1, keepdim=True) + + return td, td["done"].squeeze(1) + + def _get_reward(self, td, actions=None) -> TensorDict: + if self.stepwise_reward and actions is None: + return td["reward"] + else: + assert td[ + "done" + ].all(), "Set stepwise_reward to True if you want reward prior to completion" + return ( + -td["finish_times"].masked_fill(td["pad_mask"], -torch.inf).max(1).values + ) + + def _make_spec(self, generator: FJSPGenerator): + self.observation_spec = CompositeSpec( + time=UnboundedDiscreteTensorSpec( + shape=(1,), + dtype=torch.int64, + ), + next_op=UnboundedDiscreteTensorSpec( + shape=(self.num_jobs,), + dtype=torch.int64, + ), + proc_times=UnboundedDiscreteTensorSpec( + shape=(self.num_mas, self.n_ops_max), + dtype=torch.float32, + ), + pad_mask=UnboundedDiscreteTensorSpec( + shape=(self.num_mas, self.n_ops_max), + dtype=torch.bool, + ), + start_op_per_job=UnboundedDiscreteTensorSpec( + shape=(self.num_jobs,), + dtype=torch.bool, + ), + end_op_per_job=UnboundedDiscreteTensorSpec( + shape=(self.num_jobs,), + dtype=torch.bool, + ), + start_times=UnboundedDiscreteTensorSpec( + shape=(self.n_ops_max,), + dtype=torch.int64, + ), + finish_times=UnboundedDiscreteTensorSpec( + shape=(self.n_ops_max,), + dtype=torch.int64, + ), + job_ops_adj=UnboundedDiscreteTensorSpec( + shape=(self.num_jobs, self.n_ops_max), + dtype=torch.int64, + ), + ops_job_map=UnboundedDiscreteTensorSpec( + shape=(self.n_ops_max), + dtype=torch.int64, + ), + ops_sequence_order=UnboundedDiscreteTensorSpec( + shape=(self.n_ops_max), + dtype=torch.int64, + ), + ma_assignment=UnboundedDiscreteTensorSpec( + shape=(self.num_mas, self.n_ops_max), + dtype=torch.int64, + ), + busy_until=UnboundedDiscreteTensorSpec( + shape=(self.num_mas,), + dtype=torch.int64, + ), + num_eligible=UnboundedDiscreteTensorSpec( + shape=(self.n_ops_max,), + dtype=torch.int64, + ), + job_in_process=UnboundedDiscreteTensorSpec( + shape=(self.num_jobs,), + dtype=torch.bool, + ), + job_done=UnboundedDiscreteTensorSpec( + shape=(self.num_jobs,), + dtype=torch.bool, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=-1, + high=self.n_ops_max, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + @staticmethod + def render(td, idx): + return render(td, idx) + + def select_start_nodes(self, td: TensorDict, num_starts: int): + return sample_n_random_actions(td, num_starts) + + def get_num_starts(self, td): + # NOTE in the paper they use N_s = 100 + return 100 + + def load_data(self, fpath, batch_size=[]): + g = FJSPFileGenerator(fpath) + return g(batch_size=batch_size) diff --git a/rl4co/envs/scheduling/fjsp/generator.py b/rl4co/envs/scheduling/fjsp/generator.py new file mode 100644 index 00000000..8d2f427f --- /dev/null +++ b/rl4co/envs/scheduling/fjsp/generator.py @@ -0,0 +1,238 @@ +from functools import partial +from typing import List + +import numpy as np +import torch + +from tensordict.tensordict import TensorDict + +from rl4co.envs.common.utils import Generator +from rl4co.utils.pylogger import get_pylogger + +from .parser import get_max_ops_from_files, read + +log = get_pylogger(__name__) + + +class FJSPGenerator(Generator): + """Data generator for the Flexible Job-Shop Scheduling Problem (FJSP). + + Args: + num_stage: number of stages + num_machine: number of machines + num_job: number of jobs + min_time: minimum running time of each job on each machine + max_time: maximum running time of each job on each machine + flatten_stages: whether to flatten the stages + + Returns: + A TensorDict with the following key: + start_op_per_job [batch_size, num_jobs]: first operation of each job + end_op_per_job [batch_size, num_jobs]: last operation of each job + proc_times [batch_size, num_machines, total_n_ops]: processing time of ops on machines + pad_mask [batch_size, total_n_ops]: not all instances have the same number of ops, so padding is used + + """ + + def __init__( + self, + num_jobs: int = 10, + num_machines: int = 5, + min_ops_per_job: int = 4, + max_ops_per_job: int = 6, + min_processing_time: int = 1, + max_processing_time: int = 20, + min_eligible_ma_per_op: int = 1, + max_eligible_ma_per_op: int = None, + same_mean_per_op: bool = True, + **unused_kwargs, + ): + self.num_jobs = num_jobs + self.num_mas = num_machines + self.min_ops_per_job = min_ops_per_job + self.max_ops_per_job = max_ops_per_job + self.min_processing_time = min_processing_time + self.max_processing_time = max_processing_time + self.min_eligible_ma_per_op = min_eligible_ma_per_op + self.max_eligible_ma_per_op = max_eligible_ma_per_op or num_machines + # determines whether to use a fixed number of total operations or let it vary between instances + # NOTE: due to the way rl4co builds datasets, we need a fixed size here + self.n_ops_max = max_ops_per_job * num_jobs + self.same_mean_per_op = same_mean_per_op + # FFSP environment doen't have any other kwargs + if len(unused_kwargs) > 0: + log.error(f"Found {len(unused_kwargs)} unused kwargs: {unused_kwargs}") + + def _simulate_processing_times( + self, n_eligible_per_ops: torch.Tensor + ) -> torch.Tensor: + bs, n_ops_max = n_eligible_per_ops.shape + + # (bs, max_ops, machines) + ma_seq_per_ops = torch.arange(1, self.num_mas + 1)[None, None].expand( + bs, n_ops_max, self.num_mas + ) + # generate a matrix of size (ops, mas) per batch, each row having as many ones as the operation eligible machines + # E.g. n_eligible_per_ops=[1,3,2]; num_mas=4 + # [[1,0,0,0], + # 1,1,1,0], + # 1,1,0,0]] + # This will be shuffled randomly to generate a machine-operation mapping + ma_ops_edges_unshuffled = torch.Tensor.float( + ma_seq_per_ops <= n_eligible_per_ops[..., None] + ) + # random shuffling + idx = torch.rand_like(ma_ops_edges_unshuffled).argsort() + ma_ops_edges = ma_ops_edges_unshuffled.gather(2, idx).transpose(1, 2) + + # (bs, max_ops, machines) + if self.same_mean_per_op: + proc_times = torch.ones((bs, self.num_mas, n_ops_max)) + proc_time_means = torch.randint( + self.min_processing_time, self.max_processing_time, (bs, n_ops_max) + ) + low_bounds = torch.maximum( + torch.full_like(proc_times, self.min_processing_time), + (proc_time_means * (1 - 0.2)).round().unsqueeze(1), + ) + high_bounds = ( + torch.minimum( + torch.full_like(proc_times, self.max_processing_time), + (proc_time_means * (1 + 0.2)).round().unsqueeze(1), + ) + + 1 + ) + proc_times = ( + torch.randint(2**63 - 1, size=proc_times.shape) + % (high_bounds - low_bounds) + + low_bounds + ) + else: + proc_times = torch.randint( + self.min_processing_time, + self.max_processing_time + 1, + size=(bs, self.num_mas, n_ops_max), + ) + + # remove proc_times for which there is no corresponding ma-ops connection + proc_times = proc_times * ma_ops_edges + return proc_times + + def _generate(self, batch_size) -> TensorDict: + # simulate how many operations each job has + n_ope_per_job = torch.randint( + self.min_ops_per_job, + self.max_ops_per_job + 1, + size=(*batch_size, self.num_jobs), + ) + + # determine the total number of operations per batch instance (which may differ) + n_ops_batch = n_ope_per_job.sum(1) # (bs) + # determine the maximum total number of operations over all batch instances + n_ops_max = self.n_ops_max or n_ops_batch.max() + + # generate a mask, specifying which operations are padded + pad_mask = torch.arange(n_ops_max).unsqueeze(0).expand(*batch_size, -1) + pad_mask = pad_mask.ge(n_ops_batch[:, None].expand_as(pad_mask)) + + # determine the id of the end operation for each job + end_op_per_job = n_ope_per_job.cumsum(1) - 1 + + # determine the id of the starting operation for each job + # (bs, num_jobs) + start_op_per_job = torch.cat( + ( + torch.zeros((*batch_size, 1)).to(end_op_per_job), + end_op_per_job[:, :-1] + 1, + ), + dim=1, + ) + + # here we simulate the eligible machines per operation and the processing times + n_eligible_per_ops = torch.randint( + self.min_eligible_ma_per_op, + self.max_eligible_ma_per_op + 1, + (*batch_size, n_ops_max), + ) + n_eligible_per_ops[pad_mask] = 0 + + # simulate processing times for machine-operation pairs + # (bs, num_mas, n_ops_max) + proc_times = self._simulate_processing_times(n_eligible_per_ops) + + td = TensorDict( + { + "start_op_per_job": start_op_per_job, + "end_op_per_job": end_op_per_job, + "proc_times": proc_times, + "pad_mask": pad_mask, + }, + batch_size=batch_size, + ) + + return td + + +class FJSPFileGenerator(Generator): + """Data generator for the Flexible Job-Shop Scheduling Problem (FJSP) using instance files + + Args: + path: path to files + + Returns: + A TensorDict with the following key: + start_op_per_job [batch_size, num_jobs]: first operation of each job + end_op_per_job [batch_size, num_jobs]: last operation of each job + proc_times [batch_size, num_machines, total_n_ops]: processing time of ops on machines + pad_mask [batch_size, total_n_ops]: not all instances have the same number of ops, so padding is used + + """ + + def __init__(self, file_path: str, n_ops_max: int = None, **unused_kwargs): + self.files = self.list_files(file_path) + self.num_samples = len(self.files) + + if len(unused_kwargs) > 0: + log.error(f"Found {len(unused_kwargs)} unused kwargs: {unused_kwargs}") + + if len(self.files) > 1: + n_ops_max = get_max_ops_from_files(self.files) + + ret = map(partial(read, max_ops=n_ops_max), self.files) + + td_list, num_jobs, num_machines, max_ops_per_job = list(zip(*list(ret))) + num_jobs, num_machines = map(lambda x: x[0], (num_jobs, num_machines)) + max_ops_per_job = max(max_ops_per_job) + + self.td = torch.cat(td_list, dim=0) + self.num_mas = num_machines + self.num_jobs = num_jobs + self.max_ops_per_job = max_ops_per_job + self.n_ops_max = max_ops_per_job * num_jobs + + self.start_idx = 0 + + def _generate(self, batch_size: List[int]) -> TensorDict: + batch_size = np.prod(batch_size) + if batch_size > self.num_samples: + log.warning( + f"Only found {self.num_samples} instance files, but specified dataset size is {batch_size}" + ) + end_idx = self.start_idx + batch_size + td = self.td[self.start_idx : end_idx] + self.start_idx += batch_size + if self.start_idx >= self.num_samples: + self.start_idx = 0 + return td + + @staticmethod + def list_files(path): + import os + + files = [ + os.path.join(path, f) + for f in os.listdir(path) + if os.path.isfile(os.path.join(path, f)) + ] + assert len(files) > 0 + return files diff --git a/rl4co/envs/scheduling/fjsp/parser.py b/rl4co/envs/scheduling/fjsp/parser.py new file mode 100644 index 00000000..f05c8fca --- /dev/null +++ b/rl4co/envs/scheduling/fjsp/parser.py @@ -0,0 +1,180 @@ +import os + +from functools import partial +from pathlib import Path +from typing import List, Tuple, Union + +import torch + +from tensordict import TensorDict + +ProcessingData = List[Tuple[int, int]] + + +def list_files(path): + import os + + files = [ + os.path.join(path, f) + for f in os.listdir(path) + if os.path.isfile(os.path.join(path, f)) + ] + return files + + +def parse_job_line(line: Tuple[int]) -> Tuple[ProcessingData]: + """ + Parses a FJSPLIB job data line of the following form: + + * ( * ( )) + + In words, the first value is the number of operations. Then, for each + operation, the first number represents the number of machines that can + process the operation, followed by, the machine index and processing time + for each eligible machine. + + Note that the machine indices start from 1, so we subtract 1 to make them + zero-based. + """ + num_operations = line[0] + operations = [] + idx = 1 + + for _ in range(num_operations): + num_pairs = int(line[idx]) * 2 + machines = line[idx + 1 : idx + 1 + num_pairs : 2] + durations = line[idx + 2 : idx + 2 + num_pairs : 2] + operations.append([(m, d) for m, d in zip(machines, durations)]) + + idx += 1 + num_pairs + + return operations + + +def get_n_ops_of_instance(file): + lines = file2lines(file) + jobs = [parse_job_line(line) for line in lines[1:]] + n_ope_per_job = torch.Tensor([len(x) for x in jobs]).unsqueeze(0) + total_ops = int(n_ope_per_job.sum()) + return total_ops + + +def get_max_ops_from_files(files): + return max(map(get_n_ops_of_instance, files)) + + +def read(loc: Path, max_ops=None): + """ + Reads an FJSPLIB instance. + + Args: + loc: location of instance file + max_ops: optionally specify the maximum number of total operations (will be filled by padding) + + Returns: + instance: the parsed instance + """ + lines = file2lines(loc) + + # First line contains metadata. + num_jobs, num_machines = lines[0][0], lines[0][1] + + # The remaining lines contain the job-operation data, where each line + # represents a job and its operations. + jobs = [parse_job_line(line) for line in lines[1:]] + n_ope_per_job = torch.Tensor([len(x) for x in jobs]).unsqueeze(0) + total_ops = int(n_ope_per_job.sum()) + if max_ops is not None: + assert total_ops <= max_ops, "got more operations then specified through max_ops" + max_ops = max_ops or total_ops + max_ops_per_job = int(n_ope_per_job.max()) + + end_op_per_job = n_ope_per_job.cumsum(1) - 1 + start_op_per_job = torch.cat((torch.zeros((1, 1)), end_op_per_job[:, :-1] + 1), dim=1) + + pad_mask = torch.arange(max_ops) + pad_mask = pad_mask.ge(total_ops).unsqueeze(0) + + proc_times = torch.zeros((num_machines, max_ops)) + op_cnt = 0 + for job in jobs: + for op in job: + for ma, dur in op: + # subtract one to let indices start from zero + proc_times[ma - 1, op_cnt] = dur + op_cnt += 1 + proc_times = proc_times.unsqueeze(0) + + td = TensorDict( + { + "start_op_per_job": start_op_per_job, + "end_op_per_job": end_op_per_job, + "proc_times": proc_times, + "pad_mask": pad_mask, + }, + batch_size=[1], + ) + + return td, num_jobs, num_machines, max_ops_per_job + + +def file2lines(loc: Union[Path, str]) -> List[List[int]]: + with open(loc, "r") as fh: + lines = [line for line in fh.readlines() if line.strip()] + + def parse_num(word: str): + return int(word) if "." not in word else int(float(word)) + + return [[parse_num(x) for x in line.split()] for line in lines] + + +def write_one(args, where=None): + id, instance = args + assert ( + len(instance["proc_times"].shape) == 2 + ), "no batch dimension allowed in write operation" + lines = [] + + # The flexibility is the average number of eligible machines per operation. + num_eligible = (instance["proc_times"] > 0).sum() + n_ops = (~instance["pad_mask"]).sum() + num_jobs = instance["next_op"].size(0) + num_machines = instance["proc_times"].size(0) + flexibility = round(int(num_eligible) / int(n_ops), 5) + + metadata = f"{num_jobs}\t{num_machines}\t{flexibility}" + lines.append(metadata) + + for i in range(num_jobs): + ops_of_job = instance["job_ops_adj"][i].nonzero().squeeze(1) + job = [len(ops_of_job)] # number of operations of the job + + for op in ops_of_job: + eligible_ma = instance["proc_times"][:, op].nonzero().squeeze(1) + job.append(eligible_ma.size(0)) # num_eligible + + for machine in eligible_ma: + duration = instance["proc_times"][machine, op] + assert duration > 0, "something is wrong" + # add one since in song instances ma indices start from one + job.extend([int(machine.item()) + 1, int(duration.item())]) + + line = " ".join(str(num) for num in job) + lines.append(line) + + formatted = "\n".join(lines) + + file_name = f"{str(id+1).rjust(4, '0')}_{num_jobs}j_{num_machines}m.txt" + full_path = os.path.join(where, file_name) + + with open(full_path, "w") as fh: + fh.write(formatted) + + return formatted + + +def write(where: Union[Path, str], instances: TensorDict): + if not os.path.exists(where): + os.makedirs(where) + + return list(map(partial(write_one, where=where), enumerate(iter(instances)))) diff --git a/rl4co/envs/scheduling/fjsp/render.py b/rl4co/envs/scheduling/fjsp/render.py new file mode 100644 index 00000000..bfb86bf4 --- /dev/null +++ b/rl4co/envs/scheduling/fjsp/render.py @@ -0,0 +1,72 @@ +from collections import defaultdict + +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.colors import ListedColormap +from tensordict.tensordict import TensorDict + +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def render(td: TensorDict, idx: int): + inst = td[idx] + num_jobs = inst["job_ops_adj"].size(0) + + # Define a colormap with a color for each job + colors = plt.cm.tab10(np.linspace(0, 1, num_jobs)) + cmap = ListedColormap(colors) + + assign = inst["ma_assignment"].nonzero() + + schedule = defaultdict(list) + + for val in assign: + machine = val[0].item() + op = val[1].item() + # get start and end times of operation + start = inst["start_times"][val[1]] + end = inst["finish_times"][val[1]] + # write information to schedule dictionary + schedule[machine].append((op, start, end)) + + _, ax = plt.subplots() + + # Plot horizontal bars for each task + for ma, ops in schedule.items(): + for op, start, end in ops: + job = inst["job_ops_adj"][:, op].nonzero().item() + ax.barh( + ma, + end - start, + left=start, + height=0.6, + color=cmap(job), + edgecolor="black", + linewidth=1, + ) + + ax.text( + start + (end - start) / 2, ma, op, ha="center", va="center", color="white" + ) + + # Set labels and title + ax.set_yticks(range(len(schedule))) + ax.set_yticklabels([f"Machine {i}" for i in range(len(schedule))]) + ax.set_xlabel("Time") + ax.set_title("Gantt Chart") + + # Add a legend for class labels + handles = [plt.Rectangle((0, 0), 1, 1, color=cmap(i)) for i in range(num_jobs)] + ax.legend( + handles, + [f"Job {label}" for label in range(num_jobs)], + loc="center left", + bbox_to_anchor=(1, 0.5), + ) + + plt.tight_layout() + # Show the Gantt chart + plt.show() diff --git a/rl4co/envs/scheduling/fjsp/utils.py b/rl4co/envs/scheduling/fjsp/utils.py new file mode 100644 index 00000000..f870e8b6 --- /dev/null +++ b/rl4co/envs/scheduling/fjsp/utils.py @@ -0,0 +1,334 @@ +import logging + +from typing import List, Tuple, Union + +import torch + +from tensordict import TensorDict +from torch import Size, Tensor + +from rl4co.envs.scheduling.fjsp import INIT_FINISH + +logger = logging.getLogger(__name__) + + +def get_op_features(td: TensorDict): + return torch.stack((td["lbs"], td["is_ready"], td["num_eligible"]), dim=-1) + + +def cat_and_norm_features( + td: TensorDict, feats: List[str], time_feats: List[str], norm_const: int +): + # logger.info(f"will scale the features {','.join(time_feats)} with a constant ({norm_const})") + feature_list = [] + for feat in feats: + if feat in time_feats: + feature_list.append(td[feat] / norm_const) + else: + feature_list.append(td[feat]) + + return torch.stack(feature_list, dim=-1).to(torch.float32) + + +def view( + tensor: Tensor, + idx: Tuple[Tensor], + pad_mask: Tensor, + new_shape: Union[Size, List[int]], + pad_value: Union[float, int], +): + # convert mask specifying which entries are padded into mask specifying which entries to keep + mask = ~pad_mask + new_view = tensor.new_full(size=new_shape, fill_value=pad_value) + new_view[idx] = tensor[mask] + return new_view + + +def _get_idx_for_job_op_view(td: TensorDict) -> tuple: + bs, _, n_total_ops = td["job_ops_adj"].shape + # (bs, ops) + batch_idx = torch.arange(bs, device=td.device).repeat_interleave(n_total_ops) + batch_idx = batch_idx.reshape(bs, -1) + # (bs, ops) + ops_job_map = td["ops_job_map"] + # (bs, ops) + ops_sequence_order = td["ops_sequence_order"] + # (bs*n_ops_max, 3) + idx = ( + torch.stack((batch_idx, ops_job_map, ops_sequence_order), dim=-1) + .to(torch.long) + .flatten(0, 1) + ) + # (bs, n_ops_max) + mask = ~td["pad_mask"] + # (total_ops_in_batch, 3) + idx = idx[mask.flatten(0, 1)] + b, j, o = map(lambda x: x.squeeze(1), idx.chunk(3, dim=-1)) + return b, j, o + + +def get_job_op_view( + td: TensorDict, keys: List[str] = [], pad_value: Union[float, int] = 0 +): + """This function reshapes all tensors of the tensordict from a flat operations-only view + to a nested job-operation view and creates a new tensordict from it. + :param _type_ td: tensordict + :return _type_: dict + """ + # ============= Prepare the new index ============= + bs, num_jobs, _ = td["job_ops_adj"].shape + max_ops_per_job = int(td["job_ops_adj"].sum(-1).max()) + idx = _get_idx_for_job_op_view(td) + new_shape = Size((bs, num_jobs, max_ops_per_job)) + pad_mask = td["pad_mask"] + # ============================================== + + # due to special structure, processing times are treated seperately + if "proc_times" in keys: + keys.remove("proc_times") + # reshape processing times; (bs, ma, ops) -> (bs, ma, jobs, ops_per_job) + new_proc_times_view = view( + td["proc_times"].permute(0, 2, 1), idx, pad_mask, new_shape, pad_value + ).permute(0, 3, 1, 2) + + # add padding mask if not in keys + if "pad_mask" not in keys: + keys.append("pad_mask") + + new_views = dict( + map(lambda key: (key, view(td[key], idx, pad_mask, new_shape)), keys) + ) + + # update tensordict clone with reshaped tensors + return {"proc_times": new_proc_times_view, **new_views} + + +def blockify(td, tensor: Tensor, pad_value: Union[float, int] = 0): + assert len(tensor.shape) in [ + 2, + 3, + ], "blockify only supports tensors of shape (bs, seq, (d)), where the feature dim d is optional" + # get the size of the blockified tensor + bs, _, *d = tensor.shape + num_jobs = td["job_ops_adj"].size(1) + max_ops_per_job = int(td["job_ops_adj"].sum(-1).max()) + new_shape = Size((bs, num_jobs, max_ops_per_job, *d)) + # get indices of valid entries of blockified tensor + idx = _get_idx_for_job_op_view(td) + pad_mask = td["pad_mask"] + # create the blockified view + new_view_tensor = view(tensor, idx, pad_mask, new_shape, pad_value) + return new_view_tensor + + +def unblockify( + td: TensorDict, tensor: Tensor, mask: Tensor = None, pad_value: Union[float, int] = 0 +): + assert len(tensor.shape) in [ + 3, + 4, + ], "blockify only supports tensors of shape (bs, nb, s, (d)), where the feature dim d is optional" + # get the size of the blockified tensor + bs, _, _, *d = tensor.shape + n_ops_per_batch = td["job_ops_adj"].sum((1, 2)).unsqueeze(1) # (bs) + seq_len = int(n_ops_per_batch.max()) + new_shape = Size((bs, seq_len, *d)) + + # create the mask to gather then entries of the blockified tensor. NOTE that only by + # blockifying the original pad_mask + pad_mask = td["pad_mask"] + pad_mask = blockify(td, pad_mask, True) + + # get indices of valid entrie in flat matrix + b = torch.arange(bs, device=td.device).repeat_interleave(seq_len).reshape(bs, seq_len) + i = torch.arange(seq_len, device=td.device)[None].repeat(bs, 1) + idx = tuple(map(lambda x: x[i < n_ops_per_batch], (b, i))) + # create view + new_tensor = view(tensor, idx, pad_mask, new_shape, pad_value=pad_value) + return new_tensor + + +def first_diff(x: Tensor, dim: int): + shape = x.shape + shape = (*shape[:dim], 1, *shape[dim + 1 :]) + seq_cutoff = x.index_select(dim, torch.arange(x.size(dim) - 1, device=x.device)) + first_diff_seq = x - torch.cat((seq_cutoff.new_zeros(*shape), seq_cutoff), dim=dim) + return first_diff_seq + + +def spatial_encoding(td: TensorDict): + """We use a spatial encoing as proposed in GraphFormer (https://arxiv.org/abs/2106.05234) + The spatial encoding in GraphFormer determines the distance of the shortest path between and + nodes i and j and uses a special value for node pairs that cannot be connected at all. + For any two operations i e=2) and for i>j the negative number of + operations that starting from j, have been completet before arriving at i (e.g. i=5 j=3 -> e=-2). + For i=j we set e=0 as well as for operations of different jobs. + + :param torch.Tensor[bs, n_ops] ops_job_map: tensor specifying the index of its corresponding job + :return torch.Tensor[bs, n_ops, n_ops]: length of shortest path between any two operations + """ + bs, _, n_total_ops = td["job_ops_adj"].shape + max_ops_per_job = int(td["job_ops_adj"].sum(-1).max()) + ops_job_map = td["ops_job_map"] + pad_mask = td["pad_mask"] + + same_job = (ops_job_map[:, None] == ops_job_map[..., None]).to(torch.int32) + # mask padded + same_job[pad_mask.unsqueeze(2).expand_as(same_job)] = 0 + same_job[pad_mask.unsqueeze(1).expand_as(same_job)] = 0 + # take upper triangular of same_job and set diagonal to zero for counting purposes + upper_tri = torch.triu(same_job) - torch.diag( + torch.ones(n_total_ops, device=td.device) + )[None].expand_as(same_job) + # cumsum and masking of operations that do not belong to the same job + num_jumps = upper_tri.cumsum(2) * upper_tri + # mirror the matrix + num_jumps = num_jumps + num_jumps.transpose(1, 2) + # NOTE: shifted this logic into the spatial encoding module + # num_jumps = num_jumps + (-num_jumps.transpose(1,2)) + assert not torch.any(num_jumps >= max_ops_per_job) + # special value for ops of different jobs and self-loops + num_jumps = torch.where(num_jumps == 0, -1, num_jumps) + self_mask = torch.eye(n_total_ops).repeat(bs, 1, 1).bool() + num_jumps[self_mask] = 0 + return num_jumps + + +def calc_lower_bound(td: TensorDict): + """Here we calculate the lower bound of the operations finish times. In the FJSP case, multiple things need to + be taken into account due to the usability of the different machines for multiple ops of different jobs: + + 1.) Operations may only start once their direct predecessor is finished. We calculate its lower bound by + adding the minimum possible operation time to this detected start time. However, we cannot use the proc_times + directly, but need to account for the fact, that machines might still be busy, once an operation can be processed. + We detect this offset by detecting ops-machine pairs, where the first possible start point of the operation is before + the machine becomes idle again - Therefore, we add this discrepancy to the proc_time of the respective ops-ma combination + + 2.) If an operation has been scheduled, we use its actual finishing time as lower bound. In this case, using the cumulative sum + of all peedecessors of a job does not make sense, since it is likely to differ from the real finishing time of its direct + predecessor (its only a lower bound). Therefore, we add the finish time to the cumulative sum of processing time of all + UNSCHEDULED operations, to obtain the lower bound. + Making this work is a bit hacky: We compute the first differences of finishing times of those operations scheduled and + add them to the matrix of processing times, where already processed operations are masked (with zero) + + + """ + + proc_times = td["proc_times"].clone() # (bs, ma, ops) + busy_until = td["busy_until"] # (bs, ma) + ops_adj = td["ops_adj"] # (bs, ops, ops, 2) + finish_times = td["finish_times"] # (bs, ops) + job_ops_adj = td["job_ops_adj"] # (bs, jobs, ops) + op_scheduled = td["op_scheduled"].to(torch.float32) # (bs, ops) + + ############## REGARDING POINT 1 OF DOCSTRING ############## + # for operations whose immidiate predecessor is scheduled, we can determine its earliest + # start time by the end time of the predecessor. + # (bs, num_ops, 1) + maybe_start_at = torch.bmm(ops_adj[..., 0], finish_times[..., None]).squeeze(2) + # using the start_time, we can determine if and how long an op needs to wait for a machine to finish + wait_for_ma_offset = torch.clip(busy_until[..., None] - maybe_start_at[:, None], 0) + # we add this required waiting time to the respective processing time + proc_time_plus_wait = torch.where( + proc_times == 0, proc_times, proc_times + wait_for_ma_offset + ) + # NOTE get the mean processing time over all eligible machines for lb calulation + # ops_proc_times = torch.where(proc_times == 0, torch.inf, proc_time_plus_wait).min(1).values) + ops_proc_times = proc_time_plus_wait.sum(1) / (proc_times.gt(0).sum(1) + 1e-9) + # mask proc times for already scheduled ops + ops_proc_times[op_scheduled.to(torch.bool)] = 0 + + ############### REGARDING POINT 2 OF DOCSTRING ################### + # Now we determine all operations that are not scheduled yet (and thus have no finish_time). We will compute the cumulative + # sum over the processing time to determine the lower bound of unscheduled operations... + proc_matrix = job_ops_adj + ops_assigned = proc_matrix * op_scheduled[:, None] + proc_matrix_not_scheduled = proc_matrix * ( + torch.ones_like(proc_matrix) - op_scheduled[:, None] + ) + + # ...and add the finish_time of the last scheduled operation of the respective job to that. To make this work, using the cumsum logic, + # we calc the first differences of the finish times and seperate by job. + # We use the first differences, so that the finish times do not add up during cumulative sum below + # (bs, num_jobs, num_ops) + finish_times_1st_diff = ops_assigned * first_diff( + ops_assigned * finish_times[:, None], 2 + ) + + # masking the processing time of scheduled operations and add their finish times instead (first diff thereof) + lb_end_expand = ( + proc_matrix_not_scheduled * ops_proc_times.unsqueeze(1).expand_as(job_ops_adj) + + finish_times_1st_diff + ) + # (bs, max_ops); lower bound finish time per operation using the cumsum logic + LBs = torch.sum(job_ops_adj * lb_end_expand.cumsum(-1), dim=1) + # remove nans + LBs = torch.nan_to_num(LBs, nan=0.0) + + # test + assert torch.where( + finish_times != INIT_FINISH, torch.isclose(LBs, finish_times), True + ).all() + + return LBs + + +def op_is_ready(td: TensorDict): + # compare finish times of predecessors with current time step; shape=(b, n_ops_max) + is_ready = ( + torch.bmm(td["ops_adj"][..., 0], td["finish_times"][..., None]).squeeze(2) + <= td["time"][:, None] + ) + # shape=(b, n_ops_max) + is_scheduled = td["ma_assignment"].sum(1).bool() + # op is ready for scheduling if it has not been scheduled and its predecessor is finished + return torch.logical_and(is_ready, ~is_scheduled) + + +def get_job_ops_mapping( + start_op_per_job: torch.Tensor, end_op_per_job: torch.Tensor, n_ops_max: int +) -> Tuple[torch.Tensor, torch.Tensor]: + """Implements a mapping function from operations to jobs + + :param torch.Tensor start_op_per_job: index of first operation of each job + :param torch.Tensor end_op_per_job: index of last operation of each job + :return Tuple[torch.Tensor, torch.Tensor]: + 1st.) index mapping (bs, num_ops): [0,0,1,1,1] means that first two operations belong to job 0 + 2st.) binary mapping (bs, num_jobs, num_ops): [[1,1,0], [0,0,1]] means that first two operations belong to job 0 + """ + device = end_op_per_job.device + end_op_per_job = end_op_per_job.clone() + + bs, num_jobs = end_op_per_job.shape + + # in order to avoid shape conflicts, set the end operation id to the id of max_ops (all batches have same #ops) + end_op_per_job[:, -1] = n_ops_max - 1 + + # here we will generate the operations-job mapping: + # Therefore we first generate a sequence of operation ids and expand it the the size of the mapping matrix: + # (bs, jobs, max_ops) + ops_seq_exp = torch.arange(n_ops_max, device=device)[None, None].expand( + bs, num_jobs, -1 + ) + # (bs, jobs, max_ops) # expanding start and end operation ids + end_op_per_job_exp = end_op_per_job[..., None].expand_as(ops_seq_exp) + start_op_per_job_exp = start_op_per_job[..., None].expand_as(ops_seq_exp) + # given ids of start and end operations per job, this generates the mapping of ops to jobs + # (bs, jobs, max_ops) + ops_job_map = torch.nonzero( + (ops_seq_exp <= end_op_per_job_exp) & (ops_seq_exp >= start_op_per_job_exp) + ) + # (bs, max_ops) + ops_job_map = torch.stack(ops_job_map[:, 1].split(n_ops_max), dim=0) + + # we might also want a binary mapping / adjacency matrix connecting jobs to operations + # (bs, num_jobs, num_ops) + ops_job_bin_map = torch.scatter_add( + input=ops_job_map.new_zeros((bs, num_jobs, n_ops_max)), + dim=1, + index=ops_job_map.unsqueeze(1), + src=ops_job_map.new_ones((bs, num_jobs, n_ops_max)), + ) + + return ops_job_map, ops_job_bin_map diff --git a/rl4co/envs/scheduling/jssp/__init__.py b/rl4co/envs/scheduling/jssp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/scheduling/jssp/env.py b/rl4co/envs/scheduling/jssp/env.py new file mode 100644 index 00000000..2381836a --- /dev/null +++ b/rl4co/envs/scheduling/jssp/env.py @@ -0,0 +1,123 @@ +import torch + +from einops import einsum, reduce +from tensordict import TensorDict +from torch._tensor import Tensor + +from rl4co.envs.scheduling.fjsp.env import FJSPEnv +from rl4co.utils.ops import gather_by_index + +from .generator import JSSPFileGenerator, JSSPGenerator + + +class JSSPEnv(FJSPEnv): + """Job-Shop Scheduling Problem (JSSP) environment + At each step, the agent chooses a job. The operation to be processed next for the selected job is + then executed on the associated machine. The reward is 0 unless the agent scheduled all operations of all jobs. + In that case, the reward is (-)makespan of the schedule: maximizing the reward is equivalent to minimizing the makespan. + NOTE: The JSSP is a special case of the FJSP, when the number of eligible machines per operation is equal to one for all + operations. Therefore, this environment is a subclass of the FJSP environment. + Observations: + - time: current time + - next_op: next operation per job + - proc_times: processing time of operation-machine pairs + - pad_mask: specifies padded operations + - start_op_per_job: id of first operation per job + - end_op_per_job: id of last operation per job + - start_times: start time of operation (defaults to 0 if not scheduled) + - finish_times: finish time of operation (defaults to INIT_FINISH if not scheduled) + - job_ops_adj: adjacency matrix specifying job-operation affiliation + - ops_job_map: same as above but using ids of jobs to indicate affiliation + - ops_sequence_order: specifies the order in which operations have to be processed + - ma_assignment: specifies which operation has been scheduled on which machine + - busy_until: specifies until when the machine will be busy + - num_eligible: number of machines that can process an operation + - job_in_process: whether job is currently being processed + - job_done: whether the job is done + + Constrains: + the agent may not select: + - jobs that are done already + - jobs that are currently processed + + Finish condition: + - the agent has scheduled all operations of all jobs + + Reward: + - the negative makespan of the final schedule + + Args: + generator: JSSPGenerator instance as the data generator + generator_params: parameters for the generator + mask_no_ops: if True, agent may not select waiting operation (unless instance is done) + """ + + name = "jssp" + + def __init__( + self, + generator: JSSPGenerator = None, + generator_params: dict = {}, + mask_no_ops: bool = True, + **kwargs, + ): + if generator is None: + if generator_params.get("file_path", None) is not None: + generator = JSSPFileGenerator(**generator_params) + else: + generator = JSSPGenerator(**generator_params) + + super().__init__(generator, generator_params, mask_no_ops, **kwargs) + + def _get_features(self, td): + td = super()._get_features(td) + # get the id of the machine that executes an operation: + # (bs, ops, ma) + ops_ma_adj = td["ops_ma_adj"].transpose(1, 2) + # (bs, jobs, ma) + ma_of_next_op = gather_by_index(ops_ma_adj, td["next_op"], dim=1) + # (bs, jobs) + td["next_ma"] = ma_of_next_op.argmax(-1) + + # adjacency matrix specifying neighbors of an operation, including its + # predecessor and successor operations and operations on the same machine + ops_on_same_ma_adj = einsum( + td["ops_ma_adj"], td["ops_ma_adj"], "b m o1, b m o2 -> b o1 o2 " + ) + # concat pred, succ and ops on same machine + adj = torch.cat((td["ops_adj"], ops_on_same_ma_adj.unsqueeze(-1)), dim=-1).sum(-1) + # mask padded operations and those scheduled + mask = td["pad_mask"] + td["op_scheduled"] + adj.masked_fill_(mask.unsqueeze(1), 0) + td["adjacency"] = adj + + return td + + def get_action_mask(self, td: TensorDict) -> Tensor: + action_mask = self._get_job_machine_availability(td) + if self.mask_no_ops: + # masking is only allowed if instance is finished + no_op_mask = td["done"] + else: + # if no job is currently processed and instance is not finished yet, waiting is not allowed + no_op_mask = ( + td["job_in_process"].any(1, keepdims=True) & (~td["done"]) + ) | td["done"] + # reduce action mask to correspond with logit shape + action_mask = reduce(action_mask, "bs j m -> bs j", reduction="all") + # NOTE: 1 means feasible action, 0 means infeasible action + # (bs, 1 + n_j) + mask = torch.cat((no_op_mask, ~action_mask), dim=1) + return mask + + def _translate_action(self, td): + job = td["action"] + op = gather_by_index(td["next_op"], job, dim=1) + # get the machine that corresponds to the selected operation + ma = gather_by_index(td["ops_ma_adj"], op.unsqueeze(1), dim=2).nonzero()[:, 1] + return job, op, ma + + @staticmethod + def load_data(fpath, batch_size=[]): + g = JSSPFileGenerator(fpath) + return g(batch_size=batch_size) diff --git a/rl4co/envs/scheduling/jssp/generator.py b/rl4co/envs/scheduling/jssp/generator.py new file mode 100644 index 00000000..bc9f1fc6 --- /dev/null +++ b/rl4co/envs/scheduling/jssp/generator.py @@ -0,0 +1,208 @@ +import os + +from functools import partial +from typing import List + +import numpy as np +import torch + +from tensordict.tensordict import TensorDict +from torch.nn.functional import one_hot + +from rl4co.envs.common.utils import Generator +from rl4co.utils.pylogger import get_pylogger + +from .parser import get_max_ops_from_files, read + +log = get_pylogger(__name__) + + +class JSSPGenerator(Generator): + + """Data generator for the Job-Shop Scheduling Problem (JSSP) + + Args: + num_stage: number of stages + num_machine: number of machines + num_job: number of jobs + min_time: minimum running time of each job on each machine + max_time: maximum running time of each job on each machine + flatten_stages: whether to flatten the stages + one2one_ma_map: whether each machine should have exactly one operation per job (common in jssp benchmark instances) + + Returns: + A TensorDict with the following key: + start_op_per_job [batch_size, num_jobs]: first operation of each job + end_op_per_job [batch_size, num_jobs]: last operation of each job + proc_times [batch_size, num_machines, total_n_ops]: processing time of ops on machines + pad_mask [batch_size, total_n_ops]: not all instances have the same number of ops, so padding is used + + """ + + def __init__( + self, + num_jobs: int = 6, + num_machines: int = 6, + min_ops_per_job: int = None, + max_ops_per_job: int = None, + min_processing_time: int = 1, + max_processing_time: int = 99, + one2one_ma_map: bool = True, + **unused_kwargs, + ): + self.num_jobs = num_jobs + self.num_mas = num_machines + # quite common in jssp to have as many ops per job as there are machines + self.min_ops_per_job = min_ops_per_job or self.num_mas + self.max_ops_per_job = max_ops_per_job or self.num_mas + self.min_processing_time = min_processing_time + self.max_processing_time = max_processing_time + self.one2one_ma_map = one2one_ma_map + if self.one2one_ma_map: + assert self.min_ops_per_job == self.max_ops_per_job == self.num_mas + + # determines whether to use a fixed number of total operations or let it vary between instances + # NOTE: due to the way rl4co builds datasets, we need a fixed size here + self.n_ops_max = self.max_ops_per_job * self.num_jobs + + # FFSP environment doen't have any other kwargs + if len(unused_kwargs) > 0: + log.error(f"Found {len(unused_kwargs)} unused kwargs: {unused_kwargs}") + + def _simulate_processing_times(self, bs, n_ops_max) -> torch.Tensor: + if self.one2one_ma_map: + ops_machine_ids = ( + torch.rand((*bs, self.num_jobs, self.num_mas)) + .argsort(dim=-1) + .flatten(1, 2) + ) + else: + ops_machine_ids = torch.randint( + low=0, + high=self.num_mas, + size=(*bs, n_ops_max), + ) + ops_machine_adj = one_hot(ops_machine_ids, num_classes=self.num_mas) + + # (bs, max_ops, machines) + proc_times = torch.ones((*bs, n_ops_max, self.num_mas)) + proc_times = torch.randint( + self.min_processing_time, + self.max_processing_time + 1, + size=(*bs, self.num_mas, n_ops_max), + ) + + # remove proc_times for which there is no corresponding ma-ops connection + proc_times = proc_times * ops_machine_adj.transpose(1, 2) + # in JSSP there is only one machine capable to process an operation + assert (proc_times > 0).sum(1).eq(1).all() + return proc_times.to(torch.float32) + + def _generate(self, batch_size) -> TensorDict: + # simulate how many operations each job has + n_ope_per_job = torch.randint( + self.min_ops_per_job, + self.max_ops_per_job + 1, + size=(*batch_size, self.num_jobs), + ) + + # determine the total number of operations per batch instance (which may differ) + n_ops_batch = n_ope_per_job.sum(1) # (bs) + # determine the maximum total number of operations over all batch instances + n_ops_max = self.n_ops_max or n_ops_batch.max() + + # generate a mask, specifying which operations are padded + pad_mask = torch.arange(n_ops_max).unsqueeze(0).expand(*batch_size, -1) + pad_mask = pad_mask.ge(n_ops_batch[:, None].expand_as(pad_mask)) + + # determine the id of the end operation for each job + end_op_per_job = n_ope_per_job.cumsum(1) - 1 + + # determine the id of the starting operation for each job + # (bs, num_jobs) + start_op_per_job = torch.cat( + ( + torch.zeros((*batch_size, 1)).to(end_op_per_job), + end_op_per_job[:, :-1] + 1, + ), + dim=1, + ) + + # simulate processing times for machine-operation pairs + # (bs, num_mas, n_ops_max) + proc_times = self._simulate_processing_times(batch_size, n_ops_max) + + td = TensorDict( + { + "start_op_per_job": start_op_per_job, + "end_op_per_job": end_op_per_job, + "proc_times": proc_times, + "pad_mask": pad_mask, + }, + batch_size=batch_size, + ) + + return td + + +class JSSPFileGenerator(Generator): + """Data generator for the Job-Shop Scheduling Problem (JSSP) using instance files + + Args: + path: path to files + + Returns: + A TensorDict with the following key: + start_op_per_job [batch_size, num_jobs]: first operation of each job + end_op_per_job [batch_size, num_jobs]: last operation of each job + proc_times [batch_size, num_machines, total_n_ops]: processing time of ops on machines + pad_mask [batch_size, total_n_ops]: not all instances have the same number of ops, so padding is used + + """ + + def __init__(self, file_path: str, n_ops_max: int = None, **unused_kwargs): + self.files = ( + [file_path] if os.path.isfile(file_path) else self.list_files(file_path) + ) + self.num_samples = len(self.files) + + if len(unused_kwargs) > 0: + log.error(f"Found {len(unused_kwargs)} unused kwargs: {unused_kwargs}") + + if len(self.files) > 1: + n_ops_max = get_max_ops_from_files(self.files) + + ret = map(partial(read, max_ops=n_ops_max), self.files) + + td_list, num_jobs, num_machines, max_ops_per_job = list(zip(*list(ret))) + num_jobs, num_machines = map(lambda x: x[0], (num_jobs, num_machines)) + max_ops_per_job = max(max_ops_per_job) + + self.td = torch.cat(td_list, dim=0) + self.num_mas = num_machines + self.num_jobs = num_jobs + self.max_ops_per_job = max_ops_per_job + self.start_idx = 0 + + def _generate(self, batch_size: List[int]) -> TensorDict: + batch_size = np.prod(batch_size) + if batch_size > self.num_samples: + log.warning( + f"Only found {self.num_samples} instance files, but specified dataset size is {batch_size}" + ) + end_idx = self.start_idx + batch_size + td = self.td[self.start_idx : end_idx] + self.start_idx += batch_size + if self.start_idx >= self.num_samples: + self.start_idx = 0 + return td + + @staticmethod + def list_files(path): + files = [ + os.path.join(path, f) + for f in os.listdir(path) + if os.path.isfile(os.path.join(path, f)) + ] + assert len(files) > 0, "No files found in the specified path" + return files diff --git a/rl4co/envs/scheduling/jssp/parser.py b/rl4co/envs/scheduling/jssp/parser.py new file mode 100644 index 00000000..9fcdb4bf --- /dev/null +++ b/rl4co/envs/scheduling/jssp/parser.py @@ -0,0 +1,110 @@ +from pathlib import Path +from typing import List, Tuple, Union + +import torch + +from tensordict import TensorDict + +ProcessingData = List[Tuple[int, int]] + + +def parse_job_line(line: Tuple[int]) -> Tuple[ProcessingData]: + """ + Parses a JSSP job data line of the following form: + + * ( ) + + In words, a line consist of n_ops pairs of values, where the first value is the + machine identifier and the second value is the processing time of the corresponding + operation-machine combination + + Note that the machine indices start from 1, so we subtract 1 to make them + zero-based. + """ + + operations = [] + i = 0 + + while i < len(line): + machine = int(line[i]) + duration = int(line[i + 1]) + operations.append((machine, duration)) + i += 2 + + return operations + + +def get_n_ops_of_instance(file): + lines = file2lines(file) + jobs = [parse_job_line(line) for line in lines[1:]] + n_ope_per_job = torch.Tensor([len(x) for x in jobs]).unsqueeze(0) + total_ops = int(n_ope_per_job.sum()) + return total_ops + + +def get_max_ops_from_files(files): + return max(map(get_n_ops_of_instance, files)) + + +def read(loc: Path, max_ops=None): + """ + Reads an JSSP instance. + + Args: + loc: location of instance file + max_ops: optionally specify the maximum number of total operations (will be filled by padding) + + Returns: + instance: the parsed instance + """ + lines = file2lines(loc) + + # First line contains metadata. + num_jobs, num_machines = lines[0][0], lines[0][1] + + # The remaining lines contain the job-operation data, where each line + # represents a job and its operations. + jobs = [parse_job_line(line) for line in lines[1:]] + n_ope_per_job = torch.Tensor([len(x) for x in jobs]).unsqueeze(0) + total_ops = int(n_ope_per_job.sum()) + if max_ops is not None: + assert total_ops <= max_ops, "got more operations then specified through max_ops" + max_ops = max_ops or total_ops + max_ops_per_job = int(n_ope_per_job.max()) + + end_op_per_job = n_ope_per_job.cumsum(1) - 1 + start_op_per_job = torch.cat((torch.zeros((1, 1)), end_op_per_job[:, :-1] + 1), dim=1) + + pad_mask = torch.arange(max_ops) + pad_mask = pad_mask.ge(total_ops).unsqueeze(0) + + proc_times = torch.zeros((num_machines, max_ops)) + op_cnt = 0 + for job in jobs: + for ma, dur in job: + # subtract one to let indices start from zero + proc_times[ma - 1, op_cnt] = dur + op_cnt += 1 + proc_times = proc_times.unsqueeze(0) + + td = TensorDict( + { + "start_op_per_job": start_op_per_job, + "end_op_per_job": end_op_per_job, + "proc_times": proc_times, + "pad_mask": pad_mask, + }, + batch_size=[1], + ) + + return td, num_jobs, num_machines, max_ops_per_job + + +def file2lines(loc: Union[Path, str]) -> List[List[int]]: + with open(loc, "r") as fh: + lines = [line for line in fh.readlines() if line.strip()] + + def parse_num(word: str): + return int(word) if "." not in word else int(float(word)) + + return [[parse_num(x) for x in line.split()] for line in lines] diff --git a/rl4co/envs/scheduling/smtwtp/__init__.py b/rl4co/envs/scheduling/smtwtp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/envs/scheduling/smtwtp/env.py b/rl4co/envs/scheduling/smtwtp/env.py new file mode 100644 index 00000000..8bc311ea --- /dev/null +++ b/rl4co/envs/scheduling/smtwtp/env.py @@ -0,0 +1,203 @@ +from typing import Optional + +import torch + +from tensordict.tensordict import TensorDict +from torchrl.data import ( + BoundedTensorSpec, + CompositeSpec, + UnboundedContinuousTensorSpec, + UnboundedDiscreteTensorSpec, +) + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.utils.pylogger import get_pylogger + +from .generator import SMTWTPGenerator +from .render import render + +log = get_pylogger(__name__) + + +class SMTWTPEnv(RL4COEnvBase): + """ + Single Machine Total Weighted Tardiness Problem environment as described in DeepACO (https://arxiv.org/pdf/2309.14032.pdf) + SMTWTP is a scheduling problem in which a set of jobs must be processed on a single machine. + Each job i has a processing time, a weight, and a due date. The objective is to minimize the sum of the weighted tardiness of all jobs, + where the weighted tardiness of a job is defined as the product of its weight and the duration by which its completion time exceeds its due date. + At each step, the agent chooses a job to process. The reward is 0 unless the agent processes all the jobs. + In that case, the reward is (-)objective value of the processing order: maximizing the reward is equivalent to minimizing the objective. + + Observation: + - job_due_time: the due time of each job + - job_weight: the weight of each job + - job_process_time: the process time of each job + - current_node: the current node + - action_mask: a mask of available actions + - current_time: the current time + + Constants: + - num_job: number of jobs + - min_time_span: lower bound of jobs' due time. By default, jobs' due time is uniformly sampled from (min_time_span, max_time_span) + - max_time_span: upper bound of jobs' due time. By default, it will be set to num_job / 2 + - min_job_weight: lower bound of jobs' weights. By default, jobs' weights are uniformly sampled from (min_job_weight, max_job_weight) + - max_job_weight: upper bound of jobs' weights + - min_process_time: lower bound of jobs' process time. By default, jobs' process time is uniformly sampled from (min_process_time, max_process_time) + - max_process_time: upper bound of jobs' process time + + Finishing condition: + - All jobs are processed + + Reward: + - The reward is 0 unless the agent processes all the jobs. + - In that case, the reward is (-)objective value of the processing order: maximizing the reward is equivalent to minimizing the objective. + + Args: + generator: FFSPGenerator instance as the data generator + generator_params: parameters for the generator + """ + + name = "smtwtp" + + def __init__( + self, + generator: SMTWTPGenerator = None, + generator_params: dict = {}, + **kwargs, + ): + super().__init__(**kwargs) + if generator is None: + generator = SMTWTPGenerator(**generator_params) + self.generator = generator + self._make_spec(self.generator) + + @staticmethod + def _step(td: TensorDict) -> TensorDict: + current_job = td["action"] + + # Set not visited to 0 (i.e., we visited the node) + available = td["action_mask"].scatter( + -1, current_job.unsqueeze(-1).expand_as(td["action_mask"]), 0 + ) + + # Increase used time + selected_process_time = td["job_process_time"][ + torch.arange(current_job.size(0)), current_job + ] + current_time = td["current_time"] + selected_process_time.unsqueeze(-1) + + # We are done there are no unvisited locations + done = torch.count_nonzero(available, dim=-1) <= 0 + + # The reward is calculated outside via get_reward for efficiency, so we set it to 0 here + reward = torch.zeros_like(done) + + td.update( + { + "current_job": current_job, + "current_time": current_time, + "action_mask": available, + "reward": reward, + "done": done, + } + ) + return td + + def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: + device = td.device + + init_job_due_time = td["job_due_time"] + init_job_process_time = td["job_process_time"] + init_job_weight = td["job_weight"] + + # Other variables + current_job = torch.zeros((*batch_size, 1), dtype=torch.int64, device=device) + current_time = torch.zeros((*batch_size, 1), dtype=torch.int64, device=device) + available = torch.ones( + (*batch_size, self.generator.num_job + 1), dtype=torch.bool, device=device + ) + available[:, 0] = 0 # mask the starting dummy node + + return TensorDict( + { + "job_due_time": init_job_due_time, + "job_weight": init_job_weight, + "job_process_time": init_job_process_time, + "current_job": current_job, + "current_time": current_time, + "action_mask": available, + }, + batch_size=batch_size, + ) + + def _make_spec(self, generator: SMTWTPGenerator) -> None: + self.observation_spec = CompositeSpec( + job_due_time=BoundedTensorSpec( + low=generator.min_time_span, + high=generator.max_time_span, + shape=(generator.num_job + 1,), + dtype=torch.float32, + ), + job_weight=BoundedTensorSpec( + low=generator.min_job_weight, + high=generator.max_job_weight, + shape=(generator.num_job + 1,), + dtype=torch.float32, + ), + job_process_time=BoundedTensorSpec( + low=generator.min_process_time, + high=generator.max_process_time, + shape=(generator.num_job + 1,), + dtype=torch.float32, + ), + current_node=UnboundedDiscreteTensorSpec( + shape=(1,), + dtype=torch.int64, + ), + action_mask=UnboundedDiscreteTensorSpec( + shape=(generator.num_job + 1,), + dtype=torch.bool, + ), + current_time=UnboundedContinuousTensorSpec( + shape=(1,), + dtype=torch.float32, + ), + shape=(), + ) + self.action_spec = BoundedTensorSpec( + shape=(1,), + dtype=torch.int64, + low=0, + high=generator.num_job + 1, + ) + self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) + self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) + + def _get_reward(self, td, actions) -> TensorDict: + job_due_time = td["job_due_time"] + job_weight = td["job_weight"] + job_process_time = td["job_process_time"] + + batch_idx = torch.arange( + job_process_time.shape[0], device=job_process_time.device + ).unsqueeze(1) + + ordered_process_time = job_process_time[batch_idx, actions] + ordered_due_time = job_due_time[batch_idx, actions] + ordered_job_weight = job_weight[batch_idx, actions] + presum_process_time = torch.cumsum( + ordered_process_time, dim=1 + ) # ending time of each job + job_tardiness = presum_process_time - ordered_due_time + job_tardiness[job_tardiness < 0] = 0 + job_weighted_tardiness = ordered_job_weight * job_tardiness + + return -job_weighted_tardiness.sum(-1) + + def check_solution_validity(self, td, actions): + log.warning("Checking solution validity is not implemented for SMTWTP") + pass + + @staticmethod + def render(td, actions=None, ax=None): + raise render(td, actions, ax) diff --git a/rl4co/envs/scheduling/smtwtp/generator.py b/rl4co/envs/scheduling/smtwtp/generator.py new file mode 100644 index 00000000..39701478 --- /dev/null +++ b/rl4co/envs/scheduling/smtwtp/generator.py @@ -0,0 +1,88 @@ +import os +import zipfile +from typing import Union, Callable + +import torch +import numpy as np + +from robust_downloader import download +from torch.distributions import Uniform +from tensordict.tensordict import TensorDict + +from rl4co.data.utils import load_npz_to_tensordict +from rl4co.utils.pylogger import get_pylogger +from rl4co.envs.common.utils import get_sampler, Generator + +log = get_pylogger(__name__) + + +class SMTWTPGenerator(Generator): + """Data generator for the Single Machine Total Weighted Tardiness Problem (SMTWTP) environment + + Args: + num_job: number of jobs + min_time_span: lower bound of jobs' due time. By default, jobs' due time is uniformly sampled from (min_time_span, max_time_span) + max_time_span: upper bound of jobs' due time. By default, it will be set to num_job / 2 + min_job_weight: lower bound of jobs' weights. By default, jobs' weights are uniformly sampled from (min_job_weight, max_job_weight) + max_job_weight: upper bound of jobs' weights + min_process_time: lower bound of jobs' process time. By default, jobs' process time is uniformly sampled from (min_process_time, max_process_time) + max_process_time: upper bound of jobs' process time + + Returns: + A TensorDict with the following key: + job_due_time [batch_size, num_job + 1]: the due time of each job + job_weight [batch_size, num_job + 1]: the weight of each job + job_process_time [batch_size, num_job + 1]: the process time of each job + """ + def __init__( + self, + num_job: int = 10, + min_time_span: float = 0, + max_time_span: float = None, # will be set to num_job / 2 by default. In DeepACO, it is set to num_job, which would be too simple + min_job_weight: float = 0, + max_job_weight: float = 1, + min_process_time: float = 0, + max_process_time: float = 1, + **unused_kwargs + ): + self.num_job = num_job + self.min_time_span = min_time_span + self.max_time_span = num_job / 2 if max_time_span is None else max_time_span + self.min_job_weight = min_job_weight + self.max_job_weight = max_job_weight + self.min_process_time = min_process_time + self.max_process_time = max_process_time + + # SMTWTP environment doen't have any other kwargs + if len(unused_kwargs) > 0: + log.error(f"Found {len(unused_kwargs)} unused kwargs: {unused_kwargs}") + + def _generate(self, batch_size) -> TensorDict: + batch_size = [batch_size] if isinstance(batch_size, int) else batch_size + # Sampling according to Ye et al. (2023) + job_due_time = ( + torch.FloatTensor(*batch_size, self.num_job + 1) + .uniform_(self.min_time_span, self.max_time_span) + ) + job_weight = ( + torch.FloatTensor(*batch_size, self.num_job + 1) + .uniform_(self.min_job_weight, self.max_job_weight) + ) + job_process_time = ( + torch.FloatTensor(*batch_size, self.num_job + 1) + .uniform_(self.min_process_time, self.max_process_time) + ) + + # Rollouts begin at dummy node 0, whose features are set to 0 + job_due_time[:, 0] = 0 + job_weight[:, 0] = 0 + job_process_time[:, 0] = 0 + + return TensorDict( + { + "job_due_time": job_due_time, + "job_weight": job_weight, + "job_process_time": job_process_time, + }, + batch_size=batch_size, + ) diff --git a/rl4co/envs/scheduling/smtwtp/render.py b/rl4co/envs/scheduling/smtwtp/render.py new file mode 100644 index 00000000..9f8eedf0 --- /dev/null +++ b/rl4co/envs/scheduling/smtwtp/render.py @@ -0,0 +1,15 @@ +import torch +import numpy as np +import matplotlib.pyplot as plt + +from matplotlib import cm, colormaps +from tensordict.tensordict import TensorDict + +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def render(td: TensorDict, actions=None, ax=None): + raise NotImplementedError diff --git a/rl4co/models/__init__.py b/rl4co/models/__init__.py new file mode 100644 index 00000000..339c3b01 --- /dev/null +++ b/rl4co/models/__init__.py @@ -0,0 +1,49 @@ +from rl4co.models.common.constructive.autoregressive import ( + AutoregressiveDecoder, + AutoregressiveEncoder, + AutoregressivePolicy, +) +from rl4co.models.common.constructive.base import ( + ConstructiveDecoder, + ConstructiveEncoder, + ConstructivePolicy, +) +from rl4co.models.common.constructive.nonautoregressive import ( + NonAutoregressiveDecoder, + NonAutoregressiveEncoder, + NonAutoregressivePolicy, +) +from rl4co.models.common.transductive import TransductiveModel +from rl4co.models.rl import StepwisePPO +from rl4co.models.rl.a2c.a2c import A2C +from rl4co.models.rl.common.base import RL4COLitModule +from rl4co.models.rl.ppo.ppo import PPO +from rl4co.models.rl.reinforce.baselines import REINFORCEBaseline, get_reinforce_baseline +from rl4co.models.rl.reinforce.reinforce import REINFORCE +from rl4co.models.zoo.active_search import ActiveSearch +from rl4co.models.zoo.am import AttentionModel, AttentionModelPolicy +from rl4co.models.zoo.amppo import AMPPO +from rl4co.models.zoo.dact import DACT, DACTPolicy +from rl4co.models.zoo.deepaco import DeepACO, DeepACOPolicy +from rl4co.models.zoo.eas import EAS, EASEmb, EASLay +from rl4co.models.zoo.ham import ( + HeterogeneousAttentionModel, + HeterogeneousAttentionModelPolicy, +) +from rl4co.models.zoo.l2d import ( + L2DAttnPolicy, + L2DModel, + L2DPolicy, + L2DPolicy4PPO, + L2DPPOModel, +) +from rl4co.models.zoo.matnet import MatNet, MatNetPolicy +from rl4co.models.zoo.mdam import MDAM, MDAMPolicy +from rl4co.models.zoo.mvmoe import MVMoE_AM, MVMoE_POMO +from rl4co.models.zoo.n2s import N2S, N2SPolicy +from rl4co.models.zoo.nargnn import NARGNNPolicy +from rl4co.models.zoo.neuopt import NeuOpt, NeuOptPolicy +from rl4co.models.zoo.polynet import PolyNet +from rl4co.models.zoo.pomo import POMO +from rl4co.models.zoo.ptrnet import PointerNetwork, PointerNetworkPolicy +from rl4co.models.zoo.symnco import SymNCO, SymNCOPolicy diff --git a/rl4co/models/common/__init__.py b/rl4co/models/common/__init__.py new file mode 100644 index 00000000..57eea304 --- /dev/null +++ b/rl4co/models/common/__init__.py @@ -0,0 +1,21 @@ +from rl4co.models.common.constructive.autoregressive import ( + AutoregressiveDecoder, + AutoregressiveEncoder, + AutoregressivePolicy, +) +from rl4co.models.common.constructive.base import ( + ConstructiveDecoder, + ConstructiveEncoder, + ConstructivePolicy, +) +from rl4co.models.common.constructive.nonautoregressive import ( + NonAutoregressiveDecoder, + NonAutoregressiveEncoder, + NonAutoregressivePolicy, +) +from rl4co.models.common.improvement import ( + ImprovementDecoder, + ImprovementEncoder, + ImprovementPolicy, +) +from rl4co.models.common.transductive.base import TransductiveModel diff --git a/rl4co/models/common/constructive/__init__.py b/rl4co/models/common/constructive/__init__.py new file mode 100644 index 00000000..e8e4739a --- /dev/null +++ b/rl4co/models/common/constructive/__init__.py @@ -0,0 +1,15 @@ +from rl4co.models.common.constructive.autoregressive import ( + AutoregressiveDecoder, + AutoregressiveEncoder, + AutoregressivePolicy, +) +from rl4co.models.common.constructive.base import ( + ConstructiveDecoder, + ConstructiveEncoder, + ConstructivePolicy, +) +from rl4co.models.common.constructive.nonautoregressive import ( + NonAutoregressiveDecoder, + NonAutoregressiveEncoder, + NonAutoregressivePolicy, +) diff --git a/rl4co/models/common/constructive/autoregressive/__init__.py b/rl4co/models/common/constructive/autoregressive/__init__.py new file mode 100644 index 00000000..976742f2 --- /dev/null +++ b/rl4co/models/common/constructive/autoregressive/__init__.py @@ -0,0 +1,3 @@ +from rl4co.models.common.constructive.autoregressive.decoder import AutoregressiveDecoder +from rl4co.models.common.constructive.autoregressive.encoder import AutoregressiveEncoder +from rl4co.models.common.constructive.autoregressive.policy import AutoregressivePolicy diff --git a/rl4co/models/common/constructive/autoregressive/decoder.py b/rl4co/models/common/constructive/autoregressive/decoder.py new file mode 100644 index 00000000..b901e969 --- /dev/null +++ b/rl4co/models/common/constructive/autoregressive/decoder.py @@ -0,0 +1,13 @@ +import abc + +from rl4co.models.common.constructive.base import ConstructiveDecoder + + +class AutoregressiveDecoder(ConstructiveDecoder, metaclass=abc.ABCMeta): + """Template class for an autoregressive decoder, simple wrapper around + :class:`rl4co.models.common.constructive.base.ConstructiveDecoder` + + Tip: + This class will not work as it is and is just a template. + An example for autoregressive encoder can be found as :class:`rl4co.models.zoo.am.decoder.AttentionModelDecoder`. + """ diff --git a/rl4co/models/common/constructive/autoregressive/encoder.py b/rl4co/models/common/constructive/autoregressive/encoder.py new file mode 100644 index 00000000..d33e104f --- /dev/null +++ b/rl4co/models/common/constructive/autoregressive/encoder.py @@ -0,0 +1,13 @@ +import abc + +from rl4co.models.common.constructive.base import ConstructiveEncoder + + +class AutoregressiveEncoder(ConstructiveEncoder, metaclass=abc.ABCMeta): + """Template class for an autoregressive encoder, simple wrapper around + :class:`rl4co.models.common.constructive.base.ConstructiveEncoder`. + + Tip: + This class will not work as it is and is just a template. + An example for autoregressive encoder can be found as :class:`rl4co.models.zoo.am.encoder.AttentionModelEncoder`. + """ diff --git a/rl4co/models/common/constructive/autoregressive/policy.py b/rl4co/models/common/constructive/autoregressive/policy.py new file mode 100644 index 00000000..3cad5961 --- /dev/null +++ b/rl4co/models/common/constructive/autoregressive/policy.py @@ -0,0 +1,46 @@ +from rl4co.models.common.constructive.base import ConstructivePolicy + +from .decoder import AutoregressiveDecoder +from .encoder import AutoregressiveEncoder + + +class AutoregressivePolicy(ConstructivePolicy): + """Template class for an autoregressive policy, simple wrapper around + :class:`rl4co.models.common.constructive.base.ConstructivePolicy`. + + Note: + While a decoder is required, an encoder is optional and will be initialized to + :class:`rl4co.models.common.constructive.autoregressive.encoder.NoEncoder`. + This can be used in decoder-only models in which at each step actions do not depend on + previously encoded states. + """ + + def __init__( + self, + encoder: AutoregressiveEncoder, + decoder: AutoregressiveDecoder, + env_name: str = "tsp", + temperature: float = 1.0, + tanh_clipping: float = 0, + mask_logits: bool = True, + train_decode_type: str = "sampling", + val_decode_type: str = "greedy", + test_decode_type: str = "greedy", + **unused_kw, + ): + # We raise an error for the user if no decoder was provided + if decoder is None: + raise ValueError("AutoregressivePolicy requires a decoder to be provided.") + + super(AutoregressivePolicy, self).__init__( + encoder=encoder, + decoder=decoder, + env_name=env_name, + temperature=temperature, + tanh_clipping=tanh_clipping, + mask_logits=mask_logits, + train_decode_type=train_decode_type, + val_decode_type=val_decode_type, + test_decode_type=test_decode_type, + **unused_kw, + ) diff --git a/rl4co/models/common/constructive/base.py b/rl4co/models/common/constructive/base.py new file mode 100644 index 00000000..9ad61db3 --- /dev/null +++ b/rl4co/models/common/constructive/base.py @@ -0,0 +1,268 @@ +import abc + +from typing import Any, Callable, Optional, Tuple, Union + +import torch.nn as nn + +from tensordict import TensorDict +from torch import Tensor + +from rl4co.envs import RL4COEnvBase, get_env +from rl4co.utils.decoding import ( + DecodingStrategy, + get_decoding_strategy, + get_log_likelihood, +) +from rl4co.utils.ops import calculate_entropy +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class ConstructiveEncoder(nn.Module, metaclass=abc.ABCMeta): + """Base class for the encoder of constructive models""" + + @abc.abstractmethod + def forward(self, td: TensorDict) -> Tuple[Any, Tensor]: + """Forward pass for the encoder + + Args: + td: TensorDict containing the input data + + Returns: + Tuple containing: + - latent representation (any type) + - initial embeddings (from feature space to embedding space) + """ + raise NotImplementedError("Implement me in subclass!") + + +class ConstructiveDecoder(nn.Module, metaclass=abc.ABCMeta): + """Base decoder model for constructive models. The decoder is responsible for generating the logits for the action""" + + @abc.abstractmethod + def forward( + self, td: TensorDict, hidden: Any = None, num_starts: int = 0 + ) -> Tuple[Tensor, Tensor]: + """Obtain logits for current action to the next ones + + Args: + td: TensorDict containing the input data + hidden: Hidden state from the encoder. Can be any type + num_starts: Number of starts for multistart decoding + + Returns: + Tuple containing the logits and the action mask + """ + raise NotImplementedError("Implement me in subclass!") + + def pre_decoder_hook( + self, td: TensorDict, env: RL4COEnvBase, hidden: Any = None, num_starts: int = 0 + ) -> Tuple[TensorDict, Any, RL4COEnvBase]: + """By default, we don't need to do anything here. + + Args: + td: TensorDict containing the input data + hidden: Hidden state from the encoder + env: Environment for decoding + num_starts: Number of starts for multistart decoding + + Returns: + Tuple containing the updated hidden state, TensorDict, and environment + """ + return td, env, hidden + + +class NoEncoder(ConstructiveEncoder): + """Default encoder decoder-only models, i.e. autoregressive models that re-encode all the state at each decoding step.""" + + def forward(self, td: TensorDict) -> Tuple[Tensor, Tensor]: + """Return Nones for the hidden state and initial embeddings""" + return None, None + + +class ConstructivePolicy(nn.Module): + """ + Base class for constructive policies. Constructive policies take as input and instance and output a solution (sequence of actions). + "Constructive" means that a solution is created from scratch by the model. + + The structure follows roughly the following steps: + 1. Create a hidden state from the encoder + 2. Initialize decoding strategy (such as greedy, sampling, etc.) + 3. Decode the action given the hidden state and the environment state at the current step + 4. Update the environment state with the action. Repeat 3-4 until all sequences are done + 5. Obtain log likelihood, rewards etc. + + Note that an encoder is not strictly needed (see :class:`NoEncoder`).). A decoder however is always needed either in the form of a + network or a function. + + Note: + There are major differences between this decoding and most RL problems. The most important one is + that reward may not defined for partial solutions, hence we have to wait for the environment to reach a terminal + state before we can compute the reward with `env.get_reward()`. + + Warning: + We suppose environments in the `done` state are still available for sampling. This is because in NCO we need to + wait for all the environments to reach a terminal state before we can stop the decoding process. This is in + contrast with the TorchRL framework (at the moment) where the `env.rollout` function automatically resets. + You may follow tighter integration with TorchRL here: https://github.com/ai4co/rl4co/issues/72. + + Args: + encoder: Encoder to use + decoder: Decoder to use + env_name: Environment name to solve (used for automatically instantiating networks) + temperature: Temperature for the softmax during decoding + tanh_clipping: Clipping value for the tanh activation (see Bello et al. 2016) during decoding + mask_logits: Whether to mask the logits or not during decoding + train_decode_type: Decoding strategy for training + val_decode_type: Decoding strategy for validation + test_decode_type: Decoding strategy for testing + """ + + def __init__( + self, + encoder: Union[ConstructiveEncoder, Callable], + decoder: Union[ConstructiveDecoder, Callable], + env_name: str = "tsp", + temperature: float = 1.0, + tanh_clipping: float = 0, + mask_logits: bool = True, + train_decode_type: str = "sampling", + val_decode_type: str = "greedy", + test_decode_type: str = "greedy", + **unused_kw, + ): + super(ConstructivePolicy, self).__init__() + + if len(unused_kw) > 0: + log.error(f"Found {len(unused_kw)} unused kwargs: {unused_kw}") + + self.env_name = env_name + + # Encoder and decoder + if encoder is None: + log.warning("`None` was provided as encoder. Using `NoEncoder`.") + encoder = NoEncoder() + self.encoder = encoder + self.decoder = decoder + + # Decoding strategies + self.temperature = temperature + self.tanh_clipping = tanh_clipping + self.mask_logits = mask_logits + self.train_decode_type = train_decode_type + self.val_decode_type = val_decode_type + self.test_decode_type = test_decode_type + + def forward( + self, + td: TensorDict, + env: Optional[Union[str, RL4COEnvBase]] = None, + phase: str = "train", + calc_reward: bool = True, + return_actions: bool = False, + return_entropy: bool = False, + return_hidden: bool = False, + return_init_embeds: bool = False, + return_sum_log_likelihood: bool = True, + actions=None, + max_steps=1_000_000, + **decoding_kwargs, + ) -> dict: + """Forward pass of the policy. + + Args: + td: TensorDict containing the environment state + env: Environment to use for decoding. If None, the environment is instantiated from `env_name`. Note that + it is more efficient to pass an already instantiated environment each time for fine-grained control + phase: Phase of the algorithm (train, val, test) + calc_reward: Whether to calculate the reward + return_actions: Whether to return the actions + return_entropy: Whether to return the entropy + return_hidden: Whether to return the hidden state + return_init_embeds: Whether to return the initial embeddings + return_sum_log_likelihood: Whether to return the sum of the log likelihood + actions: Actions to use for evaluating the policy. + If passed, use these actions instead of sampling from the policy to calculate log likelihood + max_steps: Maximum number of decoding steps for sanity check to avoid infinite loops if envs are buggy (i.e. do not reach `done`) + decoding_kwargs: Keyword arguments for the decoding strategy. See :class:`rl4co.utils.decoding.DecodingStrategy` for more information. + + Returns: + out: Dictionary containing the reward, log likelihood, and optionally the actions and entropy + """ + + # Encoder: get encoder output and initial embeddings from initial state + hidden, init_embeds = self.encoder(td) + + # Instantiate environment if needed + if isinstance(env, str) or env is None: + env_name = self.env_name if env is None else env + log.info(f"Instantiated environment not provided; instantiating {env_name}") + env = get_env(env_name) + + # Get decode type depending on phase and whether actions are passed for evaluation + decode_type = decoding_kwargs.pop("decode_type", None) + if actions is not None: + decode_type = "evaluate" + elif decode_type is None: + decode_type = getattr(self, f"{phase}_decode_type") + + # Setup decoding strategy + # we pop arguments that are not part of the decoding strategy + decode_strategy: DecodingStrategy = get_decoding_strategy( + decode_type, + temperature=decoding_kwargs.pop("temperature", self.temperature), + tanh_clipping=decoding_kwargs.pop("tanh_clipping", self.tanh_clipping), + mask_logits=decoding_kwargs.pop("mask_logits", self.mask_logits), + store_all_logp=decoding_kwargs.pop("store_all_logp", return_entropy), + **decoding_kwargs, + ) + + # Pre-decoding hook: used for the initial step(s) of the decoding strategy + td, env, num_starts = decode_strategy.pre_decoder_hook(td, env) + + # Additionally call a decoder hook if needed before main decoding + td, env, hidden = self.decoder.pre_decoder_hook(td, env, hidden, num_starts) + + # Main decoding: loop until all sequences are done + step = 0 + while not td["done"].all(): + logits, mask = self.decoder(td, hidden, num_starts) + td = decode_strategy.step( + logits, + mask, + td, + action=actions[..., step] if actions is not None else None, + ) + td = env.step(td)["next"] + step += 1 + if step > max_steps: + log.error( + f"Exceeded maximum number of steps ({max_steps}) duing decoding" + ) + break + + # Post-decoding hook: used for the final step(s) of the decoding strategy + logprobs, actions, td, env = decode_strategy.post_decoder_hook(td, env) + + # Output dictionary construction + if calc_reward: + td.set("reward", env.get_reward(td, actions)) + + outdict = { + "reward": td["reward"], + "log_likelihood": get_log_likelihood( + logprobs, actions, td.get("mask", None), return_sum_log_likelihood + ), + } + + if return_actions: + outdict["actions"] = actions + if return_entropy: + outdict["entropy"] = calculate_entropy(logprobs) + if return_hidden: + outdict["hidden"] = hidden + if return_init_embeds: + outdict["init_embeds"] = init_embeds + + return outdict diff --git a/rl4co/models/common/constructive/nonautoregressive/__init__.py b/rl4co/models/common/constructive/nonautoregressive/__init__.py new file mode 100644 index 00000000..f170d079 --- /dev/null +++ b/rl4co/models/common/constructive/nonautoregressive/__init__.py @@ -0,0 +1,9 @@ +from rl4co.models.common.constructive.nonautoregressive.decoder import ( + NonAutoregressiveDecoder, +) +from rl4co.models.common.constructive.nonautoregressive.encoder import ( + NonAutoregressiveEncoder, +) +from rl4co.models.common.constructive.nonautoregressive.policy import ( + NonAutoregressivePolicy, +) diff --git a/rl4co/models/common/constructive/nonautoregressive/decoder.py b/rl4co/models/common/constructive/nonautoregressive/decoder.py new file mode 100644 index 00000000..a649121e --- /dev/null +++ b/rl4co/models/common/constructive/nonautoregressive/decoder.py @@ -0,0 +1,40 @@ +from functools import lru_cache + +import torch + +from tensordict import TensorDict + +from rl4co.models.common.constructive.base import ConstructiveDecoder +from rl4co.utils.ops import batchify + + +@lru_cache(10) +def _multistart_batched_index(batch_size: int, num_starts: int): + """Create a batched index for multistart decoding""" + arr = torch.arange(batch_size) + if num_starts <= 1: + return arr + else: + return batchify(arr, num_starts) + + +class NonAutoregressiveDecoder(ConstructiveDecoder): + """The nonautoregressive decoder is a simple callable class that + takes the tensor dictionary and the heatmaps logits and returns the logits for the current + action logits and the action mask. + """ + + def forward(self, td: TensorDict, heatmaps_logits: torch.Tensor, num_starts: int): + return self.heatmap_to_logits(td, heatmaps_logits, num_starts) + + @staticmethod + def heatmap_to_logits(td: TensorDict, heatmaps_logits: torch.Tensor, num_starts: int): + """Obtain heatmap logits for current action to the next ones""" + current_action = td.get("action", None) + if current_action is None: + logits = heatmaps_logits.mean(-1) + else: + batch_size = heatmaps_logits.shape[0] + _indexer = _multistart_batched_index(batch_size, num_starts) + logits = heatmaps_logits[_indexer, current_action, :] + return logits, td["action_mask"] diff --git a/rl4co/models/common/constructive/nonautoregressive/encoder.py b/rl4co/models/common/constructive/nonautoregressive/encoder.py new file mode 100644 index 00000000..cfaf5392 --- /dev/null +++ b/rl4co/models/common/constructive/nonautoregressive/encoder.py @@ -0,0 +1,13 @@ +import abc + +from rl4co.models.common.constructive.base import ConstructiveEncoder + + +class NonAutoregressiveEncoder(ConstructiveEncoder, metaclass=abc.ABCMeta): + """Template class for an autoregressive encoder, simple wrapper around + :class:`rl4co.models.common.constructive.base.ConstructiveEncoder`. + + Tip: + This class will not work as it is and is just a template. + An example for autoregressive encoder can be found as :class:`rl4co.models.zoo.am.encoder.AttentionModelEncoder`. + """ diff --git a/rl4co/models/common/constructive/nonautoregressive/policy.py b/rl4co/models/common/constructive/nonautoregressive/policy.py new file mode 100644 index 00000000..ad5b724c --- /dev/null +++ b/rl4co/models/common/constructive/nonautoregressive/policy.py @@ -0,0 +1,40 @@ +from rl4co.models.common.constructive.base import ConstructivePolicy + +from .decoder import NonAutoregressiveDecoder +from .encoder import NonAutoregressiveEncoder + + +class NonAutoregressivePolicy(ConstructivePolicy): + """Template class for an nonautoregressive policy, simple wrapper around + :class:`rl4co.models.common.constructive.base.ConstructivePolicy`. + """ + + def __init__( + self, + encoder: NonAutoregressiveEncoder, + decoder: NonAutoregressiveDecoder = None, + env_name: str = "tsp", + temperature: float = 1.0, + tanh_clipping: float = 0, + mask_logits: bool = True, + train_decode_type: str = "sampling", + val_decode_type: str = "greedy", + test_decode_type: str = "greedy", + **unused_kw, + ): + # If decoder is not passed, we default to the non-autoregressive decoder that decodes the heatmap + if decoder is None: + decoder = NonAutoregressiveDecoder() + + super(NonAutoregressivePolicy, self).__init__( + encoder=encoder, + decoder=decoder, + env_name=env_name, + temperature=temperature, + tanh_clipping=tanh_clipping, + mask_logits=mask_logits, + train_decode_type=train_decode_type, + val_decode_type=val_decode_type, + test_decode_type=test_decode_type, + **unused_kw, + ) diff --git a/rl4co/models/common/improvement/__init__.py b/rl4co/models/common/improvement/__init__.py new file mode 100644 index 00000000..3eb4a954 --- /dev/null +++ b/rl4co/models/common/improvement/__init__.py @@ -0,0 +1 @@ +from rl4co.models.common.improvement.base import ImprovementDecoder, ImprovementEncoder, ImprovementPolicy \ No newline at end of file diff --git a/rl4co/models/common/improvement/base.py b/rl4co/models/common/improvement/base.py new file mode 100644 index 00000000..f97e07f3 --- /dev/null +++ b/rl4co/models/common/improvement/base.py @@ -0,0 +1,146 @@ +import abc + +from typing import Tuple, Union + +import torch.nn as nn + +from tensordict import TensorDict +from torch import Tensor + +from rl4co.envs import RL4COEnvBase +from rl4co.models.nn.env_embeddings import env_init_embedding +from rl4co.models.nn.pos_embeddings import pos_init_embedding +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class ImprovementEncoder(nn.Module): + """Base class for the encoder of improvement models""" + + def __init__( + self, + embed_dim: int = 128, + init_embedding: nn.Module = None, + pos_embedding: nn.Module = None, + env_name: str = "pdp_ruin_repair", + pos_type: str = "CPE", + num_heads: int = 4, + num_layers: int = 3, + normalization: str = "layer", + feedforward_hidden: int = 128, + linear_bias: bool = False, + ): + super(ImprovementEncoder, self).__init__() + + if isinstance(env_name, RL4COEnvBase): + env_name = env_name.name + self.env_name = env_name + self.init_embedding = ( + env_init_embedding( + self.env_name, {"embed_dim": embed_dim, "linear_bias": linear_bias} + ) + if init_embedding is None + else init_embedding + ) + + self.pos_type = pos_type + self.pos_embedding = ( + pos_init_embedding(self.pos_type, {"embed_dim": embed_dim}) + if pos_embedding is None + else pos_embedding + ) + + @abc.abstractmethod + def _encoder_forward(self, init_h: Tensor, init_p: Tensor) -> Tuple[Tensor, Tensor]: + """Process the node embeddings and positional embeddings to the final embeddings + + Args: + init_h: initialized node embeddings + init_p: initialized positional embeddings + + Returns: + Tuple containing the final node embeddings and final positional embeddings (if any) + """ + raise NotImplementedError("Implement me in subclass!") + + def forward(self, td: TensorDict) -> Tuple[Tensor, Tensor]: + """Forward pass of the encoder. + Transform the input TensorDict into a latent representation. + + Args: + td: Input TensorDict containing the environment state + + Returns: + h: Latent representation of the input + init_h: Initial embedding of the input + """ + # Transfer to embedding space (node) + init_h = self.init_embedding(td) + + # Transfer to embedding space (solution) + init_p = self.pos_embedding(td) + + # Process embedding + final_h, final_p = self._encoder_forward(init_h, init_p) + + # Return latent representation and initial embedding + return final_h, final_p + + +class ImprovementDecoder(nn.Module, metaclass=abc.ABCMeta): + """Base decoder model for improvement models. The decoder is responsible for generating the logits of the action""" + + @abc.abstractmethod + def forward(self, td: TensorDict, final_h: Tensor, final_p: Tensor) -> Tensor: + """Obtain logits to perform operators that improve the current solution to the next ones + + Args: + td: TensorDict with the current environment state + final_h: final node embeddings + final_p: final positional embeddings + + Returns: + Tuple containing the logits + """ + raise NotImplementedError("Implement me in subclass!") + + +class ImprovementPolicy(nn.Module): + """ + Base class for improvement policies. Improvement policies take an instance + a solution as input and output a specific operator that changes the current solution to a new one. + + "Improvement" means that a solution is (potentially) improved to a new one by the model. + + """ + + @abc.abstractmethod + def forward( + self, + td: TensorDict, + env: Union[str, RL4COEnvBase] = None, + phase: str = "train", + return_actions: bool = False, + return_entropy: bool = False, + return_init_embeds: bool = False, + actions=None, + **decoding_kwargs, + ) -> dict: + """Forward pass of the policy. + + Args: + td: TensorDict containing the environment state + env: Environment to use for decoding. If None, the environment is instantiated from `env_name`. Note that + it is more efficient to pass an already instantiated environment each time for fine-grained control + phase: Phase of the algorithm (train, val, test) + return_actions: Whether to return the actions + return_entropy: Whether to return the entropy + return_init_embeds: Whether to return the initial embeddings + actions: Actions to use for evaluating the policy. + If passed, use these actions instead of sampling from the policy to calculate log likelihood + decoding_kwargs: Keyword arguments for the decoding strategy. See :class:`rl4co.utils.decoding.DecodingStrategy` for more information. + + Returns: + out: Dictionary containing the reward, log likelihood, and optionally the actions and entropy + """ + raise NotImplementedError("Implement me in subclass!") diff --git a/rl4co/models/common/transductive/__init__.py b/rl4co/models/common/transductive/__init__.py new file mode 100644 index 00000000..961db6ff --- /dev/null +++ b/rl4co/models/common/transductive/__init__.py @@ -0,0 +1 @@ +from rl4co.models.common.transductive.base import TransductiveModel diff --git a/rl4co/models/common/transductive/base.py b/rl4co/models/common/transductive/base.py new file mode 100644 index 00000000..1ba42082 --- /dev/null +++ b/rl4co/models/common/transductive/base.py @@ -0,0 +1,93 @@ +import abc + +from typing import Any, Optional, Union + +from lightning.pytorch.utilities.types import STEP_OUTPUT +from torch.utils.data import Dataset + +from rl4co.models.rl.common.base import RL4COLitModule + + +class TransductiveModel(RL4COLitModule, metaclass=abc.ABCMeta): + """Base class for transductive algorithms (i.e. that optimize policy parameters for + specific instances, see https://en.wikipedia.org/wiki/Transduction_(machine_learning)). + Transductive algorithms are used online to find better solutions for a given dataset, i.e. + given a policy, improve (a part of) its parameters such that + the policy performs better on the given dataset. + + Note: + By default, we use manual optimization to handle the search. + + Args: + env: RL4CO environment + policy: policy network + dataset: dataset to use for training + batch_size: batch size + max_iters: maximum number of iterations + max_runtime: maximum runtime in seconds + save_path: path to save the model + **kwargs: additional arguments + """ + + def __init__( + self, + env, + policy, + dataset: Union[Dataset, str], + batch_size: int = 1, + max_iters: int = 100, + max_runtime: Optional[int] = 86_400, + save_path: Optional[str] = None, + **kwargs, + ): + self.save_hyperparameters(logger=False) + super().__init__(env, policy, **kwargs) + self.dataset = dataset + self.automatic_optimization = False # we optimize manually + + def setup(self, stage="fit"): + """Setup the dataset and attributes. + The RL4COLitModulebase class automatically loads the data. + """ + if isinstance(self.dataset, str): + # load from file + self.dataset = self.env.dataset(filename=self.dataset) + + # Set all datasets and batch size as the same + for split in ["train", "val", "test"]: + setattr(self, f"{split}_dataset", self.dataset) + setattr(self, f"{split}_batch_size", self.hparams.batch_size) + + # Setup loggers + self.setup_loggers() + + def on_train_batch_start(self, batch: Any, batch_idx: int): + """Called before training (i.e. search) for a new batch begins. + This can be used to perform changes to the model or optimizer at the start of each batch. + """ + pass # Implement in subclass + + @abc.abstractmethod + def training_step(self, batch, batch_idx): + """Main search loop. We use the training step to effectively adapt to a `batch` of instances.""" + raise NotImplementedError("Implement in subclass") + + def on_train_batch_end( + self, outputs: STEP_OUTPUT, batch: Any, batch_idx: int + ) -> None: + """Called when the train batch ends. This can be used for + instance for logging or clearing cache. + """ + pass # Implement in subclass + + def on_train_epoch_end(self) -> None: + """Called when the train ends.""" + pass # Implement in subclass + + def validation_step(self, batch: Any, batch_idx: int): + """Not used during search""" + pass + + def test_step(self, batch: Any, batch_idx: int): + """Not used during search""" + pass diff --git a/rl4co/models/nn/__init__.py b/rl4co/models/nn/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/models/nn/attention.py b/rl4co/models/nn/attention.py new file mode 100644 index 00000000..b65169f0 --- /dev/null +++ b/rl4co/models/nn/attention.py @@ -0,0 +1,537 @@ +import itertools +import math +import warnings + +from typing import Callable, Optional, Union + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from einops import rearrange + +from rl4co.models.nn.moe import MoE +from rl4co.utils import get_pylogger + +log = get_pylogger(__name__) + + +def scaled_dot_product_attention_simple( + q, k, v, attn_mask=None, dropout_p=0.0, is_causal=False +): + """Simple Scaled Dot-Product Attention in PyTorch without Flash Attention""" + # Check for causal and attn_mask conflict + if is_causal and attn_mask is not None: + raise ValueError("Cannot set both is_causal and attn_mask") + + # Calculate scaled dot product + scores = torch.matmul(q, k.transpose(-2, -1)) / (k.size(-1) ** 0.5) + + # Apply the provided attention mask + if attn_mask is not None: + if attn_mask.dtype == torch.bool: + scores.masked_fill_(~attn_mask, float("-inf")) + else: + scores += attn_mask + + # Apply causal mask + if is_causal: + s, l_ = scores.size(-2), scores.size(-1) + mask = torch.triu(torch.ones((s, l_), device=scores.device), diagonal=1) + scores.masked_fill_(mask.bool(), float("-inf")) + + # Softmax to get attention weights + attn_weights = F.softmax(scores, dim=-1) + + # Apply dropout + if dropout_p > 0.0: + attn_weights = F.dropout(attn_weights, p=dropout_p) + + # Compute the weighted sum of values + return torch.matmul(attn_weights, v) + + +try: + from torch.nn.functional import scaled_dot_product_attention +except ImportError: + log.warning( + "torch.nn.functional.scaled_dot_product_attention not found. Make sure you are using PyTorch >= 2.0.0." + "Alternatively, install Flash Attention https://github.com/HazyResearch/flash-attention ." + "Using custom implementation of scaled_dot_product_attention without Flash Attention. " + ) + scaled_dot_product_attention = scaled_dot_product_attention_simple + + +class MultiHeadAttention(nn.Module): + """PyTorch native implementation of Flash Multi-Head Attention with automatic mixed precision support. + Uses PyTorch's native `scaled_dot_product_attention` implementation, available from 2.0 + + Note: + If `scaled_dot_product_attention` is not available, use custom implementation of `scaled_dot_product_attention` without Flash Attention. + + Args: + embed_dim: total dimension of the model + num_heads: number of heads + bias: whether to use bias + attention_dropout: dropout rate for attention weights + causal: whether to apply causal mask to attention scores + device: torch device + dtype: torch dtype + sdpa_fn: scaled dot product attention function (SDPA) implementation + """ + + def __init__( + self, + embed_dim: int, + num_heads: int, + bias: bool = True, + attention_dropout: float = 0.0, + causal: bool = False, + device: str = None, + dtype: torch.dtype = None, + sdpa_fn: Optional[Callable] = None, + ) -> None: + factory_kwargs = {"device": device, "dtype": dtype} + super().__init__() + self.embed_dim = embed_dim + self.causal = causal + self.attention_dropout = attention_dropout + self.sdpa_fn = sdpa_fn if sdpa_fn is not None else scaled_dot_product_attention + + self.num_heads = num_heads + assert self.embed_dim % num_heads == 0, "self.kdim must be divisible by num_heads" + self.head_dim = self.embed_dim // num_heads + assert ( + self.head_dim % 8 == 0 and self.head_dim <= 128 + ), "Only support head_dim <= 128 and divisible by 8" + + self.Wqkv = nn.Linear(embed_dim, 3 * embed_dim, bias=bias, **factory_kwargs) + self.out_proj = nn.Linear(embed_dim, embed_dim, bias=bias, **factory_kwargs) + + def forward(self, x, attn_mask=None): + """x: (batch, seqlen, hidden_dim) (where hidden_dim = num heads * head dim) + attn_mask: bool tensor of shape (batch, seqlen) + """ + # Project query, key, value + q, k, v = rearrange( + self.Wqkv(x), "b s (three h d) -> three b h s d", three=3, h=self.num_heads + ).unbind(dim=0) + + if attn_mask is not None: + attn_mask = ( + attn_mask.unsqueeze(1) + if attn_mask.ndim == 3 + else attn_mask.unsqueeze(1).unsqueeze(2) + ) + + # Scaled dot product attention + out = self.sdpa_fn( + q, + k, + v, + attn_mask=attn_mask, + dropout_p=self.attention_dropout, + ) + return self.out_proj(rearrange(out, "b h s d -> b s (h d)")) + + +def sdpa_fn_wrapper(q, k, v, attn_mask=None, dmat=None, dropout_p=0.0, is_causal=False): + if dmat is not None: + log.warning( + "Edge weights passed to simple attention-fn, which is not supported. Weights will be ignored..." + ) + return scaled_dot_product_attention( + q, k, v, attn_mask=attn_mask, dropout_p=dropout_p, is_causal=is_causal + ) + + +class MultiHeadCrossAttention(nn.Module): + """PyTorch native implementation of Flash Multi-Head Cross Attention with automatic mixed precision support. + Uses PyTorch's native `scaled_dot_product_attention` implementation, available from 2.0 + + Note: + If `scaled_dot_product_attention` is not available, use custom implementation of `scaled_dot_product_attention` without Flash Attention. + + Args: + embed_dim: total dimension of the model + num_heads: number of heads + bias: whether to use bias + attention_dropout: dropout rate for attention weights + device: torch device + dtype: torch dtype + sdpa_fn: scaled dot product attention function (SDPA) + """ + + def __init__( + self, + embed_dim: int, + num_heads: int, + bias: bool = False, + attention_dropout: float = 0.0, + device: str = None, + dtype: torch.dtype = None, + sdpa_fn: Optional[Union[Callable, nn.Module]] = None, + ) -> None: + factory_kwargs = {"device": device, "dtype": dtype} + super().__init__() + self.embed_dim = embed_dim + self.attention_dropout = attention_dropout + + # Default to `scaled_dot_product_attention` if `sdpa_fn` is not provided + if sdpa_fn is None: + sdpa_fn = sdpa_fn_wrapper + self.sdpa_fn = sdpa_fn + + self.num_heads = num_heads + assert self.embed_dim % num_heads == 0, "self.kdim must be divisible by num_heads" + self.head_dim = self.embed_dim // num_heads + assert ( + self.head_dim % 8 == 0 and self.head_dim <= 128 + ), "Only support head_dim <= 128 and divisible by 8" + + self.Wq = nn.Linear(embed_dim, embed_dim, bias=bias, **factory_kwargs) + self.Wkv = nn.Linear(embed_dim, 2 * embed_dim, bias=bias, **factory_kwargs) + self.out_proj = nn.Linear(embed_dim, embed_dim, bias=bias, **factory_kwargs) + + def forward(self, q_input, kv_input, cross_attn_mask=None, dmat=None): + # Project query, key, value + q = rearrange( + self.Wq(q_input), "b m (h d) -> b h m d", h=self.num_heads + ) # [b, h, m, d] + k, v = rearrange( + self.Wkv(kv_input), "b n (two h d) -> two b h n d", two=2, h=self.num_heads + ).unbind( + dim=0 + ) # [b, h, n, d] + + if cross_attn_mask is not None: + # add head dim + cross_attn_mask = cross_attn_mask.unsqueeze(1) + + # Scaled dot product attention + out = self.sdpa_fn( + q, + k, + v, + attn_mask=cross_attn_mask, + dmat=dmat, + dropout_p=self.attention_dropout, + ) + return self.out_proj(rearrange(out, "b h s d -> b s (h d)")) + + +class PointerAttention(nn.Module): + """Calculate logits given query, key and value and logit key. + This follows the pointer mechanism of Vinyals et al. (2015) (https://arxiv.org/abs/1506.03134). + + Note: + With Flash Attention, masking is not supported + + Performs the following: + 1. Apply cross attention to get the heads + 2. Project heads to get glimpse + 3. Compute attention score between glimpse and logit key + + Args: + embed_dim: total dimension of the model + num_heads: number of heads + mask_inner: whether to mask inner attention + linear_bias: whether to use bias in linear projection + check_nan: whether to check for NaNs in logits + sdpa_fn: scaled dot product attention function (SDPA) implementation + """ + + def __init__( + self, + embed_dim: int, + num_heads: int, + mask_inner: bool = True, + out_bias: bool = False, + check_nan: bool = True, + sdpa_fn: Optional[Callable] = None, + **kwargs, + ): + super(PointerAttention, self).__init__() + self.num_heads = num_heads + self.mask_inner = mask_inner + + # Projection - query, key, value already include projections + self.project_out = nn.Linear(embed_dim, embed_dim, bias=out_bias) + self.sdpa_fn = sdpa_fn if sdpa_fn is not None else scaled_dot_product_attention + self.check_nan = check_nan + + def forward(self, query, key, value, logit_key, attn_mask=None): + """Compute attention logits given query, key, value, logit key and attention mask. + + Args: + query: query tensor of shape [B, ..., L, E] + key: key tensor of shape [B, ..., S, E] + value: value tensor of shape [B, ..., S, E] + logit_key: logit key tensor of shape [B, ..., S, E] + attn_mask: attention mask tensor of shape [B, ..., S]. Note that `True` means that the value _should_ take part in attention + as described in the [PyTorch Documentation](https://pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html) + """ + # Compute inner multi-head attention with no projections. + heads = self._inner_mha(query, key, value, attn_mask) + glimpse = self._project_out(heads, attn_mask) + + # Batch matrix multiplication to compute logits (batch_size, num_steps, graph_size) + # bmm is slightly faster than einsum and matmul + logits = (torch.bmm(glimpse, logit_key.squeeze(-2).transpose(-2, -1))).squeeze( + -2 + ) / math.sqrt(glimpse.size(-1)) + + if self.check_nan: + assert not torch.isnan(logits).any(), "Logits contain NaNs" + + return logits + + def _inner_mha(self, query, key, value, attn_mask): + q = self._make_heads(query) + k = self._make_heads(key) + v = self._make_heads(value) + if self.mask_inner: + # make mask the same number of dimensions as q + attn_mask = ( + attn_mask.unsqueeze(1) + if attn_mask.ndim == 3 + else attn_mask.unsqueeze(1).unsqueeze(2) + ) + else: + attn_mask = None + heads = self.sdpa_fn(q, k, v, attn_mask=attn_mask) + return rearrange(heads, "... h n g -> ... n (h g)", h=self.num_heads) + + def _make_heads(self, v): + return rearrange(v, "... g (h s) -> ... h g s", h=self.num_heads) + + def _project_out(self, out, *kwargs): + return self.project_out(out) + + +class PointerAttnMoE(PointerAttention): + """Calculate logits given query, key and value and logit key. + This follows the pointer mechanism of Vinyals et al. (2015) , + and the MoE gating mechanism of Zhou et al. (2024) . + + Note: + With Flash Attention, masking is not supported + + Performs the following: + 1. Apply cross attention to get the heads + 2. Project heads to get glimpse + 3. Compute attention score between glimpse and logit key + + Args: + embed_dim: total dimension of the model + num_heads: number of heads + mask_inner: whether to mask inner attention + linear_bias: whether to use bias in linear projection + check_nan: whether to check for NaNs in logits + sdpa_fn: scaled dot product attention function (SDPA) implementation + moe_kwargs: Keyword arguments for MoE + """ + + def __init__( + self, + embed_dim: int, + num_heads: int, + mask_inner: bool = True, + out_bias: bool = False, + check_nan: bool = True, + sdpa_fn: Optional[Callable] = None, + moe_kwargs: Optional[dict] = None, + ): + super(PointerAttnMoE, self).__init__( + embed_dim, num_heads, mask_inner, out_bias, check_nan, sdpa_fn + ) + self.moe_kwargs = moe_kwargs + + self.project_out = None + self.project_out_moe = MoE( + embed_dim, embed_dim, num_neurons=[], out_bias=out_bias, **moe_kwargs + ) + if self.moe_kwargs["light_version"]: + self.dense_or_moe = nn.Linear(embed_dim, 2, bias=False) + self.project_out = nn.Linear(embed_dim, embed_dim, bias=out_bias) + + def _project_out(self, out, attn_mask): + """Implementation of Hierarchical Gating based on Zhou et al. (2024) .""" + if self.moe_kwargs["light_version"]: + num_nodes, num_available_nodes = attn_mask.size(-1), attn_mask.sum(-1) + # only do this at the "second" step, which is depot -> pomo -> first select + if (num_available_nodes >= num_nodes - 1).any(): + self.probs = F.softmax( + self.dense_or_moe( + out.view(-1, out.size(-1)).mean(dim=0, keepdim=True) + ), + dim=-1, + ) + selected = self.probs.multinomial(1).squeeze(0) + out = ( + self.project_out_moe(out) + if selected.item() == 1 + else self.project_out(out) + ) + glimpse = out * self.probs.squeeze(0)[selected] + else: + glimpse = self.project_out_moe(out) + return glimpse + + +# Deprecated +class LogitAttention(PointerAttention): + def __init__(self, *args, **kwargs): + warnings.simplefilter("always", DeprecationWarning) + warnings.warn( + "LogitAttention is deprecated and will be removed in a future release. " + "Please use PointerAttention instead." + "Note that several components of the previous LogitAttention have moved to `rl4co.models.nn.dec_strategies`.", + category=DeprecationWarning, + ) + super(LogitAttention, self).__init__(*args, **kwargs) + + +# MultiHeadCompat +class MultiHeadCompat(nn.Module): + def __init__(self, n_heads, input_dim, embed_dim=None, val_dim=None, key_dim=None): + super(MultiHeadCompat, self).__init__() + + if val_dim is None: + # assert embed_dim is not None, "Provide either embed_dim or val_dim" + val_dim = embed_dim // n_heads + if key_dim is None: + key_dim = val_dim + + self.n_heads = n_heads + self.input_dim = input_dim + self.embed_dim = embed_dim + self.val_dim = val_dim + self.key_dim = key_dim + + self.W_query = nn.Parameter(torch.Tensor(n_heads, input_dim, key_dim)) + self.W_key = nn.Parameter(torch.Tensor(n_heads, input_dim, key_dim)) + + self.init_parameters() + + # used for init nn.Parameter + def init_parameters(self): + for param in self.parameters(): + stdv = 1.0 / math.sqrt(param.size(-1)) + param.data.uniform_(-stdv, stdv) + + def forward(self, q, h=None, mask=None): + """ + + :param q: queries (batch_size, n_query, input_dim) + :param h: data (batch_size, graph_size, input_dim) + :param mask: mask (batch_size, n_query, graph_size) or viewable as that (i.e. can be 2 dim if n_query == 1) + Mask should contain 1 if attention is not possible (i.e. mask is negative adjacency) + :return: + """ + + if h is None: + h = q # compute self-attention + + # h should be (batch_size, graph_size, input_dim) + batch_size, graph_size, input_dim = h.size() + n_query = q.size(1) + + hflat = h.contiguous().view(-1, input_dim) ################# reshape + qflat = q.contiguous().view(-1, input_dim) + + # last dimension can be different for keys and values + shp = (self.n_heads, batch_size, graph_size, -1) + shp_q = (self.n_heads, batch_size, n_query, -1) + + # Calculate queries, (n_heads, n_query, graph_size, key/val_size) + Q = torch.matmul(qflat, self.W_query).view(shp_q) + K = torch.matmul(hflat, self.W_key).view(shp) + + # Calculate compatibility (n_heads, batch_size, n_query, graph_size) + compatibility_s2n = torch.matmul(Q, K.transpose(2, 3)) + + return compatibility_s2n + + +class PolyNetAttention(PointerAttention): + """Calculate logits given query, key and value and logit key. + This implements a modified version the pointer mechanism of Vinyals et al. (2015) (https://arxiv.org/abs/1506.03134) + as described in Hottung et al. (2024) (https://arxiv.org/abs/2402.14048) PolyNetAttention conditions the attention logits on + a set of k different binary vectors allowing to learn k different solution strategies. + + Note: + With Flash Attention, masking is not supported + + Performs the following: + 1. Apply cross attention to get the heads + 2. Project heads to get glimpse + 3. Apply PolyNet layers + 4. Compute attention score between glimpse and logit key + + Args: + k: Number unique bit vectors used to compute attention score + embed_dim: total dimension of the model + poly_layer_dim: Dimension of the PolyNet layers + num_heads: number of heads + mask_inner: whether to mask inner attention + linear_bias: whether to use bias in linear projection + check_nan: whether to check for NaNs in logits + sdpa_fn: scaled dot product attention function (SDPA) implementation + """ + + def __init__( + self, k: int, embed_dim: int, poly_layer_dim: int, num_heads: int, **kwargs + ): + super(PolyNetAttention, self).__init__(embed_dim, num_heads, **kwargs) + + self.k = k + self.binary_vector_dim = math.ceil(math.log2(k)) + self.binary_vectors = torch.nn.Parameter( + torch.Tensor( + list(itertools.product([0, 1], repeat=self.binary_vector_dim))[:k] + ), + requires_grad=False, + ) + + self.poly_layer_1 = nn.Linear(embed_dim + self.binary_vector_dim, poly_layer_dim) + self.poly_layer_2 = nn.Linear(poly_layer_dim, embed_dim) + + def forward(self, query, key, value, logit_key, attn_mask=None): + """Compute attention logits given query, key, value, logit key and attention mask. + + Args: + query: query tensor of shape [B, ..., L, E] + key: key tensor of shape [B, ..., S, E] + value: value tensor of shape [B, ..., S, E] + logit_key: logit key tensor of shape [B, ..., S, E] + attn_mask: attention mask tensor of shape [B, ..., S]. Note that `True` means that the value _should_ take part in attention + as described in the [PyTorch Documentation](https://pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html) + """ + # Compute inner multi-head attention with no projections. + heads = self._inner_mha(query, key, value, attn_mask) + glimpse = self.project_out(heads) + + num_solutions = glimpse.shape[1] + z = self.binary_vectors.repeat(math.ceil(num_solutions / self.k), 1)[ + :num_solutions + ] + z = z[None].expand(glimpse.shape[0], num_solutions, self.binary_vector_dim) + + # PolyNet layers + poly_out = self.poly_layer_1(torch.cat((glimpse, z), dim=2)) + poly_out = F.relu(poly_out) + poly_out = self.poly_layer_2(poly_out) + + glimpse += poly_out + + # Batch matrix multiplication to compute logits (batch_size, num_steps, graph_size) + # bmm is slightly faster than einsum and matmul + logits = (torch.bmm(glimpse, logit_key.squeeze(-2).transpose(-2, -1))).squeeze( + -2 + ) / math.sqrt(glimpse.size(-1)) + + if self.check_nan: + assert not torch.isnan(logits).any(), "Logits contain NaNs" + + return logits diff --git a/rl4co/models/nn/env_embeddings/__init__.py b/rl4co/models/nn/env_embeddings/__init__.py new file mode 100644 index 00000000..0c0e870e --- /dev/null +++ b/rl4co/models/nn/env_embeddings/__init__.py @@ -0,0 +1,4 @@ +from rl4co.models.nn.env_embeddings.context import env_context_embedding +from rl4co.models.nn.env_embeddings.dynamic import env_dynamic_embedding +from rl4co.models.nn.env_embeddings.edge import env_edge_embedding +from rl4co.models.nn.env_embeddings.init import env_init_embedding diff --git a/rl4co/models/nn/env_embeddings/context.py b/rl4co/models/nn/env_embeddings/context.py new file mode 100644 index 00000000..b6059f04 --- /dev/null +++ b/rl4co/models/nn/env_embeddings/context.py @@ -0,0 +1,372 @@ +import torch +import torch.nn as nn + +from tensordict import TensorDict + +from rl4co.utils.ops import gather_by_index + + +def env_context_embedding(env_name: str, config: dict) -> nn.Module: + """Get environment context embedding. The context embedding is used to modify the + query embedding of the problem node of the current partial solution. + Usually consists of a projection of gathered node embeddings and features to the embedding space. + + Args: + env: Environment or its name. + config: A dictionary of configuration options for the environment. + """ + embedding_registry = { + "tsp": TSPContext, + "atsp": TSPContext, + "cvrp": VRPContext, + "cvrptw": VRPTWContext, + "ffsp": FFSPContext, + "svrp": SVRPContext, + "sdvrp": VRPContext, + "pctsp": PCTSPContext, + "spctsp": PCTSPContext, + "op": OPContext, + "dpp": DPPContext, + "mdpp": DPPContext, + "pdp": PDPContext, + "mtsp": MTSPContext, + "smtwtp": SMTWTPContext, + "mdcpdp": MDCPDPContext, + "mtvrp": MTVRPContext, + } + + if env_name not in embedding_registry: + raise ValueError( + f"Unknown environment name '{env_name}'. Available context embeddings: {embedding_registry.keys()}" + ) + + return embedding_registry[env_name](**config) + + +class EnvContext(nn.Module): + """Base class for environment context embeddings. The context embedding is used to modify the + query embedding of the problem node of the current partial solution. + Consists of a linear layer that projects the node features to the embedding space.""" + + def __init__(self, embed_dim, step_context_dim=None, linear_bias=False): + super(EnvContext, self).__init__() + self.embed_dim = embed_dim + step_context_dim = step_context_dim if step_context_dim is not None else embed_dim + self.project_context = nn.Linear(step_context_dim, embed_dim, bias=linear_bias) + + def _cur_node_embedding(self, embeddings, td): + """Get embedding of current node""" + cur_node_embedding = gather_by_index(embeddings, td["current_node"]) + return cur_node_embedding + + def _state_embedding(self, embeddings, td): + """Get state embedding""" + raise NotImplementedError("Implement for each environment") + + def forward(self, embeddings, td): + cur_node_embedding = self._cur_node_embedding(embeddings, td) + state_embedding = self._state_embedding(embeddings, td) + context_embedding = torch.cat([cur_node_embedding, state_embedding], -1) + return self.project_context(context_embedding) + + +class FFSPContext(EnvContext): + def __init__(self, embed_dim, stage_cnt=None): + self.has_stage_emb = stage_cnt is not None + step_context_dim = (1 + int(self.has_stage_emb)) * embed_dim + super().__init__(embed_dim=embed_dim, step_context_dim=step_context_dim) + if self.has_stage_emb: + self.stage_emb = nn.Parameter(torch.rand(stage_cnt, embed_dim)) + + def _cur_node_embedding(self, embeddings: TensorDict, td): + cur_node_embedding = gather_by_index( + embeddings["machine_embeddings"], td["stage_machine_idx"] + ) + return cur_node_embedding + + def forward(self, embeddings, td): + cur_node_embedding = self._cur_node_embedding(embeddings, td) + if self.has_stage_emb: + state_embedding = self._state_embedding(embeddings, td) + context_embedding = torch.cat([cur_node_embedding, state_embedding], -1) + return self.project_context(context_embedding) + else: + return self.project_context(cur_node_embedding) + + def _state_embedding(self, _, td): + cur_stage_emb = self.stage_emb[td["stage_idx"]] + return cur_stage_emb + + +class TSPContext(EnvContext): + """Context embedding for the Traveling Salesman Problem (TSP). + Project the following to the embedding space: + - first node embedding + - current node embedding + """ + + def __init__(self, embed_dim): + super(TSPContext, self).__init__(embed_dim, 2 * embed_dim) + self.W_placeholder = nn.Parameter( + torch.Tensor(2 * self.embed_dim).uniform_(-1, 1) + ) + + def forward(self, embeddings, td): + batch_size = embeddings.size(0) + # By default, node_dim = -1 (we only have one node embedding per node) + node_dim = ( + (-1,) if td["first_node"].dim() == 1 else (td["first_node"].size(-1), -1) + ) + if td["i"][(0,) * td["i"].dim()].item() < 1: # get first item fast + if len(td.batch_size) < 2: + context_embedding = self.W_placeholder[None, :].expand( + batch_size, self.W_placeholder.size(-1) + ) + else: + context_embedding = self.W_placeholder[None, None, :].expand( + batch_size, td.batch_size[1], self.W_placeholder.size(-1) + ) + else: + context_embedding = gather_by_index( + embeddings, + torch.stack([td["first_node"], td["current_node"]], -1).view( + batch_size, -1 + ), + ).view(batch_size, *node_dim) + return self.project_context(context_embedding) + + +class VRPContext(EnvContext): + """Context embedding for the Capacitated Vehicle Routing Problem (CVRP). + Project the following to the embedding space: + - current node embedding + - remaining capacity (vehicle_capacity - used_capacity) + """ + + def __init__(self, embed_dim): + super(VRPContext, self).__init__( + embed_dim=embed_dim, step_context_dim=embed_dim + 1 + ) + + def _state_embedding(self, embeddings, td): + state_embedding = td["vehicle_capacity"] - td["used_capacity"] + return state_embedding + + +class VRPTWContext(VRPContext): + """Context embedding for the Capacitated Vehicle Routing Problem (CVRP). + Project the following to the embedding space: + - current node embedding + - remaining capacity (vehicle_capacity - used_capacity) + - current time + """ + + def __init__(self, embed_dim): + super(VRPContext, self).__init__( + embed_dim=embed_dim, step_context_dim=embed_dim + 2 + ) + + def _state_embedding(self, embeddings, td): + capacity = super()._state_embedding(embeddings, td) + current_time = td["current_time"] + return torch.cat([capacity, current_time], -1) + + +class SVRPContext(EnvContext): + """Context embedding for the Skill Vehicle Routing Problem (SVRP). + Project the following to the embedding space: + - current node embedding + - current technician + """ + + def __init__(self, embed_dim): + super(SVRPContext, self).__init__(embed_dim=embed_dim, step_context_dim=embed_dim) + + def forward(self, embeddings, td): + cur_node_embedding = self._cur_node_embedding(embeddings, td).squeeze() + return self.project_context(cur_node_embedding) + + +class PCTSPContext(EnvContext): + """Context embedding for the Prize Collecting TSP (PCTSP). + Project the following to the embedding space: + - current node embedding + - remaining prize (prize_required - cur_total_prize) + """ + + def __init__(self, embed_dim): + super(PCTSPContext, self).__init__(embed_dim, embed_dim + 1) + + def _state_embedding(self, embeddings, td): + state_embedding = torch.clamp( + td["prize_required"] - td["cur_total_prize"], min=0 + )[..., None] + return state_embedding + + +class OPContext(EnvContext): + """Context embedding for the Orienteering Problem (OP). + Project the following to the embedding space: + - current node embedding + - remaining distance (max_length - tour_length) + """ + + def __init__(self, embed_dim): + super(OPContext, self).__init__(embed_dim, embed_dim + 1) + + def _state_embedding(self, embeddings, td): + state_embedding = td["max_length"][..., 0] - td["tour_length"] + return state_embedding[..., None] + + +class DPPContext(EnvContext): + """Context embedding for the Decap Placement Problem (DPP), EDA (electronic design automation). + Project the following to the embedding space: + - current cell embedding + """ + + def __init__(self, embed_dim): + super(DPPContext, self).__init__(embed_dim) + + def forward(self, embeddings, td): + """Context cannot be defined by a single node embedding for DPP, hence 0. + We modify the dynamic embedding instead to capture placed items + """ + return embeddings.new_zeros(embeddings.size(0), self.embed_dim) + + +class PDPContext(EnvContext): + """Context embedding for the Pickup and Delivery Problem (PDP). + Project the following to the embedding space: + - current node embedding + """ + + def __init__(self, embed_dim): + super(PDPContext, self).__init__(embed_dim, embed_dim) + + def forward(self, embeddings, td): + cur_node_embedding = self._cur_node_embedding(embeddings, td).squeeze() + return self.project_context(cur_node_embedding) + + +class MTSPContext(EnvContext): + """Context embedding for the Multiple Traveling Salesman Problem (mTSP). + Project the following to the embedding space: + - current node embedding + - remaining_agents + - current_length + - max_subtour_length + - distance_from_depot + """ + + def __init__(self, embed_dim, linear_bias=False): + super(MTSPContext, self).__init__(embed_dim, 2 * embed_dim) + proj_in_dim = ( + 4 # remaining_agents, current_length, max_subtour_length, distance_from_depot + ) + self.proj_dynamic_feats = nn.Linear(proj_in_dim, embed_dim, bias=linear_bias) + + def _cur_node_embedding(self, embeddings, td): + cur_node_embedding = gather_by_index(embeddings, td["current_node"]) + return cur_node_embedding.squeeze() + + def _state_embedding(self, embeddings, td): + dynamic_feats = torch.stack( + [ + (td["num_agents"] - td["agent_idx"]).float(), + td["current_length"], + td["max_subtour_length"], + self._distance_from_depot(td), + ], + dim=-1, + ) + return self.proj_dynamic_feats(dynamic_feats) + + def _distance_from_depot(self, td): + # Euclidean distance from the depot (loc[..., 0, :]) + cur_loc = gather_by_index(td["locs"], td["current_node"]) + return torch.norm(cur_loc - td["locs"][..., 0, :], dim=-1) + + +class SMTWTPContext(EnvContext): + """Context embedding for the Single Machine Total Weighted Tardiness Problem (SMTWTP). + Project the following to the embedding space: + - current node embedding + - current time + """ + + def __init__(self, embed_dim): + super(SMTWTPContext, self).__init__(embed_dim, embed_dim + 1) + + def _cur_node_embedding(self, embeddings, td): + cur_node_embedding = gather_by_index(embeddings, td["current_job"]) + return cur_node_embedding + + def _state_embedding(self, embeddings, td): + state_embedding = td["current_time"] + return state_embedding + + +class MDCPDPContext(EnvContext): + """Context embedding for the MDCPDP. + Project the following to the embedding space: + - current node embedding + """ + + def __init__(self, embed_dim): + super(MDCPDPContext, self).__init__(embed_dim, embed_dim) + + def forward(self, embeddings, td): + cur_node_embedding = self._cur_node_embedding(embeddings, td).squeeze() + return self.project_context(cur_node_embedding) + + +class SchedulingContext(nn.Module): + def __init__(self, embed_dim: int, scaling_factor: int = 1000): + super().__init__() + self.scaling_factor = scaling_factor + self.proj_busy = nn.Linear(1, embed_dim, bias=False) + + def forward(self, h, td): + busy_for = (td["busy_until"] - td["time"].unsqueeze(1)) / self.scaling_factor + busy_proj = self.proj_busy(busy_for.unsqueeze(-1)) + # (b m e) + return h + busy_proj + + +class MTVRPContext(VRPContext): + """Context embedding for Multi-Task VRPEnv. + Project the following to the embedding space: + - current node embedding + - remaining_linehaul_capacity (vehicle_capacity - used_capacity_linehaul) + - remaining_backhaul_capacity (vehicle_capacity - used_capacity_backhaul) + - current time + - current_route_length + - open route indicator + """ + + def __init__(self, embed_dim): + super(VRPContext, self).__init__( + embed_dim=embed_dim, step_context_dim=embed_dim + 5 + ) + + def _state_embedding(self, embeddings, td): + remaining_linehaul_capacity = ( + td["vehicle_capacity"] - td["used_capacity_linehaul"] + ) + remaining_backhaul_capacity = ( + td["vehicle_capacity"] - td["used_capacity_backhaul"] + ) + current_time = td["current_time"] + current_route_length = td["current_route_length"] + open_route = td["open_route"] + return torch.cat( + [ + remaining_linehaul_capacity, + remaining_backhaul_capacity, + current_time, + current_route_length, + open_route, + ], + -1, + ) diff --git a/rl4co/models/nn/env_embeddings/dynamic.py b/rl4co/models/nn/env_embeddings/dynamic.py new file mode 100644 index 00000000..470af835 --- /dev/null +++ b/rl4co/models/nn/env_embeddings/dynamic.py @@ -0,0 +1,121 @@ +import torch +import torch.nn as nn + +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def env_dynamic_embedding(env_name: str, config: dict) -> nn.Module: + """Get environment dynamic embedding. The dynamic embedding is used to modify query, key and value vectors of the attention mechanism + based on the current state of the environment (which is changing during the rollout). + Consists of a linear layer that projects the node features to the embedding space. + + Args: + env: Environment or its name. + config: A dictionary of configuration options for the environment. + """ + embedding_registry = { + "tsp": StaticEmbedding, + "atsp": StaticEmbedding, + "cvrp": StaticEmbedding, + "cvrptw": StaticEmbedding, + "ffsp": StaticEmbedding, + "svrp": StaticEmbedding, + "sdvrp": SDVRPDynamicEmbedding, + "pctsp": StaticEmbedding, + "spctsp": StaticEmbedding, + "op": StaticEmbedding, + "dpp": StaticEmbedding, + "mdpp": StaticEmbedding, + "pdp": StaticEmbedding, + "mtsp": StaticEmbedding, + "smtwtp": StaticEmbedding, + "jssp": JSSPDynamicEmbedding, + "fjsp": JSSPDynamicEmbedding, + "mtvrp": StaticEmbedding, + } + + if env_name not in embedding_registry: + log.warning( + f"Unknown environment name '{env_name}'. Available dynamic embeddings: {embedding_registry.keys()}. Defaulting to StaticEmbedding." + ) + return embedding_registry.get(env_name, StaticEmbedding)(**config) + + +class StaticEmbedding(nn.Module): + """Static embedding for general problems. + This is used for problems that do not have any dynamic information, except for the + information regarding the current action (e.g. the current node in TSP). See context embedding for more details. + """ + + def __init__(self, *args, **kwargs): + super(StaticEmbedding, self).__init__() + + def forward(self, td): + return 0, 0, 0 + + +class SDVRPDynamicEmbedding(nn.Module): + """Dynamic embedding for the Split Delivery Vehicle Routing Problem (SDVRP). + Embed the following node features to the embedding space: + - demand_with_depot: demand of the customers and the depot + The demand with depot is used to modify the query, key and value vectors of the attention mechanism + based on the current state of the environment (which is changing during the rollout). + """ + + def __init__(self, embed_dim, linear_bias=False): + super(SDVRPDynamicEmbedding, self).__init__() + self.projection = nn.Linear(1, 3 * embed_dim, bias=linear_bias) + + def forward(self, td): + demands_with_depot = td["demand_with_depot"][..., None].clone() + demands_with_depot[..., 0, :] = 0 + glimpse_key_dynamic, glimpse_val_dynamic, logit_key_dynamic = self.projection( + demands_with_depot + ).chunk(3, dim=-1) + return glimpse_key_dynamic, glimpse_val_dynamic, logit_key_dynamic + + +class JSSPDynamicEmbedding(nn.Module): + def __init__(self, embed_dim, linear_bias=False, scaling_factor: int = 1000) -> None: + super().__init__() + self.embed_dim = embed_dim + self.project_node_step = nn.Linear(2, 3 * embed_dim, bias=linear_bias) + self.project_edge_step = nn.Linear(1, 3, bias=linear_bias) + self.scaling_factor = scaling_factor + + def forward(self, td, cache): + ma_emb = cache.node_embeddings["machine_embeddings"] + bs, _, emb_dim = ma_emb.shape + num_jobs = td["next_op"].size(1) + # updates + updates = ma_emb.new_zeros((bs, num_jobs, 3 * emb_dim)) + + lbs = torch.clip(td["lbs"] - td["time"][:, None], 0) / self.scaling_factor + update_feat = torch.stack((lbs, td["is_ready"]), dim=-1) + job_update_feat = gather_by_index(update_feat, td["next_op"], dim=1) + updates = updates + self.project_node_step(job_update_feat) + + ma_busy = td["busy_until"] > td["time"][:, None] + # mask machines currently busy + masked_proc_times = td["proc_times"].clone() / self.scaling_factor + # bs, ma, ops + masked_proc_times[ma_busy] = 0.0 + # bs, ops, ma, 3 + edge_feat = self.project_edge_step(masked_proc_times.unsqueeze(-1)).transpose( + 1, 2 + ) + job_edge_feat = gather_by_index(edge_feat, td["next_op"], dim=1) + # bs, nodes, 3*emb + edge_upd = torch.einsum("ijkl,ikm->ijlm", job_edge_feat, ma_emb).view( + bs, num_jobs, 3 * emb_dim + ) + updates = updates + edge_upd + + # (bs, nodes, emb) + glimpse_key_dynamic, glimpse_val_dynamic, logit_key_dynamic = updates.chunk( + 3, dim=-1 + ) + return glimpse_key_dynamic, glimpse_val_dynamic, logit_key_dynamic diff --git a/rl4co/models/nn/env_embeddings/edge.py b/rl4co/models/nn/env_embeddings/edge.py new file mode 100644 index 00000000..97fa3fb5 --- /dev/null +++ b/rl4co/models/nn/env_embeddings/edge.py @@ -0,0 +1,153 @@ +import torch +import torch.nn as nn + +from torch import Tensor + +try: + from torch_geometric.data import Batch, Data +except ImportError: + Batch = Data = None + +from rl4co.utils.ops import get_distance_matrix, get_full_graph_edge_index, sparsify_graph +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def env_edge_embedding(env_name: str, config: dict) -> nn.Module: + """Retrieve the edge embedding module specific to the environment. Edge embeddings are crucial for + transforming the raw edge features into a format suitable for the neural network, especially in + graph neural networks where edge features can significantly impact the model's performance. + + Args: + env: Environment or its name. + config: A dictionary of configuration options for the environment. + """ + embedding_registry = { + "tsp": TSPEdgeEmbedding, + "atsp": ATSPEdgeEmbedding, + "cvrp": TSPEdgeEmbedding, + "sdvrp": TSPEdgeEmbedding, + "pctsp": TSPEdgeEmbedding, + "spctsp": TSPEdgeEmbedding, + "op": TSPEdgeEmbedding, + "dpp": TSPEdgeEmbedding, + "mdpp": TSPEdgeEmbedding, + "pdp": TSPEdgeEmbedding, + "mtsp": TSPEdgeEmbedding, + "smtwtp": NoEdgeEmbedding, + } + + if env_name not in embedding_registry: + raise ValueError( + f"Unknown environment name '{env_name}'. Available init embeddings: {embedding_registry.keys()}" + ) + + return embedding_registry[env_name](**config) + + +class TSPEdgeEmbedding(nn.Module): + """Edge embedding module for the Traveling Salesman Problem (TSP) and related problems. + This module converts the cost matrix or the distances between nodes into embeddings that can be + used by the neural network. It supports sparsification to focus on a subset of relevant edges, + which is particularly useful for large graphs. + """ + + def __init__( + self, + embed_dim, + linear_bias=True, + sparsify=True, + k_sparse: int = None, + ): + assert Batch is not None, ( + "torch_geometric not found. Please install torch_geometric using instructions from " + "https://pytorch-geometric.readthedocs.io/en/latest/install/installation.html." + ) + + super(TSPEdgeEmbedding, self).__init__() + node_dim = 1 + self.k_sparse = k_sparse + self.sparsify = sparsify + self.edge_embed = nn.Linear(node_dim, embed_dim, linear_bias) + + def forward(self, td, init_embeddings: Tensor): + cost_matrix = get_distance_matrix(td["locs"]) + batch = self._cost_matrix_to_graph(cost_matrix, init_embeddings) + return batch + + def _cost_matrix_to_graph(self, batch_cost_matrix: Tensor, init_embeddings: Tensor): + """Convert batched cost_matrix to batched PyG graph, and calculate edge embeddings. + + Args: + batch_cost_matrix: Tensor of shape [batch_size, n, n] + init_embedding: init embeddings + """ + graph_data = [] + for index, cost_matrix in enumerate(batch_cost_matrix): + if self.sparsify: + edge_index, edge_attr = sparsify_graph( + cost_matrix, self.k_sparse, self_loop=False + ) + else: + edge_index = get_full_graph_edge_index( + cost_matrix.shape[0], self_loop=False + ).to(cost_matrix.device) + edge_attr = cost_matrix[edge_index[0], edge_index[1]] + + graph = Data( + x=init_embeddings[index], + edge_index=edge_index, + edge_attr=edge_attr, + ) + graph_data.append(graph) + + batch = Batch.from_data_list(graph_data) + batch.edge_attr = self.edge_embed(batch.edge_attr) + return batch + + +class ATSPEdgeEmbedding(TSPEdgeEmbedding): + """Edge embedding module for the Asymmetric Traveling Salesman Problem (ATSP). + Inherits from TSPEdgeEmbedding and adapts the edge embedding process to handle + asymmetric cost matrices, where the cost from node i to node j may not be the same as from j to i. + """ + + def forward(self, td, init_embeddings: Tensor): + batch = self._cost_matrix_to_graph(td["cost_matrix"], init_embeddings) + return batch + + +class NoEdgeEmbedding(nn.Module): + """A module for environments that do not require edge embeddings, or where edge features + are not used. This can be useful for simplifying models in problems where only node + features are relevant. + """ + + def __init__(self, embed_dim, self_loop=False, **kwargs): + assert Batch is not None, ( + "torch_geometric not found. Please install torch_geometric using instructions from " + "https://pytorch-geometric.readthedocs.io/en/latest/install/installation.html." + ) + + super(NoEdgeEmbedding, self).__init__() + self.embed_dim = embed_dim + self.self_loop = self_loop + + def forward(self, td, init_embeddings: Tensor): + data_list = [] + n = init_embeddings.shape[1] + device = init_embeddings.device + edge_index = get_full_graph_edge_index(n, self_loop=self.self_loop).to(device) + m = edge_index.shape[1] + + for node_embed in init_embeddings: + data = Data( + x=node_embed, + edge_index=edge_index, + edge_attr=torch.zeros((m, self.embed_dim), device=device), + ) + data_list.append(data) + + batch = Batch.from_data_list(data_list) + return batch diff --git a/rl4co/models/nn/env_embeddings/init.py b/rl4co/models/nn/env_embeddings/init.py new file mode 100644 index 00000000..06391cb2 --- /dev/null +++ b/rl4co/models/nn/env_embeddings/init.py @@ -0,0 +1,512 @@ +import torch +import torch.nn as nn + +from tensordict.tensordict import TensorDict + +from rl4co.models.nn.ops import PositionalEncoding + + +def env_init_embedding(env_name: str, config: dict) -> nn.Module: + """Get environment initial embedding. The init embedding is used to initialize the + general embedding of the problem nodes without any solution information. + Consists of a linear layer that projects the node features to the embedding space. + + Args: + env: Environment or its name. + config: A dictionary of configuration options for the environment. + """ + embedding_registry = { + "tsp": TSPInitEmbedding, + "atsp": TSPInitEmbedding, + "matnet": MatNetInitEmbedding, + "cvrp": VRPInitEmbedding, + "cvrptw": VRPTWInitEmbedding, + "svrp": SVRPInitEmbedding, + "sdvrp": VRPInitEmbedding, + "pctsp": PCTSPInitEmbedding, + "spctsp": PCTSPInitEmbedding, + "op": OPInitEmbedding, + "dpp": DPPInitEmbedding, + "mdpp": MDPPInitEmbedding, + "pdp": PDPInitEmbedding, + "pdp_ruin_repair": TSPInitEmbedding, + "tsp_kopt": TSPInitEmbedding, + "mtsp": MTSPInitEmbedding, + "smtwtp": SMTWTPInitEmbedding, + "mdcpdp": MDCPDPInitEmbedding, + "fjsp": FJSPInitEmbedding, + "jssp": FJSPInitEmbedding, + "mtvrp": MTVRPInitEmbedding, + } + + if env_name not in embedding_registry: + raise ValueError( + f"Unknown environment name '{env_name}'. Available init embeddings: {embedding_registry.keys()}" + ) + + return embedding_registry[env_name](**config) + + +class TSPInitEmbedding(nn.Module): + """Initial embedding for the Traveling Salesman Problems (TSP). + Embed the following node features to the embedding space: + - locs: x, y coordinates of the cities + """ + + def __init__(self, embed_dim, linear_bias=True): + super(TSPInitEmbedding, self).__init__() + node_dim = 2 # x, y + self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias) + + def forward(self, td): + out = self.init_embed(td["locs"]) + return out + + +class MatNetInitEmbedding(nn.Module): + """ + Preparing the initial row and column embeddings for MatNet. + + Reference: + https://github.com/yd-kwon/MatNet/blob/782698b60979effe2e7b61283cca155b7cdb727f/ATSP/ATSP_MatNet/ATSPModel.py#L51 + + + """ + + def __init__(self, embed_dim: int, mode: str = "RandomOneHot") -> None: + super().__init__() + + self.embed_dim = embed_dim + assert mode in { + "RandomOneHot", + "Random", + }, "mode must be one of ['RandomOneHot', 'Random']" + self.mode = mode + + def forward(self, td: TensorDict): + dmat = td["cost_matrix"] + b, r, c = dmat.shape + + row_emb = torch.zeros(b, r, self.embed_dim, device=dmat.device) + + if self.mode == "RandomOneHot": + # MatNet uses one-hot encoding for column embeddings + # https://github.com/yd-kwon/MatNet/blob/782698b60979effe2e7b61283cca155b7cdb727f/ATSP/ATSP_MatNet/ATSPModel.py#L60 + col_emb = torch.zeros(b, c, self.embed_dim, device=dmat.device) + rand = torch.rand(b, c) + rand_idx = rand.argsort(dim=1) + b_idx = torch.arange(b)[:, None].expand(b, c) + n_idx = torch.arange(c)[None, :].expand(b, c) + col_emb[b_idx, n_idx, rand_idx] = 1.0 + + elif self.mode == "Random": + col_emb = torch.rand(b, c, self.embed_dim, device=dmat.device) + else: + raise NotImplementedError + + return row_emb, col_emb, dmat + + +class VRPInitEmbedding(nn.Module): + """Initial embedding for the Vehicle Routing Problems (VRP). + Embed the following node features to the embedding space: + - locs: x, y coordinates of the nodes (depot and customers separately) + - demand: demand of the customers + """ + + def __init__(self, embed_dim, linear_bias=True, node_dim: int = 3): + super(VRPInitEmbedding, self).__init__() + node_dim = node_dim # 3: x, y, demand + self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias) + self.init_embed_depot = nn.Linear(2, embed_dim, linear_bias) # depot embedding + + def forward(self, td): + # [batch, 1, 2]-> [batch, 1, embed_dim] + depot, cities = td["locs"][:, :1, :], td["locs"][:, 1:, :] + depot_embedding = self.init_embed_depot(depot) + # [batch, n_city, 2, batch, n_city, 1] -> [batch, n_city, embed_dim] + node_embeddings = self.init_embed( + torch.cat((cities, td["demand"][..., None]), -1) + ) + # [batch, n_city+1, embed_dim] + out = torch.cat((depot_embedding, node_embeddings), -2) + return out + + +class VRPTWInitEmbedding(VRPInitEmbedding): + def __init__(self, embed_dim, linear_bias=True, node_dim: int = 6): + # node_dim = 6: x, y, demand, tw start, tw end, service time + super(VRPTWInitEmbedding, self).__init__(embed_dim, linear_bias, node_dim) + + def forward(self, td): + depot, cities = td["locs"][:, :1, :], td["locs"][:, 1:, :] + durations = td["durations"][..., 1:] + time_windows = td["time_windows"][..., 1:, :] + # embeddings + depot_embedding = self.init_embed_depot(depot) + node_embeddings = self.init_embed( + torch.cat( + (cities, td["demand"][..., None], time_windows, durations[..., None]), -1 + ) + ) + return torch.cat((depot_embedding, node_embeddings), -2) + + +class SVRPInitEmbedding(nn.Module): + def __init__(self, embed_dim, linear_bias=True, node_dim: int = 3): + super(SVRPInitEmbedding, self).__init__() + node_dim = node_dim # 3: x, y, skill + self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias) + self.init_embed_depot = nn.Linear(2, embed_dim, linear_bias) # depot embedding + + def forward(self, td): + # [batch, 1, 2]-> [batch, 1, embed_dim] + depot, cities = td["locs"][:, :1, :], td["locs"][:, 1:, :] + depot_embedding = self.init_embed_depot(depot) + # [batch, n_city, 2, batch, n_city, 1] -> [batch, n_city, embed_dim] + node_embeddings = self.init_embed(torch.cat((cities, td["skills"]), -1)) + # [batch, n_city+1, embed_dim] + out = torch.cat((depot_embedding, node_embeddings), -2) + return out + + +class PCTSPInitEmbedding(nn.Module): + """Initial embedding for the Prize Collecting Traveling Salesman Problems (PCTSP). + Embed the following node features to the embedding space: + - locs: x, y coordinates of the nodes (depot and customers separately) + - expected_prize: expected prize for visiting the customers. + In PCTSP, this is the actual prize. In SPCTSP, this is the expected prize. + - penalty: penalty for not visiting the customers + """ + + def __init__(self, embed_dim, linear_bias=True): + super(PCTSPInitEmbedding, self).__init__() + node_dim = 4 # x, y, prize, penalty + self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias) + self.init_embed_depot = nn.Linear(2, embed_dim, linear_bias) + + def forward(self, td): + depot, cities = td["locs"][:, :1, :], td["locs"][:, 1:, :] + depot_embedding = self.init_embed_depot(depot) + node_embeddings = self.init_embed( + torch.cat( + ( + cities, + td["expected_prize"][..., None], + td["penalty"][..., 1:, None], + ), + -1, + ) + ) + # batch, n_city+1, embed_dim + out = torch.cat((depot_embedding, node_embeddings), -2) + return out + + +class OPInitEmbedding(nn.Module): + """Initial embedding for the Orienteering Problems (OP). + Embed the following node features to the embedding space: + - locs: x, y coordinates of the nodes (depot and customers separately) + - prize: prize for visiting the customers + """ + + def __init__(self, embed_dim, linear_bias=True): + super(OPInitEmbedding, self).__init__() + node_dim = 3 # x, y, prize + self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias) + self.init_embed_depot = nn.Linear(2, embed_dim, linear_bias) # depot embedding + + def forward(self, td): + depot, cities = td["locs"][:, :1, :], td["locs"][:, 1:, :] + depot_embedding = self.init_embed_depot(depot) + node_embeddings = self.init_embed( + torch.cat( + ( + cities, + td["prize"][..., 1:, None], # exclude depot + ), + -1, + ) + ) + out = torch.cat((depot_embedding, node_embeddings), -2) + return out + + +class DPPInitEmbedding(nn.Module): + """Initial embedding for the Decap Placement Problem (DPP), EDA (electronic design automation). + Embed the following node features to the embedding space: + - locs: x, y coordinates of the nodes (cells) + - probe: index of the (single) probe cell. We embed the euclidean distance from the probe to all cells. + """ + + def __init__(self, embed_dim, linear_bias=True): + super(DPPInitEmbedding, self).__init__() + node_dim = 2 # x, y + self.init_embed = nn.Linear(node_dim, embed_dim // 2, linear_bias) # locs + self.init_embed_probe = nn.Linear(1, embed_dim // 2, linear_bias) # probe + + def forward(self, td): + node_embeddings = self.init_embed(td["locs"]) + probe_embedding = self.init_embed_probe( + self._distance_probe(td["locs"], td["probe"]) + ) + return torch.cat([node_embeddings, probe_embedding], -1) + + def _distance_probe(self, locs, probe): + # Euclidean distance from probe to all locations + probe_loc = torch.gather(locs, 1, probe.unsqueeze(-1).expand(-1, -1, 2)) + return torch.norm(locs - probe_loc, dim=-1).unsqueeze(-1) + + +class MDPPInitEmbedding(nn.Module): + """Initial embedding for the Multi-port Placement Problem (MDPP), EDA (electronic design automation). + Embed the following node features to the embedding space: + - locs: x, y coordinates of the nodes (cells) + - probe: indexes of the probe cells (multiple). We embed the euclidean distance of each cell to the closest probe. + """ + + def __init__(self, embed_dim, linear_bias=True): + super(MDPPInitEmbedding, self).__init__() + node_dim = 2 # x, y + self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias) # locs + self.init_embed_probe_distance = nn.Linear( + 1, embed_dim, linear_bias + ) # probe_distance + self.project_out = nn.Linear(embed_dim * 2, embed_dim, linear_bias) + + def forward(self, td): + probes = td["probe"] + locs = td["locs"] + node_embeddings = self.init_embed(locs) + + # Get the shortest distance from any probe + dist = torch.cdist(locs, locs, p=2) + dist[~probes] = float("inf") + min_dist, _ = torch.min(dist, dim=1) + min_probe_dist_embedding = self.init_embed_probe_distance(min_dist[..., None]) + + return self.project_out( + torch.cat([node_embeddings, min_probe_dist_embedding], -1) + ) + + +class PDPInitEmbedding(nn.Module): + """Initial embedding for the Pickup and Delivery Problem (PDP). + Embed the following node features to the embedding space: + - locs: x, y coordinates of the nodes (depot, pickups and deliveries separately) + Note that pickups and deliveries are interleaved in the input. + """ + + def __init__(self, embed_dim, linear_bias=True): + super(PDPInitEmbedding, self).__init__() + node_dim = 2 # x, y + self.init_embed_depot = nn.Linear(2, embed_dim, linear_bias) + self.init_embed_pick = nn.Linear(node_dim * 2, embed_dim, linear_bias) + self.init_embed_delivery = nn.Linear(node_dim, embed_dim, linear_bias) + + def forward(self, td): + depot, locs = td["locs"][..., 0:1, :], td["locs"][..., 1:, :] + num_locs = locs.size(-2) + pick_feats = torch.cat( + [locs[:, : num_locs // 2, :], locs[:, num_locs // 2 :, :]], -1 + ) # [batch_size, graph_size//2, 4] + delivery_feats = locs[:, num_locs // 2 :, :] # [batch_size, graph_size//2, 2] + depot_embeddings = self.init_embed_depot(depot) + pick_embeddings = self.init_embed_pick(pick_feats) + delivery_embeddings = self.init_embed_delivery(delivery_feats) + # concatenate on graph size dimension + return torch.cat([depot_embeddings, pick_embeddings, delivery_embeddings], -2) + + +class MTSPInitEmbedding(nn.Module): + """Initial embedding for the Multiple Traveling Salesman Problem (mTSP). + Embed the following node features to the embedding space: + - locs: x, y coordinates of the nodes (depot, cities) + """ + + def __init__(self, embed_dim, linear_bias=True): + """NOTE: new made by Fede. May need to be checked""" + super(MTSPInitEmbedding, self).__init__() + node_dim = 2 # x, y + self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias) + self.init_embed_depot = nn.Linear(2, embed_dim, linear_bias) # depot embedding + + def forward(self, td): + depot_embedding = self.init_embed_depot(td["locs"][..., 0:1, :]) + node_embedding = self.init_embed(td["locs"][..., 1:, :]) + return torch.cat([depot_embedding, node_embedding], -2) + + +class SMTWTPInitEmbedding(nn.Module): + """Initial embedding for the Single Machine Total Weighted Tardiness Problem (SMTWTP). + Embed the following node features to the embedding space: + - job_due_time: due time of the jobs + - job_weight: weights of the jobs + - job_process_time: the processing time of jobs + """ + + def __init__(self, embed_dim, linear_bias=True): + super(SMTWTPInitEmbedding, self).__init__() + node_dim = 3 # job_due_time, job_weight, job_process_time + self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias) + + def forward(self, td): + job_due_time = td["job_due_time"] + job_weight = td["job_weight"] + job_process_time = td["job_process_time"] + feat = torch.stack((job_due_time, job_weight, job_process_time), dim=-1) + out = self.init_embed(feat) + return out + + +class MDCPDPInitEmbedding(nn.Module): + """Initial embedding for the MDCPDP environment + Embed the following node features to the embedding space: + - locs: x, y coordinates of the nodes (depot, pickups and deliveries separately) + Note that pickups and deliveries are interleaved in the input. + """ + + def __init__(self, embed_dim, linear_bias=True): + super(MDCPDPInitEmbedding, self).__init__() + node_dim = 2 # x, y + self.init_embed_depot = nn.Linear(2, embed_dim, linear_bias) + self.init_embed_pick = nn.Linear(node_dim * 2, embed_dim, linear_bias) + self.init_embed_delivery = nn.Linear(node_dim, embed_dim, linear_bias) + + def forward(self, td): + num_depots = td["capacity"].size(-1) + depot, locs = td["locs"][..., 0:num_depots, :], td["locs"][..., num_depots:, :] + num_locs = locs.size(-2) + pick_feats = torch.cat( + [locs[:, : num_locs // 2, :], locs[:, num_locs // 2 :, :]], -1 + ) # [batch_size, graph_size//2, 4] + delivery_feats = locs[:, num_locs // 2 :, :] # [batch_size, graph_size//2, 2] + depot_embeddings = self.init_embed_depot(depot) + pick_embeddings = self.init_embed_pick(pick_feats) + delivery_embeddings = self.init_embed_delivery(delivery_feats) + # concatenate on graph size dimension + return torch.cat([depot_embeddings, pick_embeddings, delivery_embeddings], -2) + + +class JSSPInitEmbedding(nn.Module): + def __init__( + self, + embed_dim, + linear_bias: bool = True, + scaling_factor: int = 1000, + num_op_feats=5, + ): + super(JSSPInitEmbedding, self).__init__() + self.embed_dim = embed_dim + self.scaling_factor = scaling_factor + self.init_ops_embed = nn.Linear(num_op_feats, embed_dim, linear_bias) + self.pos_encoder = PositionalEncoding(embed_dim, dropout=0.0) + + def _op_features(self, td): + proc_times = td["proc_times"] + mean_durations = proc_times.sum(1) / (proc_times.gt(0).sum(1) + 1e-9) + feats = [ + mean_durations / self.scaling_factor, + # td["lbs"] / self.scaling_factor, + td["is_ready"], + td["num_eligible"], + td["ops_job_map"], + td["op_scheduled"], + ] + return torch.stack(feats, dim=-1) + + def _init_ops_embed(self, td: TensorDict): + ops_feat = self._op_features(td) + ops_emb = self.init_ops_embed(ops_feat) + ops_emb = self.pos_encoder(ops_emb, td["ops_sequence_order"]) + + # zero out padded and finished ops + mask = td["pad_mask"] # NOTE dont mask scheduled - leads to instable training + ops_emb[mask.unsqueeze(-1).expand_as(ops_emb)] = 0 + return ops_emb + + def forward(self, td): + return self._init_ops_embed(td) + + +class FJSPInitEmbedding(JSSPInitEmbedding): + def __init__(self, embed_dim, linear_bias=False, scaling_factor: int = 100): + super().__init__(embed_dim, linear_bias, scaling_factor) + self.init_ma_embed = nn.Linear(1, self.embed_dim, bias=linear_bias) + self.edge_embed = nn.Linear(1, embed_dim, bias=linear_bias) + + def forward(self, td: TensorDict): + ops_emb = self._init_ops_embed(td) + ma_emb = self._init_machine_embed(td) + edge_emb = self._init_edge_embed(td) + # get edges between operations and machines + # (bs, ops, ma) + edges = td["ops_ma_adj"].transpose(1, 2) + return ops_emb, ma_emb, edge_emb, edges + + def _init_edge_embed(self, td: TensorDict): + proc_times = td["proc_times"].transpose(1, 2) / self.scaling_factor + edge_embed = self.edge_embed(proc_times.unsqueeze(-1)) + return edge_embed + + def _init_machine_embed(self, td: TensorDict): + busy_for = (td["busy_until"] - td["time"].unsqueeze(1)) / self.scaling_factor + ma_embeddings = self.init_ma_embed(busy_for.unsqueeze(2)) + return ma_embeddings + + +class FJSPMatNetInitEmbedding(JSSPInitEmbedding): + def __init__( + self, + embed_dim, + linear_bias: bool = False, + scaling_factor: int = 1000, + ): + super().__init__(embed_dim, linear_bias, scaling_factor) + self.init_ma_embed = nn.Linear(1, self.embed_dim, bias=linear_bias) + + def _init_machine_embed(self, td: TensorDict): + busy_for = (td["busy_until"] - td["time"].unsqueeze(1)) / self.scaling_factor + ma_embeddings = self.init_ma_embed(busy_for.unsqueeze(2)) + return ma_embeddings + + def forward(self, td: TensorDict): + proc_times = td["proc_times"] + ops_emb = self._init_ops_embed(td) + # encoding machines + ma_emb = self._init_machine_embed(td) + # edgeweights for matnet + matnet_edge_weights = proc_times.transpose(1, 2) / self.scaling_factor + return ops_emb, ma_emb, matnet_edge_weights + + +class MTVRPInitEmbedding(VRPInitEmbedding): + def __init__(self, embed_dim, linear_bias=True, node_dim: int = 7): + # node_dim = 7: x, y, demand_linehaul, demand_backhaul, tw start, tw end, service time + super(MTVRPInitEmbedding, self).__init__(embed_dim, linear_bias, node_dim) + + def forward(self, td): + depot, cities = td["locs"][:, :1, :], td["locs"][:, 1:, :] + demand_linehaul, demand_backhaul = ( + td["demand_linehaul"][..., 1:], + td["demand_backhaul"][..., 1:], + ) + service_time = td["service_time"][..., 1:] + time_windows = td["time_windows"][..., 1:, :] + # [!] convert [0, inf] -> [0, 0] if a problem does not include the time window constraint, do not modify in-place + time_windows = torch.nan_to_num(time_windows, posinf=0.0) + # embeddings + depot_embedding = self.init_embed_depot(depot) + node_embeddings = self.init_embed( + torch.cat( + ( + cities, + demand_linehaul[..., None], + demand_backhaul[..., None], + time_windows, + service_time[..., None], + ), + -1, + ) + ) + return torch.cat((depot_embedding, node_embeddings), -2) diff --git a/rl4co/models/nn/flash_attention.py b/rl4co/models/nn/flash_attention.py new file mode 100644 index 00000000..28dff562 --- /dev/null +++ b/rl4co/models/nn/flash_attention.py @@ -0,0 +1,64 @@ +import torch + +try: + # from fla.ops.linear_attn.chunk_fuse import fused_chunk_linear_attn + from fla.ops.linear_attn.chunk import chunk_linear_attn as fused_chunk_linear_attn +except ImportError: + fused_chunk_linear_attn = None + +try: + from flash_attn import flash_attn_func +except ImportError: + flash_attn_func = None + + +def fused_chunk_linear_attn_wrapper( + q: torch.Tensor, + k: torch.Tensor, + v: torch.Tensor, + scale: float = -1, + initial_state: torch.Tensor = None, + output_final_state: bool = False, + normalize: bool = True, + **kwargs, +): + assert ( + fused_chunk_linear_attn is not None + ), "fused_chunk_linear_attn not found. Install Flash Linear Attention using instructions from https://github.com/sustcsonglin/flash-linear-attention" + assert ( + kwargs.get("attn_mask", None) is None + ), "attn_mask is not supported in Flash Linear Attention" + return fused_chunk_linear_attn( + q, k, v, scale, initial_state, output_final_state, normalize + )[0] + + +def scaled_dot_product_attention_flash_attn( + q, k, v, attn_mask=None, dropout_p=0.0, is_causal=False +): + """ + Flash Attention 2 wrapper (https://github.com/Dao-AILab/flash-attention) around `flash_attn_func` to obtain the same behavior as + `torch.nn.functional.scaled_dot_product_attention`. + We need to permute the query, key, and value tensors before calling the scaled dot product attention function + Reference: https://github.com/Dao-AILab/flash-attention/issues/383 + + Note: + Flash Attention does not support masking except for causal masking. + + Args: + q (torch.Tensor): Query tensor of shape `(batch_size, num_heads, seq_len_q, head_dim)` + k (torch.Tensor): Key tensor of shape `(batch_size, num_heads, seq_len_k, head_dim)` + v (torch.Tensor): Value tensor of shape `(batch_size, num_heads, seq_len_v, head_dim)` + attn_mask (torch.Tensor): Attention mask of shape `(batch_size, seq_len_q, seq_len_k)` + dropout_p (float): Dropout probability + is_causal (bool): Whether to apply causal mask to attention scores + """ + assert attn_mask is None, "`attn_mask` is not supported in Flash Attention" + assert flash_attn_func is not None, ( + "Flash Attention not found. Install Flash Attention using instructions from " + "https://github.com/Dao-AILab/flash-attention . " + "Alternatively, use `torch.nn.functional.scaled_dot_product_attention` available from PyTorch 2.0.0" + ) + q, k, v = q.transpose(-2, -3), k.transpose(-2, -3), v.transpose(-2, -3) + out = flash_attn_func(q, k, v, dropout_p=dropout_p, causal=is_causal) + return out.transpose(-2, -3) diff --git a/rl4co/models/nn/graph/__init__.py b/rl4co/models/nn/graph/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/models/nn/graph/attnnet.py b/rl4co/models/nn/graph/attnnet.py new file mode 100644 index 00000000..9bfc29c6 --- /dev/null +++ b/rl4co/models/nn/graph/attnnet.py @@ -0,0 +1,103 @@ +from typing import Callable, Optional + +import torch.nn as nn + +from torch import Tensor + +from rl4co.models.nn.mlp import MLP +from rl4co.models.nn.moe import MoE +from rl4co.models.nn.attention import MultiHeadAttention +from rl4co.models.nn.ops import Normalization, SkipConnection +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class MultiHeadAttentionLayer(nn.Sequential): + """Multi-Head Attention Layer with normalization and feed-forward layer + + Args: + embed_dim: dimension of the embeddings + num_heads: number of heads in the MHA + feedforward_hidden: dimension of the hidden layer in the feed-forward layer + normalization: type of normalization to use (batch, layer, none) + sdpa_fn: scaled dot product attention function (SDPA) + moe_kwargs: Keyword arguments for MoE + """ + + def __init__( + self, + embed_dim: int, + num_heads: int = 8, + feedforward_hidden: int = 512, + normalization: Optional[str] = "batch", + bias: bool = True, + sdpa_fn: Optional[Callable] = None, + moe_kwargs: Optional[dict] = None, + ): + num_neurons = [feedforward_hidden] if feedforward_hidden > 0 else [] + if moe_kwargs is not None: + ffn = MoE(embed_dim, embed_dim, num_neurons=num_neurons, **moe_kwargs) + else: + ffn = MLP(input_dim=embed_dim, output_dim=embed_dim, num_neurons=num_neurons, hidden_act="ReLU") + + super(MultiHeadAttentionLayer, self).__init__( + SkipConnection( + MultiHeadAttention(embed_dim, num_heads, bias=bias, sdpa_fn=sdpa_fn) + ), + Normalization(embed_dim, normalization), + SkipConnection(ffn), + Normalization(embed_dim, normalization), + ) + + +class GraphAttentionNetwork(nn.Module): + """Graph Attention Network to encode embeddings with a series of MHA layers consisting of a MHA layer, + normalization, feed-forward layer, and normalization. Similar to Transformer encoder, as used in Kool et al. (2019). + + Args: + num_heads: number of heads in the MHA + embed_dim: dimension of the embeddings + num_layers: number of MHA layers + normalization: type of normalization to use (batch, layer, none) + feedforward_hidden: dimension of the hidden layer in the feed-forward layer + sdpa_fn: scaled dot product attention function (SDPA) + moe_kwargs: Keyword arguments for MoE + """ + + def __init__( + self, + num_heads: int, + embed_dim: int, + num_layers: int, + normalization: str = "batch", + feedforward_hidden: int = 512, + sdpa_fn: Optional[Callable] = None, + moe_kwargs: Optional[dict] = None, + ): + super(GraphAttentionNetwork, self).__init__() + + self.layers = nn.Sequential( + *( + MultiHeadAttentionLayer( + embed_dim, + num_heads, + feedforward_hidden=feedforward_hidden, + normalization=normalization, + sdpa_fn=sdpa_fn, + moe_kwargs=moe_kwargs, + ) + for _ in range(num_layers) + ) + ) + + def forward(self, x: Tensor, mask: Optional[Tensor] = None) -> Tensor: + """Forward pass of the encoder + + Args: + x: [batch_size, graph_size, embed_dim] initial embeddings to process + mask: [batch_size, graph_size, graph_size] mask for the input embeddings. Unused for now. + """ + assert mask is None, "Mask not yet supported!" + h = self.layers(x) + return h diff --git a/rl4co/models/nn/graph/gcn.py b/rl4co/models/nn/graph/gcn.py new file mode 100644 index 00000000..348c6b21 --- /dev/null +++ b/rl4co/models/nn/graph/gcn.py @@ -0,0 +1,114 @@ +from typing import Callable, Tuple, Union + +import torch.nn as nn +import torch.nn.functional as F + +from tensordict import TensorDict +from torch import Tensor + +try: + from torch_geometric.nn import GCNConv +except ImportError: + GCNConv = None +from rl4co.models.nn.env_embeddings import env_init_embedding +from rl4co.utils.ops import get_full_graph_edge_index +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +EdgeIndexFnSignature = Callable[[TensorDict, int], Tensor] + + +def edge_idx_fn_wrapper(td: TensorDict, num_nodes: int): + # self-loop is added by GCNConv layer + return get_full_graph_edge_index(num_nodes, self_loop=False).to(td.device) + + +class GCNEncoder(nn.Module): + """Graph Convolutional Network to encode embeddings with a series of GCN + layers from the pytorch geometric package + + Args: + embed_dim: dimension of the embeddings + num_nodes: number of nodes in the graph + num_gcn_layer: number of GCN layers + self_loop: whether to add self loop in the graph + residual: whether to use residual connection + """ + + def __init__( + self, + env_name: str, + embed_dim: int, + num_layers: int, + init_embedding: nn.Module = None, + residual: bool = True, + edge_idx_fn: EdgeIndexFnSignature = None, + dropout: float = 0.5, + bias: bool = True, + ): + super().__init__() + + self.env_name = env_name + self.embed_dim = embed_dim + self.residual = residual + self.dropout = dropout + + self.init_embedding = ( + env_init_embedding(self.env_name, {"embed_dim": embed_dim}) + if init_embedding is None + else init_embedding + ) + + if edge_idx_fn is None: + log.warning("No edge indices passed. Assume a fully connected graph") + edge_idx_fn = edge_idx_fn_wrapper + + self.edge_idx_fn = edge_idx_fn + + # Define the GCN layers + self.gcn_layers = nn.ModuleList( + [GCNConv(embed_dim, embed_dim, bias=bias) for _ in range(num_layers)] + ) + + def forward( + self, td: TensorDict, mask: Union[Tensor, None] = None + ) -> Tuple[Tensor, Tensor]: + """Forward pass of the encoder. + Transform the input TensorDict into a latent representation. + + Args: + td: Input TensorDict containing the environment state + mask: Mask to apply to the attention + + Returns: + h: Latent representation of the input + init_h: Initial embedding of the input + """ + # Transfer to embedding space + init_h = self.init_embedding(td) + bs, num_nodes, emb_dim = init_h.shape + # (bs*num_nodes, emb_dim) + update_node_feature = init_h.reshape(-1, emb_dim) + # shape=(2, num_edges) + edge_index = self.edge_idx_fn(td, num_nodes) + + for layer in self.gcn_layers[:-1]: + update_node_feature = layer(update_node_feature, edge_index) + update_node_feature = F.relu(update_node_feature) + update_node_feature = F.dropout( + update_node_feature, training=self.training, p=self.dropout + ) + + # last layer without relu activation and dropout + update_node_feature = self.gcn_layers[-1](update_node_feature, edge_index) + + # De-batch the graph + update_node_feature = update_node_feature.view(bs, num_nodes, emb_dim) + + # Residual + if self.residual: + update_node_feature = update_node_feature + init_h + + return update_node_feature, init_h diff --git a/rl4co/models/nn/graph/gnn.py b/rl4co/models/nn/graph/gnn.py new file mode 100644 index 00000000..91e84ffe --- /dev/null +++ b/rl4co/models/nn/graph/gnn.py @@ -0,0 +1,99 @@ +import torch +import torch.nn as nn + +try: + import torch_geometric.nn as gnn +except ImportError: + gnn = None + +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class GNNLayer(nn.Module): + """Graph Neural Network Layer for processing graph structures. + + Args: + units: The number of units in each linear transformation layer. + act_fn: The name of the activation function to use after each linear layer. Defaults to 'silu'. + agg_fn: The name of the global aggregation function to use for pooling features across the graph. Defaults to 'mean'. + """ + + def __init__(self, units: int, act_fn: str = "silu", agg_fn: str = "mean"): + assert gnn is not None, ( + "torch_geometric not found. Please install torch_geometric using instructions from " + "https://pytorch-geometric.readthedocs.io/en/latest/install/installation.html." + ) + + super(GNNLayer, self).__init__() + self.units = units + self.act_fn = getattr(nn.functional, act_fn) + self.agg_fn = getattr(gnn, f"global_{agg_fn}_pool") + + # Vertex updates + self.v_lin1 = nn.Linear(units, units) + self.v_lin2 = nn.Linear(units, units) + self.v_lin3 = nn.Linear(units, units) + self.v_lin4 = nn.Linear(units, units) + self.v_bn = gnn.BatchNorm(units) + + # Edge updates + self.e_lin = nn.Linear(units, units) + self.e_bn = gnn.BatchNorm(units) + + def forward(self, x, edge_index, edge_attr): + x0 = x + w0 = w = edge_attr + + # Vertex updates + x1 = self.v_lin1(x0) + x2 = self.v_lin2(x0) + x3 = self.v_lin3(x0) + x4 = self.v_lin4(x0) + x = x0 + self.act_fn( + self.v_bn( + x1 + self.agg_fn(torch.sigmoid(w0) * x2[edge_index[1]], edge_index[0]) + ) + ) + + # Edge updates + w1 = self.e_lin(w0) + w = w0 + self.act_fn(self.e_bn(w1 + x3[edge_index[0]] + x4[edge_index[1]])) + return x, w + + +class GNNEncoder(nn.Module): + """Anisotropic Graph Neural Network encoder with edge-gating mechanism as in Joshi et al. (2022) + + Args: + num_layers: The number of GNN layers to stack in the network. + embed_dim: The dimensionality of the embeddings for each node in the graph. + act_fn: The activation function to use in each GNNLayer, see https://pytorch.org/docs/stable/nn.functional.html#non-linear-activation-functions for available options. Defaults to 'silu'. + agg_fn: The aggregation function to use in each GNNLayer for pooling features. Options: 'add', 'mean', 'max'. Defaults to 'mean'. + """ + + def __init__(self, num_layers: int, embed_dim: int, act_fn="silu", agg_fn="mean"): + super(GNNEncoder, self).__init__() + self.act_fn = getattr(nn.functional, act_fn) + self.agg_fn = agg_fn + + # Stack of GNN layers + self.layers = nn.ModuleList( + [GNNLayer(embed_dim, act_fn, agg_fn) for _ in range(num_layers)] + ) + + def forward(self, x, edge_index, w): + """Sequentially passes the input graph data through the stacked GNN layers, + applying specified transformations and aggregations to learn graph representations. + + Args: + x: The node features of the graph with shape [num_nodes, embed_dim]. + edge_index: The edge indices of the graph with shape [2, num_edges]. + w: The edge attributes or weights with shape [num_edges, embed_dim]. + """ + x = self.act_fn(x) + w = self.act_fn(w) + for layer in self.layers: + x, w = layer(x, edge_index, w) + return x, w diff --git a/rl4co/models/nn/graph/hgnn.py b/rl4co/models/nn/graph/hgnn.py new file mode 100644 index 00000000..bd4ce0d2 --- /dev/null +++ b/rl4co/models/nn/graph/hgnn.py @@ -0,0 +1,133 @@ +import math + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from einops import einsum +from torch import Tensor + +from rl4co.models.nn.env_embeddings import env_init_embedding +from rl4co.models.nn.ops import TransformerFFN + + +class HetGNNLayer(nn.Module): + def __init__( + self, + embed_dim: int, + ) -> None: + super().__init__() + + self.self_attn = nn.Parameter(torch.rand(size=(embed_dim, 1), dtype=torch.float)) + self.cross_attn = nn.Parameter(torch.rand(size=(embed_dim, 1), dtype=torch.float)) + self.edge_attn = nn.Parameter(torch.rand(size=(embed_dim, 1), dtype=torch.float)) + self.activation = nn.ReLU() + self.scale = 1 / math.sqrt(embed_dim) + + def forward( + self, self_emb: Tensor, other_emb: Tensor, edge_emb: Tensor, edges: Tensor + ): + bs, n_rows, _ = self_emb.shape + + # concat operation embeddings and o-m edge features (proc times) + # Calculate attention coefficients + er = einsum(self_emb, self.self_attn, "b m e, e one -> b m") * self.scale + ec = einsum(other_emb, self.cross_attn, "b o e, e one -> b o") * self.scale + ee = einsum(edge_emb, self.edge_attn, "b m o e, e one -> b m o") * self.scale + + # element wise multiplication similar to broadcast column logits over rows with masking + ec_expanded = einsum(edges, ec, "b m o, b o -> b m o") + # element wise multiplication similar to broadcast row logits over cols with masking + er_expanded = einsum(edges, er, "b m o, b m -> b m o") + + # adding the projections of different node types and edges together (equivalent to first concat and then project) + # (bs, n_rows, n_cols) + cross_logits = self.activation(ec_expanded + ee + er_expanded) + + # (bs, n_rows, 1) + self_logits = self.activation(er + er).unsqueeze(-1) + + # (bs, n_ma, n_ops + 1) + mask = torch.cat( + ( + edges == 1, + torch.full( + size=(bs, n_rows, 1), + dtype=torch.bool, + fill_value=True, + device=edges.device, + ), + ), + dim=-1, + ) + + # (bs, n_ma, n_ops + 1) + all_logits = torch.cat((cross_logits, self_logits), dim=-1) + all_logits[~mask] = -torch.inf + attn_scores = F.softmax(all_logits, dim=-1) + # (bs, n_ma, n_ops) + cross_attn_scores = attn_scores[..., :-1] + # (bs, n_ma, 1) + self_attn_scores = attn_scores[..., -1].unsqueeze(-1) + + # augment column embeddings with edge features, (bs, r, c, e) + other_emb_aug = edge_emb + other_emb.unsqueeze(-3) + cross_emb = einsum(cross_attn_scores, other_emb_aug, "b m o, b m o e -> b m e") + self_emb = self_emb * self_attn_scores + # (bs, n_ma, emb_dim) + hidden = cross_emb + self_emb + return hidden + + +class HetGNNBlock(nn.Module): + def __init__(self, embed_dim, normalization: str = "batch") -> None: + super().__init__() + self.hgnn1 = HetGNNLayer(embed_dim) + self.hgnn2 = HetGNNLayer(embed_dim) + self.ffn1 = TransformerFFN(embed_dim, embed_dim * 2, normalization=normalization) + self.ffn2 = TransformerFFN(embed_dim, embed_dim * 2, normalization=normalization) + + def forward(self, x1, x2, edge_emb, edges): + h1 = self.hgnn1(x1, x2, edge_emb, edges) + h1 = self.ffn1(h1, x1) + + h2 = self.hgnn2(x2, x1, edge_emb.transpose(1, 2), edges.transpose(1, 2)) + h2 = self.ffn2(h2, x2) + + return h1, h2 + + +class HetGNNEncoder(nn.Module): + def __init__( + self, + embed_dim: int, + num_layers: int = 2, + normalization: str = "batch", + init_embedding=None, + env_name: str = "fjsp", + **init_embedding_kwargs, + ) -> None: + super().__init__() + + if init_embedding is None: + init_embedding_kwargs["embed_dim"] = embed_dim + init_embedding = env_init_embedding(env_name, init_embedding_kwargs) + + self.init_embedding = init_embedding + + self.num_layers = num_layers + self.layers = nn.ModuleList( + [HetGNNBlock(embed_dim, normalization) for _ in range(num_layers)] + ) + + def forward(self, td): + row_emb, col_emb, edge_emb, edges = self.init_embedding(td) + # perform sanity check to validate correct order of row and col embeddings + n_rows, n_cols = edges.shape[1:] + assert row_emb.size(1) == n_rows, "incorrect number of row embeddings" + assert col_emb.size(1) == n_cols, "incorrect number of column embeddings" + + for layer in self.layers: + row_emb, col_emb = layer(row_emb, col_emb, edge_emb, edges) + + return (row_emb, col_emb), None diff --git a/rl4co/models/nn/graph/mpnn.py b/rl4co/models/nn/graph/mpnn.py new file mode 100644 index 00000000..fd6e14af --- /dev/null +++ b/rl4co/models/nn/graph/mpnn.py @@ -0,0 +1,173 @@ +from typing import Tuple, Union + +import torch +import torch.nn as nn + +from tensordict import TensorDict +from torch import Tensor +from torch_geometric.data import Batch, Data +from torch_geometric.nn import MessagePassing + +from rl4co.models.nn.env_embeddings import env_init_embedding +from rl4co.models.nn.mlp import MLP +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class MessagePassingLayer(MessagePassing): + def __init__( + self, + node_indim, + node_outdim, + edge_indim, + edge_outdim, + aggregation="add", + residual=False, + **mlp_params, + ): + super(MessagePassingLayer, self).__init__(aggr=aggregation) + # Init message passing models + self.edge_model = MLP( + input_dim=edge_indim + 2 * node_indim, output_dim=edge_outdim, **mlp_params + ) + self.node_model = MLP( + input_dim=edge_outdim + node_indim, output_dim=node_outdim, **mlp_params + ) + self.residual = residual + + def forward(self, node_feature, edge_feature, edge_index, mask=None): + # Message passing + update_edge_feature = self.edge_update(node_feature, edge_feature, edge_index) + update_node_feature = self.propagate( + edge_index, x=node_feature, edge_features=update_edge_feature + ) + + # Update with residual connection + if self.residual: + update_node_feature = update_node_feature + node_feature + + return update_node_feature, update_edge_feature + + def edge_update(self, nf, ef, edge_index): + row, col = edge_index + x_i, x_j = nf[row], nf[col] + uef = self.edge_model(torch.cat([x_i, x_j, ef], dim=-1)) + return uef + + def message(self, edge_features: torch.tensor): + return edge_features + + def update(self, aggr_msg: torch.tensor, x: torch.tensor): + unf = self.node_model(torch.cat([x, aggr_msg], dim=-1)) + return unf + + +class MessagePassingEncoder(nn.Module): + def __init__( + self, + env_name: str, + embed_dim: int, + num_nodes: int, + num_layers: int, + init_embedding: nn.Module = None, + aggregation: str = "add", + self_loop: bool = False, + residual: bool = True, + ): + """ + Note: + - Support fully connected graph for now. + """ + super(MessagePassingEncoder, self).__init__() + + self.env_name = env_name + + self.init_embedding = ( + env_init_embedding(self.env_name, {"embed_dim": embed_dim}) + if init_embedding is None + else init_embedding + ) + + # Generate edge index for a fully connected graph + adj_matrix = torch.ones(num_nodes, num_nodes) + if self_loop: + adj_matrix.fill_diagonal_(0) # No self-loops + self.edge_index = torch.permute(torch.nonzero(adj_matrix), (1, 0)) + + # Init message passing models + self.mpnn_layers = nn.ModuleList( + [ + MessagePassingLayer( + node_indim=embed_dim, + node_outdim=embed_dim, + edge_indim=1, + edge_outdim=1, + aggregation=aggregation, + residual=residual, + ) + for _ in range(num_layers) + ] + ) + + # Record parameters + self.self_loop = self_loop + + # def forward(self, x, mask=None): + def forward( + self, td: TensorDict, mask: Union[Tensor, None] = None + ) -> Tuple[Tensor, Tensor]: + init_h = self.init_embedding(td) + num_node = init_h.size(-2) + + # Check to update the edge index with different number of node + if num_node != self.edge_index.max().item() + 1: + adj_matrix = torch.ones(num_node, num_node) + if self.self_loop: + adj_matrix.fill_diagonal_(0) + edge_index = torch.permute(torch.nonzero(adj_matrix), (1, 0)) + edge_index = edge_index.to(init_h.device) + else: + edge_index = self.edge_index.to(init_h.device) + + # Generate edge features: distance + edge_feature = torch.norm( + init_h[..., edge_index[0], :] - init_h[..., edge_index[1], :], + dim=-1, + keepdim=True, + ) + + # Create the batched graph + data_list = [ + Data(x=x, edge_index=edge_index, edge_attr=edge_attr) + for x, edge_attr in zip(init_h, edge_feature) + ] + data_batch = Batch.from_data_list(data_list) + update_node_feature = data_batch.x + update_edge_feature = data_batch.edge_attr + edge_index = data_batch.edge_index + + # Message passing + for layer in self.mpnn_layers: + update_node_feature, update_edge_feature = layer( + update_node_feature, update_edge_feature, edge_index + ) + + # De-batch the graph + input_size = init_h.size() + update_node_feature = update_node_feature.view(*input_size) + + return update_node_feature, init_h + + def edge_update(self, nf, ef, edge_index): + row, col = edge_index + x_i, x_j = nf[row], nf[col] + uef = self.edge_model(torch.cat([x_i, x_j, ef], dim=-1)) + return uef + + def message(self, edge_features: torch.tensor): + return edge_features + + def update(self, aggr_msg: torch.tensor, x: torch.tensor): + unf = self.node_model(torch.cat([x, aggr_msg], dim=-1)) + return unf diff --git a/rl4co/models/nn/mlp.py b/rl4co/models/nn/mlp.py new file mode 100644 index 00000000..83afcb62 --- /dev/null +++ b/rl4co/models/nn/mlp.py @@ -0,0 +1,80 @@ +from typing import List, Union + +import torch.nn as nn + +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class MLP(nn.Module): + def __init__( + self, + input_dim: int, + output_dim: int, + num_neurons: List[int] = [64, 32], + dropout_probs: Union[None, List[float]] = None, + hidden_act: str = "ReLU", + out_act: str = "Identity", + input_norm: str = "None", + output_norm: str = "None", + ): + super(MLP, self).__init__() + + assert input_norm in ["Batch", "Layer", "None"] + assert output_norm in ["Batch", "Layer", "None"] + + if dropout_probs is None: + dropout_probs = [0.0] * len(num_neurons) + elif len(dropout_probs) != len(num_neurons): + log.info( + "dropout_probs List length should match the num_neurons List length for MLP, dropouts set to False instead" + ) + dropout_probs = [0.0] * len(num_neurons) + + self.input_dim = input_dim + self.output_dim = output_dim + self.num_neurons = num_neurons + self.hidden_act = getattr(nn, hidden_act)() + self.out_act = getattr(nn, out_act)() + self.dropouts = [] + for i in range(len(dropout_probs)): + self.dropouts.append(nn.Dropout(p=dropout_probs[i])) + + input_dims = [input_dim] + num_neurons + output_dims = num_neurons + [output_dim] + + self.lins = nn.ModuleList() + for i, (in_dim, out_dim) in enumerate(zip(input_dims, output_dims)): + self.lins.append(nn.Linear(in_dim, out_dim)) + + self.input_norm = self._get_norm_layer(input_norm, input_dim) + self.output_norm = self._get_norm_layer(output_norm, output_dim) + + def forward(self, xs): + xs = self.input_norm(xs) + for i, lin in enumerate(self.lins[:-1]): + xs = lin(xs) + xs = self.hidden_act(xs) + xs = self.dropouts[i](xs) + xs = self.lins[-1](xs) + xs = self.out_act(xs) + xs = self.output_norm(xs) + return xs + + @staticmethod + def _get_norm_layer(norm_method, dim): + if norm_method == "Batch": + in_norm = nn.BatchNorm1d(dim) + elif norm_method == "Layer": + in_norm = nn.LayerNorm(dim) + elif norm_method == "None": + in_norm = nn.Identity() # kinda placeholder + else: + raise RuntimeError( + "Not implemented normalization layer type {}".format(norm_method) + ) + return in_norm + + def _get_act(self, is_last): + return self.out_act if is_last else self.hidden_act diff --git a/rl4co/models/nn/moe.py b/rl4co/models/nn/moe.py new file mode 100644 index 00000000..a2b04584 --- /dev/null +++ b/rl4co/models/nn/moe.py @@ -0,0 +1,277 @@ +import torch +import torch.nn as nn +from torch.distributions.normal import Normal + +from rl4co.models.nn.mlp import MLP + +""" + Pytorch Implementation based on + Author: David Rau + Link: +""" + + +class SparseDispatcher(object): + """ + Helper for implementing a mixture of experts. + The purpose of this class is to create input minibatches for the experts + and to combine the results of the experts to form a unified output tensor. + + There are two functions: + dispatch - take an input Tensor and create input Tensors for each expert. + combine - take output Tensors from each expert and form a combined output + Tensor. Outputs from different experts for the same batch element are + summed together, weighted by the provided "gates". + + The class is initialized with a "gates" Tensor, which specifies which + batch elements go to which experts, and the weights to use when combining + the outputs. Batch element b is sent to expert e iff gates[b, e] != 0. + The inputs and outputs are all two-dimensional [batch, depth]. + Caller is responsible for collapsing additional dimensions prior to + calling this class and reshaping the output to the original shape. + See common_layers.reshape_like(). + + Example use: + gates: a float32 `Tensor` with shape `[batch_size, num_experts]` + inputs: a float32 `Tensor` with shape `[batch_size, input_size]` + experts: a list of length `num_experts` containing sub-networks. + dispatcher = SparseDispatcher(num_experts, gates) + expert_inputs = dispatcher.dispatch(inputs) + expert_outputs = [experts[i](expert_inputs[i]) for i in range(num_experts)] + outputs = dispatcher.combine(expert_outputs) + The preceding code sets the output for a particular example b to: + output[b] = Sum_i(gates[b, i] * experts[i](inputs[b])) + This class takes advantage of sparsity in the gate matrix by including in the + `Tensor`s for expert i only the batch elements for which `gates[b, i] > 0`. + """ + + def __init__(self, num_experts, gates): + """Create a SparseDispatcher.""" + + self._gates = gates + self._num_experts = num_experts + # sort experts + sorted_experts, index_sorted_experts = torch.nonzero(gates).sort(0) + # drop indices + _, self._expert_index = sorted_experts.split(1, dim=1) + # get according batch index for each expert + self._batch_index = torch.nonzero(gates)[index_sorted_experts[:, 1], 0] + # calculate num samples that each expert gets + self._part_sizes = (gates > 0).sum(0).tolist() + # expand gates to match with self._batch_index + gates_exp = gates[self._batch_index.flatten()] + self._nonzero_gates = torch.gather(gates_exp, 1, self._expert_index) + + def dispatch(self, inp): + """Create one input Tensor for each expert. + The `Tensor` for a expert `i` contains the slices of `inp` corresponding + to the batch elements `b` where `gates[b, i] > 0`. + Args: + inp: a `Tensor` of shape "[batch_size, ]` + Returns: + a list of `num_experts` `Tensor`s with shapes + [expert_batch_size_i, ]`. + """ + + # assigns samples to experts whose gate is nonzero + # expand according to batch index so we can just split by _part_sizes + inp_exp = inp[self._batch_index].squeeze(1) + return torch.split(inp_exp, self._part_sizes, dim=0) + + def combine(self, expert_out, multiply_by_gates=True): + """Sum together the expert output, weighted by the gates. + The slice corresponding to a particular batch element `b` is computed + as the sum over all experts `i` of the expert output, weighted by the + corresponding gate values. If `multiply_by_gates` is set to False, the + gate values are ignored. + Args: + expert_out: a list of `num_experts` `Tensor`s, each with shape + [expert_batch_size_i, ]`. + multiply_by_gates: a boolean + Returns: + a `Tensor` with shape `[batch_size, ]`. + """ + # apply exp to expert outputs, so we are not longer in log space + stitched = torch.cat(expert_out, 0) + + if multiply_by_gates: + stitched = stitched.mul(self._nonzero_gates) + zeros = torch.zeros(self._gates.size(0), expert_out[-1].size(-1), requires_grad=True, device=stitched.device) + # combine samples that have been processed by the same k experts + combined = zeros.index_add(0, self._batch_index, stitched.float()) + return combined + + def expert_to_gates(self): + """Gate values corresponding to the examples in the per-expert `Tensor`s. + Returns: + a list of `num_experts` one-dimensional `Tensor`s with type `tf.float32` + and shapes `[expert_batch_size_i]` + """ + # split nonzero gates for each expert + return torch.split(self._nonzero_gates, self._part_sizes, dim=0) + + +class MoE(nn.Module): + """Call a Sparsely gated mixture of experts layer with 1-layer Feed-Forward networks as experts. + Args: + input_size: integer - size of the input + output_size: integer - size of the input + num_experts: an integer - number of experts + num_neurons: a list - hidden dimension of the experts + noisy_gating: a boolean + k: an integer - how many experts to use for each batch element + """ + + def __init__(self, input_size, output_size, num_neurons=[], hidden_act="ReLU", out_bias=True, num_experts=4, k=2, noisy_gating=True, **kwargs): + super(MoE, self).__init__() + self.noisy_gating = noisy_gating + self.num_experts = num_experts + self.output_size = output_size + self.input_size = input_size + self.k = k + + # instantiate experts + if num_neurons != []: + self.experts = nn.ModuleList([MLP(input_dim=input_size, output_dim=output_size, num_neurons=num_neurons, + hidden_act=hidden_act) for _ in range(self.num_experts)]) + else: + self.experts = nn.ModuleList([nn.Linear(self.input_size, self.output_size, bias=out_bias) for _ in range(self.num_experts)]) + self.w_gate = nn.Parameter(torch.zeros(input_size, num_experts), requires_grad=True) + self.w_noise = nn.Parameter(torch.zeros(input_size, num_experts), requires_grad=True) + + self.softplus = nn.Softplus() + self.softmax = nn.Softmax(-1) + self.register_buffer("mean", torch.tensor([0.0])) + self.register_buffer("std", torch.tensor([1.0])) + assert(self.k <= self.num_experts) + + def cv_squared(self, x): + """The squared coefficient of variation of a sample. + Useful as a loss to encourage a positive distribution to be more uniform. + Epsilons added for numerical stability. + Returns 0 for an empty Tensor. + Args: + x: a `Tensor`. + Returns: + a `Scalar`. + """ + eps = 1e-10 + # if only num_experts = 1 + + if x.shape[0] == 1: + return torch.tensor([0], device=x.device, dtype=x.dtype) + return x.float().var() / (x.float().mean()**2 + eps) + + def _gates_to_load(self, gates): + """Compute the true load per expert, given the gates. + The load is the number of examples for which the corresponding gate is >0. + Args: + gates: a `Tensor` of shape [batch_size, n] + Returns: + a float32 `Tensor` of shape [n] + """ + return (gates > 0).sum(0) + + def _prob_in_top_k(self, clean_values, noisy_values, noise_stddev, noisy_top_values): + """Helper function to NoisyTopKGating. + Computes the probability that value is in top k, given different random noise. + This gives us a way of backpropagating from a loss that balances the number + of times each expert is in the top k experts per example. + In the case of no noise, pass in None for noise_stddev, and the result will + not be differentiable. + Args: + clean_values: a `Tensor` of shape [batch, n]. + noisy_values: a `Tensor` of shape [batch, n]. Equal to clean values plus + normally distributed noise with standard deviation noise_stddev. + noise_stddev: a `Tensor` of shape [batch, n], or None + noisy_top_values: a `Tensor` of shape [batch, m]. + "values" Output of tf.top_k(noisy_top_values, m). m >= k+1 + Returns: + a `Tensor` of shape [batch, n]. + """ + batch = clean_values.size(0) + m = noisy_top_values.size(1) + top_values_flat = noisy_top_values.flatten() + + threshold_positions_if_in = torch.arange(batch, device=clean_values.device) * m + self.k + threshold_if_in = torch.unsqueeze(torch.gather(top_values_flat, 0, threshold_positions_if_in), 1) + is_in = torch.gt(noisy_values, threshold_if_in) + threshold_positions_if_out = threshold_positions_if_in - 1 + threshold_if_out = torch.unsqueeze(torch.gather(top_values_flat, 0, threshold_positions_if_out), 1) + # is each value currently in the top k. + normal = Normal(self.mean, self.std) + prob_if_in = normal.cdf((clean_values - threshold_if_in)/noise_stddev) + prob_if_out = normal.cdf((clean_values - threshold_if_out)/noise_stddev) + prob = torch.where(is_in, prob_if_in, prob_if_out) + return prob + + def noisy_top_k_gating(self, x, train, noise_epsilon=1e-2): + """Noisy top-k gating. + See paper: . + Args: + x: input Tensor with shape [batch_size, input_size] + train: a boolean - we only add noise at training time. + noise_epsilon: a float + Returns: + gates: a Tensor with shape [batch_size, num_experts] + load: a Tensor with shape [num_experts] + """ + clean_logits = x @ self.w_gate + if self.noisy_gating and train: + raw_noise_stddev = x @ self.w_noise + noise_stddev = self.softplus(raw_noise_stddev) + noise_epsilon + noisy_logits = clean_logits + (torch.randn_like(clean_logits) * noise_stddev) + logits = noisy_logits + else: + logits = clean_logits + + # calculate topk + 1 that will be needed for the noisy gates + logits = self.softmax(logits) + top_logits, top_indices = logits.topk(min(self.k + 1, self.num_experts), dim=-1) + top_k_logits = top_logits[:, :self.k] + top_k_indices = top_indices[:, :self.k] + top_k_gates = top_k_logits / (top_k_logits.sum(1, keepdim=True) + 1e-6) # normalization + + zeros = torch.zeros_like(logits, requires_grad=True) + gates = zeros.scatter(-1, top_k_indices, top_k_gates) # non-topk elements will be 0 + + if self.noisy_gating and self.k < self.num_experts and train: + load = (self._prob_in_top_k(clean_logits, noisy_logits, noise_stddev, top_logits)).sum(0) + else: + load = self._gates_to_load(gates) + return gates, load + + def forward(self, x, loss_coef=0.): + """ + Token/Node-level Gating with the default gating algorithm in . + In specific, each token/node chooses TopK experts, auxiliary losses required for load balancing. + Empirically, we found that the load-balancing loss may conflict with the reinforcement loss, + and thus we do not return loss (i.e., loss_coef=0.). + Please Refer to (Zhou et al, 2024) . + + Args: + x: tensor shape [batch_size, problem_size, input_size] + loss_coef: a scalar - multiplier on load-balancing losses + + Returns: + y: a tensor with shape [batch_size, problem_size, output_size]. + loss: a scalar. This should be added into the overall training loss of the model. + The backpropagation of this loss encourages all experts to be approximately equally used across a batch. + """ + output_shape = list(x.size()[:-1]) + [self.output_size] + x = x.reshape(-1, self.input_size) if x.dim() != 2 else x + + gates, load = self.noisy_top_k_gating(x, self.training) + # calculate importance loss + importance = gates.sum(0) + loss = self.cv_squared(importance) + self.cv_squared(load) + loss *= loss_coef + + dispatcher = SparseDispatcher(self.num_experts, gates) + expert_inputs = dispatcher.dispatch(x) + # gates = dispatcher.expert_to_gates() + expert_outputs = [self.experts[i](expert_inputs[i]) for i in range(self.num_experts)] + y = dispatcher.combine(expert_outputs) + + # return y.reshape(output_shape), loss + return y.reshape(output_shape) diff --git a/rl4co/models/nn/ops.py b/rl4co/models/nn/ops.py new file mode 100644 index 00000000..f6f774fe --- /dev/null +++ b/rl4co/models/nn/ops.py @@ -0,0 +1,137 @@ +import math + +from typing import Tuple, Union + +import torch +import torch.nn as nn + +from rl4co.utils.ops import gather_by_index + + +class SkipConnection(nn.Module): + def __init__(self, module): + super(SkipConnection, self).__init__() + self.module = module + + def forward(self, x): + return x + self.module(x) + + +class AdaptiveSequential(nn.Sequential): + def forward( + self, *inputs: Union[Tuple[torch.Tensor], torch.Tensor] + ) -> Union[Tuple[torch.Tensor], torch.Tensor]: + for module in self._modules.values(): + if type(inputs) == tuple: + inputs = module(*inputs) + else: + inputs = module(inputs) + return inputs + + +class Normalization(nn.Module): + def __init__(self, embed_dim, normalization="batch"): + super(Normalization, self).__init__() + if normalization != "layer": + normalizer_class = { + "batch": nn.BatchNorm1d, + "instance": nn.InstanceNorm1d, + }.get(normalization, None) + + self.normalizer = normalizer_class(embed_dim, affine=True) + else: + self.normalizer = "layer" + + def forward(self, x): + if isinstance(self.normalizer, nn.BatchNorm1d): + return self.normalizer(x.view(-1, x.size(-1))).view(*x.size()) + elif isinstance(self.normalizer, nn.InstanceNorm1d): + return self.normalizer(x.permute(0, 2, 1)).permute(0, 2, 1) + elif self.normalizer == "layer": + return (x - x.mean((1, 2)).view(-1, 1, 1)) / torch.sqrt( + x.var((1, 2)).view(-1, 1, 1) + 1e-05 + ) + else: + assert self.normalizer is None, "Unknown normalizer type" + return x + + +class PositionalEncoding(nn.Module): + def __init__(self, embed_dim: int, dropout: float = 0.1, max_len: int = 1000): + super().__init__() + self.dropout = nn.Dropout(p=dropout) + self.d_model = embed_dim + max_len = max_len + position = torch.arange(max_len).unsqueeze(1) + div_term = torch.exp( + torch.arange(0, self.d_model, 2) * (-math.log(10000.0) / self.d_model) + ) + pe = torch.zeros(max_len, 1, self.d_model) + pe[:, 0, 0::2] = torch.sin(position * div_term) + pe[:, 0, 1::2] = torch.cos(position * div_term) + pe = pe.transpose(0, 1) # [1, max_len, d_model] + self.register_buffer("pe", pe) + + def forward(self, hidden: torch.Tensor, seq_pos) -> torch.Tensor: + """ + Arguments: + x: Tensor, shape ``[batch_size, seq_len, embedding_dim]`` + seq_pos: Tensor, shape ``[batch_size, seq_len]`` + """ + pes = self.pe.expand(hidden.size(0), -1, -1).gather( + 1, seq_pos.unsqueeze(-1).expand(-1, -1, self.d_model) + ) + hidden = hidden + pes + return self.dropout(hidden) + + +class TransformerFFN(nn.Module): + def __init__(self, embed_dim, feed_forward_hidden, normalization="batch") -> None: + super().__init__() + + self.ops = nn.ModuleDict( + { + "norm1": Normalization(embed_dim, normalization), + "ffn": nn.Sequential( + nn.Linear(embed_dim, feed_forward_hidden), + nn.ReLU(), + nn.Linear(feed_forward_hidden, embed_dim), + ), + "norm2": Normalization(embed_dim, normalization), + } + ) + + def forward(self, x, x_old): + x = self.ops["norm1"](x_old + x) + x = self.ops["norm2"](x + self.ops["ffn"](x)) + + return x + + +class RandomEncoding(nn.Module): + """This is like torch.nn.Embedding but with rows of embeddings are randomly + permuted in each forward pass before lookup operation. This might be useful + in cases where classes have no fixed meaning but rather indicate a connection + between different elements in a sequence. Reference is the MatNet model. + """ + + def __init__(self, embed_dim: int, max_classes: int = 100): + super().__init__() + self.embed_dim = embed_dim + self.max_classes = max_classes + rand_emb = torch.rand(max_classes, self.embed_dim) + self.register_buffer("emb", rand_emb) + + def forward(self, hidden: torch.Tensor, classes=None) -> torch.Tensor: + b, s, _ = hidden.shape + if classes is None: + classes = torch.eye(s).unsqueeze(0).expand(b, s) + assert ( + classes.max() < self.max_classes + ), "number of classes larger than embedding table" + classes = classes.unsqueeze(-1).expand(-1, -1, self.embed_dim) + rand_idx = torch.rand(b, self.max_classes).argsort(dim=1) + embs_permuted = self.emb[rand_idx] + rand_emb = gather_by_index(embs_permuted, classes, dim=1) + hidden = hidden + rand_emb + return hidden diff --git a/rl4co/models/nn/pos_embeddings.py b/rl4co/models/nn/pos_embeddings.py new file mode 100644 index 00000000..9d217e63 --- /dev/null +++ b/rl4co/models/nn/pos_embeddings.py @@ -0,0 +1,159 @@ +import numpy as np +import torch +import torch.nn as nn + + +def pos_init_embedding(pos_name: str, config: dict) -> nn.Module: + """Get positional embedding. The positional embedding is used for improvement methods to encode current solutions. + + Args: + pos_name: Positional embeding method name. + config: A dictionary of configuration options for the initlization. + """ + embedding_registry = { + "APE": AbsolutePositionalEmbedding, + "CPE": CyclicPositionalEmbedding, + } + + if pos_name not in embedding_registry: + raise ValueError( + f"Unknown positional embedding name '{pos_name}'. Available positional embeddings: {embedding_registry.keys()}" + ) + + return embedding_registry[pos_name](**config) + + +class AbsolutePositionalEmbedding(nn.Module): + """Absolute Positional Embedding in the original Transformer.""" + + def __init__(self, embed_dim): + super(AbsolutePositionalEmbedding, self).__init__() + self.embed_dim = embed_dim + self.pattern = None + + def _init(self, n_position, emb_dim): + pattern = torch.tensor( + [ + [pos / np.power(10000, 2 * (j // 2) / emb_dim) for j in range(emb_dim)] + for pos in range(1, n_position + 1) + ], + dtype=torch.float32, + ) + + pattern[1:, 0::2] = torch.sin(pattern[1:, 0::2]) # dim 2i + pattern[1:, 1::2] = torch.cos(pattern[1:, 1::2]) # dim 2i+1 + + return pattern + + def forward(self, td): + batch_size, seq_length = td["rec_current"].size() + visited_time = td["visited_time"] + embedding_dim = self.embed_dim + + # expand for every batch + if self.pattern is None or self.pattern.size(0) != seq_length: + self.pattern = self._init(seq_length, self.embed_dim) + + batch_vector = ( + self.pattern.expand(batch_size, seq_length, embedding_dim) + .clone() + .to(visited_time.device) + ) + index = ( + (visited_time % seq_length) + .long() + .unsqueeze(-1) + .expand(batch_size, seq_length, embedding_dim) + ) + + return torch.gather(batch_vector, 1, index) + + +class CyclicPositionalEmbedding(nn.Module): + """Cyclic Positional Embedding presented in Ma et al.(2021) + See https://arxiv.org/abs/2110.02544 + """ + + def __init__(self, embed_dim, mean_pooling=True): + super(CyclicPositionalEmbedding, self).__init__() + self.embed_dim = embed_dim + self.mean_pooling = mean_pooling + self.pattern = None + + def _basesin(self, x, T, fai=0): + return np.sin(2 * np.pi / T * np.abs(np.mod(x, 2 * T) - T) + fai) + + def _basecos(self, x, T, fai=0): + return np.cos(2 * np.pi / T * np.abs(np.mod(x, 2 * T) - T) + fai) + + def _init(self, n_position, emb_dim, mean_pooling): + Td_set = np.linspace( + np.power(n_position, 1 / (emb_dim // 2)), + n_position, + emb_dim // 2, + dtype="int", + ) + x = np.zeros((n_position, emb_dim)) + + for i in range(emb_dim): + Td = ( + Td_set[i // 3 * 3 + 1] + if (i // 3 * 3 + 1) < (emb_dim // 2) + else Td_set[-1] + ) + fai = ( + 0 + if i <= (emb_dim // 2) + else 2 * np.pi * ((-i + (emb_dim // 2)) / (emb_dim // 2)) + ) + longer_pattern = np.arange(0, np.ceil((n_position) / Td) * Td, 0.01) + if i % 2 == 1: + x[:, i] = self._basecos(longer_pattern, Td, fai)[ + np.linspace( + 0, len(longer_pattern), n_position, dtype="int", endpoint=False + ) + ] + else: + x[:, i] = self._basesin(longer_pattern, Td, fai)[ + np.linspace( + 0, len(longer_pattern), n_position, dtype="int", endpoint=False + ) + ] + + pattern = torch.from_numpy(x).type(torch.FloatTensor) + pattern_sum = torch.zeros_like(pattern) + + # averaging the adjacient embeddings if needed (optional, almost the same performance) + arange = torch.arange(n_position) + pooling = [0] if not mean_pooling else [-2, -1, 0, 1, 2] + time = 0 + for i in pooling: + time += 1 + index = (arange + i + n_position) % n_position + pattern_sum += pattern.gather(0, index.view(-1, 1).expand_as(pattern)) + pattern = 1.0 / time * pattern_sum - pattern.mean(0) + + return pattern + + def forward(self, td): + batch_size, seq_length = td["rec_current"].size() + visited_time = td["visited_time"] + embedding_dim = self.embed_dim + + # expand for every batch + if self.pattern is None or self.pattern.size(0) != seq_length: + self.pattern = self._init(seq_length, self.embed_dim, self.mean_pooling) + + batch_vector = ( + self.pattern.expand(batch_size, seq_length, embedding_dim) + .clone() + .to(visited_time.device) + ) + index = ( + (visited_time % seq_length) + .long() + .unsqueeze(-1) + .expand(batch_size, seq_length, embedding_dim) + ) + + return torch.gather(batch_vector, 1, index) diff --git a/rl4co/models/rl/__init__.py b/rl4co/models/rl/__init__.py new file mode 100644 index 00000000..1a3bf7e2 --- /dev/null +++ b/rl4co/models/rl/__init__.py @@ -0,0 +1,6 @@ +from rl4co.models.rl.a2c.a2c import A2C +from rl4co.models.rl.common.base import RL4COLitModule +from rl4co.models.rl.ppo.n_step_ppo import n_step_PPO +from rl4co.models.rl.ppo.ppo import PPO +from rl4co.models.rl.ppo.stepwise_ppo import StepwisePPO +from rl4co.models.rl.reinforce.reinforce import REINFORCE diff --git a/rl4co/models/rl/a2c/__init__.py b/rl4co/models/rl/a2c/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/models/rl/a2c/a2c.py b/rl4co/models/rl/a2c/a2c.py new file mode 100644 index 00000000..09b3f980 --- /dev/null +++ b/rl4co/models/rl/a2c/a2c.py @@ -0,0 +1,58 @@ +import torch.nn as nn + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl.common.critic import CriticNetwork, create_critic_from_actor +from rl4co.models.rl.reinforce.baselines import CriticBaseline +from rl4co.models.rl.reinforce.reinforce import REINFORCE +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class A2C(REINFORCE): + """Advantage Actor Critic (A2C) algorithm. + A2C is a variant of REINFORCE where a baseline is provided by a critic network. + Here we additionally support different optimizers for the actor and the critic. + + Args: + env: Environment to use for the algorithm + policy: Policy to use for the algorithm + critic: Critic network to use for the algorithm + critic_kwargs: Keyword arguments to pass to the critic network + actor_optimizer_kwargs: Keyword arguments for the policy (=actor) optimizer + critic_optimizer_kwargs: Keyword arguments for the critic optimizer. If None, use the same as actor_optimizer_kwargs + **kwargs: Keyword arguments passed to the superclass + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: nn.Module, + critic: CriticNetwork = None, + critic_kwargs: dict = {}, + actor_optimizer_kwargs: dict = {"lr": 1e-4}, + critic_optimizer_kwargs: dict = None, + **kwargs, + ): + if critic is None: + log.info("Creating critic network for {}".format(env.name)) + critic = create_critic_from_actor(policy, **critic_kwargs) + + # The baseline is directly created here, so we eliminate the baseline argument + kwargs.pop("baseline", None) + + super().__init__(env, policy, baseline=CriticBaseline(critic), **kwargs) + self.actor_optimizer_kwargs = actor_optimizer_kwargs + self.critic_optimizer_kwargs = ( + critic_optimizer_kwargs + if critic_optimizer_kwargs is not None + else actor_optimizer_kwargs + ) + + def configure_optimizers(self): + """Configure the optimizers for the policy and the critic network (=baseline)""" + parameters = [ + {"params": self.policy.parameters(), **self.actor_optimizer_kwargs}, + ] + [{"params": self.baseline.parameters(), **self.critic_optimizer_kwargs}] + + return super().configure_optimizers(parameters) diff --git a/rl4co/models/rl/common/__init__.py b/rl4co/models/rl/common/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/models/rl/common/base.py b/rl4co/models/rl/common/base.py new file mode 100644 index 00000000..1d30ca52 --- /dev/null +++ b/rl4co/models/rl/common/base.py @@ -0,0 +1,333 @@ +import abc + +from functools import partial +from typing import Any, Iterable, List, Union + +import torch +import torch.nn as nn + +from lightning import LightningModule +from torch.utils.data import DataLoader + +from rl4co.data.generate_data import generate_default_datasets +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.utils.optim_helpers import create_optimizer, create_scheduler +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class RL4COLitModule(LightningModule, metaclass=abc.ABCMeta): + """Base class for Lightning modules for RL4CO. This defines the general training loop in terms of + RL algorithms. Subclasses should implement mainly the `shared_step` to define the specific + loss functions and optimization routines. + + Args: + env: RL4CO environment + policy: policy network (actor) + batch_size: batch size (general one, default used for training) + val_batch_size: specific batch size for validation. If None, will use `batch_size`. If list, will use one for each dataset + test_batch_size: specific batch size for testing. If None, will use `val_batch_size`. If list, will use one for each dataset + train_data_size: size of training dataset for one epoch + val_data_size: size of validation dataset for one epoch + test_data_size: size of testing dataset for one epoch + optimizer: optimizer or optimizer name + optimizer_kwargs: optimizer kwargs + lr_scheduler: learning rate scheduler or learning rate scheduler name + lr_scheduler_kwargs: learning rate scheduler kwargs + lr_scheduler_interval: learning rate scheduler interval + lr_scheduler_monitor: learning rate scheduler monitor + generate_default_data: whether to generate default datasets, filling up the data directory + shuffle_train_dataloader: whether to shuffle training dataloader. Default is False since we recreate dataset every epoch + dataloader_num_workers: number of workers for dataloader + data_dir: data directory + metrics: metrics + litmodule_kwargs: kwargs for `LightningModule` + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: nn.Module, + batch_size: int = 512, + val_batch_size: Union[List[int], int] = None, + test_batch_size: Union[List[int], int] = None, + train_data_size: int = 100_000, + val_data_size: int = 10_000, + test_data_size: int = 10_000, + optimizer: Union[str, torch.optim.Optimizer, partial] = "Adam", + optimizer_kwargs: dict = {"lr": 1e-4}, + lr_scheduler: Union[str, torch.optim.lr_scheduler.LRScheduler, partial] = None, + lr_scheduler_kwargs: dict = { + "milestones": [80, 95], + "gamma": 0.1, + }, + lr_scheduler_interval: str = "epoch", + lr_scheduler_monitor: str = "val/reward", + generate_default_data: bool = False, + shuffle_train_dataloader: bool = False, + dataloader_num_workers: int = 0, + data_dir: str = "data/", + log_on_step: bool = True, + metrics: dict = {}, + **litmodule_kwargs, + ): + super().__init__(**litmodule_kwargs) + + # This line ensures params passed to LightningModule will be saved to ckpt + # it also allows to access params with 'self.hparams' attribute + # Note: we will send to logger with `self.logger.save_hyperparams` in `setup` + self.save_hyperparameters(logger=False) + + self.env = env + self.policy = policy + + self.instantiate_metrics(metrics) + self.log_on_step = log_on_step + + self.data_cfg = { + "batch_size": batch_size, + "val_batch_size": val_batch_size, + "test_batch_size": test_batch_size, + "generate_default_data": generate_default_data, + "data_dir": data_dir, + "train_data_size": train_data_size, + "val_data_size": val_data_size, + "test_data_size": test_data_size, + } + + self._optimizer_name_or_cls: Union[str, torch.optim.Optimizer] = optimizer + self.optimizer_kwargs: dict = optimizer_kwargs + self._lr_scheduler_name_or_cls: Union[ + str, torch.optim.lr_scheduler.LRScheduler + ] = lr_scheduler + self.lr_scheduler_kwargs: dict = lr_scheduler_kwargs + self.lr_scheduler_interval: str = lr_scheduler_interval + self.lr_scheduler_monitor: str = lr_scheduler_monitor + + self.shuffle_train_dataloader = shuffle_train_dataloader + self.dataloader_num_workers = dataloader_num_workers + + def instantiate_metrics(self, metrics: dict): + """Dictionary of metrics to be logged at each phase""" + + if not metrics: + log.info("No metrics specified, using default") + self.train_metrics = metrics.get("train", ["loss", "reward"]) + self.val_metrics = metrics.get("val", ["reward"]) + self.test_metrics = metrics.get("test", ["reward"]) + self.log_on_step = metrics.get("log_on_step", True) + + def setup(self, stage="fit"): + """Base LightningModule setup method. This will setup the datasets and dataloaders + + Note: + We also send to the loggers all hyperparams that are not `nn.Module` (i.e. the policy). + Apparently PyTorch Lightning does not do this by default. + """ + + log.info("Setting up batch sizes for train/val/test") + train_bs, val_bs, test_bs = ( + self.data_cfg["batch_size"], + self.data_cfg["val_batch_size"], + self.data_cfg["test_batch_size"], + ) + self.train_batch_size = train_bs + self.val_batch_size = train_bs if val_bs is None else val_bs + self.test_batch_size = self.val_batch_size if test_bs is None else test_bs + + if self.data_cfg["generate_default_data"]: + log.info( + "Generating default datasets. If found, they will not be overwritten" + ) + generate_default_datasets(data_dir=self.data_cfg["data_dir"]) + + log.info("Setting up datasets") + self.train_dataset = self.wrap_dataset( + self.env.dataset(self.data_cfg["train_data_size"], phase="train") + ) + self.val_dataset = self.env.dataset(self.data_cfg["val_data_size"], phase="val") + self.test_dataset = self.env.dataset( + self.data_cfg["test_data_size"], phase="test" + ) + self.dataloader_names = None + self.setup_loggers() + self.post_setup_hook() + + def setup_loggers(self): + """Log all hyperparameters except those in `nn.Module`""" + if self.loggers is not None: + hparams_save = { + k: v for k, v in self.hparams.items() if not isinstance(v, nn.Module) + } + for logger in self.loggers: + logger.log_hyperparams(hparams_save) + logger.log_graph(self) + logger.save() + + def post_setup_hook(self): + """Hook to be called after setup. Can be used to set up subclasses without overriding `setup`""" + pass + + def configure_optimizers(self, parameters=None): + """ + Args: + parameters: parameters to be optimized. If None, will use `self.parameters()`, i.e. all parameters + """ + + if parameters is None: + parameters = self.parameters() + + log.info(f"Instantiating optimizer <{self._optimizer_name_or_cls}>") + if isinstance(self._optimizer_name_or_cls, str): + optimizer = create_optimizer( + parameters, self._optimizer_name_or_cls, **self.optimizer_kwargs + ) + elif isinstance(self._optimizer_name_or_cls, partial): + optimizer = self._optimizer_name_or_cls(parameters, **self.optimizer_kwargs) + else: # User-defined optimizer + opt_cls = self._optimizer_name_or_cls + optimizer = opt_cls(parameters, **self.optimizer_kwargs) + assert isinstance(optimizer, torch.optim.Optimizer) + + # instantiate lr scheduler + if self._lr_scheduler_name_or_cls is None: + return optimizer + else: + log.info(f"Instantiating LR scheduler <{self._lr_scheduler_name_or_cls}>") + if isinstance(self._lr_scheduler_name_or_cls, str): + scheduler = create_scheduler( + optimizer, self._lr_scheduler_name_or_cls, **self.lr_scheduler_kwargs + ) + elif isinstance(self._lr_scheduler_name_or_cls, partial): + scheduler = self._lr_scheduler_name_or_cls( + optimizer, **self.lr_scheduler_kwargs + ) + else: # User-defined scheduler + scheduler_cls = self._lr_scheduler_name_or_cls + scheduler = scheduler_cls(optimizer, **self.lr_scheduler_kwargs) + assert isinstance(scheduler, torch.optim.lr_scheduler.LRScheduler) + return [optimizer], { + "scheduler": scheduler, + "interval": self.lr_scheduler_interval, + "monitor": self.lr_scheduler_monitor, + } + + def log_metrics( + self, metric_dict: dict, phase: str, dataloader_idx: Union[int, None] = None + ): + """Log metrics to logger and progress bar""" + metrics = getattr(self, f"{phase}_metrics") + dataloader_name = "" + if dataloader_idx is not None and self.dataloader_names is not None: + dataloader_name = "/" + self.dataloader_names[dataloader_idx] + metrics = { + f"{phase}/{k}{dataloader_name}": v.mean() + if isinstance(v, torch.Tensor) + else v + for k, v in metric_dict.items() + if k in metrics + } + log_on_step = self.log_on_step if phase == "train" else False + on_epoch = False if phase == "train" else True + self.log_dict( + metrics, + on_step=log_on_step, + on_epoch=on_epoch, + prog_bar=True, + sync_dist=True, + add_dataloader_idx=False, # we add manually above + ) + return metrics + + def forward(self, td, **kwargs): + """Forward pass for the model. Simple wrapper around `policy`. Uses `env` from the module if not provided.""" + if kwargs.get("env", None) is None: + env = self.env + else: + log.info("Using env from kwargs") + env = kwargs.pop("env") + return self.policy(td, env, **kwargs) + + def shared_step(self, batch: Any, batch_idx: int, phase: str, **kwargs): + """Shared step between train/val/test. To be implemented in subclass""" + raise NotImplementedError("Shared step is required to implemented in subclass") + + def training_step(self, batch: Any, batch_idx: int): + # To use new data every epoch, we need to call reload_dataloaders_every_epoch=True in Trainer + return self.shared_step(batch, batch_idx, phase="train") + + def validation_step(self, batch: Any, batch_idx: int, dataloader_idx: int = None): + return self.shared_step( + batch, batch_idx, phase="val", dataloader_idx=dataloader_idx + ) + + def test_step(self, batch: Any, batch_idx: int, dataloader_idx: int = None): + return self.shared_step( + batch, batch_idx, phase="test", dataloader_idx=dataloader_idx + ) + + def train_dataloader(self): + return self._dataloader( + self.train_dataset, self.train_batch_size, self.shuffle_train_dataloader + ) + + def val_dataloader(self): + return self._dataloader(self.val_dataset, self.val_batch_size) + + def test_dataloader(self): + return self._dataloader(self.test_dataset, self.test_batch_size) + + def on_train_epoch_end(self): + """Called at the end of the training epoch. This can be used for instance to update the train dataset + with new data (which is the case in RL). + """ + # Only update if not in the first epoch + # If last epoch, we don't need to update since we will not use the dataset anymore + if self.current_epoch < self.trainer.max_epochs - 1: + log.info("Generating training dataset for next epoch...") + train_dataset = self.env.dataset(self.data_cfg["train_data_size"], "train") + self.train_dataset = self.wrap_dataset(train_dataset) + + def wrap_dataset(self, dataset): + """Wrap dataset with policy-specific wrapper. This is useful i.e. in REINFORCE where we need to + collect the greedy rollout baseline outputs. + """ + return dataset + + def _dataloader(self, dataset, batch_size, shuffle=False): + """Handle both single datasets and list / dict of datasets""" + if isinstance(dataset, Iterable): + # load dataloader names if available as dict, else use indices + if isinstance(dataset, dict): + self.dataloader_names = list(dataset.keys()) + else: + self.dataloader_names = [f"{i}" for i in range(len(dataset))] + # if batch size is int, make it into list + if isinstance(batch_size, int): + batch_size = [batch_size] * len(self.dataloader_names) + assert len(batch_size) == len( + self.dataloader_names + ), f"Batch size must match number of datasets. \ + Found: {len(batch_size)} and {len(self.dataloader_names)}" + return [ + self._dataloader_single(dset, bsize, shuffle) + for dset, bsize in zip(dataset.values(), batch_size) + ] + else: + assert isinstance( + batch_size, int + ), f"Batch size must be an integer for a single dataset, found {batch_size}" + return self._dataloader_single(dataset, batch_size, shuffle) + + def _dataloader_single(self, dataset, batch_size, shuffle=False): + """The dataloader used by the trainer. This is a wrapper around the dataset with a custom collate_fn + to efficiently handle TensorDicts. + """ + return DataLoader( + dataset, + batch_size=batch_size, + shuffle=shuffle, + num_workers=self.dataloader_num_workers, + collate_fn=dataset.collate_fn, + ) diff --git a/rl4co/models/rl/common/critic.py b/rl4co/models/rl/common/critic.py new file mode 100644 index 00000000..2a37e273 --- /dev/null +++ b/rl4co/models/rl/common/critic.py @@ -0,0 +1,77 @@ +import copy + +from typing import Optional, Union + +from tensordict import TensorDict +from torch import Tensor, nn + +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class CriticNetwork(nn.Module): + """Create a critic network given an encoder (e.g. as the one in the policy network) + with a value head to transform the embeddings to a scalar value. + + Args: + encoder: Encoder module to encode the input + value_head: Value head to transform the embeddings to a scalar value + embed_dim: Dimension of the embeddings of the value head + hidden_dim: Dimension of the hidden layer of the value head + """ + + def __init__( + self, + encoder: nn.Module, + value_head: Optional[nn.Module] = None, + embed_dim: int = 128, + hidden_dim: int = 512, + customized: bool = False, + ): + super(CriticNetwork, self).__init__() + + self.encoder = encoder + if value_head is None: + # check if embed dim of encoder is different, if so, use it + if getattr(encoder, "embed_dim", embed_dim) != embed_dim: + log.warning( + f"Found encoder with different embed_dim {encoder.embed_dim} than the value head {embed_dim}. Using encoder embed_dim for value head." + ) + embed_dim = getattr(encoder, "embed_dim", embed_dim) + value_head = nn.Sequential( + nn.Linear(embed_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, 1) + ) + self.value_head = value_head + self.customized = customized + + def forward(self, x: Union[Tensor, TensorDict], hidden=None) -> Tensor: + """Forward pass of the critic network: encode the imput in embedding space and return the value + + Args: + x: Input containing the environment state. Can be a Tensor or a TensorDict + + Returns: + Value of the input state + """ + if not self.customized: # fir for most of costructive tasks + h, _ = self.encoder(x) # [batch_size, N, embed_dim] -> [batch_size, N] + return self.value_head(h).mean(1) # [batch_size, N] -> [batch_size] + else: # custimized encoder and value head with hidden input + h = self.encoder(x) # [batch_size, N, embed_dim] -> [batch_size, N] + return self.value_head(h, hidden) + + +def create_critic_from_actor( + policy: nn.Module, backbone: str = "encoder", **critic_kwargs +): + # we reuse the network of the policy's backbone, such as an encoder + encoder = getattr(policy, backbone, None) + if encoder is None: + raise ValueError( + f"CriticBaseline requires a backbone in the policy network: {backbone}" + ) + critic = CriticNetwork(copy.deepcopy(encoder), **critic_kwargs).to( + next(policy.parameters()).device + ) + return critic diff --git a/rl4co/models/rl/common/utils.py b/rl4co/models/rl/common/utils.py new file mode 100644 index 00000000..6c16976a --- /dev/null +++ b/rl4co/models/rl/common/utils.py @@ -0,0 +1,48 @@ +import torch + + +class RewardScaler: + """This class calculates the running mean and variance of a stepwise observed + quantity, like the RL reward / advantage using the Welford online algorithm. + The mean and variance are either used to standardize the input (scale='norm') or + to scale it (scale='scale'). + + Args: + scale: None | 'scale' | 'mean': specifies how to transform the input; defaults to None + """ + + def __init__(self, scale: str = None): + self.scale = scale + self.count = 0 + self.mean = 0 + self.M2 = 0 + + def __call__(self, scores: torch.Tensor): + if self.scale is None: + return scores + elif isinstance(self.scale, int): + return scores / self.scale + # Score scaling + self.update(scores) + tensor_to_kwargs = dict(dtype=scores.dtype, device=scores.device) + std = (self.M2 / (self.count - 1)).float().sqrt() + score_scaling_factor = std.to(**tensor_to_kwargs) + torch.finfo(scores.dtype).eps + if self.scale == "norm": + scores = (scores - self.mean.to(**tensor_to_kwargs)) / score_scaling_factor + elif self.scale == "scale": + scores /= score_scaling_factor + else: + raise ValueError("unknown scaling operation requested: %s" % self.scale) + return scores + + @torch.no_grad() + def update(self, batch: torch.Tensor): + batch = batch.reshape(-1) + self.count += len(batch) + + # newvalues - oldMean + delta = batch - self.mean + self.mean += (delta / self.count).sum() + # newvalues - newMeant + delta2 = batch - self.mean + self.M2 += (delta * delta2).sum() diff --git a/rl4co/models/rl/ppo/__init__.py b/rl4co/models/rl/ppo/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/models/rl/ppo/n_step_ppo.py b/rl4co/models/rl/ppo/n_step_ppo.py new file mode 100644 index 00000000..66e869fb --- /dev/null +++ b/rl4co/models/rl/ppo/n_step_ppo.py @@ -0,0 +1,282 @@ +from typing import Any + +import torch +import torch.nn as nn + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl.common.base import RL4COLitModule +from rl4co.models.rl.common.critic import CriticNetwork +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class Memory: + def __init__(self): + self.tds = [] + self.actions = [] + self.logprobs = [] + self.rewards = [] + + def clear_memory(self): + del self.tds[:] + del self.actions[:] + del self.logprobs[:] + del self.rewards[:] + + +class n_step_PPO(RL4COLitModule): + """ + An implementation of the n-step dactProximal Policy Optimization (PPO) algorithm (https://arxiv.org/abs/2110.02544) + is presented for training improvement models. + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: nn.Module, + critic: CriticNetwork = None, + critic_kwargs: dict = {}, + clip_range: float = 0.1, # epsilon of PPO + ppo_epochs: int = 3, # inner epoch, K + vf_lambda: float = 1.0, # lambda of Value function fitting + normalize_adv: bool = False, # whether to normalize advantage + max_grad_norm: float = 0.05, # max gradient norm + gamma: float = 0.999, # gamma for improvement MDP task + n_step: float = 5, # n-step for n-step PPO + T_train: int = 250, # the maximum inference T used for training + T_test: int = 1000, # the maximum inference T used for test + lr_policy: float = 8e-5, # the learning rate for actor + lr_critic: float = 2e-5, # the learning rate for critic + CL_scalar: float = 2.0, # hyperparameter of CL scalar of PPO-CL algorithm + CL_best: bool = False, # whether use the best solution from the CL rollout + metrics: dict = { + "train": ["loss", "surrogate_loss", "value_loss", "cost_bsf", "cost_init"], + "val": ["cost_bsf", "cost_init"], + "test": ["cost_bsf", "cost_init"], + }, + lr_scheduler=torch.optim.lr_scheduler.ExponentialLR, + lr_scheduler_kwargs: dict = { + "gamma": 0.985, # the learning decay per epoch, + }, + lr_scheduler_interval: str = "epoch", + lr_scheduler_monitor=None, + **kwargs, + ): + super().__init__( + env, + policy, + metrics=metrics, + lr_scheduler=lr_scheduler, + lr_scheduler_kwargs=lr_scheduler_kwargs, + lr_scheduler_interval=lr_scheduler_interval, + lr_scheduler_monitor=lr_scheduler_monitor, + **kwargs, + ) + + self.CL_scalar = CL_scalar + self.CL_num = 0.0 + self.CL_best = CL_best + self.automatic_optimization = False # n_step_PPO uses custom optimization routine + + self.critic = critic + + self.ppo_cfg = { + "clip_range": clip_range, + "ppo_epochs": ppo_epochs, + "vf_lambda": vf_lambda, + "normalize_adv": normalize_adv, + "max_grad_norm": max_grad_norm, + "gamma": gamma, + "n_step": n_step, + "T_train": T_train, + "T_test": T_test, + "lr_policy": lr_policy, + "lr_critic": lr_critic, + } + + def configure_optimizers(self): + parameters = [ + {"params": self.policy.parameters(), "lr": self.ppo_cfg["lr_policy"]} + ] + [{"params": self.critic.parameters(), "lr": self.ppo_cfg["lr_critic"]}] + + return super().configure_optimizers(parameters) + + def on_train_epoch_end(self): + """ + Learning rate scheduler and CL scheduler + """ + # Learning rate scheduler + sch = self.lr_schedulers() + sch.step() + + # CL scheduler + self.CL_num += 1 / self.CL_scalar + + def shared_step( + self, batch: Any, batch_idx: int, phase: str, dataloader_idx: int = None + ): + if phase != "train": + with torch.no_grad(): + td = self.env.reset(batch) + cost_init = td["cost_current"] + for i in range(self.ppo_cfg["T_test"]): + out = self.policy(td, self.env, phase=phase) + self.env.step(td) + out["cost_bsf"] = td["cost_bsf"] + + else: + # init the training + memory = Memory() + td = self.env.reset(batch) + + # perform CL strategy + with torch.no_grad(): + for i in range(int(self.CL_num)): + out = self.policy(td, self.env, phase=phase) + self.env.step(td) + if self.CL_best: + td = self.env.step_to_solution(td, td["rec_best"]) + cost_init = td["cost_current"] + + # perform gradiant updates every n_step untill reaching T_max + assert ( + self.ppo_cfg["T_train"] % self.ppo_cfg["n_step"] == 0 + ), "T_max should be divided by n_step with no remainder" + t = 0 + while t < self.ppo_cfg["T_train"]: + memory.clear_memory() + bl = [] + ll = [] + # Rollout for n_step, perform actor and critic and env step, store the information in memory + for i in range(self.ppo_cfg["n_step"]): + memory.tds.append(td.clone()) + + out = self.policy( + td, self.env, phase=phase, return_actions=True, return_embeds=True + ) + value_pred = self.critic( + out["embeds"].detach(), td["cost_bsf"].unsqueeze(-1) + ) + + memory.actions.append(out["actions"].clone()) + memory.logprobs.append(out["log_likelihood"].clone()) + bl.append(value_pred) + + self.env.step(td) + memory.rewards.append(td["reward"].clone().view(-1, 1)) + + t += self.ppo_cfg["n_step"] + + # PPO inner epoch, K + old_value = None + for k in range(self.ppo_cfg["ppo_epochs"]): + if k == 0: + ll = memory.logprobs + + else: + ll = [] + bl = [] + for i in range(self.ppo_cfg["n_step"]): + out = self.policy( + memory.tds[i].clone(), + actions=memory.actions[i], + env=self.env, + phase=phase, + return_actions=False, + return_embeds=True, + ) + bl_value = self.critic( + out["embeds"].detach(), + memory.tds[i]["cost_bsf"].unsqueeze(-1), + ) + + ll.append(out["log_likelihood"]) + bl.append(bl_value) + + # prepare loglikelihood (ll) and baseline value (bl) + ll = torch.stack(ll).view(-1, 1) + bl = torch.stack(bl).view(-1, 1) + old_ll = torch.stack(memory.logprobs).view(-1, 1) + + # Compute the Reward wrt n_step + Reward = [] + reward_reversed = memory.rewards[::-1] + R = self.critic( + self.policy(td, self.env, phase=phase, only_return_embed=True)[ + "embeds" + ].detach(), + td["cost_bsf"].unsqueeze(-1), + ).detach() # Remember to detach() since we only need the predicted value here + for r in range(len(reward_reversed)): + R = R * self.ppo_cfg["gamma"] + reward_reversed[r] + Reward.append(R.clone()) + Reward = torch.stack(Reward[::-1]).view(-1, 1) + + # Compute the ratio of probabilities of new and old actions + ratio = torch.exp(ll - old_ll.detach()) + + # Compute the advantage + adv = Reward - bl.detach() + + # Normalize advantage + if self.ppo_cfg["normalize_adv"]: + adv = (adv - adv.mean()) / (adv.std() + 1e-8) + + # Compute the surrogate loss + surrogate_loss = -torch.min( + ratio * adv, + torch.clamp( + ratio, + 1 - self.ppo_cfg["clip_range"], + 1 + self.ppo_cfg["clip_range"], + ) + * adv, + ).mean() + + # compute value function loss + if old_value is None: + value_loss = ((bl - Reward) ** 2).mean() + old_value = bl.detach() + else: + value_clipped = ( + torch.clamp( + bl - old_value, + -self.ppo_cfg["clip_range"], + self.ppo_cfg["clip_range"], + ) + + old_value + ) + + value_loss = torch.max( + (bl - Reward) ** 2, + (value_clipped - Reward) ** 2, + ).mean() + + # compute total loss + loss = surrogate_loss + self.ppo_cfg["vf_lambda"] * value_loss + + # perform manual optimization following the Lightning routine + # https://lightning.ai/docs/pytorch/stable/common/optimization.html + opt = self.optimizers() + opt.zero_grad() + self.manual_backward(loss) + if self.ppo_cfg["max_grad_norm"] is not None: + self.clip_gradients( + opt, + gradient_clip_val=self.ppo_cfg["max_grad_norm"], + gradient_clip_algorithm="norm", + ) + opt.step() + + out.update( + { + "cost_init": cost_init, + "cost_bsf": td["cost_bsf"], + "loss": loss, + "surrogate_loss": surrogate_loss, + "value_loss": value_loss, + } + ) + metrics = self.log_metrics(out, phase, dataloader_idx=dataloader_idx) + return {"loss": out.get("loss", None), **metrics} diff --git a/rl4co/models/rl/ppo/ppo.py b/rl4co/models/rl/ppo/ppo.py new file mode 100644 index 00000000..7837b1e7 --- /dev/null +++ b/rl4co/models/rl/ppo/ppo.py @@ -0,0 +1,235 @@ +from typing import Any, Union + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from torch.utils.data import DataLoader + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl.common.base import RL4COLitModule +from rl4co.models.rl.common.critic import CriticNetwork, create_critic_from_actor +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class PPO(RL4COLitModule): + """ + An implementation of the Proximal Policy Optimization (PPO) algorithm (https://arxiv.org/abs/1707.06347) + is presented with modifications for autoregressive decoding schemes. + + In contrast to the original PPO algorithm, this implementation does not consider autoregressive decoding steps + as part of the MDP transition. While many Neural Combinatorial Optimization (NCO) studies model decoding steps + as transitions in a solution-construction MDP, we treat autoregressive solution construction as an algorithmic + choice for tractable CO solution generation. This choice aligns with the Attention Model (AM) + (https://openreview.net/forum?id=ByxBFsRqYm), which treats decoding steps as a single-step MDP in Equation 9. + + Modeling autoregressive decoding steps as a single-step MDP introduces significant changes to the PPO implementation, + including: + - Generalized Advantage Estimation (GAE) (https://arxiv.org/abs/1506.02438) is not applicable since we are dealing with a single-step MDP. + - The definition of policy entropy can differ from the commonly implemented manner. + + The commonly implemented definition of policy entropy is the entropy of the policy distribution, given by: + + $$H(\\pi(x_t)) = - \\sum_{a_t \\in A_t} \\pi(a_t|x_t) \\log \\pi(a_t|x_t)$$ + + where $x_t$ represents the given state at step $t$, $A_t$ is the set of all (admisible) actions + at step $t$, and $a_t$ is the action taken at step $t$. + + If we interpret autoregressive decoding steps as transition steps of an MDP, the entropy for the entire decoding + process can be defined as the sum of entropies for each decoding step: + + $$H(\\pi) = \\sum_t H(\\pi(x_t))$$ + + However, if we consider autoregressive decoding steps as an algorithmic choice, the entropy for the entire decoding + process is defined as: + + $$H(\\pi) = - \\sum_{a \\in A} \\pi(a|x) \\log \\pi(a|x)$$ + + where $x$ represents the given CO problem instance, and $A$ is the set of all feasible solutions. + + Due to the intractability of computing the entropy of the policy distribution over all feasible solutions, + we approximate it by computing the entropy over solutions generated by the policy itself. This approximation serves + as a proxy for the second definition of entropy, utilizing Monte Carlo sampling. + + It is worth noting that our modeling of decoding steps and the implementation of the PPO algorithm align with recent + work in the Natural Language Processing (NLP) community, specifically RL with Human Feedback (RLHF) + (e.g., https://github.com/lucidrains/PaLM-rlhf-pytorch). + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: nn.Module, + critic: CriticNetwork = None, + critic_kwargs: dict = {}, + clip_range: float = 0.2, # epsilon of PPO + ppo_epochs: int = 2, # inner epoch, K + mini_batch_size: Union[int, float] = 0.25, # 0.25, + vf_lambda: float = 0.5, # lambda of Value function fitting + entropy_lambda: float = 0.0, # lambda of entropy bonus + normalize_adv: bool = False, # whether to normalize advantage + max_grad_norm: float = 0.5, # max gradient norm + metrics: dict = { + "train": ["reward", "loss", "surrogate_loss", "value_loss", "entropy"], + }, + **kwargs, + ): + super().__init__(env, policy, metrics=metrics, **kwargs) + self.automatic_optimization = False # PPO uses custom optimization routine + + if critic is None: + log.info("Creating critic network for {}".format(env.name)) + critic = create_critic_from_actor(policy, **critic_kwargs) + self.critic = critic + + if isinstance(mini_batch_size, float) and ( + mini_batch_size <= 0 or mini_batch_size > 1 + ): + default_mini_batch_fraction = 0.25 + log.warning( + f"mini_batch_size must be an integer or a float in the range (0, 1], got {mini_batch_size}. Setting mini_batch_size to {default_mini_batch_fraction}." + ) + mini_batch_size = default_mini_batch_fraction + + if isinstance(mini_batch_size, int) and (mini_batch_size <= 0): + default_mini_batch_size = 128 + log.warning( + f"mini_batch_size must be an integer or a float in the range (0, 1], got {mini_batch_size}. Setting mini_batch_size to {default_mini_batch_size}." + ) + mini_batch_size = default_mini_batch_size + + self.ppo_cfg = { + "clip_range": clip_range, + "ppo_epochs": ppo_epochs, + "mini_batch_size": mini_batch_size, + "vf_lambda": vf_lambda, + "entropy_lambda": entropy_lambda, + "normalize_adv": normalize_adv, + "max_grad_norm": max_grad_norm, + } + + def configure_optimizers(self): + parameters = list(self.policy.parameters()) + list(self.critic.parameters()) + return super().configure_optimizers(parameters) + + def on_train_epoch_end(self): + """ + ToDo: Add support for other schedulers. + """ + + sch = self.lr_schedulers() + + # If the selected scheduler is a MultiStepLR scheduler. + if isinstance(sch, torch.optim.lr_scheduler.MultiStepLR): + sch.step() + + def shared_step( + self, batch: Any, batch_idx: int, phase: str, dataloader_idx: int = None + ): + # Evaluate old actions, log probabilities, and rewards + with torch.no_grad(): + td = self.env.reset(batch) # note: clone needed for dataloader + out = self.policy(td.clone(), self.env, phase=phase, return_actions=True) + + if phase == "train": + batch_size = out["actions"].shape[0] + + # infer batch size + if isinstance(self.ppo_cfg["mini_batch_size"], float): + mini_batch_size = int(batch_size * self.ppo_cfg["mini_batch_size"]) + elif isinstance(self.ppo_cfg["mini_batch_size"], int): + mini_batch_size = self.ppo_cfg["mini_batch_size"] + else: + raise ValueError("mini_batch_size must be an integer or a float.") + + if mini_batch_size > batch_size: + mini_batch_size = batch_size + + # Todo: Add support for multi dimensional batches + td.set("logprobs", out["log_likelihood"]) + td.set("reward", out["reward"]) + td.set("action", out["actions"]) + + # Inherit the dataset class from the environment for efficiency + dataset = self.env.dataset_cls(td) + dataloader = DataLoader( + dataset, + batch_size=mini_batch_size, + shuffle=True, + collate_fn=dataset.collate_fn, + ) + + for _ in range(self.ppo_cfg["ppo_epochs"]): # PPO inner epoch, K + for sub_td in dataloader: + sub_td = sub_td.to(td.device) + previous_reward = sub_td["reward"].view(-1, 1) + out = self.policy( # note: remember to clone to avoid in-place replacements! + sub_td.clone(), + actions=sub_td["action"], + env=self.env, + return_entropy=True, + return_sum_log_likelihood=False, + ) + ll, entropy = out["log_likelihood"], out["entropy"] + + # Compute the ratio of probabilities of new and old actions + ratio = torch.exp(ll.sum(dim=-1) - sub_td["logprobs"]).view( + -1, 1 + ) # [batch, 1] + + # Compute the advantage + value_pred = self.critic(sub_td) # [batch, 1] + adv = previous_reward - value_pred.detach() + + # Normalize advantage + if self.ppo_cfg["normalize_adv"]: + adv = (adv - adv.mean()) / (adv.std() + 1e-8) + + # Compute the surrogate loss + surrogate_loss = -torch.min( + ratio * adv, + torch.clamp( + ratio, + 1 - self.ppo_cfg["clip_range"], + 1 + self.ppo_cfg["clip_range"], + ) + * adv, + ).mean() + + # compute value function loss + value_loss = F.huber_loss(value_pred, previous_reward) + + # compute total loss + loss = ( + surrogate_loss + + self.ppo_cfg["vf_lambda"] * value_loss + - self.ppo_cfg["entropy_lambda"] * entropy.mean() + ) + + # perform manual optimization following the Lightning routine + # https://lightning.ai/docs/pytorch/stable/common/optimization.html + + opt = self.optimizers() + opt.zero_grad() + self.manual_backward(loss) + if self.ppo_cfg["max_grad_norm"] is not None: + self.clip_gradients( + opt, + gradient_clip_val=self.ppo_cfg["max_grad_norm"], + gradient_clip_algorithm="norm", + ) + opt.step() + + out.update( + { + "loss": loss, + "surrogate_loss": surrogate_loss, + "value_loss": value_loss, + "entropy": entropy.mean(), + } + ) + + metrics = self.log_metrics(out, phase, dataloader_idx=dataloader_idx) + return {"loss": out.get("loss", None), **metrics} diff --git a/rl4co/models/rl/ppo/stepwise_ppo.py b/rl4co/models/rl/ppo/stepwise_ppo.py new file mode 100644 index 00000000..49d087d0 --- /dev/null +++ b/rl4co/models/rl/ppo/stepwise_ppo.py @@ -0,0 +1,171 @@ +import copy + +from typing import Any, Union + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from torchrl.data.replay_buffers import ( + LazyMemmapStorage, + ListStorage, + SamplerWithoutReplacement, + TensorDictReplayBuffer, +) + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl.common.base import RL4COLitModule +from rl4co.models.rl.common.utils import RewardScaler +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def make_replay_buffer(buffer_size, batch_size, device="cpu"): + if device == "cpu": + storage = LazyMemmapStorage(buffer_size, device="cpu") + prefetch = 3 + else: + storage = ListStorage(buffer_size) + prefetch = None + return TensorDictReplayBuffer( + storage=storage, + batch_size=batch_size, + sampler=SamplerWithoutReplacement(drop_last=True), + pin_memory=False, + prefetch=prefetch, + ) + + +class StepwisePPO(RL4COLitModule): + def __init__( + self, + env: RL4COEnvBase, + policy: nn.Module, + clip_range: float = 0.2, # epsilon of PPO + update_timestep: int = 1, + buffer_size: int = 100_000, + ppo_epochs: int = 2, # inner epoch, K + batch_size: int = 256, + mini_batch_size: int = 256, + vf_lambda: float = 0.5, # lambda of Value function fitting + entropy_lambda: float = 0.01, # lambda of entropy bonus + max_grad_norm: float = 0.5, # max gradient norm + buffer_storage_device: str = "gpu", + metrics: dict = { + "train": ["loss", "surrogate_loss", "value_loss", "entropy"], + }, + reward_scale: Union[str, int] = None, + **kwargs, + ): + super().__init__(env, policy, metrics=metrics, batch_size=batch_size, **kwargs) + + self.policy_old = copy.deepcopy(self.policy) + self.automatic_optimization = False # PPO uses custom optimization routine + self.rb = make_replay_buffer(buffer_size, mini_batch_size, buffer_storage_device) + self.scaler = RewardScaler(reward_scale) + + self.ppo_cfg = { + "clip_range": clip_range, + "ppo_epochs": ppo_epochs, + "update_timestep": update_timestep, + "mini_batch_size": mini_batch_size, + "vf_lambda": vf_lambda, + "entropy_lambda": entropy_lambda, + "max_grad_norm": max_grad_norm, + } + + def update(self, device): + outs = [] + # PPO inner epoch + for _ in range(self.ppo_cfg["ppo_epochs"]): + for sub_td in self.rb: + sub_td = sub_td.to(device) + previous_reward = sub_td["reward"].view(-1, 1) + previous_logp = sub_td["logprobs"] + + logprobs, value_pred, entropy = self.policy.evaluate(sub_td) + + ratios = torch.exp(logprobs - previous_logp) + + advantages = torch.squeeze(previous_reward - value_pred.detach(), 1) + surr1 = ratios * advantages + surr2 = ( + torch.clamp( + ratios, + 1 - self.ppo_cfg["clip_range"], + 1 + self.ppo_cfg["clip_range"], + ) + * advantages + ) + surrogate_loss = -torch.min(surr1, surr2).mean() + + # compute value function loss + value_loss = F.mse_loss(value_pred, previous_reward) + + # compute total loss + loss = ( + surrogate_loss + + self.ppo_cfg["vf_lambda"] * value_loss + - self.ppo_cfg["entropy_lambda"] * entropy.mean() + ) + + # perform manual optimization following the Lightning routine + # https://lightning.ai/docs/pytorch/stable/common/optimization.html + + opt = self.optimizers() + opt.zero_grad() + self.manual_backward(loss) + if self.ppo_cfg["max_grad_norm"] is not None: + self.clip_gradients( + opt, + gradient_clip_val=self.ppo_cfg["max_grad_norm"], + gradient_clip_algorithm="norm", + ) + opt.step() + + out = { + "reward": previous_reward.mean(), + "loss": loss, + "surrogate_loss": surrogate_loss, + "value_loss": value_loss, + "entropy": entropy.mean(), + } + + outs.append(out) + # Copy new weights into old policy: + self.policy_old.load_state_dict(self.policy.state_dict()) + outs = {k: torch.stack([dic[k] for dic in outs], dim=0) for k in outs[0]} + return outs + + def shared_step( + self, batch: Any, batch_idx: int, phase: str, dataloader_idx: int = None + ): + next_td = self.env.reset(batch) + device = next_td.device + if phase == "train": + while not next_td["done"].all(): + with torch.no_grad(): + td = self.policy_old.act(next_td, self.env, phase="train") + # get next state + next_td = self.env.step(td)["next"] + # get reward of action + reward = self.env.get_reward(next_td, None) + reward = self.scaler(reward) + # add reward to prior state + td.set("reward", reward) + # add tensordict with action, logprobs and reward information to buffer + self.rb.extend(td) + + # if iter mod x = 0 then update the policy (x = 1 in paper) + if batch_idx % self.ppo_cfg["update_timestep"] == 0: + out = self.update(device) + self.rb.empty() + + else: + out = self.policy.generate( + next_td, self.env, phase=phase, select_best=phase != "train" + ) + + metrics = self.log_metrics(out, phase, dataloader_idx=dataloader_idx) + return {"loss": out.get("loss", None), **metrics} diff --git a/rl4co/models/rl/reinforce/__init__.py b/rl4co/models/rl/reinforce/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/models/rl/reinforce/baselines.py b/rl4co/models/rl/reinforce/baselines.py new file mode 100644 index 00000000..e59b1969 --- /dev/null +++ b/rl4co/models/rl/reinforce/baselines.py @@ -0,0 +1,311 @@ +import abc +import copy + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from scipy.stats import ttest_rel +from tensordict import TensorDict +from torch.utils.data import DataLoader, Dataset + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl.common.critic import CriticNetwork, create_critic_from_actor +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class REINFORCEBaseline(nn.Module, metaclass=abc.ABCMeta): + """Base class for REINFORCE baselines""" + + def __init__(self, *args, **kw): + super().__init__() + pass + + def wrap_dataset(self, dataset: Dataset, *args, **kw): + """Wrap dataset with baseline-specific functionality""" + return dataset + + @abc.abstractmethod + def eval( + self, td: TensorDict, reward: torch.Tensor, env: RL4COEnvBase = None, **kwargs + ): + """Evaluate baseline""" + raise NotImplementedError + + def epoch_callback(self, *args, **kw): + """Callback at the end of each epoch + For example, update baseline parameters and obtain baseline values + """ + pass + + def setup(self, *args, **kw): + """To be called before training during setup phase + This follow PyTorch Lightning's setup() convention + """ + pass + + +class NoBaseline(REINFORCEBaseline): + """No baseline: return 0 for baseline and neg_los""" + + def eval(self, td, reward, env=None): + return 0, 0 # No baseline, no neg_los + + +class SharedBaseline(REINFORCEBaseline): + """Shared baseline: return mean of reward as baseline""" + + def eval(self, td, reward, env=None, on_dim=1): # e.g. [batch, pomo, ...] + return reward.mean(dim=on_dim, keepdims=True), 0 + + +class ExponentialBaseline(REINFORCEBaseline): + """Exponential baseline: return exponential moving average of reward as baseline + + Args: + beta: Beta value for the exponential moving average + """ + + def __init__(self, beta=0.8, **kw): + super(REINFORCEBaseline, self).__init__() + + self.beta = beta + self.v = None + + def eval(self, td, reward, env=None): + if self.v is None: + v = reward.mean() + else: + v = self.beta * self.v + (1.0 - self.beta) * reward.mean() + self.v = v.detach() # Detach since we never want to backprop + return self.v, 0 # No loss + + +class MeanBaseline(REINFORCEBaseline): + """Mean baseline: return mean of reward as baseline""" + + def __new__(cls, **kw): + return ExponentialBaseline(beta=0.0, **kw) + + +class WarmupBaseline(REINFORCEBaseline): + """Warmup baseline: return convex combination of baseline and exponential baseline + + Args: + baseline: Baseline to use after warmup + n_epochs: Number of epochs to warmup + warmup_exp_beta: Beta value for the exponential baseline during warmup + """ + + def __init__(self, baseline, n_epochs=1, warmup_exp_beta=0.8, **kw): + super(REINFORCEBaseline, self).__init__() + + self.baseline = baseline + assert n_epochs > 0, "n_epochs to warmup must be positive" + self.warmup_baseline = ExponentialBaseline(warmup_exp_beta) + self.alpha = 0 + self.n_epochs = n_epochs + + def wrap_dataset(self, dataset, *args, **kw): + if self.alpha > 0: + return self.baseline.wrap_dataset(dataset, *args, **kw) + return self.warmup_baseline.wrap_dataset(dataset, *args, **kw) + + def setup(self, *args, **kw): + self.baseline.setup(*args, **kw) + + def eval(self, td, reward, env=None): + if self.alpha == 1: + return self.baseline.eval(td, reward, env) + if self.alpha == 0: + return self.warmup_baseline.eval(td, reward, env) + v_b, l_b = self.baseline.eval(td, reward, env) + v_wb, l_wb = self.warmup_baseline.eval(td, reward, env) + # Return convex combination of baseline and of loss + return ( + self.alpha * v_b + (1 - self.alpha) * v_wb, + self.alpha * l_b + (1 - self.alpha) * l_wb, + ) + + def epoch_callback(self, *args, **kw): + # Need to call epoch callback of inner policy (also after first epoch if we have not used it) + self.baseline.epoch_callback(*args, **kw) + if kw["epoch"] < self.n_epochs: + self.alpha = (kw["epoch"] + 1) / float(self.n_epochs) + log.info("Set warmup alpha = {}".format(self.alpha)) + + +class CriticBaseline(REINFORCEBaseline): + """Critic baseline: use critic network as baseline + + Args: + critic: Critic network to use as baseline. If None, create a new critic network based on the environment + """ + + def __init__(self, critic: CriticNetwork = None, **unused_kw): + super(CriticBaseline, self).__init__() + self.critic = critic + + def setup(self, policy, env, **kwargs): + if self.critic is None: + log.info("Critic not found. Creating critic network for {}".format(env.name)) + self.critic = create_critic_from_actor(policy) + + def eval(self, x, c, env=None): + v = self.critic(x).squeeze(-1) + # detach v since actor should not backprop through baseline, only for loss + return v.detach(), F.mse_loss(v, c.detach()) + + +class RolloutBaseline(REINFORCEBaseline): + """Rollout baseline: use greedy rollout as baseline + + Args: + bl_alpha: Alpha value for the baseline T-test + """ + + def __init__(self, bl_alpha=0.05, **kw): + super(RolloutBaseline, self).__init__() + self.bl_alpha = bl_alpha + + def setup(self, *args, **kw): + self._update_policy(*args, **kw) + + def _update_policy( + self, policy, env, batch_size=64, device="cpu", dataset_size=None, dataset=None + ): + """Update policy (=actor) and rollout baseline values""" + self.policy = copy.deepcopy(policy).to(device) + if dataset is None: + log.info("Creating evaluation dataset for rollout baseline") + self.dataset = env.dataset(batch_size=[dataset_size]) + + log.info("Evaluating baseline policy on evaluation dataset") + self.bl_vals = ( + self.rollout(self.policy, env, batch_size, device, self.dataset).cpu().numpy() + ) + self.mean = self.bl_vals.mean() + + def eval(self, td, reward, env): + """Evaluate rollout baseline + + Warning: + This is not differentiable and should only be used for evaluation. + Also, it is recommended to use the `rollout` method directly instead of this method. + """ + with torch.inference_mode(): + reward = self.policy(td, env)["reward"] + return reward, 0 + + def epoch_callback( + self, policy, env, batch_size=64, device="cpu", epoch=None, dataset_size=None + ): + """Challenges the current baseline with the policy and replaces the baseline policy if it is improved""" + log.info("Evaluating candidate policy on evaluation dataset") + candidate_vals = self.rollout(policy, env, batch_size, device).cpu().numpy() + candidate_mean = candidate_vals.mean() + + log.info( + "Candidate mean: {:.3f}, Baseline mean: {:.3f}".format( + candidate_mean, self.mean + ) + ) + if candidate_mean - self.mean > 0: + # Calc p value with inverse logic (costs) + t, p = ttest_rel(-candidate_vals, -self.bl_vals) + + p_val = p / 2 # one-sided + assert t < 0, "T-statistic should be negative" + log.info("p-value: {:.3f}".format(p_val)) + if p_val < self.bl_alpha: + log.info("Updating baseline") + self._update_policy(policy, env, batch_size, device, dataset_size) + + def rollout(self, policy, env, batch_size=64, device="cpu", dataset=None): + """Rollout the policy on the given dataset""" + + # if dataset is None, use the dataset of the baseline + dataset = self.dataset if dataset is None else dataset + + policy.eval() + policy = policy.to(device) + + def eval_policy(batch): + with torch.inference_mode(): + batch = env.reset(batch.to(device)) + return policy(batch, env, decode_type="greedy")["reward"] + + dl = DataLoader(dataset, batch_size=batch_size, collate_fn=dataset.collate_fn) + + rewards = torch.cat([eval_policy(batch) for batch in dl], 0) + return rewards + + def wrap_dataset(self, dataset, env, batch_size=64, device="cpu", **kw): + """Wrap the dataset in a baseline dataset + + Note: + This is an alternative to `eval` that does not require the policy to be passed + at every call but just once. Values are added to the dataset. This also allows for + larger batch sizes since we evauate the policy without gradients. + """ + rewards = ( + self.rollout(self.policy, env, batch_size, device, dataset=dataset) + .detach() + .cpu() + ) + return dataset.add_key("extra", rewards) + + def __getstate__(self): + """Do not include datasets in state to avoid pickling issues""" + state = self.__dict__.copy() + try: + del state["dataset"] + except KeyError: + pass + return state + + def __setstate__(self, state): + """Restore datasets after unpickling. Will be restored in setup""" + self.__dict__.update(state) + self.dataset = None + + +REINFORCE_BASELINES_REGISTRY = { + "no": NoBaseline, + "shared": SharedBaseline, + "exponential": ExponentialBaseline, + "critic": CriticBaseline, + "mean": MeanBaseline, + "rollout_only": RolloutBaseline, + "warmup": WarmupBaseline, +} + + +def get_reinforce_baseline(name, **kw): + """Get a REINFORCE baseline by name + The rollout baseline default to warmup baseline with one epoch of + exponential baseline and the greedy rollout + """ + if name == "warmup": + inner_baseline = kw.get("baseline", "rollout") + if not isinstance(inner_baseline, REINFORCEBaseline): + inner_baseline = get_reinforce_baseline(inner_baseline, **kw) + return WarmupBaseline(inner_baseline, **kw) + elif name == "rollout": + warmup_epochs = kw.get("n_epochs", 1) + warmup_exp_beta = kw.get("exp_beta", 0.8) + bl_alpha = kw.get("bl_alpha", 0.05) + return WarmupBaseline( + RolloutBaseline(bl_alpha=bl_alpha), warmup_epochs, warmup_exp_beta + ) + + if name is None: + name = "no" # default to no baseline + baseline_cls = REINFORCE_BASELINES_REGISTRY.get(name, None) + if baseline_cls is None: + raise ValueError( + f"Unknown baseline {baseline_cls}. Available baselines: {REINFORCE_BASELINES_REGISTRY.keys()}" + ) + return baseline_cls(**kw) diff --git a/rl4co/models/rl/reinforce/reinforce.py b/rl4co/models/rl/reinforce/reinforce.py new file mode 100644 index 00000000..269aaaff --- /dev/null +++ b/rl4co/models/rl/reinforce/reinforce.py @@ -0,0 +1,210 @@ +from typing import IO, Any, Optional, Union, cast + +import torch +import torch.nn as nn + +from lightning.fabric.utilities.types import _MAP_LOCATION_TYPE, _PATH +from lightning.pytorch.core.saving import _load_from_checkpoint +from tensordict import TensorDict +from typing_extensions import Self + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl.common.base import RL4COLitModule +from rl4co.models.rl.common.utils import RewardScaler +from rl4co.models.rl.reinforce.baselines import REINFORCEBaseline, get_reinforce_baseline +from rl4co.utils.lightning import get_lightning_device +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class REINFORCE(RL4COLitModule): + """REINFORCE algorithm, also known as policy gradients. + See superclass `RL4COLitModule` for more details. + + Args: + env: Environment to use for the algorithm + policy: Policy to use for the algorithm + baseline: REINFORCE baseline + baseline_kwargs: Keyword arguments for baseline. Ignored if baseline is not a string + **kwargs: Keyword arguments passed to the superclass + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: nn.Module, + baseline: Union[REINFORCEBaseline, str] = "rollout", + baseline_kwargs: dict = {}, + reward_scale: str = None, + **kwargs, + ): + super().__init__(env, policy, **kwargs) + + self.save_hyperparameters(logger=False) + + if baseline == "critic": + log.warning( + "Using critic as baseline. If you want more granular support, use the A2C module instead." + ) + + if isinstance(baseline, str): + baseline = get_reinforce_baseline(baseline, **baseline_kwargs) + else: + if baseline_kwargs != {}: + log.warning("baseline_kwargs is ignored when baseline is not a string") + self.baseline = baseline + self.advantage_scaler = RewardScaler(reward_scale) + + def shared_step( + self, batch: Any, batch_idx: int, phase: str, dataloader_idx: int = None + ): + td = self.env.reset(batch) + # Perform forward pass (i.e., constructing solution and computing log-likelihoods) + out = self.policy(td, self.env, phase=phase, select_best=phase != "train") + + # Compute loss + if phase == "train": + out = self.calculate_loss(td, batch, out) + + metrics = self.log_metrics(out, phase, dataloader_idx=dataloader_idx) + return {"loss": out.get("loss", None), **metrics} + + def calculate_loss( + self, + td: TensorDict, + batch: TensorDict, + policy_out: dict, + reward: Optional[torch.Tensor] = None, + log_likelihood: Optional[torch.Tensor] = None, + ): + """Calculate loss for REINFORCE algorithm. + + Args: + td: TensorDict containing the current state of the environment + batch: Batch of data. This is used to get the extra loss terms, e.g., REINFORCE baseline + policy_out: Output of the policy network + reward: Reward tensor. If None, it is taken from `policy_out` + log_likelihood: Log-likelihood tensor. If None, it is taken from `policy_out` + """ + # Extra: this is used for additional loss terms, e.g., REINFORCE baseline + extra = batch.get("extra", None) + reward = reward if reward is not None else policy_out["reward"] + log_likelihood = ( + log_likelihood if log_likelihood is not None else policy_out["log_likelihood"] + ) + + # REINFORCE baseline + bl_val, bl_loss = ( + self.baseline.eval(td, reward, self.env) if extra is None else (extra, 0) + ) + + # Main loss function + advantage = reward - bl_val # advantage = reward - baseline + advantage = self.advantage_scaler(advantage) + reinforce_loss = -(advantage * log_likelihood).mean() + loss = reinforce_loss + bl_loss + policy_out.update( + { + "loss": loss, + "reinforce_loss": reinforce_loss, + "bl_loss": bl_loss, + "bl_val": bl_val, + } + ) + return policy_out + + def post_setup_hook(self, stage="fit"): + # Make baseline taking model itself and train_dataloader from model as input + self.baseline.setup( + self.policy, + self.env, + batch_size=self.val_batch_size, + device=get_lightning_device(self), + dataset_size=self.data_cfg["val_data_size"], + ) + + def on_train_epoch_end(self): + """Callback for end of training epoch: we evaluate the baseline""" + self.baseline.epoch_callback( + self.policy, + env=self.env, + batch_size=self.val_batch_size, + device=get_lightning_device(self), + epoch=self.current_epoch, + dataset_size=self.data_cfg["val_data_size"], + ) + # Need to call super() for the dataset to be reset + super().on_train_epoch_end() + + def wrap_dataset(self, dataset): + """Wrap dataset from baseline evaluation. Used in greedy rollout baseline""" + return self.baseline.wrap_dataset( + dataset, + self.env, + batch_size=self.val_batch_size, + device=get_lightning_device(self), + ) + + def set_decode_type_multistart(self, phase: str): + """Set decode type to `multistart` for train, val and test in policy. + For example, if the decode type is `greedy`, it will be set to `multistart_greedy`. + + Args: + phase: Phase to set decode type for. Must be one of `train`, `val` or `test`. + """ + attribute = f"{phase}_decode_type" + attr_get = getattr(self.policy, attribute) + # If does not exist, log error + if attr_get is None: + log.error(f"Decode type for {phase} is None. Cannot prepend `multistart_`.") + return + elif "multistart" in attr_get: + return + else: + setattr(self.policy, attribute, f"multistart_{attr_get}") + + @classmethod + def load_from_checkpoint( + cls, + checkpoint_path: Union[_PATH, IO], + map_location: _MAP_LOCATION_TYPE = None, + hparams_file: Optional[_PATH] = None, + strict: bool = False, + load_baseline: bool = True, + **kwargs: Any, + ) -> Self: + """Load model from checkpoint/ + + Note: + This is a modified version of `load_from_checkpoint` from `pytorch_lightning.core.saving`. + It deals with matching keys for the baseline by first running setup + """ + + if strict: + log.warning("Setting strict=False for loading model from checkpoint.") + strict = False + + # Do not use strict + loaded = _load_from_checkpoint( + cls, + checkpoint_path, + map_location, + hparams_file, + strict, + **kwargs, + ) + + # Load baseline state dict + if load_baseline: + # setup baseline first + loaded.setup() + loaded.post_setup_hook() + # load baseline state dict + state_dict = torch.load(checkpoint_path, map_location=map_location)["state_dict"] + # get only baseline parameters + state_dict = {k: v for k, v in state_dict.items() if "baseline" in k} + state_dict = {k.replace("baseline.", "", 1): v for k, v in state_dict.items()} + loaded.baseline.load_state_dict(state_dict) + + return cast(Self, loaded) diff --git a/rl4co/models/zoo/__init__.py b/rl4co/models/zoo/__init__.py new file mode 100644 index 00000000..7fbb41eb --- /dev/null +++ b/rl4co/models/zoo/__init__.py @@ -0,0 +1,30 @@ +from rl4co.models.common.constructive.autoregressive import AutoregressivePolicy +from rl4co.models.common.constructive.nonautoregressive import NonAutoregressivePolicy +from rl4co.models.common.transductive import TransductiveModel +from rl4co.models.zoo.active_search import ActiveSearch +from rl4co.models.zoo.am import AttentionModel, AttentionModelPolicy +from rl4co.models.zoo.amppo import AMPPO +from rl4co.models.zoo.dact import DACT, DACTPolicy +from rl4co.models.zoo.deepaco import DeepACO, DeepACOPolicy +from rl4co.models.zoo.eas import EAS, EASEmb, EASLay +from rl4co.models.zoo.ham import ( + HeterogeneousAttentionModel, + HeterogeneousAttentionModelPolicy, +) +from rl4co.models.zoo.l2d import ( + L2DAttnPolicy, + L2DModel, + L2DPolicy, + L2DPolicy4PPO, + L2DPPOModel, +) +from rl4co.models.zoo.matnet import MatNet, MatNetPolicy +from rl4co.models.zoo.mdam import MDAM, MDAMPolicy +from rl4co.models.zoo.mvmoe import MVMoE_AM, MVMoE_POMO +from rl4co.models.zoo.n2s import N2S, N2SPolicy +from rl4co.models.zoo.nargnn import NARGNNPolicy +from rl4co.models.zoo.neuopt import NeuOpt, NeuOptPolicy +from rl4co.models.zoo.polynet import PolyNet +from rl4co.models.zoo.pomo import POMO +from rl4co.models.zoo.ptrnet import PointerNetwork, PointerNetworkPolicy +from rl4co.models.zoo.symnco import SymNCO, SymNCOPolicy diff --git a/rl4co/models/zoo/active_search/__init__.py b/rl4co/models/zoo/active_search/__init__.py new file mode 100644 index 00000000..9e25b87d --- /dev/null +++ b/rl4co/models/zoo/active_search/__init__.py @@ -0,0 +1 @@ +from .search import ActiveSearch diff --git a/rl4co/models/zoo/active_search/search.py b/rl4co/models/zoo/active_search/search.py new file mode 100644 index 00000000..5994a4a2 --- /dev/null +++ b/rl4co/models/zoo/active_search/search.py @@ -0,0 +1,203 @@ +import time + +from functools import partial +from typing import Any, Union + +import torch + +from lightning.pytorch.utilities.types import STEP_OUTPUT +from torch.utils.data import Dataset + +from rl4co.data.transforms import StateAugmentation +from rl4co.models.common.transductive import TransductiveModel +from rl4co.utils.ops import batchify, unbatchify +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class ActiveSearch(TransductiveModel): + """Active Search for Neural Combination Optimization from Bello et al. (2016). + Fine-tunes the whole policy network (encoder + decoder) on a batch of instances. + Reference: https://arxiv.org/abs/1611.09940 + + Args: + env: RL4CO environment to be solved + policy: policy network + dataset: dataset to be used for training + batch_size: batch size for training + max_iters: maximum number of iterations + augment_size: number of augmentations per state + augment_dihedral: whether to augment with dihedral rotations + parallel_runs: number of parallel runs + max_runtime: maximum runtime in seconds + save_path: path to save solution checkpoints + optimizer: optimizer to use for training + optimizer_kwargs: keyword arguments for optimizer + **kwargs: additional keyword arguments + """ + + def __init__( + self, + env, + policy, + dataset: Union[Dataset, str], + batch_size: int = 1, + max_iters: int = 200, + augment_size: int = 8, + augment_dihedral: bool = True, + num_parallel_runs: int = 1, + max_runtime: int = 86_400, + save_path: str = None, + optimizer: Union[str, torch.optim.Optimizer, partial] = "Adam", + optimizer_kwargs: dict = {"lr": 2.6e-4, "weight_decay": 1e-6}, + **kwargs, + ): + self.save_hyperparameters(logger=False) + + assert batch_size == 1, "Batch size must be 1 for active search" + + super(ActiveSearch, self).__init__( + env, + policy=policy, + dataset=dataset, + batch_size=batch_size, + max_iters=max_iters, + max_runtime=max_runtime, + save_path=save_path, + optimizer=optimizer, + optimizer_kwargs=optimizer_kwargs, + **kwargs, + ) + + def setup(self, stage="fit"): + """Setup base class and instantiate: + - augmentation + - instance solutions and rewards + - original policy state dict + """ + log.info("Setting up active search...") + super(ActiveSearch, self).setup(stage) + + # Instantiate augmentation + self.augmentation = StateAugmentation( + num_augment=self.hparams.augment_size, + augment_fn="dihedral8" if self.hparams.augment_dihedral else "symmetric", + ) + + # Store original policy state dict + self.original_policy_state = self.policy.state_dict() + + # Get dataset size and problem size + dataset_size = len(self.dataset) + _batch = next(iter(self.train_dataloader())) + self.problem_size = self.env.reset(_batch)["action_mask"].shape[-1] + self.instance_solutions = torch.zeros( + dataset_size, self.problem_size * 2, dtype=int + ) + self.instance_rewards = torch.zeros(dataset_size) + + def on_train_batch_start(self, batch: Any, batch_idx: int): + """Called before training (i.e. search) for a new batch begins. + We re-load the original policy state dict and configure the optimizer. + """ + self.policy.load_state_dict(self.original_policy_state) + self.configure_optimizers(self.policy.parameters()) + + def training_step(self, batch, batch_idx): + """Main search loop. We use the training step to effectively adapt to a `batch` of instances.""" + # Augment state + batch_size = batch.shape[0] + td_init = self.env.reset(batch) + n_aug, n_start, n_runs = ( + self.augmentation.num_augment, + self.env.get_num_starts(td_init), + self.hparams.num_parallel_runs, + ) + td_init = self.augmentation(td_init) + td_init = batchify(td_init, n_runs) + + # Solution and reward buffer + max_reward = torch.full((batch_size,), -float("inf"), device=batch.device) + best_solutions = torch.zeros( + batch_size, self.problem_size * 2, device=batch.device, dtype=int + ) + + # Init search + t_start = time.time() + for i in range(self.hparams.max_iters): + # Evaluate policy with sampling multistarts (as in POMO) + out = self.policy( + td_init.clone(), + env=self.env, + decode_type="multistart_sampling", + num_starts=n_start, + return_actions=True, + ) + + if i == 0: + log.info(f"Initial reward: {out['reward'].max():.2f}") + + # Update best solution and reward found + max_reward_iter = out["reward"].max() + if max_reward_iter > max_reward: + max_reward_idx = out["reward"].argmax() + best_solution_iter = out["actions"][max_reward_idx] + max_reward = max_reward_iter + best_solutions[0, : best_solution_iter.shape[0]] = best_solution_iter + + # Compute REINFORCE loss with shared baseline + reward = unbatchify(out["reward"], (n_runs, n_aug, n_start)) + ll = unbatchify(out["log_likelihood"], (n_runs, n_aug, n_start)) + advantage = reward - reward.mean(dim=-1, keepdim=True) + loss = -(advantage * ll).mean() + + # Backpropagate loss + # perform manual optimization following the Lightning routine + # https://lightning.ai/docs/pytorch/stable/common/optimization.html + opt = self.optimizers() + opt.zero_grad() + self.manual_backward(loss) + + self.log_dict( + { + "loss": loss, + "max_reward": max_reward, + "step": i, + "time": time.time() - t_start, + }, + on_step=self.log_on_step, + ) + + # Stop if max runtime is exceeded + if time.time() - t_start > self.hparams.max_runtime: + break + + return {"max_reward": max_reward, "best_solutions": best_solutions} + + def on_train_batch_end( + self, outputs: STEP_OUTPUT, batch: Any, batch_idx: int + ) -> None: + """We store the best solution and reward found.""" + max_rewards, best_solutions = outputs["max_reward"], outputs["best_solutions"] + self.instance_rewards[batch_idx] = max_rewards + self.instance_solutions[batch_idx, :] = best_solutions.squeeze( + 0 + ) # only one instance + log.info(f"Best reward: {max_rewards.mean():.2f}") + + def on_train_epoch_end(self) -> None: + """Called when the training ends. + If the epoch ends, it means we have finished searching over the + instances, thus the trainer should stop. + """ + save_path = self.hparams.save_path + if save_path is not None: + log.info(f"Saving solutions and rewards to {save_path}...") + torch.save( + {"solutions": self.instance_solutions, "rewards": self.instance_rewards}, + save_path, + ) + + # https://github.com/Lightning-AI/lightning/issues/1406 + self.trainer.should_stop = True diff --git a/rl4co/models/zoo/am/__init__.py b/rl4co/models/zoo/am/__init__.py new file mode 100644 index 00000000..dda6581c --- /dev/null +++ b/rl4co/models/zoo/am/__init__.py @@ -0,0 +1,2 @@ +from .model import AttentionModel +from .policy import AttentionModelPolicy diff --git a/rl4co/models/zoo/am/decoder.py b/rl4co/models/zoo/am/decoder.py new file mode 100644 index 00000000..61600050 --- /dev/null +++ b/rl4co/models/zoo/am/decoder.py @@ -0,0 +1,235 @@ +from dataclasses import dataclass, fields +from typing import Tuple, Union + +import torch +import torch.nn as nn + +from einops import rearrange +from tensordict import TensorDict +from torch import Tensor + +from rl4co.envs import RL4COEnvBase +from rl4co.models.common.constructive.autoregressive.decoder import AutoregressiveDecoder +from rl4co.models.nn.attention import PointerAttention, PointerAttnMoE +from rl4co.models.nn.env_embeddings import env_context_embedding, env_dynamic_embedding +from rl4co.models.nn.env_embeddings.dynamic import StaticEmbedding +from rl4co.utils.ops import batchify, unbatchify +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +@dataclass +class PrecomputedCache: + node_embeddings: Tensor + graph_context: Union[Tensor, float] + glimpse_key: Tensor + glimpse_val: Tensor + logit_key: Tensor + + @property + def fields(self): + return tuple(getattr(self, x.name) for x in fields(self)) + + def batchify(self, num_starts): + new_embs = [] + for emb in self.fields: + if isinstance(emb, Tensor) or isinstance(emb, TensorDict): + new_embs.append(batchify(emb, num_starts)) + else: + new_embs.append(emb) + return PrecomputedCache(*new_embs) + + +class AttentionModelDecoder(AutoregressiveDecoder): + """ + Auto-regressive decoder based on Kool et al. (2019): https://arxiv.org/abs/1803.08475. + Given the environment state and the embeddings, compute the logits and sample actions autoregressively until + all the environments in the batch have reached a terminal state. + In this case we additionally have a `pre_decoder_hook` method that allows to precompute the embeddings before + the decoder is called, which saves a lot of computation. + + + Args: + embed_dim: Embedding dimension + num_heads: Number of attention heads + env_name: Name of the environment used to initialize embeddings + context_embedding: Context embedding module + dynamic_embedding: Dynamic embedding module + mask_inner: Whether to mask the inner loop + out_bias_pointer_attn: Whether to use a bias in the pointer attention + linear_bias: Whether to use a bias in the linear layer + use_graph_context: Whether to use the graph context + check_nan: Whether to check for nan values during decoding + sdpa_fn: scaled_dot_product_attention function + pointer: Module implementing the pointer logic (defaults to PointerAttention) + moe_kwargs: Keyword arguments for MoE + """ + + def __init__( + self, + embed_dim: int = 128, + num_heads: int = 8, + env_name: str = "tsp", + context_embedding: nn.Module = None, + dynamic_embedding: nn.Module = None, + mask_inner: bool = True, + out_bias_pointer_attn: bool = False, + linear_bias: bool = False, + use_graph_context: bool = True, + check_nan: bool = True, + sdpa_fn: callable = None, + pointer: nn.Module = None, + moe_kwargs: dict = None, + ): + super().__init__() + + if isinstance(env_name, RL4COEnvBase): + env_name = env_name.name + self.env_name = env_name + self.embed_dim = embed_dim + self.num_heads = num_heads + + assert embed_dim % num_heads == 0 + + self.context_embedding = ( + env_context_embedding(self.env_name, {"embed_dim": embed_dim}) + if context_embedding is None + else context_embedding + ) + self.dynamic_embedding = ( + env_dynamic_embedding(self.env_name, {"embed_dim": embed_dim}) + if dynamic_embedding is None + else dynamic_embedding + ) + self.is_dynamic_embedding = ( + False if isinstance(self.dynamic_embedding, StaticEmbedding) else True + ) + + if pointer is None: + # MHA with Pointer mechanism (https://arxiv.org/abs/1506.03134) + pointer_attn_class = ( + PointerAttention if moe_kwargs is None else PointerAttnMoE + ) + pointer = pointer_attn_class( + embed_dim, + num_heads, + mask_inner=mask_inner, + out_bias=out_bias_pointer_attn, + check_nan=check_nan, + sdpa_fn=sdpa_fn, + moe_kwargs=moe_kwargs, + ) + + self.pointer = pointer + + # For each node we compute (glimpse key, glimpse value, logit key) so 3 * embed_dim + self.project_node_embeddings = nn.Linear( + embed_dim, 3 * embed_dim, bias=linear_bias + ) + self.project_fixed_context = nn.Linear(embed_dim, embed_dim, bias=linear_bias) + self.use_graph_context = use_graph_context + + def _compute_q(self, cached: PrecomputedCache, td: TensorDict): + node_embeds_cache = cached.node_embeddings + graph_context_cache = cached.graph_context + + if td.dim() == 2 and isinstance(graph_context_cache, Tensor): + graph_context_cache = graph_context_cache.unsqueeze(1) + + step_context = self.context_embedding(node_embeds_cache, td) + glimpse_q = step_context + graph_context_cache + # add seq_len dim if not present + glimpse_q = glimpse_q.unsqueeze(1) if glimpse_q.ndim == 2 else glimpse_q + + return glimpse_q + + def _compute_kvl(self, cached: PrecomputedCache, td: TensorDict): + glimpse_k_stat, glimpse_v_stat, logit_k_stat = ( + cached.glimpse_key, + cached.glimpse_val, + cached.logit_key, + ) + # Compute dynamic embeddings and add to static embeddings + glimpse_k_dyn, glimpse_v_dyn, logit_k_dyn = self.dynamic_embedding(td) + glimpse_k = glimpse_k_stat + glimpse_k_dyn + glimpse_v = glimpse_v_stat + glimpse_v_dyn + logit_k = logit_k_stat + logit_k_dyn + + return glimpse_k, glimpse_v, logit_k + + def forward( + self, + td: TensorDict, + cached: PrecomputedCache, + num_starts: int = 0, + ) -> Tuple[Tensor, Tensor]: + """Compute the logits of the next actions given the current state + + Args: + cache: Precomputed embeddings + td: TensorDict with the current environment state + num_starts: Number of starts for the multi-start decoding + """ + + has_dyn_emb_multi_start = self.is_dynamic_embedding and num_starts > 1 + + # Handle efficient multi-start decoding + if has_dyn_emb_multi_start: + # if num_starts > 0 and we have some dynamic embeddings, we need to reshape them to [B*S, ...] + # since keys and values are not shared across starts (i.e. the episodes modify these embeddings at each step) + cached = cached.batchify(num_starts=num_starts) + + elif num_starts > 1: + td = unbatchify(td, num_starts) + + glimpse_q = self._compute_q(cached, td) + glimpse_k, glimpse_v, logit_k = self._compute_kvl(cached, td) + + # Compute logits + mask = td["action_mask"] + logits = self.pointer(glimpse_q, glimpse_k, glimpse_v, logit_k, mask) + + # Now we need to reshape the logits and mask to [B*S,N,...] is num_starts > 1 without dynamic embeddings + # note that rearranging order is important here + if num_starts > 1 and not has_dyn_emb_multi_start: + logits = rearrange(logits, "b s l -> (s b) l", s=num_starts) + mask = rearrange(mask, "b s l -> (s b) l", s=num_starts) + return logits, mask + + def pre_decoder_hook( + self, td, env, embeddings, num_starts: int = 0 + ) -> Tuple[TensorDict, RL4COEnvBase, PrecomputedCache]: + """Precompute the embeddings cache before the decoder is called""" + return td, env, self._precompute_cache(embeddings, num_starts=num_starts) + + def _precompute_cache( + self, embeddings: torch.Tensor, num_starts: int = 0 + ) -> PrecomputedCache: + """Compute the cached embeddings for the pointer attention. + + Args: + embeddings: Precomputed embeddings for the nodes + num_starts: Number of starts for the multi-start decoding + """ + # The projection of the node embeddings for the attention is calculated once up front + ( + glimpse_key_fixed, + glimpse_val_fixed, + logit_key_fixed, + ) = self.project_node_embeddings(embeddings).chunk(3, dim=-1) + + # Optionally disable the graph context from the initial embedding as done in POMO + if self.use_graph_context: + graph_context = self.project_fixed_context(embeddings.mean(1)) + else: + graph_context = 0 + + # Organize in a dataclass for easy access + return PrecomputedCache( + node_embeddings=embeddings, + graph_context=graph_context, + glimpse_key=glimpse_key_fixed, + glimpse_val=glimpse_val_fixed, + logit_key=logit_key_fixed, + ) diff --git a/rl4co/models/zoo/am/encoder.py b/rl4co/models/zoo/am/encoder.py new file mode 100644 index 00000000..b3a01a2f --- /dev/null +++ b/rl4co/models/zoo/am/encoder.py @@ -0,0 +1,91 @@ +from typing import Tuple, Union + +import torch.nn as nn + +from tensordict import TensorDict +from torch import Tensor + +from rl4co.envs import RL4COEnvBase +from rl4co.models.common.constructive import AutoregressiveEncoder +from rl4co.models.nn.env_embeddings import env_init_embedding +from rl4co.models.nn.graph.attnnet import GraphAttentionNetwork + + +class AttentionModelEncoder(AutoregressiveEncoder): + """Graph Attention Encoder as in Kool et al. (2019). + First embed the input and then process it with a Graph Attention Network. + + Args: + embed_dim: Dimension of the embedding space + init_embedding: Module to use for the initialization of the embeddings + env_name: Name of the environment used to initialize embeddings + num_heads: Number of heads in the attention layers + num_layers: Number of layers in the attention network + normalization: Normalization type in the attention layers + feedforward_hidden: Hidden dimension in the feedforward layers + net: Graph Attention Network to use + sdpa_fn: Function to use for the scaled dot product attention + moe_kwargs: Keyword arguments for MoE + """ + + def __init__( + self, + embed_dim: int = 128, + init_embedding: nn.Module = None, + env_name: str = "tsp", + num_heads: int = 8, + num_layers: int = 3, + normalization: str = "batch", + feedforward_hidden: int = 512, + net: nn.Module = None, + sdpa_fn = None, + moe_kwargs: dict = None, + ): + super(AttentionModelEncoder, self).__init__() + + if isinstance(env_name, RL4COEnvBase): + env_name = env_name.name + self.env_name = env_name + + self.init_embedding = ( + env_init_embedding(self.env_name, {"embed_dim": embed_dim}) + if init_embedding is None + else init_embedding + ) + + self.net = ( + GraphAttentionNetwork( + num_heads, + embed_dim, + num_layers, + normalization, + feedforward_hidden, + sdpa_fn=sdpa_fn, + moe_kwargs=moe_kwargs, + ) + if net is None + else net + ) + + def forward( + self, td: TensorDict, mask: Union[Tensor, None] = None + ) -> Tuple[Tensor, Tensor]: + """Forward pass of the encoder. + Transform the input TensorDict into a latent representation. + + Args: + td: Input TensorDict containing the environment state + mask: Mask to apply to the attention + + Returns: + h: Latent representation of the input + init_h: Initial embedding of the input + """ + # Transfer to embedding space + init_h = self.init_embedding(td) + + # Process embedding + h = self.net(init_h, mask) + + # Return latent representation and initial embedding + return h, init_h diff --git a/rl4co/models/zoo/am/model.py b/rl4co/models/zoo/am/model.py new file mode 100644 index 00000000..bb6b8e41 --- /dev/null +++ b/rl4co/models/zoo/am/model.py @@ -0,0 +1,34 @@ +from typing import Union + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl import REINFORCE +from rl4co.models.rl.reinforce.baselines import REINFORCEBaseline +from rl4co.models.zoo.am.policy import AttentionModelPolicy + + +class AttentionModel(REINFORCE): + """Attention Model based on REINFORCE: https://arxiv.org/abs/1803.08475. + Check :class:`REINFORCE` and :class:`rl4co.models.RL4COLitModule` for more details such as additional parameters including batch size. + + Args: + env: Environment to use for the algorithm + policy: Policy to use for the algorithm + baseline: REINFORCE baseline. Defaults to rollout (1 epoch of exponential, then greedy rollout baseline) + policy_kwargs: Keyword arguments for policy + baseline_kwargs: Keyword arguments for baseline + **kwargs: Keyword arguments passed to the superclass + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: AttentionModelPolicy = None, + baseline: Union[REINFORCEBaseline, str] = "rollout", + policy_kwargs={}, + baseline_kwargs={}, + **kwargs, + ): + if policy is None: + policy = AttentionModelPolicy(env_name=env.name, **policy_kwargs) + + super().__init__(env, policy, baseline, baseline_kwargs, **kwargs) diff --git a/rl4co/models/zoo/am/policy.py b/rl4co/models/zoo/am/policy.py new file mode 100644 index 00000000..d650b72a --- /dev/null +++ b/rl4co/models/zoo/am/policy.py @@ -0,0 +1,122 @@ +from typing import Callable + +import torch.nn as nn + +from rl4co.models.common.constructive.autoregressive.policy import AutoregressivePolicy +from rl4co.models.zoo.am.decoder import AttentionModelDecoder +from rl4co.models.zoo.am.encoder import AttentionModelEncoder + + +class AttentionModelPolicy(AutoregressivePolicy): + """ + Attention Model Policy based on Kool et al. (2019): https://arxiv.org/abs/1803.08475. + This model first encodes the input graph using a Graph Attention Network (GAT) (:class:`AttentionModelEncoder`) + and then decodes the solution using a pointer network (:class:`AttentionModelDecoder`). Cache is used to store the + embeddings of the nodes to be used by the decoder to save computation. + See :class:`rl4co.models.common.constructive.autoregressive.policy.AutoregressivePolicy` for more details on the inference process. + + Args: + encoder: Encoder module, defaults to :class:`AttentionModelEncoder` + decoder: Decoder module, defaults to :class:`AttentionModelDecoder` + embed_dim: Dimension of the node embeddings + num_encoder_layers: Number of layers in the encoder + num_heads: Number of heads in the attention layers + normalization: Normalization type in the attention layers + feedforward_hidden: Dimension of the hidden layer in the feedforward network + env_name: Name of the environment used to initialize embeddings + encoder_network: Network to use for the encoder + init_embedding: Module to use for the initialization of the embeddings + context_embedding: Module to use for the context embedding + dynamic_embedding: Module to use for the dynamic embedding + use_graph_context: Whether to use the graph context + linear_bias_decoder: Whether to use a bias in the linear layer of the decoder + sdpa_fn_encoder: Function to use for the scaled dot product attention in the encoder + sdpa_fn_decoder: Function to use for the scaled dot product attention in the decoder + sdpa_fn: (deprecated) Function to use for the scaled dot product attention + mask_inner: Whether to mask the inner product + out_bias_pointer_attn: Whether to use a bias in the pointer attention + check_nan: Whether to check for nan values during decoding + temperature: Temperature for the softmax + tanh_clipping: Tanh clipping value (see Bello et al., 2016) + mask_logits: Whether to mask the logits during decoding + train_decode_type: Type of decoding to use during training + val_decode_type: Type of decoding to use during validation + test_decode_type: Type of decoding to use during testing + moe_kwargs: Keyword arguments for MoE, + e.g., {"encoder": {"hidden_act": "ReLU", "num_experts": 4, "k": 2, "noisy_gating": True}, + "decoder": {"light_version": True, ...}} + """ + + def __init__( + self, + encoder: nn.Module = None, + decoder: nn.Module = None, + embed_dim: int = 128, + num_encoder_layers: int = 3, + num_heads: int = 8, + normalization: str = "batch", + feedforward_hidden: int = 512, + env_name: str = "tsp", + encoder_network: nn.Module = None, + init_embedding: nn.Module = None, + context_embedding: nn.Module = None, + dynamic_embedding: nn.Module = None, + use_graph_context: bool = True, + linear_bias_decoder: bool = False, + sdpa_fn: Callable = None, + sdpa_fn_encoder: Callable = None, + sdpa_fn_decoder: Callable = None, + mask_inner: bool = True, + out_bias_pointer_attn: bool = False, + check_nan: bool = True, + temperature: float = 1.0, + tanh_clipping: float = 10.0, + mask_logits: bool = True, + train_decode_type: str = "sampling", + val_decode_type: str = "greedy", + test_decode_type: str = "greedy", + moe_kwargs: dict = {"encoder": None, "decoder": None}, + **unused_kwargs, + ): + if encoder is None: + encoder = AttentionModelEncoder( + embed_dim=embed_dim, + num_heads=num_heads, + num_layers=num_encoder_layers, + env_name=env_name, + normalization=normalization, + feedforward_hidden=feedforward_hidden, + net=encoder_network, + init_embedding=init_embedding, + sdpa_fn=sdpa_fn if sdpa_fn_encoder is None else sdpa_fn_encoder, + moe_kwargs=moe_kwargs["encoder"], + ) + + if decoder is None: + decoder = AttentionModelDecoder( + embed_dim=embed_dim, + num_heads=num_heads, + env_name=env_name, + context_embedding=context_embedding, + dynamic_embedding=dynamic_embedding, + sdpa_fn=sdpa_fn if sdpa_fn_decoder is None else sdpa_fn_decoder, + mask_inner=mask_inner, + out_bias_pointer_attn=out_bias_pointer_attn, + linear_bias=linear_bias_decoder, + use_graph_context=use_graph_context, + check_nan=check_nan, + moe_kwargs=moe_kwargs["decoder"], + ) + + super(AttentionModelPolicy, self).__init__( + encoder=encoder, + decoder=decoder, + env_name=env_name, + temperature=temperature, + tanh_clipping=tanh_clipping, + mask_logits=mask_logits, + train_decode_type=train_decode_type, + val_decode_type=val_decode_type, + test_decode_type=test_decode_type, + **unused_kwargs, + ) diff --git a/rl4co/models/zoo/amppo/__init__.py b/rl4co/models/zoo/amppo/__init__.py new file mode 100644 index 00000000..8a94600d --- /dev/null +++ b/rl4co/models/zoo/amppo/__init__.py @@ -0,0 +1 @@ +from .model import AMPPO diff --git a/rl4co/models/zoo/amppo/model.py b/rl4co/models/zoo/amppo/model.py new file mode 100644 index 00000000..17a55257 --- /dev/null +++ b/rl4co/models/zoo/amppo/model.py @@ -0,0 +1,49 @@ +import copy + +import torch.nn as nn + +from rl4co.envs import RL4COEnvBase +from rl4co.models.rl import PPO +from rl4co.models.rl.common.critic import CriticNetwork +from rl4co.models.zoo.am.policy import AttentionModelPolicy +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class AMPPO(PPO): + """PPO Model based on Proximal Policy Optimization (PPO) with an attention model policy. + We default to the attention model policy and the Attention Critic Network. + + Args: + env: Environment to use for the algorithm + policy: Policy to use for the algorithm + critic: Critic to use for the algorithm + policy_kwargs: Keyword arguments for policy + critic_kwargs: Keyword arguments for critic + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: nn.Module = None, + critic: CriticNetwork = None, + policy_kwargs: dict = {}, + critic_kwargs: dict = {}, + **kwargs, + ): + if policy is None: + policy = AttentionModelPolicy(env_name=env.name, **policy_kwargs) + + if critic is None: + log.info("Creating critic network for {}".format(env.name)) + # we reuse the parameters of the model + encoder = getattr(policy, "encoder", None) + if encoder is None: + raise ValueError("Critic network requires an encoder") + critic = CriticNetwork( + copy.deepcopy(encoder).to(next(encoder.parameters()).device), + **critic_kwargs, + ) + + super().__init__(env, policy, critic, **kwargs) diff --git a/rl4co/models/zoo/dact/__init__.py b/rl4co/models/zoo/dact/__init__.py new file mode 100644 index 00000000..c0c9c6a1 --- /dev/null +++ b/rl4co/models/zoo/dact/__init__.py @@ -0,0 +1,2 @@ +from .model import DACT +from .policy import DACTPolicy diff --git a/rl4co/models/zoo/dact/decoder.py b/rl4co/models/zoo/dact/decoder.py new file mode 100644 index 00000000..81a684ad --- /dev/null +++ b/rl4co/models/zoo/dact/decoder.py @@ -0,0 +1,132 @@ +import math + +import torch +import torch.nn as nn + +from tensordict import TensorDict +from torch import Tensor + +from rl4co.models.common.improvement.base import ImprovementDecoder +from rl4co.models.nn.attention import MultiHeadCompat +from rl4co.models.nn.mlp import MLP +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class DACTDecoder(ImprovementDecoder): + """ + DACT decoder based on Ma et al. (2021) + Given the environment state and the dual sets of embeddings (PFE, NFE embeddings), compute the logits for + selecting two nodes for the 2-opt local search from the current solution + + + Args: + embed_dim: Embedding dimension + num_heads: Number of attention heads + """ + + def __init__( + self, + embed_dim: int = 64, + num_heads: int = 4, + ): + super().__init__() + self.embed_dim = embed_dim + self.n_heads = num_heads + self.hidden_dim = embed_dim + + # for MHC sublayer (NFE aspect) + self.compater_node = MultiHeadCompat( + num_heads, embed_dim, embed_dim, embed_dim, embed_dim + ) + + # for MHC sublayer (PFE aspect) + self.compater_pos = MultiHeadCompat( + num_heads, embed_dim, embed_dim, embed_dim, embed_dim + ) + + self.norm_factor = 1 / math.sqrt(1 * self.hidden_dim) + + # for Max-Pooling sublayer + self.project_graph_pos = nn.Linear(self.embed_dim, self.embed_dim, bias=False) + self.project_graph_node = nn.Linear(self.embed_dim, self.embed_dim, bias=False) + self.project_node_pos = nn.Linear(self.embed_dim, self.embed_dim, bias=False) + self.project_node_node = nn.Linear(self.embed_dim, self.embed_dim, bias=False) + + # for feed-forward aggregation (FFA)sublayer + self.value_head = MLP( + input_dim=2 * self.n_heads, + output_dim=1, + num_neurons=[32, 32], + dropout_probs=[0.05, 0.00], + ) + + def forward(self, td: TensorDict, final_h: Tensor, final_p: Tensor) -> Tensor: + """Compute the logits of the removing a node pair from the current solution + + Args: + td: TensorDict with the current environment state + final_h: final NFE embeddings + final_p: final pfe embeddings + """ + + batch_size, graph_size, dim = final_h.size() + + # Max-Pooling sublayer + h_node_refined = self.project_node_node(final_h) + self.project_graph_node( + final_h.max(1)[0] + )[:, None, :].expand(batch_size, graph_size, dim) + h_pos_refined = self.project_node_pos(final_p) + self.project_graph_pos( + final_p.max(1)[0] + )[:, None, :].expand(batch_size, graph_size, dim) + + # MHC sublayer + compatibility = torch.zeros( + (batch_size, graph_size, graph_size, self.n_heads * 2), + device=h_node_refined.device, + ) + compatibility[:, :, :, : self.n_heads] = self.compater_pos(h_pos_refined).permute( + 1, 2, 3, 0 + ) + compatibility[:, :, :, self.n_heads :] = self.compater_node( + h_node_refined + ).permute(1, 2, 3, 0) + + # FFA sublater + return self.value_head(self.norm_factor * compatibility).squeeze(-1) + + +class CriticDecoder(nn.Module): + def __init__(self, input_dim: int) -> None: + super().__init__() + self.input_dim = input_dim + + self.project_graph = nn.Linear(self.input_dim, self.input_dim, bias=False) + self.project_node = nn.Linear(self.input_dim, self.input_dim, bias=False) + + self.MLP = MLP( + input_dim=input_dim, + output_dim=1, + num_neurons=[input_dim, input_dim // 2], + dropout_probs=[0.05, 0.0], + ) + + def forward(self, x: torch.Tensor, hidden=None) -> torch.Tensor: + # h_wave: (batch_size, graph_size+1, input_size) + mean_pooling = x.mean(1) # mean Pooling (batch_size, input_size) + graph_feature: torch.Tensor = self.project_graph(mean_pooling)[ + :, None, : + ] # (batch_size, 1, input_dim/2) + node_feature: torch.Tensor = self.project_node( + x + ) # (batch_size, graph_size+1, input_dim/2) + + # pass through value_head, get estimated value + fusion = node_feature + graph_feature.expand_as( + node_feature + ) # (batch_size, graph_size+1, input_dim/2) + + value = self.MLP(fusion.mean(1)) + + return value diff --git a/rl4co/models/zoo/dact/encoder.py b/rl4co/models/zoo/dact/encoder.py new file mode 100644 index 00000000..0e263de0 --- /dev/null +++ b/rl4co/models/zoo/dact/encoder.py @@ -0,0 +1,274 @@ +import math + +from typing import Tuple + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from torch import Tensor + +from rl4co.models.common import ImprovementEncoder +from rl4co.models.nn.ops import AdaptiveSequential, Normalization +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +# implements the Multi-head DAC-Att module +class DAC_ATT(nn.Module): + def __init__(self, n_heads, input_dim, embed_dim=None, val_dim=None, key_dim=None): + super(DAC_ATT, self).__init__() + + self.n_heads = n_heads + + self.key_dim = self.val_dim = embed_dim // n_heads + self.input_dim = input_dim + self.embed_dim = embed_dim + + self.norm_factor = 1 / math.sqrt(1 * self.key_dim) + + # W_h^Q in the paper + self.W_query_node = nn.Parameter( + torch.Tensor(n_heads, self.input_dim, self.key_dim) + ) + # W_g^Q in the paper + self.W_query_pos = nn.Parameter( + torch.Tensor(n_heads, self.input_dim, self.key_dim) + ) + # W_h^K in the paper + self.W_key_node = nn.Parameter( + torch.Tensor(n_heads, self.input_dim, self.key_dim) + ) + # W_g^K in the paper + self.W_key_pos = nn.Parameter(torch.Tensor(n_heads, self.input_dim, self.key_dim)) + + # W_h^V and W_h^Vref in the paper + self.W_val_node = nn.Parameter( + torch.Tensor(2 * n_heads, self.input_dim, self.val_dim) + ) + # W_g^V and W_g^Vref in the paper + self.W_val_pos = nn.Parameter( + torch.Tensor(2 * n_heads, self.input_dim, self.val_dim) + ) + + # W_h^O and W_g^O in the paper + if embed_dim is not None: + self.W_out_node = nn.Parameter( + torch.Tensor(n_heads, 2 * self.key_dim, embed_dim) + ) + self.W_out_pos = nn.Parameter( + torch.Tensor(n_heads, 2 * self.key_dim, embed_dim) + ) + + self.init_parameters() + + def init_parameters(self): + for param in self.parameters(): + stdv = 1.0 / math.sqrt(param.size(-1)) + param.data.uniform_(-stdv, stdv) + + def forward(self, h_node_in, h_pos_in): # input (NFEs, PFEs) + # h,g should be (batch_size, graph_size, input_dim) + batch_size, graph_size, input_dim = h_node_in.size() + + shp = (self.n_heads, batch_size, graph_size, -1) + shp_v = (2, self.n_heads, batch_size, graph_size, -1) + + h_node = h_node_in.contiguous().view(-1, input_dim) + h_pos = h_pos_in.contiguous().view(-1, input_dim) + + Q_node = torch.matmul(h_node, self.W_query_node).view(shp) + Q_pos = torch.matmul(h_pos, self.W_query_pos).view(shp) + + K_node = torch.matmul(h_node, self.W_key_node).view(shp) + K_pos = torch.matmul(h_pos, self.W_key_pos).view(shp) + + V_node = torch.matmul(h_node, self.W_val_node).view(shp_v) + V_pos = torch.matmul(h_pos, self.W_val_pos).view(shp_v) + + # Get attention correlations and norm by softmax + node_correlations = self.norm_factor * torch.matmul( + Q_node, K_node.transpose(2, 3) + ) + pos_correlations = self.norm_factor * torch.matmul(Q_pos, K_pos.transpose(2, 3)) + attn1 = F.softmax(node_correlations, dim=-1) # head, bs, n, n + attn2 = F.softmax(pos_correlations, dim=-1) # head, bs, n, n + + heads_node_1 = torch.matmul(attn1, V_node[0]) # self-attn + heads_node_2 = torch.matmul(attn2, V_node[1]) # cross-aspect ref attn + + heads_pos_1 = torch.matmul(attn1, V_pos[0]) # cross-aspect ref attn + heads_pos_2 = torch.matmul(attn2, V_pos[1]) # self-attn + + heads_node = torch.cat((heads_node_1, heads_node_2), -1) + heads_pos = torch.cat((heads_pos_1, heads_pos_2), -1) + + # get output + out_node = torch.mm( + heads_node.permute(1, 2, 0, 3) + .contiguous() + .view(-1, self.n_heads * 2 * self.val_dim), + self.W_out_node.view(-1, self.embed_dim), + ).view(batch_size, graph_size, self.embed_dim) + + out_pos = torch.mm( + heads_pos.permute(1, 2, 0, 3) + .contiguous() + .view(-1, self.n_heads * 2 * self.val_dim), + self.W_out_pos.view(-1, self.embed_dim), + ).view(batch_size, graph_size, self.embed_dim) + + return out_node, out_pos # dual-aspect representation (NFEs, PFEs) + + +# implements the DAC encoder +class DACTEncoderLayer(nn.Module): + def __init__( + self, + n_heads, + embed_dim, + feed_forward_hidden, + normalization="layer", + ): + super(DACTEncoderLayer, self).__init__() + + self.MHA_sublayer = DACsubLayer( + n_heads, + embed_dim, + feed_forward_hidden, + normalization=normalization, + ) + + self.FFandNorm_sublayer = FFNsubLayer( + n_heads, + embed_dim, + feed_forward_hidden, + normalization=normalization, + ) + + def forward(self, input1, input2): + out1, out2 = self.MHA_sublayer(input1, input2) + return self.FFandNorm_sublayer(out1, out2) + + +# implements the DAC encoder (DAC-Att sublayer) +class DACsubLayer(nn.Module): + def __init__( + self, + n_heads, + embed_dim, + feed_forward_hidden, + normalization="layer", + ): + super(DACsubLayer, self).__init__() + + self.MHA = DAC_ATT(n_heads, input_dim=embed_dim, embed_dim=embed_dim) + + self.Norm = Normalization(embed_dim, normalization) + + def forward(self, input1, input2): + # Attention and Residual connection + out1, out2 = self.MHA(input1, input2) + + # Normalization + return self.Norm(out1 + input1), self.Norm(out2 + input2) + + +# implements the DAC encoder (FFN sublayer) +class FFNsubLayer(nn.Module): + def __init__( + self, + n_heads, + embed_dim, + feed_forward_hidden, + normalization="layer", + ): + super(FFNsubLayer, self).__init__() + + self.FF1 = ( + nn.Sequential( + nn.Linear(embed_dim, feed_forward_hidden), + nn.ReLU(inplace=True), + nn.Linear(feed_forward_hidden, embed_dim), + ) + if feed_forward_hidden > 0 + else nn.Linear(embed_dim, embed_dim) + ) + + self.FF2 = ( + nn.Sequential( + nn.Linear(embed_dim, feed_forward_hidden), + nn.ReLU(inplace=True), + nn.Linear(feed_forward_hidden, embed_dim), + ) + if feed_forward_hidden > 0 + else nn.Linear(embed_dim, embed_dim) + ) + + self.Norm = Normalization(embed_dim, normalization) + + def forward(self, input1, input2): + # FF and Residual connection + out1 = self.FF1(input1) + out2 = self.FF2(input2) + + # Normalization + return self.Norm(out1 + input1), self.Norm(out2 + input2) + + +class DACTEncoder(ImprovementEncoder): + """Dual-Aspect Collaborative Transformer Encoder as in Ma et al. (2021) + + Args: + embed_dim: Dimension of the embedding space + init_embedding: Module to use for the initialization of the node embeddings + pos_embedding: Module to use for the initialization of the positional embeddings + env_name: Name of the environment used to initialize embeddings + pos_type: Name of the used positional encoding method (CPE or APE) + num_heads: Number of heads in the attention layers + num_layers: Number of layers in the attention network + normalization: Normalization type in the attention layers + feedforward_hidden: Hidden dimension in the feedforward layers + """ + + def __init__( + self, + embed_dim: int = 64, + init_embedding: nn.Module = None, + pos_embedding: nn.Module = None, + env_name: str = "tsp_kopt", + pos_type: str = "CPE", + num_heads: int = 4, + num_layers: int = 3, + normalization: str = "layer", + feedforward_hidden: int = 64, + ): + super(DACTEncoder, self).__init__( + embed_dim=embed_dim, + env_name=env_name, + pos_type=pos_type, + num_heads=num_heads, + num_layers=num_layers, + normalization=normalization, + feedforward_hidden=feedforward_hidden, + ) + + assert self.env_name in ["tsp_kopt"], NotImplementedError() + + self.net = AdaptiveSequential( + *( + DACTEncoderLayer( + num_heads, + embed_dim, + feedforward_hidden, + normalization, + ) + for _ in range(num_layers) + ) + ) + + def _encoder_forward(self, init_h: Tensor, init_p: Tensor) -> Tuple[Tensor, Tensor]: + NFE, PFE = self.net(init_h, init_p) + + return NFE, PFE diff --git a/rl4co/models/zoo/dact/model.py b/rl4co/models/zoo/dact/model.py new file mode 100644 index 00000000..34bf9c5e --- /dev/null +++ b/rl4co/models/zoo/dact/model.py @@ -0,0 +1,62 @@ +import torch.nn as nn + +from rl4co.envs import RL4COEnvBase +from rl4co.models.nn.graph.attnnet import MultiHeadAttentionLayer +from rl4co.models.rl import n_step_PPO +from rl4co.models.rl.common.critic import CriticNetwork +from rl4co.models.zoo.dact.decoder import CriticDecoder +from rl4co.models.zoo.dact.policy import DACTPolicy +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class DACT(n_step_PPO): + """DACT Model based on n_step Proximal Policy Optimization (PPO) with an DACT model policy. + We default to the DACT model policy and the improvement Critic Network. + + Args: + env: Environment to use for the algorithm + policy: Policy to use for the algorithm + critic: Critic to use for the algorithm + policy_kwargs: Keyword arguments for policy + critic_kwargs: Keyword arguments for critic + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: nn.Module = None, + critic: CriticNetwork = None, + policy_kwargs: dict = {}, + critic_kwargs: dict = {}, + **kwargs, + ): + if policy is None: + policy = DACTPolicy(env_name=env.name, **policy_kwargs) + + if critic is None: + embed_dim = ( + policy_kwargs["embed_dim"] * 2 if "embed_dim" in policy_kwargs else 128 + ) # the critic's embed_dim must be as policy's + + encoder = MultiHeadAttentionLayer( + embed_dim, + critic_kwargs["num_heads"] if "num_heads" in critic_kwargs else 4, + critic_kwargs["feedforward_hidden"] * 2 + if "feedforward_hidden" in critic_kwargs + else 128, + critic_kwargs["normalization"] + if "normalization" in critic_kwargs + else "layer", + bias=False, + ) + value_head = CriticDecoder(embed_dim) + + critic = CriticNetwork( + encoder=encoder, + value_head=value_head, + customized=True, + ) + + super().__init__(env, policy, critic, **kwargs) diff --git a/rl4co/models/zoo/dact/policy.py b/rl4co/models/zoo/dact/policy.py new file mode 100644 index 00000000..475ef07d --- /dev/null +++ b/rl4co/models/zoo/dact/policy.py @@ -0,0 +1,186 @@ +from typing import Union + +import torch +import torch.nn as nn + +from tensordict import TensorDict + +from rl4co.envs import RL4COEnvBase, get_env +from rl4co.models.common.improvement.base import ImprovementPolicy +from rl4co.models.zoo.dact.decoder import DACTDecoder +from rl4co.models.zoo.dact.encoder import DACTEncoder +from rl4co.utils.decoding import DecodingStrategy, get_decoding_strategy +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class DACTPolicy(ImprovementPolicy): + """ + DACT Policy based on Ma et al. (2021) + This model first encodes the input graph and current solution using a DACT encoder (:class:`DACTEncoder`) + and then decodes the 2-opt action (:class:`DACTDecoder`) + + Args: + embed_dim: Dimension of the node embeddings + num_encoder_layers: Number of layers in the encoder + num_heads: Number of heads in the attention layers + normalization: Normalization type in the attention layers + feedforward_hidden: Dimension of the hidden layer in the feedforward network + env_name: Name of the environment used to initialize embeddings + pos_type: Name of the used positional encoding method (CPE or APE) + init_embedding: Module to use for the initialization of the embeddings + pos_embedding: Module to use for the initialization of the positional embeddings + temperature: Temperature for the softmax + tanh_clipping: Tanh clipping value (see Bello et al., 2016) + train_decode_type: Type of decoding to use during training + val_decode_type: Type of decoding to use during validation + test_decode_type: Type of decoding to use during testing + """ + + def __init__( + self, + embed_dim: int = 64, + num_encoder_layers: int = 3, + num_heads: int = 4, + normalization: str = "layer", + feedforward_hidden: int = 64, + env_name: str = "tsp_kopt", + pos_type: str = "CPE", + init_embedding: nn.Module = None, + pos_embedding: nn.Module = None, + temperature: float = 1.0, + tanh_clipping: float = 6.0, + train_decode_type: str = "sampling", + val_decode_type: str = "sampling", + test_decode_type: str = "sampling", + ): + super(DACTPolicy, self).__init__() + + self.env_name = env_name + + # Encoder and decoder + self.encoder = DACTEncoder( + embed_dim=embed_dim, + init_embedding=init_embedding, + pos_embedding=pos_embedding, + env_name=env_name, + pos_type=pos_type, + num_heads=num_heads, + num_layers=num_encoder_layers, + normalization=normalization, + feedforward_hidden=feedforward_hidden, + ) + + self.decoder = DACTDecoder(embed_dim=embed_dim, num_heads=num_heads) + + # Decoding strategies + self.temperature = temperature + self.tanh_clipping = tanh_clipping + self.train_decode_type = train_decode_type + self.val_decode_type = val_decode_type + self.test_decode_type = test_decode_type + + def forward( + self, + td: TensorDict, + env: Union[str, RL4COEnvBase] = None, + phase: str = "train", + return_actions: bool = False, + return_embeds: bool = False, + only_return_embed: bool = False, + actions=None, + **decoding_kwargs, + ) -> dict: + """Forward pass of the policy. + + Args: + td: TensorDict containing the environment state + env: Environment to use for decoding. If None, the environment is instantiated from `env_name`. Note that + it is more efficient to pass an already instantiated environment each time for fine-grained control + phase: Phase of the algorithm (train, val, test) + return_actions: Whether to return the actions + actions: Actions to use for evaluating the policy. + If passed, use these actions instead of sampling from the policy to calculate log likelihood + decoding_kwargs: Keyword arguments for the decoding strategy. See :class:`rl4co.utils.decoding.DecodingStrategy` for more information. + + Returns: + out: Dictionary containing the reward, log likelihood, and optionally the actions and entropy + """ + + # Encoder: get encoder output and initial embeddings from initial state + NFE, PFE = self.encoder(td) + h_featrues = torch.cat((NFE, PFE), -1) + + if only_return_embed: + return {"embeds": h_featrues.detach()} + + # Instantiate environment if needed + if isinstance(env, str) or env is None: + env_name = self.env_name if env is None else env + log.info(f"Instantiated environment not provided; instantiating {env_name}") + env = get_env(env_name) + assert env.two_opt_mode, "DACT only support 2-opt" + + # Get decode type depending on phase and whether actions are passed for evaluation + decode_type = decoding_kwargs.pop("decode_type", None) + if actions is not None: + decode_type = "evaluate" + elif decode_type is None: + decode_type = getattr(self, f"{phase}_decode_type") + + # Setup decoding strategy + # we pop arguments that are not part of the decoding strategy + decode_strategy: DecodingStrategy = get_decoding_strategy( + decode_type, + temperature=decoding_kwargs.pop("temperature", self.temperature), + tanh_clipping=decoding_kwargs.pop("tanh_clipping", self.tanh_clipping), + mask_logits=True, + improvement_method_mode=True, + **decoding_kwargs, + ) + + # Perform the decoding + batch_size, seq_length = td["rec_current"].size() + logits = self.decoder(td, NFE, PFE).view(batch_size, -1) + + # Get mask + mask = env.get_mask(td) + if "action" in td.keys(): + mask[torch.arange(batch_size), td["action"][:, 0], td["action"][:, 1]] = False + mask[torch.arange(batch_size), td["action"][:, 1], td["action"][:, 0]] = False + mask = mask.view(batch_size, -1) + + # Get action and log-likelihood + logprob, action_sampled = decode_strategy.step( + logits, + mask, + action=actions[:, 0] * seq_length + actions[:, 1] + if actions is not None + else None, + ) + action_sampled = action_sampled.unsqueeze(-1) + if phase == "train": + log_likelihood = logprob.gather(1, action_sampled) + else: + log_likelihood = torch.zeros(batch_size, device=td.device) + + ## return + DACT_action = torch.cat( + ( + action_sampled // seq_length, + action_sampled % seq_length, + ), + -1, + ) + + outdict = {"log_likelihood": log_likelihood, "cost_bsf": td["cost_bsf"]} + td.set("action", DACT_action) + + if return_embeds: + outdict["embeds"] = h_featrues.detach() + + if return_actions: + outdict["actions"] = DACT_action + + return outdict diff --git a/rl4co/models/zoo/deepaco/__init__.py b/rl4co/models/zoo/deepaco/__init__.py new file mode 100644 index 00000000..adb4d8f5 --- /dev/null +++ b/rl4co/models/zoo/deepaco/__init__.py @@ -0,0 +1,2 @@ +from rl4co.models.zoo.deepaco.model import DeepACO +from rl4co.models.zoo.deepaco.policy import DeepACOPolicy diff --git a/rl4co/models/zoo/deepaco/antsystem.py b/rl4co/models/zoo/deepaco/antsystem.py new file mode 100644 index 00000000..1965cd3d --- /dev/null +++ b/rl4co/models/zoo/deepaco/antsystem.py @@ -0,0 +1,347 @@ +from functools import lru_cache, cached_property, partial +from typing import Optional, Tuple + +import numpy as np +import torch + +from tensordict import TensorDict +from torch import Tensor + +from rl4co.envs import RL4COEnvBase +from rl4co.models.common.constructive.nonautoregressive.decoder import ( + NonAutoregressiveDecoder, +) +from rl4co.utils.decoding import Sampling +from rl4co.utils.ops import get_distance_matrix, unbatchify + + +class AntSystem: + """Implements the Ant System algorithm: https://doi.org/10.1109/3477.484436. + + Args: + log_heuristic: Logarithm of the heuristic matrix. + n_ants: Number of ants to be used in the algorithm. Defaults to 20. + alpha: Importance of pheromone in the decision-making process. Defaults to 1.0. + beta: Importance of heuristic information in the decision-making process. Defaults to 1.0. + decay: Rate at which pheromone evaporates. Should be between 0 and 1. Defaults to 0.95. + Q: Rate at which pheromone deposits. Defaults to `1 / n_ants`. + temperature: Temperature for the softmax during decoding. Defaults to 0.1. + pheromone: Initial pheromone matrix. Defaults to `torch.ones_like(log_heuristic)`. + require_logprobs: Whether to require the log probability of actions. Defaults to False. + use_local_search: Whether to use local_search provided by the env. Default to False. + use_nls: Whether to use neural-guided local search provided by the env. Default to False. + n_perturbations: Number of perturbations to be used for nls. Defaults to 5. + local_search_params: Arguments to be passed to the local_search. + perturbation_params: Arguments to be passed to the perturbation used for nls. + """ + + def __init__( + self, + log_heuristic: Tensor, + n_ants: int = 20, + alpha: float = 1.0, + beta: float = 1.0, + decay: float = 0.95, + Q: Optional[float] = None, + temperature: float = 0.1, + pheromone: Optional[Tensor] = None, + require_logprobs: bool = False, + use_local_search: bool = False, + use_nls: bool = False, + n_perturbations: int = 5, + local_search_params: dict = {}, + perturbation_params: dict = {}, + start_node: Optional[int] = None, + ): + self.batch_size = log_heuristic.shape[0] + self.n_ants = n_ants + self.alpha = alpha + self.beta = beta + self.decay = decay + self.Q = 1 / self.n_ants if Q is None else Q + self.temperature = temperature + + self.log_heuristic = log_heuristic / self.temperature + + if pheromone is None: + self.pheromone = torch.ones_like(log_heuristic) + self.pheromone.fill_(0.0005) + else: + self.pheromone = pheromone + + self.final_actions = self.final_reward = None + self.require_logprobs = require_logprobs + self.all_records = [] + + self.use_local_search = use_local_search + assert not (use_nls and not use_local_search), "use_nls requires use_local_search" + self.use_nls = use_nls + self.n_perturbations = n_perturbations + self.local_search_params = local_search_params + self.perturbation_params = perturbation_params + self.start_node = start_node + + self._batchindex = torch.arange(self.batch_size, device=log_heuristic.device) + + @cached_property + def heuristic_dist(self) -> torch.Tensor: + heuristic = self.log_heuristic.exp().detach().cpu() + 1e-10 + heuristic_dist = 1 / (heuristic / heuristic.max(-1, keepdim=True)[0] + 1e-5) + heuristic_dist[:, torch.arange(heuristic_dist.shape[1]), torch.arange(heuristic_dist.shape[2])] = 0 + return heuristic_dist + + @staticmethod + def select_start_node_fn( + td: TensorDict, env: RL4COEnvBase, num_starts: int, start_node: Optional[int]=None + ): + if env.name == "tsp" and start_node is not None: + # For now, only TSP supports explicitly setting the start node + return start_node * torch.ones( + td.shape[0] * num_starts, dtype=torch.long, device=td.device + ) + + # if start_node is not set, we use random start nodes + return torch.multinomial(td["action_mask"].float(), num_starts, replacement=True).view(-1) + + def run( + self, + td_initial: TensorDict, + env: RL4COEnvBase, + n_iterations: int, + ) -> Tuple[TensorDict, Tensor, Tensor]: + """Run the Ant System algorithm for a specified number of iterations. + + Args: + td_initial: Initial state of the problem. + env: Environment representing the problem. + n_iterations: Number of iterations to run the algorithm. + + Returns: + td: The final state of the problem. + actions: The final actions chosen by the algorithm. + reward: The final reward achieved by the algorithm. + """ + for _ in range(n_iterations): + # reset environment + td = td_initial.clone() + self._one_step(td, env) + + action_matrix = self._convert_final_action_to_matrix() + assert action_matrix is not None and self.final_reward is not None + td, env = self._recreate_final_routes(td_initial, env, action_matrix) + + return td, action_matrix, self.final_reward + + def _one_step(self, td: TensorDict, env: RL4COEnvBase): + """Run one step of the Ant System algorithm. + + Args: + td: Current state of the problem. + env: Environment representing the problem. + + Returns: + actions: The actions chosen by the algorithm. + reward: The reward achieved by the algorithm. + """ + # sampling + td, env, actions, reward = self._sampling(td, env) + # local search, reserved for extensions + if self.use_local_search: + actions, reward = self.local_search(td, env, actions) + + # reshape from (batch_size * n_ants, ...) to (batch_size, n_ants, ...) + reward = unbatchify(reward, self.n_ants) + actions = unbatchify(actions, self.n_ants) + + # update final actions and rewards + self._update_results(actions, reward) + # update pheromone matrix + self._update_pheromone(actions, reward) + + return actions, reward + + def _sampling( + self, + td: TensorDict, + env: RL4COEnvBase, + ): + # Sample from heatmaps + # p = phe**alpha * heu**beta <==> log(p) = alpha*log(phe) + beta*log(heu) + heatmaps_logits = ( + self.alpha * torch.log(self.pheromone) + self.beta * self.log_heuristic + ) + decode_strategy = Sampling( + multistart=True, + num_starts=self.n_ants, + select_start_nodes_fn=partial(self.select_start_node_fn, start_node=self.start_node), + ) + + td, env, num_starts = decode_strategy.pre_decoder_hook(td, env) + while not td["done"].all(): + logits, mask = NonAutoregressiveDecoder.heatmap_to_logits( + td, heatmaps_logits, num_starts + ) + td = decode_strategy.step(logits, mask, td) + td = env.step(td)["next"] + + logprobs, actions, td, env = decode_strategy.post_decoder_hook(td, env) + reward = env.get_reward(td, actions) + + if self.require_logprobs: + self.all_records.append((logprobs, actions, reward, td.get("mask", None))) + + return td, env, actions, reward + + def local_search( + self, td: TensorDict, env: RL4COEnvBase, actions: Tensor + ) -> Tuple[Tensor, Tensor]: + """Perform local search on the actions and reward obtained. + + Args: + td: Current state of the problem. + env: Environment representing the problem. + actions: Actions chosen by the algorithm. + + Returns: + actions: The modified actions + reward: The modified reward + """ + td_cpu = td.detach().cpu() # Convert to CPU in advance to minimize the overhead from device transfer + td_cpu["distances"] = get_distance_matrix(td_cpu["locs"]) + # TODO: avoid or generalize this, e.g., pre-compute for local search in each env + actions = actions.detach().cpu() + best_actions = env.local_search(td=td_cpu, actions=actions, **self.local_search_params) + best_rewards = env.get_reward(td_cpu, best_actions) + + if self.use_nls: + td_cpu_perturb = td_cpu.clone() + td_cpu_perturb["distances"] = torch.tile(self.heuristic_dist, (self.n_ants, 1, 1)) + new_actions = best_actions.clone() + + for _ in range(self.n_perturbations): + perturbed_actions = env.local_search( + td=td_cpu_perturb, actions=new_actions, **self.perturbation_params + ) + new_actions = env.local_search(td=td_cpu, actions=perturbed_actions, **self.local_search_params) + new_rewards = env.get_reward(td_cpu, new_actions) + + improved_indices = new_rewards > best_rewards + best_actions = env.replace_selected_actions(best_actions, new_actions, improved_indices) + best_rewards[improved_indices] = new_rewards[improved_indices] + + best_actions = best_actions.to(td.device) + best_rewards = best_rewards.to(td.device) + + return best_actions, best_rewards + + def _update_results(self, actions, reward): + # update the best-trails recorded in self.final_actions + best_index = reward.argmax(-1) + best_reward = reward[self._batchindex, best_index] + best_actions = actions[self._batchindex, best_index] + + if self.final_actions is None or self.final_reward is None: + self.final_actions = list(iter(best_actions.clone())) + self.final_reward = best_reward.clone() + else: + require_update = self._batchindex[self.final_reward <= best_reward] + for index in require_update: + self.final_actions[index] = best_actions[index] + self.final_reward[require_update] = best_reward[require_update] + + return best_index + + def _update_pheromone(self, actions, reward): + # calculate Δphe + delta_pheromone = torch.zeros_like(self.pheromone) + from_node = actions + to_node = torch.roll(from_node, -1, -1) + mapped_reward = self._reward_map(reward).detach() + batch_action_indices = self._batch_action_indices( + self.batch_size, actions.shape[-1], reward.device + ) + + for ant_index in range(self.n_ants): + delta_pheromone[ + batch_action_indices, + from_node[:, ant_index].flatten(), + to_node[:, ant_index].flatten(), + ] += mapped_reward[batch_action_indices, ant_index] + + # decay & update + self.pheromone *= self.decay + self.pheromone += delta_pheromone + + def _reward_map(self, x: Tensor): + """Map reward $f: \\mathbb{R} \\rightarrow \\mathbb{R}^+$""" + M, _ = x.max(-1, keepdim=True) + m, _ = x.min(-1, keepdim=True) + v = ((x - m) / (M - m)) ** 2 * self.Q + return v + + def _recreate_final_routes(self, td, env, action_matrix): + for action_index in range(action_matrix.shape[-1]): + actions = action_matrix[:, action_index] + td.set("action", actions) + td = env.step(td)["next"] + + assert td["done"].all() + return td, env + + def get_logp(self): + """Get the log probability (logprobs) values recorded during the execution of the algorithm. + + Returns: + results: Tuple containing the log probability values, + actions chosen, rewards obtained, and mask values (if available). + + Raises: + AssertionError: If `require_logp` is not enabled. + """ + + assert ( + self.require_logprobs + ), "Please enable `require_logp` to record logprobs values" + + logprobs_list, actions_list, reward_list, mask_list = [], [], [], [] + + for logprobs, actions, reward, mask in self.all_records: + logprobs_list.append(logprobs) + actions_list.append(actions) + reward_list.append(reward) + mask_list.append(mask) + + if mask_list[0] is None: + mask_list = None + else: + mask_list = torch.stack(mask_list, 0) + + # reset records + self.all_records = [] + + return ( + torch.stack(logprobs_list, 0), + torch.stack(actions_list, 0), + torch.stack(reward_list, 0), + mask_list, + ) + + @staticmethod + @lru_cache(5) + def _batch_action_indices(batch_size: int, n_actions: int, device: torch.device): + batchindex = torch.arange(batch_size, device=device) + return batchindex.unsqueeze(1).repeat(1, n_actions).view(-1) + + def _convert_final_action_to_matrix(self) -> Optional[Tensor]: + if self.final_actions is None: + return None + action_count = max(len(actions) for actions in self.final_actions) + mat_actions = torch.zeros( + (self.batch_size, action_count), + device=self.final_actions[0].device, + dtype=self.final_actions[0].dtype, + ) + for index, action in enumerate(self.final_actions): + mat_actions[index, : len(action)] = action + + return mat_actions diff --git a/rl4co/models/zoo/deepaco/model.py b/rl4co/models/zoo/deepaco/model.py new file mode 100644 index 00000000..3155d20a --- /dev/null +++ b/rl4co/models/zoo/deepaco/model.py @@ -0,0 +1,51 @@ +from typing import Any, Optional, Union + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl import REINFORCE +from rl4co.models.rl.reinforce.baselines import REINFORCEBaseline +from rl4co.models.zoo.deepaco.policy import DeepACOPolicy + + +class DeepACO(REINFORCE): + """Implements DeepACO: https://arxiv.org/abs/2309.14032. + + Args: + env: Environment to use for the algorithm + policy: Policy to use for the algorithm + baseline: REINFORCE baseline. Defaults to exponential + policy_kwargs: Keyword arguments for policy + baseline_kwargs: Keyword arguments for baseline + **kwargs: Keyword arguments passed to the superclass + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: Optional[DeepACOPolicy] = None, + baseline: Union[REINFORCEBaseline, str] = "no", + policy_kwargs: dict = {}, + baseline_kwargs: dict = {}, + **kwargs, + ): + if policy is None: + policy = DeepACOPolicy(env_name=env.name, **policy_kwargs) + + super().__init__(env, policy, baseline, baseline_kwargs, **kwargs) + + def shared_step( + self, + batch: Any, + batch_idx: int, + phase: str, + dataloader_idx: Union[int, None] = None, + ): + td = self.env.reset(batch) + # Perform forward pass (i.e., constructing solution and computing log-likelihoods) + out = self.policy(td, self.env, phase=phase) + + # Compute loss + if phase == "train": + out["loss"] = -(out["advantage"] * out["log_likelihood"]).mean() + + metrics = self.log_metrics(out, phase, dataloader_idx=dataloader_idx) + return {"loss": out.get("loss", None), **metrics} diff --git a/rl4co/models/zoo/deepaco/policy.py b/rl4co/models/zoo/deepaco/policy.py new file mode 100644 index 00000000..4f7d3d72 --- /dev/null +++ b/rl4co/models/zoo/deepaco/policy.py @@ -0,0 +1,147 @@ +from functools import partial +from typing import Optional, Type, Union + +from tensordict import TensorDict + +from rl4co.envs import RL4COEnvBase, get_env +from rl4co.models.common.constructive.nonautoregressive import ( + NonAutoregressiveEncoder, + NonAutoregressivePolicy, +) +from rl4co.models.zoo.deepaco.antsystem import AntSystem +from rl4co.models.zoo.nargnn.encoder import NARGNNEncoder +from rl4co.utils.utils import merge_with_defaults +from rl4co.utils.ops import batchify, unbatchify + + +class DeepACOPolicy(NonAutoregressivePolicy): + """Implememts DeepACO policy based on :class:`NonAutoregressivePolicy`. Introduced by Ye et al. (2023): https://arxiv.org/abs/2309.14032. + This policy uses a Non-Autoregressive Graph Neural Network to generate heatmaps, + which are then used to run Ant Colony Optimization (ACO) to construct solutions. + + Args: + encoder: Encoder module. Can be passed by sub-classes + env_name: Name of the environment used to initialize embeddings + temperature: Temperature for the softmax during decoding. Defaults to 0.1. + aco_class: Class representing the ACO algorithm to be used. Defaults to :class:`AntSystem`. + aco_kwargs: Additional arguments to be passed to the ACO algorithm. + n_ants: Number of ants to be used in the ACO algorithm. Can be an integer or dictionary. Defaults to 20. + n_iterations: Number of iterations to run the ACO algorithm. Can be an integer or dictionary. Defaults to `dict(train=1, val=20, test=100)`. + ls_reward_aug_W: Coefficient to be used for the reward augmentation with the local search. Defaults to 0.95. + encoder_kwargs: Additional arguments to be passed to the encoder. + """ + + def __init__( + self, + encoder: Optional[NonAutoregressiveEncoder] = None, + env_name: str = "tsp", + temperature: float = 1.0, + aco_class: Optional[Type[AntSystem]] = None, + aco_kwargs: dict = {}, + train_with_local_search: bool = True, + n_ants: Optional[Union[int, dict]] = None, + n_iterations: Optional[Union[int, dict]] = None, + ls_reward_aug_W: float = 0.95, + **encoder_kwargs, + ): + if encoder is None: + encoder = NARGNNEncoder(**encoder_kwargs) + + super(DeepACOPolicy, self).__init__( + encoder=encoder, + env_name=env_name, + temperature=temperature, + train_decode_type="multistart_sampling", + val_decode_type="multistart_sampling", + test_decode_type="multistart_sampling", + ) + + self.aco_class = AntSystem if aco_class is None else aco_class + self.aco_kwargs = aco_kwargs + self.train_with_local_search = train_with_local_search + self.n_ants = merge_with_defaults(n_ants, train=30, val=48, test=48) + self.n_iterations = merge_with_defaults(n_iterations, train=1, val=5, test=10) + self.ls_reward_aug_W = ls_reward_aug_W + + def forward( + self, + td_initial: TensorDict, + env: Optional[Union[str, RL4COEnvBase]] = None, + calc_reward: bool = True, + phase: str = "train", + actions=None, + return_actions: bool = True, + return_hidden: bool = True, + **kwargs, + ): + """ + Forward method. During validation and testing, the policy runs the ACO algorithm to construct solutions. + See :class:`NonAutoregressivePolicy` for more details during the training phase. + """ + n_ants = self.n_ants[phase] + # Instantiate environment if needed + if (phase != "train" or self.ls_reward_aug_W > 0) and (env is None or isinstance(env, str)): + env_name = self.env_name if env is None else env + env = get_env(env_name) + + if phase == "train": + select_start_nodes_fn = partial( + self.aco_class.select_start_node_fn, start_node=self.aco_kwargs.get("start_node", None) + ) + kwargs.update({"select_start_nodes_fn": select_start_nodes_fn}) + # we just use the constructive policy + outdict = super().forward( + td_initial, + env, + phase=phase, + decode_type="multistart_sampling", + calc_reward=calc_reward, + num_starts=n_ants, + actions=actions, + return_actions=return_actions, + return_hidden=return_hidden, + **kwargs, + ) + + # manually compute the advantage + reward = unbatchify(outdict["reward"], n_ants) + advantage = reward - reward.mean(dim=1, keepdim=True) + + if self.ls_reward_aug_W > 0 and self.train_with_local_search: + heatmap_logits = outdict["hidden"] + aco = self.aco_class( + heatmap_logits, + n_ants=n_ants, + temperature=self.aco_kwargs.get("temperature", self.temperature), + **self.aco_kwargs, + ) + + actions = outdict["actions"] + _, ls_reward = aco.local_search(batchify(td_initial, n_ants), env, actions) + + ls_reward = unbatchify(ls_reward, n_ants) + ls_advantage = ls_reward - ls_reward.mean(dim=1, keepdim=True) + advantage = advantage * (1 - self.ls_reward_aug_W) + ls_advantage * self.ls_reward_aug_W + + outdict["advantage"] = advantage + outdict["log_likelihood"] = unbatchify(outdict["log_likelihood"], n_ants) + + return outdict + + heatmap_logits, _ = self.encoder(td_initial) + + aco = self.aco_class( + heatmap_logits, + n_ants=self.n_ants[phase], + temperature=self.aco_kwargs.get("temperature", self.temperature), + **self.aco_kwargs, + ) + td, actions, reward = aco.run(td_initial, env, self.n_iterations[phase]) + + out = {} + if calc_reward: + out["reward"] = reward + if return_actions: + out["actions"] = actions + + return out diff --git a/rl4co/models/zoo/eas/__init__.py b/rl4co/models/zoo/eas/__init__.py new file mode 100644 index 00000000..641f2a3b --- /dev/null +++ b/rl4co/models/zoo/eas/__init__.py @@ -0,0 +1 @@ +from .search import EAS, EASEmb, EASLay diff --git a/rl4co/models/zoo/eas/decoder.py b/rl4co/models/zoo/eas/decoder.py new file mode 100644 index 00000000..71d13df8 --- /dev/null +++ b/rl4co/models/zoo/eas/decoder.py @@ -0,0 +1,128 @@ +import math + +from typing import Union + +import torch + +from tensordict import TensorDict + +from rl4co.envs import RL4COEnvBase +from rl4co.utils.decoding import decode_logprobs, process_logits +from rl4co.utils.ops import batchify, unbatchify + + +def forward_pointer_attn_eas_lay(self, query, key, value, logit_key, mask): + """Add layer to the forward pass of logit attention, i.e. + Single-head attention. + """ + # Compute inner multi-head attention with no projections. + heads = self._inner_mha(query, key, value, mask) + + # Add residual for EAS layer if is set + if getattr(self, "eas_layer", None) is not None: + heads = heads + self.eas_layer(heads) + + glimpse = self.project_out(heads) + + # Batch matrix multiplication to compute logits (batch_size, num_steps, graph_size) + # bmm is slightly faster than einsum and matmul + logits = ( + torch.bmm(glimpse, logit_key.squeeze(1).transpose(-2, -1)) + / math.sqrt(glimpse.size(-1)) + ).squeeze(1) + + return logits + + +def forward_eas( + self, + td: TensorDict, + cached_embeds, + best_solutions, + iter_count: int = 0, + env: Union[str, RL4COEnvBase] = None, + decode_type: str = "multistart_sampling", + num_starts: int = None, + mask_logits: bool = True, + temperature: float = 1.0, + tanh_clipping: float = 0, + **decode_kwargs, +): + """Forward pass of the decoder + Given the environment state and the pre-computed embeddings, compute the logits and sample actions + + Args: + td: Input TensorDict containing the environment state + embeddings: Precomputed embeddings for the nodes. Can be already precomputed cached in form of q, k, v and + env: Environment to use for decoding. If None, the environment is instantiated from `env_name`. Note that + it is more efficient to pass an already instantiated environment each time for fine-grained control + decode_type: Type of decoding to use. Can be one of: + - "sampling": sample from the logits + - "greedy": take the argmax of the logits + - "multistart_sampling": sample as sampling, but with multi-start decoding + - "multistart_greedy": sample as greedy, but with multi-start decoding + num_starts: Number of multi-starts to use. If None, will be calculated from the action mask + calc_reward: Whether to calculate the reward for the decoded sequence + """ + # TODO: this could be refactored by decoding strategies + + # Collect logprobs + logprobs = [] + actions = [] + + decode_step = 0 + # Multi-start decoding: first action is chosen by ad-hoc node selection + if num_starts > 1 or "multistart" in decode_type: + action = env.select_start_nodes(td, num_starts + 1) % num_starts + # Append incumbent solutions + if iter_count > 0: + action = unbatchify(action, num_starts + 1) + action[:, -1] = best_solutions[:, decode_step] + action = action.permute(1, 0).reshape(-1) + + # Expand td to batch_size * (num_starts + 1) + td = batchify(td, num_starts + 1) + + td.set("action", action) + td = env.step(td)["next"] + logp = torch.zeros_like( + td["action_mask"], device=td.device + ) # first logprobs is 0, so p = logprobs.exp() = 1 + + logprobs.append(logp) + actions.append(action) + + # Main decoding: loop until all sequences are done + while not td["done"].all(): + decode_step += 1 + logits, mask = self.forward(td, cached_embeds, num_starts + 1) + + logp = process_logits( + logits, + mask, + temperature=self.temperature if self.temperature is not None else temperature, + tanh_clipping=self.tanh_clipping + if self.tanh_clipping is not None + else tanh_clipping, + mask_logits=self.mask_logits if self.mask_logits is not None else mask_logits, + ) + + # Select the indices of the next nodes in the sequences, result (batch_size) long + action = decode_logprobs(logp, mask, decode_type=decode_type) + + if iter_count > 0: # append incumbent solutions + init_shp = action.shape + action = unbatchify(action, num_starts + 1) + action[:, -1] = best_solutions[:, decode_step] + action = action.permute(1, 0).reshape(init_shp) + + td.set("action", action) + td = env.step(td)["next"] + + # Collect output of step + logprobs.append(logp) + actions.append(action) + + logprobs, actions = torch.stack(logprobs, 1), torch.stack(actions, 1) + rewards = env.get_reward(td, actions) + return logprobs, actions, td, rewards diff --git a/rl4co/models/zoo/eas/nn.py b/rl4co/models/zoo/eas/nn.py new file mode 100644 index 00000000..68a23f20 --- /dev/null +++ b/rl4co/models/zoo/eas/nn.py @@ -0,0 +1,30 @@ +import torch +import torch.nn as nn + + +class EASLayerNet(nn.Module): + """Instantiate weights and biases for the added layer. + The layer is defined as: h = relu(emb * W1 + b1); out = h * W2 + b2. + Wrapping in `nn.Parameter` makes the parameters trainable and sets gradient to True. + + Args: + num_instances: Number of instances in the dataset + emb_dim: Dimension of the embedding + """ + + def __init__(self, num_instances: int, emb_dim: int): + super().__init__() + # W2 and b2 are initialized to zero so in the first iteration the layer is identity + self.W1 = nn.Parameter(torch.randn(num_instances, emb_dim, emb_dim)) + self.b1 = nn.Parameter(torch.randn(num_instances, 1, emb_dim)) + self.W2 = nn.Parameter(torch.zeros(num_instances, emb_dim, emb_dim)) + self.b2 = nn.Parameter(torch.zeros(num_instances, 1, emb_dim)) + torch.nn.init.xavier_uniform_(self.W1) + torch.nn.init.xavier_uniform_(self.b1) + + def forward(self, *args): + """emb: [num_instances, group_num, emb_dim]""" + # get tensor arg (from partial instantiation) + emb = [arg for arg in args if isinstance(arg, torch.Tensor)][0] + h = torch.relu(torch.matmul(emb, self.W1) + self.b1.expand_as(emb)) + return torch.matmul(h, self.W2) + self.b2.expand_as(h) diff --git a/rl4co/models/zoo/eas/search.py b/rl4co/models/zoo/eas/search.py new file mode 100644 index 00000000..ef352d93 --- /dev/null +++ b/rl4co/models/zoo/eas/search.py @@ -0,0 +1,346 @@ +import time + +from functools import partial +from typing import Any, List, Union + +import torch + +from lightning.pytorch.utilities.types import STEP_OUTPUT +from torch.nn.utils.rnn import pad_sequence +from torch.utils.data import Dataset + +from rl4co.data.transforms import StateAugmentation +from rl4co.models.common.transductive import TransductiveModel +from rl4co.models.zoo.eas.decoder import forward_eas, forward_pointer_attn_eas_lay +from rl4co.models.zoo.eas.nn import EASLayerNet +from rl4co.utils.decoding import get_log_likelihood +from rl4co.utils.ops import batchify, gather_by_index, unbatchify +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class EAS(TransductiveModel): + """Efficient Active Search for Neural Combination Optimization from Hottung et al. (2022). + Fine-tunes a subset of parameters (such as node embeddings or newly added layers) thus avoiding + expensive re-encoding of the problem. + Reference: https://openreview.net/pdf?id=nO5caZwFwYu + + Args: + env: RL4CO environment to be solved + policy: policy network + dataset: dataset to be used for training + use_eas_embedding: whether to use EAS embedding (EASEmb) + use_eas_layer: whether to use EAS layer (EASLay) + eas_emb_cache_keys: keys to cache in the embedding + eas_lambda: lambda parameter for IL loss + batch_size: batch size for training + max_iters: maximum number of iterations + augment_size: number of augmentations per state + augment_dihedral: whether to augment with dihedral rotations + parallel_runs: number of parallel runs + baseline: REINFORCE baseline type (multistart, symmetric, full) + max_runtime: maximum runtime in seconds + save_path: path to save solution checkpoints + optimizer: optimizer to use for training + optimizer_kwargs: keyword arguments for optimizer + verbose: whether to print progress for each iteration + """ + + def __init__( + self, + env, + policy, + dataset: Union[Dataset, str], + use_eas_embedding: bool = True, + use_eas_layer: bool = False, + eas_emb_cache_keys: List[str] = ["logit_key"], + eas_lambda: float = 0.013, + batch_size: int = 2, + max_iters: int = 200, + augment_size: int = 8, + augment_dihedral: bool = True, + num_parallel_runs: int = 1, + baseline: str = "multistart", + max_runtime: int = 86_400, + save_path: str = None, + optimizer: Union[str, torch.optim.Optimizer, partial] = "Adam", + optimizer_kwargs: dict = {"lr": 0.0041, "weight_decay": 1e-6}, + verbose: bool = True, + **kwargs, + ): + self.save_hyperparameters(logger=False) + + assert ( + self.hparams.use_eas_embedding or self.hparams.use_eas_layer + ), "At least one of `use_eas_embedding` or `use_eas_layer` must be True." + + super(EAS, self).__init__( + env, + policy=policy, + dataset=dataset, + batch_size=batch_size, + max_iters=max_iters, + max_runtime=max_runtime, + save_path=save_path, + optimizer=optimizer, + optimizer_kwargs=optimizer_kwargs, + **kwargs, + ) + + assert self.hparams.baseline in [ + "multistart", + "symmetric", + "full", + ], f"Baseline {self.hparams.baseline} not supported." + + def setup(self, stage="fit"): + """Setup base class and instantiate: + - augmentation + - instance solutions and rewards + - original policy state dict + """ + log.info( + f"Setting up Efficient Active Search (EAS) with: \n" + f"- EAS Embedding: {self.hparams.use_eas_embedding} \n" + f"- EAS Layer: {self.hparams.use_eas_layer} \n" + ) + super(EAS, self).setup(stage) + + # Instantiate augmentation + self.augmentation = StateAugmentation( + num_augment=self.hparams.augment_size, + augment_fn="dihedral8" if self.hparams.augment_dihedral else "symmetric", + ) + + # Store original policy state dict + self.original_policy_state = self.policy.state_dict() + + # Get dataset size and problem size + len(self.dataset) + _batch = next(iter(self.train_dataloader())) + self.problem_size = self.env.reset(_batch)["action_mask"].shape[-1] + self.instance_solutions = [] + self.instance_rewards = [] + + def on_train_batch_start(self, batch: Any, batch_idx: int): + """Called before training (i.e. search) for a new batch begins. + We re-load the original policy state dict and configure all parameters not to require gradients. + We do the rest in the training step. + """ + self.policy.load_state_dict(self.original_policy_state) + + # Set all policy parameters to not require gradients + for param in self.policy.parameters(): + param.requires_grad = False + + def training_step(self, batch, batch_idx): + """Main search loop. We use the training step to effectively adapt to a `batch` of instances.""" + # Augment state + batch_size = batch.shape[0] + td_init = self.env.reset(batch) + n_aug, n_start, n_runs = ( + self.augmentation.num_augment, + self.env.get_num_starts(td_init), + self.hparams.num_parallel_runs, + ) + td_init = self.augmentation(td_init) + td_init = batchify(td_init, n_runs) + num_instances = batch_size * n_aug * n_runs # NOTE: no num_starts! + # batch_r = n_runs * batch_size # effective batch size + group_s = ( + n_start + 1 + ) # number of different rollouts per instance (+1 for incumbent solution construction) + + # Get encoder and decoder for simplicity + encoder = self.policy.encoder + decoder = self.policy.decoder + + # Precompute the cache of the embeddings (i.e. q,k,v and logit_key) + embeddings, _ = encoder(td_init) + cached_embeds = decoder._precompute_cache(embeddings) + + # Collect optimizer parameters + opt_params = [] + if self.hparams.use_eas_layer: + # EASLay: replace forward of logit attention computation. EASLayer + eas_layer = EASLayerNet(num_instances, decoder.embed_dim).to(batch.device) + decoder.pointer.eas_layer = partial(eas_layer, decoder.pointer) + decoder.pointer.forward = partial( + forward_pointer_attn_eas_lay, decoder.pointer + ) + for param in eas_layer.parameters(): + opt_params.append(param) + if self.hparams.use_eas_embedding: + # EASEmb: set gradient of emb_key to True + # for all the keys, wrap the embedding in a nn.Parameter + for key in self.hparams.eas_emb_cache_keys: + setattr( + cached_embeds, key, torch.nn.Parameter(getattr(cached_embeds, key)) + ) + opt_params.append(getattr(cached_embeds, key)) + decoder.forward_eas = partial(forward_eas, decoder) + + # We pass attributes saved in policy too + def set_attr_if_exists(attr): + if hasattr(self.policy, attr): + setattr(decoder, attr, getattr(self.policy, attr)) + + for attr in ["temperature", "tanh_clipping", "mask_logits"]: + set_attr_if_exists(attr) + + self.configure_optimizers(opt_params) + + # Solution and reward buffer + max_reward = torch.full((batch_size,), -float("inf"), device=batch.device) + best_solutions = torch.zeros( + batch_size, self.problem_size * 2, device=batch.device, dtype=int + ) # i.e. incumbent solutions + + # Init search + t_start = time.time() + for iter_count in range(self.hparams.max_iters): + # Evaluate policy with sampling multistarts passing the cached embeddings + best_solutions_expanded = best_solutions.repeat(n_aug, 1).repeat(n_runs, 1) + logprobs, actions, td_out, reward = decoder.forward_eas( + td_init.clone(), + cached_embeds=cached_embeds, + best_solutions=best_solutions_expanded, + iter_count=iter_count, + env=self.env, + decode_type="multistart_sampling", + num_starts=n_start, + ) + + # Unbatchify to get correct dimensions + ll = get_log_likelihood(logprobs, actions, td_out.get("mask", None)) + ll = unbatchify(ll, (n_runs * batch_size, n_aug, group_s)).squeeze() + reward = unbatchify(reward, (n_runs * batch_size, n_aug, group_s)).squeeze() + actions = unbatchify(actions, (n_runs * batch_size, n_aug, group_s)).squeeze() + + # Compute REINFORCE loss with shared baselines + # compared to original EAS, we also support symmetric and full baselines + group_reward = reward[..., :-1] # exclude incumbent solution + if self.hparams.baseline == "multistart": + bl_val = group_reward.mean(dim=-1, keepdim=True) + elif self.hparams.baseline == "symmetric": + bl_val = group_reward.mean(dim=-2, keepdim=True) + elif self.hparams.baseline == "full": + bl_val = group_reward.mean(dim=-1, keepdim=True).mean( + dim=-2, keepdim=True + ) + else: + raise ValueError(f"Baseline {self.hparams.baseline} not supported.") + + # REINFORCE loss + advantage = group_reward - bl_val + loss_rl = -(advantage * ll[..., :-1]).mean() + # IL loss + loss_il = -ll[..., -1].mean() + # Total loss + loss = loss_rl + self.hparams.eas_lambda * loss_il + + # Manual backpropagation + opt = self.optimizers() + opt.zero_grad() + self.manual_backward(loss) + + # Save best solutions and rewards + # Get max reward for each group and instance + max_reward = reward.max(dim=2)[0].max(dim=1)[0] + + # Reshape and rank rewards + reward_group = reward.reshape(n_runs * batch_size, -1) + _, top_indices = torch.topk(reward_group, k=1, dim=1) + + # Obtain best solutions found so far + solutions = actions.reshape(n_runs * batch_size, n_aug * group_s, -1) + best_solutions_iter = gather_by_index(solutions, top_indices, dim=1) + best_solutions[:, : best_solutions_iter.shape[1]] = best_solutions_iter + + self.log_dict( + { + "loss": loss, + "max_reward": max_reward.mean(), + "step": iter_count, + "time": time.time() - t_start, + }, + on_step=self.log_on_step, + ) + + log.info( + f"{iter_count}/{self.hparams.max_iters} | " + f" Reward: {max_reward.mean().item():.2f} " + ) + + # Stop if max runtime is exceeded + if time.time() - t_start > self.hparams.max_runtime: + log.info(f"Max runtime of {self.hparams.max_runtime} seconds exceeded.") + break + + return {"max_reward": max_reward, "best_solutions": best_solutions} + + def on_train_batch_end( + self, outputs: STEP_OUTPUT, batch: Any, batch_idx: int + ) -> None: + """We store the best solution and reward found.""" + max_rewards, best_solutions = outputs["max_reward"], outputs["best_solutions"] + self.instance_solutions.append(best_solutions) + self.instance_rewards.append(max_rewards) + log.info(f"Best reward: {max_rewards.mean():.2f}") + + def on_train_epoch_end(self) -> None: + """Called when the train ends.""" + save_path = self.hparams.save_path + # concatenate solutions and rewards + self.instance_solutions = pad_sequence( + self.instance_solutions, batch_first=True, padding_value=0 + ).squeeze() + self.instance_rewards = torch.cat(self.instance_rewards, dim=0).squeeze() + if save_path is not None: + log.info(f"Saving solutions and rewards to {save_path}...") + torch.save( + {"solutions": self.instance_solutions, "rewards": self.instance_rewards}, + save_path, + ) + + # https://github.com/Lightning-AI/lightning/issues/1406 + self.trainer.should_stop = True + + +class EASEmb(EAS): + """EAS with embedding adaptation""" + + def __init__( + self, + *args, + **kwargs, + ): + if not kwargs.get("use_eas_embedding", False) or kwargs.get( + "use_eas_layer", True + ): + log.warning( + "Setting `use_eas_embedding` to True and `use_eas_layer` to False. Use EAS base class to override." + ) + kwargs["use_eas_embedding"] = True + kwargs["use_eas_layer"] = False + super(EASEmb, self).__init__(*args, **kwargs) + + +class EASLay(EAS): + """EAS with layer adaptation""" + + def __init__( + self, + *args, + **kwargs, + ): + if kwargs.get("use_eas_embedding", False) or not kwargs.get( + "use_eas_layer", True + ): + log.warning( + "Setting `use_eas_embedding` to True and `use_eas_layer` to False. Use EAS base class to override." + ) + kwargs["use_eas_embedding"] = False + kwargs["use_eas_layer"] = True + super(EASLay, self).__init__(*args, **kwargs) diff --git a/rl4co/models/zoo/ham/__init__.py b/rl4co/models/zoo/ham/__init__.py new file mode 100644 index 00000000..1e283fc4 --- /dev/null +++ b/rl4co/models/zoo/ham/__init__.py @@ -0,0 +1,2 @@ +from .model import HeterogeneousAttentionModel +from .policy import HeterogeneousAttentionModelPolicy diff --git a/rl4co/models/zoo/ham/attention.py b/rl4co/models/zoo/ham/attention.py new file mode 100644 index 00000000..0c4d593e --- /dev/null +++ b/rl4co/models/zoo/ham/attention.py @@ -0,0 +1,488 @@ +import math + +import torch +import torch.nn as nn + + +class HeterogenousMHA(nn.Module): + def __init__(self, num_heads, input_dim, embed_dim=None, val_dim=None, key_dim=None): + """ + Heterogenous Multi-Head Attention for Pickup and Delivery problems + https://arxiv.org/abs/2110.02634 + """ + super(HeterogenousMHA, self).__init__() + + if val_dim is None: + assert embed_dim is not None, "Provide either embed_dim or val_dim" + val_dim = embed_dim // num_heads + if key_dim is None: + key_dim = val_dim + + self.num_heads = num_heads + self.input_dim = input_dim + self.embed_dim = embed_dim + self.val_dim = val_dim + self.key_dim = key_dim + + self.norm_factor = 1 / math.sqrt(key_dim) # See Attention is all you need + + self.W_query = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim)) + self.W_key = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim)) + self.W_val = nn.Parameter(torch.Tensor(num_heads, input_dim, val_dim)) + + # Pickup weights + self.W1_query = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim)) + self.W2_query = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim)) + self.W3_query = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim)) + + # Delivery weights + self.W4_query = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim)) + self.W5_query = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim)) + self.W6_query = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim)) + + if embed_dim is not None: + self.W_out = nn.Parameter(torch.Tensor(num_heads, key_dim, embed_dim)) + + self.init_parameters() + + def init_parameters(self): + for param in self.parameters(): + stdv = 1.0 / math.sqrt(param.size(-1)) + param.data.uniform_(-stdv, stdv) + + def forward(self, q, h=None, mask=None): + """ + Args: + q: queries (batch_size, n_query, input_dim) + h: data (batch_size, graph_size, input_dim) + mask: mask (batch_size, n_query, graph_size) or viewable as that (i.e. can be 2 dim if n_query == 1) + + Mask should contain 1 if attention is not possible (i.e. mask is negative adjacency) + """ + if h is None: + h = q # compute self-attention + + # h should be (batch_size, graph_size, input_dim) + batch_size, graph_size, input_dim = h.size() + + # Check if graph size is odd number + assert ( + graph_size % 2 == 1 + ), "Graph size should have odd number of nodes due to pickup-delivery problem \ + (n/2 pickup, n/2 delivery, 1 depot)" + + n_query = q.size(1) + assert q.size(0) == batch_size + assert q.size(2) == input_dim + assert input_dim == self.input_dim, "Wrong embedding dimension of input" + + hflat = h.contiguous().view(-1, input_dim) # [batch_size * graph_size, embed_dim] + qflat = q.contiguous().view(-1, input_dim) # [batch_size * n_query, embed_dim] + + # last dimension can be different for keys and values + shp = (self.num_heads, batch_size, graph_size, -1) + shp_q = (self.num_heads, batch_size, n_query, -1) + + # pickup -> its delivery attention + n_pick = (graph_size - 1) // 2 + shp_delivery = (self.num_heads, batch_size, n_pick, -1) + shp_q_pick = (self.num_heads, batch_size, n_pick, -1) + + # pickup -> all pickups attention + shp_allpick = (self.num_heads, batch_size, n_pick, -1) + shp_q_allpick = (self.num_heads, batch_size, n_pick, -1) + + # pickup -> all pickups attention + shp_alldelivery = (self.num_heads, batch_size, n_pick, -1) + shp_q_alldelivery = (self.num_heads, batch_size, n_pick, -1) + + # Calculate queries, (num_heads, n_query, graph_size, key/val_size) + Q = torch.matmul(qflat, self.W_query).view(shp_q) + # Calculate keys and values (num_heads, batch_size, graph_size, key/val_size) + K = torch.matmul(hflat, self.W_key).view(shp) + V = torch.matmul(hflat, self.W_val).view(shp) + + # pickup -> its delivery + pick_flat = ( + h[:, 1 : n_pick + 1, :].contiguous().view(-1, input_dim) + ) # [batch_size * n_pick, embed_dim] + delivery_flat = ( + h[:, n_pick + 1 :, :].contiguous().view(-1, input_dim) + ) # [batch_size * n_pick, embed_dim] + + # pickup -> its delivery attention + Q_pick = torch.matmul(pick_flat, self.W1_query).view( + shp_q_pick + ) # (self.num_heads, batch_size, n_pick, key_size) + K_delivery = torch.matmul(delivery_flat, self.W_key).view( + shp_delivery + ) # (self.num_heads, batch_size, n_pick, -1) + V_delivery = torch.matmul(delivery_flat, self.W_val).view( + shp_delivery + ) # (num_heads, batch_size, n_pick, key/val_size) + + # pickup -> all pickups attention + Q_pick_allpick = torch.matmul(pick_flat, self.W2_query).view( + shp_q_allpick + ) # (self.num_heads, batch_size, n_pick, -1) + K_allpick = torch.matmul(pick_flat, self.W_key).view( + shp_allpick + ) # [self.num_heads, batch_size, n_pick, key_size] + V_allpick = torch.matmul(pick_flat, self.W_val).view( + shp_allpick + ) # [self.num_heads, batch_size, n_pick, key_size] + + # pickup -> all delivery + Q_pick_alldelivery = torch.matmul(pick_flat, self.W3_query).view( + shp_q_alldelivery + ) # (self.num_heads, batch_size, n_pick, key_size) + K_alldelivery = torch.matmul(delivery_flat, self.W_key).view( + shp_alldelivery + ) # (self.num_heads, batch_size, n_pick, -1) + V_alldelivery = torch.matmul(delivery_flat, self.W_val).view( + shp_alldelivery + ) # (num_heads, batch_size, n_pick, key/val_size) + + # pickup -> its delivery + V_additional_delivery = torch.cat( + [ # [num_heads, batch_size, graph_size, key_size] + torch.zeros( + self.num_heads, + batch_size, + 1, + self.input_dim // self.num_heads, + dtype=V.dtype, + device=V.device, + ), + V_delivery, # [num_heads, batch_size, n_pick, key/val_size] + torch.zeros( + self.num_heads, + batch_size, + n_pick, + self.input_dim // self.num_heads, + dtype=V.dtype, + device=V.device, + ), + ], + 2, + ) + + # delivery -> its pickup attention + Q_delivery = torch.matmul(delivery_flat, self.W4_query).view( + shp_delivery + ) # (self.num_heads, batch_size, n_pick, key_size) + K_pick = torch.matmul(pick_flat, self.W_key).view( + shp_q_pick + ) # (self.num_heads, batch_size, n_pick, -1) + V_pick = torch.matmul(pick_flat, self.W_val).view( + shp_q_pick + ) # (num_heads, batch_size, n_pick, key/val_size) + + # delivery -> all delivery attention + Q_delivery_alldelivery = torch.matmul(delivery_flat, self.W5_query).view( + shp_alldelivery + ) # (self.num_heads, batch_size, n_pick, -1) + K_alldelivery2 = torch.matmul(delivery_flat, self.W_key).view( + shp_alldelivery + ) # [self.num_heads, batch_size, n_pick, key_size] + V_alldelivery2 = torch.matmul(delivery_flat, self.W_val).view( + shp_alldelivery + ) # [self.num_heads, batch_size, n_pick, key_size] + + # delivery -> all pickup + Q_delivery_allpickup = torch.matmul(delivery_flat, self.W6_query).view( + shp_alldelivery + ) # (self.num_heads, batch_size, n_pick, key_size) + K_allpickup2 = torch.matmul(pick_flat, self.W_key).view( + shp_q_alldelivery + ) # (self.num_heads, batch_size, n_pick, -1) + V_allpickup2 = torch.matmul(pick_flat, self.W_val).view( + shp_q_alldelivery + ) # (num_heads, batch_size, n_pick, key/val_size) + + # delivery -> its pick up + V_additional_pick = torch.cat( + [ # [num_heads, batch_size, graph_size, key_size] + torch.zeros( + self.num_heads, + batch_size, + 1, + self.input_dim // self.num_heads, + dtype=V.dtype, + device=V.device, + ), + torch.zeros( + self.num_heads, + batch_size, + n_pick, + self.input_dim // self.num_heads, + dtype=V.dtype, + device=V.device, + ), + V_pick, # [num_heads, batch_size, n_pick, key/val_size] + ], + 2, + ) + + # Calculate compatibility (num_heads, batch_size, n_query, graph_size) + compatibility = self.norm_factor * torch.matmul(Q, K.transpose(2, 3)) + + ##Pick up pair attention + compatibility_pick_delivery = self.norm_factor * torch.sum( + Q_pick * K_delivery, -1 + ) # element_wise, [num_heads, batch_size, n_pick] + # [num_heads, batch_size, n_pick, n_pick] + compatibility_pick_allpick = self.norm_factor * torch.matmul( + Q_pick_allpick, K_allpick.transpose(2, 3) + ) # [num_heads, batch_size, n_pick, n_pick] + compatibility_pick_alldelivery = self.norm_factor * torch.matmul( + Q_pick_alldelivery, K_alldelivery.transpose(2, 3) + ) # [num_heads, batch_size, n_pick, n_pick] + + ##Delivery + compatibility_delivery_pick = self.norm_factor * torch.sum( + Q_delivery * K_pick, -1 + ) # element_wise, [num_heads, batch_size, n_pick] + compatibility_delivery_alldelivery = self.norm_factor * torch.matmul( + Q_delivery_alldelivery, K_alldelivery2.transpose(2, 3) + ) # [num_heads, batch_size, n_pick, n_pick] + compatibility_delivery_allpick = self.norm_factor * torch.matmul( + Q_delivery_allpickup, K_allpickup2.transpose(2, 3) + ) # [num_heads, batch_size, n_pick, n_pick] + + ##Pick up-> + # compatibility_additional?pickup????delivery????attention(size 1),1:n_pick+1??attention,depot?delivery?? + compatibility_additional_delivery = torch.cat( + [ # [num_heads, batch_size, graph_size, 1] + float("-inf") + * torch.ones( + self.num_heads, + batch_size, + 1, + dtype=compatibility.dtype, + device=compatibility.device, + ), + compatibility_pick_delivery, # [num_heads, batch_size, n_pick] + float("-inf") + * torch.ones( + self.num_heads, + batch_size, + n_pick, + dtype=compatibility.dtype, + device=compatibility.device, + ), + ], + -1, + ).view(self.num_heads, batch_size, graph_size, 1) + + compatibility_additional_allpick = torch.cat( + [ # [num_heads, batch_size, graph_size, n_pick] + float("-inf") + * torch.ones( + self.num_heads, + batch_size, + 1, + n_pick, + dtype=compatibility.dtype, + device=compatibility.device, + ), + compatibility_pick_allpick, # [num_heads, batch_size, n_pick, n_pick] + float("-inf") + * torch.ones( + self.num_heads, + batch_size, + n_pick, + n_pick, + dtype=compatibility.dtype, + device=compatibility.device, + ), + ], + 2, + ).view(self.num_heads, batch_size, graph_size, n_pick) + + compatibility_additional_alldelivery = torch.cat( + [ # [num_heads, batch_size, graph_size, n_pick] + float("-inf") + * torch.ones( + self.num_heads, + batch_size, + 1, + n_pick, + dtype=compatibility.dtype, + device=compatibility.device, + ), + compatibility_pick_alldelivery, # [num_heads, batch_size, n_pick, n_pick] + float("-inf") + * torch.ones( + self.num_heads, + batch_size, + n_pick, + n_pick, + dtype=compatibility.dtype, + device=compatibility.device, + ), + ], + 2, + ).view(self.num_heads, batch_size, graph_size, n_pick) + # [num_heads, batch_size, n_query, graph_size+1+n_pick+n_pick] + + # Delivery + compatibility_additional_pick = torch.cat( + [ # [num_heads, batch_size, graph_size, 1] + float("-inf") + * torch.ones( + self.num_heads, + batch_size, + 1, + dtype=compatibility.dtype, + device=compatibility.device, + ), + float("-inf") + * torch.ones( + self.num_heads, + batch_size, + n_pick, + dtype=compatibility.dtype, + device=compatibility.device, + ), + compatibility_delivery_pick, # [num_heads, batch_size, n_pick] + ], + -1, + ).view(self.num_heads, batch_size, graph_size, 1) + + compatibility_additional_alldelivery2 = torch.cat( + [ # [num_heads, batch_size, graph_size, n_pick] + float("-inf") + * torch.ones( + self.num_heads, + batch_size, + 1, + n_pick, + dtype=compatibility.dtype, + device=compatibility.device, + ), + float("-inf") + * torch.ones( + self.num_heads, + batch_size, + n_pick, + n_pick, + dtype=compatibility.dtype, + device=compatibility.device, + ), + compatibility_delivery_alldelivery, # [num_heads, batch_size, n_pick, n_pick] + ], + 2, + ).view(self.num_heads, batch_size, graph_size, n_pick) + + compatibility_additional_allpick2 = torch.cat( + [ # [num_heads, batch_size, graph_size, n_pick] + float("-inf") + * torch.ones( + self.num_heads, + batch_size, + 1, + n_pick, + dtype=compatibility.dtype, + device=compatibility.device, + ), + float("-inf") + * torch.ones( + self.num_heads, + batch_size, + n_pick, + n_pick, + dtype=compatibility.dtype, + device=compatibility.device, + ), + compatibility_delivery_allpick, # [num_heads, batch_size, n_pick, n_pick] + ], + 2, + ).view(self.num_heads, batch_size, graph_size, n_pick) + + compatibility = torch.cat( + [ + compatibility, + compatibility_additional_delivery, + compatibility_additional_allpick, + compatibility_additional_alldelivery, + compatibility_additional_pick, + compatibility_additional_alldelivery2, + compatibility_additional_allpick2, + ], + dim=-1, + ) + + # Optionally apply mask to prevent attention + if mask is not None: + mask = mask.view(1, batch_size, n_query, graph_size).expand_as(compatibility) + compatibility[mask] = float("-inf") + + attn = torch.softmax( + compatibility, dim=-1 + ) # [num_heads, batch_size, n_query, graph_size+1+n_pick*2] (graph_size include depot) + + # If there are nodes with no neighbours then softmax returns nan so we fix them to 0 + if mask is not None: + attnc = attn.clone() + attnc[mask] = 0 + attn = attnc + + # heads: [num_heads, batrch_size, n_query, val_size] pick -> its delivery + heads = torch.matmul( + attn[:, :, :, :graph_size], V + ) # V: (self.num_heads, batch_size, graph_size, val_size) + heads = ( + heads + + attn[:, :, :, graph_size].view(self.num_heads, batch_size, graph_size, 1) + * V_additional_delivery + ) # V_addi:[num_heads, batch_size, graph_size, key_size] + + # Heads pick -> otherpick, V_allpick: # [num_heads, batch_size, n_pick, key_size] + heads = heads + torch.matmul( + attn[:, :, :, graph_size + 1 : graph_size + 1 + n_pick].view( + self.num_heads, batch_size, graph_size, n_pick + ), + V_allpick, + ) + + # V_alldelivery: # (num_heads, batch_size, n_pick, key/val_size) + heads = heads + torch.matmul( + attn[:, :, :, graph_size + 1 + n_pick : graph_size + 1 + 2 * n_pick].view( + self.num_heads, batch_size, graph_size, n_pick + ), + V_alldelivery, + ) + + # Delivery + heads = ( + heads + + attn[:, :, :, graph_size + 1 + 2 * n_pick].view( + self.num_heads, batch_size, graph_size, 1 + ) + * V_additional_pick + ) + heads = heads + torch.matmul( + attn[ + :, + :, + :, + graph_size + 1 + 2 * n_pick + 1 : graph_size + 1 + 3 * n_pick + 1, + ].view(self.num_heads, batch_size, graph_size, n_pick), + V_alldelivery2, + ) + heads = heads + torch.matmul( + attn[:, :, :, graph_size + 1 + 3 * n_pick + 1 :].view( + self.num_heads, batch_size, graph_size, n_pick + ), + V_allpickup2, + ) + + out = torch.mm( + heads.permute(1, 2, 0, 3) + .contiguous() + .view(-1, self.num_heads * self.val_dim), + self.W_out.view(-1, self.embed_dim), + ).view(batch_size, n_query, self.embed_dim) + + return out diff --git a/rl4co/models/zoo/ham/encoder.py b/rl4co/models/zoo/ham/encoder.py new file mode 100644 index 00000000..8a116336 --- /dev/null +++ b/rl4co/models/zoo/ham/encoder.py @@ -0,0 +1,73 @@ +import torch.nn as nn + +from rl4co.models.nn.env_embeddings import env_init_embedding +from rl4co.models.nn.graph.attnnet import Normalization, SkipConnection +from rl4co.models.zoo.ham.attention import HeterogenousMHA + + +class HeterogeneuousMHALayer(nn.Sequential): + def __init__( + self, + num_heads, + embed_dim, + feedforward_hidden=512, + normalization="batch", + ): + super(HeterogeneuousMHALayer, self).__init__( + SkipConnection(HeterogenousMHA(num_heads, embed_dim, embed_dim)), + Normalization(embed_dim, normalization), + SkipConnection( + nn.Sequential( + nn.Linear(embed_dim, feedforward_hidden), + nn.ReLU(), + nn.Linear(feedforward_hidden, embed_dim), + ) + if feedforward_hidden > 0 + else nn.Linear(embed_dim, embed_dim) + ), + Normalization(embed_dim, normalization), + ) + + +class GraphHeterogeneousAttentionEncoder(nn.Module): + def __init__( + self, + init_embedding=None, + num_heads=8, + embed_dim=128, + num_encoder_layers=3, + env_name=None, + normalization="batch", + feedforward_hidden=512, + sdpa_fn=None, + ): + super(GraphHeterogeneousAttentionEncoder, self).__init__() + + # substitute env_name with pdp if none + if env_name is None: + env_name = "pdp" + # Map input to embedding space + if init_embedding is None: + self.init_embedding = env_init_embedding(env_name, {"embed_dim": embed_dim}) + else: + self.init_embedding = init_embedding + + self.layers = nn.Sequential( + *( + HeterogeneuousMHALayer( + num_heads, + embed_dim, + feedforward_hidden, + normalization, + ) + for _ in range(num_encoder_layers) + ) + ) + + def forward(self, x, mask=None): + assert mask is None, "Mask not yet supported!" + # initial Embedding from features + init_embeds = self.init_embedding(x) # (batch_size, graph_size, embed_dim) + # layers (batch_size, graph_size, embed_dim) + embeds = self.layers(init_embeds) + return embeds, init_embeds diff --git a/rl4co/models/zoo/ham/model.py b/rl4co/models/zoo/ham/model.py new file mode 100644 index 00000000..416f7771 --- /dev/null +++ b/rl4co/models/zoo/ham/model.py @@ -0,0 +1,37 @@ +from typing import Union + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl import REINFORCE +from rl4co.models.rl.reinforce.baselines import REINFORCEBaseline +from rl4co.models.zoo.ham.policy import HeterogeneousAttentionModelPolicy + + +class HeterogeneousAttentionModel(REINFORCE): + """Heterogenous Attention Model for solving the Pickup and Delivery Problem based on + REINFORCE: https://arxiv.org/abs/2110.02634. + + Args: + env: Environment to use for the algorithm + policy: Policy to use for the algorithm + baseline: REINFORCE baseline. Defaults to rollout (1 epoch of exponential, then greedy rollout baseline) + policy_kwargs: Keyword arguments for policy + baseline_kwargs: Keyword arguments for baseline + **kwargs: Keyword arguments passed to the superclass + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: HeterogeneousAttentionModelPolicy = None, + baseline: Union[REINFORCEBaseline, str] = "rollout", + policy_kwargs={}, + baseline_kwargs={}, + **kwargs, + ): + assert ( + env.name == "pdp" + ), "HeterogeneousAttentionModel only works for PDP (Pickup and Delivery Problem)" + if policy is None: + policy = HeterogeneousAttentionModelPolicy(env_name=env.name, **policy_kwargs) + + super().__init__(env, policy, baseline, baseline_kwargs, **kwargs) diff --git a/rl4co/models/zoo/ham/policy.py b/rl4co/models/zoo/ham/policy.py new file mode 100644 index 00000000..3dc8ddbc --- /dev/null +++ b/rl4co/models/zoo/ham/policy.py @@ -0,0 +1,62 @@ +from typing import Callable, Optional + +import torch.nn as nn + +from rl4co.models.zoo.am import AttentionModelPolicy +from rl4co.models.zoo.ham.encoder import GraphHeterogeneousAttentionEncoder + + +class HeterogeneousAttentionModelPolicy(AttentionModelPolicy): + """Heterogeneous Attention Model Policy based on https://ieeexplore.ieee.org/document/9352489. + We re-declare the most important arguments here for convenience as in the paper. + See :class:`rl4co.models.zoo.am.AttentionModelPolicy` for more details. + + Args: + encoder: Encoder module. Can be passed by sub-classes + env_name: Name of the environment used to initialize embeddings + init_embedding: Model to use for the initial embedding. If None, use the default embedding for the environment + embed_dim: Dimension of the embeddings + num_encoder_layers: Number of layers in the encoder + num_heads: Number of heads for the attention in encoder + normalization: Normalization to use for the attention layers + feedforward_hidden: Dimension of the hidden layer in the feedforward network + sdpa_fn: Function to use for the scaled dot product attention + **kwargs: keyword arguments passed to the :class:`rl4co.models.zoo.am.AttentionModelPolicy` + """ + + def __init__( + self, + encoder: nn.Module = None, + env_name: str = "pdp", + init_embedding: nn.Module = None, + embed_dim: int = 128, + num_encoder_layers: int = 3, + num_heads: int = 8, + normalization: str = "batch", + feedforward_hidden: int = 512, + sdpa_fn: Optional[Callable] = None, + **kwargs, + ): + if encoder is None: + encoder = GraphHeterogeneousAttentionEncoder( + init_embedding=init_embedding, + num_heads=num_heads, + embed_dim=embed_dim, + num_encoder_layers=num_encoder_layers, + env_name=env_name, + normalization=normalization, + feedforward_hidden=feedforward_hidden, + sdpa_fn=sdpa_fn, + ) + else: + encoder = encoder + + super(HeterogeneousAttentionModelPolicy, self).__init__( + env_name=env_name, + encoder=encoder, + embed_dim=embed_dim, + num_encoder_layers=num_encoder_layers, + num_heads=num_heads, + normalization=normalization, + **kwargs, + ) diff --git a/rl4co/models/zoo/l2d/__init__.py b/rl4co/models/zoo/l2d/__init__.py new file mode 100644 index 00000000..398dea98 --- /dev/null +++ b/rl4co/models/zoo/l2d/__init__.py @@ -0,0 +1,2 @@ +from .model import L2DModel, L2DPPOModel +from .policy import L2DAttnPolicy, L2DPolicy, L2DPolicy4PPO diff --git a/rl4co/models/zoo/l2d/decoder.py b/rl4co/models/zoo/l2d/decoder.py new file mode 100644 index 00000000..833e9c6e --- /dev/null +++ b/rl4co/models/zoo/l2d/decoder.py @@ -0,0 +1,389 @@ +import abc + +from typing import Any, Tuple + +import torch +import torch.nn as nn + +from einops import einsum, rearrange +from tensordict import TensorDict +from torch import Tensor + +from rl4co.models.common.constructive.autoregressive import AutoregressiveDecoder +from rl4co.models.nn.attention import PointerAttention +from rl4co.models.nn.env_embeddings.context import SchedulingContext +from rl4co.models.nn.env_embeddings.dynamic import JSSPDynamicEmbedding +from rl4co.models.nn.graph.hgnn import HetGNNEncoder +from rl4co.models.nn.mlp import MLP +from rl4co.models.zoo.am.decoder import AttentionModelDecoder, PrecomputedCache +from rl4co.utils.ops import batchify, gather_by_index + +from .encoder import GCN4JSSP + + +class L2DActor(nn.Module, metaclass=abc.ABCMeta): + """Base decoder model for actor in L2D. The actor is responsible for generating the logits for the action + similar to the decoder in autoregressive models. Since the decoder in L2D can have the additional purpose + of extracting features (i.e. encoding the environment in ever iteration), we need an additional actor class. + This function serves as template for such actor classes in L2D + """ + + @abc.abstractmethod + def forward( + self, td: TensorDict, hidden: Any = None, num_starts: int = 0 + ) -> Tuple[Tensor, Tensor]: + """Obtain logits for current action to the next ones + + Args: + td: TensorDict containing the input data + hidden: Hidden state from the encoder. Can be any type + num_starts: Number of starts for multistart decoding + + Returns: + Tuple containing the logits and the action mask + """ + raise NotImplementedError("Implement me in subclass!") + + def pre_decoder_hook( + self, td: TensorDict, env=None, hidden: Any = None, num_starts: int = 0 + ) -> Tuple[TensorDict, Any]: + """By default, we only require the input for the actor to be a tuple + (in JSSP we only have operation embeddings but in FJSP we have operation + and machine embeddings. By expecting a tuple we can generalize things.) + + Args: + td: TensorDict containing the input data + hidden: Hidden state from the encoder + num_starts: Number of starts for multistart decoding + + Returns: + Tuple containing the updated hidden state(s) and the input TensorDict + """ + + hidden = (hidden,) if not isinstance(hidden, tuple) else hidden + + if num_starts > 1: + # NOTE: when using pomo, we need this + hidden = tuple(map(lambda x: batchify(x, num_starts), hidden)) + + return td, env, hidden + + +class JSSPActor(L2DActor): + def __init__( + self, + embed_dim: int, + hidden_dim: int, + hidden_layers: int = 2, + het_emb: bool = False, + check_nan: bool = True, + ) -> None: + super().__init__() + + input_dim = (1 + int(het_emb)) * embed_dim + self.mlp = MLP( + input_dim=input_dim, + output_dim=1, + num_neurons=[hidden_dim] * hidden_layers, + hidden_act="ReLU", + out_act="Identity", + input_norm="None", + output_norm="None", + ) + self.het_emb = het_emb + self.dummy = nn.Parameter(torch.rand(input_dim)) + self.check_nan = check_nan + + def forward(self, td, op_emb, ma_emb=None): + bs = td.size(0) + # (bs, n_j) + next_op = td["next_op"] + # (bs, n_j, emb) + job_emb = gather_by_index(op_emb, next_op, dim=1) + if ma_emb is not None: + ma_emb_per_op = einsum(td["ops_ma_adj"], ma_emb, "b m o, b m e -> b o e") + # (bs, n_j, emb) + ma_emb_per_job = gather_by_index(ma_emb_per_op, next_op, dim=1) + # (bs, n_j, 2 * emb) + job_emb = torch.cat((job_emb, ma_emb_per_job), dim=2) + # (bs, n_j, 2 * emb) + no_ops = self.dummy[None, None].expand(bs, 1, -1) + # (bs, 1 + n_j, 2 * emb) + all_actions = torch.cat((no_ops, job_emb), 1) + # (bs, 1 + n_j) + logits = self.mlp(all_actions).squeeze(2) + + if self.check_nan: + assert not torch.isnan(logits).any(), "Logits contain NaNs" + + # (b, 1 + j) + mask = td["action_mask"] + + return logits, mask + + +class FJSPActor(L2DActor): + def __init__( + self, + embed_dim: int, + hidden_dim: int, + hidden_layers: int = 2, + check_nan: bool = True, + ) -> None: + super().__init__() + self.mlp = MLP( + input_dim=2 * embed_dim, + output_dim=1, + num_neurons=[hidden_dim] * hidden_layers, + hidden_act="ReLU", + out_act="Identity", + input_norm="None", + output_norm="None", + ) + self.dummy = nn.Parameter(torch.rand(2 * embed_dim)) + self.check_nan = check_nan + + def forward(self, td, ops_emb, ma_emb): + bs, n_ma = ma_emb.shape[:2] + # (bs, n_jobs, emb) + job_emb = gather_by_index(ops_emb, td["next_op"], squeeze=False) + # (bs, n_jobs, n_ma, emb) + job_emb_expanded = job_emb.unsqueeze(2).expand(-1, -1, n_ma, -1) + ma_emb_expanded = ma_emb.unsqueeze(1).expand_as(job_emb_expanded) + # (bs, num_jobs * n_ma, 2*emb) + h_actions = torch.cat((job_emb_expanded, ma_emb_expanded), dim=-1).flatten(1, 2) + # (bs, 1, 2*emb_dim) + no_ops = self.dummy[None, None].expand(bs, 1, -1) + # (bs, num_jobs * n_ma + 1, 2*emb_dim) + h_actions_w_noop = torch.cat((no_ops, h_actions), 1) + # (b, j*m) + logits = self.mlp(h_actions_w_noop).squeeze(-1) + + if self.check_nan: + assert not torch.isnan(logits).any(), "Logits contain NaNs" + # (b, 1 + j) + mask = td["action_mask"] + return logits, mask + + +class L2DDecoder(AutoregressiveDecoder): + # feature extractor + actor + def __init__( + self, + env_name: str = "jssp", + feature_extractor: nn.Module = None, + actor: nn.Module = None, + init_embedding: nn.Module = None, + embed_dim: int = 128, + actor_hidden_dim: int = 128, + actor_hidden_layers: int = 2, + num_encoder_layers: int = 3, + normalization: str = "batch", + het_emb: bool = False, + stepwise: bool = False, + scaling_factor: int = 1000, + ): + super(L2DDecoder, self).__init__() + + if feature_extractor is None and stepwise: + if env_name == "fjsp" or (het_emb and env_name == "jssp"): + feature_extractor = HetGNNEncoder( + env_name=env_name, + embed_dim=embed_dim, + num_layers=num_encoder_layers, + normalization=normalization, + init_embedding=init_embedding, + scaling_factor=scaling_factor, + ) + else: + feature_extractor = GCN4JSSP( + embed_dim, + num_encoder_layers, + init_embedding=init_embedding, + scaling_factor=scaling_factor, + ) + + self.feature_extractor = feature_extractor + + if actor is None: + if env_name == "fjsp": + actor = FJSPActor( + embed_dim=embed_dim, + hidden_dim=actor_hidden_dim, + hidden_layers=actor_hidden_layers, + ) + else: + actor = JSSPActor( + embed_dim=embed_dim, + hidden_dim=actor_hidden_dim, + hidden_layers=actor_hidden_layers, + het_emb=het_emb, + ) + + self.actor = actor + + def forward(self, td, hidden, num_starts): + if hidden is None: + # NOTE in case we have multiple starts, td is batchified + # (through decoding strategy pre decoding hook). Thus the + # embeddings from feature_extractor have the correct shape + num_starts = 0 + # (bs, n_j * n_ops, e), (bs, n_m, e) + hidden, _ = self.feature_extractor(td) + + td, _, hidden = self.actor.pre_decoder_hook(td, None, hidden, num_starts) + + # (bs, n_j, e) + logits, mask = self.actor(td, *hidden) + + return logits, mask + + +class L2DAttnPointer(PointerAttention): + def __init__( + self, + env_name: str, + embed_dim: int, + num_heads: int, + out_bias: bool = False, + check_nan: bool = True, + ): + super().__init__( + embed_dim=embed_dim, + num_heads=num_heads, + mask_inner=False, + out_bias=out_bias, + check_nan=check_nan, + ) + self.env_name = env_name + + def forward(self, query, key, value, logit_key, attn_mask=None): + # bs = query.size(0) + # (b m j) + logits = super().forward(query, key, value, logit_key, attn_mask=attn_mask) + if self.env_name == "jssp": + # (b j) + logits = logits.sum(1) + elif self.env_name == "fjsp": + no_op_logits = logits[..., 0].sum(1, keepdims=True) + logits = rearrange(logits[..., 1:], "b m j -> b (j m)") + logits = torch.cat((no_op_logits, logits), dim=1) + + return logits + + +class AttnActor(AttentionModelDecoder): + def __init__( + self, + embed_dim: int = 128, + num_heads: int = 8, + env_name: str = "tsp", + context_embedding: nn.Module = None, + dynamic_embedding: nn.Module = None, + mask_inner: bool = True, + out_bias_pointer_attn: bool = False, + linear_bias: bool = False, + use_graph_context: bool = True, + check_nan: bool = True, + sdpa_fn: callable = None, + pointer: nn.Module = None, + moe_kwargs: dict = None, + ): + super().__init__( + embed_dim, + num_heads, + env_name, + context_embedding, + dynamic_embedding, + mask_inner, + out_bias_pointer_attn, + linear_bias, + use_graph_context, + check_nan, + sdpa_fn, + pointer, + moe_kwargs, + ) + + def pre_decoder_hook( + self, td: TensorDict, env=None, hidden: Any = None, num_starts: int = 0 + ) -> Tuple[TensorDict, Any]: + cache = self._precompute_cache(hidden, num_starts=num_starts) + return td, env, (cache,) + + +class L2DAttnActor(AttnActor): + def __init__( + self, + embed_dim: int = 128, + num_heads: int = 8, + env_name: str = "jssp", + scaling_factor: int = 1000, + stepwise: bool = False, + ): + context_embedding = SchedulingContext(embed_dim, scaling_factor=scaling_factor) + if stepwise: + # in a stepwise encoding setting, the embeddings contain all current information + dynamic_embedding = None + else: + # otherwise we might want to update the static embeddings using dynamic updates + dynamic_embedding = JSSPDynamicEmbedding( + embed_dim, scaling_factor=scaling_factor + ) + pointer = L2DAttnPointer(env_name, embed_dim, num_heads, check_nan=False) + + super().__init__( + embed_dim=embed_dim, + num_heads=num_heads, + env_name=env_name, + context_embedding=context_embedding, + dynamic_embedding=dynamic_embedding, + pointer=pointer, + ) + self.dummy = nn.Parameter(torch.rand(1, embed_dim)) + + def _compute_q(self, cached: PrecomputedCache, td: TensorDict): + embeddings = cached.node_embeddings + ma_embs = embeddings["machine_embeddings"] + return self.context_embedding(ma_embs, td) + + def _compute_kvl(self, cached: PrecomputedCache, td: TensorDict): + glimpse_k_stat, glimpse_v_stat, logit_k_stat = ( + gather_by_index(cached.glimpse_key, td["next_op"], dim=1), + gather_by_index(cached.glimpse_val, td["next_op"], dim=1), + gather_by_index(cached.logit_key, td["next_op"], dim=1), + ) + # Compute dynamic embeddings and add to static embeddings + glimpse_k_dyn, glimpse_v_dyn, logit_k_dyn = self.dynamic_embedding(td, cached) + glimpse_k = glimpse_k_stat + glimpse_k_dyn + glimpse_v = glimpse_v_stat + glimpse_v_dyn + logit_k = logit_k_stat + logit_k_dyn + + no_ops = self.dummy.unsqueeze(1).expand(td.size(0), 1, -1).to(logit_k) + logit_k = torch.cat((no_ops, logit_k), dim=1) + + return glimpse_k, glimpse_v, logit_k + + def _precompute_cache(self, embeddings: Tuple[torch.Tensor, torch.Tensor], **kwargs): + ops_emb, ma_emb = embeddings + + ( + glimpse_key_fixed, + glimpse_val_fixed, + logit_key, + ) = self.project_node_embeddings( + ops_emb + ).chunk(3, dim=-1) + + embeddings = TensorDict( + {"op_embeddings": ops_emb, "machine_embeddings": ma_emb}, + batch_size=ops_emb.size(0), + ) + # Organize in a dataclass for easy access + return PrecomputedCache( + node_embeddings=embeddings, + graph_context=0, + glimpse_key=glimpse_key_fixed, + glimpse_val=glimpse_val_fixed, + logit_key=logit_key, + ) diff --git a/rl4co/models/zoo/l2d/encoder.py b/rl4co/models/zoo/l2d/encoder.py new file mode 100644 index 00000000..0bc43fa9 --- /dev/null +++ b/rl4co/models/zoo/l2d/encoder.py @@ -0,0 +1,26 @@ +from rl4co.models.nn.env_embeddings.init import JSSPInitEmbedding +from rl4co.models.nn.graph.gcn import GCNEncoder +from rl4co.utils.ops import adj_to_pyg_edge_index + + +class GCN4JSSP(GCNEncoder): + def __init__( + self, + embed_dim: int, + num_layers: int, + init_embedding=None, + **init_embedding_kwargs, + ): + def edge_idx_fn(td, _): + return adj_to_pyg_edge_index(td["adjacency"]) + + if init_embedding is None: + init_embedding = JSSPInitEmbedding(embed_dim, **init_embedding_kwargs) + + super().__init__( + env_name="jssp", + embed_dim=embed_dim, + num_layers=num_layers, + edge_idx_fn=edge_idx_fn, + init_embedding=init_embedding, + ) diff --git a/rl4co/models/zoo/l2d/model.py b/rl4co/models/zoo/l2d/model.py new file mode 100644 index 00000000..b70784b1 --- /dev/null +++ b/rl4co/models/zoo/l2d/model.py @@ -0,0 +1,69 @@ +from typing import Union + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl import REINFORCE, StepwisePPO +from rl4co.models.rl.reinforce.baselines import REINFORCEBaseline + +from .policy import L2DPolicy, L2DPolicy4PPO + + +class L2DPPOModel(StepwisePPO): + """Learning2Dispatch model by Zhang et al. (2020): + 'Learning to Dispatch for Job Shop Scheduling via Deep Reinforcement Learning' + + Args: + env: Environment to use for the algorithm + policy: Policy to use for the algorithm + baseline: REINFORCE baseline. Defaults to rollout (1 epoch of exponential, then greedy rollout baseline) + policy_kwargs: Keyword arguments for policy + baseline_kwargs: Keyword arguments for baseline + **kwargs: Keyword arguments passed to the superclass + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: L2DPolicy = None, + policy_kwargs={}, + **kwargs, + ): + assert env.name in [ + "fjsp", + "jssp", + ], "L2DModel currently only works for Job-Shop Scheduling Problems" + if policy is None: + policy = L2DPolicy4PPO(env_name=env.name, **policy_kwargs) + + super().__init__(env, policy, **kwargs) + + +class L2DModel(REINFORCE): + """Learning2Dispatch model by Zhang et al. (2020): + 'Learning to Dispatch for Job Shop Scheduling via Deep Reinforcement Learning' + + Args: + env: Environment to use for the algorithm + policy: Policy to use for the algorithm + baseline: REINFORCE baseline. Defaults to rollout (1 epoch of exponential, then greedy rollout baseline) + policy_kwargs: Keyword arguments for policy + baseline_kwargs: Keyword arguments for baseline + **kwargs: Keyword arguments passed to the superclass + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: L2DPolicy = None, + baseline: Union[REINFORCEBaseline, str] = "rollout", + policy_kwargs={}, + baseline_kwargs={}, + **kwargs, + ): + assert env.name in [ + "fjsp", + "jssp", + ], "L2DModel currently only works for Job-Shop Scheduling Problems" + if policy is None: + policy = L2DPolicy(env_name=env.name, **policy_kwargs) + + super().__init__(env, policy, baseline, baseline_kwargs, **kwargs) diff --git a/rl4co/models/zoo/l2d/policy.py b/rl4co/models/zoo/l2d/policy.py new file mode 100644 index 00000000..0cfac356 --- /dev/null +++ b/rl4co/models/zoo/l2d/policy.py @@ -0,0 +1,251 @@ +from typing import Optional + +import torch +import torch.nn as nn + +from torch.distributions import Categorical + +from rl4co.models.common.constructive.autoregressive import ( + AutoregressiveDecoder, + AutoregressiveEncoder, + AutoregressivePolicy, +) +from rl4co.models.common.constructive.base import NoEncoder +from rl4co.models.nn.env_embeddings.init import FJSPMatNetInitEmbedding +from rl4co.models.nn.graph.hgnn import HetGNNEncoder +from rl4co.models.nn.mlp import MLP +from rl4co.models.zoo.matnet.matnet_w_sa import Encoder +from rl4co.utils.decoding import DecodingStrategy, process_logits +from rl4co.utils.ops import gather_by_index +from rl4co.utils.pylogger import get_pylogger + +from .decoder import L2DAttnActor, L2DDecoder +from .encoder import GCN4JSSP + +log = get_pylogger(__name__) + + +class L2DPolicy(AutoregressivePolicy): + def __init__( + self, + encoder: Optional[AutoregressiveEncoder] = None, + decoder: Optional[AutoregressiveDecoder] = None, + embed_dim: int = 64, + num_encoder_layers: int = 2, + env_name: str = "fjsp", + het_emb: bool = True, + scaling_factor: int = 1000, + normalization: str = "batch", + init_embedding: Optional[nn.Module] = None, + stepwise_encoding: bool = False, + tanh_clipping: float = 10, + train_decode_type: str = "sampling", + val_decode_type: str = "greedy", + test_decode_type: str = "multistart_sampling", + **constructive_policy_kw, + ): + if len(constructive_policy_kw) > 0: + log.warn(f"Unused kwargs: {constructive_policy_kw}") + + if encoder is None: + if stepwise_encoding: + encoder = NoEncoder() + elif env_name == "fjsp" or (env_name == "jssp" and het_emb): + encoder = HetGNNEncoder( + env_name=env_name, + embed_dim=embed_dim, + num_layers=num_encoder_layers, + normalization="batch", + init_embedding=init_embedding, + scaling_factor=scaling_factor, + ) + else: + encoder = GCN4JSSP( + embed_dim, + num_encoder_layers, + init_embedding=init_embedding, + scaling_factor=scaling_factor, + ) + + # The decoder generates logits given the current td and heatmap + if decoder is None: + decoder = L2DDecoder( + env_name=env_name, + embed_dim=embed_dim, + actor_hidden_dim=embed_dim, + num_encoder_layers=num_encoder_layers, + init_embedding=init_embedding, + het_emb=het_emb, + stepwise=stepwise_encoding, + scaling_factor=scaling_factor, + normalization=normalization, + ) + + # Pass to constructive policy + super(L2DPolicy, self).__init__( + encoder=encoder, + decoder=decoder, + env_name=env_name, + tanh_clipping=tanh_clipping, + train_decode_type=train_decode_type, + val_decode_type=val_decode_type, + test_decode_type=test_decode_type, + **constructive_policy_kw, + ) + + +class L2DAttnPolicy(AutoregressivePolicy): + def __init__( + self, + encoder: Optional[AutoregressiveEncoder] = None, + decoder: Optional[AutoregressiveDecoder] = None, + embed_dim: int = 256, + num_heads: int = 8, + num_encoder_layers: int = 4, + scaling_factor: int = 1000, + normalization: str = "batch", + env_name: str = "fjsp", + init_embedding: Optional[nn.Module] = None, + tanh_clipping: float = 10, + train_decode_type: str = "sampling", + val_decode_type: str = "greedy", + test_decode_type: str = "multistart_sampling", + **constructive_policy_kw, + ): + if len(constructive_policy_kw) > 0: + log.warn(f"Unused kwargs: {constructive_policy_kw}") + + if encoder is None: + if init_embedding is None: + init_embedding = FJSPMatNetInitEmbedding( + embed_dim, scaling_factor=scaling_factor + ) + + encoder = Encoder( + embed_dim=embed_dim, + num_heads=num_heads, + num_layers=num_encoder_layers, + normalization=normalization, + feedforward_hidden=embed_dim * 2, + init_embedding=init_embedding, + ) + + # The decoder generates logits given the current td and heatmap + if decoder is None: + decoder = L2DAttnActor( + env_name=env_name, + embed_dim=embed_dim, + num_heads=num_heads, + scaling_factor=scaling_factor, + stepwise=False, + ) + + # Pass to constructive policy + super(L2DAttnPolicy, self).__init__( + encoder=encoder, + decoder=decoder, + env_name=env_name, + tanh_clipping=tanh_clipping, + train_decode_type=train_decode_type, + val_decode_type=val_decode_type, + test_decode_type=test_decode_type, + **constructive_policy_kw, + ) + + +class L2DPolicy4PPO(L2DPolicy): + def __init__( + self, + encoder=None, + decoder=None, + critic=None, + embed_dim: int = 64, + num_encoder_layers: int = 2, + env_name: str = "fjsp", + het_emb: bool = True, + scaling_factor: int = 1000, + init_embedding=None, + tanh_clipping: float = 10, + train_decode_type: str = "sampling", + val_decode_type: str = "greedy", + test_decode_type: str = "multistart_sampling", + **constructive_policy_kw, + ): + if init_embedding is None: + pass # TODO PPO specific init emb? + + super().__init__( + encoder=encoder, + decoder=decoder, + embed_dim=embed_dim, + num_encoder_layers=num_encoder_layers, + env_name=env_name, + het_emb=het_emb, + scaling_factor=scaling_factor, + init_embedding=init_embedding, + stepwise_encoding=True, + tanh_clipping=tanh_clipping, + train_decode_type=train_decode_type, + val_decode_type=val_decode_type, + test_decode_type=test_decode_type, + **constructive_policy_kw, + ) + + if critic is None: + if env_name == "fjsp" or het_emb: + input_dim = 2 * embed_dim + else: + input_dim = embed_dim + critic = MLP(input_dim, 1, num_neurons=[embed_dim] * 2) + + self.critic = critic + assert isinstance( + self.encoder, NoEncoder + ), "Define a feature extractor for decoder rather than an encoder in stepwise PPO" + + def evaluate(self, td): + # Encoder: get encoder output and initial embeddings from initial state + hidden, _ = self.decoder.feature_extractor(td) + # pool the embeddings for the critic + h_tuple = (hidden,) if isinstance(hidden, torch.Tensor) else hidden + pooled = tuple(map(lambda x: x.mean(dim=-2), h_tuple)) + # potentially cat multiple embeddings (pooled ops and machines) + h_pooled = torch.cat(pooled, dim=-1) + # pred value via the value head + value_pred = self.critic(h_pooled) + # pre decoder / actor hook + td, _, hidden = self.decoder.actor.pre_decoder_hook( + td, None, hidden, num_starts=0 + ) + logits, mask = self.decoder.actor(td, *hidden) + # get logprobs and entropy over logp distribution + logprobs = process_logits(logits, mask, tanh_clipping=self.tanh_clipping) + action_logprobs = gather_by_index(logprobs, td["action"], dim=1) + dist_entropys = Categorical(logprobs.exp()).entropy() + + return action_logprobs, value_pred, dist_entropys + + def act(self, td, env, phase: str = "train"): + logits, mask = self.decoder(td, hidden=None, num_starts=0) + logprobs = process_logits(logits, mask, tanh_clipping=self.tanh_clipping) + + # DRL-S, sampling actions following \pi + if phase == "train": + action_indexes = DecodingStrategy.sampling(logprobs) + td["logprobs"] = gather_by_index(logprobs, action_indexes, dim=1) + + # DRL-G, greedily picking actions with the maximum probability + else: + action_indexes = DecodingStrategy.greedy(logprobs) + + # memories.states.append(copy.deepcopy(state)) + td["action"] = action_indexes + + return td + + @torch.no_grad() + def generate(self, td, env=None, phase: str = "train", **kwargs) -> dict: + assert phase != "train", "dont use generate() in training mode" + with torch.no_grad(): + out = super().__call__(td, env, phase=phase, **kwargs) + return out diff --git a/rl4co/models/zoo/matnet/__init__.py b/rl4co/models/zoo/matnet/__init__.py new file mode 100644 index 00000000..c2789c34 --- /dev/null +++ b/rl4co/models/zoo/matnet/__init__.py @@ -0,0 +1,2 @@ +from .model import MatNet +from .policy import MatNetPolicy diff --git a/rl4co/models/zoo/matnet/decoder.py b/rl4co/models/zoo/matnet/decoder.py new file mode 100644 index 00000000..5a8d6e28 --- /dev/null +++ b/rl4co/models/zoo/matnet/decoder.py @@ -0,0 +1,157 @@ +from dataclasses import dataclass +from typing import Tuple, Union + +import torch +import torch.nn as nn + +from tensordict import TensorDict +from torch import Tensor + +from rl4co.models.nn.env_embeddings.context import FFSPContext +from rl4co.models.zoo.am.decoder import AttentionModelDecoder +from rl4co.utils.decoding import decode_logprobs, process_logits +from rl4co.utils.ops import gather_by_index + + +@dataclass +class PrecomputedCache: + node_embeddings: Union[Tensor, TensorDict] + graph_context: Union[Tensor, float] + glimpse_key: Tensor + glimpse_val: Tensor + logit_key: Tensor + + +class MatNetDecoder(AttentionModelDecoder): + def _precompute_cache(self, embeddings: Tuple[Tensor, Tensor], *args, **kwargs): + col_emb, row_emb = embeddings + ( + glimpse_key_fixed, + glimpse_val_fixed, + logit_key, + ) = self.project_node_embeddings( + col_emb + ).chunk(3, dim=-1) + + # Optionally disable the graph context from the initial embedding as done in POMO + if self.use_graph_context: + graph_context = self.project_fixed_context(col_emb.mean(1)) + else: + graph_context = 0 + + # Organize in a dataclass for easy access + return PrecomputedCache( + node_embeddings=row_emb, + graph_context=graph_context, + glimpse_key=glimpse_key_fixed, + glimpse_val=glimpse_val_fixed, + logit_key=logit_key, + ) + + +class MatNetFFSPDecoder(AttentionModelDecoder): + def __init__( + self, + embed_dim: int, + num_heads: int, + linear_bias: bool = False, + out_bias_pointer_attn: bool = True, + use_graph_context: bool = False, + **kwargs, + ): + context_embedding = FFSPContext(embed_dim) + + super().__init__( + env_name="ffsp", + embed_dim=embed_dim, + num_heads=num_heads, + context_embedding=context_embedding, + out_bias_pointer_attn=out_bias_pointer_attn, + linear_bias=linear_bias, + use_graph_context=use_graph_context, + **kwargs, + ) + + self.no_job_emb = nn.Parameter(torch.rand(1, 1, embed_dim), requires_grad=True) + + def _precompute_cache(self, embeddings: Tuple[Tensor, Tensor], **kwargs): + job_emb, ma_emb = embeddings + + bs, _, emb_dim = job_emb.shape + + job_emb_plus_one = torch.cat( + (job_emb, self.no_job_emb.expand((bs, 1, emb_dim))), dim=1 + ) + + ( + glimpse_key_fixed, + glimpse_val_fixed, + logit_key, + ) = self.project_node_embeddings( + job_emb_plus_one + ).chunk(3, dim=-1) + + # Optionally disable the graph context from the initial embedding as done in POMO + if self.use_graph_context: + graph_context = self.project_fixed_context(job_emb_plus_one.mean(1)) + else: + graph_context = 0 + + embeddings = TensorDict( + {"job_embeddings": job_emb_plus_one, "machine_embeddings": ma_emb}, + batch_size=bs, + ) + # Organize in a dataclass for easy access + return PrecomputedCache( + node_embeddings=embeddings, + graph_context=graph_context, + glimpse_key=glimpse_key_fixed, + glimpse_val=glimpse_val_fixed, + logit_key=logit_key, + ) + + +class MultiStageFFSPDecoder(MatNetFFSPDecoder): + """Decoder class for the solving the FFSP using a seperate MatNet decoder for each stage + as originally implemented by Kwon et al. (2021) + """ + + def __init__( + self, + embed_dim: int, + num_heads: int, + use_graph_context: bool = True, + tanh_clipping: float = 10, + **kwargs, + ): + super().__init__( + embed_dim=embed_dim, + num_heads=num_heads, + use_graph_context=use_graph_context, + **kwargs, + ) + self.cached_embs: PrecomputedCache = None + self.tanh_clipping = tanh_clipping + + def _precompute_cache(self, embeddings: Tuple[Tensor], **kwargs): + self.cached_embs = super()._precompute_cache(embeddings, **kwargs) + + def forward( + self, + td: TensorDict, + decode_type="sampling", + num_starts: int = 1, + **decoding_kwargs, + ) -> Tuple[Tensor, Tensor, TensorDict]: + + logits, mask = super().forward(td, self.cached_embs, num_starts) + logprobs = process_logits( + logits, + mask, + tanh_clipping=self.tanh_clipping, + **decoding_kwargs, + ) + job_selected = decode_logprobs(logprobs, mask, decode_type) + job_prob = gather_by_index(logprobs, job_selected, dim=1) + + return job_selected, job_prob diff --git a/rl4co/models/zoo/matnet/encoder.py b/rl4co/models/zoo/matnet/encoder.py new file mode 100644 index 00000000..0af88e23 --- /dev/null +++ b/rl4co/models/zoo/matnet/encoder.py @@ -0,0 +1,224 @@ +from typing import Optional + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from rl4co.models.nn.attention import MultiHeadCrossAttention +from rl4co.models.nn.env_embeddings import env_init_embedding +from rl4co.models.nn.ops import TransformerFFN + + +class MixedScoresSDPA(nn.Module): + def __init__( + self, + num_heads: int, + num_scores: int = 1, + mixer_hidden_dim: int = 16, + mix1_init: float = (1 / 2) ** (1 / 2), + mix2_init: float = (1 / 16) ** (1 / 2), + ): + super().__init__() + self.num_heads = num_heads + self.num_scores = num_scores + mix_W1 = torch.torch.distributions.Uniform(low=-mix1_init, high=mix1_init).sample( + (num_heads, self.num_scores + 1, mixer_hidden_dim) + ) + mix_b1 = torch.torch.distributions.Uniform(low=-mix1_init, high=mix1_init).sample( + (num_heads, mixer_hidden_dim) + ) + self.mix_W1 = nn.Parameter(mix_W1) + self.mix_b1 = nn.Parameter(mix_b1) + + mix_W2 = torch.torch.distributions.Uniform(low=-mix2_init, high=mix2_init).sample( + (num_heads, mixer_hidden_dim, 1) + ) + mix_b2 = torch.torch.distributions.Uniform(low=-mix2_init, high=mix2_init).sample( + (num_heads, 1) + ) + self.mix_W2 = nn.Parameter(mix_W2) + self.mix_b2 = nn.Parameter(mix_b2) + + def forward(self, q, k, v, attn_mask=None, dmat=None, dropout_p=0.0): + """Scaled Dot-Product Attention with MatNet Scores Mixer""" + assert dmat is not None + b, m, n = dmat.shape[:3] + dmat = dmat.reshape(b, m, n, self.num_scores) + + # Calculate scaled dot product + attn_scores = torch.matmul(q, k.transpose(-2, -1)) / (k.size(-1) ** 0.5) + # [b, h, m, n, num_scores+1] + mix_attn_scores = torch.cat( + [ + attn_scores.unsqueeze(-1), + dmat[:, None, ...].expand(b, self.num_heads, m, n, self.num_scores), + ], + dim=-1, + ) + # [b, h, m, n] + attn_scores = ( + ( + torch.matmul( + F.relu( + torch.matmul(mix_attn_scores.transpose(1, 2), self.mix_W1) + + self.mix_b1[None, None, :, None, :] + ), + self.mix_W2, + ) + + self.mix_b2[None, None, :, None, :] + ) + .transpose(1, 2) + .squeeze(-1) + ) + + # Apply the provided attention mask + if attn_mask is not None: + if attn_mask.dtype == torch.bool: + attn_mask[~attn_mask.any(-1)] = True + attn_scores.masked_fill_(~attn_mask, float("-inf")) + else: + attn_scores += attn_mask + + # Softmax to get attention weights + attn_weights = F.softmax(attn_scores, dim=-1) + + # Apply dropout + if dropout_p > 0.0: + attn_weights = F.dropout(attn_weights, p=dropout_p) + + # Compute the weighted sum of values + return torch.matmul(attn_weights, v) + + +class MatNetCrossMHA(MultiHeadCrossAttention): + def __init__( + self, + embed_dim: int, + num_heads: int, + bias: bool = False, + mixer_hidden_dim: int = 16, + mix1_init: float = (1 / 2) ** (1 / 2), + mix2_init: float = (1 / 16) ** (1 / 2), + ): + attn_fn = MixedScoresSDPA( + num_heads=num_heads, + mixer_hidden_dim=mixer_hidden_dim, + mix1_init=mix1_init, + mix2_init=mix2_init, + ) + + super().__init__( + embed_dim=embed_dim, num_heads=num_heads, bias=bias, sdpa_fn=attn_fn + ) + + +class MatNetMHA(nn.Module): + def __init__(self, embed_dim: int, num_heads: int, bias: bool = False): + super().__init__() + self.row_encoding_block = MatNetCrossMHA(embed_dim, num_heads, bias) + self.col_encoding_block = MatNetCrossMHA(embed_dim, num_heads, bias) + + def forward(self, row_emb, col_emb, dmat, attn_mask=None): + """ + Args: + row_emb (Tensor): [b, m, d] + col_emb (Tensor): [b, n, d] + dmat (Tensor): [b, m, n] + + Returns: + Updated row_emb (Tensor): [b, m, d] + Updated col_emb (Tensor): [b, n, d] + """ + updated_row_emb = self.row_encoding_block( + row_emb, col_emb, dmat=dmat, cross_attn_mask=attn_mask + ) + attn_mask_t = attn_mask.transpose(-2, -1) if attn_mask is not None else None + updated_col_emb = self.col_encoding_block( + col_emb, + row_emb, + dmat=dmat.transpose(-2, -1), + cross_attn_mask=attn_mask_t, + ) + return updated_row_emb, updated_col_emb + + +class MatNetLayer(nn.Module): + def __init__( + self, + embed_dim: int, + num_heads: int, + bias: bool = False, + feedforward_hidden: int = 512, + normalization: Optional[str] = "instance", + ): + super().__init__() + self.MHA = MatNetMHA(embed_dim, num_heads, bias) + self.F_a = TransformerFFN(embed_dim, feedforward_hidden, normalization) + self.F_b = TransformerFFN(embed_dim, feedforward_hidden, normalization) + + def forward(self, row_emb, col_emb, dmat, attn_mask=None): + """ + Args: + row_emb (Tensor): [b, m, d] + col_emb (Tensor): [b, n, d] + dmat (Tensor): [b, m, n] + + Returns: + Updated row_emb (Tensor): [b, m, d] + Updated col_emb (Tensor): [b, n, d] + """ + + row_emb_out, col_emb_out = self.MHA(row_emb, col_emb, dmat, attn_mask) + row_emb_out = self.F_a(row_emb_out, row_emb) + col_emb_out = self.F_b(col_emb_out, col_emb) + return row_emb_out, col_emb_out + + +class MatNetEncoder(nn.Module): + def __init__( + self, + embed_dim: int = 256, + num_heads: int = 16, + num_layers: int = 3, + normalization: str = "batch", + feedforward_hidden: int = 512, + init_embedding: nn.Module = None, + init_embedding_kwargs: dict = {}, + bias: bool = False, + mask_non_neighbors: bool = False, + ): + super().__init__() + + if init_embedding is None: + init_embedding = env_init_embedding( + "matnet", {"embed_dim": embed_dim, **init_embedding_kwargs} + ) + + self.init_embedding = init_embedding + self.mask_non_neighbors = mask_non_neighbors + self.layers = nn.ModuleList( + [ + MatNetLayer( + embed_dim=embed_dim, + num_heads=num_heads, + bias=bias, + feedforward_hidden=feedforward_hidden, + normalization=normalization, + ) + for _ in range(num_layers) + ] + ) + + def forward(self, td, attn_mask: torch.Tensor = None): + row_emb, col_emb, dmat = self.init_embedding(td) + + if self.mask_non_neighbors and attn_mask is None: + # attn_mask (keep 1s discard 0s) to only attend on neighborhood + attn_mask = dmat.ne(0) + + for layer in self.layers: + row_emb, col_emb = layer(row_emb, col_emb, dmat, attn_mask) + + embedding = (row_emb, col_emb) + init_embedding = None + return embedding, init_embedding # match output signature for the AR policy class diff --git a/rl4co/models/zoo/matnet/matnet_w_sa.py b/rl4co/models/zoo/matnet/matnet_w_sa.py new file mode 100644 index 00000000..cf06056f --- /dev/null +++ b/rl4co/models/zoo/matnet/matnet_w_sa.py @@ -0,0 +1,202 @@ +import math + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from einops import rearrange + +from rl4co.models.nn.attention import MultiHeadAttention +from rl4co.models.nn.env_embeddings import env_init_embedding +from rl4co.models.nn.ops import Normalization, TransformerFFN + + +def apply_weights_and_combine(dots, v, tanh_clipping=0): + # scale to avoid numerical underflow + logits = dots / dots.std() + if tanh_clipping > 0: + # tanh clipping to avoid explosions + logits = torch.tanh(logits) * tanh_clipping + # shape: (batch, num_heads, row_cnt, col_cnt) + weights = nn.Softmax(dim=-1)(logits) + weights = weights.nan_to_num(0) + # shape: (batch, num_heads, row_cnt, qkv_dim) + out = torch.matmul(weights, v) + # shape: (batch, row_cnt, num_heads, qkv_dim) + out = rearrange(out, "b h s d -> b s (h d)") + return out + + +class MixedScoreFF(nn.Module): + def __init__(self, num_heads, ms_hidden_dim: int = 32, bias: bool = False) -> None: + super().__init__() + + self.lin1 = nn.Linear(2 * num_heads, num_heads * ms_hidden_dim, bias=bias) + self.lin2 = nn.Linear(num_heads * ms_hidden_dim, num_heads, bias=bias) + + def forward(self, dot_product_score, cost_mat_score): + # dot_product_score shape: (batch, head_num, row_cnt, col_cnt) + # cost_mat_score shape: (batch, head_num, row_cnt, col_cnt) + # shape: (batch, head_num, row_cnt, col_cnt, 2) + two_scores = torch.stack((dot_product_score, cost_mat_score), dim=-1) + two_scores = rearrange(two_scores, "b h r c s -> b r c (h s)") + # shape: (batch, row_cnt, col_cnt, 2 * num_heads) + ms1 = self.lin1(two_scores) + ms1_activated = F.relu(ms1) + # shape: (batch, row_cnt, col_cnt, num_heads) + ms2 = self.lin2(ms1_activated) + # shape: (batch, row_cnt, head_num, col_cnt) + mixed_scores = rearrange(ms2, "b r c h -> b h r c") + + return mixed_scores + + +class EfficientMixedScoreMultiHeadAttention(nn.Module): + def __init__(self, embed_dim: int, num_heads: int, bias: bool = False): + super().__init__() + + qkv_dim = embed_dim // num_heads + + self.num_heads = num_heads + self.qkv_dim = qkv_dim + self.norm_factor = 1 / math.sqrt(qkv_dim) + + self.Wqv1 = nn.Linear(embed_dim, 2 * embed_dim, bias=bias) + self.Wkv2 = nn.Linear(embed_dim, 2 * embed_dim, bias=bias) + + # self.init_parameters() + self.mixed_scores_layer = MixedScoreFF(num_heads, qkv_dim, bias) + + self.out_proj1 = nn.Linear(embed_dim, embed_dim, bias=bias) + self.out_proj2 = nn.Linear(embed_dim, embed_dim, bias=bias) + + def forward(self, x1, x2, attn_mask=None, cost_mat=None): + batch_size = x1.size(0) + row_cnt = x1.size(-2) + col_cnt = x2.size(-2) + + # Project query, key, value + q, v1 = rearrange( + self.Wqv1(x1), "b s (two h d) -> two b h s d", two=2, h=self.num_heads + ).unbind(dim=0) + + # Project query, key, value + k, v2 = rearrange( + self.Wqv1(x2), "b s (two h d) -> two b h s d", two=2, h=self.num_heads + ).unbind(dim=0) + + # shape: (batch, num_heads, row_cnt, col_cnt) + dot = self.norm_factor * torch.matmul(q, k.transpose(-2, -1)) + + if cost_mat is not None: + # shape: (batch, num_heads, row_cnt, col_cnt) + cost_mat_score = cost_mat[:, None, :, :].expand_as(dot) + dot = self.mixed_scores_layer(dot, cost_mat_score) + + if attn_mask is not None: + attn_mask = attn_mask.view(batch_size, 1, row_cnt, col_cnt).expand_as(dot) + dot.masked_fill_(~attn_mask, float("-inf")) + + h1 = self.out_proj1(apply_weights_and_combine(dot, v2)) + h2 = self.out_proj2(apply_weights_and_combine(dot.transpose(-2, -1), v1)) + + return h1, h2 + + +class EncoderLayer(nn.Module): + def __init__( + self, + embed_dim: int, + num_heads: int = 8, + feedforward_hidden: int = 512, + normalization: str = "batch", + bias: bool = False, + ): + super().__init__() + + self.op_attn = MultiHeadAttention(embed_dim, num_heads, bias=bias) + self.ma_attn = MultiHeadAttention(embed_dim, num_heads, bias=bias) + self.cross_attn = EfficientMixedScoreMultiHeadAttention( + embed_dim, num_heads, bias=bias + ) + + self.op_ffn = TransformerFFN(embed_dim, feedforward_hidden, normalization) + self.ma_ffn = TransformerFFN(embed_dim, feedforward_hidden, normalization) + + self.op_norm = Normalization(embed_dim, normalization) + self.ma_norm = Normalization(embed_dim, normalization) + + def forward( + self, op_in, ma_in, cost_mat, op_mask=None, ma_mask=None, cross_mask=None + ): + op_cross_out, ma_cross_out = self.cross_attn( + op_in, ma_in, attn_mask=cross_mask, cost_mat=cost_mat + ) + op_cross_out = self.op_norm(op_cross_out + op_in) + ma_cross_out = self.ma_norm(ma_cross_out + ma_in) + + # (bs, num_jobs, ops_per_job, d) + op_self_out = self.op_attn(op_cross_out, attn_mask=op_mask) + # (bs, num_ma, d) + ma_self_out = self.ma_attn(ma_cross_out, attn_mask=ma_mask) + + op_out = self.op_ffn(op_cross_out, op_self_out) + ma_out = self.ma_ffn(ma_cross_out, ma_self_out) + + return op_out, ma_out + + +class Encoder(nn.Module): + def __init__( + self, + embed_dim: int = 256, + num_heads: int = 16, + num_layers: int = 5, + normalization: str = "batch", + feedforward_hidden: int = 512, + init_embedding: nn.Module = None, + init_embedding_kwargs: dict = {}, + bias: bool = False, + ): + super().__init__() + self.d_model = embed_dim + + if init_embedding is None: + init_embedding = env_init_embedding( + "matnet", {"embed_dim": embed_dim, **init_embedding_kwargs} + ) + self.init_embedding = init_embedding + self.layers = nn.ModuleList( + [ + EncoderLayer( + embed_dim=embed_dim, + num_heads=num_heads, + feedforward_hidden=feedforward_hidden, + normalization=normalization, + bias=bias, + ) + for _ in range(num_layers) + ] + ) + + def forward(self, td, attn_mask: torch.Tensor = None): + # [BS, num_machines, emb], [BS, num_operations, emb] + ops_embed, ma_embed, edge_feat = self.init_embedding(td) + try: + # mask padded ops; shape=(bs, ops) + ops_attn_mask = ~td["pad_mask"] + except KeyError: + ops_attn_mask = None + # padded ops should also be masked in cross attention; shape=(bs, ops, ma) + # cross_mask = ops_attn_mask.unsqueeze(-1).expand(-1, -1, ma_embed.size(1)) + for layer in self.layers: + ops_embed, ma_embed = layer( + ops_embed, + ma_embed, + cost_mat=edge_feat, + op_mask=ops_attn_mask, # mask padded operations in attention + ma_mask=None, # no padding for machines + cross_mask=None, + ) + embedding = (ops_embed, ma_embed) + return embedding, None diff --git a/rl4co/models/zoo/matnet/model.py b/rl4co/models/zoo/matnet/model.py new file mode 100644 index 00000000..ea3f9188 --- /dev/null +++ b/rl4co/models/zoo/matnet/model.py @@ -0,0 +1,54 @@ +from typing import Union + +import torch.nn as nn + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.zoo.matnet.policy import MatNetPolicy, MultiStageFFSPPolicy +from rl4co.models.zoo.pomo import POMO +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def select_matnet_policy(env, **policy_params): + if env.name == "ffsp": + if env.flatten_stages: + return MatNetPolicy(env_name=env.name, **policy_params) + else: + return MultiStageFFSPPolicy(stage_cnt=env.num_stage, **policy_params) + else: + return MatNetPolicy(env_name=env.name, **policy_params) + + +class MatNet(POMO): + def __init__( + self, + env: RL4COEnvBase, + policy: Union[nn.Module, MatNetPolicy] = None, + num_starts: int = None, + policy_params: dict = {}, + **kwargs, + ): + if policy is None: + policy = select_matnet_policy(env=env, **policy_params) + + # Check if using augmentation and the validation of augmentation function + if kwargs.get("num_augment", 0) != 0: + log.warning("MatNet is using augmentation.") + if ( + kwargs.get("augment_fn") in ["symmetric", "dihedral8"] + or kwargs.get("augment_fn") is None + ): + log.error( + "MatNet does not use symmetric or dihedral augmentation. Seeting no augmentation function." + ) + kwargs["num_augment"] = 0 + else: + kwargs["num_augment"] = 0 + + super(MatNet, self).__init__( + env=env, + policy=policy, + num_starts=num_starts, + **kwargs, + ) diff --git a/rl4co/models/zoo/matnet/policy.py b/rl4co/models/zoo/matnet/policy.py new file mode 100644 index 00000000..4e3ea980 --- /dev/null +++ b/rl4co/models/zoo/matnet/policy.py @@ -0,0 +1,210 @@ +from math import factorial +from typing import List + +import torch +import torch.nn as nn + +from tensordict import TensorDict + +from rl4co.envs.scheduling.ffsp.env import FFSPEnv +from rl4co.models.common.constructive.autoregressive import AutoregressivePolicy +from rl4co.models.zoo.matnet.decoder import ( + MatNetDecoder, + MatNetFFSPDecoder, + MultiStageFFSPDecoder, +) +from rl4co.models.zoo.matnet.encoder import MatNetEncoder +from rl4co.utils.ops import batchify +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class MatNetPolicy(AutoregressivePolicy): + """MatNet Policy from Kwon et al., 2021. + Reference: https://arxiv.org/abs/2106.11113 + + Warning: + This implementation is under development and subject to change. + + Args: + env_name: Name of the environment used to initialize embeddings + embed_dim: Dimension of the node embeddings + num_encoder_layers: Number of layers in the encoder + num_heads: Number of heads in the attention layers + normalization: Normalization type in the attention layers + **kwargs: keyword arguments passed to the `AutoregressivePolicy` + + Default paarameters are adopted from the original implementation. + """ + + def __init__( + self, + env_name: str = "atsp", + embed_dim: int = 256, + num_encoder_layers: int = 5, + num_heads: int = 16, + normalization: str = "instance", + init_embedding_kwargs: dict = {"mode": "RandomOneHot"}, + use_graph_context: bool = False, + bias: bool = False, + **kwargs, + ): + if env_name not in ["atsp", "ffsp"]: + log.error(f"env_name {env_name} is not originally implemented in MatNet") + + if env_name == "ffsp": + decoder = MatNetFFSPDecoder( + embed_dim=embed_dim, + num_heads=num_heads, + use_graph_context=use_graph_context, + out_bias=True, + ) + + else: + decoder = MatNetDecoder( + env_name=env_name, + embed_dim=embed_dim, + num_heads=num_heads, + use_graph_context=use_graph_context, + ) + + super(MatNetPolicy, self).__init__( + env_name=env_name, + encoder=MatNetEncoder( + embed_dim=embed_dim, + num_heads=num_heads, + num_layers=num_encoder_layers, + normalization=normalization, + init_embedding_kwargs=init_embedding_kwargs, + bias=bias, + ), + decoder=decoder, + embed_dim=embed_dim, + num_encoder_layers=num_encoder_layers, + num_heads=num_heads, + normalization=normalization, + **kwargs, + ) + + +class MultiStageFFSPPolicy(nn.Module): + """Policy for solving the FFSP using a seperate encoder and decoder for each + stage. This requires the 'while not td["done"].all()'-loop to be on policy level + (instead of decoder level).""" + + def __init__( + self, + stage_cnt: int, + embed_dim: int = 512, + num_heads: int = 16, + num_encoder_layers: int = 5, + use_graph_context: bool = False, + normalization: str = "instance", + feedforward_hidden: int = 512, + bias: bool = False, + train_decode_type: str = "sampling", + val_decode_type: str = "sampling", + test_decode_type: str = "sampling", + ): + super().__init__() + self.stage_cnt = stage_cnt + + self.encoders: List[MatNetEncoder] = nn.ModuleList( + [ + MatNetEncoder( + embed_dim=embed_dim, + num_heads=num_heads, + num_layers=num_encoder_layers, + normalization=normalization, + feedforward_hidden=feedforward_hidden, + bias=bias, + init_embedding_kwargs={"mode": "RandomOneHot"}, + ) + for _ in range(self.stage_cnt) + ] + ) + self.decoders: List[MultiStageFFSPDecoder] = nn.ModuleList( + [ + MultiStageFFSPDecoder(embed_dim, num_heads, use_graph_context) + for _ in range(self.stage_cnt) + ] + ) + + self.train_decode_type = train_decode_type + self.val_decode_type = val_decode_type + self.test_decode_type = test_decode_type + + def pre_forward(self, td: TensorDict, env: FFSPEnv, num_starts: int): + run_time_list = td["run_time"].chunk(env.num_stage, dim=-1) + for stage_idx in range(self.stage_cnt): + td["cost_matrix"] = run_time_list[stage_idx] + encoder = self.encoders[stage_idx] + embeddings, _ = encoder(td) + decoder = self.decoders[stage_idx] + decoder._precompute_cache(embeddings) + + if num_starts > 1: + # repeat num_start times + td = batchify(td, num_starts) + # update machine idx and action mask + td = env.pre_step(td) + + return td + + def forward( + self, + td: TensorDict, + env: FFSPEnv, + phase="train", + num_starts=1, + return_actions: bool = False, + **decoder_kwargs, + ): + assert not env.flatten_stages, "Multistage model only supports unflattened env" + assert num_starts <= factorial(env.num_machine) + + # Get decode type depending on phase + decode_type = getattr(self, f"{phase}_decode_type") + device = td.device + + td = self.pre_forward(td, env, num_starts) + + # NOTE: this must come after pre_forward due to batchify op + batch_size = td.size(0) + logp_list = torch.zeros(size=(batch_size, 0), device=device) + action_list = [] + + while not td["done"].all(): + action_stack = torch.empty( + size=(batch_size, self.stage_cnt), dtype=torch.long, device=device + ) + logp_stack = torch.empty(size=(batch_size, self.stage_cnt), device=device) + + for stage_idx in range(self.stage_cnt): + decoder = self.decoders[stage_idx] + action, logp = decoder(td, decode_type, num_starts, **decoder_kwargs) + action_stack[:, stage_idx] = action + logp_stack[:, stage_idx] = logp + + gathering_index = td["stage_idx"][:, None] + # shape: (batch, 1) + action = action_stack.gather(dim=1, index=gathering_index).squeeze(dim=1) + logp = logp_stack.gather(dim=1, index=gathering_index).squeeze(dim=1) + # shape: (batch) + action_list.append(action) + # transition + td.set("action", action) + td = env.step(td)["next"] + + logp_list = torch.cat((logp_list, logp[:, None]), dim=1) + + out = { + "reward": td["reward"], + "log_likelihood": logp_list.sum(1), + } + + if return_actions: + out["actions"] = torch.stack(action_list, 1) + + return out diff --git a/rl4co/models/zoo/mdam/__init__.py b/rl4co/models/zoo/mdam/__init__.py new file mode 100644 index 00000000..2b7a14da --- /dev/null +++ b/rl4co/models/zoo/mdam/__init__.py @@ -0,0 +1,2 @@ +from .model import MDAM +from .policy import MDAMPolicy diff --git a/rl4co/models/zoo/mdam/decoder.py b/rl4co/models/zoo/mdam/decoder.py new file mode 100644 index 00000000..7764fc12 --- /dev/null +++ b/rl4co/models/zoo/mdam/decoder.py @@ -0,0 +1,331 @@ +import math + +from dataclasses import dataclass +from typing import Union + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from tensordict import TensorDict + +from rl4co.envs import RL4COEnvBase +from rl4co.models.nn.attention import PointerAttention +from rl4co.models.nn.env_embeddings import env_context_embedding, env_dynamic_embedding +from rl4co.utils.decoding import decode_logprobs, get_log_likelihood + + +@dataclass +class PrecomputedCache: + node_embeddings: torch.Tensor + graph_context: torch.Tensor + glimpse_key: torch.Tensor + glimpse_val: torch.Tensor + logit_key: torch.Tensor + + +class MDAMDecoder(nn.Module): + def __init__( + self, + embed_dim: int = 128, + num_heads: int = 8, + num_paths: int = 5, + env_name: str = "tsp", + mask_inner: bool = True, + mask_logits: bool = True, + eg_step_gap: int = 200, + tanh_clipping: float = 10.0, + shrink_size=None, + train_decode_type: str = "sampling", + val_decode_type: str = "greedy", + test_decode_type: str = "greedy", + ): + super(MDAMDecoder, self).__init__() + self.dynamic_embedding = env_dynamic_embedding(env_name, {"embed_dim": embed_dim}) + + self.train_decode_type = train_decode_type + self.val_decode_type = val_decode_type + self.test_decode_type = test_decode_type + + self.W_placeholder = nn.Parameter(torch.Tensor(2 * embed_dim)) + self.W_placeholder.data.uniform_( + -1, 1 + ) # Placeholder should be in range of activations + + self.context = nn.ModuleList( + [ + env_context_embedding(env_name, {"embed_dim": embed_dim}) + for _ in range(num_paths) + ] + ) + + self.project_node_embeddings = [ + nn.Linear(embed_dim, 3 * embed_dim, bias=False) for _ in range(num_paths) + ] + self.project_node_embeddings = nn.ModuleList(self.project_node_embeddings) + + self.project_fixed_context = [ + nn.Linear(embed_dim, embed_dim, bias=False) for _ in range(num_paths) + ] + self.project_fixed_context = nn.ModuleList(self.project_fixed_context) + + self.project_step_context = [ + nn.Linear(2 * embed_dim, embed_dim, bias=False) for _ in range(num_paths) + ] + self.project_step_context = nn.ModuleList(self.project_step_context) + + self.project_out = [ + nn.Linear(embed_dim, embed_dim, bias=False) for _ in range(num_paths) + ] + self.project_out = nn.ModuleList(self.project_out) + + self.dynamic_embedding = env_dynamic_embedding(env_name, {"embed_dim": embed_dim}) + + # MHA with Pointer mechanism (https://arxiv.org/abs/1506.03134) + self.pointer = [ + PointerAttention( + embed_dim, + num_heads, + mask_inner=mask_inner, + ) + for _ in range(num_paths) + ] + + self.env_name = env_name + self.mask_inner = mask_inner + self.mask_logits = mask_logits + self.num_heads = num_heads + self.num_paths = num_paths + self.eg_step_gap = eg_step_gap + self.tanh_clipping = tanh_clipping + self.shrink_size = shrink_size + + def forward( + self, + td: TensorDict, + encoded_inputs: torch.Tensor, + env: Union[str, RL4COEnvBase], + attn, + V, + h_old, + encoder, # note: used because of different paths, could be better modularized + **decoder_kwargs, + ): + # SECTION: Decoder first step: calculate for the decoder divergence loss + # Cost list and log likelihood list along with path + output_list = [] + # td_list = [env.reset(td) for i in range(self.num_paths)] + td_list = [td.clone() for i in range(self.num_paths)] + for i in range(self.num_paths): + # Clone the encoded features for this path + _encoded_inputs = encoded_inputs.clone() + + # Compute keys, values for the glimpse and keys for the logits once as they can be reused in every step + fixed = self._precompute(_encoded_inputs, path_index=i) + logprobs, _ = self._get_logprobs(fixed, td_list[i], i) + + # Collect output of step + output_list.append(logprobs[:, 0, :]) + output_list[-1] = torch.max( + output_list[-1], + torch.ones( + output_list[-1].shape, + dtype=output_list[-1].dtype, + device=output_list[-1].device, + ) + * (-1e9), + ) # for the kl loss + + if self.num_paths > 1: + kl_divergences = [] + for _i in range(self.num_paths): + for _j in range(self.num_paths): + if _i == _j: + continue + kl_divergence = torch.sum( + torch.exp(output_list[_i]) * (output_list[_i] - output_list[_j]), + -1, + ) + kl_divergences.append(kl_divergence) + loss_kl_divergence = torch.stack(kl_divergences, 0).mean() + + # SECTION: Decoder rest step: calculate for other decoder divergence loss + # Cost list and log likelihood list along with path + reward_list = [] + output_list = [] + action_list = [] + ll_list = [] + # td_list = [env.reset(td) for _ in range(self.num_paths)] + td_list = [td.clone() for i in range(self.num_paths)] + for i in range(self.num_paths): + # Clone the encoded features for this path + _encoded_inputs = encoded_inputs.clone() + _attn = attn.clone() + _V = V.clone() + _h_old = h_old.clone() + + outputs, actions = [], [] + fixed = self._precompute(_encoded_inputs, path_index=i) + + j = 0 + mask, mask_first = None, None # dummy, we get them during the steps + while not (self.shrink_size is None and td_list[i]["done"].all()): + if j > 1 and j % self.eg_step_gap == 0: + if not self.is_vrp: + # TODO: modularize + mask_attn = mask ^ mask_first + else: + mask_attn = mask + + # TODO: decoder + _encoded_inputs, _ = encoder.change(_attn, _V, _h_old, mask_attn) + fixed = self._precompute(_encoded_inputs, path_index=i) + logprobs, mask = self._get_logprobs(fixed, td_list[i], i) + if j == 0: + pass + + # Select the indices of the next nodes in the sequences, result (batch_size) long + action = decode_logprobs( + logprobs[:, 0, :], + mask, + decode_type=decoder_kwargs["decode_type"], + ) + + td_list[i].set("action", action) + td_list[i] = env.step(td_list[i])["next"] + + # Collect output of step + outputs.append(logprobs[:, 0, :]) + actions.append(action) + j += 1 + + assert len(outputs) > 0, "No outputs were generated, check if envs were done" + outputs, actions = torch.stack(outputs, 1), torch.stack(actions, 1) + reward = env.get_reward(td, actions) + ll = get_log_likelihood(outputs, actions, mask=None) + + reward_list.append(reward) + output_list.append(outputs) + action_list.append(actions) + ll_list.append(ll) + + reward = torch.stack(reward_list, 1) + log_likelihood = torch.stack(ll_list, 1) + return reward, log_likelihood, loss_kl_divergence, actions + + def _precompute(self, embeddings, num_steps=1, path_index=None): + # The fixed context projection of the graph embedding is calculated only once for efficiency + graph_embed = embeddings.mean(1) + + # Fixed context = (batch_size, 1, embed_dim) to make broadcastable with parallel timesteps + fixed_context = self.project_fixed_context[path_index](graph_embed)[:, None, :] + + # The projection of the node embeddings for the attention is calculated once up front + ( + glimpse_key_fixed, + glimpse_val_fixed, + logit_key_fixed, + ) = self.project_node_embeddings[path_index](embeddings[:, None, :, :]).chunk( + 3, dim=-1 + ) + + fixed = PrecomputedCache( + node_embeddings=embeddings, + graph_context=fixed_context, + glimpse_key=self._make_heads(glimpse_key_fixed, num_steps), + glimpse_val=self._make_heads(glimpse_val_fixed, num_steps), + logit_key=logit_key_fixed.contiguous(), + ) + return fixed + + def _make_heads(self, v, num_steps=None): + assert num_steps is None or v.size(1) == 1 or v.size(1) == num_steps + return ( + v.contiguous() + .view(v.size(0), v.size(1), v.size(2), self.num_heads, -1) + .expand( + v.size(0), + v.size(1) if num_steps is None else num_steps, + v.size(2), + self.num_heads, + -1, + ) + .permute( + 3, 0, 1, 2, 4 + ) # (n_heads, batch_size, num_steps, graph_size, head_dim) + ) + + def _get_logprobs(self, fixed, td, path_index, normalize=True): + step_context = self.context[path_index]( + fixed.node_embeddings, td + ) # [batch, embed_dim] + glimpse_q = fixed.graph_context + step_context.unsqueeze(1).to( + fixed.graph_context.device + ) + + # Compute keys and values for the nodes + ( + glimpse_key_dynamic, + glimpse_val_dynamic, + logit_key_dynamic, + ) = self.dynamic_embedding(td) + glimpse_k = fixed.glimpse_key + glimpse_key_dynamic + glimpse_v = fixed.glimpse_val + glimpse_val_dynamic + logit_k = fixed.logit_key + logit_key_dynamic + + # Compute the action mask + mask = td["action_mask"] + + # Compute logits (unnormalized logprobs) + # logprobs, _ = self.logit_attention[path_index](glimpse_q, glimpse_k, glimpse_v, logit_k, mask, path_index) + logprobs, _ = self._one_to_many_logits( + glimpse_q, glimpse_k, glimpse_v, logit_k, mask, path_index + ) + return logprobs, mask + + def _one_to_many_logits(self, query, glimpse_K, glimpse_V, logit_K, mask, path_index): + batch_size, num_steps, embed_dim = query.size() + key_size = val_size = embed_dim // self.num_heads + + # Compute the glimpse, rearrange dimensions so the dimensions are (n_heads, batch_size, num_steps, 1, key_size) + glimpse_Q = query.view( + batch_size, num_steps, self.num_heads, 1, key_size + ).permute(2, 0, 1, 3, 4) + + # Batch matrix multiplication to compute compatibilities (n_heads, batch_size, num_steps, graph_size) + compatibility = torch.matmul(glimpse_Q, glimpse_K.transpose(-2, -1)) / math.sqrt( + glimpse_Q.size(-1) + ) + if self.mask_inner: + assert self.mask_logits, "Cannot mask inner without masking logits" + compatibility[ + ~mask[None, :, None, None, :].expand_as(compatibility) + ] = -math.inf + + # Batch matrix multiplication to compute heads (n_heads, batch_size, num_steps, val_size) + heads = torch.matmul(F.softmax(compatibility, dim=-1), glimpse_V) + + # Project to get glimpse/updated context node embedding (batch_size, num_steps, embed_dim) + glimpse = self.project_out[path_index]( + heads.permute(1, 2, 3, 0, 4) + .contiguous() + .view(-1, num_steps, 1, self.num_heads * val_size) + ) + + # Now projecting the glimpse is not needed since this can be absorbed into project_out + # final_Q = self.project_glimpse(glimpse) + final_Q = glimpse + + # Batch matrix multiplication to compute logits (batch_size, num_steps, graph_size) + # logits = 'compatibility' + logits = torch.matmul(final_Q, logit_K.transpose(-2, -1)).squeeze(-2) / math.sqrt( + final_Q.size(-1) + ) + + # From the logits compute the probabilities by clipping, masking and softmax + if self.tanh_clipping > 0: + logits = F.tanh(logits) * self.tanh_clipping + if self.mask_logits: + logits[~mask[:, None, :]] = -math.inf + + return logits, glimpse.squeeze(-2) diff --git a/rl4co/models/zoo/mdam/encoder.py b/rl4co/models/zoo/mdam/encoder.py new file mode 100644 index 00000000..bab7546f --- /dev/null +++ b/rl4co/models/zoo/mdam/encoder.py @@ -0,0 +1,101 @@ +from typing import Callable, Optional + +import torch +import torch.nn as nn + +from rl4co.models.nn.graph.attnnet import ( + MultiHeadAttentionLayer, + Normalization, + SkipConnection, +) +from rl4co.models.zoo.mdam.mha import MultiHeadAttentionMDAM + + +class MDAMGraphAttentionEncoder(nn.Module): + def __init__( + self, + num_heads, + embed_dim, + num_layers, + node_dim=None, + normalization="batch", + feedforward_hidden=512, + sdpa_fn: Optional[Callable] = None, + ): + super(MDAMGraphAttentionEncoder, self).__init__() + + # To map input to embedding space + self.init_embed = nn.Linear(node_dim, embed_dim) if node_dim is not None else None + + self.layers = nn.Sequential( + *( + MultiHeadAttentionLayer( + embed_dim, + num_heads, + feedforward_hidden, + normalization, + sdpa_fn=sdpa_fn, + ) + for _ in range(num_layers - 1) # because last layer is different + ) + ) + self.attention_layer = MultiHeadAttentionMDAM( + embed_dim, num_heads, sdpa_fn=sdpa_fn, last_one=True + ) + self.BN1 = Normalization(embed_dim, normalization) + self.projection = SkipConnection( + nn.Sequential( + nn.Linear(embed_dim, feedforward_hidden), + nn.ReLU(), + nn.Linear(feedforward_hidden, embed_dim), + ) + if feedforward_hidden > 0 + else nn.Linear(embed_dim, embed_dim) + ) + self.BN2 = Normalization(embed_dim, normalization) + + def forward(self, x, mask=None, return_transform_loss=False): + """ + Returns: + - h [batch_size, graph_size, embed_dim] + - attn [num_head, batch_size, graph_size, graph_size] + - V [num_head, batch_size, graph_size, key_dim] + - h_old [batch_size, graph_size, embed_dim] + """ + assert mask is None, "TODO mask not yet supported!" + + h_embeded = x + h_old = self.layers(h_embeded) + h_new, attn, V = self.attention_layer(h_old) + h = h_new + h_old + h = self.BN1(h) + h = self.projection(h) + h = self.BN2(h) + + return (h, h.mean(dim=1), attn, V, h_old) + + def change(self, attn, V, h_old, mask): + num_heads, batch_size, graph_size, feat_size = V.size() + attn = ( + mask.float() + .view(1, batch_size, 1, graph_size) + .repeat(num_heads, 1, graph_size, 1) + * attn + ) + attn = attn / ( + torch.sum(attn, dim=-1).view(num_heads, batch_size, graph_size, 1) + 1e-9 + ) + heads = torch.matmul(attn, V) + + h_new = torch.mm( + heads.permute(1, 2, 0, 3) + .contiguous() + .view(-1, self.attention_layer.num_heads * self.attention_layer.val_dim), + self.attention_layer.W_out.view(-1, self.attention_layer.embed_dim), + ).view(batch_size, graph_size, self.attention_layer.embed_dim) + h = h_new + h_old + h = self.BN1(h) + h = self.projection(h) + h = self.BN2(h) + + return (h, h.mean(dim=1)) diff --git a/rl4co/models/zoo/mdam/mha.py b/rl4co/models/zoo/mdam/mha.py new file mode 100644 index 00000000..4499faa0 --- /dev/null +++ b/rl4co/models/zoo/mdam/mha.py @@ -0,0 +1,87 @@ +import math + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class MultiHeadAttentionMDAM(nn.Module): + def __init__(self, embed_dim, n_heads, last_one=False, sdpa_fn=None): + super(MultiHeadAttentionMDAM, self).__init__() + + if sdpa_fn is not None: + log.warning("sdpa_fn is not used in this implementation") + + self.embed_dim = embed_dim + self.n_heads = n_heads + + self.norm_factor = 1 / math.sqrt(embed_dim) # See Attention is all you need + + self.W_query = nn.Parameter(torch.Tensor(n_heads, embed_dim, embed_dim)) + self.W_key = nn.Parameter(torch.Tensor(n_heads, embed_dim, embed_dim)) + self.W_val = nn.Parameter(torch.Tensor(n_heads, embed_dim, embed_dim)) + self.W_out = nn.Parameter(torch.Tensor(n_heads, embed_dim, embed_dim)) + + self.init_parameters() + self.last_one = last_one + + def init_parameters(self): + for param in self.parameters(): + stdv = 1.0 / math.sqrt(param.size(-1)) + param.data.uniform_(-stdv, stdv) + + def forward(self, q, h=None, mask=None): + if h is None: + h = q # compute self-attention + + # h should be (batch_size, graph_size, input_dim) + batch_size, graph_size, input_dim = h.size() + n_query = q.size(1) + assert q.size(0) == batch_size + assert q.size(2) == input_dim + assert input_dim == self.embed_dim, "Wrong embedding dimension of input" + + hflat = h.contiguous().view(-1, input_dim) + qflat = q.contiguous().view(-1, input_dim) + + # last dimension can be different for keys and values + shp = (self.n_heads, batch_size, graph_size, -1) + shp_q = (self.n_heads, batch_size, n_query, -1) + + # Calculate queries, (n_heads, n_query, graph_size, key/val_size) + Q = torch.matmul(qflat, self.W_query).view(shp_q) + # Calculate keys and values (n_heads, batch_size, graph_size, key/val_size) + K = torch.matmul(hflat, self.W_key).view(shp) + V = torch.matmul(hflat, self.W_val).view(shp) + + # Calculate compatibility (n_heads, batch_size, n_query, graph_size) + compatibility = self.norm_factor * torch.matmul(Q, K.transpose(2, 3)) + + # Optionally apply mask to prevent attention + if mask is not None: + mask = mask.view(1, batch_size, n_query, graph_size).expand_as(compatibility) + compatibility[mask] = float("-inf") + + attn = F.softmax(compatibility, dim=-1) + + # If there are nodes with no neighbours then softmax returns nan so we fix them to 0 + if mask is not None: + attnc = attn.clone() + attnc[mask] = 0 + attn = attnc + + heads = torch.matmul(attn, V) + + out = torch.mm( + heads.permute(1, 2, 0, 3) + .contiguous() + .view(-1, self.n_heads * self.embed_dim), + self.W_out.view(-1, self.embed_dim), + ).view(batch_size, n_query, self.embed_dim) + if self.last_one: + return (out, attn, V) + return out diff --git a/rl4co/models/zoo/mdam/model.py b/rl4co/models/zoo/mdam/model.py new file mode 100644 index 00000000..0b830866 --- /dev/null +++ b/rl4co/models/zoo/mdam/model.py @@ -0,0 +1,125 @@ +from functools import partial +from typing import Union + +import torch + +from torch.utils.data import DataLoader + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl import REINFORCE +from rl4co.models.rl.reinforce.baselines import ( + REINFORCEBaseline, + RolloutBaseline, + WarmupBaseline, +) +from rl4co.models.zoo.mdam.policy import MDAMPolicy + + +def rollout(self, model, env, batch_size=64, device="cpu", dataset=None): + """In this case the reward from the model is [batch, num_paths] + and the baseline takes the maximum reward from the model as the baseline. + https://github.com/liangxinedu/MDAM/blob/19b0bf813fb2dbec2fcde9e22eb50e04675400cd/train.py#L38C29-L38C33 + """ + # if dataset is None, use the dataset of the baseline + dataset = self.dataset if dataset is None else dataset + + model.eval() + model = model.to(device) + + def eval_model(batch): + with torch.inference_mode(): + batch = env.reset(batch.to(device)) + return model(batch, env, decode_type="greedy")["reward"].max(1).values + + dl = DataLoader(dataset, batch_size=batch_size, collate_fn=dataset.collate_fn) + + rewards = torch.cat([eval_model(batch) for batch in dl], 0) + return rewards + + +class MDAM(REINFORCE): + """Multi-Decoder Attention Model (MDAM) is a model + to train multiple diverse policies, which effectively increases the chance of finding + good solutions compared with existing methods that train only one policy. + Reference link: https://arxiv.org/abs/2012.10638; + Implementation reference: https://github.com/liangxinedu/MDAM. + + Args: + env: Environment to use for the algorithm + policy: Policy to use for the algorithm + baseline: REINFORCE baseline. Defaults to rollout (1 epoch of exponential, then greedy rollout baseline) + policy_kwargs: Keyword arguments for policy + baseline_kwargs: Keyword arguments for baseline + **kwargs: Keyword arguments passed to the superclass + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: MDAMPolicy = None, + baseline: Union[REINFORCEBaseline, str] = "rollout", + policy_kwargs={}, + baseline_kwargs={}, + **kwargs, + ): + if policy is None: + policy = MDAMPolicy(env_name=env.name, **policy_kwargs) + + super().__init__(env, policy, baseline, baseline_kwargs, **kwargs) + + # Change rollout of baseline to the rollout function + if isinstance(self.baseline, WarmupBaseline): + if isinstance(self.baseline.baseline, RolloutBaseline): + self.baseline.baseline.rollout = partial(rollout, self.baseline.baseline) + elif isinstance(self.baseline, RolloutBaseline): + self.baseline.rollout = partial(rollout, self.baseline) + + def calculate_loss( + self, + td, + batch, + policy_out, + reward=None, + log_likelihood=None, + ): + """Calculate loss for REINFORCE algorithm. + Same as in :class:`REINFORCE`, but the bl_val is calculated is simply unsqueezed to match + the reward shape (i.e., [batch, num_paths]) + + Args: + td: TensorDict containing the current state of the environment + batch: Batch of data. This is used to get the extra loss terms, e.g., REINFORCE baseline + policy_out: Output of the policy network + reward: Reward tensor. If None, it is taken from `policy_out` + log_likelihood: Log-likelihood tensor. If None, it is taken from `policy_out` + """ + # Extra: this is used for additional loss terms, e.g., REINFORCE baseline + extra = batch.get("extra", None) + reward = reward if reward is not None else policy_out["reward"] + log_likelihood = ( + log_likelihood if log_likelihood is not None else policy_out["log_likelihood"] + ) + + # REINFORCE baseline + bl_val, bl_loss = ( + self.baseline.eval(td, reward, self.env) if extra is None else (extra, 0) + ) + + # Main loss function + # reward: [batch, num_paths]. Note that the baseline value is the max reward + # if bl_val is a tensor, unsqueeze it to match the reward shape + if isinstance(bl_val, torch.Tensor): + if len(bl_val.shape) > 0: + bl_val = bl_val.unsqueeze(1) + advantage = reward - bl_val # advantage = reward - baseline + reinforce_loss = -(advantage * log_likelihood).mean() + loss = reinforce_loss + bl_loss + policy_out.update( + { + "loss": loss, + "reinforce_loss": reinforce_loss, + "bl_loss": bl_loss, + "bl_val": bl_val, + } + ) + return policy_out diff --git a/rl4co/models/zoo/mdam/policy.py b/rl4co/models/zoo/mdam/policy.py new file mode 100644 index 00000000..e9bad3ff --- /dev/null +++ b/rl4co/models/zoo/mdam/policy.py @@ -0,0 +1,90 @@ +from typing import Union + +from tensordict import TensorDict + +from rl4co.envs import RL4COEnvBase, get_env +from rl4co.models.common.constructive.autoregressive import AutoregressivePolicy +from rl4co.models.nn.env_embeddings import env_init_embedding +from rl4co.models.zoo.mdam.decoder import MDAMDecoder +from rl4co.models.zoo.mdam.encoder import MDAMGraphAttentionEncoder +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class MDAMPolicy(AutoregressivePolicy): + """Multi-Decoder Attention Model (MDAM) policy. + Args: + + """ + + def __init__( + self, + encoder: MDAMGraphAttentionEncoder = None, + decoder: MDAMDecoder = None, + embed_dim: int = 128, + env_name: str = "tsp", + num_encoder_layers: int = 3, + num_heads: int = 8, + normalization: str = "batch", + **decoder_kwargs, + ): + encoder = ( + MDAMGraphAttentionEncoder( + num_heads=num_heads, + embed_dim=embed_dim, + num_layers=num_encoder_layers, + normalization=normalization, + ) + if encoder is None + else encoder + ) + + decoder = ( + MDAMDecoder( + env_name=env_name, + embed_dim=embed_dim, + num_heads=num_heads, + **decoder_kwargs, + ) + if decoder is None + else decoder + ) + + super(MDAMPolicy, self).__init__( + env_name=env_name, encoder=encoder, decoder=decoder + ) + + self.init_embedding = env_init_embedding(env_name, {"embed_dim": embed_dim}) + + def forward( + self, + td: TensorDict, + env: Union[str, RL4COEnvBase] = None, + phase: str = "train", + return_actions: bool = False, + **decoder_kwargs, + ) -> TensorDict: + embedding = self.init_embedding(td) + encoded_inputs, _, attn, V, h_old = self.encoder(embedding) + + # Instantiate environment if needed + if isinstance(env, str) or env is None: + env_name = self.env_name if env is None else env + log.info(f"Instantiated environment not provided; instantiating {env_name}") + env = get_env(env_name) + + # Get decode type depending on phase + if decoder_kwargs.get("decode_type", None) is None: + decoder_kwargs["decode_type"] = getattr(self, f"{phase}_decode_type") + + reward, log_likelihood, kl_divergence, actions = self.decoder( + td, encoded_inputs, env, attn, V, h_old, self.encoder, **decoder_kwargs + ) + out = { + "reward": reward, + "log_likelihood": log_likelihood, + "entropy": kl_divergence, + "actions": actions if return_actions else None, + } + return out diff --git a/rl4co/models/zoo/mvmoe/__init__.py b/rl4co/models/zoo/mvmoe/__init__.py new file mode 100644 index 00000000..a26e33c4 --- /dev/null +++ b/rl4co/models/zoo/mvmoe/__init__.py @@ -0,0 +1,2 @@ +from .model import MVMoE_POMO +from .model import MVMoE_AM diff --git a/rl4co/models/zoo/mvmoe/model.py b/rl4co/models/zoo/mvmoe/model.py new file mode 100644 index 00000000..124402e4 --- /dev/null +++ b/rl4co/models/zoo/mvmoe/model.py @@ -0,0 +1,79 @@ +from typing import Union + +import torch.nn as nn + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl.reinforce.baselines import REINFORCEBaseline +from rl4co.models.zoo.am import AttentionModel, AttentionModelPolicy +from rl4co.models.zoo.pomo import POMO +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class MVMoE_POMO(POMO): + """MVMoE Model for neural combinatorial optimization based on POMO and REINFORCE + Please refer to Zhou et al. (2024) . + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: nn.Module = None, + policy_kwargs = {}, + baseline: str = "shared", + num_augment: int = 8, + augment_fn: Union[str, callable] = "dihedral8", + first_aug_identity: bool = True, + feats: list = None, + num_starts: int = None, + moe_kwargs: dict = None, + **kwargs, + ): + if moe_kwargs is None: + moe_kwargs = {"encoder": {"hidden_act": "ReLU", "num_experts": 4, "k": 2, "noisy_gating": True}, + "decoder": {"light_version": True, "num_experts": 4, "k": 2, "noisy_gating": True}} + + if policy is None: + policy_kwargs_ = { + "num_encoder_layers": 6, + "normalization": "instance", + "use_graph_context": False, + "moe_kwargs": moe_kwargs, + } + policy_kwargs.update(policy_kwargs_) + policy = AttentionModelPolicy(env_name=env.name, **policy_kwargs) + + # Initialize with the shared baseline + super(MVMoE_POMO, self).__init__(env, policy, policy_kwargs, baseline, num_augment, augment_fn, + first_aug_identity, feats, num_starts, **kwargs) + + +class MVMoE_AM(AttentionModel): + """MVMoE Model for neural combinatorial optimization based on AM and REINFORCE + Please refer to Zhou et al. (2024) . + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: AttentionModelPolicy = None, + baseline: Union[REINFORCEBaseline, str] = "rollout", + policy_kwargs={}, + baseline_kwargs={}, + moe_kwargs: dict = None, + **kwargs, + ): + if moe_kwargs is None: + moe_kwargs = {"encoder": {"hidden_act": "ReLU", "num_experts": 4, "k": 2, "noisy_gating": True}, + "decoder": {"light_version": True, "out_bias": False, "num_experts": 4, "k": 2, "noisy_gating": True}} + + if policy is None: + policy_kwargs_ = { + "moe_kwargs": moe_kwargs, + } + policy_kwargs.update(policy_kwargs_) + policy = AttentionModelPolicy(env_name=env.name, **policy_kwargs) + + # Initialize with the shared baseline + super(MVMoE_AM, self).__init__(env, policy, baseline, policy_kwargs, baseline_kwargs, **kwargs) diff --git a/rl4co/models/zoo/n2s/__init__.py b/rl4co/models/zoo/n2s/__init__.py new file mode 100644 index 00000000..77085511 --- /dev/null +++ b/rl4co/models/zoo/n2s/__init__.py @@ -0,0 +1,2 @@ +from .model import N2S +from .policy import N2SPolicy diff --git a/rl4co/models/zoo/n2s/decoder.py b/rl4co/models/zoo/n2s/decoder.py new file mode 100644 index 00000000..2c843a8b --- /dev/null +++ b/rl4co/models/zoo/n2s/decoder.py @@ -0,0 +1,261 @@ +import math + +import torch +import torch.nn as nn + +from tensordict import TensorDict +from torch import Tensor + +from rl4co.models.common.improvement.base import ImprovementDecoder +from rl4co.models.nn.attention import MultiHeadCompat +from rl4co.models.nn.mlp import MLP +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class NodePairRemovalDecoder(ImprovementDecoder): + """ + N2S Node-Pair Removal decoder based on Ma et al. (2022) + Given the environment state and the node embeddings (positional embeddings are discarded), compute the logits for + selecting a pair of pickup and delivery nodes for node pair removal from the current solution + + + Args: + embed_dim: Embedding dimension + num_heads: Number of attention heads + """ + + def __init__( + self, + embed_dim: int = 128, + num_heads: int = 4, + ): + super().__init__() + self.input_dim = embed_dim + self.n_heads = num_heads + self.hidden_dim = embed_dim + + assert embed_dim % num_heads == 0 + + self.W_Q = nn.Parameter( + torch.Tensor(self.n_heads, self.input_dim, self.hidden_dim) + ) + self.W_K = nn.Parameter( + torch.Tensor(self.n_heads, self.input_dim, self.hidden_dim) + ) + + self.agg = MLP(input_dim=2 * self.n_heads + 4, output_dim=1, num_neurons=[32, 32]) + + self.init_parameters() + + def init_parameters(self) -> None: + for param in self.parameters(): + stdv = 1.0 / math.sqrt(param.size(-1)) + param.data.uniform_(-stdv, stdv) + + def forward(self, td: TensorDict, final_h: Tensor, final_p: Tensor) -> Tensor: + """Compute the logits of the removing a node pair from the current solution + + Args: + td: TensorDict with the current environment state + final_h: final node embeddings + final_p: final positional embeddings + """ + + selection_recent = torch.cat( + (td["action_record"][:, -3:], td["action_record"].mean(1, True)), 1 + ) + solution = td["rec_current"] + + pre = solution.argsort() # pre=[1,2,0] + post = solution.gather( + 1, solution + ) # post=[1,2,0] # the second neighbour works better + batch_size, graph_size_plus1, input_dim = final_h.size() + + hflat = final_h.contiguous().view(-1, input_dim) ################# reshape + + shp = (self.n_heads, batch_size, graph_size_plus1, self.hidden_dim) + + # Calculate queries, (n_heads, batch_size, graph_size+1, key_size) + hidden_Q = torch.matmul(hflat, self.W_Q).view(shp) + hidden_K = torch.matmul(hflat, self.W_K).view(shp) + + Q_pre = hidden_Q.gather( + 2, pre.view(1, batch_size, graph_size_plus1, 1).expand_as(hidden_Q) + ) + K_post = hidden_K.gather( + 2, post.view(1, batch_size, graph_size_plus1, 1).expand_as(hidden_Q) + ) + + compatibility = ( + (Q_pre * hidden_K).sum(-1) + + (hidden_Q * K_post).sum(-1) + - (Q_pre * K_post).sum(-1) + )[ + :, :, 1: + ] # (n_heads, batch_size, graph_size) (12) + + compatibility_pairing = torch.cat( + ( + compatibility[:, :, : graph_size_plus1 // 2], + compatibility[:, :, graph_size_plus1 // 2 :], + ), + 0, + ) # (n_heads*2, batch_size, graph_size/2) + + compatibility_pairing = self.agg( + torch.cat( + ( + compatibility_pairing.permute(1, 2, 0), + selection_recent.permute(0, 2, 1), + ), + -1, + ) + ).squeeze() # (batch_size, graph_size/2) + + return compatibility_pairing + + +class NodePairReinsertionDecoder(ImprovementDecoder): + """ + N2S Node-Pair Reinsertion decoder based on Ma et al. (2022) + Given the environment state, the node embeddings (positional embeddings are discarded), and the removed node from the NodePairRemovalDecoder, + compute the logits for finding places to re-insert the removed pair of pickup and delivery nodes to form a new solution + + + Args: + embed_dim: Embedding dimension + num_heads: Number of attention heads + """ + + def __init__( + self, + embed_dim: int = 128, + num_heads: int = 4, + ): + super().__init__() + self.input_dim = embed_dim + self.n_heads = num_heads + self.hidden_dim = embed_dim + + assert embed_dim % num_heads == 0 + + self.compater_insert1 = MultiHeadCompat( + num_heads, embed_dim, embed_dim, embed_dim, embed_dim + ) + + self.compater_insert2 = MultiHeadCompat( + num_heads, embed_dim, embed_dim, embed_dim, embed_dim + ) + + self.agg = MLP(input_dim=4 * self.n_heads, output_dim=1, num_neurons=[32, 32]) + + def forward(self, td: TensorDict, final_h: Tensor, final_p: Tensor) -> torch.Tensor: + action_removal = td["action"] + solution = td["rec_current"] + + pos_pickup = (1 + action_removal).view(-1) + pos_delivery = pos_pickup + solution.size(-1) // 2 + + batch_size, graph_size_plus1, input_dim = final_h.size() + shp = (batch_size, graph_size_plus1, graph_size_plus1, self.n_heads) + shp_p = (batch_size, -1, 1, self.n_heads) + shp_d = (batch_size, 1, -1, self.n_heads) + + arange = torch.arange(batch_size, device=final_h.device) + h_pickup = final_h[arange, pos_pickup].unsqueeze(1) # (batch_size, 1, input_dim) + h_delivery = final_h[arange, pos_delivery].unsqueeze( + 1 + ) # (batch_size, 1, input_dim) + h_K_neibour = final_h.gather( + 1, solution.view(batch_size, graph_size_plus1, 1).expand_as(final_h) + ) # (batch_size, graph_size+1, input_dim) + + compatibility_pickup_pre = ( + self.compater_insert1( + h_pickup, final_h + ) # (n_heads, batch_size, 1, graph_size+1) + .permute(1, 2, 3, 0) # (batch_size, 1, graph_size+1, n_heads) + .view(shp_p) # (batch_size, graph_size+1, 1, n_heads) + .expand(shp) # (batch_size, graph_size+1, graph_size+1, n_heads) + ) + compatibility_pickup_post = ( + self.compater_insert2(h_pickup, h_K_neibour) + .permute(1, 2, 3, 0) + .view(shp_p) + .expand(shp) + ) + compatibility_delivery_pre = ( + self.compater_insert1( + h_delivery, final_h + ) # (n_heads, batch_size, 1, graph_size+1) + .permute(1, 2, 3, 0) # (batch_size, 1, graph_size+1, n_heads) + .view(shp_d) # (batch_size, 1, graph_size+1, n_heads) + .expand(shp) # (batch_size, graph_size+1, graph_size+1, n_heads) + ) + compatibility_delivery_post = ( + self.compater_insert2(h_delivery, h_K_neibour) + .permute(1, 2, 3, 0) + .view(shp_d) + .expand(shp) + ) + + compatibility = self.agg( + torch.cat( + ( + compatibility_pickup_pre, + compatibility_pickup_post, + compatibility_delivery_pre, + compatibility_delivery_post, + ), + -1, + ) + ).squeeze() + + return compatibility # (batch_size, graph_size+1, graph_size+1) + + +class CriticDecoder(nn.Module): + def __init__(self, input_dim: int, dropout_rate=0.01) -> None: + super().__init__() + self.input_dim = input_dim + + self.project_graph = nn.Linear(self.input_dim, self.input_dim // 2) + self.project_node = nn.Linear(self.input_dim, self.input_dim // 2) + + self.MLP = MLP( + input_dim=input_dim + 1, + output_dim=1, + num_neurons=[input_dim, input_dim // 2], + dropout_probs=[dropout_rate, 0.0], + ) + + def forward(self, x: torch.Tensor, best_cost: torch.Tensor) -> torch.Tensor: + # h_wave: (batch_size, graph_size+1, input_size) + mean_pooling = x.mean(1) # mean Pooling (batch_size, input_size) + graph_feature: torch.Tensor = self.project_graph(mean_pooling)[ + :, None, : + ] # (batch_size, 1, input_dim/2) + node_feature: torch.Tensor = self.project_node( + x + ) # (batch_size, graph_size+1, input_dim/2) + + # pass through value_head, get estimated value + fusion = node_feature + graph_feature.expand_as( + node_feature + ) # (batch_size, graph_size+1, input_dim/2) + + fusion_feature = torch.cat( + ( + fusion.mean(1), + fusion.max(1)[0], # max_pooling + best_cost.to(x.device), + ), + -1, + ) # (batch_size, input_dim + 1) + + value = self.MLP(fusion_feature) + + return value diff --git a/rl4co/models/zoo/n2s/encoder.py b/rl4co/models/zoo/n2s/encoder.py new file mode 100644 index 00000000..c219c3c3 --- /dev/null +++ b/rl4co/models/zoo/n2s/encoder.py @@ -0,0 +1,217 @@ +import math + +from typing import Callable, Tuple + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from torch import Tensor + +from rl4co.models.common import ImprovementEncoder +from rl4co.models.nn.attention import MultiHeadCompat +from rl4co.models.nn.ops import AdaptiveSequential, Normalization +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class Synth_Attention(nn.Module): + def __init__(self, n_heads: int, input_dim: int) -> None: + super().__init__() + + hidden_dim = input_dim // n_heads + + self.n_heads = n_heads + self.input_dim = input_dim + self.hidden_dim = hidden_dim + + self.W_query = nn.Parameter(torch.Tensor(n_heads, input_dim, hidden_dim)) + self.W_key = nn.Parameter(torch.Tensor(n_heads, input_dim, hidden_dim)) + self.W_val = nn.Parameter(torch.Tensor(n_heads, input_dim, hidden_dim)) + + self.score_aggr = nn.Sequential( + nn.Linear(2 * n_heads, 2 * n_heads), + nn.ReLU(inplace=True), + nn.Linear(2 * n_heads, n_heads), + ) + + self.W_out = nn.Parameter(torch.Tensor(n_heads, hidden_dim, input_dim)) + + self.init_parameters() + + # used for init nn.Parameter + def init_parameters(self): + for param in self.parameters(): + stdv = 1.0 / math.sqrt(param.size(-1)) + param.data.uniform_(-stdv, stdv) + + def forward( + self, h_fea: torch.Tensor, aux_att_score: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + # h should be (batch_size, n_query, input_dim) + batch_size, n_query, input_dim = h_fea.size() + + hflat = h_fea.contiguous().view(-1, input_dim) + + shp = (self.n_heads, batch_size, n_query, self.hidden_dim) + + # Calculate queries, (n_heads, batch_size, n_query, hidden_dim) + Q = torch.matmul(hflat, self.W_query).view(shp) + K = torch.matmul(hflat, self.W_key).view(shp) + V = torch.matmul(hflat, self.W_val).view(shp) + + # Calculate compatibility (n_heads, batch_size, n_query, n_key) + compatibility = torch.cat((torch.matmul(Q, K.transpose(2, 3)), aux_att_score), 0) + + attn_raw = compatibility.permute( + 1, 2, 3, 0 + ) # (batch_size, n_query, n_key, n_heads) + attn = self.score_aggr(attn_raw).permute( + 3, 0, 1, 2 + ) # (n_heads, batch_size, n_query, n_key) + heads = torch.matmul( + F.softmax(attn, dim=-1), V + ) # (n_heads, batch_size, n_query, hidden_dim) + + h_wave = torch.mm( + heads.permute(1, 2, 0, 3) # (batch_size, n_query, n_heads, hidden_dim) + .contiguous() + .view( + -1, self.n_heads * self.hidden_dim + ), # (batch_size * n_query, n_heads * hidden_dim) + self.W_out.view(-1, self.input_dim), # (n_heads * hidden_dim, input_dim) + ).view(batch_size, n_query, self.input_dim) + + return h_wave, aux_att_score + + +class SynthAttNormSubLayer(nn.Module): + def __init__(self, n_heads: int, input_dim: int, normalization: str) -> None: + super().__init__() + + self.SynthAtt = Synth_Attention(n_heads, input_dim) + + self.Norm = Normalization(input_dim, normalization) + + __call__: Callable[..., Tuple[torch.Tensor, torch.Tensor]] + + def forward( + self, h_fea: torch.Tensor, aux_att_score: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + # Attention and Residual connection + h_wave, aux_att_score = self.SynthAtt(h_fea, aux_att_score) + + # Normalization + return self.Norm(h_wave + h_fea), aux_att_score + + +class FFNormSubLayer(nn.Module): + def __init__( + self, input_dim: int, feed_forward_hidden: int, normalization: str + ) -> None: + super().__init__() + + self.FF = ( + nn.Sequential( + nn.Linear(input_dim, feed_forward_hidden, bias=False), + nn.ReLU(inplace=True), + nn.Linear(feed_forward_hidden, input_dim, bias=False), + ) + if feed_forward_hidden > 0 + else nn.Linear(input_dim, input_dim, bias=False) + ) + + self.Norm = Normalization(input_dim, normalization) + + __call__: Callable[..., torch.Tensor] + + def forward(self, input: torch.Tensor) -> torch.Tensor: + # FF and Residual connection + out = self.FF(input) + # Normalization + return self.Norm(out + input) + + +class N2SEncoderLayer(nn.Module): + def __init__( + self, n_heads: int, input_dim: int, feed_forward_hidden: int, normalization: str + ) -> None: + super().__init__() + + self.SynthAttNorm_sublayer = SynthAttNormSubLayer( + n_heads, input_dim, normalization + ) + + self.FFNorm_sublayer = FFNormSubLayer( + input_dim, feed_forward_hidden, normalization + ) + + __call__: Callable[..., Tuple[torch.Tensor, torch.Tensor]] + + def forward( + self, h_fea: torch.Tensor, aux_att_score: torch.Tensor + ) -> Tuple[torch.Tensor, torch.Tensor]: + h_wave, aux_att_score = self.SynthAttNorm_sublayer(h_fea, aux_att_score) + return self.FFNorm_sublayer(h_wave), aux_att_score + + +class N2SEncoder(ImprovementEncoder): + """Neural Neighborhood Search Encoder as in Ma et al. (2022) + First embed the input and then process it with a Graph AttepdN2ntion Network. + + Args: + embed_dim: Dimension of the embedding space + init_embedding: Module to use for the initialization of the node embeddings + pos_embedding: Module to use for the initialization of the positional embeddings + env_name: Name of the environment used to initialize embeddings + pos_type: Name of the used positional encoding method (CPE or APE) + num_heads: Number of heads in the attention layers + num_layers: Number of layers in the attention network + normalization: Normalization type in the attention layers + feedforward_hidden: Hidden dimension in the feedforward layers + """ + + def __init__( + self, + embed_dim: int = 128, + init_embedding: nn.Module = None, + pos_embedding: nn.Module = None, + env_name: str = "pdp_ruin_repair", + pos_type: str = "CPE", + num_heads: int = 4, + num_layers: int = 3, + normalization: str = "layer", + feedforward_hidden: int = 128, + ): + super(N2SEncoder, self).__init__( + embed_dim=embed_dim, + init_embedding=init_embedding, + pos_embedding=pos_embedding, + env_name=env_name, + pos_type=pos_type, + num_heads=num_heads, + num_layers=num_layers, + normalization=normalization, + feedforward_hidden=feedforward_hidden, + ) + + self.pos_net = MultiHeadCompat(num_heads, embed_dim, feedforward_hidden) + + self.net = AdaptiveSequential( + *( + N2SEncoderLayer( + num_heads, + embed_dim, + feedforward_hidden, + normalization, + ) + for _ in range(num_layers) + ) + ) + + def _encoder_forward(self, init_h: Tensor, init_p: Tensor) -> Tuple[Tensor, Tensor]: + embed_p = self.pos_net(init_p) + final_h, final_p = self.net(init_h, embed_p) + + return final_h, final_p diff --git a/rl4co/models/zoo/n2s/model.py b/rl4co/models/zoo/n2s/model.py new file mode 100644 index 00000000..d3080e4a --- /dev/null +++ b/rl4co/models/zoo/n2s/model.py @@ -0,0 +1,62 @@ +import torch.nn as nn + +from rl4co.envs import RL4COEnvBase +from rl4co.models.nn.graph.attnnet import MultiHeadAttentionLayer +from rl4co.models.rl import n_step_PPO +from rl4co.models.rl.common.critic import CriticNetwork +from rl4co.models.zoo.n2s.decoder import CriticDecoder +from rl4co.models.zoo.n2s.policy import N2SPolicy +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class N2S(n_step_PPO): + """N2S Model based on n_step Proximal Policy Optimization (PPO) with an N2S model policy. + We default to the N2S model policy and the improvement Critic Network. + + Args: + env: Environment to use for the algorithm + policy: Policy to use for the algorithm + critic: Critic to use for the algorithm + policy_kwargs: Keyword arguments for policy + critic_kwargs: Keyword arguments for critic + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: nn.Module = None, + critic: CriticNetwork = None, + policy_kwargs: dict = {}, + critic_kwargs: dict = {}, + **kwargs, + ): + if policy is None: + policy = N2SPolicy(env_name=env.name, **policy_kwargs) + + if critic is None: + embed_dim = ( + policy_kwargs["embed_dim"] if "embed_dim" in policy_kwargs else 128 + ) # the critic's embed_dim must be as policy's + + encoder = MultiHeadAttentionLayer( + embed_dim, + critic_kwargs["num_heads"] if "num_heads" in critic_kwargs else 4, + critic_kwargs["feedforward_hidden"] + if "feedforward_hidden" in critic_kwargs + else 128, + critic_kwargs["normalization"] + if "normalization" in critic_kwargs + else "layer", + bias=False, + ) + value_head = CriticDecoder(embed_dim) + + critic = CriticNetwork( + encoder=encoder, + value_head=value_head, + customized=True, + ) + + super().__init__(env, policy, critic, **kwargs) diff --git a/rl4co/models/zoo/n2s/policy.py b/rl4co/models/zoo/n2s/policy.py new file mode 100644 index 00000000..02611f42 --- /dev/null +++ b/rl4co/models/zoo/n2s/policy.py @@ -0,0 +1,220 @@ +from typing import Union + +import torch +import torch.nn as nn + +from tensordict import TensorDict + +from rl4co.envs import RL4COEnvBase, get_env +from rl4co.models.common.improvement.base import ImprovementPolicy +from rl4co.models.zoo.n2s.decoder import ( + NodePairReinsertionDecoder, + NodePairRemovalDecoder, +) +from rl4co.models.zoo.n2s.encoder import N2SEncoder +from rl4co.utils.decoding import DecodingStrategy, get_decoding_strategy +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class N2SPolicy(ImprovementPolicy): + """ + N2S Policy based on Ma et al. (2022) + This model first encodes the input graph and current solution using a N2S encoder (:class:`N2SEncoder`) + and then decodes the node-pair removal and reinsertion action using + the Node-Pair Removal (:class:`NodePairRemovalDecoder`) and Reinsertion (:class:`NodePairReinsertionDecoder`) decoders + + Args: + embed_dim: Dimension of the node embeddings + num_encoder_layers: Number of layers in the encoder + num_heads: Number of heads in the attention layers + normalization: Normalization type in the attention layers + feedforward_hidden: Dimension of the hidden layer in the feedforward network + env_name: Name of the environment used to initialize embeddings + pos_type: Name of the used positional encoding method (CPE or APE) + init_embedding: Module to use for the initialization of the embeddings + pos_embedding: Module to use for the initialization of the positional embeddings + temperature: Temperature for the softmax + tanh_clipping: Tanh clipping value (see Bello et al., 2016) + train_decode_type: Type of decoding to use during training + val_decode_type: Type of decoding to use during validation + test_decode_type: Type of decoding to use during testing + """ + + def __init__( + self, + embed_dim: int = 128, + num_encoder_layers: int = 3, + num_heads: int = 4, + normalization: str = "layer", + feedforward_hidden: int = 128, + env_name: str = "pdp_ruin_repair", + pos_type: str = "CPE", + init_embedding: nn.Module = None, + pos_embedding: nn.Module = None, + temperature: float = 1.0, + tanh_clipping: float = 6.0, + train_decode_type: str = "sampling", + val_decode_type: str = "sampling", + test_decode_type: str = "sampling", + ): + super(N2SPolicy, self).__init__() + + self.env_name = env_name + + # Encoder and decoder + self.encoder = N2SEncoder( + embed_dim=embed_dim, + init_embedding=init_embedding, + pos_embedding=pos_embedding, + env_name=env_name, + pos_type=pos_type, + num_heads=num_heads, + num_layers=num_encoder_layers, + normalization=normalization, + feedforward_hidden=feedforward_hidden, + ) + + self.removal_decoder = NodePairRemovalDecoder( + embed_dim=embed_dim, num_heads=num_heads + ) + + self.reinsertion_decoder = NodePairReinsertionDecoder( + embed_dim=embed_dim, num_heads=num_heads + ) + + self.project_graph = nn.Linear(embed_dim, embed_dim, bias=False) + self.project_node = nn.Linear(embed_dim, embed_dim, bias=False) + + # Decoding strategies + self.temperature = temperature + self.tanh_clipping = tanh_clipping + self.train_decode_type = train_decode_type + self.val_decode_type = val_decode_type + self.test_decode_type = test_decode_type + + def forward( + self, + td: TensorDict, + env: Union[str, RL4COEnvBase] = None, + phase: str = "train", + return_actions: bool = False, + return_embeds: bool = False, + only_return_embed: bool = False, + actions=None, + **decoding_kwargs, + ) -> dict: + """Forward pass of the policy. + + Args: + td: TensorDict containing the environment state + env: Environment to use for decoding. If None, the environment is instantiated from `env_name`. Note that + it is more efficient to pass an already instantiated environment each time for fine-grained control + phase: Phase of the algorithm (train, val, test) + return_actions: Whether to return the actions + actions: Actions to use for evaluating the policy. + If passed, use these actions instead of sampling from the policy to calculate log likelihood + decoding_kwargs: Keyword arguments for the decoding strategy. See :class:`rl4co.utils.decoding.DecodingStrategy` for more information. + + Returns: + out: Dictionary containing the reward, log likelihood, and optionally the actions and entropy + """ + + # Encoder: get encoder output and initial embeddings from initial state + h_wave, final_p = self.encoder(td) + if only_return_embed: + return {"embeds": h_wave.detach()} + final_h = ( + self.project_node(h_wave) + self.project_graph(h_wave.max(1)[0])[:, None, :] + ) + + # Instantiate environment if needed + if isinstance(env, str) or env is None: + env_name = self.env_name if env is None else env + log.info(f"Instantiated environment not provided; instantiating {env_name}") + env = get_env(env_name) + + # Get decode type depending on phase and whether actions are passed for evaluation + decode_type = decoding_kwargs.pop("decode_type", None) + if actions is not None: + decode_type = "evaluate" + elif decode_type is None: + decode_type = getattr(self, f"{phase}_decode_type") + + # Setup decoding strategy + # we pop arguments that are not part of the decoding strategy + decode_strategy: DecodingStrategy = get_decoding_strategy( + decode_type, + temperature=decoding_kwargs.pop("temperature", self.temperature), + tanh_clipping=decoding_kwargs.pop("tanh_clipping", self.tanh_clipping), + mask_logits=True, + improvement_method_mode=True, + **decoding_kwargs, + ) + + ## action 1 + + # Perform the decoding + logits = self.removal_decoder(td, final_h, final_p) + + # Get mask + mask = torch.ones_like(td["action_record"][:, 0], device=td.device).bool() + if "action" in td.keys(): + mask = mask.scatter(1, td["action"][:, :1], 0) + + # Get action and log-likelihood + logprob_removal, action_removal = decode_strategy.step( + logits, + mask, + action=actions[:, 0] if actions is not None else None, + ) + action_removal = action_removal.unsqueeze(-1) + if phase == "train": + selected_log_ll_action1 = logprob_removal.gather(1, action_removal) + + ## action 2 + td.set("action", action_removal) + + # Perform the decoding + batch_size, seq_length = td["rec_current"].size() + logits = self.reinsertion_decoder(td, final_h, final_p).view(batch_size, -1) + + # Get mask + mask = env.get_mask(action_removal + 1, td).view(batch_size, -1) + # Get action and log-likelihood + logprob_reinsertion, action_reinsertion = decode_strategy.step( + logits, + mask, + action=actions[:, 1] * seq_length + actions[:, 2] + if actions is not None + else None, + ) + action_reinsertion = action_reinsertion.unsqueeze(-1) + if phase == "train": + selected_log_ll_action2 = logprob_reinsertion.gather(1, action_reinsertion) + + ## return + N2S_action = torch.cat( + ( + action_removal.view(batch_size, -1), + action_reinsertion // seq_length, + action_reinsertion % seq_length, + ), + -1, + ) + if phase == "train": + log_likelihood = selected_log_ll_action1 + selected_log_ll_action2 + else: + log_likelihood = torch.zeros(batch_size, device=td.device) + + outdict = {"log_likelihood": log_likelihood, "cost_bsf": td["cost_bsf"]} + td.set("action", N2S_action) + + if return_embeds: + outdict["embeds"] = h_wave.detach() + + if return_actions: + outdict["actions"] = N2S_action + + return outdict diff --git a/rl4co/models/zoo/nargnn/__init__.py b/rl4co/models/zoo/nargnn/__init__.py new file mode 100644 index 00000000..9da8ee9b --- /dev/null +++ b/rl4co/models/zoo/nargnn/__init__.py @@ -0,0 +1,2 @@ +from .encoder import NARGNNEncoder +from .policy import NARGNNPolicy diff --git a/rl4co/models/zoo/nargnn/encoder.py b/rl4co/models/zoo/nargnn/encoder.py new file mode 100644 index 00000000..0ace632b --- /dev/null +++ b/rl4co/models/zoo/nargnn/encoder.py @@ -0,0 +1,212 @@ +from typing import Callable, Optional, Union + +import torch +import torch.nn as nn + +from tensordict import TensorDict +from torch import Tensor + +from rl4co.models.common.constructive.nonautoregressive import NonAutoregressiveEncoder +from rl4co.models.nn.env_embeddings import env_edge_embedding, env_init_embedding +from rl4co.models.nn.graph.gnn import GNNEncoder + +try: + from torch_geometric.data import Batch +except ImportError: + # `Batch` is referred to only as type notations in this file + Batch = None + + +class EdgeHeatmapGenerator(nn.Module): + """MLP for converting edge embeddings to heatmaps. + + Args: + embed_dim: Dimension of the embeddings + num_layers: The number of linear layers in the network. + act_fn: Activation function. Defaults to "silu". + linear_bias: Use bias in linear layers. Defaults to True. + undirected_graph: Whether the graph is undirected. Defaults to True. + """ + + def __init__( + self, + embed_dim: int, + num_layers: int, + act_fn: Union[str, Callable] = "silu", + linear_bias: bool = True, + undirected_graph: bool = True, + ) -> None: + super(EdgeHeatmapGenerator, self).__init__() + + self.linears = nn.ModuleList( + [ + nn.Linear(embed_dim, embed_dim, bias=linear_bias) + for _ in range(num_layers - 1) + ] + ) + self.output = nn.Linear(embed_dim, 1, bias=linear_bias) + + self.act = getattr(nn.functional, act_fn) if isinstance(act_fn, str) else act_fn + + self.undirected_graph = undirected_graph + + def forward(self, graph: Batch) -> Tensor: # type: ignore + # do not reuse the input value + edge_attr = graph.edge_attr # type: ignore + for layer in self.linears: + edge_attr = self.act(layer(edge_attr)) + graph.edge_attr = torch.sigmoid(self.output(edge_attr)) # type: ignore + + heatmap_logits = self._make_heatmap_logits(graph) + return heatmap_logits + + def _make_heatmap_logits(self, batch_graph: Batch) -> Tensor: # type: ignore + graphs = batch_graph.to_data_list() + device = graphs[0].edge_attr.device + batch_size = len(graphs) + num_nodes = graphs[0].x.shape[0] + + heatmap = torch.zeros( + (batch_size, num_nodes, num_nodes), + device=device, + dtype=graphs[0].edge_attr.dtype, + ) + + for index, graph in enumerate(graphs): + edge_index, edge_attr = graph.edge_index, graph.edge_attr + heatmap[index, edge_index[0], edge_index[1]] = edge_attr.flatten() + + # This is commented out, because it undo the some of the sparsification. + # if self.undirected_graph: + # heatmap = (heatmap + heatmap.transpose(1, 2)) * 0.5 + + heatmap += 1e-10 if heatmap.dtype != torch.float16 else 3e-8 + # 3e-8 is the smallest positive number such that log(3e-8) is not -inf + heatmap_logits = torch.log(heatmap) + + return heatmap_logits + + +class NARGNNEncoder(NonAutoregressiveEncoder): + """Anisotropic Graph Neural Network encoder with edge-gating mechanism as in Joshi et al. (2022), and used in DeepACO (Ye et al., 2023). + This creates a heatmap of NxN for N nodes (i.e., heuristic) that models the probability to go from one node to another for all nodes. + This model utilizes a multi-layer perceptron (MLP) approach to predict edge attributes directly from the input graph features, + which are then transformed into a heatmap representation to facilitate the decoding of the solution. The decoding process + is managed by a specified strategy which could vary from simple greedy selection to more complex sampling methods. + + Tip: + This decoder's performance heavily relies on the ability of the MLP to capture the dependencies between different + parts of the solution without the iterative refinement provided by autoregressive models. It is particularly useful + in scenarios where the solution space can be effectively explored in a parallelized manner or when the solution components + are largely independent. + + Args: + embed_dim: Dimension of the node embeddings + env_name: Name of the environment used to initialize embeddings + num_layers: Number of layers in the encoder + init_embedding: Model to use for the initial embedding. If None, use the default embedding for the environment + edge_embedding: Model to use for the edge embedding. If None, use the default embedding for the environment + graph_network: Model to use for the graph network. If None, use the default network for the environment + heatmap_generator: Model to use for the heatmap generator. If None, use the default network for the environment + num_layers_heatmap_generator: Number of layers in the heatmap generator + num_layers_graph_encoder: Number of layers in the graph encoder + act_fn: The activation function to use in each GNNLayer, see https://pytorch.org/docs/stable/nn.functional.html#non-linear-activation-functions for available options. Defaults to 'silu'. + agg_fn: The aggregation function to use in each GNNLayer for pooling features. Options: 'add', 'mean', 'max'. Defaults to 'mean'. + linear_bias: Use bias in linear layers. Defaults to True. + k_sparse: Number of edges to keep for each node. Defaults to None. + """ + + def __init__( + self, + embed_dim: int = 64, + env_name: str = "tsp", + # TODO: pass network + init_embedding: Optional[nn.Module] = None, + edge_embedding: Optional[nn.Module] = None, + graph_network: Optional[nn.Module] = None, + heatmap_generator: Optional[nn.Module] = None, + num_layers_heatmap_generator: int = 5, + num_layers_graph_encoder: int = 15, + act_fn="silu", + agg_fn="mean", + linear_bias: bool = True, + k_sparse: Optional[int] = None, + ): + super(NonAutoregressiveEncoder, self).__init__() + self.env_name = env_name + + self.init_embedding = ( + env_init_embedding(self.env_name, {"embed_dim": embed_dim}) + if init_embedding is None + else init_embedding + ) + + self.edge_embedding = ( + env_edge_embedding(self.env_name, {"embed_dim": embed_dim, "k_sparse": k_sparse}) + if edge_embedding is None + else edge_embedding + ) + + self.graph_network = ( + GNNEncoder( + embed_dim=embed_dim, + num_layers=num_layers_graph_encoder, + act_fn=act_fn, + agg_fn=agg_fn, + ) + if graph_network is None + else graph_network + ) + + self.heatmap_generator = ( + EdgeHeatmapGenerator( + embed_dim=embed_dim, + num_layers=num_layers_heatmap_generator, + linear_bias=linear_bias, + ) + if heatmap_generator is None + else heatmap_generator + ) + + def forward(self, td: TensorDict): + """Forward pass of the encoder. + Transform the input TensorDict into the latent representation. + """ + # Transfer to embedding space + node_embed = self.init_embedding(td) + graph = self.edge_embedding(td, node_embed) + + # Process embedding into graph + # TODO: standardize? + graph.x, graph.edge_attr = self.graph_network( + graph.x, graph.edge_index, graph.edge_attr + ) + + # Generate heatmap logits + heatmap_logits = self.heatmap_generator(graph) + + # Return latent representation (i.e. heatmap logits) and initial embeddings + return heatmap_logits, node_embed + + +class NARGNNNodeEncoder(NARGNNEncoder): + """In this case, we just use the node embeddings from the graph + without transforming them into a heatmap. + """ + + def forward(self, td: TensorDict): + # Transfer to embedding space + node_embed = self.init_embedding(td) + graph = self.edge_embedding(td, node_embed) + + # Process embedding into graph + # TODO: standardize? + graph.x, graph.edge_attr = self.graph_network( + graph.x, graph.edge_index, graph.edge_attr + ) + + proc_embeds = graph.x + batch_size = node_embed.shape[0] + # reshape proc_embeds from [bs*n, h] to [bs, n, h] + proc_embeds = proc_embeds.reshape(batch_size, -1, proc_embeds.shape[1]) + return proc_embeds, node_embed diff --git a/rl4co/models/zoo/nargnn/policy.py b/rl4co/models/zoo/nargnn/policy.py new file mode 100644 index 00000000..5d83cb73 --- /dev/null +++ b/rl4co/models/zoo/nargnn/policy.py @@ -0,0 +1,107 @@ +from typing import Optional + +import torch.nn as nn + +from rl4co.models.common.constructive.nonautoregressive import ( + NonAutoregressiveDecoder, + NonAutoregressiveEncoder, + NonAutoregressivePolicy, +) +from rl4co.utils.pylogger import get_pylogger + +from .encoder import NARGNNEncoder + +log = get_pylogger(__name__) + + +class NARGNNPolicy(NonAutoregressivePolicy): + """ + Base Non-autoregressive policy for NCO construction methods. + This creates a heatmap of NxN for N nodes (i.e., heuristic) that models the probability to go from one node to another for all nodes. + + The policy performs the following steps: + 1. Encode the environment initial state into node embeddings + 2. Decode (non-autoregressively) to construct the solution to the NCO problem + + Warning: + The effectiveness of the non-autoregressive approach can vary significantly across different problem types and configurations. + It may require careful tuning of the model architecture and decoding strategy to achieve competitive results. + + Args: + encoder: Encoder module. Can be passed by sub-classes + decoder: Decoder module. Note that this moule defaults to the non-autoregressive decoder + embed_dim: Dimension of the embeddings + env_name: Name of the environment used to initialize embeddings + init_embedding: Model to use for the initial embedding. If None, use the default embedding for the environment + edge_embedding: Model to use for the edge embedding. If None, use the default embedding for the environment + graph_network: Model to use for the graph network. If None, use the default embedding for the environment + heatmap_generator: Model to use for the heatmap generator. If None, use the default embedding for the environment + num_layers_heatmap_generator: Number of layers in the heatmap generator + num_layers_graph_encoder: Number of layers in the graph encoder + act_fn: Activation function to use in the encoder + agg_fn: Aggregation function to use in the encoder + linear_bias: Whether to use bias in the encoder + train_decode_type: Type of decoding during training + val_decode_type: Type of decoding during validation + test_decode_type: Type of decoding during testing + **constructive_policy_kw: Unused keyword arguments + """ + + def __init__( + self, + encoder: Optional[NonAutoregressiveEncoder] = None, + decoder: Optional[NonAutoregressiveDecoder] = None, + embed_dim: int = 64, + env_name: str = "tsp", + init_embedding: Optional[nn.Module] = None, + edge_embedding: Optional[nn.Module] = None, + graph_network: Optional[nn.Module] = None, + heatmap_generator: Optional[nn.Module] = None, + num_layers_heatmap_generator: int = 5, + num_layers_graph_encoder: int = 15, + act_fn="silu", + agg_fn="mean", + linear_bias: bool = True, + train_decode_type: str = "multistart_sampling", + val_decode_type: str = "multistart_greedy", + test_decode_type: str = "multistart_greedy", + **constructive_policy_kw, + ): + if len(constructive_policy_kw) > 0: + log.warn(f"Unused kwargs: {constructive_policy_kw}") + + if encoder is None: + encoder = NARGNNEncoder( + embed_dim=embed_dim, + env_name=env_name, + init_embedding=init_embedding, + edge_embedding=edge_embedding, + graph_network=graph_network, + heatmap_generator=heatmap_generator, + num_layers_heatmap_generator=num_layers_heatmap_generator, + num_layers_graph_encoder=num_layers_graph_encoder, + act_fn=act_fn, + agg_fn=agg_fn, + linear_bias=linear_bias, + ) + + # The decoder generates logits given the current td and heatmap + if decoder is None: + decoder = NonAutoregressiveDecoder() + else: + # check if the decoder has trainable parameters + if any(p.requires_grad for p in decoder.parameters()): + log.error( + "The decoder contains trainable parameters. This should not happen in a non-autoregressive policy." + ) + + # Pass to constructive policy + super(NARGNNPolicy, self).__init__( + encoder=encoder, + decoder=decoder, + env_name=env_name, + train_decode_type=train_decode_type, + val_decode_type=val_decode_type, + test_decode_type=test_decode_type, + **constructive_policy_kw, + ) diff --git a/rl4co/models/zoo/neuopt/__init__.py b/rl4co/models/zoo/neuopt/__init__.py new file mode 100644 index 00000000..f9fe19c0 --- /dev/null +++ b/rl4co/models/zoo/neuopt/__init__.py @@ -0,0 +1,2 @@ +from .model import NeuOpt +from .policy import NeuOptPolicy diff --git a/rl4co/models/zoo/neuopt/decoder.py b/rl4co/models/zoo/neuopt/decoder.py new file mode 100644 index 00000000..f9cca584 --- /dev/null +++ b/rl4co/models/zoo/neuopt/decoder.py @@ -0,0 +1,77 @@ +import torch +import torch.nn as nn + +from torch import Tensor + +from rl4co.models.common.improvement.base import ImprovementDecoder +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class RDSDecoder(ImprovementDecoder): + """ + RDS Decoder for flexible k-opt based on Ma et al. (2023) + Given the environment state and the node embeddings (positional embeddings are discarded), compute the logits for + selecting a k-opt exchange on basis moves (S-move, I-move, E-move) from the current solution + + Args: + embed_dim: Embedding dimension + num_heads: Number of attention heads + """ + + def __init__( + self, + embed_dim: int = 128, + ): + super().__init__() + self.embed_dim = embed_dim + + self.linear_K1 = nn.Linear(self.embed_dim, self.embed_dim, bias=False) + self.linear_K2 = nn.Linear(self.embed_dim, self.embed_dim, bias=False) + self.linear_K3 = nn.Linear(self.embed_dim, self.embed_dim, bias=False) + self.linear_K4 = nn.Linear(self.embed_dim, self.embed_dim, bias=False) + + self.linear_Q1 = nn.Linear(self.embed_dim, self.embed_dim, bias=False) + self.linear_Q2 = nn.Linear(self.embed_dim, self.embed_dim, bias=False) + self.linear_Q3 = nn.Linear(self.embed_dim, self.embed_dim, bias=False) + self.linear_Q4 = nn.Linear(self.embed_dim, self.embed_dim, bias=False) + + self.linear_V1 = nn.Parameter(torch.Tensor(self.embed_dim)) + self.linear_V2 = nn.Parameter(torch.Tensor(self.embed_dim)) + + self.rnn1 = nn.GRUCell(self.embed_dim, self.embed_dim) + self.rnn2 = nn.GRUCell(self.embed_dim, self.embed_dim) + + def forward(self, h, q1, q2, input_q1, input_q2) -> Tensor: + bs = h.size(0) + + # GRUs + q1 = self.rnn1(input_q1, q1) + q2 = self.rnn2(input_q2, q2) + + # Dual-Stream Attention + linear_V1 = self.linear_V1.view(1, -1).expand(bs, -1) + linear_V2 = self.linear_V2.view(1, -1).expand(bs, -1) + result = ( + linear_V1.unsqueeze(1) + * torch.tanh( + self.linear_K1(h) + + self.linear_Q1(q1).unsqueeze(1) + + self.linear_K3(h) * self.linear_Q3(q1).unsqueeze(1) + ) + ).sum( + -1 + ) # \mu stream + result += ( + linear_V2.unsqueeze(1) + * torch.tanh( + self.linear_K2(h) + + self.linear_Q2(q2).unsqueeze(1) + + self.linear_K4(h) * self.linear_Q4(q2).unsqueeze(1) + ) + ).sum( + -1 + ) # \lambda stream + + return result, q1, q2 diff --git a/rl4co/models/zoo/neuopt/model.py b/rl4co/models/zoo/neuopt/model.py new file mode 100644 index 00000000..5bd7050d --- /dev/null +++ b/rl4co/models/zoo/neuopt/model.py @@ -0,0 +1,62 @@ +import torch.nn as nn + +from rl4co.envs import RL4COEnvBase +from rl4co.models.nn.graph.attnnet import MultiHeadAttentionLayer +from rl4co.models.rl import n_step_PPO +from rl4co.models.rl.common.critic import CriticNetwork +from rl4co.models.zoo.n2s.decoder import CriticDecoder +from rl4co.models.zoo.neuopt.policy import NeuOptPolicy +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class NeuOpt(n_step_PPO): + """NeuOpt Model based on n_step Proximal Policy Optimization (PPO) with an NeuOpt model policy. + We default to the NeuOpt model policy and the improvement Critic Network. + + Args: + env: Environment to use for the algorithm + policy: Policy to use for the algorithm + critic: Critic to use for the algorithm + policy_kwargs: Keyword arguments for policy + critic_kwargs: Keyword arguments for critic + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: nn.Module = None, + critic: CriticNetwork = None, + policy_kwargs: dict = {}, + critic_kwargs: dict = {}, + **kwargs, + ): + if policy is None: + policy = NeuOptPolicy(env_name=env.name, **policy_kwargs) + + if critic is None: + embed_dim = ( + policy_kwargs["embed_dim"] if "embed_dim" in policy_kwargs else 128 + ) # the critic's embed_dim must be as policy's + + encoder = MultiHeadAttentionLayer( + embed_dim, + critic_kwargs["num_heads"] if "num_heads" in critic_kwargs else 4, + critic_kwargs["feedforward_hidden"] + if "feedforward_hidden" in critic_kwargs + else 128, + critic_kwargs["normalization"] + if "normalization" in critic_kwargs + else "layer", + bias=False, + ) + value_head = CriticDecoder(embed_dim, dropout_rate=0.001) + + critic = CriticNetwork( + encoder=encoder, + value_head=value_head, + customized=True, + ) + + super().__init__(env, policy, critic, **kwargs) diff --git a/rl4co/models/zoo/neuopt/policy.py b/rl4co/models/zoo/neuopt/policy.py new file mode 100644 index 00000000..0a4cc969 --- /dev/null +++ b/rl4co/models/zoo/neuopt/policy.py @@ -0,0 +1,300 @@ +import math + +from typing import Union + +import torch +import torch.nn as nn + +from tensordict import TensorDict + +from rl4co.envs import RL4COEnvBase, get_env +from rl4co.models.common.improvement.base import ImprovementPolicy +from rl4co.models.zoo.n2s.encoder import N2SEncoder +from rl4co.models.zoo.neuopt.decoder import RDSDecoder +from rl4co.utils.decoding import DecodingStrategy, get_decoding_strategy +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class CustomizeTSPInitEmbedding(nn.Module): + """Initial embedding for the Traveling Salesman Problems (TSP). + Embed the following node features to the embedding space: + - locs: x, y coordinates of the cities + """ + + def __init__(self, embed_dim, linear_bias=True): + super(CustomizeTSPInitEmbedding, self).__init__() + node_dim = 2 # x, y + self.init_embed = nn.Sequential( + nn.Linear(node_dim, embed_dim // 2, linear_bias), + nn.ReLU(inplace=True), + nn.Linear(embed_dim // 2, embed_dim, linear_bias), + ) + + def forward(self, td): + out = self.init_embed(td["locs"]) + return out + + +class NeuOptPolicy(ImprovementPolicy): + """ + NeuOpt Policy based on Ma et al. (2023) + This model first encodes the input graph and current solution using a N2S encoder (:class:`N2SEncoder`) + and then decodes the k-opt action (:class:`RDSDecoder`) + + Args: + embed_dim: Dimension of the node embeddings + num_encoder_layers: Number of layers in the encoder + num_heads: Number of heads in the attention layers + normalization: Normalization type in the attention layers + feedforward_hidden: Dimension of the hidden layer in the feedforward network + env_name: Name of the environment used to initialize embeddings + pos_type: Name of the used positional encoding method (CPE or APE) + init_embedding: Module to use for the initialization of the embeddings + pos_embedding: Module to use for the initialization of the positional embeddings + temperature: Temperature for the softmax + tanh_clipping: Tanh clipping value (see Bello et al., 2016) + train_decode_type: Type of decoding to use during training + val_decode_type: Type of decoding to use during validation + test_decode_type: Type of decoding to use during testing + """ + + def __init__( + self, + embed_dim: int = 128, + num_encoder_layers: int = 3, + num_heads: int = 4, + normalization: str = "layer", + feedforward_hidden: int = 128, + env_name: str = "tsp_kopt", + pos_type: str = "CPE", + init_embedding: nn.Module = None, + pos_embedding: nn.Module = None, + temperature: float = 1.0, + tanh_clipping: float = 6.0, + train_decode_type: str = "sampling", + val_decode_type: str = "sampling", + test_decode_type: str = "sampling", + ): + super(NeuOptPolicy, self).__init__() + + self.env_name = env_name + self.embed_dim = embed_dim + + # Decoding strategies + self.temperature = temperature + self.tanh_clipping = tanh_clipping + self.train_decode_type = train_decode_type + self.val_decode_type = val_decode_type + self.test_decode_type = test_decode_type + + # Encoder and decoder + if init_embedding is None: + init_embedding = CustomizeTSPInitEmbedding(self.embed_dim) + + self.encoder = N2SEncoder( + embed_dim=embed_dim, + init_embedding=init_embedding, + pos_embedding=pos_embedding, + env_name=env_name, + pos_type=pos_type, + num_heads=num_heads, + num_layers=num_encoder_layers, + normalization=normalization, + feedforward_hidden=feedforward_hidden, + ) + + self.decoder = RDSDecoder(embed_dim=embed_dim) + + self.init_hidden_W = nn.Linear(self.embed_dim, self.embed_dim) + self.init_query_learnable = nn.Parameter(torch.Tensor(self.embed_dim)) + + self.init_parameters() + + def init_parameters(self) -> None: + for param in self.parameters(): + stdv = 1.0 / math.sqrt(param.size(-1)) + param.data.uniform_(-stdv, stdv) + + def forward( + self, + td: TensorDict, + env: Union[str, RL4COEnvBase] = None, + phase: str = "train", + return_actions: bool = False, + return_embeds: bool = False, + only_return_embed: bool = False, + actions=None, + **decoding_kwargs, + ) -> dict: + """Forward pass of the policy. + + Args: + td: TensorDict containing the environment state + env: Environment to use for decoding. If None, the environment is instantiated from `env_name`. Note that + it is more efficient to pass an already instantiated environment each time for fine-grained control + phase: Phase of the algorithm (train, val, test) + return_actions: Whether to return the actions + actions: Actions to use for evaluating the policy. + If passed, use these actions instead of sampling from the policy to calculate log likelihood + decoding_kwargs: Keyword arguments for the decoding strategy. See :class:`rl4co.utils.decoding.DecodingStrategy` for more information. + + Returns: + out: Dictionary containing the reward, log likelihood, and optionally the actions and entropy + """ + + # Encoder: get encoder output and initial embeddings from initial state + nfe, _ = self.encoder(td) + if only_return_embed: + return {"embeds": nfe.detach()} + + # Instantiate environment if needed + if isinstance(env, str) or env is None: + env_name = self.env_name if env is None else env + log.info(f"Instantiated environment not provided; instantiating {env_name}") + env = get_env(env_name) + assert not env.two_opt_mode, "NeuOpt only support k-opt with k > 2" + + # Get decode type depending on phase and whether actions are passed for evaluation + decode_type = decoding_kwargs.pop("decode_type", None) + if actions is not None: + decode_type = "evaluate" + elif decode_type is None: + decode_type = getattr(self, f"{phase}_decode_type") + + # Setup decoding strategy + # we pop arguments that are not part of the decoding strategy + decode_strategy: DecodingStrategy = get_decoding_strategy( + decode_type, + temperature=decoding_kwargs.pop("temperature", self.temperature), + tanh_clipping=decoding_kwargs.pop("tanh_clipping", self.tanh_clipping), + mask_logits=True, + improvement_method_mode=True, + **decoding_kwargs, + ) + + # Perform the decoding + bs, gs, _, ll, action_sampled, rec, visited_time = ( + *nfe.size(), + 0.0, + None, + td["rec_current"], + td["visited_time"], + ) + action_index = torch.zeros(bs, env.k_max, dtype=torch.long).to(rec.device) + k_action_left = torch.zeros(bs, env.k_max + 1, dtype=torch.long).to(rec.device) + k_action_right = torch.zeros(bs, env.k_max, dtype=torch.long).to(rec.device) + next_of_last_action = ( + torch.zeros_like(rec[:, :1], dtype=torch.long).to(rec.device) - 1 + ) + mask = torch.zeros_like(rec, dtype=torch.bool).to(rec.device) + stopped = torch.ones(bs, dtype=torch.bool).to(rec.device) + zeros = torch.zeros((bs, 1), device=td.device) + + # init queries + h_mean = nfe.mean(1) + init_query = self.init_query_learnable.repeat(bs, 1) + input_q1 = input_q2 = init_query.clone() + init_hidden = self.init_hidden_W(h_mean) + q1 = q2 = init_hidden.clone() + + for i in range(env.k_max): + # Pass RDS decoder + logits, q1, q2 = self.decoder(nfe, q1, q2, input_q1, input_q2) + + # Calc probs + if i == 0 and "action" in td.keys(): + mask = mask.scatter(1, td["action"][:, :1], 1) + + logprob, action_sampled = decode_strategy.step( + logits, + ~mask.clone(), + action=actions[:, i : i + 1].squeeze() if actions is not None else None, + ) + action_sampled = action_sampled.unsqueeze(-1) + if i > 0: + action_sampled = torch.where( + stopped.unsqueeze(-1), action_index[:, :1], action_sampled + ) + if phase == "train": + loss_now = logprob.gather(1, action_sampled) + else: + loss_now = zeros.clone() + + # Record log_likelihood and Entropy + if i > 0: + ll = ll + torch.where(stopped.unsqueeze(-1), zeros * 0, loss_now) + else: + ll = ll + loss_now + + # Store and Process actions + next_of_new_action = rec.gather(1, action_sampled) + action_index[:, i] = action_sampled.squeeze().clone() + k_action_left[stopped, i] = action_sampled[stopped].squeeze().clone() + k_action_right[~stopped, i - 1] = action_sampled[~stopped].squeeze().clone() + k_action_left[:, i + 1] = next_of_new_action.squeeze().clone() + + # Prepare next RNN input + input_q1 = nfe.gather( + 1, action_sampled.view(bs, 1, 1).expand(bs, 1, self.embed_dim) + ).squeeze(1) + input_q2 = torch.where( + stopped.view(bs, 1).expand(bs, self.embed_dim), + input_q1.clone(), + nfe.gather( + 1, + (next_of_last_action % gs) + .view(bs, 1, 1) + .expand(bs, 1, self.embed_dim), + ).squeeze(1), + ) + + # Process if k-opt close + # assert (input_q1[stopped] == input_q2[stopped]).all() + if i > 0: + stopped = stopped | (action_sampled == next_of_last_action).squeeze() + else: + stopped = (action_sampled == next_of_last_action).squeeze() + # assert (input_q1[stopped] == input_q2[stopped]).all() + + k_action_left[stopped, i] = k_action_left[stopped, i - 1] + k_action_right[stopped, i] = k_action_right[stopped, i - 1] + + # Calc next basic masks + if i == 0: + visited_time_tag = ( + visited_time - visited_time.gather(1, action_sampled) + ) % gs + mask &= False + mask[(visited_time_tag <= visited_time_tag.gather(1, action_sampled))] = True + if i == 0: + mask[visited_time_tag > (gs - 2)] = True + mask[ + stopped, action_sampled[stopped].squeeze() + ] = False # allow next k-opt starts immediately + # if True:#i == env.k_max - 2: # allow special case: close k-opt at the first selected node + index_allow_first_node = (~stopped) & ( + next_of_new_action.squeeze() == action_index[:, 0] + ) + mask[index_allow_first_node, action_index[index_allow_first_node, 0]] = False + + # Move to next + next_of_last_action = next_of_new_action + next_of_last_action[stopped] = -1 + + # Form final action + k_action_right[~stopped, -1] = k_action_left[~stopped, -1].clone() + k_action_left = k_action_left[:, : env.k_max] + action_all = torch.cat((action_index, k_action_left, k_action_right), -1) + + outdict = {"log_likelihood": ll, "cost_bsf": td["cost_bsf"]} + td.set("action", action_all) + + if return_embeds: + outdict["embeds"] = nfe.detach() + + if return_actions: + outdict["actions"] = action_all + + return outdict diff --git a/rl4co/models/zoo/polynet/__init__.py b/rl4co/models/zoo/polynet/__init__.py new file mode 100644 index 00000000..1a908241 --- /dev/null +++ b/rl4co/models/zoo/polynet/__init__.py @@ -0,0 +1 @@ +from .model import PolyNet diff --git a/rl4co/models/zoo/polynet/decoder.py b/rl4co/models/zoo/polynet/decoder.py new file mode 100644 index 00000000..7a28fa1a --- /dev/null +++ b/rl4co/models/zoo/polynet/decoder.py @@ -0,0 +1,145 @@ +from dataclasses import dataclass +from typing import Tuple, Union + +import torch.nn as nn + +from torch import Tensor + +from rl4co.envs import RL4COEnvBase +from rl4co.models.nn.attention import PolyNetAttention +from rl4co.models.nn.env_embeddings import env_context_embedding, env_dynamic_embedding +from rl4co.models.nn.env_embeddings.dynamic import StaticEmbedding +from rl4co.models.zoo.am.decoder import AttentionModelDecoder +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +@dataclass +class PrecomputedCache: + node_embeddings: Tensor + graph_context: Union[Tensor, float] + glimpse_key: Tensor + glimpse_val: Tensor + logit_key: Tensor + + +class PolyNetDecoder(AttentionModelDecoder): + """ + PolyNet decoder for constructing diverse solutions for combinatorial optimization problems. + Given the environment state and the embeddings, compute the logits and sample actions autoregressively until + all the environments in the batch have reached a terminal state. + We additionally include support for multi-starts as it is more efficient to do so in the decoder as we can + natively perform the attention computation. + + Args: + k: Number of strategies to learn ("K" in the PolyNet paper) + encoder_type: Type of encoder that should be used. "AM" or "MatNet" are supported + embed_dim: Embedding dimension + poly_layer_dim: Dimension of the PolyNet layers + num_heads: Number of attention heads + env_name: Name of the environment used to initialize embeddings + context_embedding: Context embedding module + dynamic_embedding: Dynamic embedding module + mask_inner: Whether to mask the inner loop + out_bias_pointer_attn: Whether to use a bias in the pointer attention + linear_bias: Whether to use a bias in the linear layer + use_graph_context: Whether to use the graph context + check_nan: Whether to check for nan values during decoding + sdpa_fn: scaled_dot_product_attention function + """ + + def __init__( + self, + k: int, + encoder_type: str, + embed_dim: int = 128, + poly_layer_dim: int = 256, + num_heads: int = 8, + env_name: Union[str, RL4COEnvBase] = "tsp", + context_embedding: nn.Module = None, + dynamic_embedding: nn.Module = None, + mask_inner: bool = True, + out_bias_pointer_attn: bool = False, + linear_bias: bool = False, + use_graph_context: bool = True, + check_nan: bool = True, + sdpa_fn: callable = None, + **unused_kwargs, + ): + super().__init__() + + if isinstance(env_name, RL4COEnvBase): + env_name = env_name.name + self.env_name = env_name + self.embed_dim = embed_dim + self.num_heads = num_heads + self.encoder_type = encoder_type + + assert embed_dim % num_heads == 0 + + self.context_embedding = ( + env_context_embedding(self.env_name, {"embed_dim": embed_dim}) + if context_embedding is None + else context_embedding + ) + self.dynamic_embedding = ( + env_dynamic_embedding(self.env_name, {"embed_dim": embed_dim}) + if dynamic_embedding is None + else dynamic_embedding + ) + self.is_dynamic_embedding = ( + False if isinstance(self.dynamic_embedding, StaticEmbedding) else True + ) + + # MHA with Pointer mechanism (https://arxiv.org/abs/1506.03134) + self.pointer = PolyNetAttention( + k, + embed_dim, + poly_layer_dim, + num_heads, + mask_inner=mask_inner, + out_bias=out_bias_pointer_attn, + check_nan=check_nan, + sdpa_fn=sdpa_fn, + ) + + # For each node we compute (glimpse key, glimpse value, logit key) so 3 * embed_dim + self.project_node_embeddings = nn.Linear( + embed_dim, 3 * embed_dim, bias=linear_bias + ) + self.project_fixed_context = nn.Linear(embed_dim, embed_dim, bias=linear_bias) + self.use_graph_context = use_graph_context + + def _precompute_cache_matnet( + self, embeddings: Tuple[Tensor, Tensor], *args, **kwargs + ): + col_emb, row_emb = embeddings + ( + glimpse_key_fixed, + glimpse_val_fixed, + logit_key, + ) = self.project_node_embeddings( + col_emb + ).chunk(3, dim=-1) + + # Optionally disable the graph context from the initial embedding as done in POMO + if self.use_graph_context: + graph_context = self.project_fixed_context(col_emb.mean(1)) + else: + graph_context = 0 + + # Organize in a dataclass for easy access + return PrecomputedCache( + node_embeddings=row_emb, + graph_context=graph_context, + glimpse_key=glimpse_key_fixed, + glimpse_val=glimpse_val_fixed, + logit_key=logit_key, + ) + + def _precompute_cache(self, embeddings: Tuple[Tensor, Tensor], *args, **kwargs): + if self.encoder_type == "AM": + return super()._precompute_cache(embeddings, *args, **kwargs) + elif self.encoder_type == "MatNet": + return self._precompute_cache_matnet(embeddings, *args, **kwargs) diff --git a/rl4co/models/zoo/polynet/model.py b/rl4co/models/zoo/polynet/model.py new file mode 100644 index 00000000..a1271da8 --- /dev/null +++ b/rl4co/models/zoo/polynet/model.py @@ -0,0 +1,241 @@ +import logging + +from typing import Any, Optional, Union + +import torch + +from tensordict import TensorDict + +from rl4co.data.transforms import StateAugmentation +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl.reinforce.reinforce import REINFORCE +from rl4co.models.zoo.polynet.policy import PolyNetPolicy +from rl4co.utils.ops import gather_by_index, unbatchify +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class PolyNet(REINFORCE): + """PolyNet + Based on Hottung et al. (2024) https://arxiv.org/abs/2402.14048. + + Note: + PolyNet allows to learn diverse solution stratgies with a single model. This is achieved + through a modified decoder and the Poppy loss (Grinsztajn et al. (2021)). PolyNet can be used with the attention model encoder or the MatNet encoder by + setting encoder_type to "AM" or "MatNet", respectively. + + Args: + env: TorchRL Environment + policy: Policy to use for the algorithm + k: Number of strategies to learn ("K" in the paper) + val_num_solutions: Number of solutions that are generated per instance during validation + encoder_type: Type of encoder that should be used. "AM" or "MatNet" are supported + policy_kwargs: Keyword arguments for policy + baseline: Baseline to use for the algorithm. Note that PolyNet only supports shared baseline, + so we will throw an error if anything else is passed. + num_augment: Number of augmentations (used only for validation and test) + augment_fn: Function to use for augmentation, defaulting to dihedral8 + first_aug_identity: Whether to include the identity augmentation in the first position + feats: List of features to augment + **kwargs: Keyword arguments passed to the superclass + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: PolyNetPolicy = None, + k: int = 128, + val_num_solutions: int = 800, + encoder_type="AM", + base_model_checkpoint_path: str = None, + policy_kwargs={}, + baseline: str = "shared", + num_augment: int = 8, + augment_fn: Union[str, callable] = "dihedral8", + first_aug_identity: bool = True, + feats: list = None, + **kwargs, + ): + self.save_hyperparameters(logger=False) + + self.k = k + self.val_num_solutions = val_num_solutions + + assert encoder_type in [ + "AM", + "MatNet", + ], "Supported encoder types are 'AM' and 'MatNet'" + + assert baseline == "shared", "PolyNet only supports shared baseline" + + if ( + policy_kwargs.get("val_decode_type") == "greedy" + or policy_kwargs.get("test_decode_type") == "greedy" + ): + assert ( + val_num_solutions <= k + ), "If greedy decoding is used val_num_solutions must be <= k" + + if encoder_type == "MatNet": + assert ( + num_augment == 1 + ), "MatNet does not use symmetric or dihedral augmentation" + + if policy is None: + policy = PolyNetPolicy( + env_name=env.name, k=k, encoder_type=encoder_type, **policy_kwargs + ) + + if base_model_checkpoint_path is not None: + logging.info( + f"Trying to load weights from baseline model {base_model_checkpoint_path}" + ) + checkpoint = torch.load(base_model_checkpoint_path) + state_dict = checkpoint["state_dict"] + state_dict = {k.replace("policy.", "", 1): v for k, v in state_dict.items()} + policy.load_state_dict(state_dict, strict=False) + + train_batch_size = kwargs["batch_size"] if "batch_size" in kwargs else 64 + kwargs_with_defaults = { + "val_batch_size": train_batch_size, + "test_batch_size": train_batch_size, + } + kwargs_with_defaults.update(kwargs) + + # Initialize with the shared baseline + super(PolyNet, self).__init__(env, policy, baseline, **kwargs_with_defaults) + + self.num_augment = num_augment + if self.num_augment > 1: + self.augment = StateAugmentation( + num_augment=self.num_augment, + augment_fn=augment_fn, + first_aug_identity=first_aug_identity, + feats=feats, + ) + else: + self.augment = None + + # Add `_multistart` to decode type for train, val and test in policy + # for phase in ["train", "val", "test"]: + # self.set_decode_type_multistart(phase) + + def shared_step( + self, batch: Any, batch_idx: int, phase: str, dataloader_idx: int = None + ): + td = self.env.reset(batch) + n_aug = self.num_augment + + # During training, we do not augment the data + if phase == "train": + n_aug = 0 + elif n_aug > 1: + td = self.augment(td) + + if phase == "train": + n_start = self.k + else: + n_start = self.val_num_solutions + + # Evaluate policy + out = self.policy( + td, + self.env, + phase=phase, + num_starts=n_start, + multisample=True, + return_actions=True, + ) + + # Unbatchify reward to [batch_size, num_augment, num_starts]. + reward = unbatchify(out["reward"], (n_aug, n_start)) + + # Training phase + if phase == "train": + assert n_start > 1, "num_starts must be > 1 during training" + log_likelihood = unbatchify(out["log_likelihood"], (n_aug, n_start)) + self.calculate_loss(td, batch, out, reward, log_likelihood) + max_reward, max_idxs = reward.max(dim=-1) + out.update({"max_reward": max_reward}) + # Get multi-start (=POMO) rewards and best actions only during validation and test + else: + if n_start > 1: + # max multi-start reward + max_reward, max_idxs = reward.max(dim=-1) + out.update({"max_reward": max_reward}) + + if out.get("actions", None) is not None: + # Reshape batch to [batch_size, num_augment, num_starts, ...] + actions = unbatchify(out["actions"], (n_aug, n_start)) + out.update( + { + "best_multistart_actions": gather_by_index( + actions, max_idxs.unsqueeze(2), dim=2 + ) + } + ) + out["actions"] = actions + + # Get augmentation score only during inference + if n_aug > 1: + # If multistart is enabled, we use the best multistart rewards + reward_ = max_reward if n_start > 1 else reward + max_aug_reward, max_idxs = reward_.max(dim=1) + out.update({"max_aug_reward": max_aug_reward}) + + if out.get("actions", None) is not None: + actions_ = ( + out["best_multistart_actions"] if n_start > 1 else out["actions"] + ) + out.update({"best_aug_actions": gather_by_index(actions_, max_idxs)}) + + metrics = self.log_metrics(out, phase, dataloader_idx=dataloader_idx) + return {"loss": out.get("loss", None), **metrics} + + def calculate_loss( + self, + td: TensorDict, + batch: TensorDict, + policy_out: dict, + reward: Optional[torch.Tensor] = None, + log_likelihood: Optional[torch.Tensor] = None, + ): + """Calculate loss following Poppy (https://arxiv.org/abs/2210.03475). + + Args: + td: TensorDict containing the current state of the environment + batch: Batch of data. This is used to get the extra loss terms, e.g., REINFORCE baseline + policy_out: Output of the policy network + reward: Reward tensor. If None, it is taken from `policy_out` + log_likelihood: Log-likelihood tensor. If None, it is taken from `policy_out` + """ + # Extra: this is used for additional loss terms, e.g., REINFORCE baseline + extra = batch.get("extra", None) + reward = reward if reward is not None else policy_out["reward"] + log_likelihood = ( + log_likelihood if log_likelihood is not None else policy_out["log_likelihood"] + ) + + # REINFORCE baseline + bl_val, bl_loss = ( + self.baseline.eval(td, reward, self.env) if extra is None else (extra, 0) + ) + + # Log-likelihood mask. Mask everything but the best rollout per instance + best_idx = (-reward).argsort(1).argsort(1) + mask = best_idx < 1 + + # Main loss function + advantage = reward - bl_val # advantage = reward - baseline + reinforce_loss = -(advantage * log_likelihood * mask).mean() + loss = reinforce_loss + bl_loss + policy_out.update( + { + "loss": loss, + "reinforce_loss": reinforce_loss, + "bl_loss": bl_loss, + "bl_val": bl_val, + } + ) + return policy_out diff --git a/rl4co/models/zoo/polynet/policy.py b/rl4co/models/zoo/polynet/policy.py new file mode 100644 index 00000000..d2128a6f --- /dev/null +++ b/rl4co/models/zoo/polynet/policy.py @@ -0,0 +1,101 @@ +from typing import Union + +import torch.nn as nn + +from rl4co.envs import RL4COEnvBase +from rl4co.models.common.constructive.autoregressive.policy import AutoregressivePolicy +from rl4co.models.zoo.am.encoder import AttentionModelEncoder +from rl4co.models.zoo.matnet.encoder import MatNetEncoder +from rl4co.models.zoo.polynet.decoder import PolyNetDecoder + + +class PolyNetPolicy(AutoregressivePolicy): + """ + # TODO + Polynet policy based on Hottung et al. (2024) https://arxiv.org/abs/2402.14048. + The model uses either the AttentionModel encoder or the MatNet encoder in combination with + a custom PolyNet decoder. + + Note: The default arguments for the AttentionModel encoder follow the POMO paper. The default decoding type + during validation and testing is 'sampling'. + + Args: + k: Number of strategies to learn ("K" in the paper) + encoder_type: Type of encoder that should be used. "AM" or "MatNet" are supported. + embed_dim: Dimension of the node embeddings + num_encoder_layers: Number of layers in the encoder + num_heads: Number of heads in the attention layers + normalization: Normalization type in the attention layers + feedforward_hidden: Dimension of the hidden layer in the feedforward network + env_name: Name of the environment used to initialize embeddings + temperature: Temperature for the softmax + tanh_clipping: Tanh clipping value (see Bello et al., 2016) + mask_logits: Whether to mask the logits during decoding + train_decode_type: Type of decoding to use during training + val_decode_type: Type of decoding to use during validation + test_decode_type: Type of decoding to use during testing + **kwargs: keyword arguments passed to the encoder and decoder modules + """ + + def __init__( + self, + k: int, + encoder: nn.Module = None, + encoder_type: str = "AM", + embed_dim: int = 128, + num_encoder_layers: int = 6, + num_heads: int = 8, + normalization: str = "instance", + feedforward_hidden: int = 512, + env_name: Union[str, RL4COEnvBase] = "tsp", + temperature: float = 1.0, + tanh_clipping: float = 10.0, + mask_logits: bool = True, + train_decode_type: str = "sampling", + val_decode_type: str = "sampling", + test_decode_type: str = "sampling", + **kwargs, + ): + if encoder is None: + if encoder_type == "AM": + encoder = AttentionModelEncoder( + embed_dim=embed_dim, + num_heads=num_heads, + num_layers=num_encoder_layers, + env_name=env_name, + normalization=normalization, + feedforward_hidden=feedforward_hidden, + **kwargs, + ) + elif encoder_type == "MatNet": + kwargs_with_defaults = {"init_embedding_kwargs": {"mode": "RandomOneHot"}} + kwargs_with_defaults.update(kwargs) + encoder = MatNetEncoder( + embed_dim=embed_dim, + num_heads=num_heads, + num_layers=num_encoder_layers, + normalization=normalization, + **kwargs_with_defaults, + ) + + decoder = PolyNetDecoder( + k=k, + encoder_type=encoder_type, + embed_dim=embed_dim, + num_heads=num_heads, + env_name=env_name, + **kwargs, + ) + + super(PolyNetPolicy, self).__init__( + encoder=encoder, + decoder=decoder, + env_name=env_name, + temperature=temperature, + tanh_clipping=tanh_clipping, + mask_logits=mask_logits, + train_decode_type=train_decode_type, + val_decode_type=val_decode_type, + test_decode_type=test_decode_type, + **kwargs, + ) diff --git a/rl4co/models/zoo/pomo/__init__.py b/rl4co/models/zoo/pomo/__init__.py new file mode 100644 index 00000000..d16e98d7 --- /dev/null +++ b/rl4co/models/zoo/pomo/__init__.py @@ -0,0 +1 @@ +from .model import POMO diff --git a/rl4co/models/zoo/pomo/model.py b/rl4co/models/zoo/pomo/model.py new file mode 100644 index 00000000..7b481d30 --- /dev/null +++ b/rl4co/models/zoo/pomo/model.py @@ -0,0 +1,144 @@ +from typing import Any, Union + +import torch.nn as nn + +from rl4co.data.transforms import StateAugmentation +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl.reinforce.reinforce import REINFORCE +from rl4co.models.zoo.am import AttentionModelPolicy +from rl4co.utils.ops import gather_by_index, unbatchify +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class POMO(REINFORCE): + """POMO Model for neural combinatorial optimization based on REINFORCE + Based on Kwon et al. (2020) http://arxiv.org/abs/2010.16011. + + Note: + If no policy kwargs is passed, we use the Attention Model policy with the following arguments: + Differently to the base class: + - `num_encoder_layers=6` (instead of 3) + - `normalization="instance"` (instead of "batch") + - `use_graph_context=False` (instead of True) + The latter is due to the fact that the paper does not use the graph context in the policy, which seems to be + helpful in overfitting to the training graph size. + + Args: + env: TorchRL Environment + policy: Policy to use for the algorithm + policy_kwargs: Keyword arguments for policy + baseline: Baseline to use for the algorithm. Note that POMO only supports shared baseline, + so we will throw an error if anything else is passed. + num_augment: Number of augmentations (used only for validation and test) + augment_fn: Function to use for augmentation, defaulting to dihedral8 + first_aug_identity: Whether to include the identity augmentation in the first position + feats: List of features to augment + num_starts: Number of starts for multi-start. If None, use the number of available actions + **kwargs: Keyword arguments passed to the superclass + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: nn.Module = None, + policy_kwargs={}, + baseline: str = "shared", + num_augment: int = 8, + augment_fn: Union[str, callable] = "dihedral8", + first_aug_identity: bool = True, + feats: list = None, + num_starts: int = None, + **kwargs, + ): + self.save_hyperparameters(logger=False) + + if policy is None: + policy_kwargs_with_defaults = { + "num_encoder_layers": 6, + "normalization": "instance", + "use_graph_context": False, + } + policy_kwargs_with_defaults.update(policy_kwargs) + policy = AttentionModelPolicy(env_name=env.name, **policy_kwargs_with_defaults) + + assert baseline == "shared", "POMO only supports shared baseline" + + # Initialize with the shared baseline + super(POMO, self).__init__(env, policy, baseline, **kwargs) + + self.num_starts = num_starts + self.num_augment = num_augment + if self.num_augment > 1: + self.augment = StateAugmentation( + num_augment=self.num_augment, + augment_fn=augment_fn, + first_aug_identity=first_aug_identity, + feats=feats, + ) + else: + self.augment = None + + # Add `_multistart` to decode type for train, val and test in policy + for phase in ["train", "val", "test"]: + self.set_decode_type_multistart(phase) + + def shared_step( + self, batch: Any, batch_idx: int, phase: str, dataloader_idx: int = None + ): + td = self.env.reset(batch) + n_aug, n_start = self.num_augment, self.num_starts + n_start = self.env.get_num_starts(td) if n_start is None else n_start + + # During training, we do not augment the data + if phase == "train": + n_aug = 0 + elif n_aug > 1: + td = self.augment(td) + + # Evaluate policy + out = self.policy( + td, self.env, phase=phase, num_starts=n_start, return_actions=True + ) + + # Unbatchify reward to [batch_size, num_augment, num_starts]. + reward = unbatchify(out["reward"], (n_aug, n_start)) + + # Training phase + if phase == "train": + assert n_start > 1, "num_starts must be > 1 during training" + log_likelihood = unbatchify(out["log_likelihood"], (n_aug, n_start)) + self.calculate_loss(td, batch, out, reward, log_likelihood) + max_reward, max_idxs = reward.max(dim=-1) + out.update({"max_reward": max_reward}) + # Get multi-start (=POMO) rewards and best actions only during validation and test + else: + if n_start > 1: + # max multi-start reward + max_reward, max_idxs = reward.max(dim=-1) + out.update({"max_reward": max_reward}) + + if out.get("actions", None) is not None: + # Reshape batch to [batch_size, num_augment, num_starts, ...] + actions = unbatchify(out["actions"], (n_aug, n_start)) + out.update( + {"best_multistart_actions": gather_by_index(actions, max_idxs, dim=max_idxs.dim())} + ) + out["actions"] = actions + + # Get augmentation score only during inference + if n_aug > 1: + # If multistart is enabled, we use the best multistart rewards + reward_ = max_reward if n_start > 1 else reward + max_aug_reward, max_idxs = reward_.max(dim=1) + out.update({"max_aug_reward": max_aug_reward}) + + if out.get("actions", None) is not None: + actions_ = ( + out["best_multistart_actions"] if n_start > 1 else out["actions"] + ) + out.update({"best_aug_actions": gather_by_index(actions_, max_idxs)}) + + metrics = self.log_metrics(out, phase, dataloader_idx=dataloader_idx) + return {"loss": out.get("loss", None), **metrics} diff --git a/rl4co/models/zoo/ptrnet/__init__.py b/rl4co/models/zoo/ptrnet/__init__.py new file mode 100644 index 00000000..631b3154 --- /dev/null +++ b/rl4co/models/zoo/ptrnet/__init__.py @@ -0,0 +1,2 @@ +from .model import PointerNetwork +from .policy import PointerNetworkPolicy diff --git a/rl4co/models/zoo/ptrnet/critic.py b/rl4co/models/zoo/ptrnet/critic.py new file mode 100644 index 00000000..efbda9ed --- /dev/null +++ b/rl4co/models/zoo/ptrnet/critic.py @@ -0,0 +1,58 @@ +import torch +import torch.nn as nn + +from .decoder import SimpleAttention +from .encoder import Encoder + + +class CriticNetworkLSTM(nn.Module): + """Useful as a baseline in REINFORCE updates""" + + def __init__( + self, + embed_dim, + hidden_dim, + n_process_block_iters, + tanh_exploration, + use_tanh, + ): + super(CriticNetworkLSTM, self).__init__() + + self.hidden_dim = hidden_dim + self.n_process_block_iters = n_process_block_iters + + self.encoder = Encoder(embed_dim, hidden_dim) + + self.process_block = SimpleAttention( + hidden_dim, use_tanh=use_tanh, C=tanh_exploration + ) + self.sm = nn.Softmax(dim=1) + self.decoder = nn.Sequential( + nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, 1) + ) + + def forward(self, inputs): + """ + Args: + inputs: [embed_dim x batch_size x sourceL] of embedded inputs + """ + inputs = inputs.transpose(0, 1).contiguous() + + encoder_hx = ( + self.encoder.init_hx.unsqueeze(0).repeat(inputs.size(1), 1).unsqueeze(0) + ) + encoder_cx = ( + self.encoder.init_cx.unsqueeze(0).repeat(inputs.size(1), 1).unsqueeze(0) + ) + + # encoder forward pass + enc_outputs, (enc_h_t, enc_c_t) = self.encoder(inputs, (encoder_hx, encoder_cx)) + + # grab the hidden state and process it via the process block + process_block_state = enc_h_t[-1] + for i in range(self.n_process_block_iters): + ref, logits = self.process_block(process_block_state, enc_outputs) + process_block_state = torch.bmm(ref, self.sm(logits).unsqueeze(2)).squeeze(2) + # produce the final scalar output + out = self.decoder(process_block_state) + return out diff --git a/rl4co/models/zoo/ptrnet/decoder.py b/rl4co/models/zoo/ptrnet/decoder.py new file mode 100644 index 00000000..710f03c0 --- /dev/null +++ b/rl4co/models/zoo/ptrnet/decoder.py @@ -0,0 +1,182 @@ +import math + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from rl4co.utils.decoding import decode_logprobs +from rl4co.utils.ops import gather_by_index + + +class SimpleAttention(nn.Module): + """A generic attention module for a decoder in seq2seq""" + + def __init__(self, dim, use_tanh=False, C=10): + super(SimpleAttention, self).__init__() + self.use_tanh = use_tanh + self.project_query = nn.Linear(dim, dim) + self.project_ref = nn.Conv1d(dim, dim, 1, 1) + self.C = C # tanh exploration + + self.v = nn.Parameter(torch.FloatTensor(dim)) + self.v.data.uniform_(-(1.0 / math.sqrt(dim)), 1.0 / math.sqrt(dim)) + + def forward(self, query, ref): + """ + Args: + query: is the hidden state of the decoder at the current + time step. batch x dim + ref: the set of hidden states from the encoder. + sourceL x batch x hidden_dim + """ + # ref is now [batch_size x hidden_dim x sourceL] + ref = ref.permute(1, 2, 0) + q = self.project_query(query).unsqueeze(2) # batch x dim x 1 + e = self.project_ref(ref) # batch_size x hidden_dim x sourceL + # expand the query by sourceL + # batch x dim x sourceL + expanded_q = q.repeat(1, 1, e.size(2)) + # batch x 1 x hidden_dim + v_view = self.v.unsqueeze(0).expand(expanded_q.size(0), len(self.v)).unsqueeze(1) + # [batch_size x 1 x hidden_dim] * [batch_size x hidden_dim x sourceL] + u = torch.bmm(v_view, F.tanh(expanded_q + e)).squeeze(1) + if self.use_tanh: + logits = self.C * F.tanh(u) + else: + logits = u + return e, logits + + +class Decoder(nn.Module): + def __init__( + self, + embed_dim: int = 128, + hidden_dim: int = 128, + tanh_exploration: float = 10.0, + use_tanh: bool = True, + num_glimpses=1, + mask_glimpses=True, + mask_logits=True, + ): + super(Decoder, self).__init__() + + self.embed_dim = embed_dim + self.hidden_dim = hidden_dim + self.num_glimpses = num_glimpses + self.mask_glimpses = mask_glimpses + self.mask_logits = mask_logits + self.use_tanh = use_tanh + self.tanh_exploration = tanh_exploration + + self.lstm = nn.LSTMCell(embed_dim, hidden_dim) + self.pointer = SimpleAttention(hidden_dim, use_tanh=use_tanh, C=tanh_exploration) + self.glimpse = SimpleAttention(hidden_dim, use_tanh=False) + + def update_mask(self, mask, selected): + return mask.clone().scatter_(1, selected.unsqueeze(-1), False) + + def recurrence(self, x, h_in, prev_mask, prev_idxs, step, context): + logit_mask = ( + self.update_mask(prev_mask, prev_idxs) if prev_idxs is not None else prev_mask + ) + + logits, h_out = self.calc_logits( + x, h_in, logit_mask, context, self.mask_glimpses, self.mask_logits + ) + + # Calculate log_softmax for better numerical stability + log_p = torch.log_softmax(logits, dim=1) + + if not self.mask_logits: + log_p[~logit_mask] = float("-inf") + + return h_out, log_p, logit_mask + + def calc_logits( + self, x, h_in, logit_mask, context, mask_glimpses=None, mask_logits=None + ): + if mask_glimpses is None: + mask_glimpses = self.mask_glimpses + + if mask_logits is None: + mask_logits = self.mask_logits + + hy, cy = self.lstm(x, h_in) + g_l, h_out = hy, (hy, cy) + + for i in range(self.num_glimpses): + ref, logits = self.glimpse(g_l, context) + # For the glimpses, only mask before softmax so we have always an L1 norm 1 readout vector + if mask_glimpses: + logits[~logit_mask] = float("-inf") + # [batch_size x h_dim x sourceL] * [batch_size x sourceL x 1] = + # [batch_size x h_dim x 1] + g_l = torch.bmm(ref, F.softmax(logits, dim=1).unsqueeze(2)).squeeze(2) + _, logits = self.pointer(g_l, context) + + # Masking before softmax makes probs sum to one + if mask_logits: + logits[~logit_mask] = float("-inf") + + return logits, h_out + + def forward( + self, + decoder_input, + embedded_inputs, + hidden, + context, + decode_type="sampling", + eval_tours=None, + ): + """ + Args: + decoder_input: The initial input to the decoder + size is [batch_size x embed_dim]. Trainable parameter. + embedded_inputs: [sourceL x batch_size x embed_dim] + hidden: the prev hidden state, size is [batch_size x hidden_dim]. + Initially this is set to (enc_h[-1], enc_c[-1]) + context: encoder outputs, [sourceL x batch_size x hidden_dim] + """ + + batch_size = context.size(1) + outputs = [] + selections = [] + steps = range(embedded_inputs.size(0)) + idxs = None + mask = torch.ones( + embedded_inputs.size(1), + embedded_inputs.size(0), + dtype=torch.bool, + device=embedded_inputs.device, + ) + + for i in steps: + hidden, log_p, mask = self.recurrence( + decoder_input, hidden, mask, idxs, i, context + ) + # select the next inputs for the decoder [batch_size x hidden_dim] + idxs = ( + decode_logprobs(log_p, mask, decode_type=decode_type) + if eval_tours is None + else eval_tours[:, i] + ) + # select logp of chosen action + log_p = gather_by_index(log_p, idxs, dim=1) + + idxs = ( + idxs.detach() + ) # Otherwise pytorch complains it want's a reward, todo implement this more properly? + # Gather input embedding of selected + decoder_input = torch.gather( + embedded_inputs, + 0, + idxs.contiguous() + .view(1, batch_size, 1) + .expand(1, batch_size, *embedded_inputs.size()[2:]), + ).squeeze(0) + + # use outs to point to next object + outputs.append(log_p) + selections.append(idxs) + return (torch.stack(outputs, 1), torch.stack(selections, 1)), hidden diff --git a/rl4co/models/zoo/ptrnet/encoder.py b/rl4co/models/zoo/ptrnet/encoder.py new file mode 100644 index 00000000..575c7430 --- /dev/null +++ b/rl4co/models/zoo/ptrnet/encoder.py @@ -0,0 +1,29 @@ +import math + +import torch +import torch.nn as nn + + +class Encoder(nn.Module): + """Maps a graph represented as an input sequence + to a hidden vector""" + + def __init__(self, input_dim, hidden_dim): + super(Encoder, self).__init__() + self.hidden_dim = hidden_dim + self.lstm = nn.LSTM(input_dim, hidden_dim) + self.init_hx, self.init_cx = self.init_hidden(hidden_dim) + + def forward(self, x, hidden): + output, hidden = self.lstm(x, hidden) + return output, hidden + + def init_hidden(self, hidden_dim): + """Trainable initial hidden state""" + std = 1.0 / math.sqrt(hidden_dim) + enc_init_hx = nn.Parameter(torch.FloatTensor(hidden_dim)) + enc_init_hx.data.uniform_(-std, std) + + enc_init_cx = nn.Parameter(torch.FloatTensor(hidden_dim)) + enc_init_cx.data.uniform_(-std, std) + return enc_init_hx, enc_init_cx diff --git a/rl4co/models/zoo/ptrnet/model.py b/rl4co/models/zoo/ptrnet/model.py new file mode 100644 index 00000000..66381255 --- /dev/null +++ b/rl4co/models/zoo/ptrnet/model.py @@ -0,0 +1,35 @@ +from typing import Union + +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl import REINFORCE +from rl4co.models.rl.reinforce.baselines import REINFORCEBaseline +from rl4co.models.zoo.ptrnet.policy import PointerNetworkPolicy + + +class PointerNetwork(REINFORCE): + """Pointer Network for neural combinatorial optimization based on REINFORCE + Based on Vinyals et al. (2015) https://arxiv.org/abs/1506.03134 + Refactored from reference implementation: https://github.com/wouterkool/attention-learn-to-route + + Args: + env: Environment to use for the algorithm + policy: Policy to use for the algorithm + baseline: REINFORCE baseline. Defaults to rollout (1 epoch of exponential, then greedy rollout baseline) + policy_kwargs: Keyword arguments for policy + baseline_kwargs: Keyword arguments for baseline + **kwargs: Keyword arguments passed to the superclass + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: PointerNetworkPolicy = None, + baseline: Union[REINFORCEBaseline, str] = "rollout", + policy_kwargs={}, + baseline_kwargs={}, + **kwargs, + ): + policy = ( + PointerNetworkPolicy(env=env, **policy_kwargs) if policy is None else policy + ) + super().__init__(env, policy, baseline, baseline_kwargs, **kwargs) diff --git a/rl4co/models/zoo/ptrnet/policy.py b/rl4co/models/zoo/ptrnet/policy.py new file mode 100644 index 00000000..dc0373a3 --- /dev/null +++ b/rl4co/models/zoo/ptrnet/policy.py @@ -0,0 +1,107 @@ +import math + +import torch +import torch.nn as nn + +from rl4co.models.zoo.ptrnet.decoder import Decoder +from rl4co.models.zoo.ptrnet.encoder import Encoder +from rl4co.utils.decoding import get_log_likelihood +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class PointerNetworkPolicy(nn.Module): + def __init__( + self, + env_name: str = "tsp", + embed_dim: int = 128, + hidden_dim: int = 128, + tanh_clipping=10.0, + mask_inner=True, + mask_logits=True, + **kwargs, + ): + super(PointerNetworkPolicy, self).__init__() + + assert env_name == "tsp", "Only the Euclidean TSP env is implemented" + self.env_name = env_name + self.input_dim = 2 + + self.encoder = Encoder(embed_dim, hidden_dim) + + self.decoder = Decoder( + embed_dim, + hidden_dim, + tanh_exploration=tanh_clipping, + use_tanh=tanh_clipping > 0, + num_glimpses=1, + mask_glimpses=mask_inner, + mask_logits=mask_logits, + ) + + # Trainable initial hidden states + std = 1.0 / math.sqrt(embed_dim) + self.decoder_in_0 = nn.Parameter(torch.FloatTensor(embed_dim)) + self.decoder_in_0.data.uniform_(-std, std) + + self.embedding = nn.Parameter(torch.FloatTensor(self.input_dim, embed_dim)) + self.embedding.data.uniform_(-std, std) + + def forward( + self, + td, + env, + phase: str = "train", + decode_type="sampling", + eval_tours=None, + **unused_kwargs, + ): + if len(unused_kwargs) > 0: + log.info(f"Unused kwargs for {self.__class__.__name__}: {unused_kwargs}") + + # Set train or eval mode. Although this is already done by PyTorch Lightning, + # there still is an exception raised otherwise https://github.com/pytorch/captum/issues/564 + if phase == "train": + self.train() + else: + self.eval() + + batch_size, graph_size, input_dim = td["locs"].size() + + embedded_inputs = torch.mm( + td["locs"].transpose(0, 1).contiguous().view(-1, input_dim), + self.embedding, + ).view(graph_size, batch_size, -1) + + # query the actor net for the input indices + # making up the output, and the pointer attn + _logprobs, actions = self._inner(embedded_inputs, decode_type, eval_tours) + + reward = env.get_reward(td, actions) + + # Log likelyhood is calculated within the model since returning it per action does not work well with + # DataParallel since sequences can be of different lengths + ll = get_log_likelihood(_logprobs, actions, td.get("mask", None)) + + out = {"reward": reward, "log_likelihood": ll, "actions": actions} + return out + + def _inner(self, inputs, decode_type="sampling", eval_tours=None): + encoder_hx = encoder_cx = torch.zeros( + 1, *inputs.shape[1:], device=inputs.device + ) # (1, inputs.size(1), self.encoder.hidden_dim, device=inputs.device, out=inputs.data.new(), requires_grad=False) + + # encoder forward pass + enc_h, (enc_h_t, enc_c_t) = self.encoder(inputs, (encoder_hx, encoder_cx)) + + dec_init_state = (enc_h_t[-1], enc_c_t[-1]) + + # repeat decoder_in_0 across batch + decoder_input = self.decoder_in_0.unsqueeze(0).repeat(inputs.size(1), 1) + + (pointer_probs, input_idxs), dec_hidden_t = self.decoder( + decoder_input, inputs, dec_init_state, enc_h, decode_type, eval_tours + ) + + return pointer_probs, input_idxs diff --git a/rl4co/models/zoo/symnco/__init__.py b/rl4co/models/zoo/symnco/__init__.py new file mode 100644 index 00000000..80a9ca2e --- /dev/null +++ b/rl4co/models/zoo/symnco/__init__.py @@ -0,0 +1,2 @@ +from .model import SymNCO +from .policy import SymNCOPolicy diff --git a/rl4co/models/zoo/symnco/losses.py b/rl4co/models/zoo/symnco/losses.py new file mode 100644 index 00000000..38f9265e --- /dev/null +++ b/rl4co/models/zoo/symnco/losses.py @@ -0,0 +1,39 @@ +from einops import rearrange +from torch.nn.functional import cosine_similarity + + +def problem_symmetricity_loss(reward, log_likelihood, dim=1): + """REINFORCE loss for problem symmetricity + Baseline is the average reward for all augmented problems + Corresponds to `L_ps` in the SymNCO paper + """ + num_augment = reward.shape[dim] + if num_augment < 2: + return 0 + advantage = reward - reward.mean(dim=dim, keepdim=True) + loss = -advantage * log_likelihood + return loss.mean() + + +def solution_symmetricity_loss(reward, log_likelihood, dim=-1): + """REINFORCE loss for solution symmetricity + Baseline is the average reward for all start nodes + Corresponds to `L_ss` in the SymNCO paper + """ + num_starts = reward.shape[dim] + if num_starts < 2: + return 0 + advantage = reward - reward.mean(dim=dim, keepdim=True) + loss = -advantage * log_likelihood + return loss.mean() + + +def invariance_loss(proj_embed, num_augment): + """Loss for invariant representation on projected nodes + Corresponds to `L_inv` in the SymNCO paper + """ + pe = rearrange(proj_embed, "(b a) ... -> b a ...", a=num_augment) + similarity = sum( + [cosine_similarity(pe[:, 0], pe[:, i], dim=-1) for i in range(1, num_augment)] + ) + return similarity.mean() diff --git a/rl4co/models/zoo/symnco/model.py b/rl4co/models/zoo/symnco/model.py new file mode 100644 index 00000000..93d73d1a --- /dev/null +++ b/rl4co/models/zoo/symnco/model.py @@ -0,0 +1,142 @@ +from typing import Any, Union + +import torch.nn as nn + +from rl4co.data.transforms import StateAugmentation +from rl4co.envs.common.base import RL4COEnvBase +from rl4co.models.rl.reinforce.reinforce import REINFORCE +from rl4co.models.zoo.symnco.losses import ( + invariance_loss, + problem_symmetricity_loss, + solution_symmetricity_loss, +) +from rl4co.models.zoo.symnco.policy import SymNCOPolicy +from rl4co.utils.ops import gather_by_index, get_num_starts, unbatchify +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class SymNCO(REINFORCE): + """SymNCO Model based on REINFORCE with shared baselines. + Based on Kim et al. (2022) https://arxiv.org/abs/2205.13209. + + Args: + env: TorchRL environment to use for the algorithm + policy: Policy to use for the algorithm + policy_kwargs: Keyword arguments for policy + num_augment: Number of augmentations + augment_fn: Function to use for augmentation, defaulting to dihedral_8_augmentation + feats: List of features to augment + alpha: weight for invariance loss + beta: weight for solution symmetricity loss + num_starts: Number of starts for multi-start. If None, use the number of available actions + **kwargs: Keyword arguments passed to the superclass + """ + + def __init__( + self, + env: RL4COEnvBase, + policy: Union[nn.Module, SymNCOPolicy] = None, + policy_kwargs: dict = {}, + baseline: str = "symnco", + num_augment: int = 4, + augment_fn: Union[str, callable] = "symmetric", + feats: list = None, + alpha: float = 0.2, + beta: float = 1, + num_starts: int = 0, + **kwargs, + ): + self.save_hyperparameters(logger=False) + + if policy is None: + policy = SymNCOPolicy(env_name=env.name, **policy_kwargs) + + assert baseline == "symnco", "SymNCO only supports custom-symnco baseline" + baseline = "no" # Pass no baseline to superclass since there are multiple custom baselines + + # Pass no baseline to superclass since there are multiple custom baselines + super().__init__(env, policy, baseline, **kwargs) + + self.num_starts = num_starts + self.num_augment = num_augment + self.augment = StateAugmentation( + num_augment=self.num_augment, augment_fn=augment_fn, feats=feats + ) + self.alpha = alpha # weight for invariance loss + self.beta = beta # weight for solution symmetricity loss + + # Add `_multistart` to decode type for train, val and test in policy if num_starts > 1 + if self.num_starts > 1: + for phase in ["train", "val", "test"]: + self.set_decode_type_multistart(phase) + + def shared_step( + self, batch: Any, batch_idx: int, phase: str, dataloader_idx: int = None + ): + td = self.env.reset(batch) + n_aug, n_start = self.num_augment, self.num_starts + n_start = get_num_starts(td, self.env.name) if n_start is None else n_start + + # Symmetric augmentation + if n_aug > 1: + td = self.augment(td) + + # Evaluate policy + out = self.policy(td, self.env, phase=phase, num_starts=n_start) + + # Unbatchify reward to [batch_size, n_start, n_aug]. + reward = unbatchify(out["reward"], (n_start, n_aug)) + + # Main training loss + if phase == "train": + # [batch_size, n_start, n_aug] + ll = unbatchify(out["log_likelihood"], (n_start, n_aug)) + + # Calculate losses: problem symmetricity, solution symmetricity, invariance + loss_ps = problem_symmetricity_loss(reward, ll) if n_start > 1 else 0 + loss_ss = solution_symmetricity_loss(reward, ll) if n_aug > 1 else 0 + loss_inv = invariance_loss(out["proj_embeddings"], n_aug) if n_aug > 1 else 0 + loss = loss_ps + self.beta * loss_ss + self.alpha * loss_inv + out.update( + { + "loss": loss, + "loss_ss": loss_ss, + "loss_ps": loss_ps, + "loss_inv": loss_inv, + } + ) + + # Log only during validation and test + else: + if n_start > 1: + # max multi-start reward + max_reward, max_idxs = reward.max(dim=1) + out.update({"max_reward": max_reward}) + + # Reshape batch to [batch, n_start, n_aug] + if out.get("actions", None) is not None: + actions = unbatchify(out["actions"], (n_start, n_aug)) + out.update( + {"best_multistart_actions": gather_by_index(actions, max_idxs)} + ) + out["actions"] = actions + + # Get augmentation score only during inference + if n_aug > 1: + # If multistart is enabled, we use the best multistart rewards + reward_ = max_reward if n_start > 1 else reward + max_aug_reward, max_idxs = reward_.max(dim=1) + out.update({"max_aug_reward": max_aug_reward}) + if out.get("best_multistart_actions", None) is not None: + out.update( + { + "best_aug_actions": gather_by_index( + out["best_multistart_actions"], max_idxs + ) + } + ) + + metrics = self.log_metrics(out, phase, dataloader_idx=dataloader_idx) + return {"loss": out.get("loss", None), **metrics} diff --git a/rl4co/models/zoo/symnco/policy.py b/rl4co/models/zoo/symnco/policy.py new file mode 100644 index 00000000..5cf3ebfa --- /dev/null +++ b/rl4co/models/zoo/symnco/policy.py @@ -0,0 +1,91 @@ +from typing import Union + +import torch.nn as nn + +from tensordict.tensordict import TensorDict +from torchrl.modules.models import MLP + +from rl4co.envs import RL4COEnvBase +from rl4co.models.zoo.am import AttentionModelPolicy +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +class SymNCOPolicy(AttentionModelPolicy): + """SymNCO Policy based on AutoregressivePolicy. + This differs from the default :class:`AutoregressivePolicy` in that it + projects the initial embeddings to a lower dimension using a projection head and + returns it. This is used in the SymNCO algorithm to compute the invariance loss. + Based on Kim et al. (2022) https://arxiv.org/abs/2205.13209. + + Args: + embed_dim: Dimension of the embedding + env_name: Name of the environment + num_encoder_layers: Number of layers in the encoder + num_heads: Number of heads in the encoder + normalization: Normalization to use in the encoder + projection_head: Projection head to use + use_projection_head: Whether to use projection head + **kwargs: Keyword arguments passed to the superclass + """ + + def __init__( + self, + embed_dim: int = 128, + env_name: str = "tsp", + num_encoder_layers: int = 3, + num_heads: int = 8, + normalization: str = "batch", + projection_head: nn.Module = None, + use_projection_head: bool = True, + **kwargs, + ): + super(SymNCOPolicy, self).__init__( + env_name=env_name, + embed_dim=embed_dim, + num_encoder_layers=num_encoder_layers, + num_heads=num_heads, + normalization=normalization, + **kwargs, + ) + + self.use_projection_head = use_projection_head + + if self.use_projection_head: + self.projection_head = ( + MLP(embed_dim, embed_dim, 1, embed_dim, nn.ReLU) + if projection_head is None + else projection_head + ) + + def forward( + self, + td: TensorDict, + env: Union[str, RL4COEnvBase] = None, + phase: str = "train", + return_actions: bool = False, + return_init_embeds: bool = True, + **kwargs, + ) -> dict: + super().forward.__doc__ # trick to get docs from parent class + + # Ensure that if use_projection_head is True, then return_init_embeds is True + assert not ( + self.use_projection_head and not return_init_embeds + ), "If `use_projection_head` is True, then we must `return_init_embeds`" + + out = super().forward( + td, + env, + phase, + return_actions=return_actions, + return_init_embeds=return_init_embeds, + **kwargs, + ) + + # Project initial embeddings + if self.use_projection_head: + out["proj_embeddings"] = self.projection_head(out["init_embeds"]) + + return out diff --git a/rl4co/tasks/README.md b/rl4co/tasks/README.md new file mode 100644 index 00000000..19c4dda7 --- /dev/null +++ b/rl4co/tasks/README.md @@ -0,0 +1,103 @@ +# Evaluation + +To evaluate your trained model, here are some steps to follow: + +**Step 1**. Prepare your *pre-trained model checkpoint* and *test instances data file*. Put them in your preferred place. e.g., we will test the `AttentionModel` on TSP50: + +``` +. +├── rl4co/ +│ └── ... +├── checkpoints/ +│ └── am-tsp50.ckpt +└── data/ + └── tsp/ + └── tsp50_test_seed1234.npz +``` + +You can generate the test instances data file by running the following command: + +```bash +python -c "from rl4co.data.generate_data import generate_default_datasets; generate_default_datasets('data')" +``` + +**Step 2**. Run the `eval.py` with your customized setting. e.g., let's use the `sampling` method with a `top_p=0.95` sampling strategy: + +```bash +python rl4co/tasks/eval.py --problem tsp --data-path data/tsp/tsp50_test_seed1234.npz --model AttentionModel --ckpt-path checkpoints/am-tsp50.ckpt --method sampling --top-p 0.95 +``` + +Arguments guideline: +- `--problem`: the problem name, e.g., `tsp`, `cvrp`, `pdp`, etc. This should be consistent with the `env.name`. Default is `tsp`. +- `--generator-params`: the generator parameters for the test instances. You could specify the `num_loc` etc. Default is `{'num_loc': 50}`. +- `--data-path`: the path to the test instances data file. Default is `data/tsp/tsp50_test_seed1234.npz`. +- `--model`: the model **class name**, e.g., `AttentionModel`, `POMO`, `SymNCO`, etc. It will be dynamically imported and instantiated. Default is `AttentionModel`. +- `--ckpt-path`: the path to the pre-trained model checkpoint. Default is `checkpoints/am-tsp50.ckpt`. +- `--device`: the device to run the evaluation, e.g., `cuda:0`, `cpu`, etc. Default is `cuda:0`. +- `--method`: the evaluation method, e.g., `greedy`, `sampling`, `multistart_greedy`, `augment_dihedral_8`, `augment`, `multistart_greedy_augment_dihedral_8`, and `multistart_greedy_augment`. Default is `greedy`. +- `--save-results`: whether to save the evaluation results as a `.pkl` file. Deafult is `True`. The results include `actions`, `rewards`, `inference_time`, and `avg_reward`. +- `--save-path`: the path to save the evaluation results. Default is `results/`. +- `--num-instances`: the number of test instances to evaluate. Default is `1000`. + +If you use the `sampling` method, you may need to specify the following parameters: +- `--samples`: the number of samples for the sampling method. Default is `1280`. +- `--temperature`: the temperature for the sampling method. Default is `1.0`. +- `--top-p`: the top-p for the sampling method. Default is `0.0`, i.e. not activated. +- `--top-k`: the top-k for the sampling method. Deafult is `0`, i.e. not activated. +- `--select-best`: whether to select the best action from the sampling results. If `False`, the results will include all sampled rewards, i.e., `[num_instances * num_samples]`. + +If you use the `augment` method, you may need to specify the following parameters: +- `--num-augments`: the number of augmented instances for the augment method. Default is `8`. +- `--force-dihedral-8`: whether to force the augmented instances to be dihedral 8. Default is `True`. + +**Step 3**. If you want to launch several evaluations with various parameters, you may refer to the following examples: + +- Evaluate POMO on TSP50 with a sampling of different Top-p and temperature: + + ```bash + #!/bin/bash + + top_p_list=(0.5 0.6 0.7 0.8 0.9 0.95 0.98 0.99 0.995 1.0) + temp_list=(0.1 0.3 0.5 0.7 0.8 0.9 1.0 1.1 1.2 1.5 1.8 2.0 2.2 2.5 2.8 3.0) + + device=cuda:0 + + problem=tsp + model=POMO + ckpt_path=checkpoints/pomo-tsp50.ckpt + data_path=data/tsp/tsp50_test_seed1234.npz + + num_instances=1000 + save_path=results/tsp50-pomo-topp-1k + + for top_p in ${top_p_list[@]}; do + for temp in ${temp_list[@]}; do + python rl4co/tasks/eval.py --problem ${problem} --model ${model} --ckpt_path ${ckpt_path} --data_path ${data_path} --save_path ${save_path} --method sampling --temperature=${temp} --top_p=${top_p} --top_k=0 --device ${device} + done + done + ``` + +- Evaluate POMO on CVRP50 with a sampling of different Top-k and temperature: + + ```bash + #!/bin/bash + + top_k_list=(5 10 15 20 25) + temp_list=(0.1 0.3 0.5 0.7 0.8 0.9 1.0 1.1 1.2 1.5 1.8 2.0 2.2 2.5 2.8 3.0) + + device=cuda:1 + + problem=cvrp + model=POMO + ckpt_path=checkpoints/pomo-cvrp50.ckpt + data_path=data/vrp/vrp50_test_seed1234.npz + + num_instances=1000 + save_path=results/cvrp50-pomo-topk-1k + + for top_k in ${top_k_list[@]}; do + for temp in ${temp_list[@]}; do + python rl4co/tasks/eval.py --problem ${problem} --model ${model} --ckpt_path ${ckpt_path} --data_path ${data_path} --save_path ${save_path} --method sampling --temperature=${temp} --top_p=0.0 --top_k=${top_k} --device ${device} + done + done + ``` diff --git a/rl4co/tasks/__init__.py b/rl4co/tasks/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/tasks/eval.py b/rl4co/tasks/eval.py new file mode 100644 index 00000000..7580d374 --- /dev/null +++ b/rl4co/tasks/eval.py @@ -0,0 +1,595 @@ +import time + +import numpy as np +import torch + +from torch.utils.data import DataLoader +from tqdm.auto import tqdm + +from rl4co.data.transforms import StateAugmentation +from rl4co.utils.ops import batchify, gather_by_index, sample_n_random_actions, unbatchify + + +def check_unused_kwargs(class_, kwargs): + if len(kwargs) > 0 and not (len(kwargs) == 1 and "progress" in kwargs): + print(f"Warning: {class_.__class__.__name__} does not use kwargs {kwargs}") + + +class EvalBase: + """Base class for evaluation + + Args: + env: Environment + progress: Whether to show progress bar + **kwargs: Additional arguments (to be implemented in subclasses) + """ + + name = "base" + + def __init__(self, env, progress=True, **kwargs): + check_unused_kwargs(self, kwargs) + self.env = env + self.progress = progress + + def __call__(self, policy, dataloader, **kwargs): + """Evaluate the policy on the given dataloader with **kwargs parameter + self._inner is implemented in subclasses and returns actions and rewards + """ + start = time.time() + + with torch.inference_mode(): + rewards_list = [] + actions_list = [] + + for batch in tqdm( + dataloader, disable=not self.progress, desc=f"Running {self.name}" + ): + td = batch.to(next(policy.parameters()).device) + td = self.env.reset(td) + actions, rewards = self._inner(policy, td, **kwargs) + rewards_list.append(rewards) + actions_list.append(actions) + + rewards = torch.cat(rewards_list) + + # Padding: pad actions to the same length with zeros + max_length = max(action.size(-1) for action in actions_list) + actions = torch.cat( + [ + torch.nn.functional.pad(action, (0, max_length - action.size(-1))) + for action in actions_list + ], + 0, + ) + + inference_time = time.time() - start + + tqdm.write(f"Mean reward for {self.name}: {rewards.mean():.4f}") + tqdm.write(f"Time: {inference_time:.4f}s") + + # Empty cache + if torch.cuda.is_available(): + torch.cuda.empty_cache() + + return { + "actions": actions.cpu(), + "rewards": rewards.cpu(), + "inference_time": inference_time, + "avg_reward": rewards.cpu().mean(), + } + + def _inner(self, policy, td): + """Inner function to be implemented in subclasses. + This function returns actions and rewards for the given policy + """ + raise NotImplementedError("Implement in subclass") + + +class GreedyEval(EvalBase): + """Evaluates the policy using greedy decoding and single trajectory""" + + name = "greedy" + + def __init__(self, env, **kwargs): + check_unused_kwargs(self, kwargs) + super().__init__(env, kwargs.get("progress", True)) + + def _inner(self, policy, td): + out = policy( + td.clone(), + decode_type="greedy", + num_starts=0, + return_actions=True, + ) + rewards = self.env.get_reward(td, out["actions"]) + return out["actions"], rewards + + +class AugmentationEval(EvalBase): + """Evaluates the policy via N state augmentations + `force_dihedral_8` forces the use of 8 augmentations (rotations and flips) as in POMO + https://en.wikipedia.org/wiki/Examples_of_groups#dihedral_group_of_order_8 + + Args: + num_augment (int): Number of state augmentations + force_dihedral_8 (bool): Whether to force the use of 8 augmentations + """ + + name = "augmentation" + + def __init__(self, env, num_augment=8, force_dihedral_8=False, feats=None, **kwargs): + check_unused_kwargs(self, kwargs) + super().__init__(env, kwargs.get("progress", True)) + self.augmentation = StateAugmentation( + num_augment=num_augment, + augment_fn="dihedral8" if force_dihedral_8 else "symmetric", + feats=feats, + ) + + def _inner(self, policy, td, num_augment=None): + if num_augment is None: + num_augment = self.augmentation.num_augment + td_init = td.clone() + td = self.augmentation(td) + out = policy(td.clone(), decode_type="greedy", num_starts=0, return_actions=True) + + # Move into batches and compute rewards + rewards = self.env.get_reward(batchify(td_init, num_augment), out["actions"]) + rewards = unbatchify(rewards, num_augment) + actions = unbatchify(out["actions"], num_augment) + + # Get best reward and corresponding action + rewards, max_idxs = rewards.max(dim=1) + actions = gather_by_index(actions, max_idxs, dim=1) + return actions, rewards + + @property + def num_augment(self): + return self.augmentation.num_augment + + +class SamplingEval(EvalBase): + """Evaluates the policy via N samples from the policy + + Args: + samples (int): Number of samples to take + softmax_temp (float): Temperature for softmax sampling. The higher the temperature, the more random the sampling + """ + + name = "sampling" + + def __init__( + self, + env, + samples, + softmax_temp=None, + select_best=True, + temperature=1.0, + top_p=0.0, + top_k=0, + **kwargs, + ): + check_unused_kwargs(self, kwargs) + super().__init__(env, kwargs.get("progress", True)) + + self.samples = samples + self.softmax_temp = softmax_temp + self.temperature = temperature + self.select_best = select_best + self.top_p = top_p + self.top_k = top_k + + def _inner(self, policy, td): + out = policy( + td.clone(), + decode_type="sampling", + num_starts=self.samples, + temperature=self.temperature, + top_p=self.top_p, + top_k=self.top_k, + multisample=True, + return_actions=True, + softmax_temp=self.softmax_temp, + select_best=self.select_best, + select_start_nodes_fn=lambda td, _, n: sample_n_random_actions(td, n), + ) + + # Move into batches and compute rewards + rewards = out["reward"] + actions = out["actions"] + + return actions, rewards + + +class GreedyMultiStartEval(EvalBase): + """Evaluates the policy via `num_starts` greedy multistarts samples from the policy + + Args: + num_starts (int): Number of greedy multistarts to use + """ + + name = "multistart_greedy" + + def __init__(self, env, num_starts=None, **kwargs): + check_unused_kwargs(self, kwargs) + super().__init__(env, kwargs.get("progress", True)) + + assert num_starts is not None, "Must specify num_starts" + self.num_starts = num_starts + + def _inner(self, policy, td): + td_init = td.clone() + out = policy( + td.clone(), + decode_type="multistart_greedy", + num_starts=self.num_starts, + return_actions=True, + ) + + # Move into batches and compute rewards + td = batchify(td_init, self.num_starts) + rewards = self.env.get_reward(td, out["actions"]) + rewards = unbatchify(rewards, self.num_starts) + actions = unbatchify(out["actions"], self.num_starts) + + # Get the best trajectories + rewards, max_idxs = rewards.max(dim=1) + actions = gather_by_index(actions, max_idxs, dim=1) + return actions, rewards + + +class GreedyMultiStartAugmentEval(EvalBase): + """Evaluates the policy via `num_starts` samples from the policy + and `num_augment` augmentations of each sample.` + `force_dihedral_8` forces the use of 8 augmentations (rotations and flips) as in POMO + https://en.wikipedia.org/wiki/Examples_of_groups#dihedral_group_of_order_8 + + Args: + num_starts: Number of greedy multistart samples + num_augment: Number of augmentations per sample + force_dihedral_8: If True, force the use of 8 augmentations (rotations and flips) as in POMO + """ + + name = "multistart_greedy_augment" + + def __init__( + self, + env, + num_starts=None, + num_augment=8, + force_dihedral_8=False, + feats=None, + **kwargs, + ): + check_unused_kwargs(self, kwargs) + super().__init__(env, kwargs.get("progress", True)) + + assert num_starts is not None, "Must specify num_starts" + self.num_starts = num_starts + assert not ( + num_augment != 8 and force_dihedral_8 + ), "Cannot force dihedral 8 when num_augment != 8" + self.augmentation = StateAugmentation( + num_augment=num_augment, + augment_fn="dihedral8" if force_dihedral_8 else "symmetric", + feats=feats, + ) + + def _inner(self, policy, td, num_augment=None): + if num_augment is None: + num_augment = self.augmentation.num_augment + + td_init = td.clone() + + td = self.augmentation(td) + out = policy( + td.clone(), + decode_type="multistart_greedy", + num_starts=self.num_starts, + return_actions=True, + ) + + # Move into batches and compute rewards + td = batchify(td_init, (num_augment, self.num_starts)) + rewards = self.env.get_reward(td, out["actions"]) + rewards = unbatchify(rewards, self.num_starts * num_augment) + actions = unbatchify(out["actions"], self.num_starts * num_augment) + + # Get the best trajectories + rewards, max_idxs = rewards.max(dim=1) + actions = gather_by_index(actions, max_idxs, dim=1) + return actions, rewards + + @property + def num_augment(self): + return self.augmentation.num_augment + + +def get_automatic_batch_size(eval_fn, start_batch_size=8192, max_batch_size=4096): + """Automatically reduces the batch size based on the eval function + + Args: + eval_fn: The eval function + start_batch_size: The starting batch size. This should be the theoretical maximum batch size + max_batch_size: The maximum batch size. This is the practical maximum batch size + """ + batch_size = start_batch_size + + effective_ratio = 1 + + if hasattr(eval_fn, "num_starts"): + batch_size = batch_size // (eval_fn.num_starts // 10) + effective_ratio *= eval_fn.num_starts // 10 + if hasattr(eval_fn, "num_augment"): + batch_size = batch_size // eval_fn.num_augment + effective_ratio *= eval_fn.num_augment + if hasattr(eval_fn, "samples"): + batch_size = batch_size // eval_fn.samples + effective_ratio *= eval_fn.samples + + batch_size = min(batch_size, max_batch_size) + # get closest integer power of 2 + batch_size = 2 ** int(np.log2(batch_size)) + + print(f"Effective batch size: {batch_size} (ratio: {effective_ratio})") + + return batch_size + + +def evaluate_policy( + env, + policy, + dataset, + method="greedy", + batch_size=None, + max_batch_size=4096, + start_batch_size=8192, + auto_batch_size=True, + samples=1280, + softmax_temp=1.0, + num_augment=8, + force_dihedral_8=True, + **kwargs, +): + num_loc = getattr(env.generator, "num_loc", None) + + methods_mapping = { + "greedy": {"func": GreedyEval, "kwargs": {}}, + "sampling": { + "func": SamplingEval, + "kwargs": {"samples": samples, "softmax_temp": softmax_temp}, + }, + "multistart_greedy": { + "func": GreedyMultiStartEval, + "kwargs": {"num_starts": num_loc}, + }, + "augment_dihedral_8": { + "func": AugmentationEval, + "kwargs": {"num_augment": num_augment, "force_dihedral_8": force_dihedral_8}, + }, + "augment": {"func": AugmentationEval, "kwargs": {"num_augment": num_augment}}, + "multistart_greedy_augment_dihedral_8": { + "func": GreedyMultiStartAugmentEval, + "kwargs": { + "num_augment": num_augment, + "force_dihedral_8": force_dihedral_8, + "num_starts": num_loc, + }, + }, + "multistart_greedy_augment": { + "func": GreedyMultiStartAugmentEval, + "kwargs": {"num_augment": num_augment, "num_starts": num_loc}, + }, + } + + assert method in methods_mapping, "Method {} not found".format(method) + + # Set up the evaluation function + eval_settings = methods_mapping[method] + func, kwargs_ = eval_settings["func"], eval_settings["kwargs"] + # subsitute kwargs with the ones passed in + kwargs_.update(kwargs) + kwargs = kwargs_ + eval_fn = func(env, **kwargs) + + if auto_batch_size: + assert ( + batch_size is None + ), "Cannot specify batch_size when auto_batch_size is True" + batch_size = get_automatic_batch_size( + eval_fn, max_batch_size=max_batch_size, start_batch_size=start_batch_size + ) + print("Using automatic batch size: {}".format(batch_size)) + + # Set up the dataloader + dataloader = DataLoader( + dataset, + batch_size=batch_size, + shuffle=False, + num_workers=0, + collate_fn=dataset.collate_fn, + ) + + # Run evaluation + retvals = eval_fn(policy, dataloader) + + return retvals + + +if __name__ == "__main__": + import argparse + import importlib + import os + import pickle + + import torch + + from rl4co.envs import get_env + + parser = argparse.ArgumentParser() + + # Environment + parser.add_argument("--problem", type=str, default="tsp", help="Problem to solve") + parser.add_argument( + "--generator-params", + type=dict, + default={"num_loc": 50}, + help="Generator parameters for the environment", + ) + parser.add_argument( + "--data-path", + type=str, + default="data/tsp/tsp50_test_seed1234.npz", + help="Path of the test data npz file", + ) + + # Model + parser.add_argument( + "--model", + type=str, + default="AttentionModel", + help="The class name of the valid model", + ) + parser.add_argument( + "--ckpt-path", + type=str, + default="checkpoints/am-tsp50.ckpt", + help="The path of the checkpoint file", + ) + parser.add_argument( + "--device", type=str, default="cuda:1", help="Device to run the evaluation" + ) + + # Evaluation + parser.add_argument( + "--method", + type=str, + default="greedy", + help="Evaluation method, support 'greedy', 'sampling',\ + 'multistart_greedy', 'augment_dihedral_8', 'augment', 'multistart_greedy_augment_dihedral_8',\ + 'multistart_greedy_augment'", + ) + parser.add_argument( + "--temperature", type=float, default=1.0, help="Temperature for sampling" + ) + parser.add_argument( + "--top-p", + type=float, + default=0.0, + help="Top-p for sampling, from 0.0 to 1.0, 0.0 means not activated", + ) + parser.add_argument("--top-k", type=int, default=0, help="Top-k for sampling") + parser.add_argument( + "--select-best", + default=True, + action=argparse.BooleanOptionalAction, + help="During sampling, whether to select the best action, use --no-select_best to disable", + ) + parser.add_argument( + "--save-results", + default=True, + action=argparse.BooleanOptionalAction, + help="Whether to save the evaluation results", + ) + parser.add_argument( + "--save-path", + type=str, + default="results", + help="The root path to save the results", + ) + parser.add_argument( + "--num-instances", + type=int, + default=1000, + help="Number of instances to test, maximum 10000", + ) + + parser.add_argument( + "--samples", type=int, default=1280, help="Number of samples for sampling method" + ) + parser.add_argument( + "--softmax-temp", + type=float, + default=1.0, + help="Temperature for softmax in the sampling method", + ) + parser.add_argument( + "--num-augment", + type=int, + default=8, + help="Number of augmentations for augmentation method", + ) + parser.add_argument( + "--force-dihedral-8", + default=True, + action=argparse.BooleanOptionalAction, + help="Force the use of 8 augmentations for augmentation method", + ) + + opts = parser.parse_args() + + # Log the evaluation setting information + print(f"Problem: {opts.problem}-{opts.generator_params['num_loc']}") + print(f"Model: {opts.model}") + print(f"Loading test instances from: {opts.data_path}") + print(f"Loading model checkpoint from: {opts.ckpt_path}") + print(f"Using the device: {opts.device}") + print(f"Evaluation method: {opts.method}") + print(f"Number of instances to test: {opts.num_instances}") + + if opts.method == "sampling": + print(f"[Sampling] Number of samples: {opts.samples}") + print(f"[Sampling] Temperature: {opts.temperature}") + print(f"[Sampling] Top-p: {opts.top_p}") + print(f"[Sampling] Top-k: {opts.top_k}") + print(f"[Sampling] Softmax temperature: {opts.softmax_temp}") + print(f"[Sampling] Select best: {opts.select_best}") + + if opts.method == "augment" or opts.method == "augment_dihedral_8": + print(f"[Augmentation] Number of augmentations: {opts.num_augment}") + print(f"[Augmentation] Force dihedral 8: {opts.force_dihedral_8}") + + if opts.save_results: + print(f"Saving the results to: {opts.save_path}") + else: + print("[Warning] The result will not be saved!") + + # Init the environment + env = get_env(opts.problem, generator_params=opts.generator_params) + + # Load the test data + dataset = env.dataset(filename=opts.data_path) + + # Restrict the instances of testing + dataset.data_len = min(opts.num_instances, len(dataset)) + + # Load the model from checkpoint + model_root = importlib.import_module("rl4co.models.zoo") + model_cls = getattr(model_root, opts.model) + model = model_cls.load_from_checkpoint(opts.ckpt_path, load_baseline=False) + model = model.to(opts.device) + + # Evaluate + result = evaluate_policy( + env=env, + policy=model.policy, + dataset=dataset, + method=opts.method, + temperature=opts.temperature, + top_p=opts.top_p, + top_k=opts.top_k, + samples=opts.samples, + softmax_temp=opts.softmax_temp, + num_augment=opts.num_augment, + select_best=True, + force_dihedral_8=True, + ) + + # Save the results + if opts.save_results: + if not os.path.exists(opts.save_path): + os.makedirs(opts.save_path) + save_fname = f"{env.name}{env.generator.num_loc}-{opts.model}-{opts.method}-temp-{opts.temperature}-top_p-{opts.top_p}-top_k-{opts.top_k}.pkl" + save_path = os.path.join(opts.save_path, save_fname) + with open(save_path, "wb") as f: + pickle.dump(result, f) diff --git a/rl4co/tasks/index.html b/rl4co/tasks/index.html new file mode 100644 index 00000000..11fadac5 --- /dev/null +++ b/rl4co/tasks/index.html @@ -0,0 +1,2454 @@ + + + + + + + + + + + + + + + + + + + + + + + Evaluation - RL4CO + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + + + + +
+
+ + + +
+
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+ + + + + + + + + +

Evaluation

+

To evaluate your trained model, here are some steps to follow:

+

Step 1. Prepare your pre-trained model checkpoint and test instances data file. Put them in your preferred place. e.g., we will test the AttentionModel on TSP50:

+
.
+├── rl4co/
+│   └── ...
+├── checkpoints/
+│   └── am-tsp50.ckpt
+└── data/
+    └── tsp/
+        └── tsp50_test_seed1234.npz
+
+

You can generate the test instances data file by running the following command:

+
python -c "from rl4co.data.generate_data import generate_default_datasets; generate_default_datasets('data')"
+
+

Step 2. Run the eval.py with your customized setting. e.g., let's use the sampling method with a top_p=0.95 sampling strategy:

+
python rl4co/tasks/eval.py --problem tsp --data-path data/tsp/tsp50_test_seed1234.npz --model AttentionModel --ckpt-path checkpoints/am-tsp50.ckpt --method sampling --top-p 0.95
+
+

Arguments guideline:

+
    +
  • --problem: the problem name, e.g., tsp, cvrp, pdp, etc. This should be consistent with the env.name. Default is tsp.
  • +
  • --generator-params: the generator parameters for the test instances. You could specify the num_loc etc. Default is {'num_loc': 50}.
  • +
  • --data-path: the path to the test instances data file. Default is data/tsp/tsp50_test_seed1234.npz.
  • +
  • --model: the model class name, e.g., AttentionModel, POMO, SymNCO, etc. It will be dynamically imported and instantiated. Default is AttentionModel.
  • +
  • --ckpt-path: the path to the pre-trained model checkpoint. Default is checkpoints/am-tsp50.ckpt.
  • +
  • --device: the device to run the evaluation, e.g., cuda:0, cpu, etc. Default is cuda:0.
  • +
  • --method: the evaluation method, e.g., greedy, sampling, multistart_greedy, augment_dihedral_8, augment, multistart_greedy_augment_dihedral_8, and multistart_greedy_augment. Default is greedy.
  • +
  • --save-results: whether to save the evaluation results as a .pkl file. Deafult is True. The results include actions, rewards, inference_time, and avg_reward.
  • +
  • --save-path: the path to save the evaluation results. Default is results/.
  • +
  • --num-instances: the number of test instances to evaluate. Default is 1000.
  • +
+

If you use the sampling method, you may need to specify the following parameters:

+
    +
  • --samples: the number of samples for the sampling method. Default is 1280.
  • +
  • --temperature: the temperature for the sampling method. Default is 1.0.
  • +
  • --top-p: the top-p for the sampling method. Default is 0.0, i.e. not activated.
  • +
  • --top-k: the top-k for the sampling method. Deafult is 0, i.e. not activated.
  • +
  • --select-best: whether to select the best action from the sampling results. If False, the results will include all sampled rewards, i.e., [num_instances * num_samples].
  • +
+

If you use the augment method, you may need to specify the following parameters:

+
    +
  • --num-augments: the number of augmented instances for the augment method. Default is 8.
  • +
  • --force-dihedral-8: whether to force the augmented instances to be dihedral 8. Default is True.
  • +
+

Step 3. If you want to launch several evaluations with various parameters, you may refer to the following examples:

+
    +
  • Evaluate POMO on TSP50 with a sampling of different Top-p and temperature:
        #!/bin/bash
    +
    +    top_p_list=(0.5 0.6 0.7 0.8 0.9 0.95 0.98 0.99 0.995 1.0)
    +    temp_list=(0.1 0.3 0.5 0.7 0.8 0.9 1.0 1.1 1.2 1.5 1.8 2.0 2.2 2.5 2.8 3.0)
    +
    +    device=cuda:0
    +
    +    problem=tsp
    +    model=POMO
    +    ckpt_path=checkpoints/pomo-tsp50.ckpt
    +    data_path=data/tsp/tsp50_test_seed1234.npz
    +
    +    num_instances=1000
    +    save_path=results/tsp50-pomo-topp-1k
    +
    +    for top_p in ${top_p_list[@]}; do
    +        for temp in ${temp_list[@]}; do
    +            python rl4co/tasks/eval.py --problem ${problem} --model ${model} --ckpt_path ${ckpt_path} --data_path ${data_path} --save_path ${save_path} --method sampling --temperature=${temp} --top_p=${top_p} --top_k=0 --device ${device}
    +        done
    +    done
    +
    +
  • +
+
    +
  • Evaluate POMO on CVRP50 with a sampling of different Top-k and temperature:
        #!/bin/bash
    +
    +    top_k_list=(5 10 15 20 25)
    +    temp_list=(0.1 0.3 0.5 0.7 0.8 0.9 1.0 1.1 1.2 1.5 1.8 2.0 2.2 2.5 2.8 3.0)
    +
    +    device=cuda:1
    +
    +    problem=cvrp
    +    model=POMO
    +    ckpt_path=checkpoints/pomo-cvrp50.ckpt
    +    data_path=data/vrp/vrp50_test_seed1234.npz
    +
    +    num_instances=1000
    +    save_path=results/cvrp50-pomo-topk-1k
    +
    +    for top_k in ${top_k_list[@]}; do
    +        for temp in ${temp_list[@]}; do
    +            python rl4co/tasks/eval.py --problem ${problem} --model ${model} --ckpt_path ${ckpt_path} --data_path ${data_path} --save_path ${save_path} --method sampling --temperature=${temp} --top_p=0.0 --top_k=${top_k} --device ${device}
    +        done
    +    done
    +
    +
  • +
+ + + + + + + + + + + + + + +
+
+ + + + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rl4co/tasks/train.py b/rl4co/tasks/train.py new file mode 100644 index 00000000..b1d104b4 --- /dev/null +++ b/rl4co/tasks/train.py @@ -0,0 +1,117 @@ +from typing import List, Optional, Tuple + +import hydra +import lightning as L +import pyrootutils +import torch + +from lightning import Callback, LightningModule +from lightning.pytorch.loggers import Logger +from omegaconf import DictConfig + +from rl4co import utils +from rl4co.utils import RL4COTrainer + +pyrootutils.setup_root(__file__, indicator=".gitignore", pythonpath=True) + + +log = utils.get_pylogger(__name__) + + +@utils.task_wrapper +def run(cfg: DictConfig) -> Tuple[dict, dict]: + """Trains the model. Can additionally evaluate on a testset, using best weights obtained during + training. + This method is wrapped in optional @task_wrapper decorator, that controls the behavior during + failure. Useful for multiruns, saving info about the crash, etc. + + Args: + cfg (DictConfig): Configuration composed by Hydra. + Returns: + Tuple[dict, dict]: Dict with metrics and dict with all instantiated objects. + """ + + # set seed for random number generators in pytorch, numpy and python.random + if cfg.get("seed"): + L.seed_everything(cfg.seed, workers=True) + + # We instantiate the environment separately and then pass it to the model + log.info(f"Instantiating environment <{cfg.env._target_}>") + env = hydra.utils.instantiate(cfg.env) + + # Note that the RL environment is instantiated inside the model + log.info(f"Instantiating model <{cfg.model._target_}>") + model: LightningModule = hydra.utils.instantiate(cfg.model, env) + + log.info("Instantiating callbacks...") + callbacks: List[Callback] = utils.instantiate_callbacks(cfg.get("callbacks")) + + log.info("Instantiating loggers...") + logger: List[Logger] = utils.instantiate_loggers(cfg.get("logger"), model) + + log.info("Instantiating trainer...") + trainer: RL4COTrainer = hydra.utils.instantiate( + cfg.trainer, + callbacks=callbacks, + logger=logger, + ) + + object_dict = { + "cfg": cfg, + "model": model, + "callbacks": callbacks, + "logger": logger, + "trainer": trainer, + } + + if logger: + log.info("Logging hyperparameters!") + utils.log_hyperparameters(object_dict) + + if cfg.get("compile", False): + log.info("Compiling model!") + model = torch.compile(model) + + if cfg.get("train"): + log.info("Starting training!") + trainer.fit(model=model, ckpt_path=cfg.get("ckpt_path")) + + train_metrics = trainer.callback_metrics + + if cfg.get("test"): + log.info("Starting testing!") + ckpt_path = trainer.checkpoint_callback.best_model_path + if ckpt_path == "": + log.warning("Best ckpt not found! Using current weights for testing...") + ckpt_path = None + trainer.test(model=model, ckpt_path=ckpt_path) + log.info(f"Best ckpt path: {ckpt_path}") + + test_metrics = trainer.callback_metrics + + # merge train and test metrics + metric_dict = {**train_metrics, **test_metrics} + + return metric_dict, object_dict + + +@hydra.main(version_base="1.3", config_path="../../configs", config_name="main.yaml") +def train(cfg: DictConfig) -> Optional[float]: + # apply extra utilities + # (e.g. ask for tags if none are provided in cfg, print cfg tree, etc.) + utils.extras(cfg) + + # train the model + metric_dict, _ = run(cfg) + + # safely retrieve metric value for hydra-based hyperparameter optimization + metric_value = utils.get_metric_value( + metric_dict=metric_dict, metric_name=cfg.get("optimized_metric") + ) + + # return optimized metric + return metric_value + + +if __name__ == "__main__": + train() diff --git a/rl4co/utils/__init__.py b/rl4co/utils/__init__.py new file mode 100644 index 00000000..4b0246aa --- /dev/null +++ b/rl4co/utils/__init__.py @@ -0,0 +1,11 @@ +from rl4co.utils.instantiators import instantiate_callbacks, instantiate_loggers +from rl4co.utils.pylogger import get_pylogger +from rl4co.utils.rich_utils import enforce_tags, print_config_tree +from rl4co.utils.trainer import RL4COTrainer +from rl4co.utils.utils import ( + extras, + get_metric_value, + log_hyperparameters, + show_versions, + task_wrapper, +) diff --git a/rl4co/utils/callbacks/__init__.py b/rl4co/utils/callbacks/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rl4co/utils/callbacks/speed_monitor.py b/rl4co/utils/callbacks/speed_monitor.py new file mode 100644 index 00000000..3f1ab6ae --- /dev/null +++ b/rl4co/utils/callbacks/speed_monitor.py @@ -0,0 +1,123 @@ +# Adapted from https://pytorch-lightning.readthedocs.io/en/latest/_modules/pytorch_lightning/callbacks/gpu_stats_monitor.html#GPUStatsMonitor +# We only need the speed monitoring, not the GPU monitoring +import time + +import lightning as L + +from lightning.pytorch.callbacks import Callback +from lightning.pytorch.utilities.parsing import AttributeDict +from lightning.pytorch.utilities.rank_zero import rank_zero_only + + +class SpeedMonitor(Callback): + """Monitor the speed of each step and each epoch.""" + + def __init__( + self, + intra_step_time: bool = True, + inter_step_time: bool = True, + epoch_time: bool = True, + verbose=False, + ): + super().__init__() + self._log_stats = AttributeDict( + { + "intra_step_time": intra_step_time, + "inter_step_time": inter_step_time, + "epoch_time": epoch_time, + } + ) + self.verbose = verbose + + def on_train_start(self, trainer: "L.Trainer", L_module: "L.LightningModule") -> None: + self._snap_epoch_time = None + + def on_train_epoch_start( + self, trainer: "L.Trainer", L_module: "L.LightningModule" + ) -> None: + self._snap_intra_step_time = None + self._snap_inter_step_time = None + self._snap_epoch_time = time.time() + + def on_validation_epoch_start( + self, trainer: "L.Trainer", L_module: "L.LightningModule" + ) -> None: + self._snap_inter_step_time = None + + def on_test_epoch_start( + self, trainer: "L.Trainer", L_module: "L.LightningModule" + ) -> None: + self._snap_inter_step_time = None + + @rank_zero_only + def on_train_batch_start( + self, + trainer: "L.Trainer", + *unused_args, + **unused_kwargs, # easy fix for new pytorch lightning versions + ) -> None: + if self._log_stats.intra_step_time: + self._snap_intra_step_time = time.time() + + if not self._should_log(trainer): + return + + logs = {} + if self._log_stats.inter_step_time and self._snap_inter_step_time: + # First log at beginning of second step + logs["time/inter_step (ms)"] = ( + time.time() - self._snap_inter_step_time + ) * 1000 + + if trainer.logger is not None: + trainer.logger.log_metrics(logs, step=trainer.global_step) + + @rank_zero_only + def on_train_batch_end( + self, + trainer: "L.Trainer", + L_module: "L.LightningModule", + *unused_args, + **unused_kwargs, # easy fix for new pytorch lightning versions + ) -> None: + if self._log_stats.inter_step_time: + self._snap_inter_step_time = time.time() + + if ( + self.verbose + and self._log_stats.intra_step_time + and self._snap_intra_step_time + ): + L_module.print( + f"time/intra_step (ms): {(time.time() - self._snap_intra_step_time) * 1000}" + ) + + if not self._should_log(trainer): + return + + logs = {} + if self._log_stats.intra_step_time and self._snap_intra_step_time: + logs["time/intra_step (ms)"] = ( + time.time() - self._snap_intra_step_time + ) * 1000 + + if trainer.logger is not None: + trainer.logger.log_metrics(logs, step=trainer.global_step) + + @rank_zero_only + def on_train_epoch_end( + self, + trainer: "L.Trainer", + L_module: "L.LightningModule", + ) -> None: + logs = {} + if self._log_stats.epoch_time and self._snap_epoch_time: + logs["time/epoch (s)"] = time.time() - self._snap_epoch_time + if trainer.logger is not None: + trainer.logger.log_metrics(logs, step=trainer.global_step) + + @staticmethod + def _should_log(trainer) -> bool: + return ( + trainer.global_step + 1 + ) % trainer.log_every_n_steps == 0 or trainer.should_stop diff --git a/rl4co/utils/decoding.py b/rl4co/utils/decoding.py new file mode 100644 index 00000000..f29e8214 --- /dev/null +++ b/rl4co/utils/decoding.py @@ -0,0 +1,584 @@ +import abc + +from typing import Optional, Tuple + +import torch +import torch.nn.functional as F + +from tensordict.tensordict import TensorDict + +from rl4co.envs import RL4COEnvBase +from rl4co.utils.ops import batchify, gather_by_index, unbatchify, unbatchify_and_gather +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def get_decoding_strategy(decoding_strategy, **config): + strategy_registry = { + "greedy": Greedy, + "sampling": Sampling, + "multistart_greedy": Greedy, + "multistart_sampling": Sampling, + "beam_search": BeamSearch, + "evaluate": Evaluate, + } + + if decoding_strategy not in strategy_registry: + log.warning( + f"Unknown decode type '{decoding_strategy}'. Available decode types: {strategy_registry.keys()}. Defaulting to Sampling." + ) + + if "multistart" in decoding_strategy: + config["multistart"] = True + + return strategy_registry.get(decoding_strategy, Sampling)(**config) + + +def get_log_likelihood(logprobs, actions=None, mask=None, return_sum: bool = True): + """Get log likelihood of selected actions. + Note that mask is a boolean tensor where True means the value should be kept. + + Args: + logprobs: Log probabilities of actions from the model (batch_size, seq_len, action_dim). + actions: Selected actions (batch_size, seq_len). + mask: Action mask. 1 if feasible, 0 otherwise (so we keep if 1 as done in PyTorch). + return_sum: Whether to return the sum of log probabilities or not. Defaults to True. + """ + # Optional: select logp when logp.shape = (bs, dec_steps, N) + if actions is not None and logprobs.dim() == 3: + logprobs = logprobs.gather(-1, actions.unsqueeze(-1)).squeeze(-1) + + # Optional: mask out actions irrelevant to objective so they do not get reinforced + if mask is not None: + logprobs[~mask] = 0 + + assert ( + logprobs > -1000 + ).data.all(), "Logprobs should not be -inf, check sampling procedure!" + + # Calculate log_likelihood + if return_sum: + return logprobs.sum(1) # [batch] + else: + return logprobs # [batch, decode_len] + + +def decode_logprobs(logprobs, mask, decode_type="sampling"): + """Decode log probabilities to select actions with mask. + Note that mask is a boolean tensor where True means the value should be kept. + """ + if "greedy" in decode_type: + selected = DecodingStrategy.greedy(logprobs, mask) + elif "sampling" in decode_type: + selected = DecodingStrategy.sampling(logprobs, mask) + else: + assert False, "Unknown decode type: {}".format(decode_type) + return selected + + +def random_policy(td): + """Helper function to select a random action from available actions""" + action = torch.multinomial(td["action_mask"].float(), 1).squeeze(-1) + td.set("action", action) + return td + + +def rollout(env, td, policy, max_steps: int = None): + """Helper function to rollout a policy. Currently, TorchRL does not allow to step + over envs when done with `env.rollout()`. We need this because for environments that complete at different steps. + """ + + max_steps = float("inf") if max_steps is None else max_steps + actions = [] + steps = 0 + + while not td["done"].all(): + td = policy(td) + actions.append(td["action"]) + td = env.step(td)["next"] + steps += 1 + if steps > max_steps: + log.info("Max steps reached") + break + return ( + env.get_reward(td, torch.stack(actions, dim=1)), + td, + torch.stack(actions, dim=1), + ) + + +def modify_logits_for_top_k_filtering(logits, top_k): + """Set the logits for none top-k values to -inf. Done out-of-place. + Ref: https://github.com/togethercomputer/stripedhyena/blob/7e13f618027fea9625be1f2d2d94f9a361f6bd02/stripedhyena/sample.py#L6 + """ + indices_to_remove = logits < torch.topk(logits, top_k)[0][..., -1, None] + return logits.masked_fill(indices_to_remove, float("-inf")) + + +def modify_logits_for_top_p_filtering(logits, top_p): + """Set the logits for none top-p values to -inf. Done out-of-place. + Ref: https://github.com/togethercomputer/stripedhyena/blob/7e13f618027fea9625be1f2d2d94f9a361f6bd02/stripedhyena/sample.py#L14 + """ + if top_p <= 0.0 or top_p >= 1.0: + return logits + + # First sort and calculate cumulative sum of probabilities. + sorted_logits, sorted_indices = torch.sort(logits, descending=False) + cumulative_probs = sorted_logits.softmax(dim=-1).cumsum(dim=-1) + + # Remove tokens with cumulative top_p above the threshold (token with 0 are kept) + sorted_indices_to_remove = cumulative_probs <= (1 - top_p) + + # Scatter sorted tensors to original indexing + indices_to_remove = sorted_indices_to_remove.scatter( + -1, sorted_indices, sorted_indices_to_remove + ) + return logits.masked_fill(indices_to_remove, float("-inf")) + + +def process_logits( + logits: torch.Tensor, + mask: torch.Tensor = None, + temperature: float = 1.0, + top_p: float = 0.0, + top_k: int = 0, + tanh_clipping: float = 0, + mask_logits: bool = True, +): + """Convert logits to log probabilities with additional features like temperature scaling, top-k and top-p sampling. + + Note: + We convert to log probabilities instead of probabilities to avoid numerical instability. + This is because, roughly, softmax = exp(logits) / sum(exp(logits)) and log(softmax) = logits - log(sum(exp(logits))), + and avoiding the division by the sum of exponentials can help with numerical stability. + You may check the [official PyTorch documentation](https://pytorch.org/docs/stable/generated/torch.nn.functional.log_softmax.html). + + Args: + logits: Logits from the model (batch_size, num_actions). + mask: Action mask. 1 if feasible, 0 otherwise (so we keep if 1 as done in PyTorch). + temperature: Temperature scaling. Higher values make the distribution more uniform (exploration), + lower values make it more peaky (exploitation). + top_p: Top-p sampling, a.k.a. Nucleus Sampling (https://arxiv.org/abs/1904.09751). Remove tokens that have a cumulative probability + less than the threshold 1 - top_p (lower tail of the distribution). If 0, do not perform. + top_k: Top-k sampling, i.e. restrict sampling to the top k logits. If 0, do not perform. Note that we only do filtering and + do not return all the top-k logits here. + tanh_clipping: Tanh clipping (https://arxiv.org/abs/1611.09940). + mask_logits: Whether to mask logits of infeasible actions. + """ + + # Tanh clipping from Bello et al. 2016 + if tanh_clipping > 0: + logits = torch.tanh(logits) * tanh_clipping + + # In RL, we want to mask the logits to prevent the agent from selecting infeasible actions + if mask_logits: + assert mask is not None, "mask must be provided if mask_logits is True" + logits[~mask] = float("-inf") + + logits = logits / temperature # temperature scaling + + if top_k > 0: + top_k = min(top_k, logits.size(-1)) # safety check + logits = modify_logits_for_top_k_filtering(logits, top_k) + + if top_p > 0: + assert top_p <= 1.0, "top-p should be in (0, 1]." + logits = modify_logits_for_top_p_filtering(logits, top_p) + + # Compute log probabilities + return F.log_softmax(logits, dim=-1) + + +class DecodingStrategy(metaclass=abc.ABCMeta): + """Base class for decoding strategies. Subclasses should implement the :meth:`_step` method. + Includes hooks for pre and post main decoding operations. + + Args: + temperature: Temperature scaling. Higher values make the distribution more uniform (exploration), + lower values make it more peaky (exploitation). Defaults to 1.0. + top_p: Top-p sampling, a.k.a. Nucleus Sampling (https://arxiv.org/abs/1904.09751). Defaults to 0.0. + top_k: Top-k sampling, i.e. restrict sampling to the top k logits. If 0, do not perform. Defaults to 0. + mask_logits: Whether to mask logits of infeasible actions. Defaults to True. + tanh_clipping: Tanh clipping (https://arxiv.org/abs/1611.09940). Defaults to 0. + multistart: Whether to use multistart decoding. Defaults to False. + multisample: Whether to use sampling decoding. Defaults to False. + num_starts: Number of starts for multistart decoding. Defaults to None. + """ + + name = "base" + + def __init__( + self, + temperature: float = 1.0, + top_p: float = 0.0, + top_k: int = 0, + mask_logits: bool = True, + tanh_clipping: float = 0, + multistart: bool = False, + multisample: bool = False, + num_starts: Optional[int] = None, + select_start_nodes_fn: Optional[callable] = None, + improvement_method_mode: bool = False, + select_best: bool = False, + store_all_logp: bool = False, + **kwargs, + ) -> None: + self.temperature = temperature + self.top_p = top_p + self.top_k = top_k + self.mask_logits = mask_logits + self.tanh_clipping = tanh_clipping + self.multistart = multistart + self.multisample = multisample + self.num_starts = num_starts + self.select_start_nodes_fn = select_start_nodes_fn + self.improvement_method_mode = improvement_method_mode + self.select_best = select_best + self.store_all_logp = store_all_logp + # initialize buffers + self.actions = [] + self.logprobs = [] + + @abc.abstractmethod + def _step( + self, + logprobs: torch.Tensor, + mask: torch.Tensor, + td: TensorDict, + action: torch.Tensor = None, + **kwargs, + ) -> Tuple[torch.Tensor, torch.Tensor, TensorDict]: + """Main decoding operation. This method should be called in a loop until all sequences are done. + + Args: + logprobs: Log probabilities processed from logits of the model. + mask: Action mask. 1 if feasible, 0 otherwise (so we keep if 1 as done in PyTorch). + td: TensorDict containing the current state of the environment. + action: Optional action to use, e.g. for evaluating log probabilities. + """ + raise NotImplementedError("Must be implemented by subclass") + + def pre_decoder_hook( + self, td: TensorDict, env: RL4COEnvBase, action: torch.Tensor = None + ): + """Pre decoding hook. This method is called before the main decoding operation.""" + + # Multi-start decoding. If num_starts is None, we use the number of actions in the action mask + if self.multistart or self.multisample: + if self.num_starts is None: + self.num_starts = env.get_num_starts(td) + if self.multisample: + log.warn( + f"num_starts is not provided for sampling, using num_starts={self.num_starts}" + ) + else: + if self.num_starts is not None: + if self.num_starts >= 1: + log.warn( + f"num_starts={self.num_starts} is ignored for decode_type={self.name}" + ) + + self.num_starts = 0 + + # Multi-start decoding: first action is chosen by ad-hoc node selection + if self.num_starts >= 1: + if self.multistart: + if action is None: # if action is provided, we use it as the first action + if self.select_start_nodes_fn is not None: + action = self.select_start_nodes_fn(td, env, self.num_starts) + else: + action = env.select_start_nodes(td, num_starts=self.num_starts) + + # Expand td to batch_size * num_starts + td = batchify(td, self.num_starts) + + td.set("action", action) + td = env.step(td)["next"] + # first logprobs is 0, so p = logprobs.exp() = 1 + if self.store_all_logp: + logprobs = torch.zeros_like(td["action_mask"]) # [B, N] + else: + logprobs = torch.zeros_like(action, device=td.device) # [B] + + self.logprobs.append(logprobs) + self.actions.append(action) + else: + # Expand td to batch_size * num_samplestarts + td = batchify(td, self.num_starts) + + return td, env, self.num_starts + + def post_decoder_hook( + self, td: TensorDict, env: RL4COEnvBase + ) -> Tuple[torch.Tensor, torch.Tensor, TensorDict, RL4COEnvBase]: + assert ( + len(self.logprobs) > 0 + ), "No logprobs were collected because all environments were done. Check your initial state" + logprobs = torch.stack(self.logprobs, 1) + actions = torch.stack(self.actions, 1) + if self.num_starts > 0 and self.select_best: + logprobs, actions, td, env = self._select_best(logprobs, actions, td, env) + return logprobs, actions, td, env + + def step( + self, + logits: torch.Tensor, + mask: torch.Tensor, + td: TensorDict = None, + action: torch.Tensor = None, + **kwargs, + ) -> TensorDict: + """Main decoding operation. This method should be called in a loop until all sequences are done. + + Args: + logits: Logits from the model. + mask: Action mask. 1 if feasible, 0 otherwise (so we keep if 1 as done in PyTorch). + td: TensorDict containing the current state of the environment. + action: Optional action to use, e.g. for evaluating log probabilities. + """ + if not self.mask_logits: # set mask_logit to None if mask_logits is False + mask = None + + logprobs = process_logits( + logits, + mask, + temperature=self.temperature, + top_p=self.top_p, + top_k=self.top_k, + tanh_clipping=self.tanh_clipping, + mask_logits=self.mask_logits, + ) + logprobs, selected_action, td = self._step( + logprobs, mask, td, action=action, **kwargs + ) + + # directly return for improvement methods, since the action for improvement methods is finalized in its own policy + if self.improvement_method_mode: + return logprobs, selected_action + # for others + if not self.store_all_logp: + logprobs = gather_by_index(logprobs, selected_action, dim=1) + td.set("action", selected_action) + self.actions.append(selected_action) + self.logprobs.append(logprobs) + return td + + @staticmethod + def greedy(logprobs, mask=None): + """Select the action with the highest probability.""" + # [BS], [BS] + selected = logprobs.argmax(dim=-1) + if mask is not None: + assert ( + not (~mask).gather(1, selected.unsqueeze(-1)).data.any() + ), "infeasible action selected" + + return selected + + @staticmethod + def sampling(logprobs, mask=None): + """Sample an action with a multinomial distribution given by the log probabilities.""" + probs = logprobs.exp() + selected = torch.multinomial(probs, 1).squeeze(1) + + if mask is not None: + while (~mask).gather(1, selected.unsqueeze(-1)).data.any(): + log.info("Sampled bad values, resampling!") + selected = probs.multinomial(1).squeeze(1) + assert ( + not (~mask).gather(1, selected.unsqueeze(-1)).data.any() + ), "infeasible action selected" + + return selected + + def _select_best(self, logprobs, actions, td: TensorDict, env: RL4COEnvBase): + rewards = env.get_reward(td, actions) + _, max_idxs = unbatchify(rewards, self.num_starts).max(dim=-1) + + actions = unbatchify_and_gather(actions, max_idxs, self.num_starts) + logprobs = unbatchify_and_gather(logprobs, max_idxs, self.num_starts) + td = unbatchify_and_gather(td, max_idxs, self.num_starts) + + return logprobs, actions, td, env + + +class Greedy(DecodingStrategy): + name = "greedy" + + def _step( + self, logprobs: torch.Tensor, mask: torch.Tensor, td: TensorDict, **kwargs + ) -> Tuple[torch.Tensor, torch.Tensor, TensorDict]: + """Select the action with the highest log probability""" + selected = self.greedy(logprobs, mask) + return logprobs, selected, td + + +class Sampling(DecodingStrategy): + name = "sampling" + + def _step( + self, logprobs: torch.Tensor, mask: torch.Tensor, td: TensorDict, **kwargs + ) -> Tuple[torch.Tensor, torch.Tensor, TensorDict]: + """Sample an action with a multinomial distribution given by the log probabilities.""" + selected = self.sampling(logprobs, mask) + return logprobs, selected, td + + +class Evaluate(DecodingStrategy): + name = "evaluate" + + def _step( + self, + logprobs: torch.Tensor, + mask: torch.Tensor, + td: TensorDict, + action: torch.Tensor, + **kwargs, + ) -> Tuple[torch.Tensor, torch.Tensor, TensorDict]: + """The action is provided externally, so we just return the action""" + selected = action + return logprobs, selected, td + + +class BeamSearch(DecodingStrategy): + name = "beam_search" + + def __init__(self, beam_width=None, select_best=True, **kwargs) -> None: + # TODO do we really need all logp in beam search? + kwargs["store_all_logp"] = True + super().__init__(**kwargs) + self.beam_width = beam_width + self.select_best = select_best + self.parent_beam_logprobs = None + self.beam_path = [] + + def _step( + self, logprobs: torch.Tensor, mask: torch.Tensor, td: TensorDict, **kwargs + ) -> Tuple[torch.Tensor, torch.Tensor, TensorDict]: + selected, batch_beam_idx = self._make_beam_step(logprobs) + # select the correct state representation, logprobs and mask according to beam parent + td = td[batch_beam_idx] + logprobs = logprobs[batch_beam_idx] + mask = mask[batch_beam_idx] + + assert ( + not (~mask).gather(1, selected.unsqueeze(-1)).data.any() + ), "infeasible action selected" + + return logprobs, selected, td + + def pre_decoder_hook(self, td: TensorDict, env: RL4COEnvBase, **kwargs): + if self.beam_width is None: + self.beam_width = env.get_num_starts(td) + assert self.beam_width > 1, "beam width must be larger than 1" + + # select start nodes. TODO: include first step in beam search as well + if self.select_start_nodes_fn is not None: + action = self.select_start_nodes_fn(td, env, self.beam_width) + else: + action = env.select_start_nodes(td, num_starts=self.beam_width) + + # Expand td to batch_size * beam_width + td = batchify(td, self.beam_width) + + td.set("action", action) + td = env.step(td)["next"] + + logprobs = torch.zeros_like(td["action_mask"], device=td.device) + beam_parent = torch.zeros(logprobs.size(0), device=td.device, dtype=torch.int32) + + self.logprobs.append(logprobs) + self.actions.append(action) + self.parent_beam_logprobs = logprobs.gather(1, action[..., None]) + self.beam_path.append(beam_parent) + + return td, env, self.beam_width + + def post_decoder_hook(self, td, env): + # [BS*BW, seq_len] + aligned_sequences, aligned_logprobs = self._backtrack() + + if self.select_best: + return self._select_best_beam(aligned_logprobs, aligned_sequences, td, env) + else: + return aligned_logprobs, aligned_sequences, td, env + + def _backtrack(self): + # [BS*BW, seq_len] + actions = torch.stack(self.actions, 1) + # [BS*BW, seq_len] + logprobs = torch.stack(self.logprobs, 1) + assert actions.size(1) == len( + self.beam_path + ), "action idx shape and beam path shape dont match" + + # [BS*BW] + cur_parent = self.beam_path[-1] + # [BS*BW] + reversed_aligned_sequences = [actions[:, -1]] + reversed_aligned_logprobs = [logprobs[:, -1]] + + aug_batch_size = actions.size(0) + batch_size = aug_batch_size // self.beam_width + batch_beam_sequence = ( + torch.arange(0, batch_size).repeat(self.beam_width).to(actions.device) + ) + + for k in reversed(range(len(self.beam_path) - 1)): + batch_beam_idx = batch_beam_sequence + cur_parent * batch_size + + reversed_aligned_sequences.append(actions[batch_beam_idx, k]) + reversed_aligned_logprobs.append(logprobs[batch_beam_idx, k]) + cur_parent = self.beam_path[k][batch_beam_idx] + + # [BS*BW, seq_len*num_targets] + actions = torch.stack(list(reversed(reversed_aligned_sequences)), dim=1) + logprobs = torch.stack(list(reversed(reversed_aligned_logprobs)), dim=1) + + return actions, logprobs + + def _select_best_beam(self, logprobs, actions, td: TensorDict, env: RL4COEnvBase): + aug_batch_size = logprobs.size(0) # num nodes + batch_size = aug_batch_size // self.beam_width + rewards = env.get_reward(td, actions) + _, idx = torch.cat(rewards.unsqueeze(1).split(batch_size), 1).max(1) + flat_idx = torch.arange(batch_size, device=rewards.device) + idx * batch_size + return logprobs[flat_idx], actions[flat_idx], td[flat_idx], env + + def _make_beam_step(self, logprobs: torch.Tensor): + aug_batch_size, num_nodes = logprobs.shape # num nodes + batch_size = aug_batch_size // self.beam_width + batch_beam_sequence = ( + torch.arange(0, batch_size).repeat(self.beam_width).to(logprobs.device) + ) + + # [BS*BW, num_nodes] + [BS*BW, 1] -> [BS*BW, num_nodes] + log_beam_prob = logprobs + self.parent_beam_logprobs # + + # [BS, num_nodes * BW] + log_beam_prob_hstacked = torch.cat(log_beam_prob.split(batch_size), dim=1) + # [BS, BW] + topk_logprobs, topk_ind = torch.topk( + log_beam_prob_hstacked, self.beam_width, dim=1 + ) + + # [BS*BW, 1] + logprobs_selected = torch.hstack(torch.unbind(topk_logprobs, 1)).unsqueeze(1) + + # [BS*BW, 1] + topk_ind = torch.hstack(torch.unbind(topk_ind, 1)) + + # since we stack the logprobs from the distinct branches, the indices in + # topk dont correspond to node indices directly and need to be translated + selected = topk_ind % num_nodes # determine node index + + # calc parent this branch comes from + beam_parent = (topk_ind // num_nodes).int() + + batch_beam_idx = batch_beam_sequence + beam_parent * batch_size + + self.parent_beam_logprobs = logprobs_selected + self.beam_path.append(beam_parent) + + return selected, batch_beam_idx diff --git a/rl4co/utils/instantiators.py b/rl4co/utils/instantiators.py new file mode 100644 index 00000000..9f4cdaf4 --- /dev/null +++ b/rl4co/utils/instantiators.py @@ -0,0 +1,61 @@ +from typing import List + +import hydra + +from lightning import Callback +from lightning.pytorch.loggers import Logger +from omegaconf import DictConfig + +from rl4co.utils import pylogger + +log = pylogger.get_pylogger(__name__) + + +def instantiate_callbacks(callbacks_cfg: DictConfig) -> List[Callback]: + """Instantiates callbacks from config.""" + + callbacks: List[Callback] = [] + + if not callbacks_cfg: + log.warning("No callback configs found! Skipping..") + return callbacks + + if not isinstance(callbacks_cfg, DictConfig): + raise TypeError("Callbacks config must be a DictConfig!") + + for _, cb_conf in callbacks_cfg.items(): + if isinstance(cb_conf, DictConfig) and "_target_" in cb_conf: + log.info(f"Instantiating callback <{cb_conf._target_}>") + callbacks.append(hydra.utils.instantiate(cb_conf)) + + return callbacks + + +def instantiate_loggers(logger_cfg: DictConfig, model) -> List[Logger]: + """Instantiates loggers from config.""" + + logger_list: List[Logger] = [] + + if not logger_cfg: + log.warning("No logger configs found! Skipping...") + return logger_list + + if not isinstance(logger_cfg, DictConfig): + raise TypeError("Logger config must be a DictConfig!") + + for _, lg_conf in logger_cfg.items(): + if isinstance(lg_conf, DictConfig) and "_target_" in lg_conf: + log.info(f"Instantiating logger <{lg_conf._target_}>") + if hasattr(lg_conf, "log_gradients"): + log_gradients = lg_conf.get("log_gradients", False) + # manually remove parameter, since pop doesnt work on DictConfig + del lg_conf.log_gradients + else: + log_gradients = False + logger = hydra.utils.instantiate(lg_conf) + if hasattr(logger, "watch") and log_gradients: + # make use of wandb gradient statistics logger + logger.watch(model, log_graph=False) + logger_list.append(logger) + + return logger_list diff --git a/rl4co/utils/lightning.py b/rl4co/utils/lightning.py new file mode 100644 index 00000000..a3f29cb7 --- /dev/null +++ b/rl4co/utils/lightning.py @@ -0,0 +1,76 @@ +import os + +import lightning as L +import torch + +from omegaconf import DictConfig + +# from rl4co. +from rl4co.utils.pylogger import get_pylogger + +log = get_pylogger(__name__) + + +def get_lightning_device(lit_module: L.LightningModule) -> torch.device: + """Get the device of the Lightning module before setup is called + See device setting issue in setup https://github.com/Lightning-AI/lightning/issues/2638 + """ + try: + if lit_module.trainer.strategy.root_device != lit_module.device: + return lit_module.trainer.strategy.root_device + return lit_module.device + except Exception: + return lit_module.device + + +def remove_key(config, key="wandb"): + """Remove keys containing 'key`""" + new_config = {} + for k, v in config.items(): + if key in k: + continue + else: + new_config[k] = v + return new_config + + +def clean_hydra_config( + config, keep_value_only=True, remove_keys="wandb", clean_cfg_path=True +): + """Clean hydra config by nesting dictionary and cleaning values""" + # Remove keys containing `remove_keys` + if not isinstance(remove_keys, list): + remove_keys = [remove_keys] + for key in remove_keys: + config = remove_key(config, key=key) + + new_config = {} + # Iterate over config dictionary + for key, value in config.items(): + # If key contains slash, split it and create nested dictionary recursively + if "/" in key: + keys = key.split("/") + d = new_config + for k in keys[:-1]: + d = d.setdefault(k, {}) + d[keys[-1]] = value["value"] if keep_value_only else value + else: + new_config[key] = value["value"] if keep_value_only else value + + cfg = DictConfig(new_config) + + if clean_cfg_path: + # Clean cfg_path recursively substituting root_dir with cwd + root_dir = cfg.paths.root_dir + + def replace_dir_recursive(d, search, replace): + for k, v in d.items(): + if isinstance(v, dict) or isinstance(v, DictConfig): + replace_dir_recursive(v, search, replace) + elif isinstance(v, str): + if search in v: + d[k] = v.replace(search, replace) + + replace_dir_recursive(cfg, root_dir, os.getcwd()) + + return cfg diff --git a/rl4co/utils/meta_trainer.py b/rl4co/utils/meta_trainer.py new file mode 100644 index 00000000..ccd64352 --- /dev/null +++ b/rl4co/utils/meta_trainer.py @@ -0,0 +1,170 @@ +import lightning.pytorch as pl +import torch +import math +import copy +from torch.optim import Adam + +from lightning import Callback +from rl4co import utils +import random +log = utils.get_pylogger(__name__) + + +class ReptileCallback(Callback): + + """ Meta training framework for addressing the generalization issue (implement the Reptile algorithm only) + Based on Manchanda et al. 2022 (https://arxiv.org/abs/2206.00787) and Zhou et al. 2023 (https://arxiv.org/abs/2305.19587) + + Args: + - num_tasks: the number of tasks in a mini-batch, i.e. `B` in the original paper + - alpha: initial weight of the task model for the outer-loop optimization of reptile + - alpha_decay: weight decay of the task model for the outer-loop optimization of reptile + - min_size: minimum problem size of the task (only supported in cross-size generalization) + - max_size: maximum problem size of the task (only supported in cross-size generalization) + - sch_bar: for the task scheduler of size setting, where lr_decay_epoch = sch_bar * epochs, i.e. after this epoch, learning rate will decay with a weight 0.1 + - data_type: type of the tasks, chosen from ["size", "distribution", "size_distribution"] + - print_log: whether to print the specific task sampled in each inner-loop optimization + """ + def __init__(self, + num_tasks: int, + alpha: float, + alpha_decay: float, + min_size: int, + max_size: int, + sch_bar: float = 0.9, + data_type: str = "size", + print_log: bool =True): + + super().__init__() + + self.num_tasks = num_tasks + self.alpha = alpha + self.alpha_decay = alpha_decay + self.sch_bar = sch_bar + self.print_log = print_log + self.data_type = data_type + self.task_set = self._generate_task_set(data_type, min_size, max_size) + + def on_fit_start(self, trainer: pl.Trainer, pl_module: pl.LightningModule) -> None: + + # Sample a batch of tasks + self._sample_task() + + # Pre-set the distribution + if self.data_type == "size_distribution": + pl_module.env.generator.loc_distribution = "gaussian_mixture" + self.selected_tasks[0] = (pl_module.env.generator.num_loc, 0, 0) + elif self.data_type == "size": + pl_module.env.generator.loc_distribution = "uniform" + self.selected_tasks[0] = (pl_module.env.generator.num_loc, ) + elif self.data_type == "distribution": + pl_module.env.generator.loc_distribution = "gaussian_mixture" + self.selected_tasks[0] = (0, 0) + self.task_params = self.selected_tasks[0] + + def on_train_epoch_start(self, trainer: pl.Trainer, pl_module: pl.LightningModule) -> None: + + # Alpha scheduler (decay for the update of meta model) + self._alpha_scheduler() + + # Reinitialize the task model with the parameters of the meta model + if trainer.current_epoch % self.num_tasks == 0: # Save the meta model + self.meta_model_state_dict = copy.deepcopy(pl_module.state_dict()) + self.task_models = [] + # Print sampled tasks + if self.print_log: + print('\n>> Meta epoch: {} (Exact epoch: {}), Training task: {}'.format(trainer.current_epoch//self.num_tasks, trainer.current_epoch, self.selected_tasks)) + else: + pl_module.load_state_dict(self.meta_model_state_dict) + + # Reinitialize the optimizer every epoch + lr_decay = 0.1 if trainer.current_epoch+1 == int(self.sch_bar * trainer.max_epochs) else 1 + old_lr = trainer.optimizers[0].param_groups[0]['lr'] + new_optimizer = Adam(pl_module.parameters(), lr=old_lr * lr_decay) + trainer.optimizers = [new_optimizer] + + # Print + if self.print_log: + if hasattr(pl_module.env.generator, 'capacity'): + print('>> Training task: {}, capacity: {}'.format(self.task_params, pl_module.env.generator.capacity)) + else: + print('>> Training task: {}'.format(self.task_params)) + + def on_train_epoch_end(self, trainer: pl.Trainer, pl_module: pl.LightningModule): + + # Save the task model + self.task_models.append(copy.deepcopy(pl_module.state_dict())) + if (trainer.current_epoch+1) % self.num_tasks == 0: + # Outer-loop optimization (update the meta model with the parameters of the task model) + with torch.no_grad(): + state_dict = {params_key: (self.meta_model_state_dict[params_key] + + self.alpha * torch.mean(torch.stack([fast_weight[params_key] - self.meta_model_state_dict[params_key] + for fast_weight in self.task_models], dim=0).float(), dim=0)) + for params_key in self.meta_model_state_dict} + pl_module.load_state_dict(state_dict) + + # Get ready for the next meta-training iteration + if (trainer.current_epoch + 1) % self.num_tasks == 0: + # Sample a batch of tasks + self._sample_task() + + # Load new training task (Update the environment) for the next meta-training iteration + self._load_task(pl_module, task_idx = (trainer.current_epoch+1) % self.num_tasks) + + def _sample_task(self): + + # Sample a batch of tasks + self.selected_tasks = [] + for b in range(self.num_tasks): + task_params = random.sample(self.task_set, 1)[0] + self.selected_tasks.append(task_params) + + def _load_task(self, pl_module: pl.LightningModule, task_idx=0): + + # Load new training task (Update the environment) + self.task_params = self.selected_tasks[task_idx] + + if self.data_type == "size_distribution": + assert len(self.task_params) == 3 + pl_module.env.generator.num_loc = self.task_params[0] + pl_module.env.generator.num_modes = self.task_params[1] + pl_module.env.generator.cdist = self.task_params[2] + elif self.data_type == "distribution": # fixed size + assert len(self.task_params) == 2 + pl_module.env.generator.num_modes = self.task_params[0] + pl_module.env.generator.cdist = self.task_params[1] + elif self.data_type == "size": # fixed distribution + assert len(self.task_params) == 1 + pl_module.env.generator.num_loc = self.task_params[0] + + if hasattr(pl_module.env.generator, 'capacity') and self.data_type in ["size_distribution", "size"]: + task_capacity = math.ceil(30 + self.task_params[0] / 5) if self.task_params[0] >= 20 else 20 + pl_module.env.generator.capacity = task_capacity + + def _alpha_scheduler(self): + self.alpha = max(self.alpha * self.alpha_decay, 0.0001) + + def _generate_task_set(self, data_type, min_size, max_size): + """ + Following the setting in Zhou et al. 2023 (https://arxiv.org/abs/2305.19587) + Current setting: + size: (n,) \in [20, 150] + distribution: (m, c) \in {(0, 0) + [1-9] * [1, 10, 20, 30, 40, 50]} + size_distribution: (n, m, c) \in [50, 200, 5] * {(0, 0) + (1, 1) + [3, 5, 7] * [10, 30, 50]} + """ + + if data_type == "distribution": # focus on TSP100 with gaussian mixture distributions + task_set = [(0, 0)] + [(m, c) for m in range(1, 10) for c in [1, 10, 20, 30, 40, 50]] + elif data_type == "size": # focus on uniform distribution with different sizes + task_set = [(n,) for n in range(min_size, max_size + 1)] + elif data_type == "size_distribution": + dist_set = [(0, 0), (1, 1)] + [(m, c) for m in [3, 5, 7] for c in [10, 30, 50]] + task_set = [(n, m, c) for n in range(50, 201, 5) for (m, c) in dist_set] + else: + raise NotImplementedError + + print(">> Generating training task set: {} tasks with type {}".format(len(task_set), data_type)) + print(">> Training task set: {}".format(task_set)) + + return task_set + diff --git a/rl4co/utils/ops.py b/rl4co/utils/ops.py new file mode 100644 index 00000000..b78821dc --- /dev/null +++ b/rl4co/utils/ops.py @@ -0,0 +1,262 @@ +from functools import lru_cache +from typing import Optional, Union + +import torch + +from einops import rearrange +from tensordict import TensorDict +from torch import Tensor + + +def _batchify_single( + x: Union[Tensor, TensorDict], repeats: int +) -> Union[Tensor, TensorDict]: + """Same as repeat on dim=0 for Tensordicts as well""" + s = x.shape + return x.expand(repeats, *s).contiguous().view(s[0] * repeats, *s[1:]) + + +def batchify( + x: Union[Tensor, TensorDict], shape: Union[tuple, int] +) -> Union[Tensor, TensorDict]: + """Same as `einops.repeat(x, 'b ... -> (b r) ...', r=repeats)` but ~1.5x faster and supports TensorDicts. + Repeats batchify operation `n` times as specified by each shape element. + If shape is a tuple, iterates over each element and repeats that many times to match the tuple shape. + + Example: + >>> x.shape: [a, b, c, ...] + >>> shape: [a, b, c] + >>> out.shape: [a*b*c, ...] + """ + shape = [shape] if isinstance(shape, int) else shape + for s in reversed(shape): + x = _batchify_single(x, s) if s > 0 else x + return x + + +def _unbatchify_single( + x: Union[Tensor, TensorDict], repeats: int +) -> Union[Tensor, TensorDict]: + """Undoes batchify operation for Tensordicts as well""" + s = x.shape + return x.view(repeats, s[0] // repeats, *s[1:]).permute(1, 0, *range(2, len(s) + 1)) + + +def unbatchify( + x: Union[Tensor, TensorDict], shape: Union[tuple, int] +) -> Union[Tensor, TensorDict]: + """Same as `einops.rearrange(x, '(r b) ... -> b r ...', r=repeats)` but ~2x faster and supports TensorDicts + Repeats unbatchify operation `n` times as specified by each shape element + If shape is a tuple, iterates over each element and unbatchifies that many times to match the tuple shape. + + Example: + >>> x.shape: [a*b*c, ...] + >>> shape: [a, b, c] + >>> out.shape: [a, b, c, ...] + """ + shape = [shape] if isinstance(shape, int) else shape + for s in reversed( + shape + ): # we need to reverse the shape to unbatchify in the right order + x = _unbatchify_single(x, s) if s > 0 else x + return x + + +def gather_by_index(src, idx, dim=1, squeeze=True): + """Gather elements from src by index idx along specified dim + + Example: + >>> src: shape [64, 20, 2] + >>> idx: shape [64, 3)] # 3 is the number of idxs on dim 1 + >>> Returns: [64, 3, 2] # get the 3 elements from src at idx + """ + expanded_shape = list(src.shape) + expanded_shape[dim] = -1 + idx = idx.view(idx.shape + (1,) * (src.dim() - idx.dim())).expand(expanded_shape) + squeeze = idx.size(dim) == 1 and squeeze + return src.gather(dim, idx).squeeze(dim) if squeeze else src.gather(dim, idx) + + +def unbatchify_and_gather(x: Tensor, idx: Tensor, n: int): + """first unbatchify a tensor by n and then gather (usually along the unbatchified dimension) + by the specified index + """ + x = unbatchify(x, n) + return gather_by_index(x, idx, dim=idx.dim()) + + +def get_distance(x: Tensor, y: Tensor): + """Euclidean distance between two tensors of shape `[..., n, dim]`""" + return (x - y).norm(p=2, dim=-1) + + +def get_tour_length(ordered_locs): + """Compute the total tour distance for a batch of ordered tours. + Computes the L2 norm between each pair of consecutive nodes in the tour and sums them up. + + Args: + ordered_locs: Tensor of shape [batch_size, num_nodes, 2] containing the ordered locations of the tour + """ + ordered_locs_next = torch.roll(ordered_locs, -1, dims=-2) + return get_distance(ordered_locs_next, ordered_locs).sum(-1) + + +def get_distance_matrix(locs: Tensor): + """Compute the euclidean distance matrix for the given coordinates. + + Args: + locs: Tensor of shape [..., n, dim] + """ + distance = (locs[..., :, None, :] - locs[..., None, :, :]).norm(p=2, dim=-1) + return distance + + +def calculate_entropy(logprobs: Tensor): + """Calculate the entropy of the log probabilities distribution + logprobs: Tensor of shape [batch, decoder_steps, num_actions] + """ + logprobs = torch.nan_to_num(logprobs, nan=0.0) + entropy = -(logprobs.exp() * logprobs).sum(dim=-1) # [batch, decoder steps] + entropy = entropy.sum(dim=1) # [batch] -- sum over decoding steps + assert entropy.isfinite().all(), "Entropy is not finite" + return entropy + + +# TODO: modularize inside the envs +def get_num_starts(td, env_name=None): + """Returns the number of possible start nodes for the environment based on the action mask""" + num_starts = td["action_mask"].shape[-1] + if env_name == "pdp": + num_starts = ( + num_starts - 1 + ) // 2 # only half of the nodes (i.e. pickup nodes) can be start nodes + elif env_name in ["cvrp", "cvrptw", "sdvrp", "mtsp", "op", "pctsp", "spctsp"]: + num_starts = num_starts - 1 # depot cannot be a start node + + return num_starts + + +def select_start_nodes(td, env, num_starts): + """Node selection strategy as proposed in POMO (Kwon et al. 2020) + and extended in SymNCO (Kim et al. 2022). + Selects different start nodes for each batch element + + Args: + td: TensorDict containing the data. We may need to access the available actions to select the start nodes + env: Environment may determine the node selection strategy + num_starts: Number of nodes to select. This may be passed when calling the policy directly. See :class:`rl4co.models.AutoregressiveDecoder` + """ + num_loc = env.generator.num_loc if hasattr(env.generator, "num_loc") else 0xFFFFFFFF + if env.name in ["tsp", "atsp", "flp", "mcp"]: + selected = ( + torch.arange(num_starts, device=td.device).repeat_interleave(td.shape[0]) + % num_loc + ) + elif env.name in ["jssp", "fjsp"]: + raise NotImplementedError("Multistart not yet supported for FJSP/JSSP") + else: + # Environments with depot: we do not select the depot as a start node + selected = ( + torch.arange(num_starts, device=td.device).repeat_interleave(td.shape[0]) + % num_loc + + 1 + ) + if env.name == "op": + if (td["action_mask"][..., 1:].float().sum(-1) < num_starts).any(): + # for the orienteering problem, we may have some nodes that are not available + # so we need to resample from the distribution of available nodes + selected = ( + torch.multinomial( + td["action_mask"][..., 1:].float(), num_starts, replacement=True + ) + + 1 + ) # re-add depot index + selected = rearrange(selected, "b n -> (n b)") + return selected + + +def get_best_actions(actions, max_idxs): + actions = unbatchify(actions, max_idxs.shape[0]) + return actions.gather(0, max_idxs[..., None, None]) + + +def sparsify_graph(cost_matrix: Tensor, k_sparse: Optional[int] = None, self_loop=False): + """Generate a sparsified graph for the cost_matrix by selecting k edges with the lowest cost for each node. + + Args: + cost_matrix: Tensor of shape [m, n] + k_sparse: Number of edges to keep for each node. Defaults to max(n//5, 10) if not provided. + self_loop: Include self-loop edges in the generated graph when m==n. Defaults to False. + """ + m, n = cost_matrix.shape + k_sparse = max(n // 5, 10) if k_sparse is None else k_sparse + + # fill diagonal value with +inf to exclude them from topk results + if not self_loop and m == n: + # k_sparse should not exceed n-1 in this occasion + k_sparse = min(k_sparse, n - 1) + cost_matrix.fill_diagonal_(torch.inf) + + # select top-k edges with least cost + topk_values, topk_indices = torch.topk( + cost_matrix, k=k_sparse, dim=-1, largest=False, sorted=False + ) + + # generate PyG-compatiable edge_index + edge_index_u = torch.repeat_interleave( + torch.arange(m, device=cost_matrix.device), topk_indices.shape[1] + ) + edge_index_v = topk_indices.flatten() + edge_index = torch.stack([edge_index_u, edge_index_v]) + + edge_attr = topk_values.flatten().unsqueeze(-1) + return edge_index, edge_attr + + +@lru_cache(5) +def get_full_graph_edge_index(num_node: int, self_loop=False) -> Tensor: + adj_matrix = torch.ones(num_node, num_node) + if not self_loop: + adj_matrix.fill_diagonal_(0) + edge_index = torch.permute(torch.nonzero(adj_matrix), (1, 0)) + return edge_index + + +def adj_to_pyg_edge_index(adj: Tensor) -> Tensor: + """transforms an adjacency matrix (boolean) to a Tensor with the respective edge + indices (in the format required by the pytorch geometric module). + + :param Tensor adj: shape=(bs, num_nodes, num_nodes) + :return Tensor: shape=(2, num_edges) + """ + assert adj.size(1) == adj.size(2), "only symmetric adjacency matrices are supported" + num_nodes = adj.size(1) + # (num_edges, 3) + edge_idx = adj.nonzero() + batch_idx = edge_idx[:, 0] * num_nodes + # PyG expects a "single, flat graph", in which the graphs of the batch are not connected. + # Therefore, add the batch_idx to edge_idx to have unique indices + flat_edge_idx = edge_idx[:, 1:] + batch_idx[:, None] + # (2, num_edges) + flat_edge_idx = torch.permute(flat_edge_idx, (1, 0)) + return flat_edge_idx + + +def sample_n_random_actions(td: TensorDict, n: int): + """Helper function to sample n random actions from available actions. If + number of valid actions is less then n, we sample with replacement from the + valid actions + """ + action_mask = td["action_mask"] + # check whether to use replacement or not + n_valid_actions = torch.sum(action_mask[:, 1:], 1).min() + if n_valid_actions < n: + replace = True + else: + replace = False + ps = torch.rand((action_mask.shape)) + ps[~action_mask] = -torch.inf + ps = torch.softmax(ps, dim=1) + selected = torch.multinomial(ps, n, replacement=replace).squeeze(1) + selected = rearrange(selected, "b n -> (n b)") + return selected.to(td.device) diff --git a/rl4co/utils/optim_helpers.py b/rl4co/utils/optim_helpers.py new file mode 100644 index 00000000..46367a37 --- /dev/null +++ b/rl4co/utils/optim_helpers.py @@ -0,0 +1,38 @@ +import inspect + +import torch +from torch.optim import Optimizer + + +def get_pytorch_lr_schedulers(): + """Get all learning rate schedulers from `torch.optim.lr_scheduler`""" + return torch.optim.lr_scheduler.__all__ + + +def get_pytorch_optimizers(): + """Get all optimizers from `torch.optim`""" + optimizers = [] + for name, obj in inspect.getmembers(torch.optim): + if inspect.isclass(obj) and issubclass(obj, Optimizer): + optimizers.append(name) + return optimizers + + +def create_optimizer(parameters, optimizer_name: str, **optimizer_kwargs) -> Optimizer: + """Create optimizer for model. If `optimizer_name` is not found, raise ValueError.""" + if optimizer_name in get_pytorch_optimizers(): + optimizer_cls = getattr(torch.optim, optimizer_name) + return optimizer_cls(parameters, **optimizer_kwargs) + else: + raise ValueError(f"Optimizer {optimizer_name} not found.") + + +def create_scheduler( + optimizer: Optimizer, scheduler_name: str, **scheduler_kwargs +) -> torch.optim.lr_scheduler.LRScheduler: + """Create scheduler for optimizer. If `scheduler_name` is not found, raise ValueError.""" + if scheduler_name in get_pytorch_lr_schedulers(): + scheduler_cls = getattr(torch.optim.lr_scheduler, scheduler_name) + return scheduler_cls(optimizer, **scheduler_kwargs) + else: + raise ValueError(f"Scheduler {scheduler_name} not found.") diff --git a/rl4co/utils/pylogger.py b/rl4co/utils/pylogger.py new file mode 100644 index 00000000..aa1b5f1a --- /dev/null +++ b/rl4co/utils/pylogger.py @@ -0,0 +1,25 @@ +import logging + +from lightning.pytorch.utilities.rank_zero import rank_zero_only + + +def get_pylogger(name=__name__) -> logging.Logger: + """Initializes multi-GPU-friendly python command line logger.""" + + logger = logging.getLogger(name) + + # this ensures all logging levels get marked with the rank zero decorator + # otherwise logs would get multiplied for each GPU process in multi-GPU setup + logging_levels = ( + "debug", + "info", + "warning", + "error", + "exception", + "fatal", + "critical", + ) + for level in logging_levels: + setattr(logger, level, rank_zero_only(getattr(logger, level))) + + return logger diff --git a/rl4co/utils/rich_utils.py b/rl4co/utils/rich_utils.py new file mode 100644 index 00000000..652ba568 --- /dev/null +++ b/rl4co/utils/rich_utils.py @@ -0,0 +1,97 @@ +from pathlib import Path +from typing import Sequence + +import rich +import rich.syntax +import rich.tree + +from hydra.core.hydra_config import HydraConfig +from lightning.pytorch.utilities.rank_zero import rank_zero_only +from omegaconf import DictConfig, OmegaConf, open_dict +from rich.prompt import Prompt + +from rl4co.utils.utils import pylogger + +log = pylogger.get_pylogger(__name__) + + +@rank_zero_only +def print_config_tree( + cfg: DictConfig, + print_order: Sequence[str] = ( + # "data", # note: data is dealt with in model + "model", + "callbacks", + "logger", + "trainer", + "paths", + "extras", + ), + resolve: bool = True, + save_to_file: bool = False, +) -> None: + """Prints content of DictConfig using Rich library and its tree structure. + Args: + cfg (DictConfig): Configuration composed by Hydra. + print_order (Sequence[str], optional): Determines in what order config components are printed. + resolve (bool, optional): Whether to resolve reference fields of DictConfig. + save_to_file (bool, optional): Whether to export config to the hydra output folder. + """ + + style = "dim" + tree = rich.tree.Tree("CONFIG", style=style, guide_style=style) + + queue = [] + + # add fields from `print_order` to queue + for field in print_order: + queue.append(field) if field in cfg else log.warning( + f"Field '{field}' not found in config. Skipping '{field}' config printing..." + ) + + # add all the other fields to queue (not specified in `print_order`) + for field in cfg: + if field not in queue: + queue.append(field) + + # generate config tree from queue + for field in queue: + branch = tree.add(field, style=style, guide_style=style) + + config_group = cfg[field] + if isinstance(config_group, DictConfig): + branch_content = OmegaConf.to_yaml(config_group, resolve=resolve) + else: + branch_content = str(config_group) + + branch.add(rich.syntax.Syntax(branch_content, "yaml")) + + # print config tree + rich.print(tree) + + # save config tree to file + if save_to_file: + with open(Path(cfg.paths.output_dir, "config_tree.log"), "w") as file: + rich.print(tree, file=file) + + +@rank_zero_only +def enforce_tags(cfg: DictConfig, save_to_file: bool = False) -> None: + """Prompts user to input tags from command line if no tags are provided in config.""" + + if not cfg.get("tags"): + if "id" in HydraConfig().cfg.hydra.job: + raise ValueError("Specify tags before launching a multirun!") + + log.warning("No tags provided in config. Prompting user to input tags...") + tags = Prompt.ask("Enter a list of comma separated tags", default="dev") + tags = [t.strip() for t in tags.split(",") if t != ""] + + with open_dict(cfg): + cfg.tags = tags + + log.info(f"Tags: {cfg.tags}") + + if save_to_file: + with open(Path(cfg.paths.output_dir, "tags.log"), "w") as file: + rich.print(cfg.tags, file=file) diff --git a/rl4co/utils/test_utils.py b/rl4co/utils/test_utils.py new file mode 100644 index 00000000..60e2a327 --- /dev/null +++ b/rl4co/utils/test_utils.py @@ -0,0 +1,71 @@ +from torch.utils.data import DataLoader + +from rl4co.envs import ( + CVRPEnv, + CVRPTWEnv, + DPPEnv, + MDPPEnv, + MTSPEnv, + OPEnv, + PCTSPEnv, + PDPEnv, + PDPRuinRepairEnv, + SDVRPEnv, + SMTWTPEnv, + SPCTSPEnv, + TSPEnv, + FLPEnv, + MCPEnv, +) + + +def get_env(name, size): + if name == "tsp": + env = TSPEnv(generator_params=dict(num_loc=size)) + elif name == "cvrp": + env = CVRPEnv(generator_params=dict(num_loc=size)) + elif name == "cvrptw": + env = CVRPTWEnv(generator_params=dict(num_loc=size)) + elif name == "sdvrp": + env = SDVRPEnv(generator_params=dict(num_loc=size)) + elif name == "pdp": + env = PDPEnv(generator_params=dict(num_loc=size)) + elif name == "op": + env = OPEnv(generator_params=dict(num_loc=size)) + elif name == "mtsp": + env = MTSPEnv(generator_params=dict(num_loc=size)) + elif name == "pctsp": + env = PCTSPEnv(generator_params=dict(num_loc=size)) + elif name == "spctsp": + env = SPCTSPEnv(generator_params=dict(num_loc=size)) + elif name == "dpp": + env = DPPEnv() + elif name == "mdpp": + env = MDPPEnv() + elif name == "smtwtp": + env = SMTWTPEnv() + elif name == "pdp_ruin_repair": + env = PDPRuinRepairEnv() + elif name == "mcp": + env = MCPEnv() + elif name == "flp": + env = FLPEnv() + else: + raise ValueError(f"Unknown env_name: {name}") + + return env.transform() + + +def generate_env_data(env, size, batch_size): + env = get_env(env, size) + dataset = env.dataset([batch_size]) + + dataloader = DataLoader( + dataset, + batch_size=batch_size, + shuffle=False, + num_workers=0, + collate_fn=dataset.collate_fn, + ) + + return env, next(iter(dataloader)) diff --git a/rl4co/utils/trainer.py b/rl4co/utils/trainer.py new file mode 100644 index 00000000..0ad10fa1 --- /dev/null +++ b/rl4co/utils/trainer.py @@ -0,0 +1,152 @@ +from typing import Iterable, List, Optional, Union + +import lightning.pytorch as pl +import torch + +from lightning import Callback, Trainer +from lightning.fabric.accelerators.cuda import num_cuda_devices +from lightning.pytorch.accelerators import Accelerator +from lightning.pytorch.core.datamodule import LightningDataModule +from lightning.pytorch.loggers import Logger +from lightning.pytorch.strategies import DDPStrategy, Strategy +from lightning.pytorch.utilities.types import EVAL_DATALOADERS, TRAIN_DATALOADERS + +from rl4co import utils + +log = utils.get_pylogger(__name__) + + +class RL4COTrainer(Trainer): + """Wrapper around Lightning Trainer, with some RL4CO magic for efficient training. + + Note: + The most important hyperparameter to use is `reload_dataloaders_every_n_epochs`. + This allows for datasets to be re-created on the run and distributed by Lightning across + devices on each epoch. Setting to a value different than 1 may lead to overfitting to a + specific (such as the initial) data distribution. + + Args: + accelerator: hardware accelerator to use. + callbacks: list of callbacks. + logger: logger (or iterable collection of loggers) for experiment tracking. + min_epochs: minimum number of training epochs. + max_epochs: maximum number of training epochs. + strategy: training strategy to use (if any), such as Distributed Data Parallel (DDP). + devices: number of devices to train on (int) or which GPUs to train on (list or str) applied per node. + gradient_clip_val: 0 means don't clip. Defaults to 1.0 for stability. + precision: allows for mixed precision training. Can be specified as a string (e.g., '16'). + This also allows to use `FlashAttention` by default. + disable_profiling_executor: Disable JIT profiling executor. This reduces memory and increases speed. + auto_configure_ddp: Automatically configure DDP strategy if multiple GPUs are available. + reload_dataloaders_every_n_epochs: Set to a value different than 1 to reload dataloaders every n epochs. + matmul_precision: Set matmul precision for faster inference https://pytorch.org/docs/stable/generated/torch.set_float32_matmul_precision.html#torch.set_float32_matmul_precision + **kwargs: Additional keyword arguments passed to the Lightning Trainer. See :class:`lightning.pytorch.trainer.Trainer` for details. + """ + + def __init__( + self, + accelerator: Union[str, Accelerator] = "auto", + callbacks: Optional[List[Callback]] = None, + logger: Optional[Union[Logger, Iterable[Logger]]] = None, + min_epochs: Optional[int] = None, + max_epochs: Optional[int] = None, + strategy: Union[str, Strategy] = "auto", + devices: Union[List[int], str, int] = "auto", + gradient_clip_val: Union[int, float] = 1.0, + precision: Union[str, int] = "16-mixed", + reload_dataloaders_every_n_epochs: int = 1, + disable_profiling_executor: bool = True, + auto_configure_ddp: bool = True, + matmul_precision: Union[str, int] = "medium", + **kwargs, + ): + # Disable JIT profiling executor. This reduces memory and increases speed. + # Reference: https://github.com/HazyResearch/safari/blob/111d2726e7e2b8d57726b7a8b932ad8a4b2ad660/train.py#LL124-L129C17 + if disable_profiling_executor: + try: + torch._C._jit_set_profiling_executor(False) + torch._C._jit_set_profiling_mode(False) + except AttributeError: + pass + + # Configure DDP automatically if multiple GPUs are available + if auto_configure_ddp and strategy == "auto": + if devices == "auto": + n_devices = num_cuda_devices() + elif isinstance(devices, Iterable): + n_devices = len(devices) + else: + n_devices = devices + if n_devices > 1: + log.info( + "Configuring DDP strategy automatically with {} GPUs".format( + n_devices + ) + ) + strategy = DDPStrategy( + find_unused_parameters=True, # We set to True due to RL envs + gradient_as_bucket_view=True, # https://pytorch-lightning.readthedocs.io/en/stable/advanced/advanced_gpu.html#ddp-optimizations + ) + + # Set matmul precision for faster inference https://pytorch.org/docs/stable/generated/torch.set_float32_matmul_precision.html#torch.set_float32_matmul_precision + if matmul_precision is not None: + torch.set_float32_matmul_precision(matmul_precision) + + # Check if gradient_clip_val is set to None + if gradient_clip_val is None: + log.warning( + "gradient_clip_val is set to None. This may lead to unstable training." + ) + + # We should reload dataloaders every epoch for RL training + if reload_dataloaders_every_n_epochs != 1: + log.warning( + "We reload dataloaders every epoch for RL training. Setting reload_dataloaders_every_n_epochs to a value different than 1 " + + "may lead to unexpected behavior since the initial conditions will be the same for `n_epochs` epochs." + ) + + # Main call to `Trainer` superclass + super().__init__( + accelerator=accelerator, + callbacks=callbacks, + logger=logger, + min_epochs=min_epochs, + max_epochs=max_epochs, + strategy=strategy, + gradient_clip_val=gradient_clip_val, + devices=devices, + precision=precision, + reload_dataloaders_every_n_epochs=reload_dataloaders_every_n_epochs, + **kwargs, + ) + + def fit( + self, + model: "pl.LightningModule", + train_dataloaders: Optional[Union[TRAIN_DATALOADERS, LightningDataModule]] = None, + val_dataloaders: Optional[EVAL_DATALOADERS] = None, + datamodule: Optional[LightningDataModule] = None, + ckpt_path: Optional[str] = None, + ) -> None: + """ + We override the `fit` method to automatically apply and handle RL4CO magic + to 'self.automatic_optimization = False' models, such as PPO + + It behaves exactly like the original `fit` method, but with the following changes: + - if the given model is 'self.automatic_optimization = False', we override 'gradient_clip_val' as None + """ + + if not model.automatic_optimization: + if self.gradient_clip_val is not None: + log.warning( + "Overriding gradient_clip_val to None for 'automatic_optimization=False' models" + ) + self.gradient_clip_val = None + + super().fit( + model=model, + train_dataloaders=train_dataloaders, + val_dataloaders=val_dataloaders, + datamodule=datamodule, + ckpt_path=ckpt_path, + ) diff --git a/rl4co/utils/utils.py b/rl4co/utils/utils.py new file mode 100644 index 00000000..41ac59f4 --- /dev/null +++ b/rl4co/utils/utils.py @@ -0,0 +1,285 @@ +import importlib +import platform +import sys +import warnings + +from importlib.util import find_spec +from typing import Callable, List + +import hydra + +from lightning import Callback +from lightning.pytorch.loggers.logger import Logger + +# Import the necessary PyTorch Lightning component +from lightning.pytorch.trainer.connectors.accelerator_connector import ( + _AcceleratorConnector, +) +from lightning.pytorch.utilities.rank_zero import rank_zero_only +from omegaconf import DictConfig, OmegaConf + +from rl4co.utils import pylogger, rich_utils + +log = pylogger.get_pylogger(__name__) + + +def task_wrapper(task_func: Callable) -> Callable: + """Optional decorator that wraps the task function in extra utilities. + + Makes multirun more resistant to failure. + + Utilities: + - Calling the `utils.extras()` before the task is started + - Calling the `utils.close_loggers()` after the task is finished or failed + - Logging the exception if occurs + - Logging the output dir + """ + + def wrap(cfg: DictConfig): + # execute the task + try: + metric_dict, object_dict = task_func(cfg=cfg) + + # things to do if exception occurs + except Exception as ex: + # save exception to `.log` file + log.exception("") + + # some hyperparameter combinations might be invalid or cause out-of-memory errors + # so when using hparam search plugins like Optuna, you might want to disable + # raising the below exception to avoid multirun failure + raise ex + + # things to always do after either success or exception + finally: + # display output dir path in terminal + log.info(f"Output dir: {cfg.paths.output_dir}") + + # close loggers (even if exception occurs so multirun won't fail) + close_loggers() + + return metric_dict, object_dict + + return wrap + + +def extras(cfg: DictConfig) -> None: + """Applies optional utilities before the task is started. + + Utilities: + - Ignoring python warnings + - Setting tags from command line + - Rich config printing + """ + + # return if no `extras` config + if not cfg.get("extras"): + log.warning("Extras config not found! ") + return + + # disable python warnings + if cfg.extras.get("ignore_warnings"): + log.info("Disabling python warnings! ") + warnings.filterwarnings("ignore") + + # prompt user to input tags from command line if none are provided in the config + if cfg.extras.get("enforce_tags"): + log.info("Enforcing tags! ") + rich_utils.enforce_tags(cfg, save_to_file=True) + + # pretty print config tree using Rich library + if cfg.extras.get("print_config"): + log.info("Printing config tree with Rich! ") + rich_utils.print_config_tree(cfg, resolve=True, save_to_file=True) + + +def instantiate_callbacks(callbacks_cfg: DictConfig) -> List[Callback]: + """Instantiates callbacks from config.""" + callbacks: List[Callback] = [] + + if not callbacks_cfg: + log.warning("No callback configs found! Skipping..") + return callbacks + + if not isinstance(callbacks_cfg, DictConfig): + raise TypeError("Callbacks config must be a DictConfig!") + + for _, cb_conf in callbacks_cfg.items(): + if isinstance(cb_conf, DictConfig) and "_target_" in cb_conf: + log.info(f"Instantiating callback <{cb_conf._target_}>") + callbacks.append(hydra.utils.instantiate(cb_conf)) + + return callbacks + + +def instantiate_loggers(logger_cfg: DictConfig) -> List[Logger]: + """Instantiates loggers from config.""" + logger: List[Logger] = [] + + if not logger_cfg: + log.warning("No logger configs found! Skipping...") + return logger + + if not isinstance(logger_cfg, DictConfig): + raise TypeError("Logger config must be a DictConfig!") + + for _, lg_conf in logger_cfg.items(): + if isinstance(lg_conf, DictConfig) and "_target_" in lg_conf: + log.info(f"Instantiating logger <{lg_conf._target_}>") + logger.append(hydra.utils.instantiate(lg_conf)) + + return logger + + +@rank_zero_only +def log_hyperparameters(object_dict: dict) -> None: + """Controls which config parts are saved by lightning loggers. + + Additionally saves: + - Number of model parameters + """ + + hparams = {} + + cfg = OmegaConf.to_container(object_dict["cfg"]) + model = object_dict["model"] + trainer = object_dict["trainer"] + + if not trainer.logger: + log.warning("Logger not found! Skipping hyperparameter logging...") + return + + hparams["model"] = cfg["model"] + + # save number of model parameters + hparams["model/params/total"] = sum(p.numel() for p in model.parameters()) + hparams["model/params/trainable"] = sum( + p.numel() for p in model.parameters() if p.requires_grad + ) + hparams["model/params/non_trainable"] = sum( + p.numel() for p in model.parameters() if not p.requires_grad + ) + + ## Note: we do not use the data config, since it is dealt with in the model + ## which is a `LightningModule` + # hparams["data"] = cfg["data"] + hparams["trainer"] = cfg["trainer"] + + hparams["callbacks"] = cfg.get("callbacks") + hparams["extras"] = cfg.get("extras") + + hparams["task_name"] = cfg.get("task_name") + hparams["tags"] = cfg.get("tags") + hparams["ckpt_path"] = cfg.get("ckpt_path") + hparams["seed"] = cfg.get("seed") + + # send hparams to all loggers + for logger in trainer.loggers: + logger.log_hyperparams(hparams) + + +def get_metric_value(metric_dict: dict, metric_name: str) -> float: + """Safely retrieves value of the metric logged in LightningModule.""" + + if not metric_name: + log.info("Metric name is None! Skipping metric value retrieval...") + return None + + if metric_name not in metric_dict: + raise Exception( + f"Metric value not found! \n" + "Make sure metric name logged in LightningModule is correct!\n" + "Make sure `optimized_metric` name in `hparams_search` config is correct!" + ) + + metric_value = metric_dict[metric_name].item() + log.info(f"Retrieved metric value! <{metric_name}={metric_value}>") + + return metric_value + + +def close_loggers() -> None: + """Makes sure all loggers closed properly (prevents logging failure during multirun).""" + + log.info("Closing loggers...") + + if find_spec("wandb"): # if wandb is installed + import wandb + + if wandb.run: + log.info("Closing wandb!") + wandb.finish() + + +@rank_zero_only +def save_file(path: str, content: str) -> None: + """Save file in rank zero mode (only on one process in multi-GPU setup).""" + with open(path, "w+") as file: + file.write(content) + + +def merge_with_defaults(_config=None, **defaults) -> dict: + """Merge configuration with default values. + + This function merges a provided configuration dictionary with default values. + If no configuration is provided (`_config` is None), it returns the default values. + If a dictionary is provided, it updates the defaults dictionary with the values from the provided dictionary. + Otherwise, it sets all keys in the defaults dictionary to `_config`. + + Args: + _config: Configuration to merge. Defaults to None. + **defaults: Default values to merge with the configuration. + + Returns: + dict: Merged configuration with default values. + """ + if _config is None: + return defaults + elif isinstance(_config, (DictConfig, dict)): + defaults.update(dict(**_config)) # type: ignore + return defaults + else: + return {key: _config for key in defaults.keys()} + + +def show_versions(): + """ + This function prints version information that is useful when filing bug + reports. Inspired by https://github.com/PyVRP/PyVRP + """ + + modules = { + "rl4co": "rl4co", + "torch": "torch", + "lightning": "pytorch_lightning", # Updated module name if necessary + "torchrl": "torchrl", + "tensordict": "tensordict", + "numpy": "numpy", + "pytorch_geometric": "torch_geometric", + "hydra-core": "hydra", + "omegaconf": "omegaconf", + "matplotlib": "matplotlib", + } + + # Find the longest module name for formatting + longest_name = max(len(name) for name in modules.keys()) + + print("INSTALLED VERSIONS") + print("-" * (longest_name + 20)) + # modules + for name, module in modules.items(): + try: + imported_module = importlib.import_module(module) + version = imported_module.__version__ + except ImportError: + version = "Not installed" + print(f"{name.rjust(longest_name)} : {version}") + # platform information + print(f'{"Python".rjust(longest_name)} : {sys.version.split()[0]}') + print(f'{"Platform".rjust(longest_name)} : {platform.platform()}') + try: + lightning_auto_device = _AcceleratorConnector()._choose_auto_accelerator(None) + except Exception: + lightning_auto_device = _AcceleratorConnector()._choose_auto_accelerator() + # lightning hardware accelerators + print(f'{"Lightning device".rjust(longest_name)} : {lightning_auto_device}') diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 00000000..ce2c2ba8 --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Home","text":"Loading...

An extensive Reinforcement Learning (RL) for Combinatorial Optimization (CO) benchmark. Our goal is to provide a unified framework for RL-based CO algorithms, and to facilitate reproducible research in this field, decoupling the science from the engineering.

RL4CO is built upon:

  • TorchRL: official PyTorch framework for RL algorithms and vectorized environments on GPUs
  • TensorDict: a library to easily handle heterogeneous data such as states, actions and rewards
  • PyTorch Lightning: a lightweight PyTorch wrapper for high-performance AI research
  • Hydra: a framework for elegantly configuring complex applications

We offer flexible and efficient implementations of the following policies:

  • Constructive: learn to construct a solution from scratch
    • Autoregressive (AR): construct solutions one step at a time via a decoder
    • NonAutoregressive (NAR): learn to predict a heuristic, such as a heatmap, to then construct a solution
  • Improvement: learn to improve a pre-existing solution

We provide several utilities and modularization. For example, we modularize reusable components such as environment embeddings that can easily be swapped to solve new problems.

"},{"location":"#getting-started","title":"Getting started","text":"

RL4CO is now available for installation on pip!

pip install rl4co\n

To get started, we recommend checking out our quickstart notebook or the minimalistic example below.

"},{"location":"#install-from-source","title":"Install from source","text":"

This command installs the bleeding edge main version, useful for staying up-to-date with the latest developments - for instance, if a bug has been fixed since the last official release but a new release hasn\u2019t been rolled out yet:

pip install -U git+https://github.com/ai4co/rl4co.git\n
"},{"location":"#local-install-and-development","title":"Local install and development","text":"

If you want to develop RL4CO we recommend you to install it locally with pip in editable mode:

git clone https://github.com/ai4co/rl4co && cd rl4co\npip install -e .\n

We recommend using a virtual environment such as conda to install rl4co locally.

"},{"location":"#usage","title":"Usage","text":"

Train model with default configuration (AM on TSP environment):

python run.py\n

Tip

You may check out this notebook to get started with Hydra!

Change experiment settings Train model with chosen experiment configuration from [configs/experiment/](configs/experiment/)
python run.py experiment=routing/am env=tsp env.num_loc=50 model.optimizer_kwargs.lr=2e-4\n
Here you may change the environment, e.g. with `env=cvrp` by command line or by modifying the corresponding experiment e.g. [configs/experiment/routing/am.yaml](configs/experiment/routing/am.yaml). Disable logging
python run.py experiment=routing/am logger=none '~callbacks.learning_rate_monitor'\n
Note that `~` is used to disable a callback that would need a logger. Create a sweep over hyperparameters (-m for multirun)
python run.py -m experiment=routing/am  model.optimizer.lr=1e-3,1e-4,1e-5\n
"},{"location":"#minimalistic-example","title":"Minimalistic Example","text":"

Here is a minimalistic example training the Attention Model with greedy rollout baseline on TSP in less than 30 lines of code:

from rl4co.envs.routing import TSPEnv, TSPGenerator\nfrom rl4co.models import AttentionModelPolicy, POMO\nfrom rl4co.utils import RL4COTrainer\n\n# Instantiate generator and environment\ngenerator = TSPGenerator(num_loc=50, loc_distribution=\"uniform\")\nenv = TSPEnv(generator)\n\n# Create policy and RL model\npolicy = AttentionModelPolicy(env_name=env.name, num_encoder_layers=6)\nmodel = POMO(env, policy, batch_size=64, optimizer_kwargs={\"lr\": 1e-4})\n\n# Instantiate Trainer and fit\ntrainer = RL4COTrainer(max_epochs=10, accelerator=\"gpu\", precision=\"16-mixed\")\ntrainer.fit(model)\n

Other examples can be found on our documentation!

"},{"location":"#testing","title":"Testing","text":"

Run tests with pytest from the root directory:

pytest tests\n
"},{"location":"#known-bugs","title":"Known Bugs","text":""},{"location":"#bugs-installing-pytorch-geometric-pyg","title":"Bugs installing PyTorch Geometric (PyG)","text":"

Installing PyG via Conda seems to update Torch itself. We have found that this update introduces some bugs with torchrl. At this moment, we recommend installing PyG with Pip:

pip install torch_geometric\n

"},{"location":"#contributing","title":"Contributing","text":"

Have a suggestion, request, or found a bug? Feel free to open an issue or submit a pull request. If you would like to contribute, please check out our contribution guidelines here. We welcome and look forward to all contributions to RL4CO!

We are also on Slack if you have any questions or would like to discuss RL4CO with us. We are open to collaborations and would love to hear from you \ud83d\ude80

"},{"location":"#contributors","title":"Contributors","text":""},{"location":"#citation","title":"Citation","text":"

If you find RL4CO valuable for your research or applied projects:

@article{berto2024rl4co,\n    title={{RL4CO: an Extensive Reinforcement Learning for Combinatorial Optimization Benchmark}},\n    author={Federico Berto and Chuanbo Hua and Junyoung Park and Laurin Luttmann and Yining Ma and Fanchen Bu and Jiarui Wang and Haoran Ye and Minsu Kim and Sanghyeok Choi and Nayeli Gast Zepeda and Andr\\'e Hottung and Jianan Zhou and Jieyi Bi and Yu Hu and Fei Liu and Hyeonah Kim and Jiwoo Son and Haeyeon Kim and Davide Angioni and Wouter Kool and Zhiguang Cao and Jie Zhang and Kijung Shin and Cathy Wu and Sungsoo Ahn and Guojie Song and Changhyun Kwon and Lin Xie and Jinkyoo Park},\n    year={2024},\n    journal={arXiv preprint arXiv:2306.17100},\n    note={\\url{https://github.com/ai4co/rl4co}}\n}\n

Note that a previous version of RL4CO has been accepted as an oral presentation at the NeurIPS 2023 GLFrontiers Workshop. Since then, the library has greatly evolved and improved!

"},{"location":"#join-us","title":"Join us","text":"

We invite you to join our AI4CO community, an open research group in Artificial Intelligence (AI) for Combinatorial Optimization (CO)!

"},{"location":"README_backup/","title":"README backup","text":"

Documentation | Getting Started | Usage | Contributing | Paper | Join Us

An extensive Reinforcement Learning (RL) for Combinatorial Optimization (CO) benchmark. Our goal is to provide a unified framework for RL-based CO algorithms, and to facilitate reproducible research in this field, decoupling the science from the engineering.

RL4CO is built upon:

  • TorchRL: official PyTorch framework for RL algorithms and vectorized environments on GPUs
  • TensorDict: a library to easily handle heterogeneous data such as states, actions and rewards
  • PyTorch Lightning: a lightweight PyTorch wrapper for high-performance AI research
  • Hydra: a framework for elegantly configuring complex applications

We offer flexible and efficient implementations of the following policies:

  • Constructive: learn to construct a solution from scratch
    • Autoregressive (AR): construct solutions one step at a time via a decoder
    • NonAutoregressive (NAR): learn to predict a heuristic, such as a heatmap, to then construct a solution
  • Improvement: learn to improve a pre-existing solution

We provide several utilities and modularization. For example, we modularize reusable components such as environment embeddings that can easily be swapped to solve new problems.

"},{"location":"README_backup/#getting-started","title":"Getting started","text":"

RL4CO is now available for installation on pip!

pip install rl4co\n

To get started, we recommend checking out our quickstart notebook or the minimalistic example below.

"},{"location":"README_backup/#install-from-source","title":"Install from source","text":"

This command installs the bleeding edge main version, useful for staying up-to-date with the latest developments - for instance, if a bug has been fixed since the last official release but a new release hasn\u2019t been rolled out yet:

pip install -U git+https://github.com/ai4co/rl4co.git\n
"},{"location":"README_backup/#local-install-and-development","title":"Local install and development","text":"

If you want to develop RL4CO we recommend you to install it locally with pip in editable mode:

git clone https://github.com/ai4co/rl4co && cd rl4co\npip install -e .\n

We recommend using a virtual environment such as conda to install rl4co locally.

"},{"location":"README_backup/#usage","title":"Usage","text":"

Train model with default configuration (AM on TSP environment):

python run.py\n

Tip

You may check out this notebook to get started with Hydra!

Change experiment settings Train model with chosen experiment configuration from [configs/experiment/](configs/experiment/)
python run.py experiment=routing/am env=tsp env.num_loc=50 model.optimizer_kwargs.lr=2e-4\n
Here you may change the environment, e.g. with `env=cvrp` by command line or by modifying the corresponding experiment e.g. [configs/experiment/routing/am.yaml](configs/experiment/routing/am.yaml). Disable logging
python run.py experiment=routing/am logger=none '~callbacks.learning_rate_monitor'\n
Note that `~` is used to disable a callback that would need a logger. Create a sweep over hyperparameters (-m for multirun)
python run.py -m experiment=routing/am  model.optimizer.lr=1e-3,1e-4,1e-5\n
"},{"location":"README_backup/#minimalistic-example","title":"Minimalistic Example","text":"

Here is a minimalistic example training the Attention Model with greedy rollout baseline on TSP in less than 30 lines of code:

from rl4co.envs.routing import TSPEnv, TSPGenerator\nfrom rl4co.models import AttentionModelPolicy, POMO\nfrom rl4co.utils import RL4COTrainer\n\n# Instantiate generator and environment\ngenerator = TSPGenerator(num_loc=50, loc_distribution=\"uniform\")\nenv = TSPEnv(generator)\n\n# Create policy and RL model\npolicy = AttentionModelPolicy(env_name=env.name, num_encoder_layers=6)\nmodel = POMO(env, policy, batch_size=64, optimizer_kwargs={\"lr\": 1e-4})\n\n# Instantiate Trainer and fit\ntrainer = RL4COTrainer(max_epochs=10, accelerator=\"gpu\", precision=\"16-mixed\")\ntrainer.fit(model)\n

Other examples can be found on our documentation!

"},{"location":"README_backup/#testing","title":"Testing","text":"

Run tests with pytest from the root directory:

pytest tests\n
"},{"location":"README_backup/#known-bugs","title":"Known Bugs","text":""},{"location":"README_backup/#bugs-installing-pytorch-geometric-pyg","title":"Bugs installing PyTorch Geometric (PyG)","text":"

Installing PyG via Conda seems to update Torch itself. We have found that this update introduces some bugs with torchrl. At this moment, we recommend installing PyG with Pip:

pip install torch_geometric\n

"},{"location":"README_backup/#contributing","title":"Contributing","text":"

Have a suggestion, request, or found a bug? Feel free to open an issue or submit a pull request. If you would like to contribute, please check out our contribution guidelines here. We welcome and look forward to all contributions to RL4CO!

We are also on Slack if you have any questions or would like to discuss RL4CO with us. We are open to collaborations and would love to hear from you \ud83d\ude80

"},{"location":"README_backup/#contributors","title":"Contributors","text":""},{"location":"README_backup/#citation","title":"Citation","text":"

If you find RL4CO valuable for your research or applied projects:

@article{berto2024rl4co,\n    title={{RL4CO: an Extensive Reinforcement Learning for Combinatorial Optimization Benchmark}},\n    author={Federico Berto and Chuanbo Hua and Junyoung Park and Laurin Luttmann and Yining Ma and Fanchen Bu and Jiarui Wang and Haoran Ye and Minsu Kim and Sanghyeok Choi and Nayeli Gast Zepeda and Andr\\'e Hottung and Jianan Zhou and Jieyi Bi and Yu Hu and Fei Liu and Hyeonah Kim and Jiwoo Son and Haeyeon Kim and Davide Angioni and Wouter Kool and Zhiguang Cao and Jie Zhang and Kijung Shin and Cathy Wu and Sungsoo Ahn and Guojie Song and Changhyun Kwon and Lin Xie and Jinkyoo Park},\n    year={2024},\n    journal={arXiv preprint arXiv:2306.17100},\n    note={\\url{https://github.com/ai4co/rl4co}}\n}\n

Note that a previous version of RL4CO has been accepted as an oral presentation at the NeurIPS 2023 GLFrontiers Workshop. Since then, the library has greatly evolved and improved!

"},{"location":"README_backup/#join-us","title":"Join us","text":"

We invite you to join our AI4CO community, an open research group in Artificial Intelligence (AI) for Combinatorial Optimization (CO)!

"},{"location":"docs/","title":"RL4CO Documentation","text":"

We use MkDocs to generate the documentation with the MkDocs Material theme.

"},{"location":"docs/#development","title":"Development","text":"

From the root directory:

  1. Install RL4CO locally
pip install -e \".[dev,graph,routing,docs]\"\n

note that docs is the extra requirement for the documentation.

  1. To build the documentation, run:
mkdocs serve\n
"},{"location":"docs/#hooks","title":"Hooks","text":"

We are using the hooks.py for additional modifications. MkDocs for instance cannot detect files that are not in the same directory as an __init__.py (as described here) so we are automatically creating and deleting such files with our script

"},{"location":"docs/content/api/data/","title":"Data","text":""},{"location":"docs/content/api/data/#datasets","title":"Datasets","text":""},{"location":"docs/content/api/data/#data.dataset.FastTdDataset","title":"FastTdDataset","text":"
FastTdDataset(td: TensorDict)\n

Bases: Dataset

Note

Check out the issue on tensordict for more details: https://github.com/pytorch-labs/tensordict/issues/374.

Source code in rl4co/data/dataset.py
def __init__(self, td: TensorDict):\n    self.data_len = td.batch_size[0]\n    self.data = td\n
"},{"location":"docs/content/api/data/#data.dataset.FastTdDataset.collate_fn","title":"collate_fn staticmethod","text":"
collate_fn(batch: Union[dict, TensorDict])\n

Collate function compatible with TensorDicts that reassembles a list of dicts.

Source code in rl4co/data/dataset.py
@staticmethod\ndef collate_fn(batch: Union[dict, TensorDict]):\n    \"\"\"Collate function compatible with TensorDicts that reassembles a list of dicts.\"\"\"\n    return batch\n
"},{"location":"docs/content/api/data/#data.dataset.TensorDictDataset","title":"TensorDictDataset","text":"
TensorDictDataset(td: TensorDict)\n

Bases: Dataset

Dataset compatible with TensorDicts with low CPU usage. Fast loading but somewhat slow instantiation due to list comprehension since we \"disassemble\" the TensorDict into a list of dicts.

Note

Check out the issue on tensordict for more details: https://github.com/pytorch-labs/tensordict/issues/374.

Source code in rl4co/data/dataset.py
def __init__(self, td: TensorDict):\n    self.data_len = td.batch_size[0]\n    self.data = [\n        {key: value[i] for key, value in td.items()} for i in range(self.data_len)\n    ]\n
"},{"location":"docs/content/api/data/#data.dataset.TensorDictDataset.collate_fn","title":"collate_fn staticmethod","text":"
collate_fn(batch: Union[dict, TensorDict])\n

Collate function compatible with TensorDicts that reassembles a list of dicts.

Source code in rl4co/data/dataset.py
@staticmethod\ndef collate_fn(batch: Union[dict, TensorDict]):\n    \"\"\"Collate function compatible with TensorDicts that reassembles a list of dicts.\"\"\"\n    return TensorDict(\n        {key: torch.stack([b[key] for b in batch]) for key in batch[0].keys()},\n        batch_size=torch.Size([len(batch)]),\n        **td_kwargs,\n    )\n
"},{"location":"docs/content/api/data/#data.dataset.ExtraKeyDataset","title":"ExtraKeyDataset","text":"
ExtraKeyDataset(\n    dataset: TensorDictDataset,\n    extra: Tensor,\n    key_name=\"extra\",\n)\n

Bases: TensorDictDataset

Dataset that includes an extra key to add to the data dict. This is useful for adding a REINFORCE baseline reward to the data dict. Note that this is faster to instantiate than using list comprehension.

Source code in rl4co/data/dataset.py
def __init__(self, dataset: TensorDictDataset, extra: torch.Tensor, key_name=\"extra\"):\n    self.data_len = len(dataset)\n    assert self.data_len == len(extra), \"Data and extra must be same length\"\n    self.data = dataset.data\n    self.extra = extra\n    self.key_name = key_name\n
"},{"location":"docs/content/api/data/#data.dataset.TensorDictDatasetFastGeneration","title":"TensorDictDatasetFastGeneration","text":"
TensorDictDatasetFastGeneration(td: TensorDict)\n

Bases: Dataset

Dataset compatible with TensorDicts. Similar performance in loading to list comprehension, but is faster in instantiation than :class:TensorDictDatasetList (more than 10x faster).

Warning

Note that directly indexing TensorDicts may be faster in creating the dataset but uses > 3x more CPU. We may generally recommend using the :class:TensorDictDatasetList

Note

Check out the issue on tensordict for more details: https://github.com/pytorch-labs/tensordict/issues/374.

Source code in rl4co/data/dataset.py
def __init__(self, td: TensorDict):\n    self.data = td\n
"},{"location":"docs/content/api/data/#data.dataset.TensorDictDatasetFastGeneration.collate_fn","title":"collate_fn staticmethod","text":"
collate_fn(batch: Union[dict, TensorDict])\n

Equivalent to collating with lambda x: x

Source code in rl4co/data/dataset.py
@staticmethod\ndef collate_fn(batch: Union[dict, TensorDict]):\n    \"\"\"Equivalent to collating with `lambda x: x`\"\"\"\n    return batch\n
"},{"location":"docs/content/api/data/#data-generation","title":"Data Generation","text":""},{"location":"docs/content/api/data/#data.generate_data.generate_env_data","title":"generate_env_data","text":"
generate_env_data(env_type, *args, **kwargs)\n

Generate data for a given environment type in the form of a dictionary

Source code in rl4co/data/generate_data.py
def generate_env_data(env_type, *args, **kwargs):\n    \"\"\"Generate data for a given environment type in the form of a dictionary\"\"\"\n    try:\n        # breakpoint()\n        # remove all None values from args\n        args = [arg for arg in args if arg is not None]\n\n        return getattr(sys.modules[__name__], f\"generate_{env_type}_data\")(\n            *args, **kwargs\n        )\n    except AttributeError:\n        raise NotImplementedError(f\"Environment type {env_type} not implemented\")\n
"},{"location":"docs/content/api/data/#data.generate_data.generate_mdpp_data","title":"generate_mdpp_data","text":"
generate_mdpp_data(\n    dataset_size,\n    size=10,\n    num_probes_min=2,\n    num_probes_max=5,\n    num_keepout_min=1,\n    num_keepout_max=50,\n    lock_size=True,\n)\n

Generate data for the nDPP problem. If lock_size is True, then the size if fixed and we skip the size argument if it is not 10. This is because the RL environment is based on a real-world PCB (parametrized with data)

Source code in rl4co/data/generate_data.py
def generate_mdpp_data(\n    dataset_size,\n    size=10,\n    num_probes_min=2,\n    num_probes_max=5,\n    num_keepout_min=1,\n    num_keepout_max=50,\n    lock_size=True,\n):\n    \"\"\"Generate data for the nDPP problem.\n    If `lock_size` is True, then the size if fixed and we skip the `size` argument if it is not 10.\n    This is because the RL environment is based on a real-world PCB (parametrized with data)\n    \"\"\"\n    if lock_size and size != 10:\n        # log.info(\"Locking size to 10, skipping generate_mdpp_data with size {}\".format(size))\n        return None\n\n    bs = dataset_size  # bs = batch_size to generate data in batch\n    m = n = size\n    if isinstance(bs, int):\n        bs = [bs]\n\n    locs = np.stack(np.meshgrid(np.arange(m), np.arange(n)), axis=-1).reshape(-1, 2)\n    locs = locs / np.array([m, n], dtype=np.float32)\n    locs = np.expand_dims(locs, axis=0)\n    locs = np.repeat(locs, bs[0], axis=0)\n\n    available = np.ones((bs[0], m * n), dtype=bool)\n\n    probe = np.random.randint(0, high=m * n, size=(bs[0], 1))\n    np.put_along_axis(available, probe, False, axis=1)\n\n    num_probe = np.random.randint(num_probes_min, num_probes_max + 1, size=(bs[0], 1))\n    probes = np.zeros((bs[0], m * n), dtype=bool)\n    for i in range(bs[0]):\n        p = np.random.choice(m * n, num_probe[i], replace=False)\n        np.put_along_axis(available[i], p, False, axis=0)\n        np.put_along_axis(probes[i], p, True, axis=0)\n\n    num_keepout = np.random.randint(num_keepout_min, num_keepout_max + 1, size=(bs[0], 1))\n    for i in range(bs[0]):\n        k = np.random.choice(m * n, num_keepout[i], replace=False)\n        np.put_along_axis(available[i], k, False, axis=0)\n\n    return {\n        \"locs\": locs.astype(np.float32),\n        \"probe\": probes.astype(bool),\n        \"action_mask\": available.astype(bool),\n    }\n
"},{"location":"docs/content/api/data/#data.generate_data.generate_dataset","title":"generate_dataset","text":"
generate_dataset(\n    filename: Union[str, List[str]] = None,\n    data_dir: str = \"data\",\n    name: str = None,\n    problem: Union[str, List[str]] = \"all\",\n    data_distribution: str = \"all\",\n    dataset_size: int = 10000,\n    graph_sizes: Union[int, List[int]] = [20, 50, 100],\n    overwrite: bool = False,\n    seed: int = 1234,\n    disable_warning: bool = True,\n    distributions_per_problem: Union[int, dict] = None,\n)\n

We keep a similar structure as in Kool et al. 2019 but save and load the data as npz This is way faster and more memory efficient than pickle and also allows for easy transfer to TensorDict

Parameters:

  • filename (Union[str, List[str]], default: None ) \u2013

    Filename to save the data to. If None, the data is saved to data_dir/problem/problem_graph_size_seed.npz. Defaults to None.

  • data_dir (str, default: 'data' ) \u2013

    Directory to save the data to. Defaults to \"data\".

  • name (str, default: None ) \u2013

    Name of the dataset. Defaults to None.

  • problem (Union[str, List[str]], default: 'all' ) \u2013

    Problem to generate data for. Defaults to \"all\".

  • data_distribution (str, default: 'all' ) \u2013

    Data distribution to generate data for. Defaults to \"all\".

  • dataset_size (int, default: 10000 ) \u2013

    Number of datasets to generate. Defaults to 10000.

  • graph_sizes (Union[int, List[int]], default: [20, 50, 100] ) \u2013

    Graph size to generate data for. Defaults to [20, 50, 100].

  • overwrite (bool, default: False ) \u2013

    Whether to overwrite existing files. Defaults to False.

  • seed (int, default: 1234 ) \u2013

    Random seed. Defaults to 1234.

  • disable_warning (bool, default: True ) \u2013

    Whether to disable warnings. Defaults to True.

  • distributions_per_problem (Union[int, dict], default: None ) \u2013

    Number of distributions to generate per problem. Defaults to None.

Source code in rl4co/data/generate_data.py
def generate_dataset(\n    filename: Union[str, List[str]] = None,\n    data_dir: str = \"data\",\n    name: str = None,\n    problem: Union[str, List[str]] = \"all\",\n    data_distribution: str = \"all\",\n    dataset_size: int = 10000,\n    graph_sizes: Union[int, List[int]] = [20, 50, 100],\n    overwrite: bool = False,\n    seed: int = 1234,\n    disable_warning: bool = True,\n    distributions_per_problem: Union[int, dict] = None,\n):\n    \"\"\"We keep a similar structure as in Kool et al. 2019 but save and load the data as npz\n    This is way faster and more memory efficient than pickle and also allows for easy transfer to TensorDict\n\n    Args:\n        filename: Filename to save the data to. If None, the data is saved to data_dir/problem/problem_graph_size_seed.npz. Defaults to None.\n        data_dir: Directory to save the data to. Defaults to \"data\".\n        name: Name of the dataset. Defaults to None.\n        problem: Problem to generate data for. Defaults to \"all\".\n        data_distribution: Data distribution to generate data for. Defaults to \"all\".\n        dataset_size: Number of datasets to generate. Defaults to 10000.\n        graph_sizes: Graph size to generate data for. Defaults to [20, 50, 100].\n        overwrite: Whether to overwrite existing files. Defaults to False.\n        seed: Random seed. Defaults to 1234.\n        disable_warning: Whether to disable warnings. Defaults to True.\n        distributions_per_problem: Number of distributions to generate per problem. Defaults to None.\n    \"\"\"\n\n    if isinstance(problem, list) and len(problem) == 1:\n        problem = problem[0]\n\n    graph_sizes = [graph_sizes] if isinstance(graph_sizes, int) else graph_sizes\n\n    if distributions_per_problem is None:\n        distributions_per_problem = DISTRIBUTIONS_PER_PROBLEM\n\n    if problem == \"all\":\n        problems = distributions_per_problem\n    else:\n        problems = {\n            problem: distributions_per_problem[problem]\n            if data_distribution == \"all\"\n            else [data_distribution]\n        }\n\n    # Support multiple filenames if necessary\n    filenames = [filename] if isinstance(filename, str) else filename\n    iter = 0\n\n    # Main loop for data generation. We loop over all problems, distributions and sizes\n    for problem, distributions in problems.items():\n        for distribution in distributions or [None]:\n            for graph_size in graph_sizes:\n                if filename is None:\n                    datadir = os.path.join(data_dir, problem)\n                    os.makedirs(datadir, exist_ok=True)\n                    fname = os.path.join(\n                        datadir,\n                        \"{}{}{}_{}_seed{}.npz\".format(\n                            problem,\n                            \"_{}\".format(distribution)\n                            if distribution is not None\n                            else \"\",\n                            graph_size,\n                            name,\n                            seed,\n                        ),\n                    )\n                else:\n                    try:\n                        fname = filenames[iter]\n                        # make directory if necessary\n                        os.makedirs(os.path.dirname(fname), exist_ok=True)\n                        iter += 1\n                    except Exception:\n                        raise ValueError(\n                            \"Number of filenames does not match number of problems\"\n                        )\n                    fname = check_extension(filename, extension=\".npz\")\n\n                if not overwrite and os.path.isfile(\n                    check_extension(fname, extension=\".npz\")\n                ):\n                    if not disable_warning:\n                        log.info(\n                            \"File {} already exists! Run with -f option to overwrite. Skipping...\".format(\n                                fname\n                            )\n                        )\n                    continue\n\n                # Set seed\n                np.random.seed(seed)\n\n                # Automatically generate dataset\n                dataset = generate_env_data(\n                    problem, dataset_size, graph_size, distribution\n                )\n\n                # A function can return None in case of an error or a skip\n                if dataset is not None:\n                    # Save to disk as dict\n                    log.info(\"Saving {} dataset to {}\".format(problem, fname))\n                    np.savez(fname, **dataset)\n
"},{"location":"docs/content/api/data/#data.generate_data.generate_default_datasets","title":"generate_default_datasets","text":"
generate_default_datasets(data_dir, generate_eda=False)\n

Generate the default datasets used in the paper and save them to data_dir/problem

Source code in rl4co/data/generate_data.py
def generate_default_datasets(data_dir, generate_eda=False):\n    \"\"\"Generate the default datasets used in the paper and save them to data_dir/problem\"\"\"\n    generate_dataset(data_dir=data_dir, name=\"val\", problem=\"all\", seed=4321)\n    generate_dataset(data_dir=data_dir, name=\"test\", problem=\"all\", seed=1234)\n\n    # By default, we skip the EDA datasets since they can easily be generated on the fly when needed\n    if generate_eda:\n        generate_dataset(\n            data_dir=data_dir,\n            name=\"test\",\n            problem=\"mdpp\",\n            seed=1234,\n            graph_sizes=[10],\n            dataset_size=100,\n        )  # EDA (mDPP)\n
"},{"location":"docs/content/api/data/#transforms","title":"Transforms","text":""},{"location":"docs/content/api/data/#data.transforms.StateAugmentation","title":"StateAugmentation","text":"
StateAugmentation(\n    num_augment: int = 8,\n    augment_fn: Union[str, callable] = \"symmetric\",\n    first_aug_identity: bool = True,\n    normalize: bool = False,\n    feats: list = None,\n)\n

Bases: object

Augment state by N times via symmetric rotation/reflection transform

Parameters:

  • num_augment (int, default: 8 ) \u2013

    number of augmentations

  • augment_fn (Union[str, callable], default: 'symmetric' ) \u2013

    augmentation function to use, e.g. 'symmetric' (default) or 'dihedral8', if callable, then use the function directly. If 'dihedral8', then num_augment must be 8

  • first_aug_identity (bool, default: True ) \u2013

    whether to augment the first data point too

  • normalize (bool, default: False ) \u2013

    whether to normalize the augmented data

  • feats (list, default: None ) \u2013

    list of features to augment

Source code in rl4co/data/transforms.py
def __init__(\n    self,\n    num_augment: int = 8,\n    augment_fn: Union[str, callable] = 'symmetric', \n    first_aug_identity: bool = True,\n    normalize: bool = False,\n    feats: list = None,\n):\n    self.augmentation = get_augment_function(augment_fn)\n    assert not (\n        self.augmentation == dihedral_8_augmentation_wrapper and num_augment != 8\n    ), \"When using the `dihedral8` augmentation function, then num_augment must be 8\"\n\n    if feats is None:\n        log.info(\"Features not passed, defaulting to 'locs'\")\n        self.feats = [\"locs\"]\n    else:\n        self.feats = feats\n    self.num_augment = num_augment\n    self.normalize = normalize\n    self.first_aug_identity = first_aug_identity\n
"},{"location":"docs/content/api/data/#data.transforms.dihedral_8_augmentation","title":"dihedral_8_augmentation","text":"
dihedral_8_augmentation(xy: Tensor) -> Tensor\n

Augmentation (x8) for grid-based data (x, y) as done in POMO. This is a Dihedral group of order 8 (rotations and reflections) https://en.wikipedia.org/wiki/Examples_of_groups#dihedral_group_of_order_8

Parameters:

  • xy (Tensor) \u2013

    [batch, graph, 2] tensor of x and y coordinates

Source code in rl4co/data/transforms.py
def dihedral_8_augmentation(xy: Tensor) -> Tensor:\n    \"\"\"\n    Augmentation (x8) for grid-based data (x, y) as done in POMO.\n    This is a Dihedral group of order 8 (rotations and reflections)\n    https://en.wikipedia.org/wiki/Examples_of_groups#dihedral_group_of_order_8\n\n    Args:\n        xy: [batch, graph, 2] tensor of x and y coordinates\n    \"\"\"\n    # [batch, graph, 2]\n    x, y = xy.split(1, dim=2)\n    # augmnetations [batch, graph, 2]\n    z0 = torch.cat((x, y), dim=2)\n    z1 = torch.cat((1 - x, y), dim=2)\n    z2 = torch.cat((x, 1 - y), dim=2)\n    z3 = torch.cat((1 - x, 1 - y), dim=2)\n    z4 = torch.cat((y, x), dim=2)\n    z5 = torch.cat((1 - y, x), dim=2)\n    z6 = torch.cat((y, 1 - x), dim=2)\n    z7 = torch.cat((1 - y, 1 - x), dim=2)\n    # [batch*8, graph, 2]\n    aug_xy = torch.cat((z0, z1, z2, z3, z4, z5, z6, z7), dim=0)\n    return aug_xy\n
"},{"location":"docs/content/api/data/#data.transforms.dihedral_8_augmentation_wrapper","title":"dihedral_8_augmentation_wrapper","text":"
dihedral_8_augmentation_wrapper(\n    xy: Tensor, reduce: bool = True, *args, **kw\n) -> Tensor\n

Wrapper for dihedral_8_augmentation. If reduce, only return the first 1/8 of the augmented data since the augmentation augments the data 8 times.

Source code in rl4co/data/transforms.py
def dihedral_8_augmentation_wrapper(\n    xy: Tensor, reduce: bool = True, *args, **kw\n) -> Tensor:\n    \"\"\"Wrapper for dihedral_8_augmentation. If reduce, only return the first 1/8 of the augmented data\n    since the augmentation augments the data 8 times.\n    \"\"\"\n    xy = xy[: xy.shape[0] // 8, ...] if reduce else xy\n    return dihedral_8_augmentation(xy)\n
"},{"location":"docs/content/api/data/#data.transforms.symmetric_transform","title":"symmetric_transform","text":"
symmetric_transform(\n    x: Tensor, y: Tensor, phi: Tensor, offset: float = 0.5\n)\n

SR group transform with rotation and reflection Like the one in SymNCO, but a vectorized version

Parameters:

  • x (Tensor) \u2013

    [batch, graph, 1] tensor of x coordinates

  • y (Tensor) \u2013

    [batch, graph, 1] tensor of y coordinates

  • phi (Tensor) \u2013

    [batch, 1] tensor of random rotation angles

  • offset (float, default: 0.5 ) \u2013

    offset for x and y coordinates

Source code in rl4co/data/transforms.py
def symmetric_transform(x: Tensor, y: Tensor, phi: Tensor, offset: float = 0.5):\n    \"\"\"SR group transform with rotation and reflection\n    Like the one in SymNCO, but a vectorized version\n\n    Args:\n        x: [batch, graph, 1] tensor of x coordinates\n        y: [batch, graph, 1] tensor of y coordinates\n        phi: [batch, 1] tensor of random rotation angles\n        offset: offset for x and y coordinates\n    \"\"\"\n    x, y = x - offset, y - offset\n    # random rotation\n    x_prime = torch.cos(phi) * x - torch.sin(phi) * y\n    y_prime = torch.sin(phi) * x + torch.cos(phi) * y\n    # make random reflection if phi > 2*pi (i.e. 50% of the time)\n    mask = phi > 2 * math.pi\n    # vectorized random reflection: swap axes x and y if mask\n    xy = torch.cat((x_prime, y_prime), dim=-1)\n    xy = torch.where(mask, xy.flip(-1), xy)\n    return xy + offset\n
"},{"location":"docs/content/api/data/#data.transforms.symmetric_augmentation","title":"symmetric_augmentation","text":"
symmetric_augmentation(\n    xy: Tensor,\n    num_augment: int = 8,\n    first_augment: bool = False,\n)\n

Augment xy data by num_augment times via symmetric rotation transform and concatenate to original data

Parameters:

  • xy (Tensor) \u2013

    [batch, graph, 2] tensor of x and y coordinates

  • num_augment (int, default: 8 ) \u2013

    number of augmentations

  • first_augment (bool, default: False ) \u2013

    whether to augment the first data point

Source code in rl4co/data/transforms.py
def symmetric_augmentation(xy: Tensor, num_augment: int = 8, first_augment: bool = False):\n    \"\"\"Augment xy data by `num_augment` times via symmetric rotation transform and concatenate to original data\n\n    Args:\n        xy: [batch, graph, 2] tensor of x and y coordinates\n        num_augment: number of augmentations\n        first_augment: whether to augment the first data point\n    \"\"\"\n    # create random rotation angles (4*pi for reflection, 2*pi for rotation)\n    phi = torch.rand(xy.shape[0], device=xy.device) * 4 * math.pi\n\n    # set phi to 0 for first , i.e. no augmentation as in SymNCO\n    if not first_augment:\n        phi[: xy.shape[0] // num_augment] = 0.0\n    x, y = xy[..., [0]], xy[..., [1]]\n    return symmetric_transform(x, y, phi[:, None, None])\n
"},{"location":"docs/content/api/data/#utils","title":"Utils","text":""},{"location":"docs/content/api/data/#data.utils.load_npz_to_tensordict","title":"load_npz_to_tensordict","text":"
load_npz_to_tensordict(filename)\n

Load a npz file directly into a TensorDict We assume that the npz file contains a dictionary of numpy arrays This is at least an order of magnitude faster than pickle

Source code in rl4co/data/utils.py
def load_npz_to_tensordict(filename):\n    \"\"\"Load a npz file directly into a TensorDict\n    We assume that the npz file contains a dictionary of numpy arrays\n    This is at least an order of magnitude faster than pickle\n    \"\"\"\n    x = np.load(filename)\n    x_dict = dict(x)\n    batch_size = x_dict[list(x_dict.keys())[0]].shape[0]\n    return TensorDict(x_dict, batch_size=batch_size)\n
"},{"location":"docs/content/api/data/#data.utils.save_tensordict_to_npz","title":"save_tensordict_to_npz","text":"
save_tensordict_to_npz(\n    tensordict, filename, compress: bool = False\n)\n

Save a TensorDict to a npz file We assume that the TensorDict contains a dictionary of tensors

Source code in rl4co/data/utils.py
def save_tensordict_to_npz(tensordict, filename, compress: bool = False):\n    \"\"\"Save a TensorDict to a npz file\n    We assume that the TensorDict contains a dictionary of tensors\n    \"\"\"\n    x_dict = {k: v.numpy() for k, v in tensordict.items()}\n    if compress:\n        np.savez_compressed(filename, **x_dict)\n    else:\n        np.savez(filename, **x_dict)\n
"},{"location":"docs/content/api/data/#data.utils.check_extension","title":"check_extension","text":"
check_extension(filename, extension='.npz')\n

Check that filename has extension, otherwise add it

Source code in rl4co/data/utils.py
def check_extension(filename, extension=\".npz\"):\n    \"\"\"Check that filename has extension, otherwise add it\"\"\"\n    if os.path.splitext(filename)[1] != extension:\n        return filename + extension\n    return filename\n
"},{"location":"docs/content/api/data/#data.utils.load_solomon_instance","title":"load_solomon_instance","text":"
load_solomon_instance(name, path=None, edge_weights=False)\n

Load solomon instance from a file

Source code in rl4co/data/utils.py
def load_solomon_instance(name, path=None, edge_weights=False):\n    \"\"\"Load solomon instance from a file\"\"\"\n    import vrplib\n\n    if not path:\n        path = \"data/solomon/instances/\"\n        path = os.path.join(ROOT_PATH, path)\n    if not os.path.isdir(path):\n        os.makedirs(path)\n    file_path = f\"{path}{name}.txt\"\n    if not os.path.isfile(file_path):\n        vrplib.download_instance(name=name, path=path)\n    return vrplib.read_instance(\n        path=file_path,\n        instance_format=\"solomon\",\n        compute_edge_weights=edge_weights,\n    )\n
"},{"location":"docs/content/api/data/#data.utils.load_solomon_solution","title":"load_solomon_solution","text":"
load_solomon_solution(name, path=None)\n

Load solomon solution from a file

Source code in rl4co/data/utils.py
def load_solomon_solution(name, path=None):\n    \"\"\"Load solomon solution from a file\"\"\"\n    import vrplib\n\n    if not path:\n        path = \"data/solomon/solutions/\"\n        path = os.path.join(ROOT_PATH, path)\n    if not os.path.isdir(path):\n        os.makedirs(path)\n    file_path = f\"{path}{name}.sol\"\n    if not os.path.isfile(file_path):\n        vrplib.download_solution(name=name, path=path)\n    return vrplib.read_solution(path=file_path)\n
"},{"location":"docs/content/api/decoding/","title":"Decoding Strategies","text":""},{"location":"docs/content/api/decoding/#utils.decoding.DecodingStrategy","title":"DecodingStrategy","text":"
DecodingStrategy(\n    temperature: float = 1.0,\n    top_p: float = 0.0,\n    top_k: int = 0,\n    mask_logits: bool = True,\n    tanh_clipping: float = 0,\n    multistart: bool = False,\n    multisample: bool = False,\n    num_starts: Optional[int] = None,\n    select_start_nodes_fn: Optional[callable] = None,\n    improvement_method_mode: bool = False,\n    select_best: bool = False,\n    store_all_logp: bool = False,\n    **kwargs\n)\n

Base class for decoding strategies. Subclasses should implement the :meth:_step method. Includes hooks for pre and post main decoding operations.

Parameters:

  • temperature (float, default: 1.0 ) \u2013

    Temperature scaling. Higher values make the distribution more uniform (exploration), lower values make it more peaky (exploitation). Defaults to 1.0.

  • top_p (float, default: 0.0 ) \u2013

    Top-p sampling, a.k.a. Nucleus Sampling (https://arxiv.org/abs/1904.09751). Defaults to 0.0.

  • top_k (int, default: 0 ) \u2013

    Top-k sampling, i.e. restrict sampling to the top k logits. If 0, do not perform. Defaults to 0.

  • mask_logits (bool, default: True ) \u2013

    Whether to mask logits of infeasible actions. Defaults to True.

  • tanh_clipping (float, default: 0 ) \u2013

    Tanh clipping (https://arxiv.org/abs/1611.09940). Defaults to 0.

  • multistart (bool, default: False ) \u2013

    Whether to use multistart decoding. Defaults to False.

  • multisample (bool, default: False ) \u2013

    Whether to use sampling decoding. Defaults to False.

  • num_starts (Optional[int], default: None ) \u2013

    Number of starts for multistart decoding. Defaults to None.

Source code in rl4co/utils/decoding.py
def __init__(\n    self,\n    temperature: float = 1.0,\n    top_p: float = 0.0,\n    top_k: int = 0,\n    mask_logits: bool = True,\n    tanh_clipping: float = 0,\n    multistart: bool = False,\n    multisample: bool = False,\n    num_starts: Optional[int] = None,\n    select_start_nodes_fn: Optional[callable] = None,\n    improvement_method_mode: bool = False,\n    select_best: bool = False,\n    store_all_logp: bool = False,\n    **kwargs,\n) -> None:\n    self.temperature = temperature\n    self.top_p = top_p\n    self.top_k = top_k\n    self.mask_logits = mask_logits\n    self.tanh_clipping = tanh_clipping\n    self.multistart = multistart\n    self.multisample = multisample\n    self.num_starts = num_starts\n    self.select_start_nodes_fn = select_start_nodes_fn\n    self.improvement_method_mode = improvement_method_mode\n    self.select_best = select_best\n    self.store_all_logp = store_all_logp\n    # initialize buffers\n    self.actions = []\n    self.logprobs = []\n
"},{"location":"docs/content/api/decoding/#utils.decoding.DecodingStrategy.pre_decoder_hook","title":"pre_decoder_hook","text":"
pre_decoder_hook(\n    td: TensorDict, env: RL4COEnvBase, action: Tensor = None\n)\n

Pre decoding hook. This method is called before the main decoding operation.

Source code in rl4co/utils/decoding.py
def pre_decoder_hook(\n    self, td: TensorDict, env: RL4COEnvBase, action: torch.Tensor = None\n):\n    \"\"\"Pre decoding hook. This method is called before the main decoding operation.\"\"\"\n\n    # Multi-start decoding. If num_starts is None, we use the number of actions in the action mask\n    if self.multistart or self.multisample:\n        if self.num_starts is None:\n            self.num_starts = env.get_num_starts(td)\n            if self.multisample:\n                log.warn(\n                    f\"num_starts is not provided for sampling, using num_starts={self.num_starts}\"\n                )\n    else:\n        if self.num_starts is not None:\n            if self.num_starts >= 1:\n                log.warn(\n                    f\"num_starts={self.num_starts} is ignored for decode_type={self.name}\"\n                )\n\n        self.num_starts = 0\n\n    # Multi-start decoding: first action is chosen by ad-hoc node selection\n    if self.num_starts >= 1:\n        if self.multistart:\n            if action is None:  # if action is provided, we use it as the first action\n                if self.select_start_nodes_fn is not None:\n                    action = self.select_start_nodes_fn(td, env, self.num_starts)\n                else:\n                    action = env.select_start_nodes(td, num_starts=self.num_starts)\n\n            # Expand td to batch_size * num_starts\n            td = batchify(td, self.num_starts)\n\n            td.set(\"action\", action)\n            td = env.step(td)[\"next\"]\n            # first logprobs is 0, so p = logprobs.exp() = 1\n            if self.store_all_logp:\n                logprobs = torch.zeros_like(td[\"action_mask\"])  # [B, N]\n            else:\n                logprobs = torch.zeros_like(action, device=td.device)  # [B]\n\n            self.logprobs.append(logprobs)\n            self.actions.append(action)\n        else:\n            # Expand td to batch_size * num_samplestarts\n            td = batchify(td, self.num_starts)\n\n    return td, env, self.num_starts\n
"},{"location":"docs/content/api/decoding/#utils.decoding.DecodingStrategy.step","title":"step","text":"
step(\n    logits: Tensor,\n    mask: Tensor,\n    td: TensorDict = None,\n    action: Tensor = None,\n    **kwargs\n) -> TensorDict\n

Main decoding operation. This method should be called in a loop until all sequences are done.

Parameters:

  • logits (Tensor) \u2013

    Logits from the model.

  • mask (Tensor) \u2013

    Action mask. 1 if feasible, 0 otherwise (so we keep if 1 as done in PyTorch).

  • td (TensorDict, default: None ) \u2013

    TensorDict containing the current state of the environment.

  • action (Tensor, default: None ) \u2013

    Optional action to use, e.g. for evaluating log probabilities.

Source code in rl4co/utils/decoding.py
def step(\n    self,\n    logits: torch.Tensor,\n    mask: torch.Tensor,\n    td: TensorDict = None,\n    action: torch.Tensor = None,\n    **kwargs,\n) -> TensorDict:\n    \"\"\"Main decoding operation. This method should be called in a loop until all sequences are done.\n\n    Args:\n        logits: Logits from the model.\n        mask: Action mask. 1 if feasible, 0 otherwise (so we keep if 1 as done in PyTorch).\n        td: TensorDict containing the current state of the environment.\n        action: Optional action to use, e.g. for evaluating log probabilities.\n    \"\"\"\n    if not self.mask_logits:  # set mask_logit to None if mask_logits is False\n        mask = None\n\n    logprobs = process_logits(\n        logits,\n        mask,\n        temperature=self.temperature,\n        top_p=self.top_p,\n        top_k=self.top_k,\n        tanh_clipping=self.tanh_clipping,\n        mask_logits=self.mask_logits,\n    )\n    logprobs, selected_action, td = self._step(\n        logprobs, mask, td, action=action, **kwargs\n    )\n\n    # directly return for improvement methods, since the action for improvement methods is finalized in its own policy\n    if self.improvement_method_mode:\n        return logprobs, selected_action\n    # for others\n    if not self.store_all_logp:\n        logprobs = gather_by_index(logprobs, selected_action, dim=1)\n    td.set(\"action\", selected_action)\n    self.actions.append(selected_action)\n    self.logprobs.append(logprobs)\n    return td\n
"},{"location":"docs/content/api/decoding/#utils.decoding.DecodingStrategy.greedy","title":"greedy staticmethod","text":"
greedy(logprobs, mask=None)\n

Select the action with the highest probability.

Source code in rl4co/utils/decoding.py
@staticmethod\ndef greedy(logprobs, mask=None):\n    \"\"\"Select the action with the highest probability.\"\"\"\n    # [BS], [BS]\n    selected = logprobs.argmax(dim=-1)\n    if mask is not None:\n        assert (\n            not (~mask).gather(1, selected.unsqueeze(-1)).data.any()\n        ), \"infeasible action selected\"\n\n    return selected\n
"},{"location":"docs/content/api/decoding/#utils.decoding.DecodingStrategy.sampling","title":"sampling staticmethod","text":"
sampling(logprobs, mask=None)\n

Sample an action with a multinomial distribution given by the log probabilities.

Source code in rl4co/utils/decoding.py
@staticmethod\ndef sampling(logprobs, mask=None):\n    \"\"\"Sample an action with a multinomial distribution given by the log probabilities.\"\"\"\n    probs = logprobs.exp()\n    selected = torch.multinomial(probs, 1).squeeze(1)\n\n    if mask is not None:\n        while (~mask).gather(1, selected.unsqueeze(-1)).data.any():\n            log.info(\"Sampled bad values, resampling!\")\n            selected = probs.multinomial(1).squeeze(1)\n        assert (\n            not (~mask).gather(1, selected.unsqueeze(-1)).data.any()\n        ), \"infeasible action selected\"\n\n    return selected\n
"},{"location":"docs/content/api/decoding/#utils.decoding.Greedy","title":"Greedy","text":"
Greedy(\n    temperature: float = 1.0,\n    top_p: float = 0.0,\n    top_k: int = 0,\n    mask_logits: bool = True,\n    tanh_clipping: float = 0,\n    multistart: bool = False,\n    multisample: bool = False,\n    num_starts: Optional[int] = None,\n    select_start_nodes_fn: Optional[callable] = None,\n    improvement_method_mode: bool = False,\n    select_best: bool = False,\n    store_all_logp: bool = False,\n    **kwargs\n)\n

Bases: DecodingStrategy

Source code in rl4co/utils/decoding.py
def __init__(\n    self,\n    temperature: float = 1.0,\n    top_p: float = 0.0,\n    top_k: int = 0,\n    mask_logits: bool = True,\n    tanh_clipping: float = 0,\n    multistart: bool = False,\n    multisample: bool = False,\n    num_starts: Optional[int] = None,\n    select_start_nodes_fn: Optional[callable] = None,\n    improvement_method_mode: bool = False,\n    select_best: bool = False,\n    store_all_logp: bool = False,\n    **kwargs,\n) -> None:\n    self.temperature = temperature\n    self.top_p = top_p\n    self.top_k = top_k\n    self.mask_logits = mask_logits\n    self.tanh_clipping = tanh_clipping\n    self.multistart = multistart\n    self.multisample = multisample\n    self.num_starts = num_starts\n    self.select_start_nodes_fn = select_start_nodes_fn\n    self.improvement_method_mode = improvement_method_mode\n    self.select_best = select_best\n    self.store_all_logp = store_all_logp\n    # initialize buffers\n    self.actions = []\n    self.logprobs = []\n
"},{"location":"docs/content/api/decoding/#utils.decoding.Sampling","title":"Sampling","text":"
Sampling(\n    temperature: float = 1.0,\n    top_p: float = 0.0,\n    top_k: int = 0,\n    mask_logits: bool = True,\n    tanh_clipping: float = 0,\n    multistart: bool = False,\n    multisample: bool = False,\n    num_starts: Optional[int] = None,\n    select_start_nodes_fn: Optional[callable] = None,\n    improvement_method_mode: bool = False,\n    select_best: bool = False,\n    store_all_logp: bool = False,\n    **kwargs\n)\n

Bases: DecodingStrategy

Source code in rl4co/utils/decoding.py
def __init__(\n    self,\n    temperature: float = 1.0,\n    top_p: float = 0.0,\n    top_k: int = 0,\n    mask_logits: bool = True,\n    tanh_clipping: float = 0,\n    multistart: bool = False,\n    multisample: bool = False,\n    num_starts: Optional[int] = None,\n    select_start_nodes_fn: Optional[callable] = None,\n    improvement_method_mode: bool = False,\n    select_best: bool = False,\n    store_all_logp: bool = False,\n    **kwargs,\n) -> None:\n    self.temperature = temperature\n    self.top_p = top_p\n    self.top_k = top_k\n    self.mask_logits = mask_logits\n    self.tanh_clipping = tanh_clipping\n    self.multistart = multistart\n    self.multisample = multisample\n    self.num_starts = num_starts\n    self.select_start_nodes_fn = select_start_nodes_fn\n    self.improvement_method_mode = improvement_method_mode\n    self.select_best = select_best\n    self.store_all_logp = store_all_logp\n    # initialize buffers\n    self.actions = []\n    self.logprobs = []\n
"},{"location":"docs/content/api/decoding/#utils.decoding.Evaluate","title":"Evaluate","text":"
Evaluate(\n    temperature: float = 1.0,\n    top_p: float = 0.0,\n    top_k: int = 0,\n    mask_logits: bool = True,\n    tanh_clipping: float = 0,\n    multistart: bool = False,\n    multisample: bool = False,\n    num_starts: Optional[int] = None,\n    select_start_nodes_fn: Optional[callable] = None,\n    improvement_method_mode: bool = False,\n    select_best: bool = False,\n    store_all_logp: bool = False,\n    **kwargs\n)\n

Bases: DecodingStrategy

Source code in rl4co/utils/decoding.py
def __init__(\n    self,\n    temperature: float = 1.0,\n    top_p: float = 0.0,\n    top_k: int = 0,\n    mask_logits: bool = True,\n    tanh_clipping: float = 0,\n    multistart: bool = False,\n    multisample: bool = False,\n    num_starts: Optional[int] = None,\n    select_start_nodes_fn: Optional[callable] = None,\n    improvement_method_mode: bool = False,\n    select_best: bool = False,\n    store_all_logp: bool = False,\n    **kwargs,\n) -> None:\n    self.temperature = temperature\n    self.top_p = top_p\n    self.top_k = top_k\n    self.mask_logits = mask_logits\n    self.tanh_clipping = tanh_clipping\n    self.multistart = multistart\n    self.multisample = multisample\n    self.num_starts = num_starts\n    self.select_start_nodes_fn = select_start_nodes_fn\n    self.improvement_method_mode = improvement_method_mode\n    self.select_best = select_best\n    self.store_all_logp = store_all_logp\n    # initialize buffers\n    self.actions = []\n    self.logprobs = []\n
"},{"location":"docs/content/api/decoding/#utils.decoding.BeamSearch","title":"BeamSearch","text":"
BeamSearch(beam_width=None, select_best=True, **kwargs)\n

Bases: DecodingStrategy

Source code in rl4co/utils/decoding.py
def __init__(self, beam_width=None, select_best=True, **kwargs) -> None:\n    # TODO do we really need all logp in beam search?\n    kwargs[\"store_all_logp\"] = True\n    super().__init__(**kwargs)\n    self.beam_width = beam_width\n    self.select_best = select_best\n    self.parent_beam_logprobs = None\n    self.beam_path = []\n
"},{"location":"docs/content/api/decoding/#utils.decoding.BeamSearch.pre_decoder_hook","title":"pre_decoder_hook","text":"
pre_decoder_hook(\n    td: TensorDict, env: RL4COEnvBase, **kwargs\n)\n

Pre decoding hook. This method is called before the main decoding operation.

Source code in rl4co/utils/decoding.py
def pre_decoder_hook(self, td: TensorDict, env: RL4COEnvBase, **kwargs):\n    if self.beam_width is None:\n        self.beam_width = env.get_num_starts(td)\n    assert self.beam_width > 1, \"beam width must be larger than 1\"\n\n    # select start nodes. TODO: include first step in beam search as well\n    if self.select_start_nodes_fn is not None:\n        action = self.select_start_nodes_fn(td, env, self.beam_width)\n    else:\n        action = env.select_start_nodes(td, num_starts=self.beam_width)\n\n    # Expand td to batch_size * beam_width\n    td = batchify(td, self.beam_width)\n\n    td.set(\"action\", action)\n    td = env.step(td)[\"next\"]\n\n    logprobs = torch.zeros_like(td[\"action_mask\"], device=td.device)\n    beam_parent = torch.zeros(logprobs.size(0), device=td.device, dtype=torch.int32)\n\n    self.logprobs.append(logprobs)\n    self.actions.append(action)\n    self.parent_beam_logprobs = logprobs.gather(1, action[..., None])\n    self.beam_path.append(beam_parent)\n\n    return td, env, self.beam_width\n
"},{"location":"docs/content/api/decoding/#utils.decoding.get_log_likelihood","title":"get_log_likelihood","text":"
get_log_likelihood(\n    logprobs,\n    actions=None,\n    mask=None,\n    return_sum: bool = True,\n)\n

Get log likelihood of selected actions. Note that mask is a boolean tensor where True means the value should be kept.

Parameters:

  • logprobs \u2013

    Log probabilities of actions from the model (batch_size, seq_len, action_dim).

  • actions \u2013

    Selected actions (batch_size, seq_len).

  • mask \u2013

    Action mask. 1 if feasible, 0 otherwise (so we keep if 1 as done in PyTorch).

  • return_sum (bool, default: True ) \u2013

    Whether to return the sum of log probabilities or not. Defaults to True.

Source code in rl4co/utils/decoding.py
def get_log_likelihood(logprobs, actions=None, mask=None, return_sum: bool = True):\n    \"\"\"Get log likelihood of selected actions.\n    Note that mask is a boolean tensor where True means the value should be kept.\n\n    Args:\n        logprobs: Log probabilities of actions from the model (batch_size, seq_len, action_dim).\n        actions: Selected actions (batch_size, seq_len).\n        mask: Action mask. 1 if feasible, 0 otherwise (so we keep if 1 as done in PyTorch).\n        return_sum: Whether to return the sum of log probabilities or not. Defaults to True.\n    \"\"\"\n    # Optional: select logp when logp.shape = (bs, dec_steps, N)\n    if actions is not None and logprobs.dim() == 3:\n        logprobs = logprobs.gather(-1, actions.unsqueeze(-1)).squeeze(-1)\n\n    # Optional: mask out actions irrelevant to objective so they do not get reinforced\n    if mask is not None:\n        logprobs[~mask] = 0\n\n    assert (\n        logprobs > -1000\n    ).data.all(), \"Logprobs should not be -inf, check sampling procedure!\"\n\n    # Calculate log_likelihood\n    if return_sum:\n        return logprobs.sum(1)  # [batch]\n    else:\n        return logprobs  # [batch, decode_len]\n
"},{"location":"docs/content/api/decoding/#utils.decoding.decode_logprobs","title":"decode_logprobs","text":"
decode_logprobs(logprobs, mask, decode_type='sampling')\n

Decode log probabilities to select actions with mask. Note that mask is a boolean tensor where True means the value should be kept.

Source code in rl4co/utils/decoding.py
def decode_logprobs(logprobs, mask, decode_type=\"sampling\"):\n    \"\"\"Decode log probabilities to select actions with mask.\n    Note that mask is a boolean tensor where True means the value should be kept.\n    \"\"\"\n    if \"greedy\" in decode_type:\n        selected = DecodingStrategy.greedy(logprobs, mask)\n    elif \"sampling\" in decode_type:\n        selected = DecodingStrategy.sampling(logprobs, mask)\n    else:\n        assert False, \"Unknown decode type: {}\".format(decode_type)\n    return selected\n
"},{"location":"docs/content/api/decoding/#utils.decoding.random_policy","title":"random_policy","text":"
random_policy(td)\n

Helper function to select a random action from available actions

Source code in rl4co/utils/decoding.py
def random_policy(td):\n    \"\"\"Helper function to select a random action from available actions\"\"\"\n    action = torch.multinomial(td[\"action_mask\"].float(), 1).squeeze(-1)\n    td.set(\"action\", action)\n    return td\n
"},{"location":"docs/content/api/decoding/#utils.decoding.rollout","title":"rollout","text":"
rollout(env, td, policy, max_steps: int = None)\n

Helper function to rollout a policy. Currently, TorchRL does not allow to step over envs when done with env.rollout(). We need this because for environments that complete at different steps.

Source code in rl4co/utils/decoding.py
def rollout(env, td, policy, max_steps: int = None):\n    \"\"\"Helper function to rollout a policy. Currently, TorchRL does not allow to step\n    over envs when done with `env.rollout()`. We need this because for environments that complete at different steps.\n    \"\"\"\n\n    max_steps = float(\"inf\") if max_steps is None else max_steps\n    actions = []\n    steps = 0\n\n    while not td[\"done\"].all():\n        td = policy(td)\n        actions.append(td[\"action\"])\n        td = env.step(td)[\"next\"]\n        steps += 1\n        if steps > max_steps:\n            log.info(\"Max steps reached\")\n            break\n    return (\n        env.get_reward(td, torch.stack(actions, dim=1)),\n        td,\n        torch.stack(actions, dim=1),\n    )\n
"},{"location":"docs/content/api/decoding/#utils.decoding.modify_logits_for_top_k_filtering","title":"modify_logits_for_top_k_filtering","text":"
modify_logits_for_top_k_filtering(logits, top_k)\n

Set the logits for none top-k values to -inf. Done out-of-place. Ref: https://github.com/togethercomputer/stripedhyena/blob/7e13f618027fea9625be1f2d2d94f9a361f6bd02/stripedhyena/sample.py#L6

Source code in rl4co/utils/decoding.py
def modify_logits_for_top_k_filtering(logits, top_k):\n    \"\"\"Set the logits for none top-k values to -inf. Done out-of-place.\n    Ref: https://github.com/togethercomputer/stripedhyena/blob/7e13f618027fea9625be1f2d2d94f9a361f6bd02/stripedhyena/sample.py#L6\n    \"\"\"\n    indices_to_remove = logits < torch.topk(logits, top_k)[0][..., -1, None]\n    return logits.masked_fill(indices_to_remove, float(\"-inf\"))\n
"},{"location":"docs/content/api/decoding/#utils.decoding.modify_logits_for_top_p_filtering","title":"modify_logits_for_top_p_filtering","text":"
modify_logits_for_top_p_filtering(logits, top_p)\n

Set the logits for none top-p values to -inf. Done out-of-place. Ref: https://github.com/togethercomputer/stripedhyena/blob/7e13f618027fea9625be1f2d2d94f9a361f6bd02/stripedhyena/sample.py#L14

Source code in rl4co/utils/decoding.py
def modify_logits_for_top_p_filtering(logits, top_p):\n    \"\"\"Set the logits for none top-p values to -inf. Done out-of-place.\n    Ref: https://github.com/togethercomputer/stripedhyena/blob/7e13f618027fea9625be1f2d2d94f9a361f6bd02/stripedhyena/sample.py#L14\n    \"\"\"\n    if top_p <= 0.0 or top_p >= 1.0:\n        return logits\n\n    # First sort and calculate cumulative sum of probabilities.\n    sorted_logits, sorted_indices = torch.sort(logits, descending=False)\n    cumulative_probs = sorted_logits.softmax(dim=-1).cumsum(dim=-1)\n\n    # Remove tokens with cumulative top_p above the threshold (token with 0 are kept)\n    sorted_indices_to_remove = cumulative_probs <= (1 - top_p)\n\n    # Scatter sorted tensors to original indexing\n    indices_to_remove = sorted_indices_to_remove.scatter(\n        -1, sorted_indices, sorted_indices_to_remove\n    )\n    return logits.masked_fill(indices_to_remove, float(\"-inf\"))\n
"},{"location":"docs/content/api/decoding/#utils.decoding.process_logits","title":"process_logits","text":"
process_logits(\n    logits: Tensor,\n    mask: Tensor = None,\n    temperature: float = 1.0,\n    top_p: float = 0.0,\n    top_k: int = 0,\n    tanh_clipping: float = 0,\n    mask_logits: bool = True,\n)\n

Convert logits to log probabilities with additional features like temperature scaling, top-k and top-p sampling.

Note

We convert to log probabilities instead of probabilities to avoid numerical instability. This is because, roughly, softmax = exp(logits) / sum(exp(logits)) and log(softmax) = logits - log(sum(exp(logits))), and avoiding the division by the sum of exponentials can help with numerical stability. You may check the official PyTorch documentation.

Parameters:

  • logits (Tensor) \u2013

    Logits from the model (batch_size, num_actions).

  • mask (Tensor, default: None ) \u2013

    Action mask. 1 if feasible, 0 otherwise (so we keep if 1 as done in PyTorch).

  • temperature (float, default: 1.0 ) \u2013

    Temperature scaling. Higher values make the distribution more uniform (exploration), lower values make it more peaky (exploitation).

  • top_p (float, default: 0.0 ) \u2013

    Top-p sampling, a.k.a. Nucleus Sampling (https://arxiv.org/abs/1904.09751). Remove tokens that have a cumulative probability less than the threshold 1 - top_p (lower tail of the distribution). If 0, do not perform.

  • top_k (int, default: 0 ) \u2013

    Top-k sampling, i.e. restrict sampling to the top k logits. If 0, do not perform. Note that we only do filtering and do not return all the top-k logits here.

  • tanh_clipping (float, default: 0 ) \u2013

    Tanh clipping (https://arxiv.org/abs/1611.09940).

  • mask_logits (bool, default: True ) \u2013

    Whether to mask logits of infeasible actions.

Source code in rl4co/utils/decoding.py
def process_logits(\n    logits: torch.Tensor,\n    mask: torch.Tensor = None,\n    temperature: float = 1.0,\n    top_p: float = 0.0,\n    top_k: int = 0,\n    tanh_clipping: float = 0,\n    mask_logits: bool = True,\n):\n    \"\"\"Convert logits to log probabilities with additional features like temperature scaling, top-k and top-p sampling.\n\n    Note:\n        We convert to log probabilities instead of probabilities to avoid numerical instability.\n        This is because, roughly, softmax = exp(logits) / sum(exp(logits)) and log(softmax) = logits - log(sum(exp(logits))),\n        and avoiding the division by the sum of exponentials can help with numerical stability.\n        You may check the [official PyTorch documentation](https://pytorch.org/docs/stable/generated/torch.nn.functional.log_softmax.html).\n\n    Args:\n        logits: Logits from the model (batch_size, num_actions).\n        mask: Action mask. 1 if feasible, 0 otherwise (so we keep if 1 as done in PyTorch).\n        temperature: Temperature scaling. Higher values make the distribution more uniform (exploration),\n            lower values make it more peaky (exploitation).\n        top_p: Top-p sampling, a.k.a. Nucleus Sampling (https://arxiv.org/abs/1904.09751). Remove tokens that have a cumulative probability\n            less than the threshold 1 - top_p (lower tail of the distribution). If 0, do not perform.\n        top_k: Top-k sampling, i.e. restrict sampling to the top k logits. If 0, do not perform. Note that we only do filtering and\n            do not return all the top-k logits here.\n        tanh_clipping: Tanh clipping (https://arxiv.org/abs/1611.09940).\n        mask_logits: Whether to mask logits of infeasible actions.\n    \"\"\"\n\n    # Tanh clipping from Bello et al. 2016\n    if tanh_clipping > 0:\n        logits = torch.tanh(logits) * tanh_clipping\n\n    # In RL, we want to mask the logits to prevent the agent from selecting infeasible actions\n    if mask_logits:\n        assert mask is not None, \"mask must be provided if mask_logits is True\"\n        logits[~mask] = float(\"-inf\")\n\n    logits = logits / temperature  # temperature scaling\n\n    if top_k > 0:\n        top_k = min(top_k, logits.size(-1))  # safety check\n        logits = modify_logits_for_top_k_filtering(logits, top_k)\n\n    if top_p > 0:\n        assert top_p <= 1.0, \"top-p should be in (0, 1].\"\n        logits = modify_logits_for_top_p_filtering(logits, top_p)\n\n    # Compute log probabilities\n    return F.log_softmax(logits, dim=-1)\n
"},{"location":"docs/content/api/tasks/","title":"Train and Evaluation","text":""},{"location":"docs/content/api/tasks/#train","title":"Train","text":""},{"location":"docs/content/api/tasks/#tasks.train.run","title":"run","text":"
run(cfg: DictConfig) -> Tuple[dict, dict]\n

Trains the model. Can additionally evaluate on a testset, using best weights obtained during training. This method is wrapped in optional @task_wrapper decorator, that controls the behavior during failure. Useful for multiruns, saving info about the crash, etc.

Parameters:

  • cfg (DictConfig) \u2013

    Configuration composed by Hydra.

Returns: Tuple[dict, dict]: Dict with metrics and dict with all instantiated objects.

Source code in rl4co/tasks/train.py
@utils.task_wrapper\ndef run(cfg: DictConfig) -> Tuple[dict, dict]:\n    \"\"\"Trains the model. Can additionally evaluate on a testset, using best weights obtained during\n    training.\n    This method is wrapped in optional @task_wrapper decorator, that controls the behavior during\n    failure. Useful for multiruns, saving info about the crash, etc.\n\n    Args:\n        cfg (DictConfig): Configuration composed by Hydra.\n    Returns:\n        Tuple[dict, dict]: Dict with metrics and dict with all instantiated objects.\n    \"\"\"\n\n    # set seed for random number generators in pytorch, numpy and python.random\n    if cfg.get(\"seed\"):\n        L.seed_everything(cfg.seed, workers=True)\n\n    # We instantiate the environment separately and then pass it to the model\n    log.info(f\"Instantiating environment <{cfg.env._target_}>\")\n    env = hydra.utils.instantiate(cfg.env)\n\n    # Note that the RL environment is instantiated inside the model\n    log.info(f\"Instantiating model <{cfg.model._target_}>\")\n    model: LightningModule = hydra.utils.instantiate(cfg.model, env)\n\n    log.info(\"Instantiating callbacks...\")\n    callbacks: List[Callback] = utils.instantiate_callbacks(cfg.get(\"callbacks\"))\n\n    log.info(\"Instantiating loggers...\")\n    logger: List[Logger] = utils.instantiate_loggers(cfg.get(\"logger\"), model)\n\n    log.info(\"Instantiating trainer...\")\n    trainer: RL4COTrainer = hydra.utils.instantiate(\n        cfg.trainer,\n        callbacks=callbacks,\n        logger=logger,\n    )\n\n    object_dict = {\n        \"cfg\": cfg,\n        \"model\": model,\n        \"callbacks\": callbacks,\n        \"logger\": logger,\n        \"trainer\": trainer,\n    }\n\n    if logger:\n        log.info(\"Logging hyperparameters!\")\n        utils.log_hyperparameters(object_dict)\n\n    if cfg.get(\"compile\", False):\n        log.info(\"Compiling model!\")\n        model = torch.compile(model)\n\n    if cfg.get(\"train\"):\n        log.info(\"Starting training!\")\n        trainer.fit(model=model, ckpt_path=cfg.get(\"ckpt_path\"))\n\n        train_metrics = trainer.callback_metrics\n\n    if cfg.get(\"test\"):\n        log.info(\"Starting testing!\")\n        ckpt_path = trainer.checkpoint_callback.best_model_path\n        if ckpt_path == \"\":\n            log.warning(\"Best ckpt not found! Using current weights for testing...\")\n            ckpt_path = None\n        trainer.test(model=model, ckpt_path=ckpt_path)\n        log.info(f\"Best ckpt path: {ckpt_path}\")\n\n    test_metrics = trainer.callback_metrics\n\n    # merge train and test metrics\n    metric_dict = {**train_metrics, **test_metrics}\n\n    return metric_dict, object_dict\n
"},{"location":"docs/content/api/tasks/#evaluate","title":"Evaluate","text":""},{"location":"docs/content/api/tasks/#tasks.eval.EvalBase","title":"EvalBase","text":"
EvalBase(env, progress=True, **kwargs)\n

Base class for evaluation

Parameters:

  • env \u2013

    Environment

  • progress \u2013

    Whether to show progress bar

  • **kwargs \u2013

    Additional arguments (to be implemented in subclasses)

Source code in rl4co/tasks/eval.py
def __init__(self, env, progress=True, **kwargs):\n    check_unused_kwargs(self, kwargs)\n    self.env = env\n    self.progress = progress\n
"},{"location":"docs/content/api/tasks/#tasks.eval.GreedyEval","title":"GreedyEval","text":"
GreedyEval(env, **kwargs)\n

Bases: EvalBase

Evaluates the policy using greedy decoding and single trajectory

Source code in rl4co/tasks/eval.py
def __init__(self, env, **kwargs):\n    check_unused_kwargs(self, kwargs)\n    super().__init__(env, kwargs.get(\"progress\", True))\n
"},{"location":"docs/content/api/tasks/#tasks.eval.AugmentationEval","title":"AugmentationEval","text":"
AugmentationEval(\n    env,\n    num_augment=8,\n    force_dihedral_8=False,\n    feats=None,\n    **kwargs\n)\n

Bases: EvalBase

Evaluates the policy via N state augmentations force_dihedral_8 forces the use of 8 augmentations (rotations and flips) as in POMO https://en.wikipedia.org/wiki/Examples_of_groups#dihedral_group_of_order_8

Parameters:

  • num_augment (int, default: 8 ) \u2013

    Number of state augmentations

  • force_dihedral_8 (bool, default: False ) \u2013

    Whether to force the use of 8 augmentations

Source code in rl4co/tasks/eval.py
def __init__(self, env, num_augment=8, force_dihedral_8=False, feats=None, **kwargs):\n    check_unused_kwargs(self, kwargs)\n    super().__init__(env, kwargs.get(\"progress\", True))\n    self.augmentation = StateAugmentation(\n        num_augment=num_augment,\n        augment_fn=\"dihedral8\" if force_dihedral_8 else \"symmetric\",\n        feats=feats,\n    )\n
"},{"location":"docs/content/api/tasks/#tasks.eval.SamplingEval","title":"SamplingEval","text":"
SamplingEval(\n    env,\n    samples,\n    softmax_temp=None,\n    select_best=True,\n    temperature=1.0,\n    top_p=0.0,\n    top_k=0,\n    **kwargs\n)\n

Bases: EvalBase

Evaluates the policy via N samples from the policy

Parameters:

  • samples (int) \u2013

    Number of samples to take

  • softmax_temp (float, default: None ) \u2013

    Temperature for softmax sampling. The higher the temperature, the more random the sampling

Source code in rl4co/tasks/eval.py
def __init__(\n    self,\n    env,\n    samples,\n    softmax_temp=None,\n    select_best=True,\n    temperature=1.0,\n    top_p=0.0,\n    top_k=0,\n    **kwargs,\n):\n    check_unused_kwargs(self, kwargs)\n    super().__init__(env, kwargs.get(\"progress\", True))\n\n    self.samples = samples\n    self.softmax_temp = softmax_temp\n    self.temperature = temperature\n    self.select_best = select_best\n    self.top_p = top_p\n    self.top_k = top_k\n
"},{"location":"docs/content/api/tasks/#tasks.eval.GreedyMultiStartEval","title":"GreedyMultiStartEval","text":"
GreedyMultiStartEval(env, num_starts=None, **kwargs)\n

Bases: EvalBase

Evaluates the policy via num_starts greedy multistarts samples from the policy

Parameters:

  • num_starts (int, default: None ) \u2013

    Number of greedy multistarts to use

Source code in rl4co/tasks/eval.py
def __init__(self, env, num_starts=None, **kwargs):\n    check_unused_kwargs(self, kwargs)\n    super().__init__(env, kwargs.get(\"progress\", True))\n\n    assert num_starts is not None, \"Must specify num_starts\"\n    self.num_starts = num_starts\n
"},{"location":"docs/content/api/tasks/#tasks.eval.GreedyMultiStartAugmentEval","title":"GreedyMultiStartAugmentEval","text":"
GreedyMultiStartAugmentEval(\n    env,\n    num_starts=None,\n    num_augment=8,\n    force_dihedral_8=False,\n    feats=None,\n    **kwargs\n)\n

Bases: EvalBase

Evaluates the policy via num_starts samples from the policy and num_augment augmentations of each sample.force_dihedral_8` forces the use of 8 augmentations (rotations and flips) as in POMO https://en.wikipedia.org/wiki/Examples_of_groups#dihedral_group_of_order_8

Parameters:

  • num_starts \u2013

    Number of greedy multistart samples

  • num_augment \u2013

    Number of augmentations per sample

  • force_dihedral_8 \u2013

    If True, force the use of 8 augmentations (rotations and flips) as in POMO

Source code in rl4co/tasks/eval.py
def __init__(\n    self,\n    env,\n    num_starts=None,\n    num_augment=8,\n    force_dihedral_8=False,\n    feats=None,\n    **kwargs,\n):\n    check_unused_kwargs(self, kwargs)\n    super().__init__(env, kwargs.get(\"progress\", True))\n\n    assert num_starts is not None, \"Must specify num_starts\"\n    self.num_starts = num_starts\n    assert not (\n        num_augment != 8 and force_dihedral_8\n    ), \"Cannot force dihedral 8 when num_augment != 8\"\n    self.augmentation = StateAugmentation(\n        num_augment=num_augment,\n        augment_fn=\"dihedral8\" if force_dihedral_8 else \"symmetric\",\n        feats=feats,\n    )\n
"},{"location":"docs/content/api/tasks/#tasks.eval.get_automatic_batch_size","title":"get_automatic_batch_size","text":"
get_automatic_batch_size(\n    eval_fn, start_batch_size=8192, max_batch_size=4096\n)\n

Automatically reduces the batch size based on the eval function

Parameters:

  • eval_fn \u2013

    The eval function

  • start_batch_size \u2013

    The starting batch size. This should be the theoretical maximum batch size

  • max_batch_size \u2013

    The maximum batch size. This is the practical maximum batch size

Source code in rl4co/tasks/eval.py
def get_automatic_batch_size(eval_fn, start_batch_size=8192, max_batch_size=4096):\n    \"\"\"Automatically reduces the batch size based on the eval function\n\n    Args:\n        eval_fn: The eval function\n        start_batch_size: The starting batch size. This should be the theoretical maximum batch size\n        max_batch_size: The maximum batch size. This is the practical maximum batch size\n    \"\"\"\n    batch_size = start_batch_size\n\n    effective_ratio = 1\n\n    if hasattr(eval_fn, \"num_starts\"):\n        batch_size = batch_size // (eval_fn.num_starts // 10)\n        effective_ratio *= eval_fn.num_starts // 10\n    if hasattr(eval_fn, \"num_augment\"):\n        batch_size = batch_size // eval_fn.num_augment\n        effective_ratio *= eval_fn.num_augment\n    if hasattr(eval_fn, \"samples\"):\n        batch_size = batch_size // eval_fn.samples\n        effective_ratio *= eval_fn.samples\n\n    batch_size = min(batch_size, max_batch_size)\n    # get closest integer power of 2\n    batch_size = 2 ** int(np.log2(batch_size))\n\n    print(f\"Effective batch size: {batch_size} (ratio: {effective_ratio})\")\n\n    return batch_size\n
"},{"location":"docs/content/api/envs/base/","title":"Base Environment","text":"

This is the base wrapper around TorchRL's EnvBase, with additional functionality.

"},{"location":"docs/content/api/envs/base/#envs.common.base.RL4COEnvBase","title":"RL4COEnvBase","text":"
RL4COEnvBase(\n    *,\n    data_dir: str = \"data/\",\n    train_file: str = None,\n    val_file: str = None,\n    test_file: str = None,\n    val_dataloader_names: list = None,\n    test_dataloader_names: list = None,\n    check_solution: bool = True,\n    dataset_cls: callable = TensorDictDataset,\n    seed: int = None,\n    device: str = \"cpu\",\n    batch_size: Size = None,\n    run_type_checks: bool = False,\n    allow_done_after_reset: bool = False,\n    _torchrl_mode: bool = False,\n    **kwargs\n)\n

Bases: EnvBase

Base class for RL4CO environments based on TorchRL EnvBase. The environment has the usual methods for stepping, resetting, and getting the specifications of the environment that shoud be implemented by the subclasses of this class. It also has methods for getting the reward, action mask, and checking the validity of the solution, and for generating and loading the datasets (supporting multiple dataloaders as well for validation and testing).

Parameters:

  • data_dir (str, default: 'data/' ) \u2013

    Root directory for the dataset

  • train_file (str, default: None ) \u2013

    Name of the training file

  • val_file (str, default: None ) \u2013

    Name of the validation file

  • test_file (str, default: None ) \u2013

    Name of the test file

  • val_dataloader_names (list, default: None ) \u2013

    Names of the dataloaders to use for validation

  • test_dataloader_names (list, default: None ) \u2013

    Names of the dataloaders to use for testing

  • check_solution (bool, default: True ) \u2013

    Whether to check the validity of the solution at the end of the episode

  • dataset_cls (callable, default: TensorDictDataset ) \u2013

    Dataset class to use for the environment (which can influence performance)

  • seed (int, default: None ) \u2013

    Seed for the environment

  • device (str, default: 'cpu' ) \u2013

    Device to use. Generally, no need to set as tensors are updated on the fly

  • batch_size (Size, default: None ) \u2013

    Batch size to use for the environment. Generally, no need to set as tensors are updated on the fly

  • run_type_checks (bool, default: False ) \u2013

    If True, run type checks on the TensorDicts at each step

  • allow_done_after_reset (bool, default: False ) \u2013

    If True, an environment can be done after a reset

  • _torchrl_mode (bool, default: False ) \u2013

    Whether to use the TorchRL mode (see :meth:step for more details)

Source code in rl4co/envs/common/base.py
def __init__(\n    self,\n    *,\n    data_dir: str = \"data/\",\n    train_file: str = None,\n    val_file: str = None,\n    test_file: str = None,\n    val_dataloader_names: list = None,\n    test_dataloader_names: list = None,\n    check_solution: bool = True,\n    dataset_cls: callable = TensorDictDataset,\n    seed: int = None,\n    device: str = \"cpu\",\n    batch_size: torch.Size = None,\n    run_type_checks: bool = False,\n    allow_done_after_reset: bool = False,\n    _torchrl_mode: bool = False,\n    **kwargs,\n):\n    super().__init__(\n        device=device,\n        batch_size=batch_size,\n        run_type_checks=run_type_checks,\n        allow_done_after_reset=allow_done_after_reset,\n    )\n    # if any kwargs are left, we want to warn the user\n    kwargs.pop(\"name\", None)  # we remove the name for checking\n    if kwargs:\n        log.error(\n            f\"Unused keyword arguments: {', '.join(kwargs.keys())}. \"\n            \"Please check the base class documentation at https://rl4co.readthedocs.io/en/latest/_content/api/envs/base.html. \"\n            \"In case you would like to pass data generation arguments, please pass a `generator` method instead \"\n            \"or for example: `generator_kwargs=dict(num_loc=50)` to the constructor.\"\n        )\n    self.data_dir = data_dir\n    self.train_file = pjoin(data_dir, train_file) if train_file is not None else None\n    self._torchrl_mode = _torchrl_mode\n    self.dataset_cls = dataset_cls\n\n    def get_files(f):\n        if f is not None:\n            if isinstance(f, Iterable) and not isinstance(f, str):\n                return [pjoin(data_dir, _f) for _f in f]\n            else:\n                return pjoin(data_dir, f)\n        return None\n\n    def get_multiple_dataloader_names(f, names):\n        if f is not None:\n            if isinstance(f, Iterable) and not isinstance(f, str):\n                if names is None:\n                    names = [f\"{i}\" for i in range(len(f))]\n                else:\n                    assert len(names) == len(\n                        f\n                    ), \"Number of dataloader names must match number of files\"\n            else:\n                if names is not None:\n                    log.warning(\n                        \"Ignoring dataloader names since only one dataloader is provided\"\n                    )\n        return names\n\n    self.val_file = get_files(val_file)\n    self.test_file = get_files(test_file)\n    self.val_dataloader_names = get_multiple_dataloader_names(\n        self.val_file, val_dataloader_names\n    )\n    self.test_dataloader_names = get_multiple_dataloader_names(\n        self.test_file, test_dataloader_names\n    )\n    self.check_solution = check_solution\n    if seed is None:\n        seed = torch.empty((), dtype=torch.int64).random_().item()\n    self.set_seed(seed)\n
"},{"location":"docs/content/api/envs/base/#envs.common.base.RL4COEnvBase.step","title":"step","text":"
step(td: TensorDict) -> TensorDict\n

Step function to call at each step of the episode containing an action. If _torchrl_mode is True, we call _torchrl_step instead which set the next key of the TensorDict to the next state - this is the usual way to do it in TorchRL, but inefficient in our case

Source code in rl4co/envs/common/base.py
def step(self, td: TensorDict) -> TensorDict:\n    \"\"\"Step function to call at each step of the episode containing an action.\n    If `_torchrl_mode` is True, we call `_torchrl_step` instead which set the\n    `next` key of the TensorDict to the next state - this is the usual way to do it in TorchRL,\n    but inefficient in our case\n    \"\"\"\n    if not self._torchrl_mode:\n        # Default: just return the TensorDict without farther checks etc is faster\n        td = self._step(td)\n        return {\"next\": td}\n    else:\n        # Since we simplify the syntax\n        return self._torchrl_step(td)\n
"},{"location":"docs/content/api/envs/base/#envs.common.base.RL4COEnvBase.reset","title":"reset","text":"
reset(\n    td: Optional[TensorDict] = None, batch_size=None\n) -> TensorDict\n

Reset function to call at the beginning of each episode

Source code in rl4co/envs/common/base.py
def reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict:\n    \"\"\"Reset function to call at the beginning of each episode\"\"\"\n    if batch_size is None:\n        batch_size = self.batch_size if td is None else td.batch_size\n    if td is None or td.is_empty():\n        td = self.generator(batch_size=batch_size)\n    batch_size = [batch_size] if isinstance(batch_size, int) else batch_size\n    self.to(td.device)\n    return super().reset(td, batch_size=batch_size)\n
"},{"location":"docs/content/api/envs/base/#envs.common.base.RL4COEnvBase.get_reward","title":"get_reward","text":"
get_reward(td: TensorDict, actions: Tensor) -> Tensor\n

Function to compute the reward. Can be called by the agent to compute the reward of the current state This is faster than calling step() and getting the reward from the returned TensorDict at each time for CO tasks

Source code in rl4co/envs/common/base.py
def get_reward(self, td: TensorDict, actions: torch.Tensor) -> torch.Tensor:\n    \"\"\"Function to compute the reward. Can be called by the agent to compute the reward of the current state\n    This is faster than calling step() and getting the reward from the returned TensorDict at each time for CO tasks\n    \"\"\"\n    if self.check_solution:\n        self.check_solution_validity(td, actions)\n    return self._get_reward(td, actions)\n
"},{"location":"docs/content/api/envs/base/#envs.common.base.RL4COEnvBase.get_action_mask","title":"get_action_mask","text":"
get_action_mask(td: TensorDict) -> Tensor\n

Function to compute the action mask (feasible actions) for the current state Action mask is 1 if the action is feasible, 0 otherwise

Source code in rl4co/envs/common/base.py
def get_action_mask(self, td: TensorDict) -> torch.Tensor:\n    \"\"\"Function to compute the action mask (feasible actions) for the current state\n    Action mask is 1 if the action is feasible, 0 otherwise\n    \"\"\"\n    raise NotImplementedError\n
"},{"location":"docs/content/api/envs/base/#envs.common.base.RL4COEnvBase.check_solution_validity","title":"check_solution_validity","text":"
check_solution_validity(\n    td: TensorDict, actions: Tensor\n) -> None\n

Function to check whether the solution is valid. Can be called by the agent to check the validity of the current state This is called with the full solution (i.e. all actions) at the end of the episode

Source code in rl4co/envs/common/base.py
def check_solution_validity(self, td: TensorDict, actions: torch.Tensor) -> None:\n    \"\"\"Function to check whether the solution is valid. Can be called by the agent to check the validity of the current state\n    This is called with the full solution (i.e. all actions) at the end of the episode\n    \"\"\"\n    raise NotImplementedError\n
"},{"location":"docs/content/api/envs/base/#envs.common.base.RL4COEnvBase.replace_selected_actions","title":"replace_selected_actions","text":"
replace_selected_actions(\n    cur_actions: Tensor,\n    new_actions: Tensor,\n    selection_mask: Tensor,\n) -> Tensor\n

Replace selected current actions with updated actions based on selection_mask.

Source code in rl4co/envs/common/base.py
def replace_selected_actions(\n    self,\n    cur_actions: torch.Tensor,\n    new_actions: torch.Tensor,\n    selection_mask: torch.Tensor,\n) -> torch.Tensor:\n    \"\"\"\n    Replace selected current actions with updated actions based on `selection_mask`.\n    \"\"\"\n    raise NotImplementedError\n
"},{"location":"docs/content/api/envs/base/#envs.common.base.RL4COEnvBase.local_search","title":"local_search","text":"
local_search(\n    td: TensorDict, actions: Tensor, **kwargs\n) -> Tensor\n

Function to improve the solution. Can be called by the agent to improve the current state This is called with the full solution (i.e. all actions) at the end of the episode

Source code in rl4co/envs/common/base.py
def local_search(\n    self, td: TensorDict, actions: torch.Tensor, **kwargs\n) -> torch.Tensor:\n    \"\"\"Function to improve the solution. Can be called by the agent to improve the current state\n    This is called with the full solution (i.e. all actions) at the end of the episode\n    \"\"\"\n    raise NotImplementedError(\n        f\"Local is not implemented yet for {self.name} environment\"\n    )\n
"},{"location":"docs/content/api/envs/base/#envs.common.base.RL4COEnvBase.dataset","title":"dataset","text":"
dataset(batch_size=[], phase='train', filename=None)\n

Return a dataset of observations Generates the dataset if it does not exist, otherwise loads it from file

Source code in rl4co/envs/common/base.py
def dataset(self, batch_size=[], phase=\"train\", filename=None):\n    \"\"\"Return a dataset of observations\n    Generates the dataset if it does not exist, otherwise loads it from file\n    \"\"\"\n    if filename is not None:\n        log.info(f\"Overriding dataset filename from {filename}\")\n    f = getattr(self, f\"{phase}_file\") if filename is None else filename\n    if f is None:\n        if phase != \"train\":\n            log.warning(f\"{phase}_file not set. Generating dataset instead\")\n        td = self.generator(batch_size)\n    else:\n        log.info(f\"Loading {phase} dataset from {f}\")\n        if phase == \"train\":\n            log.warning(\n                \"Loading training dataset from file. This may not be desired in RL since \"\n                \"the dataset is fixed and the agent will not be able to explore new states\"\n            )\n        try:\n            if isinstance(f, Iterable) and not isinstance(f, str):\n                names = getattr(self, f\"{phase}_dataloader_names\")\n                return {\n                    name: self.dataset_cls(self.load_data(_f, batch_size))\n                    for name, _f in zip(names, f)\n                }\n            else:\n                td = self.load_data(f, batch_size)\n        except FileNotFoundError:\n            log.error(\n                f\"Provided file name {f} not found. Make sure to provide a file in the right path first or \"\n                f\"unset {phase}_file to generate data automatically instead\"\n            )\n            td = self.generator(batch_size)\n\n    return self.dataset_cls(td)\n
"},{"location":"docs/content/api/envs/base/#envs.common.base.RL4COEnvBase.transform","title":"transform","text":"
transform()\n

Used for converting TensorDict variables (such as with torch.cat) efficiently https://pytorch.org/rl/reference/generated/torchrl.envs.transforms.Transform.html By default, we do not need to transform the environment since we use specific embeddings

Source code in rl4co/envs/common/base.py
def transform(self):\n    \"\"\"Used for converting TensorDict variables (such as with torch.cat) efficiently\n    https://pytorch.org/rl/reference/generated/torchrl.envs.transforms.Transform.html\n    By default, we do not need to transform the environment since we use specific embeddings\n    \"\"\"\n    return self\n
"},{"location":"docs/content/api/envs/base/#envs.common.base.RL4COEnvBase.render","title":"render","text":"
render(*args, **kwargs)\n

Render the environment

Source code in rl4co/envs/common/base.py
def render(self, *args, **kwargs):\n    \"\"\"Render the environment\"\"\"\n    raise NotImplementedError\n
"},{"location":"docs/content/api/envs/base/#envs.common.base.RL4COEnvBase.load_data","title":"load_data staticmethod","text":"
load_data(fpath, batch_size=[])\n

Dataset loading from file

Source code in rl4co/envs/common/base.py
@staticmethod\ndef load_data(fpath, batch_size=[]):\n    \"\"\"Dataset loading from file\"\"\"\n    return load_npz_to_tensordict(fpath)\n
"},{"location":"docs/content/api/envs/base/#envs.common.base.RL4COEnvBase.to","title":"to","text":"
to(device)\n

Override to device method for safety against None device (may be found in TensorDict)

Source code in rl4co/envs/common/base.py
def to(self, device):\n    \"\"\"Override `to` device method for safety against `None` device (may be found in `TensorDict`)\"\"\"\n    if device is None:\n        return self\n    else:\n        return super().to(device)\n
"},{"location":"docs/content/api/envs/base/#envs.common.base.RL4COEnvBase.solve","title":"solve staticmethod","text":"
solve(\n    instances: TensorDict,\n    max_runtime: float,\n    num_procs: int = 1,\n    **kwargs\n) -> tuple[Tensor, Tensor]\n

Classical solver for the environment. This is a wrapper for the baselines solver.

Parameters:

  • instances (TensorDict) \u2013

    The instances to solve

  • max_runtime (float) \u2013

    The maximum runtime for the solver

  • num_procs (int, default: 1 ) \u2013

    The number of processes to use

Returns:

  • tuple[Tensor, Tensor] \u2013

    A tuple containing the action and the cost, respectively

Source code in rl4co/envs/common/base.py
@staticmethod\ndef solve(\n    instances: TensorDict,\n    max_runtime: float,\n    num_procs: int = 1,\n    **kwargs,\n) -> tuple[torch.Tensor, torch.Tensor]:\n    \"\"\"Classical solver for the environment. This is a wrapper for the baselines solver.\n\n    Args:\n        instances: The instances to solve\n        max_runtime: The maximum runtime for the solver\n        num_procs: The number of processes to use\n\n    Returns:\n        A tuple containing the action and the cost, respectively\n    \"\"\"\n    raise NotImplementedError\n
"},{"location":"docs/content/api/envs/base/#envs.common.base.ImprovementEnvBase","title":"ImprovementEnvBase","text":"
ImprovementEnvBase(**kwargs)\n

Bases: RL4COEnvBase

Base class for Improvement environments based on RL4CO EnvBase. Note that this class assumes that the solution is stored in a linked list format. Here, if rec[i] = j, it means the node i is connected to node j, i.e., edge i-j is in the solution. For example, if edge 0-1, edge 1-5, edge 2-10 are in the solution, so we have rec[0]=1, rec[1]=5 and rec[2]=10. Kindly see https://github.com/yining043/VRP-DACT/blob/new_version/Play_with_DACT.ipynb for an example at the end for TSP.

Source code in rl4co/envs/common/base.py
def __init__(\n    self,\n    **kwargs,\n):\n    super().__init__(**kwargs)\n
"},{"location":"docs/content/api/envs/base/#utilities","title":"Utilities","text":"

These contain utilities such as the base Generator class and get_sampler.

"},{"location":"docs/content/api/envs/base/#envs.common.utils.Generator","title":"Generator","text":"
Generator(**kwargs)\n

Base data generator class, to be called with env.generator(batch_size)

Source code in rl4co/envs/common/utils.py
def __init__(self, **kwargs):\n    self.kwargs = kwargs\n
"},{"location":"docs/content/api/envs/base/#envs.common.utils.get_sampler","title":"get_sampler","text":"
get_sampler(\n    val_name: str,\n    distribution: Union[int, float, str, type, Callable],\n    low: float = 0,\n    high: float = 1.0,\n    **kwargs\n)\n

Get the sampler for the variable with the given distribution. If kwargs are passed, they will be parsed e.g. with val_name + _dist_arg (e.g. loc_std for Normal distribution).

Parameters:

  • val_name (str) \u2013

    Name of the variable

  • distribution (Union[int, float, str, type, Callable]) \u2013

    int/float value (as constant distribution), or string with the distribution name (supporting uniform, normal, exponential, and poisson) or PyTorch Distribution type or a callable function that returns a PyTorch Distribution

  • low (float, default: 0 ) \u2013

    Minimum value for the variable, used for Uniform distribution

  • high (float, default: 1.0 ) \u2013

    Maximum value for the variable, used for Uniform distribution

  • kwargs \u2013

    Additional arguments for the distribution

Example
sampler_uniform = get_sampler(\"loc\", \"uniform\", 0, 1)\nsampler_normal = get_sampler(\"loc\", \"normal\", loc_mean=0.5, loc_std=.2)\n
Source code in rl4co/envs/common/utils.py
def get_sampler(\n    val_name: str,\n    distribution: Union[int, float, str, type, Callable],\n    low: float = 0,\n    high: float = 1.0,\n    **kwargs,\n):\n    \"\"\"Get the sampler for the variable with the given distribution.\n    If kwargs are passed, they will be parsed e.g. with `val_name` + `_dist_arg` (e.g. `loc_std` for Normal distribution).\n\n    Args:\n        val_name: Name of the variable\n        distribution: int/float value (as constant distribution), or string with the distribution name (supporting\n            uniform, normal, exponential, and poisson) or PyTorch Distribution type or a callable function that\n            returns a PyTorch Distribution\n        low: Minimum value for the variable, used for Uniform distribution\n        high: Maximum value for the variable, used for Uniform distribution\n        kwargs: Additional arguments for the distribution\n\n    Example:\n        ```python\n        sampler_uniform = get_sampler(\"loc\", \"uniform\", 0, 1)\n        sampler_normal = get_sampler(\"loc\", \"normal\", loc_mean=0.5, loc_std=.2)\n        ```\n    \"\"\"\n    if isinstance(distribution, (int, float)):\n        return Uniform(low=distribution, high=distribution)\n    elif distribution == Uniform or distribution == \"uniform\":\n        return Uniform(low=low, high=high)\n    elif distribution == Normal or distribution == \"normal\" or distribution == \"gaussian\":\n        assert (\n            kwargs.get(val_name + \"_mean\", None) is not None\n        ), \"mean is required for Normal distribution\"\n        assert (\n            kwargs.get(val_name + \"_std\", None) is not None\n        ), \"std is required for Normal distribution\"\n        return Normal(loc=kwargs[val_name + \"_mean\"], scale=kwargs[val_name + \"_std\"])\n    elif distribution == Exponential or distribution == \"exponential\":\n        assert (\n            kwargs.get(val_name + \"_rate\", None) is not None\n        ), \"rate is required for Exponential/Poisson distribution\"\n        return Exponential(rate=kwargs[val_name + \"_rate\"])\n    elif distribution == Poisson or distribution == \"poisson\":\n        assert (\n            kwargs.get(val_name + \"_rate\", None) is not None\n        ), \"rate is required for Exponential/Poisson distribution\"\n        return Poisson(rate=kwargs[val_name + \"_rate\"])\n    elif distribution == \"center\":\n        return Uniform(low=(high - low) / 2, high=(high - low) / 2)\n    elif distribution == \"corner\":\n        return Uniform(\n            low=low, high=low\n        )  # todo: should be also `low, high` and any other corner\n    elif isinstance(distribution, Callable):\n        return distribution(**kwargs)\n    elif distribution == \"gaussian_mixture\":\n        return Gaussian_Mixture(num_modes=kwargs[\"num_modes\"], cdist=kwargs[\"cdist\"])\n    elif distribution == \"cluster\":\n        return Cluster(kwargs[\"n_cluster\"])\n    elif distribution == \"mixed\":\n        return Mixed(kwargs[\"n_cluster_mix\"])\n    elif distribution == \"mix_distribution\":\n        return Mix_Distribution(kwargs[\"n_cluster\"], kwargs[\"n_cluster_mix\"])\n    elif distribution == \"mix_multi_distributions\":\n        return Mix_Multi_Distributions()\n    else:\n        raise ValueError(f\"Invalid distribution type of {distribution}\")\n
"},{"location":"docs/content/api/envs/base/#envs.common.utils.batch_to_scalar","title":"batch_to_scalar","text":"
batch_to_scalar(param)\n

Return first element if in batch. Used for batched parameters that are the same for all elements in the batch.

Source code in rl4co/envs/common/utils.py
def batch_to_scalar(param):\n    \"\"\"Return first element if in batch. Used for batched parameters that are the same for all elements in the batch.\"\"\"\n    if len(param.shape) > 0:\n        return param[0].item()\n    if isinstance(param, torch.Tensor):\n        return param.item()\n    return param\n
"},{"location":"docs/content/api/envs/eda/","title":"EDA Problems","text":"

Environment for Electronic Design Automation (EDA) problems

"},{"location":"docs/content/api/envs/eda/#decap-placement-problem-dpp","title":"Decap Placement Problem (DPP)","text":""},{"location":"docs/content/api/envs/eda/#envs.eda.dpp.env.DPPEnv","title":"DPPEnv","text":"
DPPEnv(\n    generator: DPPGenerator = None,\n    generator_params: dict = {},\n    **kwargs\n)\n

Bases: RL4COEnvBase

Decap Placement Problem (DPP) as done in DevFormer paper: https://arxiv.org/abs/2205.13225

The environment is a 10x10 grid with 100 locations containing either a probing port or a keepout region. The goal is to place decaps (decoupling capacitors) to maximize the impedance suppression at the probing port. Decaps cannot be placed in keepout regions or at the probing port and the number of decaps is limited.

Observations
  • locations of the probing port and keepout regions
  • current decap placement
  • remaining decaps
Constraints
  • decaps cannot be placed at the probing port or keepout regions
  • the number of decaps is limited
Finish Condition
  • the number of decaps exceeds the limit
Reward
  • the impedance suppression at the probing port

Parameters:

  • generator (DPPGenerator, default: None ) \u2013

    DPPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

Source code in rl4co/envs/eda/dpp/env.py
def __init__(\n    self,\n    generator: DPPGenerator = None,\n    generator_params: dict = {},\n    **kwargs,\n):\n    super().__init__(**kwargs)\n    if generator is None:\n        generator = DPPGenerator(**generator_params)\n    self.generator = generator\n\n    self.max_decaps = self.generator.max_decaps\n    self.size = self.generator.size\n    self.raw_pdn = self.generator.raw_pdn\n    self.decap = self.generator.decap\n    self.freq = self.generator.freq\n    self.num_freq = self.generator.num_freq\n    self.data_dir = self.generator.data_dir\n\n    self._make_spec(self.generator)\n
"},{"location":"docs/content/api/envs/eda/#envs.eda.dpp.generator.DPPGenerator","title":"DPPGenerator","text":"
DPPGenerator(\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    num_keepout_min: int = 1,\n    num_keepout_max: int = 50,\n    max_decaps: int = 20,\n    data_dir: str = \"data/dpp/\",\n    chip_file: str = \"10x10_pkg_chip.npy\",\n    decap_file: str = \"01nF_decap.npy\",\n    freq_file: str = \"freq_201.npy\",\n    url: str = None,\n    **unused_kwargs\n)\n

Bases: Generator

Data generator for the Decap Placement Problem (DPP).

Parameters:

  • min_loc (float, default: 0.0 ) \u2013

    Minimum location value. Defaults to 0.

  • max_loc (float, default: 1.0 ) \u2013

    Maximum location value. Defaults to 1.

  • num_keepout_min (int, default: 1 ) \u2013

    Minimum number of keepout regions. Defaults to 1.

  • num_keepout_max (int, default: 50 ) \u2013

    Maximum number of keepout regions. Defaults to 50.

  • max_decaps (int, default: 20 ) \u2013

    Maximum number of decaps. Defaults to 20.

  • data_dir (str, default: 'data/dpp/' ) \u2013

    Directory to store data. Defaults to \"data/dpp/\". This can be downloaded from this url.

  • chip_file (str, default: '10x10_pkg_chip.npy' ) \u2013

    Name of the chip file. Defaults to \"10x10_pkg_chip.npy\".

  • decap_file (str, default: '01nF_decap.npy' ) \u2013

    Name of the decap file. Defaults to \"01nF_decap.npy\".

  • freq_file (str, default: 'freq_201.npy' ) \u2013

    Name of the frequency file. Defaults to \"freq_201.npy\".

  • url (str, default: None ) \u2013

    URL to download data from. Defaults to None.

Returns:

  • \u2013

    A TensorDict with the following keys: locs [batch_size, num_loc, 2]: locations of each customer depot [batch_size, 2]: location of the depot demand [batch_size, num_loc]: demand of each customer capacity [batch_size]: capacity of the vehicle

Source code in rl4co/envs/eda/dpp/generator.py
def __init__(\n    self,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    num_keepout_min: int = 1,\n    num_keepout_max: int = 50,\n    max_decaps: int = 20,\n    data_dir: str = \"data/dpp/\",\n    chip_file: str = \"10x10_pkg_chip.npy\",\n    decap_file: str = \"01nF_decap.npy\",\n    freq_file: str = \"freq_201.npy\",\n    url: str = None,\n    **unused_kwargs\n):\n    self.min_loc = min_loc\n    self.max_loc = max_loc\n    self.num_keepout_min = num_keepout_min\n    self.num_keepout_max = num_keepout_max\n    self.max_decaps = max_decaps\n    self.data_dir = data_dir\n\n    # DPP environment doen't have any other kwargs\n    if len(unused_kwargs) > 0:\n        log.error(f\"Found {len(unused_kwargs)} unused kwargs: {unused_kwargs}\")\n\n\n    # Download and load the data from online dataset\n    self.url = (\n        \"https://github.com/kaist-silab/devformer/raw/main/data/data.zip\"\n        if url is None\n        else url\n    )\n    self.backup_url = (\n        \"https://drive.google.com/uc?id=1IEuR2v8Le-mtHWHxwTAbTOPIkkQszI95\"\n    )\n    self._load_dpp_data(chip_file, decap_file, freq_file)\n\n    # Check the validity of the keepout parameters\n    assert (\n        num_keepout_min <= num_keepout_max\n    ), \"num_keepout_min must be <= num_keepout_max\"\n    assert (\n        num_keepout_max <= self.size**2\n    ), \"num_keepout_max must be <= size * size (total number of locations)\"\n
"},{"location":"docs/content/api/envs/eda/#multi-port-decap-placement-problem-mdpp","title":"Multi-port Decap Placement Problem (mDPP)","text":""},{"location":"docs/content/api/envs/eda/#envs.eda.mdpp.env.MDPPEnv","title":"MDPPEnv","text":"
MDPPEnv(\n    generator: MDPPGenerator = None,\n    generator_params: dict = {},\n    reward_type: str = \"minmax\",\n    **kwargs\n)\n

Bases: DPPEnv

Multiple decap placement problem (mDPP) environment This is a modified version of the DPP environment where we allow multiple probing ports

Observations
  • locations of the probing ports and keepout regions
  • current decap placement
  • remaining decaps
Constraints
  • decaps cannot be placed at the probing ports or keepout regions
  • the number of decaps is limited
Finish Condition
  • the number of decaps exceeds the limit
Reward
  • the impedance suppression at the probing ports

Parameters:

  • generator (MDPPGenerator, default: None ) \u2013

    DPPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

  • reward_type (str, default: 'minmax' ) \u2013

    reward type, either minmax or meansum

    • minmax: min of the max of the decap scores
    • meansum: mean of the sum of the decap scores
Note

The minmax is more challenging as it requires to find the best decap location for the worst case

Source code in rl4co/envs/eda/mdpp/env.py
def __init__(\n    self,\n    generator: MDPPGenerator = None,\n    generator_params: dict = {},\n    reward_type: str = \"minmax\",\n    **kwargs,\n):\n    super().__init__(**kwargs)\n    if generator is None:\n        generator = MDPPGenerator(**generator_params)\n    self.generator = generator\n\n    assert reward_type in [\n        \"minmax\",\n        \"meansum\",\n    ], \"reward_type must be minmax or meansum\"\n    self.reward_type = reward_type\n\n    self._make_spec(self.generator)\n
"},{"location":"docs/content/api/envs/eda/#envs.eda.mdpp.generator.MDPPGenerator","title":"MDPPGenerator","text":"
MDPPGenerator(\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    num_keepout_min: int = 1,\n    num_keepout_max: int = 50,\n    num_probes_min: int = 2,\n    num_probes_max: int = 5,\n    max_decaps: int = 20,\n    data_dir: str = \"data/dpp/\",\n    chip_file: str = \"10x10_pkg_chip.npy\",\n    decap_file: str = \"01nF_decap.npy\",\n    freq_file: str = \"freq_201.npy\",\n    url: str = None,\n    **unused_kwargs\n)\n

Bases: Generator

Data generator for the Multi Decap Placement Problem (MDPP).

Parameters:

  • min_loc (float, default: 0.0 ) \u2013

    Minimum location value. Defaults to 0.

  • max_loc (float, default: 1.0 ) \u2013

    Maximum location value. Defaults to 1.

  • num_keepout_min (int, default: 1 ) \u2013

    Minimum number of keepout regions. Defaults to 1.

  • num_keepout_max (int, default: 50 ) \u2013

    Maximum number of keepout regions. Defaults to 50.

  • max_decaps (int, default: 20 ) \u2013

    Maximum number of decaps. Defaults to 20.

  • data_dir (str, default: 'data/dpp/' ) \u2013

    Directory to store data. Defaults to \"data/dpp/\". This can be downloaded from this url.

  • chip_file (str, default: '10x10_pkg_chip.npy' ) \u2013

    Name of the chip file. Defaults to \"10x10_pkg_chip.npy\".

  • decap_file (str, default: '01nF_decap.npy' ) \u2013

    Name of the decap file. Defaults to \"01nF_decap.npy\".

  • freq_file (str, default: 'freq_201.npy' ) \u2013

    Name of the frequency file. Defaults to \"freq_201.npy\".

  • url (str, default: None ) \u2013

    URL to download data from. Defaults to None.

Returns:

  • \u2013

    A TensorDict with the following keys: locs [batch_size, num_loc, 2]: locations of each customer depot [batch_size, 2]: location of the depot demand [batch_size, num_loc]: demand of each customer capacity [batch_size]: capacity of the vehicle

Source code in rl4co/envs/eda/mdpp/generator.py
def __init__(\n    self,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    num_keepout_min: int = 1,\n    num_keepout_max: int = 50,\n    num_probes_min: int = 2,\n    num_probes_max: int = 5,\n    max_decaps: int = 20,\n    data_dir: str = \"data/dpp/\",\n    chip_file: str = \"10x10_pkg_chip.npy\",\n    decap_file: str = \"01nF_decap.npy\",\n    freq_file: str = \"freq_201.npy\",\n    url: str = None,\n    **unused_kwargs\n):\n    self.min_loc = min_loc\n    self.max_loc = max_loc\n    self.num_keepout_min = num_keepout_min\n    self.num_keepout_max = num_keepout_max\n    self.num_probes_min = num_probes_min\n    self.num_probes_max = num_probes_max\n    self.max_decaps = max_decaps\n    self.data_dir = data_dir\n\n    # DPP environment doen't have any other kwargs\n    if len(unused_kwargs) > 0:\n        log.error(f\"Found {len(unused_kwargs)} unused kwargs: {unused_kwargs}\")\n\n\n    # Download and load the data from online dataset\n    self.url = (\n        \"https://github.com/kaist-silab/devformer/raw/main/data/data.zip\"\n        if url is None\n        else url\n    )\n    self.backup_url = (\n        \"https://drive.google.com/uc?id=1IEuR2v8Le-mtHWHxwTAbTOPIkkQszI95\"\n    )\n    self._load_dpp_data(chip_file, decap_file, freq_file)\n\n    # Check the validity of the keepout parameters\n    assert (\n        num_keepout_min <= num_keepout_max\n    ), \"num_keepout_min must be <= num_keepout_max\"\n    assert (\n        num_keepout_max <= self.size**2\n    ), \"num_keepout_max must be <= size * size (total number of locations)\"\n
"},{"location":"docs/content/api/envs/graph/","title":"Graph Problems","text":""},{"location":"docs/content/api/envs/graph/#facility-location-problem-flp","title":"Facility Location Problem (FLP)","text":""},{"location":"docs/content/api/envs/graph/#envs.graph.flp.env.FLPEnv","title":"FLPEnv","text":"
FLPEnv(\n    generator: FLPGenerator = None,\n    generator_params: dict = {},\n    check_solution=False,\n    **kwargs\n)\n

Bases: RL4COEnvBase

Facility Location Problem (FLP) environment At each step, the agent chooses a location. The reward is 0 unless enough number of locations are chosen. The reward is (-) the total distance of each location to its closest chosen location.

Observations
  • the locations
  • the number of locations to choose
Constraints
  • the given number of locations must be chosen
Finish condition
  • the given number of locations are chosen
Reward
  • (minus) the total distance of each location to its closest chosen location

Parameters:

  • generator (FLPGenerator, default: None ) \u2013

    FLPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

Source code in rl4co/envs/graph/flp/env.py
def __init__(\n    self,\n    generator: FLPGenerator = None,\n    generator_params: dict = {},\n    check_solution=False,\n    **kwargs,\n):\n    super().__init__(**kwargs)\n    if generator is None:\n        generator = FLPGenerator(**generator_params)\n    self.generator = generator\n    self.check_solution = check_solution\n    self._make_spec(self.generator)\n
"},{"location":"docs/content/api/envs/graph/#envs.graph.flp.generator.FLPGenerator","title":"FLPGenerator","text":"
FLPGenerator(\n    num_loc: int = 100,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    loc_distribution: Union[\n        int, float, str, type, Callable\n    ] = Uniform,\n    to_choose: int = 10,\n    **kwargs\n)\n

Bases: Generator

Data generator for the Facility Location Problem (FLP).

Parameters:

  • num_loc (int, default: 100 ) \u2013

    number of locations in the FLP

  • min_loc (float, default: 0.0 ) \u2013

    minimum value for the location coordinates

  • max_loc (float, default: 1.0 ) \u2013

    maximum value for the location coordinates

  • loc_distribution (Union[int, float, str, type, Callable], default: Uniform ) \u2013

    distribution for the location coordinates

Returns:

  • \u2013

    A TensorDict with the following keys: locs [batch_size, num_loc, 2]: locations orig_distances [batch_size, num_loc, num_loc]: original distances between locations distances [batch_size, num_loc]: the current minimum distance rom each location to the chosen locations chosen [batch_size, num_loc]: indicators of chosen locations to_choose [batch_size, 1]: number of locations to choose in the FLP

Source code in rl4co/envs/graph/flp/generator.py
def __init__(\n    self,\n    num_loc: int = 100,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    loc_distribution: Union[int, float, str, type, Callable] = Uniform,\n    to_choose: int = 10,\n    **kwargs,\n):\n    self.num_loc = num_loc\n    self.min_loc = min_loc\n    self.max_loc = max_loc\n    self.to_choose = to_choose\n\n    # Location distribution\n    if kwargs.get(\"loc_sampler\", None) is not None:\n        self.loc_sampler = kwargs[\"loc_sampler\"]\n    else:\n        self.loc_sampler = get_sampler(\n            \"loc\", loc_distribution, min_loc, max_loc, **kwargs\n        )\n
"},{"location":"docs/content/api/envs/graph/#maximum-coverage-problem-mcp","title":"Maximum Coverage Problem (MCP)","text":""},{"location":"docs/content/api/envs/graph/#envs.graph.mcp.env.MCPEnv","title":"MCPEnv","text":"
MCPEnv(\n    generator: MCPGenerator = None,\n    generator_params: dict = {},\n    check_solution=False,\n    **kwargs\n)\n

Bases: RL4COEnvBase

Maximum Coverage Problem (MCP) environment At each step, the agent chooses a set. The reward is 0 unless enough number of sets are chosen. The reward is the total weights of the covered items (i.e., items in any chosen set).

Observations
  • the weights of items
  • the membership of items in sets
  • the number of sets to choose
Constraints
  • the given number of sets must be chosen
Finish condition
  • the given number of sets are chosen
Reward
  • the total weights of the covered items (i.e., items in any chosen set)

Parameters:

  • generator (MCPGenerator, default: None ) \u2013

    MCPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

Source code in rl4co/envs/graph/mcp/env.py
def __init__(\n    self,\n    generator: MCPGenerator = None,\n    generator_params: dict = {},\n    check_solution=False,\n    **kwargs,\n):\n    super().__init__(**kwargs)\n    if generator is None:\n        generator = MCPGenerator(**generator_params)\n    self.generator = generator\n    self.check_solution = check_solution\n    self._make_spec(self.generator)\n
"},{"location":"docs/content/api/envs/graph/#envs.graph.mcp.generator.MCPGenerator","title":"MCPGenerator","text":"
MCPGenerator(\n    num_items: int = 200,\n    num_sets: int = 100,\n    min_weight: int = 1,\n    max_weight: int = 10,\n    min_size: int = 5,\n    max_size: int = 15,\n    n_sets_to_choose: int = 10,\n    size_distribution: Union[\n        int, float, str, type, Callable\n    ] = Uniform,\n    weight_distribution: Union[\n        int, float, str, type, Callable\n    ] = Uniform,\n    **kwargs\n)\n

Bases: Generator

Data generator for the Maximum Coverage Problem (MCP).

Parameters:

  • num_items (int, default: 200 ) \u2013

    number of items in the MCP

  • num_sets (int, default: 100 ) \u2013

    number of sets in the MCP

  • min_weight (int, default: 1 ) \u2013

    minimum value for the item weights

  • max_weight (int, default: 10 ) \u2013

    maximum value for the item weights

  • min_size (int, default: 5 ) \u2013

    minimum size for the sets

  • max_size (int, default: 15 ) \u2013

    maximum size for the sets

  • n_sets_to_choose (int, default: 10 ) \u2013

    number of sets to choose in the MCP

Returns:

  • \u2013

    A TensorDict with the following keys: membership [batch_size, num_sets, max_size]: membership of items in sets weights [batch_size, num_items]: weights of the items n_sets_to_choose [batch_size, 1]: number of sets to choose in the MCP

Source code in rl4co/envs/graph/mcp/generator.py
def __init__(\n    self,\n    num_items: int = 200,\n    num_sets: int = 100,\n    min_weight: int = 1,\n    max_weight: int = 10,\n    min_size: int = 5,\n    max_size: int = 15,\n    n_sets_to_choose: int = 10,\n    size_distribution: Union[int, float, str, type, Callable] = Uniform,\n    weight_distribution: Union[int, float, str, type, Callable] = Uniform,\n    **kwargs,\n):\n    self.num_items = num_items\n    self.num_sets = num_sets\n    self.min_weight = min_weight\n    self.max_weight = max_weight\n    self.min_size = min_size\n    self.max_size = max_size\n    self.n_sets_to_choose = n_sets_to_choose\n\n    # Set size distribution\n    if kwargs.get(\"size_sampler\", None) is not None:\n        self.size_sampler = kwargs[\"size_sampler\"]\n    else:\n        self.size_sampler = get_sampler(\n            \"size\", size_distribution, min_size, max_size + 1, **kwargs\n        )\n\n    # Item weight distribution\n    if kwargs.get(\"weight_sampler\", None) is not None:\n        self.weight_sampler = kwargs[\"weight_sampler\"]\n    else:\n        self.weight_sampler = get_sampler(\n            \"weight\", weight_distribution, min_weight, max_weight + 1, **kwargs\n        )\n
"},{"location":"docs/content/api/envs/routing/","title":"Routing Problems","text":"

See also the Multi-Task VRP at the bottom of this page, that includes 16 variants!

"},{"location":"docs/content/api/envs/routing/#asymmetric-traveling-salesman-problem-atsp","title":"Asymmetric Traveling Salesman Problem (ATSP)","text":""},{"location":"docs/content/api/envs/routing/#envs.routing.atsp.env.ATSPEnv","title":"ATSPEnv","text":"
ATSPEnv(\n    generator: ATSPGenerator = None,\n    generator_params: dict = {},\n    **kwargs\n)\n

Bases: RL4COEnvBase

Asymmetric Traveling Salesman Problem (ATSP) environment At each step, the agent chooses a customer to visit. The reward is 0 unless the agent visits all the customers. In that case, the reward is (-)length of the path: maximizing the reward is equivalent to minimizing the path length. Unlike the TSP, the distance matrix is asymmetric, i.e., the distance from A to B is not necessarily the same as the distance from B to A.

Observations
  • distance matrix between customers
  • the current customer
  • the first customer (for calculating the reward)
  • the remaining unvisited customers
Constraints
  • the tour starts and ends at the same customer.
  • each customer must be visited exactly once.
Finish Condition
  • the agent has visited all customers.
Reward
  • (minus) the negative length of the path.

Parameters:

  • generator (ATSPGenerator, default: None ) \u2013

    ATSPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

Source code in rl4co/envs/routing/atsp/env.py
def __init__(\n    self,\n    generator: ATSPGenerator = None,\n    generator_params: dict = {},\n    **kwargs,\n):\n    super().__init__(**kwargs)\n    if generator is None:\n        generator = ATSPGenerator(**generator_params)\n    self.generator = generator\n    self._make_spec(self.generator)\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.atsp.generator.ATSPGenerator","title":"ATSPGenerator","text":"
ATSPGenerator(\n    num_loc: int = 10,\n    min_dist: float = 0.0,\n    max_dist: float = 1.0,\n    dist_distribution: Union[\n        int, float, str, type, Callable\n    ] = Uniform,\n    tmat_class: bool = True,\n    **kwargs\n)\n

Bases: Generator

Data generator for the Asymmetric Travelling Salesman Problem (ATSP) Generate distance matrices inspired by the reference MatNet (Kwon et al., 2021) We satifsy the triangle inequality (TMAT class) in a batch

Parameters:

  • num_loc (int, default: 10 ) \u2013

    number of locations (customers) in the TSP

  • min_dist (float, default: 0.0 ) \u2013

    minimum value for the distance between nodes

  • max_dist (float, default: 1.0 ) \u2013

    maximum value for the distance between nodes

  • dist_distribution (Union[int, float, str, type, Callable], default: Uniform ) \u2013

    distribution for the distance between nodes

  • tmat_class (bool, default: True ) \u2013

    whether to generate a class of distance matrix

Returns:

  • \u2013

    A TensorDict with the following keys: locs [batch_size, num_loc, 2]: locations of each customer

Source code in rl4co/envs/routing/atsp/generator.py
def __init__(\n    self,\n    num_loc: int = 10,\n    min_dist: float = 0.0,\n    max_dist: float = 1.0,\n    dist_distribution: Union[\n        int, float, str, type, Callable\n    ] = Uniform,\n    tmat_class: bool = True,\n    **kwargs\n):\n    self.num_loc = num_loc\n    self.min_dist = min_dist\n    self.max_dist = max_dist\n    self.tmat_class = tmat_class\n\n    # Distance distribution\n    if kwargs.get(\"dist_sampler\", None) is not None:\n        self.dist_sampler = kwargs[\"dist_sampler\"]\n    else:\n        self.dist_sampler = get_sampler(\"dist\", dist_distribution, 0.0, 1.0, **kwargs)\n
"},{"location":"docs/content/api/envs/routing/#capacitated-vehicle-routing-problem-cvrp","title":"Capacitated Vehicle Routing Problem (CVRP)","text":""},{"location":"docs/content/api/envs/routing/#envs.routing.cvrp.env.CVRPEnv","title":"CVRPEnv","text":"
CVRPEnv(\n    generator: CVRPGenerator = None,\n    generator_params: dict = {},\n    **kwargs\n)\n

Bases: RL4COEnvBase

Capacitated Vehicle Routing Problem (CVRP) environment. At each step, the agent chooses a customer to visit depending on the current location and the remaining capacity. When the agent visits a customer, the remaining capacity is updated. If the remaining capacity is not enough to visit any customer, the agent must go back to the depot. The reward is 0 unless the agent visits all the cities. In that case, the reward is (-)length of the path: maximizing the reward is equivalent to minimizing the path length.

Observations
  • location of the depot.
  • locations and demand of each customer.
  • current location of the vehicle.
  • the remaining customer of the vehicle,
Constraints
  • the tour starts and ends at the depot.
  • each customer must be visited exactly once.
  • the vehicle cannot visit customers exceed the remaining capacity.
  • the vehicle can return to the depot to refill the capacity.
Finish Condition
  • the vehicle has visited all customers and returned to the depot.
Reward
  • (minus) the negative length of the path.

Parameters:

  • generator (CVRPGenerator, default: None ) \u2013

    CVRPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

Source code in rl4co/envs/routing/cvrp/env.py
def __init__(\n    self,\n    generator: CVRPGenerator = None,\n    generator_params: dict = {},\n    **kwargs,\n):\n    super().__init__(**kwargs)\n    if generator is None:\n        generator = CVRPGenerator(**generator_params)\n    self.generator = generator\n    self._make_spec(self.generator)\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.cvrp.env.CVRPEnv.check_solution_validity","title":"check_solution_validity staticmethod","text":"
check_solution_validity(td: TensorDict, actions: Tensor)\n

Check that solution is valid: nodes are not visited twice except depot and capacity is not exceeded

Source code in rl4co/envs/routing/cvrp/env.py
@staticmethod\ndef check_solution_validity(td: TensorDict, actions: torch.Tensor):\n    \"\"\"Check that solution is valid: nodes are not visited twice except depot and capacity is not exceeded\"\"\"\n    # Check if tour is valid, i.e. contain 0 to n-1\n    batch_size, graph_size = td[\"demand\"].size()\n    sorted_pi = actions.data.sort(1)[0]\n\n    # Sorting it should give all zeros at front and then 1...n\n    assert (\n        torch.arange(1, graph_size + 1, out=sorted_pi.data.new())\n        .view(1, -1)\n        .expand(batch_size, graph_size)\n        == sorted_pi[:, -graph_size:]\n    ).all() and (sorted_pi[:, :-graph_size] == 0).all(), \"Invalid tour\"\n\n    # Visiting depot resets capacity so we add demand = -capacity (we make sure it does not become negative)\n    demand_with_depot = torch.cat((-td[\"vehicle_capacity\"], td[\"demand\"]), 1)\n    d = demand_with_depot.gather(1, actions)\n\n    used_cap = torch.zeros_like(td[\"demand\"][:, 0])\n    for i in range(actions.size(1)):\n        used_cap += d[\n            :, i\n        ]  # This will reset/make capacity negative if i == 0, e.g. depot visited\n        # Cannot use less than 0\n        used_cap[used_cap < 0] = 0\n        assert (\n            used_cap <= td[\"vehicle_capacity\"] + 1e-5\n        ).all(), \"Used more than capacity\"\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.cvrp.env.CVRPEnv.load_data","title":"load_data staticmethod","text":"
load_data(fpath, batch_size=[])\n

Dataset loading from file Normalize demand by capacity to be in [0, 1]

Source code in rl4co/envs/routing/cvrp/env.py
@staticmethod\ndef load_data(fpath, batch_size=[]):\n    \"\"\"Dataset loading from file\n    Normalize demand by capacity to be in [0, 1]\n    \"\"\"\n    td_load = load_npz_to_tensordict(fpath)\n    td_load.set(\"demand\", td_load[\"demand\"] / td_load[\"capacity\"][:, None])\n    return td_load\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.cvrp.env.CVRPEnv.replace_selected_actions","title":"replace_selected_actions","text":"
replace_selected_actions(\n    cur_actions: Tensor,\n    new_actions: Tensor,\n    selection_mask: Tensor,\n) -> Tensor\n

Replace selected current actions with updated actions based on selection_mask.

Source code in rl4co/envs/routing/cvrp/env.py
def replace_selected_actions(self, cur_actions: torch.Tensor, new_actions: torch.Tensor, selection_mask: torch.Tensor) -> torch.Tensor:\n    \"\"\"\n    Replace selected current actions with updated actions based on `selection_mask`.\n\n    Args:\n        cur_actions [batch_size, num_loc]\n        new_actions [batch_size, num_loc]\n        selection_mask [batch_size,]\n    \"\"\"\n    diff_length = cur_actions.size(-1) - new_actions.size(-1)\n    if diff_length > 0:\n        new_actions = torch.nn.functional.pad(new_actions, (0, diff_length, 0, 0), mode=\"constant\", value=0)\n    elif diff_length < 0:\n        cur_actions = torch.nn.functional.pad(cur_actions, (0, -diff_length, 0, 0), mode=\"constant\", value=0)\n    cur_actions[selection_mask] = new_actions[selection_mask]\n    return cur_actions\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.cvrp.generator.CVRPGenerator","title":"CVRPGenerator","text":"
CVRPGenerator(\n    num_loc: int = 20,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    loc_distribution: Union[\n        int, float, str, type, Callable\n    ] = Uniform,\n    depot_distribution: Union[\n        int, float, str, type, Callable\n    ] = None,\n    min_demand: int = 1,\n    max_demand: int = 10,\n    demand_distribution: Union[\n        int, float, type, Callable\n    ] = Uniform,\n    vehicle_capacity: float = 1.0,\n    capacity: float = None,\n    **kwargs\n)\n

Bases: Generator

Data generator for the Capacitated Vehicle Routing Problem (CVRP).

Parameters:

  • num_loc (int, default: 20 ) \u2013

    number of locations (cities) in the VRP, without the depot. (e.g. 10 means 10 locs + 1 depot)

  • min_loc (float, default: 0.0 ) \u2013

    minimum value for the location coordinates

  • max_loc (float, default: 1.0 ) \u2013

    maximum value for the location coordinates

  • loc_distribution (Union[int, float, str, type, Callable], default: Uniform ) \u2013

    distribution for the location coordinates

  • depot_distribution (Union[int, float, str, type, Callable], default: None ) \u2013

    distribution for the depot location. If None, sample the depot from the locations

  • min_demand (int, default: 1 ) \u2013

    minimum value for the demand of each customer

  • max_demand (int, default: 10 ) \u2013

    maximum value for the demand of each customer

  • demand_distribution (Union[int, float, type, Callable], default: Uniform ) \u2013

    distribution for the demand of each customer

  • capacity (float, default: None ) \u2013

    capacity of the vehicle

Returns:

  • \u2013

    A TensorDict with the following keys: locs [batch_size, num_loc, 2]: locations of each customer depot [batch_size, 2]: location of the depot demand [batch_size, num_loc]: demand of each customer capacity [batch_size]: capacity of the vehicle

Source code in rl4co/envs/routing/cvrp/generator.py
def __init__(\n    self,\n    num_loc: int = 20,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    loc_distribution: Union[int, float, str, type, Callable] = Uniform,\n    depot_distribution: Union[int, float, str, type, Callable] = None,\n    min_demand: int = 1,\n    max_demand: int = 10,\n    demand_distribution: Union[int, float, type, Callable] = Uniform,\n    vehicle_capacity: float = 1.0,\n    capacity: float = None,\n    **kwargs,\n):\n    self.num_loc = num_loc\n    self.min_loc = min_loc\n    self.max_loc = max_loc\n    self.min_demand = min_demand\n    self.max_demand = max_demand\n    self.vehicle_capacity = vehicle_capacity\n\n    # Location distribution\n    if kwargs.get(\"loc_sampler\", None) is not None:\n        self.loc_sampler = kwargs[\"loc_sampler\"]\n    else:\n        self.loc_sampler = get_sampler(\n            \"loc\", loc_distribution, min_loc, max_loc, **kwargs\n        )\n\n    # Depot distribution\n    if kwargs.get(\"depot_sampler\", None) is not None:\n        self.depot_sampler = kwargs[\"depot_sampler\"]\n    else:\n        self.depot_sampler = get_sampler(\n            \"depot\", depot_distribution, min_loc, max_loc, **kwargs\n        ) if depot_distribution is not None else None\n\n    # Demand distribution\n    if kwargs.get(\"demand_sampler\", None) is not None:\n        self.demand_sampler = kwargs[\"demand_sampler\"]\n    else:\n        self.demand_sampler = get_sampler(\n            \"demand\", demand_distribution, min_demand - 1, max_demand - 1, **kwargs\n        )\n\n    # Capacity\n    if (\n        capacity is None\n    ):  # If not provided, use the default capacity from Kool et al. 2019\n        capacity = CAPACITIES.get(num_loc, None)\n    if (\n        capacity is None\n    ):  # If not in the table keys, find the closest number of nodes as the key\n        closest_num_loc = min(CAPACITIES.keys(), key=lambda x: abs(x - num_loc))\n        capacity = CAPACITIES[closest_num_loc]\n        log.warning(\n            f\"The capacity capacity for {num_loc} locations is not defined. Using the closest capacity: {capacity}\\\n                with {closest_num_loc} locations.\"\n        )\n    self.capacity = capacity\n
"},{"location":"docs/content/api/envs/routing/#multiple-traveling-salesman-problem-mtsp","title":"Multiple Traveling Salesman Problem (mTSP)","text":""},{"location":"docs/content/api/envs/routing/#envs.routing.mtsp.env.MTSPEnv","title":"MTSPEnv","text":"
MTSPEnv(\n    generator: MTSPGenerator = None,\n    generator_params: dict = {},\n    cost_type: str = \"minmax\",\n    **kwargs\n)\n

Bases: RL4COEnvBase

Multiple Traveling Salesman Problem environment At each step, an agent chooses to visit a city. A maximum of num_agents agents can be employed to visit the cities. The cost can be defined in two ways:

- `minmax`: (default) the reward is the maximum of the path lengths of all the agents\n- `sum`: the cost is the sum of the path lengths of all the agents\n

Reward is - cost, so the goal is to maximize the reward (minimize the cost).

Observations
  • locations of the depot and each customer.
  • number of agents.
  • the current agent index.
  • the current location of the vehicle.
Constrains
  • each agent's tour starts and ends at the depot.
  • each customer must be visited exactly once.
Finish condition
  • all customers are visited and all agents back to the depot.
Reward

There are two ways to calculate the cost (-reward):

  • minmax: (default) the cost is the maximum of the path lengths of all the agents.
  • sum: the cost is the sum of the path lengths of all the agents.

Parameters:

  • cost_type (str, default: 'minmax' ) \u2013

    type of cost to use, either minmax or sum

  • generator (MTSPGenerator, default: None ) \u2013

    MTSPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

Source code in rl4co/envs/routing/mtsp/env.py
def __init__(\n    self,\n    generator: MTSPGenerator = None,\n    generator_params: dict = {},\n    cost_type: str = \"minmax\",\n    **kwargs,\n):\n    super().__init__(**kwargs)\n    if generator is None:\n        generator = MTSPGenerator(**generator_params)\n    self.generator = generator\n    self.cost_type = cost_type\n    self._make_spec(self.generator)\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.mtsp.generator.MTSPGenerator","title":"MTSPGenerator","text":"
MTSPGenerator(\n    num_loc: int = 20,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    loc_distribution: Union[\n        int, float, str, type, Callable\n    ] = Uniform,\n    min_num_agents: int = 5,\n    max_num_agents: int = 5,\n    **kwargs\n)\n

Bases: Generator

Data generator for the Multiple Travelling Salesman Problem (mTSP).

Parameters:

  • num_loc (int, default: 20 ) \u2013

    number of locations (customers) in the TSP

  • min_loc (float, default: 0.0 ) \u2013

    minimum value for the location coordinates

  • max_loc (float, default: 1.0 ) \u2013

    maximum value for the location coordinates

  • loc_distribution (Union[int, float, str, type, Callable], default: Uniform ) \u2013

    distribution for the location coordinates

  • min_num_agents (int, default: 5 ) \u2013

    minimum number of agents (vehicles), include

  • max_num_agents (int, default: 5 ) \u2013

    maximum number of agents (vehicles), include

Returns:

  • \u2013

    A TensorDict with the following keys: locs [batch_size, num_loc, 2]: locations of each customer num_agents [batch_size]: number of agents (vehicles)

Source code in rl4co/envs/routing/mtsp/generator.py
def __init__(\n    self,\n    num_loc: int = 20,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    loc_distribution: Union[int, float, str, type, Callable] = Uniform,\n    min_num_agents: int = 5,\n    max_num_agents: int = 5,\n    **kwargs,\n):\n    self.num_loc = num_loc\n    self.min_loc = min_loc\n    self.max_loc = max_loc\n    self.min_num_agents = min_num_agents\n    self.max_num_agents = max_num_agents\n\n    # Location distribution\n    if kwargs.get(\"loc_sampler\", None) is not None:\n        self.loc_sampler = kwargs[\"loc_sampler\"]\n    else:\n        self.loc_sampler = get_sampler(\n            \"loc\", loc_distribution, min_loc, max_loc, **kwargs\n        )\n
"},{"location":"docs/content/api/envs/routing/#orienteering-problem-op","title":"Orienteering Problem (OP)","text":""},{"location":"docs/content/api/envs/routing/#envs.routing.op.env.OPEnv","title":"OPEnv","text":"
OPEnv(\n    generator: OPGenerator = None,\n    generator_params: dict = {},\n    prize_type: str = \"dist\",\n    **kwargs\n)\n

Bases: RL4COEnvBase

Orienteering Problem (OP) environment. At each step, the agent chooses a location to visit in order to maximize the collected prize. The total length of the path must not exceed a given threshold.

Observations
  • location of the depot
  • locations and prize of each customer
  • current location of the vehicle
  • current tour length
  • current total prize
  • the remaining length of the path
Constraints
  • the tour starts and ends at the depot
  • not all customers need to be visited
  • the vehicle cannot visit customers exceed the remaining length of the path
Finish Condition
  • the vehicle back to the depot
Reward
  • the sum of the prizes of visited nodes

Parameters:

  • generator (OPGenerator, default: None ) \u2013

    OPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

Source code in rl4co/envs/routing/op/env.py
def __init__(\n    self,\n    generator: OPGenerator = None,\n    generator_params: dict = {},\n    prize_type: str = \"dist\",\n    **kwargs,\n):\n    super().__init__(**kwargs)\n    if generator is None:\n        generator = OPGenerator(**generator_params)\n    self.generator = generator\n    self.prize_type = prize_type\n    assert self.prize_type in [\n        \"dist\",\n        \"unif\",\n        \"const\",\n    ], f\"Invalid prize_type: {self.prize_type}\"\n    self._make_spec(self.generator)\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.op.env.OPEnv.get_action_mask","title":"get_action_mask staticmethod","text":"
get_action_mask(td: TensorDict) -> Tensor\n

Get action mask with 1 = feasible action, 0 = infeasible action. Cannot visit if already visited, if depot has been visited, or if the length exceeds the maximum length.

Source code in rl4co/envs/routing/op/env.py
@staticmethod\ndef get_action_mask(td: TensorDict) -> torch.Tensor:\n    \"\"\"Get action mask with 1 = feasible action, 0 = infeasible action.\n    Cannot visit if already visited, if depot has been visited, or if the length exceeds the maximum length.\n    \"\"\"\n    current_loc = gather_by_index(td[\"locs\"], td[\"current_node\"])[..., None, :]\n    exceeds_length = (\n        td[\"tour_length\"][..., None] + (td[\"locs\"] - current_loc).norm(p=2, dim=-1)\n        > td[\"max_length\"]\n    )\n    mask = td[\"visited\"] | td[\"visited\"][..., 0:1] | exceeds_length\n\n    action_mask = ~mask  # 1 = feasible action, 0 = infeasible action\n\n    # Depot can always be visited: we do not hardcode knowledge that this is strictly suboptimal if other options are available\n    action_mask[..., 0] = 1\n    return action_mask\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.op.env.OPEnv.check_solution_validity","title":"check_solution_validity staticmethod","text":"
check_solution_validity(\n    td: TensorDict,\n    actions: Tensor,\n    add_distance_to_depot: bool = True,\n) -> None\n

Check that solution is valid: nodes are not visited twice except depot and capacity is not exceeded. If add_distance_to_depot if True, then the distance to the depot is added to max length since by default, the max length is modified in the reset function to account for the distance to the depot.

Source code in rl4co/envs/routing/op/env.py
@staticmethod\ndef check_solution_validity(\n    td: TensorDict, actions: torch.Tensor, add_distance_to_depot: bool = True\n) -> None:\n    \"\"\"Check that solution is valid: nodes are not visited twice except depot and capacity is not exceeded.\n    If `add_distance_to_depot` if True, then the distance to the depot is added to max length since by default, the max length is\n    modified in the reset function to account for the distance to the depot.\n    \"\"\"\n\n    # Check that tours are valid, i.e. contain 0 to n -1\n    sorted_actions = actions.data.sort(1)[0]\n    # Make sure each node visited once at most (except for depot)\n    assert (\n        (sorted_actions[:, 1:] == 0)\n        | (sorted_actions[:, 1:] > sorted_actions[:, :-1])\n    ).all(), \"Duplicates\"\n\n    # Gather locations in order of tour and get the length of tours\n    locs_ordered = gather_by_index(td[\"locs\"], actions)\n    length = get_tour_length(locs_ordered)\n\n    max_length = td[\"max_length\"]\n    if add_distance_to_depot:\n        max_length = (\n            max_length\n            + (td[\"locs\"][..., 0:1, :] - td[\"locs\"]).norm(p=2, dim=-1)\n            + 1e-6\n        )\n    assert (\n        length[..., None] <= max_length + 1e-5\n    ).all(), \"Max length exceeded by {}\".format(\n        (length[..., None] - max_length).max()\n    )\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.op.generator.OPGenerator","title":"OPGenerator","text":"
OPGenerator(\n    num_loc: int = 20,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    loc_distribution: Union[\n        int, float, str, type, Callable\n    ] = Uniform,\n    depot_distribution: Union[\n        int, float, str, type, Callable\n    ] = None,\n    min_prize: float = 1.0,\n    max_prize: float = 1.0,\n    prize_distribution: Union[\n        int, float, type, Callable\n    ] = Uniform,\n    prize_type: str = \"dist\",\n    max_length: Union[float, Tensor] = None,\n    **kwargs\n)\n

Bases: Generator

Data generator for the Orienteering Problem (OP).

Parameters:

  • num_loc (int, default: 20 ) \u2013

    number of locations (customers) in the OP, without the depot. (e.g. 10 means 10 locs + 1 depot)

  • min_loc (float, default: 0.0 ) \u2013

    minimum value for the location coordinates

  • max_loc (float, default: 1.0 ) \u2013

    maximum value for the location coordinates

  • loc_distribution (Union[int, float, str, type, Callable], default: Uniform ) \u2013

    distribution for the location coordinates

  • depot_distribution (Union[int, float, str, type, Callable], default: None ) \u2013

    distribution for the depot location. If None, sample the depot from the locations

  • min_prize (float, default: 1.0 ) \u2013

    minimum value for the prize of each customer

  • max_prize (float, default: 1.0 ) \u2013

    maximum value for the prize of each customer

  • prize_distribution (Union[int, float, type, Callable], default: Uniform ) \u2013

    distribution for the prize of each customer

  • max_length (Union[float, Tensor], default: None ) \u2013

    maximum length of the path

Returns:

  • \u2013

    A TensorDict with the following keys: locs [batch_size, num_loc, 2]: locations of each customer depot [batch_size, 2]: location of the depot prize [batch_size, num_loc]: prize of each customer max_length [batch_size, 1]: maximum length of the path for each customer

Source code in rl4co/envs/routing/op/generator.py
def __init__(\n    self,\n    num_loc: int = 20,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    loc_distribution: Union[int, float, str, type, Callable] = Uniform,\n    depot_distribution: Union[int, float, str, type, Callable] = None,\n    min_prize: float = 1.0,\n    max_prize: float = 1.0,\n    prize_distribution: Union[int, float, type, Callable] = Uniform,\n    prize_type: str = \"dist\",\n    max_length: Union[float, torch.Tensor] = None,\n    **kwargs,\n):\n    self.num_loc = num_loc\n    self.min_loc = min_loc\n    self.max_loc = max_loc\n    self.min_prize = min_prize\n    self.max_prize = max_prize\n    self.prize_type = prize_type\n    self.max_length = max_length\n\n    # Location distribution\n    if kwargs.get(\"loc_sampler\", None) is not None:\n        self.loc_sampler = kwargs[\"loc_sampler\"]\n    else:\n        self.loc_sampler = get_sampler(\n            \"loc\", loc_distribution, min_loc, max_loc, **kwargs\n        )\n\n    # Depot distribution\n    if kwargs.get(\"depot_sampler\", None) is not None:\n        self.depot_sampler = kwargs[\"depot_sampler\"]\n    else:\n        self.depot_sampler = get_sampler(\n            \"depot\", depot_distribution, min_loc, max_loc, **kwargs\n        ) if depot_distribution is not None else None\n\n    # Prize distribution\n    if kwargs.get(\"prize_sampler\", None) is not None:\n        self.prize_sampler = kwargs[\"prize_sampler\"]\n    elif (\n        prize_distribution == \"dist\"\n    ):  # If prize_distribution is 'dist', then the prize is the distance from the depot\n        self.prize_sampler = None\n    else:\n        self.prize_sampler = get_sampler(\n            \"prize\", prize_distribution, min_prize, max_prize, **kwargs\n        )\n\n    # Max length\n    if max_length is not None:\n        self.max_length = max_length\n    else:\n        self.max_length = MAX_LENGTHS.get(num_loc, None)\n    if self.max_length is None:\n        closest_num_loc = min(MAX_LENGTHS.keys(), key=lambda x: abs(x - num_loc))\n        self.max_length = MAX_LENGTHS[closest_num_loc]\n        log.warning(\n            f\"The max length for {num_loc} locations is not defined. Using the closest max length: {self.max_length}\\\n                with {closest_num_loc} locations.\"\n        )\n
"},{"location":"docs/content/api/envs/routing/#pickup-and-delivery-problem-pdp","title":"Pickup and Delivery Problem (PDP)","text":""},{"location":"docs/content/api/envs/routing/#envs.routing.pdp.env.PDPEnv","title":"PDPEnv","text":"
PDPEnv(\n    generator: PDPGenerator = None,\n    generator_params: dict = {},\n    **kwargs\n)\n

Bases: RL4COEnvBase

Pickup and Delivery Problem (PDP) environment. The environment is made of num_loc + 1 locations (cities):

- 1 depot\n- `num_loc` / 2 pickup locations\n- `num_loc` / 2 delivery locations\n

The goal is to visit all the pickup and delivery locations in the shortest path possible starting from the depot The conditions is that the agent must visit a pickup location before visiting its corresponding delivery location

Observations
  • locations of the depot, pickup, and delivery locations
  • current location of the vehicle
  • the remaining locations to deliver
  • the visited locations
  • the current step
Constraints
  • the tour starts and ends at the depot
  • each pickup location must be visited before its corresponding delivery location
  • the vehicle cannot visit the same location twice
Finish Condition
  • the vehicle has visited all locations
Reward
  • (minus) the negative length of the path

Parameters:

  • generator (PDPGenerator, default: None ) \u2013

    PDPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

Source code in rl4co/envs/routing/pdp/env.py
def __init__(\n    self,\n    generator: PDPGenerator = None,\n    generator_params: dict = {},\n    **kwargs,\n):\n    super().__init__(**kwargs)\n    if generator is None:\n        generator = PDPGenerator(**generator_params)\n    self.generator = generator\n    self._make_spec(self.generator)\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.pdp.env.PDPEnv.get_num_starts","title":"get_num_starts","text":"
get_num_starts(td)\n

Only half of the nodes (i.e. pickup nodes) can be start nodes

Source code in rl4co/envs/routing/pdp/env.py
def get_num_starts(self, td):\n    \"\"\"Only half of the nodes (i.e. pickup nodes) can be start nodes\"\"\"\n    return (td[\"locs\"].shape[-2] - 1) // 2\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.pdp.env.PDPEnv.select_start_nodes","title":"select_start_nodes","text":"
select_start_nodes(td, num_starts)\n

Only nodes from [1 : num_loc // 2 +1] (i.e. pickups) can be selected

Source code in rl4co/envs/routing/pdp/env.py
def select_start_nodes(self, td, num_starts):\n    \"\"\"Only nodes from [1 : num_loc // 2 +1] (i.e. pickups) can be selected\"\"\"\n    num_possible_starts = (td[\"locs\"].shape[-2] - 1) // 2\n    selected = (\n        torch.arange(num_starts, device=td.device).repeat_interleave(td.shape[0])\n        % num_possible_starts\n        + 1\n    )\n    return selected\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.pdp.generator.PDPGenerator","title":"PDPGenerator","text":"
PDPGenerator(\n    num_loc: int = 20,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    init_sol_type: str = \"random\",\n    loc_distribution: Union[\n        int, float, str, type, Callable\n    ] = Uniform,\n    depot_distribution: Union[\n        int, float, str, type, Callable\n    ] = None,\n    **kwargs\n)\n

Bases: Generator

Data generator for the Pickup and Delivery Problem (PDP). Args: num_loc: number of locations (customers) in the PDP, without the depot. (e.g. 10 means 10 locs + 1 depot)

    - 1 depot\n    - `num_loc` / 2 pickup locations\n    - `num_loc` / 2 delivery locations\nmin_loc: minimum value for the location coordinates\nmax_loc: maximum value for the location coordinates\ninit_sol_type: the method type used for generating initial solutions (random or greedy)\nloc_distribution: distribution for the location coordinates\ndepot_distribution: distribution for the depot location. If None, sample the depot from the locations\n

Returns:

  • \u2013

    A TensorDict with the following keys: locs [batch_size, num_loc, 2]: locations of each customer depot [batch_size, 2]: location of the depot

Source code in rl4co/envs/routing/pdp/generator.py
def __init__(\n    self,\n    num_loc: int = 20,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    init_sol_type: str = \"random\",\n    loc_distribution: Union[int, float, str, type, Callable] = Uniform,\n    depot_distribution: Union[int, float, str, type, Callable] = None,\n    **kwargs,\n):\n    self.num_loc = num_loc\n    self.min_loc = min_loc\n    self.max_loc = max_loc\n    self.init_sol_type = init_sol_type\n\n    # Number of locations must be even\n    if num_loc % 2 != 0:\n        log.warn(\n            \"Number of locations must be even. Adding 1 to the number of locations.\"\n        )\n        self.num_loc += 1\n\n    # Location distribution\n    if kwargs.get(\"loc_sampler\", None) is not None:\n        self.loc_sampler = kwargs[\"loc_sampler\"]\n    else:\n        self.loc_sampler = get_sampler(\n            \"loc\", loc_distribution, min_loc, max_loc, **kwargs\n        )\n\n    # Depot distribution\n    if kwargs.get(\"depot_sampler\", None) is not None:\n        self.depot_sampler = kwargs[\"depot_sampler\"]\n    else:\n        self.depot_sampler = get_sampler(\n            \"depot\", depot_distribution, min_loc, max_loc, **kwargs\n        ) if depot_distribution is not None else None\n
"},{"location":"docs/content/api/envs/routing/#prize-collecting-traveling-salesman-problem-pctsp","title":"Prize Collecting Traveling Salesman Problem (PCTSP)","text":""},{"location":"docs/content/api/envs/routing/#envs.routing.pctsp.env.PCTSPEnv","title":"PCTSPEnv","text":"
PCTSPEnv(\n    generator: PCTSPGenerator = None,\n    generator_params: dict = {},\n    **kwargs\n)\n

Bases: RL4COEnvBase

Prize-collecting TSP (PCTSP) environment. The goal is to collect as much prize as possible while minimizing the total travel cost. The environment is stochastic, the prize is only revealed when the node is visited.

Observations
  • locations of the nodes
  • prize and penalty of each node
  • current location of the vehicle
  • current total prize
  • current total penalty
  • visited nodes
  • prize required to visit a node
  • the current step
Constraints
  • the tour starts and ends at the depot
  • the vehicle cannot visit nodes exceed the remaining prize
Finish Condition
  • the vehicle back to the depot
Reward
  • the sum of the saved penalties

Parameters:

  • generator (PCTSPGenerator, default: None ) \u2013

    OPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

Source code in rl4co/envs/routing/pctsp/env.py
def __init__(\n    self,\n    generator: PCTSPGenerator = None,\n    generator_params: dict = {},\n    **kwargs,\n):\n    super().__init__(**kwargs)\n    if generator is None:\n        generator = PCTSPGenerator(**generator_params)\n    self.generator = generator\n    self._make_spec(self.generator)\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.pctsp.env.PCTSPEnv.get_action_mask","title":"get_action_mask staticmethod","text":"
get_action_mask(td: TensorDict) -> Tensor\n

Cannot visit depot if not yet collected 1 total prize and there are unvisited nodes

Source code in rl4co/envs/routing/pctsp/env.py
@staticmethod\ndef get_action_mask(td: TensorDict) -> torch.Tensor:\n    \"\"\"Cannot visit depot if not yet collected 1 total prize and there are unvisited nodes\"\"\"\n    mask = td[\"visited\"] | td[\"visited\"][..., 0:1]\n    mask[..., 0] = (td[\"cur_total_prize\"] < 1.0) & (\n        td[\"visited\"][..., 1:].int().sum(-1) < td[\"visited\"][..., 1:].size(-1)\n    )\n    return ~(mask > 0)  # Invert mask, since 1 means feasible action\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.pctsp.env.PCTSPEnv.check_solution_validity","title":"check_solution_validity staticmethod","text":"
check_solution_validity(\n    td: TensorDict, actions: Tensor\n) -> None\n

Check that the solution is valid, i.e. contains all nodes once at most, and either prize constraint is met or all nodes are visited

Source code in rl4co/envs/routing/pctsp/env.py
@staticmethod\ndef check_solution_validity(td: TensorDict, actions: torch.Tensor) -> None:\n    \"\"\"Check that the solution is valid, i.e. contains all nodes once at most, and either prize constraint is met or all nodes are visited\"\"\"\n\n    # Check that tours are valid, i.e. contain 0 to n -1\n    sorted_actions = actions.data.sort(1)[0]\n\n    # Make sure each node visited once at most (except for depot)\n    assert (\n        (sorted_actions[..., 1:] == 0)\n        | (sorted_actions[..., 1:] > sorted_actions[..., :-1])\n    ).all(), \"Duplicates\"\n\n    prize = td[\"real_prize\"][..., 1:]  # Remove depot\n    prize_with_depot = torch.cat((torch.zeros_like(prize[:, :1]), prize), 1)\n    p = prize_with_depot.gather(1, actions)\n\n    # Either prize constraint should be satisfied or all prizes should be visited\n    assert (\n        (p.sum(-1) >= 1 - 1e-5)\n        | (\n            sorted_actions.size(-1) - (sorted_actions == 0).int().sum(-1)\n            == (td[\"locs\"].size(-2) - 1)\n        )  # no depot\n    ).all(), \"Total prize does not satisfy min total prize\"\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.pctsp.generator.PCTSPGenerator","title":"PCTSPGenerator","text":"
PCTSPGenerator(\n    num_loc: int = 20,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    loc_distribution: Union[\n        int, float, str, type, Callable\n    ] = Uniform,\n    depot_distribution: Union[\n        int, float, str, type, Callable\n    ] = None,\n    penalty_factor: float = 3.0,\n    prize_required: float = 1.0,\n    **kwargs\n)\n

Bases: Generator

Data generator for the Prize-collecting Traveling Salesman Problem (PCTSP).

Parameters:

  • num_loc (int, default: 20 ) \u2013

    number of locations (customers) in the VRP, without the depot. (e.g. 10 means 10 locs + 1 depot)

  • min_loc (float, default: 0.0 ) \u2013

    minimum value for the location coordinates

  • max_loc (float, default: 1.0 ) \u2013

    maximum value for the location coordinates

  • loc_distribution (Union[int, float, str, type, Callable], default: Uniform ) \u2013

    distribution for the location coordinates

  • depot_distribution (Union[int, float, str, type, Callable], default: None ) \u2013

    distribution for the depot location. If None, sample the depot from the locations

  • min_demand \u2013

    minimum value for the demand of each customer

  • max_demand \u2013

    maximum value for the demand of each customer

  • demand_distribution \u2013

    distribution for the demand of each customer

  • capacity \u2013

    capacity of the vehicle

Returns:

  • \u2013

    A TensorDict with the following keys: locs [batch_size, num_loc, 2]: locations of each city depot [batch_size, 2]: location of the depot demand [batch_size, num_loc]: demand of each customer capacity [batch_size, 1]: capacity of the vehicle

Source code in rl4co/envs/routing/pctsp/generator.py
def __init__(\n    self,\n    num_loc: int = 20,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    loc_distribution: Union[int, float, str, type, Callable] = Uniform,\n    depot_distribution: Union[int, float, str, type, Callable] = None,\n    penalty_factor: float = 3.0,\n    prize_required: float = 1.0,\n    **kwargs,\n):\n    self.num_loc = num_loc\n    self.min_loc = min_loc\n    self.max_loc = max_loc\n    self.penalty_fctor = penalty_factor\n    self.prize_required = prize_required\n\n    # Location distribution\n    if kwargs.get(\"loc_sampler\", None) is not None:\n        self.loc_sampler = kwargs[\"loc_sampler\"]\n    else:\n        self.loc_sampler = get_sampler(\n            \"loc\", loc_distribution, min_loc, max_loc, **kwargs\n        )\n\n    # Depot distribution\n    if kwargs.get(\"depot_sampler\", None) is not None:\n        self.depot_sampler = kwargs[\"depot_sampler\"]\n    else:\n        self.depot_sampler = get_sampler(\n            \"depot\", depot_distribution, min_loc, max_loc, **kwargs\n        ) if depot_distribution is not None else None\n\n    # Prize distribution\n    self.deterministic_prize_sampler = get_sampler(\n        \"deterministric_prize\", \"uniform\", 0.0, 4.0 / self.num_loc, **kwargs\n    )\n    self.stochastic_prize_sampler = get_sampler(\n        \"stochastic_prize\", \"uniform\", 0.0, 2.0, **kwargs\n    )\n\n    # For the penalty to make sense it should be not too large (in which case all nodes will be visited) nor too small\n    # so we want the objective term to be approximately equal to the length of the tour, which we estimate with half\n    # of the nodes by half of the tour length (which is very rough but similar to op)\n    # This means that the sum of penalties for all nodes will be approximately equal to the tour length (on average)\n    # The expected total (uniform) penalty of half of the nodes (since approx half will be visited by the constraint)\n    # is (n / 2) / 2 = n / 4 so divide by this means multiply by 4 / n,\n    # However instead of 4 we use penalty_factor (3 works well) so we can make them larger or smaller        \n    self.max_penalty = kwargs.get(\"max_penalty\", None)\n    if self.max_penalty is None:  # If not provided, use the default max penalty\n        self.max_penalty = MAX_LENGTHS.get(num_loc, None)\n    if (\n        self.max_penalty is None\n    ):  # If not in the table keys, find the closest number of nodes as the key\n        closest_num_loc = min(MAX_LENGTHS.keys(), key=lambda x: abs(x - num_loc))\n        self.max_penalty = MAX_LENGTHS[closest_num_loc]\n        log.warning(\n            f\"The max penalty for {num_loc} locations is not defined. Using the closest max penalty: {self.max_penalty}\\\n                with {closest_num_loc} locations.\"\n        )\n\n    # Adjust as in Kool et al. (2019)\n    self.max_penalty *= penalty_factor / self.num_loc\n    self.penalty_sampler = get_sampler(\n        \"penalty\", \"uniform\", 0.0, self.max_penalty, **kwargs\n    )\n
"},{"location":"docs/content/api/envs/routing/#split-delivery-vehicle-routing-problem-sdvrp","title":"Split Delivery Vehicle Routing Problem (SDVRP)","text":""},{"location":"docs/content/api/envs/routing/#envs.routing.sdvrp.env.SDVRPEnv","title":"SDVRPEnv","text":"
SDVRPEnv(\n    generator: CVRPGenerator = None,\n    generator_params: dict = {},\n    **kwargs\n)\n

Bases: CVRPEnv

Split Delivery Vehicle Routing Problem (SDVRP) environment. SDVRP is a generalization of CVRP, where nodes can be visited multiple times and a fraction of the demand can be met. At each step, the agent chooses a customer to visit depending on the current location and the remaining capacity. When the agent visits a customer, the remaining capacity is updated. If the remaining capacity is not enough to visit any customer, the agent must go back to the depot. The reward is the -infinite unless the agent visits all the customers. In that case, the reward is (-)length of the path: maximizing the reward is equivalent to minimizing the path length.

Observations
  • location of the depot.
  • locations and demand/remaining demand of each customer
  • current location of the vehicle.
  • the remaining capacity of the vehicle.
Constraints
  • the tour starts and ends at the depot.
  • each customer can be visited multiple times.
  • the vehicle cannot visit customers exceed the remaining capacity.
  • the vehicle can return to the depot to refill the capacity.
Finish Condition
  • the vehicle has finished all customers demand and returned to the depot.
Reward
  • (minus) the negative length of the path.

Parameters:

  • generator (CVRPGenerator, default: None ) \u2013

    CVRPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

Source code in rl4co/envs/routing/sdvrp/env.py
def __init__(\n    self,\n    generator: CVRPGenerator = None,\n    generator_params: dict = {},\n    **kwargs,\n):\n    super().__init__(generator, generator_params, **kwargs)\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.sdvrp.env.SDVRPEnv.check_solution_validity","title":"check_solution_validity staticmethod","text":"
check_solution_validity(\n    td: TensorDict, actions: Tensor\n) -> None\n

Check that the solution is valid (all demand is satisfied)

Source code in rl4co/envs/routing/sdvrp/env.py
@staticmethod\ndef check_solution_validity(td: TensorDict, actions: torch.Tensor) -> None:\n    \"\"\"Check that the solution is valid (all demand is satisfied)\"\"\"\n\n    batch_size, graph_size = td[\"demand\"].size()\n\n    # Each node can be visited multiple times, but we always deliver as much demand as possible\n    # We check that at the end all demand has been satisfied\n    demands = torch.cat((-td[\"vehicle_capacity\"], td[\"demand\"]), 1)\n\n    rng = torch.arange(batch_size, out=demands.data.new().long())\n    used_cap = torch.zeros_like(td[\"demand\"][..., 0])\n    a_prev = None\n    for a in actions.transpose(0, 1):\n        assert (\n            a_prev is None or (demands[((a_prev == 0) & (a == 0)), :] == 0).all()\n        ), \"Cannot visit depot twice if any nonzero demand\"\n        d = torch.min(demands[rng, a], td[\"vehicle_capacity\"].squeeze(-1) - used_cap)\n        demands[rng, a] -= d\n        used_cap += d\n        used_cap[a == 0] = 0\n        a_prev = a\n    assert (demands == 0).all(), \"All demand must be satisfied\"\n
"},{"location":"docs/content/api/envs/routing/#stochastic-prize-collecting-traveling-salesman-problem-spctsp","title":"Stochastic Prize Collecting Traveling Salesman Problem (SPCTSP)","text":""},{"location":"docs/content/api/envs/routing/#envs.routing.spctsp.env.SPCTSPEnv","title":"SPCTSPEnv","text":"
SPCTSPEnv(**kwargs)\n

Bases: PCTSPEnv

Stochastic Prize Collecting Traveling Salesman Problem (SPCTSP) environment.

Note

The only difference with deterministic PCTSP is that the prizes are stochastic (i.e. the expected prize is not the same as the real prize).

Source code in rl4co/envs/routing/spctsp/env.py
def __init__(self, **kwargs):\n    super().__init__(**kwargs)\n
"},{"location":"docs/content/api/envs/routing/#traveling-salesman-problem-tsp","title":"Traveling Salesman Problem (TSP)","text":""},{"location":"docs/content/api/envs/routing/#envs.routing.tsp.env.TSPEnv","title":"TSPEnv","text":"
TSPEnv(\n    generator: TSPGenerator = None,\n    generator_params: dict = {},\n    **kwargs\n)\n

Bases: RL4COEnvBase

Traveling Salesman Problem (TSP) environment At each step, the agent chooses a city to visit. The reward is 0 unless the agent visits all the cities. In that case, the reward is (-)length of the path: maximizing the reward is equivalent to minimizing the path length.

Observations
  • locations of each customer.
  • the current location of the vehicle.
Constraints
  • the tour must return to the starting customer.
  • each customer must be visited exactly once.
Finish condition
  • the agent has visited all customers and returned to the starting customer.
Reward
  • (minus) the negative length of the path.

Parameters:

  • generator (TSPGenerator, default: None ) \u2013

    TSPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

Source code in rl4co/envs/routing/tsp/env.py
def __init__(\n    self,\n    generator: TSPGenerator = None,\n    generator_params: dict = {},\n    **kwargs,\n):\n    super().__init__(**kwargs)\n    if generator is None:\n        generator = TSPGenerator(**generator_params)\n    self.generator = generator\n    self._make_spec(self.generator)\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.tsp.env.TSPEnv.check_solution_validity","title":"check_solution_validity staticmethod","text":"
check_solution_validity(\n    td: TensorDict, actions: Tensor\n) -> None\n

Check that solution is valid: nodes are visited exactly once

Source code in rl4co/envs/routing/tsp/env.py
@staticmethod\ndef check_solution_validity(td: TensorDict, actions: torch.Tensor) -> None:\n    \"\"\"Check that solution is valid: nodes are visited exactly once\"\"\"\n    assert (\n        torch.arange(actions.size(1), out=actions.data.new())\n        .view(1, -1)\n        .expand_as(actions)\n        == actions.data.sort(1)[0]\n    ).all(), \"Invalid tour\"\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.tsp.env.TSPEnv.replace_selected_actions","title":"replace_selected_actions","text":"
replace_selected_actions(\n    cur_actions: Tensor,\n    new_actions: Tensor,\n    selection_mask: Tensor,\n) -> Tensor\n

Replace selected current actions with updated actions based on selection_mask.

Source code in rl4co/envs/routing/tsp/env.py
def replace_selected_actions(\n    self,\n    cur_actions: torch.Tensor,\n    new_actions: torch.Tensor,\n    selection_mask: torch.Tensor,\n) -> torch.Tensor:\n    \"\"\"\n    Replace selected current actions with updated actions based on `selection_mask`.\n\n    Args:\n        cur_actions [batch_size, num_loc]\n        new_actions [batch_size, num_loc]\n        selection_mask [batch_size,]\n    \"\"\"\n    cur_actions[selection_mask] = new_actions[selection_mask]\n    return cur_actions\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.tsp.generator.TSPGenerator","title":"TSPGenerator","text":"
TSPGenerator(\n    num_loc: int = 20,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    init_sol_type: str = \"random\",\n    loc_distribution: Union[\n        int, float, str, type, Callable\n    ] = Uniform,\n    **kwargs\n)\n

Bases: Generator

Data generator for the Travelling Salesman Problem (TSP).

Parameters:

  • num_loc (int, default: 20 ) \u2013

    number of locations (customers) in the TSP

  • min_loc (float, default: 0.0 ) \u2013

    minimum value for the location coordinates

  • max_loc (float, default: 1.0 ) \u2013

    maximum value for the location coordinates

  • init_sol_type (str, default: 'random' ) \u2013

    the method type used for generating initial solutions (random or greedy)

  • loc_distribution (Union[int, float, str, type, Callable], default: Uniform ) \u2013

    distribution for the location coordinates

Returns:

  • \u2013

    A TensorDict with the following keys: locs [batch_size, num_loc, 2]: locations of each customer

Source code in rl4co/envs/routing/tsp/generator.py
def __init__(\n    self,\n    num_loc: int = 20,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    init_sol_type: str = \"random\",\n    loc_distribution: Union[int, float, str, type, Callable] = Uniform,\n    **kwargs,\n):\n    self.num_loc = num_loc\n    self.min_loc = min_loc\n    self.max_loc = max_loc\n    self.init_sol_type = init_sol_type\n\n    # Location distribution\n    if kwargs.get(\"loc_sampler\", None) is not None:\n        self.loc_sampler = kwargs[\"loc_sampler\"]\n    else:\n        self.loc_sampler = get_sampler(\n            \"loc\", loc_distribution, min_loc, max_loc, **kwargs\n        )\n
"},{"location":"docs/content/api/envs/routing/#multi-task-vehicle-routing-problem-mtvrp","title":"Multi-Task Vehicle Routing Problem (MTVRP)","text":""},{"location":"docs/content/api/envs/routing/#envs.routing.mtvrp.env.MTVRPEnv","title":"MTVRPEnv","text":"
MTVRPEnv(\n    generator: MTVRPGenerator = None,\n    generator_params: dict = {},\n    check_solution: bool = False,\n    **kwargs\n)\n

Bases: RL4COEnvBase

MTVRPEnv is a Multi-Task VRP environment which can take any combination of the following constraints:

Features:

  • Capacity (C) - Each vehicle has a maximum capacity \\(Q\\), restricting the total load that can be in the vehicle at any point of the route. - The route must be planned such that the sum of demands and pickups for all customers visited does not exceed this capacity.
  • Time Windows (TW) - Every node \\(i\\) has an associated time window \\([e_i, l_i]\\) during which service must commence. - Additionally, each node has a service time \\(s_i\\). Vehicles must reach node \\(i\\) within its time window; early arrivals must wait at the node location until time \\(e_i\\).
  • Open Routes (O) - Vehicles are not required to return to the depot after serving all customers. - Note that this does not need to be counted as a constraint since it can be modelled by setting zero costs on arcs returning to the depot \\(c_{i0} = 0\\) from any customer \\(i \\in C\\), and not counting the return arc as part of the route.
  • Backhauls (B) - Backhauls generalize demand to also account for return shipments. Customers are either linehaul or backhaul customers. - Linehaul customers require delivery of a demand \\(q_i > 0\\) that needs to be transported from the depot to the customer, whereas backhaul customers need a pickup of an amount \\(p_i > 0\\) that is transported from the client back to the depot. - It is possible for vehicles to serve a combination of linehaul and backhaul customers in a single route, but then any linehaul customers must precede the backhaul customers in the route.
  • Duration Limits (L) - Imposes a limit on the total travel duration (or length) of each route, ensuring a balanced workload across vehicles.

The environment covers the following 16 variants depending on the data generation:

VRP Variant Capacity (C) Open Route (O) Backhaul (B) Duration Limit (L) Time Window (TW) CVRP \u2714 OVRP \u2714 \u2714 VRPB \u2714 \u2714 VRPL \u2714 \u2714 VRPTW \u2714 \u2714 OVRPTW \u2714 \u2714 \u2714 OVRPB \u2714 \u2714 \u2714 OVRPL \u2714 \u2714 \u2714 VRPBL \u2714 \u2714 \u2714 VRPBTW \u2714 \u2714 \u2714 VRPLTW \u2714 \u2714 \u2714 OVRPBL \u2714 \u2714 \u2714 \u2714 OVRPBTW \u2714 \u2714 \u2714 \u2714 OVRPLTW \u2714 \u2714 \u2714 \u2714 VRPBLTW \u2714 \u2714 \u2714 \u2714 OVRPBLTW \u2714 \u2714 \u2714 \u2714 \u2714

You may also check out the following papers as reference:

  • \"Multi-Task Learning for Routing Problem with Cross-Problem Zero-Shot Generalization\" (Liu et al, 2024)
  • \"MVMoE: Multi-Task Vehicle Routing Solver with Mixture-of-Experts\" (Zhou et al, 2024)
  • \"RouteFinder: Towards Foundation Models for Vehicle Routing Problems\" (Berto et al, 2024)
Tip

Have a look at https://pyvrp.org/ for more information about VRP and its variants and their solutions. Kudos to their help and great job!

Parameters:

  • generator (MTVRPGenerator, default: None ) \u2013

    Generator for the environment, see :class:MTVRPGenerator.

  • generator_params (dict, default: {} ) \u2013

    Parameters for the generator.

Source code in rl4co/envs/routing/mtvrp/env.py
def __init__(\n    self,\n    generator: MTVRPGenerator = None,\n    generator_params: dict = {},\n    check_solution: bool = False,\n    **kwargs,\n):\n    if check_solution:\n        log.warning(\n            \"Solution checking is enabled. This may slow down the environment.\"\n            \" We recommend disabling this for training by passing `check_solution=False`.\"\n        )\n\n    super().__init__(check_solution=check_solution, **kwargs)\n\n    if generator is None:\n        generator = MTVRPGenerator(**generator_params)\n    self.generator = generator\n    self._make_spec(self.generator)\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.mtvrp.env.MTVRPEnv.load_data","title":"load_data","text":"
load_data(fpath, batch_size=[], scale=False)\n

Dataset loading from file Normalize demand by capacity to be in [0, 1]

Source code in rl4co/envs/routing/mtvrp/env.py
def load_data(self, fpath, batch_size=[], scale=False):\n    \"\"\"Dataset loading from file\n    Normalize demand by capacity to be in [0, 1]\n    \"\"\"\n    td_load = load_npz_to_tensordict(fpath)\n    if scale:\n        td_load.set(\n            \"demand_linehaul\",\n            td_load[\"demand_linehaul\"] / td_load[\"capacity_original\"],\n        )\n        td_load.set(\n            \"demand_backhaul\",\n            td_load[\"demand_backhaul\"] / td_load[\"capacity_original\"],\n        )\n    return td_load\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.mtvrp.env.MTVRPEnv.render","title":"render staticmethod","text":"
render(*args, **kwargs)\n

Simple wrapper for render function

Source code in rl4co/envs/routing/mtvrp/env.py
@staticmethod\ndef render(*args, **kwargs):\n    \"\"\"Simple wrapper for render function\"\"\"\n    from .render import render\n\n    return render(*args, **kwargs)\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.mtvrp.env.MTVRPEnv.select_start_nodes","title":"select_start_nodes","text":"
select_start_nodes(td, num_starts)\n

Select available start nodes for the environment (e.g. for POMO-based training)

Source code in rl4co/envs/routing/mtvrp/env.py
def select_start_nodes(self, td, num_starts):\n    \"\"\"Select available start nodes for the environment (e.g. for POMO-based training)\"\"\"\n    num_loc = td[\"locs\"].shape[-2] - 1\n    selected = (\n        torch.arange(num_starts, device=td.device).repeat_interleave(td.shape[0])\n        % num_loc\n        + 1\n    )\n    return selected\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.mtvrp.env.MTVRPEnv.solve","title":"solve staticmethod","text":"
solve(\n    instances: TensorDict,\n    max_runtime: float,\n    num_procs: int = 1,\n    solver: str = \"pyvrp\",\n    **kwargs\n) -> tuple[Tensor, Tensor]\n

Classical solver for the environment. This is a wrapper for the baselines solver. Available solvers are: pyvrp, ortools, lkh. Returns the actions and costs.

Source code in rl4co/envs/routing/mtvrp/env.py
@staticmethod\ndef solve(\n    instances: TensorDict,\n    max_runtime: float,\n    num_procs: int = 1,\n    solver: str = \"pyvrp\",\n    **kwargs,\n) -> tuple[torch.Tensor, torch.Tensor]:\n    \"\"\"Classical solver for the environment. This is a wrapper for the baselines solver.\n    Available solvers are: `pyvrp`, `ortools`, `lkh`. Returns the actions and costs.\n    \"\"\"\n    from .baselines.solve import solve\n\n    return solve(instances, max_runtime, num_procs, solver, **kwargs)\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.mtvrp.env.MTVRPEnv.check_variants","title":"check_variants staticmethod","text":"
check_variants(td)\n

Check if the problem has the variants

Source code in rl4co/envs/routing/mtvrp/env.py
@staticmethod\ndef check_variants(td):\n    \"\"\"Check if the problem has the variants\"\"\"\n    has_open = td[\"open_route\"].squeeze(-1)\n    has_tw = (td[\"time_windows\"][:, :, 1] != float(\"inf\")).any(-1)\n    has_limit = (td[\"distance_limit\"] != float(\"inf\")).squeeze(-1)\n    has_backhaul = (td[\"demand_backhaul\"] != 0).any(-1)\n    return has_open, has_tw, has_limit, has_backhaul\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.mtvrp.generator.MTVRPGenerator","title":"MTVRPGenerator","text":"
MTVRPGenerator(\n    num_loc: int = 20,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    loc_distribution: Union[\n        int, float, str, type, Callable\n    ] = Uniform,\n    capacity: float = None,\n    min_demand: int = 1,\n    max_demand: int = 10,\n    min_backhaul: int = 1,\n    max_backhaul: int = 10,\n    scale_demand: bool = True,\n    max_time: float = 4.6,\n    backhaul_ratio: float = 0.2,\n    distance_limit: float = 3.0,\n    speed: float = 1.0,\n    prob_open: float = 0.5,\n    prob_time_window: float = 0.5,\n    prob_limit: float = 0.5,\n    prob_backhaul: float = 0.5,\n    variant_preset=None,\n    use_combinations=True,\n    subsample=True,\n    **kwargs\n)\n

Bases: Generator

MTVRP Generator. Class to generate instances of the MTVRP problem. If a variant is declared and Subsample is True, the generator will sample the problem based on the variant probabilities. By default, we use Mixed-Batch Training as in Berto et al. 2024 (RouteFinder), i.e. one batch can contain multiple variants.

Example presets:

  • \"all\": Sample uniformly from 16 variants
  • \"single_feat\": Sample uniformly between CVRP, OVRP, VRPB, VRPL, VRPTW (as done in Liu et al. 2024 (MTPOMO))
  • \"single_feat_otw\": Sample uniformly between CVRP, OVRP, VRPB, VRPL, VRPTW, OVRPTW (as done in Zhou et al. 2024 (MVMoE))
  • \"cvrp\": Only CVRP (similarly for other variants)

Parameters:

  • num_loc (int, default: 20 ) \u2013

    Number of locations to generate

  • min_loc (float, default: 0.0 ) \u2013

    Minimum location value

  • max_loc (float, default: 1.0 ) \u2013

    Maximum location value

  • loc_distribution (Union[int, float, str, type, Callable], default: Uniform ) \u2013

    Distribution to sample locations from

  • capacity (float, default: None ) \u2013

    Vehicle capacity. If None, get value based on get_vehicle_capacity

  • min_demand (int, default: 1 ) \u2013

    Minimum demand value

  • max_demand (int, default: 10 ) \u2013

    Maximum demand value

  • min_backhaul (int, default: 1 ) \u2013

    Minimum backhaul value

  • max_backhaul (int, default: 10 ) \u2013

    Maximum backhaul value

  • scale_demand (bool, default: True ) \u2013

    Scale demand values (by default, generate between 1 and 10)

  • max_time (float, default: 4.6 ) \u2013

    Maximum time window value (at depot)

  • backhaul_ratio (float, default: 0.2 ) \u2013

    Fraction of backhauls (e.g. 0.2 means 20% of nodes are backhaul)

  • distance_limit (float, default: 3.0 ) \u2013

    Distance limit

  • speed (float, default: 1.0 ) \u2013

    Speed of vehicle. Defaults to 1

  • subsample \u2013

    If False, we always sample all attributes (i.e., OVRPBLTW) If true, we use the

  • **kwargs \u2013

    Additional keyword arguments

Source code in rl4co/envs/routing/mtvrp/generator.py
def __init__(\n    self,\n    num_loc: int = 20,\n    min_loc: float = 0.0,\n    max_loc: float = 1.0,\n    loc_distribution: Union[int, float, str, type, Callable] = Uniform,\n    capacity: float = None,\n    min_demand: int = 1,\n    max_demand: int = 10,\n    min_backhaul: int = 1,\n    max_backhaul: int = 10,\n    scale_demand: bool = True,\n    max_time: float = 4.6,\n    backhaul_ratio: float = 0.2,\n    distance_limit: float = 3.0,\n    speed: float = 1.0,\n    prob_open: float = 0.5,\n    prob_time_window: float = 0.5,\n    prob_limit: float = 0.5,\n    prob_backhaul: float = 0.5,\n    variant_preset=None,\n    use_combinations=True,\n    subsample=True,\n    **kwargs,\n) -> None:\n    # Location distribution\n    self.num_loc = num_loc\n    self.min_loc = min_loc\n    self.max_loc = max_loc\n    if kwargs.get(\"loc_sampler\", None) is not None:\n        self.loc_sampler = kwargs[\"loc_sampler\"]\n    else:\n        self.loc_sampler = get_sampler(\n            \"loc\", loc_distribution, min_loc, max_loc, **kwargs\n        )\n\n    if capacity is None:\n        capacity = get_vehicle_capacity(num_loc)\n    self.capacity = capacity\n    self.min_demand = min_demand\n    self.max_demand = max_demand\n    self.min_backhaul = min_backhaul\n    self.max_backhaul = max_backhaul\n    self.scale_demand = scale_demand\n    self.backhaul_ratio = backhaul_ratio\n\n    self.max_time = max_time\n    self.distance_limit = distance_limit\n    self.speed = speed\n\n    assert not (subsample and (variant_preset is None)), (\n        \"Cannot use subsample if variant_preset is not specified. \"\n    )\n    if variant_preset is not None:\n        log.info(f\"Using variant generation preset {variant_preset}\")\n        variant_probs = VARIANT_GENERATION_PRESETS.get(variant_preset)\n        assert (\n            variant_probs is not None\n        ), f\"Variant generation preset {variant_preset} not found. \\\n            Available presets are {VARIANT_GENERATION_PRESETS.keys()} with probabilities {VARIANT_GENERATION_PRESETS.values()}\"\n    else:\n        variant_probs = {\n            \"O\": prob_open,\n            \"TW\": prob_time_window,\n            \"L\": prob_limit,\n            \"B\": prob_backhaul,\n        }\n    # check probabilities\n    for key, prob in variant_probs.items():\n        assert 0 <= prob <= 1, f\"Probability {key} must be between 0 and 1\"\n    self.variant_probs = variant_probs\n    self.variant_preset = variant_preset\n    if isinstance(variant_preset, str) and variant_preset != \"all\":\n        log.warning(f\"{variant_preset} selected. Will not use feature combination!\")\n        use_combinations = False\n    self.use_combinations = use_combinations\n    self.subsample = subsample\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.mtvrp.generator.MTVRPGenerator.subsample_problems","title":"subsample_problems","text":"
subsample_problems(td)\n

Create subproblems starting from seed probabilities depending on their variant. If random seed sampled in [0, 1] in batch is greater than prob, remove the constraint thus, if prob high, it is less likely to remove the constraint (i.e. prob=0.9, 90% chance to keep constraint)

Source code in rl4co/envs/routing/mtvrp/generator.py
def subsample_problems(self, td):\n    \"\"\"Create subproblems starting from seed probabilities depending on their variant.\n    If random seed sampled in [0, 1] in batch is greater than prob, remove the constraint\n    thus, if prob high, it is less likely to remove the constraint (i.e. prob=0.9, 90% chance to keep constraint)\n    \"\"\"\n    batch_size = td.batch_size[0]\n\n    variant_probs = torch.tensor(list(self.variant_probs.values()))\n\n    if self.use_combinations:\n        # in a batch, multiple variants combinations can be picked\n        keep_mask = torch.rand(batch_size, 4) >= variant_probs  # O, TW, L, B\n    else:\n        # in a batch, only a variant can be picked.\n        # we assign a 0.5 prob to the last variant (which is normal cvrp)\n        if self.variant_preset in list(\n            VARIANT_GENERATION_PRESETS.keys()\n        ) and self.variant_preset not in (\n            \"all\",\n            \"cvrp\",\n            \"single_feat\",\n            \"single_feat_otw\",\n        ):\n            cvrp_prob = 0\n        else:\n            cvrp_prob = 0.5\n        if self.variant_preset in (\"all\", \"cvrp\", \"single_feat\", \"single_feat_otw\"):\n            indices = torch.distributions.Categorical(\n                torch.Tensor(list(self.variant_probs.values()) + [cvrp_prob])[\n                    None\n                ].repeat(batch_size, 1)\n            ).sample()\n            if self.variant_preset == \"single_feat_otw\":\n                keep_mask = torch.zeros((batch_size, 6), dtype=torch.bool)\n                keep_mask[torch.arange(batch_size), indices] = True\n\n                # If keep_mask[:, 4] is True, make both keep_mask[:, 0] and keep_mask[:, 1] True\n                keep_mask[:, :2] |= keep_mask[:, 4:5]\n            else:\n                keep_mask = torch.zeros((batch_size, 5), dtype=torch.bool)\n                keep_mask[torch.arange(batch_size), indices] = True\n        else:\n            # if the variant is specified, we keep the attributes with probability > 0\n            keep_mask = torch.zeros((batch_size, 4), dtype=torch.bool)\n            indices = torch.nonzero(variant_probs).squeeze()\n            keep_mask[:, indices] = True\n\n    td = self._default_open(td, ~keep_mask[:, 0])\n    td = self._default_time_window(td, ~keep_mask[:, 1])\n    td = self._default_distance_limit(td, ~keep_mask[:, 2])\n    td = self._default_backhaul(td, ~keep_mask[:, 3])\n\n    return td\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.mtvrp.generator.MTVRPGenerator.generate_locations","title":"generate_locations","text":"
generate_locations(batch_size, num_loc) -> Tensor\n

Generate seed locations.

Returns:

  • locs ( Tensor ) \u2013

    [B, N+1, 2] where the first location is the depot.

Source code in rl4co/envs/routing/mtvrp/generator.py
def generate_locations(self, batch_size, num_loc) -> torch.Tensor:\n    \"\"\"Generate seed locations.\n\n    Returns:\n        locs: [B, N+1, 2] where the first location is the depot.\n    \"\"\"\n    locs = torch.FloatTensor(*batch_size, num_loc + 1, 2).uniform_(\n        self.min_loc, self.max_loc\n    )\n    return locs\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.mtvrp.generator.MTVRPGenerator.generate_demands","title":"generate_demands","text":"
generate_demands(batch_size: int, num_loc: int) -> Tensor\n

Classical lineahul demand / delivery from depot (C) and backhaul demand / pickup to depot (B) generation. Initialize the demand for nodes except the depot, which are added during reset. Demand sampling Following Kool et al. (2019), demands as integers between 1 and 10. Generates a slightly different distribution than using torch.randint.

Returns:

  • linehaul_demand ( Tensor ) \u2013

    [B, N]

  • backhaul_demand ( Tensor ) \u2013

    [B, N]

Source code in rl4co/envs/routing/mtvrp/generator.py
def generate_demands(self, batch_size: int, num_loc: int) -> torch.Tensor:\n    \"\"\"Classical lineahul demand / delivery from depot (C) and backhaul demand / pickup to depot (B) generation.\n    Initialize the demand for nodes except the depot, which are added during reset.\n    Demand sampling Following Kool et al. (2019), demands as integers between 1 and 10.\n    Generates a slightly different distribution than using torch.randint.\n\n    Returns:\n        linehaul_demand: [B, N]\n        backhaul_demand: [B, N]\n    \"\"\"\n    linehaul_demand = (\n        torch.FloatTensor(*batch_size, num_loc)\n        .uniform_(self.min_demand - 1, self.max_demand - 1)\n        .int()\n        + 1\n    ).float()\n    # Backhaul demand sampling\n    backhaul_demand = (\n        torch.FloatTensor(*batch_size, num_loc)\n        .uniform_(self.min_backhaul - 1, self.max_backhaul - 1)\n        .int()\n        + 1\n    ).float()\n    is_linehaul = torch.rand(*batch_size, num_loc) > self.backhaul_ratio\n    backhaul_demand = (\n        backhaul_demand * ~is_linehaul\n    )  # keep only values where they are not linehauls\n    linehaul_demand = (\n        linehaul_demand * is_linehaul\n    )\n    return linehaul_demand, backhaul_demand\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.mtvrp.generator.MTVRPGenerator.generate_time_windows","title":"generate_time_windows","text":"
generate_time_windows(\n    locs: Tensor, speed: Tensor\n) -> Tensor\n

Generate time windows (TW) and service times for each location including depot. We refer to the generation process in \"Multi-Task Learning for Routing Problem with Cross-Problem Zero-Shot Generalization\" (Liu et al., 2024). Note that another way to generate is from \"Learning to Delegate for Large-scale Vehicle Routing\" (Li et al, 2021) which is used in \"MVMoE: Multi-Task Vehicle Routing Solver with Mixture-of-Experts\" (Zhou et al, 2024). Note that however, in that case the distance limit would have no influence when time windows are present, since the tw for depot is the same as distance with speed=1. This function can be overridden for that implementation. See also https://github.com/RoyalSkye/Routing-MVMoE

Parameters:

  • locs (Tensor) \u2013

    [B, N+1, 2] (depot, locs)

  • speed (Tensor) \u2013

    [B]

Returns:

  • time_windows ( Tensor ) \u2013

    [B, N+1, 2]

  • service_time ( Tensor ) \u2013

    [B, N+1]

Source code in rl4co/envs/routing/mtvrp/generator.py
def generate_time_windows(\n    self,\n    locs: torch.Tensor,\n    speed: torch.Tensor,\n) -> torch.Tensor:\n    \"\"\"Generate time windows (TW) and service times for each location including depot.\n    We refer to the generation process in \"Multi-Task Learning for Routing Problem with Cross-Problem Zero-Shot Generalization\"\n    (Liu et al., 2024). Note that another way to generate is from \"Learning to Delegate for Large-scale Vehicle Routing\" (Li et al, 2021) which\n    is used in \"MVMoE: Multi-Task Vehicle Routing Solver with Mixture-of-Experts\" (Zhou et al, 2024). Note that however, in that case\n    the distance limit would have no influence when time windows are present, since the tw for depot is the same as distance with speed=1.\n    This function can be overridden for that implementation.\n    See also https://github.com/RoyalSkye/Routing-MVMoE\n\n    Args:\n        locs: [B, N+1, 2] (depot, locs)\n        speed: [B]\n\n    Returns:\n        time_windows: [B, N+1, 2]\n        service_time: [B, N+1]\n    \"\"\"\n\n    batch_size, n_loc = locs.shape[0], locs.shape[1] - 1  # no depot\n\n    a, b, c = 0.15, 0.18, 0.2\n    service_time = a + (b - a) * torch.rand(batch_size, n_loc)\n    tw_length = b + (c - b) * torch.rand(batch_size, n_loc)\n    d_0i = get_distance(locs[:, 0:1], locs[:, 1:])\n    h_max = (self.max_time - service_time - tw_length) / d_0i * speed - 1\n    tw_start = (1 + (h_max - 1) * torch.rand(batch_size, n_loc)) * d_0i / speed\n    tw_end = tw_start + tw_length\n\n    # Depot tw is 0, max_time\n    time_windows = torch.stack(\n        (\n            torch.cat((torch.zeros(batch_size, 1), tw_start), -1),  # start\n            torch.cat((torch.full((batch_size, 1), self.max_time), tw_end), -1),\n        ),  # en\n        dim=-1,\n    )\n    # depot service time is 0\n    service_time = torch.cat((torch.zeros(batch_size, 1), service_time), dim=-1)\n    return time_windows, service_time  # [B, N+1, 2], [B, N+1]\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.mtvrp.generator.MTVRPGenerator.generate_distance_limit","title":"generate_distance_limit","text":"
generate_distance_limit(\n    shape: Tuple[int, int], locs: Tensor\n) -> Tensor\n

Generates distance limits (L) and checks their feasibilities.

Returns:

  • distance_limit ( Tensor ) \u2013

    [B, 1]

Source code in rl4co/envs/routing/mtvrp/generator.py
def generate_distance_limit(\n    self, shape: Tuple[int, int], locs: torch.Tensor\n) -> torch.Tensor:\n    \"\"\"Generates distance limits (L) and checks their feasibilities.\n\n    Returns:\n        distance_limit: [B, 1]\n    \"\"\"\n    # calculate distance of all locations to depot\n    dist_to_depot = torch.cdist(locs, locs[:, 0:1, :], p=2)\n    assert (\n        dist_to_depot * 2 < self.distance_limit  # go back and forth\n    ).all(), \"Distance limit too low, not all nodes can be reached from the depot.\"\n    return torch.full(shape, self.distance_limit, dtype=torch.float32)\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.mtvrp.generator.MTVRPGenerator.generate_open_route","title":"generate_open_route","text":"
generate_open_route(shape: Tuple[int, int])\n

Generate open route flags (O). Here we could have a sampler but we simply return True here so all routes are open. Afterwards, we subsample the problems.

Source code in rl4co/envs/routing/mtvrp/generator.py
def generate_open_route(self, shape: Tuple[int, int]):\n    \"\"\"Generate open route flags (O). Here we could have a sampler but we simply return True here so all\n    routes are open. Afterwards, we subsample the problems.\n    \"\"\"\n    return torch.ones(shape, dtype=torch.bool)\n
"},{"location":"docs/content/api/envs/routing/#envs.routing.mtvrp.generator.MTVRPGenerator.generate_speed","title":"generate_speed","text":"
generate_speed(shape: Tuple[int, int])\n

We simply generate the speed as constant here

Source code in rl4co/envs/routing/mtvrp/generator.py
def generate_speed(self, shape: Tuple[int, int]):\n    \"\"\"We simply generate the speed as constant here\"\"\"\n    # in this version, the speed is constant but this class may be overridden\n    return torch.full(shape, self.speed, dtype=torch.float32)\n
"},{"location":"docs/content/api/envs/scheduling/","title":"Scheduling Problems","text":""},{"location":"docs/content/api/envs/scheduling/#flexible-flow-shop-problem-ffsp","title":"Flexible Flow Shop Problem (FFSP)","text":""},{"location":"docs/content/api/envs/scheduling/#envs.scheduling.ffsp.env.FFSPEnv","title":"FFSPEnv","text":"
FFSPEnv(\n    generator: FFSPGenerator = None,\n    generator_params: dict = {},\n    **kwargs\n)\n

Bases: RL4COEnvBase

Flexible Flow Shop Problem (FFSP) environment. The goal is to schedule a set of jobs on a set of machines such that the makespan is minimized.

Observations
  • time index
  • sub time index
  • batch index
  • machine index
  • schedule
  • machine wait step
  • job location
  • job wait step
  • job duration
Constraints
  • each job has to be processed on each machine in a specific order
  • the machine has to be available to process the job
  • the job has to be available to be processed
Finish Condition
  • all jobs are scheduled
Reward
  • (minus) the makespan of the schedule

Parameters:

  • generator (FFSPGenerator, default: None ) \u2013

    FFSPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

Source code in rl4co/envs/scheduling/ffsp/env.py
def __init__(\n    self,\n    generator: FFSPGenerator = None,\n    generator_params: dict = {},\n    **kwargs,\n):\n    super().__init__(check_solution=False, dataset_cls=FastTdDataset, **kwargs)\n    if generator is None:\n        generator = FFSPGenerator(**generator_params)\n    self.generator = generator\n\n    self.num_stage = generator.num_stage\n    self.num_machine = generator.num_machine\n    self.num_job = generator.num_job\n    self.num_machine_total = generator.num_machine_total\n    self.tables = None\n    self.step_cnt = None\n    self.flatten_stages = generator.flatten_stages\n\n    self._make_spec(generator)\n
"},{"location":"docs/content/api/envs/scheduling/#envs.scheduling.ffsp.generator.FFSPGenerator","title":"FFSPGenerator","text":"
FFSPGenerator(\n    num_stage: int = 2,\n    num_machine: int = 3,\n    num_job: int = 4,\n    min_time: int = 2,\n    max_time: int = 10,\n    flatten_stages: bool = True,\n    **unused_kwargs\n)\n

Bases: Generator

Data generator for the Flow Shop Scheduling Problem (FFSP).

Parameters:

  • num_stage (int, default: 2 ) \u2013

    number of stages

  • num_machine (int, default: 3 ) \u2013

    number of machines

  • num_job (int, default: 4 ) \u2013

    number of jobs

  • min_time (int, default: 2 ) \u2013

    minimum running time of each job on each machine

  • max_time (int, default: 10 ) \u2013

    maximum running time of each job on each machine

  • flatten_stages (bool, default: True ) \u2013

    whether to flatten the stages

Returns:

  • \u2013

    A TensorDict with the following key: run_time [batch_size, num_job, num_machine, num_stage]: running time of each job on each machine

Note
  • [IMPORTANT] This version of ffsp requires the number of machines in each stage to be the same
Source code in rl4co/envs/scheduling/ffsp/generator.py
def __init__(\n    self,\n    num_stage: int = 2,\n    num_machine: int = 3,\n    num_job: int = 4,\n    min_time: int = 2,\n    max_time: int = 10,\n    flatten_stages: bool = True,\n    **unused_kwargs,\n):\n    self.num_stage = num_stage\n    self.num_machine = num_machine\n    self.num_machine_total = num_machine * num_stage\n    self.num_job = num_job\n    self.min_time = min_time\n    self.max_time = max_time\n    self.flatten_stages = flatten_stages\n\n    # FFSP environment doen't have any other kwargs\n    if len(unused_kwargs) > 0:\n        log.error(f\"Found {len(unused_kwargs)} unused kwargs: {unused_kwargs}\")\n
"},{"location":"docs/content/api/envs/scheduling/#flexible-job-shop-problem-fjsp","title":"Flexible Job Shop Problem (FJSP)","text":""},{"location":"docs/content/api/envs/scheduling/#envs.scheduling.fjsp.env.FJSPEnv","title":"FJSPEnv","text":"
FJSPEnv(\n    generator: FJSPGenerator = None,\n    generator_params: dict = {},\n    mask_no_ops: bool = True,\n    check_mask: bool = False,\n    stepwise_reward: bool = False,\n    **kwargs\n)\n

Bases: RL4COEnvBase

Flexible Job-Shop Scheduling Problem (FJSP) environment At each step, the agent chooses a job-machine combination. The operation to be processed next for the selected job is then executed on the selected machine. The reward is 0 unless the agent scheduled all operations of all jobs. In that case, the reward is (-)makespan of the schedule: maximizing the reward is equivalent to minimizing the makespan.

Observations
  • time: current time
  • next_op: next operation per job
  • proc_times: processing time of operation-machine pairs
  • pad_mask: specifies padded operations
  • start_op_per_job: id of first operation per job
  • end_op_per_job: id of last operation per job
  • start_times: start time of operation (defaults to 0 if not scheduled)
  • finish_times: finish time of operation (defaults to INIT_FINISH if not scheduled)
  • job_ops_adj: adjacency matrix specifying job-operation affiliation
  • ops_job_map: same as above but using ids of jobs to indicate affiliation
  • ops_sequence_order: specifies the order in which operations have to be processed
  • ma_assignment: specifies which operation has been scheduled on which machine
  • busy_until: specifies until when the machine will be busy
  • num_eligible: number of machines that can process an operation
  • job_in_process: whether job is currently being processed
  • job_done: whether the job is done
Constrains

the agent may not select:

  • machines that are currently busy
  • jobs that are done already
  • jobs that are currently processed
  • job-machine combinations, where the machine cannot process the next operation of the job
Finish condition
  • the agent has scheduled all operations of all jobs
Reward
  • the negative makespan of the final schedule

Parameters:

  • generator (FJSPGenerator, default: None ) \u2013

    FJSPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

  • mask_no_ops (bool, default: True ) \u2013

    if True, agent may not select waiting operation (unless instance is done)

Source code in rl4co/envs/scheduling/fjsp/env.py
def __init__(\n    self,\n    generator: FJSPGenerator = None,\n    generator_params: dict = {},\n    mask_no_ops: bool = True,\n    check_mask: bool = False,\n    stepwise_reward: bool = False,\n    **kwargs,\n):\n    super().__init__(check_solution=False, **kwargs)\n    if generator is None:\n        if generator_params.get(\"file_path\", None) is not None:\n            generator = FJSPFileGenerator(**generator_params)\n        else:\n            generator = FJSPGenerator(**generator_params)\n    self.generator = generator\n    self._num_mas = generator.num_mas\n    self._num_jobs = generator.num_jobs\n    self._n_ops_max = generator.max_ops_per_job * self.num_jobs\n\n    self.mask_no_ops = mask_no_ops\n    self.check_mask = check_mask\n    self.stepwise_reward = stepwise_reward\n    self._make_spec(self.generator)\n
"},{"location":"docs/content/api/envs/scheduling/#envs.scheduling.fjsp.generator.FJSPGenerator","title":"FJSPGenerator","text":"
FJSPGenerator(\n    num_jobs: int = 10,\n    num_machines: int = 5,\n    min_ops_per_job: int = 4,\n    max_ops_per_job: int = 6,\n    min_processing_time: int = 1,\n    max_processing_time: int = 20,\n    min_eligible_ma_per_op: int = 1,\n    max_eligible_ma_per_op: int = None,\n    same_mean_per_op: bool = True,\n    **unused_kwargs\n)\n

Bases: Generator

Data generator for the Flexible Job-Shop Scheduling Problem (FJSP).

Parameters:

  • num_stage \u2013

    number of stages

  • num_machine \u2013

    number of machines

  • num_job \u2013

    number of jobs

  • min_time \u2013

    minimum running time of each job on each machine

  • max_time \u2013

    maximum running time of each job on each machine

  • flatten_stages \u2013

    whether to flatten the stages

Returns:

  • \u2013

    A TensorDict with the following key: start_op_per_job [batch_size, num_jobs]: first operation of each job end_op_per_job [batch_size, num_jobs]: last operation of each job proc_times [batch_size, num_machines, total_n_ops]: processing time of ops on machines pad_mask [batch_size, total_n_ops]: not all instances have the same number of ops, so padding is used

Source code in rl4co/envs/scheduling/fjsp/generator.py
def __init__(\n    self,\n    num_jobs: int = 10,\n    num_machines: int = 5,\n    min_ops_per_job: int = 4,\n    max_ops_per_job: int = 6,\n    min_processing_time: int = 1,\n    max_processing_time: int = 20,\n    min_eligible_ma_per_op: int = 1,\n    max_eligible_ma_per_op: int = None,\n    same_mean_per_op: bool = True,\n    **unused_kwargs,\n):\n    self.num_jobs = num_jobs\n    self.num_mas = num_machines\n    self.min_ops_per_job = min_ops_per_job\n    self.max_ops_per_job = max_ops_per_job\n    self.min_processing_time = min_processing_time\n    self.max_processing_time = max_processing_time\n    self.min_eligible_ma_per_op = min_eligible_ma_per_op\n    self.max_eligible_ma_per_op = max_eligible_ma_per_op or num_machines\n    # determines whether to use a fixed number of total operations or let it vary between instances\n    # NOTE: due to the way rl4co builds datasets, we need a fixed size here\n    self.n_ops_max = max_ops_per_job * num_jobs\n    self.same_mean_per_op = same_mean_per_op\n    # FFSP environment doen't have any other kwargs\n    if len(unused_kwargs) > 0:\n        log.error(f\"Found {len(unused_kwargs)} unused kwargs: {unused_kwargs}\")\n
"},{"location":"docs/content/api/envs/scheduling/#job-shop-scheduling-problem-jssp","title":"Job Shop Scheduling Problem (JSSP)","text":""},{"location":"docs/content/api/envs/scheduling/#envs.scheduling.jssp.env.JSSPEnv","title":"JSSPEnv","text":"
JSSPEnv(\n    generator: JSSPGenerator = None,\n    generator_params: dict = {},\n    mask_no_ops: bool = True,\n    **kwargs\n)\n

Bases: FJSPEnv

Job-Shop Scheduling Problem (JSSP) environment At each step, the agent chooses a job. The operation to be processed next for the selected job is then executed on the associated machine. The reward is 0 unless the agent scheduled all operations of all jobs. In that case, the reward is (-)makespan of the schedule: maximizing the reward is equivalent to minimizing the makespan. NOTE: The JSSP is a special case of the FJSP, when the number of eligible machines per operation is equal to one for all operations. Therefore, this environment is a subclass of the FJSP environment. Observations:

- time: current time\n- next_op: next operation per job\n- proc_times: processing time of operation-machine pairs\n- pad_mask: specifies padded operations\n- start_op_per_job: id of first operation per job\n- end_op_per_job: id of last operation per job\n- start_times: start time of operation (defaults to 0 if not scheduled)\n- finish_times: finish time of operation (defaults to INIT_FINISH if not scheduled)\n- job_ops_adj: adjacency matrix specifying job-operation affiliation\n- ops_job_map: same as above but using ids of jobs to indicate affiliation\n- ops_sequence_order: specifies the order in which operations have to be processed\n- ma_assignment: specifies which operation has been scheduled on which machine\n- busy_until: specifies until when the machine will be busy\n- num_eligible: number of machines that can process an operation\n- job_in_process: whether job is currently being processed\n- job_done: whether the job is done\n
Constrains

the agent may not select:

  • jobs that are done already
  • jobs that are currently processed
Finish condition
  • the agent has scheduled all operations of all jobs
Reward
  • the negative makespan of the final schedule

Parameters:

  • generator (JSSPGenerator, default: None ) \u2013

    JSSPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

  • mask_no_ops (bool, default: True ) \u2013

    if True, agent may not select waiting operation (unless instance is done)

Source code in rl4co/envs/scheduling/jssp/env.py
def __init__(\n    self,\n    generator: JSSPGenerator = None,\n    generator_params: dict = {},\n    mask_no_ops: bool = True,\n    **kwargs,\n):\n    if generator is None:\n        if generator_params.get(\"file_path\", None) is not None:\n            generator = JSSPFileGenerator(**generator_params)\n        else:\n            generator = JSSPGenerator(**generator_params)\n\n    super().__init__(generator, generator_params, mask_no_ops, **kwargs)\n
"},{"location":"docs/content/api/envs/scheduling/#envs.scheduling.jssp.generator.JSSPGenerator","title":"JSSPGenerator","text":"
JSSPGenerator(\n    num_jobs: int = 6,\n    num_machines: int = 6,\n    min_ops_per_job: int = None,\n    max_ops_per_job: int = None,\n    min_processing_time: int = 1,\n    max_processing_time: int = 99,\n    one2one_ma_map: bool = True,\n    **unused_kwargs\n)\n

Bases: Generator

Data generator for the Job-Shop Scheduling Problem (JSSP)

Parameters:

  • num_stage \u2013

    number of stages

  • num_machine \u2013

    number of machines

  • num_job \u2013

    number of jobs

  • min_time \u2013

    minimum running time of each job on each machine

  • max_time \u2013

    maximum running time of each job on each machine

  • flatten_stages \u2013

    whether to flatten the stages

  • one2one_ma_map (bool, default: True ) \u2013

    whether each machine should have exactly one operation per job (common in jssp benchmark instances)

Returns:

  • \u2013

    A TensorDict with the following key: start_op_per_job [batch_size, num_jobs]: first operation of each job end_op_per_job [batch_size, num_jobs]: last operation of each job proc_times [batch_size, num_machines, total_n_ops]: processing time of ops on machines pad_mask [batch_size, total_n_ops]: not all instances have the same number of ops, so padding is used

Source code in rl4co/envs/scheduling/jssp/generator.py
def __init__(\n    self,\n    num_jobs: int = 6,\n    num_machines: int = 6,\n    min_ops_per_job: int = None,\n    max_ops_per_job: int = None,\n    min_processing_time: int = 1,\n    max_processing_time: int = 99,\n    one2one_ma_map: bool = True,\n    **unused_kwargs,\n):\n    self.num_jobs = num_jobs\n    self.num_mas = num_machines\n    # quite common in jssp to have as many ops per job as there are machines\n    self.min_ops_per_job = min_ops_per_job or self.num_mas\n    self.max_ops_per_job = max_ops_per_job or self.num_mas\n    self.min_processing_time = min_processing_time\n    self.max_processing_time = max_processing_time\n    self.one2one_ma_map = one2one_ma_map\n    if self.one2one_ma_map:\n        assert self.min_ops_per_job == self.max_ops_per_job == self.num_mas\n\n    # determines whether to use a fixed number of total operations or let it vary between instances\n    # NOTE: due to the way rl4co builds datasets, we need a fixed size here\n    self.n_ops_max = self.max_ops_per_job * self.num_jobs\n\n    # FFSP environment doen't have any other kwargs\n    if len(unused_kwargs) > 0:\n        log.error(f\"Found {len(unused_kwargs)} unused kwargs: {unused_kwargs}\")\n
"},{"location":"docs/content/api/envs/scheduling/#single-machine-total-weighted-tardiness-problem-smtwtp","title":"Single Machine Total Weighted Tardiness Problem (SMTWTP)","text":""},{"location":"docs/content/api/envs/scheduling/#envs.scheduling.smtwtp.env.SMTWTPEnv","title":"SMTWTPEnv","text":"
SMTWTPEnv(\n    generator: SMTWTPGenerator = None,\n    generator_params: dict = {},\n    **kwargs\n)\n

Bases: RL4COEnvBase

Single Machine Total Weighted Tardiness Problem environment as described in DeepACO (https://arxiv.org/pdf/2309.14032.pdf) SMTWTP is a scheduling problem in which a set of jobs must be processed on a single machine. Each job i has a processing time, a weight, and a due date. The objective is to minimize the sum of the weighted tardiness of all jobs, where the weighted tardiness of a job is defined as the product of its weight and the duration by which its completion time exceeds its due date. At each step, the agent chooses a job to process. The reward is 0 unless the agent processes all the jobs. In that case, the reward is (-)objective value of the processing order: maximizing the reward is equivalent to minimizing the objective.

Observation
  • job_due_time: the due time of each job
  • job_weight: the weight of each job
  • job_process_time: the process time of each job
  • current_node: the current node
  • action_mask: a mask of available actions
  • current_time: the current time
Constants
  • num_job: number of jobs
  • min_time_span: lower bound of jobs' due time. By default, jobs' due time is uniformly sampled from (min_time_span, max_time_span)
  • max_time_span: upper bound of jobs' due time. By default, it will be set to num_job / 2
  • min_job_weight: lower bound of jobs' weights. By default, jobs' weights are uniformly sampled from (min_job_weight, max_job_weight)
  • max_job_weight: upper bound of jobs' weights
  • min_process_time: lower bound of jobs' process time. By default, jobs' process time is uniformly sampled from (min_process_time, max_process_time)
  • max_process_time: upper bound of jobs' process time
Finishing condition
  • All jobs are processed
Reward
  • The reward is 0 unless the agent processes all the jobs.
  • In that case, the reward is (-)objective value of the processing order: maximizing the reward is equivalent to minimizing the objective.

Parameters:

  • generator (SMTWTPGenerator, default: None ) \u2013

    FFSPGenerator instance as the data generator

  • generator_params (dict, default: {} ) \u2013

    parameters for the generator

Source code in rl4co/envs/scheduling/smtwtp/env.py
def __init__(\n    self,\n    generator: SMTWTPGenerator = None,\n    generator_params: dict = {},\n    **kwargs,\n):\n    super().__init__(**kwargs)\n    if generator is None:\n        generator = SMTWTPGenerator(**generator_params)\n    self.generator = generator\n    self._make_spec(self.generator)\n
"},{"location":"docs/content/api/envs/scheduling/#envs.scheduling.smtwtp.generator.SMTWTPGenerator","title":"SMTWTPGenerator","text":"
SMTWTPGenerator(\n    num_job: int = 10,\n    min_time_span: float = 0,\n    max_time_span: float = None,\n    min_job_weight: float = 0,\n    max_job_weight: float = 1,\n    min_process_time: float = 0,\n    max_process_time: float = 1,\n    **unused_kwargs\n)\n

Bases: Generator

Data generator for the Single Machine Total Weighted Tardiness Problem (SMTWTP) environment

Parameters:

  • num_job (int, default: 10 ) \u2013

    number of jobs

  • min_time_span (float, default: 0 ) \u2013

    lower bound of jobs' due time. By default, jobs' due time is uniformly sampled from (min_time_span, max_time_span)

  • max_time_span (float, default: None ) \u2013

    upper bound of jobs' due time. By default, it will be set to num_job / 2

  • min_job_weight (float, default: 0 ) \u2013

    lower bound of jobs' weights. By default, jobs' weights are uniformly sampled from (min_job_weight, max_job_weight)

  • max_job_weight (float, default: 1 ) \u2013

    upper bound of jobs' weights

  • min_process_time (float, default: 0 ) \u2013

    lower bound of jobs' process time. By default, jobs' process time is uniformly sampled from (min_process_time, max_process_time)

  • max_process_time (float, default: 1 ) \u2013

    upper bound of jobs' process time

Returns:

  • \u2013

    A TensorDict with the following key: job_due_time [batch_size, num_job + 1]: the due time of each job job_weight [batch_size, num_job + 1]: the weight of each job job_process_time [batch_size, num_job + 1]: the process time of each job

Source code in rl4co/envs/scheduling/smtwtp/generator.py
def __init__(\n    self,\n    num_job: int = 10,\n    min_time_span: float = 0,\n    max_time_span: float = None, # will be set to num_job / 2 by default. In DeepACO, it is set to num_job, which would be too simple\n    min_job_weight: float = 0,\n    max_job_weight: float = 1,\n    min_process_time: float = 0,\n    max_process_time: float = 1,\n    **unused_kwargs\n):\n    self.num_job = num_job\n    self.min_time_span = min_time_span\n    self.max_time_span = num_job / 2 if max_time_span is None else max_time_span\n    self.min_job_weight = min_job_weight\n    self.max_job_weight = max_job_weight\n    self.min_process_time = min_process_time\n    self.max_process_time = max_process_time\n\n    # SMTWTP environment doen't have any other kwargs\n    if len(unused_kwargs) > 0:\n        log.error(f\"Found {len(unused_kwargs)} unused kwargs: {unused_kwargs}\")\n
"},{"location":"docs/content/api/networks/base_policies/","title":"Constructive Policies Base Classes","text":""},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.base.ConstructiveEncoder","title":"ConstructiveEncoder","text":"

Bases: Module

Base class for the encoder of constructive models

"},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.base.ConstructiveEncoder.forward","title":"forward abstractmethod","text":"
forward(td: TensorDict) -> Tuple[Any, Tensor]\n

Forward pass for the encoder

Parameters:

  • td (TensorDict) \u2013

    TensorDict containing the input data

Returns:

  • Tuple[Any, Tensor] \u2013

    Tuple containing:

    • latent representation (any type)
    • initial embeddings (from feature space to embedding space)
Source code in rl4co/models/common/constructive/base.py
@abc.abstractmethod\ndef forward(self, td: TensorDict) -> Tuple[Any, Tensor]:\n    \"\"\"Forward pass for the encoder\n\n    Args:\n        td: TensorDict containing the input data\n\n    Returns:\n        Tuple containing:\n          - latent representation (any type)\n          - initial embeddings (from feature space to embedding space)\n    \"\"\"\n    raise NotImplementedError(\"Implement me in subclass!\")\n
"},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.base.ConstructiveDecoder","title":"ConstructiveDecoder","text":"

Bases: Module

Base decoder model for constructive models. The decoder is responsible for generating the logits for the action

"},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.base.ConstructiveDecoder.forward","title":"forward abstractmethod","text":"
forward(\n    td: TensorDict, hidden: Any = None, num_starts: int = 0\n) -> Tuple[Tensor, Tensor]\n

Obtain logits for current action to the next ones

Parameters:

  • td (TensorDict) \u2013

    TensorDict containing the input data

  • hidden (Any, default: None ) \u2013

    Hidden state from the encoder. Can be any type

  • num_starts (int, default: 0 ) \u2013

    Number of starts for multistart decoding

Returns:

  • Tuple[Tensor, Tensor] \u2013

    Tuple containing the logits and the action mask

Source code in rl4co/models/common/constructive/base.py
@abc.abstractmethod\ndef forward(\n    self, td: TensorDict, hidden: Any = None, num_starts: int = 0\n) -> Tuple[Tensor, Tensor]:\n    \"\"\"Obtain logits for current action to the next ones\n\n    Args:\n        td: TensorDict containing the input data\n        hidden: Hidden state from the encoder. Can be any type\n        num_starts: Number of starts for multistart decoding\n\n    Returns:\n        Tuple containing the logits and the action mask\n    \"\"\"\n    raise NotImplementedError(\"Implement me in subclass!\")\n
"},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.base.ConstructiveDecoder.pre_decoder_hook","title":"pre_decoder_hook","text":"
pre_decoder_hook(\n    td: TensorDict,\n    env: RL4COEnvBase,\n    hidden: Any = None,\n    num_starts: int = 0,\n) -> Tuple[TensorDict, Any, RL4COEnvBase]\n

By default, we don't need to do anything here.

Parameters:

  • td (TensorDict) \u2013

    TensorDict containing the input data

  • hidden (Any, default: None ) \u2013

    Hidden state from the encoder

  • env (RL4COEnvBase) \u2013

    Environment for decoding

  • num_starts (int, default: 0 ) \u2013

    Number of starts for multistart decoding

Returns:

  • Tuple[TensorDict, Any, RL4COEnvBase] \u2013

    Tuple containing the updated hidden state, TensorDict, and environment

Source code in rl4co/models/common/constructive/base.py
def pre_decoder_hook(\n    self, td: TensorDict, env: RL4COEnvBase, hidden: Any = None, num_starts: int = 0\n) -> Tuple[TensorDict, Any, RL4COEnvBase]:\n    \"\"\"By default, we don't need to do anything here.\n\n    Args:\n        td: TensorDict containing the input data\n        hidden: Hidden state from the encoder\n        env: Environment for decoding\n        num_starts: Number of starts for multistart decoding\n\n    Returns:\n        Tuple containing the updated hidden state, TensorDict, and environment\n    \"\"\"\n    return td, env, hidden\n
"},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.base.NoEncoder","title":"NoEncoder","text":"

Bases: ConstructiveEncoder

Default encoder decoder-only models, i.e. autoregressive models that re-encode all the state at each decoding step.

"},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.base.NoEncoder.forward","title":"forward","text":"
forward(td: TensorDict) -> Tuple[Tensor, Tensor]\n

Return Nones for the hidden state and initial embeddings

Source code in rl4co/models/common/constructive/base.py
def forward(self, td: TensorDict) -> Tuple[Tensor, Tensor]:\n    \"\"\"Return Nones for the hidden state and initial embeddings\"\"\"\n    return None, None\n
"},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.base.ConstructivePolicy","title":"ConstructivePolicy","text":"
ConstructivePolicy(\n    encoder: Union[ConstructiveEncoder, Callable],\n    decoder: Union[ConstructiveDecoder, Callable],\n    env_name: str = \"tsp\",\n    temperature: float = 1.0,\n    tanh_clipping: float = 0,\n    mask_logits: bool = True,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"greedy\",\n    test_decode_type: str = \"greedy\",\n    **unused_kw\n)\n

Bases: Module

Base class for constructive policies. Constructive policies take as input and instance and output a solution (sequence of actions). \"Constructive\" means that a solution is created from scratch by the model.

The structure follows roughly the following steps
  1. Create a hidden state from the encoder
  2. Initialize decoding strategy (such as greedy, sampling, etc.)
  3. Decode the action given the hidden state and the environment state at the current step
  4. Update the environment state with the action. Repeat 3-4 until all sequences are done
  5. Obtain log likelihood, rewards etc.

Note that an encoder is not strictly needed (see :class:NoEncoder).). A decoder however is always needed either in the form of a network or a function.

Note

There are major differences between this decoding and most RL problems. The most important one is that reward may not defined for partial solutions, hence we have to wait for the environment to reach a terminal state before we can compute the reward with env.get_reward().

Warning

We suppose environments in the done state are still available for sampling. This is because in NCO we need to wait for all the environments to reach a terminal state before we can stop the decoding process. This is in contrast with the TorchRL framework (at the moment) where the env.rollout function automatically resets. You may follow tighter integration with TorchRL here: https://github.com/ai4co/rl4co/issues/72.

Parameters:

  • encoder (Union[ConstructiveEncoder, Callable]) \u2013

    Encoder to use

  • decoder (Union[ConstructiveDecoder, Callable]) \u2013

    Decoder to use

  • env_name (str, default: 'tsp' ) \u2013

    Environment name to solve (used for automatically instantiating networks)

  • temperature (float, default: 1.0 ) \u2013

    Temperature for the softmax during decoding

  • tanh_clipping (float, default: 0 ) \u2013

    Clipping value for the tanh activation (see Bello et al. 2016) during decoding

  • mask_logits (bool, default: True ) \u2013

    Whether to mask the logits or not during decoding

  • train_decode_type (str, default: 'sampling' ) \u2013

    Decoding strategy for training

  • val_decode_type (str, default: 'greedy' ) \u2013

    Decoding strategy for validation

  • test_decode_type (str, default: 'greedy' ) \u2013

    Decoding strategy for testing

Source code in rl4co/models/common/constructive/base.py
def __init__(\n    self,\n    encoder: Union[ConstructiveEncoder, Callable],\n    decoder: Union[ConstructiveDecoder, Callable],\n    env_name: str = \"tsp\",\n    temperature: float = 1.0,\n    tanh_clipping: float = 0,\n    mask_logits: bool = True,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"greedy\",\n    test_decode_type: str = \"greedy\",\n    **unused_kw,\n):\n    super(ConstructivePolicy, self).__init__()\n\n    if len(unused_kw) > 0:\n        log.error(f\"Found {len(unused_kw)} unused kwargs: {unused_kw}\")\n\n    self.env_name = env_name\n\n    # Encoder and decoder\n    if encoder is None:\n        log.warning(\"`None` was provided as encoder. Using `NoEncoder`.\")\n        encoder = NoEncoder()\n    self.encoder = encoder\n    self.decoder = decoder\n\n    # Decoding strategies\n    self.temperature = temperature\n    self.tanh_clipping = tanh_clipping\n    self.mask_logits = mask_logits\n    self.train_decode_type = train_decode_type\n    self.val_decode_type = val_decode_type\n    self.test_decode_type = test_decode_type\n
"},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.base.ConstructivePolicy.forward","title":"forward","text":"
forward(\n    td: TensorDict,\n    env: Optional[Union[str, RL4COEnvBase]] = None,\n    phase: str = \"train\",\n    calc_reward: bool = True,\n    return_actions: bool = False,\n    return_entropy: bool = False,\n    return_hidden: bool = False,\n    return_init_embeds: bool = False,\n    return_sum_log_likelihood: bool = True,\n    actions=None,\n    max_steps=1000000,\n    **decoding_kwargs\n) -> dict\n

Forward pass of the policy.

Parameters:

  • td (TensorDict) \u2013

    TensorDict containing the environment state

  • env (Optional[Union[str, RL4COEnvBase]], default: None ) \u2013

    Environment to use for decoding. If None, the environment is instantiated from env_name. Note that it is more efficient to pass an already instantiated environment each time for fine-grained control

  • phase (str, default: 'train' ) \u2013

    Phase of the algorithm (train, val, test)

  • calc_reward (bool, default: True ) \u2013

    Whether to calculate the reward

  • return_actions (bool, default: False ) \u2013

    Whether to return the actions

  • return_entropy (bool, default: False ) \u2013

    Whether to return the entropy

  • return_hidden (bool, default: False ) \u2013

    Whether to return the hidden state

  • return_init_embeds (bool, default: False ) \u2013

    Whether to return the initial embeddings

  • return_sum_log_likelihood (bool, default: True ) \u2013

    Whether to return the sum of the log likelihood

  • actions \u2013

    Actions to use for evaluating the policy. If passed, use these actions instead of sampling from the policy to calculate log likelihood

  • max_steps \u2013

    Maximum number of decoding steps for sanity check to avoid infinite loops if envs are buggy (i.e. do not reach done)

  • decoding_kwargs \u2013

    Keyword arguments for the decoding strategy. See :class:rl4co.utils.decoding.DecodingStrategy for more information.

Returns:

  • out ( dict ) \u2013

    Dictionary containing the reward, log likelihood, and optionally the actions and entropy

Source code in rl4co/models/common/constructive/base.py
def forward(\n    self,\n    td: TensorDict,\n    env: Optional[Union[str, RL4COEnvBase]] = None,\n    phase: str = \"train\",\n    calc_reward: bool = True,\n    return_actions: bool = False,\n    return_entropy: bool = False,\n    return_hidden: bool = False,\n    return_init_embeds: bool = False,\n    return_sum_log_likelihood: bool = True,\n    actions=None,\n    max_steps=1_000_000,\n    **decoding_kwargs,\n) -> dict:\n    \"\"\"Forward pass of the policy.\n\n    Args:\n        td: TensorDict containing the environment state\n        env: Environment to use for decoding. If None, the environment is instantiated from `env_name`. Note that\n            it is more efficient to pass an already instantiated environment each time for fine-grained control\n        phase: Phase of the algorithm (train, val, test)\n        calc_reward: Whether to calculate the reward\n        return_actions: Whether to return the actions\n        return_entropy: Whether to return the entropy\n        return_hidden: Whether to return the hidden state\n        return_init_embeds: Whether to return the initial embeddings\n        return_sum_log_likelihood: Whether to return the sum of the log likelihood\n        actions: Actions to use for evaluating the policy.\n            If passed, use these actions instead of sampling from the policy to calculate log likelihood\n        max_steps: Maximum number of decoding steps for sanity check to avoid infinite loops if envs are buggy (i.e. do not reach `done`)\n        decoding_kwargs: Keyword arguments for the decoding strategy. See :class:`rl4co.utils.decoding.DecodingStrategy` for more information.\n\n    Returns:\n        out: Dictionary containing the reward, log likelihood, and optionally the actions and entropy\n    \"\"\"\n\n    # Encoder: get encoder output and initial embeddings from initial state\n    hidden, init_embeds = self.encoder(td)\n\n    # Instantiate environment if needed\n    if isinstance(env, str) or env is None:\n        env_name = self.env_name if env is None else env\n        log.info(f\"Instantiated environment not provided; instantiating {env_name}\")\n        env = get_env(env_name)\n\n    # Get decode type depending on phase and whether actions are passed for evaluation\n    decode_type = decoding_kwargs.pop(\"decode_type\", None)\n    if actions is not None:\n        decode_type = \"evaluate\"\n    elif decode_type is None:\n        decode_type = getattr(self, f\"{phase}_decode_type\")\n\n    # Setup decoding strategy\n    # we pop arguments that are not part of the decoding strategy\n    decode_strategy: DecodingStrategy = get_decoding_strategy(\n        decode_type,\n        temperature=decoding_kwargs.pop(\"temperature\", self.temperature),\n        tanh_clipping=decoding_kwargs.pop(\"tanh_clipping\", self.tanh_clipping),\n        mask_logits=decoding_kwargs.pop(\"mask_logits\", self.mask_logits),\n        store_all_logp=decoding_kwargs.pop(\"store_all_logp\", return_entropy),\n        **decoding_kwargs,\n    )\n\n    # Pre-decoding hook: used for the initial step(s) of the decoding strategy\n    td, env, num_starts = decode_strategy.pre_decoder_hook(td, env)\n\n    # Additionally call a decoder hook if needed before main decoding\n    td, env, hidden = self.decoder.pre_decoder_hook(td, env, hidden, num_starts)\n\n    # Main decoding: loop until all sequences are done\n    step = 0\n    while not td[\"done\"].all():\n        logits, mask = self.decoder(td, hidden, num_starts)\n        td = decode_strategy.step(\n            logits,\n            mask,\n            td,\n            action=actions[..., step] if actions is not None else None,\n        )\n        td = env.step(td)[\"next\"]\n        step += 1\n        if step > max_steps:\n            log.error(\n                f\"Exceeded maximum number of steps ({max_steps}) duing decoding\"\n            )\n            break\n\n    # Post-decoding hook: used for the final step(s) of the decoding strategy\n    logprobs, actions, td, env = decode_strategy.post_decoder_hook(td, env)\n\n    # Output dictionary construction\n    if calc_reward:\n        td.set(\"reward\", env.get_reward(td, actions))\n\n    outdict = {\n        \"reward\": td[\"reward\"],\n        \"log_likelihood\": get_log_likelihood(\n            logprobs, actions, td.get(\"mask\", None), return_sum_log_likelihood\n        ),\n    }\n\n    if return_actions:\n        outdict[\"actions\"] = actions\n    if return_entropy:\n        outdict[\"entropy\"] = calculate_entropy(logprobs)\n    if return_hidden:\n        outdict[\"hidden\"] = hidden\n    if return_init_embeds:\n        outdict[\"init_embeds\"] = init_embeds\n\n    return outdict\n
"},{"location":"docs/content/api/networks/base_policies/#autoregressive-policies","title":"Autoregressive Policies","text":""},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.autoregressive.encoder.AutoregressiveEncoder","title":"AutoregressiveEncoder","text":"

Bases: ConstructiveEncoder

Template class for an autoregressive encoder, simple wrapper around :class:rl4co.models.common.constructive.base.ConstructiveEncoder.

Tip

This class will not work as it is and is just a template. An example for autoregressive encoder can be found as :class:rl4co.models.zoo.am.encoder.AttentionModelEncoder.

"},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.autoregressive.decoder.AutoregressiveDecoder","title":"AutoregressiveDecoder","text":"

Bases: ConstructiveDecoder

Template class for an autoregressive decoder, simple wrapper around :class:rl4co.models.common.constructive.base.ConstructiveDecoder

Tip

This class will not work as it is and is just a template. An example for autoregressive encoder can be found as :class:rl4co.models.zoo.am.decoder.AttentionModelDecoder.

"},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.autoregressive.policy.AutoregressivePolicy","title":"AutoregressivePolicy","text":"
AutoregressivePolicy(\n    encoder: AutoregressiveEncoder,\n    decoder: AutoregressiveDecoder,\n    env_name: str = \"tsp\",\n    temperature: float = 1.0,\n    tanh_clipping: float = 0,\n    mask_logits: bool = True,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"greedy\",\n    test_decode_type: str = \"greedy\",\n    **unused_kw\n)\n

Bases: ConstructivePolicy

Template class for an autoregressive policy, simple wrapper around :class:rl4co.models.common.constructive.base.ConstructivePolicy.

Note

While a decoder is required, an encoder is optional and will be initialized to :class:rl4co.models.common.constructive.autoregressive.encoder.NoEncoder. This can be used in decoder-only models in which at each step actions do not depend on previously encoded states.

Source code in rl4co/models/common/constructive/autoregressive/policy.py
def __init__(\n    self,\n    encoder: AutoregressiveEncoder,\n    decoder: AutoregressiveDecoder,\n    env_name: str = \"tsp\",\n    temperature: float = 1.0,\n    tanh_clipping: float = 0,\n    mask_logits: bool = True,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"greedy\",\n    test_decode_type: str = \"greedy\",\n    **unused_kw,\n):\n    # We raise an error for the user if no decoder was provided\n    if decoder is None:\n        raise ValueError(\"AutoregressivePolicy requires a decoder to be provided.\")\n\n    super(AutoregressivePolicy, self).__init__(\n        encoder=encoder,\n        decoder=decoder,\n        env_name=env_name,\n        temperature=temperature,\n        tanh_clipping=tanh_clipping,\n        mask_logits=mask_logits,\n        train_decode_type=train_decode_type,\n        val_decode_type=val_decode_type,\n        test_decode_type=test_decode_type,\n        **unused_kw,\n    )\n
"},{"location":"docs/content/api/networks/base_policies/#nonautoregressive-policies","title":"Nonautoregressive Policies","text":""},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.nonautoregressive.encoder.NonAutoregressiveEncoder","title":"NonAutoregressiveEncoder","text":"

Bases: ConstructiveEncoder

Template class for an autoregressive encoder, simple wrapper around :class:rl4co.models.common.constructive.base.ConstructiveEncoder.

Tip

This class will not work as it is and is just a template. An example for autoregressive encoder can be found as :class:rl4co.models.zoo.am.encoder.AttentionModelEncoder.

"},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.nonautoregressive.decoder.NonAutoregressiveDecoder","title":"NonAutoregressiveDecoder","text":"

Bases: ConstructiveDecoder

The nonautoregressive decoder is a simple callable class that takes the tensor dictionary and the heatmaps logits and returns the logits for the current action logits and the action mask.

"},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.nonautoregressive.decoder.NonAutoregressiveDecoder.heatmap_to_logits","title":"heatmap_to_logits staticmethod","text":"
heatmap_to_logits(\n    td: TensorDict, heatmaps_logits: Tensor, num_starts: int\n)\n

Obtain heatmap logits for current action to the next ones

Source code in rl4co/models/common/constructive/nonautoregressive/decoder.py
@staticmethod\ndef heatmap_to_logits(td: TensorDict, heatmaps_logits: torch.Tensor, num_starts: int):\n    \"\"\"Obtain heatmap logits for current action to the next ones\"\"\"\n    current_action = td.get(\"action\", None)\n    if current_action is None:\n        logits = heatmaps_logits.mean(-1)\n    else:\n        batch_size = heatmaps_logits.shape[0]\n        _indexer = _multistart_batched_index(batch_size, num_starts)\n        logits = heatmaps_logits[_indexer, current_action, :]\n    return logits, td[\"action_mask\"]\n
"},{"location":"docs/content/api/networks/base_policies/#models.common.constructive.nonautoregressive.policy.NonAutoregressivePolicy","title":"NonAutoregressivePolicy","text":"
NonAutoregressivePolicy(\n    encoder: NonAutoregressiveEncoder,\n    decoder: NonAutoregressiveDecoder = None,\n    env_name: str = \"tsp\",\n    temperature: float = 1.0,\n    tanh_clipping: float = 0,\n    mask_logits: bool = True,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"greedy\",\n    test_decode_type: str = \"greedy\",\n    **unused_kw\n)\n

Bases: ConstructivePolicy

Template class for an nonautoregressive policy, simple wrapper around :class:rl4co.models.common.constructive.base.ConstructivePolicy.

Source code in rl4co/models/common/constructive/nonautoregressive/policy.py
def __init__(\n    self,\n    encoder: NonAutoregressiveEncoder,\n    decoder: NonAutoregressiveDecoder = None,\n    env_name: str = \"tsp\",\n    temperature: float = 1.0,\n    tanh_clipping: float = 0,\n    mask_logits: bool = True,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"greedy\",\n    test_decode_type: str = \"greedy\",\n    **unused_kw,\n):\n    # If decoder is not passed, we default to the non-autoregressive decoder that decodes the heatmap\n    if decoder is None:\n        decoder = NonAutoregressiveDecoder()\n\n    super(NonAutoregressivePolicy, self).__init__(\n        encoder=encoder,\n        decoder=decoder,\n        env_name=env_name,\n        temperature=temperature,\n        tanh_clipping=tanh_clipping,\n        mask_logits=mask_logits,\n        train_decode_type=train_decode_type,\n        val_decode_type=val_decode_type,\n        test_decode_type=test_decode_type,\n        **unused_kw,\n    )\n
"},{"location":"docs/content/api/networks/base_policies/#improvement-policies-base-classes","title":"Improvement Policies (Base Classes)","text":""},{"location":"docs/content/api/networks/base_policies/#models.common.improvement.base.ImprovementEncoder","title":"ImprovementEncoder","text":"
ImprovementEncoder(\n    embed_dim: int = 128,\n    init_embedding: Module = None,\n    pos_embedding: Module = None,\n    env_name: str = \"pdp_ruin_repair\",\n    pos_type: str = \"CPE\",\n    num_heads: int = 4,\n    num_layers: int = 3,\n    normalization: str = \"layer\",\n    feedforward_hidden: int = 128,\n    linear_bias: bool = False,\n)\n

Bases: Module

Base class for the encoder of improvement models

Source code in rl4co/models/common/improvement/base.py
def __init__(\n    self,\n    embed_dim: int = 128,\n    init_embedding: nn.Module = None,\n    pos_embedding: nn.Module = None,\n    env_name: str = \"pdp_ruin_repair\",\n    pos_type: str = \"CPE\",\n    num_heads: int = 4,\n    num_layers: int = 3,\n    normalization: str = \"layer\",\n    feedforward_hidden: int = 128,\n    linear_bias: bool = False,\n):\n    super(ImprovementEncoder, self).__init__()\n\n    if isinstance(env_name, RL4COEnvBase):\n        env_name = env_name.name\n    self.env_name = env_name\n    self.init_embedding = (\n        env_init_embedding(\n            self.env_name, {\"embed_dim\": embed_dim, \"linear_bias\": linear_bias}\n        )\n        if init_embedding is None\n        else init_embedding\n    )\n\n    self.pos_type = pos_type\n    self.pos_embedding = (\n        pos_init_embedding(self.pos_type, {\"embed_dim\": embed_dim})\n        if pos_embedding is None\n        else pos_embedding\n    )\n
"},{"location":"docs/content/api/networks/base_policies/#models.common.improvement.base.ImprovementEncoder.forward","title":"forward","text":"
forward(td: TensorDict) -> Tuple[Tensor, Tensor]\n

Forward pass of the encoder. Transform the input TensorDict into a latent representation.

Parameters:

  • td (TensorDict) \u2013

    Input TensorDict containing the environment state

Returns:

  • h ( Tensor ) \u2013

    Latent representation of the input

  • init_h ( Tensor ) \u2013

    Initial embedding of the input

Source code in rl4co/models/common/improvement/base.py
def forward(self, td: TensorDict) -> Tuple[Tensor, Tensor]:\n    \"\"\"Forward pass of the encoder.\n    Transform the input TensorDict into a latent representation.\n\n    Args:\n        td: Input TensorDict containing the environment state\n\n    Returns:\n        h: Latent representation of the input\n        init_h: Initial embedding of the input\n    \"\"\"\n    # Transfer to embedding space (node)\n    init_h = self.init_embedding(td)\n\n    # Transfer to embedding space (solution)\n    init_p = self.pos_embedding(td)\n\n    # Process embedding\n    final_h, final_p = self._encoder_forward(init_h, init_p)\n\n    # Return latent representation and initial embedding\n    return final_h, final_p\n
"},{"location":"docs/content/api/networks/base_policies/#models.common.improvement.base.ImprovementDecoder","title":"ImprovementDecoder","text":"

Bases: Module

Base decoder model for improvement models. The decoder is responsible for generating the logits of the action

"},{"location":"docs/content/api/networks/base_policies/#models.common.improvement.base.ImprovementDecoder.forward","title":"forward abstractmethod","text":"
forward(\n    td: TensorDict, final_h: Tensor, final_p: Tensor\n) -> Tensor\n

Obtain logits to perform operators that improve the current solution to the next ones

Parameters:

  • td (TensorDict) \u2013

    TensorDict with the current environment state

  • final_h (Tensor) \u2013

    final node embeddings

  • final_p (Tensor) \u2013

    final positional embeddings

Returns:

  • Tensor \u2013

    Tuple containing the logits

Source code in rl4co/models/common/improvement/base.py
@abc.abstractmethod\ndef forward(self, td: TensorDict, final_h: Tensor, final_p: Tensor) -> Tensor:\n    \"\"\"Obtain logits to perform operators that improve the current solution to the next ones\n\n    Args:\n        td: TensorDict with the current environment state\n        final_h: final node embeddings\n        final_p: final positional embeddings\n\n    Returns:\n        Tuple containing the logits\n    \"\"\"\n    raise NotImplementedError(\"Implement me in subclass!\")\n
"},{"location":"docs/content/api/networks/base_policies/#models.common.improvement.base.ImprovementPolicy","title":"ImprovementPolicy","text":"

Bases: Module

Base class for improvement policies. Improvement policies take an instance + a solution as input and output a specific operator that changes the current solution to a new one.

\"Improvement\" means that a solution is (potentially) improved to a new one by the model.

"},{"location":"docs/content/api/networks/base_policies/#models.common.improvement.base.ImprovementPolicy.forward","title":"forward abstractmethod","text":"
forward(\n    td: TensorDict,\n    env: Union[str, RL4COEnvBase] = None,\n    phase: str = \"train\",\n    return_actions: bool = False,\n    return_entropy: bool = False,\n    return_init_embeds: bool = False,\n    actions=None,\n    **decoding_kwargs\n) -> dict\n

Forward pass of the policy.

Parameters:

  • td (TensorDict) \u2013

    TensorDict containing the environment state

  • env (Union[str, RL4COEnvBase], default: None ) \u2013

    Environment to use for decoding. If None, the environment is instantiated from env_name. Note that it is more efficient to pass an already instantiated environment each time for fine-grained control

  • phase (str, default: 'train' ) \u2013

    Phase of the algorithm (train, val, test)

  • return_actions (bool, default: False ) \u2013

    Whether to return the actions

  • return_entropy (bool, default: False ) \u2013

    Whether to return the entropy

  • return_init_embeds (bool, default: False ) \u2013

    Whether to return the initial embeddings

  • actions \u2013

    Actions to use for evaluating the policy. If passed, use these actions instead of sampling from the policy to calculate log likelihood

  • decoding_kwargs \u2013

    Keyword arguments for the decoding strategy. See :class:rl4co.utils.decoding.DecodingStrategy for more information.

Returns:

  • out ( dict ) \u2013

    Dictionary containing the reward, log likelihood, and optionally the actions and entropy

Source code in rl4co/models/common/improvement/base.py
@abc.abstractmethod\ndef forward(\n    self,\n    td: TensorDict,\n    env: Union[str, RL4COEnvBase] = None,\n    phase: str = \"train\",\n    return_actions: bool = False,\n    return_entropy: bool = False,\n    return_init_embeds: bool = False,\n    actions=None,\n    **decoding_kwargs,\n) -> dict:\n    \"\"\"Forward pass of the policy.\n\n    Args:\n        td: TensorDict containing the environment state\n        env: Environment to use for decoding. If None, the environment is instantiated from `env_name`. Note that\n            it is more efficient to pass an already instantiated environment each time for fine-grained control\n        phase: Phase of the algorithm (train, val, test)\n        return_actions: Whether to return the actions\n        return_entropy: Whether to return the entropy\n        return_init_embeds: Whether to return the initial embeddings\n        actions: Actions to use for evaluating the policy.\n            If passed, use these actions instead of sampling from the policy to calculate log likelihood\n        decoding_kwargs: Keyword arguments for the decoding strategy. See :class:`rl4co.utils.decoding.DecodingStrategy` for more information.\n\n    Returns:\n        out: Dictionary containing the reward, log likelihood, and optionally the actions and entropy\n    \"\"\"\n    raise NotImplementedError(\"Implement me in subclass!\")\n
"},{"location":"docs/content/api/networks/env_embeddings/","title":"Environment Embeddings","text":"

In autoregressive policies, environment embeddings transfer data from feature space to hidden space:

  • Initial Embeddings: encode global problem features
  • Context Embeddings: modify current node embedding during decoding
  • Dynamic Embeddings: modify all nodes embeddings during decoding

"},{"location":"docs/content/api/networks/env_embeddings/#context-embeddings","title":"Context Embeddings","text":"

The context embedding is used to modify the query embedding of the problem node of the current partial solution. Usually consists of a projection of gathered node embeddings and features to the embedding space.

"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.EnvContext","title":"EnvContext","text":"
EnvContext(\n    embed_dim, step_context_dim=None, linear_bias=False\n)\n

Bases: Module

Base class for environment context embeddings. The context embedding is used to modify the query embedding of the problem node of the current partial solution. Consists of a linear layer that projects the node features to the embedding space.

Source code in rl4co/models/nn/env_embeddings/context.py
def __init__(self, embed_dim, step_context_dim=None, linear_bias=False):\n    super(EnvContext, self).__init__()\n    self.embed_dim = embed_dim\n    step_context_dim = step_context_dim if step_context_dim is not None else embed_dim\n    self.project_context = nn.Linear(step_context_dim, embed_dim, bias=linear_bias)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.FFSPContext","title":"FFSPContext","text":"
FFSPContext(embed_dim, stage_cnt=None)\n

Bases: EnvContext

Source code in rl4co/models/nn/env_embeddings/context.py
def __init__(self, embed_dim, stage_cnt=None):\n    self.has_stage_emb = stage_cnt is not None\n    step_context_dim = (1 + int(self.has_stage_emb)) * embed_dim\n    super().__init__(embed_dim=embed_dim, step_context_dim=step_context_dim)\n    if self.has_stage_emb:\n        self.stage_emb = nn.Parameter(torch.rand(stage_cnt, embed_dim))\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.TSPContext","title":"TSPContext","text":"
TSPContext(embed_dim)\n

Bases: EnvContext

Context embedding for the Traveling Salesman Problem (TSP). Project the following to the embedding space:

- first node embedding\n- current node embedding\n
Source code in rl4co/models/nn/env_embeddings/context.py
def __init__(self, embed_dim):\n    super(TSPContext, self).__init__(embed_dim, 2 * embed_dim)\n    self.W_placeholder = nn.Parameter(\n        torch.Tensor(2 * self.embed_dim).uniform_(-1, 1)\n    )\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.VRPContext","title":"VRPContext","text":"
VRPContext(embed_dim)\n

Bases: EnvContext

Context embedding for the Capacitated Vehicle Routing Problem (CVRP). Project the following to the embedding space:

- current node embedding\n- remaining capacity (vehicle_capacity - used_capacity)\n
Source code in rl4co/models/nn/env_embeddings/context.py
def __init__(self, embed_dim):\n    super(VRPContext, self).__init__(\n        embed_dim=embed_dim, step_context_dim=embed_dim + 1\n    )\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.VRPTWContext","title":"VRPTWContext","text":"
VRPTWContext(embed_dim)\n

Bases: VRPContext

Context embedding for the Capacitated Vehicle Routing Problem (CVRP). Project the following to the embedding space:

- current node embedding\n- remaining capacity (vehicle_capacity - used_capacity)\n- current time\n
Source code in rl4co/models/nn/env_embeddings/context.py
def __init__(self, embed_dim):\n    super(VRPContext, self).__init__(\n        embed_dim=embed_dim, step_context_dim=embed_dim + 2\n    )\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.SVRPContext","title":"SVRPContext","text":"
SVRPContext(embed_dim)\n

Bases: EnvContext

Context embedding for the Skill Vehicle Routing Problem (SVRP). Project the following to the embedding space:

- current node embedding\n- current technician\n
Source code in rl4co/models/nn/env_embeddings/context.py
def __init__(self, embed_dim):\n    super(SVRPContext, self).__init__(embed_dim=embed_dim, step_context_dim=embed_dim)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.PCTSPContext","title":"PCTSPContext","text":"
PCTSPContext(embed_dim)\n

Bases: EnvContext

Context embedding for the Prize Collecting TSP (PCTSP). Project the following to the embedding space:

- current node embedding\n- remaining prize (prize_required - cur_total_prize)\n
Source code in rl4co/models/nn/env_embeddings/context.py
def __init__(self, embed_dim):\n    super(PCTSPContext, self).__init__(embed_dim, embed_dim + 1)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.OPContext","title":"OPContext","text":"
OPContext(embed_dim)\n

Bases: EnvContext

Context embedding for the Orienteering Problem (OP). Project the following to the embedding space:

- current node embedding\n- remaining distance (max_length - tour_length)\n
Source code in rl4co/models/nn/env_embeddings/context.py
def __init__(self, embed_dim):\n    super(OPContext, self).__init__(embed_dim, embed_dim + 1)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.DPPContext","title":"DPPContext","text":"
DPPContext(embed_dim)\n

Bases: EnvContext

Context embedding for the Decap Placement Problem (DPP), EDA (electronic design automation). Project the following to the embedding space:

- current cell embedding\n
Source code in rl4co/models/nn/env_embeddings/context.py
def __init__(self, embed_dim):\n    super(DPPContext, self).__init__(embed_dim)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.DPPContext.forward","title":"forward","text":"
forward(embeddings, td)\n

Context cannot be defined by a single node embedding for DPP, hence 0. We modify the dynamic embedding instead to capture placed items

Source code in rl4co/models/nn/env_embeddings/context.py
def forward(self, embeddings, td):\n    \"\"\"Context cannot be defined by a single node embedding for DPP, hence 0.\n    We modify the dynamic embedding instead to capture placed items\n    \"\"\"\n    return embeddings.new_zeros(embeddings.size(0), self.embed_dim)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.PDPContext","title":"PDPContext","text":"
PDPContext(embed_dim)\n

Bases: EnvContext

Context embedding for the Pickup and Delivery Problem (PDP). Project the following to the embedding space:

- current node embedding\n
Source code in rl4co/models/nn/env_embeddings/context.py
def __init__(self, embed_dim):\n    super(PDPContext, self).__init__(embed_dim, embed_dim)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.MTSPContext","title":"MTSPContext","text":"
MTSPContext(embed_dim, linear_bias=False)\n

Bases: EnvContext

Context embedding for the Multiple Traveling Salesman Problem (mTSP). Project the following to the embedding space:

- current node embedding\n- remaining_agents\n- current_length\n- max_subtour_length\n- distance_from_depot\n
Source code in rl4co/models/nn/env_embeddings/context.py
def __init__(self, embed_dim, linear_bias=False):\n    super(MTSPContext, self).__init__(embed_dim, 2 * embed_dim)\n    proj_in_dim = (\n        4  # remaining_agents, current_length, max_subtour_length, distance_from_depot\n    )\n    self.proj_dynamic_feats = nn.Linear(proj_in_dim, embed_dim, bias=linear_bias)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.SMTWTPContext","title":"SMTWTPContext","text":"
SMTWTPContext(embed_dim)\n

Bases: EnvContext

Context embedding for the Single Machine Total Weighted Tardiness Problem (SMTWTP). Project the following to the embedding space:

- current node embedding\n- current time\n
Source code in rl4co/models/nn/env_embeddings/context.py
def __init__(self, embed_dim):\n    super(SMTWTPContext, self).__init__(embed_dim, embed_dim + 1)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.MDCPDPContext","title":"MDCPDPContext","text":"
MDCPDPContext(embed_dim)\n

Bases: EnvContext

Context embedding for the MDCPDP. Project the following to the embedding space:

- current node embedding\n
Source code in rl4co/models/nn/env_embeddings/context.py
def __init__(self, embed_dim):\n    super(MDCPDPContext, self).__init__(embed_dim, embed_dim)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.MTVRPContext","title":"MTVRPContext","text":"
MTVRPContext(embed_dim)\n

Bases: VRPContext

Context embedding for Multi-Task VRPEnv. Project the following to the embedding space:

- current node embedding\n- remaining_linehaul_capacity (vehicle_capacity - used_capacity_linehaul)\n- remaining_backhaul_capacity (vehicle_capacity - used_capacity_backhaul)\n- current time\n- current_route_length\n- open route indicator\n
Source code in rl4co/models/nn/env_embeddings/context.py
def __init__(self, embed_dim):\n    super(VRPContext, self).__init__(\n        embed_dim=embed_dim, step_context_dim=embed_dim + 5\n    )\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.context.env_context_embedding","title":"env_context_embedding","text":"
env_context_embedding(\n    env_name: str, config: dict\n) -> Module\n

Get environment context embedding. The context embedding is used to modify the query embedding of the problem node of the current partial solution. Usually consists of a projection of gathered node embeddings and features to the embedding space.

Parameters:

  • env \u2013

    Environment or its name.

  • config (dict) \u2013

    A dictionary of configuration options for the environment.

Source code in rl4co/models/nn/env_embeddings/context.py
def env_context_embedding(env_name: str, config: dict) -> nn.Module:\n    \"\"\"Get environment context embedding. The context embedding is used to modify the\n    query embedding of the problem node of the current partial solution.\n    Usually consists of a projection of gathered node embeddings and features to the embedding space.\n\n    Args:\n        env: Environment or its name.\n        config: A dictionary of configuration options for the environment.\n    \"\"\"\n    embedding_registry = {\n        \"tsp\": TSPContext,\n        \"atsp\": TSPContext,\n        \"cvrp\": VRPContext,\n        \"cvrptw\": VRPTWContext,\n        \"ffsp\": FFSPContext,\n        \"svrp\": SVRPContext,\n        \"sdvrp\": VRPContext,\n        \"pctsp\": PCTSPContext,\n        \"spctsp\": PCTSPContext,\n        \"op\": OPContext,\n        \"dpp\": DPPContext,\n        \"mdpp\": DPPContext,\n        \"pdp\": PDPContext,\n        \"mtsp\": MTSPContext,\n        \"smtwtp\": SMTWTPContext,\n        \"mdcpdp\": MDCPDPContext,\n        \"mtvrp\": MTVRPContext,\n    }\n\n    if env_name not in embedding_registry:\n        raise ValueError(\n            f\"Unknown environment name '{env_name}'. Available context embeddings: {embedding_registry.keys()}\"\n        )\n\n    return embedding_registry[env_name](**config)\n
"},{"location":"docs/content/api/networks/env_embeddings/#dynamic-embeddings","title":"Dynamic Embeddings","text":"

The dynamic embedding is used to modify query, key and value vectors of the attention mechanism based on the current state of the environment (which is changing during the rollout). Generally consists of a linear layer that projects the node features to the embedding space.

"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.dynamic.StaticEmbedding","title":"StaticEmbedding","text":"
StaticEmbedding(*args, **kwargs)\n

Bases: Module

Static embedding for general problems. This is used for problems that do not have any dynamic information, except for the information regarding the current action (e.g. the current node in TSP). See context embedding for more details.

Source code in rl4co/models/nn/env_embeddings/dynamic.py
def __init__(self, *args, **kwargs):\n    super(StaticEmbedding, self).__init__()\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.dynamic.SDVRPDynamicEmbedding","title":"SDVRPDynamicEmbedding","text":"
SDVRPDynamicEmbedding(embed_dim, linear_bias=False)\n

Bases: Module

Dynamic embedding for the Split Delivery Vehicle Routing Problem (SDVRP). Embed the following node features to the embedding space:

- demand_with_depot: demand of the customers and the depot\n

The demand with depot is used to modify the query, key and value vectors of the attention mechanism based on the current state of the environment (which is changing during the rollout).

Source code in rl4co/models/nn/env_embeddings/dynamic.py
def __init__(self, embed_dim, linear_bias=False):\n    super(SDVRPDynamicEmbedding, self).__init__()\n    self.projection = nn.Linear(1, 3 * embed_dim, bias=linear_bias)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.dynamic.env_dynamic_embedding","title":"env_dynamic_embedding","text":"
env_dynamic_embedding(\n    env_name: str, config: dict\n) -> Module\n

Get environment dynamic embedding. The dynamic embedding is used to modify query, key and value vectors of the attention mechanism based on the current state of the environment (which is changing during the rollout). Consists of a linear layer that projects the node features to the embedding space.

Parameters:

  • env \u2013

    Environment or its name.

  • config (dict) \u2013

    A dictionary of configuration options for the environment.

Source code in rl4co/models/nn/env_embeddings/dynamic.py
def env_dynamic_embedding(env_name: str, config: dict) -> nn.Module:\n    \"\"\"Get environment dynamic embedding. The dynamic embedding is used to modify query, key and value vectors of the attention mechanism\n    based on the current state of the environment (which is changing during the rollout).\n    Consists of a linear layer that projects the node features to the embedding space.\n\n    Args:\n        env: Environment or its name.\n        config: A dictionary of configuration options for the environment.\n    \"\"\"\n    embedding_registry = {\n        \"tsp\": StaticEmbedding,\n        \"atsp\": StaticEmbedding,\n        \"cvrp\": StaticEmbedding,\n        \"cvrptw\": StaticEmbedding,\n        \"ffsp\": StaticEmbedding,\n        \"svrp\": StaticEmbedding,\n        \"sdvrp\": SDVRPDynamicEmbedding,\n        \"pctsp\": StaticEmbedding,\n        \"spctsp\": StaticEmbedding,\n        \"op\": StaticEmbedding,\n        \"dpp\": StaticEmbedding,\n        \"mdpp\": StaticEmbedding,\n        \"pdp\": StaticEmbedding,\n        \"mtsp\": StaticEmbedding,\n        \"smtwtp\": StaticEmbedding,\n        \"jssp\": JSSPDynamicEmbedding,\n        \"fjsp\": JSSPDynamicEmbedding,\n        \"mtvrp\": StaticEmbedding,\n    }\n\n    if env_name not in embedding_registry:\n        log.warning(\n            f\"Unknown environment name '{env_name}'. Available dynamic embeddings: {embedding_registry.keys()}. Defaulting to StaticEmbedding.\"\n        )\n    return embedding_registry.get(env_name, StaticEmbedding)(**config)\n
"},{"location":"docs/content/api/networks/env_embeddings/#init-embeddings","title":"Init Embeddings","text":"

The init embedding is used to initialize the general embedding of the problem nodes without any solution information. Generally consists of a linear layer that projects the node features to the embedding space.

"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.init.TSPInitEmbedding","title":"TSPInitEmbedding","text":"
TSPInitEmbedding(embed_dim, linear_bias=True)\n

Bases: Module

Initial embedding for the Traveling Salesman Problems (TSP). Embed the following node features to the embedding space:

- locs: x, y coordinates of the cities\n
Source code in rl4co/models/nn/env_embeddings/init.py
def __init__(self, embed_dim, linear_bias=True):\n    super(TSPInitEmbedding, self).__init__()\n    node_dim = 2  # x, y\n    self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.init.MatNetInitEmbedding","title":"MatNetInitEmbedding","text":"
MatNetInitEmbedding(\n    embed_dim: int, mode: str = \"RandomOneHot\"\n)\n

Bases: Module

Preparing the initial row and column embeddings for MatNet.

Reference: https://github.com/yd-kwon/MatNet/blob/782698b60979effe2e7b61283cca155b7cdb727f/ATSP/ATSP_MatNet/ATSPModel.py#L51

Source code in rl4co/models/nn/env_embeddings/init.py
def __init__(self, embed_dim: int, mode: str = \"RandomOneHot\") -> None:\n    super().__init__()\n\n    self.embed_dim = embed_dim\n    assert mode in {\n        \"RandomOneHot\",\n        \"Random\",\n    }, \"mode must be one of ['RandomOneHot', 'Random']\"\n    self.mode = mode\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.init.VRPInitEmbedding","title":"VRPInitEmbedding","text":"
VRPInitEmbedding(\n    embed_dim, linear_bias=True, node_dim: int = 3\n)\n

Bases: Module

Initial embedding for the Vehicle Routing Problems (VRP). Embed the following node features to the embedding space:

- locs: x, y coordinates of the nodes (depot and customers separately)\n- demand: demand of the customers\n
Source code in rl4co/models/nn/env_embeddings/init.py
def __init__(self, embed_dim, linear_bias=True, node_dim: int = 3):\n    super(VRPInitEmbedding, self).__init__()\n    node_dim = node_dim  # 3: x, y, demand\n    self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias)\n    self.init_embed_depot = nn.Linear(2, embed_dim, linear_bias)  # depot embedding\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.init.PCTSPInitEmbedding","title":"PCTSPInitEmbedding","text":"
PCTSPInitEmbedding(embed_dim, linear_bias=True)\n

Bases: Module

Initial embedding for the Prize Collecting Traveling Salesman Problems (PCTSP). Embed the following node features to the embedding space:

- locs: x, y coordinates of the nodes (depot and customers separately)\n- expected_prize: expected prize for visiting the customers.\n    In PCTSP, this is the actual prize. In SPCTSP, this is the expected prize.\n- penalty: penalty for not visiting the customers\n
Source code in rl4co/models/nn/env_embeddings/init.py
def __init__(self, embed_dim, linear_bias=True):\n    super(PCTSPInitEmbedding, self).__init__()\n    node_dim = 4  # x, y, prize, penalty\n    self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias)\n    self.init_embed_depot = nn.Linear(2, embed_dim, linear_bias)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.init.OPInitEmbedding","title":"OPInitEmbedding","text":"
OPInitEmbedding(embed_dim, linear_bias=True)\n

Bases: Module

Initial embedding for the Orienteering Problems (OP). Embed the following node features to the embedding space:

- locs: x, y coordinates of the nodes (depot and customers separately)\n- prize: prize for visiting the customers\n
Source code in rl4co/models/nn/env_embeddings/init.py
def __init__(self, embed_dim, linear_bias=True):\n    super(OPInitEmbedding, self).__init__()\n    node_dim = 3  # x, y, prize\n    self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias)\n    self.init_embed_depot = nn.Linear(2, embed_dim, linear_bias)  # depot embedding\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.init.DPPInitEmbedding","title":"DPPInitEmbedding","text":"
DPPInitEmbedding(embed_dim, linear_bias=True)\n

Bases: Module

Initial embedding for the Decap Placement Problem (DPP), EDA (electronic design automation). Embed the following node features to the embedding space:

- locs: x, y coordinates of the nodes (cells)\n- probe: index of the (single) probe cell. We embed the euclidean distance from the probe to all cells.\n
Source code in rl4co/models/nn/env_embeddings/init.py
def __init__(self, embed_dim, linear_bias=True):\n    super(DPPInitEmbedding, self).__init__()\n    node_dim = 2  # x, y\n    self.init_embed = nn.Linear(node_dim, embed_dim // 2, linear_bias)  # locs\n    self.init_embed_probe = nn.Linear(1, embed_dim // 2, linear_bias)  # probe\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.init.MDPPInitEmbedding","title":"MDPPInitEmbedding","text":"
MDPPInitEmbedding(embed_dim, linear_bias=True)\n

Bases: Module

Initial embedding for the Multi-port Placement Problem (MDPP), EDA (electronic design automation). Embed the following node features to the embedding space:

- locs: x, y coordinates of the nodes (cells)\n- probe: indexes of the probe cells (multiple). We embed the euclidean distance of each cell to the closest probe.\n
Source code in rl4co/models/nn/env_embeddings/init.py
def __init__(self, embed_dim, linear_bias=True):\n    super(MDPPInitEmbedding, self).__init__()\n    node_dim = 2  # x, y\n    self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias)  # locs\n    self.init_embed_probe_distance = nn.Linear(\n        1, embed_dim, linear_bias\n    )  # probe_distance\n    self.project_out = nn.Linear(embed_dim * 2, embed_dim, linear_bias)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.init.PDPInitEmbedding","title":"PDPInitEmbedding","text":"
PDPInitEmbedding(embed_dim, linear_bias=True)\n

Bases: Module

Initial embedding for the Pickup and Delivery Problem (PDP). Embed the following node features to the embedding space:

- locs: x, y coordinates of the nodes (depot, pickups and deliveries separately)\n   Note that pickups and deliveries are interleaved in the input.\n
Source code in rl4co/models/nn/env_embeddings/init.py
def __init__(self, embed_dim, linear_bias=True):\n    super(PDPInitEmbedding, self).__init__()\n    node_dim = 2  # x, y\n    self.init_embed_depot = nn.Linear(2, embed_dim, linear_bias)\n    self.init_embed_pick = nn.Linear(node_dim * 2, embed_dim, linear_bias)\n    self.init_embed_delivery = nn.Linear(node_dim, embed_dim, linear_bias)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.init.MTSPInitEmbedding","title":"MTSPInitEmbedding","text":"
MTSPInitEmbedding(embed_dim, linear_bias=True)\n

Bases: Module

Initial embedding for the Multiple Traveling Salesman Problem (mTSP). Embed the following node features to the embedding space:

- locs: x, y coordinates of the nodes (depot, cities)\n
Source code in rl4co/models/nn/env_embeddings/init.py
def __init__(self, embed_dim, linear_bias=True):\n    \"\"\"NOTE: new made by Fede. May need to be checked\"\"\"\n    super(MTSPInitEmbedding, self).__init__()\n    node_dim = 2  # x, y\n    self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias)\n    self.init_embed_depot = nn.Linear(2, embed_dim, linear_bias)  # depot embedding\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.init.SMTWTPInitEmbedding","title":"SMTWTPInitEmbedding","text":"
SMTWTPInitEmbedding(embed_dim, linear_bias=True)\n

Bases: Module

Initial embedding for the Single Machine Total Weighted Tardiness Problem (SMTWTP). Embed the following node features to the embedding space:

- job_due_time: due time of the jobs\n- job_weight: weights of the jobs\n- job_process_time: the processing time of jobs\n
Source code in rl4co/models/nn/env_embeddings/init.py
def __init__(self, embed_dim, linear_bias=True):\n    super(SMTWTPInitEmbedding, self).__init__()\n    node_dim = 3  # job_due_time, job_weight, job_process_time\n    self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.init.MDCPDPInitEmbedding","title":"MDCPDPInitEmbedding","text":"
MDCPDPInitEmbedding(embed_dim, linear_bias=True)\n

Bases: Module

Initial embedding for the MDCPDP environment Embed the following node features to the embedding space:

- locs: x, y coordinates of the nodes (depot, pickups and deliveries separately)\n   Note that pickups and deliveries are interleaved in the input.\n
Source code in rl4co/models/nn/env_embeddings/init.py
def __init__(self, embed_dim, linear_bias=True):\n    super(MDCPDPInitEmbedding, self).__init__()\n    node_dim = 2  # x, y\n    self.init_embed_depot = nn.Linear(2, embed_dim, linear_bias)\n    self.init_embed_pick = nn.Linear(node_dim * 2, embed_dim, linear_bias)\n    self.init_embed_delivery = nn.Linear(node_dim, embed_dim, linear_bias)\n
"},{"location":"docs/content/api/networks/env_embeddings/#models.nn.env_embeddings.init.env_init_embedding","title":"env_init_embedding","text":"
env_init_embedding(env_name: str, config: dict) -> Module\n

Get environment initial embedding. The init embedding is used to initialize the general embedding of the problem nodes without any solution information. Consists of a linear layer that projects the node features to the embedding space.

Parameters:

  • env \u2013

    Environment or its name.

  • config (dict) \u2013

    A dictionary of configuration options for the environment.

Source code in rl4co/models/nn/env_embeddings/init.py
def env_init_embedding(env_name: str, config: dict) -> nn.Module:\n    \"\"\"Get environment initial embedding. The init embedding is used to initialize the\n    general embedding of the problem nodes without any solution information.\n    Consists of a linear layer that projects the node features to the embedding space.\n\n    Args:\n        env: Environment or its name.\n        config: A dictionary of configuration options for the environment.\n    \"\"\"\n    embedding_registry = {\n        \"tsp\": TSPInitEmbedding,\n        \"atsp\": TSPInitEmbedding,\n        \"matnet\": MatNetInitEmbedding,\n        \"cvrp\": VRPInitEmbedding,\n        \"cvrptw\": VRPTWInitEmbedding,\n        \"svrp\": SVRPInitEmbedding,\n        \"sdvrp\": VRPInitEmbedding,\n        \"pctsp\": PCTSPInitEmbedding,\n        \"spctsp\": PCTSPInitEmbedding,\n        \"op\": OPInitEmbedding,\n        \"dpp\": DPPInitEmbedding,\n        \"mdpp\": MDPPInitEmbedding,\n        \"pdp\": PDPInitEmbedding,\n        \"pdp_ruin_repair\": TSPInitEmbedding,\n        \"tsp_kopt\": TSPInitEmbedding,\n        \"mtsp\": MTSPInitEmbedding,\n        \"smtwtp\": SMTWTPInitEmbedding,\n        \"mdcpdp\": MDCPDPInitEmbedding,\n        \"fjsp\": FJSPInitEmbedding,\n        \"jssp\": FJSPInitEmbedding,\n        \"mtvrp\": MTVRPInitEmbedding,\n    }\n\n    if env_name not in embedding_registry:\n        raise ValueError(\n            f\"Unknown environment name '{env_name}'. Available init embeddings: {embedding_registry.keys()}\"\n        )\n\n    return embedding_registry[env_name](**config)\n
"},{"location":"docs/content/api/networks/improvement_policies/","title":"Improvement policies","text":""},{"location":"docs/content/api/networks/improvement_policies/#improvement-policies-base-classes","title":"Improvement Policies (Base Classes)","text":""},{"location":"docs/content/api/networks/improvement_policies/#models.common.improvement.base.ImprovementEncoder","title":"ImprovementEncoder","text":"
ImprovementEncoder(\n    embed_dim: int = 128,\n    init_embedding: Module = None,\n    pos_embedding: Module = None,\n    env_name: str = \"pdp_ruin_repair\",\n    pos_type: str = \"CPE\",\n    num_heads: int = 4,\n    num_layers: int = 3,\n    normalization: str = \"layer\",\n    feedforward_hidden: int = 128,\n    linear_bias: bool = False,\n)\n

Bases: Module

Base class for the encoder of improvement models

Source code in rl4co/models/common/improvement/base.py
def __init__(\n    self,\n    embed_dim: int = 128,\n    init_embedding: nn.Module = None,\n    pos_embedding: nn.Module = None,\n    env_name: str = \"pdp_ruin_repair\",\n    pos_type: str = \"CPE\",\n    num_heads: int = 4,\n    num_layers: int = 3,\n    normalization: str = \"layer\",\n    feedforward_hidden: int = 128,\n    linear_bias: bool = False,\n):\n    super(ImprovementEncoder, self).__init__()\n\n    if isinstance(env_name, RL4COEnvBase):\n        env_name = env_name.name\n    self.env_name = env_name\n    self.init_embedding = (\n        env_init_embedding(\n            self.env_name, {\"embed_dim\": embed_dim, \"linear_bias\": linear_bias}\n        )\n        if init_embedding is None\n        else init_embedding\n    )\n\n    self.pos_type = pos_type\n    self.pos_embedding = (\n        pos_init_embedding(self.pos_type, {\"embed_dim\": embed_dim})\n        if pos_embedding is None\n        else pos_embedding\n    )\n
"},{"location":"docs/content/api/networks/improvement_policies/#models.common.improvement.base.ImprovementEncoder.forward","title":"forward","text":"
forward(td: TensorDict) -> Tuple[Tensor, Tensor]\n

Forward pass of the encoder. Transform the input TensorDict into a latent representation.

Parameters:

  • td (TensorDict) \u2013

    Input TensorDict containing the environment state

Returns:

  • h ( Tensor ) \u2013

    Latent representation of the input

  • init_h ( Tensor ) \u2013

    Initial embedding of the input

Source code in rl4co/models/common/improvement/base.py
def forward(self, td: TensorDict) -> Tuple[Tensor, Tensor]:\n    \"\"\"Forward pass of the encoder.\n    Transform the input TensorDict into a latent representation.\n\n    Args:\n        td: Input TensorDict containing the environment state\n\n    Returns:\n        h: Latent representation of the input\n        init_h: Initial embedding of the input\n    \"\"\"\n    # Transfer to embedding space (node)\n    init_h = self.init_embedding(td)\n\n    # Transfer to embedding space (solution)\n    init_p = self.pos_embedding(td)\n\n    # Process embedding\n    final_h, final_p = self._encoder_forward(init_h, init_p)\n\n    # Return latent representation and initial embedding\n    return final_h, final_p\n
"},{"location":"docs/content/api/networks/improvement_policies/#models.common.improvement.base.ImprovementDecoder","title":"ImprovementDecoder","text":"

Bases: Module

Base decoder model for improvement models. The decoder is responsible for generating the logits of the action

"},{"location":"docs/content/api/networks/improvement_policies/#models.common.improvement.base.ImprovementDecoder.forward","title":"forward abstractmethod","text":"
forward(\n    td: TensorDict, final_h: Tensor, final_p: Tensor\n) -> Tensor\n

Obtain logits to perform operators that improve the current solution to the next ones

Parameters:

  • td (TensorDict) \u2013

    TensorDict with the current environment state

  • final_h (Tensor) \u2013

    final node embeddings

  • final_p (Tensor) \u2013

    final positional embeddings

Returns:

  • Tensor \u2013

    Tuple containing the logits

Source code in rl4co/models/common/improvement/base.py
@abc.abstractmethod\ndef forward(self, td: TensorDict, final_h: Tensor, final_p: Tensor) -> Tensor:\n    \"\"\"Obtain logits to perform operators that improve the current solution to the next ones\n\n    Args:\n        td: TensorDict with the current environment state\n        final_h: final node embeddings\n        final_p: final positional embeddings\n\n    Returns:\n        Tuple containing the logits\n    \"\"\"\n    raise NotImplementedError(\"Implement me in subclass!\")\n
"},{"location":"docs/content/api/networks/improvement_policies/#models.common.improvement.base.ImprovementPolicy","title":"ImprovementPolicy","text":"

Bases: Module

Base class for improvement policies. Improvement policies take an instance + a solution as input and output a specific operator that changes the current solution to a new one.

\"Improvement\" means that a solution is (potentially) improved to a new one by the model.

"},{"location":"docs/content/api/networks/improvement_policies/#models.common.improvement.base.ImprovementPolicy.forward","title":"forward abstractmethod","text":"
forward(\n    td: TensorDict,\n    env: Union[str, RL4COEnvBase] = None,\n    phase: str = \"train\",\n    return_actions: bool = False,\n    return_entropy: bool = False,\n    return_init_embeds: bool = False,\n    actions=None,\n    **decoding_kwargs\n) -> dict\n

Forward pass of the policy.

Parameters:

  • td (TensorDict) \u2013

    TensorDict containing the environment state

  • env (Union[str, RL4COEnvBase], default: None ) \u2013

    Environment to use for decoding. If None, the environment is instantiated from env_name. Note that it is more efficient to pass an already instantiated environment each time for fine-grained control

  • phase (str, default: 'train' ) \u2013

    Phase of the algorithm (train, val, test)

  • return_actions (bool, default: False ) \u2013

    Whether to return the actions

  • return_entropy (bool, default: False ) \u2013

    Whether to return the entropy

  • return_init_embeds (bool, default: False ) \u2013

    Whether to return the initial embeddings

  • actions \u2013

    Actions to use for evaluating the policy. If passed, use these actions instead of sampling from the policy to calculate log likelihood

  • decoding_kwargs \u2013

    Keyword arguments for the decoding strategy. See :class:rl4co.utils.decoding.DecodingStrategy for more information.

Returns:

  • out ( dict ) \u2013

    Dictionary containing the reward, log likelihood, and optionally the actions and entropy

Source code in rl4co/models/common/improvement/base.py
@abc.abstractmethod\ndef forward(\n    self,\n    td: TensorDict,\n    env: Union[str, RL4COEnvBase] = None,\n    phase: str = \"train\",\n    return_actions: bool = False,\n    return_entropy: bool = False,\n    return_init_embeds: bool = False,\n    actions=None,\n    **decoding_kwargs,\n) -> dict:\n    \"\"\"Forward pass of the policy.\n\n    Args:\n        td: TensorDict containing the environment state\n        env: Environment to use for decoding. If None, the environment is instantiated from `env_name`. Note that\n            it is more efficient to pass an already instantiated environment each time for fine-grained control\n        phase: Phase of the algorithm (train, val, test)\n        return_actions: Whether to return the actions\n        return_entropy: Whether to return the entropy\n        return_init_embeds: Whether to return the initial embeddings\n        actions: Actions to use for evaluating the policy.\n            If passed, use these actions instead of sampling from the policy to calculate log likelihood\n        decoding_kwargs: Keyword arguments for the decoding strategy. See :class:`rl4co.utils.decoding.DecodingStrategy` for more information.\n\n    Returns:\n        out: Dictionary containing the reward, log likelihood, and optionally the actions and entropy\n    \"\"\"\n    raise NotImplementedError(\"Implement me in subclass!\")\n
"},{"location":"docs/content/api/networks/nn/","title":"Neural Network Modules","text":""},{"location":"docs/content/api/networks/nn/#critic-network","title":"Critic Network","text":""},{"location":"docs/content/api/networks/nn/#models.rl.common.critic.CriticNetwork","title":"CriticNetwork","text":"
CriticNetwork(\n    encoder: Module,\n    value_head: Optional[Module] = None,\n    embed_dim: int = 128,\n    hidden_dim: int = 512,\n    customized: bool = False,\n)\n

Bases: Module

Create a critic network given an encoder (e.g. as the one in the policy network) with a value head to transform the embeddings to a scalar value.

Parameters:

  • encoder (Module) \u2013

    Encoder module to encode the input

  • value_head (Optional[Module], default: None ) \u2013

    Value head to transform the embeddings to a scalar value

  • embed_dim (int, default: 128 ) \u2013

    Dimension of the embeddings of the value head

  • hidden_dim (int, default: 512 ) \u2013

    Dimension of the hidden layer of the value head

Source code in rl4co/models/rl/common/critic.py
def __init__(\n    self,\n    encoder: nn.Module,\n    value_head: Optional[nn.Module] = None,\n    embed_dim: int = 128,\n    hidden_dim: int = 512,\n    customized: bool = False,\n):\n    super(CriticNetwork, self).__init__()\n\n    self.encoder = encoder\n    if value_head is None:\n        # check if embed dim of encoder is different, if so, use it\n        if getattr(encoder, \"embed_dim\", embed_dim) != embed_dim:\n            log.warning(\n                f\"Found encoder with different embed_dim {encoder.embed_dim} than the value head {embed_dim}. Using encoder embed_dim for value head.\"\n            )\n            embed_dim = getattr(encoder, \"embed_dim\", embed_dim)\n        value_head = nn.Sequential(\n            nn.Linear(embed_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, 1)\n        )\n    self.value_head = value_head\n    self.customized = customized\n
"},{"location":"docs/content/api/networks/nn/#models.rl.common.critic.CriticNetwork.forward","title":"forward","text":"
forward(\n    x: Union[Tensor, TensorDict], hidden=None\n) -> Tensor\n

Forward pass of the critic network: encode the imput in embedding space and return the value

Parameters:

  • x (Union[Tensor, TensorDict]) \u2013

    Input containing the environment state. Can be a Tensor or a TensorDict

Returns:

  • Tensor \u2013

    Value of the input state

Source code in rl4co/models/rl/common/critic.py
def forward(self, x: Union[Tensor, TensorDict], hidden=None) -> Tensor:\n    \"\"\"Forward pass of the critic network: encode the imput in embedding space and return the value\n\n    Args:\n        x: Input containing the environment state. Can be a Tensor or a TensorDict\n\n    Returns:\n        Value of the input state\n    \"\"\"\n    if not self.customized:  # fir for most of costructive tasks\n        h, _ = self.encoder(x)  # [batch_size, N, embed_dim] -> [batch_size, N]\n        return self.value_head(h).mean(1)  # [batch_size, N] -> [batch_size]\n    else:  # custimized encoder and value head with hidden input\n        h = self.encoder(x)  # [batch_size, N, embed_dim] -> [batch_size, N]\n        return self.value_head(h, hidden)\n
"},{"location":"docs/content/api/networks/nn/#graph-neural-networks","title":"Graph Neural Networks","text":""},{"location":"docs/content/api/networks/nn/#models.nn.graph.attnnet.MultiHeadAttentionLayer","title":"MultiHeadAttentionLayer","text":"
MultiHeadAttentionLayer(\n    embed_dim: int,\n    num_heads: int = 8,\n    feedforward_hidden: int = 512,\n    normalization: Optional[str] = \"batch\",\n    bias: bool = True,\n    sdpa_fn: Optional[Callable] = None,\n    moe_kwargs: Optional[dict] = None,\n)\n

Bases: Sequential

Multi-Head Attention Layer with normalization and feed-forward layer

Parameters:

  • embed_dim (int) \u2013

    dimension of the embeddings

  • num_heads (int, default: 8 ) \u2013

    number of heads in the MHA

  • feedforward_hidden (int, default: 512 ) \u2013

    dimension of the hidden layer in the feed-forward layer

  • normalization (Optional[str], default: 'batch' ) \u2013

    type of normalization to use (batch, layer, none)

  • sdpa_fn (Optional[Callable], default: None ) \u2013

    scaled dot product attention function (SDPA)

  • moe_kwargs (Optional[dict], default: None ) \u2013

    Keyword arguments for MoE

Source code in rl4co/models/nn/graph/attnnet.py
def __init__(\n    self,\n    embed_dim: int,\n    num_heads: int = 8,\n    feedforward_hidden: int = 512,\n    normalization: Optional[str] = \"batch\",\n    bias: bool = True,\n    sdpa_fn: Optional[Callable] = None,\n    moe_kwargs: Optional[dict] = None,\n):\n    num_neurons = [feedforward_hidden] if feedforward_hidden > 0 else []\n    if moe_kwargs is not None:\n        ffn = MoE(embed_dim, embed_dim, num_neurons=num_neurons, **moe_kwargs)\n    else:\n        ffn = MLP(input_dim=embed_dim, output_dim=embed_dim, num_neurons=num_neurons, hidden_act=\"ReLU\")\n\n    super(MultiHeadAttentionLayer, self).__init__(\n        SkipConnection(\n            MultiHeadAttention(embed_dim, num_heads, bias=bias, sdpa_fn=sdpa_fn)\n        ),\n        Normalization(embed_dim, normalization),\n        SkipConnection(ffn),\n        Normalization(embed_dim, normalization),\n    )\n
"},{"location":"docs/content/api/networks/nn/#models.nn.graph.attnnet.GraphAttentionNetwork","title":"GraphAttentionNetwork","text":"
GraphAttentionNetwork(\n    num_heads: int,\n    embed_dim: int,\n    num_layers: int,\n    normalization: str = \"batch\",\n    feedforward_hidden: int = 512,\n    sdpa_fn: Optional[Callable] = None,\n    moe_kwargs: Optional[dict] = None,\n)\n

Bases: Module

Graph Attention Network to encode embeddings with a series of MHA layers consisting of a MHA layer, normalization, feed-forward layer, and normalization. Similar to Transformer encoder, as used in Kool et al. (2019).

Parameters:

  • num_heads (int) \u2013

    number of heads in the MHA

  • embed_dim (int) \u2013

    dimension of the embeddings

  • num_layers (int) \u2013

    number of MHA layers

  • normalization (str, default: 'batch' ) \u2013

    type of normalization to use (batch, layer, none)

  • feedforward_hidden (int, default: 512 ) \u2013

    dimension of the hidden layer in the feed-forward layer

  • sdpa_fn (Optional[Callable], default: None ) \u2013

    scaled dot product attention function (SDPA)

  • moe_kwargs (Optional[dict], default: None ) \u2013

    Keyword arguments for MoE

Source code in rl4co/models/nn/graph/attnnet.py
def __init__(\n    self,\n    num_heads: int,\n    embed_dim: int,\n    num_layers: int,\n    normalization: str = \"batch\",\n    feedforward_hidden: int = 512,\n    sdpa_fn: Optional[Callable] = None,\n    moe_kwargs: Optional[dict] = None,\n):\n    super(GraphAttentionNetwork, self).__init__()\n\n    self.layers = nn.Sequential(\n        *(\n            MultiHeadAttentionLayer(\n                embed_dim,\n                num_heads,\n                feedforward_hidden=feedforward_hidden,\n                normalization=normalization,\n                sdpa_fn=sdpa_fn,\n                moe_kwargs=moe_kwargs,\n            )\n            for _ in range(num_layers)\n        )\n    )\n
"},{"location":"docs/content/api/networks/nn/#models.nn.graph.attnnet.GraphAttentionNetwork.forward","title":"forward","text":"
forward(x: Tensor, mask: Optional[Tensor] = None) -> Tensor\n

Forward pass of the encoder

Parameters:

  • x (Tensor) \u2013

    [batch_size, graph_size, embed_dim] initial embeddings to process

  • mask (Optional[Tensor], default: None ) \u2013

    [batch_size, graph_size, graph_size] mask for the input embeddings. Unused for now.

Source code in rl4co/models/nn/graph/attnnet.py
def forward(self, x: Tensor, mask: Optional[Tensor] = None) -> Tensor:\n    \"\"\"Forward pass of the encoder\n\n    Args:\n        x: [batch_size, graph_size, embed_dim] initial embeddings to process\n        mask: [batch_size, graph_size, graph_size] mask for the input embeddings. Unused for now.\n    \"\"\"\n    assert mask is None, \"Mask not yet supported!\"\n    h = self.layers(x)\n    return h\n
"},{"location":"docs/content/api/networks/nn/#models.nn.graph.gcn.GCNEncoder","title":"GCNEncoder","text":"
GCNEncoder(\n    env_name: str,\n    embed_dim: int,\n    num_layers: int,\n    init_embedding: Module = None,\n    residual: bool = True,\n    edge_idx_fn: EdgeIndexFnSignature = None,\n    dropout: float = 0.5,\n    bias: bool = True,\n)\n

Bases: Module

Graph Convolutional Network to encode embeddings with a series of GCN layers from the pytorch geometric package

Parameters:

  • embed_dim (int) \u2013

    dimension of the embeddings

  • num_nodes \u2013

    number of nodes in the graph

  • num_gcn_layer \u2013

    number of GCN layers

  • self_loop \u2013

    whether to add self loop in the graph

  • residual (bool, default: True ) \u2013

    whether to use residual connection

Source code in rl4co/models/nn/graph/gcn.py
def __init__(\n    self,\n    env_name: str,\n    embed_dim: int,\n    num_layers: int,\n    init_embedding: nn.Module = None,\n    residual: bool = True,\n    edge_idx_fn: EdgeIndexFnSignature = None,\n    dropout: float = 0.5,\n    bias: bool = True,\n):\n    super().__init__()\n\n    self.env_name = env_name\n    self.embed_dim = embed_dim\n    self.residual = residual\n    self.dropout = dropout\n\n    self.init_embedding = (\n        env_init_embedding(self.env_name, {\"embed_dim\": embed_dim})\n        if init_embedding is None\n        else init_embedding\n    )\n\n    if edge_idx_fn is None:\n        log.warning(\"No edge indices passed. Assume a fully connected graph\")\n        edge_idx_fn = edge_idx_fn_wrapper\n\n    self.edge_idx_fn = edge_idx_fn\n\n    # Define the GCN layers\n    self.gcn_layers = nn.ModuleList(\n        [GCNConv(embed_dim, embed_dim, bias=bias) for _ in range(num_layers)]\n    )\n
"},{"location":"docs/content/api/networks/nn/#models.nn.graph.gcn.GCNEncoder.forward","title":"forward","text":"
forward(\n    td: TensorDict, mask: Union[Tensor, None] = None\n) -> Tuple[Tensor, Tensor]\n

Forward pass of the encoder. Transform the input TensorDict into a latent representation.

Parameters:

  • td (TensorDict) \u2013

    Input TensorDict containing the environment state

  • mask (Union[Tensor, None], default: None ) \u2013

    Mask to apply to the attention

Returns:

  • h ( Tensor ) \u2013

    Latent representation of the input

  • init_h ( Tensor ) \u2013

    Initial embedding of the input

Source code in rl4co/models/nn/graph/gcn.py
def forward(\n    self, td: TensorDict, mask: Union[Tensor, None] = None\n) -> Tuple[Tensor, Tensor]:\n    \"\"\"Forward pass of the encoder.\n    Transform the input TensorDict into a latent representation.\n\n    Args:\n        td: Input TensorDict containing the environment state\n        mask: Mask to apply to the attention\n\n    Returns:\n        h: Latent representation of the input\n        init_h: Initial embedding of the input\n    \"\"\"\n    # Transfer to embedding space\n    init_h = self.init_embedding(td)\n    bs, num_nodes, emb_dim = init_h.shape\n    # (bs*num_nodes, emb_dim)\n    update_node_feature = init_h.reshape(-1, emb_dim)\n    # shape=(2, num_edges)\n    edge_index = self.edge_idx_fn(td, num_nodes)\n\n    for layer in self.gcn_layers[:-1]:\n        update_node_feature = layer(update_node_feature, edge_index)\n        update_node_feature = F.relu(update_node_feature)\n        update_node_feature = F.dropout(\n            update_node_feature, training=self.training, p=self.dropout\n        )\n\n    # last layer without relu activation and dropout\n    update_node_feature = self.gcn_layers[-1](update_node_feature, edge_index)\n\n    # De-batch the graph\n    update_node_feature = update_node_feature.view(bs, num_nodes, emb_dim)\n\n    # Residual\n    if self.residual:\n        update_node_feature = update_node_feature + init_h\n\n    return update_node_feature, init_h\n
"},{"location":"docs/content/api/networks/nn/#models.nn.graph.mpnn.MessagePassingEncoder","title":"MessagePassingEncoder","text":"
MessagePassingEncoder(\n    env_name: str,\n    embed_dim: int,\n    num_nodes: int,\n    num_layers: int,\n    init_embedding: Module = None,\n    aggregation: str = \"add\",\n    self_loop: bool = False,\n    residual: bool = True,\n)\n

Bases: Module

Source code in rl4co/models/nn/graph/mpnn.py
def __init__(\n    self,\n    env_name: str,\n    embed_dim: int,\n    num_nodes: int,\n    num_layers: int,\n    init_embedding: nn.Module = None,\n    aggregation: str = \"add\",\n    self_loop: bool = False,\n    residual: bool = True,\n):\n    \"\"\"\n    Note:\n        - Support fully connected graph for now.\n    \"\"\"\n    super(MessagePassingEncoder, self).__init__()\n\n    self.env_name = env_name\n\n    self.init_embedding = (\n        env_init_embedding(self.env_name, {\"embed_dim\": embed_dim})\n        if init_embedding is None\n        else init_embedding\n    )\n\n    # Generate edge index for a fully connected graph\n    adj_matrix = torch.ones(num_nodes, num_nodes)\n    if self_loop:\n        adj_matrix.fill_diagonal_(0)  # No self-loops\n    self.edge_index = torch.permute(torch.nonzero(adj_matrix), (1, 0))\n\n    # Init message passing models\n    self.mpnn_layers = nn.ModuleList(\n        [\n            MessagePassingLayer(\n                node_indim=embed_dim,\n                node_outdim=embed_dim,\n                edge_indim=1,\n                edge_outdim=1,\n                aggregation=aggregation,\n                residual=residual,\n            )\n            for _ in range(num_layers)\n        ]\n    )\n\n    # Record parameters\n    self.self_loop = self_loop\n
"},{"location":"docs/content/api/networks/nn/#attention-mechanisms","title":"Attention Mechanisms","text":""},{"location":"docs/content/api/networks/nn/#models.nn.attention.MultiHeadAttention","title":"MultiHeadAttention","text":"
MultiHeadAttention(\n    embed_dim: int,\n    num_heads: int,\n    bias: bool = True,\n    attention_dropout: float = 0.0,\n    causal: bool = False,\n    device: str = None,\n    dtype: dtype = None,\n    sdpa_fn: Optional[Callable] = None,\n)\n

Bases: Module

PyTorch native implementation of Flash Multi-Head Attention with automatic mixed precision support. Uses PyTorch's native scaled_dot_product_attention implementation, available from 2.0

Note

If scaled_dot_product_attention is not available, use custom implementation of scaled_dot_product_attention without Flash Attention.

Parameters:

  • embed_dim (int) \u2013

    total dimension of the model

  • num_heads (int) \u2013

    number of heads

  • bias (bool, default: True ) \u2013

    whether to use bias

  • attention_dropout (float, default: 0.0 ) \u2013

    dropout rate for attention weights

  • causal (bool, default: False ) \u2013

    whether to apply causal mask to attention scores

  • device (str, default: None ) \u2013

    torch device

  • dtype (dtype, default: None ) \u2013

    torch dtype

  • sdpa_fn (Optional[Callable], default: None ) \u2013

    scaled dot product attention function (SDPA) implementation

Source code in rl4co/models/nn/attention.py
def __init__(\n    self,\n    embed_dim: int,\n    num_heads: int,\n    bias: bool = True,\n    attention_dropout: float = 0.0,\n    causal: bool = False,\n    device: str = None,\n    dtype: torch.dtype = None,\n    sdpa_fn: Optional[Callable] = None,\n) -> None:\n    factory_kwargs = {\"device\": device, \"dtype\": dtype}\n    super().__init__()\n    self.embed_dim = embed_dim\n    self.causal = causal\n    self.attention_dropout = attention_dropout\n    self.sdpa_fn = sdpa_fn if sdpa_fn is not None else scaled_dot_product_attention\n\n    self.num_heads = num_heads\n    assert self.embed_dim % num_heads == 0, \"self.kdim must be divisible by num_heads\"\n    self.head_dim = self.embed_dim // num_heads\n    assert (\n        self.head_dim % 8 == 0 and self.head_dim <= 128\n    ), \"Only support head_dim <= 128 and divisible by 8\"\n\n    self.Wqkv = nn.Linear(embed_dim, 3 * embed_dim, bias=bias, **factory_kwargs)\n    self.out_proj = nn.Linear(embed_dim, embed_dim, bias=bias, **factory_kwargs)\n
"},{"location":"docs/content/api/networks/nn/#models.nn.attention.MultiHeadAttention.forward","title":"forward","text":"
forward(x, attn_mask=None)\n

x: (batch, seqlen, hidden_dim) (where hidden_dim = num heads * head dim) attn_mask: bool tensor of shape (batch, seqlen)

Source code in rl4co/models/nn/attention.py
def forward(self, x, attn_mask=None):\n    \"\"\"x: (batch, seqlen, hidden_dim) (where hidden_dim = num heads * head dim)\n    attn_mask: bool tensor of shape (batch, seqlen)\n    \"\"\"\n    # Project query, key, value\n    q, k, v = rearrange(\n        self.Wqkv(x), \"b s (three h d) -> three b h s d\", three=3, h=self.num_heads\n    ).unbind(dim=0)\n\n    if attn_mask is not None:\n        attn_mask = (\n            attn_mask.unsqueeze(1)\n            if attn_mask.ndim == 3\n            else attn_mask.unsqueeze(1).unsqueeze(2)\n        )\n\n    # Scaled dot product attention\n    out = self.sdpa_fn(\n        q,\n        k,\n        v,\n        attn_mask=attn_mask,\n        dropout_p=self.attention_dropout,\n    )\n    return self.out_proj(rearrange(out, \"b h s d -> b s (h d)\"))\n
"},{"location":"docs/content/api/networks/nn/#models.nn.attention.MultiHeadCrossAttention","title":"MultiHeadCrossAttention","text":"
MultiHeadCrossAttention(\n    embed_dim: int,\n    num_heads: int,\n    bias: bool = False,\n    attention_dropout: float = 0.0,\n    device: str = None,\n    dtype: dtype = None,\n    sdpa_fn: Optional[Union[Callable, Module]] = None,\n)\n

Bases: Module

PyTorch native implementation of Flash Multi-Head Cross Attention with automatic mixed precision support. Uses PyTorch's native scaled_dot_product_attention implementation, available from 2.0

Note

If scaled_dot_product_attention is not available, use custom implementation of scaled_dot_product_attention without Flash Attention.

Parameters:

  • embed_dim (int) \u2013

    total dimension of the model

  • num_heads (int) \u2013

    number of heads

  • bias (bool, default: False ) \u2013

    whether to use bias

  • attention_dropout (float, default: 0.0 ) \u2013

    dropout rate for attention weights

  • device (str, default: None ) \u2013

    torch device

  • dtype (dtype, default: None ) \u2013

    torch dtype

  • sdpa_fn (Optional[Union[Callable, Module]], default: None ) \u2013

    scaled dot product attention function (SDPA)

Source code in rl4co/models/nn/attention.py
def __init__(\n    self,\n    embed_dim: int,\n    num_heads: int,\n    bias: bool = False,\n    attention_dropout: float = 0.0,\n    device: str = None,\n    dtype: torch.dtype = None,\n    sdpa_fn: Optional[Union[Callable, nn.Module]] = None,\n) -> None:\n    factory_kwargs = {\"device\": device, \"dtype\": dtype}\n    super().__init__()\n    self.embed_dim = embed_dim\n    self.attention_dropout = attention_dropout\n\n    # Default to `scaled_dot_product_attention` if `sdpa_fn` is not provided\n    if sdpa_fn is None:\n        sdpa_fn = sdpa_fn_wrapper\n    self.sdpa_fn = sdpa_fn\n\n    self.num_heads = num_heads\n    assert self.embed_dim % num_heads == 0, \"self.kdim must be divisible by num_heads\"\n    self.head_dim = self.embed_dim // num_heads\n    assert (\n        self.head_dim % 8 == 0 and self.head_dim <= 128\n    ), \"Only support head_dim <= 128 and divisible by 8\"\n\n    self.Wq = nn.Linear(embed_dim, embed_dim, bias=bias, **factory_kwargs)\n    self.Wkv = nn.Linear(embed_dim, 2 * embed_dim, bias=bias, **factory_kwargs)\n    self.out_proj = nn.Linear(embed_dim, embed_dim, bias=bias, **factory_kwargs)\n
"},{"location":"docs/content/api/networks/nn/#models.nn.attention.PointerAttention","title":"PointerAttention","text":"
PointerAttention(\n    embed_dim: int,\n    num_heads: int,\n    mask_inner: bool = True,\n    out_bias: bool = False,\n    check_nan: bool = True,\n    sdpa_fn: Optional[Callable] = None,\n    **kwargs\n)\n

Bases: Module

Calculate logits given query, key and value and logit key. This follows the pointer mechanism of Vinyals et al. (2015) (https://arxiv.org/abs/1506.03134).

Note

With Flash Attention, masking is not supported

Performs the following
  1. Apply cross attention to get the heads
  2. Project heads to get glimpse
  3. Compute attention score between glimpse and logit key

Parameters:

  • embed_dim (int) \u2013

    total dimension of the model

  • num_heads (int) \u2013

    number of heads

  • mask_inner (bool, default: True ) \u2013

    whether to mask inner attention

  • linear_bias \u2013

    whether to use bias in linear projection

  • check_nan (bool, default: True ) \u2013

    whether to check for NaNs in logits

  • sdpa_fn (Optional[Callable], default: None ) \u2013

    scaled dot product attention function (SDPA) implementation

Source code in rl4co/models/nn/attention.py
def __init__(\n    self,\n    embed_dim: int,\n    num_heads: int,\n    mask_inner: bool = True,\n    out_bias: bool = False,\n    check_nan: bool = True,\n    sdpa_fn: Optional[Callable] = None,\n    **kwargs,\n):\n    super(PointerAttention, self).__init__()\n    self.num_heads = num_heads\n    self.mask_inner = mask_inner\n\n    # Projection - query, key, value already include projections\n    self.project_out = nn.Linear(embed_dim, embed_dim, bias=out_bias)\n    self.sdpa_fn = sdpa_fn if sdpa_fn is not None else scaled_dot_product_attention\n    self.check_nan = check_nan\n
"},{"location":"docs/content/api/networks/nn/#models.nn.attention.PointerAttention.forward","title":"forward","text":"
forward(query, key, value, logit_key, attn_mask=None)\n

Compute attention logits given query, key, value, logit key and attention mask.

Parameters:

  • query \u2013

    query tensor of shape [B, ..., L, E]

  • key \u2013

    key tensor of shape [B, ..., S, E]

  • value \u2013

    value tensor of shape [B, ..., S, E]

  • logit_key \u2013

    logit key tensor of shape [B, ..., S, E]

  • attn_mask \u2013

    attention mask tensor of shape [B, ..., S]. Note that True means that the value should take part in attention as described in the PyTorch Documentation

Source code in rl4co/models/nn/attention.py
def forward(self, query, key, value, logit_key, attn_mask=None):\n    \"\"\"Compute attention logits given query, key, value, logit key and attention mask.\n\n    Args:\n        query: query tensor of shape [B, ..., L, E]\n        key: key tensor of shape [B, ..., S, E]\n        value: value tensor of shape [B, ..., S, E]\n        logit_key: logit key tensor of shape [B, ..., S, E]\n        attn_mask: attention mask tensor of shape [B, ..., S]. Note that `True` means that the value _should_ take part in attention\n            as described in the [PyTorch Documentation](https://pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html)\n    \"\"\"\n    # Compute inner multi-head attention with no projections.\n    heads = self._inner_mha(query, key, value, attn_mask)\n    glimpse = self._project_out(heads, attn_mask)\n\n    # Batch matrix multiplication to compute logits (batch_size, num_steps, graph_size)\n    # bmm is slightly faster than einsum and matmul\n    logits = (torch.bmm(glimpse, logit_key.squeeze(-2).transpose(-2, -1))).squeeze(\n        -2\n    ) / math.sqrt(glimpse.size(-1))\n\n    if self.check_nan:\n        assert not torch.isnan(logits).any(), \"Logits contain NaNs\"\n\n    return logits\n
"},{"location":"docs/content/api/networks/nn/#models.nn.attention.PointerAttnMoE","title":"PointerAttnMoE","text":"
PointerAttnMoE(\n    embed_dim: int,\n    num_heads: int,\n    mask_inner: bool = True,\n    out_bias: bool = False,\n    check_nan: bool = True,\n    sdpa_fn: Optional[Callable] = None,\n    moe_kwargs: Optional[dict] = None,\n)\n

Bases: PointerAttention

Calculate logits given query, key and value and logit key. This follows the pointer mechanism of Vinyals et al. (2015) https://arxiv.org/abs/1506.03134, and the MoE gating mechanism of Zhou et al. (2024) https://arxiv.org/abs/2405.01029.

Note

With Flash Attention, masking is not supported

Performs the following
  1. Apply cross attention to get the heads
  2. Project heads to get glimpse
  3. Compute attention score between glimpse and logit key

Parameters:

  • embed_dim (int) \u2013

    total dimension of the model

  • num_heads (int) \u2013

    number of heads

  • mask_inner (bool, default: True ) \u2013

    whether to mask inner attention

  • linear_bias \u2013

    whether to use bias in linear projection

  • check_nan (bool, default: True ) \u2013

    whether to check for NaNs in logits

  • sdpa_fn (Optional[Callable], default: None ) \u2013

    scaled dot product attention function (SDPA) implementation

  • moe_kwargs (Optional[dict], default: None ) \u2013

    Keyword arguments for MoE

Source code in rl4co/models/nn/attention.py
def __init__(\n    self,\n    embed_dim: int,\n    num_heads: int,\n    mask_inner: bool = True,\n    out_bias: bool = False,\n    check_nan: bool = True,\n    sdpa_fn: Optional[Callable] = None,\n    moe_kwargs: Optional[dict] = None,\n):\n    super(PointerAttnMoE, self).__init__(\n        embed_dim, num_heads, mask_inner, out_bias, check_nan, sdpa_fn\n    )\n    self.moe_kwargs = moe_kwargs\n\n    self.project_out = None\n    self.project_out_moe = MoE(\n        embed_dim, embed_dim, num_neurons=[], out_bias=out_bias, **moe_kwargs\n    )\n    if self.moe_kwargs[\"light_version\"]:\n        self.dense_or_moe = nn.Linear(embed_dim, 2, bias=False)\n        self.project_out = nn.Linear(embed_dim, embed_dim, bias=out_bias)\n
"},{"location":"docs/content/api/networks/nn/#models.nn.attention.MultiHeadCompat","title":"MultiHeadCompat","text":"
MultiHeadCompat(\n    n_heads,\n    input_dim,\n    embed_dim=None,\n    val_dim=None,\n    key_dim=None,\n)\n

Bases: Module

Source code in rl4co/models/nn/attention.py
def __init__(self, n_heads, input_dim, embed_dim=None, val_dim=None, key_dim=None):\n    super(MultiHeadCompat, self).__init__()\n\n    if val_dim is None:\n        # assert embed_dim is not None, \"Provide either embed_dim or val_dim\"\n        val_dim = embed_dim // n_heads\n    if key_dim is None:\n        key_dim = val_dim\n\n    self.n_heads = n_heads\n    self.input_dim = input_dim\n    self.embed_dim = embed_dim\n    self.val_dim = val_dim\n    self.key_dim = key_dim\n\n    self.W_query = nn.Parameter(torch.Tensor(n_heads, input_dim, key_dim))\n    self.W_key = nn.Parameter(torch.Tensor(n_heads, input_dim, key_dim))\n\n    self.init_parameters()\n
"},{"location":"docs/content/api/networks/nn/#models.nn.attention.MultiHeadCompat.forward","title":"forward","text":"
forward(q, h=None, mask=None)\n

:param q: queries (batch_size, n_query, input_dim) :param h: data (batch_size, graph_size, input_dim) :param mask: mask (batch_size, n_query, graph_size) or viewable as that (i.e. can be 2 dim if n_query == 1) Mask should contain 1 if attention is not possible (i.e. mask is negative adjacency) :return:

Source code in rl4co/models/nn/attention.py
def forward(self, q, h=None, mask=None):\n    \"\"\"\n\n    :param q: queries (batch_size, n_query, input_dim)\n    :param h: data (batch_size, graph_size, input_dim)\n    :param mask: mask (batch_size, n_query, graph_size) or viewable as that (i.e. can be 2 dim if n_query == 1)\n    Mask should contain 1 if attention is not possible (i.e. mask is negative adjacency)\n    :return:\n    \"\"\"\n\n    if h is None:\n        h = q  # compute self-attention\n\n    # h should be (batch_size, graph_size, input_dim)\n    batch_size, graph_size, input_dim = h.size()\n    n_query = q.size(1)\n\n    hflat = h.contiguous().view(-1, input_dim)  #################   reshape\n    qflat = q.contiguous().view(-1, input_dim)\n\n    # last dimension can be different for keys and values\n    shp = (self.n_heads, batch_size, graph_size, -1)\n    shp_q = (self.n_heads, batch_size, n_query, -1)\n\n    # Calculate queries, (n_heads, n_query, graph_size, key/val_size)\n    Q = torch.matmul(qflat, self.W_query).view(shp_q)\n    K = torch.matmul(hflat, self.W_key).view(shp)\n\n    # Calculate compatibility (n_heads, batch_size, n_query, graph_size)\n    compatibility_s2n = torch.matmul(Q, K.transpose(2, 3))\n\n    return compatibility_s2n\n
"},{"location":"docs/content/api/networks/nn/#models.nn.attention.PolyNetAttention","title":"PolyNetAttention","text":"
PolyNetAttention(\n    k: int,\n    embed_dim: int,\n    poly_layer_dim: int,\n    num_heads: int,\n    **kwargs\n)\n

Bases: PointerAttention

Calculate logits given query, key and value and logit key. This implements a modified version the pointer mechanism of Vinyals et al. (2015) (https://arxiv.org/abs/1506.03134) as described in Hottung et al. (2024) (https://arxiv.org/abs/2402.14048) PolyNetAttention conditions the attention logits on a set of k different binary vectors allowing to learn k different solution strategies.

Note

With Flash Attention, masking is not supported

Performs the following
  1. Apply cross attention to get the heads
  2. Project heads to get glimpse
  3. Apply PolyNet layers
  4. Compute attention score between glimpse and logit key

Parameters:

  • k (int) \u2013

    Number unique bit vectors used to compute attention score

  • embed_dim (int) \u2013

    total dimension of the model

  • poly_layer_dim (int) \u2013

    Dimension of the PolyNet layers

  • num_heads (int) \u2013

    number of heads

  • mask_inner \u2013

    whether to mask inner attention

  • linear_bias \u2013

    whether to use bias in linear projection

  • check_nan \u2013

    whether to check for NaNs in logits

  • sdpa_fn \u2013

    scaled dot product attention function (SDPA) implementation

Source code in rl4co/models/nn/attention.py
def __init__(\n    self, k: int, embed_dim: int, poly_layer_dim: int, num_heads: int, **kwargs\n):\n    super(PolyNetAttention, self).__init__(embed_dim, num_heads, **kwargs)\n\n    self.k = k\n    self.binary_vector_dim = math.ceil(math.log2(k))\n    self.binary_vectors = torch.nn.Parameter(\n        torch.Tensor(\n            list(itertools.product([0, 1], repeat=self.binary_vector_dim))[:k]\n        ),\n        requires_grad=False,\n    )\n\n    self.poly_layer_1 = nn.Linear(embed_dim + self.binary_vector_dim, poly_layer_dim)\n    self.poly_layer_2 = nn.Linear(poly_layer_dim, embed_dim)\n
"},{"location":"docs/content/api/networks/nn/#models.nn.attention.PolyNetAttention.forward","title":"forward","text":"
forward(query, key, value, logit_key, attn_mask=None)\n

Compute attention logits given query, key, value, logit key and attention mask.

Parameters:

  • query \u2013

    query tensor of shape [B, ..., L, E]

  • key \u2013

    key tensor of shape [B, ..., S, E]

  • value \u2013

    value tensor of shape [B, ..., S, E]

  • logit_key \u2013

    logit key tensor of shape [B, ..., S, E]

  • attn_mask \u2013

    attention mask tensor of shape [B, ..., S]. Note that True means that the value should take part in attention as described in the PyTorch Documentation

Source code in rl4co/models/nn/attention.py
def forward(self, query, key, value, logit_key, attn_mask=None):\n    \"\"\"Compute attention logits given query, key, value, logit key and attention mask.\n\n    Args:\n        query: query tensor of shape [B, ..., L, E]\n        key: key tensor of shape [B, ..., S, E]\n        value: value tensor of shape [B, ..., S, E]\n        logit_key: logit key tensor of shape [B, ..., S, E]\n        attn_mask: attention mask tensor of shape [B, ..., S]. Note that `True` means that the value _should_ take part in attention\n            as described in the [PyTorch Documentation](https://pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html)\n    \"\"\"\n    # Compute inner multi-head attention with no projections.\n    heads = self._inner_mha(query, key, value, attn_mask)\n    glimpse = self.project_out(heads)\n\n    num_solutions = glimpse.shape[1]\n    z = self.binary_vectors.repeat(math.ceil(num_solutions / self.k), 1)[\n        :num_solutions\n    ]\n    z = z[None].expand(glimpse.shape[0], num_solutions, self.binary_vector_dim)\n\n    # PolyNet layers\n    poly_out = self.poly_layer_1(torch.cat((glimpse, z), dim=2))\n    poly_out = F.relu(poly_out)\n    poly_out = self.poly_layer_2(poly_out)\n\n    glimpse += poly_out\n\n    # Batch matrix multiplication to compute logits (batch_size, num_steps, graph_size)\n    # bmm is slightly faster than einsum and matmul\n    logits = (torch.bmm(glimpse, logit_key.squeeze(-2).transpose(-2, -1))).squeeze(\n        -2\n    ) / math.sqrt(glimpse.size(-1))\n\n    if self.check_nan:\n        assert not torch.isnan(logits).any(), \"Logits contain NaNs\"\n\n    return logits\n
"},{"location":"docs/content/api/networks/nn/#models.nn.attention.scaled_dot_product_attention_simple","title":"scaled_dot_product_attention_simple","text":"
scaled_dot_product_attention_simple(\n    q, k, v, attn_mask=None, dropout_p=0.0, is_causal=False\n)\n

Simple Scaled Dot-Product Attention in PyTorch without Flash Attention

Source code in rl4co/models/nn/attention.py
def scaled_dot_product_attention_simple(\n    q, k, v, attn_mask=None, dropout_p=0.0, is_causal=False\n):\n    \"\"\"Simple Scaled Dot-Product Attention in PyTorch without Flash Attention\"\"\"\n    # Check for causal and attn_mask conflict\n    if is_causal and attn_mask is not None:\n        raise ValueError(\"Cannot set both is_causal and attn_mask\")\n\n    # Calculate scaled dot product\n    scores = torch.matmul(q, k.transpose(-2, -1)) / (k.size(-1) ** 0.5)\n\n    # Apply the provided attention mask\n    if attn_mask is not None:\n        if attn_mask.dtype == torch.bool:\n            scores.masked_fill_(~attn_mask, float(\"-inf\"))\n        else:\n            scores += attn_mask\n\n    # Apply causal mask\n    if is_causal:\n        s, l_ = scores.size(-2), scores.size(-1)\n        mask = torch.triu(torch.ones((s, l_), device=scores.device), diagonal=1)\n        scores.masked_fill_(mask.bool(), float(\"-inf\"))\n\n    # Softmax to get attention weights\n    attn_weights = F.softmax(scores, dim=-1)\n\n    # Apply dropout\n    if dropout_p > 0.0:\n        attn_weights = F.dropout(attn_weights, p=dropout_p)\n\n    # Compute the weighted sum of values\n    return torch.matmul(attn_weights, v)\n
"},{"location":"docs/content/api/networks/nn/#multi-layer-perceptron","title":"Multi-Layer Perceptron","text":""},{"location":"docs/content/api/networks/nn/#models.nn.mlp.MLP","title":"MLP","text":"
MLP(\n    input_dim: int,\n    output_dim: int,\n    num_neurons: List[int] = [64, 32],\n    dropout_probs: Union[None, List[float]] = None,\n    hidden_act: str = \"ReLU\",\n    out_act: str = \"Identity\",\n    input_norm: str = \"None\",\n    output_norm: str = \"None\",\n)\n

Bases: Module

Source code in rl4co/models/nn/mlp.py
def __init__(\n    self,\n    input_dim: int,\n    output_dim: int,\n    num_neurons: List[int] = [64, 32],\n    dropout_probs: Union[None, List[float]] = None,\n    hidden_act: str = \"ReLU\",\n    out_act: str = \"Identity\",\n    input_norm: str = \"None\",\n    output_norm: str = \"None\",\n):\n    super(MLP, self).__init__()\n\n    assert input_norm in [\"Batch\", \"Layer\", \"None\"]\n    assert output_norm in [\"Batch\", \"Layer\", \"None\"]\n\n    if dropout_probs is None:\n        dropout_probs = [0.0] * len(num_neurons)\n    elif len(dropout_probs) != len(num_neurons):\n        log.info(\n            \"dropout_probs List length should match the num_neurons List length for MLP, dropouts set to False instead\"\n        )\n        dropout_probs = [0.0] * len(num_neurons)\n\n    self.input_dim = input_dim\n    self.output_dim = output_dim\n    self.num_neurons = num_neurons\n    self.hidden_act = getattr(nn, hidden_act)()\n    self.out_act = getattr(nn, out_act)()\n    self.dropouts = []\n    for i in range(len(dropout_probs)):\n        self.dropouts.append(nn.Dropout(p=dropout_probs[i]))\n\n    input_dims = [input_dim] + num_neurons\n    output_dims = num_neurons + [output_dim]\n\n    self.lins = nn.ModuleList()\n    for i, (in_dim, out_dim) in enumerate(zip(input_dims, output_dims)):\n        self.lins.append(nn.Linear(in_dim, out_dim))\n\n    self.input_norm = self._get_norm_layer(input_norm, input_dim)\n    self.output_norm = self._get_norm_layer(output_norm, output_dim)\n
"},{"location":"docs/content/api/networks/nn/#operations","title":"Operations","text":""},{"location":"docs/content/api/networks/nn/#models.nn.ops.PositionalEncoding","title":"PositionalEncoding","text":"
PositionalEncoding(\n    embed_dim: int,\n    dropout: float = 0.1,\n    max_len: int = 1000,\n)\n

Bases: Module

Source code in rl4co/models/nn/ops.py
def __init__(self, embed_dim: int, dropout: float = 0.1, max_len: int = 1000):\n    super().__init__()\n    self.dropout = nn.Dropout(p=dropout)\n    self.d_model = embed_dim\n    max_len = max_len\n    position = torch.arange(max_len).unsqueeze(1)\n    div_term = torch.exp(\n        torch.arange(0, self.d_model, 2) * (-math.log(10000.0) / self.d_model)\n    )\n    pe = torch.zeros(max_len, 1, self.d_model)\n    pe[:, 0, 0::2] = torch.sin(position * div_term)\n    pe[:, 0, 1::2] = torch.cos(position * div_term)\n    pe = pe.transpose(0, 1)  # [1, max_len, d_model]\n    self.register_buffer(\"pe\", pe)\n
"},{"location":"docs/content/api/networks/nn/#models.nn.ops.PositionalEncoding.forward","title":"forward","text":"
forward(hidden: Tensor, seq_pos) -> Tensor\n

Parameters:

  • x \u2013

    Tensor, shape [batch_size, seq_len, embedding_dim]

  • seq_pos \u2013

    Tensor, shape [batch_size, seq_len]

Source code in rl4co/models/nn/ops.py
def forward(self, hidden: torch.Tensor, seq_pos) -> torch.Tensor:\n    \"\"\"\n    Arguments:\n        x: Tensor, shape ``[batch_size, seq_len, embedding_dim]``\n        seq_pos: Tensor, shape ``[batch_size, seq_len]``\n    \"\"\"\n    pes = self.pe.expand(hidden.size(0), -1, -1).gather(\n        1, seq_pos.unsqueeze(-1).expand(-1, -1, self.d_model)\n    )\n    hidden = hidden + pes\n    return self.dropout(hidden)\n
"},{"location":"docs/content/api/networks/nn/#models.nn.ops.RandomEncoding","title":"RandomEncoding","text":"
RandomEncoding(embed_dim: int, max_classes: int = 100)\n

Bases: Module

This is like torch.nn.Embedding but with rows of embeddings are randomly permuted in each forward pass before lookup operation. This might be useful in cases where classes have no fixed meaning but rather indicate a connection between different elements in a sequence. Reference is the MatNet model.

Source code in rl4co/models/nn/ops.py
def __init__(self, embed_dim: int, max_classes: int = 100):\n    super().__init__()\n    self.embed_dim = embed_dim\n    self.max_classes = max_classes\n    rand_emb = torch.rand(max_classes, self.embed_dim)\n    self.register_buffer(\"emb\", rand_emb)\n
"},{"location":"docs/content/api/rl/a2c/","title":"A2C","text":""},{"location":"docs/content/api/rl/a2c/#models.rl.a2c.a2c.A2C","title":"A2C","text":"
A2C(\n    env: RL4COEnvBase,\n    policy: Module,\n    critic: CriticNetwork = None,\n    critic_kwargs: dict = {},\n    actor_optimizer_kwargs: dict = {\"lr\": 0.0001},\n    critic_optimizer_kwargs: dict = None,\n    **kwargs\n)\n

Bases: REINFORCE

Advantage Actor Critic (A2C) algorithm. A2C is a variant of REINFORCE where a baseline is provided by a critic network. Here we additionally support different optimizers for the actor and the critic.

Parameters:

  • env (RL4COEnvBase) \u2013

    Environment to use for the algorithm

  • policy (Module) \u2013

    Policy to use for the algorithm

  • critic (CriticNetwork, default: None ) \u2013

    Critic network to use for the algorithm

  • critic_kwargs (dict, default: {} ) \u2013

    Keyword arguments to pass to the critic network

  • actor_optimizer_kwargs (dict, default: {'lr': 0.0001} ) \u2013

    Keyword arguments for the policy (=actor) optimizer

  • critic_optimizer_kwargs (dict, default: None ) \u2013

    Keyword arguments for the critic optimizer. If None, use the same as actor_optimizer_kwargs

  • **kwargs \u2013

    Keyword arguments passed to the superclass

Source code in rl4co/models/rl/a2c/a2c.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: nn.Module,\n    critic: CriticNetwork = None,\n    critic_kwargs: dict = {},\n    actor_optimizer_kwargs: dict = {\"lr\": 1e-4},\n    critic_optimizer_kwargs: dict = None,\n    **kwargs,\n):\n    if critic is None:\n        log.info(\"Creating critic network for {}\".format(env.name))\n        critic = create_critic_from_actor(policy, **critic_kwargs)\n\n    # The baseline is directly created here, so we eliminate the baseline argument\n    kwargs.pop(\"baseline\", None)\n\n    super().__init__(env, policy, baseline=CriticBaseline(critic), **kwargs)\n    self.actor_optimizer_kwargs = actor_optimizer_kwargs\n    self.critic_optimizer_kwargs = (\n        critic_optimizer_kwargs\n        if critic_optimizer_kwargs is not None\n        else actor_optimizer_kwargs\n    )\n
"},{"location":"docs/content/api/rl/a2c/#models.rl.a2c.a2c.A2C.configure_optimizers","title":"configure_optimizers","text":"
configure_optimizers()\n

Configure the optimizers for the policy and the critic network (=baseline)

Source code in rl4co/models/rl/a2c/a2c.py
def configure_optimizers(self):\n    \"\"\"Configure the optimizers for the policy and the critic network (=baseline)\"\"\"\n    parameters = [\n        {\"params\": self.policy.parameters(), **self.actor_optimizer_kwargs},\n    ] + [{\"params\": self.baseline.parameters(), **self.critic_optimizer_kwargs}]\n\n    return super().configure_optimizers(parameters)\n
"},{"location":"docs/content/api/rl/base/","title":"RL4COLitModule","text":"

The RL4COLitModule is a wrapper around PyTorch Lightning's LightningModule that provides additional functionality for RL algorithms. It is the parent class for all RL algorithms in the library.

"},{"location":"docs/content/api/rl/base/#models.rl.common.base.RL4COLitModule","title":"RL4COLitModule","text":"
RL4COLitModule(\n    env: RL4COEnvBase,\n    policy: Module,\n    batch_size: int = 512,\n    val_batch_size: Union[List[int], int] = None,\n    test_batch_size: Union[List[int], int] = None,\n    train_data_size: int = 100000,\n    val_data_size: int = 10000,\n    test_data_size: int = 10000,\n    optimizer: Union[str, Optimizer, partial] = \"Adam\",\n    optimizer_kwargs: dict = {\"lr\": 0.0001},\n    lr_scheduler: Union[str, LRScheduler, partial] = None,\n    lr_scheduler_kwargs: dict = {\n        \"milestones\": [80, 95],\n        \"gamma\": 0.1,\n    },\n    lr_scheduler_interval: str = \"epoch\",\n    lr_scheduler_monitor: str = \"val/reward\",\n    generate_default_data: bool = False,\n    shuffle_train_dataloader: bool = False,\n    dataloader_num_workers: int = 0,\n    data_dir: str = \"data/\",\n    log_on_step: bool = True,\n    metrics: dict = {},\n    **litmodule_kwargs\n)\n

Bases: LightningModule

Base class for Lightning modules for RL4CO. This defines the general training loop in terms of RL algorithms. Subclasses should implement mainly the shared_step to define the specific loss functions and optimization routines.

Parameters:

  • env (RL4COEnvBase) \u2013

    RL4CO environment

  • policy (Module) \u2013

    policy network (actor)

  • batch_size (int, default: 512 ) \u2013

    batch size (general one, default used for training)

  • val_batch_size (Union[List[int], int], default: None ) \u2013

    specific batch size for validation. If None, will use batch_size. If list, will use one for each dataset

  • test_batch_size (Union[List[int], int], default: None ) \u2013

    specific batch size for testing. If None, will use val_batch_size. If list, will use one for each dataset

  • train_data_size (int, default: 100000 ) \u2013

    size of training dataset for one epoch

  • val_data_size (int, default: 10000 ) \u2013

    size of validation dataset for one epoch

  • test_data_size (int, default: 10000 ) \u2013

    size of testing dataset for one epoch

  • optimizer (Union[str, Optimizer, partial], default: 'Adam' ) \u2013

    optimizer or optimizer name

  • optimizer_kwargs (dict, default: {'lr': 0.0001} ) \u2013

    optimizer kwargs

  • lr_scheduler (Union[str, LRScheduler, partial], default: None ) \u2013

    learning rate scheduler or learning rate scheduler name

  • lr_scheduler_kwargs (dict, default: {'milestones': [80, 95], 'gamma': 0.1} ) \u2013

    learning rate scheduler kwargs

  • lr_scheduler_interval (str, default: 'epoch' ) \u2013

    learning rate scheduler interval

  • lr_scheduler_monitor (str, default: 'val/reward' ) \u2013

    learning rate scheduler monitor

  • generate_default_data (bool, default: False ) \u2013

    whether to generate default datasets, filling up the data directory

  • shuffle_train_dataloader (bool, default: False ) \u2013

    whether to shuffle training dataloader. Default is False since we recreate dataset every epoch

  • dataloader_num_workers (int, default: 0 ) \u2013

    number of workers for dataloader

  • data_dir (str, default: 'data/' ) \u2013

    data directory

  • metrics (dict, default: {} ) \u2013

    metrics

  • litmodule_kwargs \u2013

    kwargs for LightningModule

Source code in rl4co/models/rl/common/base.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: nn.Module,\n    batch_size: int = 512,\n    val_batch_size: Union[List[int], int] = None,\n    test_batch_size: Union[List[int], int] = None,\n    train_data_size: int = 100_000,\n    val_data_size: int = 10_000,\n    test_data_size: int = 10_000,\n    optimizer: Union[str, torch.optim.Optimizer, partial] = \"Adam\",\n    optimizer_kwargs: dict = {\"lr\": 1e-4},\n    lr_scheduler: Union[str, torch.optim.lr_scheduler.LRScheduler, partial] = None,\n    lr_scheduler_kwargs: dict = {\n        \"milestones\": [80, 95],\n        \"gamma\": 0.1,\n    },\n    lr_scheduler_interval: str = \"epoch\",\n    lr_scheduler_monitor: str = \"val/reward\",\n    generate_default_data: bool = False,\n    shuffle_train_dataloader: bool = False,\n    dataloader_num_workers: int = 0,\n    data_dir: str = \"data/\",\n    log_on_step: bool = True,\n    metrics: dict = {},\n    **litmodule_kwargs,\n):\n    super().__init__(**litmodule_kwargs)\n\n    # This line ensures params passed to LightningModule will be saved to ckpt\n    # it also allows to access params with 'self.hparams' attribute\n    # Note: we will send to logger with `self.logger.save_hyperparams` in `setup`\n    self.save_hyperparameters(logger=False)\n\n    self.env = env\n    self.policy = policy\n\n    self.instantiate_metrics(metrics)\n    self.log_on_step = log_on_step\n\n    self.data_cfg = {\n        \"batch_size\": batch_size,\n        \"val_batch_size\": val_batch_size,\n        \"test_batch_size\": test_batch_size,\n        \"generate_default_data\": generate_default_data,\n        \"data_dir\": data_dir,\n        \"train_data_size\": train_data_size,\n        \"val_data_size\": val_data_size,\n        \"test_data_size\": test_data_size,\n    }\n\n    self._optimizer_name_or_cls: Union[str, torch.optim.Optimizer] = optimizer\n    self.optimizer_kwargs: dict = optimizer_kwargs\n    self._lr_scheduler_name_or_cls: Union[\n        str, torch.optim.lr_scheduler.LRScheduler\n    ] = lr_scheduler\n    self.lr_scheduler_kwargs: dict = lr_scheduler_kwargs\n    self.lr_scheduler_interval: str = lr_scheduler_interval\n    self.lr_scheduler_monitor: str = lr_scheduler_monitor\n\n    self.shuffle_train_dataloader = shuffle_train_dataloader\n    self.dataloader_num_workers = dataloader_num_workers\n
"},{"location":"docs/content/api/rl/base/#models.rl.common.base.RL4COLitModule.instantiate_metrics","title":"instantiate_metrics","text":"
instantiate_metrics(metrics: dict)\n

Dictionary of metrics to be logged at each phase

Source code in rl4co/models/rl/common/base.py
def instantiate_metrics(self, metrics: dict):\n    \"\"\"Dictionary of metrics to be logged at each phase\"\"\"\n\n    if not metrics:\n        log.info(\"No metrics specified, using default\")\n    self.train_metrics = metrics.get(\"train\", [\"loss\", \"reward\"])\n    self.val_metrics = metrics.get(\"val\", [\"reward\"])\n    self.test_metrics = metrics.get(\"test\", [\"reward\"])\n    self.log_on_step = metrics.get(\"log_on_step\", True)\n
"},{"location":"docs/content/api/rl/base/#models.rl.common.base.RL4COLitModule.setup","title":"setup","text":"
setup(stage='fit')\n

Base LightningModule setup method. This will setup the datasets and dataloaders

Note

We also send to the loggers all hyperparams that are not nn.Module (i.e. the policy). Apparently PyTorch Lightning does not do this by default.

Source code in rl4co/models/rl/common/base.py
def setup(self, stage=\"fit\"):\n    \"\"\"Base LightningModule setup method. This will setup the datasets and dataloaders\n\n    Note:\n        We also send to the loggers all hyperparams that are not `nn.Module` (i.e. the policy).\n        Apparently PyTorch Lightning does not do this by default.\n    \"\"\"\n\n    log.info(\"Setting up batch sizes for train/val/test\")\n    train_bs, val_bs, test_bs = (\n        self.data_cfg[\"batch_size\"],\n        self.data_cfg[\"val_batch_size\"],\n        self.data_cfg[\"test_batch_size\"],\n    )\n    self.train_batch_size = train_bs\n    self.val_batch_size = train_bs if val_bs is None else val_bs\n    self.test_batch_size = self.val_batch_size if test_bs is None else test_bs\n\n    if self.data_cfg[\"generate_default_data\"]:\n        log.info(\n            \"Generating default datasets. If found, they will not be overwritten\"\n        )\n        generate_default_datasets(data_dir=self.data_cfg[\"data_dir\"])\n\n    log.info(\"Setting up datasets\")\n    self.train_dataset = self.wrap_dataset(\n        self.env.dataset(self.data_cfg[\"train_data_size\"], phase=\"train\")\n    )\n    self.val_dataset = self.env.dataset(self.data_cfg[\"val_data_size\"], phase=\"val\")\n    self.test_dataset = self.env.dataset(\n        self.data_cfg[\"test_data_size\"], phase=\"test\"\n    )\n    self.dataloader_names = None\n    self.setup_loggers()\n    self.post_setup_hook()\n
"},{"location":"docs/content/api/rl/base/#models.rl.common.base.RL4COLitModule.setup_loggers","title":"setup_loggers","text":"
setup_loggers()\n

Log all hyperparameters except those in nn.Module

Source code in rl4co/models/rl/common/base.py
def setup_loggers(self):\n    \"\"\"Log all hyperparameters except those in `nn.Module`\"\"\"\n    if self.loggers is not None:\n        hparams_save = {\n            k: v for k, v in self.hparams.items() if not isinstance(v, nn.Module)\n        }\n        for logger in self.loggers:\n            logger.log_hyperparams(hparams_save)\n            logger.log_graph(self)\n            logger.save()\n
"},{"location":"docs/content/api/rl/base/#models.rl.common.base.RL4COLitModule.post_setup_hook","title":"post_setup_hook","text":"
post_setup_hook()\n

Hook to be called after setup. Can be used to set up subclasses without overriding setup

Source code in rl4co/models/rl/common/base.py
def post_setup_hook(self):\n    \"\"\"Hook to be called after setup. Can be used to set up subclasses without overriding `setup`\"\"\"\n    pass\n
"},{"location":"docs/content/api/rl/base/#models.rl.common.base.RL4COLitModule.configure_optimizers","title":"configure_optimizers","text":"
configure_optimizers(parameters=None)\n

Parameters:

  • parameters \u2013

    parameters to be optimized. If None, will use self.parameters(), i.e. all parameters

Source code in rl4co/models/rl/common/base.py
def configure_optimizers(self, parameters=None):\n    \"\"\"\n    Args:\n        parameters: parameters to be optimized. If None, will use `self.parameters()`, i.e. all parameters\n    \"\"\"\n\n    if parameters is None:\n        parameters = self.parameters()\n\n    log.info(f\"Instantiating optimizer <{self._optimizer_name_or_cls}>\")\n    if isinstance(self._optimizer_name_or_cls, str):\n        optimizer = create_optimizer(\n            parameters, self._optimizer_name_or_cls, **self.optimizer_kwargs\n        )\n    elif isinstance(self._optimizer_name_or_cls, partial):\n        optimizer = self._optimizer_name_or_cls(parameters, **self.optimizer_kwargs)\n    else:  # User-defined optimizer\n        opt_cls = self._optimizer_name_or_cls\n        optimizer = opt_cls(parameters, **self.optimizer_kwargs)\n        assert isinstance(optimizer, torch.optim.Optimizer)\n\n    # instantiate lr scheduler\n    if self._lr_scheduler_name_or_cls is None:\n        return optimizer\n    else:\n        log.info(f\"Instantiating LR scheduler <{self._lr_scheduler_name_or_cls}>\")\n        if isinstance(self._lr_scheduler_name_or_cls, str):\n            scheduler = create_scheduler(\n                optimizer, self._lr_scheduler_name_or_cls, **self.lr_scheduler_kwargs\n            )\n        elif isinstance(self._lr_scheduler_name_or_cls, partial):\n            scheduler = self._lr_scheduler_name_or_cls(\n                optimizer, **self.lr_scheduler_kwargs\n            )\n        else:  # User-defined scheduler\n            scheduler_cls = self._lr_scheduler_name_or_cls\n            scheduler = scheduler_cls(optimizer, **self.lr_scheduler_kwargs)\n            assert isinstance(scheduler, torch.optim.lr_scheduler.LRScheduler)\n        return [optimizer], {\n            \"scheduler\": scheduler,\n            \"interval\": self.lr_scheduler_interval,\n            \"monitor\": self.lr_scheduler_monitor,\n        }\n
"},{"location":"docs/content/api/rl/base/#models.rl.common.base.RL4COLitModule.log_metrics","title":"log_metrics","text":"
log_metrics(\n    metric_dict: dict,\n    phase: str,\n    dataloader_idx: Union[int, None] = None,\n)\n

Log metrics to logger and progress bar

Source code in rl4co/models/rl/common/base.py
def log_metrics(\n    self, metric_dict: dict, phase: str, dataloader_idx: Union[int, None] = None\n):\n    \"\"\"Log metrics to logger and progress bar\"\"\"\n    metrics = getattr(self, f\"{phase}_metrics\")\n    dataloader_name = \"\"\n    if dataloader_idx is not None and self.dataloader_names is not None:\n        dataloader_name = \"/\" + self.dataloader_names[dataloader_idx]\n    metrics = {\n        f\"{phase}/{k}{dataloader_name}\": v.mean()\n        if isinstance(v, torch.Tensor)\n        else v\n        for k, v in metric_dict.items()\n        if k in metrics\n    }\n    log_on_step = self.log_on_step if phase == \"train\" else False\n    on_epoch = False if phase == \"train\" else True\n    self.log_dict(\n        metrics,\n        on_step=log_on_step,\n        on_epoch=on_epoch,\n        prog_bar=True,\n        sync_dist=True,\n        add_dataloader_idx=False,  # we add manually above\n    )\n    return metrics\n
"},{"location":"docs/content/api/rl/base/#models.rl.common.base.RL4COLitModule.forward","title":"forward","text":"
forward(td, **kwargs)\n

Forward pass for the model. Simple wrapper around policy. Uses env from the module if not provided.

Source code in rl4co/models/rl/common/base.py
def forward(self, td, **kwargs):\n    \"\"\"Forward pass for the model. Simple wrapper around `policy`. Uses `env` from the module if not provided.\"\"\"\n    if kwargs.get(\"env\", None) is None:\n        env = self.env\n    else:\n        log.info(\"Using env from kwargs\")\n        env = kwargs.pop(\"env\")\n    return self.policy(td, env, **kwargs)\n
"},{"location":"docs/content/api/rl/base/#models.rl.common.base.RL4COLitModule.shared_step","title":"shared_step","text":"
shared_step(\n    batch: Any, batch_idx: int, phase: str, **kwargs\n)\n

Shared step between train/val/test. To be implemented in subclass

Source code in rl4co/models/rl/common/base.py
def shared_step(self, batch: Any, batch_idx: int, phase: str, **kwargs):\n    \"\"\"Shared step between train/val/test. To be implemented in subclass\"\"\"\n    raise NotImplementedError(\"Shared step is required to implemented in subclass\")\n
"},{"location":"docs/content/api/rl/base/#models.rl.common.base.RL4COLitModule.on_train_epoch_end","title":"on_train_epoch_end","text":"
on_train_epoch_end()\n

Called at the end of the training epoch. This can be used for instance to update the train dataset with new data (which is the case in RL).

Source code in rl4co/models/rl/common/base.py
def on_train_epoch_end(self):\n    \"\"\"Called at the end of the training epoch. This can be used for instance to update the train dataset\n    with new data (which is the case in RL).\n    \"\"\"\n    # Only update if not in the first epoch\n    # If last epoch, we don't need to update since we will not use the dataset anymore\n    if self.current_epoch < self.trainer.max_epochs - 1:\n        log.info(\"Generating training dataset for next epoch...\")\n        train_dataset = self.env.dataset(self.data_cfg[\"train_data_size\"], \"train\")\n        self.train_dataset = self.wrap_dataset(train_dataset)\n
"},{"location":"docs/content/api/rl/base/#models.rl.common.base.RL4COLitModule.wrap_dataset","title":"wrap_dataset","text":"
wrap_dataset(dataset)\n

Wrap dataset with policy-specific wrapper. This is useful i.e. in REINFORCE where we need to collect the greedy rollout baseline outputs.

Source code in rl4co/models/rl/common/base.py
def wrap_dataset(self, dataset):\n    \"\"\"Wrap dataset with policy-specific wrapper. This is useful i.e. in REINFORCE where we need to\n    collect the greedy rollout baseline outputs.\n    \"\"\"\n    return dataset\n
"},{"location":"docs/content/api/rl/base/#transductive-learning","title":"Transductive Learning","text":"

Transductive models are learning algorithms that optimize on a specific instance. They improve solutions by updating policy parameters \\(\\theta\\), which means that we are running optimization (backprop) at test time. Transductive learning can be performed with different policies: for example EAS updates (a part of) AR policies parameters to obtain better solutions, but I guess there are ways (or papers out there I don't know of) that optimize at test time.

Tip

You may refer to the definition of inductive vs transductive RL . In inductive RL, we train to generalize to new instances. In transductive RL we train (or finetune) to solve only specific ones.

"},{"location":"docs/content/api/rl/base/#models.common.transductive.base.TransductiveModel","title":"TransductiveModel","text":"
TransductiveModel(\n    env,\n    policy,\n    dataset: Union[Dataset, str],\n    batch_size: int = 1,\n    max_iters: int = 100,\n    max_runtime: Optional[int] = 86400,\n    save_path: Optional[str] = None,\n    **kwargs\n)\n

Bases: RL4COLitModule

Base class for transductive algorithms (i.e. that optimize policy parameters for specific instances, see https://en.wikipedia.org/wiki/Transduction_(machine_learning)). Transductive algorithms are used online to find better solutions for a given dataset, i.e. given a policy, improve (a part of) its parameters such that the policy performs better on the given dataset.

Note

By default, we use manual optimization to handle the search.

Parameters:

  • env \u2013

    RL4CO environment

  • policy \u2013

    policy network

  • dataset (Union[Dataset, str]) \u2013

    dataset to use for training

  • batch_size (int, default: 1 ) \u2013

    batch size

  • max_iters (int, default: 100 ) \u2013

    maximum number of iterations

  • max_runtime (Optional[int], default: 86400 ) \u2013

    maximum runtime in seconds

  • save_path (Optional[str], default: None ) \u2013

    path to save the model

  • **kwargs \u2013

    additional arguments

Source code in rl4co/models/common/transductive/base.py
def __init__(\n    self,\n    env,\n    policy,\n    dataset: Union[Dataset, str],\n    batch_size: int = 1,\n    max_iters: int = 100,\n    max_runtime: Optional[int] = 86_400,\n    save_path: Optional[str] = None,\n    **kwargs,\n):\n    self.save_hyperparameters(logger=False)\n    super().__init__(env, policy, **kwargs)\n    self.dataset = dataset\n    self.automatic_optimization = False  # we optimize manually\n
"},{"location":"docs/content/api/rl/base/#models.common.transductive.base.TransductiveModel.setup","title":"setup","text":"
setup(stage='fit')\n

Setup the dataset and attributes. The RL4COLitModulebase class automatically loads the data.

Source code in rl4co/models/common/transductive/base.py
def setup(self, stage=\"fit\"):\n    \"\"\"Setup the dataset and attributes.\n    The RL4COLitModulebase class automatically loads the data.\n    \"\"\"\n    if isinstance(self.dataset, str):\n        # load from file\n        self.dataset = self.env.dataset(filename=self.dataset)\n\n    # Set all datasets and batch size as the same\n    for split in [\"train\", \"val\", \"test\"]:\n        setattr(self, f\"{split}_dataset\", self.dataset)\n        setattr(self, f\"{split}_batch_size\", self.hparams.batch_size)\n\n    # Setup loggers\n    self.setup_loggers()\n
"},{"location":"docs/content/api/rl/base/#models.common.transductive.base.TransductiveModel.on_train_batch_start","title":"on_train_batch_start","text":"
on_train_batch_start(batch: Any, batch_idx: int)\n

Called before training (i.e. search) for a new batch begins. This can be used to perform changes to the model or optimizer at the start of each batch.

Source code in rl4co/models/common/transductive/base.py
def on_train_batch_start(self, batch: Any, batch_idx: int):\n    \"\"\"Called before training (i.e. search) for a new batch begins.\n    This can be used to perform changes to the model or optimizer at the start of each batch.\n    \"\"\"\n    pass  # Implement in subclass\n
"},{"location":"docs/content/api/rl/base/#models.common.transductive.base.TransductiveModel.training_step","title":"training_step abstractmethod","text":"
training_step(batch, batch_idx)\n

Main search loop. We use the training step to effectively adapt to a batch of instances.

Source code in rl4co/models/common/transductive/base.py
@abc.abstractmethod\ndef training_step(self, batch, batch_idx):\n    \"\"\"Main search loop. We use the training step to effectively adapt to a `batch` of instances.\"\"\"\n    raise NotImplementedError(\"Implement in subclass\")\n
"},{"location":"docs/content/api/rl/base/#models.common.transductive.base.TransductiveModel.on_train_batch_end","title":"on_train_batch_end","text":"
on_train_batch_end(\n    outputs: STEP_OUTPUT, batch: Any, batch_idx: int\n) -> None\n

Called when the train batch ends. This can be used for instance for logging or clearing cache.

Source code in rl4co/models/common/transductive/base.py
def on_train_batch_end(\n    self, outputs: STEP_OUTPUT, batch: Any, batch_idx: int\n) -> None:\n    \"\"\"Called when the train batch ends. This can be used for\n    instance for logging or clearing cache.\n    \"\"\"\n    pass  # Implement in subclass\n
"},{"location":"docs/content/api/rl/base/#models.common.transductive.base.TransductiveModel.on_train_epoch_end","title":"on_train_epoch_end","text":"
on_train_epoch_end() -> None\n

Called when the train ends.

Source code in rl4co/models/common/transductive/base.py
def on_train_epoch_end(self) -> None:\n    \"\"\"Called when the train ends.\"\"\"\n    pass  # Implement in subclass\n
"},{"location":"docs/content/api/rl/base/#models.common.transductive.base.TransductiveModel.validation_step","title":"validation_step","text":"
validation_step(batch: Any, batch_idx: int)\n

Not used during search

Source code in rl4co/models/common/transductive/base.py
def validation_step(self, batch: Any, batch_idx: int):\n    \"\"\"Not used during search\"\"\"\n    pass\n
"},{"location":"docs/content/api/rl/base/#models.common.transductive.base.TransductiveModel.test_step","title":"test_step","text":"
test_step(batch: Any, batch_idx: int)\n

Not used during search

Source code in rl4co/models/common/transductive/base.py
def test_step(self, batch: Any, batch_idx: int):\n    \"\"\"Not used during search\"\"\"\n    pass\n
"},{"location":"docs/content/api/rl/ppo/","title":"PPO","text":""},{"location":"docs/content/api/rl/ppo/#models.rl.ppo.ppo.PPO","title":"PPO","text":"
PPO(\n    env: RL4COEnvBase,\n    policy: Module,\n    critic: CriticNetwork = None,\n    critic_kwargs: dict = {},\n    clip_range: float = 0.2,\n    ppo_epochs: int = 2,\n    mini_batch_size: Union[int, float] = 0.25,\n    vf_lambda: float = 0.5,\n    entropy_lambda: float = 0.0,\n    normalize_adv: bool = False,\n    max_grad_norm: float = 0.5,\n    metrics: dict = {\n        \"train\": [\n            \"reward\",\n            \"loss\",\n            \"surrogate_loss\",\n            \"value_loss\",\n            \"entropy\",\n        ]\n    },\n    **kwargs\n)\n

Bases: RL4COLitModule

An implementation of the Proximal Policy Optimization (PPO) algorithm (https://arxiv.org/abs/1707.06347) is presented with modifications for autoregressive decoding schemes.

In contrast to the original PPO algorithm, this implementation does not consider autoregressive decoding steps as part of the MDP transition. While many Neural Combinatorial Optimization (NCO) studies model decoding steps as transitions in a solution-construction MDP, we treat autoregressive solution construction as an algorithmic choice for tractable CO solution generation. This choice aligns with the Attention Model (AM) (https://openreview.net/forum?id=ByxBFsRqYm), which treats decoding steps as a single-step MDP in Equation 9.

Modeling autoregressive decoding steps as a single-step MDP introduces significant changes to the PPO implementation, including:

  • Generalized Advantage Estimation (GAE) (https://arxiv.org/abs/1506.02438) is not applicable since we are dealing with a single-step MDP.
  • The definition of policy entropy can differ from the commonly implemented manner.

The commonly implemented definition of policy entropy is the entropy of the policy distribution, given by:

\\[H(\\pi(x_t)) = - \\sum_{a_t \\in A_t} \\pi(a_t|x_t) \\log \\pi(a_t|x_t)\\]

where \\(x_t\\) represents the given state at step \\(t\\), \\(A_t\\) is the set of all (admisible) actions at step \\(t\\), and \\(a_t\\) is the action taken at step \\(t\\).

If we interpret autoregressive decoding steps as transition steps of an MDP, the entropy for the entire decoding process can be defined as the sum of entropies for each decoding step:

\\[H(\\pi) = \\sum_t H(\\pi(x_t))\\]

However, if we consider autoregressive decoding steps as an algorithmic choice, the entropy for the entire decoding process is defined as:

\\[H(\\pi) = - \\sum_{a \\in A} \\pi(a|x) \\log \\pi(a|x)\\]

where \\(x\\) represents the given CO problem instance, and \\(A\\) is the set of all feasible solutions.

Due to the intractability of computing the entropy of the policy distribution over all feasible solutions, we approximate it by computing the entropy over solutions generated by the policy itself. This approximation serves as a proxy for the second definition of entropy, utilizing Monte Carlo sampling.

It is worth noting that our modeling of decoding steps and the implementation of the PPO algorithm align with recent work in the Natural Language Processing (NLP) community, specifically RL with Human Feedback (RLHF) (e.g., https://github.com/lucidrains/PaLM-rlhf-pytorch).

Source code in rl4co/models/rl/ppo/ppo.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: nn.Module,\n    critic: CriticNetwork = None,\n    critic_kwargs: dict = {},\n    clip_range: float = 0.2,  # epsilon of PPO\n    ppo_epochs: int = 2,  # inner epoch, K\n    mini_batch_size: Union[int, float] = 0.25,  # 0.25,\n    vf_lambda: float = 0.5,  # lambda of Value function fitting\n    entropy_lambda: float = 0.0,  # lambda of entropy bonus\n    normalize_adv: bool = False,  # whether to normalize advantage\n    max_grad_norm: float = 0.5,  # max gradient norm\n    metrics: dict = {\n        \"train\": [\"reward\", \"loss\", \"surrogate_loss\", \"value_loss\", \"entropy\"],\n    },\n    **kwargs,\n):\n    super().__init__(env, policy, metrics=metrics, **kwargs)\n    self.automatic_optimization = False  # PPO uses custom optimization routine\n\n    if critic is None:\n        log.info(\"Creating critic network for {}\".format(env.name))\n        critic = create_critic_from_actor(policy, **critic_kwargs)\n    self.critic = critic\n\n    if isinstance(mini_batch_size, float) and (\n        mini_batch_size <= 0 or mini_batch_size > 1\n    ):\n        default_mini_batch_fraction = 0.25\n        log.warning(\n            f\"mini_batch_size must be an integer or a float in the range (0, 1], got {mini_batch_size}. Setting mini_batch_size to {default_mini_batch_fraction}.\"\n        )\n        mini_batch_size = default_mini_batch_fraction\n\n    if isinstance(mini_batch_size, int) and (mini_batch_size <= 0):\n        default_mini_batch_size = 128\n        log.warning(\n            f\"mini_batch_size must be an integer or a float in the range (0, 1], got {mini_batch_size}. Setting mini_batch_size to {default_mini_batch_size}.\"\n        )\n        mini_batch_size = default_mini_batch_size\n\n    self.ppo_cfg = {\n        \"clip_range\": clip_range,\n        \"ppo_epochs\": ppo_epochs,\n        \"mini_batch_size\": mini_batch_size,\n        \"vf_lambda\": vf_lambda,\n        \"entropy_lambda\": entropy_lambda,\n        \"normalize_adv\": normalize_adv,\n        \"max_grad_norm\": max_grad_norm,\n    }\n
"},{"location":"docs/content/api/rl/ppo/#models.rl.ppo.ppo.PPO.on_train_epoch_end","title":"on_train_epoch_end","text":"
on_train_epoch_end()\n

ToDo: Add support for other schedulers.

Source code in rl4co/models/rl/ppo/ppo.py
def on_train_epoch_end(self):\n    \"\"\"\n    ToDo: Add support for other schedulers.\n    \"\"\"\n\n    sch = self.lr_schedulers()\n\n    # If the selected scheduler is a MultiStepLR scheduler.\n    if isinstance(sch, torch.optim.lr_scheduler.MultiStepLR):\n        sch.step()\n
"},{"location":"docs/content/api/rl/reinforce/","title":"REINFORCE","text":""},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.reinforce.REINFORCE","title":"REINFORCE","text":"
REINFORCE(\n    env: RL4COEnvBase,\n    policy: Module,\n    baseline: Union[REINFORCEBaseline, str] = \"rollout\",\n    baseline_kwargs: dict = {},\n    reward_scale: str = None,\n    **kwargs\n)\n

Bases: RL4COLitModule

REINFORCE algorithm, also known as policy gradients. See superclass RL4COLitModule for more details.

Parameters:

  • env (RL4COEnvBase) \u2013

    Environment to use for the algorithm

  • policy (Module) \u2013

    Policy to use for the algorithm

  • baseline (Union[REINFORCEBaseline, str], default: 'rollout' ) \u2013

    REINFORCE baseline

  • baseline_kwargs (dict, default: {} ) \u2013

    Keyword arguments for baseline. Ignored if baseline is not a string

  • **kwargs \u2013

    Keyword arguments passed to the superclass

Source code in rl4co/models/rl/reinforce/reinforce.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: nn.Module,\n    baseline: Union[REINFORCEBaseline, str] = \"rollout\",\n    baseline_kwargs: dict = {},\n    reward_scale: str = None,\n    **kwargs,\n):\n    super().__init__(env, policy, **kwargs)\n\n    self.save_hyperparameters(logger=False)\n\n    if baseline == \"critic\":\n        log.warning(\n            \"Using critic as baseline. If you want more granular support, use the A2C module instead.\"\n        )\n\n    if isinstance(baseline, str):\n        baseline = get_reinforce_baseline(baseline, **baseline_kwargs)\n    else:\n        if baseline_kwargs != {}:\n            log.warning(\"baseline_kwargs is ignored when baseline is not a string\")\n    self.baseline = baseline\n    self.advantage_scaler = RewardScaler(reward_scale)\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.reinforce.REINFORCE.calculate_loss","title":"calculate_loss","text":"
calculate_loss(\n    td: TensorDict,\n    batch: TensorDict,\n    policy_out: dict,\n    reward: Optional[Tensor] = None,\n    log_likelihood: Optional[Tensor] = None,\n)\n

Calculate loss for REINFORCE algorithm.

Parameters:

  • td (TensorDict) \u2013

    TensorDict containing the current state of the environment

  • batch (TensorDict) \u2013

    Batch of data. This is used to get the extra loss terms, e.g., REINFORCE baseline

  • policy_out (dict) \u2013

    Output of the policy network

  • reward (Optional[Tensor], default: None ) \u2013

    Reward tensor. If None, it is taken from policy_out

  • log_likelihood (Optional[Tensor], default: None ) \u2013

    Log-likelihood tensor. If None, it is taken from policy_out

Source code in rl4co/models/rl/reinforce/reinforce.py
def calculate_loss(\n    self,\n    td: TensorDict,\n    batch: TensorDict,\n    policy_out: dict,\n    reward: Optional[torch.Tensor] = None,\n    log_likelihood: Optional[torch.Tensor] = None,\n):\n    \"\"\"Calculate loss for REINFORCE algorithm.\n\n    Args:\n        td: TensorDict containing the current state of the environment\n        batch: Batch of data. This is used to get the extra loss terms, e.g., REINFORCE baseline\n        policy_out: Output of the policy network\n        reward: Reward tensor. If None, it is taken from `policy_out`\n        log_likelihood: Log-likelihood tensor. If None, it is taken from `policy_out`\n    \"\"\"\n    # Extra: this is used for additional loss terms, e.g., REINFORCE baseline\n    extra = batch.get(\"extra\", None)\n    reward = reward if reward is not None else policy_out[\"reward\"]\n    log_likelihood = (\n        log_likelihood if log_likelihood is not None else policy_out[\"log_likelihood\"]\n    )\n\n    # REINFORCE baseline\n    bl_val, bl_loss = (\n        self.baseline.eval(td, reward, self.env) if extra is None else (extra, 0)\n    )\n\n    # Main loss function\n    advantage = reward - bl_val  # advantage = reward - baseline\n    advantage = self.advantage_scaler(advantage)\n    reinforce_loss = -(advantage * log_likelihood).mean()\n    loss = reinforce_loss + bl_loss\n    policy_out.update(\n        {\n            \"loss\": loss,\n            \"reinforce_loss\": reinforce_loss,\n            \"bl_loss\": bl_loss,\n            \"bl_val\": bl_val,\n        }\n    )\n    return policy_out\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.reinforce.REINFORCE.on_train_epoch_end","title":"on_train_epoch_end","text":"
on_train_epoch_end()\n

Callback for end of training epoch: we evaluate the baseline

Source code in rl4co/models/rl/reinforce/reinforce.py
def on_train_epoch_end(self):\n    \"\"\"Callback for end of training epoch: we evaluate the baseline\"\"\"\n    self.baseline.epoch_callback(\n        self.policy,\n        env=self.env,\n        batch_size=self.val_batch_size,\n        device=get_lightning_device(self),\n        epoch=self.current_epoch,\n        dataset_size=self.data_cfg[\"val_data_size\"],\n    )\n    # Need to call super() for the dataset to be reset\n    super().on_train_epoch_end()\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.reinforce.REINFORCE.wrap_dataset","title":"wrap_dataset","text":"
wrap_dataset(dataset)\n

Wrap dataset from baseline evaluation. Used in greedy rollout baseline

Source code in rl4co/models/rl/reinforce/reinforce.py
def wrap_dataset(self, dataset):\n    \"\"\"Wrap dataset from baseline evaluation. Used in greedy rollout baseline\"\"\"\n    return self.baseline.wrap_dataset(\n        dataset,\n        self.env,\n        batch_size=self.val_batch_size,\n        device=get_lightning_device(self),\n    )\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.reinforce.REINFORCE.set_decode_type_multistart","title":"set_decode_type_multistart","text":"
set_decode_type_multistart(phase: str)\n

Set decode type to multistart for train, val and test in policy. For example, if the decode type is greedy, it will be set to multistart_greedy.

Parameters:

  • phase (str) \u2013

    Phase to set decode type for. Must be one of train, val or test.

Source code in rl4co/models/rl/reinforce/reinforce.py
def set_decode_type_multistart(self, phase: str):\n    \"\"\"Set decode type to `multistart` for train, val and test in policy.\n    For example, if the decode type is `greedy`, it will be set to `multistart_greedy`.\n\n    Args:\n        phase: Phase to set decode type for. Must be one of `train`, `val` or `test`.\n    \"\"\"\n    attribute = f\"{phase}_decode_type\"\n    attr_get = getattr(self.policy, attribute)\n    # If does not exist, log error\n    if attr_get is None:\n        log.error(f\"Decode type for {phase} is None. Cannot prepend `multistart_`.\")\n        return\n    elif \"multistart\" in attr_get:\n        return\n    else:\n        setattr(self.policy, attribute, f\"multistart_{attr_get}\")\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.reinforce.REINFORCE.load_from_checkpoint","title":"load_from_checkpoint classmethod","text":"
load_from_checkpoint(\n    checkpoint_path: Union[_PATH, IO],\n    map_location: _MAP_LOCATION_TYPE = None,\n    hparams_file: Optional[_PATH] = None,\n    strict: bool = False,\n    load_baseline: bool = True,\n    **kwargs: Any\n) -> Self\n

Load model from checkpoint/

Note

This is a modified version of load_from_checkpoint from pytorch_lightning.core.saving. It deals with matching keys for the baseline by first running setup

Source code in rl4co/models/rl/reinforce/reinforce.py
@classmethod\ndef load_from_checkpoint(\n    cls,\n    checkpoint_path: Union[_PATH, IO],\n    map_location: _MAP_LOCATION_TYPE = None,\n    hparams_file: Optional[_PATH] = None,\n    strict: bool = False,\n    load_baseline: bool = True,\n    **kwargs: Any,\n) -> Self:\n    \"\"\"Load model from checkpoint/\n\n    Note:\n        This is a modified version of `load_from_checkpoint` from `pytorch_lightning.core.saving`.\n        It deals with matching keys for the baseline by first running setup\n    \"\"\"\n\n    if strict:\n        log.warning(\"Setting strict=False for loading model from checkpoint.\")\n        strict = False\n\n    # Do not use strict\n    loaded = _load_from_checkpoint(\n        cls,\n        checkpoint_path,\n        map_location,\n        hparams_file,\n        strict,\n        **kwargs,\n    )\n\n    # Load baseline state dict\n    if load_baseline:\n        # setup baseline first\n        loaded.setup()\n        loaded.post_setup_hook()\n        # load baseline state dict\n        state_dict = torch.load(checkpoint_path, map_location=map_location)[\"state_dict\"]\n        # get only baseline parameters\n        state_dict = {k: v for k, v in state_dict.items() if \"baseline\" in k}\n        state_dict = {k.replace(\"baseline.\", \"\", 1): v for k, v in state_dict.items()}\n        loaded.baseline.load_state_dict(state_dict)\n\n    return cast(Self, loaded)\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.REINFORCEBaseline","title":"REINFORCEBaseline","text":"
REINFORCEBaseline(*args, **kw)\n

Bases: Module

Base class for REINFORCE baselines

Source code in rl4co/models/rl/reinforce/baselines.py
def __init__(self, *args, **kw):\n    super().__init__()\n    pass\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.REINFORCEBaseline.wrap_dataset","title":"wrap_dataset","text":"
wrap_dataset(dataset: Dataset, *args, **kw)\n

Wrap dataset with baseline-specific functionality

Source code in rl4co/models/rl/reinforce/baselines.py
def wrap_dataset(self, dataset: Dataset, *args, **kw):\n    \"\"\"Wrap dataset with baseline-specific functionality\"\"\"\n    return dataset\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.REINFORCEBaseline.eval","title":"eval abstractmethod","text":"
eval(\n    td: TensorDict,\n    reward: Tensor,\n    env: RL4COEnvBase = None,\n    **kwargs\n)\n

Evaluate baseline

Source code in rl4co/models/rl/reinforce/baselines.py
@abc.abstractmethod\ndef eval(\n    self, td: TensorDict, reward: torch.Tensor, env: RL4COEnvBase = None, **kwargs\n):\n    \"\"\"Evaluate baseline\"\"\"\n    raise NotImplementedError\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.REINFORCEBaseline.epoch_callback","title":"epoch_callback","text":"
epoch_callback(*args, **kw)\n

Callback at the end of each epoch For example, update baseline parameters and obtain baseline values

Source code in rl4co/models/rl/reinforce/baselines.py
def epoch_callback(self, *args, **kw):\n    \"\"\"Callback at the end of each epoch\n    For example, update baseline parameters and obtain baseline values\n    \"\"\"\n    pass\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.REINFORCEBaseline.setup","title":"setup","text":"
setup(*args, **kw)\n

To be called before training during setup phase This follow PyTorch Lightning's setup() convention

Source code in rl4co/models/rl/reinforce/baselines.py
def setup(self, *args, **kw):\n    \"\"\"To be called before training during setup phase\n    This follow PyTorch Lightning's setup() convention\n    \"\"\"\n    pass\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.NoBaseline","title":"NoBaseline","text":"
NoBaseline(*args, **kw)\n

Bases: REINFORCEBaseline

No baseline: return 0 for baseline and neg_los

Source code in rl4co/models/rl/reinforce/baselines.py
def __init__(self, *args, **kw):\n    super().__init__()\n    pass\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.NoBaseline.eval","title":"eval","text":"
eval(td, reward, env=None)\n

Evaluate baseline

Source code in rl4co/models/rl/reinforce/baselines.py
def eval(self, td, reward, env=None):\n    return 0, 0  # No baseline, no neg_los\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.SharedBaseline","title":"SharedBaseline","text":"
SharedBaseline(*args, **kw)\n

Bases: REINFORCEBaseline

Shared baseline: return mean of reward as baseline

Source code in rl4co/models/rl/reinforce/baselines.py
def __init__(self, *args, **kw):\n    super().__init__()\n    pass\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.SharedBaseline.eval","title":"eval","text":"
eval(td, reward, env=None, on_dim=1)\n

Evaluate baseline

Source code in rl4co/models/rl/reinforce/baselines.py
def eval(self, td, reward, env=None, on_dim=1):  # e.g. [batch, pomo, ...]\n    return reward.mean(dim=on_dim, keepdims=True), 0\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.ExponentialBaseline","title":"ExponentialBaseline","text":"
ExponentialBaseline(beta=0.8, **kw)\n

Bases: REINFORCEBaseline

Exponential baseline: return exponential moving average of reward as baseline

Parameters:

  • beta \u2013

    Beta value for the exponential moving average

Source code in rl4co/models/rl/reinforce/baselines.py
def __init__(self, beta=0.8, **kw):\n    super(REINFORCEBaseline, self).__init__()\n\n    self.beta = beta\n    self.v = None\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.ExponentialBaseline.eval","title":"eval","text":"
eval(td, reward, env=None)\n

Evaluate baseline

Source code in rl4co/models/rl/reinforce/baselines.py
def eval(self, td, reward, env=None):\n    if self.v is None:\n        v = reward.mean()\n    else:\n        v = self.beta * self.v + (1.0 - self.beta) * reward.mean()\n    self.v = v.detach()  # Detach since we never want to backprop\n    return self.v, 0  # No loss\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.MeanBaseline","title":"MeanBaseline","text":"
MeanBaseline(*args, **kw)\n

Bases: REINFORCEBaseline

Mean baseline: return mean of reward as baseline

Source code in rl4co/models/rl/reinforce/baselines.py
def __init__(self, *args, **kw):\n    super().__init__()\n    pass\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.WarmupBaseline","title":"WarmupBaseline","text":"
WarmupBaseline(\n    baseline, n_epochs=1, warmup_exp_beta=0.8, **kw\n)\n

Bases: REINFORCEBaseline

Warmup baseline: return convex combination of baseline and exponential baseline

Parameters:

  • baseline \u2013

    Baseline to use after warmup

  • n_epochs \u2013

    Number of epochs to warmup

  • warmup_exp_beta \u2013

    Beta value for the exponential baseline during warmup

Source code in rl4co/models/rl/reinforce/baselines.py
def __init__(self, baseline, n_epochs=1, warmup_exp_beta=0.8, **kw):\n    super(REINFORCEBaseline, self).__init__()\n\n    self.baseline = baseline\n    assert n_epochs > 0, \"n_epochs to warmup must be positive\"\n    self.warmup_baseline = ExponentialBaseline(warmup_exp_beta)\n    self.alpha = 0\n    self.n_epochs = n_epochs\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.WarmupBaseline.wrap_dataset","title":"wrap_dataset","text":"
wrap_dataset(dataset, *args, **kw)\n

Wrap dataset with baseline-specific functionality

Source code in rl4co/models/rl/reinforce/baselines.py
def wrap_dataset(self, dataset, *args, **kw):\n    if self.alpha > 0:\n        return self.baseline.wrap_dataset(dataset, *args, **kw)\n    return self.warmup_baseline.wrap_dataset(dataset, *args, **kw)\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.WarmupBaseline.setup","title":"setup","text":"
setup(*args, **kw)\n

To be called before training during setup phase This follow PyTorch Lightning's setup() convention

Source code in rl4co/models/rl/reinforce/baselines.py
def setup(self, *args, **kw):\n    self.baseline.setup(*args, **kw)\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.WarmupBaseline.eval","title":"eval","text":"
eval(td, reward, env=None)\n

Evaluate baseline

Source code in rl4co/models/rl/reinforce/baselines.py
def eval(self, td, reward, env=None):\n    if self.alpha == 1:\n        return self.baseline.eval(td, reward, env)\n    if self.alpha == 0:\n        return self.warmup_baseline.eval(td, reward, env)\n    v_b, l_b = self.baseline.eval(td, reward, env)\n    v_wb, l_wb = self.warmup_baseline.eval(td, reward, env)\n    # Return convex combination of baseline and of loss\n    return (\n        self.alpha * v_b + (1 - self.alpha) * v_wb,\n        self.alpha * l_b + (1 - self.alpha) * l_wb,\n    )\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.WarmupBaseline.epoch_callback","title":"epoch_callback","text":"
epoch_callback(*args, **kw)\n

Callback at the end of each epoch For example, update baseline parameters and obtain baseline values

Source code in rl4co/models/rl/reinforce/baselines.py
def epoch_callback(self, *args, **kw):\n    # Need to call epoch callback of inner policy (also after first epoch if we have not used it)\n    self.baseline.epoch_callback(*args, **kw)\n    if kw[\"epoch\"] < self.n_epochs:\n        self.alpha = (kw[\"epoch\"] + 1) / float(self.n_epochs)\n        log.info(\"Set warmup alpha = {}\".format(self.alpha))\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.CriticBaseline","title":"CriticBaseline","text":"
CriticBaseline(critic: CriticNetwork = None, **unused_kw)\n

Bases: REINFORCEBaseline

Critic baseline: use critic network as baseline

Parameters:

  • critic (CriticNetwork, default: None ) \u2013

    Critic network to use as baseline. If None, create a new critic network based on the environment

Source code in rl4co/models/rl/reinforce/baselines.py
def __init__(self, critic: CriticNetwork = None, **unused_kw):\n    super(CriticBaseline, self).__init__()\n    self.critic = critic\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.CriticBaseline.setup","title":"setup","text":"
setup(policy, env, **kwargs)\n

To be called before training during setup phase This follow PyTorch Lightning's setup() convention

Source code in rl4co/models/rl/reinforce/baselines.py
def setup(self, policy, env, **kwargs):\n    if self.critic is None:\n        log.info(\"Critic not found. Creating critic network for {}\".format(env.name))\n        self.critic = create_critic_from_actor(policy)\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.CriticBaseline.eval","title":"eval","text":"
eval(x, c, env=None)\n

Evaluate baseline

Source code in rl4co/models/rl/reinforce/baselines.py
def eval(self, x, c, env=None):\n    v = self.critic(x).squeeze(-1)\n    # detach v since actor should not backprop through baseline, only for loss\n    return v.detach(), F.mse_loss(v, c.detach())\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.RolloutBaseline","title":"RolloutBaseline","text":"
RolloutBaseline(bl_alpha=0.05, **kw)\n

Bases: REINFORCEBaseline

Rollout baseline: use greedy rollout as baseline

Parameters:

  • bl_alpha \u2013

    Alpha value for the baseline T-test

Source code in rl4co/models/rl/reinforce/baselines.py
def __init__(self, bl_alpha=0.05, **kw):\n    super(RolloutBaseline, self).__init__()\n    self.bl_alpha = bl_alpha\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.RolloutBaseline.setup","title":"setup","text":"
setup(*args, **kw)\n

To be called before training during setup phase This follow PyTorch Lightning's setup() convention

Source code in rl4co/models/rl/reinforce/baselines.py
def setup(self, *args, **kw):\n    self._update_policy(*args, **kw)\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.RolloutBaseline.eval","title":"eval","text":"
eval(td, reward, env)\n

Evaluate rollout baseline

Warning

This is not differentiable and should only be used for evaluation. Also, it is recommended to use the rollout method directly instead of this method.

Source code in rl4co/models/rl/reinforce/baselines.py
def eval(self, td, reward, env):\n    \"\"\"Evaluate rollout baseline\n\n    Warning:\n        This is not differentiable and should only be used for evaluation.\n        Also, it is recommended to use the `rollout` method directly instead of this method.\n    \"\"\"\n    with torch.inference_mode():\n        reward = self.policy(td, env)[\"reward\"]\n    return reward, 0\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.RolloutBaseline.epoch_callback","title":"epoch_callback","text":"
epoch_callback(\n    policy,\n    env,\n    batch_size=64,\n    device=\"cpu\",\n    epoch=None,\n    dataset_size=None,\n)\n

Challenges the current baseline with the policy and replaces the baseline policy if it is improved

Source code in rl4co/models/rl/reinforce/baselines.py
def epoch_callback(\n    self, policy, env, batch_size=64, device=\"cpu\", epoch=None, dataset_size=None\n):\n    \"\"\"Challenges the current baseline with the policy and replaces the baseline policy if it is improved\"\"\"\n    log.info(\"Evaluating candidate policy on evaluation dataset\")\n    candidate_vals = self.rollout(policy, env, batch_size, device).cpu().numpy()\n    candidate_mean = candidate_vals.mean()\n\n    log.info(\n        \"Candidate mean: {:.3f}, Baseline mean: {:.3f}\".format(\n            candidate_mean, self.mean\n        )\n    )\n    if candidate_mean - self.mean > 0:\n        # Calc p value with inverse logic (costs)\n        t, p = ttest_rel(-candidate_vals, -self.bl_vals)\n\n        p_val = p / 2  # one-sided\n        assert t < 0, \"T-statistic should be negative\"\n        log.info(\"p-value: {:.3f}\".format(p_val))\n        if p_val < self.bl_alpha:\n            log.info(\"Updating baseline\")\n            self._update_policy(policy, env, batch_size, device, dataset_size)\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.RolloutBaseline.rollout","title":"rollout","text":"
rollout(\n    policy, env, batch_size=64, device=\"cpu\", dataset=None\n)\n

Rollout the policy on the given dataset

Source code in rl4co/models/rl/reinforce/baselines.py
def rollout(self, policy, env, batch_size=64, device=\"cpu\", dataset=None):\n    \"\"\"Rollout the policy on the given dataset\"\"\"\n\n    # if dataset is None, use the dataset of the baseline\n    dataset = self.dataset if dataset is None else dataset\n\n    policy.eval()\n    policy = policy.to(device)\n\n    def eval_policy(batch):\n        with torch.inference_mode():\n            batch = env.reset(batch.to(device))\n            return policy(batch, env, decode_type=\"greedy\")[\"reward\"]\n\n    dl = DataLoader(dataset, batch_size=batch_size, collate_fn=dataset.collate_fn)\n\n    rewards = torch.cat([eval_policy(batch) for batch in dl], 0)\n    return rewards\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.RolloutBaseline.wrap_dataset","title":"wrap_dataset","text":"
wrap_dataset(\n    dataset, env, batch_size=64, device=\"cpu\", **kw\n)\n

Wrap the dataset in a baseline dataset

Note

This is an alternative to eval that does not require the policy to be passed at every call but just once. Values are added to the dataset. This also allows for larger batch sizes since we evauate the policy without gradients.

Source code in rl4co/models/rl/reinforce/baselines.py
def wrap_dataset(self, dataset, env, batch_size=64, device=\"cpu\", **kw):\n    \"\"\"Wrap the dataset in a baseline dataset\n\n    Note:\n        This is an alternative to `eval` that does not require the policy to be passed\n        at every call but just once. Values are added to the dataset. This also allows for\n        larger batch sizes since we evauate the policy without gradients.\n    \"\"\"\n    rewards = (\n        self.rollout(self.policy, env, batch_size, device, dataset=dataset)\n        .detach()\n        .cpu()\n    )\n    return dataset.add_key(\"extra\", rewards)\n
"},{"location":"docs/content/api/rl/reinforce/#models.rl.reinforce.baselines.get_reinforce_baseline","title":"get_reinforce_baseline","text":"
get_reinforce_baseline(name, **kw)\n

Get a REINFORCE baseline by name The rollout baseline default to warmup baseline with one epoch of exponential baseline and the greedy rollout

Source code in rl4co/models/rl/reinforce/baselines.py
def get_reinforce_baseline(name, **kw):\n    \"\"\"Get a REINFORCE baseline by name\n    The rollout baseline default to warmup baseline with one epoch of\n    exponential baseline and the greedy rollout\n    \"\"\"\n    if name == \"warmup\":\n        inner_baseline = kw.get(\"baseline\", \"rollout\")\n        if not isinstance(inner_baseline, REINFORCEBaseline):\n            inner_baseline = get_reinforce_baseline(inner_baseline, **kw)\n        return WarmupBaseline(inner_baseline, **kw)\n    elif name == \"rollout\":\n        warmup_epochs = kw.get(\"n_epochs\", 1)\n        warmup_exp_beta = kw.get(\"exp_beta\", 0.8)\n        bl_alpha = kw.get(\"bl_alpha\", 0.05)\n        return WarmupBaseline(\n            RolloutBaseline(bl_alpha=bl_alpha), warmup_epochs, warmup_exp_beta\n        )\n\n    if name is None:\n        name = \"no\"  # default to no baseline\n    baseline_cls = REINFORCE_BASELINES_REGISTRY.get(name, None)\n    if baseline_cls is None:\n        raise ValueError(\n            f\"Unknown baseline {baseline_cls}. Available baselines: {REINFORCE_BASELINES_REGISTRY.keys()}\"\n        )\n    return baseline_cls(**kw)\n
"},{"location":"docs/content/api/zoo/constructive_ar/","title":"Constructive Autoregressive Methods","text":""},{"location":"docs/content/api/zoo/constructive_ar/#attention-model-am","title":"Attention Model (AM)","text":""},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.am.model.AttentionModel","title":"AttentionModel","text":"
AttentionModel(\n    env: RL4COEnvBase,\n    policy: AttentionModelPolicy = None,\n    baseline: Union[REINFORCEBaseline, str] = \"rollout\",\n    policy_kwargs={},\n    baseline_kwargs={},\n    **kwargs\n)\n

Bases: REINFORCE

Attention Model based on REINFORCE: https://arxiv.org/abs/1803.08475. Check :class:REINFORCE and :class:rl4co.models.RL4COLitModule for more details such as additional parameters including batch size.

Parameters:

  • env (RL4COEnvBase) \u2013

    Environment to use for the algorithm

  • policy (AttentionModelPolicy, default: None ) \u2013

    Policy to use for the algorithm

  • baseline (Union[REINFORCEBaseline, str], default: 'rollout' ) \u2013

    REINFORCE baseline. Defaults to rollout (1 epoch of exponential, then greedy rollout baseline)

  • policy_kwargs \u2013

    Keyword arguments for policy

  • baseline_kwargs \u2013

    Keyword arguments for baseline

  • **kwargs \u2013

    Keyword arguments passed to the superclass

Source code in rl4co/models/zoo/am/model.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: AttentionModelPolicy = None,\n    baseline: Union[REINFORCEBaseline, str] = \"rollout\",\n    policy_kwargs={},\n    baseline_kwargs={},\n    **kwargs,\n):\n    if policy is None:\n        policy = AttentionModelPolicy(env_name=env.name, **policy_kwargs)\n\n    super().__init__(env, policy, baseline, baseline_kwargs, **kwargs)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.am.policy.AttentionModelPolicy","title":"AttentionModelPolicy","text":"
AttentionModelPolicy(\n    encoder: Module = None,\n    decoder: Module = None,\n    embed_dim: int = 128,\n    num_encoder_layers: int = 3,\n    num_heads: int = 8,\n    normalization: str = \"batch\",\n    feedforward_hidden: int = 512,\n    env_name: str = \"tsp\",\n    encoder_network: Module = None,\n    init_embedding: Module = None,\n    context_embedding: Module = None,\n    dynamic_embedding: Module = None,\n    use_graph_context: bool = True,\n    linear_bias_decoder: bool = False,\n    sdpa_fn: Callable = None,\n    sdpa_fn_encoder: Callable = None,\n    sdpa_fn_decoder: Callable = None,\n    mask_inner: bool = True,\n    out_bias_pointer_attn: bool = False,\n    check_nan: bool = True,\n    temperature: float = 1.0,\n    tanh_clipping: float = 10.0,\n    mask_logits: bool = True,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"greedy\",\n    test_decode_type: str = \"greedy\",\n    moe_kwargs: dict = {\"encoder\": None, \"decoder\": None},\n    **unused_kwargs\n)\n

Bases: AutoregressivePolicy

Attention Model Policy based on Kool et al. (2019): https://arxiv.org/abs/1803.08475. This model first encodes the input graph using a Graph Attention Network (GAT) (:class:AttentionModelEncoder) and then decodes the solution using a pointer network (:class:AttentionModelDecoder). Cache is used to store the embeddings of the nodes to be used by the decoder to save computation. See :class:rl4co.models.common.constructive.autoregressive.policy.AutoregressivePolicy for more details on the inference process.

Parameters:

  • encoder (Module, default: None ) \u2013

    Encoder module, defaults to :class:AttentionModelEncoder

  • decoder (Module, default: None ) \u2013

    Decoder module, defaults to :class:AttentionModelDecoder

  • embed_dim (int, default: 128 ) \u2013

    Dimension of the node embeddings

  • num_encoder_layers (int, default: 3 ) \u2013

    Number of layers in the encoder

  • num_heads (int, default: 8 ) \u2013

    Number of heads in the attention layers

  • normalization (str, default: 'batch' ) \u2013

    Normalization type in the attention layers

  • feedforward_hidden (int, default: 512 ) \u2013

    Dimension of the hidden layer in the feedforward network

  • env_name (str, default: 'tsp' ) \u2013

    Name of the environment used to initialize embeddings

  • encoder_network (Module, default: None ) \u2013

    Network to use for the encoder

  • init_embedding (Module, default: None ) \u2013

    Module to use for the initialization of the embeddings

  • context_embedding (Module, default: None ) \u2013

    Module to use for the context embedding

  • dynamic_embedding (Module, default: None ) \u2013

    Module to use for the dynamic embedding

  • use_graph_context (bool, default: True ) \u2013

    Whether to use the graph context

  • linear_bias_decoder (bool, default: False ) \u2013

    Whether to use a bias in the linear layer of the decoder

  • sdpa_fn_encoder (Callable, default: None ) \u2013

    Function to use for the scaled dot product attention in the encoder

  • sdpa_fn_decoder (Callable, default: None ) \u2013

    Function to use for the scaled dot product attention in the decoder

  • sdpa_fn (Callable, default: None ) \u2013

    (deprecated) Function to use for the scaled dot product attention

  • mask_inner (bool, default: True ) \u2013

    Whether to mask the inner product

  • out_bias_pointer_attn (bool, default: False ) \u2013

    Whether to use a bias in the pointer attention

  • check_nan (bool, default: True ) \u2013

    Whether to check for nan values during decoding

  • temperature (float, default: 1.0 ) \u2013

    Temperature for the softmax

  • tanh_clipping (float, default: 10.0 ) \u2013

    Tanh clipping value (see Bello et al., 2016)

  • mask_logits (bool, default: True ) \u2013

    Whether to mask the logits during decoding

  • train_decode_type (str, default: 'sampling' ) \u2013

    Type of decoding to use during training

  • val_decode_type (str, default: 'greedy' ) \u2013

    Type of decoding to use during validation

  • test_decode_type (str, default: 'greedy' ) \u2013

    Type of decoding to use during testing

  • moe_kwargs (dict, default: {'encoder': None, 'decoder': None} ) \u2013

    Keyword arguments for MoE, e.g., {\"encoder\": {\"hidden_act\": \"ReLU\", \"num_experts\": 4, \"k\": 2, \"noisy_gating\": True}, \"decoder\": {\"light_version\": True, ...}}

Source code in rl4co/models/zoo/am/policy.py
def __init__(\n    self,\n    encoder: nn.Module = None,\n    decoder: nn.Module = None,\n    embed_dim: int = 128,\n    num_encoder_layers: int = 3,\n    num_heads: int = 8,\n    normalization: str = \"batch\",\n    feedforward_hidden: int = 512,\n    env_name: str = \"tsp\",\n    encoder_network: nn.Module = None,\n    init_embedding: nn.Module = None,\n    context_embedding: nn.Module = None,\n    dynamic_embedding: nn.Module = None,\n    use_graph_context: bool = True,\n    linear_bias_decoder: bool = False,\n    sdpa_fn: Callable = None,\n    sdpa_fn_encoder: Callable = None,\n    sdpa_fn_decoder: Callable = None,\n    mask_inner: bool = True,\n    out_bias_pointer_attn: bool = False,\n    check_nan: bool = True,\n    temperature: float = 1.0,\n    tanh_clipping: float = 10.0,\n    mask_logits: bool = True,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"greedy\",\n    test_decode_type: str = \"greedy\",\n    moe_kwargs: dict = {\"encoder\": None, \"decoder\": None},\n    **unused_kwargs,\n):\n    if encoder is None:\n        encoder = AttentionModelEncoder(\n            embed_dim=embed_dim,\n            num_heads=num_heads,\n            num_layers=num_encoder_layers,\n            env_name=env_name,\n            normalization=normalization,\n            feedforward_hidden=feedforward_hidden,\n            net=encoder_network,\n            init_embedding=init_embedding,\n            sdpa_fn=sdpa_fn if sdpa_fn_encoder is None else sdpa_fn_encoder,\n            moe_kwargs=moe_kwargs[\"encoder\"],\n        )\n\n    if decoder is None:\n        decoder = AttentionModelDecoder(\n            embed_dim=embed_dim,\n            num_heads=num_heads,\n            env_name=env_name,\n            context_embedding=context_embedding,\n            dynamic_embedding=dynamic_embedding,\n            sdpa_fn=sdpa_fn if sdpa_fn_decoder is None else sdpa_fn_decoder,\n            mask_inner=mask_inner,\n            out_bias_pointer_attn=out_bias_pointer_attn,\n            linear_bias=linear_bias_decoder,\n            use_graph_context=use_graph_context,\n            check_nan=check_nan,\n            moe_kwargs=moe_kwargs[\"decoder\"],\n        )\n\n    super(AttentionModelPolicy, self).__init__(\n        encoder=encoder,\n        decoder=decoder,\n        env_name=env_name,\n        temperature=temperature,\n        tanh_clipping=tanh_clipping,\n        mask_logits=mask_logits,\n        train_decode_type=train_decode_type,\n        val_decode_type=val_decode_type,\n        test_decode_type=test_decode_type,\n        **unused_kwargs,\n    )\n
"},{"location":"docs/content/api/zoo/constructive_ar/#attention-model-ppo-am-ppo","title":"Attention Model - PPO (AM-PPO)","text":""},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.amppo.model.AMPPO","title":"AMPPO","text":"
AMPPO(\n    env: RL4COEnvBase,\n    policy: Module = None,\n    critic: CriticNetwork = None,\n    policy_kwargs: dict = {},\n    critic_kwargs: dict = {},\n    **kwargs\n)\n

Bases: PPO

PPO Model based on Proximal Policy Optimization (PPO) with an attention model policy. We default to the attention model policy and the Attention Critic Network.

Parameters:

  • env (RL4COEnvBase) \u2013

    Environment to use for the algorithm

  • policy (Module, default: None ) \u2013

    Policy to use for the algorithm

  • critic (CriticNetwork, default: None ) \u2013

    Critic to use for the algorithm

  • policy_kwargs (dict, default: {} ) \u2013

    Keyword arguments for policy

  • critic_kwargs (dict, default: {} ) \u2013

    Keyword arguments for critic

Source code in rl4co/models/zoo/amppo/model.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: nn.Module = None,\n    critic: CriticNetwork = None,\n    policy_kwargs: dict = {},\n    critic_kwargs: dict = {},\n    **kwargs,\n):\n    if policy is None:\n        policy = AttentionModelPolicy(env_name=env.name, **policy_kwargs)\n\n    if critic is None:\n        log.info(\"Creating critic network for {}\".format(env.name))\n        # we reuse the parameters of the model\n        encoder = getattr(policy, \"encoder\", None)\n        if encoder is None:\n            raise ValueError(\"Critic network requires an encoder\")\n        critic = CriticNetwork(\n            copy.deepcopy(encoder).to(next(encoder.parameters()).device),\n            **critic_kwargs,\n        )\n\n    super().__init__(env, policy, critic, **kwargs)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#heterogeneous-attention-model-ham","title":"Heterogeneous Attention Model (HAM)","text":""},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.ham.model.HeterogeneousAttentionModel","title":"HeterogeneousAttentionModel","text":"
HeterogeneousAttentionModel(\n    env: RL4COEnvBase,\n    policy: HeterogeneousAttentionModelPolicy = None,\n    baseline: Union[REINFORCEBaseline, str] = \"rollout\",\n    policy_kwargs={},\n    baseline_kwargs={},\n    **kwargs\n)\n

Bases: REINFORCE

Heterogenous Attention Model for solving the Pickup and Delivery Problem based on REINFORCE: https://arxiv.org/abs/2110.02634.

Parameters:

  • env (RL4COEnvBase) \u2013

    Environment to use for the algorithm

  • policy (HeterogeneousAttentionModelPolicy, default: None ) \u2013

    Policy to use for the algorithm

  • baseline (Union[REINFORCEBaseline, str], default: 'rollout' ) \u2013

    REINFORCE baseline. Defaults to rollout (1 epoch of exponential, then greedy rollout baseline)

  • policy_kwargs \u2013

    Keyword arguments for policy

  • baseline_kwargs \u2013

    Keyword arguments for baseline

  • **kwargs \u2013

    Keyword arguments passed to the superclass

Source code in rl4co/models/zoo/ham/model.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: HeterogeneousAttentionModelPolicy = None,\n    baseline: Union[REINFORCEBaseline, str] = \"rollout\",\n    policy_kwargs={},\n    baseline_kwargs={},\n    **kwargs,\n):\n    assert (\n        env.name == \"pdp\"\n    ), \"HeterogeneousAttentionModel only works for PDP (Pickup and Delivery Problem)\"\n    if policy is None:\n        policy = HeterogeneousAttentionModelPolicy(env_name=env.name, **policy_kwargs)\n\n    super().__init__(env, policy, baseline, baseline_kwargs, **kwargs)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.ham.policy.HeterogeneousAttentionModelPolicy","title":"HeterogeneousAttentionModelPolicy","text":"
HeterogeneousAttentionModelPolicy(\n    encoder: Module = None,\n    env_name: str = \"pdp\",\n    init_embedding: Module = None,\n    embed_dim: int = 128,\n    num_encoder_layers: int = 3,\n    num_heads: int = 8,\n    normalization: str = \"batch\",\n    feedforward_hidden: int = 512,\n    sdpa_fn: Optional[Callable] = None,\n    **kwargs\n)\n

Bases: AttentionModelPolicy

Heterogeneous Attention Model Policy based on https://ieeexplore.ieee.org/document/9352489. We re-declare the most important arguments here for convenience as in the paper. See :class:rl4co.models.zoo.am.AttentionModelPolicy for more details.

Parameters:

  • encoder (Module, default: None ) \u2013

    Encoder module. Can be passed by sub-classes

  • env_name (str, default: 'pdp' ) \u2013

    Name of the environment used to initialize embeddings

  • init_embedding (Module, default: None ) \u2013

    Model to use for the initial embedding. If None, use the default embedding for the environment

  • embed_dim (int, default: 128 ) \u2013

    Dimension of the embeddings

  • num_encoder_layers (int, default: 3 ) \u2013

    Number of layers in the encoder

  • num_heads (int, default: 8 ) \u2013

    Number of heads for the attention in encoder

  • normalization (str, default: 'batch' ) \u2013

    Normalization to use for the attention layers

  • feedforward_hidden (int, default: 512 ) \u2013

    Dimension of the hidden layer in the feedforward network

  • sdpa_fn (Optional[Callable], default: None ) \u2013

    Function to use for the scaled dot product attention

  • **kwargs \u2013

    keyword arguments passed to the :class:rl4co.models.zoo.am.AttentionModelPolicy

Source code in rl4co/models/zoo/ham/policy.py
def __init__(\n    self,\n    encoder: nn.Module = None,\n    env_name: str = \"pdp\",\n    init_embedding: nn.Module = None,\n    embed_dim: int = 128,\n    num_encoder_layers: int = 3,\n    num_heads: int = 8,\n    normalization: str = \"batch\",\n    feedforward_hidden: int = 512,\n    sdpa_fn: Optional[Callable] = None,\n    **kwargs,\n):\n    if encoder is None:\n        encoder = GraphHeterogeneousAttentionEncoder(\n            init_embedding=init_embedding,\n            num_heads=num_heads,\n            embed_dim=embed_dim,\n            num_encoder_layers=num_encoder_layers,\n            env_name=env_name,\n            normalization=normalization,\n            feedforward_hidden=feedforward_hidden,\n            sdpa_fn=sdpa_fn,\n        )\n    else:\n        encoder = encoder\n\n    super(HeterogeneousAttentionModelPolicy, self).__init__(\n        env_name=env_name,\n        encoder=encoder,\n        embed_dim=embed_dim,\n        num_encoder_layers=num_encoder_layers,\n        num_heads=num_heads,\n        normalization=normalization,\n        **kwargs,\n    )\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.ham.attention.HeterogenousMHA","title":"HeterogenousMHA","text":"
HeterogenousMHA(\n    num_heads,\n    input_dim,\n    embed_dim=None,\n    val_dim=None,\n    key_dim=None,\n)\n

Bases: Module

Source code in rl4co/models/zoo/ham/attention.py
def __init__(self, num_heads, input_dim, embed_dim=None, val_dim=None, key_dim=None):\n    \"\"\"\n    Heterogenous Multi-Head Attention for Pickup and Delivery problems\n    https://arxiv.org/abs/2110.02634\n    \"\"\"\n    super(HeterogenousMHA, self).__init__()\n\n    if val_dim is None:\n        assert embed_dim is not None, \"Provide either embed_dim or val_dim\"\n        val_dim = embed_dim // num_heads\n    if key_dim is None:\n        key_dim = val_dim\n\n    self.num_heads = num_heads\n    self.input_dim = input_dim\n    self.embed_dim = embed_dim\n    self.val_dim = val_dim\n    self.key_dim = key_dim\n\n    self.norm_factor = 1 / math.sqrt(key_dim)  # See Attention is all you need\n\n    self.W_query = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim))\n    self.W_key = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim))\n    self.W_val = nn.Parameter(torch.Tensor(num_heads, input_dim, val_dim))\n\n    # Pickup weights\n    self.W1_query = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim))\n    self.W2_query = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim))\n    self.W3_query = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim))\n\n    # Delivery weights\n    self.W4_query = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim))\n    self.W5_query = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim))\n    self.W6_query = nn.Parameter(torch.Tensor(num_heads, input_dim, key_dim))\n\n    if embed_dim is not None:\n        self.W_out = nn.Parameter(torch.Tensor(num_heads, key_dim, embed_dim))\n\n    self.init_parameters()\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.ham.attention.HeterogenousMHA.forward","title":"forward","text":"
forward(q, h=None, mask=None)\n

Parameters:

  • q \u2013

    queries (batch_size, n_query, input_dim)

  • h \u2013

    data (batch_size, graph_size, input_dim)

  • mask \u2013

    mask (batch_size, n_query, graph_size) or viewable as that (i.e. can be 2 dim if n_query == 1)

Mask should contain 1 if attention is not possible (i.e. mask is negative adjacency)

Source code in rl4co/models/zoo/ham/attention.py
def forward(self, q, h=None, mask=None):\n    \"\"\"\n    Args:\n        q: queries (batch_size, n_query, input_dim)\n        h: data (batch_size, graph_size, input_dim)\n        mask: mask (batch_size, n_query, graph_size) or viewable as that (i.e. can be 2 dim if n_query == 1)\n\n    Mask should contain 1 if attention is not possible (i.e. mask is negative adjacency)\n    \"\"\"\n    if h is None:\n        h = q  # compute self-attention\n\n    # h should be (batch_size, graph_size, input_dim)\n    batch_size, graph_size, input_dim = h.size()\n\n    # Check if graph size is odd number\n    assert (\n        graph_size % 2 == 1\n    ), \"Graph size should have odd number of nodes due to pickup-delivery problem  \\\n                                 (n/2 pickup, n/2 delivery, 1 depot)\"\n\n    n_query = q.size(1)\n    assert q.size(0) == batch_size\n    assert q.size(2) == input_dim\n    assert input_dim == self.input_dim, \"Wrong embedding dimension of input\"\n\n    hflat = h.contiguous().view(-1, input_dim)  # [batch_size * graph_size, embed_dim]\n    qflat = q.contiguous().view(-1, input_dim)  # [batch_size * n_query, embed_dim]\n\n    # last dimension can be different for keys and values\n    shp = (self.num_heads, batch_size, graph_size, -1)\n    shp_q = (self.num_heads, batch_size, n_query, -1)\n\n    # pickup -> its delivery attention\n    n_pick = (graph_size - 1) // 2\n    shp_delivery = (self.num_heads, batch_size, n_pick, -1)\n    shp_q_pick = (self.num_heads, batch_size, n_pick, -1)\n\n    # pickup -> all pickups attention\n    shp_allpick = (self.num_heads, batch_size, n_pick, -1)\n    shp_q_allpick = (self.num_heads, batch_size, n_pick, -1)\n\n    # pickup -> all pickups attention\n    shp_alldelivery = (self.num_heads, batch_size, n_pick, -1)\n    shp_q_alldelivery = (self.num_heads, batch_size, n_pick, -1)\n\n    # Calculate queries, (num_heads, n_query, graph_size, key/val_size)\n    Q = torch.matmul(qflat, self.W_query).view(shp_q)\n    # Calculate keys and values (num_heads, batch_size, graph_size, key/val_size)\n    K = torch.matmul(hflat, self.W_key).view(shp)\n    V = torch.matmul(hflat, self.W_val).view(shp)\n\n    # pickup -> its delivery\n    pick_flat = (\n        h[:, 1 : n_pick + 1, :].contiguous().view(-1, input_dim)\n    )  # [batch_size * n_pick, embed_dim]\n    delivery_flat = (\n        h[:, n_pick + 1 :, :].contiguous().view(-1, input_dim)\n    )  # [batch_size * n_pick, embed_dim]\n\n    # pickup -> its delivery attention\n    Q_pick = torch.matmul(pick_flat, self.W1_query).view(\n        shp_q_pick\n    )  # (self.num_heads, batch_size, n_pick, key_size)\n    K_delivery = torch.matmul(delivery_flat, self.W_key).view(\n        shp_delivery\n    )  # (self.num_heads, batch_size, n_pick, -1)\n    V_delivery = torch.matmul(delivery_flat, self.W_val).view(\n        shp_delivery\n    )  # (num_heads, batch_size, n_pick, key/val_size)\n\n    # pickup -> all pickups attention\n    Q_pick_allpick = torch.matmul(pick_flat, self.W2_query).view(\n        shp_q_allpick\n    )  # (self.num_heads, batch_size, n_pick, -1)\n    K_allpick = torch.matmul(pick_flat, self.W_key).view(\n        shp_allpick\n    )  # [self.num_heads, batch_size, n_pick, key_size]\n    V_allpick = torch.matmul(pick_flat, self.W_val).view(\n        shp_allpick\n    )  # [self.num_heads, batch_size, n_pick, key_size]\n\n    # pickup -> all delivery\n    Q_pick_alldelivery = torch.matmul(pick_flat, self.W3_query).view(\n        shp_q_alldelivery\n    )  # (self.num_heads, batch_size, n_pick, key_size)\n    K_alldelivery = torch.matmul(delivery_flat, self.W_key).view(\n        shp_alldelivery\n    )  # (self.num_heads, batch_size, n_pick, -1)\n    V_alldelivery = torch.matmul(delivery_flat, self.W_val).view(\n        shp_alldelivery\n    )  # (num_heads, batch_size, n_pick, key/val_size)\n\n    # pickup -> its delivery\n    V_additional_delivery = torch.cat(\n        [  # [num_heads, batch_size, graph_size, key_size]\n            torch.zeros(\n                self.num_heads,\n                batch_size,\n                1,\n                self.input_dim // self.num_heads,\n                dtype=V.dtype,\n                device=V.device,\n            ),\n            V_delivery,  # [num_heads, batch_size, n_pick, key/val_size]\n            torch.zeros(\n                self.num_heads,\n                batch_size,\n                n_pick,\n                self.input_dim // self.num_heads,\n                dtype=V.dtype,\n                device=V.device,\n            ),\n        ],\n        2,\n    )\n\n    # delivery -> its pickup attention\n    Q_delivery = torch.matmul(delivery_flat, self.W4_query).view(\n        shp_delivery\n    )  # (self.num_heads, batch_size, n_pick, key_size)\n    K_pick = torch.matmul(pick_flat, self.W_key).view(\n        shp_q_pick\n    )  # (self.num_heads, batch_size, n_pick, -1)\n    V_pick = torch.matmul(pick_flat, self.W_val).view(\n        shp_q_pick\n    )  # (num_heads, batch_size, n_pick, key/val_size)\n\n    # delivery -> all delivery attention\n    Q_delivery_alldelivery = torch.matmul(delivery_flat, self.W5_query).view(\n        shp_alldelivery\n    )  # (self.num_heads, batch_size, n_pick, -1)\n    K_alldelivery2 = torch.matmul(delivery_flat, self.W_key).view(\n        shp_alldelivery\n    )  # [self.num_heads, batch_size, n_pick, key_size]\n    V_alldelivery2 = torch.matmul(delivery_flat, self.W_val).view(\n        shp_alldelivery\n    )  # [self.num_heads, batch_size, n_pick, key_size]\n\n    # delivery -> all pickup\n    Q_delivery_allpickup = torch.matmul(delivery_flat, self.W6_query).view(\n        shp_alldelivery\n    )  # (self.num_heads, batch_size, n_pick, key_size)\n    K_allpickup2 = torch.matmul(pick_flat, self.W_key).view(\n        shp_q_alldelivery\n    )  # (self.num_heads, batch_size, n_pick, -1)\n    V_allpickup2 = torch.matmul(pick_flat, self.W_val).view(\n        shp_q_alldelivery\n    )  # (num_heads, batch_size, n_pick, key/val_size)\n\n    # delivery -> its pick up\n    V_additional_pick = torch.cat(\n        [  # [num_heads, batch_size, graph_size, key_size]\n            torch.zeros(\n                self.num_heads,\n                batch_size,\n                1,\n                self.input_dim // self.num_heads,\n                dtype=V.dtype,\n                device=V.device,\n            ),\n            torch.zeros(\n                self.num_heads,\n                batch_size,\n                n_pick,\n                self.input_dim // self.num_heads,\n                dtype=V.dtype,\n                device=V.device,\n            ),\n            V_pick,  # [num_heads, batch_size, n_pick, key/val_size]\n        ],\n        2,\n    )\n\n    # Calculate compatibility (num_heads, batch_size, n_query, graph_size)\n    compatibility = self.norm_factor * torch.matmul(Q, K.transpose(2, 3))\n\n    ##Pick up pair attention\n    compatibility_pick_delivery = self.norm_factor * torch.sum(\n        Q_pick * K_delivery, -1\n    )  # element_wise, [num_heads, batch_size, n_pick]\n    # [num_heads, batch_size, n_pick, n_pick]\n    compatibility_pick_allpick = self.norm_factor * torch.matmul(\n        Q_pick_allpick, K_allpick.transpose(2, 3)\n    )  # [num_heads, batch_size, n_pick, n_pick]\n    compatibility_pick_alldelivery = self.norm_factor * torch.matmul(\n        Q_pick_alldelivery, K_alldelivery.transpose(2, 3)\n    )  # [num_heads, batch_size, n_pick, n_pick]\n\n    ##Delivery\n    compatibility_delivery_pick = self.norm_factor * torch.sum(\n        Q_delivery * K_pick, -1\n    )  # element_wise, [num_heads, batch_size, n_pick]\n    compatibility_delivery_alldelivery = self.norm_factor * torch.matmul(\n        Q_delivery_alldelivery, K_alldelivery2.transpose(2, 3)\n    )  # [num_heads, batch_size, n_pick, n_pick]\n    compatibility_delivery_allpick = self.norm_factor * torch.matmul(\n        Q_delivery_allpickup, K_allpickup2.transpose(2, 3)\n    )  # [num_heads, batch_size, n_pick, n_pick]\n\n    ##Pick up->\n    # compatibility_additional?pickup????delivery????attention(size 1),1:n_pick+1??attention,depot?delivery??\n    compatibility_additional_delivery = torch.cat(\n        [  # [num_heads, batch_size, graph_size, 1]\n            float(\"-inf\")\n            * torch.ones(\n                self.num_heads,\n                batch_size,\n                1,\n                dtype=compatibility.dtype,\n                device=compatibility.device,\n            ),\n            compatibility_pick_delivery,  # [num_heads, batch_size, n_pick]\n            float(\"-inf\")\n            * torch.ones(\n                self.num_heads,\n                batch_size,\n                n_pick,\n                dtype=compatibility.dtype,\n                device=compatibility.device,\n            ),\n        ],\n        -1,\n    ).view(self.num_heads, batch_size, graph_size, 1)\n\n    compatibility_additional_allpick = torch.cat(\n        [  # [num_heads, batch_size, graph_size, n_pick]\n            float(\"-inf\")\n            * torch.ones(\n                self.num_heads,\n                batch_size,\n                1,\n                n_pick,\n                dtype=compatibility.dtype,\n                device=compatibility.device,\n            ),\n            compatibility_pick_allpick,  # [num_heads, batch_size, n_pick, n_pick]\n            float(\"-inf\")\n            * torch.ones(\n                self.num_heads,\n                batch_size,\n                n_pick,\n                n_pick,\n                dtype=compatibility.dtype,\n                device=compatibility.device,\n            ),\n        ],\n        2,\n    ).view(self.num_heads, batch_size, graph_size, n_pick)\n\n    compatibility_additional_alldelivery = torch.cat(\n        [  # [num_heads, batch_size, graph_size, n_pick]\n            float(\"-inf\")\n            * torch.ones(\n                self.num_heads,\n                batch_size,\n                1,\n                n_pick,\n                dtype=compatibility.dtype,\n                device=compatibility.device,\n            ),\n            compatibility_pick_alldelivery,  # [num_heads, batch_size, n_pick, n_pick]\n            float(\"-inf\")\n            * torch.ones(\n                self.num_heads,\n                batch_size,\n                n_pick,\n                n_pick,\n                dtype=compatibility.dtype,\n                device=compatibility.device,\n            ),\n        ],\n        2,\n    ).view(self.num_heads, batch_size, graph_size, n_pick)\n    # [num_heads, batch_size, n_query, graph_size+1+n_pick+n_pick]\n\n    # Delivery\n    compatibility_additional_pick = torch.cat(\n        [  # [num_heads, batch_size, graph_size, 1]\n            float(\"-inf\")\n            * torch.ones(\n                self.num_heads,\n                batch_size,\n                1,\n                dtype=compatibility.dtype,\n                device=compatibility.device,\n            ),\n            float(\"-inf\")\n            * torch.ones(\n                self.num_heads,\n                batch_size,\n                n_pick,\n                dtype=compatibility.dtype,\n                device=compatibility.device,\n            ),\n            compatibility_delivery_pick,  # [num_heads, batch_size, n_pick]\n        ],\n        -1,\n    ).view(self.num_heads, batch_size, graph_size, 1)\n\n    compatibility_additional_alldelivery2 = torch.cat(\n        [  # [num_heads, batch_size, graph_size, n_pick]\n            float(\"-inf\")\n            * torch.ones(\n                self.num_heads,\n                batch_size,\n                1,\n                n_pick,\n                dtype=compatibility.dtype,\n                device=compatibility.device,\n            ),\n            float(\"-inf\")\n            * torch.ones(\n                self.num_heads,\n                batch_size,\n                n_pick,\n                n_pick,\n                dtype=compatibility.dtype,\n                device=compatibility.device,\n            ),\n            compatibility_delivery_alldelivery,  # [num_heads, batch_size, n_pick, n_pick]\n        ],\n        2,\n    ).view(self.num_heads, batch_size, graph_size, n_pick)\n\n    compatibility_additional_allpick2 = torch.cat(\n        [  # [num_heads, batch_size, graph_size, n_pick]\n            float(\"-inf\")\n            * torch.ones(\n                self.num_heads,\n                batch_size,\n                1,\n                n_pick,\n                dtype=compatibility.dtype,\n                device=compatibility.device,\n            ),\n            float(\"-inf\")\n            * torch.ones(\n                self.num_heads,\n                batch_size,\n                n_pick,\n                n_pick,\n                dtype=compatibility.dtype,\n                device=compatibility.device,\n            ),\n            compatibility_delivery_allpick,  # [num_heads, batch_size, n_pick, n_pick]\n        ],\n        2,\n    ).view(self.num_heads, batch_size, graph_size, n_pick)\n\n    compatibility = torch.cat(\n        [\n            compatibility,\n            compatibility_additional_delivery,\n            compatibility_additional_allpick,\n            compatibility_additional_alldelivery,\n            compatibility_additional_pick,\n            compatibility_additional_alldelivery2,\n            compatibility_additional_allpick2,\n        ],\n        dim=-1,\n    )\n\n    # Optionally apply mask to prevent attention\n    if mask is not None:\n        mask = mask.view(1, batch_size, n_query, graph_size).expand_as(compatibility)\n        compatibility[mask] = float(\"-inf\")\n\n    attn = torch.softmax(\n        compatibility, dim=-1\n    )  # [num_heads, batch_size, n_query, graph_size+1+n_pick*2] (graph_size include depot)\n\n    # If there are nodes with no neighbours then softmax returns nan so we fix them to 0\n    if mask is not None:\n        attnc = attn.clone()\n        attnc[mask] = 0\n        attn = attnc\n\n    # heads: [num_heads, batrch_size, n_query, val_size] pick -> its delivery\n    heads = torch.matmul(\n        attn[:, :, :, :graph_size], V\n    )  # V: (self.num_heads, batch_size, graph_size, val_size)\n    heads = (\n        heads\n        + attn[:, :, :, graph_size].view(self.num_heads, batch_size, graph_size, 1)\n        * V_additional_delivery\n    )  # V_addi:[num_heads, batch_size, graph_size, key_size]\n\n    # Heads pick -> otherpick, V_allpick: # [num_heads, batch_size, n_pick, key_size]\n    heads = heads + torch.matmul(\n        attn[:, :, :, graph_size + 1 : graph_size + 1 + n_pick].view(\n            self.num_heads, batch_size, graph_size, n_pick\n        ),\n        V_allpick,\n    )\n\n    # V_alldelivery: # (num_heads, batch_size, n_pick, key/val_size)\n    heads = heads + torch.matmul(\n        attn[:, :, :, graph_size + 1 + n_pick : graph_size + 1 + 2 * n_pick].view(\n            self.num_heads, batch_size, graph_size, n_pick\n        ),\n        V_alldelivery,\n    )\n\n    # Delivery\n    heads = (\n        heads\n        + attn[:, :, :, graph_size + 1 + 2 * n_pick].view(\n            self.num_heads, batch_size, graph_size, 1\n        )\n        * V_additional_pick\n    )\n    heads = heads + torch.matmul(\n        attn[\n            :,\n            :,\n            :,\n            graph_size + 1 + 2 * n_pick + 1 : graph_size + 1 + 3 * n_pick + 1,\n        ].view(self.num_heads, batch_size, graph_size, n_pick),\n        V_alldelivery2,\n    )\n    heads = heads + torch.matmul(\n        attn[:, :, :, graph_size + 1 + 3 * n_pick + 1 :].view(\n            self.num_heads, batch_size, graph_size, n_pick\n        ),\n        V_allpickup2,\n    )\n\n    out = torch.mm(\n        heads.permute(1, 2, 0, 3)\n        .contiguous()\n        .view(-1, self.num_heads * self.val_dim),\n        self.W_out.view(-1, self.embed_dim),\n    ).view(batch_size, n_query, self.embed_dim)\n\n    return out\n
"},{"location":"docs/content/api/zoo/constructive_ar/#matrix-encoding-network-matnet","title":"Matrix Encoding Network (MatNet)","text":""},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.matnet.policy.MatNetPolicy","title":"MatNetPolicy","text":"
MatNetPolicy(\n    env_name: str = \"atsp\",\n    embed_dim: int = 256,\n    num_encoder_layers: int = 5,\n    num_heads: int = 16,\n    normalization: str = \"instance\",\n    init_embedding_kwargs: dict = {\"mode\": \"RandomOneHot\"},\n    use_graph_context: bool = False,\n    bias: bool = False,\n    **kwargs\n)\n

Bases: AutoregressivePolicy

MatNet Policy from Kwon et al., 2021. Reference: https://arxiv.org/abs/2106.11113

Warning

This implementation is under development and subject to change.

Parameters:

  • env_name (str, default: 'atsp' ) \u2013

    Name of the environment used to initialize embeddings

  • embed_dim (int, default: 256 ) \u2013

    Dimension of the node embeddings

  • num_encoder_layers (int, default: 5 ) \u2013

    Number of layers in the encoder

  • num_heads (int, default: 16 ) \u2013

    Number of heads in the attention layers

  • normalization (str, default: 'instance' ) \u2013

    Normalization type in the attention layers

  • **kwargs \u2013

    keyword arguments passed to the AutoregressivePolicy

Default paarameters are adopted from the original implementation.

Source code in rl4co/models/zoo/matnet/policy.py
def __init__(\n    self,\n    env_name: str = \"atsp\",\n    embed_dim: int = 256,\n    num_encoder_layers: int = 5,\n    num_heads: int = 16,\n    normalization: str = \"instance\",\n    init_embedding_kwargs: dict = {\"mode\": \"RandomOneHot\"},\n    use_graph_context: bool = False,\n    bias: bool = False,\n    **kwargs,\n):\n    if env_name not in [\"atsp\", \"ffsp\"]:\n        log.error(f\"env_name {env_name} is not originally implemented in MatNet\")\n\n    if env_name == \"ffsp\":\n        decoder = MatNetFFSPDecoder(\n            embed_dim=embed_dim,\n            num_heads=num_heads,\n            use_graph_context=use_graph_context,\n            out_bias=True,\n        )\n\n    else:\n        decoder = MatNetDecoder(\n            env_name=env_name,\n            embed_dim=embed_dim,\n            num_heads=num_heads,\n            use_graph_context=use_graph_context,\n        )\n\n    super(MatNetPolicy, self).__init__(\n        env_name=env_name,\n        encoder=MatNetEncoder(\n            embed_dim=embed_dim,\n            num_heads=num_heads,\n            num_layers=num_encoder_layers,\n            normalization=normalization,\n            init_embedding_kwargs=init_embedding_kwargs,\n            bias=bias,\n        ),\n        decoder=decoder,\n        embed_dim=embed_dim,\n        num_encoder_layers=num_encoder_layers,\n        num_heads=num_heads,\n        normalization=normalization,\n        **kwargs,\n    )\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.matnet.policy.MultiStageFFSPPolicy","title":"MultiStageFFSPPolicy","text":"
MultiStageFFSPPolicy(\n    stage_cnt: int,\n    embed_dim: int = 512,\n    num_heads: int = 16,\n    num_encoder_layers: int = 5,\n    use_graph_context: bool = False,\n    normalization: str = \"instance\",\n    feedforward_hidden: int = 512,\n    bias: bool = False,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"sampling\",\n    test_decode_type: str = \"sampling\",\n)\n

Bases: Module

Policy for solving the FFSP using a seperate encoder and decoder for each stage. This requires the 'while not td[\"done\"].all()'-loop to be on policy level (instead of decoder level).

Source code in rl4co/models/zoo/matnet/policy.py
def __init__(\n    self,\n    stage_cnt: int,\n    embed_dim: int = 512,\n    num_heads: int = 16,\n    num_encoder_layers: int = 5,\n    use_graph_context: bool = False,\n    normalization: str = \"instance\",\n    feedforward_hidden: int = 512,\n    bias: bool = False,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"sampling\",\n    test_decode_type: str = \"sampling\",\n):\n    super().__init__()\n    self.stage_cnt = stage_cnt\n\n    self.encoders: List[MatNetEncoder] = nn.ModuleList(\n        [\n            MatNetEncoder(\n                embed_dim=embed_dim,\n                num_heads=num_heads,\n                num_layers=num_encoder_layers,\n                normalization=normalization,\n                feedforward_hidden=feedforward_hidden,\n                bias=bias,\n                init_embedding_kwargs={\"mode\": \"RandomOneHot\"},\n            )\n            for _ in range(self.stage_cnt)\n        ]\n    )\n    self.decoders: List[MultiStageFFSPDecoder] = nn.ModuleList(\n        [\n            MultiStageFFSPDecoder(embed_dim, num_heads, use_graph_context)\n            for _ in range(self.stage_cnt)\n        ]\n    )\n\n    self.train_decode_type = train_decode_type\n    self.val_decode_type = val_decode_type\n    self.test_decode_type = test_decode_type\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.matnet.encoder.MixedScoresSDPA","title":"MixedScoresSDPA","text":"
MixedScoresSDPA(\n    num_heads: int,\n    num_scores: int = 1,\n    mixer_hidden_dim: int = 16,\n    mix1_init: float = 1 / 2**1 / 2,\n    mix2_init: float = 1 / 16**1 / 2,\n)\n

Bases: Module

Source code in rl4co/models/zoo/matnet/encoder.py
def __init__(\n    self,\n    num_heads: int,\n    num_scores: int = 1,\n    mixer_hidden_dim: int = 16,\n    mix1_init: float = (1 / 2) ** (1 / 2),\n    mix2_init: float = (1 / 16) ** (1 / 2),\n):\n    super().__init__()\n    self.num_heads = num_heads\n    self.num_scores = num_scores\n    mix_W1 = torch.torch.distributions.Uniform(low=-mix1_init, high=mix1_init).sample(\n        (num_heads, self.num_scores + 1, mixer_hidden_dim)\n    )\n    mix_b1 = torch.torch.distributions.Uniform(low=-mix1_init, high=mix1_init).sample(\n        (num_heads, mixer_hidden_dim)\n    )\n    self.mix_W1 = nn.Parameter(mix_W1)\n    self.mix_b1 = nn.Parameter(mix_b1)\n\n    mix_W2 = torch.torch.distributions.Uniform(low=-mix2_init, high=mix2_init).sample(\n        (num_heads, mixer_hidden_dim, 1)\n    )\n    mix_b2 = torch.torch.distributions.Uniform(low=-mix2_init, high=mix2_init).sample(\n        (num_heads, 1)\n    )\n    self.mix_W2 = nn.Parameter(mix_W2)\n    self.mix_b2 = nn.Parameter(mix_b2)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.matnet.encoder.MixedScoresSDPA.forward","title":"forward","text":"
forward(q, k, v, attn_mask=None, dmat=None, dropout_p=0.0)\n

Scaled Dot-Product Attention with MatNet Scores Mixer

Source code in rl4co/models/zoo/matnet/encoder.py
def forward(self, q, k, v, attn_mask=None, dmat=None, dropout_p=0.0):\n    \"\"\"Scaled Dot-Product Attention with MatNet Scores Mixer\"\"\"\n    assert dmat is not None\n    b, m, n = dmat.shape[:3]\n    dmat = dmat.reshape(b, m, n, self.num_scores)\n\n    # Calculate scaled dot product\n    attn_scores = torch.matmul(q, k.transpose(-2, -1)) / (k.size(-1) ** 0.5)\n    # [b, h, m, n, num_scores+1]\n    mix_attn_scores = torch.cat(\n        [\n            attn_scores.unsqueeze(-1),\n            dmat[:, None, ...].expand(b, self.num_heads, m, n, self.num_scores),\n        ],\n        dim=-1,\n    )\n    # [b, h, m, n]\n    attn_scores = (\n        (\n            torch.matmul(\n                F.relu(\n                    torch.matmul(mix_attn_scores.transpose(1, 2), self.mix_W1)\n                    + self.mix_b1[None, None, :, None, :]\n                ),\n                self.mix_W2,\n            )\n            + self.mix_b2[None, None, :, None, :]\n        )\n        .transpose(1, 2)\n        .squeeze(-1)\n    )\n\n    # Apply the provided attention mask\n    if attn_mask is not None:\n        if attn_mask.dtype == torch.bool:\n            attn_mask[~attn_mask.any(-1)] = True\n            attn_scores.masked_fill_(~attn_mask, float(\"-inf\"))\n        else:\n            attn_scores += attn_mask\n\n    # Softmax to get attention weights\n    attn_weights = F.softmax(attn_scores, dim=-1)\n\n    # Apply dropout\n    if dropout_p > 0.0:\n        attn_weights = F.dropout(attn_weights, p=dropout_p)\n\n    # Compute the weighted sum of values\n    return torch.matmul(attn_weights, v)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.matnet.encoder.MatNetMHA","title":"MatNetMHA","text":"
MatNetMHA(\n    embed_dim: int, num_heads: int, bias: bool = False\n)\n

Bases: Module

Source code in rl4co/models/zoo/matnet/encoder.py
def __init__(self, embed_dim: int, num_heads: int, bias: bool = False):\n    super().__init__()\n    self.row_encoding_block = MatNetCrossMHA(embed_dim, num_heads, bias)\n    self.col_encoding_block = MatNetCrossMHA(embed_dim, num_heads, bias)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.matnet.encoder.MatNetMHA.forward","title":"forward","text":"
forward(row_emb, col_emb, dmat, attn_mask=None)\n

Parameters:

  • row_emb (Tensor) \u2013

    [b, m, d]

  • col_emb (Tensor) \u2013

    [b, n, d]

  • dmat (Tensor) \u2013

    [b, m, n]

Returns:

  • \u2013

    Updated row_emb (Tensor): [b, m, d]

  • \u2013

    Updated col_emb (Tensor): [b, n, d]

Source code in rl4co/models/zoo/matnet/encoder.py
def forward(self, row_emb, col_emb, dmat, attn_mask=None):\n    \"\"\"\n    Args:\n        row_emb (Tensor): [b, m, d]\n        col_emb (Tensor): [b, n, d]\n        dmat (Tensor): [b, m, n]\n\n    Returns:\n        Updated row_emb (Tensor): [b, m, d]\n        Updated col_emb (Tensor): [b, n, d]\n    \"\"\"\n    updated_row_emb = self.row_encoding_block(\n        row_emb, col_emb, dmat=dmat, cross_attn_mask=attn_mask\n    )\n    attn_mask_t = attn_mask.transpose(-2, -1) if attn_mask is not None else None\n    updated_col_emb = self.col_encoding_block(\n        col_emb,\n        row_emb,\n        dmat=dmat.transpose(-2, -1),\n        cross_attn_mask=attn_mask_t,\n    )\n    return updated_row_emb, updated_col_emb\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.matnet.encoder.MatNetLayer","title":"MatNetLayer","text":"
MatNetLayer(\n    embed_dim: int,\n    num_heads: int,\n    bias: bool = False,\n    feedforward_hidden: int = 512,\n    normalization: Optional[str] = \"instance\",\n)\n

Bases: Module

Source code in rl4co/models/zoo/matnet/encoder.py
def __init__(\n    self,\n    embed_dim: int,\n    num_heads: int,\n    bias: bool = False,\n    feedforward_hidden: int = 512,\n    normalization: Optional[str] = \"instance\",\n):\n    super().__init__()\n    self.MHA = MatNetMHA(embed_dim, num_heads, bias)\n    self.F_a = TransformerFFN(embed_dim, feedforward_hidden, normalization)\n    self.F_b = TransformerFFN(embed_dim, feedforward_hidden, normalization)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.matnet.encoder.MatNetLayer.forward","title":"forward","text":"
forward(row_emb, col_emb, dmat, attn_mask=None)\n

Parameters:

  • row_emb (Tensor) \u2013

    [b, m, d]

  • col_emb (Tensor) \u2013

    [b, n, d]

  • dmat (Tensor) \u2013

    [b, m, n]

Returns:

  • \u2013

    Updated row_emb (Tensor): [b, m, d]

  • \u2013

    Updated col_emb (Tensor): [b, n, d]

Source code in rl4co/models/zoo/matnet/encoder.py
def forward(self, row_emb, col_emb, dmat, attn_mask=None):\n    \"\"\"\n    Args:\n        row_emb (Tensor): [b, m, d]\n        col_emb (Tensor): [b, n, d]\n        dmat (Tensor): [b, m, n]\n\n    Returns:\n        Updated row_emb (Tensor): [b, m, d]\n        Updated col_emb (Tensor): [b, n, d]\n    \"\"\"\n\n    row_emb_out, col_emb_out = self.MHA(row_emb, col_emb, dmat, attn_mask)\n    row_emb_out = self.F_a(row_emb_out, row_emb)\n    col_emb_out = self.F_b(col_emb_out, col_emb)\n    return row_emb_out, col_emb_out\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.matnet.decoder.MultiStageFFSPDecoder","title":"MultiStageFFSPDecoder","text":"
MultiStageFFSPDecoder(\n    embed_dim: int,\n    num_heads: int,\n    use_graph_context: bool = True,\n    tanh_clipping: float = 10,\n    **kwargs\n)\n

Bases: MatNetFFSPDecoder

Decoder class for the solving the FFSP using a seperate MatNet decoder for each stage as originally implemented by Kwon et al. (2021)

Source code in rl4co/models/zoo/matnet/decoder.py
def __init__(\n    self,\n    embed_dim: int,\n    num_heads: int,\n    use_graph_context: bool = True,\n    tanh_clipping: float = 10,\n    **kwargs,\n):\n    super().__init__(\n        embed_dim=embed_dim,\n        num_heads=num_heads,\n        use_graph_context=use_graph_context,\n        **kwargs,\n    )\n    self.cached_embs: PrecomputedCache = None\n    self.tanh_clipping = tanh_clipping\n
"},{"location":"docs/content/api/zoo/constructive_ar/#multi-decoder-attention-model-mdam","title":"Multi-Decoder Attention Model (MDAM)","text":""},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.mdam.model.MDAM","title":"MDAM","text":"
MDAM(\n    env: RL4COEnvBase,\n    policy: MDAMPolicy = None,\n    baseline: Union[REINFORCEBaseline, str] = \"rollout\",\n    policy_kwargs={},\n    baseline_kwargs={},\n    **kwargs\n)\n

Bases: REINFORCE

Multi-Decoder Attention Model (MDAM) is a model to train multiple diverse policies, which effectively increases the chance of finding good solutions compared with existing methods that train only one policy. Reference link: https://arxiv.org/abs/2012.10638; Implementation reference: https://github.com/liangxinedu/MDAM.

Parameters:

  • env (RL4COEnvBase) \u2013

    Environment to use for the algorithm

  • policy (MDAMPolicy, default: None ) \u2013

    Policy to use for the algorithm

  • baseline (Union[REINFORCEBaseline, str], default: 'rollout' ) \u2013

    REINFORCE baseline. Defaults to rollout (1 epoch of exponential, then greedy rollout baseline)

  • policy_kwargs \u2013

    Keyword arguments for policy

  • baseline_kwargs \u2013

    Keyword arguments for baseline

  • **kwargs \u2013

    Keyword arguments passed to the superclass

Source code in rl4co/models/zoo/mdam/model.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: MDAMPolicy = None,\n    baseline: Union[REINFORCEBaseline, str] = \"rollout\",\n    policy_kwargs={},\n    baseline_kwargs={},\n    **kwargs,\n):\n    if policy is None:\n        policy = MDAMPolicy(env_name=env.name, **policy_kwargs)\n\n    super().__init__(env, policy, baseline, baseline_kwargs, **kwargs)\n\n    # Change rollout of baseline to the rollout function\n    if isinstance(self.baseline, WarmupBaseline):\n        if isinstance(self.baseline.baseline, RolloutBaseline):\n            self.baseline.baseline.rollout = partial(rollout, self.baseline.baseline)\n    elif isinstance(self.baseline, RolloutBaseline):\n        self.baseline.rollout = partial(rollout, self.baseline)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.mdam.model.MDAM.calculate_loss","title":"calculate_loss","text":"
calculate_loss(\n    td, batch, policy_out, reward=None, log_likelihood=None\n)\n

Calculate loss for REINFORCE algorithm. Same as in :class:REINFORCE, but the bl_val is calculated is simply unsqueezed to match the reward shape (i.e., [batch, num_paths])

Parameters:

  • td \u2013

    TensorDict containing the current state of the environment

  • batch \u2013

    Batch of data. This is used to get the extra loss terms, e.g., REINFORCE baseline

  • policy_out \u2013

    Output of the policy network

  • reward \u2013

    Reward tensor. If None, it is taken from policy_out

  • log_likelihood \u2013

    Log-likelihood tensor. If None, it is taken from policy_out

Source code in rl4co/models/zoo/mdam/model.py
def calculate_loss(\n    self,\n    td,\n    batch,\n    policy_out,\n    reward=None,\n    log_likelihood=None,\n):\n    \"\"\"Calculate loss for REINFORCE algorithm.\n    Same as in :class:`REINFORCE`, but the bl_val is calculated is simply unsqueezed to match\n    the reward shape (i.e., [batch, num_paths])\n\n    Args:\n        td: TensorDict containing the current state of the environment\n        batch: Batch of data. This is used to get the extra loss terms, e.g., REINFORCE baseline\n        policy_out: Output of the policy network\n        reward: Reward tensor. If None, it is taken from `policy_out`\n        log_likelihood: Log-likelihood tensor. If None, it is taken from `policy_out`\n    \"\"\"\n    # Extra: this is used for additional loss terms, e.g., REINFORCE baseline\n    extra = batch.get(\"extra\", None)\n    reward = reward if reward is not None else policy_out[\"reward\"]\n    log_likelihood = (\n        log_likelihood if log_likelihood is not None else policy_out[\"log_likelihood\"]\n    )\n\n    # REINFORCE baseline\n    bl_val, bl_loss = (\n        self.baseline.eval(td, reward, self.env) if extra is None else (extra, 0)\n    )\n\n    # Main loss function\n    # reward: [batch, num_paths]. Note that the baseline value is the max reward\n    # if bl_val is a tensor, unsqueeze it to match the reward shape\n    if isinstance(bl_val, torch.Tensor):\n        if len(bl_val.shape) > 0:\n            bl_val = bl_val.unsqueeze(1)\n    advantage = reward - bl_val  # advantage = reward - baseline\n    reinforce_loss = -(advantage * log_likelihood).mean()\n    loss = reinforce_loss + bl_loss\n    policy_out.update(\n        {\n            \"loss\": loss,\n            \"reinforce_loss\": reinforce_loss,\n            \"bl_loss\": bl_loss,\n            \"bl_val\": bl_val,\n        }\n    )\n    return policy_out\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.mdam.model.rollout","title":"rollout","text":"
rollout(\n    self,\n    model,\n    env,\n    batch_size=64,\n    device=\"cpu\",\n    dataset=None,\n)\n

In this case the reward from the model is [batch, num_paths] and the baseline takes the maximum reward from the model as the baseline. https://github.com/liangxinedu/MDAM/blob/19b0bf813fb2dbec2fcde9e22eb50e04675400cd/train.py#L38C29-L38C33

Source code in rl4co/models/zoo/mdam/model.py
def rollout(self, model, env, batch_size=64, device=\"cpu\", dataset=None):\n    \"\"\"In this case the reward from the model is [batch, num_paths]\n    and the baseline takes the maximum reward from the model as the baseline.\n    https://github.com/liangxinedu/MDAM/blob/19b0bf813fb2dbec2fcde9e22eb50e04675400cd/train.py#L38C29-L38C33\n    \"\"\"\n    # if dataset is None, use the dataset of the baseline\n    dataset = self.dataset if dataset is None else dataset\n\n    model.eval()\n    model = model.to(device)\n\n    def eval_model(batch):\n        with torch.inference_mode():\n            batch = env.reset(batch.to(device))\n            return model(batch, env, decode_type=\"greedy\")[\"reward\"].max(1).values\n\n    dl = DataLoader(dataset, batch_size=batch_size, collate_fn=dataset.collate_fn)\n\n    rewards = torch.cat([eval_model(batch) for batch in dl], 0)\n    return rewards\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.mdam.policy.MDAMPolicy","title":"MDAMPolicy","text":"
MDAMPolicy(\n    encoder: MDAMGraphAttentionEncoder = None,\n    decoder: MDAMDecoder = None,\n    embed_dim: int = 128,\n    env_name: str = \"tsp\",\n    num_encoder_layers: int = 3,\n    num_heads: int = 8,\n    normalization: str = \"batch\",\n    **decoder_kwargs\n)\n

Bases: AutoregressivePolicy

Multi-Decoder Attention Model (MDAM) policy. Args:

Source code in rl4co/models/zoo/mdam/policy.py
def __init__(\n    self,\n    encoder: MDAMGraphAttentionEncoder = None,\n    decoder: MDAMDecoder = None,\n    embed_dim: int = 128,\n    env_name: str = \"tsp\",\n    num_encoder_layers: int = 3,\n    num_heads: int = 8,\n    normalization: str = \"batch\",\n    **decoder_kwargs,\n):\n    encoder = (\n        MDAMGraphAttentionEncoder(\n            num_heads=num_heads,\n            embed_dim=embed_dim,\n            num_layers=num_encoder_layers,\n            normalization=normalization,\n        )\n        if encoder is None\n        else encoder\n    )\n\n    decoder = (\n        MDAMDecoder(\n            env_name=env_name,\n            embed_dim=embed_dim,\n            num_heads=num_heads,\n            **decoder_kwargs,\n        )\n        if decoder is None\n        else decoder\n    )\n\n    super(MDAMPolicy, self).__init__(\n        env_name=env_name, encoder=encoder, decoder=decoder\n    )\n\n    self.init_embedding = env_init_embedding(env_name, {\"embed_dim\": embed_dim})\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.mdam.encoder.MDAMGraphAttentionEncoder","title":"MDAMGraphAttentionEncoder","text":"
MDAMGraphAttentionEncoder(\n    num_heads,\n    embed_dim,\n    num_layers,\n    node_dim=None,\n    normalization=\"batch\",\n    feedforward_hidden=512,\n    sdpa_fn: Optional[Callable] = None,\n)\n

Bases: Module

Source code in rl4co/models/zoo/mdam/encoder.py
def __init__(\n    self,\n    num_heads,\n    embed_dim,\n    num_layers,\n    node_dim=None,\n    normalization=\"batch\",\n    feedforward_hidden=512,\n    sdpa_fn: Optional[Callable] = None,\n):\n    super(MDAMGraphAttentionEncoder, self).__init__()\n\n    # To map input to embedding space\n    self.init_embed = nn.Linear(node_dim, embed_dim) if node_dim is not None else None\n\n    self.layers = nn.Sequential(\n        *(\n            MultiHeadAttentionLayer(\n                embed_dim,\n                num_heads,\n                feedforward_hidden,\n                normalization,\n                sdpa_fn=sdpa_fn,\n            )\n            for _ in range(num_layers - 1)  # because last layer is different\n        )\n    )\n    self.attention_layer = MultiHeadAttentionMDAM(\n        embed_dim, num_heads, sdpa_fn=sdpa_fn, last_one=True\n    )\n    self.BN1 = Normalization(embed_dim, normalization)\n    self.projection = SkipConnection(\n        nn.Sequential(\n            nn.Linear(embed_dim, feedforward_hidden),\n            nn.ReLU(),\n            nn.Linear(feedforward_hidden, embed_dim),\n        )\n        if feedforward_hidden > 0\n        else nn.Linear(embed_dim, embed_dim)\n    )\n    self.BN2 = Normalization(embed_dim, normalization)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.mdam.encoder.MDAMGraphAttentionEncoder.forward","title":"forward","text":"
forward(x, mask=None, return_transform_loss=False)\n

Returns:

  • \u2013
    • h [batch_size, graph_size, embed_dim]
  • \u2013
    • attn [num_head, batch_size, graph_size, graph_size]
  • \u2013
    • V [num_head, batch_size, graph_size, key_dim]
  • \u2013
    • h_old [batch_size, graph_size, embed_dim]
Source code in rl4co/models/zoo/mdam/encoder.py
def forward(self, x, mask=None, return_transform_loss=False):\n    \"\"\"\n    Returns:\n        - h [batch_size, graph_size, embed_dim]\n        - attn [num_head, batch_size, graph_size, graph_size]\n        - V [num_head, batch_size, graph_size, key_dim]\n        - h_old [batch_size, graph_size, embed_dim]\n    \"\"\"\n    assert mask is None, \"TODO mask not yet supported!\"\n\n    h_embeded = x\n    h_old = self.layers(h_embeded)\n    h_new, attn, V = self.attention_layer(h_old)\n    h = h_new + h_old\n    h = self.BN1(h)\n    h = self.projection(h)\n    h = self.BN2(h)\n\n    return (h, h.mean(dim=1), attn, V, h_old)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#pomo","title":"POMO","text":""},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.pomo.model.POMO","title":"POMO","text":"
POMO(\n    env: RL4COEnvBase,\n    policy: Module = None,\n    policy_kwargs={},\n    baseline: str = \"shared\",\n    num_augment: int = 8,\n    augment_fn: Union[str, callable] = \"dihedral8\",\n    first_aug_identity: bool = True,\n    feats: list = None,\n    num_starts: int = None,\n    **kwargs\n)\n

Bases: REINFORCE

POMO Model for neural combinatorial optimization based on REINFORCE Based on Kwon et al. (2020) http://arxiv.org/abs/2010.16011.

Note

If no policy kwargs is passed, we use the Attention Model policy with the following arguments: Differently to the base class:

  • num_encoder_layers=6 (instead of 3)
  • normalization=\"instance\" (instead of \"batch\")
  • use_graph_context=False (instead of True) The latter is due to the fact that the paper does not use the graph context in the policy, which seems to be helpful in overfitting to the training graph size.

Parameters:

  • env (RL4COEnvBase) \u2013

    TorchRL Environment

  • policy (Module, default: None ) \u2013

    Policy to use for the algorithm

  • policy_kwargs \u2013

    Keyword arguments for policy

  • baseline (str, default: 'shared' ) \u2013

    Baseline to use for the algorithm. Note that POMO only supports shared baseline, so we will throw an error if anything else is passed.

  • num_augment (int, default: 8 ) \u2013

    Number of augmentations (used only for validation and test)

  • augment_fn (Union[str, callable], default: 'dihedral8' ) \u2013

    Function to use for augmentation, defaulting to dihedral8

  • first_aug_identity (bool, default: True ) \u2013

    Whether to include the identity augmentation in the first position

  • feats (list, default: None ) \u2013

    List of features to augment

  • num_starts (int, default: None ) \u2013

    Number of starts for multi-start. If None, use the number of available actions

  • **kwargs \u2013

    Keyword arguments passed to the superclass

Source code in rl4co/models/zoo/pomo/model.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: nn.Module = None,\n    policy_kwargs={},\n    baseline: str = \"shared\",\n    num_augment: int = 8,\n    augment_fn: Union[str, callable] = \"dihedral8\",\n    first_aug_identity: bool = True,\n    feats: list = None,\n    num_starts: int = None,\n    **kwargs,\n):\n    self.save_hyperparameters(logger=False)\n\n    if policy is None:\n        policy_kwargs_with_defaults = {\n            \"num_encoder_layers\": 6,\n            \"normalization\": \"instance\",\n            \"use_graph_context\": False,\n        }\n        policy_kwargs_with_defaults.update(policy_kwargs)\n        policy = AttentionModelPolicy(env_name=env.name, **policy_kwargs_with_defaults)\n\n    assert baseline == \"shared\", \"POMO only supports shared baseline\"\n\n    # Initialize with the shared baseline\n    super(POMO, self).__init__(env, policy, baseline, **kwargs)\n\n    self.num_starts = num_starts\n    self.num_augment = num_augment\n    if self.num_augment > 1:\n        self.augment = StateAugmentation(\n            num_augment=self.num_augment,\n            augment_fn=augment_fn,\n            first_aug_identity=first_aug_identity,\n            feats=feats,\n        )\n    else:\n        self.augment = None\n\n    # Add `_multistart` to decode type for train, val and test in policy\n    for phase in [\"train\", \"val\", \"test\"]:\n        self.set_decode_type_multistart(phase)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#pointer-network-ptrnet","title":"Pointer Network (PtrNet)","text":""},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.ptrnet.model.PointerNetwork","title":"PointerNetwork","text":"
PointerNetwork(\n    env: RL4COEnvBase,\n    policy: PointerNetworkPolicy = None,\n    baseline: Union[REINFORCEBaseline, str] = \"rollout\",\n    policy_kwargs={},\n    baseline_kwargs={},\n    **kwargs\n)\n

Bases: REINFORCE

Pointer Network for neural combinatorial optimization based on REINFORCE Based on Vinyals et al. (2015) https://arxiv.org/abs/1506.03134 Refactored from reference implementation: https://github.com/wouterkool/attention-learn-to-route

Parameters:

  • env (RL4COEnvBase) \u2013

    Environment to use for the algorithm

  • policy (PointerNetworkPolicy, default: None ) \u2013

    Policy to use for the algorithm

  • baseline (Union[REINFORCEBaseline, str], default: 'rollout' ) \u2013

    REINFORCE baseline. Defaults to rollout (1 epoch of exponential, then greedy rollout baseline)

  • policy_kwargs \u2013

    Keyword arguments for policy

  • baseline_kwargs \u2013

    Keyword arguments for baseline

  • **kwargs \u2013

    Keyword arguments passed to the superclass

Source code in rl4co/models/zoo/ptrnet/model.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: PointerNetworkPolicy = None,\n    baseline: Union[REINFORCEBaseline, str] = \"rollout\",\n    policy_kwargs={},\n    baseline_kwargs={},\n    **kwargs,\n):\n    policy = (\n        PointerNetworkPolicy(env=env, **policy_kwargs) if policy is None else policy\n    )\n    super().__init__(env, policy, baseline, baseline_kwargs, **kwargs)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.ptrnet.encoder.Encoder","title":"Encoder","text":"
Encoder(input_dim, hidden_dim)\n

Bases: Module

Maps a graph represented as an input sequence to a hidden vector

Source code in rl4co/models/zoo/ptrnet/encoder.py
def __init__(self, input_dim, hidden_dim):\n    super(Encoder, self).__init__()\n    self.hidden_dim = hidden_dim\n    self.lstm = nn.LSTM(input_dim, hidden_dim)\n    self.init_hx, self.init_cx = self.init_hidden(hidden_dim)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.ptrnet.encoder.Encoder.init_hidden","title":"init_hidden","text":"
init_hidden(hidden_dim)\n

Trainable initial hidden state

Source code in rl4co/models/zoo/ptrnet/encoder.py
def init_hidden(self, hidden_dim):\n    \"\"\"Trainable initial hidden state\"\"\"\n    std = 1.0 / math.sqrt(hidden_dim)\n    enc_init_hx = nn.Parameter(torch.FloatTensor(hidden_dim))\n    enc_init_hx.data.uniform_(-std, std)\n\n    enc_init_cx = nn.Parameter(torch.FloatTensor(hidden_dim))\n    enc_init_cx.data.uniform_(-std, std)\n    return enc_init_hx, enc_init_cx\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.ptrnet.decoder.SimpleAttention","title":"SimpleAttention","text":"
SimpleAttention(dim, use_tanh=False, C=10)\n

Bases: Module

A generic attention module for a decoder in seq2seq

Source code in rl4co/models/zoo/ptrnet/decoder.py
def __init__(self, dim, use_tanh=False, C=10):\n    super(SimpleAttention, self).__init__()\n    self.use_tanh = use_tanh\n    self.project_query = nn.Linear(dim, dim)\n    self.project_ref = nn.Conv1d(dim, dim, 1, 1)\n    self.C = C  # tanh exploration\n\n    self.v = nn.Parameter(torch.FloatTensor(dim))\n    self.v.data.uniform_(-(1.0 / math.sqrt(dim)), 1.0 / math.sqrt(dim))\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.ptrnet.decoder.SimpleAttention.forward","title":"forward","text":"
forward(query, ref)\n

Parameters:

  • query \u2013

    is the hidden state of the decoder at the current time step. batch x dim

  • ref \u2013

    the set of hidden states from the encoder. sourceL x batch x hidden_dim

Source code in rl4co/models/zoo/ptrnet/decoder.py
def forward(self, query, ref):\n    \"\"\"\n    Args:\n        query: is the hidden state of the decoder at the current\n            time step. batch x dim\n        ref: the set of hidden states from the encoder.\n            sourceL x batch x hidden_dim\n    \"\"\"\n    # ref is now [batch_size x hidden_dim x sourceL]\n    ref = ref.permute(1, 2, 0)\n    q = self.project_query(query).unsqueeze(2)  # batch x dim x 1\n    e = self.project_ref(ref)  # batch_size x hidden_dim x sourceL\n    # expand the query by sourceL\n    # batch x dim x sourceL\n    expanded_q = q.repeat(1, 1, e.size(2))\n    # batch x 1 x hidden_dim\n    v_view = self.v.unsqueeze(0).expand(expanded_q.size(0), len(self.v)).unsqueeze(1)\n    # [batch_size x 1 x hidden_dim] * [batch_size x hidden_dim x sourceL]\n    u = torch.bmm(v_view, F.tanh(expanded_q + e)).squeeze(1)\n    if self.use_tanh:\n        logits = self.C * F.tanh(u)\n    else:\n        logits = u\n    return e, logits\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.ptrnet.decoder.Decoder","title":"Decoder","text":"
Decoder(\n    embed_dim: int = 128,\n    hidden_dim: int = 128,\n    tanh_exploration: float = 10.0,\n    use_tanh: bool = True,\n    num_glimpses=1,\n    mask_glimpses=True,\n    mask_logits=True,\n)\n

Bases: Module

Source code in rl4co/models/zoo/ptrnet/decoder.py
def __init__(\n    self,\n    embed_dim: int = 128,\n    hidden_dim: int = 128,\n    tanh_exploration: float = 10.0,\n    use_tanh: bool = True,\n    num_glimpses=1,\n    mask_glimpses=True,\n    mask_logits=True,\n):\n    super(Decoder, self).__init__()\n\n    self.embed_dim = embed_dim\n    self.hidden_dim = hidden_dim\n    self.num_glimpses = num_glimpses\n    self.mask_glimpses = mask_glimpses\n    self.mask_logits = mask_logits\n    self.use_tanh = use_tanh\n    self.tanh_exploration = tanh_exploration\n\n    self.lstm = nn.LSTMCell(embed_dim, hidden_dim)\n    self.pointer = SimpleAttention(hidden_dim, use_tanh=use_tanh, C=tanh_exploration)\n    self.glimpse = SimpleAttention(hidden_dim, use_tanh=False)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.ptrnet.decoder.Decoder.forward","title":"forward","text":"
forward(\n    decoder_input,\n    embedded_inputs,\n    hidden,\n    context,\n    decode_type=\"sampling\",\n    eval_tours=None,\n)\n

Parameters:

  • decoder_input \u2013

    The initial input to the decoder size is [batch_size x embed_dim]. Trainable parameter.

  • embedded_inputs \u2013

    [sourceL x batch_size x embed_dim]

  • hidden \u2013

    the prev hidden state, size is [batch_size x hidden_dim]. Initially this is set to (enc_h[-1], enc_c[-1])

  • context \u2013

    encoder outputs, [sourceL x batch_size x hidden_dim]

Source code in rl4co/models/zoo/ptrnet/decoder.py
def forward(\n    self,\n    decoder_input,\n    embedded_inputs,\n    hidden,\n    context,\n    decode_type=\"sampling\",\n    eval_tours=None,\n):\n    \"\"\"\n    Args:\n        decoder_input: The initial input to the decoder\n            size is [batch_size x embed_dim]. Trainable parameter.\n        embedded_inputs: [sourceL x batch_size x embed_dim]\n        hidden: the prev hidden state, size is [batch_size x hidden_dim].\n            Initially this is set to (enc_h[-1], enc_c[-1])\n        context: encoder outputs, [sourceL x batch_size x hidden_dim]\n    \"\"\"\n\n    batch_size = context.size(1)\n    outputs = []\n    selections = []\n    steps = range(embedded_inputs.size(0))\n    idxs = None\n    mask = torch.ones(\n        embedded_inputs.size(1),\n        embedded_inputs.size(0),\n        dtype=torch.bool,\n        device=embedded_inputs.device,\n    )\n\n    for i in steps:\n        hidden, log_p, mask = self.recurrence(\n            decoder_input, hidden, mask, idxs, i, context\n        )\n        # select the next inputs for the decoder [batch_size x hidden_dim]\n        idxs = (\n            decode_logprobs(log_p, mask, decode_type=decode_type)\n            if eval_tours is None\n            else eval_tours[:, i]\n        )\n        # select logp of chosen action\n        log_p = gather_by_index(log_p, idxs, dim=1)\n\n        idxs = (\n            idxs.detach()\n        )  # Otherwise pytorch complains it want's a reward, todo implement this more properly?\n        # Gather input embedding of selected\n        decoder_input = torch.gather(\n            embedded_inputs,\n            0,\n            idxs.contiguous()\n            .view(1, batch_size, 1)\n            .expand(1, batch_size, *embedded_inputs.size()[2:]),\n        ).squeeze(0)\n\n        # use outs to point to next object\n        outputs.append(log_p)\n        selections.append(idxs)\n    return (torch.stack(outputs, 1), torch.stack(selections, 1)), hidden\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.ptrnet.critic.CriticNetworkLSTM","title":"CriticNetworkLSTM","text":"
CriticNetworkLSTM(\n    embed_dim,\n    hidden_dim,\n    n_process_block_iters,\n    tanh_exploration,\n    use_tanh,\n)\n

Bases: Module

Useful as a baseline in REINFORCE updates

Source code in rl4co/models/zoo/ptrnet/critic.py
def __init__(\n    self,\n    embed_dim,\n    hidden_dim,\n    n_process_block_iters,\n    tanh_exploration,\n    use_tanh,\n):\n    super(CriticNetworkLSTM, self).__init__()\n\n    self.hidden_dim = hidden_dim\n    self.n_process_block_iters = n_process_block_iters\n\n    self.encoder = Encoder(embed_dim, hidden_dim)\n\n    self.process_block = SimpleAttention(\n        hidden_dim, use_tanh=use_tanh, C=tanh_exploration\n    )\n    self.sm = nn.Softmax(dim=1)\n    self.decoder = nn.Sequential(\n        nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, 1)\n    )\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.ptrnet.critic.CriticNetworkLSTM.forward","title":"forward","text":"
forward(inputs)\n

Parameters:

  • inputs \u2013

    [embed_dim x batch_size x sourceL] of embedded inputs

Source code in rl4co/models/zoo/ptrnet/critic.py
def forward(self, inputs):\n    \"\"\"\n    Args:\n        inputs: [embed_dim x batch_size x sourceL] of embedded inputs\n    \"\"\"\n    inputs = inputs.transpose(0, 1).contiguous()\n\n    encoder_hx = (\n        self.encoder.init_hx.unsqueeze(0).repeat(inputs.size(1), 1).unsqueeze(0)\n    )\n    encoder_cx = (\n        self.encoder.init_cx.unsqueeze(0).repeat(inputs.size(1), 1).unsqueeze(0)\n    )\n\n    # encoder forward pass\n    enc_outputs, (enc_h_t, enc_c_t) = self.encoder(inputs, (encoder_hx, encoder_cx))\n\n    # grab the hidden state and process it via the process block\n    process_block_state = enc_h_t[-1]\n    for i in range(self.n_process_block_iters):\n        ref, logits = self.process_block(process_block_state, enc_outputs)\n        process_block_state = torch.bmm(ref, self.sm(logits).unsqueeze(2)).squeeze(2)\n    # produce the final scalar output\n    out = self.decoder(process_block_state)\n    return out\n
"},{"location":"docs/content/api/zoo/constructive_ar/#symnco","title":"SymNCO","text":""},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.symnco.model.SymNCO","title":"SymNCO","text":"
SymNCO(\n    env: RL4COEnvBase,\n    policy: Union[Module, SymNCOPolicy] = None,\n    policy_kwargs: dict = {},\n    baseline: str = \"symnco\",\n    num_augment: int = 4,\n    augment_fn: Union[str, callable] = \"symmetric\",\n    feats: list = None,\n    alpha: float = 0.2,\n    beta: float = 1,\n    num_starts: int = 0,\n    **kwargs\n)\n

Bases: REINFORCE

SymNCO Model based on REINFORCE with shared baselines. Based on Kim et al. (2022) https://arxiv.org/abs/2205.13209.

Parameters:

  • env (RL4COEnvBase) \u2013

    TorchRL environment to use for the algorithm

  • policy (Union[Module, SymNCOPolicy], default: None ) \u2013

    Policy to use for the algorithm

  • policy_kwargs (dict, default: {} ) \u2013

    Keyword arguments for policy

  • num_augment (int, default: 4 ) \u2013

    Number of augmentations

  • augment_fn (Union[str, callable], default: 'symmetric' ) \u2013

    Function to use for augmentation, defaulting to dihedral_8_augmentation

  • feats (list, default: None ) \u2013

    List of features to augment

  • alpha (float, default: 0.2 ) \u2013

    weight for invariance loss

  • beta (float, default: 1 ) \u2013

    weight for solution symmetricity loss

  • num_starts (int, default: 0 ) \u2013

    Number of starts for multi-start. If None, use the number of available actions

  • **kwargs \u2013

    Keyword arguments passed to the superclass

Source code in rl4co/models/zoo/symnco/model.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: Union[nn.Module, SymNCOPolicy] = None,\n    policy_kwargs: dict = {},\n    baseline: str = \"symnco\",\n    num_augment: int = 4,\n    augment_fn: Union[str, callable] = \"symmetric\",\n    feats: list = None,\n    alpha: float = 0.2,\n    beta: float = 1,\n    num_starts: int = 0,\n    **kwargs,\n):\n    self.save_hyperparameters(logger=False)\n\n    if policy is None:\n        policy = SymNCOPolicy(env_name=env.name, **policy_kwargs)\n\n    assert baseline == \"symnco\", \"SymNCO only supports custom-symnco baseline\"\n    baseline = \"no\"  # Pass no baseline to superclass since there are multiple custom baselines\n\n    # Pass no baseline to superclass since there are multiple custom baselines\n    super().__init__(env, policy, baseline, **kwargs)\n\n    self.num_starts = num_starts\n    self.num_augment = num_augment\n    self.augment = StateAugmentation(\n        num_augment=self.num_augment, augment_fn=augment_fn, feats=feats\n    )\n    self.alpha = alpha  # weight for invariance loss\n    self.beta = beta  # weight for solution symmetricity loss\n\n    # Add `_multistart` to decode type for train, val and test in policy if num_starts > 1\n    if self.num_starts > 1:\n        for phase in [\"train\", \"val\", \"test\"]:\n            self.set_decode_type_multistart(phase)\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.symnco.policy.SymNCOPolicy","title":"SymNCOPolicy","text":"
SymNCOPolicy(\n    embed_dim: int = 128,\n    env_name: str = \"tsp\",\n    num_encoder_layers: int = 3,\n    num_heads: int = 8,\n    normalization: str = \"batch\",\n    projection_head: Module = None,\n    use_projection_head: bool = True,\n    **kwargs\n)\n

Bases: AttentionModelPolicy

SymNCO Policy based on AutoregressivePolicy. This differs from the default :class:AutoregressivePolicy in that it projects the initial embeddings to a lower dimension using a projection head and returns it. This is used in the SymNCO algorithm to compute the invariance loss. Based on Kim et al. (2022) https://arxiv.org/abs/2205.13209.

Parameters:

  • embed_dim (int, default: 128 ) \u2013

    Dimension of the embedding

  • env_name (str, default: 'tsp' ) \u2013

    Name of the environment

  • num_encoder_layers (int, default: 3 ) \u2013

    Number of layers in the encoder

  • num_heads (int, default: 8 ) \u2013

    Number of heads in the encoder

  • normalization (str, default: 'batch' ) \u2013

    Normalization to use in the encoder

  • projection_head (Module, default: None ) \u2013

    Projection head to use

  • use_projection_head (bool, default: True ) \u2013

    Whether to use projection head

  • **kwargs \u2013

    Keyword arguments passed to the superclass

Source code in rl4co/models/zoo/symnco/policy.py
def __init__(\n    self,\n    embed_dim: int = 128,\n    env_name: str = \"tsp\",\n    num_encoder_layers: int = 3,\n    num_heads: int = 8,\n    normalization: str = \"batch\",\n    projection_head: nn.Module = None,\n    use_projection_head: bool = True,\n    **kwargs,\n):\n    super(SymNCOPolicy, self).__init__(\n        env_name=env_name,\n        embed_dim=embed_dim,\n        num_encoder_layers=num_encoder_layers,\n        num_heads=num_heads,\n        normalization=normalization,\n        **kwargs,\n    )\n\n    self.use_projection_head = use_projection_head\n\n    if self.use_projection_head:\n        self.projection_head = (\n            MLP(embed_dim, embed_dim, 1, embed_dim, nn.ReLU)\n            if projection_head is None\n            else projection_head\n        )\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.symnco.losses.problem_symmetricity_loss","title":"problem_symmetricity_loss","text":"
problem_symmetricity_loss(reward, log_likelihood, dim=1)\n

REINFORCE loss for problem symmetricity Baseline is the average reward for all augmented problems Corresponds to L_ps in the SymNCO paper

Source code in rl4co/models/zoo/symnco/losses.py
def problem_symmetricity_loss(reward, log_likelihood, dim=1):\n    \"\"\"REINFORCE loss for problem symmetricity\n    Baseline is the average reward for all augmented problems\n    Corresponds to `L_ps` in the SymNCO paper\n    \"\"\"\n    num_augment = reward.shape[dim]\n    if num_augment < 2:\n        return 0\n    advantage = reward - reward.mean(dim=dim, keepdim=True)\n    loss = -advantage * log_likelihood\n    return loss.mean()\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.symnco.losses.solution_symmetricity_loss","title":"solution_symmetricity_loss","text":"
solution_symmetricity_loss(reward, log_likelihood, dim=-1)\n

REINFORCE loss for solution symmetricity Baseline is the average reward for all start nodes Corresponds to L_ss in the SymNCO paper

Source code in rl4co/models/zoo/symnco/losses.py
def solution_symmetricity_loss(reward, log_likelihood, dim=-1):\n    \"\"\"REINFORCE loss for solution symmetricity\n    Baseline is the average reward for all start nodes\n    Corresponds to `L_ss` in the SymNCO paper\n    \"\"\"\n    num_starts = reward.shape[dim]\n    if num_starts < 2:\n        return 0\n    advantage = reward - reward.mean(dim=dim, keepdim=True)\n    loss = -advantage * log_likelihood\n    return loss.mean()\n
"},{"location":"docs/content/api/zoo/constructive_ar/#models.zoo.symnco.losses.invariance_loss","title":"invariance_loss","text":"
invariance_loss(proj_embed, num_augment)\n

Loss for invariant representation on projected nodes Corresponds to L_inv in the SymNCO paper

Source code in rl4co/models/zoo/symnco/losses.py
def invariance_loss(proj_embed, num_augment):\n    \"\"\"Loss for invariant representation on projected nodes\n    Corresponds to `L_inv` in the SymNCO paper\n    \"\"\"\n    pe = rearrange(proj_embed, \"(b a) ... -> b a ...\", a=num_augment)\n    similarity = sum(\n        [cosine_similarity(pe[:, 0], pe[:, i], dim=-1) for i in range(1, num_augment)]\n    )\n    return similarity.mean()\n
"},{"location":"docs/content/api/zoo/constructive_nar/","title":"Constructive NonAutoregressive","text":""},{"location":"docs/content/api/zoo/constructive_nar/#deepaco","title":"DeepACO","text":""},{"location":"docs/content/api/zoo/constructive_nar/#models.zoo.deepaco.antsystem.AntSystem","title":"AntSystem","text":"
AntSystem(\n    log_heuristic: Tensor,\n    n_ants: int = 20,\n    alpha: float = 1.0,\n    beta: float = 1.0,\n    decay: float = 0.95,\n    Q: Optional[float] = None,\n    temperature: float = 0.1,\n    pheromone: Optional[Tensor] = None,\n    require_logprobs: bool = False,\n    use_local_search: bool = False,\n    use_nls: bool = False,\n    n_perturbations: int = 5,\n    local_search_params: dict = {},\n    perturbation_params: dict = {},\n    start_node: Optional[int] = None,\n)\n

Implements the Ant System algorithm: https://doi.org/10.1109/3477.484436.

Parameters:

  • log_heuristic (Tensor) \u2013

    Logarithm of the heuristic matrix.

  • n_ants (int, default: 20 ) \u2013

    Number of ants to be used in the algorithm. Defaults to 20.

  • alpha (float, default: 1.0 ) \u2013

    Importance of pheromone in the decision-making process. Defaults to 1.0.

  • beta (float, default: 1.0 ) \u2013

    Importance of heuristic information in the decision-making process. Defaults to 1.0.

  • decay (float, default: 0.95 ) \u2013

    Rate at which pheromone evaporates. Should be between 0 and 1. Defaults to 0.95.

  • Q (Optional[float], default: None ) \u2013

    Rate at which pheromone deposits. Defaults to 1 / n_ants.

  • temperature (float, default: 0.1 ) \u2013

    Temperature for the softmax during decoding. Defaults to 0.1.

  • pheromone (Optional[Tensor], default: None ) \u2013

    Initial pheromone matrix. Defaults to torch.ones_like(log_heuristic).

  • require_logprobs (bool, default: False ) \u2013

    Whether to require the log probability of actions. Defaults to False.

  • use_local_search (bool, default: False ) \u2013

    Whether to use local_search provided by the env. Default to False.

  • use_nls (bool, default: False ) \u2013

    Whether to use neural-guided local search provided by the env. Default to False.

  • n_perturbations (int, default: 5 ) \u2013

    Number of perturbations to be used for nls. Defaults to 5.

  • local_search_params (dict, default: {} ) \u2013

    Arguments to be passed to the local_search.

  • perturbation_params (dict, default: {} ) \u2013

    Arguments to be passed to the perturbation used for nls.

Source code in rl4co/models/zoo/deepaco/antsystem.py
def __init__(\n    self,\n    log_heuristic: Tensor,\n    n_ants: int = 20,\n    alpha: float = 1.0,\n    beta: float = 1.0,\n    decay: float = 0.95,\n    Q: Optional[float] = None,\n    temperature: float = 0.1,\n    pheromone: Optional[Tensor] = None,\n    require_logprobs: bool = False,\n    use_local_search: bool = False,\n    use_nls: bool = False,\n    n_perturbations: int = 5,\n    local_search_params: dict = {},\n    perturbation_params: dict = {},\n    start_node: Optional[int] = None,\n):\n    self.batch_size = log_heuristic.shape[0]\n    self.n_ants = n_ants\n    self.alpha = alpha\n    self.beta = beta\n    self.decay = decay\n    self.Q = 1 / self.n_ants if Q is None else Q\n    self.temperature = temperature\n\n    self.log_heuristic = log_heuristic / self.temperature\n\n    if pheromone is None:\n        self.pheromone = torch.ones_like(log_heuristic)\n        self.pheromone.fill_(0.0005)\n    else:\n        self.pheromone = pheromone\n\n    self.final_actions = self.final_reward = None\n    self.require_logprobs = require_logprobs\n    self.all_records = []\n\n    self.use_local_search = use_local_search\n    assert not (use_nls and not use_local_search), \"use_nls requires use_local_search\"\n    self.use_nls = use_nls\n    self.n_perturbations = n_perturbations\n    self.local_search_params = local_search_params\n    self.perturbation_params = perturbation_params\n    self.start_node = start_node\n\n    self._batchindex = torch.arange(self.batch_size, device=log_heuristic.device)\n
"},{"location":"docs/content/api/zoo/constructive_nar/#models.zoo.deepaco.antsystem.AntSystem.run","title":"run","text":"
run(\n    td_initial: TensorDict,\n    env: RL4COEnvBase,\n    n_iterations: int,\n) -> Tuple[TensorDict, Tensor, Tensor]\n

Run the Ant System algorithm for a specified number of iterations.

Parameters:

  • td_initial (TensorDict) \u2013

    Initial state of the problem.

  • env (RL4COEnvBase) \u2013

    Environment representing the problem.

  • n_iterations (int) \u2013

    Number of iterations to run the algorithm.

Returns:

  • td ( TensorDict ) \u2013

    The final state of the problem.

  • actions ( Tensor ) \u2013

    The final actions chosen by the algorithm.

  • reward ( Tensor ) \u2013

    The final reward achieved by the algorithm.

Source code in rl4co/models/zoo/deepaco/antsystem.py
def run(\n    self,\n    td_initial: TensorDict,\n    env: RL4COEnvBase,\n    n_iterations: int,\n) -> Tuple[TensorDict, Tensor, Tensor]:\n    \"\"\"Run the Ant System algorithm for a specified number of iterations.\n\n    Args:\n        td_initial: Initial state of the problem.\n        env: Environment representing the problem.\n        n_iterations: Number of iterations to run the algorithm.\n\n    Returns:\n        td: The final state of the problem.\n        actions: The final actions chosen by the algorithm.\n        reward: The final reward achieved by the algorithm.\n    \"\"\"\n    for _ in range(n_iterations):\n        # reset environment\n        td = td_initial.clone()\n        self._one_step(td, env)\n\n    action_matrix = self._convert_final_action_to_matrix()\n    assert action_matrix is not None and self.final_reward is not None\n    td, env = self._recreate_final_routes(td_initial, env, action_matrix)\n\n    return td, action_matrix, self.final_reward\n
"},{"location":"docs/content/api/zoo/constructive_nar/#models.zoo.deepaco.antsystem.AntSystem.local_search","title":"local_search","text":"
local_search(\n    td: TensorDict, env: RL4COEnvBase, actions: Tensor\n) -> Tuple[Tensor, Tensor]\n

Perform local search on the actions and reward obtained.

Parameters:

  • td (TensorDict) \u2013

    Current state of the problem.

  • env (RL4COEnvBase) \u2013

    Environment representing the problem.

  • actions (Tensor) \u2013

    Actions chosen by the algorithm.

Returns:

  • actions ( Tensor ) \u2013

    The modified actions

  • reward ( Tensor ) \u2013

    The modified reward

Source code in rl4co/models/zoo/deepaco/antsystem.py
def local_search(\n    self, td: TensorDict, env: RL4COEnvBase, actions: Tensor\n) -> Tuple[Tensor, Tensor]:\n    \"\"\"Perform local search on the actions and reward obtained.\n\n    Args:\n        td: Current state of the problem.\n        env: Environment representing the problem.\n        actions: Actions chosen by the algorithm.\n\n    Returns:\n        actions: The modified actions\n        reward: The modified reward\n    \"\"\"\n    td_cpu = td.detach().cpu()  # Convert to CPU in advance to minimize the overhead from device transfer\n    td_cpu[\"distances\"] = get_distance_matrix(td_cpu[\"locs\"])\n    # TODO: avoid or generalize this, e.g., pre-compute for local search in each env\n    actions = actions.detach().cpu()\n    best_actions = env.local_search(td=td_cpu, actions=actions, **self.local_search_params)\n    best_rewards = env.get_reward(td_cpu, best_actions)\n\n    if self.use_nls:\n        td_cpu_perturb = td_cpu.clone()\n        td_cpu_perturb[\"distances\"] = torch.tile(self.heuristic_dist, (self.n_ants, 1, 1))\n        new_actions = best_actions.clone()\n\n        for _ in range(self.n_perturbations):\n            perturbed_actions = env.local_search(\n                td=td_cpu_perturb, actions=new_actions, **self.perturbation_params\n            )\n            new_actions = env.local_search(td=td_cpu, actions=perturbed_actions, **self.local_search_params)\n            new_rewards = env.get_reward(td_cpu, new_actions)\n\n            improved_indices = new_rewards > best_rewards\n            best_actions = env.replace_selected_actions(best_actions, new_actions, improved_indices)\n            best_rewards[improved_indices] = new_rewards[improved_indices]\n\n    best_actions = best_actions.to(td.device)\n    best_rewards = best_rewards.to(td.device)\n\n    return best_actions, best_rewards\n
"},{"location":"docs/content/api/zoo/constructive_nar/#models.zoo.deepaco.antsystem.AntSystem.get_logp","title":"get_logp","text":"
get_logp()\n

Get the log probability (logprobs) values recorded during the execution of the algorithm.

Returns:

  • results \u2013

    Tuple containing the log probability values, actions chosen, rewards obtained, and mask values (if available).

Raises:

  • AssertionError \u2013

    If require_logp is not enabled.

Source code in rl4co/models/zoo/deepaco/antsystem.py
def get_logp(self):\n    \"\"\"Get the log probability (logprobs) values recorded during the execution of the algorithm.\n\n    Returns:\n        results: Tuple containing the log probability values,\n            actions chosen, rewards obtained, and mask values (if available).\n\n    Raises:\n        AssertionError: If `require_logp` is not enabled.\n    \"\"\"\n\n    assert (\n        self.require_logprobs\n    ), \"Please enable `require_logp` to record logprobs values\"\n\n    logprobs_list, actions_list, reward_list, mask_list = [], [], [], []\n\n    for logprobs, actions, reward, mask in self.all_records:\n        logprobs_list.append(logprobs)\n        actions_list.append(actions)\n        reward_list.append(reward)\n        mask_list.append(mask)\n\n    if mask_list[0] is None:\n        mask_list = None\n    else:\n        mask_list = torch.stack(mask_list, 0)\n\n    # reset records\n    self.all_records = []\n\n    return (\n        torch.stack(logprobs_list, 0),\n        torch.stack(actions_list, 0),\n        torch.stack(reward_list, 0),\n        mask_list,\n    )\n
"},{"location":"docs/content/api/zoo/constructive_nar/#models.zoo.deepaco.model.DeepACO","title":"DeepACO","text":"
DeepACO(\n    env: RL4COEnvBase,\n    policy: Optional[DeepACOPolicy] = None,\n    baseline: Union[REINFORCEBaseline, str] = \"no\",\n    policy_kwargs: dict = {},\n    baseline_kwargs: dict = {},\n    **kwargs\n)\n

Bases: REINFORCE

Implements DeepACO: https://arxiv.org/abs/2309.14032.

Parameters:

  • env (RL4COEnvBase) \u2013

    Environment to use for the algorithm

  • policy (Optional[DeepACOPolicy], default: None ) \u2013

    Policy to use for the algorithm

  • baseline (Union[REINFORCEBaseline, str], default: 'no' ) \u2013

    REINFORCE baseline. Defaults to exponential

  • policy_kwargs (dict, default: {} ) \u2013

    Keyword arguments for policy

  • baseline_kwargs (dict, default: {} ) \u2013

    Keyword arguments for baseline

  • **kwargs \u2013

    Keyword arguments passed to the superclass

Source code in rl4co/models/zoo/deepaco/model.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: Optional[DeepACOPolicy] = None,\n    baseline: Union[REINFORCEBaseline, str] = \"no\",\n    policy_kwargs: dict = {},\n    baseline_kwargs: dict = {},\n    **kwargs,\n):\n    if policy is None:\n        policy = DeepACOPolicy(env_name=env.name, **policy_kwargs)\n\n    super().__init__(env, policy, baseline, baseline_kwargs, **kwargs)\n
"},{"location":"docs/content/api/zoo/constructive_nar/#models.zoo.deepaco.policy.DeepACOPolicy","title":"DeepACOPolicy","text":"
DeepACOPolicy(\n    encoder: Optional[NonAutoregressiveEncoder] = None,\n    env_name: str = \"tsp\",\n    temperature: float = 1.0,\n    aco_class: Optional[Type[AntSystem]] = None,\n    aco_kwargs: dict = {},\n    train_with_local_search: bool = True,\n    n_ants: Optional[Union[int, dict]] = None,\n    n_iterations: Optional[Union[int, dict]] = None,\n    ls_reward_aug_W: float = 0.95,\n    **encoder_kwargs\n)\n

Bases: NonAutoregressivePolicy

Implememts DeepACO policy based on :class:NonAutoregressivePolicy. Introduced by Ye et al. (2023): https://arxiv.org/abs/2309.14032. This policy uses a Non-Autoregressive Graph Neural Network to generate heatmaps, which are then used to run Ant Colony Optimization (ACO) to construct solutions.

Parameters:

  • encoder (Optional[NonAutoregressiveEncoder], default: None ) \u2013

    Encoder module. Can be passed by sub-classes

  • env_name (str, default: 'tsp' ) \u2013

    Name of the environment used to initialize embeddings

  • temperature (float, default: 1.0 ) \u2013

    Temperature for the softmax during decoding. Defaults to 0.1.

  • aco_class (Optional[Type[AntSystem]], default: None ) \u2013

    Class representing the ACO algorithm to be used. Defaults to :class:AntSystem.

  • aco_kwargs (dict, default: {} ) \u2013

    Additional arguments to be passed to the ACO algorithm.

  • n_ants (Optional[Union[int, dict]], default: None ) \u2013

    Number of ants to be used in the ACO algorithm. Can be an integer or dictionary. Defaults to 20.

  • n_iterations (Optional[Union[int, dict]], default: None ) \u2013

    Number of iterations to run the ACO algorithm. Can be an integer or dictionary. Defaults to dict(train=1, val=20, test=100).

  • ls_reward_aug_W (float, default: 0.95 ) \u2013

    Coefficient to be used for the reward augmentation with the local search. Defaults to 0.95.

  • encoder_kwargs \u2013

    Additional arguments to be passed to the encoder.

Source code in rl4co/models/zoo/deepaco/policy.py
def __init__(\n    self,\n    encoder: Optional[NonAutoregressiveEncoder] = None,\n    env_name: str = \"tsp\",\n    temperature: float = 1.0,\n    aco_class: Optional[Type[AntSystem]] = None,\n    aco_kwargs: dict = {},\n    train_with_local_search: bool = True,\n    n_ants: Optional[Union[int, dict]] = None,\n    n_iterations: Optional[Union[int, dict]] = None,\n    ls_reward_aug_W: float = 0.95,\n    **encoder_kwargs,\n):\n    if encoder is None:\n        encoder = NARGNNEncoder(**encoder_kwargs)\n\n    super(DeepACOPolicy, self).__init__(\n        encoder=encoder,\n        env_name=env_name,\n        temperature=temperature,\n        train_decode_type=\"multistart_sampling\",\n        val_decode_type=\"multistart_sampling\",\n        test_decode_type=\"multistart_sampling\",\n    )\n\n    self.aco_class = AntSystem if aco_class is None else aco_class\n    self.aco_kwargs = aco_kwargs\n    self.train_with_local_search = train_with_local_search\n    self.n_ants = merge_with_defaults(n_ants, train=30, val=48, test=48)\n    self.n_iterations = merge_with_defaults(n_iterations, train=1, val=5, test=10)\n    self.ls_reward_aug_W = ls_reward_aug_W\n
"},{"location":"docs/content/api/zoo/constructive_nar/#models.zoo.deepaco.policy.DeepACOPolicy.forward","title":"forward","text":"
forward(\n    td_initial: TensorDict,\n    env: Optional[Union[str, RL4COEnvBase]] = None,\n    calc_reward: bool = True,\n    phase: str = \"train\",\n    actions=None,\n    return_actions: bool = True,\n    return_hidden: bool = True,\n    **kwargs\n)\n

Forward method. During validation and testing, the policy runs the ACO algorithm to construct solutions. See :class:NonAutoregressivePolicy for more details during the training phase.

Source code in rl4co/models/zoo/deepaco/policy.py
def forward(\n    self,\n    td_initial: TensorDict,\n    env: Optional[Union[str, RL4COEnvBase]] = None,\n    calc_reward: bool = True,\n    phase: str = \"train\",\n    actions=None,\n    return_actions: bool = True,\n    return_hidden: bool = True,\n    **kwargs,\n):\n    \"\"\"\n    Forward method. During validation and testing, the policy runs the ACO algorithm to construct solutions.\n    See :class:`NonAutoregressivePolicy` for more details during the training phase.\n    \"\"\"\n    n_ants = self.n_ants[phase]\n    # Instantiate environment if needed\n    if (phase != \"train\" or self.ls_reward_aug_W > 0) and (env is None or isinstance(env, str)):\n        env_name = self.env_name if env is None else env\n        env = get_env(env_name)\n\n    if phase == \"train\":\n        select_start_nodes_fn = partial(\n            self.aco_class.select_start_node_fn, start_node=self.aco_kwargs.get(\"start_node\", None)\n        )\n        kwargs.update({\"select_start_nodes_fn\": select_start_nodes_fn})\n        #  we just use the constructive policy\n        outdict = super().forward(\n            td_initial,\n            env,\n            phase=phase,\n            decode_type=\"multistart_sampling\",\n            calc_reward=calc_reward,\n            num_starts=n_ants,\n            actions=actions,\n            return_actions=return_actions,\n            return_hidden=return_hidden,\n            **kwargs,\n        )\n\n        # manually compute the advantage\n        reward = unbatchify(outdict[\"reward\"], n_ants)\n        advantage = reward - reward.mean(dim=1, keepdim=True)\n\n        if self.ls_reward_aug_W > 0 and self.train_with_local_search:\n            heatmap_logits = outdict[\"hidden\"]\n            aco = self.aco_class(\n                heatmap_logits,\n                n_ants=n_ants,\n                temperature=self.aco_kwargs.get(\"temperature\", self.temperature),\n                **self.aco_kwargs,\n            )\n\n            actions = outdict[\"actions\"]\n            _, ls_reward = aco.local_search(batchify(td_initial, n_ants), env, actions)\n\n            ls_reward = unbatchify(ls_reward, n_ants)\n            ls_advantage = ls_reward - ls_reward.mean(dim=1, keepdim=True)\n            advantage = advantage * (1 - self.ls_reward_aug_W) + ls_advantage * self.ls_reward_aug_W\n\n        outdict[\"advantage\"] = advantage\n        outdict[\"log_likelihood\"] = unbatchify(outdict[\"log_likelihood\"], n_ants)\n\n        return outdict\n\n    heatmap_logits, _ = self.encoder(td_initial)\n\n    aco = self.aco_class(\n        heatmap_logits,\n        n_ants=self.n_ants[phase],\n        temperature=self.aco_kwargs.get(\"temperature\", self.temperature),\n        **self.aco_kwargs,\n    )\n    td, actions, reward = aco.run(td_initial, env, self.n_iterations[phase])\n\n    out = {}\n    if calc_reward:\n        out[\"reward\"] = reward\n    if return_actions:\n        out[\"actions\"] = actions\n\n    return out\n
"},{"location":"docs/content/api/zoo/constructive_nar/#nar-gnn","title":"NAR-GNN","text":""},{"location":"docs/content/api/zoo/constructive_nar/#models.zoo.nargnn.policy.NARGNNPolicy","title":"NARGNNPolicy","text":"
NARGNNPolicy(\n    encoder: Optional[NonAutoregressiveEncoder] = None,\n    decoder: Optional[NonAutoregressiveDecoder] = None,\n    embed_dim: int = 64,\n    env_name: str = \"tsp\",\n    init_embedding: Optional[Module] = None,\n    edge_embedding: Optional[Module] = None,\n    graph_network: Optional[Module] = None,\n    heatmap_generator: Optional[Module] = None,\n    num_layers_heatmap_generator: int = 5,\n    num_layers_graph_encoder: int = 15,\n    act_fn=\"silu\",\n    agg_fn=\"mean\",\n    linear_bias: bool = True,\n    train_decode_type: str = \"multistart_sampling\",\n    val_decode_type: str = \"multistart_greedy\",\n    test_decode_type: str = \"multistart_greedy\",\n    **constructive_policy_kw\n)\n

Bases: NonAutoregressivePolicy

Base Non-autoregressive policy for NCO construction methods. This creates a heatmap of NxN for N nodes (i.e., heuristic) that models the probability to go from one node to another for all nodes.

The policy performs the following steps
  1. Encode the environment initial state into node embeddings
  2. Decode (non-autoregressively) to construct the solution to the NCO problem
Warning

The effectiveness of the non-autoregressive approach can vary significantly across different problem types and configurations. It may require careful tuning of the model architecture and decoding strategy to achieve competitive results.

Parameters:

  • encoder (Optional[NonAutoregressiveEncoder], default: None ) \u2013

    Encoder module. Can be passed by sub-classes

  • decoder (Optional[NonAutoregressiveDecoder], default: None ) \u2013

    Decoder module. Note that this moule defaults to the non-autoregressive decoder

  • embed_dim (int, default: 64 ) \u2013

    Dimension of the embeddings

  • env_name (str, default: 'tsp' ) \u2013

    Name of the environment used to initialize embeddings

  • init_embedding (Optional[Module], default: None ) \u2013

    Model to use for the initial embedding. If None, use the default embedding for the environment

  • edge_embedding (Optional[Module], default: None ) \u2013

    Model to use for the edge embedding. If None, use the default embedding for the environment

  • graph_network (Optional[Module], default: None ) \u2013

    Model to use for the graph network. If None, use the default embedding for the environment

  • heatmap_generator (Optional[Module], default: None ) \u2013

    Model to use for the heatmap generator. If None, use the default embedding for the environment

  • num_layers_heatmap_generator (int, default: 5 ) \u2013

    Number of layers in the heatmap generator

  • num_layers_graph_encoder (int, default: 15 ) \u2013

    Number of layers in the graph encoder

  • act_fn \u2013

    Activation function to use in the encoder

  • agg_fn \u2013

    Aggregation function to use in the encoder

  • linear_bias (bool, default: True ) \u2013

    Whether to use bias in the encoder

  • train_decode_type (str, default: 'multistart_sampling' ) \u2013

    Type of decoding during training

  • val_decode_type (str, default: 'multistart_greedy' ) \u2013

    Type of decoding during validation

  • test_decode_type (str, default: 'multistart_greedy' ) \u2013

    Type of decoding during testing

  • **constructive_policy_kw \u2013

    Unused keyword arguments

Source code in rl4co/models/zoo/nargnn/policy.py
def __init__(\n    self,\n    encoder: Optional[NonAutoregressiveEncoder] = None,\n    decoder: Optional[NonAutoregressiveDecoder] = None,\n    embed_dim: int = 64,\n    env_name: str = \"tsp\",\n    init_embedding: Optional[nn.Module] = None,\n    edge_embedding: Optional[nn.Module] = None,\n    graph_network: Optional[nn.Module] = None,\n    heatmap_generator: Optional[nn.Module] = None,\n    num_layers_heatmap_generator: int = 5,\n    num_layers_graph_encoder: int = 15,\n    act_fn=\"silu\",\n    agg_fn=\"mean\",\n    linear_bias: bool = True,\n    train_decode_type: str = \"multistart_sampling\",\n    val_decode_type: str = \"multistart_greedy\",\n    test_decode_type: str = \"multistart_greedy\",\n    **constructive_policy_kw,\n):\n    if len(constructive_policy_kw) > 0:\n        log.warn(f\"Unused kwargs: {constructive_policy_kw}\")\n\n    if encoder is None:\n        encoder = NARGNNEncoder(\n            embed_dim=embed_dim,\n            env_name=env_name,\n            init_embedding=init_embedding,\n            edge_embedding=edge_embedding,\n            graph_network=graph_network,\n            heatmap_generator=heatmap_generator,\n            num_layers_heatmap_generator=num_layers_heatmap_generator,\n            num_layers_graph_encoder=num_layers_graph_encoder,\n            act_fn=act_fn,\n            agg_fn=agg_fn,\n            linear_bias=linear_bias,\n        )\n\n    # The decoder generates logits given the current td and heatmap\n    if decoder is None:\n        decoder = NonAutoregressiveDecoder()\n    else:\n        # check if the decoder has trainable parameters\n        if any(p.requires_grad for p in decoder.parameters()):\n            log.error(\n                \"The decoder contains trainable parameters. This should not happen in a non-autoregressive policy.\"\n            )\n\n    # Pass to constructive policy\n    super(NARGNNPolicy, self).__init__(\n        encoder=encoder,\n        decoder=decoder,\n        env_name=env_name,\n        train_decode_type=train_decode_type,\n        val_decode_type=val_decode_type,\n        test_decode_type=test_decode_type,\n        **constructive_policy_kw,\n    )\n
"},{"location":"docs/content/api/zoo/constructive_nar/#models.zoo.nargnn.encoder.EdgeHeatmapGenerator","title":"EdgeHeatmapGenerator","text":"
EdgeHeatmapGenerator(\n    embed_dim: int,\n    num_layers: int,\n    act_fn: Union[str, Callable] = \"silu\",\n    linear_bias: bool = True,\n    undirected_graph: bool = True,\n)\n

Bases: Module

MLP for converting edge embeddings to heatmaps.

Parameters:

  • embed_dim (int) \u2013

    Dimension of the embeddings

  • num_layers (int) \u2013

    The number of linear layers in the network.

  • act_fn (Union[str, Callable], default: 'silu' ) \u2013

    Activation function. Defaults to \"silu\".

  • linear_bias (bool, default: True ) \u2013

    Use bias in linear layers. Defaults to True.

  • undirected_graph (bool, default: True ) \u2013

    Whether the graph is undirected. Defaults to True.

Source code in rl4co/models/zoo/nargnn/encoder.py
def __init__(\n    self,\n    embed_dim: int,\n    num_layers: int,\n    act_fn: Union[str, Callable] = \"silu\",\n    linear_bias: bool = True,\n    undirected_graph: bool = True,\n) -> None:\n    super(EdgeHeatmapGenerator, self).__init__()\n\n    self.linears = nn.ModuleList(\n        [\n            nn.Linear(embed_dim, embed_dim, bias=linear_bias)\n            for _ in range(num_layers - 1)\n        ]\n    )\n    self.output = nn.Linear(embed_dim, 1, bias=linear_bias)\n\n    self.act = getattr(nn.functional, act_fn) if isinstance(act_fn, str) else act_fn\n\n    self.undirected_graph = undirected_graph\n
"},{"location":"docs/content/api/zoo/constructive_nar/#models.zoo.nargnn.encoder.NARGNNEncoder","title":"NARGNNEncoder","text":"
NARGNNEncoder(\n    embed_dim: int = 64,\n    env_name: str = \"tsp\",\n    init_embedding: Optional[Module] = None,\n    edge_embedding: Optional[Module] = None,\n    graph_network: Optional[Module] = None,\n    heatmap_generator: Optional[Module] = None,\n    num_layers_heatmap_generator: int = 5,\n    num_layers_graph_encoder: int = 15,\n    act_fn=\"silu\",\n    agg_fn=\"mean\",\n    linear_bias: bool = True,\n    k_sparse: Optional[int] = None,\n)\n

Bases: NonAutoregressiveEncoder

Anisotropic Graph Neural Network encoder with edge-gating mechanism as in Joshi et al. (2022), and used in DeepACO (Ye et al., 2023). This creates a heatmap of NxN for N nodes (i.e., heuristic) that models the probability to go from one node to another for all nodes. This model utilizes a multi-layer perceptron (MLP) approach to predict edge attributes directly from the input graph features, which are then transformed into a heatmap representation to facilitate the decoding of the solution. The decoding process is managed by a specified strategy which could vary from simple greedy selection to more complex sampling methods.

Tip

This decoder's performance heavily relies on the ability of the MLP to capture the dependencies between different parts of the solution without the iterative refinement provided by autoregressive models. It is particularly useful in scenarios where the solution space can be effectively explored in a parallelized manner or when the solution components are largely independent.

Parameters:

  • embed_dim (int, default: 64 ) \u2013

    Dimension of the node embeddings

  • env_name (str, default: 'tsp' ) \u2013

    Name of the environment used to initialize embeddings

  • num_layers \u2013

    Number of layers in the encoder

  • init_embedding (Optional[Module], default: None ) \u2013

    Model to use for the initial embedding. If None, use the default embedding for the environment

  • edge_embedding (Optional[Module], default: None ) \u2013

    Model to use for the edge embedding. If None, use the default embedding for the environment

  • graph_network (Optional[Module], default: None ) \u2013

    Model to use for the graph network. If None, use the default network for the environment

  • heatmap_generator (Optional[Module], default: None ) \u2013

    Model to use for the heatmap generator. If None, use the default network for the environment

  • num_layers_heatmap_generator (int, default: 5 ) \u2013

    Number of layers in the heatmap generator

  • num_layers_graph_encoder (int, default: 15 ) \u2013

    Number of layers in the graph encoder

  • act_fn \u2013

    The activation function to use in each GNNLayer, see https://pytorch.org/docs/stable/nn.functional.html#non-linear-activation-functions for available options. Defaults to 'silu'.

  • agg_fn \u2013

    The aggregation function to use in each GNNLayer for pooling features. Options: 'add', 'mean', 'max'. Defaults to 'mean'.

  • linear_bias (bool, default: True ) \u2013

    Use bias in linear layers. Defaults to True.

  • k_sparse (Optional[int], default: None ) \u2013

    Number of edges to keep for each node. Defaults to None.

Source code in rl4co/models/zoo/nargnn/encoder.py
def __init__(\n    self,\n    embed_dim: int = 64,\n    env_name: str = \"tsp\",\n    # TODO: pass network\n    init_embedding: Optional[nn.Module] = None,\n    edge_embedding: Optional[nn.Module] = None,\n    graph_network: Optional[nn.Module] = None,\n    heatmap_generator: Optional[nn.Module] = None,\n    num_layers_heatmap_generator: int = 5,\n    num_layers_graph_encoder: int = 15,\n    act_fn=\"silu\",\n    agg_fn=\"mean\",\n    linear_bias: bool = True,\n    k_sparse: Optional[int] = None,\n):\n    super(NonAutoregressiveEncoder, self).__init__()\n    self.env_name = env_name\n\n    self.init_embedding = (\n        env_init_embedding(self.env_name, {\"embed_dim\": embed_dim})\n        if init_embedding is None\n        else init_embedding\n    )\n\n    self.edge_embedding = (\n        env_edge_embedding(self.env_name, {\"embed_dim\": embed_dim, \"k_sparse\": k_sparse})\n        if edge_embedding is None\n        else edge_embedding\n    )\n\n    self.graph_network = (\n        GNNEncoder(\n            embed_dim=embed_dim,\n            num_layers=num_layers_graph_encoder,\n            act_fn=act_fn,\n            agg_fn=agg_fn,\n        )\n        if graph_network is None\n        else graph_network\n    )\n\n    self.heatmap_generator = (\n        EdgeHeatmapGenerator(\n            embed_dim=embed_dim,\n            num_layers=num_layers_heatmap_generator,\n            linear_bias=linear_bias,\n        )\n        if heatmap_generator is None\n        else heatmap_generator\n    )\n
"},{"location":"docs/content/api/zoo/constructive_nar/#models.zoo.nargnn.encoder.NARGNNEncoder.forward","title":"forward","text":"
forward(td: TensorDict)\n

Forward pass of the encoder. Transform the input TensorDict into the latent representation.

Source code in rl4co/models/zoo/nargnn/encoder.py
def forward(self, td: TensorDict):\n    \"\"\"Forward pass of the encoder.\n    Transform the input TensorDict into the latent representation.\n    \"\"\"\n    # Transfer to embedding space\n    node_embed = self.init_embedding(td)\n    graph = self.edge_embedding(td, node_embed)\n\n    # Process embedding into graph\n    # TODO: standardize?\n    graph.x, graph.edge_attr = self.graph_network(\n        graph.x, graph.edge_index, graph.edge_attr\n    )\n\n    # Generate heatmap logits\n    heatmap_logits = self.heatmap_generator(graph)\n\n    # Return latent representation (i.e. heatmap logits) and initial embeddings\n    return heatmap_logits, node_embed\n
"},{"location":"docs/content/api/zoo/constructive_nar/#models.zoo.nargnn.encoder.NARGNNNodeEncoder","title":"NARGNNNodeEncoder","text":"
NARGNNNodeEncoder(\n    embed_dim: int = 64,\n    env_name: str = \"tsp\",\n    init_embedding: Optional[Module] = None,\n    edge_embedding: Optional[Module] = None,\n    graph_network: Optional[Module] = None,\n    heatmap_generator: Optional[Module] = None,\n    num_layers_heatmap_generator: int = 5,\n    num_layers_graph_encoder: int = 15,\n    act_fn=\"silu\",\n    agg_fn=\"mean\",\n    linear_bias: bool = True,\n    k_sparse: Optional[int] = None,\n)\n

Bases: NARGNNEncoder

In this case, we just use the node embeddings from the graph without transforming them into a heatmap.

Source code in rl4co/models/zoo/nargnn/encoder.py
def __init__(\n    self,\n    embed_dim: int = 64,\n    env_name: str = \"tsp\",\n    # TODO: pass network\n    init_embedding: Optional[nn.Module] = None,\n    edge_embedding: Optional[nn.Module] = None,\n    graph_network: Optional[nn.Module] = None,\n    heatmap_generator: Optional[nn.Module] = None,\n    num_layers_heatmap_generator: int = 5,\n    num_layers_graph_encoder: int = 15,\n    act_fn=\"silu\",\n    agg_fn=\"mean\",\n    linear_bias: bool = True,\n    k_sparse: Optional[int] = None,\n):\n    super(NonAutoregressiveEncoder, self).__init__()\n    self.env_name = env_name\n\n    self.init_embedding = (\n        env_init_embedding(self.env_name, {\"embed_dim\": embed_dim})\n        if init_embedding is None\n        else init_embedding\n    )\n\n    self.edge_embedding = (\n        env_edge_embedding(self.env_name, {\"embed_dim\": embed_dim, \"k_sparse\": k_sparse})\n        if edge_embedding is None\n        else edge_embedding\n    )\n\n    self.graph_network = (\n        GNNEncoder(\n            embed_dim=embed_dim,\n            num_layers=num_layers_graph_encoder,\n            act_fn=act_fn,\n            agg_fn=agg_fn,\n        )\n        if graph_network is None\n        else graph_network\n    )\n\n    self.heatmap_generator = (\n        EdgeHeatmapGenerator(\n            embed_dim=embed_dim,\n            num_layers=num_layers_heatmap_generator,\n            linear_bias=linear_bias,\n        )\n        if heatmap_generator is None\n        else heatmap_generator\n    )\n
"},{"location":"docs/content/api/zoo/constructive_nar/#models.zoo.nargnn.encoder.NARGNNNodeEncoder.forward","title":"forward","text":"
forward(td: TensorDict)\n

Forward pass of the encoder. Transform the input TensorDict into the latent representation.

Source code in rl4co/models/zoo/nargnn/encoder.py
def forward(self, td: TensorDict):\n    # Transfer to embedding space\n    node_embed = self.init_embedding(td)\n    graph = self.edge_embedding(td, node_embed)\n\n    # Process embedding into graph\n    # TODO: standardize?\n    graph.x, graph.edge_attr = self.graph_network(\n        graph.x, graph.edge_index, graph.edge_attr\n    )\n\n    proc_embeds = graph.x\n    batch_size = node_embed.shape[0]\n    # reshape proc_embeds from [bs*n, h] to [bs, n, h]\n    proc_embeds = proc_embeds.reshape(batch_size, -1, proc_embeds.shape[1])\n    return proc_embeds, node_embed\n
"},{"location":"docs/content/api/zoo/improvement/","title":"Improvement Methods","text":"

These methods are trained to improve existing solutions iteratively, akin to local search algorithms. They focus on refining existing solutions rather than generating them from scratch.

"},{"location":"docs/content/api/zoo/improvement/#dact","title":"DACT","text":""},{"location":"docs/content/api/zoo/improvement/#models.zoo.dact.encoder.DACTEncoder","title":"DACTEncoder","text":"
DACTEncoder(\n    embed_dim: int = 64,\n    init_embedding: Module = None,\n    pos_embedding: Module = None,\n    env_name: str = \"tsp_kopt\",\n    pos_type: str = \"CPE\",\n    num_heads: int = 4,\n    num_layers: int = 3,\n    normalization: str = \"layer\",\n    feedforward_hidden: int = 64,\n)\n

Bases: ImprovementEncoder

Dual-Aspect Collaborative Transformer Encoder as in Ma et al. (2021)

Parameters:

  • embed_dim (int, default: 64 ) \u2013

    Dimension of the embedding space

  • init_embedding (Module, default: None ) \u2013

    Module to use for the initialization of the node embeddings

  • pos_embedding (Module, default: None ) \u2013

    Module to use for the initialization of the positional embeddings

  • env_name (str, default: 'tsp_kopt' ) \u2013

    Name of the environment used to initialize embeddings

  • pos_type (str, default: 'CPE' ) \u2013

    Name of the used positional encoding method (CPE or APE)

  • num_heads (int, default: 4 ) \u2013

    Number of heads in the attention layers

  • num_layers (int, default: 3 ) \u2013

    Number of layers in the attention network

  • normalization (str, default: 'layer' ) \u2013

    Normalization type in the attention layers

  • feedforward_hidden (int, default: 64 ) \u2013

    Hidden dimension in the feedforward layers

Source code in rl4co/models/zoo/dact/encoder.py
def __init__(\n    self,\n    embed_dim: int = 64,\n    init_embedding: nn.Module = None,\n    pos_embedding: nn.Module = None,\n    env_name: str = \"tsp_kopt\",\n    pos_type: str = \"CPE\",\n    num_heads: int = 4,\n    num_layers: int = 3,\n    normalization: str = \"layer\",\n    feedforward_hidden: int = 64,\n):\n    super(DACTEncoder, self).__init__(\n        embed_dim=embed_dim,\n        env_name=env_name,\n        pos_type=pos_type,\n        num_heads=num_heads,\n        num_layers=num_layers,\n        normalization=normalization,\n        feedforward_hidden=feedforward_hidden,\n    )\n\n    assert self.env_name in [\"tsp_kopt\"], NotImplementedError()\n\n    self.net = AdaptiveSequential(\n        *(\n            DACTEncoderLayer(\n                num_heads,\n                embed_dim,\n                feedforward_hidden,\n                normalization,\n            )\n            for _ in range(num_layers)\n        )\n    )\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.dact.decoder.DACTDecoder","title":"DACTDecoder","text":"
DACTDecoder(embed_dim: int = 64, num_heads: int = 4)\n

Bases: ImprovementDecoder

DACT decoder based on Ma et al. (2021) Given the environment state and the dual sets of embeddings (PFE, NFE embeddings), compute the logits for selecting two nodes for the 2-opt local search from the current solution

Parameters:

  • embed_dim (int, default: 64 ) \u2013

    Embedding dimension

  • num_heads (int, default: 4 ) \u2013

    Number of attention heads

Source code in rl4co/models/zoo/dact/decoder.py
def __init__(\n    self,\n    embed_dim: int = 64,\n    num_heads: int = 4,\n):\n    super().__init__()\n    self.embed_dim = embed_dim\n    self.n_heads = num_heads\n    self.hidden_dim = embed_dim\n\n    # for MHC sublayer (NFE aspect)\n    self.compater_node = MultiHeadCompat(\n        num_heads, embed_dim, embed_dim, embed_dim, embed_dim\n    )\n\n    # for MHC sublayer (PFE aspect)\n    self.compater_pos = MultiHeadCompat(\n        num_heads, embed_dim, embed_dim, embed_dim, embed_dim\n    )\n\n    self.norm_factor = 1 / math.sqrt(1 * self.hidden_dim)\n\n    # for Max-Pooling sublayer\n    self.project_graph_pos = nn.Linear(self.embed_dim, self.embed_dim, bias=False)\n    self.project_graph_node = nn.Linear(self.embed_dim, self.embed_dim, bias=False)\n    self.project_node_pos = nn.Linear(self.embed_dim, self.embed_dim, bias=False)\n    self.project_node_node = nn.Linear(self.embed_dim, self.embed_dim, bias=False)\n\n    # for feed-forward aggregation (FFA)sublayer\n    self.value_head = MLP(\n        input_dim=2 * self.n_heads,\n        output_dim=1,\n        num_neurons=[32, 32],\n        dropout_probs=[0.05, 0.00],\n    )\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.dact.decoder.DACTDecoder.forward","title":"forward","text":"
forward(\n    td: TensorDict, final_h: Tensor, final_p: Tensor\n) -> Tensor\n

Compute the logits of the removing a node pair from the current solution

Parameters:

  • td (TensorDict) \u2013

    TensorDict with the current environment state

  • final_h (Tensor) \u2013

    final NFE embeddings

  • final_p (Tensor) \u2013

    final pfe embeddings

Source code in rl4co/models/zoo/dact/decoder.py
def forward(self, td: TensorDict, final_h: Tensor, final_p: Tensor) -> Tensor:\n    \"\"\"Compute the logits of the removing a node pair from the current solution\n\n    Args:\n        td: TensorDict with the current environment state\n        final_h: final NFE embeddings\n        final_p: final pfe embeddings\n    \"\"\"\n\n    batch_size, graph_size, dim = final_h.size()\n\n    # Max-Pooling sublayer\n    h_node_refined = self.project_node_node(final_h) + self.project_graph_node(\n        final_h.max(1)[0]\n    )[:, None, :].expand(batch_size, graph_size, dim)\n    h_pos_refined = self.project_node_pos(final_p) + self.project_graph_pos(\n        final_p.max(1)[0]\n    )[:, None, :].expand(batch_size, graph_size, dim)\n\n    # MHC sublayer\n    compatibility = torch.zeros(\n        (batch_size, graph_size, graph_size, self.n_heads * 2),\n        device=h_node_refined.device,\n    )\n    compatibility[:, :, :, : self.n_heads] = self.compater_pos(h_pos_refined).permute(\n        1, 2, 3, 0\n    )\n    compatibility[:, :, :, self.n_heads :] = self.compater_node(\n        h_node_refined\n    ).permute(1, 2, 3, 0)\n\n    # FFA sublater\n    return self.value_head(self.norm_factor * compatibility).squeeze(-1)\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.dact.policy.DACTPolicy","title":"DACTPolicy","text":"
DACTPolicy(\n    embed_dim: int = 64,\n    num_encoder_layers: int = 3,\n    num_heads: int = 4,\n    normalization: str = \"layer\",\n    feedforward_hidden: int = 64,\n    env_name: str = \"tsp_kopt\",\n    pos_type: str = \"CPE\",\n    init_embedding: Module = None,\n    pos_embedding: Module = None,\n    temperature: float = 1.0,\n    tanh_clipping: float = 6.0,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"sampling\",\n    test_decode_type: str = \"sampling\",\n)\n

Bases: ImprovementPolicy

DACT Policy based on Ma et al. (2021) This model first encodes the input graph and current solution using a DACT encoder (:class:DACTEncoder) and then decodes the 2-opt action (:class:DACTDecoder)

Parameters:

  • embed_dim (int, default: 64 ) \u2013

    Dimension of the node embeddings

  • num_encoder_layers (int, default: 3 ) \u2013

    Number of layers in the encoder

  • num_heads (int, default: 4 ) \u2013

    Number of heads in the attention layers

  • normalization (str, default: 'layer' ) \u2013

    Normalization type in the attention layers

  • feedforward_hidden (int, default: 64 ) \u2013

    Dimension of the hidden layer in the feedforward network

  • env_name (str, default: 'tsp_kopt' ) \u2013

    Name of the environment used to initialize embeddings

  • pos_type (str, default: 'CPE' ) \u2013

    Name of the used positional encoding method (CPE or APE)

  • init_embedding (Module, default: None ) \u2013

    Module to use for the initialization of the embeddings

  • pos_embedding (Module, default: None ) \u2013

    Module to use for the initialization of the positional embeddings

  • temperature (float, default: 1.0 ) \u2013

    Temperature for the softmax

  • tanh_clipping (float, default: 6.0 ) \u2013

    Tanh clipping value (see Bello et al., 2016)

  • train_decode_type (str, default: 'sampling' ) \u2013

    Type of decoding to use during training

  • val_decode_type (str, default: 'sampling' ) \u2013

    Type of decoding to use during validation

  • test_decode_type (str, default: 'sampling' ) \u2013

    Type of decoding to use during testing

Source code in rl4co/models/zoo/dact/policy.py
def __init__(\n    self,\n    embed_dim: int = 64,\n    num_encoder_layers: int = 3,\n    num_heads: int = 4,\n    normalization: str = \"layer\",\n    feedforward_hidden: int = 64,\n    env_name: str = \"tsp_kopt\",\n    pos_type: str = \"CPE\",\n    init_embedding: nn.Module = None,\n    pos_embedding: nn.Module = None,\n    temperature: float = 1.0,\n    tanh_clipping: float = 6.0,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"sampling\",\n    test_decode_type: str = \"sampling\",\n):\n    super(DACTPolicy, self).__init__()\n\n    self.env_name = env_name\n\n    # Encoder and decoder\n    self.encoder = DACTEncoder(\n        embed_dim=embed_dim,\n        init_embedding=init_embedding,\n        pos_embedding=pos_embedding,\n        env_name=env_name,\n        pos_type=pos_type,\n        num_heads=num_heads,\n        num_layers=num_encoder_layers,\n        normalization=normalization,\n        feedforward_hidden=feedforward_hidden,\n    )\n\n    self.decoder = DACTDecoder(embed_dim=embed_dim, num_heads=num_heads)\n\n    # Decoding strategies\n    self.temperature = temperature\n    self.tanh_clipping = tanh_clipping\n    self.train_decode_type = train_decode_type\n    self.val_decode_type = val_decode_type\n    self.test_decode_type = test_decode_type\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.dact.policy.DACTPolicy.forward","title":"forward","text":"
forward(\n    td: TensorDict,\n    env: Union[str, RL4COEnvBase] = None,\n    phase: str = \"train\",\n    return_actions: bool = False,\n    return_embeds: bool = False,\n    only_return_embed: bool = False,\n    actions=None,\n    **decoding_kwargs\n) -> dict\n

Forward pass of the policy.

Parameters:

  • td (TensorDict) \u2013

    TensorDict containing the environment state

  • env (Union[str, RL4COEnvBase], default: None ) \u2013

    Environment to use for decoding. If None, the environment is instantiated from env_name. Note that it is more efficient to pass an already instantiated environment each time for fine-grained control

  • phase (str, default: 'train' ) \u2013

    Phase of the algorithm (train, val, test)

  • return_actions (bool, default: False ) \u2013

    Whether to return the actions

  • actions \u2013

    Actions to use for evaluating the policy. If passed, use these actions instead of sampling from the policy to calculate log likelihood

  • decoding_kwargs \u2013

    Keyword arguments for the decoding strategy. See :class:rl4co.utils.decoding.DecodingStrategy for more information.

Returns:

  • out ( dict ) \u2013

    Dictionary containing the reward, log likelihood, and optionally the actions and entropy

Source code in rl4co/models/zoo/dact/policy.py
def forward(\n    self,\n    td: TensorDict,\n    env: Union[str, RL4COEnvBase] = None,\n    phase: str = \"train\",\n    return_actions: bool = False,\n    return_embeds: bool = False,\n    only_return_embed: bool = False,\n    actions=None,\n    **decoding_kwargs,\n) -> dict:\n    \"\"\"Forward pass of the policy.\n\n    Args:\n        td: TensorDict containing the environment state\n        env: Environment to use for decoding. If None, the environment is instantiated from `env_name`. Note that\n            it is more efficient to pass an already instantiated environment each time for fine-grained control\n        phase: Phase of the algorithm (train, val, test)\n        return_actions: Whether to return the actions\n        actions: Actions to use for evaluating the policy.\n            If passed, use these actions instead of sampling from the policy to calculate log likelihood\n        decoding_kwargs: Keyword arguments for the decoding strategy. See :class:`rl4co.utils.decoding.DecodingStrategy` for more information.\n\n    Returns:\n        out: Dictionary containing the reward, log likelihood, and optionally the actions and entropy\n    \"\"\"\n\n    # Encoder: get encoder output and initial embeddings from initial state\n    NFE, PFE = self.encoder(td)\n    h_featrues = torch.cat((NFE, PFE), -1)\n\n    if only_return_embed:\n        return {\"embeds\": h_featrues.detach()}\n\n    # Instantiate environment if needed\n    if isinstance(env, str) or env is None:\n        env_name = self.env_name if env is None else env\n        log.info(f\"Instantiated environment not provided; instantiating {env_name}\")\n        env = get_env(env_name)\n    assert env.two_opt_mode, \"DACT only support 2-opt\"\n\n    # Get decode type depending on phase and whether actions are passed for evaluation\n    decode_type = decoding_kwargs.pop(\"decode_type\", None)\n    if actions is not None:\n        decode_type = \"evaluate\"\n    elif decode_type is None:\n        decode_type = getattr(self, f\"{phase}_decode_type\")\n\n    # Setup decoding strategy\n    # we pop arguments that are not part of the decoding strategy\n    decode_strategy: DecodingStrategy = get_decoding_strategy(\n        decode_type,\n        temperature=decoding_kwargs.pop(\"temperature\", self.temperature),\n        tanh_clipping=decoding_kwargs.pop(\"tanh_clipping\", self.tanh_clipping),\n        mask_logits=True,\n        improvement_method_mode=True,\n        **decoding_kwargs,\n    )\n\n    # Perform the decoding\n    batch_size, seq_length = td[\"rec_current\"].size()\n    logits = self.decoder(td, NFE, PFE).view(batch_size, -1)\n\n    # Get mask\n    mask = env.get_mask(td)\n    if \"action\" in td.keys():\n        mask[torch.arange(batch_size), td[\"action\"][:, 0], td[\"action\"][:, 1]] = False\n        mask[torch.arange(batch_size), td[\"action\"][:, 1], td[\"action\"][:, 0]] = False\n    mask = mask.view(batch_size, -1)\n\n    # Get action and log-likelihood\n    logprob, action_sampled = decode_strategy.step(\n        logits,\n        mask,\n        action=actions[:, 0] * seq_length + actions[:, 1]\n        if actions is not None\n        else None,\n    )\n    action_sampled = action_sampled.unsqueeze(-1)\n    if phase == \"train\":\n        log_likelihood = logprob.gather(1, action_sampled)\n    else:\n        log_likelihood = torch.zeros(batch_size, device=td.device)\n\n    ## return\n    DACT_action = torch.cat(\n        (\n            action_sampled // seq_length,\n            action_sampled % seq_length,\n        ),\n        -1,\n    )\n\n    outdict = {\"log_likelihood\": log_likelihood, \"cost_bsf\": td[\"cost_bsf\"]}\n    td.set(\"action\", DACT_action)\n\n    if return_embeds:\n        outdict[\"embeds\"] = h_featrues.detach()\n\n    if return_actions:\n        outdict[\"actions\"] = DACT_action\n\n    return outdict\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.dact.model.DACT","title":"DACT","text":"
DACT(\n    env: RL4COEnvBase,\n    policy: Module = None,\n    critic: CriticNetwork = None,\n    policy_kwargs: dict = {},\n    critic_kwargs: dict = {},\n    **kwargs\n)\n

Bases: n_step_PPO

DACT Model based on n_step Proximal Policy Optimization (PPO) with an DACT model policy. We default to the DACT model policy and the improvement Critic Network.

Parameters:

  • env (RL4COEnvBase) \u2013

    Environment to use for the algorithm

  • policy (Module, default: None ) \u2013

    Policy to use for the algorithm

  • critic (CriticNetwork, default: None ) \u2013

    Critic to use for the algorithm

  • policy_kwargs (dict, default: {} ) \u2013

    Keyword arguments for policy

  • critic_kwargs (dict, default: {} ) \u2013

    Keyword arguments for critic

Source code in rl4co/models/zoo/dact/model.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: nn.Module = None,\n    critic: CriticNetwork = None,\n    policy_kwargs: dict = {},\n    critic_kwargs: dict = {},\n    **kwargs,\n):\n    if policy is None:\n        policy = DACTPolicy(env_name=env.name, **policy_kwargs)\n\n    if critic is None:\n        embed_dim = (\n            policy_kwargs[\"embed_dim\"] * 2 if \"embed_dim\" in policy_kwargs else 128\n        )  # the critic's embed_dim must be as policy's\n\n        encoder = MultiHeadAttentionLayer(\n            embed_dim,\n            critic_kwargs[\"num_heads\"] if \"num_heads\" in critic_kwargs else 4,\n            critic_kwargs[\"feedforward_hidden\"] * 2\n            if \"feedforward_hidden\" in critic_kwargs\n            else 128,\n            critic_kwargs[\"normalization\"]\n            if \"normalization\" in critic_kwargs\n            else \"layer\",\n            bias=False,\n        )\n        value_head = CriticDecoder(embed_dim)\n\n        critic = CriticNetwork(\n            encoder=encoder,\n            value_head=value_head,\n            customized=True,\n        )\n\n    super().__init__(env, policy, critic, **kwargs)\n
"},{"location":"docs/content/api/zoo/improvement/#n2s","title":"N2S","text":""},{"location":"docs/content/api/zoo/improvement/#models.zoo.n2s.encoder.N2SEncoder","title":"N2SEncoder","text":"
N2SEncoder(\n    embed_dim: int = 128,\n    init_embedding: Module = None,\n    pos_embedding: Module = None,\n    env_name: str = \"pdp_ruin_repair\",\n    pos_type: str = \"CPE\",\n    num_heads: int = 4,\n    num_layers: int = 3,\n    normalization: str = \"layer\",\n    feedforward_hidden: int = 128,\n)\n

Bases: ImprovementEncoder

Neural Neighborhood Search Encoder as in Ma et al. (2022) First embed the input and then process it with a Graph AttepdN2ntion Network.

Parameters:

  • embed_dim (int, default: 128 ) \u2013

    Dimension of the embedding space

  • init_embedding (Module, default: None ) \u2013

    Module to use for the initialization of the node embeddings

  • pos_embedding (Module, default: None ) \u2013

    Module to use for the initialization of the positional embeddings

  • env_name (str, default: 'pdp_ruin_repair' ) \u2013

    Name of the environment used to initialize embeddings

  • pos_type (str, default: 'CPE' ) \u2013

    Name of the used positional encoding method (CPE or APE)

  • num_heads (int, default: 4 ) \u2013

    Number of heads in the attention layers

  • num_layers (int, default: 3 ) \u2013

    Number of layers in the attention network

  • normalization (str, default: 'layer' ) \u2013

    Normalization type in the attention layers

  • feedforward_hidden (int, default: 128 ) \u2013

    Hidden dimension in the feedforward layers

Source code in rl4co/models/zoo/n2s/encoder.py
def __init__(\n    self,\n    embed_dim: int = 128,\n    init_embedding: nn.Module = None,\n    pos_embedding: nn.Module = None,\n    env_name: str = \"pdp_ruin_repair\",\n    pos_type: str = \"CPE\",\n    num_heads: int = 4,\n    num_layers: int = 3,\n    normalization: str = \"layer\",\n    feedforward_hidden: int = 128,\n):\n    super(N2SEncoder, self).__init__(\n        embed_dim=embed_dim,\n        init_embedding=init_embedding,\n        pos_embedding=pos_embedding,\n        env_name=env_name,\n        pos_type=pos_type,\n        num_heads=num_heads,\n        num_layers=num_layers,\n        normalization=normalization,\n        feedforward_hidden=feedforward_hidden,\n    )\n\n    self.pos_net = MultiHeadCompat(num_heads, embed_dim, feedforward_hidden)\n\n    self.net = AdaptiveSequential(\n        *(\n            N2SEncoderLayer(\n                num_heads,\n                embed_dim,\n                feedforward_hidden,\n                normalization,\n            )\n            for _ in range(num_layers)\n        )\n    )\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.n2s.decoder.NodePairRemovalDecoder","title":"NodePairRemovalDecoder","text":"
NodePairRemovalDecoder(\n    embed_dim: int = 128, num_heads: int = 4\n)\n

Bases: ImprovementDecoder

N2S Node-Pair Removal decoder based on Ma et al. (2022) Given the environment state and the node embeddings (positional embeddings are discarded), compute the logits for selecting a pair of pickup and delivery nodes for node pair removal from the current solution

Parameters:

  • embed_dim (int, default: 128 ) \u2013

    Embedding dimension

  • num_heads (int, default: 4 ) \u2013

    Number of attention heads

Source code in rl4co/models/zoo/n2s/decoder.py
def __init__(\n    self,\n    embed_dim: int = 128,\n    num_heads: int = 4,\n):\n    super().__init__()\n    self.input_dim = embed_dim\n    self.n_heads = num_heads\n    self.hidden_dim = embed_dim\n\n    assert embed_dim % num_heads == 0\n\n    self.W_Q = nn.Parameter(\n        torch.Tensor(self.n_heads, self.input_dim, self.hidden_dim)\n    )\n    self.W_K = nn.Parameter(\n        torch.Tensor(self.n_heads, self.input_dim, self.hidden_dim)\n    )\n\n    self.agg = MLP(input_dim=2 * self.n_heads + 4, output_dim=1, num_neurons=[32, 32])\n\n    self.init_parameters()\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.n2s.decoder.NodePairRemovalDecoder.forward","title":"forward","text":"
forward(\n    td: TensorDict, final_h: Tensor, final_p: Tensor\n) -> Tensor\n

Compute the logits of the removing a node pair from the current solution

Parameters:

  • td (TensorDict) \u2013

    TensorDict with the current environment state

  • final_h (Tensor) \u2013

    final node embeddings

  • final_p (Tensor) \u2013

    final positional embeddings

Source code in rl4co/models/zoo/n2s/decoder.py
def forward(self, td: TensorDict, final_h: Tensor, final_p: Tensor) -> Tensor:\n    \"\"\"Compute the logits of the removing a node pair from the current solution\n\n    Args:\n        td: TensorDict with the current environment state\n        final_h: final node embeddings\n        final_p: final positional embeddings\n    \"\"\"\n\n    selection_recent = torch.cat(\n        (td[\"action_record\"][:, -3:], td[\"action_record\"].mean(1, True)), 1\n    )\n    solution = td[\"rec_current\"]\n\n    pre = solution.argsort()  # pre=[1,2,0]\n    post = solution.gather(\n        1, solution\n    )  # post=[1,2,0] # the second neighbour works better\n    batch_size, graph_size_plus1, input_dim = final_h.size()\n\n    hflat = final_h.contiguous().view(-1, input_dim)  #################   reshape\n\n    shp = (self.n_heads, batch_size, graph_size_plus1, self.hidden_dim)\n\n    # Calculate queries, (n_heads, batch_size, graph_size+1, key_size)\n    hidden_Q = torch.matmul(hflat, self.W_Q).view(shp)\n    hidden_K = torch.matmul(hflat, self.W_K).view(shp)\n\n    Q_pre = hidden_Q.gather(\n        2, pre.view(1, batch_size, graph_size_plus1, 1).expand_as(hidden_Q)\n    )\n    K_post = hidden_K.gather(\n        2, post.view(1, batch_size, graph_size_plus1, 1).expand_as(hidden_Q)\n    )\n\n    compatibility = (\n        (Q_pre * hidden_K).sum(-1)\n        + (hidden_Q * K_post).sum(-1)\n        - (Q_pre * K_post).sum(-1)\n    )[\n        :, :, 1:\n    ]  # (n_heads, batch_size, graph_size) (12)\n\n    compatibility_pairing = torch.cat(\n        (\n            compatibility[:, :, : graph_size_plus1 // 2],\n            compatibility[:, :, graph_size_plus1 // 2 :],\n        ),\n        0,\n    )  # (n_heads*2, batch_size, graph_size/2)\n\n    compatibility_pairing = self.agg(\n        torch.cat(\n            (\n                compatibility_pairing.permute(1, 2, 0),\n                selection_recent.permute(0, 2, 1),\n            ),\n            -1,\n        )\n    ).squeeze()  # (batch_size, graph_size/2)\n\n    return compatibility_pairing\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.n2s.decoder.NodePairReinsertionDecoder","title":"NodePairReinsertionDecoder","text":"
NodePairReinsertionDecoder(\n    embed_dim: int = 128, num_heads: int = 4\n)\n

Bases: ImprovementDecoder

N2S Node-Pair Reinsertion decoder based on Ma et al. (2022) Given the environment state, the node embeddings (positional embeddings are discarded), and the removed node from the NodePairRemovalDecoder, compute the logits for finding places to re-insert the removed pair of pickup and delivery nodes to form a new solution

Parameters:

  • embed_dim (int, default: 128 ) \u2013

    Embedding dimension

  • num_heads (int, default: 4 ) \u2013

    Number of attention heads

Source code in rl4co/models/zoo/n2s/decoder.py
def __init__(\n    self,\n    embed_dim: int = 128,\n    num_heads: int = 4,\n):\n    super().__init__()\n    self.input_dim = embed_dim\n    self.n_heads = num_heads\n    self.hidden_dim = embed_dim\n\n    assert embed_dim % num_heads == 0\n\n    self.compater_insert1 = MultiHeadCompat(\n        num_heads, embed_dim, embed_dim, embed_dim, embed_dim\n    )\n\n    self.compater_insert2 = MultiHeadCompat(\n        num_heads, embed_dim, embed_dim, embed_dim, embed_dim\n    )\n\n    self.agg = MLP(input_dim=4 * self.n_heads, output_dim=1, num_neurons=[32, 32])\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.n2s.policy.N2SPolicy","title":"N2SPolicy","text":"
N2SPolicy(\n    embed_dim: int = 128,\n    num_encoder_layers: int = 3,\n    num_heads: int = 4,\n    normalization: str = \"layer\",\n    feedforward_hidden: int = 128,\n    env_name: str = \"pdp_ruin_repair\",\n    pos_type: str = \"CPE\",\n    init_embedding: Module = None,\n    pos_embedding: Module = None,\n    temperature: float = 1.0,\n    tanh_clipping: float = 6.0,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"sampling\",\n    test_decode_type: str = \"sampling\",\n)\n

Bases: ImprovementPolicy

N2S Policy based on Ma et al. (2022) This model first encodes the input graph and current solution using a N2S encoder (:class:N2SEncoder) and then decodes the node-pair removal and reinsertion action using the Node-Pair Removal (:class:NodePairRemovalDecoder) and Reinsertion (:class:NodePairReinsertionDecoder) decoders

Parameters:

  • embed_dim (int, default: 128 ) \u2013

    Dimension of the node embeddings

  • num_encoder_layers (int, default: 3 ) \u2013

    Number of layers in the encoder

  • num_heads (int, default: 4 ) \u2013

    Number of heads in the attention layers

  • normalization (str, default: 'layer' ) \u2013

    Normalization type in the attention layers

  • feedforward_hidden (int, default: 128 ) \u2013

    Dimension of the hidden layer in the feedforward network

  • env_name (str, default: 'pdp_ruin_repair' ) \u2013

    Name of the environment used to initialize embeddings

  • pos_type (str, default: 'CPE' ) \u2013

    Name of the used positional encoding method (CPE or APE)

  • init_embedding (Module, default: None ) \u2013

    Module to use for the initialization of the embeddings

  • pos_embedding (Module, default: None ) \u2013

    Module to use for the initialization of the positional embeddings

  • temperature (float, default: 1.0 ) \u2013

    Temperature for the softmax

  • tanh_clipping (float, default: 6.0 ) \u2013

    Tanh clipping value (see Bello et al., 2016)

  • train_decode_type (str, default: 'sampling' ) \u2013

    Type of decoding to use during training

  • val_decode_type (str, default: 'sampling' ) \u2013

    Type of decoding to use during validation

  • test_decode_type (str, default: 'sampling' ) \u2013

    Type of decoding to use during testing

Source code in rl4co/models/zoo/n2s/policy.py
def __init__(\n    self,\n    embed_dim: int = 128,\n    num_encoder_layers: int = 3,\n    num_heads: int = 4,\n    normalization: str = \"layer\",\n    feedforward_hidden: int = 128,\n    env_name: str = \"pdp_ruin_repair\",\n    pos_type: str = \"CPE\",\n    init_embedding: nn.Module = None,\n    pos_embedding: nn.Module = None,\n    temperature: float = 1.0,\n    tanh_clipping: float = 6.0,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"sampling\",\n    test_decode_type: str = \"sampling\",\n):\n    super(N2SPolicy, self).__init__()\n\n    self.env_name = env_name\n\n    # Encoder and decoder\n    self.encoder = N2SEncoder(\n        embed_dim=embed_dim,\n        init_embedding=init_embedding,\n        pos_embedding=pos_embedding,\n        env_name=env_name,\n        pos_type=pos_type,\n        num_heads=num_heads,\n        num_layers=num_encoder_layers,\n        normalization=normalization,\n        feedforward_hidden=feedforward_hidden,\n    )\n\n    self.removal_decoder = NodePairRemovalDecoder(\n        embed_dim=embed_dim, num_heads=num_heads\n    )\n\n    self.reinsertion_decoder = NodePairReinsertionDecoder(\n        embed_dim=embed_dim, num_heads=num_heads\n    )\n\n    self.project_graph = nn.Linear(embed_dim, embed_dim, bias=False)\n    self.project_node = nn.Linear(embed_dim, embed_dim, bias=False)\n\n    # Decoding strategies\n    self.temperature = temperature\n    self.tanh_clipping = tanh_clipping\n    self.train_decode_type = train_decode_type\n    self.val_decode_type = val_decode_type\n    self.test_decode_type = test_decode_type\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.n2s.policy.N2SPolicy.forward","title":"forward","text":"
forward(\n    td: TensorDict,\n    env: Union[str, RL4COEnvBase] = None,\n    phase: str = \"train\",\n    return_actions: bool = False,\n    return_embeds: bool = False,\n    only_return_embed: bool = False,\n    actions=None,\n    **decoding_kwargs\n) -> dict\n

Forward pass of the policy.

Parameters:

  • td (TensorDict) \u2013

    TensorDict containing the environment state

  • env (Union[str, RL4COEnvBase], default: None ) \u2013

    Environment to use for decoding. If None, the environment is instantiated from env_name. Note that it is more efficient to pass an already instantiated environment each time for fine-grained control

  • phase (str, default: 'train' ) \u2013

    Phase of the algorithm (train, val, test)

  • return_actions (bool, default: False ) \u2013

    Whether to return the actions

  • actions \u2013

    Actions to use for evaluating the policy. If passed, use these actions instead of sampling from the policy to calculate log likelihood

  • decoding_kwargs \u2013

    Keyword arguments for the decoding strategy. See :class:rl4co.utils.decoding.DecodingStrategy for more information.

Returns:

  • out ( dict ) \u2013

    Dictionary containing the reward, log likelihood, and optionally the actions and entropy

Source code in rl4co/models/zoo/n2s/policy.py
def forward(\n    self,\n    td: TensorDict,\n    env: Union[str, RL4COEnvBase] = None,\n    phase: str = \"train\",\n    return_actions: bool = False,\n    return_embeds: bool = False,\n    only_return_embed: bool = False,\n    actions=None,\n    **decoding_kwargs,\n) -> dict:\n    \"\"\"Forward pass of the policy.\n\n    Args:\n        td: TensorDict containing the environment state\n        env: Environment to use for decoding. If None, the environment is instantiated from `env_name`. Note that\n            it is more efficient to pass an already instantiated environment each time for fine-grained control\n        phase: Phase of the algorithm (train, val, test)\n        return_actions: Whether to return the actions\n        actions: Actions to use for evaluating the policy.\n            If passed, use these actions instead of sampling from the policy to calculate log likelihood\n        decoding_kwargs: Keyword arguments for the decoding strategy. See :class:`rl4co.utils.decoding.DecodingStrategy` for more information.\n\n    Returns:\n        out: Dictionary containing the reward, log likelihood, and optionally the actions and entropy\n    \"\"\"\n\n    # Encoder: get encoder output and initial embeddings from initial state\n    h_wave, final_p = self.encoder(td)\n    if only_return_embed:\n        return {\"embeds\": h_wave.detach()}\n    final_h = (\n        self.project_node(h_wave) + self.project_graph(h_wave.max(1)[0])[:, None, :]\n    )\n\n    # Instantiate environment if needed\n    if isinstance(env, str) or env is None:\n        env_name = self.env_name if env is None else env\n        log.info(f\"Instantiated environment not provided; instantiating {env_name}\")\n        env = get_env(env_name)\n\n    # Get decode type depending on phase and whether actions are passed for evaluation\n    decode_type = decoding_kwargs.pop(\"decode_type\", None)\n    if actions is not None:\n        decode_type = \"evaluate\"\n    elif decode_type is None:\n        decode_type = getattr(self, f\"{phase}_decode_type\")\n\n    # Setup decoding strategy\n    # we pop arguments that are not part of the decoding strategy\n    decode_strategy: DecodingStrategy = get_decoding_strategy(\n        decode_type,\n        temperature=decoding_kwargs.pop(\"temperature\", self.temperature),\n        tanh_clipping=decoding_kwargs.pop(\"tanh_clipping\", self.tanh_clipping),\n        mask_logits=True,\n        improvement_method_mode=True,\n        **decoding_kwargs,\n    )\n\n    ## action 1\n\n    # Perform the decoding\n    logits = self.removal_decoder(td, final_h, final_p)\n\n    # Get mask\n    mask = torch.ones_like(td[\"action_record\"][:, 0], device=td.device).bool()\n    if \"action\" in td.keys():\n        mask = mask.scatter(1, td[\"action\"][:, :1], 0)\n\n    # Get action and log-likelihood\n    logprob_removal, action_removal = decode_strategy.step(\n        logits,\n        mask,\n        action=actions[:, 0] if actions is not None else None,\n    )\n    action_removal = action_removal.unsqueeze(-1)\n    if phase == \"train\":\n        selected_log_ll_action1 = logprob_removal.gather(1, action_removal)\n\n    ## action 2\n    td.set(\"action\", action_removal)\n\n    # Perform the decoding\n    batch_size, seq_length = td[\"rec_current\"].size()\n    logits = self.reinsertion_decoder(td, final_h, final_p).view(batch_size, -1)\n\n    # Get mask\n    mask = env.get_mask(action_removal + 1, td).view(batch_size, -1)\n    # Get action and log-likelihood\n    logprob_reinsertion, action_reinsertion = decode_strategy.step(\n        logits,\n        mask,\n        action=actions[:, 1] * seq_length + actions[:, 2]\n        if actions is not None\n        else None,\n    )\n    action_reinsertion = action_reinsertion.unsqueeze(-1)\n    if phase == \"train\":\n        selected_log_ll_action2 = logprob_reinsertion.gather(1, action_reinsertion)\n\n    ## return\n    N2S_action = torch.cat(\n        (\n            action_removal.view(batch_size, -1),\n            action_reinsertion // seq_length,\n            action_reinsertion % seq_length,\n        ),\n        -1,\n    )\n    if phase == \"train\":\n        log_likelihood = selected_log_ll_action1 + selected_log_ll_action2\n    else:\n        log_likelihood = torch.zeros(batch_size, device=td.device)\n\n    outdict = {\"log_likelihood\": log_likelihood, \"cost_bsf\": td[\"cost_bsf\"]}\n    td.set(\"action\", N2S_action)\n\n    if return_embeds:\n        outdict[\"embeds\"] = h_wave.detach()\n\n    if return_actions:\n        outdict[\"actions\"] = N2S_action\n\n    return outdict\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.n2s.model.N2S","title":"N2S","text":"
N2S(\n    env: RL4COEnvBase,\n    policy: Module = None,\n    critic: CriticNetwork = None,\n    policy_kwargs: dict = {},\n    critic_kwargs: dict = {},\n    **kwargs\n)\n

Bases: n_step_PPO

N2S Model based on n_step Proximal Policy Optimization (PPO) with an N2S model policy. We default to the N2S model policy and the improvement Critic Network.

Parameters:

  • env (RL4COEnvBase) \u2013

    Environment to use for the algorithm

  • policy (Module, default: None ) \u2013

    Policy to use for the algorithm

  • critic (CriticNetwork, default: None ) \u2013

    Critic to use for the algorithm

  • policy_kwargs (dict, default: {} ) \u2013

    Keyword arguments for policy

  • critic_kwargs (dict, default: {} ) \u2013

    Keyword arguments for critic

Source code in rl4co/models/zoo/n2s/model.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: nn.Module = None,\n    critic: CriticNetwork = None,\n    policy_kwargs: dict = {},\n    critic_kwargs: dict = {},\n    **kwargs,\n):\n    if policy is None:\n        policy = N2SPolicy(env_name=env.name, **policy_kwargs)\n\n    if critic is None:\n        embed_dim = (\n            policy_kwargs[\"embed_dim\"] if \"embed_dim\" in policy_kwargs else 128\n        )  # the critic's embed_dim must be as policy's\n\n        encoder = MultiHeadAttentionLayer(\n            embed_dim,\n            critic_kwargs[\"num_heads\"] if \"num_heads\" in critic_kwargs else 4,\n            critic_kwargs[\"feedforward_hidden\"]\n            if \"feedforward_hidden\" in critic_kwargs\n            else 128,\n            critic_kwargs[\"normalization\"]\n            if \"normalization\" in critic_kwargs\n            else \"layer\",\n            bias=False,\n        )\n        value_head = CriticDecoder(embed_dim)\n\n        critic = CriticNetwork(\n            encoder=encoder,\n            value_head=value_head,\n            customized=True,\n        )\n\n    super().__init__(env, policy, critic, **kwargs)\n
"},{"location":"docs/content/api/zoo/improvement/#neuopt","title":"NeuOpt","text":""},{"location":"docs/content/api/zoo/improvement/#models.zoo.neuopt.decoder.RDSDecoder","title":"RDSDecoder","text":"
RDSDecoder(embed_dim: int = 128)\n

Bases: ImprovementDecoder

RDS Decoder for flexible k-opt based on Ma et al. (2023) Given the environment state and the node embeddings (positional embeddings are discarded), compute the logits for selecting a k-opt exchange on basis moves (S-move, I-move, E-move) from the current solution

Parameters:

  • embed_dim (int, default: 128 ) \u2013

    Embedding dimension

  • num_heads \u2013

    Number of attention heads

Source code in rl4co/models/zoo/neuopt/decoder.py
def __init__(\n    self,\n    embed_dim: int = 128,\n):\n    super().__init__()\n    self.embed_dim = embed_dim\n\n    self.linear_K1 = nn.Linear(self.embed_dim, self.embed_dim, bias=False)\n    self.linear_K2 = nn.Linear(self.embed_dim, self.embed_dim, bias=False)\n    self.linear_K3 = nn.Linear(self.embed_dim, self.embed_dim, bias=False)\n    self.linear_K4 = nn.Linear(self.embed_dim, self.embed_dim, bias=False)\n\n    self.linear_Q1 = nn.Linear(self.embed_dim, self.embed_dim, bias=False)\n    self.linear_Q2 = nn.Linear(self.embed_dim, self.embed_dim, bias=False)\n    self.linear_Q3 = nn.Linear(self.embed_dim, self.embed_dim, bias=False)\n    self.linear_Q4 = nn.Linear(self.embed_dim, self.embed_dim, bias=False)\n\n    self.linear_V1 = nn.Parameter(torch.Tensor(self.embed_dim))\n    self.linear_V2 = nn.Parameter(torch.Tensor(self.embed_dim))\n\n    self.rnn1 = nn.GRUCell(self.embed_dim, self.embed_dim)\n    self.rnn2 = nn.GRUCell(self.embed_dim, self.embed_dim)\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.neuopt.policy.CustomizeTSPInitEmbedding","title":"CustomizeTSPInitEmbedding","text":"
CustomizeTSPInitEmbedding(embed_dim, linear_bias=True)\n

Bases: Module

Initial embedding for the Traveling Salesman Problems (TSP). Embed the following node features to the embedding space:

- locs: x, y coordinates of the cities\n
Source code in rl4co/models/zoo/neuopt/policy.py
def __init__(self, embed_dim, linear_bias=True):\n    super(CustomizeTSPInitEmbedding, self).__init__()\n    node_dim = 2  # x, y\n    self.init_embed = nn.Sequential(\n        nn.Linear(node_dim, embed_dim // 2, linear_bias),\n        nn.ReLU(inplace=True),\n        nn.Linear(embed_dim // 2, embed_dim, linear_bias),\n    )\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.neuopt.policy.NeuOptPolicy","title":"NeuOptPolicy","text":"
NeuOptPolicy(\n    embed_dim: int = 128,\n    num_encoder_layers: int = 3,\n    num_heads: int = 4,\n    normalization: str = \"layer\",\n    feedforward_hidden: int = 128,\n    env_name: str = \"tsp_kopt\",\n    pos_type: str = \"CPE\",\n    init_embedding: Module = None,\n    pos_embedding: Module = None,\n    temperature: float = 1.0,\n    tanh_clipping: float = 6.0,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"sampling\",\n    test_decode_type: str = \"sampling\",\n)\n

Bases: ImprovementPolicy

NeuOpt Policy based on Ma et al. (2023) This model first encodes the input graph and current solution using a N2S encoder (:class:N2SEncoder) and then decodes the k-opt action (:class:RDSDecoder)

Parameters:

  • embed_dim (int, default: 128 ) \u2013

    Dimension of the node embeddings

  • num_encoder_layers (int, default: 3 ) \u2013

    Number of layers in the encoder

  • num_heads (int, default: 4 ) \u2013

    Number of heads in the attention layers

  • normalization (str, default: 'layer' ) \u2013

    Normalization type in the attention layers

  • feedforward_hidden (int, default: 128 ) \u2013

    Dimension of the hidden layer in the feedforward network

  • env_name (str, default: 'tsp_kopt' ) \u2013

    Name of the environment used to initialize embeddings

  • pos_type (str, default: 'CPE' ) \u2013

    Name of the used positional encoding method (CPE or APE)

  • init_embedding (Module, default: None ) \u2013

    Module to use for the initialization of the embeddings

  • pos_embedding (Module, default: None ) \u2013

    Module to use for the initialization of the positional embeddings

  • temperature (float, default: 1.0 ) \u2013

    Temperature for the softmax

  • tanh_clipping (float, default: 6.0 ) \u2013

    Tanh clipping value (see Bello et al., 2016)

  • train_decode_type (str, default: 'sampling' ) \u2013

    Type of decoding to use during training

  • val_decode_type (str, default: 'sampling' ) \u2013

    Type of decoding to use during validation

  • test_decode_type (str, default: 'sampling' ) \u2013

    Type of decoding to use during testing

Source code in rl4co/models/zoo/neuopt/policy.py
def __init__(\n    self,\n    embed_dim: int = 128,\n    num_encoder_layers: int = 3,\n    num_heads: int = 4,\n    normalization: str = \"layer\",\n    feedforward_hidden: int = 128,\n    env_name: str = \"tsp_kopt\",\n    pos_type: str = \"CPE\",\n    init_embedding: nn.Module = None,\n    pos_embedding: nn.Module = None,\n    temperature: float = 1.0,\n    tanh_clipping: float = 6.0,\n    train_decode_type: str = \"sampling\",\n    val_decode_type: str = \"sampling\",\n    test_decode_type: str = \"sampling\",\n):\n    super(NeuOptPolicy, self).__init__()\n\n    self.env_name = env_name\n    self.embed_dim = embed_dim\n\n    # Decoding strategies\n    self.temperature = temperature\n    self.tanh_clipping = tanh_clipping\n    self.train_decode_type = train_decode_type\n    self.val_decode_type = val_decode_type\n    self.test_decode_type = test_decode_type\n\n    # Encoder and decoder\n    if init_embedding is None:\n        init_embedding = CustomizeTSPInitEmbedding(self.embed_dim)\n\n    self.encoder = N2SEncoder(\n        embed_dim=embed_dim,\n        init_embedding=init_embedding,\n        pos_embedding=pos_embedding,\n        env_name=env_name,\n        pos_type=pos_type,\n        num_heads=num_heads,\n        num_layers=num_encoder_layers,\n        normalization=normalization,\n        feedforward_hidden=feedforward_hidden,\n    )\n\n    self.decoder = RDSDecoder(embed_dim=embed_dim)\n\n    self.init_hidden_W = nn.Linear(self.embed_dim, self.embed_dim)\n    self.init_query_learnable = nn.Parameter(torch.Tensor(self.embed_dim))\n\n    self.init_parameters()\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.neuopt.policy.NeuOptPolicy.forward","title":"forward","text":"
forward(\n    td: TensorDict,\n    env: Union[str, RL4COEnvBase] = None,\n    phase: str = \"train\",\n    return_actions: bool = False,\n    return_embeds: bool = False,\n    only_return_embed: bool = False,\n    actions=None,\n    **decoding_kwargs\n) -> dict\n

Forward pass of the policy.

Parameters:

  • td (TensorDict) \u2013

    TensorDict containing the environment state

  • env (Union[str, RL4COEnvBase], default: None ) \u2013

    Environment to use for decoding. If None, the environment is instantiated from env_name. Note that it is more efficient to pass an already instantiated environment each time for fine-grained control

  • phase (str, default: 'train' ) \u2013

    Phase of the algorithm (train, val, test)

  • return_actions (bool, default: False ) \u2013

    Whether to return the actions

  • actions \u2013

    Actions to use for evaluating the policy. If passed, use these actions instead of sampling from the policy to calculate log likelihood

  • decoding_kwargs \u2013

    Keyword arguments for the decoding strategy. See :class:rl4co.utils.decoding.DecodingStrategy for more information.

Returns:

  • out ( dict ) \u2013

    Dictionary containing the reward, log likelihood, and optionally the actions and entropy

Source code in rl4co/models/zoo/neuopt/policy.py
def forward(\n    self,\n    td: TensorDict,\n    env: Union[str, RL4COEnvBase] = None,\n    phase: str = \"train\",\n    return_actions: bool = False,\n    return_embeds: bool = False,\n    only_return_embed: bool = False,\n    actions=None,\n    **decoding_kwargs,\n) -> dict:\n    \"\"\"Forward pass of the policy.\n\n    Args:\n        td: TensorDict containing the environment state\n        env: Environment to use for decoding. If None, the environment is instantiated from `env_name`. Note that\n            it is more efficient to pass an already instantiated environment each time for fine-grained control\n        phase: Phase of the algorithm (train, val, test)\n        return_actions: Whether to return the actions\n        actions: Actions to use for evaluating the policy.\n            If passed, use these actions instead of sampling from the policy to calculate log likelihood\n        decoding_kwargs: Keyword arguments for the decoding strategy. See :class:`rl4co.utils.decoding.DecodingStrategy` for more information.\n\n    Returns:\n        out: Dictionary containing the reward, log likelihood, and optionally the actions and entropy\n    \"\"\"\n\n    # Encoder: get encoder output and initial embeddings from initial state\n    nfe, _ = self.encoder(td)\n    if only_return_embed:\n        return {\"embeds\": nfe.detach()}\n\n    # Instantiate environment if needed\n    if isinstance(env, str) or env is None:\n        env_name = self.env_name if env is None else env\n        log.info(f\"Instantiated environment not provided; instantiating {env_name}\")\n        env = get_env(env_name)\n    assert not env.two_opt_mode, \"NeuOpt only support k-opt with k > 2\"\n\n    # Get decode type depending on phase and whether actions are passed for evaluation\n    decode_type = decoding_kwargs.pop(\"decode_type\", None)\n    if actions is not None:\n        decode_type = \"evaluate\"\n    elif decode_type is None:\n        decode_type = getattr(self, f\"{phase}_decode_type\")\n\n    # Setup decoding strategy\n    # we pop arguments that are not part of the decoding strategy\n    decode_strategy: DecodingStrategy = get_decoding_strategy(\n        decode_type,\n        temperature=decoding_kwargs.pop(\"temperature\", self.temperature),\n        tanh_clipping=decoding_kwargs.pop(\"tanh_clipping\", self.tanh_clipping),\n        mask_logits=True,\n        improvement_method_mode=True,\n        **decoding_kwargs,\n    )\n\n    # Perform the decoding\n    bs, gs, _, ll, action_sampled, rec, visited_time = (\n        *nfe.size(),\n        0.0,\n        None,\n        td[\"rec_current\"],\n        td[\"visited_time\"],\n    )\n    action_index = torch.zeros(bs, env.k_max, dtype=torch.long).to(rec.device)\n    k_action_left = torch.zeros(bs, env.k_max + 1, dtype=torch.long).to(rec.device)\n    k_action_right = torch.zeros(bs, env.k_max, dtype=torch.long).to(rec.device)\n    next_of_last_action = (\n        torch.zeros_like(rec[:, :1], dtype=torch.long).to(rec.device) - 1\n    )\n    mask = torch.zeros_like(rec, dtype=torch.bool).to(rec.device)\n    stopped = torch.ones(bs, dtype=torch.bool).to(rec.device)\n    zeros = torch.zeros((bs, 1), device=td.device)\n\n    # init queries\n    h_mean = nfe.mean(1)\n    init_query = self.init_query_learnable.repeat(bs, 1)\n    input_q1 = input_q2 = init_query.clone()\n    init_hidden = self.init_hidden_W(h_mean)\n    q1 = q2 = init_hidden.clone()\n\n    for i in range(env.k_max):\n        # Pass RDS decoder\n        logits, q1, q2 = self.decoder(nfe, q1, q2, input_q1, input_q2)\n\n        # Calc probs\n        if i == 0 and \"action\" in td.keys():\n            mask = mask.scatter(1, td[\"action\"][:, :1], 1)\n\n        logprob, action_sampled = decode_strategy.step(\n            logits,\n            ~mask.clone(),\n            action=actions[:, i : i + 1].squeeze() if actions is not None else None,\n        )\n        action_sampled = action_sampled.unsqueeze(-1)\n        if i > 0:\n            action_sampled = torch.where(\n                stopped.unsqueeze(-1), action_index[:, :1], action_sampled\n            )\n        if phase == \"train\":\n            loss_now = logprob.gather(1, action_sampled)\n        else:\n            loss_now = zeros.clone()\n\n        # Record log_likelihood and Entropy\n        if i > 0:\n            ll = ll + torch.where(stopped.unsqueeze(-1), zeros * 0, loss_now)\n        else:\n            ll = ll + loss_now\n\n        # Store and Process actions\n        next_of_new_action = rec.gather(1, action_sampled)\n        action_index[:, i] = action_sampled.squeeze().clone()\n        k_action_left[stopped, i] = action_sampled[stopped].squeeze().clone()\n        k_action_right[~stopped, i - 1] = action_sampled[~stopped].squeeze().clone()\n        k_action_left[:, i + 1] = next_of_new_action.squeeze().clone()\n\n        # Prepare next RNN input\n        input_q1 = nfe.gather(\n            1, action_sampled.view(bs, 1, 1).expand(bs, 1, self.embed_dim)\n        ).squeeze(1)\n        input_q2 = torch.where(\n            stopped.view(bs, 1).expand(bs, self.embed_dim),\n            input_q1.clone(),\n            nfe.gather(\n                1,\n                (next_of_last_action % gs)\n                .view(bs, 1, 1)\n                .expand(bs, 1, self.embed_dim),\n            ).squeeze(1),\n        )\n\n        # Process if k-opt close\n        # assert (input_q1[stopped] == input_q2[stopped]).all()\n        if i > 0:\n            stopped = stopped | (action_sampled == next_of_last_action).squeeze()\n        else:\n            stopped = (action_sampled == next_of_last_action).squeeze()\n        # assert (input_q1[stopped] == input_q2[stopped]).all()\n\n        k_action_left[stopped, i] = k_action_left[stopped, i - 1]\n        k_action_right[stopped, i] = k_action_right[stopped, i - 1]\n\n        # Calc next basic masks\n        if i == 0:\n            visited_time_tag = (\n                visited_time - visited_time.gather(1, action_sampled)\n            ) % gs\n        mask &= False\n        mask[(visited_time_tag <= visited_time_tag.gather(1, action_sampled))] = True\n        if i == 0:\n            mask[visited_time_tag > (gs - 2)] = True\n        mask[\n            stopped, action_sampled[stopped].squeeze()\n        ] = False  # allow next k-opt starts immediately\n        # if True:#i == env.k_max - 2: # allow special case: close k-opt at the first selected node\n        index_allow_first_node = (~stopped) & (\n            next_of_new_action.squeeze() == action_index[:, 0]\n        )\n        mask[index_allow_first_node, action_index[index_allow_first_node, 0]] = False\n\n        # Move to next\n        next_of_last_action = next_of_new_action\n        next_of_last_action[stopped] = -1\n\n    # Form final action\n    k_action_right[~stopped, -1] = k_action_left[~stopped, -1].clone()\n    k_action_left = k_action_left[:, : env.k_max]\n    action_all = torch.cat((action_index, k_action_left, k_action_right), -1)\n\n    outdict = {\"log_likelihood\": ll, \"cost_bsf\": td[\"cost_bsf\"]}\n    td.set(\"action\", action_all)\n\n    if return_embeds:\n        outdict[\"embeds\"] = nfe.detach()\n\n    if return_actions:\n        outdict[\"actions\"] = action_all\n\n    return outdict\n
"},{"location":"docs/content/api/zoo/improvement/#models.zoo.neuopt.model.NeuOpt","title":"NeuOpt","text":"
NeuOpt(\n    env: RL4COEnvBase,\n    policy: Module = None,\n    critic: CriticNetwork = None,\n    policy_kwargs: dict = {},\n    critic_kwargs: dict = {},\n    **kwargs\n)\n

Bases: n_step_PPO

NeuOpt Model based on n_step Proximal Policy Optimization (PPO) with an NeuOpt model policy. We default to the NeuOpt model policy and the improvement Critic Network.

Parameters:

  • env (RL4COEnvBase) \u2013

    Environment to use for the algorithm

  • policy (Module, default: None ) \u2013

    Policy to use for the algorithm

  • critic (CriticNetwork, default: None ) \u2013

    Critic to use for the algorithm

  • policy_kwargs (dict, default: {} ) \u2013

    Keyword arguments for policy

  • critic_kwargs (dict, default: {} ) \u2013

    Keyword arguments for critic

Source code in rl4co/models/zoo/neuopt/model.py
def __init__(\n    self,\n    env: RL4COEnvBase,\n    policy: nn.Module = None,\n    critic: CriticNetwork = None,\n    policy_kwargs: dict = {},\n    critic_kwargs: dict = {},\n    **kwargs,\n):\n    if policy is None:\n        policy = NeuOptPolicy(env_name=env.name, **policy_kwargs)\n\n    if critic is None:\n        embed_dim = (\n            policy_kwargs[\"embed_dim\"] if \"embed_dim\" in policy_kwargs else 128\n        )  # the critic's embed_dim must be as policy's\n\n        encoder = MultiHeadAttentionLayer(\n            embed_dim,\n            critic_kwargs[\"num_heads\"] if \"num_heads\" in critic_kwargs else 4,\n            critic_kwargs[\"feedforward_hidden\"]\n            if \"feedforward_hidden\" in critic_kwargs\n            else 128,\n            critic_kwargs[\"normalization\"]\n            if \"normalization\" in critic_kwargs\n            else \"layer\",\n            bias=False,\n        )\n        value_head = CriticDecoder(embed_dim, dropout_rate=0.001)\n\n        critic = CriticNetwork(\n            encoder=encoder,\n            value_head=value_head,\n            customized=True,\n        )\n\n    super().__init__(env, policy, critic, **kwargs)\n
"},{"location":"docs/content/api/zoo/transductive/","title":"Transductive Methods","text":""},{"location":"docs/content/api/zoo/transductive/#transductive-methods","title":"Transductive Methods","text":"

These methods update policy parameters during online testing to improve the solutions of a specific instance.

"},{"location":"docs/content/api/zoo/transductive/#active-search-as","title":"Active Search (AS)","text":""},{"location":"docs/content/api/zoo/transductive/#models.zoo.active_search.search.ActiveSearch","title":"ActiveSearch","text":"
ActiveSearch(\n    env,\n    policy,\n    dataset: Union[Dataset, str],\n    batch_size: int = 1,\n    max_iters: int = 200,\n    augment_size: int = 8,\n    augment_dihedral: bool = True,\n    num_parallel_runs: int = 1,\n    max_runtime: int = 86400,\n    save_path: str = None,\n    optimizer: Union[str, Optimizer, partial] = \"Adam\",\n    optimizer_kwargs: dict = {\n        \"lr\": 0.00026,\n        \"weight_decay\": 1e-06,\n    },\n    **kwargs\n)\n

Bases: TransductiveModel

Active Search for Neural Combination Optimization from Bello et al. (2016). Fine-tunes the whole policy network (encoder + decoder) on a batch of instances. Reference: https://arxiv.org/abs/1611.09940

Parameters:

  • env \u2013

    RL4CO environment to be solved

  • policy \u2013

    policy network

  • dataset (Union[Dataset, str]) \u2013

    dataset to be used for training

  • batch_size (int, default: 1 ) \u2013

    batch size for training

  • max_iters (int, default: 200 ) \u2013

    maximum number of iterations

  • augment_size (int, default: 8 ) \u2013

    number of augmentations per state

  • augment_dihedral (bool, default: True ) \u2013

    whether to augment with dihedral rotations

  • parallel_runs \u2013

    number of parallel runs

  • max_runtime (int, default: 86400 ) \u2013

    maximum runtime in seconds

  • save_path (str, default: None ) \u2013

    path to save solution checkpoints

  • optimizer (Union[str, Optimizer, partial], default: 'Adam' ) \u2013

    optimizer to use for training

  • optimizer_kwargs (dict, default: {'lr': 0.00026, 'weight_decay': 1e-06} ) \u2013

    keyword arguments for optimizer

  • **kwargs \u2013

    additional keyword arguments

Source code in rl4co/models/zoo/active_search/search.py
def __init__(\n    self,\n    env,\n    policy,\n    dataset: Union[Dataset, str],\n    batch_size: int = 1,\n    max_iters: int = 200,\n    augment_size: int = 8,\n    augment_dihedral: bool = True,\n    num_parallel_runs: int = 1,\n    max_runtime: int = 86_400,\n    save_path: str = None,\n    optimizer: Union[str, torch.optim.Optimizer, partial] = \"Adam\",\n    optimizer_kwargs: dict = {\"lr\": 2.6e-4, \"weight_decay\": 1e-6},\n    **kwargs,\n):\n    self.save_hyperparameters(logger=False)\n\n    assert batch_size == 1, \"Batch size must be 1 for active search\"\n\n    super(ActiveSearch, self).__init__(\n        env,\n        policy=policy,\n        dataset=dataset,\n        batch_size=batch_size,\n        max_iters=max_iters,\n        max_runtime=max_runtime,\n        save_path=save_path,\n        optimizer=optimizer,\n        optimizer_kwargs=optimizer_kwargs,\n        **kwargs,\n    )\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.active_search.search.ActiveSearch.setup","title":"setup","text":"
setup(stage='fit')\n

Setup base class and instantiate:

  • augmentation
  • instance solutions and rewards
  • original policy state dict
Source code in rl4co/models/zoo/active_search/search.py
def setup(self, stage=\"fit\"):\n    \"\"\"Setup base class and instantiate:\n    - augmentation\n    - instance solutions and rewards\n    - original policy state dict\n    \"\"\"\n    log.info(\"Setting up active search...\")\n    super(ActiveSearch, self).setup(stage)\n\n    # Instantiate augmentation\n    self.augmentation = StateAugmentation(\n        num_augment=self.hparams.augment_size,\n        augment_fn=\"dihedral8\" if self.hparams.augment_dihedral else \"symmetric\",\n    )\n\n    # Store original policy state dict\n    self.original_policy_state = self.policy.state_dict()\n\n    # Get dataset size and problem size\n    dataset_size = len(self.dataset)\n    _batch = next(iter(self.train_dataloader()))\n    self.problem_size = self.env.reset(_batch)[\"action_mask\"].shape[-1]\n    self.instance_solutions = torch.zeros(\n        dataset_size, self.problem_size * 2, dtype=int\n    )\n    self.instance_rewards = torch.zeros(dataset_size)\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.active_search.search.ActiveSearch.on_train_batch_start","title":"on_train_batch_start","text":"
on_train_batch_start(batch: Any, batch_idx: int)\n

Called before training (i.e. search) for a new batch begins. We re-load the original policy state dict and configure the optimizer.

Source code in rl4co/models/zoo/active_search/search.py
def on_train_batch_start(self, batch: Any, batch_idx: int):\n    \"\"\"Called before training (i.e. search) for a new batch begins.\n    We re-load the original policy state dict and configure the optimizer.\n    \"\"\"\n    self.policy.load_state_dict(self.original_policy_state)\n    self.configure_optimizers(self.policy.parameters())\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.active_search.search.ActiveSearch.training_step","title":"training_step","text":"
training_step(batch, batch_idx)\n

Main search loop. We use the training step to effectively adapt to a batch of instances.

Source code in rl4co/models/zoo/active_search/search.py
def training_step(self, batch, batch_idx):\n    \"\"\"Main search loop. We use the training step to effectively adapt to a `batch` of instances.\"\"\"\n    # Augment state\n    batch_size = batch.shape[0]\n    td_init = self.env.reset(batch)\n    n_aug, n_start, n_runs = (\n        self.augmentation.num_augment,\n        self.env.get_num_starts(td_init),\n        self.hparams.num_parallel_runs,\n    )\n    td_init = self.augmentation(td_init)\n    td_init = batchify(td_init, n_runs)\n\n    # Solution and reward buffer\n    max_reward = torch.full((batch_size,), -float(\"inf\"), device=batch.device)\n    best_solutions = torch.zeros(\n        batch_size, self.problem_size * 2, device=batch.device, dtype=int\n    )\n\n    # Init search\n    t_start = time.time()\n    for i in range(self.hparams.max_iters):\n        # Evaluate policy with sampling multistarts (as in POMO)\n        out = self.policy(\n            td_init.clone(),\n            env=self.env,\n            decode_type=\"multistart_sampling\",\n            num_starts=n_start,\n            return_actions=True,\n        )\n\n        if i == 0:\n            log.info(f\"Initial reward: {out['reward'].max():.2f}\")\n\n        # Update best solution and reward found\n        max_reward_iter = out[\"reward\"].max()\n        if max_reward_iter > max_reward:\n            max_reward_idx = out[\"reward\"].argmax()\n            best_solution_iter = out[\"actions\"][max_reward_idx]\n            max_reward = max_reward_iter\n            best_solutions[0, : best_solution_iter.shape[0]] = best_solution_iter\n\n        # Compute REINFORCE loss with shared baseline\n        reward = unbatchify(out[\"reward\"], (n_runs, n_aug, n_start))\n        ll = unbatchify(out[\"log_likelihood\"], (n_runs, n_aug, n_start))\n        advantage = reward - reward.mean(dim=-1, keepdim=True)\n        loss = -(advantage * ll).mean()\n\n        # Backpropagate loss\n        # perform manual optimization following the Lightning routine\n        # https://lightning.ai/docs/pytorch/stable/common/optimization.html\n        opt = self.optimizers()\n        opt.zero_grad()\n        self.manual_backward(loss)\n\n        self.log_dict(\n            {\n                \"loss\": loss,\n                \"max_reward\": max_reward,\n                \"step\": i,\n                \"time\": time.time() - t_start,\n            },\n            on_step=self.log_on_step,\n        )\n\n        # Stop if max runtime is exceeded\n        if time.time() - t_start > self.hparams.max_runtime:\n            break\n\n    return {\"max_reward\": max_reward, \"best_solutions\": best_solutions}\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.active_search.search.ActiveSearch.on_train_batch_end","title":"on_train_batch_end","text":"
on_train_batch_end(\n    outputs: STEP_OUTPUT, batch: Any, batch_idx: int\n) -> None\n

We store the best solution and reward found.

Source code in rl4co/models/zoo/active_search/search.py
def on_train_batch_end(\n    self, outputs: STEP_OUTPUT, batch: Any, batch_idx: int\n) -> None:\n    \"\"\"We store the best solution and reward found.\"\"\"\n    max_rewards, best_solutions = outputs[\"max_reward\"], outputs[\"best_solutions\"]\n    self.instance_rewards[batch_idx] = max_rewards\n    self.instance_solutions[batch_idx, :] = best_solutions.squeeze(\n        0\n    )  # only one instance\n    log.info(f\"Best reward: {max_rewards.mean():.2f}\")\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.active_search.search.ActiveSearch.on_train_epoch_end","title":"on_train_epoch_end","text":"
on_train_epoch_end() -> None\n

Called when the training ends. If the epoch ends, it means we have finished searching over the instances, thus the trainer should stop.

Source code in rl4co/models/zoo/active_search/search.py
def on_train_epoch_end(self) -> None:\n    \"\"\"Called when the training ends.\n    If the epoch ends, it means we have finished searching over the\n    instances, thus the trainer should stop.\n    \"\"\"\n    save_path = self.hparams.save_path\n    if save_path is not None:\n        log.info(f\"Saving solutions and rewards to {save_path}...\")\n        torch.save(\n            {\"solutions\": self.instance_solutions, \"rewards\": self.instance_rewards},\n            save_path,\n        )\n\n    # https://github.com/Lightning-AI/lightning/issues/1406\n    self.trainer.should_stop = True\n
"},{"location":"docs/content/api/zoo/transductive/#efficent-active-search-eas","title":"Efficent Active Search (EAS)","text":""},{"location":"docs/content/api/zoo/transductive/#models.zoo.eas.search.EAS","title":"EAS","text":"
EAS(\n    env,\n    policy,\n    dataset: Union[Dataset, str],\n    use_eas_embedding: bool = True,\n    use_eas_layer: bool = False,\n    eas_emb_cache_keys: List[str] = [\"logit_key\"],\n    eas_lambda: float = 0.013,\n    batch_size: int = 2,\n    max_iters: int = 200,\n    augment_size: int = 8,\n    augment_dihedral: bool = True,\n    num_parallel_runs: int = 1,\n    baseline: str = \"multistart\",\n    max_runtime: int = 86400,\n    save_path: str = None,\n    optimizer: Union[str, Optimizer, partial] = \"Adam\",\n    optimizer_kwargs: dict = {\n        \"lr\": 0.0041,\n        \"weight_decay\": 1e-06,\n    },\n    verbose: bool = True,\n    **kwargs\n)\n

Bases: TransductiveModel

Efficient Active Search for Neural Combination Optimization from Hottung et al. (2022). Fine-tunes a subset of parameters (such as node embeddings or newly added layers) thus avoiding expensive re-encoding of the problem. Reference: https://openreview.net/pdf?id=nO5caZwFwYu

Parameters:

  • env \u2013

    RL4CO environment to be solved

  • policy \u2013

    policy network

  • dataset (Union[Dataset, str]) \u2013

    dataset to be used for training

  • use_eas_embedding (bool, default: True ) \u2013

    whether to use EAS embedding (EASEmb)

  • use_eas_layer (bool, default: False ) \u2013

    whether to use EAS layer (EASLay)

  • eas_emb_cache_keys (List[str], default: ['logit_key'] ) \u2013

    keys to cache in the embedding

  • eas_lambda (float, default: 0.013 ) \u2013

    lambda parameter for IL loss

  • batch_size (int, default: 2 ) \u2013

    batch size for training

  • max_iters (int, default: 200 ) \u2013

    maximum number of iterations

  • augment_size (int, default: 8 ) \u2013

    number of augmentations per state

  • augment_dihedral (bool, default: True ) \u2013

    whether to augment with dihedral rotations

  • parallel_runs \u2013

    number of parallel runs

  • baseline (str, default: 'multistart' ) \u2013

    REINFORCE baseline type (multistart, symmetric, full)

  • max_runtime (int, default: 86400 ) \u2013

    maximum runtime in seconds

  • save_path (str, default: None ) \u2013

    path to save solution checkpoints

  • optimizer (Union[str, Optimizer, partial], default: 'Adam' ) \u2013

    optimizer to use for training

  • optimizer_kwargs (dict, default: {'lr': 0.0041, 'weight_decay': 1e-06} ) \u2013

    keyword arguments for optimizer

  • verbose (bool, default: True ) \u2013

    whether to print progress for each iteration

Source code in rl4co/models/zoo/eas/search.py
def __init__(\n    self,\n    env,\n    policy,\n    dataset: Union[Dataset, str],\n    use_eas_embedding: bool = True,\n    use_eas_layer: bool = False,\n    eas_emb_cache_keys: List[str] = [\"logit_key\"],\n    eas_lambda: float = 0.013,\n    batch_size: int = 2,\n    max_iters: int = 200,\n    augment_size: int = 8,\n    augment_dihedral: bool = True,\n    num_parallel_runs: int = 1,\n    baseline: str = \"multistart\",\n    max_runtime: int = 86_400,\n    save_path: str = None,\n    optimizer: Union[str, torch.optim.Optimizer, partial] = \"Adam\",\n    optimizer_kwargs: dict = {\"lr\": 0.0041, \"weight_decay\": 1e-6},\n    verbose: bool = True,\n    **kwargs,\n):\n    self.save_hyperparameters(logger=False)\n\n    assert (\n        self.hparams.use_eas_embedding or self.hparams.use_eas_layer\n    ), \"At least one of `use_eas_embedding` or `use_eas_layer` must be True.\"\n\n    super(EAS, self).__init__(\n        env,\n        policy=policy,\n        dataset=dataset,\n        batch_size=batch_size,\n        max_iters=max_iters,\n        max_runtime=max_runtime,\n        save_path=save_path,\n        optimizer=optimizer,\n        optimizer_kwargs=optimizer_kwargs,\n        **kwargs,\n    )\n\n    assert self.hparams.baseline in [\n        \"multistart\",\n        \"symmetric\",\n        \"full\",\n    ], f\"Baseline {self.hparams.baseline} not supported.\"\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.eas.search.EAS.setup","title":"setup","text":"
setup(stage='fit')\n

Setup base class and instantiate:

  • augmentation
  • instance solutions and rewards
  • original policy state dict
Source code in rl4co/models/zoo/eas/search.py
def setup(self, stage=\"fit\"):\n    \"\"\"Setup base class and instantiate:\n    - augmentation\n    - instance solutions and rewards\n    - original policy state dict\n    \"\"\"\n    log.info(\n        f\"Setting up Efficient Active Search (EAS) with: \\n\"\n        f\"- EAS Embedding: {self.hparams.use_eas_embedding} \\n\"\n        f\"- EAS Layer: {self.hparams.use_eas_layer} \\n\"\n    )\n    super(EAS, self).setup(stage)\n\n    # Instantiate augmentation\n    self.augmentation = StateAugmentation(\n        num_augment=self.hparams.augment_size,\n        augment_fn=\"dihedral8\" if self.hparams.augment_dihedral else \"symmetric\",\n    )\n\n    # Store original policy state dict\n    self.original_policy_state = self.policy.state_dict()\n\n    # Get dataset size and problem size\n    len(self.dataset)\n    _batch = next(iter(self.train_dataloader()))\n    self.problem_size = self.env.reset(_batch)[\"action_mask\"].shape[-1]\n    self.instance_solutions = []\n    self.instance_rewards = []\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.eas.search.EAS.on_train_batch_start","title":"on_train_batch_start","text":"
on_train_batch_start(batch: Any, batch_idx: int)\n

Called before training (i.e. search) for a new batch begins. We re-load the original policy state dict and configure all parameters not to require gradients. We do the rest in the training step.

Source code in rl4co/models/zoo/eas/search.py
def on_train_batch_start(self, batch: Any, batch_idx: int):\n    \"\"\"Called before training (i.e. search) for a new batch begins.\n    We re-load the original policy state dict and configure all parameters not to require gradients.\n    We do the rest in the training step.\n    \"\"\"\n    self.policy.load_state_dict(self.original_policy_state)\n\n    # Set all policy parameters to not require gradients\n    for param in self.policy.parameters():\n        param.requires_grad = False\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.eas.search.EAS.training_step","title":"training_step","text":"
training_step(batch, batch_idx)\n

Main search loop. We use the training step to effectively adapt to a batch of instances.

Source code in rl4co/models/zoo/eas/search.py
def training_step(self, batch, batch_idx):\n    \"\"\"Main search loop. We use the training step to effectively adapt to a `batch` of instances.\"\"\"\n    # Augment state\n    batch_size = batch.shape[0]\n    td_init = self.env.reset(batch)\n    n_aug, n_start, n_runs = (\n        self.augmentation.num_augment,\n        self.env.get_num_starts(td_init),\n        self.hparams.num_parallel_runs,\n    )\n    td_init = self.augmentation(td_init)\n    td_init = batchify(td_init, n_runs)\n    num_instances = batch_size * n_aug * n_runs  # NOTE: no num_starts!\n    # batch_r = n_runs * batch_size # effective batch size\n    group_s = (\n        n_start + 1\n    )  # number of different rollouts per instance (+1 for incumbent solution construction)\n\n    # Get encoder and decoder for simplicity\n    encoder = self.policy.encoder\n    decoder = self.policy.decoder\n\n    # Precompute the cache of the embeddings (i.e. q,k,v and logit_key)\n    embeddings, _ = encoder(td_init)\n    cached_embeds = decoder._precompute_cache(embeddings)\n\n    # Collect optimizer parameters\n    opt_params = []\n    if self.hparams.use_eas_layer:\n        # EASLay: replace forward of logit attention computation. EASLayer\n        eas_layer = EASLayerNet(num_instances, decoder.embed_dim).to(batch.device)\n        decoder.pointer.eas_layer = partial(eas_layer, decoder.pointer)\n        decoder.pointer.forward = partial(\n            forward_pointer_attn_eas_lay, decoder.pointer\n        )\n        for param in eas_layer.parameters():\n            opt_params.append(param)\n    if self.hparams.use_eas_embedding:\n        # EASEmb: set gradient of emb_key to True\n        # for all the keys, wrap the embedding in a nn.Parameter\n        for key in self.hparams.eas_emb_cache_keys:\n            setattr(\n                cached_embeds, key, torch.nn.Parameter(getattr(cached_embeds, key))\n            )\n            opt_params.append(getattr(cached_embeds, key))\n    decoder.forward_eas = partial(forward_eas, decoder)\n\n    # We pass attributes saved in policy too\n    def set_attr_if_exists(attr):\n        if hasattr(self.policy, attr):\n            setattr(decoder, attr, getattr(self.policy, attr))\n\n    for attr in [\"temperature\", \"tanh_clipping\", \"mask_logits\"]:\n        set_attr_if_exists(attr)\n\n    self.configure_optimizers(opt_params)\n\n    # Solution and reward buffer\n    max_reward = torch.full((batch_size,), -float(\"inf\"), device=batch.device)\n    best_solutions = torch.zeros(\n        batch_size, self.problem_size * 2, device=batch.device, dtype=int\n    )  # i.e. incumbent solutions\n\n    # Init search\n    t_start = time.time()\n    for iter_count in range(self.hparams.max_iters):\n        # Evaluate policy with sampling multistarts passing the cached embeddings\n        best_solutions_expanded = best_solutions.repeat(n_aug, 1).repeat(n_runs, 1)\n        logprobs, actions, td_out, reward = decoder.forward_eas(\n            td_init.clone(),\n            cached_embeds=cached_embeds,\n            best_solutions=best_solutions_expanded,\n            iter_count=iter_count,\n            env=self.env,\n            decode_type=\"multistart_sampling\",\n            num_starts=n_start,\n        )\n\n        # Unbatchify to get correct dimensions\n        ll = get_log_likelihood(logprobs, actions, td_out.get(\"mask\", None))\n        ll = unbatchify(ll, (n_runs * batch_size, n_aug, group_s)).squeeze()\n        reward = unbatchify(reward, (n_runs * batch_size, n_aug, group_s)).squeeze()\n        actions = unbatchify(actions, (n_runs * batch_size, n_aug, group_s)).squeeze()\n\n        # Compute REINFORCE loss with shared baselines\n        # compared to original EAS, we also support symmetric and full baselines\n        group_reward = reward[..., :-1]  # exclude incumbent solution\n        if self.hparams.baseline == \"multistart\":\n            bl_val = group_reward.mean(dim=-1, keepdim=True)\n        elif self.hparams.baseline == \"symmetric\":\n            bl_val = group_reward.mean(dim=-2, keepdim=True)\n        elif self.hparams.baseline == \"full\":\n            bl_val = group_reward.mean(dim=-1, keepdim=True).mean(\n                dim=-2, keepdim=True\n            )\n        else:\n            raise ValueError(f\"Baseline {self.hparams.baseline} not supported.\")\n\n        # REINFORCE loss\n        advantage = group_reward - bl_val\n        loss_rl = -(advantage * ll[..., :-1]).mean()\n        # IL loss\n        loss_il = -ll[..., -1].mean()\n        # Total loss\n        loss = loss_rl + self.hparams.eas_lambda * loss_il\n\n        # Manual backpropagation\n        opt = self.optimizers()\n        opt.zero_grad()\n        self.manual_backward(loss)\n\n        # Save best solutions and rewards\n        # Get max reward for each group and instance\n        max_reward = reward.max(dim=2)[0].max(dim=1)[0]\n\n        # Reshape and rank rewards\n        reward_group = reward.reshape(n_runs * batch_size, -1)\n        _, top_indices = torch.topk(reward_group, k=1, dim=1)\n\n        # Obtain best solutions found so far\n        solutions = actions.reshape(n_runs * batch_size, n_aug * group_s, -1)\n        best_solutions_iter = gather_by_index(solutions, top_indices, dim=1)\n        best_solutions[:, : best_solutions_iter.shape[1]] = best_solutions_iter\n\n        self.log_dict(\n            {\n                \"loss\": loss,\n                \"max_reward\": max_reward.mean(),\n                \"step\": iter_count,\n                \"time\": time.time() - t_start,\n            },\n            on_step=self.log_on_step,\n        )\n\n        log.info(\n            f\"{iter_count}/{self.hparams.max_iters} | \"\n            f\" Reward: {max_reward.mean().item():.2f} \"\n        )\n\n        # Stop if max runtime is exceeded\n        if time.time() - t_start > self.hparams.max_runtime:\n            log.info(f\"Max runtime of {self.hparams.max_runtime} seconds exceeded.\")\n            break\n\n    return {\"max_reward\": max_reward, \"best_solutions\": best_solutions}\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.eas.search.EAS.on_train_batch_end","title":"on_train_batch_end","text":"
on_train_batch_end(\n    outputs: STEP_OUTPUT, batch: Any, batch_idx: int\n) -> None\n

We store the best solution and reward found.

Source code in rl4co/models/zoo/eas/search.py
def on_train_batch_end(\n    self, outputs: STEP_OUTPUT, batch: Any, batch_idx: int\n) -> None:\n    \"\"\"We store the best solution and reward found.\"\"\"\n    max_rewards, best_solutions = outputs[\"max_reward\"], outputs[\"best_solutions\"]\n    self.instance_solutions.append(best_solutions)\n    self.instance_rewards.append(max_rewards)\n    log.info(f\"Best reward: {max_rewards.mean():.2f}\")\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.eas.search.EAS.on_train_epoch_end","title":"on_train_epoch_end","text":"
on_train_epoch_end() -> None\n

Called when the train ends.

Source code in rl4co/models/zoo/eas/search.py
def on_train_epoch_end(self) -> None:\n    \"\"\"Called when the train ends.\"\"\"\n    save_path = self.hparams.save_path\n    # concatenate solutions and rewards\n    self.instance_solutions = pad_sequence(\n        self.instance_solutions, batch_first=True, padding_value=0\n    ).squeeze()\n    self.instance_rewards = torch.cat(self.instance_rewards, dim=0).squeeze()\n    if save_path is not None:\n        log.info(f\"Saving solutions and rewards to {save_path}...\")\n        torch.save(\n            {\"solutions\": self.instance_solutions, \"rewards\": self.instance_rewards},\n            save_path,\n        )\n\n    # https://github.com/Lightning-AI/lightning/issues/1406\n    self.trainer.should_stop = True\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.eas.search.EASEmb","title":"EASEmb","text":"
EASEmb(*args, **kwargs)\n

Bases: EAS

EAS with embedding adaptation

Source code in rl4co/models/zoo/eas/search.py
def __init__(\n    self,\n    *args,\n    **kwargs,\n):\n    if not kwargs.get(\"use_eas_embedding\", False) or kwargs.get(\n        \"use_eas_layer\", True\n    ):\n        log.warning(\n            \"Setting `use_eas_embedding` to True and `use_eas_layer` to False. Use EAS base class to override.\"\n        )\n    kwargs[\"use_eas_embedding\"] = True\n    kwargs[\"use_eas_layer\"] = False\n    super(EASEmb, self).__init__(*args, **kwargs)\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.eas.search.EASLay","title":"EASLay","text":"
EASLay(*args, **kwargs)\n

Bases: EAS

EAS with layer adaptation

Source code in rl4co/models/zoo/eas/search.py
def __init__(\n    self,\n    *args,\n    **kwargs,\n):\n    if kwargs.get(\"use_eas_embedding\", False) or not kwargs.get(\n        \"use_eas_layer\", True\n    ):\n        log.warning(\n            \"Setting `use_eas_embedding` to True and `use_eas_layer` to False. Use EAS base class to override.\"\n        )\n    kwargs[\"use_eas_embedding\"] = False\n    kwargs[\"use_eas_layer\"] = True\n    super(EASLay, self).__init__(*args, **kwargs)\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.eas.decoder.forward_pointer_attn_eas_lay","title":"forward_pointer_attn_eas_lay","text":"
forward_pointer_attn_eas_lay(\n    self, query, key, value, logit_key, mask\n)\n

Add layer to the forward pass of logit attention, i.e. Single-head attention.

Source code in rl4co/models/zoo/eas/decoder.py
def forward_pointer_attn_eas_lay(self, query, key, value, logit_key, mask):\n    \"\"\"Add layer to the forward pass of logit attention, i.e.\n    Single-head attention.\n    \"\"\"\n    # Compute inner multi-head attention with no projections.\n    heads = self._inner_mha(query, key, value, mask)\n\n    # Add residual for EAS layer if is set\n    if getattr(self, \"eas_layer\", None) is not None:\n        heads = heads + self.eas_layer(heads)\n\n    glimpse = self.project_out(heads)\n\n    # Batch matrix multiplication to compute logits (batch_size, num_steps, graph_size)\n    # bmm is slightly faster than einsum and matmul\n    logits = (\n        torch.bmm(glimpse, logit_key.squeeze(1).transpose(-2, -1))\n        / math.sqrt(glimpse.size(-1))\n    ).squeeze(1)\n\n    return logits\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.eas.decoder.forward_eas","title":"forward_eas","text":"
forward_eas(\n    self,\n    td: TensorDict,\n    cached_embeds,\n    best_solutions,\n    iter_count: int = 0,\n    env: Union[str, RL4COEnvBase] = None,\n    decode_type: str = \"multistart_sampling\",\n    num_starts: int = None,\n    mask_logits: bool = True,\n    temperature: float = 1.0,\n    tanh_clipping: float = 0,\n    **decode_kwargs\n)\n

Forward pass of the decoder Given the environment state and the pre-computed embeddings, compute the logits and sample actions

Parameters:

  • td (TensorDict) \u2013

    Input TensorDict containing the environment state

  • embeddings \u2013

    Precomputed embeddings for the nodes. Can be already precomputed cached in form of q, k, v and

  • env (Union[str, RL4COEnvBase], default: None ) \u2013

    Environment to use for decoding. If None, the environment is instantiated from env_name. Note that it is more efficient to pass an already instantiated environment each time for fine-grained control

  • decode_type (str, default: 'multistart_sampling' ) \u2013

    Type of decoding to use. Can be one of:

    • \"sampling\": sample from the logits
    • \"greedy\": take the argmax of the logits
    • \"multistart_sampling\": sample as sampling, but with multi-start decoding
    • \"multistart_greedy\": sample as greedy, but with multi-start decoding
  • num_starts (int, default: None ) \u2013

    Number of multi-starts to use. If None, will be calculated from the action mask

  • calc_reward \u2013

    Whether to calculate the reward for the decoded sequence

Source code in rl4co/models/zoo/eas/decoder.py
def forward_eas(\n    self,\n    td: TensorDict,\n    cached_embeds,\n    best_solutions,\n    iter_count: int = 0,\n    env: Union[str, RL4COEnvBase] = None,\n    decode_type: str = \"multistart_sampling\",\n    num_starts: int = None,\n    mask_logits: bool = True,\n    temperature: float = 1.0,\n    tanh_clipping: float = 0,\n    **decode_kwargs,\n):\n    \"\"\"Forward pass of the decoder\n    Given the environment state and the pre-computed embeddings, compute the logits and sample actions\n\n    Args:\n        td: Input TensorDict containing the environment state\n        embeddings: Precomputed embeddings for the nodes. Can be already precomputed cached in form of q, k, v and\n        env: Environment to use for decoding. If None, the environment is instantiated from `env_name`. Note that\n            it is more efficient to pass an already instantiated environment each time for fine-grained control\n        decode_type: Type of decoding to use. Can be one of:\n            - \"sampling\": sample from the logits\n            - \"greedy\": take the argmax of the logits\n            - \"multistart_sampling\": sample as sampling, but with multi-start decoding\n            - \"multistart_greedy\": sample as greedy, but with multi-start decoding\n        num_starts: Number of multi-starts to use. If None, will be calculated from the action mask\n        calc_reward: Whether to calculate the reward for the decoded sequence\n    \"\"\"\n    # TODO: this could be refactored by decoding strategies\n\n    # Collect logprobs\n    logprobs = []\n    actions = []\n\n    decode_step = 0\n    # Multi-start decoding: first action is chosen by ad-hoc node selection\n    if num_starts > 1 or \"multistart\" in decode_type:\n        action = env.select_start_nodes(td, num_starts + 1) % num_starts\n        # Append incumbent solutions\n        if iter_count > 0:\n            action = unbatchify(action, num_starts + 1)\n            action[:, -1] = best_solutions[:, decode_step]\n            action = action.permute(1, 0).reshape(-1)\n\n        # Expand td to batch_size * (num_starts + 1)\n        td = batchify(td, num_starts + 1)\n\n        td.set(\"action\", action)\n        td = env.step(td)[\"next\"]\n        logp = torch.zeros_like(\n            td[\"action_mask\"], device=td.device\n        )  # first logprobs is 0, so p = logprobs.exp() = 1\n\n        logprobs.append(logp)\n        actions.append(action)\n\n    # Main decoding: loop until all sequences are done\n    while not td[\"done\"].all():\n        decode_step += 1\n        logits, mask = self.forward(td, cached_embeds, num_starts + 1)\n\n        logp = process_logits(\n            logits,\n            mask,\n            temperature=self.temperature if self.temperature is not None else temperature,\n            tanh_clipping=self.tanh_clipping\n            if self.tanh_clipping is not None\n            else tanh_clipping,\n            mask_logits=self.mask_logits if self.mask_logits is not None else mask_logits,\n        )\n\n        # Select the indices of the next nodes in the sequences, result (batch_size) long\n        action = decode_logprobs(logp, mask, decode_type=decode_type)\n\n        if iter_count > 0:  # append incumbent solutions\n            init_shp = action.shape\n            action = unbatchify(action, num_starts + 1)\n            action[:, -1] = best_solutions[:, decode_step]\n            action = action.permute(1, 0).reshape(init_shp)\n\n        td.set(\"action\", action)\n        td = env.step(td)[\"next\"]\n\n        # Collect output of step\n        logprobs.append(logp)\n        actions.append(action)\n\n    logprobs, actions = torch.stack(logprobs, 1), torch.stack(actions, 1)\n    rewards = env.get_reward(td, actions)\n    return logprobs, actions, td, rewards\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.eas.nn.EASLayerNet","title":"EASLayerNet","text":"
EASLayerNet(num_instances: int, emb_dim: int)\n

Bases: Module

Instantiate weights and biases for the added layer. The layer is defined as: h = relu(emb * W1 + b1); out = h * W2 + b2. Wrapping in nn.Parameter makes the parameters trainable and sets gradient to True.

Parameters:

  • num_instances (int) \u2013

    Number of instances in the dataset

  • emb_dim (int) \u2013

    Dimension of the embedding

Source code in rl4co/models/zoo/eas/nn.py
def __init__(self, num_instances: int, emb_dim: int):\n    super().__init__()\n    # W2 and b2 are initialized to zero so in the first iteration the layer is identity\n    self.W1 = nn.Parameter(torch.randn(num_instances, emb_dim, emb_dim))\n    self.b1 = nn.Parameter(torch.randn(num_instances, 1, emb_dim))\n    self.W2 = nn.Parameter(torch.zeros(num_instances, emb_dim, emb_dim))\n    self.b2 = nn.Parameter(torch.zeros(num_instances, 1, emb_dim))\n    torch.nn.init.xavier_uniform_(self.W1)\n    torch.nn.init.xavier_uniform_(self.b1)\n
"},{"location":"docs/content/api/zoo/transductive/#models.zoo.eas.nn.EASLayerNet.forward","title":"forward","text":"
forward(*args)\n

emb: [num_instances, group_num, emb_dim]

Source code in rl4co/models/zoo/eas/nn.py
def forward(self, *args):\n    \"\"\"emb: [num_instances, group_num, emb_dim]\"\"\"\n    # get tensor arg (from partial instantiation)\n    emb = [arg for arg in args if isinstance(arg, torch.Tensor)][0]\n    h = torch.relu(torch.matmul(emb, self.W1) + self.b1.expand_as(emb))\n    return torch.matmul(h, self.W2) + self.b2.expand_as(h)\n
"},{"location":"docs/content/general/ai4co/","title":"AI4CO Community","text":"

We invite you to join our AI4CO community, an open and inclusive research group in Artificial Intelligence (AI) for Combinatorial Optimization (CO)!

"},{"location":"docs/content/general/ai4co/#links","title":"Links","text":"
  • GitHub
  • Slack
  • Website (coming soon!)
"},{"location":"docs/content/general/contribute/","title":"Contributing to RL4CO","text":"

Have a suggestion, request, or found a bug? Feel free to open an issue or submit a pull request. If you would like to contribute, please check out our contribution guidelines here. We welcome and look forward to all contributions to RL4CO!

We are also on Slack if you have any questions or would like to discuss RL4CO with us. We are open to collaborations and would love to hear from you \ud83d\ude80

"},{"location":"docs/content/general/contribute/#contributors","title":"Contributors","text":""},{"location":"docs/content/general/faq/","title":"FAQ","text":"

You can submit your questions via GitHub Issues or Discussions.

You may search for your question in the existing issues or discussions before submitting a new one. If asked more than a few times, we will add it here!

"},{"location":"docs/content/general/faq/#i-ran-into-an-error-in-the-tutorials-what-should-i-do","title":"I ran into an error in the tutorials. What should I do?","text":"

We try our best to test the tutorials but some edge cases may not be covered. If you encounter an issue, firstly we recommend to try installing the bleeding edge version of the library from source, which may resolve the it. You can do this by running the following command:

pip install -U git+https://github.com/ai4co/rl4co.git\n

If you still encounter an error, you may check out open issues on GitHub here and in case open one. Remember to report versions of the library and the environment you are using with the following commands:

python -c 'from rl4co.utils import show_versions; show_versions()'\n
"},{"location":"docs/content/general/licensing/","title":"License and Usage","text":"

Our library is released under the MIT License, which is an open and permissive license. This means:

  • You can use, modify, and distribute the code without any restrictions, even for commercial purposes.
  • Your projects will not inherit any additional limitations from our library, even if you modify or extend it.

All contributions to the library are covered by the MIT License, ensuring that everything is free to use under the same open terms. A copy of the license is available here.

"},{"location":"docs/content/general/paper/","title":"Paper and Citation","text":""},{"location":"docs/content/general/paper/#paper-reference","title":"Paper Reference","text":"

Our paper is available here for further details.

If you find RL4CO valuable for your research or applied projects, don't forget to cite us! \ud83d\ude80

@article{berto2024rl4co,\n    title={{RL4CO: an Extensive Reinforcement Learning for Combinatorial Optimization Benchmark}},\n    author={Federico Berto and Chuanbo Hua and Junyoung Park and Laurin Luttmann and Yining Ma and Fanchen Bu and Jiarui Wang and Haoran Ye and Minsu Kim and Sanghyeok Choi and Nayeli Gast Zepeda and Andr\\'e Hottung and Jianan Zhou and Jieyi Bi and Yu Hu and Fei Liu and Hyeonah Kim and Jiwoo Son and Haeyeon Kim and Davide Angioni and Wouter Kool and Zhiguang Cao and Jie Zhang and Kijung Shin and Cathy Wu and Sungsoo Ahn and Guojie Song and Changhyun Kwon and Lin Xie and Jinkyoo Park},\n    year={2024},\n    journal={arXiv preprint arXiv:2306.17100},\n    note={\\url{https://github.com/ai4co/rl4co}}\n}\n
"},{"location":"docs/content/intro/environments/","title":"Environments","text":""},{"location":"docs/content/intro/environments/#definition","title":"Definition","text":"

Given a CO problem instance \\(\\mathbf{x}\\), we formulate the solution-generating procedure as a Markov Decision Process (MDP) characterized by a tuple \\((\\mathcal{S}, \\mathcal{A}, \\mathcal{T}, \\mathcal{R}, \\gamma)\\) as follows:

  • State \\(\\mathcal{S}\\) is the space of states that represent the given problem \\(\\mathbf{x}\\) and the current partial solution being updated in the MDP.
  • Action \\(\\mathcal{A}\\) is the action space, which includes all feasible actions \\(a_t\\) that can be taken at each step \\(t\\).
  • State Transition \\(\\mathcal{T}\\) is the deterministic state transition function \\(s_{t+1} = \\mathcal{T}(s_t, a_t)\\) that updates a state \\(s_t\\) to the next state \\(s_{t+1}\\).
  • Reward \\(\\mathcal{R}\\) is the reward function \\(\\mathcal{R}(s_t, a_t)\\) representing the immediate reward received after taking action \\(a_t\\) in state \\(s_t\\).
  • Discount Factor \\(\\gamma \\in [0, 1]\\) determines the importance of future rewards. Often, \\(\\gamma = 1\\) is used for CO problems, i.e., no discounting.

Since the state transition is deterministic, we represent the solution for a problem \\(\\mathbf{x}\\) as a sequence of \\(T\\) actions \\(\\mathbf{a} = (a_1, \\ldots, a_T)\\). Then the total return \\(\\sum_{t=1}^T \\mathcal{R}(s_t, a_t)\\) translates to the negative cost function of the CO problem.

In the following, we define the above MDP for the main CO problem types we consider in our library.

"},{"location":"docs/content/intro/environments/#routing-problems","title":"Routing Problems","text":"

Routing problems are perhaps the most known class of CO problems. They are problems of great practical importance, not only for logistics, where they are more commonly framed, but also for industry, engineering, science, and medicine. The typical objective of routing problems is to minimize the total length of the paths needed to visit some (or all) the nodes in a graph \\(G = (V, E)\\)., and \\(i, j \\in V\\) are nodes in the graph.

"},{"location":"docs/content/intro/environments/#mdp","title":"MDP","text":"

For routing problems, in RL4CO we consider two types of MDPs: Construction MDP and Improvement MDP.

"},{"location":"docs/content/intro/environments/#construction-mdp","title":"Construction MDP","text":"

The Construction MDP describes a process of iteratively building a solution from scratch:

  • State \\(s_t \\in \\mathcal{S}\\): Reflects (1) node-level information for each customer node (e.g., coordinates, demand), (2) global-level information about the route construction (e.g., remaining vehicle capacity), and (3) the current partial solution \\(\\{a_1, \\ldots, a_{t-1}\\}\\) where \\(a_i\\) is the previously selected node (action) at time \\(i\\). The initial state at \\(t = 0\\) has an empty partial solution.
  • Action \\(a_t \\in \\mathcal{A}\\): Choosing a valid node from set \\(V\\). The action space is state-dependent, with infeasible actions masked to ensure all constraints are satisfied.
  • Transition \\(\\mathcal{T}\\): Deterministic transition that adds the selected action \\(a_t\\) to the partial solution, updating it from \\(\\{a_1, \\ldots, a_{t-1}\\}\\) to \\(\\{a_1, \\ldots, a_{t-1}, a_t\\}\\), and updates the node-level and global-level information accordingly.
  • Reward \\(\\mathcal{R}\\): Typically set to the negative value of the increase in tour length, ensuring that maximizing cumulative rewards is equivalent to minimizing the tour length objective.
  • Policy \\(\\pi\\): Usually parameterized by a deep neural network, it decides on an action \\(a_t\\) given the input state \\(s_t\\). The policy is typically stochastic, learning an action distribution for selecting each node.
"},{"location":"docs/content/intro/environments/#improvement-mdp","title":"Improvement MDP","text":"

The Improvement MDP describes a search process similar to neighborhood search, starting from a sub-optimal solution \\(\\bm{a}^{0}=(a_{0}^{0},\\ldots, a_{T-1}^{0})\\) and finding another one potentially with higher quality:

  • State \\(s_t \\in \\mathcal{S}\\): Reflects (1) node-level information for each customer node, (2) global-level information about the search (e.g., historical visited solutions and their costs), and (3) the current solution \\(\\bm{a^t}\\). The initial state \\(s_0\\) contains a randomly generated feasible solution \\(\\bm{a^0}\\).
  • Action \\(a_t \\in \\mathcal{A}\\): A specific operation that changes the current solution \\(\\bm{a^t}\\) into a new one \\(\\bm{a^{t+1}}\\). For example, specifying two nodes \\((i, j)\\) in \\(V\\) to perform a pairwise local search operation.
  • Transition \\(\\mathcal{T}\\): Usually deterministic, accepting the proposed solution \\(\\bm{a^{t+1}}\\) as the solution for the next state and updating node-level and global-level information accordingly.
  • Reward \\(\\mathcal{R}\\): Typically set to the immediate reduced objective value of the current best-so-far solution after taking the local search action.
  • Policy \\(\\pi\\): Usually stochastic and parameterized by a deep model. The time horizon can be user-specified based on the available time budget, often requiring a discount factor \\(\\gamma < 1\\).

The best solution found throughout the improvement horizon is recognized as the final solution to the routing problem.

"},{"location":"docs/content/intro/environments/#documentation","title":"Documentation","text":"

Click here for API documentation on routing problems.

"},{"location":"docs/content/intro/environments/#scheduling-problems","title":"Scheduling Problems","text":"

Scheduling problems are a fundamental class of problems in operations research and industrial engineering, where the objective is to optimize the allocation of resources over time. These problems are critical in various industries, such as manufacturing, computer science, and project management.

"},{"location":"docs/content/intro/environments/#mdp_1","title":"MDP","text":"

Here we show a general constructive MDP formulation based on the Job Shop Scheduling Problem (JSSP), a well-known scheduling problem, which can be adapted to other scheduling problems.

  • State \\(s_t \\in \\mathcal{S}\\): The state is represented by a disjunctive graph, where:
    • Operations are nodes
    • Processing orders between operations are shown by directed arcs
    • This graph encapsulates both the problem instance and the current partial schedule
  • Action \\(a_t \\in \\mathcal{A}\\): An action involves selecting a feasible operation to assign to its designated machine, a process often referred to as dispatching. The action space consists of all operations that can be feasibly scheduled at the current state.
  • Transition \\(\\mathcal{T}\\): The transition function deterministically updates the disjunctive graph based on the dispatched operation. This includes:
    • Modifying the graph's topology (e.g., adding new connections between operations)
    • Updating operation attributes (e.g., start times)
  • Reward \\(\\mathcal{R}\\): The reward function is designed to align with the optimization objective. For instance, if minimizing makespan is the goal, the reward could be the negative change in makespan resulting from the latest action.
  • Policy \\(\\pi\\): The policy, typically stochastic, takes the current disjunctive graph as input and outputs a probability distribution over feasible dispatching actions. This process continues until a complete schedule is constructed.
"},{"location":"docs/content/intro/environments/#documentation_1","title":"Documentation","text":"

Click here for API documentation on scheduling problems.

"},{"location":"docs/content/intro/environments/#electronic-design-automation","title":"Electronic Design Automation","text":"

Electronic Design Automation (EDA) is a sophisticated process that involves the use of software tools to design, simulate, and analyze electronic systems, particularly integrated circuits (ICs) and printed circuit boards (PCBs). EDA encompasses a wide range of tasks, from schematic capture and layout design to verification and testing. Optimization is a critical aspect of EDA, where the goal is to achieve the best possible performance, power efficiency, and cost within the constraints of the design.

"},{"location":"docs/content/intro/environments/#mdp_2","title":"MDP","text":"

EDA encompasses many problem types; here we'll focus on placement problems, which are fundamental in the physical design of integrated circuits and printed circuit boards. We'll use the Decap Placement Problem (DPP) as an example to illustrate a typical MDP formulation for EDA placement problems.

  • State \\(s_t \\in \\mathcal{S}\\): The state typically represents the current configuration of the design space, which may include:
    • Locations of fixed elements (e.g., ports, keepout regions)
    • Current placements of movable elements
    • Remaining resources or components to be placed
  • Action \\(a_t \\in \\mathcal{A}\\): An action usually involves placing a component at a valid location within the design space. The action space consists of all feasible placement locations, considering design rules and constraints.
  • Transition \\(\\mathcal{T}\\): The transition function updates the design state based on the placement action, which may include:
    • Updating the placement map
    • Adjusting available resources or remaining components
    • Recalculating relevant metrics (e.g., wire length, power distribution)
  • Reward \\(\\mathcal{R}\\): The reward is typically based on the improvement in the design objective resulting from the latest placement action. This could involve metrics such as area efficiency, signal integrity, or power consumption.
  • Policy \\(\\pi\\): The policy takes the current design state as input and outputs a probability distribution over possible placement actions.

Note that specific problems may introduce additional complexities or constraints.

"},{"location":"docs/content/intro/environments/#documentation_2","title":"Documentation","text":"

Click here for API documentation on EDA problems.

"},{"location":"docs/content/intro/environments/#graph-problems","title":"Graph Problems","text":"

Many CO problems can be (re-)formulated on graphs. In typical CO problems on graphs, actions are defined on nodes/edges, while problem variables and constraints are incorporated in graph topology and node/edge attributes (e.g., weights). The graph-based formulation gives us concise and systematic representations of CO problems.

In graph problems, we typically work with a graph \\(G = (V, E)\\), where \\(V\\) is a set of vertices (or nodes) and \\(E\\) is a set of edges connecting these vertices. The optimization task often involves selecting a subset of vertices, edges, or subgraphs to maximize or minimize a given objective function, subject to certain constraints.

"},{"location":"docs/content/intro/environments/#mdp_3","title":"MDP","text":"

Graph problems can be effectively modeled using a Markov Decision Process (MDP) framework in a constructive fashion. Here, we outline the key components of the MDP formulation for graph problems:

  • State \\(s_t \\in \\mathcal{S}\\): The state encapsulates the current configuration of the graph and the optimization progress. It typically includes:
    • The graph structure (vertices and edges)
    • Attributes associated with vertices or edges
    • The set of elements (vertices, edges, or subgraphs) selected so far
    • Problem-specific information, such as remaining selections or resources
  • Action \\(a_t \\in \\mathcal{A}\\): An action usually involves selecting a graph element (e.g., a vertex, edge, or subgraph). The action space comprises all valid selections based on the problem constraints and the current state.
  • Transition \\(\\mathcal{T}\\): The transition function \\(\\mathcal{T}(s_t, a_t) \\rightarrow s_{t+1}\\) updates the graph state based on the selected action. This typically involves:
    • Updating the set of selected elements
    • Modifying graph attributes affected by the selection
    • Updating problem-specific information (e.g., remaining selections or resources)
  • Reward \\(\\mathcal{R}\\): The reward function \\(\\mathcal{R}(s_t, a_t)\\) quantifies the quality of the action taken. It is typically based on the improvement in the optimization objective resulting from the latest selection. This could involve metrics such as coverage, distance, connectivity, or any other problem-specific criteria.
  • Policy \\(\\pi\\): The policy \\(\\pi(a_t|s_t)\\) is a probability distribution over possible actions given the current state. It guides the decision-making process, determining which graph elements to select at each step to optimize the objective.

Specific problems may introduce additional complexities or constraints, which can often be incorporated through careful design of the state space, action space, and reward function.

"},{"location":"docs/content/intro/environments/#documentation_3","title":"Documentation","text":"

Click here for API documentation on graph problems.

"},{"location":"docs/content/intro/environments/#implementation-details","title":"Implementation Details","text":"

Environments in our library fully specify the CO problems and their logic. They are based on the RL4COEnvBase class that extends from the EnvBase in TorchRL.

Key features:

  • A modular generator can be provided to the environment.
  • The generator provides CO instances to the environment, and different generators can be used to generate different data distributions.
  • Static instance data and dynamic variables, such as the current state \\(s_t\\), current solution \\(\\mathbf{a}^k\\) for improvement environments, policy actions \\(a_t\\), rewards, and additional information are passed in a stateless fashion in a TensorDict, that we call td, through the environment reset and step functions.

Our environment API contains several functions:

  • render
  • check_solution_validity
  • select_start_nodes (i.e., for POMO-based optimization)
  • Optional API such as local_search for solution improvement

It's worth noting that our library enhances the efficiency of environments when compared to vanilla TorchRL, by overriding and optimizing some methods in TorchRL EnvBase. For instance, our new step method brings a decrease of up to 50% in latency and halves the memory impact by avoiding saving duplicate components in the stateless TensorDict.

"},{"location":"docs/content/intro/intro/","title":"Introduction","text":"

RL4CO is an extensive Reinforcement Learning (RL) for Combinatorial Optimization (CO) benchmark. Our goal is to provide a unified framework for RL-based CO algorithms, and to facilitate reproducible research in this field, decoupling the science from the engineering.

"},{"location":"docs/content/intro/intro/#motivation","title":"Motivation","text":""},{"location":"docs/content/intro/intro/#why-nco","title":"Why NCO?","text":"

Neural Combinatorial Optimization (NCO) is a subfield of AI that aims to solve combinatorial optimization problems using neural networks. NCO has been successfully applied to a wide range of problems, such as the routing problems in logistics, the scheduling problems in manufacturing, and electronic design automation. The key idea behind NCO is to learn a policy that maps the input data to the optimal solution, without the need for hand-crafted heuristics or domain-specific knowledge.

"},{"location":"docs/content/intro/intro/#why-rl","title":"Why RL?","text":"

Reinforcement Learning (RL) is a machine learning paradigm that enables agents to learn how to make decisions by interacting with an environment. RL has been successfully applied to a wide range of problems, such as playing games, controlling robots, and optimizing complex systems. The key idea behind RL is to learn a policy that maps the state of the environment to the optimal action, by maximizing a reward signal. Importantly, optimal solutions are not required for training, as RL agents learn from the feedback they receive from the environment.

"},{"location":"docs/content/intro/intro/#contents","title":"Contents","text":"

We explore in other pages the following components:

  • Environments: Markov Decision Process (MDP) for CO problems and base classes for environments. These are based on TorchRL.
  • Policies: the neural networks that are used to solve CO problems and their base classes. These are based on PyTorch.
  • RL Algorithms: (broadly: \"models\"), which are the processes used to train the policies and their base classes. These are based on PyTorch Lightning.
"},{"location":"docs/content/intro/intro/#paper-reference","title":"Paper Reference","text":"

Our paper is available here for further details.

If you find RL4CO valuable for your research or applied projects, don't forget to cite us! \ud83d\ude80

@article{berto2024rl4co,\n    title={{RL4CO: an Extensive Reinforcement Learning for Combinatorial Optimization Benchmark}},\n    author={Federico Berto and Chuanbo Hua and Junyoung Park and Laurin Luttmann and Yining Ma and Fanchen Bu and Jiarui Wang and Haoran Ye and Minsu Kim and Sanghyeok Choi and Nayeli Gast Zepeda and Andr\\'e Hottung and Jianan Zhou and Jieyi Bi and Yu Hu and Fei Liu and Hyeonah Kim and Jiwoo Son and Haeyeon Kim and Davide Angioni and Wouter Kool and Zhiguang Cao and Jie Zhang and Kijung Shin and Cathy Wu and Sungsoo Ahn and Guojie Song and Changhyun Kwon and Lin Xie and Jinkyoo Park},\n    year={2024},\n    journal={arXiv preprint arXiv:2306.17100},\n    note={\\url{https://github.com/ai4co/rl4co}}\n}\n
"},{"location":"docs/content/intro/policies/","title":"Policies","text":"

The policies can be categorized into constructive policies, which generate a solution from scratch, and improvement policies, which refine an existing solution.

"},{"location":"docs/content/intro/policies/#constructive-policies","title":"Constructive policies","text":"

A policy \\(\\pi\\) is used to construct a solution from scratch for a given problem instance \\(\\mathbf{x}\\). It can be further categorized into autoregressive (AR) and non-autoregressive (NAR) policies.

"},{"location":"docs/content/intro/policies/#autoregressive-ar-policies","title":"Autoregressive (AR) policies","text":"

An AR policy is composed of an encoder \\(f\\) that maps the instance \\(\\mathbf{x}\\) into an embedding space \\(\\mathbf{h}=f(\\mathbf{x})\\) and by a decoder \\(g\\) that iteratively determines a sequence of actions \\(\\mathbf{a}\\) as follows:

\\[ a_t \\sim g(a_t | a_{t-1}, ... ,a_0, s_t, \\mathbf{h}), \\quad \\pi(\\mathbf{a}|\\mathbf{x}) \\triangleq \\prod_{t=1}^{T-1} g(a_{t} | a_{t-1}, \\ldots ,a_0, s_t, \\mathbf{h}). \\]"},{"location":"docs/content/intro/policies/#non-autoregressive-nar-policies","title":"Non-autoregressive (NAR) policies","text":"

A NAR policy encodes a problem \\(\\mathbf{x}\\) into a heuristic \\(\\mathcal{H} = f(\\mathbf{x}) \\in \\mathbb{R}^{N}_{+}\\), where \\(N\\) is the number of possible assignments across all decision variables. Each number in \\(\\mathcal{H}\\) represents a (unnormalized) probability of a particular assignment. To obtain a solution \\(\\mathbf{a}\\) from \\(\\mathcal{H}\\), one can sample a sequence of assignments from \\(\\mathcal{H}\\) while dynamically masking infeasible assignments to meet problem-specific constraints. It can also guide a search process, e.g., Ant Colony Optimization, or be incorporated into hybrid frameworks. Here, the heuristic helps identify promising transitions and improve the efficiency of finding an optimal or near-optimal solution.

"},{"location":"docs/content/intro/policies/#improvement-policies","title":"Improvement policies","text":"

A policy can be used for improving an initial solution \\(\\mathbf{a}^{0}=(a_{0}^{0},\\ldots, a_{T-1}^{0})\\) into another one potentially with higher quality, which can be formulated as follows:

\\[ \\mathbf{a}^k \\sim g(\\mathbf{a}^{0}, \\mathbf{h}), \\quad\\pi(\\mathbf{a}^K|\\mathbf{a}^0,\\mathbf{x}) \\triangleq \\prod_{k=1}^{K-1} g(\\mathbf{a}^k | \\mathbf{a}^{k-1}, ... ,\\mathbf{a}^0, \\mathbf{h}), \\]

where \\(\\mathbf{a}^{k}\\) is the \\(k\\)-th updated solution and \\(K\\) is the budget for number of improvements. This process allows continuous refinement for a long time to enhance the solution quality.

"},{"location":"docs/content/intro/policies/#implementation","title":"Implementation","text":"

Policies in our library are subclasses of PyTorch's nn.Module and contain the encoding-decoding logic and neural network parameters \\(\\theta\\). Different policies in the RL4CO \"zoo\" can inherit from metaclasses like ConstructivePolicy or ImprovementPolicy. We modularize components to process raw features into the embedding space via a parametrized function \\(\\phi_\\omega\\), called feature embeddings.

  1. Node Embeddings \\(\\phi_n\\): transform \\(m_n\\) node features of instances \\(\\mathbf{x}\\) from the feature space to the embedding space \\(h\\), i.e., \\([B, N, m_n] \\rightarrow [B, N, h]\\).
  2. Edge Embeddings \\(\\phi_e\\): transform \\(m_e\\) edge features of instances \\(\\mathbf{x}\\) from the feature space to the embedding space \\(h\\), i.e., \\([B, E, m_e] \\rightarrow [B, E, h]\\), where \\(E\\) is the number of edges.
  3. Context Embeddings \\(\\phi_c\\): capture contextual information by transforming \\(m_c\\) context features from the current decoding step \\(s_t\\) from the feature space to the embedding space \\(h\\), i.e., \\([B, m_c] \\rightarrow [B, h]\\), for nodes or edges.

Embeddings can be automatically selected by our library at runtime by simply passing the env_name to the policy. Additionally, we allow for granular control of any higher-level policy component independently, such as encoders and decoders.

"},{"location":"docs/content/intro/rl/","title":"RL Algorithms","text":""},{"location":"docs/content/intro/rl/#definitions","title":"Definitions","text":"

The RL objective is to learn a policy \\(\\pi\\) that maximizes the expected cumulative reward (or equivalently minimizes the cost) over the distribution of problem instances:

\\[ \\theta^{*} = \\underset{\\theta}{\\text{argmax}} \\, \\mathbb{E}_{\\mathbf{x} \\sim P(\\mathbf{x})} \\left[ \\mathbb{E}_{\\pi(\\mathbf{a}|\\mathbf{x})} \\left[ \\sum_{t=0}^{T-1} \\gamma^t \\mathcal{R}(s_t, a_t) \\right] \\right], \\]

where \\(\\theta\\) is the set of parameters of \\(\\pi\\) and \\(P(\\mathbf{x})\\) is the distribution of problem instances.

This equation can be solved using algorithms such as variations of REINFORCE, Advantage Actor-Critic (A2C) methods, or Proximal Policy Optimization (PPO).

These algorithms are employed to train the policy network \\(\\pi\\), by transforming the maximization problem into a minimization problem involving a loss function, which is then optimized using gradient descent algorithms. For instance, the REINFORCE loss function gradient is given by:

\\[ \\nabla_{\\theta} \\mathcal{L}_a(\\theta|\\mathbf{x}) = \\mathbb{E}_{\\pi(\\mathbf{a}|\\mathbf{x})} \\left[(R(\\mathbf{a}, \\mathbf{x}) - b(\\mathbf{x})) \\nabla_{\\theta}\\log \\pi(\\mathbf{a}|\\mathbf{x})\\right], \\]

where \\(b(\\cdot)\\) is a baseline function used to stabilize training and reduce gradient variance.

We also distinguish between two types of RL (pre)training:

  1. Inductive RL: The focus is on learning patterns from the training dataset to generalize to new instances, thus amortizing the inference procedure.
  2. Transductive RL (or test-time optimization): Optimizes parameters during testing on target instances.

Typically, a policy \\(\\pi\\) is trained using inductive RL, followed by transductive RL for test-time optimization.

"},{"location":"docs/content/intro/rl/#implementation","title":"Implementation","text":"

RL algorithms in our library define the process that takes the Environment with its problem instances and the Policy to optimize its parameters \\(\\theta\\). The parent class of algorithms is the RL4COLitModule, inheriting from PyTorch Lightning's pl.LightningModule. This allows for granular support of various methods including the [train, val, test]_step, automatic logging with several logging services such as Wandb via log_metrics, automatic optimizer configuration via configure_optimizers and several useful callbacks for RL methods such as on_train_epoch_end.

RL algorithms are additionally attached to an RL4COTrainer, a wrapper we made with additional optimizations around pl.Trainer. This module seamlessly supports features of modern training pipelines, including:

  • Logging
  • Checkpoint management
  • Mixed-precision training
  • Various hardware acceleration supports (e.g., CPU, GPU, TPU, and Apple Silicon)
  • Multi-device hardware accelerator in distributed settings

For instance, using mixed-precision training significantly decreases training time without sacrificing much convergence and enables us to leverage recent routines, e.g., FlashAttention.

"},{"location":"docs/content/start/hydra/","title":"Training with Hydra Configurations","text":"

You may find Hydra configurations under configs/ divided into categories (model, env, train, experiment, etc.).

In practice, we usually want to modify configurations under the experiment folder, of which we report an example below here.

"},{"location":"docs/content/start/hydra/#usage","title":"Usage","text":"

Train model with default configuration (AM on TSP environment):

python run.py\n

"},{"location":"docs/content/start/hydra/#change-experiment","title":"Change experiment","text":"

Train model with chosen experiment configuration from configs/experiment/

python run.py experiment=routing/am env=tsp env.generator_params.num_loc=50 model.optimizer_kwargs.lr=2e-4\n
Here you may change the environment, e.g. with env=cvrp by command line or by modifying the corresponding experiment e.g. configs/experiment/routing/am.yaml.

"},{"location":"docs/content/start/hydra/#disable-logging","title":"Disable logging","text":"

python run.py experiment=test/am logger=none '~callbacks.learning_rate_monitor'\n
Note that ~ is used to disable a callback that would need a logger.

"},{"location":"docs/content/start/hydra/#create-a-sweep-over-hyperparameters","title":"Create a sweep over hyperparameters","text":"

We can use -m for multirun:

python run.py -m experiment=routing/am  model.optimizer_kwargs.lr=1e-3,1e-4,1e-5\n
"},{"location":"docs/content/start/hydra/#experiment-configuration-example","title":"Experiment Configuration Example","text":"

We report here a configuration for running the Attention Model (AM) on a TSP environment with 50 locations that can be placed under configs/experiment:

# @package _global_\n\ndefaults:\n\n  - override /model: am.yaml\n  - override /env: tsp.yaml\n  - override /callbacks: default.yaml\n  - override /trainer: default.yaml\n  - override /logger: wandb.yaml\n\nenv:\n  generator_params:\n    loc_distribution: \"uniform\"\n    num_loc: 50\n\nmodel:\n  policy:\n    _target_: \"rl4co.models.zoo.am.AttentionModelPolicy\"\n    embed_dim: 128\n    num_heads: 8\n    num_encoder_layers: 3\n  batch_size: 512\n  val_batch_size: 1024\n  test_batch_size: 1024\n  train_data_size: 1_280_000\n  val_data_size: 10_000\n  test_data_size: 10_000\n  optimizer_kwargs:\n    lr: 1e-4\n    weight_decay: 1e-6\n  lr_scheduler:\n    \"MultiStepLR\"\n  lr_scheduler_kwargs:\n    milestones: [80, 95]\n    gamma: 0.1\n\ntrainer:\n  max_epochs: 100\n\nlogger:\n  wandb:\n    project: \"rl4co\"\n    tags: [\"am\", \"${env.name}\"]\n    group: ${env.name}${env.generator_params.num_loc}\n    name: am-${env.name}${env.generator_params.num_loc}\n

What does this configuration do? Let's break it down!

defaults:\n\n  - override /model: am.yaml\n  - override /env: tsp.yaml\n  - override /callbacks: default.yaml\n  - override /trainer: default.yaml\n  - override /logger: wandb.yaml\n

This section sets the default configuration for the model, environment, callbacks, trainer, and logger. This means that if a key is not specified in the experiment configuration, the default value will be used. Note that these are set in the root configs/ folder, and are useful for better organization and reusability.

env: \n  generator_params:\n    loc_distribution: \"uniform\"\n    num_loc: 50\n

This section specifies the environment configuration. In this case, we are using the TSP environment with 50 locations generated uniformly.

model:\n  policy:\n    _target_: \"rl4co.models.zoo.am.AttentionModelPolicy\"\n    embed_dim: 128\n    num_heads: 8\n    num_encoder_layers: 3\n  batch_size: 512\n  val_batch_size: 1024\n  test_batch_size: 1024\n  train_data_size: 1_280_000\n  val_data_size: 10_000\n  test_data_size: 10_000\n  optimizer_kwargs:\n    lr: 1e-4\n    weight_decay: 1e-6\n  lr_scheduler:\n    \"MultiStepLR\"\n  lr_scheduler_kwargs:\n    milestones: [80, 95]\n    gamma: 0.1\n

This section specifies the RL model (i.e., Lightning module) configuration. While this usually includes the policy architecture already (hence the name \"model\"), we can override it by specifying a _target_ key and additional parameters to initialize the policy. Finally, we specify the batch sizes, data sizes, optimizer parameters, and learning rate scheduler.

trainer:\n  max_epochs: 100\n

This section specifies the trainer configuration. Here, we are training the model for 100 epochs.

logger:\n  wandb:\n    project: \"rl4co\"\n    tags: [\"am\", \"${env.name}\"]\n    group: ${env.name}${env.generator_params.num_loc}\n    name: am-${env.name}${env.generator_params.num_loc}\n

Finally, this section specifies the logger configuration. In this case, we are using Weights & Biases (WandB) to log the results of the experiment. We specify the project name, tags, group, and name of the experiment.

That's it! \ud83c\udf89

Tip

For more advanced content and detailed descriptions, you may also check out this notebook!

Now, you are ready to start training. If you save the above under configs/experiment/mynewexperiment.yaml, you can run it from the root of your RL4CO-based project with:

python run.py experiment=mynewexperiment\n

"},{"location":"docs/content/start/installation/","title":"Installation","text":"

RL4CO is now available for installation on pip!

pip install rl4co\n

"},{"location":"docs/content/start/installation/#local-install-and-development","title":"Local install and development","text":"

If you want to develop RL4CO or access the latest builds, we recommend you to install it locally with pip in editable mode:

git clone https://github.com/ai4co/rl4co && cd rl4co\npip install -e .\n

Note: conda is also a good candidate for hassle-free installation of PyTorch: check out the PyTorch website for more details.

"},{"location":"docs/content/start/installation/#minimalistic-example","title":"Minimalistic Example","text":"

Here is a minimalistic example training the Attention Model with greedy rollout baseline on TSP in less than 30 lines of code:

from rl4co.envs.routing import TSPEnv, TSPGenerator\nfrom rl4co.models import AttentionModelPolicy, POMO\nfrom rl4co.utils import RL4COTrainer\n\n# Instantiate generator and environment\ngenerator = TSPGenerator(num_loc=50, loc_distribution=\"uniform\")\nenv = TSPEnv(generator)\n\n# Create policy and RL model\npolicy = AttentionModelPolicy(env_name=env.name, num_encoder_layers=6)\nmodel = POMO(env, policy, batch_size=64, optimizer_kwargs={\"lr\": 1e-4})\n\n# Instantiate Trainer and fit\ntrainer = RL4COTrainer(max_epochs=10, accelerator=\"gpu\", precision=\"16-mixed\")\ntrainer.fit(model)\n

Tip

We recommend checking out our quickstart notebook!

"},{"location":"examples/","title":"\ud83e\udde9 Examples and Tutorials","text":"

This is a collection of examples and tutorials for using the RL4CO library.

The root directory is made of quickstarts and contains the following:

"},{"location":"examples/#quickstarts","title":"\u26a1\ufe0f Quickstarts","text":"

This is the root directory of the examples. The following quickstarts are available:

  • 1-quickstart.ipynb: here we train a model on a simple environment - it takes less than 2 minutes!
  • 2-full-training.ipynb: similar to the previous notebooks but with a more interesting environment, with checkpointing, logging, and callbacks.

    - 2b-train-simple.py: here we show a simple script that can be called with python 2b-train-simple.py. This is simplified and does not use Hydra - for those who prefer a simpler setup. Note that we also made a Hydra tutorial here. - 3-creating-new-env-model.ipynb: here we show how to extend RL4CO to solve new problems and create new models from zero to hero!

"},{"location":"examples/#folders-index","title":"\ud83d\udcc1 Folders Index","text":""},{"location":"examples/#modeling","title":"Modeling","text":"

Under the modeling/ directory, here are some additional examples for modeling and inference.

"},{"location":"examples/#datasets","title":"Datasets","text":"

Under the datasets/ directory, here are some additional examples for using your custom data to train/evaluate your models

"},{"location":"examples/#advanced","title":"Advanced","text":"

Under the advanced/ directory, here are some additional examples for advanced topics.

"},{"location":"examples/#other","title":"Other","text":"

Under the other/ directory, here are some additional examples for other topics.

"},{"location":"examples/1-quickstart/","title":"RL4CO Quickstart Notebook","text":"

In this notebook we will train the AttentionModel (AM) on the TSP environment for 20 nodes. On a GPU, this should less than 2 minutes! \ud83d\ude80

In\u00a0[6]: Copied!
## Uncomment the following line to install the package from PyPI\n## You may need to restart the runtime in Colab after this\n## Remember to choose a GPU runtime for faster training!\n\n# !pip install rl4co\n
## Uncomment the following line to install the package from PyPI ## You may need to restart the runtime in Colab after this ## Remember to choose a GPU runtime for faster training! # !pip install rl4co In\u00a0[7]: Copied!
%load_ext autoreload\n%autoreload 2\n\nimport torch\n\nfrom rl4co.envs import TSPEnv\nfrom rl4co.models import AttentionModelPolicy, REINFORCE\nfrom rl4co.utils.trainer import RL4COTrainer\n
%load_ext autoreload %autoreload 2 import torch from rl4co.envs import TSPEnv from rl4co.models import AttentionModelPolicy, REINFORCE from rl4co.utils.trainer import RL4COTrainer
The autoreload extension is already loaded. To reload it, use:\n  %reload_ext autoreload\n
In\u00a0[8]: Copied!
# RL4CO env based on TorchRL\nenv = TSPEnv(generator_params={'num_loc': 50})\n\n# Policy: neural network, in this case with encoder-decoder architecture\npolicy = AttentionModelPolicy(env_name=env.name, \n                              embed_dim=128,\n                              num_encoder_layers=3,\n                              num_heads=8,\n                            )\n\n# RL Model: REINFORCE and greedy rollout baseline\nmodel = REINFORCE(env, \n                    policy,\n                    baseline=\"rollout\",\n                    batch_size=512,\n                    train_data_size=100_000,\n                    val_data_size=10_000,\n                    optimizer_kwargs={\"lr\": 1e-4},\n                    )\n
# RL4CO env based on TorchRL env = TSPEnv(generator_params={'num_loc': 50}) # Policy: neural network, in this case with encoder-decoder architecture policy = AttentionModelPolicy(env_name=env.name, embed_dim=128, num_encoder_layers=3, num_heads=8, ) # RL Model: REINFORCE and greedy rollout baseline model = REINFORCE(env, policy, baseline=\"rollout\", batch_size=512, train_data_size=100_000, val_data_size=10_000, optimizer_kwargs={\"lr\": 1e-4}, ) In\u00a0[9]: Copied!
# Greedy rollouts over untrained policy\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\ntd_init = env.reset(batch_size=[3]).to(device)\npolicy = policy.to(device)\nout = policy(td_init.clone(), phase=\"test\", decode_type=\"greedy\", return_actions=True)\nactions_untrained = out['actions'].cpu().detach()\nrewards_untrained = out['reward'].cpu().detach()\n\nfor i in range(3):\n    print(f\"Problem {i+1} | Cost: {-rewards_untrained[i]:.3f}\")\n    env.render(td_init[i], actions_untrained[i])\n
# Greedy rollouts over untrained policy device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\") td_init = env.reset(batch_size=[3]).to(device) policy = policy.to(device) out = policy(td_init.clone(), phase=\"test\", decode_type=\"greedy\", return_actions=True) actions_untrained = out['actions'].cpu().detach() rewards_untrained = out['reward'].cpu().detach() for i in range(3): print(f\"Problem {i+1} | Cost: {-rewards_untrained[i]:.3f}\") env.render(td_init[i], actions_untrained[i])
Problem 1 | Cost: 10.648\nProblem 2 | Cost: 9.375\nProblem 3 | Cost: 11.713\n
In\u00a0[10]: Copied!
trainer = RL4COTrainer(\n    max_epochs=3,\n    accelerator=\"gpu\",\n    devices=1,\n    logger=None,\n)\n
trainer = RL4COTrainer( max_epochs=3, accelerator=\"gpu\", devices=1, logger=None, )
Using 16bit Automatic Mixed Precision (AMP)\nGPU available: True (cuda), used: True\nGPU available: True (cuda), used: True\nTPU available: False, using: 0 TPU cores\nIPU available: False, using: 0 IPUs\nHPU available: False, using: 0 HPUs\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/logger_connector/logger_connector.py:75: Starting from v1.9.0, `tensorboardX` has been removed as a dependency of the `lightning.pytorch` package, due to potential conflicts with other packages in the ML ecosystem. For this reason, `logger=True` will use `CSVLogger` as the default logger, unless the `tensorboard` or `tensorboardX` packages are found. Please `pip install lightning[extra]` or one of them to enable TensorBoard support by default\n
In\u00a0[11]: Copied!
trainer.fit(model)\n
trainer.fit(model)
val_file not set. Generating dataset instead\ntest_file not set. Generating dataset instead\nLOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n\n  | Name     | Type                 | Params\n--------------------------------------------------\n0 | env      | TSPEnv               | 0     \n1 | policy   | AttentionModelPolicy | 710 K \n2 | baseline | WarmupBaseline       | 710 K \n--------------------------------------------------\n1.4 M     Trainable params\n0         Non-trainable params\n1.4 M     Total params\n5.681     Total estimated model params size (MB)\n
Sanity Checking: |          | 0/? [00:00<?, ?it/s]
/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'val_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=31` in the `DataLoader` to improve performance.\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'train_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=31` in the `DataLoader` to improve performance.\n
Training: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
`Trainer.fit` stopped: `max_epochs=3` reached.\n
In\u00a0[12]: Copied!
# Greedy rollouts over trained model (same states as previous plot)\npolicy = model.policy.to(device)\nout = policy(td_init.clone(), phase=\"test\", decode_type=\"greedy\", return_actions=True)\nactions_trained = out['actions'].cpu().detach()\n\n# Plotting\nimport matplotlib.pyplot as plt\nfor i, td in enumerate(td_init):\n    fig, axs = plt.subplots(1,2, figsize=(11,5))\n    env.render(td, actions_untrained[i], ax=axs[0]) \n    env.render(td, actions_trained[i], ax=axs[1])\n    axs[0].set_title(f\"Untrained | Cost = {-rewards_untrained[i].item():.3f}\")\n    axs[1].set_title(r\"Trained $\\pi_\\theta$\" + f\"| Cost = {-out['reward'][i].item():.3f}\")\n
# Greedy rollouts over trained model (same states as previous plot) policy = model.policy.to(device) out = policy(td_init.clone(), phase=\"test\", decode_type=\"greedy\", return_actions=True) actions_trained = out['actions'].cpu().detach() # Plotting import matplotlib.pyplot as plt for i, td in enumerate(td_init): fig, axs = plt.subplots(1,2, figsize=(11,5)) env.render(td, actions_untrained[i], ax=axs[0]) env.render(td, actions_trained[i], ax=axs[1]) axs[0].set_title(f\"Untrained | Cost = {-rewards_untrained[i].item():.3f}\") axs[1].set_title(r\"Trained $\\pi_\\theta$\" + f\"| Cost = {-out['reward'][i].item():.3f}\")

We can see that even after just 3 epochs, our trained AM is able to find much better solutions than the random policy! \ud83c\udf89

In\u00a0[13]: Copied!
# Optionally, save the checkpoint for later use (e.g. in tutorials/4-search-methods.ipynb)\ntrainer.save_checkpoint(\"tsp-quickstart.ckpt\")\n
# Optionally, save the checkpoint for later use (e.g. in tutorials/4-search-methods.ipynb) trainer.save_checkpoint(\"tsp-quickstart.ckpt\")"},{"location":"examples/1-quickstart/#rl4co-quickstart-notebook","title":"RL4CO Quickstart Notebook\u00b6","text":"

Documentation | Getting Started | Usage | Contributing | Paper | Citation

"},{"location":"examples/1-quickstart/#installation","title":"Installation\u00b6","text":""},{"location":"examples/1-quickstart/#imports","title":"Imports\u00b6","text":""},{"location":"examples/1-quickstart/#environment-policy-and-model","title":"Environment, Policy and Model\u00b6","text":"

Full documentation of:https://rl4.co/docs/content/api/envs/base/

  • Base environment class here
  • Base policy class here
  • Base model class here
"},{"location":"examples/1-quickstart/#test-greedy-rollout-with-untrained-model-and-plot","title":"Test greedy rollout with untrained model and plot\u00b6","text":""},{"location":"examples/1-quickstart/#trainer","title":"Trainer\u00b6","text":"

The RL4CO trainer is a wrapper around PyTorch Lightning's Trainer class which adds some functionality and more efficient defaults

"},{"location":"examples/1-quickstart/#fit-the-model","title":"Fit the model\u00b6","text":""},{"location":"examples/1-quickstart/#testing","title":"Testing\u00b6","text":""},{"location":"examples/2-full-training/","title":"Training: Checkpoints, Logging, and Callbacks","text":"

In this notebook we will cover a quickstart training of the Split Delivery Vehicle Routing Problem (SDVRP), with some additional comments along the way. The SDVRP is a variant of the VRP where a vehicle can deliver a part of the demand of a customer and return later to deliver the rest of the demand.

In\u00a0[1]: Copied!
# !pip install rl4co\n\n## NOTE: to install latest version from Github (may be unstable) install from source instead:\n# !pip install git+https://github.com/ai4co/rl4co.git\n
# !pip install rl4co ## NOTE: to install latest version from Github (may be unstable) install from source instead: # !pip install git+https://github.com/ai4co/rl4co.git In\u00a0[2]: Copied!
import torch\nfrom lightning.pytorch.callbacks import ModelCheckpoint, RichModelSummary\n\nfrom rl4co.envs import SDVRPEnv\nfrom rl4co.models.zoo import AttentionModel\nfrom rl4co.utils.trainer import RL4COTrainer\n
import torch from lightning.pytorch.callbacks import ModelCheckpoint, RichModelSummary from rl4co.envs import SDVRPEnv from rl4co.models.zoo import AttentionModel from rl4co.utils.trainer import RL4COTrainer In\u00a0[3]: Copied!
# RL4CO env based on TorchRL\nenv = SDVRPEnv(generator_params=dict(num_loc=20))\n\n# Model: default is AM with REINFORCE and greedy rollout baseline\nmodel = AttentionModel(env,\n                       baseline='rollout',\n                       train_data_size=100_000, # really small size for demo\n                       val_data_size=10_000)\n
# RL4CO env based on TorchRL env = SDVRPEnv(generator_params=dict(num_loc=20)) # Model: default is AM with REINFORCE and greedy rollout baseline model = AttentionModel(env, baseline='rollout', train_data_size=100_000, # really small size for demo val_data_size=10_000)
/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n
In\u00a0[4]: Copied!
# Greedy rollouts over untrained policy\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\ntd_init = env.reset(batch_size=[3]).to(device)\npolicy = model.policy.to(device)\nout = policy(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True)\n\n# Plotting\nprint(f\"Tour lengths: {[f'{-r.item():.2f}' for r in out['reward']]}\")\nfor td, actions in zip(td_init, out['actions'].cpu()):\n    env.render(td, actions)\n
# Greedy rollouts over untrained policy device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\") td_init = env.reset(batch_size=[3]).to(device) policy = model.policy.to(device) out = policy(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True) # Plotting print(f\"Tour lengths: {[f'{-r.item():.2f}' for r in out['reward']]}\") for td, actions in zip(td_init, out['actions'].cpu()): env.render(td, actions)
Tour lengths: ['29.45', '14.26', '21.15']\n
In\u00a0[5]: Copied!
# Checkpointing callback: save models when validation reward improves\ncheckpoint_callback = ModelCheckpoint(  dirpath=\"checkpoints\", # save to checkpoints/\n                                        filename=\"epoch_{epoch:03d}\",  # save as epoch_XXX.ckpt\n                                        save_top_k=1, # save only the best model\n                                        save_last=True, # save the last model\n                                        monitor=\"val/reward\", # monitor validation reward\n                                        mode=\"max\") # maximize validation reward\n\n# Print model summary\nrich_model_summary = RichModelSummary(max_depth=3)\n\n# Callbacks list\ncallbacks = [checkpoint_callback, rich_model_summary]\n
# Checkpointing callback: save models when validation reward improves checkpoint_callback = ModelCheckpoint( dirpath=\"checkpoints\", # save to checkpoints/ filename=\"epoch_{epoch:03d}\", # save as epoch_XXX.ckpt save_top_k=1, # save only the best model save_last=True, # save the last model monitor=\"val/reward\", # monitor validation reward mode=\"max\") # maximize validation reward # Print model summary rich_model_summary = RichModelSummary(max_depth=3) # Callbacks list callbacks = [checkpoint_callback, rich_model_summary]

We make sure we're logged into W&B so that our experiments can be associated with our account. You may comment the below line if you don't want to use it.

In\u00a0[6]: Copied!
# import wandb\n# wandb.login()\n
# import wandb # wandb.login() In\u00a0[7]: Copied!
## Comment following two lines if you don't want logging\nfrom lightning.pytorch.loggers import WandbLogger\n\nlogger = WandbLogger(project=\"rl4co\", name=\"sdvrp-am\")\n\n\n## Keep below if you don't want logging\n# logger = None\n
## Comment following two lines if you don't want logging from lightning.pytorch.loggers import WandbLogger logger = WandbLogger(project=\"rl4co\", name=\"sdvrp-am\") ## Keep below if you don't want logging # logger = None

The Trainer handles the logging, checkpointing and more for you.

In\u00a0[8]: Copied!
from rl4co.utils.trainer import RL4COTrainer\n\ntrainer = RL4COTrainer(\n    max_epochs=2,\n    accelerator=\"gpu\",\n    devices=1,\n    logger=logger,\n    callbacks=callbacks,\n)\n
from rl4co.utils.trainer import RL4COTrainer trainer = RL4COTrainer( max_epochs=2, accelerator=\"gpu\", devices=1, logger=logger, callbacks=callbacks, )
Using 16bit Automatic Mixed Precision (AMP)\nTrainer already configured with model summary callbacks: [<class 'lightning.pytorch.callbacks.rich_model_summary.RichModelSummary'>]. Skipping setting a default `ModelSummary` callback.\nGPU available: True (cuda), used: True\nTrainer already configured with model summary callbacks: [<class 'lightning.pytorch.callbacks.rich_model_summary.RichModelSummary'>]. Skipping setting a default `ModelSummary` callback.\nGPU available: True (cuda), used: True\nTPU available: False, using: 0 TPU cores\nIPU available: False, using: 0 IPUs\nHPU available: False, using: 0 HPUs\n
In\u00a0[9]: Copied!
trainer.fit(model)\n
trainer.fit(model)
Failed to detect the name of this notebook, you can set it manually with the WANDB_NOTEBOOK_NAME environment variable to enable code saving.\n
wandb: Currently logged in as: silab-kaist. Use `wandb login --relogin` to force relogin\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/wandb/sdk/lib/ipython.py:77: DeprecationWarning: Importing display from IPython.core.display is deprecated since IPython 7.14, please import from IPython display\n  from IPython.core.display import HTML, display  # type: ignore\n
wandb version 0.16.6 is available! To upgrade, please run: $ pip install wandb --upgrade Tracking run with wandb version 0.16.5 Run data is saved locally in ./wandb/run-20240428_182146-xcgdzio4 Syncing run sdvrp-am to Weights & Biases (docs) View project at https://wandb.ai/silab-kaist/rl4co View run at https://wandb.ai/silab-kaist/rl4co/runs/xcgdzio4/workspace
val_file not set. Generating dataset instead\ntest_file not set. Generating dataset instead\nLOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n
\u250f\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503    \u2503 Name                                   \u2503 Type                  \u2503 Params \u2503\n\u2521\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502 0  \u2502 env                                    \u2502 SDVRPEnv              \u2502      0 \u2502\n\u2502 1  \u2502 policy                                 \u2502 AttentionModelPolicy  \u2502  694 K \u2502\n\u2502 2  \u2502 policy.encoder                         \u2502 AttentionModelEncoder \u2502  595 K \u2502\n\u2502 3  \u2502 policy.encoder.init_embedding          \u2502 VRPInitEmbedding      \u2502    896 \u2502\n\u2502 4  \u2502 policy.encoder.net                     \u2502 GraphAttentionNetwork \u2502  594 K \u2502\n\u2502 5  \u2502 policy.decoder                         \u2502 AttentionModelDecoder \u2502 98.8 K \u2502\n\u2502 6  \u2502 policy.decoder.context_embedding       \u2502 VRPContext            \u2502 16.5 K \u2502\n\u2502 7  \u2502 policy.decoder.dynamic_embedding       \u2502 SDVRPDynamicEmbedding \u2502    384 \u2502\n\u2502 8  \u2502 policy.decoder.pointer                 \u2502 PointerAttention      \u2502 16.4 K \u2502\n\u2502 9  \u2502 policy.decoder.project_node_embeddings \u2502 Linear                \u2502 49.2 K \u2502\n\u2502 10 \u2502 policy.decoder.project_fixed_context   \u2502 Linear                \u2502 16.4 K \u2502\n\u2502 11 \u2502 baseline                               \u2502 WarmupBaseline        \u2502  694 K \u2502\n\u2502 12 \u2502 baseline.baseline                      \u2502 RolloutBaseline       \u2502  694 K \u2502\n\u2502 13 \u2502 baseline.baseline.policy               \u2502 AttentionModelPolicy  \u2502  694 K \u2502\n\u2502 14 \u2502 baseline.warmup_baseline               \u2502 ExponentialBaseline   \u2502      0 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
Trainable params: 1.4 M                                                                                            \nNon-trainable params: 0                                                                                            \nTotal params: 1.4 M                                                                                                \nTotal estimated model params size (MB): 5                                                                          \n
Sanity Checking: |          | 0/? [00:00<?, ?it/s]
/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'val_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=31` in the `DataLoader` to improve performance.\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'train_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=31` in the `DataLoader` to improve performance.\n
Training: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
`Trainer.fit` stopped: `max_epochs=2` reached.\n
In\u00a0[10]: Copied!
# Greedy rollouts over trained model (same states as previous plot)\npolicy = model.policy.to(device)\nout = policy(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True)\n\n# Plotting\nprint(f\"Tour lengths: {[f'{-r.item():.2f}' for r in out['reward']]}\")\nfor td, actions in zip(td_init, out['actions'].cpu()):\n    env.render(td, actions)\n
# Greedy rollouts over trained model (same states as previous plot) policy = model.policy.to(device) out = policy(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True) # Plotting print(f\"Tour lengths: {[f'{-r.item():.2f}' for r in out['reward']]}\") for td, actions in zip(td_init, out['actions'].cpu()): env.render(td, actions)
Tour lengths: ['9.12', '7.16', '9.55']\n
In\u00a0[11]: Copied!
trainer.test(model)\n
trainer.test(model)
val_file not set. Generating dataset instead\ntest_file not set. Generating dataset instead\nLOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'test_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=31` in the `DataLoader` to improve performance.\n
Testing: |          | 0/? [00:00<?, ?it/s]
\u250f\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2533\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2513\n\u2503        Test metric        \u2503       DataLoader 0        \u2503\n\u2521\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2547\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2529\n\u2502        test/reward        \u2502    -7.363526344299316     \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n
Out[11]:
[{'test/reward': -7.363526344299316}]
In\u00a0[12]: Copied!
# Test generalization to 50 nodes (not going to be great due to few epochs, but hey)\nenv = SDVRPEnv(generator_params=dict(num_loc=50))\n\n# Generate data (100) and set as test dataset\nnew_dataset = env.dataset(50)\ndataloader = model._dataloader(new_dataset, batch_size=100)\n
# Test generalization to 50 nodes (not going to be great due to few epochs, but hey) env = SDVRPEnv(generator_params=dict(num_loc=50)) # Generate data (100) and set as test dataset new_dataset = env.dataset(50) dataloader = model._dataloader(new_dataset, batch_size=100) In\u00a0[15]: Copied!
# Greedy rollouts over trained policy (same states as previous plot, with 20 nodes)\ninit_states = next(iter(dataloader))[:3]\ntd_init_generalization = env.reset(init_states).to(device)\n\npolicy = model.policy.to(device)\nout = policy(td_init_generalization.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True)\n\n# Plotting\nprint(f\"Tour lengths: {[f'{-r.item():.2f}' for r in out['reward']]}\")\nfor td, actions in zip(td_init_generalization, out['actions'].cpu()):\n    env.render(td, actions)\n
# Greedy rollouts over trained policy (same states as previous plot, with 20 nodes) init_states = next(iter(dataloader))[:3] td_init_generalization = env.reset(init_states).to(device) policy = model.policy.to(device) out = policy(td_init_generalization.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True) # Plotting print(f\"Tour lengths: {[f'{-r.item():.2f}' for r in out['reward']]}\") for td, actions in zip(td_init_generalization, out['actions'].cpu()): env.render(td, actions)
Tour lengths: ['11.84', '12.49', '12.20']\n
In\u00a0[16]: Copied!
# Environment, Model, and Lightning Module (reinstantiate from scratch)\nmodel = AttentionModel(env,\n                       baseline=\"rollout\",\n                       train_data_size=100_000,\n                       test_data_size=10_000,\n                       optimizer_kwargs={'lr': 1e-4}\n                       )\n\n# Note that by default, Lightning will call checkpoints from newer runs with \"-v{version}\" suffix\n# unless you specify the checkpoint path explicitly\nnew_model_checkpoint = AttentionModel.load_from_checkpoint(\"checkpoints/last.ckpt\", strict=False)\n
# Environment, Model, and Lightning Module (reinstantiate from scratch) model = AttentionModel(env, baseline=\"rollout\", train_data_size=100_000, test_data_size=10_000, optimizer_kwargs={'lr': 1e-4} ) # Note that by default, Lightning will call checkpoints from newer runs with \"-v{version}\" suffix # unless you specify the checkpoint path explicitly new_model_checkpoint = AttentionModel.load_from_checkpoint(\"checkpoints/last.ckpt\", strict=False)
/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/core/saving.py:188: Found keys that are not in the model state dict but in the checkpoint: ['baseline.baseline.policy.encoder.init_embedding.init_embed.weight', 'baseline.baseline.policy.encoder.init_embedding.init_embed.bias', 'baseline.baseline.policy.encoder.init_embedding.init_embed_depot.weight', 'baseline.baseline.policy.encoder.init_embedding.init_embed_depot.bias', 'baseline.baseline.policy.encoder.net.layers.0.0.module.Wqkv.weight', 'baseline.baseline.policy.encoder.net.layers.0.0.module.Wqkv.bias', 'baseline.baseline.policy.encoder.net.layers.0.0.module.out_proj.weight', 'baseline.baseline.policy.encoder.net.layers.0.0.module.out_proj.bias', 'baseline.baseline.policy.encoder.net.layers.0.1.normalizer.weight', 'baseline.baseline.policy.encoder.net.layers.0.1.normalizer.bias', 'baseline.baseline.policy.encoder.net.layers.0.1.normalizer.running_mean', 'baseline.baseline.policy.encoder.net.layers.0.1.normalizer.running_var', 'baseline.baseline.policy.encoder.net.layers.0.1.normalizer.num_batches_tracked', 'baseline.baseline.policy.encoder.net.layers.0.2.module.0.weight', 'baseline.baseline.policy.encoder.net.layers.0.2.module.0.bias', 'baseline.baseline.policy.encoder.net.layers.0.2.module.2.weight', 'baseline.baseline.policy.encoder.net.layers.0.2.module.2.bias', 'baseline.baseline.policy.encoder.net.layers.0.3.normalizer.weight', 'baseline.baseline.policy.encoder.net.layers.0.3.normalizer.bias', 'baseline.baseline.policy.encoder.net.layers.0.3.normalizer.running_mean', 'baseline.baseline.policy.encoder.net.layers.0.3.normalizer.running_var', 'baseline.baseline.policy.encoder.net.layers.0.3.normalizer.num_batches_tracked', 'baseline.baseline.policy.encoder.net.layers.1.0.module.Wqkv.weight', 'baseline.baseline.policy.encoder.net.layers.1.0.module.Wqkv.bias', 'baseline.baseline.policy.encoder.net.layers.1.0.module.out_proj.weight', 'baseline.baseline.policy.encoder.net.layers.1.0.module.out_proj.bias', 'baseline.baseline.policy.encoder.net.layers.1.1.normalizer.weight', 'baseline.baseline.policy.encoder.net.layers.1.1.normalizer.bias', 'baseline.baseline.policy.encoder.net.layers.1.1.normalizer.running_mean', 'baseline.baseline.policy.encoder.net.layers.1.1.normalizer.running_var', 'baseline.baseline.policy.encoder.net.layers.1.1.normalizer.num_batches_tracked', 'baseline.baseline.policy.encoder.net.layers.1.2.module.0.weight', 'baseline.baseline.policy.encoder.net.layers.1.2.module.0.bias', 'baseline.baseline.policy.encoder.net.layers.1.2.module.2.weight', 'baseline.baseline.policy.encoder.net.layers.1.2.module.2.bias', 'baseline.baseline.policy.encoder.net.layers.1.3.normalizer.weight', 'baseline.baseline.policy.encoder.net.layers.1.3.normalizer.bias', 'baseline.baseline.policy.encoder.net.layers.1.3.normalizer.running_mean', 'baseline.baseline.policy.encoder.net.layers.1.3.normalizer.running_var', 'baseline.baseline.policy.encoder.net.layers.1.3.normalizer.num_batches_tracked', 'baseline.baseline.policy.encoder.net.layers.2.0.module.Wqkv.weight', 'baseline.baseline.policy.encoder.net.layers.2.0.module.Wqkv.bias', 'baseline.baseline.policy.encoder.net.layers.2.0.module.out_proj.weight', 'baseline.baseline.policy.encoder.net.layers.2.0.module.out_proj.bias', 'baseline.baseline.policy.encoder.net.layers.2.1.normalizer.weight', 'baseline.baseline.policy.encoder.net.layers.2.1.normalizer.bias', 'baseline.baseline.policy.encoder.net.layers.2.1.normalizer.running_mean', 'baseline.baseline.policy.encoder.net.layers.2.1.normalizer.running_var', 'baseline.baseline.policy.encoder.net.layers.2.1.normalizer.num_batches_tracked', 'baseline.baseline.policy.encoder.net.layers.2.2.module.0.weight', 'baseline.baseline.policy.encoder.net.layers.2.2.module.0.bias', 'baseline.baseline.policy.encoder.net.layers.2.2.module.2.weight', 'baseline.baseline.policy.encoder.net.layers.2.2.module.2.bias', 'baseline.baseline.policy.encoder.net.layers.2.3.normalizer.weight', 'baseline.baseline.policy.encoder.net.layers.2.3.normalizer.bias', 'baseline.baseline.policy.encoder.net.layers.2.3.normalizer.running_mean', 'baseline.baseline.policy.encoder.net.layers.2.3.normalizer.running_var', 'baseline.baseline.policy.encoder.net.layers.2.3.normalizer.num_batches_tracked', 'baseline.baseline.policy.decoder.context_embedding.project_context.weight', 'baseline.baseline.policy.decoder.dynamic_embedding.projection.weight', 'baseline.baseline.policy.decoder.pointer.project_out.weight', 'baseline.baseline.policy.decoder.project_node_embeddings.weight', 'baseline.baseline.policy.decoder.project_fixed_context.weight']\nval_file not set. Generating dataset instead\ntest_file not set. Generating dataset instead\n

Now we can load both the model and environment from the checkpoint!

In\u00a0[17]: Copied!
# Greedy rollouts over trained model (same states as previous plot, with 20 nodes)\npolicy_new = new_model_checkpoint.policy.to(device)\nenv = new_model_checkpoint.env.to(device)\n\nout = policy_new(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True)\n\n# Plotting\nprint(f\"Tour lengths: {[f'{-r.item():.2f}' for r in out['reward']]}\")\nfor td, actions in zip(td_init, out['actions'].cpu()):\n    env.render(td, actions)\n
# Greedy rollouts over trained model (same states as previous plot, with 20 nodes) policy_new = new_model_checkpoint.policy.to(device) env = new_model_checkpoint.env.to(device) out = policy_new(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True) # Plotting print(f\"Tour lengths: {[f'{-r.item():.2f}' for r in out['reward']]}\") for td, actions in zip(td_init, out['actions'].cpu()): env.render(td, actions)
Tour lengths: ['9.12', '7.16', '9.55']\n
"},{"location":"examples/2-full-training/#training-checkpoints-logging-and-callbacks","title":"Training: Checkpoints, Logging, and Callbacks\u00b6","text":""},{"location":"examples/2-full-training/#installation","title":"Installation\u00b6","text":"

Uncomment the following line to install the package from PyPI. Remember to choose a GPU runtime for faster training!

Note: You may need to restart the runtime in Colab after this

"},{"location":"examples/2-full-training/#imports","title":"Imports\u00b6","text":""},{"location":"examples/2-full-training/#main-setup","title":"Main Setup\u00b6","text":""},{"location":"examples/2-full-training/#environment-model-and-litmodule","title":"Environment, Model and LitModule\u00b6","text":""},{"location":"examples/2-full-training/#test-greedy-rollout-with-untrained-model-and-plot","title":"Test greedy rollout with untrained model and plot\u00b6","text":""},{"location":"examples/2-full-training/#training","title":"Training\u00b6","text":""},{"location":"examples/2-full-training/#callbacks","title":"Callbacks\u00b6","text":"

Here we set up a checkpoint callback to save the best model and another callback for demonstration (nice progress bar). You may check other callbacks here

"},{"location":"examples/2-full-training/#logging","title":"Logging\u00b6","text":"

Here we will use Wandb. You may comment below lines if you don't want to use it. You may check other loggers here

"},{"location":"examples/2-full-training/#trainer","title":"Trainer\u00b6","text":"

The RL4CO trainer is a wrapper around PyTorch Lightning's Trainer class which adds some functionality and more efficient defaults

"},{"location":"examples/2-full-training/#fit-the-model","title":"Fit the model\u00b6","text":""},{"location":"examples/2-full-training/#testing","title":"Testing\u00b6","text":""},{"location":"examples/2-full-training/#plotting","title":"Plotting\u00b6","text":"

Here we plot the solution (greedy rollout) of the trained policy to the initial problem

"},{"location":"examples/2-full-training/#test-function","title":"Test function\u00b6","text":"

By default, the dataset is generated or loaded by the environment. You may load a dataset by setting test_file during the env config:

env = SDVRPEnv(\n    ...\n    test_file=\"path/to/test/file\"\n)\n

In this case, we test directly on the generated test dataset

"},{"location":"examples/2-full-training/#test-generalization-to-new-dataset","title":"Test generalization to new dataset\u00b6","text":"

Here we can load a new dataset (with 50 nodes) and test the trained model on it

"},{"location":"examples/2-full-training/#plotting-generalization","title":"Plotting generalization\u00b6","text":""},{"location":"examples/2-full-training/#loading-model","title":"Loading model\u00b6","text":"

Thanks to PyTorch Lightning, we can easily save and load a model to and from a checkpoint! This is declared in the Trainer using the model checkpoint callback. For example, we can load the last model via the last.ckpt file located in the folder we specified in the Trainer.

"},{"location":"examples/2-full-training/#checkpointing","title":"Checkpointing\u00b6","text":""},{"location":"examples/2-full-training/#additional-resources","title":"Additional resources\u00b6","text":"

Documentation | Getting Started | Usage | Contributing | Paper | Citation

Have feedback about this notebook? Feel free to contribute by either opening an issue or a pull request! ;)

"},{"location":"examples/3-creating-new-env-model/","title":"New Environment: Creating and Modeling","text":"

In this notebook, we will show how to extend RL4CO to solve new problems from zero to hero! \ud83d\ude80

In\u00a0[1]: Copied!
## Uncomment the following line to install the package from PyPI\n## You may need to restart the runtime in Colab after this\n## Remember to choose a GPU runtime for faster training!\n\n# !pip install rl4co\n
## Uncomment the following line to install the package from PyPI ## You may need to restart the runtime in Colab after this ## Remember to choose a GPU runtime for faster training! # !pip install rl4co In\u00a0[16]: Copied!
from typing import Optional\nimport torch\nimport torch.nn as nn\n\nfrom tensordict.tensordict import TensorDict\nfrom torchrl.data import (\n    BoundedTensorSpec,\n    CompositeSpec,\n    UnboundedContinuousTensorSpec,\n    UnboundedDiscreteTensorSpec,\n)\n\nfrom rl4co.utils.decoding import rollout, random_policy\nfrom rl4co.envs.common import RL4COEnvBase, Generator, get_sampler\nfrom rl4co.models.zoo import AttentionModel, AttentionModelPolicy\nfrom rl4co.utils.ops import gather_by_index, get_tour_length\nfrom rl4co.utils.trainer import RL4COTrainer\n
from typing import Optional import torch import torch.nn as nn from tensordict.tensordict import TensorDict from torchrl.data import ( BoundedTensorSpec, CompositeSpec, UnboundedContinuousTensorSpec, UnboundedDiscreteTensorSpec, ) from rl4co.utils.decoding import rollout, random_policy from rl4co.envs.common import RL4COEnvBase, Generator, get_sampler from rl4co.models.zoo import AttentionModel, AttentionModelPolicy from rl4co.utils.ops import gather_by_index, get_tour_length from rl4co.utils.trainer import RL4COTrainer

We will base environment creation on the RL4COEnvBase class, which is based on TorchRL. More information in documentation!

In\u00a0[2]: Copied!
def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict:\n    # Initialize locations\n    init_locs = td[\"locs\"] if td is not None else None\n    if batch_size is None:\n        batch_size = self.batch_size if init_locs is None else init_locs.shape[:-2]\n    device = init_locs.device if init_locs is not None else self.device\n    self.to(device)\n    if init_locs is None:\n        init_locs = self.generate_data(batch_size=batch_size).to(device)[\"locs\"]\n    batch_size = [batch_size] if isinstance(batch_size, int) else batch_size\n\n    # We do not enforce loading from self for flexibility\n    num_loc = init_locs.shape[-2]\n\n    # Other variables\n    current_node = torch.zeros((batch_size), dtype=torch.int64, device=device)\n    available = torch.ones(\n        (*batch_size, num_loc), dtype=torch.bool, device=device\n    )  # 1 means not visited, i.e. action is allowed\n    i = torch.zeros((*batch_size, 1), dtype=torch.int64, device=device)\n\n    return TensorDict(\n        {\n            \"locs\": init_locs,\n            \"first_node\": current_node,\n            \"current_node\": current_node,\n            \"i\": i,\n            \"action_mask\": available,\n            \"reward\": torch.zeros((*batch_size, 1), dtype=torch.float32),\n        },\n        batch_size=batch_size,\n    )\n
def _reset(self, td: Optional[TensorDict] = None, batch_size=None) -> TensorDict: # Initialize locations init_locs = td[\"locs\"] if td is not None else None if batch_size is None: batch_size = self.batch_size if init_locs is None else init_locs.shape[:-2] device = init_locs.device if init_locs is not None else self.device self.to(device) if init_locs is None: init_locs = self.generate_data(batch_size=batch_size).to(device)[\"locs\"] batch_size = [batch_size] if isinstance(batch_size, int) else batch_size # We do not enforce loading from self for flexibility num_loc = init_locs.shape[-2] # Other variables current_node = torch.zeros((batch_size), dtype=torch.int64, device=device) available = torch.ones( (*batch_size, num_loc), dtype=torch.bool, device=device ) # 1 means not visited, i.e. action is allowed i = torch.zeros((*batch_size, 1), dtype=torch.int64, device=device) return TensorDict( { \"locs\": init_locs, \"first_node\": current_node, \"current_node\": current_node, \"i\": i, \"action_mask\": available, \"reward\": torch.zeros((*batch_size, 1), dtype=torch.float32), }, batch_size=batch_size, ) In\u00a0[3]: Copied!
def _step(self, td: TensorDict) -> TensorDict:\n    current_node = td[\"action\"]\n    first_node = current_node if td[\"i\"].all() == 0 else td[\"first_node\"]\n\n    # Set not visited to 0 (i.e., we visited the node)\n    # Note: we may also use a separate function for obtaining the mask for more flexibility\n    available = td[\"action_mask\"].scatter(\n        -1, current_node.unsqueeze(-1).expand_as(td[\"action_mask\"]), 0\n    )\n\n    # We are done there are no unvisited locations\n    done = torch.sum(available, dim=-1) == 0\n\n    # The reward is calculated outside via get_reward for efficiency, so we set it to 0 here\n    reward = torch.zeros_like(done)\n\n    td.update(\n        {\n            \"first_node\": first_node,\n            \"current_node\": current_node,\n            \"i\": td[\"i\"] + 1,\n            \"action_mask\": available,\n            \"reward\": reward,\n            \"done\": done,\n        },\n    )\n    return td\n
def _step(self, td: TensorDict) -> TensorDict: current_node = td[\"action\"] first_node = current_node if td[\"i\"].all() == 0 else td[\"first_node\"] # Set not visited to 0 (i.e., we visited the node) # Note: we may also use a separate function for obtaining the mask for more flexibility available = td[\"action_mask\"].scatter( -1, current_node.unsqueeze(-1).expand_as(td[\"action_mask\"]), 0 ) # We are done there are no unvisited locations done = torch.sum(available, dim=-1) == 0 # The reward is calculated outside via get_reward for efficiency, so we set it to 0 here reward = torch.zeros_like(done) td.update( { \"first_node\": first_node, \"current_node\": current_node, \"i\": td[\"i\"] + 1, \"action_mask\": available, \"reward\": reward, \"done\": done, }, ) return td In\u00a0[4]: Copied!
def get_action_mask(self, td: TensorDict) -> TensorDict:\n    # Here: your logic \n    return td[\"action_mask\"]\n
def get_action_mask(self, td: TensorDict) -> TensorDict: # Here: your logic return td[\"action_mask\"] In\u00a0[5]: Copied!
def check_solution_validity(self, td: TensorDict, actions: torch.Tensor):\n    \"\"\"Check that solution is valid: nodes are visited exactly once\"\"\"\n    assert (\n        torch.arange(actions.size(1), out=actions.data.new())\n        .view(1, -1)\n        .expand_as(actions)\n        == actions.data.sort(1)[0]\n    ).all(), \"Invalid tour\"\n
def check_solution_validity(self, td: TensorDict, actions: torch.Tensor): \"\"\"Check that solution is valid: nodes are visited exactly once\"\"\" assert ( torch.arange(actions.size(1), out=actions.data.new()) .view(1, -1) .expand_as(actions) == actions.data.sort(1)[0] ).all(), \"Invalid tour\" In\u00a0[26]: Copied!
def _get_reward(self, td, actions) -> TensorDict:\n    # Sanity check if enabled\n    if self.check_solution:\n        self.check_solution_validity(td, actions)\n\n    # Gather locations in order of tour and return distance between them (i.e., -reward)\n    locs_ordered = gather_by_index(td[\"locs\"], actions)\n    return -get_tour_length(locs_ordered)\n
def _get_reward(self, td, actions) -> TensorDict: # Sanity check if enabled if self.check_solution: self.check_solution_validity(td, actions) # Gather locations in order of tour and return distance between them (i.e., -reward) locs_ordered = gather_by_index(td[\"locs\"], actions) return -get_tour_length(locs_ordered) In\u00a0[21]: Copied!
def _make_spec(self, generator):\n    \"\"\"Make the observation and action specs from the parameters\"\"\"\n    self.observation_spec = CompositeSpec(\n        locs=BoundedTensorSpec(\n            low=self.generator.min_loc,\n            high=self.generator.max_loc,\n            shape=(self.generator.num_loc, 2),\n            dtype=torch.float32,\n        ),\n        first_node=UnboundedDiscreteTensorSpec(\n            shape=(1),\n            dtype=torch.int64,\n        ),\n        current_node=UnboundedDiscreteTensorSpec(\n            shape=(1),\n            dtype=torch.int64,\n        ),\n        i=UnboundedDiscreteTensorSpec(\n            shape=(1),\n            dtype=torch.int64,\n        ),\n        action_mask=UnboundedDiscreteTensorSpec(\n            shape=(self.generator.num_loc),\n            dtype=torch.bool,\n        ),\n        shape=(),\n    )\n    self.action_spec = BoundedTensorSpec(\n        shape=(1,),\n        dtype=torch.int64,\n        low=0,\n        high=self.generator.num_loc,\n    )\n    self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,))\n    self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool)\n
def _make_spec(self, generator): \"\"\"Make the observation and action specs from the parameters\"\"\" self.observation_spec = CompositeSpec( locs=BoundedTensorSpec( low=self.generator.min_loc, high=self.generator.max_loc, shape=(self.generator.num_loc, 2), dtype=torch.float32, ), first_node=UnboundedDiscreteTensorSpec( shape=(1), dtype=torch.int64, ), current_node=UnboundedDiscreteTensorSpec( shape=(1), dtype=torch.int64, ), i=UnboundedDiscreteTensorSpec( shape=(1), dtype=torch.int64, ), action_mask=UnboundedDiscreteTensorSpec( shape=(self.generator.num_loc), dtype=torch.bool, ), shape=(), ) self.action_spec = BoundedTensorSpec( shape=(1,), dtype=torch.int64, low=0, high=self.generator.num_loc, ) self.reward_spec = UnboundedContinuousTensorSpec(shape=(1,)) self.done_spec = UnboundedDiscreteTensorSpec(shape=(1,), dtype=torch.bool) In\u00a0[22]: Copied!
class TSPGenerator(Generator):\n    def __init__(\n        self,\n        num_loc: int = 20,\n        min_loc: float = 0.0,\n        max_loc: float = 1.0,\n    ):\n        self.num_loc = num_loc\n        self.min_loc = min_loc\n        self.max_loc = max_loc\n        self.loc_sampler = torch.distributions.Uniform(\n            low=min_loc, high=max_loc\n        )\n\n    def _generate(self, batch_size) -> TensorDict:\n        # Sample locations\n        locs = self.loc_sampler.sample((*batch_size, self.num_loc, 2))\n        return TensorDict({\"locs\": locs}, batch_size=batch_size)\n    \n# Test generator\ngenerator = TSPGenerator(num_loc=20)\nlocs = generator(32)\nprint(locs[\"locs\"].shape)\n
class TSPGenerator(Generator): def __init__( self, num_loc: int = 20, min_loc: float = 0.0, max_loc: float = 1.0, ): self.num_loc = num_loc self.min_loc = min_loc self.max_loc = max_loc self.loc_sampler = torch.distributions.Uniform( low=min_loc, high=max_loc ) def _generate(self, batch_size) -> TensorDict: # Sample locations locs = self.loc_sampler.sample((*batch_size, self.num_loc, 2)) return TensorDict({\"locs\": locs}, batch_size=batch_size) # Test generator generator = TSPGenerator(num_loc=20) locs = generator(32) print(locs[\"locs\"].shape)
torch.Size([32, 20, 2])\n
In\u00a0[23]: Copied!
def render(self, td, actions=None, ax=None):\n    import matplotlib.pyplot as plt\n    import numpy as np\n\n    if ax is None:\n        # Create a plot of the nodes\n        _, ax = plt.subplots()\n\n    td = td.detach().cpu()\n\n    if actions is None:\n        actions = td.get(\"action\", None)\n    # if batch_size greater than 0 , we need to select the first batch element\n    if td.batch_size != torch.Size([]):\n        td = td[0]\n        actions = actions[0]\n\n    locs = td[\"locs\"]\n\n    # gather locs in order of action if available\n    if actions is None:\n        print(\"No action in TensorDict, rendering unsorted locs\")\n    else:\n        actions = actions.detach().cpu()\n        locs = gather_by_index(locs, actions, dim=0)\n\n    # Cat the first node to the end to complete the tour\n    locs = torch.cat((locs, locs[0:1]))\n    x, y = locs[:, 0], locs[:, 1]\n\n    # Plot the visited nodes\n    ax.scatter(x, y, color=\"tab:blue\")\n\n    # Add arrows between visited nodes as a quiver plot\n    dx, dy = np.diff(x), np.diff(y)\n    ax.quiver(\n        x[:-1], y[:-1], dx, dy, scale_units=\"xy\", angles=\"xy\", scale=1, color=\"k\"\n    )\n\n    # Setup limits and show\n    ax.set_xlim(-0.05, 1.05)\n    ax.set_ylim(-0.05, 1.05)\n
def render(self, td, actions=None, ax=None): import matplotlib.pyplot as plt import numpy as np if ax is None: # Create a plot of the nodes _, ax = plt.subplots() td = td.detach().cpu() if actions is None: actions = td.get(\"action\", None) # if batch_size greater than 0 , we need to select the first batch element if td.batch_size != torch.Size([]): td = td[0] actions = actions[0] locs = td[\"locs\"] # gather locs in order of action if available if actions is None: print(\"No action in TensorDict, rendering unsorted locs\") else: actions = actions.detach().cpu() locs = gather_by_index(locs, actions, dim=0) # Cat the first node to the end to complete the tour locs = torch.cat((locs, locs[0:1])) x, y = locs[:, 0], locs[:, 1] # Plot the visited nodes ax.scatter(x, y, color=\"tab:blue\") # Add arrows between visited nodes as a quiver plot dx, dy = np.diff(x), np.diff(y) ax.quiver( x[:-1], y[:-1], dx, dy, scale_units=\"xy\", angles=\"xy\", scale=1, color=\"k\" ) # Setup limits and show ax.set_xlim(-0.05, 1.05) ax.set_ylim(-0.05, 1.05) In\u00a0[28]: Copied!
class TSPEnv(RL4COEnvBase):\n    \"\"\"Traveling Salesman Problem (TSP) environment\"\"\"\n\n    name = \"tsp\"\n\n    def __init__(\n        self,\n        generator = TSPGenerator,\n        generator_params = {},\n        **kwargs,\n    ):\n        super().__init__(**kwargs)\n        self.generator = generator(**generator_params)\n        self._make_spec(self.generator)\n        \n    _reset = _reset\n    _step = _step\n    _get_reward = _get_reward\n    check_solution_validity = check_solution_validity\n    get_action_mask = get_action_mask\n    _make_spec = _make_spec\n    render = render\n
class TSPEnv(RL4COEnvBase): \"\"\"Traveling Salesman Problem (TSP) environment\"\"\" name = \"tsp\" def __init__( self, generator = TSPGenerator, generator_params = {}, **kwargs, ): super().__init__(**kwargs) self.generator = generator(**generator_params) self._make_spec(self.generator) _reset = _reset _step = _step _get_reward = _get_reward check_solution_validity = check_solution_validity get_action_mask = get_action_mask _make_spec = _make_spec render = render In\u00a0[29]: Copied!
batch_size = 2\n\nenv = TSPEnv(generator_params=dict(num_loc=20))\nreward, td, actions = rollout(env, env.reset(batch_size=[batch_size]), random_policy)\nenv.render(td, actions)\n
batch_size = 2 env = TSPEnv(generator_params=dict(num_loc=20)) reward, td, actions = rollout(env, env.reset(batch_size=[batch_size]), random_policy) env.render(td, actions) In\u00a0[30]: Copied!
class TSPInitEmbedding(nn.Module):\n    \"\"\"Initial embedding for the Traveling Salesman Problems (TSP).\n    Embed the following node features to the embedding space:\n        - locs: x, y coordinates of the cities\n    \"\"\"\n\n    def __init__(self, embed_dim, linear_bias=True):\n        super(TSPInitEmbedding, self).__init__()\n        node_dim = 2  # x, y\n        self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias)\n\n    def forward(self, td):\n        out = self.init_embed(td[\"locs\"])\n        return out\n
class TSPInitEmbedding(nn.Module): \"\"\"Initial embedding for the Traveling Salesman Problems (TSP). Embed the following node features to the embedding space: - locs: x, y coordinates of the cities \"\"\" def __init__(self, embed_dim, linear_bias=True): super(TSPInitEmbedding, self).__init__() node_dim = 2 # x, y self.init_embed = nn.Linear(node_dim, embed_dim, linear_bias) def forward(self, td): out = self.init_embed(td[\"locs\"]) return out In\u00a0[31]: Copied!
class TSPContext(nn.Module):\n    \"\"\"Context embedding for the Traveling Salesman Problem (TSP).\n    Project the following to the embedding space:\n        - first node embedding\n        - current node embedding\n    \"\"\"\n\n    def __init__(self, embed_dim,  linear_bias=True):\n        super(TSPContext, self).__init__()\n        self.W_placeholder = nn.Parameter(\n            torch.Tensor(2 * embed_dim).uniform_(-1, 1)\n        )\n        self.project_context = nn.Linear(\n            embed_dim*2, embed_dim, bias=linear_bias\n        )\n\n    def forward(self, embeddings, td):\n        batch_size = embeddings.size(0)\n        # By default, node_dim = -1 (we only have one node embedding per node)\n        node_dim = (\n            (-1,) if td[\"first_node\"].dim() == 1 else (td[\"first_node\"].size(-1), -1)\n        )\n        if td[\"i\"][(0,) * td[\"i\"].dim()].item() < 1:  # get first item fast\n            context_embedding = self.W_placeholder[None, :].expand(\n                batch_size, self.W_placeholder.size(-1)\n            )\n        else:\n            context_embedding = gather_by_index(\n                embeddings,\n                torch.stack([td[\"first_node\"], td[\"current_node\"]], -1).view(\n                    batch_size, -1\n                ),\n            ).view(batch_size, *node_dim)\n        return self.project_context(context_embedding)\n
class TSPContext(nn.Module): \"\"\"Context embedding for the Traveling Salesman Problem (TSP). Project the following to the embedding space: - first node embedding - current node embedding \"\"\" def __init__(self, embed_dim, linear_bias=True): super(TSPContext, self).__init__() self.W_placeholder = nn.Parameter( torch.Tensor(2 * embed_dim).uniform_(-1, 1) ) self.project_context = nn.Linear( embed_dim*2, embed_dim, bias=linear_bias ) def forward(self, embeddings, td): batch_size = embeddings.size(0) # By default, node_dim = -1 (we only have one node embedding per node) node_dim = ( (-1,) if td[\"first_node\"].dim() == 1 else (td[\"first_node\"].size(-1), -1) ) if td[\"i\"][(0,) * td[\"i\"].dim()].item() < 1: # get first item fast context_embedding = self.W_placeholder[None, :].expand( batch_size, self.W_placeholder.size(-1) ) else: context_embedding = gather_by_index( embeddings, torch.stack([td[\"first_node\"], td[\"current_node\"]], -1).view( batch_size, -1 ), ).view(batch_size, *node_dim) return self.project_context(context_embedding) In\u00a0[32]: Copied!
class StaticEmbedding(nn.Module):\n    def __init__(self, *args, **kwargs):\n        super(StaticEmbedding, self).__init__()\n\n    def forward(self, td):\n        return 0, 0, 0\n
class StaticEmbedding(nn.Module): def __init__(self, *args, **kwargs): super(StaticEmbedding, self).__init__() def forward(self, td): return 0, 0, 0 In\u00a0[33]: Copied!
# Instantiate our environment\nenv = TSPEnv(generator_params=dict(num_loc=20))\n\n# Instantiate policy with the embeddings we created above\nemb_dim = 128\npolicy = AttentionModelPolicy(env_name=env.name, # this is actually not needed since we are initializing the embeddings!\n                              embed_dim=emb_dim,\n                              init_embedding=TSPInitEmbedding(emb_dim),\n                              context_embedding=TSPContext(emb_dim),\n                              dynamic_embedding=StaticEmbedding(emb_dim)\n)\n\n\n# Model: default is AM with REINFORCE and greedy rollout baseline\nmodel = AttentionModel(env, \n                       policy=policy,\n                       baseline='rollout',\n                       train_data_size=100_000,\n                       val_data_size=10_000)\n
# Instantiate our environment env = TSPEnv(generator_params=dict(num_loc=20)) # Instantiate policy with the embeddings we created above emb_dim = 128 policy = AttentionModelPolicy(env_name=env.name, # this is actually not needed since we are initializing the embeddings! embed_dim=emb_dim, init_embedding=TSPInitEmbedding(emb_dim), context_embedding=TSPContext(emb_dim), dynamic_embedding=StaticEmbedding(emb_dim) ) # Model: default is AM with REINFORCE and greedy rollout baseline model = AttentionModel(env, policy=policy, baseline='rollout', train_data_size=100_000, val_data_size=10_000)
/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n
In\u00a0[34]: Copied!
# Greedy rollouts over untrained model\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\ntd_init = env.reset(batch_size=[3]).to(device)\npolicy = model.policy.to(device)\nout = policy(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True)\nactions_untrained = out['actions'].cpu().detach()\nrewards_untrained = out['reward'].cpu().detach()\n\nfor i in range(3):\n    print(f\"Problem {i+1} | Cost: {-rewards_untrained[i]:.3f}\")\n    env.render(td_init[i], actions_untrained[i])\n
# Greedy rollouts over untrained model device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\") td_init = env.reset(batch_size=[3]).to(device) policy = model.policy.to(device) out = policy(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True) actions_untrained = out['actions'].cpu().detach() rewards_untrained = out['reward'].cpu().detach() for i in range(3): print(f\"Problem {i+1} | Cost: {-rewards_untrained[i]:.3f}\") env.render(td_init[i], actions_untrained[i])
Problem 1 | Cost: 11.545\nProblem 2 | Cost: 8.525\nProblem 3 | Cost: 12.461\n
In\u00a0[35]: Copied!
# We use our own wrapper around Lightning's `Trainer` to make it easier to use\ntrainer = RL4COTrainer(max_epochs=3, devices=1)\ntrainer.fit(model)\n
# We use our own wrapper around Lightning's `Trainer` to make it easier to use trainer = RL4COTrainer(max_epochs=3, devices=1) trainer.fit(model)
Using 16bit Automatic Mixed Precision (AMP)\nGPU available: True (cuda), used: True\nTPU available: False, using: 0 TPU cores\nIPU available: False, using: 0 IPUs\nHPU available: False, using: 0 HPUs\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/logger_connector/logger_connector.py:75: Starting from v1.9.0, `tensorboardX` has been removed as a dependency of the `lightning.pytorch` package, due to potential conflicts with other packages in the ML ecosystem. For this reason, `logger=True` will use `CSVLogger` as the default logger, unless the `tensorboard` or `tensorboardX` packages are found. Please `pip install lightning[extra]` or one of them to enable TensorBoard support by default\nval_file not set. Generating dataset instead\ntest_file not set. Generating dataset instead\nLOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n\n  | Name     | Type                 | Params\n--------------------------------------------------\n0 | env      | TSPEnv               | 0     \n1 | policy   | AttentionModelPolicy | 710 K \n2 | baseline | WarmupBaseline       | 710 K \n--------------------------------------------------\n1.4 M     Trainable params\n0         Non-trainable params\n1.4 M     Total params\n5.682     Total estimated model params size (MB)\n
Sanity Checking: |          | 0/? [00:00<?, ?it/s]
/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'val_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=31` in the `DataLoader` to improve performance.\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'train_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=31` in the `DataLoader` to improve performance.\n
Training: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
`Trainer.fit` stopped: `max_epochs=3` reached.\n
In\u00a0[36]: Copied!
# Greedy rollouts over trained policy (same states as previous plot)\npolicy = model.policy.to(device)\nout = policy(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True)\nactions_trained = out['actions'].cpu().detach()\n\n# Plotting\nimport matplotlib.pyplot as plt\nfor i, td in enumerate(td_init):\n    fig, axs = plt.subplots(1,2, figsize=(11,5))\n    env.render(td, actions_untrained[i], ax=axs[0]) \n    env.render(td, actions_trained[i], ax=axs[1])\n    axs[0].set_title(f\"Untrained | Cost = {-rewards_untrained[i].item():.3f}\")\n    axs[1].set_title(r\"Trained $\\pi_\\theta$\" + f\"| Cost = {-out['reward'][i].item():.3f}\")\n
# Greedy rollouts over trained policy (same states as previous plot) policy = model.policy.to(device) out = policy(td_init.clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True) actions_trained = out['actions'].cpu().detach() # Plotting import matplotlib.pyplot as plt for i, td in enumerate(td_init): fig, axs = plt.subplots(1,2, figsize=(11,5)) env.render(td, actions_untrained[i], ax=axs[0]) env.render(td, actions_trained[i], ax=axs[1]) axs[0].set_title(f\"Untrained | Cost = {-rewards_untrained[i].item():.3f}\") axs[1].set_title(r\"Trained $\\pi_\\theta$\" + f\"| Cost = {-out['reward'][i].item():.3f}\")

We can see that solutions are way better than with the untrained model, even just after 3 epochs! \ud83d\ude80

"},{"location":"examples/3-creating-new-env-model/#new-environment-creating-and-modeling","title":"New Environment: Creating and Modeling\u00b6","text":""},{"location":"examples/3-creating-new-env-model/#contents","title":"Contents\u00b6","text":"
  1. Environment
  2. Modeling
  3. Training
  4. Evaluation
"},{"location":"examples/3-creating-new-env-model/#problem-tsp","title":"Problem: TSP\u00b6","text":"

We will build an environment and model for the Traveling Salesman Problem (TSP). The TSP is a well-known combinatorial optimization problem that consists of finding the shortest route that visits each city in a given list exactly once and returns to the origin city. The TSP is NP-hard, and it is one of the most studied problems in combinatorial optimization.

"},{"location":"examples/3-creating-new-env-model/#installation","title":"Installation\u00b6","text":""},{"location":"examples/3-creating-new-env-model/#imports","title":"Imports\u00b6","text":""},{"location":"examples/3-creating-new-env-model/#environment-creation","title":"Environment Creation\u00b6","text":""},{"location":"examples/3-creating-new-env-model/#reset","title":"Reset\u00b6","text":"

The _reset function is used to initialize the environment to an initial state. It returns a TensorDict of the initial state.

"},{"location":"examples/3-creating-new-env-model/#step","title":"Step\u00b6","text":"

Environment _step: this defines the state update of the TSP problem gived a TensorDict (td in the code) of the current state and the action to take:

"},{"location":"examples/3-creating-new-env-model/#optional-separate-action-mask-function","title":"[Optional] Separate Action Mask Function\u00b6","text":"

The get_action_mask function simply returns a mask of the valid actions for the current updated state. This can be used in _step and _reset for larger environments with several constraints and may be useful for modularity

"},{"location":"examples/3-creating-new-env-model/#optional-check-solution-validity","title":"[Optional] Check Solution Validity\u00b6","text":"

Another optional utility, this checks whether the solution is feasible and can help identify bugs

"},{"location":"examples/3-creating-new-env-model/#reward-function","title":"Reward function\u00b6","text":"

The _get_reward function is used to evaluate the reward given the solution (actions).

"},{"location":"examples/3-creating-new-env-model/#environment-action-specs","title":"Environment Action Specs\u00b6","text":"

This defines the input and output domains of the environment - similar to Gym's spaces. This is not strictly necessary, but it is useful to have a clear definition of the environment's action and observation spaces and if we want to sample actions using TorchRL's utils

Note: this is actually not necessary, but it is useful to have a clear definition of the environment's action and observation spaces and if we want to sample actions using TorchRL's utils

"},{"location":"examples/3-creating-new-env-model/#data-generator","title":"Data generator\u00b6","text":"

The generator allows to generate random instances of the problem. Note that this is a simplified example: this can include additional distributions via the rl4co.envs.common.utils.get_sampler method!

"},{"location":"examples/3-creating-new-env-model/#render-function","title":"Render function\u00b6","text":"

The render function is optional, but can be useful for quickly visualizing the results of your algorithm!

"},{"location":"examples/3-creating-new-env-model/#putting-everything-together","title":"Putting everything together\u00b6","text":""},{"location":"examples/3-creating-new-env-model/#modeling","title":"Modeling\u00b6","text":"

Now we need to model the problem by transforming input information into the latent space to be processed. Here we focus on AttentionModel-based embeddings with an encoder-decoder structure. In RL4CO, we divide embeddings in 3 parts:

  • init_embedding: (encoder) embed initial states of the problem
  • context_embedding: (decoder) embed context information of the problem for the current partial solution to modify the query
  • dynamic_embedding: (decoder) embed dynamic information of the problem for the current partial solution to modify the query, key, and value (i.e. if other nodes also change state)
"},{"location":"examples/3-creating-new-env-model/#init-embedding","title":"Init Embedding\u00b6","text":"

Embed initial problem into latent space. In our case, we can project the coordinates of the cities into a latent space.

"},{"location":"examples/3-creating-new-env-model/#context-embedding","title":"Context Embedding\u00b6","text":"

Context embedding takes the current context and returns a vector representation of it. In TSP, we can take the embedding of the first node visited (since we need to complete the tour) as well as the embedding of current node visited (in the first step we just have a placeholder since they are the same).

"},{"location":"examples/3-creating-new-env-model/#dynamic-embedding","title":"Dynamic Embedding\u00b6","text":"

Since the states do not change except for visited nodes, we do not need to modify the keys and values. Therefore, we set this to 0

"},{"location":"examples/3-creating-new-env-model/#training-our-model","title":"Training our Model\u00b6","text":""},{"location":"examples/3-creating-new-env-model/#rollout-untrained-model","title":"Rollout untrained model\u00b6","text":""},{"location":"examples/3-creating-new-env-model/#training-loop","title":"Training loop\u00b6","text":""},{"location":"examples/3-creating-new-env-model/#evaluation","title":"Evaluation\u00b6","text":""},{"location":"examples/advanced/","title":"Advanced","text":"

Collection of advanced examples and tutorials - which at the moment are a bit mixed together.

"},{"location":"examples/advanced/#index","title":"Index","text":"
  • 1-hydra-config.ipynb: here we show how to use Hydra to configure your training and testing scripts.
  • 2-flash-attention-2.ipynb: this notebook shows the effects of different SDPA (Scaled Dot-Product Attention) implementations on the training of a model.
"},{"location":"examples/advanced/1-hydra-config/","title":"Hydra Configuration","text":"In\u00a0[1]: Copied!
from hydra import compose, initialize\nfrom omegaconf import OmegaConf\n\nROOT_DIR = \"../../\" # relative to this file\n
from hydra import compose, initialize from omegaconf import OmegaConf ROOT_DIR = \"../../\" # relative to this file In\u00a0[2]: Copied!
# context initialization\nwith initialize(version_base=None, config_path=ROOT_DIR+\"configs\"):\n    cfg = compose(config_name=\"main\")\n
# context initialization with initialize(version_base=None, config_path=ROOT_DIR+\"configs\"): cfg = compose(config_name=\"main\")

Hydra stores the configurations in a dictionary like object called OmegaConf

In\u00a0[3]: Copied!
type(cfg)\n
type(cfg) Out[3]:
omegaconf.dictconfig.DictConfig

The different subfolders in the configs folder are represented as distinct keys in the omegaconf

In\u00a0[4]: Copied!
list(cfg.keys())\n
list(cfg.keys()) Out[4]:
['mode',\n 'tags',\n 'train',\n 'test',\n 'compile',\n 'ckpt_path',\n 'seed',\n 'matmul_precision',\n 'model',\n 'callbacks',\n 'logger',\n 'trainer',\n 'paths',\n 'extras',\n 'env']

Keys can be accessed using the dot notation (e.g. cfg.model) or via normal dictionaries:

In\u00a0[5]: Copied!
print(cfg.model == cfg[\"model\"])\n
print(cfg.model == cfg[\"model\"])
True\n

The dot notation is however more convenient especially in nested structures

In\u00a0[6]: Copied!
print(cfg.model._target_ == cfg[\"model\"][\"_target_\"])\n
print(cfg.model._target_ == cfg[\"model\"][\"_target_\"])
True\n

For example, lets look at the model configuration (which corresponds the model/default.yaml configuration).

In\u00a0[7]: Copied!
print(OmegaConf.to_yaml(cfg.model))\n
print(OmegaConf.to_yaml(cfg.model))
generate_default_data: true\nmetrics:\n  train:\n  - loss\n  - reward\n  val:\n  - reward\n  test:\n  - reward\n  log_on_step: true\n_target_: rl4co.models.AttentionModel\nbaseline: rollout\nbatch_size: 512\nval_batch_size: 1024\ntest_batch_size: 1024\ntrain_data_size: 1280000\nval_data_size: 10000\ntest_data_size: 10000\noptimizer_kwargs:\n  lr: 0.0001\n\n

If we want to change parts of the configuration, it is generally a good practice to make the changes via the command line when executing the respective python script (in the case of RL4CO for example rl4co/tasks/train.py). For example, if we want to use a different model configuration, we can do something like:

python train.py model=pomo model.batch_size=32\n

Here we use the model/pomo.yaml configuration for the model and also change the batch size during training to 32.

Note: check out the see override syntax documentation on the Hydra website for more!

In\u00a0[8]: Copied!
with initialize(version_base=None, config_path=ROOT_DIR+\"configs\"):\n    cfg = compose(config_name=\"main\", overrides=[\"model=pomo\",\"model.batch_size=32\"])\n    print(OmegaConf.to_yaml(cfg.model))\n
with initialize(version_base=None, config_path=ROOT_DIR+\"configs\"): cfg = compose(config_name=\"main\", overrides=[\"model=pomo\",\"model.batch_size=32\"]) print(OmegaConf.to_yaml(cfg.model))
generate_default_data: true\nmetrics:\n  train:\n  - loss\n  - reward\n  val:\n  - reward\n  - max_reward\n  - max_aug_reward\n  test: ${metrics.val}\n  log_on_step: true\n_target_: rl4co.models.POMO\nnum_augment: 8\nbatch_size: 32\nval_batch_size: 1024\ntest_batch_size: 1024\ntrain_data_size: 1280000\nval_data_size: 10000\ntest_data_size: 10000\noptimizer_kwargs:\n  lr: 0.0001\n\n

It is also possible to add new parameters to a config using the + prefix. Using ++ will add a new parameter if it does not exist and overwrite it if it does.

In\u00a0[9]: Copied!
with initialize(version_base=None, config_path=ROOT_DIR+\"configs\"):\n    cfg = compose(config_name=\"main\", overrides=[\"model=pomo\",\"model.batch_size=32\",\"+model.num_starts=10\"])\n    print(OmegaConf.to_yaml(cfg.model))\n
with initialize(version_base=None, config_path=ROOT_DIR+\"configs\"): cfg = compose(config_name=\"main\", overrides=[\"model=pomo\",\"model.batch_size=32\",\"+model.num_starts=10\"]) print(OmegaConf.to_yaml(cfg.model))
generate_default_data: true\nmetrics:\n  train:\n  - loss\n  - reward\n  val:\n  - reward\n  - max_reward\n  - max_aug_reward\n  test: ${metrics.val}\n  log_on_step: true\n_target_: rl4co.models.POMO\nnum_augment: 8\nbatch_size: 32\nval_batch_size: 1024\ntest_batch_size: 1024\ntrain_data_size: 1280000\nval_data_size: 10000\ntest_data_size: 10000\noptimizer_kwargs:\n  lr: 0.0001\nnum_starts: 10\n\n

Likewise, we can also remove unwanted parts of the configuration. For example, if we do not want to use any experiment configuration, we can remove the changes to the configuration made by experiments/base.yaml using the ~ prefix:

In\u00a0[10]: Copied!
with initialize(version_base=None, config_path=ROOT_DIR+\"configs\"):\n    cfg = compose(config_name=\"main\", overrides=[\"model=pomo\",\"~experiment\"])\n    print(OmegaConf.to_yaml(cfg.model))\n
with initialize(version_base=None, config_path=ROOT_DIR+\"configs\"): cfg = compose(config_name=\"main\", overrides=[\"model=pomo\",\"~experiment\"]) print(OmegaConf.to_yaml(cfg.model))
generate_default_data: true\nmetrics:\n  train:\n  - loss\n  - reward\n  val:\n  - reward\n  - max_reward\n  - max_aug_reward\n  test: ${metrics.val}\n  log_on_step: true\n_target_: rl4co.models.POMO\nnum_augment: 8\n\n

As you can see, parameters like \"batch_size\" were removed from the model config, as those were set by the experiment config base.yaml. Through the hashbang

# @package _global_\n

in the configs/experiments/base.yaml, this configuration is able to make changes to all parts of the configuration (like model, trainer, logger). So instead of adding a new key to the omegaconf object, configurations with a # @package _global_ hashbang typically alter other parts of the configuration.

Another example of such a configuration is the debug/default.yaml, which sets all parameters into a lightweight debugging mode:

In\u00a0[11]: Copied!
with initialize(version_base=None, config_path=ROOT_DIR+\"configs\"):\n    cfg = compose(config_name=\"main\", overrides=[\"debug=default\"])\n    print(OmegaConf.to_yaml(cfg.model))\n
with initialize(version_base=None, config_path=ROOT_DIR+\"configs\"): cfg = compose(config_name=\"main\", overrides=[\"debug=default\"]) print(OmegaConf.to_yaml(cfg.model))
generate_default_data: true\nmetrics:\n  train:\n  - loss\n  - reward\n  val:\n  - reward\n  test:\n  - reward\n  log_on_step: true\n_target_: rl4co.models.AttentionModel\nbaseline: rollout\nbatch_size: 8\nval_batch_size: 32\ntest_batch_size: 32\ntrain_data_size: 64\nval_data_size: 1000\ntest_data_size: 1000\noptimizer_kwargs:\n  lr: 0.0001\n\n
"},{"location":"examples/advanced/1-hydra-config/#hydra-configuration","title":"Hydra Configuration\u00b6","text":"

Hydra makes it extremely convenient to configure projects with lots of parameter settings like the RL4CO library.

While you don't need Hydra to use RL4CO, it is recommended to use it for your own projects to make it easier to manage the configuration of your experiments.

Hydra uses config files in .yaml format for this. These files can be found in the configs/ folder, where the subfolders define configurations for specific parts of the framework which are then combined in the main.yaml configuration. In this tutorial we will have a look at how to use these different configuration files and how to add new parameters to the configuration.

"},{"location":"examples/advanced/1-hydra-config/#summary","title":"Summary\u00b6","text":"
  • Reference config files using the CLI flag <key>=<config_file> (e.g. model=am)
  • Add parameters (or even entire keys) to the config using the \"+\" prefix (e.g. +model.batch_size=32)
  • Remove parameters (or even entire keys) to the config using the \"~\" prefix (e.g. ~logger.wandb)
  • The # @package _global_ hashbang allows global access from any config file
  • Turn on debugging mode using debug=default
"},{"location":"examples/advanced/2-flash-attention-2/","title":"Using Flash Attention 2 \u26a1","text":"

In this notebook we will compare Flash Attention 2 with the torch.nn.functional.scaled_dot_product_attention function and a simple implementation.

In\u00a0[1]: Copied!
## Uncomment the following line to install the package from PyPI\n## You may need to restart the runtime in Colab after this\n## Remember to choose a GPU runtime for faster training!\n\n# !pip install rl4co\n
## Uncomment the following line to install the package from PyPI ## You may need to restart the runtime in Colab after this ## Remember to choose a GPU runtime for faster training! # !pip install rl4co In\u00a0[2]: Copied!
import torch\nimport torch.utils.benchmark as benchmark\n\n\n# Simple implementation in PyTorch\nfrom rl4co.models.nn.attention import scaled_dot_product_attention_simple\n# PyTorch official implementation of FlashAttention 1\nfrom torch.nn.functional import scaled_dot_product_attention\n# FlashAttention 2\nfrom rl4co.models.nn.flash_attention import scaled_dot_product_attention_flash_attn\n\nfrom rl4co.envs import TSPEnv\nfrom rl4co.models.zoo.am import AttentionModel\nfrom rl4co.utils.trainer import RL4COTrainer\nfrom rl4co.models.common.constructive.autoregressive import GraphAttentionEncoder\n
import torch import torch.utils.benchmark as benchmark # Simple implementation in PyTorch from rl4co.models.nn.attention import scaled_dot_product_attention_simple # PyTorch official implementation of FlashAttention 1 from torch.nn.functional import scaled_dot_product_attention # FlashAttention 2 from rl4co.models.nn.flash_attention import scaled_dot_product_attention_flash_attn from rl4co.envs import TSPEnv from rl4co.models.zoo.am import AttentionModel from rl4co.utils.trainer import RL4COTrainer from rl4co.models.common.constructive.autoregressive import GraphAttentionEncoder
/home/botu/.local/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n  from .autonotebook import tqdm as notebook_tqdm\n
In\u00a0[3]: Copied!
bs, head, length, d = 64, 8, 512, 128\n\nquery = torch.rand(bs, head, length, d, dtype=torch.float16, device=\"cuda\")\nkey = torch.rand(bs, head, length, d, dtype=torch.float16, device=\"cuda\")\nvalue = torch.rand(bs, head, length, d, dtype=torch.float16, device=\"cuda\")\n\n# Simple implementation in PyTorch\nout_simple = scaled_dot_product_attention_simple(query, key, value)\n\n# PyTorch official implementation of FlashAttention 1\nout_pytorch = scaled_dot_product_attention(query, key, value)\n\n# FlashAttention 2\nout_flash_attn = scaled_dot_product_attention_flash_attn(query, key, value)\n\n\nprint(torch.allclose(out_simple, out_pytorch, atol=1e-3))\nprint(torch.allclose(out_flash_attn, out_pytorch, atol=1e-3))\n\nprint(torch.max(torch.abs(out_simple - out_pytorch)), torch.mean(torch.abs(out_simple - out_pytorch)))\nprint(torch.max(torch.abs(out_flash_attn - out_pytorch)), torch.mean(torch.abs(out_flash_attn - out_pytorch)))\n
bs, head, length, d = 64, 8, 512, 128 query = torch.rand(bs, head, length, d, dtype=torch.float16, device=\"cuda\") key = torch.rand(bs, head, length, d, dtype=torch.float16, device=\"cuda\") value = torch.rand(bs, head, length, d, dtype=torch.float16, device=\"cuda\") # Simple implementation in PyTorch out_simple = scaled_dot_product_attention_simple(query, key, value) # PyTorch official implementation of FlashAttention 1 out_pytorch = scaled_dot_product_attention(query, key, value) # FlashAttention 2 out_flash_attn = scaled_dot_product_attention_flash_attn(query, key, value) print(torch.allclose(out_simple, out_pytorch, atol=1e-3)) print(torch.allclose(out_flash_attn, out_pytorch, atol=1e-3)) print(torch.max(torch.abs(out_simple - out_pytorch)), torch.mean(torch.abs(out_simple - out_pytorch))) print(torch.max(torch.abs(out_flash_attn - out_pytorch)), torch.mean(torch.abs(out_flash_attn - out_pytorch)))
True\nTrue\ntensor(0.0005, device='cuda:0', dtype=torch.float16) tensor(1.2159e-05, device='cuda:0', dtype=torch.float16)\ntensor(0.0005, device='cuda:0', dtype=torch.float16) tensor(6.3777e-06, device='cuda:0', dtype=torch.float16)\n
In\u00a0[4]: Copied!
env = TSPEnv(generator_params=dict(num_loc=1000))\n\nnum_heads = 8\nembed_dim = 128\nnum_layers = 3\nenc_simple = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers,\n                            sdpa_fn=scaled_dot_product_attention_simple)\n\nenc_fa1 = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers,\n                            sdpa_fn=scaled_dot_product_attention)\n\nenc_fa2 = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers,\n                            sdpa_fn=scaled_dot_product_attention_flash_attn)\n\n# Flash Attention supports only FP16 and BFloat16\nenc_simple.to(\"cuda\").half()\nenc_fa1.to(\"cuda\").half()\nenc_fa2.to(\"cuda\").half()\n
env = TSPEnv(generator_params=dict(num_loc=1000)) num_heads = 8 embed_dim = 128 num_layers = 3 enc_simple = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers, sdpa_fn=scaled_dot_product_attention_simple) enc_fa1 = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers, sdpa_fn=scaled_dot_product_attention) enc_fa2 = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers, sdpa_fn=scaled_dot_product_attention_flash_attn) # Flash Attention supports only FP16 and BFloat16 enc_simple.to(\"cuda\").half() enc_fa1.to(\"cuda\").half() enc_fa2.to(\"cuda\").half() Out[4]:
GraphAttentionEncoder(\n  (init_embedding): TSPInitEmbedding(\n    (init_embed): Linear(in_features=2, out_features=128, bias=True)\n  )\n  (net): GraphAttentionNetwork(\n    (layers): Sequential(\n      (0): MultiHeadAttentionLayer(\n        (0): SkipConnection(\n          (module): MultiHeadAttention(\n            (Wqkv): Linear(in_features=128, out_features=384, bias=True)\n            (out_proj): Linear(in_features=128, out_features=128, bias=True)\n          )\n        )\n        (1): Normalization(\n          (normalizer): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n        )\n        (2): SkipConnection(\n          (module): Sequential(\n            (0): Linear(in_features=128, out_features=512, bias=True)\n            (1): ReLU()\n            (2): Linear(in_features=512, out_features=128, bias=True)\n          )\n        )\n        (3): Normalization(\n          (normalizer): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n        )\n      )\n      (1): MultiHeadAttentionLayer(\n        (0): SkipConnection(\n          (module): MultiHeadAttention(\n            (Wqkv): Linear(in_features=128, out_features=384, bias=True)\n            (out_proj): Linear(in_features=128, out_features=128, bias=True)\n          )\n        )\n        (1): Normalization(\n          (normalizer): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n        )\n        (2): SkipConnection(\n          (module): Sequential(\n            (0): Linear(in_features=128, out_features=512, bias=True)\n            (1): ReLU()\n            (2): Linear(in_features=512, out_features=128, bias=True)\n          )\n        )\n        (3): Normalization(\n          (normalizer): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n        )\n      )\n      (2): MultiHeadAttentionLayer(\n        (0): SkipConnection(\n          (module): MultiHeadAttention(\n            (Wqkv): Linear(in_features=128, out_features=384, bias=True)\n            (out_proj): Linear(in_features=128, out_features=128, bias=True)\n          )\n        )\n        (1): Normalization(\n          (normalizer): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n        )\n        (2): SkipConnection(\n          (module): Sequential(\n            (0): Linear(in_features=128, out_features=512, bias=True)\n            (1): ReLU()\n            (2): Linear(in_features=512, out_features=128, bias=True)\n          )\n        )\n        (3): Normalization(\n          (normalizer): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)\n        )\n      )\n    )\n  )\n)
In\u00a0[5]: Copied!
def build_models(num_heads=8, embed_dim=128, num_layers=3):\n    enc_simple = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers,\n                                sdpa_fn=scaled_dot_product_attention_simple)\n\n    enc_fa1 = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers,\n                                sdpa_fn=scaled_dot_product_attention)\n\n    enc_fa2 = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers,\n                                sdpa_fn=scaled_dot_product_attention_flash_attn)\n\n    # Flash Attention supports only FP16 and BFloat16\n    enc_simple.to(\"cuda\").half()\n    enc_fa1.to(\"cuda\").half()\n    enc_fa2.to(\"cuda\").half()\n    return enc_simple, enc_fa1, enc_fa2\n
def build_models(num_heads=8, embed_dim=128, num_layers=3): enc_simple = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers, sdpa_fn=scaled_dot_product_attention_simple) enc_fa1 = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers, sdpa_fn=scaled_dot_product_attention) enc_fa2 = GraphAttentionEncoder(env, num_heads=num_heads, embed_dim=embed_dim, num_layers=num_layers, sdpa_fn=scaled_dot_product_attention_flash_attn) # Flash Attention supports only FP16 and BFloat16 enc_simple.to(\"cuda\").half() enc_fa1.to(\"cuda\").half() enc_fa2.to(\"cuda\").half() return enc_simple, enc_fa1, enc_fa2 In\u00a0[6]: Copied!
threads = 32\nsizes = [10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000]\n\ntimes_simple = []\ntimes_fa1 = []\ntimes_fa2 = []\n\n# for embed_dim in [64, 128, 256]:\nfor embed_dim in [128]:\n    # Get models\n    enc_simple, enc_fa1, enc_fa2 = build_models(embed_dim=embed_dim)\n\n    for problem_size in sizes:\n\n        with torch.no_grad():\n            # initial data\n            env = TSPEnv(generator_params=dict(num_loc=problem_size))\n            td_init = env.reset(batch_size=[2])\n            # set dtype to float16\n            td_init = td_init.to(dest=\"cuda\", dtype=torch.float16)\n\n            t_simple = benchmark.Timer(\n                setup='x = td_init',\n                stmt='encode(x)',\n                globals={'td_init': td_init, 'encode': enc_simple},\n                num_threads=threads)\n\n            t_fa1 = benchmark.Timer(\n                setup='x = td_init',\n                stmt='encode(x)',\n                globals={'td_init': td_init, 'encode': enc_fa1},\n                num_threads=threads)\n            \n            t_fa2 = benchmark.Timer(\n                setup='x = td_init',\n                stmt='encode(x)',\n                globals={'td_init': td_init, 'encode': enc_fa2},\n                num_threads=threads)\n            \n            times_simple.append(torch.tensor(t_simple.blocked_autorange().times).mean())\n            times_fa2.append(torch.tensor(t_fa2.blocked_autorange().times).mean())\n            times_fa1.append(torch.tensor(t_fa1.blocked_autorange().times).mean())\n\n            print(f\"Times for problem size {problem_size}: Simple {times_simple[-1]*1e3:.3f}, FA1 {times_fa1[-1]*1e3:.3f}, FA2 {times_fa2[-1]*1e3:.3f}\")\n\n    # eliminate cache\n    torch.cuda.empty_cache()\n
threads = 32 sizes = [10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000] times_simple = [] times_fa1 = [] times_fa2 = [] # for embed_dim in [64, 128, 256]: for embed_dim in [128]: # Get models enc_simple, enc_fa1, enc_fa2 = build_models(embed_dim=embed_dim) for problem_size in sizes: with torch.no_grad(): # initial data env = TSPEnv(generator_params=dict(num_loc=problem_size)) td_init = env.reset(batch_size=[2]) # set dtype to float16 td_init = td_init.to(dest=\"cuda\", dtype=torch.float16) t_simple = benchmark.Timer( setup='x = td_init', stmt='encode(x)', globals={'td_init': td_init, 'encode': enc_simple}, num_threads=threads) t_fa1 = benchmark.Timer( setup='x = td_init', stmt='encode(x)', globals={'td_init': td_init, 'encode': enc_fa1}, num_threads=threads) t_fa2 = benchmark.Timer( setup='x = td_init', stmt='encode(x)', globals={'td_init': td_init, 'encode': enc_fa2}, num_threads=threads) times_simple.append(torch.tensor(t_simple.blocked_autorange().times).mean()) times_fa2.append(torch.tensor(t_fa2.blocked_autorange().times).mean()) times_fa1.append(torch.tensor(t_fa1.blocked_autorange().times).mean()) print(f\"Times for problem size {problem_size}: Simple {times_simple[-1]*1e3:.3f}, FA1 {times_fa1[-1]*1e3:.3f}, FA2 {times_fa2[-1]*1e3:.3f}\") # eliminate cache torch.cuda.empty_cache()
Times for problem size 10: Simple 0.633, FA1 0.511, FA2 0.554\nTimes for problem size 20: Simple 0.646, FA1 0.535, FA2 0.565\nTimes for problem size 50: Simple 0.663, FA1 0.547, FA2 0.580\nTimes for problem size 100: Simple 0.664, FA1 0.547, FA2 0.580\nTimes for problem size 200: Simple 0.670, FA1 0.509, FA2 0.585\nTimes for problem size 500: Simple 0.669, FA1 0.512, FA2 0.582\nTimes for problem size 1000: Simple 1.088, FA1 0.555, FA2 0.609\nTimes for problem size 2000: Simple 3.626, FA1 1.292, FA2 0.790\nTimes for problem size 5000: Simple 20.332, FA1 5.748, FA2 2.943\nTimes for problem size 10000: Simple 80.337, FA1 20.701, FA2 10.230\n
In\u00a0[7]: Copied!
# Plot results\nimport matplotlib.pyplot as plt\n\n\nfig, ax = plt.subplots(1, 1, figsize=(10, 5))\nax.plot(sizes, times_simple, label=\"Simple\")\nax.plot(sizes, times_fa1, label=\"FlashAttention 1\")\nax.plot(sizes, times_fa2, label=\"FlashAttention 2\")\n\n# fancy grid\nax.grid(True, which=\"both\", ls=\"-\", alpha=0.5)\nax.set_xscale(\"log\")\nax.set_yscale(\"log\")\nax.set_xlabel(\"Problem size\")\nax.set_ylabel(\"Time (ms)\")\nax.legend()\n\n# Instead of 10^1, 10^2... show nuber\nax.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f\"{x:.0f}\"))\n\nplt.show()\n
# Plot results import matplotlib.pyplot as plt fig, ax = plt.subplots(1, 1, figsize=(10, 5)) ax.plot(sizes, times_simple, label=\"Simple\") ax.plot(sizes, times_fa1, label=\"FlashAttention 1\") ax.plot(sizes, times_fa2, label=\"FlashAttention 2\") # fancy grid ax.grid(True, which=\"both\", ls=\"-\", alpha=0.5) ax.set_xscale(\"log\") ax.set_yscale(\"log\") ax.set_xlabel(\"Problem size\") ax.set_ylabel(\"Time (ms)\") ax.legend() # Instead of 10^1, 10^2... show nuber ax.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f\"{x:.0f}\")) plt.show()

Using FlashAttention can speed up inference even at small context lengths (number of nodes in the graph). Difference can be of several times for large graphs between different implementations!

"},{"location":"examples/advanced/2-flash-attention-2/#using-flash-attention-2","title":"Using Flash Attention 2 \u26a1\u00b6","text":""},{"location":"examples/advanced/2-flash-attention-2/#installation","title":"Installation\u00b6","text":"

Follow instructions here: https://github.com/Dao-AILab/flash-attention

"},{"location":"examples/advanced/2-flash-attention-2/#imports","title":"Imports\u00b6","text":""},{"location":"examples/advanced/2-flash-attention-2/#testing-differences-with-simple-tensors","title":"Testing differences with simple tensors\u00b6","text":""},{"location":"examples/advanced/2-flash-attention-2/#testing-graph-attention-encoders-with-flash-attention-2","title":"Testing Graph Attention Encoders with Flash Attention 2\u00b6","text":""},{"location":"examples/advanced/3-local-search/","title":"Local Search","text":"In\u00a0[1]: Copied!
# !pip install rl4co[routing]  # include pyvrp\n
# !pip install rl4co[routing] # include pyvrp In\u00a0[2]: Copied!
import torch\n\nfrom rl4co.envs import TSPEnv\nfrom rl4co.models.zoo import AttentionModel\n
import torch from rl4co.envs import TSPEnv from rl4co.models.zoo import AttentionModel In\u00a0[3]: Copied!
# RL4CO env based on TorchRL\nenv = TSPEnv(num_loc=50) \n\ncheckpoint_path = \"../tsp-quickstart.ckpt\"  # checkpoint from the ../1-quickstart.ipynb\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# Model: default is AM with REINFORCE and greedy rollout baseline\nmodel = AttentionModel.load_from_checkpoint(checkpoint_path, load_baseline=False)\n
# RL4CO env based on TorchRL env = TSPEnv(num_loc=50) checkpoint_path = \"../tsp-quickstart.ckpt\" # checkpoint from the ../1-quickstart.ipynb device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\") # Model: default is AM with REINFORCE and greedy rollout baseline model = AttentionModel.load_from_checkpoint(checkpoint_path, load_baseline=False)
/home/sanghyeok/NCO/rl4co/.venv/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n/home/sanghyeok/NCO/rl4co/.venv/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n/home/sanghyeok/NCO/rl4co/.venv/lib/python3.10/site-packages/lightning/pytorch/core/saving.py:188: Found keys that are not in the model state dict but in the checkpoint: ['baseline.baseline.model.encoder.init_embedding.init_embed.weight', 'baseline.baseline.model.encoder.init_embedding.init_embed.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.num_batches_tracked', 'baseline.baseline.model.decoder.context_embedding.W_placeholder', 'baseline.baseline.model.decoder.context_embedding.project_context.weight', 'baseline.baseline.model.decoder.project_node_embeddings.weight', 'baseline.baseline.model.decoder.project_fixed_context.weight', 'baseline.baseline.model.decoder.pointer.project_out.weight']\n
In\u00a0[4]: Copied!
# Greedy rollouts over trained model (same states as previous plot)\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\ntd_init = env.reset(batch_size=[3]).to(device)\nmodel = model.to(device)\nout = model(td_init.clone(), phase=\"test\", decode_type=\"greedy\", return_actions=True)\nactions = out['actions']\n\n# Improve solutions using LocalSearch\nimproved_actions = env.local_search(td_init, actions, rng=0)\nimproved_rewards = env.get_reward(td_init, improved_actions)\n\n# Plotting\nimport matplotlib.pyplot as plt\nfor i, td in enumerate(td_init):\n    fig, axs = plt.subplots(1,2, figsize=(11,5))\n    env.render(td, actions[i], ax=axs[0]) \n    env.render(td, improved_actions[i], ax=axs[1])\n    axs[0].set_title(f\"Before improvement | Cost = {-out['reward'][i].item():.3f}\")\n    axs[1].set_title(f\"After improvement | Cost = {-improved_rewards[i].item():.3f}\")\n
# Greedy rollouts over trained model (same states as previous plot) device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\") td_init = env.reset(batch_size=[3]).to(device) model = model.to(device) out = model(td_init.clone(), phase=\"test\", decode_type=\"greedy\", return_actions=True) actions = out['actions'] # Improve solutions using LocalSearch improved_actions = env.local_search(td_init, actions, rng=0) improved_rewards = env.get_reward(td_init, improved_actions) # Plotting import matplotlib.pyplot as plt for i, td in enumerate(td_init): fig, axs = plt.subplots(1,2, figsize=(11,5)) env.render(td, actions[i], ax=axs[0]) env.render(td, improved_actions[i], ax=axs[1]) axs[0].set_title(f\"Before improvement | Cost = {-out['reward'][i].item():.3f}\") axs[1].set_title(f\"After improvement | Cost = {-improved_rewards[i].item():.3f}\")

We can see that the solution has improved after using 2-opt.

"},{"location":"examples/advanced/3-local-search/#local-search","title":"Local Search\u00b6","text":"

In this notebook, we will show how to improve the solution at hand using local search and other techniques. Here we solve TSP and use 2-opt to improve the solution. You can check how the improvement works for other problems in each Env's local_search method.

Note that this notebook is based on 1-quickstart and we use the checkpoint file from it. If you haven't checked it yet, we recommend you to check it first.

"},{"location":"examples/advanced/3-local-search/#installation","title":"Installation\u00b6","text":"

We use LocalSearch operator provided by PyVRP. See https://github.com/PyVRP/PyVRP for more details.

Uncomment the following line to install the package from PyPI. Remember to choose a GPU runtime for faster training!

Note: You may need to restart the runtime in Colab after this

"},{"location":"examples/advanced/3-local-search/#imports","title":"Imports\u00b6","text":""},{"location":"examples/advanced/3-local-search/#environment-policy-and-model-from-saved-checkpoint","title":"Environment, Policy, and Model from saved checkpoint\u00b6","text":""},{"location":"examples/advanced/3-local-search/#testing-with-solution-improvement","title":"Testing with Solution Improvement\u00b6","text":""},{"location":"examples/datasets/","title":"Datasets","text":"

Collection of examples for training and testing with custom datasets.

"},{"location":"examples/datasets/#index","title":"Index","text":"
  • 1-test-on-tsplib.ipynb: here we show how to test a model on the TSPLIB dataset.
  • 2-test-on-cvrplib.ipynb: here we show how to test a model on the CVRPLIB dataset.
"},{"location":"examples/datasets/1-test-on-tsplib/","title":"Test Model on TSPLib","text":"In\u00a0[\u00a0]: Copied!
# !pip install rl4co[graph] # include torch-geometric\n\n## NOTE: to install latest version from Github (may be unstable) install from source instead:\n# !pip install git+https://github.com/ai4co/rl4co.git\n
# !pip install rl4co[graph] # include torch-geometric ## NOTE: to install latest version from Github (may be unstable) install from source instead: # !pip install git+https://github.com/ai4co/rl4co.git In\u00a0[\u00a0]: Copied!
# Install the `tsplib95` package\n# !pip install tsplib95\n
# Install the `tsplib95` package # !pip install tsplib95 In\u00a0[1]: Copied!
%load_ext autoreload\n%autoreload 2\n\nimport os\nimport re\nimport torch\n\nfrom rl4co.envs import TSPEnv, CVRPEnv\nfrom rl4co.models.zoo.am import AttentionModel\nfrom rl4co.utils.trainer import RL4COTrainer\nfrom rl4co.utils.decoding import get_log_likelihood\nfrom rl4co.models.zoo import EAS, EASLay, EASEmb, ActiveSearch\n\nfrom math import ceil\nfrom einops import repeat\nfrom tsplib95.loaders import load_problem, load_solution\n
%load_ext autoreload %autoreload 2 import os import re import torch from rl4co.envs import TSPEnv, CVRPEnv from rl4co.models.zoo.am import AttentionModel from rl4co.utils.trainer import RL4COTrainer from rl4co.utils.decoding import get_log_likelihood from rl4co.models.zoo import EAS, EASLay, EASEmb, ActiveSearch from math import ceil from einops import repeat from tsplib95.loaders import load_problem, load_solution
/home/cbhua/.local/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n  from .autonotebook import tqdm as notebook_tqdm\n
In\u00a0[2]: Copied!
# Load from checkpoint; alternatively, simply instantiate a new model\n# Note the model is trained for TSP problem\ncheckpoint_path = \"../tsp-20.ckpt\" # modify the path to your checkpoint file\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# load checkpoint\n# checkpoint = torch.load(checkpoint_path)\n\nlit_model = AttentionModel.load_from_checkpoint(checkpoint_path, load_baseline=False)\npolicy, env = lit_model.policy, lit_model.env\npolicy = policy.to(device)\n
# Load from checkpoint; alternatively, simply instantiate a new model # Note the model is trained for TSP problem checkpoint_path = \"../tsp-20.ckpt\" # modify the path to your checkpoint file device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\") # load checkpoint # checkpoint = torch.load(checkpoint_path) lit_model = AttentionModel.load_from_checkpoint(checkpoint_path, load_baseline=False) policy, env = lit_model.policy, lit_model.env policy = policy.to(device)
/home/cbhua/miniconda3/envs/rl4co-user/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n/home/cbhua/miniconda3/envs/rl4co-user/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n/home/cbhua/miniconda3/envs/rl4co-user/lib/python3.10/site-packages/lightning/pytorch/core/saving.py:177: Found keys that are not in the model state dict but in the checkpoint: ['baseline.baseline.model.encoder.init_embedding.init_embed.weight', 'baseline.baseline.model.encoder.init_embedding.init_embed.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.num_batches_tracked', 'baseline.baseline.model.decoder.context_embedding.W_placeholder', 'baseline.baseline.model.decoder.context_embedding.project_context.weight', 'baseline.baseline.model.decoder.project_node_embeddings.weight', 'baseline.baseline.model.decoder.project_fixed_context.weight', 'baseline.baseline.model.decoder.logit_attention.project_out.weight']\n
In\u00a0[3]: Copied!
# Load the problem from TSPLib\ntsplib_dir = './tsplib'# modify this to the directory of your prepared files\nfiles = os.listdir(tsplib_dir)\nproblem_files_full = [file for file in files if file.endswith('.tsp')]\n\n# Load the optimal solution files from TSPLib\nsolution_files = [file for file in files if file.endswith('.opt.tour')]\n
# Load the problem from TSPLib tsplib_dir = './tsplib'# modify this to the directory of your prepared files files = os.listdir(tsplib_dir) problem_files_full = [file for file in files if file.endswith('.tsp')] # Load the optimal solution files from TSPLib solution_files = [file for file in files if file.endswith('.opt.tour')] In\u00a0[4]: Copied!
# Utils function\ndef normalize_coord(coord:torch.Tensor) -> torch.Tensor:\n    x, y = coord[:, 0], coord[:, 1]\n    x_min, x_max = x.min(), x.max()\n    y_min, y_max = y.min(), y.max()\n    \n    x_scaled = (x - x_min) / (x_max - x_min) \n    y_scaled = (y - y_min) / (y_max - y_min)\n    coord_scaled = torch.stack([x_scaled, y_scaled], dim=1)\n    return coord_scaled\n
# Utils function def normalize_coord(coord:torch.Tensor) -> torch.Tensor: x, y = coord[:, 0], coord[:, 1] x_min, x_max = x.min(), x.max() y_min, y_max = y.min(), y.max() x_scaled = (x - x_min) / (x_max - x_min) y_scaled = (y - y_min) / (y_max - y_min) coord_scaled = torch.stack([x_scaled, y_scaled], dim=1) return coord_scaled In\u00a0[9]: Copied!
# Customized problem cases\nproblem_files_custom = [\n    \"eil51.tsp\", \"berlin52.tsp\", \"st70.tsp\", \"eil76.tsp\", \n    \"pr76.tsp\", \"rat99.tsp\", \"kroA100.tsp\", \"kroB100.tsp\", \n    \"kroC100.tsp\", \"kroD100.tsp\", \"kroE100.tsp\", \"rd100.tsp\", \n    \"eil101.tsp\", \"lin105.tsp\", \"pr124.tsp\", \"bier127.tsp\", \n    \"ch130.tsp\", \"pr136.tsp\", \"pr144.tsp\", \"kroA150.tsp\", \n    \"kroB150.tsp\", \"pr152.tsp\", \"u159.tsp\", \"rat195.tsp\", \n    \"kroA200.tsp\", \"ts225.tsp\", \"tsp225.tsp\", \"pr226.tsp\"\n]\n
# Customized problem cases problem_files_custom = [ \"eil51.tsp\", \"berlin52.tsp\", \"st70.tsp\", \"eil76.tsp\", \"pr76.tsp\", \"rat99.tsp\", \"kroA100.tsp\", \"kroB100.tsp\", \"kroC100.tsp\", \"kroD100.tsp\", \"kroE100.tsp\", \"rd100.tsp\", \"eil101.tsp\", \"lin105.tsp\", \"pr124.tsp\", \"bier127.tsp\", \"ch130.tsp\", \"pr136.tsp\", \"pr144.tsp\", \"kroA150.tsp\", \"kroB150.tsp\", \"pr152.tsp\", \"u159.tsp\", \"rat195.tsp\", \"kroA200.tsp\", \"ts225.tsp\", \"tsp225.tsp\", \"pr226.tsp\" ] In\u00a0[12]: Copied!
# problem_files = problem_files_full # if you want to test on all the problems\nproblem_files = problem_files_custom # if you want to test on the customized problems\n\nfor problem_idx in range(len(problem_files)):\n    problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx]))\n\n    # NOTE: in some problem files (e.g. hk48), the node coordinates are not available\n    # we temporarily skip these problems\n    if not len(problem.node_coords):\n        continue\n\n    # Load the node coordinates\n    coords = []\n    for _, v in problem.node_coords.items():\n        coords.append(v)\n    coords = torch.tensor(coords).float().to(device) # [n, 2]\n    coords_norm = normalize_coord(coords)\n\n    # Prepare the tensordict\n    batch_size = 2\n    td = env.reset(batch_size=(batch_size,)).to(device)\n    td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2)\n    td['action_mask'] = torch.ones(batch_size, coords_norm.shape[0], dtype=torch.bool)\n\n    # Get the solution from the policy\n    with torch.no_grad():\n        out = policy(\n            td.clone(), \n            decode_type=\"greedy\", \n            return_actions=True,\n            num_starts=0\n        )\n\n    # Calculate the cost on the original scale\n    td['locs'] = repeat(coords, 'n d -> b n d', b=batch_size, d=2)\n    neg_reward = env.get_reward(td, out['actions'])\n    cost = ceil(-1 * neg_reward[0].item())\n\n    # Check if there exists an optimal solution\n    try:\n        # Load the optimal solution\n        solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour'))\n        matches = re.findall(r'\\((.*?)\\)', solution.comment)\n\n        # NOTE: in some problem solution file (e.g. ch130), the optimal cost is not writen with a brace\n        # we temporarily skip to calculate the gap for these problems\n        optimal_cost = int(matches[0])\n        gap = (cost - optimal_cost) / optimal_cost\n        print(f'Problem: {problem_files[problem_idx][:-4]:<10} Cost: {cost:<10} Optimal Cost: {optimal_cost:<10}\\t Gap: {gap:.2%}')\n    except:\n        continue\n    finally:\n        print(f'problem: {problem_files[problem_idx][:-4]:<10} cost: {cost:<10}')\n
# problem_files = problem_files_full # if you want to test on all the problems problem_files = problem_files_custom # if you want to test on the customized problems for problem_idx in range(len(problem_files)): problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx])) # NOTE: in some problem files (e.g. hk48), the node coordinates are not available # we temporarily skip these problems if not len(problem.node_coords): continue # Load the node coordinates coords = [] for _, v in problem.node_coords.items(): coords.append(v) coords = torch.tensor(coords).float().to(device) # [n, 2] coords_norm = normalize_coord(coords) # Prepare the tensordict batch_size = 2 td = env.reset(batch_size=(batch_size,)).to(device) td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2) td['action_mask'] = torch.ones(batch_size, coords_norm.shape[0], dtype=torch.bool) # Get the solution from the policy with torch.no_grad(): out = policy( td.clone(), decode_type=\"greedy\", return_actions=True, num_starts=0 ) # Calculate the cost on the original scale td['locs'] = repeat(coords, 'n d -> b n d', b=batch_size, d=2) neg_reward = env.get_reward(td, out['actions']) cost = ceil(-1 * neg_reward[0].item()) # Check if there exists an optimal solution try: # Load the optimal solution solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour')) matches = re.findall(r'\\((.*?)\\)', solution.comment) # NOTE: in some problem solution file (e.g. ch130), the optimal cost is not writen with a brace # we temporarily skip to calculate the gap for these problems optimal_cost = int(matches[0]) gap = (cost - optimal_cost) / optimal_cost print(f'Problem: {problem_files[problem_idx][:-4]:<10} Cost: {cost:<10} Optimal Cost: {optimal_cost:<10}\\t Gap: {gap:.2%}') except: continue finally: print(f'problem: {problem_files[problem_idx][:-4]:<10} cost: {cost:<10}')
/tmp/ipykernel_3883036/2632546508.py:5: DeprecationWarning: Call to deprecated function (or staticmethod) load_problem. (Will be removed in newer versions. Use `tsplib95.load` instead.) -- Deprecated since version 7.0.0.\n  problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx]))\n/tmp/ipykernel_3883036/2632546508.py:43: DeprecationWarning: Call to deprecated function (or staticmethod) load_solution. (Will be removed in newer versions. Use `tsplib95.load` instead.) -- Deprecated since version 7.0.0.\n  solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour'))\n
Problem: eil51      Cost: 493        Optimal Cost: 426       \t Gap: 15.73%\nproblem: eil51      cost: 493       \nproblem: berlin52   cost: 8957      \nProblem: st70       Cost: 806        Optimal Cost: 675       \t Gap: 19.41%\nproblem: st70       cost: 806       \nProblem: eil76      Cost: 693        Optimal Cost: 538       \t Gap: 28.81%\nproblem: eil76      cost: 693       \nProblem: pr76       Cost: 132292     Optimal Cost: 108159    \t Gap: 22.31%\nproblem: pr76       cost: 132292    \nproblem: rat99      cost: 2053      \nProblem: kroA100    Cost: 30791      Optimal Cost: 21282     \t Gap: 44.68%\nproblem: kroA100    cost: 30791     \nproblem: kroB100    cost: 30347     \nProblem: kroC100    Cost: 28339      Optimal Cost: 20749     \t Gap: 36.58%\nproblem: kroC100    cost: 28339     \nProblem: kroD100    Cost: 27600      Optimal Cost: 21294     \t Gap: 29.61%\nproblem: kroD100    cost: 27600     \nproblem: kroE100    cost: 28396     \nProblem: rd100      Cost: 10695      Optimal Cost: 7910      \t Gap: 35.21%\nproblem: rd100      cost: 10695     \nproblem: eil101     cost: 919       \nProblem: lin105     Cost: 21796      Optimal Cost: 14379     \t Gap: 51.58%\nproblem: lin105     cost: 21796     \nproblem: pr124      cost: 75310     \nproblem: bier127    cost: 177471    \nproblem: ch130      cost: 8169      \nproblem: pr136      cost: 135974    \nproblem: pr144      cost: 71599     \nproblem: kroA150    cost: 40376     \nproblem: kroB150    cost: 37076     \nproblem: pr152      cost: 94805     \nproblem: u159       cost: 64768     \nproblem: rat195     cost: 4465      \nproblem: kroA200    cost: 44181     \nproblem: ts225      cost: 210475    \nProblem: tsp225     Cost: 6212       Optimal Cost: 3919      \t Gap: 58.51%\nproblem: tsp225     cost: 6212      \nproblem: pr226      cost: 98849     \n
In\u00a0[16]: Copied!
# problem_files = problem_files_full # if you want to test on all the problems\nproblem_files = problem_files_custom # if you want to test on the customized problems\n\n# Import augmented utils\nfrom rl4co.data.transforms import (\n    StateAugmentation as SymmetricStateAugmentation)\nfrom rl4co.utils.ops import batchify, unbatchify\n\nnum_augment = 100\naugmentation = SymmetricStateAugmentation(num_augment=num_augment)\n\nfor problem_idx in range(len(problem_files)):\n    problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx]))\n\n    # NOTE: in some problem files (e.g. hk48), the node coordinates are not available\n    # we temporarily skip these problems\n    if not len(problem.node_coords):\n        continue\n\n    # Load the node coordinates\n    coords = []\n    for _, v in problem.node_coords.items():\n        coords.append(v)\n    coords = torch.tensor(coords).float().to(device) # [n, 2]\n    coords_norm = normalize_coord(coords)\n\n    # Prepare the tensordict\n    batch_size = 2\n    td = env.reset(batch_size=(batch_size,)).to(device)\n    td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2)\n    td['action_mask'] = torch.ones(batch_size, coords_norm.shape[0], dtype=torch.bool)\n\n    # Augmentation\n    td = augmentation(td)\n\n    # Get the solution from the policy\n    with torch.no_grad():\n        out = policy(\n            td.clone(), \n            decode_type=\"greedy\", \n            return_actions=True,\n            num_starts=0\n        )\n\n    # Calculate the cost on the original scale\n    coords_repeat = repeat(coords, 'n d -> b n d', b=batch_size, d=2)\n    td['locs'] = batchify(coords_repeat, num_augment)\n    reward = env.get_reward(td, out['actions'])\n    reward = unbatchify(reward, num_augment)\n    cost = ceil(-1 * torch.max(reward).item())\n\n    # Check if there exists an optimal solution\n    try:\n        # Load the optimal solution\n        solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour'))\n        matches = re.findall(r'\\((.*?)\\)', solution.comment)\n\n        # NOTE: in some problem solution file (e.g. ch130), the optimal cost is not writen with a brace\n        # we temporarily skip to calculate the gap for these problems\n        optimal_cost = int(matches[0])\n        gap = (cost - optimal_cost) / optimal_cost\n        print(f'Problem: {problem_files[problem_idx][:-4]}\\t Cost: {cost}\\t Optimal Cost: {optimal_cost}\\t Gap: {gap:.2%}')\n    except:\n        continue\n    finally:\n        print(f'problem: {problem_files[problem_idx][:-4]}\\t cost: {cost}\\t')\n
# problem_files = problem_files_full # if you want to test on all the problems problem_files = problem_files_custom # if you want to test on the customized problems # Import augmented utils from rl4co.data.transforms import ( StateAugmentation as SymmetricStateAugmentation) from rl4co.utils.ops import batchify, unbatchify num_augment = 100 augmentation = SymmetricStateAugmentation(num_augment=num_augment) for problem_idx in range(len(problem_files)): problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx])) # NOTE: in some problem files (e.g. hk48), the node coordinates are not available # we temporarily skip these problems if not len(problem.node_coords): continue # Load the node coordinates coords = [] for _, v in problem.node_coords.items(): coords.append(v) coords = torch.tensor(coords).float().to(device) # [n, 2] coords_norm = normalize_coord(coords) # Prepare the tensordict batch_size = 2 td = env.reset(batch_size=(batch_size,)).to(device) td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2) td['action_mask'] = torch.ones(batch_size, coords_norm.shape[0], dtype=torch.bool) # Augmentation td = augmentation(td) # Get the solution from the policy with torch.no_grad(): out = policy( td.clone(), decode_type=\"greedy\", return_actions=True, num_starts=0 ) # Calculate the cost on the original scale coords_repeat = repeat(coords, 'n d -> b n d', b=batch_size, d=2) td['locs'] = batchify(coords_repeat, num_augment) reward = env.get_reward(td, out['actions']) reward = unbatchify(reward, num_augment) cost = ceil(-1 * torch.max(reward).item()) # Check if there exists an optimal solution try: # Load the optimal solution solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour')) matches = re.findall(r'\\((.*?)\\)', solution.comment) # NOTE: in some problem solution file (e.g. ch130), the optimal cost is not writen with a brace # we temporarily skip to calculate the gap for these problems optimal_cost = int(matches[0]) gap = (cost - optimal_cost) / optimal_cost print(f'Problem: {problem_files[problem_idx][:-4]}\\t Cost: {cost}\\t Optimal Cost: {optimal_cost}\\t Gap: {gap:.2%}') except: continue finally: print(f'problem: {problem_files[problem_idx][:-4]}\\t cost: {cost}\\t')
/tmp/ipykernel_3883036/2898406631.py:13: DeprecationWarning: Call to deprecated function (or staticmethod) load_problem. (Will be removed in newer versions. Use `tsplib95.load` instead.) -- Deprecated since version 7.0.0.\n  problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx]))\n/tmp/ipykernel_3883036/2898406631.py:56: DeprecationWarning: Call to deprecated function (or staticmethod) load_solution. (Will be removed in newer versions. Use `tsplib95.load` instead.) -- Deprecated since version 7.0.0.\n  solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour'))\n
Problem: eil51\t Cost: 457\t Optimal Cost: 426\t Gap: 7.28%\nproblem: eil51\t cost: 457\t\nproblem: berlin52\t cost: 8256\t\nProblem: st70\t Cost: 777\t Optimal Cost: 675\t Gap: 15.11%\nproblem: st70\t cost: 777\t\nProblem: eil76\t Cost: 652\t Optimal Cost: 538\t Gap: 21.19%\nproblem: eil76\t cost: 652\t\nProblem: pr76\t Cost: 124939\t Optimal Cost: 108159\t Gap: 15.51%\nproblem: pr76\t cost: 124939\t\nproblem: rat99\t cost: 1614\t\nProblem: kroA100\t Cost: 27694\t Optimal Cost: 21282\t Gap: 30.13%\nproblem: kroA100\t cost: 27694\t\nproblem: kroB100\t cost: 28244\t\nProblem: kroC100\t Cost: 25032\t Optimal Cost: 20749\t Gap: 20.64%\nproblem: kroC100\t cost: 25032\t\nProblem: kroD100\t Cost: 26811\t Optimal Cost: 21294\t Gap: 25.91%\nproblem: kroD100\t cost: 26811\t\nproblem: kroE100\t cost: 27831\t\nProblem: rd100\t Cost: 9657\t Optimal Cost: 7910\t Gap: 22.09%\nproblem: rd100\t cost: 9657\t\nproblem: eil101\t cost: 781\t\nProblem: lin105\t Cost: 18769\t Optimal Cost: 14379\t Gap: 30.53%\nproblem: lin105\t cost: 18769\t\nproblem: pr124\t cost: 72115\t\nproblem: bier127\t cost: 154518\t\nproblem: ch130\t cost: 7543\t\nproblem: pr136\t cost: 128134\t\nproblem: pr144\t cost: 69755\t\nproblem: kroA150\t cost: 35967\t\nproblem: kroB150\t cost: 35196\t\nproblem: pr152\t cost: 88602\t\nproblem: u159\t cost: 59484\t\nproblem: rat195\t cost: 3631\t\nproblem: kroA200\t cost: 42061\t\nproblem: ts225\t cost: 196545\t\nProblem: tsp225\t Cost: 5680\t Optimal Cost: 3919\t Gap: 44.93%\nproblem: tsp225\t cost: 5680\t\nproblem: pr226\t cost: 94540\t\n
In\u00a0[18]: Copied!
# problem_files = problem_files_full # if you want to test on all the problems\nproblem_files = problem_files_custom # if you want to test on the customized problems\n\n# Parameters for sampling\nnum_samples = 100\nsoftmax_temp = 0.05\n\nfor problem_idx in range(len(problem_files)):\n    problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx]))\n\n    # NOTE: in some problem files (e.g. hk48), the node coordinates are not available\n    # we temporarily skip these problems\n    if not len(problem.node_coords):\n        continue\n\n    # Load the node coordinates\n    coords = []\n    for _, v in problem.node_coords.items():\n        coords.append(v)\n    coords = torch.tensor(coords).float().to(device) # [n, 2]\n    coords_norm = normalize_coord(coords)\n\n    # Prepare the tensordict\n    batch_size = 2\n    td = env.reset(batch_size=(batch_size,)).to(device)\n    td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2)\n    td['action_mask'] = torch.ones(batch_size, coords_norm.shape[0], dtype=torch.bool)\n\n    # Sampling\n    td = batchify(td, num_samples)\n\n    # Get the solution from the policy\n    with torch.no_grad():\n        out = policy(\n            td.clone(), \n            decode_type=\"sampling\", \n            return_actions=True,\n            num_starts=0,\n            softmax_temp=softmax_temp\n        )\n\n    # Calculate the cost on the original scale\n    coords_repeat = repeat(coords, 'n d -> b n d', b=batch_size, d=2)\n    td['locs'] = batchify(coords_repeat, num_samples)\n    reward = env.get_reward(td, out['actions'])\n    reward = unbatchify(reward, num_samples)\n    cost = ceil(-1 * torch.max(reward).item())\n\n    # Check if there exists an optimal solution\n    try:\n        # Load the optimal solution\n        solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour'))\n        matches = re.findall(r'\\((.*?)\\)', solution.comment)\n\n        # NOTE: in some problem solution file (e.g. ch130), the optimal cost is not writen with a brace\n        # we temporarily skip to calculate the gap for these problems\n        optimal_cost = int(matches[0])\n        gap = (cost - optimal_cost) / optimal_cost\n        print(f'Problem: {problem_files[problem_idx][:-4]}\\t Cost: {cost}\\t Optimal Cost: {optimal_cost}\\t Gap: {gap:.2%}')\n    except:\n        continue\n    finally:\n        print(f'problem: {problem_files[problem_idx][:-4]}\\t cost: {cost}\\t')\n
# problem_files = problem_files_full # if you want to test on all the problems problem_files = problem_files_custom # if you want to test on the customized problems # Parameters for sampling num_samples = 100 softmax_temp = 0.05 for problem_idx in range(len(problem_files)): problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx])) # NOTE: in some problem files (e.g. hk48), the node coordinates are not available # we temporarily skip these problems if not len(problem.node_coords): continue # Load the node coordinates coords = [] for _, v in problem.node_coords.items(): coords.append(v) coords = torch.tensor(coords).float().to(device) # [n, 2] coords_norm = normalize_coord(coords) # Prepare the tensordict batch_size = 2 td = env.reset(batch_size=(batch_size,)).to(device) td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2) td['action_mask'] = torch.ones(batch_size, coords_norm.shape[0], dtype=torch.bool) # Sampling td = batchify(td, num_samples) # Get the solution from the policy with torch.no_grad(): out = policy( td.clone(), decode_type=\"sampling\", return_actions=True, num_starts=0, softmax_temp=softmax_temp ) # Calculate the cost on the original scale coords_repeat = repeat(coords, 'n d -> b n d', b=batch_size, d=2) td['locs'] = batchify(coords_repeat, num_samples) reward = env.get_reward(td, out['actions']) reward = unbatchify(reward, num_samples) cost = ceil(-1 * torch.max(reward).item()) # Check if there exists an optimal solution try: # Load the optimal solution solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour')) matches = re.findall(r'\\((.*?)\\)', solution.comment) # NOTE: in some problem solution file (e.g. ch130), the optimal cost is not writen with a brace # we temporarily skip to calculate the gap for these problems optimal_cost = int(matches[0]) gap = (cost - optimal_cost) / optimal_cost print(f'Problem: {problem_files[problem_idx][:-4]}\\t Cost: {cost}\\t Optimal Cost: {optimal_cost}\\t Gap: {gap:.2%}') except: continue finally: print(f'problem: {problem_files[problem_idx][:-4]}\\t cost: {cost}\\t')
/tmp/ipykernel_3883036/2154301274.py:9: DeprecationWarning: Call to deprecated function (or staticmethod) load_problem. (Will be removed in newer versions. Use `tsplib95.load` instead.) -- Deprecated since version 7.0.0.\n  problem = load_problem(os.path.join(tsplib_dir, problem_files[problem_idx]))\n/tmp/ipykernel_3883036/2154301274.py:53: DeprecationWarning: Call to deprecated function (or staticmethod) load_solution. (Will be removed in newer versions. Use `tsplib95.load` instead.) -- Deprecated since version 7.0.0.\n  solution = load_solution(os.path.join(tsplib_dir, problem_files[problem_idx][:-4] + '.opt.tour'))\n
Problem: eil51\t Cost: 482\t Optimal Cost: 426\t Gap: 13.15%\nproblem: eil51\t cost: 482\t\nproblem: berlin52\t cost: 8955\t\nProblem: st70\t Cost: 794\t Optimal Cost: 675\t Gap: 17.63%\nproblem: st70\t cost: 794\t\nProblem: eil76\t Cost: 673\t Optimal Cost: 538\t Gap: 25.09%\nproblem: eil76\t cost: 673\t\nProblem: pr76\t Cost: 127046\t Optimal Cost: 108159\t Gap: 17.46%\nproblem: pr76\t cost: 127046\t\nproblem: rat99\t cost: 1886\t\nProblem: kroA100\t Cost: 29517\t Optimal Cost: 21282\t Gap: 38.69%\nproblem: kroA100\t cost: 29517\t\nproblem: kroB100\t cost: 28892\t\nProblem: kroC100\t Cost: 26697\t Optimal Cost: 20749\t Gap: 28.67%\nproblem: kroC100\t cost: 26697\t\nProblem: kroD100\t Cost: 27122\t Optimal Cost: 21294\t Gap: 27.37%\nproblem: kroD100\t cost: 27122\t\nproblem: kroE100\t cost: 28016\t\nProblem: rd100\t Cost: 10424\t Optimal Cost: 7910\t Gap: 31.78%\nproblem: rd100\t cost: 10424\t\nproblem: eil101\t cost: 837\t\nProblem: lin105\t Cost: 19618\t Optimal Cost: 14379\t Gap: 36.44%\nproblem: lin105\t cost: 19618\t\nproblem: pr124\t cost: 74699\t\nproblem: bier127\t cost: 170255\t\nproblem: ch130\t cost: 7985\t\nproblem: pr136\t cost: 129964\t\nproblem: pr144\t cost: 70477\t\nproblem: kroA150\t cost: 37185\t\nproblem: kroB150\t cost: 35172\t\nproblem: pr152\t cost: 97244\t\nproblem: u159\t cost: 59792\t\nproblem: rat195\t cost: 4325\t\nproblem: kroA200\t cost: 42059\t\nproblem: ts225\t cost: 205982\t\nProblem: tsp225\t Cost: 5970\t Optimal Cost: 3919\t Gap: 52.33%\nproblem: tsp225\t cost: 5970\t\nproblem: pr226\t cost: 103135\t\n
"},{"location":"examples/datasets/1-test-on-tsplib/#test-model-on-tsplib","title":"Test Model on TSPLib\u00b6","text":"

In this notebook, we will test the trained model's performance on the TSPLib benchmark. We will use the trained model from the previous notebook.

TSPLib is a library of sample instances for the TSP (and related problems) from various sources and of various types. In the TSPLib, there are several problems, including TSP, HCP, ATSP, etc. In this notebook, we will focus on testing the model on the TSP problem.

"},{"location":"examples/datasets/1-test-on-tsplib/#before-we-start","title":"Before we start\u00b6","text":"

Before we test the model on TSPLib dataset, we need to prepare the dataset first by the following steps:

Step 1. You may come to here to download the symmetric traveling salesman problem data in TSPLib dataset and unzip to a folder;

Note that the downloaded data is gzip file with the following file tree:

.\n\u2514\u2500\u2500 ALL_tsp/\n    \u251c\u2500\u2500 a280.opt.tour.gz\n    \u251c\u2500\u2500 a280.tsp.gz\n    \u251c\u2500\u2500 ali535.tsp.gz\n    \u2514\u2500\u2500 ... (other problems)\n

We need to unzip the gzip file to get the .tsp and .opt.tour files. We can use the following command to unzip them to the same folder:

find . -name \"*.gz\" -exec gunzip {} +\n

After doing this, we will get the following file tree:

.\n\u2514\u2500\u2500 ALL_tsp/\n    \u251c\u2500\u2500 a280.opt.tour\n    \u251c\u2500\u2500 a280.tsp\n    \u251c\u2500\u2500 ali535.tsp\n    \u2514\u2500\u2500 ... (other problems)\n

Step 2. To read the TSPLib problem and optimal solution, we choose to use the tsplib95 package. Use pip install tsplib95 to install the package.

"},{"location":"examples/datasets/1-test-on-tsplib/#installation","title":"Installation\u00b6","text":"

Uncomment the following line to install the package from PyPI. Remember to choose a GPU runtime for faster training!

Note: You may need to restart the runtime in Colab after this

"},{"location":"examples/datasets/1-test-on-tsplib/#imports","title":"Imports\u00b6","text":""},{"location":"examples/datasets/1-test-on-tsplib/#load-a-trained-model","title":"Load a trained model\u00b6","text":""},{"location":"examples/datasets/1-test-on-tsplib/#load-tsp-problems","title":"Load tsp problems\u00b6","text":"

Note that in the TSPLib, only part of the problems have optimal solutions with the same problem name but with .opt.tour suffix. For example, a280.tsp has the optimal solution a280.opt.tour.

"},{"location":"examples/datasets/1-test-on-tsplib/#test-the-greedy","title":"Test the greedy\u00b6","text":"

Note that run all experiments will take long time and require large VRAM. For simple testing, we can use a subset of the problems.

"},{"location":"examples/datasets/1-test-on-tsplib/#test-the-augmentation","title":"Test the Augmentation\u00b6","text":""},{"location":"examples/datasets/1-test-on-tsplib/#test-the-sampling","title":"Test the Sampling\u00b6","text":""},{"location":"examples/datasets/2-test-on-cvrplib/","title":"Test Model on VRPLib","text":"In\u00a0[\u00a0]: Copied!
# !pip install rl4co[graph] # include torch-geometric\n\n## NOTE: to install latest version from Github (may be unstable) install from source instead:\n# !pip install git+https://github.com/ai4co/rl4co.git\n
# !pip install rl4co[graph] # include torch-geometric ## NOTE: to install latest version from Github (may be unstable) install from source instead: # !pip install git+https://github.com/ai4co/rl4co.git In\u00a0[\u00a0]: Copied!
# Install the `tsplib95` package\n# !pip install vrplib\n
# Install the `tsplib95` package # !pip install vrplib In\u00a0[8]: Copied!
%load_ext autoreload\n%autoreload 2\n\nimport os\nimport re\nimport torch\nimport vrplib\n\nfrom rl4co.envs import TSPEnv, CVRPEnv\nfrom rl4co.models.zoo.am import AttentionModel\nfrom rl4co.utils.trainer import RL4COTrainer\nfrom rl4co.utils.decoding import get_log_likelihood\nfrom rl4co.models.zoo import EAS, EASLay, EASEmb, ActiveSearch\n\nfrom tqdm import tqdm\nfrom math import ceil\nfrom einops import repeat\n
%load_ext autoreload %autoreload 2 import os import re import torch import vrplib from rl4co.envs import TSPEnv, CVRPEnv from rl4co.models.zoo.am import AttentionModel from rl4co.utils.trainer import RL4COTrainer from rl4co.utils.decoding import get_log_likelihood from rl4co.models.zoo import EAS, EASLay, EASEmb, ActiveSearch from tqdm import tqdm from math import ceil from einops import repeat
The autoreload extension is already loaded. To reload it, use:\n  %reload_ext autoreload\n
In\u00a0[15]: Copied!
# Load from checkpoint; alternatively, simply instantiate a new model\n# Note the model is trained for CVRP problem\ncheckpoint_path = \"../cvrp-20.ckpt\" # modify the path to your checkpoint file\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# load checkpoint\n# checkpoint = torch.load(checkpoint_path)\n\nlit_model = AttentionModel.load_from_checkpoint(checkpoint_path, load_baseline=False)\npolicy, env = lit_model.policy, lit_model.env\npolicy = policy.to(device)\n
# Load from checkpoint; alternatively, simply instantiate a new model # Note the model is trained for CVRP problem checkpoint_path = \"../cvrp-20.ckpt\" # modify the path to your checkpoint file device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\") # load checkpoint # checkpoint = torch.load(checkpoint_path) lit_model = AttentionModel.load_from_checkpoint(checkpoint_path, load_baseline=False) policy, env = lit_model.policy, lit_model.env policy = policy.to(device)
/home/cbhua/miniconda3/envs/rl4co-user/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n/home/cbhua/miniconda3/envs/rl4co-user/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n/home/cbhua/miniconda3/envs/rl4co-user/lib/python3.10/site-packages/lightning/pytorch/core/saving.py:177: Found keys that are not in the model state dict but in the checkpoint: ['baseline.baseline.model.encoder.init_embedding.init_embed.weight', 'baseline.baseline.model.encoder.init_embedding.init_embed.bias', 'baseline.baseline.model.encoder.init_embedding.init_embed_depot.weight', 'baseline.baseline.model.encoder.init_embedding.init_embed_depot.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.num_batches_tracked', 'baseline.baseline.model.decoder.context_embedding.project_context.weight', 'baseline.baseline.model.decoder.project_node_embeddings.weight', 'baseline.baseline.model.decoder.project_fixed_context.weight', 'baseline.baseline.model.decoder.logit_attention.project_out.weight']\n
In\u00a0[11]: Copied!
problem_names = vrplib.list_names(low=50, high=200, vrp_type='cvrp') \n\ninstances = [] # Collect Set A, B, E, F, M datasets\nfor name in problem_names:\n    if 'A' in name:\n        instances.append(name)\n    elif 'B' in name:\n        instances.append(name)\n    elif 'E' in name:\n        instances.append(name)\n    elif 'F' in name:\n        instances.append(name)\n    elif 'M' in name and 'CMT' not in name:\n        instances.append(name)\n\n# Modify the path you want to save \n# Note: we don't have to create this folder in advance\npath_to_save = './vrplib/' \n\ntry:\n    os.makedirs(path_to_save)\n    for instance in tqdm(instances):\n        vrplib.download_instance(instance, path_to_save)\n        vrplib.download_solution(instance, path_to_save)\nexcept: # already exist\n    pass\n
problem_names = vrplib.list_names(low=50, high=200, vrp_type='cvrp') instances = [] # Collect Set A, B, E, F, M datasets for name in problem_names: if 'A' in name: instances.append(name) elif 'B' in name: instances.append(name) elif 'E' in name: instances.append(name) elif 'F' in name: instances.append(name) elif 'M' in name and 'CMT' not in name: instances.append(name) # Modify the path you want to save # Note: we don't have to create this folder in advance path_to_save = './vrplib/' try: os.makedirs(path_to_save) for instance in tqdm(instances): vrplib.download_instance(instance, path_to_save) vrplib.download_solution(instance, path_to_save) except: # already exist pass
  0%|          | 0/37 [00:00<?, ?it/s]
100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 37/37 [00:42<00:00,  1.16s/it]\n
In\u00a0[12]: Copied!
# Utils function\ndef normalize_coord(coord:torch.Tensor) -> torch.Tensor:\n    x, y = coord[:, 0], coord[:, 1]\n    x_min, x_max = x.min(), x.max()\n    y_min, y_max = y.min(), y.max()\n    \n    x_scaled = (x - x_min) / (x_max - x_min) \n    y_scaled = (y - y_min) / (y_max - y_min)\n    coord_scaled = torch.stack([x_scaled, y_scaled], dim=1)\n    return coord_scaled\n
# Utils function def normalize_coord(coord:torch.Tensor) -> torch.Tensor: x, y = coord[:, 0], coord[:, 1] x_min, x_max = x.min(), x.max() y_min, y_max = y.min(), y.max() x_scaled = (x - x_min) / (x_max - x_min) y_scaled = (y - y_min) / (y_max - y_min) coord_scaled = torch.stack([x_scaled, y_scaled], dim=1) return coord_scaled In\u00a0[18]: Copied!
for instance in instances:\n    problem = vrplib.read_instance(os.path.join(path_to_save, instance+'.vrp'))\n\n    coords = torch.tensor(problem['node_coord']).float()\n    coords_norm = normalize_coord(coords)\n    demand = torch.tensor(problem['demand'][1:]).float()\n    capacity = problem['capacity']\n    n = coords.shape[0]\n\n    # Prepare the tensordict\n    batch_size = 2\n    td = env.reset(batch_size=(batch_size,)).to(device)\n    td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2)\n    td['demand'] = repeat(demand, 'n -> b n', b=batch_size) / capacity\n    td['visited'] = torch.zeros((batch_size, 1, n), dtype=torch.uint8)\n    action_mask = torch.ones(batch_size, n, dtype=torch.bool)\n    action_mask[:, 0] = False\n    td['action_mask']  = action_mask\n\n    # Get the solution from the policy\n    with torch.no_grad():\n        out = policy(td.clone(), decode_type='greedy', return_actions=True)\n\n    # Calculate the cost on the original scale\n    td['locs'] = repeat(coords, 'n d -> b n d', b=batch_size, d=2)\n    neg_reward = env.get_reward(td, out['actions'])\n    cost = ceil(-1 * neg_reward[0].item())\n\n    # Load the optimal cost\n    solution = vrplib.read_solution(os.path.join(path_to_save, instance+'.sol'))\n    optimal_cost = solution['cost']\n\n    # Calculate the gap and print\n    gap = (cost - optimal_cost) / optimal_cost\n    print(f'Problem: {instance:<15} Cost: {cost:<10} Optimal Cost: {optimal_cost:<10}\\t Gap: {gap:.2%}')\n
for instance in instances: problem = vrplib.read_instance(os.path.join(path_to_save, instance+'.vrp')) coords = torch.tensor(problem['node_coord']).float() coords_norm = normalize_coord(coords) demand = torch.tensor(problem['demand'][1:]).float() capacity = problem['capacity'] n = coords.shape[0] # Prepare the tensordict batch_size = 2 td = env.reset(batch_size=(batch_size,)).to(device) td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2) td['demand'] = repeat(demand, 'n -> b n', b=batch_size) / capacity td['visited'] = torch.zeros((batch_size, 1, n), dtype=torch.uint8) action_mask = torch.ones(batch_size, n, dtype=torch.bool) action_mask[:, 0] = False td['action_mask'] = action_mask # Get the solution from the policy with torch.no_grad(): out = policy(td.clone(), decode_type='greedy', return_actions=True) # Calculate the cost on the original scale td['locs'] = repeat(coords, 'n d -> b n d', b=batch_size, d=2) neg_reward = env.get_reward(td, out['actions']) cost = ceil(-1 * neg_reward[0].item()) # Load the optimal cost solution = vrplib.read_solution(os.path.join(path_to_save, instance+'.sol')) optimal_cost = solution['cost'] # Calculate the gap and print gap = (cost - optimal_cost) / optimal_cost print(f'Problem: {instance:<15} Cost: {cost:<10} Optimal Cost: {optimal_cost:<10}\\t Gap: {gap:.2%}')
Problem: A-n53-k7        Cost: 1371       Optimal Cost: 1010      \t Gap: 35.74%\nProblem: A-n54-k7        Cost: 1426       Optimal Cost: 1167      \t Gap: 22.19%\nProblem: A-n55-k9        Cost: 1333       Optimal Cost: 1073      \t Gap: 24.23%\nProblem: A-n60-k9        Cost: 1728       Optimal Cost: 1354      \t Gap: 27.62%\nProblem: A-n61-k9        Cost: 1297       Optimal Cost: 1034      \t Gap: 25.44%\nProblem: A-n62-k8        Cost: 1818       Optimal Cost: 1288      \t Gap: 41.15%\nProblem: A-n63-k9        Cost: 2166       Optimal Cost: 1616      \t Gap: 34.03%\nProblem: A-n63-k10       Cost: 1698       Optimal Cost: 1314      \t Gap: 29.22%\nProblem: A-n64-k9        Cost: 1805       Optimal Cost: 1401      \t Gap: 28.84%\nProblem: A-n65-k9        Cost: 1592       Optimal Cost: 1174      \t Gap: 35.60%\nProblem: A-n69-k9        Cost: 1641       Optimal Cost: 1159      \t Gap: 41.59%\nProblem: A-n80-k10       Cost: 2230       Optimal Cost: 1763      \t Gap: 26.49%\nProblem: B-n51-k7        Cost: 1270       Optimal Cost: 1032      \t Gap: 23.06%\nProblem: B-n52-k7        Cost: 994        Optimal Cost: 747       \t Gap: 33.07%\nProblem: B-n56-k7        Cost: 931        Optimal Cost: 707       \t Gap: 31.68%\nProblem: B-n57-k7        Cost: 1422       Optimal Cost: 1153      \t Gap: 23.33%\nProblem: B-n57-k9        Cost: 1889       Optimal Cost: 1598      \t Gap: 18.21%\nProblem: B-n63-k10       Cost: 1807       Optimal Cost: 1496      \t Gap: 20.79%\nProblem: B-n64-k9        Cost: 1150       Optimal Cost: 861       \t Gap: 33.57%\nProblem: B-n66-k9        Cost: 1746       Optimal Cost: 1316      \t Gap: 32.67%\nProblem: B-n67-k10       Cost: 1368       Optimal Cost: 1032      \t Gap: 32.56%\nProblem: B-n68-k9        Cost: 1737       Optimal Cost: 1272      \t Gap: 36.56%\nProblem: B-n78-k10       Cost: 1706       Optimal Cost: 1221      \t Gap: 39.72%\nProblem: E-n51-k5        Cost: 690        Optimal Cost: 521       \t Gap: 32.44%\nProblem: E-n76-k7        Cost: 1019       Optimal Cost: 682       \t Gap: 49.41%\nProblem: E-n76-k8        Cost: 1031       Optimal Cost: 735       \t Gap: 40.27%\nProblem: E-n76-k10       Cost: 1156       Optimal Cost: 830       \t Gap: 39.28%\nProblem: E-n76-k14       Cost: 1335       Optimal Cost: 1021      \t Gap: 30.75%\nProblem: E-n101-k8       Cost: 1265       Optimal Cost: 815       \t Gap: 55.21%\nProblem: E-n101-k14      Cost: 1567       Optimal Cost: 1067      \t Gap: 46.86%\nProblem: F-n72-k4        Cost: 425        Optimal Cost: 237       \t Gap: 79.32%\nProblem: F-n135-k7       Cost: 4219       Optimal Cost: 1162      \t Gap: 263.08%\nProblem: M-n101-k10      Cost: 1388       Optimal Cost: 820       \t Gap: 69.27%\nProblem: M-n121-k7       Cost: 1746       Optimal Cost: 1034      \t Gap: 68.86%\nProblem: M-n151-k12      Cost: 1906       Optimal Cost: 1015      \t Gap: 87.78%\nProblem: M-n200-k16      Cost: 2509       Optimal Cost: 1274      \t Gap: 96.94%\nProblem: M-n200-k17      Cost: 2339       Optimal Cost: 1275      \t Gap: 83.45%\n
In\u00a0[20]: Copied!
# Import augmented utils\nfrom rl4co.data.transforms import (\n    StateAugmentation as SymmetricStateAugmentation)\nfrom rl4co.utils.ops import batchify, unbatchify\n\nnum_augment = 100\naugmentation = SymmetricStateAugmentation(num_augment=num_augment)\n\nfor instance in instances:\n    problem = vrplib.read_instance(os.path.join(path_to_save, instance+'.vrp'))\n\n    coords = torch.tensor(problem['node_coord']).float()\n    coords_norm = normalize_coord(coords)\n    demand = torch.tensor(problem['demand'][1:]).float()\n    capacity = problem['capacity']\n    n = coords.shape[0]\n\n    # Prepare the tensordict\n    batch_size = 2\n    td = env.reset(batch_size=(batch_size,)).to(device)\n    td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2)\n    td['demand'] = repeat(demand, 'n -> b n', b=batch_size) / capacity\n    td['visited'] = torch.zeros((batch_size, 1, n), dtype=torch.uint8)\n    action_mask = torch.ones(batch_size, n, dtype=torch.bool)\n    action_mask[:, 0] = False\n    td['action_mask']  = action_mask\n    \n    # Augmentation\n    td = augmentation(td)\n\n    # Get the solution from the policy\n    with torch.no_grad():\n        out = policy(\n            td.clone(), decode_type='greedy', num_starts=0, return_actions=True\n        )\n\n    # Calculate the cost on the original scale\n    coords_repeat = repeat(coords, 'n d -> b n d', b=batch_size, d=2)\n    td['locs'] = batchify(coords_repeat, num_augment)\n    reward = env.get_reward(td, out['actions'])\n    reward = unbatchify(reward, num_augment)\n    cost = ceil(-1 * torch.max(reward).item())\n\n    # Load the optimal cost\n    solution = vrplib.read_solution(os.path.join(path_to_save, instance+'.sol'))\n    optimal_cost = solution['cost']\n\n    # Calculate the gap and print\n    gap = (cost - optimal_cost) / optimal_cost\n    print(f'Problem: {instance:<15} Cost: {cost:<10} Optimal Cost: {optimal_cost:<10}\\t Gap: {gap:.2%}')\n
# Import augmented utils from rl4co.data.transforms import ( StateAugmentation as SymmetricStateAugmentation) from rl4co.utils.ops import batchify, unbatchify num_augment = 100 augmentation = SymmetricStateAugmentation(num_augment=num_augment) for instance in instances: problem = vrplib.read_instance(os.path.join(path_to_save, instance+'.vrp')) coords = torch.tensor(problem['node_coord']).float() coords_norm = normalize_coord(coords) demand = torch.tensor(problem['demand'][1:]).float() capacity = problem['capacity'] n = coords.shape[0] # Prepare the tensordict batch_size = 2 td = env.reset(batch_size=(batch_size,)).to(device) td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2) td['demand'] = repeat(demand, 'n -> b n', b=batch_size) / capacity td['visited'] = torch.zeros((batch_size, 1, n), dtype=torch.uint8) action_mask = torch.ones(batch_size, n, dtype=torch.bool) action_mask[:, 0] = False td['action_mask'] = action_mask # Augmentation td = augmentation(td) # Get the solution from the policy with torch.no_grad(): out = policy( td.clone(), decode_type='greedy', num_starts=0, return_actions=True ) # Calculate the cost on the original scale coords_repeat = repeat(coords, 'n d -> b n d', b=batch_size, d=2) td['locs'] = batchify(coords_repeat, num_augment) reward = env.get_reward(td, out['actions']) reward = unbatchify(reward, num_augment) cost = ceil(-1 * torch.max(reward).item()) # Load the optimal cost solution = vrplib.read_solution(os.path.join(path_to_save, instance+'.sol')) optimal_cost = solution['cost'] # Calculate the gap and print gap = (cost - optimal_cost) / optimal_cost print(f'Problem: {instance:<15} Cost: {cost:<10} Optimal Cost: {optimal_cost:<10}\\t Gap: {gap:.2%}')
Problem: A-n53-k7        Cost: 1123       Optimal Cost: 1010      \t Gap: 11.19%\nProblem: A-n54-k7        Cost: 1305       Optimal Cost: 1167      \t Gap: 11.83%\nProblem: A-n55-k9        Cost: 1199       Optimal Cost: 1073      \t Gap: 11.74%\nProblem: A-n60-k9        Cost: 1534       Optimal Cost: 1354      \t Gap: 13.29%\nProblem: A-n61-k9        Cost: 1187       Optimal Cost: 1034      \t Gap: 14.80%\nProblem: A-n62-k8        Cost: 1474       Optimal Cost: 1288      \t Gap: 14.44%\nProblem: A-n63-k9        Cost: 1820       Optimal Cost: 1616      \t Gap: 12.62%\nProblem: A-n63-k10       Cost: 1505       Optimal Cost: 1314      \t Gap: 14.54%\nProblem: A-n64-k9        Cost: 1582       Optimal Cost: 1401      \t Gap: 12.92%\nProblem: A-n65-k9        Cost: 1332       Optimal Cost: 1174      \t Gap: 13.46%\nProblem: A-n69-k9        Cost: 1305       Optimal Cost: 1159      \t Gap: 12.60%\nProblem: A-n80-k10       Cost: 2044       Optimal Cost: 1763      \t Gap: 15.94%\nProblem: B-n51-k7        Cost: 1073       Optimal Cost: 1032      \t Gap: 3.97%\nProblem: B-n52-k7        Cost: 815        Optimal Cost: 747       \t Gap: 9.10%\nProblem: B-n56-k7        Cost: 792        Optimal Cost: 707       \t Gap: 12.02%\nProblem: B-n57-k7        Cost: 1219       Optimal Cost: 1153      \t Gap: 5.72%\nProblem: B-n57-k9        Cost: 1744       Optimal Cost: 1598      \t Gap: 9.14%\nProblem: B-n63-k10       Cost: 1611       Optimal Cost: 1496      \t Gap: 7.69%\nProblem: B-n64-k9        Cost: 931        Optimal Cost: 861       \t Gap: 8.13%\nProblem: B-n66-k9        Cost: 1427       Optimal Cost: 1316      \t Gap: 8.43%\nProblem: B-n67-k10       Cost: 1122       Optimal Cost: 1032      \t Gap: 8.72%\nProblem: B-n68-k9        Cost: 1382       Optimal Cost: 1272      \t Gap: 8.65%\nProblem: B-n78-k10       Cost: 1437       Optimal Cost: 1221      \t Gap: 17.69%\nProblem: E-n51-k5        Cost: 606        Optimal Cost: 521       \t Gap: 16.31%\nProblem: E-n76-k7        Cost: 816        Optimal Cost: 682       \t Gap: 19.65%\nProblem: E-n76-k8        Cost: 892        Optimal Cost: 735       \t Gap: 21.36%\nProblem: E-n76-k10       Cost: 943        Optimal Cost: 830       \t Gap: 13.61%\nProblem: E-n76-k14       Cost: 1160       Optimal Cost: 1021      \t Gap: 13.61%\nProblem: E-n101-k8       Cost: 1042       Optimal Cost: 815       \t Gap: 27.85%\nProblem: E-n101-k14      Cost: 1302       Optimal Cost: 1067      \t Gap: 22.02%\nProblem: F-n72-k4        Cost: 286        Optimal Cost: 237       \t Gap: 20.68%\nProblem: F-n135-k7       Cost: 1570       Optimal Cost: 1162      \t Gap: 35.11%\nProblem: M-n101-k10      Cost: 1037       Optimal Cost: 820       \t Gap: 26.46%\nProblem: M-n121-k7       Cost: 1283       Optimal Cost: 1034      \t Gap: 24.08%\nProblem: M-n151-k12      Cost: 1407       Optimal Cost: 1015      \t Gap: 38.62%\nProblem: M-n200-k16      Cost: 1811       Optimal Cost: 1274      \t Gap: 42.15%\nProblem: M-n200-k17      Cost: 1812       Optimal Cost: 1275      \t Gap: 42.12%\n
In\u00a0[21]: Copied!
# Parameters for sampling\nnum_samples = 100\nsoftmax_temp = 0.05\n\nfor instance in instances:\n    problem = vrplib.read_instance(os.path.join(path_to_save, instance+'.vrp'))\n\n    coords = torch.tensor(problem['node_coord']).float()\n    coords_norm = normalize_coord(coords)\n    demand = torch.tensor(problem['demand'][1:]).float()\n    capacity = problem['capacity']\n    n = coords.shape[0]\n\n    # Prepare the tensordict\n    batch_size = 2\n    td = env.reset(batch_size=(batch_size,)).to(device)\n    td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2)\n    td['demand'] = repeat(demand, 'n -> b n', b=batch_size) / capacity\n    td['visited'] = torch.zeros((batch_size, 1, n), dtype=torch.uint8)\n    action_mask = torch.ones(batch_size, n, dtype=torch.bool)\n    action_mask[:, 0] = False\n    td['action_mask']  = action_mask\n    \n    # Sampling\n    td = batchify(td, num_samples)\n\n    # Get the solution from the policy\n    with torch.no_grad():\n        out = policy(\n            td.clone(), decode_type='sampling', num_starts=0, return_actions=True\n        )\n\n    # Calculate the cost on the original scale\n    coords_repeat = repeat(coords, 'n d -> b n d', b=batch_size, d=2)\n    td['locs'] = batchify(coords_repeat, num_samples)\n    reward = env.get_reward(td, out['actions'])\n    reward = unbatchify(reward, num_samples)\n    cost = ceil(-1 * torch.max(reward).item())\n\n    # Load the optimal cost\n    solution = vrplib.read_solution(os.path.join(path_to_save, instance+'.sol'))\n    optimal_cost = solution['cost']\n\n    # Calculate the gap and print\n    gap = (cost - optimal_cost) / optimal_cost\n    print(f'Problem: {instance:<15} Cost: {cost:<10} Optimal Cost: {optimal_cost:<10}\\t Gap: {gap:.2%}')\n
# Parameters for sampling num_samples = 100 softmax_temp = 0.05 for instance in instances: problem = vrplib.read_instance(os.path.join(path_to_save, instance+'.vrp')) coords = torch.tensor(problem['node_coord']).float() coords_norm = normalize_coord(coords) demand = torch.tensor(problem['demand'][1:]).float() capacity = problem['capacity'] n = coords.shape[0] # Prepare the tensordict batch_size = 2 td = env.reset(batch_size=(batch_size,)).to(device) td['locs'] = repeat(coords_norm, 'n d -> b n d', b=batch_size, d=2) td['demand'] = repeat(demand, 'n -> b n', b=batch_size) / capacity td['visited'] = torch.zeros((batch_size, 1, n), dtype=torch.uint8) action_mask = torch.ones(batch_size, n, dtype=torch.bool) action_mask[:, 0] = False td['action_mask'] = action_mask # Sampling td = batchify(td, num_samples) # Get the solution from the policy with torch.no_grad(): out = policy( td.clone(), decode_type='sampling', num_starts=0, return_actions=True ) # Calculate the cost on the original scale coords_repeat = repeat(coords, 'n d -> b n d', b=batch_size, d=2) td['locs'] = batchify(coords_repeat, num_samples) reward = env.get_reward(td, out['actions']) reward = unbatchify(reward, num_samples) cost = ceil(-1 * torch.max(reward).item()) # Load the optimal cost solution = vrplib.read_solution(os.path.join(path_to_save, instance+'.sol')) optimal_cost = solution['cost'] # Calculate the gap and print gap = (cost - optimal_cost) / optimal_cost print(f'Problem: {instance:<15} Cost: {cost:<10} Optimal Cost: {optimal_cost:<10}\\t Gap: {gap:.2%}')
Problem: A-n53-k7        Cost: 1191       Optimal Cost: 1010      \t Gap: 17.92%\nProblem: A-n54-k7        Cost: 1328       Optimal Cost: 1167      \t Gap: 13.80%\nProblem: A-n55-k9        Cost: 1286       Optimal Cost: 1073      \t Gap: 19.85%\nProblem: A-n60-k9        Cost: 1631       Optimal Cost: 1354      \t Gap: 20.46%\nProblem: A-n61-k9        Cost: 1230       Optimal Cost: 1034      \t Gap: 18.96%\nProblem: A-n62-k8        Cost: 1505       Optimal Cost: 1288      \t Gap: 16.85%\nProblem: A-n63-k9        Cost: 1840       Optimal Cost: 1616      \t Gap: 13.86%\nProblem: A-n63-k10       Cost: 1590       Optimal Cost: 1314      \t Gap: 21.00%\nProblem: A-n64-k9        Cost: 1643       Optimal Cost: 1401      \t Gap: 17.27%\nProblem: A-n65-k9        Cost: 1381       Optimal Cost: 1174      \t Gap: 17.63%\nProblem: A-n69-k9        Cost: 1451       Optimal Cost: 1159      \t Gap: 25.19%\nProblem: A-n80-k10       Cost: 2170       Optimal Cost: 1763      \t Gap: 23.09%\nProblem: B-n51-k7        Cost: 1187       Optimal Cost: 1032      \t Gap: 15.02%\nProblem: B-n52-k7        Cost: 884        Optimal Cost: 747       \t Gap: 18.34%\nProblem: B-n56-k7        Cost: 853        Optimal Cost: 707       \t Gap: 20.65%\nProblem: B-n57-k7        Cost: 1314       Optimal Cost: 1153      \t Gap: 13.96%\nProblem: B-n57-k9        Cost: 1744       Optimal Cost: 1598      \t Gap: 9.14%\nProblem: B-n63-k10       Cost: 1698       Optimal Cost: 1496      \t Gap: 13.50%\nProblem: B-n64-k9        Cost: 1045       Optimal Cost: 861       \t Gap: 21.37%\nProblem: B-n66-k9        Cost: 1506       Optimal Cost: 1316      \t Gap: 14.44%\nProblem: B-n67-k10       Cost: 1254       Optimal Cost: 1032      \t Gap: 21.51%\nProblem: B-n68-k9        Cost: 1510       Optimal Cost: 1272      \t Gap: 18.71%\nProblem: B-n78-k10       Cost: 1514       Optimal Cost: 1221      \t Gap: 24.00%\nProblem: E-n51-k5        Cost: 613        Optimal Cost: 521       \t Gap: 17.66%\nProblem: E-n76-k7        Cost: 882        Optimal Cost: 682       \t Gap: 29.33%\nProblem: E-n76-k8        Cost: 952        Optimal Cost: 735       \t Gap: 29.52%\nProblem: E-n76-k10       Cost: 1015       Optimal Cost: 830       \t Gap: 22.29%\nProblem: E-n76-k14       Cost: 1185       Optimal Cost: 1021      \t Gap: 16.06%\nProblem: E-n101-k8       Cost: 1189       Optimal Cost: 815       \t Gap: 45.89%\nProblem: E-n101-k14      Cost: 1420       Optimal Cost: 1067      \t Gap: 33.08%\nProblem: F-n72-k4        Cost: 344        Optimal Cost: 237       \t Gap: 45.15%\nProblem: F-n135-k7       Cost: 3130       Optimal Cost: 1162      \t Gap: 169.36%\nProblem: M-n101-k10      Cost: 1221       Optimal Cost: 820       \t Gap: 48.90%\nProblem: M-n121-k7       Cost: 1538       Optimal Cost: 1034      \t Gap: 48.74%\nProblem: M-n151-k12      Cost: 1688       Optimal Cost: 1015      \t Gap: 66.31%\nProblem: M-n200-k16      Cost: 2252       Optimal Cost: 1274      \t Gap: 76.77%\nProblem: M-n200-k17      Cost: 2260       Optimal Cost: 1275      \t Gap: 77.25%\n
"},{"location":"examples/datasets/2-test-on-cvrplib/#test-model-on-vrplib","title":"Test Model on VRPLib\u00b6","text":"

In this notebook, we will test the trained model's performance on the VRPLib benchmark. We will use the trained model from the previous notebook.

VRPLIB is a collection of instances related to the CVRP, which is a classic optimization challenge in the field of logistics and transportation.

"},{"location":"examples/datasets/2-test-on-cvrplib/#before-we-start","title":"Before we start\u00b6","text":"

To use the VRPLib, we strongly recomment to use the Python vrplib tool:

VRPLib is a Python package for working with Vehicle Routing Problem (VRP) instances. This tool can help us easily load the VRPLib instances and visualize the results.

"},{"location":"examples/datasets/2-test-on-cvrplib/#installation","title":"Installation\u00b6","text":"

Uncomment the following line to install the package from PyPI. Remember to choose a GPU runtime for faster training!

Note: You may need to restart the runtime in Colab after this

"},{"location":"examples/datasets/2-test-on-cvrplib/#imports","title":"Imports\u00b6","text":""},{"location":"examples/datasets/2-test-on-cvrplib/#load-a-trained-model","title":"Load a trained model\u00b6","text":""},{"location":"examples/datasets/2-test-on-cvrplib/#download-vrp-problems","title":"Download vrp problems\u00b6","text":""},{"location":"examples/datasets/2-test-on-cvrplib/#test-the-greedy","title":"Test the greedy\u00b6","text":""},{"location":"examples/datasets/2-test-on-cvrplib/#test-the-augmentation","title":"Test the Augmentation\u00b6","text":""},{"location":"examples/datasets/2-test-on-cvrplib/#test-the-sampling","title":"Test the Sampling\u00b6","text":""},{"location":"examples/modeling/","title":"Modeling","text":"

Collection of examples on models and related topics.

"},{"location":"examples/modeling/#index","title":"Index","text":"
  • 1-decoding-strategies.ipynb: here we show how to use different decoding strategies at inference time, such as greedy evaluation, beam search, and various sampling methods including top-k and nucleus sampling.
  • 2-transductive-methods.ipynb: here we show how to use transductive methods (i.e. online / test time optimization) such as EAS.
  • 3-change-encoder.ipynb: here we show how to change the encoder of a model.
"},{"location":"examples/modeling/1-decoding-strategies/","title":"RL4CO Decoding Strategies Notebook","text":"In\u00a0[1]: Copied!
## Uncomment the following line to install the package from PyPI\n## You may need to restart the runtime in Colab after this\n## Remember to choose a GPU runtime for faster training!\n\n# !pip install rl4co\n
## Uncomment the following line to install the package from PyPI ## You may need to restart the runtime in Colab after this ## Remember to choose a GPU runtime for faster training! # !pip install rl4co In\u00a0[4]: Copied!
import torch\n\nfrom rl4co.envs import TSPEnv\nfrom rl4co.models.zoo import AttentionModel, AttentionModelPolicy\nfrom rl4co.utils.trainer import RL4COTrainer\nfrom rl4co.utils.ops import batchify\n
import torch from rl4co.envs import TSPEnv from rl4co.models.zoo import AttentionModel, AttentionModelPolicy from rl4co.utils.trainer import RL4COTrainer from rl4co.utils.ops import batchify In\u00a0[5]: Copied!
%%capture\n# RL4CO env based on TorchRL\nenv = TSPEnv(generator_params=dict(num_loc=50)) \n\n# Policy: neural network, in this case with encoder-decoder architecture\npolicy = AttentionModelPolicy(env_name=env.name, \n                              embed_dim=128,\n                              num_encoder_layers=3,\n                              num_heads=8,\n                            )\n\n# Model: default is AM with REINFORCE and greedy rollout baseline\nmodel = AttentionModel(env, \n                       baseline=\"rollout\",\n                       batch_size = 512,\n                       val_batch_size = 64, \n                       test_batch_size = 64, \n                       train_data_size=100_000, # fast training for demo\n                       val_data_size=1_000,\n                       test_data_size=1_000,\n                       optimizer_kwargs={\"lr\": 1e-4},\n                       policy_kwargs={  # we can specify the decode types using the policy_kwargs\n                           \"train_decode_type\": \"sampling\",\n                           \"val_decode_type\": \"greedy\",\n                           \"test_decode_type\": \"beam_search\",\n                       }\n                       )\n
%%capture # RL4CO env based on TorchRL env = TSPEnv(generator_params=dict(num_loc=50)) # Policy: neural network, in this case with encoder-decoder architecture policy = AttentionModelPolicy(env_name=env.name, embed_dim=128, num_encoder_layers=3, num_heads=8, ) # Model: default is AM with REINFORCE and greedy rollout baseline model = AttentionModel(env, baseline=\"rollout\", batch_size = 512, val_batch_size = 64, test_batch_size = 64, train_data_size=100_000, # fast training for demo val_data_size=1_000, test_data_size=1_000, optimizer_kwargs={\"lr\": 1e-4}, policy_kwargs={ # we can specify the decode types using the policy_kwargs \"train_decode_type\": \"sampling\", \"val_decode_type\": \"greedy\", \"test_decode_type\": \"beam_search\", } ) In\u00a0[4]: Copied!
trainer = RL4COTrainer(\n    max_epochs=3,\n    devices=1,\n)\n\ntrainer.fit(model)\n
trainer = RL4COTrainer( max_epochs=3, devices=1, ) trainer.fit(model)
Using 16bit Automatic Mixed Precision (AMP)\nGPU available: True (cuda), used: True\nTPU available: False, using: 0 TPU cores\nIPU available: False, using: 0 IPUs\nHPU available: False, using: 0 HPUs\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/logger_connector/logger_connector.py:75: Starting from v1.9.0, `tensorboardX` has been removed as a dependency of the `lightning.pytorch` package, due to potential conflicts with other packages in the ML ecosystem. For this reason, `logger=True` will use `CSVLogger` as the default logger, unless the `tensorboard` or `tensorboardX` packages are found. Please `pip install lightning[extra]` or one of them to enable TensorBoard support by default\nval_file not set. Generating dataset instead\ntest_file not set. Generating dataset instead\nLOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n\n  | Name     | Type                 | Params\n--------------------------------------------------\n0 | env      | TSPEnv               | 0     \n1 | policy   | AttentionModelPolicy | 710 K \n2 | baseline | WarmupBaseline       | 710 K \n--------------------------------------------------\n1.4 M     Trainable params\n0         Non-trainable params\n1.4 M     Total params\n5.681     Total estimated model params size (MB)\n
Sanity Checking: |          | 0/? [00:00<?, ?it/s]
/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'val_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=31` in the `DataLoader` to improve performance.\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'train_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=31` in the `DataLoader` to improve performance.\n
Training: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
`Trainer.fit` stopped: `max_epochs=3` reached.\n
In\u00a0[6]: Copied!
# here we evaluate the model on the test set using the beam search decoding strategy as declared in the model constructor\ntrainer.test(model=model)\n
# here we evaluate the model on the test set using the beam search decoding strategy as declared in the model constructor trainer.test(model=model) In\u00a0[9]: Copied!
# we can simply change the decoding type of the current model instance\nmodel.policy.test_decode_type = \"greedy\"\ntrainer.test(model=model)\n
# we can simply change the decoding type of the current model instance model.policy.test_decode_type = \"greedy\" trainer.test(model=model) In\u00a0[8]: Copied!
device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\ntest_td_raw = next(iter(model.test_dataloader())).to(device)\ntd_test = env.reset(test_td_raw)\nmodel = model.to(device)\n
device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\") test_td_raw = next(iter(model.test_dataloader())).to(device) td_test = env.reset(test_td_raw) model = model.to(device) In\u00a0[10]: Copied!
# Example over full dataset\nrewards = []\nfor batch in model.test_dataloader():\n    with torch.inference_mode():\n        td = env.reset(batch).to(device)\n        out = model(td, decode_type=\"greedy\")\n    rewards.append(out[\"reward\"])\nprint(\"Average reward over all dataset: %.3f\" % torch.cat(rewards).mean().item())\n\n# Example over a single instance\nwith torch.inference_mode():\n    out = model(test_td_raw.clone(), decode_type=\"greedy\")\n    print(\"Average reward: %.3f\" % out[\"reward\"].mean().item())\n
# Example over full dataset rewards = [] for batch in model.test_dataloader(): with torch.inference_mode(): td = env.reset(batch).to(device) out = model(td, decode_type=\"greedy\") rewards.append(out[\"reward\"]) print(\"Average reward over all dataset: %.3f\" % torch.cat(rewards).mean().item()) # Example over a single instance with torch.inference_mode(): out = model(test_td_raw.clone(), decode_type=\"greedy\") print(\"Average reward: %.3f\" % out[\"reward\"].mean().item())
Average reward over all dataset: -6.376\nAverage reward: -6.415\n
In\u00a0[11]: Copied!
# Example over a single instance\nwith torch.inference_mode():\n    bs = td_test.batch_size[0]\n    out = model(td_test.clone(), decode_type=\"multistart_greedy\", num_starts=20, return_actions=True)\n    rewards = torch.stack(out[\"reward\"].split(bs), 1).max(1).values\n    print(\"Average reward: %.3f\" % rewards.mean().item())\n
# Example over a single instance with torch.inference_mode(): bs = td_test.batch_size[0] out = model(td_test.clone(), decode_type=\"multistart_greedy\", num_starts=20, return_actions=True) rewards = torch.stack(out[\"reward\"].split(bs), 1).max(1).values print(\"Average reward: %.3f\" % rewards.mean().item())
Average reward: -6.279\n
In\u00a0[44]: Copied!
num_samples = 32\nwith torch.inference_mode():\n    bs = td_test.batch_size[0]\n    td_test_batched = batchify(td_test, num_samples) # repeat the same instance num_samples times\n    out = model(td_test_batched.clone(), decode_type=\"sampling\", return_actions=True)\n    rewards = torch.stack(out[\"reward\"].split(bs), 1).max(1).values # take the max reward over the num_samples samples\n    print(\"Average reward: %.3f\" % rewards.mean().item())\n
num_samples = 32 with torch.inference_mode(): bs = td_test.batch_size[0] td_test_batched = batchify(td_test, num_samples) # repeat the same instance num_samples times out = model(td_test_batched.clone(), decode_type=\"sampling\", return_actions=True) rewards = torch.stack(out[\"reward\"].split(bs), 1).max(1).values # take the max reward over the num_samples samples print(\"Average reward: %.3f\" % rewards.mean().item())
Average reward: -6.157\n
In\u00a0[75]: Copied!
num_samples = 32\ntop_p = 0.9\nwith torch.inference_mode():\n    bs = td_test.batch_size[0]\n    td_test_batched = batchify(td_test, num_samples) # repeat the same instance num_samples times\n    out = model(td_test_batched.clone(), decode_type=\"sampling\", return_actions=True, top_p=top_p)\n    rewards = torch.stack(out[\"reward\"].split(bs), 1).max(1).values # take the max reward over the num_samples samples\n    print(\"Average reward: %.3f\" % rewards.mean().item())\n
num_samples = 32 top_p = 0.9 with torch.inference_mode(): bs = td_test.batch_size[0] td_test_batched = batchify(td_test, num_samples) # repeat the same instance num_samples times out = model(td_test_batched.clone(), decode_type=\"sampling\", return_actions=True, top_p=top_p) rewards = torch.stack(out[\"reward\"].split(bs), 1).max(1).values # take the max reward over the num_samples samples print(\"Average reward: %.3f\" % rewards.mean().item())
Average reward: -6.136\n
In\u00a0[67]: Copied!
num_samples = 32\ntop_k = 10\nwith torch.inference_mode():\n    bs = td_test.batch_size[0]\n    td_test_batched = batchify(td_test, num_samples) # repeat the same instance num_samples times\n    out = model(td_test_batched.clone(), decode_type=\"sampling\", return_actions=True, top_k=top_k)\n    rewards = torch.stack(out[\"reward\"].split(bs), 1).max(1).values # take the max reward over the num_samples samples\n    print(\"Average reward: %.3f\" % rewards.mean().item())\n
num_samples = 32 top_k = 10 with torch.inference_mode(): bs = td_test.batch_size[0] td_test_batched = batchify(td_test, num_samples) # repeat the same instance num_samples times out = model(td_test_batched.clone(), decode_type=\"sampling\", return_actions=True, top_k=top_k) rewards = torch.stack(out[\"reward\"].split(bs), 1).max(1).values # take the max reward over the num_samples samples print(\"Average reward: %.3f\" % rewards.mean().item())
Average reward: -6.158\n
In\u00a0[88]: Copied!
with torch.inference_mode():\n    bs = td_test.batch_size[0]\n    out = model(td_test.clone(), decode_type=\"beam_search\", beam_width=20)\n    rewards = torch.stack(out[\"reward\"].split(bs), 1).max(1).values # take the max reward over the num_samples samples\n    print(\"Average reward: %.3f\" % rewards.mean().item())\n
with torch.inference_mode(): bs = td_test.batch_size[0] out = model(td_test.clone(), decode_type=\"beam_search\", beam_width=20) rewards = torch.stack(out[\"reward\"].split(bs), 1).max(1).values # take the max reward over the num_samples samples print(\"Average reward: %.3f\" % rewards.mean().item())
Average reward: -6.195\n

We can see that beam search finds a better solution than the greedy decoder

We can also analyze the different solutions obtained via beam search when passing \"select_best=False\" to the forward pass of the policy. The solutions in this case are sorted per instance-wise, that is:

  • instance1_solution1
  • instance2_solution1
  • instance3_solution1
  • instance1_solution2
  • instance2_solution2
  • instance3_solution2
In\u00a0[90]: Copied!
out = model(td_test.clone(), decode_type=\"beam_search\", beam_width=5, select_best=False, return_actions=True)\n
out = model(td_test.clone(), decode_type=\"beam_search\", beam_width=5, select_best=False, return_actions=True) In\u00a0[91]: Copied!
# we split the sequence ofter every \"batch_size\" instances, then stack the different solutions obtained for each minibatch instance by the beam search together.\nactions_stacked = torch.stack(out[\"actions\"].split(bs), 1)\nrewards_stacked = torch.stack(out[\"reward\"].split(bs), 1)\n
# we split the sequence ofter every \"batch_size\" instances, then stack the different solutions obtained for each minibatch instance by the beam search together. actions_stacked = torch.stack(out[\"actions\"].split(bs), 1) rewards_stacked = torch.stack(out[\"reward\"].split(bs), 1) In\u00a0[95]: Copied!
import matplotlib.pyplot as plt\nbatch_instance = 0\nfor i, actions in enumerate(actions_stacked[batch_instance].cpu()):\n    reward = rewards_stacked[batch_instance, i]\n    _, ax = plt.subplots()\n    \n    env.render(td[0], actions, ax=ax)\n    ax.set_title(\"Reward: %s\" % reward.item())\n
import matplotlib.pyplot as plt batch_instance = 0 for i, actions in enumerate(actions_stacked[batch_instance].cpu()): reward = rewards_stacked[batch_instance, i] _, ax = plt.subplots() env.render(td[0], actions, ax=ax) ax.set_title(\"Reward: %s\" % reward.item())

For evaluation, we can also use additional decoding strategies used during evaluatin, such as sampling N times or greedy augmentations, available in rl4co/tasks/eval.py

"},{"location":"examples/modeling/1-decoding-strategies/#rl4co-decoding-strategies-notebook","title":"RL4CO Decoding Strategies Notebook\u00b6","text":"

This notebook demonstrates how to utilize the different decoding strategies available in rl4co/utils/decoding.py during the different phases of model development. We will also demonstrate how to evaluate the model for different decoding strategies on the test dataset.

"},{"location":"examples/modeling/1-decoding-strategies/#installation","title":"Installation\u00b6","text":""},{"location":"examples/modeling/1-decoding-strategies/#setup-policy-and-environment","title":"Setup Policy and Environment\u00b6","text":""},{"location":"examples/modeling/1-decoding-strategies/#setup-trainer-and-train-model","title":"Setup Trainer and train model\u00b6","text":""},{"location":"examples/modeling/1-decoding-strategies/#test-the-model-using-trainer-class","title":"Test the model using Trainer class\u00b6","text":""},{"location":"examples/modeling/1-decoding-strategies/#test-loop","title":"Test Loop\u00b6","text":"

Let's compare different decoding strategies on some test samples - for simplicity, we don't loop over the entire test dataset, but only over the on a single iteration of the test dataloader.

"},{"location":"examples/modeling/1-decoding-strategies/#greedy-decoding","title":"Greedy Decoding\u00b6","text":""},{"location":"examples/modeling/1-decoding-strategies/#greedy-decoding","title":"Greedy decoding\u00b6","text":""},{"location":"examples/modeling/1-decoding-strategies/#greedy-multistart-decoding","title":"Greedy multistart decoding\u00b6","text":"

Start from different nodes as done in POMO

"},{"location":"examples/modeling/1-decoding-strategies/#sampling","title":"Sampling\u00b6","text":""},{"location":"examples/modeling/1-decoding-strategies/#decoding-via-sampling","title":"Decoding via sampling\u00b6","text":"

In this case, we can parallelize the decoding process by batching the samples and decoding them in parallel.

"},{"location":"examples/modeling/1-decoding-strategies/#top-p-sampling-nucleus-sampling","title":"Top-p sampling (nucleus sampling)\u00b6","text":"

Top-p sampling is a sampling strategy where the top-p most likely tokens are selected and the probability mass is redistributed among them. This is useful when we want to sample from a subset of the nodes and we want to exclude from the lower-end tail of the distribution.

"},{"location":"examples/modeling/1-decoding-strategies/#top-k-sampling","title":"Top-k sampling\u00b6","text":"

In this case we only sample from the top-k most likely tokens.

"},{"location":"examples/modeling/1-decoding-strategies/#beam-search","title":"Beam search\u00b6","text":"

Beam search is a popular decoding strategy in sequence-to-sequence models. It maintains a list of the top-k most likely sequences and expands them by adding the next token in the sequence. The sequences are scored based on the log-likelihood of the sequence. The sequences are expanded until the end token is reached or the maximum length is reached.

"},{"location":"examples/modeling/1-decoding-strategies/#beam-search-decoding","title":"Beam search decoding\u00b6","text":""},{"location":"examples/modeling/1-decoding-strategies/#digging-deeper-into-beam-search-solutions","title":"Digging deeper into beam search solutions\u00b6","text":""},{"location":"examples/modeling/1-decoding-strategies/#final-notes","title":"Final notes\u00b6","text":""},{"location":"examples/modeling/2-transductive-methods/","title":"Transductive Methods","text":"In\u00a0[\u00a0]: Copied!
# !pip install rl4co[graph] # include torch-geometric\n\n## NOTE: to install latest version from Github (may be unstable) install from source instead:\n# !pip install git+https://github.com/ai4co/rl4co.git\n
# !pip install rl4co[graph] # include torch-geometric ## NOTE: to install latest version from Github (may be unstable) install from source instead: # !pip install git+https://github.com/ai4co/rl4co.git In\u00a0[1]: Copied!
%load_ext autoreload\n%autoreload 2\n\nimport torch\n\nfrom rl4co.envs import TSPEnv, CVRPEnv\nfrom rl4co.models.zoo.am import AttentionModel\nfrom rl4co.utils.trainer import RL4COTrainer\nfrom rl4co.utils.decoding import get_log_likelihood\nfrom rl4co.models.zoo import EAS, EASLay, EASEmb, ActiveSearch\n\nimport logging\n
%load_ext autoreload %autoreload 2 import torch from rl4co.envs import TSPEnv, CVRPEnv from rl4co.models.zoo.am import AttentionModel from rl4co.utils.trainer import RL4COTrainer from rl4co.utils.decoding import get_log_likelihood from rl4co.models.zoo import EAS, EASLay, EASEmb, ActiveSearch import logging
2023-08-22 16:29:17.903805: I tensorflow/core/util/port.cc:110] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n2023-08-22 16:29:17.923169: I tensorflow/core/platform/cpu_feature_guard.cc:182] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\nTo enable the following instructions: AVX2 AVX512F AVX512_VNNI AVX512_BF16 FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n2023-08-22 16:29:18.249479: W tensorflow/compiler/tf2tensorrt/utils/py_utils.cc:38] TF-TRT Warning: Could not find TensorRT\n
In\u00a0[2]: Copied!
# Load from checkpoint; alternatively, simply instantiate a new model\ncheckpoint_path = \"last.ckpt\" # model trained for one epoch only just for showing the examples\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# load checkpoint\n# checkpoint = torch.load(checkpoint_path)\n\nmodel = AttentionModel.load_from_checkpoint(checkpoint_path, load_baseline=False)\npolicy = model.policy.to(device)\n
# Load from checkpoint; alternatively, simply instantiate a new model checkpoint_path = \"last.ckpt\" # model trained for one epoch only just for showing the examples device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\") # load checkpoint # checkpoint = torch.load(checkpoint_path) model = AttentionModel.load_from_checkpoint(checkpoint_path, load_baseline=False) policy = model.policy.to(device)
/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:196: UserWarning: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n  rank_zero_warn(\n/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:196: UserWarning: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n  rank_zero_warn(\n/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/core/saving.py:164: UserWarning: Found keys that are not in the model state dict but in the checkpoint: ['baseline.baseline.model.encoder.init_embedding.init_embed.weight', 'baseline.baseline.model.encoder.init_embedding.init_embed.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.0.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.0.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.0.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.1.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.1.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.1.3.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.Wqkv.bias', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.weight', 'baseline.baseline.model.encoder.net.layers.2.0.module.out_proj.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.1.normalizer.num_batches_tracked', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.0.bias', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.weight', 'baseline.baseline.model.encoder.net.layers.2.2.module.2.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.weight', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.bias', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_mean', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.running_var', 'baseline.baseline.model.encoder.net.layers.2.3.normalizer.num_batches_tracked', 'baseline.baseline.model.decoder.context_embedding.W_placeholder', 'baseline.baseline.model.decoder.context_embedding.project_context.weight', 'baseline.baseline.model.decoder.project_node_embeddings.weight', 'baseline.baseline.model.decoder.project_fixed_context.weight', 'baseline.baseline.model.decoder.logit_attention.project_out.weight']\n  rank_zero_warn(\n
In\u00a0[3]: Copied!
# env = CVRPEnv(generator_params=dict(num_loc=50))\n# policy = AttentionModel(env).policy.to(device)\n\nenv = TSPEnv(generator_params=dict(num_loc=50))\n\ntd = env.reset(batch_size=3).to(device)\n\nout = policy(td, return_actions=True)\n
# env = CVRPEnv(generator_params=dict(num_loc=50)) # policy = AttentionModel(env).policy.to(device) env = TSPEnv(generator_params=dict(num_loc=50)) td = env.reset(batch_size=3).to(device) out = policy(td, return_actions=True) In\u00a0[4]: Copied!
env.render(td.cpu(), out[\"actions\"].cpu())\n
env.render(td.cpu(), out[\"actions\"].cpu()) In\u00a0[5]: Copied!
logging.basicConfig(level=logging.DEBUG)\n\nenv.generator.num_loc = 200\n\ndataset = env.dataset(batch_size=[2])\n# eas_model = EASEmb(env, policy, dataset, batch_size=2, max_iters=20, save_path=\"eas_sols.pt\") # alternative\neas_model = EASLay(env, policy, dataset, batch_size=2, max_iters=20, save_path=\"eas_sols.pt\")\n\neas_model.setup()\n
logging.basicConfig(level=logging.DEBUG) env.generator.num_loc = 200 dataset = env.dataset(batch_size=[2]) # eas_model = EASEmb(env, policy, dataset, batch_size=2, max_iters=20, save_path=\"eas_sols.pt\") # alternative eas_model = EASLay(env, policy, dataset, batch_size=2, max_iters=20, save_path=\"eas_sols.pt\") eas_model.setup()
/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:196: UserWarning: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n  rank_zero_warn(\n/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/utilities/parsing.py:196: UserWarning: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n  rank_zero_warn(\nINFO:rl4co.models.rl.common.base:No metrics specified, using default\nINFO:rl4co.models.zoo.eas.search:Setting up Efficient Active Search (EAS) with: \n- EAS Embedding: False \n- EAS Layer: True \n\n
In\u00a0[6]: Copied!
# Plot initial solution\ntd_dataset = next(iter(eas_model.train_dataloader()))\ntd_dataset = env.reset(td_dataset).to(device)\nout = policy(td_dataset, return_actions=True)\n\nenv.render(td_dataset.cpu(), out[\"actions\"].cpu())\n
# Plot initial solution td_dataset = next(iter(eas_model.train_dataloader())) td_dataset = env.reset(td_dataset).to(device) out = policy(td_dataset, return_actions=True) env.render(td_dataset.cpu(), out[\"actions\"].cpu())
INFO:rl4co.models.common.constructive.autoregressive.policy:Instantiated environment not provided; instantiating tsp\n
In\u00a0[7]: Copied!
from rl4co.utils.trainer import RL4COTrainer\n\ntrainer = RL4COTrainer(\n    max_epochs=1,\n    gradient_clip_val=None,\n)\n\ntrainer.fit(eas_model)\n
from rl4co.utils.trainer import RL4COTrainer trainer = RL4COTrainer( max_epochs=1, gradient_clip_val=None, ) trainer.fit(eas_model)
WARNING:rl4co.utils.trainer:gradient_clip_val is set to None. This may lead to unstable training.\nUsing 16bit Automatic Mixed Precision (AMP)\nGPU available: True (cuda), used: True\nTPU available: False, using: 0 TPU cores\nIPU available: False, using: 0 IPUs\nHPU available: False, using: 0 HPUs\nINFO:rl4co.models.zoo.eas.search:Setting up Efficient Active Search (EAS) with: \n- EAS Embedding: False \n- EAS Layer: True \n\nDEBUG:fsspec.local:open file: /home/botu/Dev/rl4co-rebuttal/notebooks/dev/lightning_logs/version_181/hparams.yaml\nDEBUG:fsspec.local:open file: /home/botu/Dev/rl4co-rebuttal/notebooks/dev/lightning_logs/version_181/hparams.yaml\nLOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0]\nINFO:rl4co.models.rl.common.base:Instantiating optimizer <Adam>\n\n  | Name   | Type                 | Params\n------------------------------------------------\n0 | env    | TSPEnv               | 0     \n1 | policy | AttentionModelPolicy | 710 K \n------------------------------------------------\n710 K     Trainable params\n0         Non-trainable params\n710 K     Total params\n2.841     Total estimated model params size (MB)\n
Sanity Checking: 0it [00:00, ?it/s]
/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:432: PossibleUserWarning: The dataloader, val_dataloader, does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` (try 32 which is the number of cpus on this machine) in the `DataLoader` init to improve performance.\n  rank_zero_warn(\n/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:432: PossibleUserWarning: The dataloader, train_dataloader, does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` (try 32 which is the number of cpus on this machine) in the `DataLoader` init to improve performance.\n  rank_zero_warn(\n/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/loops/fit_loop.py:280: PossibleUserWarning: The number of training batches (1) is smaller than the logging interval Trainer(log_every_n_steps=50). Set a lower value for log_every_n_steps if you want to see logs for the training epoch.\n  rank_zero_warn(\n
Training: 0it [00:00, ?it/s]
/home/botu/Dev/rl4co-rebuttal/notebooks/dev/../../rl4co/models/zoo/eas/nn.py:22: UserWarning: nn.init.xavier_uniform is now deprecated in favor of nn.init.xavier_uniform_.\n  torch.nn.init.xavier_uniform(self.W1)\n/home/botu/Dev/rl4co-rebuttal/notebooks/dev/../../rl4co/models/zoo/eas/nn.py:23: UserWarning: nn.init.xavier_uniform is now deprecated in favor of nn.init.xavier_uniform_.\n  torch.nn.init.xavier_uniform(self.b1)\nINFO:rl4co.models.rl.common.base:Instantiating optimizer <Adam>\n
/home/botu/miniconda3/envs/rl4co/lib/python3.10/site-packages/lightning/pytorch/trainer/connectors/logger_connector/result.py:212: UserWarning: You called `self.log('step', ...)` in your `training_step` but the value needs to be floating point. Converting it to torch.float32.\n  warning_cache.warn(\nINFO:rl4co.models.zoo.eas.search:0/20 |  Reward: -15.52 \nINFO:rl4co.models.zoo.eas.search:1/20 |  Reward: -15.32 \nINFO:rl4co.models.zoo.eas.search:2/20 |  Reward: -15.30 \nINFO:rl4co.models.zoo.eas.search:3/20 |  Reward: -15.28 \nINFO:rl4co.models.zoo.eas.search:4/20 |  Reward: -15.01 \nINFO:rl4co.models.zoo.eas.search:5/20 |  Reward: -15.01 \nINFO:rl4co.models.zoo.eas.search:6/20 |  Reward: -15.01 \nINFO:rl4co.models.zoo.eas.search:7/20 |  Reward: -15.01 \nINFO:rl4co.models.zoo.eas.search:8/20 |  Reward: -15.01 \nINFO:rl4co.models.zoo.eas.search:9/20 |  Reward: -15.01 \nINFO:rl4co.models.zoo.eas.search:10/20 |  Reward: -15.01 \nINFO:rl4co.models.zoo.eas.search:11/20 |  Reward: -15.01 \nINFO:rl4co.models.zoo.eas.search:12/20 |  Reward: -15.01 \nINFO:rl4co.models.zoo.eas.search:13/20 |  Reward: -15.01 \nINFO:rl4co.models.zoo.eas.search:14/20 |  Reward: -15.01 \nINFO:rl4co.models.zoo.eas.search:15/20 |  Reward: -15.01 \nINFO:rl4co.models.zoo.eas.search:16/20 |  Reward: -15.01 \nINFO:rl4co.models.zoo.eas.search:17/20 |  Reward: -15.01 \nINFO:rl4co.models.zoo.eas.search:18/20 |  Reward: -14.84 \nINFO:rl4co.models.zoo.eas.search:19/20 |  Reward: -14.74 \nINFO:rl4co.models.zoo.eas.search:Best reward: -14.74\n
Validation: 0it [00:00, ?it/s]
INFO:rl4co.models.zoo.eas.search:Saving solutions and rewards to eas_sols.pt...\n`Trainer.fit` stopped: `max_epochs=1` reached.\n
In\u00a0[10]: Copied!
# Load\nactions = torch.load(\"eas_sols.pt\")[\"solutions\"][0].cpu()\nactions = actions[:torch.count_nonzero(actions, dim=-1)] # remove trailing zeros\nstate = td_dataset.cpu()[0]\n\nenv.render(state, actions)\n
# Load actions = torch.load(\"eas_sols.pt\")[\"solutions\"][0].cpu() actions = actions[:torch.count_nonzero(actions, dim=-1)] # remove trailing zeros state = td_dataset.cpu()[0] env.render(state, actions)

Even with few iterations, the search method can clearly find better solutions than the initial ones!

"},{"location":"examples/modeling/2-transductive-methods/#transductive-methods","title":"Transductive Methods\u00b6","text":"

In this notebook, we will showcase how to use the Efficient Active Search (EAS) algorithm to find better solutions to existing problems!

Tip: in transductive RL) we train (or finetune) to solve only specific ones.

"},{"location":"examples/modeling/2-transductive-methods/#installation","title":"Installation\u00b6","text":"

Uncomment the following line to install the package from PyPI. Remember to choose a GPU runtime for faster training!

Note: You may need to restart the runtime in Colab after this

"},{"location":"examples/modeling/2-transductive-methods/#imports","title":"Imports\u00b6","text":""},{"location":"examples/modeling/2-transductive-methods/#eas","title":"EAS\u00b6","text":"

We perform few iterations of EASLay for demonstration

"},{"location":"examples/modeling/2-transductive-methods/#perform-search","title":"Perform search\u00b6","text":""},{"location":"examples/modeling/2-transductive-methods/#load-actions","title":"Load actions\u00b6","text":""},{"location":"examples/modeling/3-change-encoder/","title":"Encoder Customization","text":"In\u00a0[1]: Copied!
# !pip install rl4co[graph] # include torch-geometric\n\n## NOTE: to install latest version from Github (may be unstable) install from source instead:\n# !pip install git+https://github.com/ai4co/rl4co.git\n
# !pip install rl4co[graph] # include torch-geometric ## NOTE: to install latest version from Github (may be unstable) install from source instead: # !pip install git+https://github.com/ai4co/rl4co.git In\u00a0[1]: Copied!
from rl4co.envs import CVRPEnv\n\nfrom rl4co.models.zoo import AttentionModel\nfrom rl4co.utils.trainer import RL4COTrainer\n
from rl4co.envs import CVRPEnv from rl4co.models.zoo import AttentionModel from rl4co.utils.trainer import RL4COTrainer In\u00a0[3]: Copied!
# Init env, model, trainer\nenv = CVRPEnv(generator_params=dict(num_loc=20))\n\nmodel = AttentionModel(\n    env, \n    baseline='rollout',\n    train_data_size=100_000, # really small size for demo\n    val_data_size=10_000\n)\n \ntrainer = RL4COTrainer(\n    max_epochs=3, # few epochs for demo\n    accelerator='gpu',\n    devices=1,\n    logger=False,\n)\n\n# By default the AM uses the Graph Attention Encoder\nprint(f'Encoder: {model.policy.encoder._get_name()}')\n
# Init env, model, trainer env = CVRPEnv(generator_params=dict(num_loc=20)) model = AttentionModel( env, baseline='rollout', train_data_size=100_000, # really small size for demo val_data_size=10_000 ) trainer = RL4COTrainer( max_epochs=3, # few epochs for demo accelerator='gpu', devices=1, logger=False, ) # By default the AM uses the Graph Attention Encoder print(f'Encoder: {model.policy.encoder._get_name()}')
/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\nUsing 16bit Automatic Mixed Precision (AMP)\nGPU available: True (cuda), used: True\n
TPU available: False, using: 0 TPU cores\nIPU available: False, using: 0 IPUs\nHPU available: False, using: 0 HPUs\n
Encoder: GraphAttentionEncoder\n
In\u00a0[4]: Copied!
# Train the model\ntrainer.fit(model)\n
# Train the model trainer.fit(model)
/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/callbacks/model_checkpoint.py:630: Checkpoint directory /datasets/home/botu/Dev/rl4co/notebooks/tutorials/checkpoints exists and is not empty.\nval_file not set. Generating dataset instead\ntest_file not set. Generating dataset instead\nLOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n\n  | Name     | Type                 | Params\n--------------------------------------------------\n0 | env      | CVRPEnv              | 0     \n1 | policy   | AttentionModelPolicy | 694 K \n2 | baseline | WarmupBaseline       | 694 K \n--------------------------------------------------\n1.4 M     Trainable params\n0         Non-trainable params\n1.4 M     Total params\n5.553     Total estimated model params size (MB)\n
Sanity Checking: |          | 0/? [00:00<?, ?it/s]
/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'val_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=47` in the `DataLoader` to improve performance.\n/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'train_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=47` in the `DataLoader` to improve performance.\n
Training: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
`Trainer.fit` stopped: `max_epochs=3` reached.\n
In\u00a0[5]: Copied!
# Before we init, we need to install the graph neural network dependencies\n# !pip install rl4co[graph]\n
# Before we init, we need to install the graph neural network dependencies # !pip install rl4co[graph] In\u00a0[7]: Copied!
# Init the model with different encoder\nfrom rl4co.models.nn.graph.gcn import GCNEncoder\nfrom rl4co.models.nn.graph.mpnn import MessagePassingEncoder\n\ngcn_encoder = GCNEncoder(\n    env_name='cvrp', \n    embed_dim=128,\n    num_nodes=20, \n    num_layers=3,\n)\n\nmpnn_encoder = MessagePassingEncoder(\n    env_name='cvrp', \n    embed_dim=128,\n    num_nodes=20, \n    num_layers=3,\n)\n\nmodel = AttentionModel(\n    env, \n    baseline='rollout',\n    train_data_size=100_000, # really small size for demo\n    val_data_size=10_000, \n    policy_kwargs={\n        'encoder': gcn_encoder # gcn_encoder or mpnn_encoder\n    }\n)\n \ntrainer = RL4COTrainer(\n    max_epochs=3, # few epochs for demo\n    accelerator='gpu',\n    devices=1,\n    logger=False,\n)\n
# Init the model with different encoder from rl4co.models.nn.graph.gcn import GCNEncoder from rl4co.models.nn.graph.mpnn import MessagePassingEncoder gcn_encoder = GCNEncoder( env_name='cvrp', embed_dim=128, num_nodes=20, num_layers=3, ) mpnn_encoder = MessagePassingEncoder( env_name='cvrp', embed_dim=128, num_nodes=20, num_layers=3, ) model = AttentionModel( env, baseline='rollout', train_data_size=100_000, # really small size for demo val_data_size=10_000, policy_kwargs={ 'encoder': gcn_encoder # gcn_encoder or mpnn_encoder } ) trainer = RL4COTrainer( max_epochs=3, # few epochs for demo accelerator='gpu', devices=1, logger=False, )
/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\nUsing 16bit Automatic Mixed Precision (AMP)\nGPU available: True (cuda), used: True\nTPU available: False, using: 0 TPU cores\nIPU available: False, using: 0 IPUs\nHPU available: False, using: 0 HPUs\n
In\u00a0[8]: Copied!
# Train the model\ntrainer.fit(model)\n
# Train the model trainer.fit(model)
/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/callbacks/model_checkpoint.py:630: Checkpoint directory /datasets/home/botu/Dev/rl4co/notebooks/tutorials/checkpoints exists and is not empty.\nval_file not set. Generating dataset instead\ntest_file not set. Generating dataset instead\n
LOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n\n  | Name     | Type                 | Params\n--------------------------------------------------\n0 | env      | CVRPEnv              | 0     \n1 | policy   | AttentionModelPolicy | 148 K \n2 | baseline | WarmupBaseline       | 148 K \n--------------------------------------------------\n297 K     Trainable params\n0         Non-trainable params\n297 K     Total params\n1.191     Total estimated model params size (MB)\n
Sanity Checking: |          | 0/? [00:00<?, ?it/s]
/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'val_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=47` in the `DataLoader` to improve performance.\n/datasets/home/botu/mambaforge/envs/rl4co-new/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'train_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=47` in the `DataLoader` to improve performance.\n
Training: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
`Trainer.fit` stopped: `max_epochs=3` reached.\n
In\u00a0[9]: Copied!
# Import necessary packages\nimport torch.nn as nn\nfrom torch import Tensor\nfrom tensordict import TensorDict\nfrom typing import Tuple, Union\nfrom rl4co.models.nn.env_embeddings import env_init_embedding\n\n\nclass BaseEncoder(nn.Module):\n    def __init__(\n            self,\n            env_name: str,\n            embed_dim: int,\n            init_embedding: nn.Module = None,\n        ):\n        super(BaseEncoder, self).__init__()\n        self.env_name = env_name\n        \n        # Init embedding for each environment\n        self.init_embedding = (\n            env_init_embedding(self.env_name, {\"embed_dim\": embed_dim})\n            if init_embedding is None\n            else init_embedding\n        )\n\n    def forward(\n        self, td: TensorDict, mask: Union[Tensor, None] = None\n    ) -> Tuple[Tensor, Tensor]:\n        \"\"\"\n        Args:\n            td: Input TensorDict containing the environment state\n            mask: Mask to apply to the attention\n\n        Returns:\n            h: Latent representation of the input\n            init_h: Initial embedding of the input\n        \"\"\"\n        init_h = self.init_embedding(td)\n        h = None\n        return h, init_h\n
# Import necessary packages import torch.nn as nn from torch import Tensor from tensordict import TensorDict from typing import Tuple, Union from rl4co.models.nn.env_embeddings import env_init_embedding class BaseEncoder(nn.Module): def __init__( self, env_name: str, embed_dim: int, init_embedding: nn.Module = None, ): super(BaseEncoder, self).__init__() self.env_name = env_name # Init embedding for each environment self.init_embedding = ( env_init_embedding(self.env_name, {\"embed_dim\": embed_dim}) if init_embedding is None else init_embedding ) def forward( self, td: TensorDict, mask: Union[Tensor, None] = None ) -> Tuple[Tensor, Tensor]: \"\"\" Args: td: Input TensorDict containing the environment state mask: Mask to apply to the attention Returns: h: Latent representation of the input init_h: Initial embedding of the input \"\"\" init_h = self.init_embedding(td) h = None return h, init_h"},{"location":"examples/modeling/3-change-encoder/#encoder-customization","title":"Encoder Customization\u00b6","text":"

In this notebook we will cover a tutorial for the flexible encoders!

"},{"location":"examples/modeling/3-change-encoder/#installation","title":"Installation\u00b6","text":"

Uncomment the following line to install the package from PyPI. Remember to choose a GPU runtime for faster training!

Note: You may need to restart the runtime in Colab after this

"},{"location":"examples/modeling/3-change-encoder/#imports","title":"Imports\u00b6","text":""},{"location":"examples/modeling/3-change-encoder/#a-default-minimal-training-script","title":"A default minimal training script\u00b6","text":"

Here we use the CVRP environment and AM model as a minimal example of training script. By default, the AM is initialized with a Graph Attention Encoder, but we can change it to anything we want.

"},{"location":"examples/modeling/3-change-encoder/#change-the-encoder","title":"Change the Encoder\u00b6","text":"

In RL4CO, we provides two graph neural network encoders: Graph Convolutionsal Network (GCN) encoder and Message Passing Neural Network (MPNN) encoder. In this tutorial, we will show how to change the encoder.

Note: while we provide these examples, you can also implement your own encoder and use it in RL4CO! For instance, you may use different encoders (and decoders) to solve problems that require e.g. distance matrices as input

"},{"location":"examples/modeling/3-change-encoder/#or-you-want-to-create-your-own-encoder","title":"Or you want to create your own encoder\u00b6","text":"

If you want to create a new encoder, you may want to follow the following base class to create the encoder class with the folowing components:

  1. RL4CO provides the env_init_embedding method for each environment. You may want to use it to get the initial embedding of the environment.
  2. h and init_h as return hidden features have the shape ([batch_size], num_node, hidden_size)
  3. In RL4CO, we put the graph neural network encoders in the rl4co/models/nn/graph folder. You may want to put your customized encoder to the same folder. Feel free to send a PR to add your encoder to RL4CO!
"},{"location":"examples/other/","title":"Miscellaneous Examples","text":"

Collection of examples on other topics.

"},{"location":"examples/other/#index","title":"Index","text":"
  • 1-mtvrp.ipynb: here we show how to use the Multi-Task Vehicle Routing Problem (MTVRP) environment, which includes 16 tasks that can be solved simultaneously.
  • 2-scheduling.ipynb: provides a brief introduction to scheduling problems with RL4CO with the Flexible Job Shop Scheduling Problem (FJSP) environment.
  • 3-data-generator-distributions.ipynb: here we show how to use the data generators and how to generate data from custom distributions.
"},{"location":"examples/other/1-mtvrp/","title":"MTVRP: Multi-task VRP environment","text":"In\u00a0[1]: Copied!
%load_ext autoreload\n%autoreload 2\n\nfrom rl4co.envs.routing.mtvrp.env import MTVRPEnv\nfrom rl4co.envs.routing.mtvrp.generator import MTVRPGenerator\n
%load_ext autoreload %autoreload 2 from rl4co.envs.routing.mtvrp.env import MTVRPEnv from rl4co.envs.routing.mtvrp.generator import MTVRPGenerator
/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning_utilities/core/imports.py:14: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html\n  import pkg_resources\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/pkg_resources/__init__.py:2832: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('sphinxcontrib')`.\nImplementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages\n  declare_namespace(pkg)\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/fabric/__init__.py:41: Deprecated call to `pkg_resources.declare_namespace('lightning.fabric')`.\nImplementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/pkg_resources/__init__.py:2317: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('lightning')`.\nImplementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages\n  declare_namespace(parent)\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/__init__.py:37: Deprecated call to `pkg_resources.declare_namespace('lightning.pytorch')`.\nImplementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/pkg_resources/__init__.py:2317: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('lightning')`.\nImplementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages\n  declare_namespace(parent)\n

Let's now generate some variants! By default, we can generate all variants with the variants_preset variable

In\u00a0[2]: Copied!
# Single feat: generate a distribution of single-featured environments\ngenerator = MTVRPGenerator(num_loc=50, variant_preset=\"all\")\nenv = MTVRPEnv(generator, check_solution=False)\n\ntd_data = env.generator(8)\nenv.get_variant_names(td_data)\n
# Single feat: generate a distribution of single-featured environments generator = MTVRPGenerator(num_loc=50, variant_preset=\"all\") env = MTVRPEnv(generator, check_solution=False) td_data = env.generator(8) env.get_variant_names(td_data) Out[2]:
['VRPLTW', 'OVRP', 'VRPLTW', 'OVRPLTW', 'OVRPL', 'VRPB', 'OVRPTW', 'OVRPB']
In\u00a0[3]: Copied!
# Here is the list of presets and their probabilities of being generated (fully customizable)\nenv.print_presets()\n
# Here is the list of presets and their probabilities of being generated (fully customizable) env.print_presets()
all: {'O': 0.5, 'TW': 0.5, 'L': 0.5, 'B': 0.5}\nsingle_feat: {'O': 0.5, 'TW': 0.5, 'L': 0.5, 'B': 0.5}\nsingle_feat_otw: {'O': 0.5, 'TW': 0.5, 'L': 0.5, 'B': 0.5, 'OTW': 0.5}\ncvrp: {'O': 0.0, 'TW': 0.0, 'L': 0.0, 'B': 0.0}\novrp: {'O': 1.0, 'TW': 0.0, 'L': 0.0, 'B': 0.0}\nvrpb: {'O': 0.0, 'TW': 0.0, 'L': 0.0, 'B': 1.0}\nvrpl: {'O': 0.0, 'TW': 0.0, 'L': 1.0, 'B': 0.0}\nvrptw: {'O': 0.0, 'TW': 1.0, 'L': 0.0, 'B': 0.0}\novrptw: {'O': 1.0, 'TW': 1.0, 'L': 0.0, 'B': 0.0}\novrpb: {'O': 1.0, 'TW': 0.0, 'L': 0.0, 'B': 1.0}\novrpl: {'O': 1.0, 'TW': 0.0, 'L': 1.0, 'B': 0.0}\nvrpbl: {'O': 0.0, 'TW': 0.0, 'L': 1.0, 'B': 1.0}\nvrpbtw: {'O': 0.0, 'TW': 1.0, 'L': 0.0, 'B': 1.0}\nvrpltw: {'O': 0.0, 'TW': 1.0, 'L': 1.0, 'B': 0.0}\novrpbl: {'O': 1.0, 'TW': 0.0, 'L': 1.0, 'B': 1.0}\novrpbtw: {'O': 1.0, 'TW': 1.0, 'L': 0.0, 'B': 1.0}\novrpltw: {'O': 1.0, 'TW': 1.0, 'L': 1.0, 'B': 0.0}\nvrpbltw: {'O': 0.0, 'TW': 1.0, 'L': 1.0, 'B': 1.0}\novrpbltw: {'O': 1.0, 'TW': 1.0, 'L': 1.0, 'B': 1.0}\n

We can change the preset to generate some specific variant, for instance the VRPB

In\u00a0[4]: Copied!
# Change generator\ngenerator = MTVRPGenerator(num_loc=50, variant_preset=\"vrpb\")\nenv.generator = generator\ntd_data = env.generator(8)\nenv.get_variant_names(td_data)\n
# Change generator generator = MTVRPGenerator(num_loc=50, variant_preset=\"vrpb\") env.generator = generator td_data = env.generator(8) env.get_variant_names(td_data)
vrpb selected. Will not use feature combination!\n
Out[4]:
['VRPB', 'VRPB', 'VRPB', 'VRPB', 'VRPB', 'VRPB', 'VRPB', 'VRPB']
In\u00a0[5]: Copied!
import torch\nfrom rl4co.utils.ops import gather_by_index\n\n\n# Simple heuristics (nearest neighbor + capacity check)\ndef greedy_policy(td):\n    \"\"\"Select closest available action\"\"\"\n    available_actions = td[\"action_mask\"]\n    # distances\n    curr_node = td[\"current_node\"]\n    loc_cur = gather_by_index(td[\"locs\"], curr_node)\n    distances_next = torch.cdist(loc_cur[:, None, :], td[\"locs\"], p=2.0).squeeze(1)\n\n    distances_next[~available_actions.bool()] = float(\"inf\")\n    # do not select depot if some capacity is left\n    distances_next[:, 0] = float(\"inf\") * (\n        td[\"used_capacity_linehaul\"] < td[\"vehicle_capacity\"]\n    ).float().squeeze(-1)\n\n    # # if sum of available actions is 0, select depot\n    # distances_next[available_actions.sum(-1) == 0, 0] = 0\n    action = torch.argmin(distances_next, dim=-1)\n    td.set(\"action\", action)\n    return td\n\n\ndef rollout(env, td, policy=greedy_policy, max_steps: int = None):\n    \"\"\"Helper function to rollout a policy. Currently, TorchRL does not allow to step\n    over envs when done with `env.rollout()`. We need this because for environments that complete at different steps.\n    \"\"\"\n\n    max_steps = float(\"inf\") if max_steps is None else max_steps\n    actions = []\n    steps = 0\n\n    while not td[\"done\"].all():\n        td = policy(td)\n        actions.append(td[\"action\"])\n        td = env.step(td)[\"next\"]\n        steps += 1\n        if steps > max_steps:\n            print(\"Max steps reached\")\n            break\n    return torch.stack(actions, dim=1)\n
import torch from rl4co.utils.ops import gather_by_index # Simple heuristics (nearest neighbor + capacity check) def greedy_policy(td): \"\"\"Select closest available action\"\"\" available_actions = td[\"action_mask\"] # distances curr_node = td[\"current_node\"] loc_cur = gather_by_index(td[\"locs\"], curr_node) distances_next = torch.cdist(loc_cur[:, None, :], td[\"locs\"], p=2.0).squeeze(1) distances_next[~available_actions.bool()] = float(\"inf\") # do not select depot if some capacity is left distances_next[:, 0] = float(\"inf\") * ( td[\"used_capacity_linehaul\"] < td[\"vehicle_capacity\"] ).float().squeeze(-1) # # if sum of available actions is 0, select depot # distances_next[available_actions.sum(-1) == 0, 0] = 0 action = torch.argmin(distances_next, dim=-1) td.set(\"action\", action) return td def rollout(env, td, policy=greedy_policy, max_steps: int = None): \"\"\"Helper function to rollout a policy. Currently, TorchRL does not allow to step over envs when done with `env.rollout()`. We need this because for environments that complete at different steps. \"\"\" max_steps = float(\"inf\") if max_steps is None else max_steps actions = [] steps = 0 while not td[\"done\"].all(): td = policy(td) actions.append(td[\"action\"]) td = env.step(td)[\"next\"] steps += 1 if steps > max_steps: print(\"Max steps reached\") break return torch.stack(actions, dim=1) In\u00a0[6]: Copied!
# NOTE: if we don't select ovrpbltw, the below does not work and there is still some\n# minor bug in either masking or variant subselection\n\ngenerator = MTVRPGenerator(num_loc=50, variant_preset=\"all\")\nenv.generator = generator\ntd_data = env.generator(3)\nvariant_names = env.get_variant_names(td_data)\n\ntd = env.reset(td_data)\n\nactions = rollout(env, td.clone(), greedy_policy)\nrewards = env.get_reward(td, actions)\n\nfor idx in [0, 1, 2]:\n    env.render(td[idx], actions[idx])\n    print(\"Cost: \", - rewards[idx].item())\n    print(\"Problem: \", variant_names[idx])\n
# NOTE: if we don't select ovrpbltw, the below does not work and there is still some # minor bug in either masking or variant subselection generator = MTVRPGenerator(num_loc=50, variant_preset=\"all\") env.generator = generator td_data = env.generator(3) variant_names = env.get_variant_names(td_data) td = env.reset(td_data) actions = rollout(env, td.clone(), greedy_policy) rewards = env.get_reward(td, actions) for idx in [0, 1, 2]: env.render(td[idx], actions[idx]) print(\"Cost: \", - rewards[idx].item()) print(\"Problem: \", variant_names[idx])
Cost:  17.503389358520508\nProblem:  OVRPLTW\n
Cost:  18.86773109436035\nProblem:  CVRP\n
Cost:  15.39835262298584\nProblem:  VRPB\n
In\u00a0[7]: Copied!
from rl4co.utils.trainer import RL4COTrainer\nfrom rl4co.models.zoo import MVMoE_POMO\n\ndevice_id = 0\ndevice = torch.device(f\"cuda:{device_id}\" if torch.cuda.is_available() else \"cpu\")\ngenerator = MTVRPGenerator(num_loc=50, variant_preset=\"single_feat\")\nenv = MTVRPEnv(generator, check_solution=False)\n
from rl4co.utils.trainer import RL4COTrainer from rl4co.models.zoo import MVMoE_POMO device_id = 0 device = torch.device(f\"cuda:{device_id}\" if torch.cuda.is_available() else \"cpu\") generator = MTVRPGenerator(num_loc=50, variant_preset=\"single_feat\") env = MTVRPEnv(generator, check_solution=False)
single_feat selected. Will not use feature combination!\n
In\u00a0[8]: Copied!
moe_kwargs = {\"encoder\": {\"hidden_act\": \"ReLU\", \"num_experts\": 4, \"k\": 2, \"noisy_gating\": True},\n              \"decoder\": {\"light_version\": False, \"num_experts\": 4, \"k\": 2, \"noisy_gating\": True}}\nmodel = MVMoE_POMO(\n    env,\n    moe_kwargs=moe_kwargs,\n    batch_size=128,\n    train_data_size=10000,  # each epoch,\n    val_batch_size=100,\n    val_data_size=1000,\n    optimizer=\"Adam\",\n    optimizer_kwargs={\"lr\": 1e-4, \"weight_decay\": 1e-6},\n    lr_scheduler=\"MultiStepLR\",\n    lr_scheduler_kwargs={\"milestones\": [451, ], \"gamma\": 0.1},\n)\n\ntrainer = RL4COTrainer(\n        max_epochs=3,\n        accelerator=\"gpu\",\n        devices=[device_id],\n        logger=None\n    )\n\ntrainer.fit(model)\n
moe_kwargs = {\"encoder\": {\"hidden_act\": \"ReLU\", \"num_experts\": 4, \"k\": 2, \"noisy_gating\": True}, \"decoder\": {\"light_version\": False, \"num_experts\": 4, \"k\": 2, \"noisy_gating\": True}} model = MVMoE_POMO( env, moe_kwargs=moe_kwargs, batch_size=128, train_data_size=10000, # each epoch, val_batch_size=100, val_data_size=1000, optimizer=\"Adam\", optimizer_kwargs={\"lr\": 1e-4, \"weight_decay\": 1e-6}, lr_scheduler=\"MultiStepLR\", lr_scheduler_kwargs={\"milestones\": [451, ], \"gamma\": 0.1}, ) trainer = RL4COTrainer( max_epochs=3, accelerator=\"gpu\", devices=[device_id], logger=None ) trainer.fit(model)
/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/utilities/parsing.py:199: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\nUsing 16bit Automatic Mixed Precision (AMP)\nGPU available: True (cuda), used: True\nTPU available: False, using: 0 TPU cores\nIPU available: False, using: 0 IPUs\nHPU available: False, using: 0 HPUs\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/logger_connector/logger_connector.py:75: Starting from v1.9.0, `tensorboardX` has been removed as a dependency of the `lightning.pytorch` package, due to potential conflicts with other packages in the ML ecosystem. For this reason, `logger=True` will use `CSVLogger` as the default logger, unless the `tensorboard` or `tensorboardX` packages are found. Please `pip install lightning[extra]` or one of them to enable TensorBoard support by default\nMissing logger folder: /home/botu/Dev/rl4co/examples/other/lightning_logs\nval_file not set. Generating dataset instead\ntest_file not set. Generating dataset instead\nLOCAL_RANK: 0 - CUDA_VISIBLE_DEVICES: [0,1]\n\n  | Name     | Type                 | Params\n--------------------------------------------------\n0 | env      | MTVRPEnv             | 0     \n1 | policy   | AttentionModelPolicy | 3.7 M \n2 | baseline | SharedBaseline       | 0     \n--------------------------------------------------\n3.7 M     Trainable params\n0         Non-trainable params\n3.7 M     Total params\n14.868    Total estimated model params size (MB)\n
Sanity Checking: |          | 0/? [00:00<?, ?it/s]
/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'val_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=31` in the `DataLoader` to improve performance.\n/home/botu/mambaforge/envs/rl4co/lib/python3.11/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'train_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=31` in the `DataLoader` to improve performance.\n
Training: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
Validation: |          | 0/? [00:00<?, ?it/s]
`Trainer.fit` stopped: `max_epochs=3` reached.\n
In\u00a0[34]: Copied!
# Greedy rollouts over trained model (same states as previous plot)\npolicy = model.policy.to(device)\nout = policy(td.to(device).clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True)\nactions_mvmoe = out['actions'].cpu().detach()\nrewards_mvmoe = out['reward'].cpu().detach()\n\nfor idx in [0, 1, 2]:\n    env.render(td[idx], actions_mvmoe[idx])\n    print(\"Cost: \", -rewards_mvmoe[idx].item())\n    print(\"Problem: \", variant_names[idx])\n
# Greedy rollouts over trained model (same states as previous plot) policy = model.policy.to(device) out = policy(td.to(device).clone(), env, phase=\"test\", decode_type=\"greedy\", return_actions=True) actions_mvmoe = out['actions'].cpu().detach() rewards_mvmoe = out['reward'].cpu().detach() for idx in [0, 1, 2]: env.render(td[idx], actions_mvmoe[idx]) print(\"Cost: \", -rewards_mvmoe[idx].item()) print(\"Problem: \", variant_names[idx])
Cost:  17.188127517700195\nProblem:  OVRPLTW\n
Cost:  14.578388214111328\nProblem:  CVRP\n
Cost:  12.24499797821045\nProblem:  VRPB\n
In\u00a0[31]: Copied!
# PyVRP - HGS\npyvrp_actions, pyvrp_costs = env.solve(td, max_runtime=5, num_procs=10, solver=\"pyvrp\")\nrewards_pyvrp = env.get_reward(td, pyvrp_actions)\n
# PyVRP - HGS pyvrp_actions, pyvrp_costs = env.solve(td, max_runtime=5, num_procs=10, solver=\"pyvrp\") rewards_pyvrp = env.get_reward(td, pyvrp_actions) In\u00a0[36]: Copied!
def calculate_gap(cost, bks):   \n    gaps = (cost - bks) / bks\n    return gaps.mean() * 100\n\n# Nearest insertion\nactions = rollout(env, td.clone(), greedy_policy)\nrewards_ni = env.get_reward(td, actions)\n\nprint(rewards_mvmoe, rewards_ni, rewards_pyvrp)   \nprint(f\"Gap to HGS (NI): {calculate_gap(-rewards_ni, -rewards_pyvrp):.2f}%\")\nprint(f\"Gap to HGS (MVMoE): {calculate_gap(-rewards_mvmoe, -rewards_pyvrp):.2f}%\")\n
def calculate_gap(cost, bks): gaps = (cost - bks) / bks return gaps.mean() * 100 # Nearest insertion actions = rollout(env, td.clone(), greedy_policy) rewards_ni = env.get_reward(td, actions) print(rewards_mvmoe, rewards_ni, rewards_pyvrp) print(f\"Gap to HGS (NI): {calculate_gap(-rewards_ni, -rewards_pyvrp):.2f}%\") print(f\"Gap to HGS (MVMoE): {calculate_gap(-rewards_mvmoe, -rewards_pyvrp):.2f}%\")
tensor([-17.1881, -14.5784, -12.2450]) tensor([-17.5034, -18.8677, -15.3984]) tensor([-12.6954, -11.9107,  -9.9261])\nGap to HGS (NI): 50.47%\nGap to HGS (MVMoE): 27.05%\n

With only two short epochs, we can already get better than NI!

"},{"location":"examples/other/1-mtvrp/#mtvrp-multi-task-vrp-environment","title":"MTVRP: Multi-task VRP environment\u00b6","text":"

This environment can handle any of the following variants:

VRP Variant Capacity (C) Open Route (O) Backhaul (B) Duration Limit (L) Time Window (TW) CVRP \u2714 OVRP \u2714 \u2714 VRPB \u2714 \u2714 VRPL \u2714 \u2714 VRPTW \u2714 \u2714 OVRPTW \u2714 \u2714 \u2714 OVRPB \u2714 \u2714 \u2714 OVRPL \u2714 \u2714 \u2714 VRPBL \u2714 \u2714 \u2714 VRPBTW \u2714 \u2714 \u2714 VRPLTW \u2714 \u2714 \u2714 OVRPBL \u2714 \u2714 \u2714 \u2714 OVRPBTW \u2714 \u2714 \u2714 \u2714 OVRPLTW \u2714 \u2714 \u2714 \u2714 VRPBLTW \u2714 \u2714 \u2714 \u2714 OVRPBLTW \u2714 \u2714 \u2714 \u2714 \u2714

It is fully batched, meaning that different variants can be in the same batch too!

"},{"location":"examples/other/1-mtvrp/#greedy-rollout-and-plot","title":"Greedy rollout and plot\u00b6","text":""},{"location":"examples/other/1-mtvrp/#train-mvmoe-on-multiple-problems","title":"Train MVMoE on Multiple Problems\u00b6","text":""},{"location":"examples/other/1-mtvrp/#getting-gaps-to-classical-solvers","title":"Getting gaps to classical solvers\u00b6","text":"

We additionally offer an optional solve API to get solutions from classical solvers. We can use this to get the gaps to the optimal solutions.

"},{"location":"examples/other/2-scheduling/","title":"Solving the Flexible Job-Shop Scheduling Problem (FJSP)","text":"In\u00a0[1]: Copied!
! pip install torch_geometric\n
! pip install torch_geometric
Requirement already satisfied: torch_geometric in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (2.5.0)\nRequirement already satisfied: tqdm in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (4.66.1)\nRequirement already satisfied: numpy in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (1.26.3)\nRequirement already satisfied: scipy in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (1.11.4)\nRequirement already satisfied: fsspec in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (2023.12.2)\nRequirement already satisfied: jinja2 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (3.1.3)\nRequirement already satisfied: aiohttp in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (3.9.1)\nRequirement already satisfied: requests in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (2.31.0)\nRequirement already satisfied: pyparsing in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (3.1.1)\nRequirement already satisfied: scikit-learn in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (1.4.1.post1)\nRequirement already satisfied: psutil>=5.8.0 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from torch_geometric) (5.9.7)\nRequirement already satisfied: attrs>=17.3.0 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from aiohttp->torch_geometric) (23.2.0)\nRequirement already satisfied: multidict<7.0,>=4.5 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from aiohttp->torch_geometric) (6.0.4)\nRequirement already satisfied: yarl<2.0,>=1.0 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from aiohttp->torch_geometric) (1.9.4)\nRequirement already satisfied: frozenlist>=1.1.1 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from aiohttp->torch_geometric) (1.4.1)\nRequirement already satisfied: aiosignal>=1.1.2 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from aiohttp->torch_geometric) (1.3.1)\nRequirement already satisfied: async-timeout<5.0,>=4.0 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from aiohttp->torch_geometric) (4.0.3)\nRequirement already satisfied: MarkupSafe>=2.0 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from jinja2->torch_geometric) (2.1.3)\nRequirement already satisfied: charset-normalizer<4,>=2 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from requests->torch_geometric) (3.3.2)\nRequirement already satisfied: idna<4,>=2.5 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from requests->torch_geometric) (3.6)\nRequirement already satisfied: urllib3<3,>=1.21.1 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from requests->torch_geometric) (1.26.18)\nRequirement already satisfied: certifi>=2017.4.17 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from requests->torch_geometric) (2023.11.17)\nRequirement already satisfied: joblib>=1.2.0 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from scikit-learn->torch_geometric) (1.3.2)\nRequirement already satisfied: threadpoolctl>=2.0.0 in /Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages (from scikit-learn->torch_geometric) (3.3.0)\n
In\u00a0[2]: Copied!
%load_ext autoreload\n%autoreload 2\n\nimport torch\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom IPython.display import display, clear_output\nimport time\nimport networkx as nx\nimport matplotlib.pyplot as plt\nfrom rl4co.envs import FJSPEnv\nfrom rl4co.models.zoo.l2d import L2DModel\nfrom rl4co.models.zoo.l2d.policy import L2DPolicy\nfrom rl4co.models.zoo.l2d.decoder import L2DDecoder\nfrom rl4co.models.nn.graph.hgnn import HetGNNEncoder\nfrom rl4co.utils.trainer import RL4COTrainer\n
%load_ext autoreload %autoreload 2 import torch import numpy as np import matplotlib.pyplot as plt import numpy as np from IPython.display import display, clear_output import time import networkx as nx import matplotlib.pyplot as plt from rl4co.envs import FJSPEnv from rl4co.models.zoo.l2d import L2DModel from rl4co.models.zoo.l2d.policy import L2DPolicy from rl4co.models.zoo.l2d.decoder import L2DDecoder from rl4co.models.nn.graph.hgnn import HetGNNEncoder from rl4co.utils.trainer import RL4COTrainer In\u00a0[3]: Copied!
generator_params = {\n  \"num_jobs\": 5,  # the total number of jobs\n  \"num_machines\": 5,  # the total number of machines that can process operations\n  \"min_ops_per_job\": 1,  # minimum number of operatios per job\n  \"max_ops_per_job\": 2,  # maximum number of operations per job\n  \"min_processing_time\": 1,  # the minimum time required for a machine to process an operation\n  \"max_processing_time\": 20,  # the maximum time required for a machine to process an operation\n  \"min_eligible_ma_per_op\": 1,  # the minimum number of machines capable to process an operation\n  \"max_eligible_ma_per_op\": 2,  # the maximum number of machines capable to process an operation\n}\n
generator_params = { \"num_jobs\": 5, # the total number of jobs \"num_machines\": 5, # the total number of machines that can process operations \"min_ops_per_job\": 1, # minimum number of operatios per job \"max_ops_per_job\": 2, # maximum number of operations per job \"min_processing_time\": 1, # the minimum time required for a machine to process an operation \"max_processing_time\": 20, # the maximum time required for a machine to process an operation \"min_eligible_ma_per_op\": 1, # the minimum number of machines capable to process an operation \"max_eligible_ma_per_op\": 2, # the maximum number of machines capable to process an operation } In\u00a0[4]: Copied!
env = FJSPEnv(generator_params=generator_params)\ntd = env.reset(batch_size=[1])\n
env = FJSPEnv(generator_params=generator_params) td = env.reset(batch_size=[1]) In\u00a0[5]: Copied!
# Create a bipartite graph from the adjacency matrix\nG = nx.Graph()\nproc_times = td[\"proc_times\"].squeeze(0)\njob_ops_adj = td[\"job_ops_adj\"].squeeze(0)\norder = td[\"ops_sequence_order\"].squeeze(0) + 1\n\nnum_machines, num_operations = proc_times.shape\nnum_jobs = job_ops_adj.size(0)\n\njobs = [f\"j{i+1}\" for i in range(num_jobs)]\nmachines = [f\"m{i+1}\" for i in range(num_machines)]\noperations = [f\"o{i+1}\" for i in range(num_operations)]\n\n# Add nodes from each set\nG.add_nodes_from(machines, bipartite=0)\nG.add_nodes_from(operations, bipartite=1)\nG.add_nodes_from(jobs, bipartite=2)\n\n# Add edges based on the adjacency matrix\nfor i in range(num_machines):\n    for j in range(num_operations):\n        edge_weigth = proc_times[i][j]\n        if edge_weigth != 0:\n            G.add_edge(f\"m{i+1}\", f\"o{j+1}\", weight=edge_weigth)\n\n\n# Add edges based on the adjacency matrix\nfor i in range(num_jobs):\n    for j in range(num_operations):\n        edge_weigth = job_ops_adj[i][j]\n        if edge_weigth != 0:\n            G.add_edge(f\"j{i+1}\", f\"o{j+1}\", weight=3, label=order[j])\n\n\nwidths = [x / 3 for x in nx.get_edge_attributes(G, 'weight').values()]\n\nplt.figure(figsize=(10,6))\n# Plot the graph\n\nmachines = [n for n, d in G.nodes(data=True) if d['bipartite'] == 0]\noperations = [n for n, d in G.nodes(data=True) if d['bipartite'] == 1]\njobs = [n for n, d in G.nodes(data=True) if d['bipartite'] == 2]\n\npos = {}\npos.update((node, (1, index)) for index, node in enumerate(machines))\npos.update((node, (2, index)) for index, node in enumerate(operations))\npos.update((node, (3, index)) for index, node in enumerate(jobs))\n\nedge_labels = {(u, v): d['label'].item() for u, v, d in G.edges(data=True) if d.get(\"label\") is not None}\nnx.draw_networkx_edge_labels(G, {k: (v[0]+.12, v[1]) for k,v in pos.items()}, edge_labels=edge_labels, rotate=False)\n\nnx.draw_networkx_nodes(G, pos, nodelist=machines, node_color='b', label=\"Machine\")\nnx.draw_networkx_nodes(G, pos, nodelist=operations, node_color='r', label=\"Operation\")\nnx.draw_networkx_nodes(G, pos, nodelist=jobs, node_color='y', label=\"jobs\")\nnx.draw_networkx_edges(G, pos, width=widths, alpha=0.6)\n\nplt.title('Visualization of the FJSP')\nplt.legend(bbox_to_anchor=(.95, 1.05))\nplt.axis('off')\nplt.show()\n
# Create a bipartite graph from the adjacency matrix G = nx.Graph() proc_times = td[\"proc_times\"].squeeze(0) job_ops_adj = td[\"job_ops_adj\"].squeeze(0) order = td[\"ops_sequence_order\"].squeeze(0) + 1 num_machines, num_operations = proc_times.shape num_jobs = job_ops_adj.size(0) jobs = [f\"j{i+1}\" for i in range(num_jobs)] machines = [f\"m{i+1}\" for i in range(num_machines)] operations = [f\"o{i+1}\" for i in range(num_operations)] # Add nodes from each set G.add_nodes_from(machines, bipartite=0) G.add_nodes_from(operations, bipartite=1) G.add_nodes_from(jobs, bipartite=2) # Add edges based on the adjacency matrix for i in range(num_machines): for j in range(num_operations): edge_weigth = proc_times[i][j] if edge_weigth != 0: G.add_edge(f\"m{i+1}\", f\"o{j+1}\", weight=edge_weigth) # Add edges based on the adjacency matrix for i in range(num_jobs): for j in range(num_operations): edge_weigth = job_ops_adj[i][j] if edge_weigth != 0: G.add_edge(f\"j{i+1}\", f\"o{j+1}\", weight=3, label=order[j]) widths = [x / 3 for x in nx.get_edge_attributes(G, 'weight').values()] plt.figure(figsize=(10,6)) # Plot the graph machines = [n for n, d in G.nodes(data=True) if d['bipartite'] == 0] operations = [n for n, d in G.nodes(data=True) if d['bipartite'] == 1] jobs = [n for n, d in G.nodes(data=True) if d['bipartite'] == 2] pos = {} pos.update((node, (1, index)) for index, node in enumerate(machines)) pos.update((node, (2, index)) for index, node in enumerate(operations)) pos.update((node, (3, index)) for index, node in enumerate(jobs)) edge_labels = {(u, v): d['label'].item() for u, v, d in G.edges(data=True) if d.get(\"label\") is not None} nx.draw_networkx_edge_labels(G, {k: (v[0]+.12, v[1]) for k,v in pos.items()}, edge_labels=edge_labels, rotate=False) nx.draw_networkx_nodes(G, pos, nodelist=machines, node_color='b', label=\"Machine\") nx.draw_networkx_nodes(G, pos, nodelist=operations, node_color='r', label=\"Operation\") nx.draw_networkx_nodes(G, pos, nodelist=jobs, node_color='y', label=\"jobs\") nx.draw_networkx_edges(G, pos, width=widths, alpha=0.6) plt.title('Visualization of the FJSP') plt.legend(bbox_to_anchor=(.95, 1.05)) plt.axis('off') plt.show() In\u00a0[6]: Copied!
# Lets generate a more complex instance\n\ngenerator_params = {\n  \"num_jobs\": 10,  # the total number of jobs\n  \"num_machines\": 5,  # the total number of machines that can process operations\n  \"min_ops_per_job\": 4,  # minimum number of operatios per job\n  \"max_ops_per_job\": 6,  # maximum number of operations per job\n  \"min_processing_time\": 1,  # the minimum time required for a machine to process an operation\n  \"max_processing_time\": 20,  # the maximum time required for a machine to process an operation\n  \"min_eligible_ma_per_op\": 1,  # the minimum number of machines capable to process an operation\n  \"max_eligible_ma_per_op\": 5,  # the maximum number of machines capable to process an operation\n}\n\nenv = FJSPEnv(generator_params=generator_params)\ntd = env.reset(batch_size=[1])\n
# Lets generate a more complex instance generator_params = { \"num_jobs\": 10, # the total number of jobs \"num_machines\": 5, # the total number of machines that can process operations \"min_ops_per_job\": 4, # minimum number of operatios per job \"max_ops_per_job\": 6, # maximum number of operations per job \"min_processing_time\": 1, # the minimum time required for a machine to process an operation \"max_processing_time\": 20, # the maximum time required for a machine to process an operation \"min_eligible_ma_per_op\": 1, # the minimum number of machines capable to process an operation \"max_eligible_ma_per_op\": 5, # the maximum number of machines capable to process an operation } env = FJSPEnv(generator_params=generator_params) td = env.reset(batch_size=[1]) In\u00a0[7]: Copied!
encoder = HetGNNEncoder(embed_dim=32, num_layers=2)\n(ma_emb, op_emb), init = encoder(td)\nprint(ma_emb.shape)\nprint(op_emb.shape)\n
encoder = HetGNNEncoder(embed_dim=32, num_layers=2) (ma_emb, op_emb), init = encoder(td) print(ma_emb.shape) print(op_emb.shape)
torch.Size([1, 60, 32])\ntorch.Size([1, 5, 32])\n

The decoder return logits over a composite action-space of size (1 + num_jobs * num_machines), where each entry corresponds to a machine-job combination plus one waiting-operation. The selected action specifies, which job is processed next by which machine. To be more precise, the next operation of the selected job is processed. This operation can be retrieved from td[\"next_op\"]

In\u00a0[8]: Copied!
# next operation per job\ntd[\"next_op\"]\n
# next operation per job td[\"next_op\"] Out[8]:
tensor([[ 0,  4, 10, 15, 21, 27, 33, 39, 45, 49]])
In\u00a0[9]: Copied!
decoder = L2DDecoder(env_name=env.name, embed_dim=32)\nlogits, mask = decoder(td, (ma_emb, op_emb), num_starts=0)\n# (1 + num_jobs * num_machines)\nprint(logits.shape)\n
decoder = L2DDecoder(env_name=env.name, embed_dim=32) logits, mask = decoder(td, (ma_emb, op_emb), num_starts=0) # (1 + num_jobs * num_machines) print(logits.shape)
torch.Size([1, 51])\n
In\u00a0[10]: Copied!
def make_step(td):\n    logits, mask = decoder(td, (ma_emb, op_emb), num_starts=0)\n    action = logits.masked_fill(~mask, -torch.inf).argmax(1)\n    td[\"action\"] = action\n    td = env.step(td)[\"next\"]\n    return td\n
def make_step(td): logits, mask = decoder(td, (ma_emb, op_emb), num_starts=0) action = logits.masked_fill(~mask, -torch.inf).argmax(1) td[\"action\"] = action td = env.step(td)[\"next\"] return td In\u00a0[11]: Copied!
env.render(td, 0)\n# Update plot within a for loop\nwhile not td[\"done\"].all():\n    # Clear the previous output for the next iteration\n    clear_output(wait=True)\n\n    td = make_step(td)\n    env.render(td, 0)\n    # Display updated plot\n    display(plt.gcf())\n    \n    # Pause for a moment to see the changes\n    time.sleep(.4)\n
env.render(td, 0) # Update plot within a for loop while not td[\"done\"].all(): # Clear the previous output for the next iteration clear_output(wait=True) td = make_step(td) env.render(td, 0) # Display updated plot display(plt.gcf()) # Pause for a moment to see the changes time.sleep(.4)
<Figure size 640x480 with 0 Axes>
<Figure size 640x480 with 0 Axes>
<Figure size 640x480 with 0 Axes>
In\u00a0[12]: Copied!
if torch.cuda.is_available():\n    accelerator = \"gpu\"\n    batch_size = 256\n    train_data_size = 2_000\n    embed_dim = 128\n    num_encoder_layers = 4\nelse:\n    accelerator = \"cpu\"\n    batch_size = 32\n    train_data_size = 1_000\n    embed_dim = 64\n    num_encoder_layers = 2\n
if torch.cuda.is_available(): accelerator = \"gpu\" batch_size = 256 train_data_size = 2_000 embed_dim = 128 num_encoder_layers = 4 else: accelerator = \"cpu\" batch_size = 32 train_data_size = 1_000 embed_dim = 64 num_encoder_layers = 2 In\u00a0[13]: Copied!
# Policy: neural network, in this case with encoder-decoder architecture\npolicy = L2DPolicy(embed_dim=embed_dim, num_encoder_layers=num_encoder_layers, env_name=\"fjsp\")\n\n# Model: default is AM with REINFORCE and greedy rollout baseline\nmodel = L2DModel(env,\n                 policy=policy, \n                 baseline=\"rollout\",\n                 batch_size=batch_size,\n                 train_data_size=train_data_size,\n                 val_data_size=1_000,\n                 optimizer_kwargs={\"lr\": 1e-4})\n\ntrainer = RL4COTrainer(\n    max_epochs=3,\n    accelerator=accelerator,\n    devices=1,\n    logger=None,\n)\n\ntrainer.fit(model)\n
# Policy: neural network, in this case with encoder-decoder architecture policy = L2DPolicy(embed_dim=embed_dim, num_encoder_layers=num_encoder_layers, env_name=\"fjsp\") # Model: default is AM with REINFORCE and greedy rollout baseline model = L2DModel(env, policy=policy, baseline=\"rollout\", batch_size=batch_size, train_data_size=train_data_size, val_data_size=1_000, optimizer_kwargs={\"lr\": 1e-4}) trainer = RL4COTrainer( max_epochs=3, accelerator=accelerator, devices=1, logger=None, ) trainer.fit(model)
/Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'env' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['env'])`.\n/Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages/lightning/pytorch/utilities/parsing.py:198: Attribute 'policy' is an instance of `nn.Module` and is already saved during checkpointing. It is recommended to ignore them using `self.save_hyperparameters(ignore=['policy'])`.\n/Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages/lightning/pytorch/trainer/connectors/accelerator_connector.py:551: You passed `Trainer(accelerator='cpu', precision='16-mixed')` but AMP with fp16 is not supported on CPU. Using `precision='bf16-mixed'` instead.\nUsing bfloat16 Automatic Mixed Precision (AMP)\nGPU available: False, used: False\nTPU available: False, using: 0 TPU cores\nIPU available: False, using: 0 IPUs\nHPU available: False, using: 0 HPUs\n/Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages/lightning/pytorch/trainer/connectors/logger_connector/logger_connector.py:67: Starting from v1.9.0, `tensorboardX` has been removed as a dependency of the `lightning.pytorch` package, due to potential conflicts with other packages in the ML ecosystem. For this reason, `logger=True` will use `CSVLogger` as the default logger, unless the `tensorboard` or `tensorboardX` packages are found. Please `pip install lightning[extra]` or one of them to enable TensorBoard support by default\nval_file not set. Generating dataset instead\ntest_file not set. Generating dataset instead\n\n  | Name     | Type           | Params\n--------------------------------------------\n0 | env      | FJSPEnv        | 0     \n1 | policy   | L2DPolicy      | 81.2 K\n2 | baseline | WarmupBaseline | 81.2 K\n--------------------------------------------\n162 K     Trainable params\n0         Non-trainable params\n162 K     Total params\n0.649     Total estimated model params size (MB)\n
Sanity Checking: |          | 0/? [00:00<?, ?it/s]
/Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'val_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=7` in the `DataLoader` to improve performance.\n/Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages/lightning/pytorch/trainer/connectors/data_connector.py:441: The 'train_dataloader' does not have many workers which may be a bottleneck. Consider increasing the value of the `num_workers` argument` to `num_workers=7` in the `DataLoader` to improve performance.\n/Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages/lightning/pytorch/loops/fit_loop.py:293: The number of training batches (32) is smaller than the logging interval Trainer(log_every_n_steps=50). Set a lower value for log_every_n_steps if you want to see logs for the training epoch.\n
Training: |          | 0/? [00:00<?, ?it/s]
/Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages/lightning/pytorch/trainer/call.py:54: Detected KeyboardInterrupt, attempting graceful shutdown...\n
In\u00a0[14]: Copied!
import gc\nfrom rl4co.envs import JSSPEnv\nfrom rl4co.models.zoo.l2d.model import L2DPPOModel\nfrom rl4co.models.zoo.l2d.policy import L2DPolicy4PPO\nfrom torch.utils.data import DataLoader\n
import gc from rl4co.envs import JSSPEnv from rl4co.models.zoo.l2d.model import L2DPPOModel from rl4co.models.zoo.l2d.policy import L2DPolicy4PPO from torch.utils.data import DataLoader In\u00a0[15]: Copied!
# Lets generate a more complex instance\n\ngenerator_params = {\n  \"num_jobs\": 15,  # the total number of jobs\n  \"num_machines\": 15,  # the total number of machines that can process operations\n  \"min_processing_time\": 1,  # the minimum time required for a machine to process an operation\n  \"max_processing_time\": 99,  # the maximum time required for a machine to process an operation\n}\n\nenv = JSSPEnv(\n    generator_params=generator_params, \n    _torchrl_mode=True, \n    stepwise_reward=True\n)\n
# Lets generate a more complex instance generator_params = { \"num_jobs\": 15, # the total number of jobs \"num_machines\": 15, # the total number of machines that can process operations \"min_processing_time\": 1, # the minimum time required for a machine to process an operation \"max_processing_time\": 99, # the maximum time required for a machine to process an operation } env = JSSPEnv( generator_params=generator_params, _torchrl_mode=True, stepwise_reward=True ) In\u00a0[16]: Copied!
# Policy: neural network, in this case with encoder-decoder architecture\npolicy = L2DPolicy4PPO(\n    embed_dim=embed_dim, \n    num_encoder_layers=num_encoder_layers, \n    env_name=\"jssp\",\n    het_emb=False\n)\n\nmodel = L2DPPOModel(\n    env=env,\n    policy=policy,\n    batch_size=batch_size,\n    train_data_size=train_data_size,\n    val_data_size=1_000,\n    optimizer_kwargs={\"lr\": 1e-4}\n)\n
# Policy: neural network, in this case with encoder-decoder architecture policy = L2DPolicy4PPO( embed_dim=embed_dim, num_encoder_layers=num_encoder_layers, env_name=\"jssp\", het_emb=False ) model = L2DPPOModel( env=env, policy=policy, batch_size=batch_size, train_data_size=train_data_size, val_data_size=1_000, optimizer_kwargs={\"lr\": 1e-4} ) In\u00a0[17]: Copied!
CHECKPOINT_PATH = \"last.ckpt\"\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\ntry:\n    model = L2DPPOModel.load_from_checkpoint(CHECKPOINT_PATH)\nexcept FileNotFoundError:\n\n    trainer = RL4COTrainer(\n        max_epochs=1,\n        accelerator=accelerator,\n        devices=1,\n        logger=None,\n    )\n\n    trainer.fit(model)\nfinally:\n    model = model.to(device)\n
CHECKPOINT_PATH = \"last.ckpt\" device = \"cuda\" if torch.cuda.is_available() else \"cpu\" try: model = L2DPPOModel.load_from_checkpoint(CHECKPOINT_PATH) except FileNotFoundError: trainer = RL4COTrainer( max_epochs=1, accelerator=accelerator, devices=1, logger=None, ) trainer.fit(model) finally: model = model.to(device)
Using bfloat16 Automatic Mixed Precision (AMP)\nGPU available: False, used: False\nTPU available: False, using: 0 TPU cores\nIPU available: False, using: 0 IPUs\nHPU available: False, using: 0 HPUs\nOverriding gradient_clip_val to None for 'automatic_optimization=False' models\n/Users/luttmann/opt/miniconda3/envs/rl4co/lib/python3.9/site-packages/lightning/pytorch/utilities/parsing.py:43: attribute 'policy' removed from hparams because it cannot be pickled\nval_file not set. Generating dataset instead\ntest_file not set. Generating dataset instead\n\n  | Name       | Type          | Params\n---------------------------------------------\n0 | env        | JSSPEnv       | 0     \n1 | policy     | L2DPolicy4PPO | 25.5 K\n2 | policy_old | L2DPolicy4PPO | 25.5 K\n---------------------------------------------\n51.1 K    Trainable params\n0         Non-trainable params\n51.1 K    Total params\n0.204     Total estimated model params size (MB)\n
Sanity Checking: |          | 0/? [00:00<?, ?it/s]
Training: |          | 0/? [00:00<?, ?it/s]
In\u00a0[8]: Copied!
%%bash\n\n# Define the folder path\nDATA_PATH=\"./taillard\"\n\n# Check if the folder exists\nif [ -d \"$DATA_PATH\" ]; then\n    echo \"Folder already exists.\"\nelse\n    echo \"Folder does not exist. Creating folder and downloading taillard instances...\"\n    mkdir -p \"$DATA_PATH\"\n    ! wget http://mistic.heig-vd.ch/taillard/problemes.dir/ordonnancement.dir/jobshop.dir/tai20_15.txt -O taillard/tai20_15.txt\n    ! wget http://mistic.heig-vd.ch/taillard/problemes.dir/ordonnancement.dir/jobshop.dir/tai15_15.txt -O taillard/tai15_15.txt\n    ! wget http://mistic.heig-vd.ch/taillard/problemes.dir/ordonnancement.dir/jobshop.dir/tai20_20.txt -O taillard/tai20_20.txt\n    ! wget http://mistic.heig-vd.ch/taillard/problemes.dir/ordonnancement.dir/jobshop.dir/tai30_15.txt -O taillard/tai30_15.txt\n    ! wget http://mistic.heig-vd.ch/taillard/problemes.dir/ordonnancement.dir/jobshop.dir/tai30_20.txt -O taillard/tai30_20.txt\nfi\n\nexit 0\n
%%bash # Define the folder path DATA_PATH=\"./taillard\" # Check if the folder exists if [ -d \"$DATA_PATH\" ]; then echo \"Folder already exists.\" else echo \"Folder does not exist. Creating folder and downloading taillard instances...\" mkdir -p \"$DATA_PATH\" ! wget http://mistic.heig-vd.ch/taillard/problemes.dir/ordonnancement.dir/jobshop.dir/tai20_15.txt -O taillard/tai20_15.txt ! wget http://mistic.heig-vd.ch/taillard/problemes.dir/ordonnancement.dir/jobshop.dir/tai15_15.txt -O taillard/tai15_15.txt ! wget http://mistic.heig-vd.ch/taillard/problemes.dir/ordonnancement.dir/jobshop.dir/tai20_20.txt -O taillard/tai20_20.txt ! wget http://mistic.heig-vd.ch/taillard/problemes.dir/ordonnancement.dir/jobshop.dir/tai30_15.txt -O taillard/tai30_15.txt ! wget http://mistic.heig-vd.ch/taillard/problemes.dir/ordonnancement.dir/jobshop.dir/tai30_20.txt -O taillard/tai30_20.txt fi exit 0
Folder does not exist. Creating folder and downloading taillard instances...\n
bash: line 11: wget: command not found\nbash: line 12: wget: command not found\nbash: line 13: wget: command not found\nbash: line 14: wget: command not found\nbash: line 15: wget: command not found\n
In\u00a0[18]: Copied!
# path to taillard instances\nFILE_PATH = \"./taillard/tai{instance_type}.txt\"\n\nresults = {}\ninstance_types = [\"15_15\", \"20_15\", \"20_20\", \"30_15\", \"30_20\"]\n\nfor instance_type in instance_types:\n    \n    dataset = env.dataset(batch_size=[10], phase=\"test\", filename=FILE_PATH.format(instance_type=instance_type))\n    dl = DataLoader(dataset, batch_size=5, collate_fn=dataset.collate_fn)\n    rewards = []\n    \n    for batch in dl:\n        td = env.reset(batch).to(device)\n        # use policy.generate to avoid grad calculations which can lead to oom \n        out = model.policy.generate(td, env=env, phase=\"test\", decode_type=\"multistart_sampling\", num_starts=100, select_best=True)\n        rewards.append(out[\"reward\"])\n\n    reward = torch.cat(rewards, dim=0).mean().item()\n    results[instance_type] = reward\n\n    print(\"Done evaluating instance type %s with reward %s\" % (instance_type, reward))\n\n    # avoid ooms due to cache not being cleared \n    model.rb.empty()\n    gc.collect()\n    torch.cuda.empty_cache()\n
# path to taillard instances FILE_PATH = \"./taillard/tai{instance_type}.txt\" results = {} instance_types = [\"15_15\", \"20_15\", \"20_20\", \"30_15\", \"30_20\"] for instance_type in instance_types: dataset = env.dataset(batch_size=[10], phase=\"test\", filename=FILE_PATH.format(instance_type=instance_type)) dl = DataLoader(dataset, batch_size=5, collate_fn=dataset.collate_fn) rewards = [] for batch in dl: td = env.reset(batch).to(device) # use policy.generate to avoid grad calculations which can lead to oom out = model.policy.generate(td, env=env, phase=\"test\", decode_type=\"multistart_sampling\", num_starts=100, select_best=True) rewards.append(out[\"reward\"]) reward = torch.cat(rewards, dim=0).mean().item() results[instance_type] = reward print(\"Done evaluating instance type %s with reward %s\" % (instance_type, reward)) # avoid ooms due to cache not being cleared model.rb.empty() gc.collect() torch.cuda.empty_cache()
Provided file name ../../ai4co/rl4co/data/jssp/taillard/15j_15m not found. Make sure to provide a file in the right path first or unset test_file to generate data automatically instead\n
Done evaluating instance type 15j_15m with reward -1408.0999755859375\n
Provided file name ../../ai4co/rl4co/data/jssp/taillard/20j_15m not found. Make sure to provide a file in the right path first or unset test_file to generate data automatically instead\nProvided file name ../../ai4co/rl4co/data/jssp/taillard/20j_20m not found. Make sure to provide a file in the right path first or unset test_file to generate data automatically instead\n
Done evaluating instance type 20j_15m with reward -1380.699951171875\n
Provided file name ../../ai4co/rl4co/data/jssp/taillard/30j_15m not found. Make sure to provide a file in the right path first or unset test_file to generate data automatically instead\n
Done evaluating instance type 20j_20m with reward -1349.9000244140625\n
Provided file name ../../ai4co/rl4co/data/jssp/taillard/30j_20m not found. Make sure to provide a file in the right path first or unset test_file to generate data automatically instead\n
Done evaluating instance type 30j_15m with reward -1374.0999755859375\nDone evaluating instance type 30j_20m with reward -1371.699951171875\n
"},{"location":"examples/other/2-scheduling/#solving-the-flexible-job-shop-scheduling-problem-fjsp","title":"Solving the Flexible Job-Shop Scheduling Problem (FJSP)\u00b6","text":"

The following notebook explains the FJSP and explains the solution construction process using an encoder-decoder architecture based on a Heterogeneous Graph Neural Network (HetGNN)

"},{"location":"examples/other/2-scheduling/#visualize-the-problem","title":"Visualize the Problem\u00b6","text":"

Below we visualize the generated instance of the FJSP. Blue nodes correspond to machines, red nodes to operations and yellow nodes to jobs. A machine may process an operation if there exists an edge between the two.

The thickness of the connection between a machine and an operation node specifies the processing time the respective machine needs to process the operation (thicker line := longer processing).

Each operation belongs to exactly one job, where an edge between a job and an operation node indicates that the respective operation belongs to the job. The number above an operation-job edge specifies the precedence-order in which the operations of a job need to be processed. A job is done when all operations belonging to it are scheduled. The instance is solved when all jobs are fully scheduled.

Also note that some operation nodes are not connected. These operation nodes are padded, so that all instances in a batch have the same number of operations (where we determine the maximum number of operations as num_jobs * max_ops_per_job).

"},{"location":"examples/other/2-scheduling/#build-a-model-to-solve-the-fjsp","title":"Build a Model to Solve the FJSP\u00b6","text":"

In the FJSP we typically encode Operations and Machines separately, since they pose different node types in a k-partite Graph. Therefore, the encoder for the FJSP returns two hidden representations, the first containing machine embeddings and the second containing operation embeddings:

"},{"location":"examples/other/2-scheduling/#visualize-solution-construction","title":"Visualize solution construction\u00b6","text":"

Starting at $t=0$, the decoder uses the machine-operation embeddings of the encoder to decide which machine-job-combination to schedule next. Note, that due to the precedence relationship, the operations to be scheduled next are fixed per job. Therefore, it is sufficient to determine the next job to be scheduled, which significantly reduces the action space.

After some operations have been scheduled, either all the machines are busy or all the jobs have been scheduled with their currently active operation. In this case, the environment transitions to a new time step $t$. The new $t$ will be equal to the first time step where a machine finishes an operation in the partial schedule. When an operation is finished, the machine that has processed it is immediately ready to process the next operation. Also, the next operation of the respective job can then be scheduled.

The start time of an operation is always equal to the time step in which it is scheduled. The finish time of an operation is equal to its start time plus the processing time required by the machine on which it is being processed.

The figure below visualises this process.

"},{"location":"examples/other/2-scheduling/#solving-the-job-shop-scheduling-problem-jssp","title":"Solving the Job-Shop Scheduling Problem (JSSP)\u00b6","text":""},{"location":"examples/other/2-scheduling/#train-on-synthetic-data-and-test-on-taillard-benchmark","title":"Train on synthetic data and test on Taillard benchmark\u00b6","text":""},{"location":"examples/other/3-data-generator-distributions/","title":"Generating data in RL4CO","text":"In\u00a0[1]: Copied!
import matplotlib.pyplot as plt\nfrom rl4co.envs.routing import TSPEnv, TSPGenerator\nfrom rl4co.envs.common.distribution_utils import Cluster, Mix_Distribution, Mix_Multi_Distributions, Gaussian_Mixture, Mixed\n\n# Instantiate the environment and generator\ngenerator = TSPGenerator(num_loc=100)\nenv = TSPEnv(generator=generator)\n\n# Simple plot\nfig, axs = plt.subplots(1, 3, figsize=(10, 3))\ntd = env.generator(3) # generate 3 instances\nfor i in range(3):\n    axs[i].scatter(td[\"locs\"][i][:, 0], td[\"locs\"][i][:, 1])\n    axs[i].set_xticks([]); axs[i].set_yticks([])\nfig.suptitle(\"TSP with 100 locations, uniform distribution\")\n
import matplotlib.pyplot as plt from rl4co.envs.routing import TSPEnv, TSPGenerator from rl4co.envs.common.distribution_utils import Cluster, Mix_Distribution, Mix_Multi_Distributions, Gaussian_Mixture, Mixed # Instantiate the environment and generator generator = TSPGenerator(num_loc=100) env = TSPEnv(generator=generator) # Simple plot fig, axs = plt.subplots(1, 3, figsize=(10, 3)) td = env.generator(3) # generate 3 instances for i in range(3): axs[i].scatter(td[\"locs\"][i][:, 0], td[\"locs\"][i][:, 1]) axs[i].set_xticks([]); axs[i].set_yticks([]) fig.suptitle(\"TSP with 100 locations, uniform distribution\")
/home/botu/anaconda3/envs/rl4co/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n  from .autonotebook import tqdm as notebook_tqdm\n
Out[1]:
Text(0.5, 0.98, 'TSP with 100 locations, uniform distribution')

Generating data with different sizes

In\u00a0[2]: Copied!
generator = TSPGenerator(num_loc=1000)\nenv.generator = generator\n\nfig, axs = plt.subplots(1, 3, figsize=(10, 3))\ntd = env.generator(3) # generate 3 instances\nfor i in range(3):\n    axs[i].scatter(td[\"locs\"][i][:, 0], td[\"locs\"][i][:, 1])\n    axs[i].set_xticks([]); axs[i].set_yticks([])\nfig.suptitle(\"TSP with 1000 locations, uniform distribution\")\n
generator = TSPGenerator(num_loc=1000) env.generator = generator fig, axs = plt.subplots(1, 3, figsize=(10, 3)) td = env.generator(3) # generate 3 instances for i in range(3): axs[i].scatter(td[\"locs\"][i][:, 0], td[\"locs\"][i][:, 1]) axs[i].set_xticks([]); axs[i].set_yticks([]) fig.suptitle(\"TSP with 1000 locations, uniform distribution\") Out[2]:
Text(0.5, 0.98, 'TSP with 1000 locations, uniform distribution')

Changing distribution of the data to normal distribution. We can pass the arguments to it by using loc_ + distribution name as well as its keyword arguments, including here the mean and std of the normal distribution

In\u00a0[3]: Copied!
generator = TSPGenerator(num_loc=100, loc_distribution=\"normal\", loc_mean=0, loc_std=1)\nenv.generator = generator\n\nfig, axs = plt.subplots(1, 3, figsize=(10, 3))\ntd = env.generator(3) # generate 3 instances\nfor i in range(3):\n    axs[i].scatter(td[\"locs\"][i][:, 0], td[\"locs\"][i][:, 1])\n    axs[i].set_xticks([]); axs[i].set_yticks([])\nfig.suptitle(\"TSP with 100 locations, normal distribution\")\n
generator = TSPGenerator(num_loc=100, loc_distribution=\"normal\", loc_mean=0, loc_std=1) env.generator = generator fig, axs = plt.subplots(1, 3, figsize=(10, 3)) td = env.generator(3) # generate 3 instances for i in range(3): axs[i].scatter(td[\"locs\"][i][:, 0], td[\"locs\"][i][:, 1]) axs[i].set_xticks([]); axs[i].set_yticks([]) fig.suptitle(\"TSP with 100 locations, normal distribution\") Out[3]:
Text(0.5, 0.98, 'TSP with 100 locations, normal distribution')

We can pass a custom loc_sampler to the generator (we can make it ourselves!) to generate data from a custom distribution. In this case we use the mixture of three exemplar distributions in batch-level, i.e. Uniform, Cluster, Mixed following the setting in Bi et al. 2022 (https://arxiv.org/abs/2210.07686)

In\u00a0[4]: Copied!
loc_sampler = Mix_Distribution(n_cluster=3)\ngenerator = TSPGenerator(num_loc=200, loc_sampler=loc_sampler)\nenv.generator = generator\n\nfig, axs = plt.subplots(1, 3, figsize=(10, 3))\ntd = env.generator(3) # generate 3 instances\nfor i in range(3):\n    axs[i].scatter(td[\"locs\"][i][:, 0], td[\"locs\"][i][:, 1])\n    axs[i].set_xticks([]); axs[i].set_yticks([])\nfig.suptitle(\"TSP with 200 locations, mixed distribution\")\n
loc_sampler = Mix_Distribution(n_cluster=3) generator = TSPGenerator(num_loc=200, loc_sampler=loc_sampler) env.generator = generator fig, axs = plt.subplots(1, 3, figsize=(10, 3)) td = env.generator(3) # generate 3 instances for i in range(3): axs[i].scatter(td[\"locs\"][i][:, 0], td[\"locs\"][i][:, 1]) axs[i].set_xticks([]); axs[i].set_yticks([]) fig.suptitle(\"TSP with 200 locations, mixed distribution\") Out[4]:
Text(0.5, 0.98, 'TSP with 200 locations, mixed distribution')
In\u00a0[5]: Copied!
from rl4co.envs.graph import MCPEnv, MCPGenerator\nfrom matplotlib import pyplot as plt\nimport torch\nfrom collections import Counter\n\ngenerator = MCPGenerator(size_distribution=\"uniform\", weight_distribution=\"uniform\")\nenv = MCPEnv(generator=generator)\ndata = env.generator(100)\n\nsizes = torch.count_nonzero(data[\"membership\"], dim=-1).flatten().tolist()\nsize2cnt = Counter(sizes)\nweights = data[\"weights\"].flatten().tolist()\nweight2cnt = Counter(weights)\n\n# plot the size distributions and the weight distributions\nplt.figure()\nplt.bar(size2cnt.keys(), size2cnt.values())\nplt.title(\"Size distribution\")\nplt.xlabel(\"Size\")\nplt.ylabel(\"Probability\")\nplt.show()\n\n# Note: the size distributions are not perfectly uniform since there might be repeated items and are removed in post-processing\n\nplt.figure()\nplt.bar(weight2cnt.keys(), weight2cnt.values())\nplt.title(\"Weight distribution\")\nplt.xlabel(\"Weight\")\nplt.ylabel(\"Probability\")\nplt.show()\n
from rl4co.envs.graph import MCPEnv, MCPGenerator from matplotlib import pyplot as plt import torch from collections import Counter generator = MCPGenerator(size_distribution=\"uniform\", weight_distribution=\"uniform\") env = MCPEnv(generator=generator) data = env.generator(100) sizes = torch.count_nonzero(data[\"membership\"], dim=-1).flatten().tolist() size2cnt = Counter(sizes) weights = data[\"weights\"].flatten().tolist() weight2cnt = Counter(weights) # plot the size distributions and the weight distributions plt.figure() plt.bar(size2cnt.keys(), size2cnt.values()) plt.title(\"Size distribution\") plt.xlabel(\"Size\") plt.ylabel(\"Probability\") plt.show() # Note: the size distributions are not perfectly uniform since there might be repeated items and are removed in post-processing plt.figure() plt.bar(weight2cnt.keys(), weight2cnt.values()) plt.title(\"Weight distribution\") plt.xlabel(\"Weight\") plt.ylabel(\"Probability\") plt.show()

We can also pass a custom sampler to generate data:

In\u00a0[6]: Copied!
from collections import Counter\nfrom torch.distributions import Normal\n\nsize_sampler = Normal(10, 2)\nweight_sampler = Normal(5, 1)\n\ngenerator = MCPGenerator(size_sampler=size_sampler, weight_sampler=weight_sampler)\nenv = MCPEnv(generator=generator)\ndata = env.generator(100)\n\nsizes = torch.count_nonzero(data[\"membership\"], dim=-1).flatten().tolist()\nsize2cnt = Counter(sizes)\nweights = data[\"weights\"].flatten().tolist()\nweight2cnt = Counter(weights)\n\n# plot the size distributions and the weight distributions\nplt.figure()\nplt.bar(size2cnt.keys(), size2cnt.values())\nplt.title(\"Size distribution\")\nplt.xlabel(\"Size\")\nplt.ylabel(\"Probability\")\nplt.show()\n\nplt.figure()\nplt.bar(weight2cnt.keys(), weight2cnt.values())\nplt.title(\"Weight distribution\")\nplt.xlabel(\"Weight\")\nplt.ylabel(\"Probability\")\nplt.show()\n
from collections import Counter from torch.distributions import Normal size_sampler = Normal(10, 2) weight_sampler = Normal(5, 1) generator = MCPGenerator(size_sampler=size_sampler, weight_sampler=weight_sampler) env = MCPEnv(generator=generator) data = env.generator(100) sizes = torch.count_nonzero(data[\"membership\"], dim=-1).flatten().tolist() size2cnt = Counter(sizes) weights = data[\"weights\"].flatten().tolist() weight2cnt = Counter(weights) # plot the size distributions and the weight distributions plt.figure() plt.bar(size2cnt.keys(), size2cnt.values()) plt.title(\"Size distribution\") plt.xlabel(\"Size\") plt.ylabel(\"Probability\") plt.show() plt.figure() plt.bar(weight2cnt.keys(), weight2cnt.values()) plt.title(\"Weight distribution\") plt.xlabel(\"Weight\") plt.ylabel(\"Probability\") plt.show()

Tl;dr: RL4CO allows for easily generating data for CO problems! \ud83d\ude80

"},{"location":"examples/other/3-data-generator-distributions/#generating-data-in-rl4co","title":"Generating data in RL4CO\u00b6","text":"

RL4CO allows for easily generating data from different distributions for CO problems

"},{"location":"examples/other/3-data-generator-distributions/#generating-different-distributions-for-tsp","title":"Generating different distributions for TSP\u00b6","text":""},{"location":"examples/other/3-data-generator-distributions/#generating-different-distributions-for-mcp","title":"Generating different distributions for MCP\u00b6","text":"

In here we visualize the different weight and size distributions for MCP by passing the distribution name, which is automatically parsed:

"},{"location":"rl4co/tasks/","title":"Evaluation","text":"

To evaluate your trained model, here are some steps to follow:

Step 1. Prepare your pre-trained model checkpoint and test instances data file. Put them in your preferred place. e.g., we will test the AttentionModel on TSP50:

.\n\u251c\u2500\u2500 rl4co/\n\u2502   \u2514\u2500\u2500 ...\n\u251c\u2500\u2500 checkpoints/\n\u2502   \u2514\u2500\u2500 am-tsp50.ckpt\n\u2514\u2500\u2500 data/\n    \u2514\u2500\u2500 tsp/\n        \u2514\u2500\u2500 tsp50_test_seed1234.npz\n

You can generate the test instances data file by running the following command:

python -c \"from rl4co.data.generate_data import generate_default_datasets; generate_default_datasets('data')\"\n

Step 2. Run the eval.py with your customized setting. e.g., let's use the sampling method with a top_p=0.95 sampling strategy:

python rl4co/tasks/eval.py --problem tsp --data-path data/tsp/tsp50_test_seed1234.npz --model AttentionModel --ckpt-path checkpoints/am-tsp50.ckpt --method sampling --top-p 0.95\n

Arguments guideline:

  • --problem: the problem name, e.g., tsp, cvrp, pdp, etc. This should be consistent with the env.name. Default is tsp.
  • --generator-params: the generator parameters for the test instances. You could specify the num_loc etc. Default is {'num_loc': 50}.
  • --data-path: the path to the test instances data file. Default is data/tsp/tsp50_test_seed1234.npz.
  • --model: the model class name, e.g., AttentionModel, POMO, SymNCO, etc. It will be dynamically imported and instantiated. Default is AttentionModel.
  • --ckpt-path: the path to the pre-trained model checkpoint. Default is checkpoints/am-tsp50.ckpt.
  • --device: the device to run the evaluation, e.g., cuda:0, cpu, etc. Default is cuda:0.
  • --method: the evaluation method, e.g., greedy, sampling, multistart_greedy, augment_dihedral_8, augment, multistart_greedy_augment_dihedral_8, and multistart_greedy_augment. Default is greedy.
  • --save-results: whether to save the evaluation results as a .pkl file. Deafult is True. The results include actions, rewards, inference_time, and avg_reward.
  • --save-path: the path to save the evaluation results. Default is results/.
  • --num-instances: the number of test instances to evaluate. Default is 1000.

If you use the sampling method, you may need to specify the following parameters:

  • --samples: the number of samples for the sampling method. Default is 1280.
  • --temperature: the temperature for the sampling method. Default is 1.0.
  • --top-p: the top-p for the sampling method. Default is 0.0, i.e. not activated.
  • --top-k: the top-k for the sampling method. Deafult is 0, i.e. not activated.
  • --select-best: whether to select the best action from the sampling results. If False, the results will include all sampled rewards, i.e., [num_instances * num_samples].

If you use the augment method, you may need to specify the following parameters:

  • --num-augments: the number of augmented instances for the augment method. Default is 8.
  • --force-dihedral-8: whether to force the augmented instances to be dihedral 8. Default is True.

Step 3. If you want to launch several evaluations with various parameters, you may refer to the following examples:

  • Evaluate POMO on TSP50 with a sampling of different Top-p and temperature:
        #!/bin/bash\n\n    top_p_list=(0.5 0.6 0.7 0.8 0.9 0.95 0.98 0.99 0.995 1.0)\n    temp_list=(0.1 0.3 0.5 0.7 0.8 0.9 1.0 1.1 1.2 1.5 1.8 2.0 2.2 2.5 2.8 3.0)\n\n    device=cuda:0\n\n    problem=tsp\n    model=POMO\n    ckpt_path=checkpoints/pomo-tsp50.ckpt\n    data_path=data/tsp/tsp50_test_seed1234.npz\n\n    num_instances=1000\n    save_path=results/tsp50-pomo-topp-1k\n\n    for top_p in ${top_p_list[@]}; do\n        for temp in ${temp_list[@]}; do\n            python rl4co/tasks/eval.py --problem ${problem} --model ${model} --ckpt_path ${ckpt_path} --data_path ${data_path} --save_path ${save_path} --method sampling --temperature=${temp} --top_p=${top_p} --top_k=0 --device ${device}\n        done\n    done\n
  • Evaluate POMO on CVRP50 with a sampling of different Top-k and temperature:
        #!/bin/bash\n\n    top_k_list=(5 10 15 20 25)\n    temp_list=(0.1 0.3 0.5 0.7 0.8 0.9 1.0 1.1 1.2 1.5 1.8 2.0 2.2 2.5 2.8 3.0)\n\n    device=cuda:1\n\n    problem=cvrp\n    model=POMO\n    ckpt_path=checkpoints/pomo-cvrp50.ckpt\n    data_path=data/vrp/vrp50_test_seed1234.npz\n\n    num_instances=1000\n    save_path=results/cvrp50-pomo-topk-1k\n\n    for top_k in ${top_k_list[@]}; do\n        for temp in ${temp_list[@]}; do\n            python rl4co/tasks/eval.py --problem ${problem} --model ${model} --ckpt_path ${ckpt_path} --data_path ${data_path} --save_path ${save_path} --method sampling --temperature=${temp} --top_p=0.0 --top_k=${top_k} --device ${device}\n        done\n    done\n
"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 00000000..febe0a7c --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,223 @@ + + + + https://ai4co.github.io/rl4co/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/README_backup/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/data/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/decoding/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/tasks/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/train_and_eval/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/envs/base/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/envs/eda/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/envs/graph/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/envs/routing/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/envs/scheduling/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/networks/base_policies/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/networks/env_embeddings/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/networks/improvement_policies/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/networks/nn/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/rl/a2c/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/rl/base/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/rl/ppo/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/rl/reinforce/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/zoo/constructive_ar/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/zoo/constructive_nar/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/zoo/improvement/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/api/zoo/transductive/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/general/ai4co/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/general/contribute/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/general/faq/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/general/licensing/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/general/paper/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/intro/environments/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/intro/intro/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/intro/policies/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/intro/rl/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/start/hydra/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/docs/content/start/installation/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/1-quickstart/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/2-full-training/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/3-creating-new-env-model/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/advanced/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/advanced/1-hydra-config/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/advanced/2-flash-attention-2/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/advanced/3-local-search/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/datasets/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/datasets/1-test-on-tsplib/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/datasets/2-test-on-cvrplib/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/modeling/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/modeling/1-decoding-strategies/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/modeling/2-transductive-methods/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/modeling/3-change-encoder/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/other/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/other/1-mtvrp/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/other/2-scheduling/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/examples/other/3-data-generator-distributions/ + 2024-09-18 + + + https://ai4co.github.io/rl4co/rl4co/tasks/ + 2024-09-18 + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..361757143747c99b6d904d1f6d7232bf7bbded25 GIT binary patch literal 678 zcmV;X0$KeZiwFn+80uyM|8r?{Wo=<_E_iKh0L_`bZrd;rfcHFw;r&cY$&eI|g91&r zE=4;VXYwo&rbvc7$!VXyl#~cTx1xYa4YDXxybq`QrFKuRommYOqIULiU2V4O6+fA|EJgoOO zt8|PD%vaN~GfwWuRbpBO^__H^MswRAH`<9{(pc=oIOpRd7`bz5UvKL>*gimYpQgOs zn`MYa$iIvG{`~pNx97tV<+=CQ7OtF(S!7CQnJf$RS}0`94?(l-Wd~u5=lt)418RFf zs}3}v$&N#Ih~kKm${-pReOm@fa6OmcKNHND4^(eT;IYIP7tXW!9=tPJYKrAx zC4C*JJCYisUqM{D^T7?&r9TSPnzh+kf)QBD5-^Gg%!$K$R{};LZBH)9{5tvV+&GRL zddYgA1BUXLY#~q|0!|S;sRXl8%}UA&)R3i+ioj`V5hUX{=wr`iDCUGOMR24fNjBy# zdfsU~ddlnBI$4Pu3mhGs9sN2MfHR--a}-fi%_t#ngBckEi}sfaSOAAksS%Aq*6!*x zCcR?k&Gl_!kz2t_ujP5xL@tOLPQ5WOZGmJ6rVGa{$UrzY)nMrYDULysKqeayssXJe zl^>vj$z372&Pg}Y>I#mEy$`UQwhG6=7 zcKwQbA#&VimtH}~$&oTs)R1rg`7e}P7-J30JsG DictConfig: + with initialize(config_path="../configs"): + cfg = compose(config_name="main.yaml", return_hydra_config=True, overrides=[]) + + # set defaults for all tests + with open_dict(cfg): + cfg.paths.root_dir = str(pyrootutils.find_root(indicator=".gitignore")) + cfg.trainer.max_epochs = 1 + cfg.model.train_data_size = 100 + cfg.model.val_data_size = 100 + cfg.model.test_data_size = 100 + cfg.model.batch_size = 2 # faster for CPU (not sure exactly why) + cfg.env.val_file = None # validate on self-generated data + cfg.env.test_file = None # validate on self-generated data + cfg.trainer.accelerator = "cpu" + cfg.trainer.devices = 1 + cfg.extras.print_config = False + cfg.extras.enforce_tags = False + cfg.logger = None + cfg.callbacks.learning_rate_monitor = None + + return cfg + + +@pytest.fixture(scope="function") +def cfg_train(cfg_train_global, tmp_path) -> DictConfig: + cfg = cfg_train_global.copy() + + with open_dict(cfg): + cfg.paths.output_dir = str(tmp_path) + cfg.paths.log_dir = str(tmp_path) + + yield cfg + + GlobalHydra.instance().clear() + + +# Skip if Python < 3.9 due to following error: +# AttributeError: 'OrphanPath' object has no attribute 'exists' +@pytest.mark.skipif( + sys.version_info[1] < 9, + reason="Python<3.9 raises error: 'OrphanPath' object has no attribute 'exists'", +) +def test_train_fast_dev_run(cfg_train): + """Run for 1 train, val and test step.""" + HydraConfig().set_config(cfg_train) + with open_dict(cfg_train): + cfg_train.trainer.fast_dev_run = True + cfg_train.trainer.accelerator = "cpu" + run(cfg_train) + + +@pytest.mark.parametrize( + "method", + ["greedy", "sampling", "multistart_greedy", "augment", "multistart_greedy_augment"], +) +def test_eval(method): + env = TSPEnv(generator_params=dict(num_loc=20)) + policy = AttentionModelPolicy(env_name=env.name) + out = evaluate_policy(env, policy, env.dataset(3), method=method) + assert out["rewards"].shape == (3,) diff --git a/tests/test_training.py b/tests/test_training.py new file mode 100644 index 00000000..07d23a25 --- /dev/null +++ b/tests/test_training.py @@ -0,0 +1,312 @@ +import os +import sys + +import pytest + +from rl4co.envs import ( + ATSPEnv, + FJSPEnv, + JSSPEnv, + PDPEnv, + PDPRuinRepairEnv, + TSPEnv, + TSPkoptEnv, +) +from rl4co.models.rl import A2C, PPO, REINFORCE +from rl4co.models.zoo import ( + DACT, + MDAM, + N2S, + POMO, + ActiveSearch, + AttentionModelPolicy, + DeepACO, + EASEmb, + EASLay, + HeterogeneousAttentionModel, + L2DPPOModel, + MatNet, + NARGNNPolicy, + NeuOpt, + PolyNet, + SymNCO, +) +from rl4co.utils import RL4COTrainer +from rl4co.utils.meta_trainer import ReptileCallback + +# Get env variable MAC_OS_GITHUB_RUNNER +if "MAC_OS_GITHUB_RUNNER" in os.environ: + accelerator = "cpu" +else: + accelerator = "auto" + + +# Test out simple training loop and test with multiple baselines +@pytest.mark.parametrize("baseline", ["rollout", "exponential", "mean", "no", "critic"]) +def test_reinforce(baseline): + env = TSPEnv(generator_params=dict(num_loc=20)) + policy = AttentionModelPolicy(env_name=env.name) + model = REINFORCE( + env, + policy, + baseline=baseline, + train_data_size=10, + val_data_size=10, + test_data_size=10, + ) + trainer = RL4COTrainer(max_epochs=1, devices=1, accelerator=accelerator) + trainer.fit(model) + trainer.test(model) + + +def test_a2c(): + env = TSPEnv(generator_params=dict(num_loc=20)) + policy = AttentionModelPolicy(env_name=env.name) + model = A2C(env, policy, train_data_size=10, val_data_size=10, test_data_size=10) + trainer = RL4COTrainer(max_epochs=1, devices=1, accelerator=accelerator) + trainer.fit(model) + trainer.test(model) + + +def test_ppo(): + env = TSPEnv(generator_params=dict(num_loc=20)) + policy = AttentionModelPolicy(env_name=env.name) + model = PPO(env, policy, train_data_size=10, val_data_size=10, test_data_size=10) + trainer = RL4COTrainer( + max_epochs=1, gradient_clip_val=None, devices=1, accelerator=accelerator + ) + trainer.fit(model) + trainer.test(model) + + +def test_symnco(): + env = TSPEnv(generator_params=dict(num_loc=20)) + model = SymNCO( + env, + train_data_size=10, + val_data_size=10, + test_data_size=10, + num_augment=2, + num_starts=20, + ) + trainer = RL4COTrainer(max_epochs=1, devices=1, accelerator=accelerator) + trainer.fit(model) + trainer.test(model) + + +def test_ham(): + env = PDPEnv(generator_params=dict(num_loc=20)) + model = HeterogeneousAttentionModel( + env, train_data_size=10, val_data_size=10, test_data_size=10 + ) + trainer = RL4COTrainer(max_epochs=1, devices=1, accelerator=accelerator) + trainer.fit(model) + trainer.test(model) + + +def test_matnet(): + env = ATSPEnv(generator_params=dict(num_loc=20)) + model = MatNet( + env, + baseline="shared", + train_data_size=10, + val_data_size=10, + test_data_size=10, + ) + trainer = RL4COTrainer(max_epochs=1, devices=1, accelerator=accelerator) + trainer.fit(model) + trainer.test(model) + + +def test_mdam(): + env = TSPEnv(generator_params=dict(num_loc=20)) + model = MDAM( + env, + train_data_size=10, + val_data_size=10, + test_data_size=10, + ) + trainer = RL4COTrainer(max_epochs=1, devices=1, accelerator=accelerator) + trainer.fit(model) + trainer.test(model) + + +def test_pomo_reptile(): + env = TSPEnv(generator_params=dict(num_loc=20)) + policy = AttentionModelPolicy( + env_name=env.name, + embed_dim=128, + num_encoder_layers=6, + num_heads=8, + normalization="instance", + use_graph_context=False, + ) + model = POMO( + env, + policy, + batch_size=5, + train_data_size=5 * 3, + val_data_size=10, + test_data_size=10, + ) + meta_callback = ReptileCallback( + data_type="size", + sch_bar=0.9, + num_tasks=2, + alpha=0.99, + alpha_decay=0.999, + min_size=20, + max_size=50, + ) + trainer = RL4COTrainer( + max_epochs=2, + callbacks=[meta_callback], + devices=1, + accelerator=accelerator, + limit_train_batches=3, + ) + trainer.fit(model) + trainer.test(model) + + +@pytest.mark.parametrize("SearchMethod", [ActiveSearch, EASEmb, EASLay]) +def test_search_methods(SearchMethod): + env = TSPEnv(generator_params=dict(num_loc=20)) + batch_size = 2 if SearchMethod not in [ActiveSearch] else 1 + dataset = env.dataset(2) + policy = AttentionModelPolicy(env_name=env.name) + model = SearchMethod(env, policy, dataset, max_iters=2, batch_size=batch_size) + trainer = RL4COTrainer(max_epochs=1, devices=1, accelerator=accelerator) + trainer.fit(model) + trainer.test(model) + + +@pytest.mark.skipif( + "torch_geometric" not in sys.modules, reason="PyTorch Geometric not installed" +) +def test_nargnn(): + env = TSPEnv(generator_params=dict(num_loc=20)) + policy = NARGNNPolicy(env_name=env.name) + model = REINFORCE( + env, policy=policy, train_data_size=10, val_data_size=10, test_data_size=10 + ) + trainer = RL4COTrainer( + max_epochs=1, gradient_clip_val=None, devices=1, accelerator=accelerator + ) + trainer.fit(model) + trainer.test(model) + + +@pytest.mark.skipif( + "torch_geometric" not in sys.modules, reason="PyTorch Geometric not installed" +) +@pytest.mark.skipfif("numba" not in sys.modules, reason="Numba not installed") +def test_deepaco(): + env = TSPEnv(generator_params=dict(num_loc=20)) + model = DeepACO( + env, + train_data_size=10, + val_data_size=10, + test_data_size=10, + policy_kwargs={"n_ants": 5}, + ) + trainer = RL4COTrainer( + max_epochs=1, gradient_clip_val=1, devices=1, accelerator=accelerator + ) + trainer.fit(model) + trainer.test(model) + + +def test_n2s(): + env = PDPRuinRepairEnv(generator_params=dict(num_loc=20)) + model = N2S( + env, + train_data_size=10, + val_data_size=10, + test_data_size=10, + n_step=2, + T_train=4, + T_test=4, + ) + trainer = RL4COTrainer( + max_epochs=1, + gradient_clip_val=0.05, + devices=1, + accelerator=accelerator, + ) + trainer.fit(model) + trainer.test(model) + + +def test_dact(): + env = TSPkoptEnv(generator_params=dict(num_loc=20), k_max=2) + model = DACT( + env, + train_data_size=10, + val_data_size=10, + test_data_size=10, + n_step=2, + T_train=4, + T_test=4, + CL_best=True, + ) + trainer = RL4COTrainer( + max_epochs=1, + gradient_clip_val=0.05, + devices=1, + accelerator=accelerator, + ) + trainer.fit(model) + trainer.test(model) + + +def test_neuopt(): + env = TSPkoptEnv(generator_params=dict(num_loc=20), k_max=4) + model = NeuOpt( + env, + train_data_size=10, + val_data_size=10, + test_data_size=10, + n_step=2, + T_train=4, + T_test=4, + CL_best=True, + ) + trainer = RL4COTrainer( + max_epochs=1, + gradient_clip_val=0.05, + devices=1, + accelerator=accelerator, + ) + trainer.fit(model) + trainer.test(model) + + +@pytest.mark.parametrize("env_cls", [FJSPEnv, JSSPEnv]) +def test_l2d_ppo(env_cls): + env = env_cls(stepwise_reward=True, _torchrl_mode=True) + model = L2DPPOModel( + env, train_data_size=10, val_data_size=10, test_data_size=10, buffer_size=1000 + ) + trainer = RL4COTrainer( + max_epochs=1, + gradient_clip_val=0.05, + devices=1, + accelerator=accelerator, + ) + trainer.fit(model) + trainer.test(model) + + +def test_polynet(): + env = TSPEnv(generator_params=dict(num_loc=20)) + model = PolyNet( + env, + k=10, + train_data_size=10, + val_data_size=10, + test_data_size=10, + ) + trainer = RL4COTrainer(max_epochs=1, devices=1, accelerator=accelerator) + trainer.fit(model) + trainer.test(model) diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 00000000..a2494e80 --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,37 @@ +import pytest +import torch + +from tensordict import TensorDict + +from rl4co.utils.decoding import process_logits +from rl4co.utils.ops import batchify, unbatchify + + +@pytest.mark.parametrize( + "a", + [ + torch.randn(10, 20, 2), + TensorDict( + {"a": torch.randn(10, 20, 2), "b": torch.randn(10, 20, 2)}, batch_size=10 + ), + ], +) +@pytest.mark.parametrize("shape", [(2,), (2, 2), (2, 2, 2)]) +def test_batchify(a, shape): + # batchify: [b, ...] -> [b * prod(shape), ...] + # unbatchify: [b * prod(shape), ...] -> [b, shape[0], shape[1], ...] + a_batch = batchify(a, shape) + a_unbatch = unbatchify(a_batch, shape) + if isinstance(a, TensorDict): + a, a_unbatch = a["a"], a_unbatch["a"] + index = (slice(None),) + (0,) * len(shape) # (slice(None), 0, 0, ..., 0) + assert torch.allclose(a, a_unbatch[index]) + + +@pytest.mark.parametrize("top_p", [0.0, 0.5, 1.0]) +@pytest.mark.parametrize("top_k", [0, 5, 10]) +def test_top_k_top_p_sampling(top_p, top_k): + logits = torch.randn(8, 10) + mask = torch.ones(8, 10).bool() + logprobs = process_logits(logits, mask, top_p=top_p, top_k=top_k) + assert len(logprobs) == logits.size(0)