Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wrong future stop tick predictions 馃悰 #384

Closed
riccardopoiani opened this issue Aug 6, 2021 · 9 comments
Closed

Wrong future stop tick predictions 馃悰 #384

riccardopoiani opened this issue Aug 6, 2021 · 9 comments
Labels
馃悰 bug Something isn't working.

Comments

@riccardopoiani
Copy link

riccardopoiani commented Aug 6, 2021

Description

There is a strange behavior in future_stop_tick_list attributes.
As you can see, the current tick is 100, and yet there are future vessel tick predictions that are way behind the current tick, for instance [ 75., 88., 96.].

I would expect the snapshot to retrieve ticks that are always ahead of the current one.

To Reproduce

from maro.backends.frame import SnapshotList
from maro.simulator import Env
from pprint import pprint
from typing import List
import numpy as np

# Initialize an Env for CIM scenario
env = Env(scenario="cim", topology="global_trade.22p_l0.8", start_tick=0, durations=200)
    
# Start the environment with None action
_, event, is_done = env.step(None)

event_list_2 = []
while not is_done:
    event_list_2.append((event.port_idx, event.vessel_idx, event.tick))
    metrics, event, is_done = env.step(None)

vs = env.snapshot_list['vessels']
vs[100:[i for i in range(45)]:'future_stop_tick_list'].reshape(45, 3)

Here you can find that output that I had:

array([[ 92., 101., 134.],
       [ 94., 131., 159.],
       [121., 130., 171.],
       [108., 115., 148.],
       [ 83., 102., 130.],
       [116., 147., 153.],
       [109., 114., 137.],
       [ 87., 113., 139.],
       [116., 147., 158.],
       [113., 138., 147.],
       [102., 110., 120.],
       [127., 138., 192.],
       [ 98., 107., 150.],
       [109., 119., 127.],
       [145., 171., 182.],
       [ 68., 111., 132.],
       [124., 130., 158.],
       [121., 127., 158.],
       [100., 111., 136.],
       [ 83., 116., 126.],
       [134., 155., 191.],
       [129., 146., 175.],
       [107., 137., 147.],
       [129., 140., 181.],
       [102., 135., 144.],
       [ 48.,  72.,  87.],
       [ 83., 109., 125.],
       [ 98., 105., 126.],
       [106., 130., 136.],
       [ 97., 108., 117.],
       [109., 136., 173.],
       [ 81., 111., 152.],
       [ 98., 107., 118.],
       [128., 137., 142.],
       [108., 112., 178.],
       [101., 160., 164.],
       [108., 111., 170.],
       [140., 144., 210.],
       [159., 163., 237.],
       [119., 122., 181.],
       [109., 130., 160.],
       [ 88., 102., 111.],
       [102., 107., 134.],
       [ 75.,  88.,  96.],
       [ 98., 107., 113.]], dtype=float32)

Expected Behavior

As you can see, the current tick is 100, but some vessels future ticks are completely in the past.
I would expect this matrix to contain all information that are > 100.

Environment

  • MARO version (e.g., v0.1.1a1): master
  • MARO scenario (CIM, Citi Bike): CIM
  • MARO component (Simulation, RL, Distributed Training): Simulation
  • Orchestration platform (GraSS on Azure, AKS on Azure):
  • How you installed MARO (pip, source): source
  • OS (Linux, Windows, macOS):
  • Python version (3.6, 3.7): 3.7
  • Docker image (e.g., maro2020/maro:latest):
  • CPU/GPU:
  • Any other relevant information:

Additional Context

EDIT: The problem seems to affect also global configurations without noise in the vessels speed.
E.g. try this config:

seed: 4096
load_cost_factor: 0.05
dsch_cost_factor: 0.05
container_usage_proportion:
  period: 112
  sample_nodes:
  - - 0
    - 0.012
  - - 111
    - 0.012
  sample_noise: 0.002
container_volumes:
- 1
order_generate_mode: fixed
ports:
  bremerhaven_ger:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.16
    order_distribution:
      source:
        noise: 0.025134751494652507
        proportion: 0.16
      targets:
        leHavre_fra:
          noise: 0.025432733187591285
          proportion: 0.18755329471737509
        montreal_can:
          noise: 0.014981815264884504
          proportion: 0.0756906048807678
        newYork_usa:
          noise: 0.07860790872534353
          proportion: 0.47933778254893905
        pusan_kor:
          noise: 0.002902145091237068
          proportion: 0.07667664751459422
        qingdao_chn:
          noise: 0.0016703057083900894
          proportion: 0.0512157380304634
        shanghai_chn:
          noise: 0.004329384963154748
          proportion: 0.04763588234031061
        singapore_sgp:
          noise: 0.00014700838968303593
          proportion: 0.005882857005910926
        yantian_chn:
          noise: 0.014277274600949947
          proportion: 0.07600719296163895
  durban_sau:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.01
    order_distribution:
      source:
        noise: 0.0003905851406890507
        proportion: 0.01
      targets:
        qingdao_chn:
          noise: 0.03386602700899302
          proportion: 0.2502879616953551
        shanghai_chn:
          noise: 0.04099351916502508
          proportion: 0.2501170152675811
        singapore_sgp:
          noise: 0.02983331512414685
          proportion: 0.24812321657873454
        yantian_chn:
          noise: 0.0398838857119423
          proportion: 0.25147180645832923
  itagual_bra:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.01
    order_distribution:
      source:
        noise: 0.0017049012580563228
        proportion: 0.01
      targets:
        qingdao_chn:
          noise: 0.006704071585248814
          proportion: 0.19992517767067194
        santos_bra:
          noise: 0.01065215665926791
          proportion: 0.20145578663243896
        shanghai_chn:
          noise: 0.01889939427623029
          proportion: 0.19975353803822685
        singapore_sgp:
          noise: 0.030425501405892584
          proportion: 0.19775168293424744
        yantian_chn:
          noise: 0.0038049637706619867
          proportion: 0.20111381472441478
  leHavre_fra:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.06
    order_distribution:
      source:
        noise: 0.010023093144315015
        proportion: 0.06
      targets:
        bremerhaven_ger:
          noise: 0.046713884416130814
          proportion: 0.2613085269688243
        montreal_can:
          noise: 0.007011738109808054
          proportion: 0.09474419644790176
        newYork_usa:
          noise: 0.0075575968616494
          proportion: 0.20255309034522379
        pusan_kor:
          noise: 0.0022204132834372364
          proportion: 0.09500755942526971
        qingdao_chn:
          noise: 0.0025163323117031356
          proportion: 0.08820727646821312
        shanghai_chn:
          noise: 0.012253843912920523
          proportion: 0.08725114792024982
        singapore_sgp:
          noise: 0.014556815408633276
          proportion: 0.07609945087001035
        yantian_chn:
          noise: 0.007509358525794673
          proportion: 0.09482875155430699
  losAngeles_usa:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.05
    order_distribution:
      source:
        noise: 0.007441531984981497
        proportion: 0.05
      targets:
        oakland_usa:
          noise: 0.04265188459544233
          proportion: 0.27616189497862537
        princeRupert_can:
          noise: 0.00273897680516611
          proportion: 0.15754923155692402
        qingdao_chn:
          noise: 0.01517255937598155
          proportion: 0.1623492157793647
        seattle_usa:
          noise: 0.014299850500812094
          proportion: 0.2423747616801366
        shanghai_chn:
          noise: 0.0051011672478115
          proportion: 0.16156489600494922
  manzanillo_mex:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.05
    order_distribution:
      source:
        noise: 0.005425915310841583
        proportion: 0.05
      targets:
        manzanillo_mex:
          noise: 0.0073296927183103605
          proportion: 0.1642819028757581
        pusan_kor:
          noise: 0.018169915140256784
          proportion: 0.1269237319062987
        qingdao_chn:
          noise: 0.02383787277319661
          proportion: 0.12072756120502863
        sanAntonio_par:
          noise: 0.0025563544317216205
          proportion: 0.10518021746764428
        shanghai_chn:
          noise: 0.02058384394808081
          proportion: 0.11985637174894495
        yantian_chn:
          noise: 0.00989286132515691
          proportion: 0.12676080545008
        yokohama_jpn:
          noise: 0.0007488162438248653
          proportion: 0.23626940934624543
  melbourne_aus:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.015
    order_distribution:
      source:
        noise: 0.0029979553756433923
        proportion: 0.015
      targets:
        singapore_sgp:
          noise: 0.0566906410775888
          proportion: 0.3293364398135728
        sydney_aus:
          noise: 0.01865388192132147
          proportion: 0.3364188275147848
        yantian_chn:
          noise: 0.014238633997660635
          proportion: 0.33424473267164256
  montreal_can:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.015
    order_distribution:
      source:
        noise: 0.0005621554647653919
        proportion: 0.015
      targets:
        bremerhaven_ger:
          noise: 0.08779643369212999
          proportion: 0.5172441914124826
        leHavre_fra:
          noise: 0.07842477295179612
          proportion: 0.4827558085875176
  newYork_usa:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.03
    order_distribution:
      source:
        noise: 0.00016057717079772171
        proportion: 0.03
      targets:
        bremerhaven_ger:
          noise: 0.05981761122488196
          proportion: 0.5332513888590196
        leHavre_fra:
          noise: 0.03990533991720246
          proportion: 0.46674861114098054
  oakland_usa:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.03
    order_distribution:
      source:
        noise: 0.004910915544061917
        proportion: 0.03
      targets:
        losAngeles_usa:
          noise: 0.048963812038470556
          proportion: 0.30175478642890274
        princeRupert_can:
          noise: 0.0254961817963097
          proportion: 0.23086917432389525
        qingdao_chn:
          noise: 0.03349874892050399
          proportion: 0.23393880851694335
        shanghai_chn:
          noise: 0.012993114869682515
          proportion: 0.23343723073025868
  princeRupert_can:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.015
    order_distribution:
      source:
        noise: 0.0027667472862969076
        proportion: 0.015
      targets:
        losAngeles_usa:
          noise: 0.05091486367601389
          proportion: 0.2657898185062753
        oakland_usa:
          noise: 0.028397329439457514
          proportion: 0.26818216862044597
        qingdao_chn:
          noise: 0.0016646658939369785
          proportion: 0.23313476502804797
        shanghai_chn:
          noise: 0.013742472852754001
          proportion: 0.23289324784523086
  pusan_kor:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.06
    order_distribution:
      source:
        noise: 0.009320427377742116
        proportion: 0.06
      targets:
        bremerhaven_ger:
          noise: 0.031991420231325084
          proportion: 0.21204226502906795
        leHavre_fra:
          noise: 0.005105457599858164
          proportion: 0.08535909653471886
        manzanillo_mex:
          noise: 0.005809147275802185
          proportion: 0.0959125358074426
        qingdao_chn:
          noise: 0.0033945457967072133
          proportion: 0.051610240792657115
        sanAntonio_par:
          noise: 0.001854192137165468
          proportion: 0.035795894860646466
        seattle_usa:
          noise: 0.018330317944630015
          proportion: 0.14202580193983683
        shanghai_chn:
          noise: 0.009459052846765289
          proportion: 0.05072408949335503
        singapore_sgp:
          noise: 0.0016197423680226325
          proportion: 0.04038858042581788
        vancouver_can:
          noise: 0.00469787131269142
          proportion: 0.059258114284493034
        yantian_chn:
          noise: 0.003856257701007031
          proportion: 0.05774708854229363
        yokohama_jpn:
          noise: 0.014803870326138143
          proportion: 0.1691362922896707
  qingdao_chn:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.08
    order_distribution:
      source:
        noise: 0.007181454765417904
        proportion: 0.08
      targets:
        bremerhaven_ger:
          noise: 0.02952708760272511
          proportion: 0.19166868266386958
        durban_sau:
          noise: 0.0026860007722877676
          proportion: 0.025475188174797537
        itagual_bra:
          noise: 0.0023058721270403397
          proportion: 0.020374390901285715
        leHavre_fra:
          noise: 0.008262798336030506
          proportion: 0.04940051725539669
        losAngeles_usa:
          noise: 0.014599621251693524
          proportion: 0.14605127409748705
        manzanillo_mex:
          noise: 0.004578888771735588
          proportion: 0.061252276599797005
        oakland_usa:
          noise: 0.0018968128853613635
          proportion: 0.15590868899027802
        princeRupert_can:
          noise: 7.825075850514062e-05
          proportion: 0.005409393840032325
        pusan_kor:
          noise: 0.0007151691535729856
          proportion: 0.018577689927305203
        santos_bra:
          noise: 0.0036806154087330586
          proportion: 0.02037439104592543
        seattle_usa:
          noise: 0.0016116464454415448
          proportion: 0.113038562331156
        shanghai_chn:
          noise: 0.0011503058311188963
          proportion: 0.010504586083902057
        vancouver_can:
          noise: 0.0031091344585237185
          proportion: 0.02008850220677704
        yantian_chn:
          noise: 0.0017512950798533396
          proportion: 0.018391591436727996
        yokohama_jpn:
          noise: 0.023837737047619264
          proportion: 0.14348426444526224
  sanAntonio_par:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.01
    order_distribution:
      source:
        noise: 0.0015229565945744795
        proportion: 0.01
      targets:
        manzanillo_mex:
          noise: 0.029864110340333205
          proportion: 0.1695702560614863
        pusan_kor:
          noise: 0.030434021872288986
          proportion: 0.16240810942168046
        qingdao_chn:
          noise: 0.031654173870326326
          proportion: 0.1612201993861513
        shanghai_chn:
          noise: 0.022840905205567065
          proportion: 0.16105317774270345
        yantian_chn:
          noise: 0.022058626605590343
          proportion: 0.16237686231768783
        yokohama_jpn:
          noise: 0.020882193597463152
          proportion: 0.18337139507029068
  santos_bra:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.01
    order_distribution:
      source:
        noise: 0.0017591918390130468
        proportion: 0.01
      targets:
        itagual_bra:
          noise: 0.00015677478442405662
          proportion: 0.20145578737905992
        qingdao_chn:
          noise: 0.007951708444894913
          proportion: 0.19992517738434895
        shanghai_chn:
          noise: 0.008394529742993468
          proportion: 0.19975353831991421
        singapore_sgp:
          noise: 0.01406059678653582
          proportion: 0.19775168256638195
        yantian_chn:
          noise: 0.011310434190498734
          proportion: 0.20111381435029493
  seattle_usa:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.07
    order_distribution:
      source:
        noise: 0.009178972285261822
        proportion: 0.07
      targets:
        losAngeles_usa:
          noise: 0.023523817623575388
          proportion: 0.2912736754142012
        pusan_kor:
          noise: 0.01876947062956955
          proportion: 0.12538821688519616
        qingdao_chn:
          noise: 0.02029673306956859
          proportion: 0.11617748395503369
        shanghai_chn:
          noise: 0.011329185762784782
          proportion: 0.11488243812354347
        singapore_sgp:
          noise: 0.00024014816912197655
          proportion: 0.09977785851511455
        vancouver_can:
          noise: 0.02057342705041732
          proportion: 0.1273542861551621
        yantian_chn:
          noise: 0.020083358186626803
          proportion: 0.12514604095174878
  shanghai_chn:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.1
    order_distribution:
      source:
        noise: 0.017109626305467616
        proportion: 0.1
      targets:
        bremerhaven_ger:
          noise: 0.021959106592952006
          proportion: 0.21398371679064213
        durban_sau:
          noise: 0.00010435314516980227
          proportion: 0.017462167174606275
        itagual_bra:
          noise: 0.0020594969751376174
          proportion: 0.011430536063236027
        leHavre_fra:
          noise: 0.0009873199353313093
          proportion: 0.04575353580273499
        losAngeles_usa:
          noise: 0.014743978442771179
          proportion: 0.16004173887997492
        manzanillo_mex:
          noise: 0.0012374290703743276
          proportion: 0.05976808154382374
        oakland_usa:
          noise: 0.022426459611386496
          proportion: 0.1716979971992254
        pusan_kor:
          noise: 0.0005070099495173756
          proportion: 0.00930596400725694
        qingdao_chn:
          noise: 0.8783239577936313e-05
          proportion: 0.0009364036349727401
        santos_bra:
          noise: 0.0012407696401487867
          proportion: 0.011430536346128936
        seattle_usa:
          noise: 0.011299147787220907
          proportion: 0.12100465463531186
        vancouver_can:
          noise: 0.002147321460772641
          proportion: 0.011092475826618629
        yantian_chn:
          noise: 0.000883163479902347
          proportion: 0.009085896257062817
        yokohama_jpn:
          noise: 0.012495339718107597
          proportion: 0.1570062958384047
  singapore_sgp:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.04
    order_distribution:
      source:
        noise: 0.0014198451145378962
        proportion: 0.04
      targets:
        bremerhaven_ger:
          noise: 0.02403294164090424
          proportion: 0.16163465526933787
        durban_sau:
          noise: 0.007339857249890276
          proportion: 0.052947229587582224
        itagual_bra:
          noise: 0.004826948332878951
          proportion: 0.049611409618781833
        leHavre_fra:
          noise: 0.000697323478201817
          proportion: 0.06859394881607536
        melbourne_aus:
          noise: 0.009748446374379698
          proportion: 0.054598902525719965
        pusan_kor:
          noise: 0.0052864459821632135
          proportion: 0.04843640111672956
        qingdao_chn:
          noise: 0.00020264478777542088
          proportion: 0.04380756610509279
        santos_bra:
          noise: 0.0060662606703405855
          proportion: 0.0496114180206766
        seattle_usa:
          noise: 0.002184489196293904
          proportion: 0.11021203091597927
        shanghai_chn:
          noise: 0.00446890645579302
          proportion: 0.043156750350596414
        singapore_sgp:
          noise: 0.0005079804300151535
          proportion: 0.03556597867096123
        sydney_aus:
          noise: 0.0032814259751614335
          proportion: 0.053961624659387086
        vancouver_can:
          noise: 0.0013725415556900408
          proportion: 0.04942443509903704
        yantian_chn:
          noise: 0.007866049277209214
          proportion: 0.04831469461601993
        yokohama_jpn:
          noise: 0.013995694253814077
          proportion: 0.13012295462802295
  sydney_aus:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.015
    order_distribution:
      source:
        noise: 5.318259543305715e-05
        proportion: 0.015
      targets:
        melbourne_aus:
          noise: 0.010959524006592607
          proportion: 0.33665441119009204
        singapore_sgp:
          noise: 0.013378806626384264
          proportion: 0.3291642505650358
        yantian_chn:
          noise: 0.043398566324619615
          proportion: 0.3341813382448723
  vancouver_can:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.02
    order_distribution:
      source:
        noise: 0.002260078974868654
        proportion: 0.02
      targets:
        pusan_kor:
          noise: 0.01022517907397126
          proportion: 0.16323476832180567
        qingdao_chn:
          noise: 0.025111111836521687
          proportion: 0.16078294599848347
        seattle_usa:
          noise: 0.025666860266381805
          proportion: 0.19595625809774195
        shanghai_chn:
          noise: 0.00391575019491024
          proportion: 0.1604382196746799
        singapore_sgp:
          noise: 0.009869415376296499
          proportion: 0.15641751563334233
        yantian_chn:
          noise: 0.01646828787230074
          proportion: 0.1631702922739467
  yantian_chn:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.07
    order_distribution:
      source:
        noise: 0.005460106707641842
        proportion: 0.07
      targets:
        bremerhaven_ger:
          noise: 0.03183934815230198
          proportion: 0.23063506921338092
        durban_sau:
          noise: 0.006955761417407662
          proportion: 0.036977112629701755
        itagual_bra:
          noise: 0.003879986047538319
          proportion: 0.03103337062146673
        leHavre_fra:
          noise: 0.0033746270986396783
          proportion: 0.06485623632186012
        manzanillo_mex:
          noise: 0.014297914647911386
          proportion: 0.07866656356344162
        melbourne_aus:
          noise: 0.0055998037357593185
          proportion: 0.03992004007199072
        pusan_kor:
          noise: 0.004337884540903886
          proportion: 0.028939753926030695
        qingdao_chn:
          noise: 0.0034845335834618927
          proportion: 0.020692152164438926
        santos_bra:
          noise: 0.0023084677027446535
          proportion: 0.03103337095193521
        seattle_usa:
          noise: 0.0043141199296154705
          proportion: 0.13901084519757625
        shanghai_chn:
          noise: 0.0001996474876791818
          proportion: 0.01953252624072474
        singapore_sgp:
          noise: 0.0011502086812016938
          proportion: 0.006007386215135132
        sydney_aus:
          noise: 0.0019319056238978993
          proportion: 0.03878455068512264
        vancouver_can:
          noise: 0.0007858696914021227
          proportion: 0.03070023678474206
        yantian_chn:
          noise: 0.0016168667042640794
          proportion: 0.02872289950079146
        yokohama_jpn:
          noise: 0.023246811699828965
          proportion: 0.17448788591166092
  yokohama_jpn:
    capacity: 10000
    empty_return:
      buffer_ticks: 1
      noise: 0
    full_return:
      buffer_ticks: 1
      noise: 0
    initial_container_proportion: 0.08
    order_distribution:
      source:
        noise: 0.014254332625813097
        proportion: 0.08
      targets:
        manzanillo_mex:
          noise: 0.03244047063421112
          proportion: 0.224773870587767
        pusan_kor:
          noise: 0.018126081484701975
          proportion: 0.1473122137604972
        qingdao_chn:
          noise: 0.017152304680050526
          proportion: 0.1344645529933837
        sanAntonio_par:
          noise: 0.0003086488347039955
          proportion: 0.10222734144856105
        shanghai_chn:
          noise: 0.0056287128415065625
          proportion: 0.13265815413379464
        singapore_sgp:
          noise: 0.019438990767313084
          proportion: 0.1115894561579222
        yantian_chn:
          noise: 0.014838419143613479
          proportion: 0.14697441091807414
routes:
  a3s:
  - distance_to_next_port: 320
    port_name: yantian_chn
  - distance_to_next_port: 240
    port_name: sydney_aus
  - distance_to_next_port: 80
    port_name: melbourne_aus
  asa:
  - distance_to_next_port: 320
    port_name: singapore_sgp
  - distance_to_next_port: 260
    port_name: sydney_aus
  - distance_to_next_port: 60
    port_name: melbourne_aus
  ate1:
  - distance_to_next_port: 160
    port_name: newYork_usa
  - distance_to_next_port: 240
    port_name: bremerhaven_ger
  - distance_to_next_port: 40
    port_name: leHavre_fra
  gex1:
  - distance_to_next_port: 220
    port_name: montreal_can
  - distance_to_next_port: 220
    port_name: bremerhaven_ger
  - distance_to_next_port: 40
    port_name: leHavre_fra
  ktx5:
  - distance_to_next_port: 240
    port_name: singapore_sgp
  - distance_to_next_port: 80
    port_name: yantian_chn
  - distance_to_next_port: 140
    port_name: yokohama_jpn
  ll4:
  - distance_to_next_port: 80
    port_name: shanghai_chn
  - distance_to_next_port: 60
    port_name: yantian_chn
  - distance_to_next_port: 80
    port_name: singapore_sgp
  - distance_to_next_port: 380
    port_name: leHavre_fra
  - distance_to_next_port: 80
    port_name: bremerhaven_ger
  - distance_to_next_port: 420
    port_name: singapore_sgp
  - distance_to_next_port: 200
    port_name: qingdao_chn
  - distance_to_next_port: 80
    port_name: pusan_kor
  pcc1:
  - distance_to_next_port: 240
    port_name: qingdao_chn
  - distance_to_next_port: 40
    port_name: shanghai_chn
  - distance_to_next_port: 240
    port_name: princeRupert_can
  - distance_to_next_port: 120
    port_name: losAngeles_usa
  - distance_to_next_port: 100
    port_name: oakland_usa
  pcc2:
  - distance_to_next_port: 80
    port_name: shanghai_chn
  - distance_to_next_port: 280
    port_name: losAngeles_usa
  - distance_to_next_port: 160
    port_name: seattle_usa
  - distance_to_next_port: 280
    port_name: qingdao_chn
  pnw1:
  - distance_to_next_port: 80
    port_name: yantian_chn
  - distance_to_next_port: 260
    port_name: vancouver_can
  - distance_to_next_port: 80
    port_name: seattle_usa
  - distance_to_next_port: 320
    port_name: pusan_kor
  pnw2:
  - distance_to_next_port: 200
    port_name: singapore_sgp
  - distance_to_next_port: 120
    port_name: yantian_chn
  - distance_to_next_port: 80
    port_name: shanghai_chn
  - distance_to_next_port: 60
    port_name: pusan_kor
  - distance_to_next_port: 200
    port_name: seattle_usa
  - distance_to_next_port: 40
    port_name: vancouver_can
  - distance_to_next_port: 520
    port_name: qingdao_chn
  - distance_to_next_port: 60
    port_name: shanghai_chn
  saf3:
  - distance_to_next_port: 80
    port_name: qingdao_chn
  - distance_to_next_port: 40
    port_name: shanghai_chn
  - distance_to_next_port: 60
    port_name: yantian_chn
  - distance_to_next_port: 80
    port_name: singapore_sgp
  - distance_to_next_port: 260
    port_name: durban_sau
  - distance_to_next_port: 360
    port_name: yantian_chn
  tla2:
  - distance_to_next_port: 60
    port_name: qingdao_chn
  - distance_to_next_port: 60
    port_name: shanghai_chn
  - distance_to_next_port: 80
    port_name: yantian_chn
  - distance_to_next_port: 100
    port_name: singapore_sgp
  - distance_to_next_port: 460
    port_name: itagual_bra
  - distance_to_next_port: 20
    port_name: santos_bra
  - distance_to_next_port: 580
    port_name: singapore_sgp
  - distance_to_next_port: 140
    port_name: yantian_chn
  - distance_to_next_port: 80
    port_name: shanghai_chn
  tlp1:
  - distance_to_next_port: 100
    port_name: yantian_chn
  - distance_to_next_port: 60
    port_name: shanghai_chn
  - distance_to_next_port: 60
    port_name: qingdao_chn
  - distance_to_next_port: 40
    port_name: pusan_kor
  - distance_to_next_port: 260
    port_name: manzanillo_mex
  - distance_to_next_port: 140
    port_name: sanAntonio_par
  - distance_to_next_port: 180
    port_name: manzanillo_mex
  - distance_to_next_port: 260
    port_name: yokohama_jpn
  - distance_to_next_port: 60
    port_name: shanghai_chn
stop_number:
- 4
- 3
total_containers: 100000
vessels:
  a3s_vessel_000:
    capacity: 7739
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: yantian_chn
      route_name: a3s
    sailing:
      noise: 0
      speed: 10
  a3s_vessel_001:
    capacity: 7739
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: sydney_aus
      route_name: a3s
    sailing:
      noise: 0
      speed: 10
  asa_vessel_000:
    capacity: 4379
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: singapore_sgp
      route_name: asa
    sailing:
      noise: 0
      speed: 10
  asa_vessel_001:
    capacity: 4379
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: melbourne_aus
      route_name: asa
    sailing:
      noise: 0
      speed: 10
  ate1_vessel_000:
    capacity: 46069
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: newYork_usa
      route_name: ate1
    sailing:
      noise: 0
      speed: 10
  ate1_vessel_001:
    capacity: 46069
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: bremerhaven_ger
      route_name: ate1
    sailing:
      noise: 0
      speed: 10
  gex1_vessel_000:
    capacity: 9182
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: bremerhaven_ger
      route_name: gex1
    sailing:
      noise: 0
      speed: 10
  gex1_vessel_001:
    capacity: 9182
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: montreal_can
      route_name: gex1
    sailing:
      noise: 0
      speed: 10
  ktx5_vessel_000:
    capacity: 11328
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: singapore_sgp
      route_name: ktx5
    sailing:
      noise: 0
      speed: 10
  ktx5_vessel_001:
    capacity: 11328
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: yokohama_jpn
      route_name: ktx5
    sailing:
      noise: 0
      speed: 10
  ll4_vessel_000:
    capacity: 52831
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: bremerhaven_ger
      route_name: ll4
    sailing:
      noise: 0
      speed: 10
  ll4_vessel_001:
    capacity: 52831
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: yantian_chn
      route_name: ll4
    sailing:
      noise: 0
      speed: 10
  ll4_vessel_002:
    capacity: 52831
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: singapore_sgp
      route_name: ll4
    sailing:
      noise: 0
      speed: 10
  ll4_vessel_003:
    capacity: 52831
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: leHavre_fra
      route_name: ll4
    sailing:
      noise: 0
      speed: 10
  ll4_vessel_004:
    capacity: 52831
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: pusan_kor
      route_name: ll4
    sailing:
      noise: 0
      speed: 10
  ll4_vessel_005:
    capacity: 52831
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: qingdao_chn
      route_name: ll4
    sailing:
      noise: 0
      speed: 10
  pcc1_vessel_000:
    capacity: 39380
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: oakland_usa
      route_name: pcc1
    sailing:
      noise: 0
      speed: 10
  pcc1_vessel_001:
    capacity: 39380
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: qingdao_chn
      route_name: pcc1
    sailing:
      noise: 0
      speed: 10
  pcc1_vessel_002:
    capacity: 39380
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: princeRupert_can
      route_name: pcc1
    sailing:
      noise: 0
      speed: 10
  pcc2_vessel_000:
    capacity: 19551
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: seattle_usa
      route_name: pcc2
    sailing:
      noise: 0
      speed: 10
  pcc2_vessel_001:
    capacity: 19551
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: losAngeles_usa
      route_name: pcc2
    sailing:
      noise: 0
      speed: 10
  pcc2_vessel_002:
    capacity: 19551
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: shanghai_chn
      route_name: pcc2
    sailing:
      noise: 0
      speed: 10
  pnw1_vessel_000:
    capacity: 17039
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: seattle_usa
      route_name: pnw1
    sailing:
      noise: 0
      speed: 10
  pnw1_vessel_001:
    capacity: 17039
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: vancouver_can
      route_name: pnw1
    sailing:
      noise: 0
      speed: 10
  pnw1_vessel_002:
    capacity: 17039
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: yantian_chn
      route_name: pnw1
    sailing:
      noise: 0
      speed: 10
  pnw2_vessel_000:
    capacity: 7178
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: pusan_kor
      route_name: pnw2
    sailing:
      noise: 0
      speed: 10
  pnw2_vessel_001:
    capacity: 7178
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: yantian_chn
      route_name: pnw2
    sailing:
      noise: 0
      speed: 10
  pnw2_vessel_002:
    capacity: 7178
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: vancouver_can
      route_name: pnw2
    sailing:
      noise: 0
      speed: 10
  pnw2_vessel_003:
    capacity: 7178
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: pusan_kor
      route_name: pnw2
    sailing:
      noise: 0
      speed: 10
  pnw2_vessel_004:
    capacity: 7178
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: qingdao_chn
      route_name: pnw2
    sailing:
      noise: 0
      speed: 10
  saf3_vessel_000:
    capacity: 5177
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: yantian_chn
      route_name: saf3
    sailing:
      noise: 0
      speed: 10
  saf3_vessel_001:
    capacity: 5177
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: qingdao_chn
      route_name: saf3
    sailing:
      noise: 0
      speed: 10
  saf3_vessel_002:
    capacity: 5177
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: singapore_sgp
      route_name: saf3
    sailing:
      noise: 0
      speed: 10
  saf3_vessel_003:
    capacity: 5177
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: durban_sau
      route_name: saf3
    sailing:
      noise: 0
      speed: 10
  tla2_vessel_000:
    capacity: 9480
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: itagual_bra
      route_name: tla2
    sailing:
      noise: 0
      speed: 10
  tla2_vessel_001:
    capacity: 9480
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: santos_bra
      route_name: tla2
    sailing:
      noise: 0
      speed: 10
  tla2_vessel_002:
    capacity: 9480
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: singapore_sgp
      route_name: tla2
    sailing:
      noise: 0
      speed: 10
  tla2_vessel_003:
    capacity: 9480
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: shanghai_chn
      route_name: tla2
    sailing:
      noise: 0
      speed: 10
  tla2_vessel_004:
    capacity: 9480
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: qingdao_chn
      route_name: tla2
    sailing:
      noise: 0
      speed: 10
  tla2_vessel_005:
    capacity: 9480
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: yantian_chn
      route_name: tla2
    sailing:
      noise: 0
      speed: 10
  tlp1_vessel_000:
    capacity: 50660
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: yantian_chn
      route_name: tlp1
    sailing:
      noise: 0
      speed: 10
  tlp1_vessel_001:
    capacity: 50660
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: manzanillo_mex
      route_name: tlp1
    sailing:
      noise: 0
      speed: 10
  tlp1_vessel_002:
    capacity: 50660
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: pusan_kor
      route_name: tlp1
    sailing:
      noise: 0
      speed: 10
  tlp1_vessel_003:
    capacity: 50660
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: manzanillo_mex
      route_name: tlp1
    sailing:
      noise: 0
      speed: 10
  tlp1_vessel_004:
    capacity: 50660
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: sanAntonio_par
      route_name: tlp1
    sailing:
      noise: 0
      speed: 10
  tlp1_vessel_005:
    capacity: 50660
    parking:
      duration: 1
      noise: 0
    route:
      initial_port_name: yokohama_jpn
      route_name: tlp1
    sailing:
      noise: 0
      speed: 10
@riccardopoiani riccardopoiani added the 馃悰 bug Something isn't working. label Aug 6, 2021
@riccardopoiani
Copy link
Author

I think that the behavior is still full of bugs.

A first fix is given by the following:

route_info = route_points[loc_idx % route_length]
route_info_2 = route_points[(loc_idx - 1) % route_length]
port_idx, distance_to_next_port = self._port_mapping[route_info.port_name], route_info_2.distance_to_next_port

However, error still occurs,

from maro.simulator import Env

# Initialize an Env for CIM scenario
env = Env(scenario="cim", topology="mod_noise_no_vessels_global_trade.22p_l0.0", start_tick=0, durations=200)

# Start the environment with None action
_, event, is_done = env.step(None)

while not is_done:
    if event.vessel_idx in [39] and event.tick < 200:
        print(f"Vessel {event.vessel_idx} arrived at port {event.port_idx} at tick {event.tick}")
    metrics, event, is_done = env.step(None)

vs = env.snapshot_list['vessels']

sample_ticks = [1, 10, 35, 68, 80, 100]
for t in sample_ticks:
    print(f"\nPast and futures at {t}")
    print(vs[t:[39]:['past_stop_tick_list', 'future_stop_tick_list']].reshape(1, 7))
    print(vs[t:[39]:['past_stop_list', 'future_stop_list']].reshape(1, 7))

Returns:

Vessel 39 arrived at port 17 at tick 9
Vessel 39 arrived at port 2 at tick 20
Vessel 39 arrived at port 14 at tick 67
Vessel 39 arrived at port 17 at tick 70
Vessel 39 arrived at port 20 at tick 129
Vessel 39 arrived at port 16 at tick 144
Vessel 39 arrived at port 12 at tick 153
Vessel 39 arrived at port 16 at tick 160
Vessel 39 arrived at port 20 at tick 167
Vessel 39 arrived at port 17 at tick 176
Vessel 39 arrived at port 2 at tick 187

Past and futures at 1
[[-1. -1. -1.  0.  9. 20. 67.]]
[[-1. -1. -1. 20. 17.  2. 14.]]

Past and futures at 10
[[-1. -1.  0.  9. 20. 67. 70.]]
[[-1. -1. 20. 17.  2. 14. 17.]]

Past and futures at 35
[[ -1.   0.   9.  20.  67.  70. 129.]]
[[-1. 20. 17.  2. 14. 17. 20.]]

Past and futures at 68
[[  0.   9.  20.  67.  70. 129. 144.]]
[[20. 17.  2. 14. 17. 20. 16.]]

Past and futures at 80
[[  9.  20.  67.  70.  81. 128. 131.]]
[[17.  2. 14. 17.  2. 14. 17.]]

Past and futures at 100
[[  9.  20.  67.  70.  81. 128. 131.]]
[[17.  2. 14. 17.  2. 14. 17.]]

As you can see, at some point, the chain is broken and wrong predictions are returned.

@riccardopoiani
Copy link
Author

Update: I figured out where the problem is. The problem arises when the same port appears multiple times in the same route.
In this case,

for loc_idx, route_point in enumerate(route_points):
    if self._port_mapping[route_point.port_name] == last_port_idx:
        last_loc_idx = loc_idx
        break

retrieves always the first time that port appears.

@riccardopoiani
Copy link
Author

riccardopoiani commented Aug 11, 2021

@Jinyu-W

Note that this problem seems not to be fixable with the current signature of the method: from vessel_idx, last_port_idx, last_port_arrival_tick and stop_number it is impossibile to retrieve correctly the next position in the route.

An option would be the one of inserting a new attribute in the vessels that stores the correct position within the route, so that it is would be very easy to understand its position.

To summarize, the problems are:

  • Usage of distance_to_next_port (the wrong one is used) (the first fix I was proposing correctly solve the issue)
  • Port that appears multiple times within the same route (no fix is possible with the current signature and more extensive modification are required to the library)

@riccardopoiani riccardopoiani changed the title Future stop tick predictions contains tick from the past馃悰 Wrong future stop tick predictions 馃悰 Aug 11, 2021
@riccardopoiani
Copy link
Author

riccardopoiani commented Aug 12, 2021

Here is the fix I'm applying.
This modification fix both bugs in (what I think to be) the easiest way.

Of course you need to modify VesselSailingPlanWrapper (that inherits from VesselFutureStopPrediction accordingly and pass last_stop as last argument.

# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.

from math import ceil

from .entities import CimBaseDataCollection, Stop


class VesselFutureStopsPrediction:
    """Wrapper to get (predict, without noise) vessel future stops, the number of stops is limited by configuration.

    Examples:

        .. code-block:: python

            # Get future stops of vessel 0.
            stops = data_cntr.vessel_future_stops[0]
    """

    def __init__(self, data: CimBaseDataCollection):
        self._vessels = data.vessel_settings
        self._stops = data.vessel_stops
        self._routes = data.routes
        self._route_mapping = data.route_mapping
        self._port_mapping = data.port_mapping
        self._stop_number = data.future_stop_number

    def __getitem__(self, key):
        """Used to support querying future stops by vessel index, last location index, next location index."""
        assert type(key) == tuple or type(key) == list
        assert len(key) == 3

        vessel_idx = key[0]
        last_loc_idx = key[1]
        loc_idx = key[2]

        # ignore current port if parking
        last_stop_idx = loc_idx + (0 if last_loc_idx == loc_idx else -1)

        last_stop = self._stops[vessel_idx][last_stop_idx]
        last_port_idx = last_stop.port_idx
        last_port_arrival_tick = last_stop.arrival_tick

        return self._predict_future_stops(vessel_idx, last_port_idx, last_port_arrival_tick, self._stop_number,
                                          last_stop)

    def _predict_future_stops(self, vessel_idx: int, last_port_idx: int, last_port_arrival_tick: int, stop_number: int,
                              last_stop: Stop):
        """Do predict future stops.
        """
        vessel = self._vessels[vessel_idx]
        speed = vessel.sailing_speed
        duration = vessel.parking_duration
        route_name = vessel.route_name
        route_points = self._routes[self._route_mapping[route_name]]
        route_length = len(route_points)

        last_loc_idx = -1

        # try to find the last location index from route
        for loc_idx, route_point in enumerate(route_points):
            if self._port_mapping[route_point.port_name] == last_port_idx:
                # Check that the routes that follows is the same
                ok = True
                for i in range(route_length):
                    if len(self._stops[vessel_idx]) > last_stop.index + i:
                        if self._stops[vessel_idx][last_stop.index + i].port_idx != self._port_mapping[route_points[(loc_idx + i) % route_length].port_name]:
                            ok = False
                if ok:
                    last_loc_idx = loc_idx
                    break

        # return if not in current route
        if last_loc_idx < 0:
            return []

        predicted_future_stops = []
        arrival_tick = last_port_arrival_tick

        # predict from configured sailing plan, not from stops
        for loc_idx in range(last_loc_idx + 1, last_loc_idx + stop_number + 1):
            route_info = route_points[loc_idx % route_length]
            route_info_2 = route_points[(loc_idx - 1) % route_length]
            port_idx, distance_to_next_port = self._port_mapping[route_info.port_name], route_info_2.distance_to_next_port

            # NO noise for speed
            arrival_tick += duration + ceil(distance_to_next_port / speed)

            predicted_future_stops.append(
                Stop(
                    -1,  # predict stop do not have valid index
                    arrival_tick,
                    arrival_tick + duration,
                    port_idx,
                    vessel_idx
                )
            )

        return predicted_future_stops

@lihuoran
Copy link
Contributor

Hi @riccardopoiani , thank you for your report & nice bug fix!

The first thing that I would like to talk about is the expectation of the "vessels' future tick matrix". You have mentioned that all values in this matrix should be greater than the corresponding "current" tick. However, under current logic, this is not the fact.

The "future tick" may be smaller than the "current tick" due to the inaccuracy of the prediction. For example, suppose we make a prediction att1, and the result shows that the vessel will arrive its next port at t2. However, this prediction is inaccurate, and the actual arrival time is t3 (t3 > t2). Then, if we query the future tick matrix after t2 and before t3, the "future tick" (= t2) is smaller than the "current tick".

The bug you found does exist, but I would say it is another unrelated matter. The "time travel" will still exist even if replacing the buggy function with the new one you proposed (you could have a try and see if you can get this result).

In my personal understanding, under current logic, a vessel's future tick vector is meaningful only at the ticks that have corresponding events (e.g., arrival, departure). The information may be incorrect between two adjacent events, and it is fine. There are also other possible ways to improve this issue. For example, once we notice that the "future tick" is behind the "current tick", we could know that the "future tick" is wrong and outdated, and we can make a new prediction accordingly. We will discuss this issue later.

@lihuoran
Copy link
Contributor

lihuoran commented Aug 17, 2021

@riccardopoiani The second thing I would like to talk about is your bug fix. In your bug fix, you compare the following route with the following vessel plan to check if the chosen port is the right one. The length being compared is equal to min(number of remaining ports in the vessel plan, length of the route). This algorithm could pass the current case (global_trade.22p_l0.8), however, it may cause errors in other corner cases.

One corner case I could think of is the repeated pattern in the route. For example, if a route is A->B->C->A->B, and the vessel is at the second A. Under your algorithm, we will only compare two ports since there are only two ports left (A->B). Therefore, both As could be the right one, and which one is selected depends entirely on the order of the loop. We may get wrong results.

In my opinion, we could use another simple way to solve this issue. We know the number of ports that the vessel has already travelled (last_stop_idx), and we could know the index of the starting port (let's call it start_port_offset) of the vessel by using the vessel's initial_port_name. Then, the index of the port we want is simply (start_port_offset + last_stop_idx) mod len(route). Since all these information can be found based on vessel index and last_stop_idx, we do not need to pass too many arguments to the function (_predict_future_stops), so its signature can be simplified.

The following is my modification. See if it is better, thanks!

def _get_vessel_start_port_offset(self, vessel_idx: int) -> int:
    vessel = self._vessels[vessel_idx]
    route_points = self._routes[self._route_mapping[vessel.route_name]]
    route_point_names = [rp.port_name for rp in route_points]
    vessel_start_port_name = self._vessels[vessel_idx].start_port_name
    vessel_start_port_offset = route_point_names.index(vessel_start_port_name)
    return vessel_start_port_offset

def _predict_future_stops(self, vessel_idx: int, last_stop_idx: int, stop_number: int):
    """Do predict future stops.
    """
    vessel = self._vessels[vessel_idx]
    speed, duration = vessel.sailing_speed, vessel.parking_duration
    route_points = self._routes[self._route_mapping[vessel.route_name]]
    route_length = len(route_points)

    last_stop = self._stops[vessel_idx][last_stop_idx]
    last_port_arrival_tick = last_stop.arrival_tick

    vessel_start_port_offset = self._get_vessel_start_port_offset(vessel_idx)
    last_loc_idx = (vessel_start_port_offset + last_stop_idx) % len(route_points)

    predicted_future_stops = []
    arrival_tick = last_port_arrival_tick

    # predict from configured sailing plan, not from stops
    for loc_idx in range(last_loc_idx + 1, last_loc_idx + stop_number + 1):
        next_route_info = route_points[loc_idx % route_length]
        last_route_info = route_points[(loc_idx - 1) % route_length]
        port_idx = self._port_mapping[next_route_info.port_name]
        distance_to_next_port = last_route_info.distance_to_next_port

        # NO noise for speed
        arrival_tick += duration + ceil(distance_to_next_port / speed)

        predicted_future_stops.append(
            Stop(
                -1,  # predict stop do not have valid index
                arrival_tick,
                arrival_tick + duration,
                port_idx,
                vessel_idx
            )
        )

    return predicted_future_stops

@riccardopoiani
Copy link
Author

riccardopoiani commented Aug 17, 2021

Hi @riccardopoiani , thank you for your report & nice bug fix!

The first thing that I would like to talk about is the expectation of the "vessels' future tick matrix". You have mentioned that all values in this matrix should be greater than the corresponding "current" tick. However, under current logic, this is not the fact.

The "future tick" may be smaller than the "current tick" due to the inaccuracy of the prediction. For example, suppose we make a prediction att1, and the result shows that the vessel will arrive its next port at t2. However, this prediction is inaccurate, and the actual arrival time is t3 (t3 > t2). Then, if we query the future tick matrix after t2 and before t3, the "future tick" (= t2) is smaller than the "current tick".

The bug you found does exist, but I would say it is another unrelated matter. The "time travel" will still exist even if replacing the buggy function with the new one you proposed (you could have a try and see if you can get this result).

In my personal understanding, under current logic, a vessel's future tick vector is meaningful only at the ticks that have corresponding events (e.g., arrival, departure). The information may be incorrect between two adjacent events, and it is fine. There are also other possible ways to improve this issue. For example, once we notice that the "future tick" is behind the "current tick", we could know that the "future tick" is wrong and outdated, and we can make a new prediction accordingly. We will discuss this issue later.

Hi @lihuoran , you are completely right about this point.
I was already aware about it, but I forgot to correct the issue description. The fact is that at the beginning I thought that the problem was related to noise in vessel arrivals. Then, with more experiments, I realized that the bug was somewhere else.

I agree that I consider acceptable for the moment to have some wrong and outdated estimates; minor fixes such as the one that you are suggesting at the end are not that crucial to me and I think it is ok to have "wrong" estimates.

@riccardopoiani
Copy link
Author

@riccardopoiani The second thing I would like to talk about is your bug fix. In your bug fix, you compare the following route with the following vessel plan to check if the chosen port is the right one. The length being compared is equal to min(number of remaining ports in the vessel plan, length of the route). This algorithm could pass the current case (global_trade.22p_l0.8), however, it may cause errors in other corner cases.

One corner case I could think of is the repeated pattern in the route. For example, if a route is A->B->C->A->B, and the vessel is at the second A. Under your algorithm, we will only compare two ports since there are only two ports left (A->B). Therefore, both As could be the right one, and which one is selected depends entirely on the order of the loop. We may get wrong results.

In my opinion, we could use another simple way to solve this issue. We know the number of ports that the vessel has already travelled (last_stop_idx), and we could know the index of the starting port (let's call it start_port_offset) of the vessel by using the vessel's initial_port_name. Then, the index of the port we want is simply (start_port_offset + last_stop_idx) mod len(route). Since all these information can be found based on vessel index and last_stop_idx, we do not need to pass too many arguments to the function (_predict_future_stops), so its signature can be simplified.

The following is my modification. See if it is better, thanks!

def _get_vessel_start_port_offset(self, vessel_idx: int) -> int:
    vessel = self._vessels[vessel_idx]
    route_points = self._routes[self._route_mapping[vessel.route_name]]
    route_point_names = [rp.port_name for rp in route_points]
    vessel_start_port_name = self._vessels[vessel_idx].start_port_name
    vessel_start_port_offset = route_point_names.index(vessel_start_port_name)
    return vessel_start_port_offset

def _predict_future_stops(self, vessel_idx: int, last_stop_idx: int, stop_number: int):
    """Do predict future stops.
    """
    vessel = self._vessels[vessel_idx]
    speed, duration = vessel.sailing_speed, vessel.parking_duration
    route_points = self._routes[self._route_mapping[vessel.route_name]]
    route_length = len(route_points)

    last_stop = self._stops[vessel_idx][last_stop_idx]
    last_port_arrival_tick = last_stop.arrival_tick

    vessel_start_port_offset = self._get_vessel_start_port_offset(vessel_idx)
    last_loc_idx = (vessel_start_port_offset + last_stop_idx) % len(route_points)

    predicted_future_stops = []
    arrival_tick = last_port_arrival_tick

    # predict from configured sailing plan, not from stops
    for loc_idx in range(last_loc_idx + 1, last_loc_idx + stop_number + 1):
        next_route_info = route_points[loc_idx % route_length]
        last_route_info = route_points[(loc_idx - 1) % route_length]
        port_idx = self._port_mapping[next_route_info.port_name]
        distance_to_next_port = last_route_info.distance_to_next_port

        # NO noise for speed
        arrival_tick += duration + ceil(distance_to_next_port / speed)

        predicted_future_stops.append(
            Stop(
                -1,  # predict stop do not have valid index
                arrival_tick,
                arrival_tick + duration,
                port_idx,
                vessel_idx
            )
        )

    return predicted_future_stops

You are right and this solutions seems to be definitely better. I did some rapid tests by hand and it seems to be working.
My sincere thanks :)

@lihuoran
Copy link
Contributor

@riccardopoiani The update mentioned above has already been merged into master (with slight modification). Thanks for your efforts!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
馃悰 bug Something isn't working.
Projects
None yet
Development

No branches or pull requests

2 participants