From 88690ed6fab85338e75a138aa4cde52349fc9e0a Mon Sep 17 00:00:00 2001 From: eleurent Date: Sun, 26 Nov 2023 12:32:01 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20@=20Farama-F?= =?UTF-8?q?oundation/HighwayEnv@d0d75711223caabfbc10b4e42c03ce59093b3ae1?= =?UTF-8?q?=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/_images/index_1_1.png | Bin 7965 -> 8031 bytes main/_images/index_2_1.png | Bin 10343 -> 10319 bytes main/_images/index_2_2.png | Bin 12357 -> 12398 bytes main/_images/index_2_3.png | Bin 13987 -> 14072 bytes main/_images/index_3_1.png | Bin 25282 -> 25029 bytes main/_images/multi_agent_0_1.png | Bin 11479 -> 11479 bytes main/_images/multi_agent_1_1.png | Bin 21969 -> 21969 bytes main/_images/quickstart_0_3.png | Bin 7521 -> 7842 bytes main/_images/quickstart_2_0.png | Bin 6105 -> 6137 bytes main/_modules/highway_env/__init__/index.html | 85 ++-- .../envs/common/abstract/index.html | 101 ++-- .../highway_env/envs/common/action/index.html | 191 ++++---- .../envs/common/graphics/index.html | 120 +++-- .../envs/common/observation/index.html | 441 ++++++++++++------ .../highway_env/envs/highway_env/index.html | 124 +++-- .../envs/intersection_env/index.html | 394 ++++++++++------ .../highway_env/envs/merge_env/index.html | 111 +++-- .../highway_env/envs/parking_env/index.html | 157 +++++-- .../highway_env/envs/racetrack_env/index.html | 410 +++++++++++----- .../envs/roundabout_env/index.html | 387 +++++++++++---- .../highway_env/road/graphics/index.html | 194 ++++++-- .../_modules/highway_env/road/lane/index.html | 176 ++++--- .../highway_env/road/regulation/index.html | 48 +- .../_modules/highway_env/road/road/index.html | 282 +++++++---- .../highway_env/vehicle/behavior/index.html | 375 +++++++++------ .../highway_env/vehicle/controller/index.html | 202 +++++--- .../highway_env/vehicle/kinematics/index.html | 175 ++++--- main/observations/index.html | 20 +- main/searchindex.js | 2 +- 29 files changed, 2678 insertions(+), 1317 deletions(-) diff --git a/main/_images/index_1_1.png b/main/_images/index_1_1.png index 2305a80013498871c9b054cc95a1104ba80dad3b..3bef64f49942ebb6dd6e538ae41b999f89fccbc6 100644 GIT binary patch literal 8031 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 literal 7965 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 S&jcfrpl{q($dY^b?0*3Ly++*t diff --git a/main/_images/index_2_1.png b/main/_images/index_2_1.png index 5e3999c05b60f62ea88ead48cca3ef67600afa18..5d3ad8690a17e8448f5daedf9e54c0a160bc9380 100644 GIT binary patch literal 10319 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 literal 10343 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 o{#ogrYX7h8vj5-q_4o`{+ALu8B({ZfZ)~ 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 Ox-an%{ZU-+>Hh)(9SWEL diff --git a/main/_images/index_2_3.png b/main/_images/index_2_3.png index dbf22d721ff096142cdbe9e3636308f2125bc0cf..f2f502838e06417eeb4bd14413c3d33f9db4763e 100644 GIT binary patch literal 14072 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 D(mZ*V literal 13987 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 UdHo1}U<|n-uOgQ%tN+)31AW<2LI3~& diff --git a/main/_images/index_3_1.png b/main/_images/index_3_1.png index 60fe7fb9432f38d9228a87b01004a8a87cc2ee9f..a62e201dcbb5667ddb6ded607f2c6f228956c738 100644 GIT binary patch literal 25029 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 XXjHZ{eFonrLE5@$=f9rVxt#wuVR+|G diff --git a/main/_images/multi_agent_0_1.png b/main/_images/multi_agent_0_1.png index 282a26e59d7298f4edd48d4e020d9eea65e179ea..86024bbfd4d199a8735021149d738b8073e13684 100644 GIT binary patch delta 41 xcmcZ}c|CH1hn$g)LPkkRL9vy-er{q(K~8>2PG*u`eo?x2PG*u`eo?yqr8UAf8`BDP08)n!{Qv*} diff --git a/main/_images/multi_agent_1_1.png b/main/_images/multi_agent_1_1.png index e77ef386e7a4bba909e532564d7066153d3fb260..c25e1b1bf83f27b41a71c1c44dd0e6c4207b75f1 100644 GIT binary patch delta 43 zcmcb(n(^Xl#t9yBMmh=^B_##LR{Hw6i6sR&`6W4-NqYH3>G}%4{~g(wmK_QJb7~RG delta 43 zcmcb(n(^Xl#t9yBhB^uvB_##LR{Hw6i6sR&`6W4-NqYH3>H3$}2-|E-%MJwqZiNuK diff --git a/main/_images/quickstart_0_3.png b/main/_images/quickstart_0_3.png index 7638c92243fa50d6f0736280a86bae84f402c2f7..d757195cc3dfa2dd587e5c11c0f256972b62c676 100644 GIT binary patch literal 7842 zcmdscbyQSQ)b9)kNP{39(jcu!mvl*qv~)?w2sp%ybfYv%2`C`o5F)K0B_Ji;Ee#R_ z(%%`sSAV?q)?4qrza9&?FzcRk&pmtZU+fdDtF1~*Kt}+9K#0}Vl=LAGEN<|3*-c#V zTd&&423#ay%EqwA9u6=+Yj1nVBWswas|U>Wnav$vdvBj-9`5%A#0Bp0-Eo4!Jbfeu z1>OGJ4FVqCj)Hg2uiC*R_?~JeJ`f10HRcCeELZdl0%0OmS9)mRpS3d^02@YM%KdTt zWj^(b^VtRmvD-T$XB-}_S9C+mq79>)G?FvqUuPGDbZ7~*%MKYN@xl*%@Me8QKVXmC zPidR{oXpt%VwtE{c{L?J)w|?97L}Pm^Wb3N2FJ6clRZ+EBSkDx=3l>)4+67>*@A-R zf=>GzpB-o&)E9@5VJU$xg8YP|8&TlvQ#(=t{2$Zye|Vu7LRML~;l|O6kyKVza&vRH zw1(obNiedqvg$`g;iMogw=B7Nc@>qFab(Z8?`vgC-d0vtcJlB@97zF>S7R}F-C%6> z@FCQ_aYyuG#{+>4`5P!}XK%k)*~Qe>lgf)at(MItUF*+Qw6S3|xI5~pm5y0}-WGpKdAYk}29D<2U=FZ=;@>S?s}qH{wybVL?R&+34sfbor?OwYfn0^?9}9fX%N$ z^|pIPU~L4bv@|L^2L}ruEhVg;a6;+@H2if=jzCFKQPJ|>{blI#c)3|*jmtRh$l5?I zX|}eQ-61ZJOEHjuRX;2m7S1ChCs)pF z-OeF@jZ8{P3dzWz`CL<@zUk)XCiJ!sx{QX)9KkO=A0>kKVC7>~-Cu`EYURo@K6&!w z>dnBK;*%%0%M4xEKm3c+t;$4yFn@*95bMtjVeI>k{q1Myt)b!J(2iJYRc8%wQz02S zAvdYa5t*cnI-%f& z^Cw<4h2DE{V3#F_n7c;rcQK#W%IvpO_@D38R=Q1#Zco=@a;{AWaW?!e1D6~`l&9~N z$f%Q*=v(Yf-$ur_Vji6?sOAXfiv>Ig(#SICw%B~&eG&$7#8B^Int zS-N=OKn>tq#JELs63kXahH~s?9hCIf~qDanb!f4 zZLO~W1c-zXpIUcvCga!F*NeY6VE^fGf5u&`p`n4@c4}%WWVhNo(*hOQYV|4*Y{t-! z2P@Ey4cO91$>SeCezY8I48I$7)_d|~b$)JQBI@^V2jlXwcR2)@eT%L@v>(2mzrgkR z{j+tV($;HtM#8|r;0`AzE+G{ka>%K@jZ`kKs_Gs)7gw8=&;qFY&{5}Aa%r%GE7ZqG z@83UZ`HU+d+1c4@j~;bo`^`mT!; zKmqDeKE`KJD&!)+8`%ae7>WWVu23|r43`A6irjRsr8lc}51)0v9=lY3!Ow)L2nJlr z|KXBVJcnn0eRZj(rWSPs1H0)&mZi<*0P?FiNH=1|=4G4x^cT0mE%fUgOm+~5^sdq! zO%#)Gi@uFl-NzsRe(ki(dgTn>zxv|(IRB8P;mz)@`_aisWHZXJ6a-LFM@MHOpmfwZ zj!8yxJ19CTpB$SYUQN4*A{Gs|3)^CokHwL3esJagSLhZ6g&zBj51n0+MSjkAl@zeX zMn;4H&|H#&5yq$c`x!L!^f?Y28|yLAP!eWb$VzADQi3Pr!?ZU9*7x=g4O#O&tmIkf z;$A{qwip}cShmGglwfTCJ{m59COSI7bLB|0r0|sHd7`7DB8cXnaDv_Fum)p@VsU7s ze4XG$AFw1OkQxs}F2PF4xPKSh=RW5)=W?I?hcL!ohKYCJ6Q6+% zKdL%={`~nO$l@eZef?XVJ>oi%v+k;oA3v540;mhpj=0{^#f29X8png!j*!ovKfelq z%0GTgvF+Pfc$~c#sCq1WhnSeyv)(*uYNb0Fyo^0sD)6sRyI4P@RKMg^ZZ2tRoX;Ec zNkRxrl9BV#8%l4~%a_oR@o~HnVq9#14$R(iMZ?j_Tsjf&sUa{JY+-w{I>{7N_q}`f z?9eXm?h$l3(G~DZGT~D1KRNUhaTKM(UkRvquU1g=7KK%n{N>1%8?$X>o2Sp#B>cTX@ zS3iILd=>Dt$)DUZ2>nD}hL=}!Oj&XuMGT5N9h%) zgwGH{Hn+9_uH7k__3q^#bW%V}k*@jJSX$2Kb*Vg;r@ikGcbzaeI7mjO%SRPk#>JF7 zK>eo|pmo(1H&T;y*9e!g+>p1?QcFuqUY_=Wb4pn-T|B3gyf9sS)fxKu821KceKS(? z3WTsc;V&yZJ{nLNCC3=-b#ck-M>=uBMJyz4`7Q$UbS zE+wU;u(32;UCXxTw^~}{<>l42v{GjGzK0V+q4r1XLseLbeGY_lx&ZfX*_q!t0LkzW zTf@QOLz%AE_CzIeDnr=Tu9@c0U-}_-%*=e~tUKvVZpmzIUpWXAs=RBPt?{0KP8Y1q z4(%h(0EU{HzA3W`{QWZ%iA+jMizqBC1Ub{Pzubk571Lq!QoHl^T-#|D&9=v)v%yl2 zYCHFWr?`~}U8U!uf=TQn08?!PJHEDCW91doJ3@iI_;(A=7(wx<(e#Wz_nr%4ql>1| zjfzqjnVgIks70F6pQ(nnI>C^p#C1}Vc6;NBBEK*I(QOs{hlgG3&FwUcWlpSUT++F_ z0wkJp`LB_Yv=rpzub2K{CcWt*g$MhB)nvmyG>(~-wG4$vHs`^t3S$EZz#1bIPo>)} zWprmK>h^&wH*@e`7Vuu!u^m{c8sUsmzG`0xSuo1O&d%^Z{K#qfhQ~c>u=f&xv-qWYV$=xfYTo7Gjrw7@S=pZ>Hah5cI$Z%vb^#fgr}}^- zPCQ)P+=%O{%2f&;dV71fDE}7V{qOYslJAOzLNBbnz5PdnI5Ro1g#klH!T8p@@hvtP zVgTZFoYpeQWs|PBkpC(}uiPA}X?J#h)hf#{k-Cb$MGyfXot*#=1+xQ%gCTO11Ov&) z$ViKG4Hl%#kQWF6T{E*S=IVeGcOcLyDJjEzFkDLcUg0XL3n&4AdRKdI-@MT^GKyST zu>+#Uwj<`Y|L;skA+IH+m6a8%(T`8S-qu}TokJlQv9w#i#*~tlw$wpw+1}CuNfWe8 zI6Yj$lL=Wf9dUjzvZ+biOKrDz(mTDP>n+EkG}znRyWv-3aW_?C%zi!;ojgr=^Q-&f zZc)m-ONE8T9(DiuAM}Mq+oWI?!V+19Al29tWB6voF|U(y5OCA+n{KcQM@adf2ivoa z)brO@C)k^@RQ%u5_|5Kw$pd#{5qxS710>Kdwbu?%_VwGhTg)!ilNEud-c6Us)4HXj z8DbtxIf$zl?Ck7B&Lkv}*dX2**ah4Sg$&4?n74G#BKHu`Bg1JhJ@*e|8HivvM5AA+b5CyEw z7cX9L^YGx;&uU}s=Q%T19v!yB#*H_3hR4|$sn7W7=kKQzX@#mW< zg@&f4G27eQ0D05<)yHOM`AbsM)7fNYWmhaLP}DBtpHgq!D>sZCEj5aqDQ#?|2jUmN z?fh9Cy|=txNH5fW@q75-2JCeX$v=@dz0)~XZiaVT_j>~=MttarV=xw==>MBbSTN5c zU^2PAYPJ@8>X*cc1u>eGu2MVbl*1rGB=CNMF_C0(=nYEXM*}GeJUTF@oh|LIO6WeX zWvB)k%|yIragO*?4}ZTLMv8lG^e_N;%XRb_OEwpd4FK|d@^1IqHu0^8kY9e9eAl&i zt;z;wNvG$=Lyx_(J;Ih}ywu%BiuIxr6G^Add0uIl?_f*f06GK4V&WS@?$)ha5D0KS zDjp~iazT?SCBscLym_L|tDx}1sBJibSumGQPW$=Z zH^CAR8qK}}L{YTc|i0{&d~`r;6IHh{SDVdvlopV^BSo0B&) zGn2o3t;+OLh2qSm9W0twAf1=58JH+cEvWO0ic-CQ{~nX%2?-w6wJTe_HYE z(JoF-E#NtKN*-n2!>HuC)J&Wg@uJOwW`kQ%>~4>wbdV?#(UvO&l_ifDkLfH>gr+>5D-`i zZfAS?4aki6>Z`+1xv!MDoNP0Q2Jh3ki> zp8HE3$OgmG%Q3ugD_mS$AdSBNB7~fsoncw%ws&-N2P<#FB(ZZoQ{1{`*DQ}eMhF2C z!^Xx&Vb`&C8h{+uCU6Z^z9U4(#$2^V6uNYV zgU1DLr*4sOr_V|gd-~-lJ~yFN>FUC3mZOPRF|i(6^t7_FlGndaLp11IQ}vs!zpKGh zmaD;Bpv>}Hur8G2quf&Er0aNKKEW|0NG3$)WtcQ%h@W#TM|D@S7nw zhz-USyH6;9@Er@r#>TeZqVBh7c|YiFU)Ri}U37n;dk1cQ%DN2431~4=5M)s@MxdAy zxoi@j8_6zO3f2;OqTxado_9Efh1WB9v8T{=2ga_PSa;*b<%UlePJ)$xJ$Gq^m(y?Zi(Oy(OWCBsEvJ`gm)~h z|3F9^$o9bk*G_gE#MB|Y*~v6WM_xwM@vi?T3H;4htA>w7{ zNLv>Xy10RE{NfXI&AUsF_fFUICth$F)bf2Tj0%nV#0u18W@hH=oKE8Cf3Es}3u%>B ztvk~NA29ViAqQTTyGlUL!!nrZ8&xXJPwsFDpWj4PRaLD2q*2nl_wQHD1_UWmp&e_7 zz!H%sb3Rhg)FdRrRV*x`tYIL*1NYV?Shv&=F@Li6_hf8~bfINZxC!&~YqP18FaLUM z!Krsjo@iR$36vxRf*bnMFHLAcGJE4n^9#M?VN^Yii`c%)2mM=6wRpuN%#sMxB~I8VQ%0>jk4EH?~M7V!WiKrOuk zjZ!Y{tXFX$hk*!q*=mLCw)+kS5fu$f#MQDM0LF`)c5fsG_FGL;v+eR^KC!b?r90z) z)?O3s&H&Ay8Nc};z#*!prgS;*O&)*goW&*{@|tJEoGWW<=L6rL)tK&Io$sC3`Vg-M z98WsF1M9NsAV9=#Nr=0QmA%w>pA-nV;kxfe}v!_Sn-S9>`FRFK8|9bp5JQw9%(d4p`p2kWArY*&;= zRi#1Kt)`}in~(2k90+^@LPFq?7+W)y(?5LR1Wjv=u^}fBkhm@15`g3cAqEu{fzYzH zW&w8tQ5g}`uVGy~4TS(`hajh>Oo@ny)W+@!3X%e0kW`a(&z|7d@bIN=OiT>m3t$xG z;;M~sQRA^7e~ylhfRphiwm1FaO1s;*C)?csZPJO@Y>%b@o`gm&SQ=2>;LHpWa;x}; z-tz~`gwz5pTWF14BFL+poCKiERhG`W4c}j9>uqQE+v2 zEi9rKjfsuDyzU z`2(vp4P%mT`W!yj)@ptUkY)msfZn@29r!lCxfgf=$J-A3fyEy`hKxGLFZ|5c)Yc~X=}>LQ z$Vh?*(&b{ysm2s6BOGMPbp|j|Z2;l(@~kG-7zam@c4Sl>AN=9H;}`IFU-%j-i0#igZ( zh(2&I1AP1y!bfJ+OEMc64@%Iq^Z#ZLqPF**{v!syKqUgF*}j&G5J=-QVb$VHwi9%2 z_#AotPBF3_{M>--ugP7TFi67G0@0&J3Q?Mov~RUI_s7gUqS;gvqUwFtaAkh}ZJfXS zR9sR*&WyOI%m6(WV!w=iwnS;xIF*8lMnBYwZaa{<*BS3M(=n)33B3CLMo}&S5VB>4 zrHJ!YMRLSZ0W${KDnb9_^_w?vMaGyq?^TUTk9palkrDO;1_@TfPv$%ZcT@j@9O4aI zptC@EFmgZTx zTw(PRwA{%6%J5k<83USCT^Li+u6S_cjs@sOUT1v$D!ad4kQh@~$WG48EXd@)0QI`M zc%hyp?W02{-j3^!D&Vdbm0A`rq`u!5y4 zDs-ueV(q&!VvNc7)U~vk@Ln>!uZeU|F;JeweZqlv95sug{G$Fllb_1 zFLmSg?~2{R$hMpmcgHsl+dH1lKlLq z5(SMKcuw|o5t!C#jmwuA?1E-bzq2fvx`iH?-k4bIFM!cvjB}Ub78vO1d#*8PW)&7v zlarHoFV&)WqOvpR1Sb8lW>>F9R97o|85Ixm%g8Xke*Ic?`kFY4t$6b8!8wZ}UNNyk z`#Jn`7pss93=E8nwf>Ln3BPPF4fgc*KB%lz)K?J~r}^2LzR6~9YKl2LyqmedJXCgF zmVIqVIVv(zPsOu>BRo7D#TKQ&1Q@z%@>)!>AwW@Smcfr#Hhav`@0Z z_fk?)WE2#d7cV||HP+pYNbQ)D8M`4}e?xkEa0_nox$DrEIj+aGDU6)a)Yf*nFi4r3 ziG`)nv*N(%PkH!I2a!Sw3M`v*9gR&+LPJ%!gXj5}PM`kGsb~l%?DEud3#29{K1fUBL>u3O=gLOzPVt>NbEf0E z`v04QnM&3>I~==Gy74bL_demZom2%c$F_vCk+HElfq{z7ooP`K5hUfg8c-2}<&0$w zHW_EC#l^*Hds15NEl-<|9&D<66Q`EHmz+9#_H1SFwg_td0nbQ`8y$W5BV=#;3zLIM_@`zrICJqd@?e<7ySG3%=C5;z0b5xUtixuNh|k78yk+rr6p*{>*dyG)fib=9`5h&7cX0xnj&JF zr;ZE^3@(TKfEm8xdy8&LOiG$P3J4BXl9ra1M9!OfjMs2wXJaGGB?R?E*%&O@GK#8biA+FHPgot-^c#d%gfv5lx~Nc1<1F6Z7-1}Rf+Zxkhq zIIpTIH>2Psb#HIU=$IJXaKYQRrZzT|*ilq*t|q?Fn%i-KsQund#~&ZuSe1~%MRvGo z00TZ@VX`}OU+* z_Wir1^8Wlwe3>1coCpxLCr4}9gG*9(<}Ov*ieE}sI?W;PVH&~?k7cSuYLZQ^>3^Q} zR&*$_lnhw4WqquJHo@O@zi!3fY53!9*W0&`TBh}bB)DNt-#AH_{>vc^qe?Q{oqdsv zmUed+2^ZzjrWp%y2hGH*ay{@h@nrsP@4x(=AhB&`?N58~RN5A)#!=5>zKx80EenJT z2*ZX~RyQrVAKR8d+lii|093ogX|tG2xJj^&w?QZYO@&m>q1NZv1e5-gO?S z)E~mwa}-4oP9gyHy)}NonIY__Y0zZKo7ajM_2QwJ$4vQSd*qOWUuliZUT4a&M?NBm z#r+n{F<;QrLQAdAmiyPD$j)HevQU70u?9NSCq0Wge_eOW+ZuPDguH z=uDDS7TvZ+97p%|(f6VQ9TSC#DsrN+W{OC?C05hO{j6u5qYJiPmD~Nz>pEH@ z(^ks(#yUUpK(mjO{vtu>c(DX>{JqYp_@27t`r{08dTLpqkx)8L0-|sSbxwf-!7F4A zu|!)VEQVSlPU_hNhJ%hok5t}nF<21vs7M~$1}kxT+t*T}spdt-V_JUU-frEh9!+L(<;PE;8v`I04xNKGxp)Ua zHvakZdHjNe@}qn&;p^Ur`BVOX9%Oi9HG(GYk-~<~o_FcWP@zmV489j5<g`(*{oCDH8hS=X=C4^0O-)V0N=0)mk2&^!wM&F9>g(%A#y&%LOaK8){3ySbVD0F5 z#?jI7#x5ZSwkdF>(Pcv;qvkA)2Ta=+Lic5>s;UIaOPpF89G;xW^M=($F$xLD;q2nJ zwvgt*1nPQvWIB)8&tfx&S6W`kxCqE4wuSY))NNlSM$kMwb@IClEg)CWAN}+xllBoH zgsFvvP=0f3E5Eq7u~}_O3j2qT9}V0aAJRS?@_077G}RpA>gKkQpZofCy{qh()qvHJ zPuQx0Lkt<7AR`|?Hs31y*_F9VE{w0{)TLOdqU|1C6Hhi# zC#Rsee7Ek#l`DzxH#xc4NO3_yyHFOaweV`d(Y{|MhJlN#PPti9Dk#uu;byBEUO|}^G)ep(TIuv05NT}EljoV1i<;@?cs=lfdQ|P z_C_aD035wLBu%=oL63RE)_;H35+iw_(W8sfIz@$y}D(H`|W*ds_5s%NYMof4+6lY59Bp~w_}uVTHQJieso_ntt!F-naH3nKz7TOPyNlwKpd zmvqh|SYkQh#fzxTpIwG6urzosbS`59zM*6m#q=&z7m#XdG0krU*Kv|RpRpH8aIK5y zGW{_;EQLA@d}m)iyLX~DZr44e;E(QjMyZcqP z;%&3@Tr>|y+!#R~Ak4O9r=jip2JyPH*QU%;^z-M>>TYg-Id^3|{`T#%W#LsXMFPy% zub1YxgE`Op5_PHUrkRZ2zfU;x^Jl?%^D}46k#d8R4JXHOA~+;MoRy%Wmprv0WR;GZ z=`G3A{rzCX`loYFwzg>jHld-oE~7_OB&Tw6a;lwHpC%_i92v1)+l7q@FyL;S9;p`} z&(CdIo8O#+GRZ+O(y_S9ytpL!;?i*j34MH60`@7R*?3-XN=b+FDetA7u9L#-?0Rg6 zb6IvtiCHNQi{2x^XqL3=b8?Bl?lAr}G!ScjG?CMx03`%~!wV;U9~EWW>e3AesCdN;#C5a%S=;I? zQfVV~{7~m|nRTIM&D~Fc_ud;*+8#eX=wIeI?<-&zI7zI1WMF7m;?l*fzp~NFlbl8` z*xH$X!OYH1JijAFj?$^+QT*tw-PO?q6;#FS%nYx*{8j(jfbmckP)|Ggwa5EQlB_d4 z%sWf=C)U2{e2Bo6@QQJyW z|6&lBcEz=_Zr=nhrOF%m*Cq;?IJU-esctXy<{EZNFBjzGoZ(bL>Rkp^%r0n@B7kK< zc#Kw^W)Zi2(#I@niGe$5AB_bsiG3(9*LSboYnGs6W){R+n3&N1+T1+r^#PF5@{{lD zWjpRTQYh0-P;YEZ%td44*kzQ0=SbbKSFKonb4$yVklODksE?_+d3f#dc5%Xw?J|`;L1Oq%<&SDoxke{Dl8gd)dZ&Ff{>NeE9-o56jj7QdE` z4wNwTz+YBYcCU{`!j9^J#&PCM=JA#g$Z_-FPotjI2dmfwYtRzR;Y&Vk|u{H#eVr8K?RyUk%I^tBmubWfT}Rt)QS! zuXdUkO&mrleM*6dS4Xiv3*XM_ul)X*seAWsbq)&ro=!*z_SHx4NzFehs~|g z`!NzVz{q4nM}QeBz<2G(pN5fBoi5r4aCl=1?k{`rUxOpj#(9oZ@{uzk=-AlEadtzU zuiv~8%(O-#Ke*$zf^j(t+Av-Y1<$;1ln794AOr-;!8?Fa(mqnUaG|HC2exiR#2Hc1 zOJ-^yJvQHPadXoow!JctK)kmu{3CIS!LN>vj;d~hP9D-=Mx>;shT4rJ?J#KWRc8TB zYiVn@fvm%yazY@4JxnXgw!TF&W!%#0M&u^OkhDl#6z} zxWALGSlo+k(J>FECi)YxQG`WAW- z_P6!)^)&!BKu>sY&6}Z3^zYzRom=l4K0ZDIrF0r>z}hnp7EOoQFG-Pcak{Rq!qPG_ zKCt!Lp3luW-*9mO`fYSC$7c)PO6f;?!iUh42uK)VNr^~kxgP=0F$2ydNGW)YH6@%i zq~qdxyuR-JHSIhjH8pjD6!c`^+zS_=sfhXqq|+{H2W(YX?7?RCUO%8~d`8A9jv{x| zvvmv?f*bx6@dfvLF133BX<3ELuV~p`PVFzSxR~3kUjrU$cC^!PONQQof|4@4$CU{{ ziaFOLlNn4I)71iVJa&e-r<4M>Zxq-c8Q?J)L5KBUN$@~#b|{25JJQ2snT3qg=z4Qa zSOD%B)6>((q)b${pR%fZMoO+gqtHTjT-dHi>0K=m*LjJ$tvpyb`h|ssseTLl z?SW4jp=Iv2;RoZkAYGM+nr>93pOiYYQ zOZqsXKfgs+(=`>+}ItV(D9-ug}0mV@8sV_>Wh?_TW&Mz(|yqnE4dkOMb)T-TQx`j_%yz_$dVqZS61w;-=wN5(@ zz*197%gCJ_|L-gQMcJB$&qV8Gx|I2?6fj--pE@(u;=puK@u+eR4GrZL782L__1(u* zrEdHq+U5_EMyP|o0oC|3*NQj;?;S zgq7vSIxp#=Ri$@2%a?B#dU;{(A)jdQteBqbNQHo`wdfl5$+Kq>(a{t|*_VLc_YOC^ ze3rjUW!}DPymL)QhvcK@Xf!F$T{=HMzt3G=txj<&5m$1JeYoU!vj{2T)x@kyiJ*xZ zV5c3aBw@BD9?(K<2n!1f_gdAC?*(nnWxsmWG~P?02uRmZP+SuodawhK5C0-}wX(7r zL+9q^^1~~Hiw|j~zu!IN)jCAhN9+oUZFEyR zB3fE>+ICh~J%OOdlW(O%K2EE4NSAr{7dgBb!1<+ikW>sme)f#HZSTThX+?PrZUqIo zs}v}qOV1?^GvDCiq9KjtJU?|! z7dsjY!+4sM6x6yrUdsb#Lw_Bqx}fPbdBKqYS~MIV9Y}e6mu%Z1XB6aBRJ1I823r*R zAn6@+*lU6H6>!JkxZT{`jyBb0KTmJe&HDOK-%OFdNdZGQGc%h!N>TJV16~?;G8Zf| zja2fPY#?rGZQTsYCq7m+uqbM1(7Z1FqG_PerWpdErX1~PHm%#*mViO3wRMi zhzUGcsn7nd9TN!i-BGue z7#0a;<{0g}fK&-r=r1TKRXf=QFPx2s9kH`EE)mP4Ccf;Cg#wMORG4TV9`Dvlh=_=2 znVH2yc!Vo9*0wEi3>W_EFM2sSxv819M91dn)0&W=#;NY>k=4sp+nj_l$I;n#)mVeW z+5;!AZDjOV5jp?l^VhFTfO0ute97wlwkj}`!kT0y;0y4NhBWB8a!@HAV{3C?orlhd zLQHJRd5tOaH5FcYY>z(jqi10e0)ToheKR`m?c0PcS9f;?$hGMwCnp;`2y8|A`$s3+qpUzcN56kBxiNC5E2^qWNk0>+5DftZJ^+H~uIblo zyS9aeg_;`s$?uIgv}gnk7e1hZ8J`9dx)H(1R~Zqo)QM>T!m%oIj@sJ`g#K)P!gsL= z-Vs5JU;YPe@kw}Qr~)__EgWUupR8#97$5rlw|w+px%hwZX%o$NUx@ooJ7yDJcOvw) LjkSt29q#`d1z_-n diff --git a/main/_images/quickstart_2_0.png b/main/_images/quickstart_2_0.png index 0837433e90515aa3ed438d66a02eaef0c3c37f0e..b30031b248e3605529b7875aba3f7566f03154c7 100644 GIT binary patch literal 6137 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 literal 6105 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 G&;A2V>4kX! diff --git a/main/_modules/highway_env/__init__/index.html b/main/_modules/highway_env/__init__/index.html index 03f0ee27c..4f3578e75 100644 --- a/main/_modules/highway_env/__init__/index.html +++ b/main/_modules/highway_env/__init__/index.html @@ -291,10 +291,22 @@

Source code for highway_env.__init__

-# Hide pygame support prompt
-import os
-os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1'
+import os
+import sys
 
+__version__ = "1.8.2"
+
+try:
+    from farama_notifications import notifications
+
+    if "highway_env" in notifications and __version__ in notifications["gymnasium"]:
+        print(notifications["highway_env"][__version__], file=sys.stderr)
+
+except Exception:  # nosec
+    pass
+
+# Hide pygame support prompt
+os.environ["PYGAME_HIDE_SUPPORT_PROMPT"] = "1"
 
 from gymnasium.envs.registration import register
 
@@ -306,96 +318,89 @@ 

Source code for highway_env.__init__

 
     # exit_env.py
     register(
-        id='exit-v0',
-        entry_point='highway_env.envs:ExitEnv',
+        id="exit-v0",
+        entry_point="highway_env.envs:ExitEnv",
     )
 
     # highway_env.py
     register(
-        id='highway-v0',
-        entry_point='highway_env.envs:HighwayEnv',
+        id="highway-v0",
+        entry_point="highway_env.envs:HighwayEnv",
     )
 
     register(
-        id='highway-fast-v0',
-        entry_point='highway_env.envs:HighwayEnvFast',
+        id="highway-fast-v0",
+        entry_point="highway_env.envs:HighwayEnvFast",
     )
 
     # intersection_env.py
     register(
-        id='intersection-v0',
-        entry_point='highway_env.envs:IntersectionEnv',
+        id="intersection-v0",
+        entry_point="highway_env.envs:IntersectionEnv",
     )
 
     register(
-        id='intersection-v1',
-        entry_point='highway_env.envs:ContinuousIntersectionEnv',
+        id="intersection-v1",
+        entry_point="highway_env.envs:ContinuousIntersectionEnv",
     )
 
     register(
-        id='intersection-multi-agent-v0',
-        entry_point='highway_env.envs:MultiAgentIntersectionEnv',
+        id="intersection-multi-agent-v0",
+        entry_point="highway_env.envs:MultiAgentIntersectionEnv",
     )
 
     register(
-        id='intersection-multi-agent-v1',
-        entry_point='highway_env.envs:TupleMultiAgentIntersectionEnv',
+        id="intersection-multi-agent-v1",
+        entry_point="highway_env.envs:TupleMultiAgentIntersectionEnv",
     )
 
     # lane_keeping_env.py
     register(
-        id='lane-keeping-v0',
-        entry_point='highway_env.envs:LaneKeepingEnv',
-        max_episode_steps=200
+        id="lane-keeping-v0",
+        entry_point="highway_env.envs:LaneKeepingEnv",
+        max_episode_steps=200,
     )
 
     # merge_env.py
     register(
-        id='merge-v0',
-        entry_point='highway_env.envs:MergeEnv',
+        id="merge-v0",
+        entry_point="highway_env.envs:MergeEnv",
     )
 
     # parking_env.py
     register(
-        id='parking-v0',
-        entry_point='highway_env.envs:ParkingEnv',
+        id="parking-v0",
+        entry_point="highway_env.envs:ParkingEnv",
     )
 
     register(
-        id='parking-ActionRepeat-v0',
-        entry_point='highway_env.envs:ParkingEnvActionRepeat'
+        id="parking-ActionRepeat-v0",
+        entry_point="highway_env.envs:ParkingEnvActionRepeat",
     )
 
     register(
-        id='parking-parked-v0',
-        entry_point='highway_env.envs:ParkingEnvParkedVehicles'
+        id="parking-parked-v0", entry_point="highway_env.envs:ParkingEnvParkedVehicles"
     )
 
     # racetrack_env.py
     register(
-        id='racetrack-v0',
-        entry_point='highway_env.envs:RacetrackEnv',
+        id="racetrack-v0",
+        entry_point="highway_env.envs:RacetrackEnv",
     )
 
     # roundabout_env.py
     register(
-        id='roundabout-v0',
-        entry_point='highway_env.envs:RoundaboutEnv',
+        id="roundabout-v0",
+        entry_point="highway_env.envs:RoundaboutEnv",
     )
 
     # two_way_env.py
     register(
-        id='two-way-v0',
-        entry_point='highway_env.envs:TwoWayEnv',
-        max_episode_steps=15
+        id="two-way-v0", entry_point="highway_env.envs:TwoWayEnv", max_episode_steps=15
     )
 
     # u_turn_env.py
-    register(
-        id='u-turn-v0',
-        entry_point='highway_env.envs:UTurnEnv'
-    )
- + register(id="u-turn-v0", entry_point="highway_env.envs:UTurnEnv")
diff --git a/main/_modules/highway_env/envs/common/abstract/index.html b/main/_modules/highway_env/envs/common/abstract/index.html index 7fc38100e..7f4ec3638 100644 --- a/main/_modules/highway_env/envs/common/abstract/index.html +++ b/main/_modules/highway_env/envs/common/abstract/index.html @@ -293,20 +293,19 @@

Source code for highway_env.envs.common.abstract

 import copy
 import os
-from typing import List, Tuple, Optional, Callable, TypeVar, Generic, Union, Dict, Text
+from typing import Dict, List, Optional, Text, Tuple, TypeVar
+
 import gymnasium as gym
+import numpy as np
 from gymnasium import Wrapper
 from gymnasium.wrappers import RecordVideo
-from gymnasium.utils import seeding
-import numpy as np
 
 from highway_env import utils
-from highway_env.envs.common.action import action_factory, Action, DiscreteMetaAction, ActionType
-from highway_env.envs.common.observation import observation_factory, ObservationType
+from highway_env.envs.common.action import Action, ActionType, action_factory
 from highway_env.envs.common.finite_mdp import finite_mdp
 from highway_env.envs.common.graphics import EnvViewer
-from highway_env.vehicle.behavior import IDMVehicle, LinearVehicle
-from highway_env.vehicle.controller import MDPVehicle
+from highway_env.envs.common.observation import ObservationType, observation_factory
+from highway_env.vehicle.behavior import IDMVehicle
 from highway_env.vehicle.kinematics import Vehicle
 
 Observation = TypeVar("Observation")
@@ -323,11 +322,12 @@ 

Source code for highway_env.envs.common.abstract

speed. The action space is fixed, but the observation space and reward function must be defined in the environment implementations. """ + observation_type: ObservationType action_type: ActionType _record_video_wrapper: Optional[RecordVideo] metadata = { - 'render_modes': ['human', 'rgb_array'], + "render_modes": ["human", "rgb_array"], } PERCEPTION_DISTANCE = 5.0 * Vehicle.MAX_SPEED @@ -386,12 +386,8 @@

Source code for highway_env.envs.common.abstract

:return: a configuration dict """ return { - "observation": { - "type": "Kinematics" - }, - "action": { - "type": "DiscreteMetaAction" - }, + "observation": {"type": "Kinematics"}, + "action": {"type": "DiscreteMetaAction"}, "simulation_frequency": 15, # [Hz] "policy_frequency": 1, # [Hz] "other_vehicles_type": "highway_env.vehicle.behavior.IDMVehicle", @@ -403,7 +399,7 @@

Source code for highway_env.envs.common.abstract

"render_agent": True, "offscreen_rendering": os.environ.get("OFFSCREEN_RENDERING", "0") == "1", "manual_control": False, - "real_time_rendering": False + "real_time_rendering": False, }
@@ -412,9 +408,12 @@

Source code for highway_env.envs.common.abstract

self.config.update(config) def update_metadata(self, video_real_time_ratio=2): - frames_freq = self.config["simulation_frequency"] \ - if self._record_video_wrapper else self.config["policy_frequency"] - self.metadata['render_fps'] = video_real_time_ratio * frames_freq + frames_freq = ( + self.config["simulation_frequency"] + if self._record_video_wrapper + else self.config["policy_frequency"] + ) + self.metadata["render_fps"] = video_real_time_ratio * frames_freq
[docs] @@ -501,10 +500,11 @@

Source code for highway_env.envs.common.abstract

[docs] - def reset(self, - *, - seed: Optional[int] = None, - options: Optional[dict] = None, + def reset( + self, + *, + seed: Optional[int] = None, + options: Optional[dict] = None, ) -> Tuple[Observation, dict]: """ Reset the environment to it's initial configuration @@ -524,7 +524,7 @@

Source code for highway_env.envs.common.abstract

self.define_spaces() # Second, to link the obs and actions to the vehicles once the scene is created obs = self.observation_type.observe() info = self._info(obs, action=self.action_space.sample()) - if self.render_mode == 'human': + if self.render_mode == "human": self.render() return obs, info
@@ -553,7 +553,9 @@

Source code for highway_env.envs.common.abstract

:return: a tuple (observation, reward, terminated, truncated, info) """ if self.road is None or self.vehicle is None: - raise NotImplementedError("The road and vehicle must be initialized in the environment implementation") + raise NotImplementedError( + "The road and vehicle must be initialized in the environment implementation" + ) self.time += 1 / self.config["policy_frequency"] self._simulate(action) @@ -563,7 +565,7 @@

Source code for highway_env.envs.common.abstract

terminated = self._is_terminated() truncated = self._is_truncated() info = self._info(obs, action) - if self.render_mode == 'human': + if self.render_mode == "human": self.render() return obs, reward, terminated, truncated, info
@@ -573,12 +575,21 @@

Source code for highway_env.envs.common.abstract

[docs] def _simulate(self, action: Optional[Action] = None) -> None: """Perform several steps of simulation with constant action.""" - frames = int(self.config["simulation_frequency"] // self.config["policy_frequency"]) + frames = int( + self.config["simulation_frequency"] // self.config["policy_frequency"] + ) for frame in range(frames): # Forward action to the vehicle - if action is not None \ - and not self.config["manual_control"] \ - and self.steps % int(self.config["simulation_frequency"] // self.config["policy_frequency"]) == 0: + if ( + action is not None + and not self.config["manual_control"] + and self.steps + % int( + self.config["simulation_frequency"] + // self.config["policy_frequency"] + ) + == 0 + ): self.action_type.act(action) self.road.act() @@ -587,7 +598,9 @@

Source code for highway_env.envs.common.abstract

# Automatically render intermediate simulation steps if a viewer has been launched # Ignored if the rendering is done offscreen - if frame < frames - 1: # Last frame will be rendered through env.render() as usual + if ( + frame < frames - 1 + ): # Last frame will be rendered through env.render() as usual self._automatic_rendering() self.enable_auto_render = False
@@ -618,7 +631,7 @@

Source code for highway_env.envs.common.abstract

if not self.viewer.offscreen: self.viewer.handle_events() - if self.render_mode == 'rgb_array': + if self.render_mode == "rgb_array": image = self.viewer.get_image() return image
@@ -654,7 +667,6 @@

Source code for highway_env.envs.common.abstract

If a RecordVideo wrapper has been set, use it to capture intermediate frames. """ if self.viewer is not None and self.enable_auto_render: - if self._record_video_wrapper and self._record_video_wrapper.video_recorder: self._record_video_wrapper.video_recorder.capture_frame() else: @@ -663,7 +675,7 @@

Source code for highway_env.envs.common.abstract

[docs] - def simplify(self) -> 'AbstractEnv': + def simplify(self) -> "AbstractEnv": """ Return a simplified copy of the environment where distant vehicles have been removed from the road. @@ -672,15 +684,18 @@

Source code for highway_env.envs.common.abstract

:return: a simplified environment state """ state_copy = copy.deepcopy(self) - state_copy.road.vehicles = [state_copy.vehicle] + state_copy.road.close_vehicles_to( - state_copy.vehicle, self.PERCEPTION_DISTANCE) + state_copy.road.vehicles = [ + state_copy.vehicle + ] + state_copy.road.close_vehicles_to( + state_copy.vehicle, self.PERCEPTION_DISTANCE + ) return state_copy
[docs] - def change_vehicles(self, vehicle_class_path: str) -> 'AbstractEnv': + def change_vehicles(self, vehicle_class_path: str) -> "AbstractEnv": """ Change the type of all vehicles on the road @@ -698,7 +713,7 @@

Source code for highway_env.envs.common.abstract

return env_copy
- def set_preferred_lane(self, preferred_lane: int = None) -> 'AbstractEnv': + def set_preferred_lane(self, preferred_lane: int = None) -> "AbstractEnv": env_copy = copy.deepcopy(self) if preferred_lane: for v in env_copy.road.vehicles: @@ -708,14 +723,14 @@

Source code for highway_env.envs.common.abstract

v.LANE_CHANGE_MAX_BRAKING_IMPOSED = 1000 return env_copy - def set_route_at_intersection(self, _to: str) -> 'AbstractEnv': + def set_route_at_intersection(self, _to: str) -> "AbstractEnv": env_copy = copy.deepcopy(self) for v in env_copy.road.vehicles: if isinstance(v, IDMVehicle): v.set_route_at_intersection(_to) return env_copy - def set_vehicle_field(self, args: Tuple[str, object]) -> 'AbstractEnv': + def set_vehicle_field(self, args: Tuple[str, object]) -> "AbstractEnv": field, value = args env_copy = copy.deepcopy(self) for v in env_copy.road.vehicles: @@ -723,7 +738,7 @@

Source code for highway_env.envs.common.abstract

setattr(v, field, value) return env_copy - def call_vehicle_method(self, args: Tuple[str, Tuple[object]]) -> 'AbstractEnv': + def call_vehicle_method(self, args: Tuple[str, Tuple[object]]) -> "AbstractEnv": method, method_args = args env_copy = copy.deepcopy(self) for i, v in enumerate(env_copy.road.vehicles): @@ -731,7 +746,7 @@

Source code for highway_env.envs.common.abstract

env_copy.road.vehicles[i] = getattr(v, method)(*method_args) return env_copy - def randomize_behavior(self) -> 'AbstractEnv': + def randomize_behavior(self) -> "AbstractEnv": env_copy = copy.deepcopy(self) for v in env_copy.road.vehicles: if isinstance(v, IDMVehicle): @@ -739,7 +754,7 @@

Source code for highway_env.envs.common.abstract

return env_copy def to_finite_mdp(self): - return finite_mdp(self, time_quantization=1/self.config["policy_frequency"]) + return finite_mdp(self, time_quantization=1 / self.config["policy_frequency"]) def __deepcopy__(self, memo): """Perform a deep copy but without copying the environment viewer.""" @@ -747,7 +762,7 @@

Source code for highway_env.envs.common.abstract

result = cls.__new__(cls) memo[id(self)] = result for k, v in self.__dict__.items(): - if k not in ['viewer', '_record_video_wrapper']: + if k not in ["viewer", "_record_video_wrapper"]: setattr(result, k, copy.deepcopy(v, memo)) else: setattr(result, k, None) diff --git a/main/_modules/highway_env/envs/common/action/index.html b/main/_modules/highway_env/envs/common/action/index.html index 06f554b63..ed9b9c138 100644 --- a/main/_modules/highway_env/envs/common/action/index.html +++ b/main/_modules/highway_env/envs/common/action/index.html @@ -293,16 +293,16 @@

Source code for highway_env.envs.common.action

 import functools
 import itertools
-from typing import TYPE_CHECKING, Optional, Union, Tuple, Callable, List
-from gymnasium import spaces
+from typing import TYPE_CHECKING, Callable, List, Optional, Tuple, Union
+
 import numpy as np
+from gymnasium import spaces
 
 from highway_env import utils
 from highway_env.utils import Vector
-from highway_env.vehicle.behavior import IDMVehicle
+from highway_env.vehicle.controller import MDPVehicle
 from highway_env.vehicle.dynamics import BicycleVehicle
 from highway_env.vehicle.kinematics import Vehicle
-from highway_env.vehicle.controller import MDPVehicle
 
 if TYPE_CHECKING:
     from highway_env.envs.common.abstract import AbstractEnv
@@ -316,7 +316,7 @@ 

Source code for highway_env.envs.common.action

"""A type of action specifies its definition space, and how actions are executed in the environment""" - def __init__(self, env: 'AbstractEnv', **kwargs) -> None: + def __init__(self, env: "AbstractEnv", **kwargs) -> None: self.env = env self.__controlled_vehicle = None @@ -391,16 +391,18 @@

Source code for highway_env.envs.common.action

STEERING_RANGE = (-np.pi / 4, np.pi / 4) """Steering angle range: [-x, x], in rad.""" - def __init__(self, - env: 'AbstractEnv', - acceleration_range: Optional[Tuple[float, float]] = None, - steering_range: Optional[Tuple[float, float]] = None, - speed_range: Optional[Tuple[float, float]] = None, - longitudinal: bool = True, - lateral: bool = True, - dynamical: bool = False, - clip: bool = True, - **kwargs) -> None: + def __init__( + self, + env: "AbstractEnv", + acceleration_range: Optional[Tuple[float, float]] = None, + steering_range: Optional[Tuple[float, float]] = None, + speed_range: Optional[Tuple[float, float]] = None, + longitudinal: bool = True, + lateral: bool = True, + dynamical: bool = False, + clip: bool = True, + **kwargs + ) -> None: """ Create a continuous action space. @@ -414,13 +416,17 @@

Source code for highway_env.envs.common.action

:param clip: clip action to the defined range """ super().__init__(env) - self.acceleration_range = acceleration_range if acceleration_range else self.ACCELERATION_RANGE + self.acceleration_range = ( + acceleration_range if acceleration_range else self.ACCELERATION_RANGE + ) self.steering_range = steering_range if steering_range else self.STEERING_RANGE self.speed_range = speed_range self.lateral = lateral self.longitudinal = longitudinal if not self.lateral and not self.longitudinal: - raise ValueError("Either longitudinal and/or lateral control must be enabled") + raise ValueError( + "Either longitudinal and/or lateral control must be enabled" + ) self.dynamical = dynamical self.clip = clip self.size = 2 if self.lateral and self.longitudinal else 1 @@ -429,7 +435,7 @@

Source code for highway_env.envs.common.action

[docs] def space(self) -> spaces.Box: - return spaces.Box(-1., 1., shape=(self.size,), dtype=np.float32)

+ return spaces.Box(-1.0, 1.0, shape=(self.size,), dtype=np.float32)
@property @@ -440,7 +446,10 @@

Source code for highway_env.envs.common.action

if self.clip: action = np.clip(action, -1, 1) if self.speed_range: - self.controlled_vehicle.MIN_SPEED, self.controlled_vehicle.MAX_SPEED = self.speed_range + ( + self.controlled_vehicle.MIN_SPEED, + self.controlled_vehicle.MAX_SPEED, + ) = self.speed_range if self.longitudinal and self.lateral: return { "acceleration": utils.lmap(action[0], [-1, 1], self.acceleration_range), @@ -454,7 +463,7 @@

Source code for highway_env.envs.common.action

elif self.lateral: return { "acceleration": 0, - "steering": utils.lmap(action[0], [-1, 1], self.steering_range) + "steering": utils.lmap(action[0], [-1, 1], self.steering_range), }

@@ -469,18 +478,27 @@

Source code for highway_env.envs.common.action

[docs] class DiscreteAction(ContinuousAction): - def __init__(self, - env: 'AbstractEnv', - acceleration_range: Optional[Tuple[float, float]] = None, - steering_range: Optional[Tuple[float, float]] = None, - longitudinal: bool = True, - lateral: bool = True, - dynamical: bool = False, - clip: bool = True, - actions_per_axis: int = 3, - **kwargs) -> None: - super().__init__(env, acceleration_range=acceleration_range, steering_range=steering_range, - longitudinal=longitudinal, lateral=lateral, dynamical=dynamical, clip=clip) + def __init__( + self, + env: "AbstractEnv", + acceleration_range: Optional[Tuple[float, float]] = None, + steering_range: Optional[Tuple[float, float]] = None, + longitudinal: bool = True, + lateral: bool = True, + dynamical: bool = False, + clip: bool = True, + actions_per_axis: int = 3, + **kwargs + ) -> None: + super().__init__( + env, + acceleration_range=acceleration_range, + steering_range=steering_range, + longitudinal=longitudinal, + lateral=lateral, + dynamical=dynamical, + clip=clip, + ) self.actions_per_axis = actions_per_axis

@@ -508,35 +526,23 @@

Source code for highway_env.envs.common.action

An discrete action space of meta-actions: lane changes, and cruise control set-point. """ - ACTIONS_ALL = { - 0: 'LANE_LEFT', - 1: 'IDLE', - 2: 'LANE_RIGHT', - 3: 'FASTER', - 4: 'SLOWER' - } + ACTIONS_ALL = {0: "LANE_LEFT", 1: "IDLE", 2: "LANE_RIGHT", 3: "FASTER", 4: "SLOWER"} """A mapping of action indexes to labels.""" - ACTIONS_LONGI = { - 0: 'SLOWER', - 1: 'IDLE', - 2: 'FASTER' - } + ACTIONS_LONGI = {0: "SLOWER", 1: "IDLE", 2: "FASTER"} """A mapping of longitudinal action indexes to labels.""" - ACTIONS_LAT = { - 0: 'LANE_LEFT', - 1: 'IDLE', - 2: 'LANE_RIGHT' - } + ACTIONS_LAT = {0: "LANE_LEFT", 1: "IDLE", 2: "LANE_RIGHT"} """A mapping of lateral action indexes to labels.""" - def __init__(self, - env: 'AbstractEnv', - longitudinal: bool = True, - lateral: bool = True, - target_speeds: Optional[Vector] = None, - **kwargs) -> None: + def __init__( + self, + env: "AbstractEnv", + longitudinal: bool = True, + lateral: bool = True, + target_speeds: Optional[Vector] = None, + **kwargs + ) -> None: """ Create a discrete action space of meta-actions. @@ -548,13 +554,24 @@

Source code for highway_env.envs.common.action

super().__init__(env) self.longitudinal = longitudinal self.lateral = lateral - self.target_speeds = np.array(target_speeds) if target_speeds is not None else MDPVehicle.DEFAULT_TARGET_SPEEDS - self.actions = self.ACTIONS_ALL if longitudinal and lateral \ - else self.ACTIONS_LONGI if longitudinal \ - else self.ACTIONS_LAT if lateral \ + self.target_speeds = ( + np.array(target_speeds) + if target_speeds is not None + else MDPVehicle.DEFAULT_TARGET_SPEEDS + ) + self.actions = ( + self.ACTIONS_ALL + if longitudinal and lateral + else self.ACTIONS_LONGI + if longitudinal + else self.ACTIONS_LAT + if lateral else None + ) if self.actions is None: - raise ValueError("At least longitudinal or lateral actions must be included") + raise ValueError( + "At least longitudinal or lateral actions must be included" + ) self.actions_indexes = {v: k for k, v in self.actions.items()}

@@ -584,21 +601,33 @@

Source code for highway_env.envs.common.action

:return: the list of available actions """ - actions = [self.actions_indexes['IDLE']] + actions = [self.actions_indexes["IDLE"]] network = self.controlled_vehicle.road.network for l_index in network.side_lanes(self.controlled_vehicle.lane_index): - if l_index[2] < self.controlled_vehicle.lane_index[2] \ - and network.get_lane(l_index).is_reachable_from(self.controlled_vehicle.position) \ - and self.lateral: - actions.append(self.actions_indexes['LANE_LEFT']) - if l_index[2] > self.controlled_vehicle.lane_index[2] \ - and network.get_lane(l_index).is_reachable_from(self.controlled_vehicle.position) \ - and self.lateral: - actions.append(self.actions_indexes['LANE_RIGHT']) - if self.controlled_vehicle.speed_index < self.controlled_vehicle.target_speeds.size - 1 and self.longitudinal: - actions.append(self.actions_indexes['FASTER']) + if ( + l_index[2] < self.controlled_vehicle.lane_index[2] + and network.get_lane(l_index).is_reachable_from( + self.controlled_vehicle.position + ) + and self.lateral + ): + actions.append(self.actions_indexes["LANE_LEFT"]) + if ( + l_index[2] > self.controlled_vehicle.lane_index[2] + and network.get_lane(l_index).is_reachable_from( + self.controlled_vehicle.position + ) + and self.lateral + ): + actions.append(self.actions_indexes["LANE_RIGHT"]) + if ( + self.controlled_vehicle.speed_index + < self.controlled_vehicle.target_speeds.size - 1 + and self.longitudinal + ): + actions.append(self.actions_indexes["FASTER"]) if self.controlled_vehicle.speed_index > 0 and self.longitudinal: - actions.append(self.actions_indexes['SLOWER']) + actions.append(self.actions_indexes["SLOWER"]) return actions

@@ -607,10 +636,7 @@

Source code for highway_env.envs.common.action

[docs] class MultiAgentAction(ActionType): - def __init__(self, - env: 'AbstractEnv', - action_config: dict, - **kwargs) -> None: + def __init__(self, env: "AbstractEnv", action_config: dict, **kwargs) -> None: super().__init__(env) self.action_config = action_config self.agents_action_types = [] @@ -622,7 +648,9 @@

Source code for highway_env.envs.common.action

[docs] def space(self) -> spaces.Space: - return spaces.Tuple([action_type.space() for action_type in self.agents_action_types])

+ return spaces.Tuple( + [action_type.space() for action_type in self.agents_action_types] + )
@property @@ -640,12 +668,17 @@

Source code for highway_env.envs.common.action

[docs] def get_available_actions(self): - return itertools.product(*[action_type.get_available_actions() for action_type in self.agents_action_types])

+ return itertools.product( + *[ + action_type.get_available_actions() + for action_type in self.agents_action_types + ] + )
-def action_factory(env: 'AbstractEnv', config: dict) -> ActionType: +def action_factory(env: "AbstractEnv", config: dict) -> ActionType: if config["type"] == "ContinuousAction": return ContinuousAction(env, **config) if config["type"] == "DiscreteAction": diff --git a/main/_modules/highway_env/envs/common/graphics/index.html b/main/_modules/highway_env/envs/common/graphics/index.html index f7d2fb32f..c81109017 100644 --- a/main/_modules/highway_env/envs/common/graphics/index.html +++ b/main/_modules/highway_env/envs/common/graphics/index.html @@ -293,11 +293,16 @@

Source code for highway_env.envs.common.graphics

 import os
 from typing import TYPE_CHECKING, Callable, List, Optional
+
 import numpy as np
 import pygame
 
-from highway_env.envs.common.action import ActionType, DiscreteMetaAction, ContinuousAction
-from highway_env.road.graphics import WorldSurface, RoadGraphics
+from highway_env.envs.common.action import (
+    ActionType,
+    ContinuousAction,
+    DiscreteMetaAction,
+)
+from highway_env.road.graphics import RoadGraphics, WorldSurface
 from highway_env.vehicle.graphics import VehicleGraphics
 
 if TYPE_CHECKING:
@@ -314,7 +319,7 @@ 

Source code for highway_env.envs.common.graphics

SAVE_IMAGES = False agent_display = None - def __init__(self, env: 'AbstractEnv', config: Optional[dict] = None) -> None: + def __init__(self, env: "AbstractEnv", config: Optional[dict] = None) -> None: self.env = env self.config = config or env.config self.offscreen = self.config["offscreen_rendering"] @@ -332,12 +337,18 @@

Source code for highway_env.envs.common.graphics

# instruction allows the drawing to be done on surfaces without # handling a screen display, useful for e.g. cloud computing if not self.offscreen: - self.screen = pygame.display.set_mode([self.config["screen_width"], self.config["screen_height"]]) + self.screen = pygame.display.set_mode( + [self.config["screen_width"], self.config["screen_height"]] + ) if self.agent_display: self.extend_display() self.sim_surface = WorldSurface(panel_size, 0, pygame.Surface(panel_size)) - self.sim_surface.scaling = self.config.get("scaling", self.sim_surface.INITIAL_SCALING) - self.sim_surface.centering_position = self.config.get("centering_position", self.sim_surface.INITIAL_CENTERING) + self.sim_surface.scaling = self.config.get( + "scaling", self.sim_surface.INITIAL_SCALING + ) + self.sim_surface.centering_position = self.config.get( + "centering_position", self.sim_surface.INITIAL_CENTERING + ) self.clock = pygame.time.Clock() self.enabled = True @@ -362,16 +373,20 @@

Source code for highway_env.envs.common.graphics

def extend_display(self) -> None: if not self.offscreen: if self.config["screen_width"] > self.config["screen_height"]: - self.screen = pygame.display.set_mode((self.config["screen_width"], - 2 * self.config["screen_height"])) + self.screen = pygame.display.set_mode( + (self.config["screen_width"], 2 * self.config["screen_height"]) + ) else: - self.screen = pygame.display.set_mode((2 * self.config["screen_width"], - self.config["screen_height"])) - self.agent_surface = pygame.Surface((self.config["screen_width"], self.config["screen_height"])) + self.screen = pygame.display.set_mode( + (2 * self.config["screen_width"], self.config["screen_height"]) + ) + self.agent_surface = pygame.Surface( + (self.config["screen_width"], self.config["screen_height"]) + )
[docs] - def set_agent_action_sequence(self, actions: List['Action']) -> None: + def set_agent_action_sequence(self, actions: List["Action"]) -> None: """ Set the sequence of actions chosen by the agent, so that it can be displayed @@ -382,10 +397,12 @@

Source code for highway_env.envs.common.graphics

elif isinstance(self.env.action_type, ContinuousAction): actions = [self.env.action_type.get_action(a) for a in actions] if len(actions) > 1: - self.vehicle_trajectory = self.env.vehicle.predict_trajectory(actions, - 1 / self.env.config["policy_frequency"], - 1 / 3 / self.env.config["policy_frequency"], - 1 / self.env.config["simulation_frequency"])
+ self.vehicle_trajectory = self.env.vehicle.predict_trajectory( + actions, + 1 / self.env.config["policy_frequency"], + 1 / 3 / self.env.config["policy_frequency"], + 1 / self.env.config["simulation_frequency"], + )
@@ -412,29 +429,31 @@

Source code for highway_env.envs.common.graphics

if self.vehicle_trajectory: VehicleGraphics.display_trajectory( - self.vehicle_trajectory, - self.sim_surface, - offscreen=self.offscreen) + self.vehicle_trajectory, self.sim_surface, offscreen=self.offscreen + ) RoadGraphics.display_road_objects( - self.env.road, - self.sim_surface, - offscreen=self.offscreen + self.env.road, self.sim_surface, offscreen=self.offscreen ) if EnvViewer.agent_display: EnvViewer.agent_display(self.agent_surface, self.sim_surface) if not self.offscreen: if self.config["screen_width"] > self.config["screen_height"]: - self.screen.blit(self.agent_surface, (0, self.config["screen_height"])) + self.screen.blit( + self.agent_surface, (0, self.config["screen_height"]) + ) else: - self.screen.blit(self.agent_surface, (self.config["screen_width"], 0)) + self.screen.blit( + self.agent_surface, (self.config["screen_width"], 0) + ) RoadGraphics.display_traffic( self.env.road, self.sim_surface, simulation_frequency=self.env.config["simulation_frequency"], - offscreen=self.offscreen) + offscreen=self.offscreen, + ) ObservationGraphics.display(self.env.observation_type, self.sim_surface) @@ -445,7 +464,10 @@

Source code for highway_env.envs.common.graphics

pygame.display.flip() if self.SAVE_IMAGES and self.directory: - pygame.image.save(self.sim_surface, str(self.directory / "highway-env_{}.png".format(self.frame))) + pygame.image.save( + self.sim_surface, + str(self.directory / "highway-env_{}.png".format(self.frame)), + ) self.frame += 1
@@ -457,7 +479,11 @@

Source code for highway_env.envs.common.graphics

Gymnasium's channel convention is H x W x C """ - surface = self.screen if self.config["render_agent"] and not self.offscreen else self.sim_surface + surface = ( + self.screen + if self.config["render_agent"] and not self.offscreen + else self.sim_surface + ) data = pygame.surfarray.array3d(surface) # in W x H x C channel convention return np.moveaxis(data, 0, 1)
@@ -485,7 +511,9 @@

Source code for highway_env.envs.common.graphics

class EventHandler(object): @classmethod - def handle_event(cls, action_type: ActionType, event: pygame.event.EventType) -> None: + def handle_event( + cls, action_type: ActionType, event: pygame.event.EventType + ) -> None: """ Map the pygame keyboard events to control decisions @@ -498,7 +526,9 @@

Source code for highway_env.envs.common.graphics

cls.handle_continuous_action_event(action_type, event) @classmethod - def handle_discrete_action_event(cls, action_type: DiscreteMetaAction, event: pygame.event.EventType) -> None: + def handle_discrete_action_event( + cls, action_type: DiscreteMetaAction, event: pygame.event.EventType + ) -> None: if event.type == pygame.KEYDOWN: if event.key == pygame.K_RIGHT and action_type.longitudinal: action_type.act(action_type.actions_indexes["FASTER"]) @@ -510,7 +540,9 @@

Source code for highway_env.envs.common.graphics

action_type.act(action_type.actions_indexes["LANE_LEFT"]) @classmethod - def handle_continuous_action_event(cls, action_type: ContinuousAction, event: pygame.event.EventType) -> None: + def handle_continuous_action_event( + cls, action_type: ContinuousAction, event: pygame.event.EventType + ) -> None: action = action_type.last_action.copy() steering_index = action_type.space().shape[0] - 1 if event.type == pygame.KEYDOWN: @@ -540,19 +572,33 @@

Source code for highway_env.envs.common.graphics

@classmethod def display(cls, obs, sim_surface): from highway_env.envs.common.observation import LidarObservation + if isinstance(obs, LidarObservation): cls.display_grid(obs, sim_surface) @classmethod def display_grid(cls, lidar_observation, surface): - psi = np.repeat(np.arange(-lidar_observation.angle/2, - 2 * np.pi - lidar_observation.angle/2, - 2 * np.pi / lidar_observation.grid.shape[0]), 2) + psi = np.repeat( + np.arange( + -lidar_observation.angle / 2, + 2 * np.pi - lidar_observation.angle / 2, + 2 * np.pi / lidar_observation.grid.shape[0], + ), + 2, + ) psi = np.hstack((psi[1:], [psi[0]])) - r = np.repeat(np.minimum(lidar_observation.grid[:, 0], lidar_observation.maximum_range), 2) - points = [(surface.pos2pix(lidar_observation.origin[0] + r[i] * np.cos(psi[i]), - lidar_observation.origin[1] + r[i] * np.sin(psi[i]))) - for i in range(np.size(psi))] + r = np.repeat( + np.minimum(lidar_observation.grid[:, 0], lidar_observation.maximum_range), 2 + ) + points = [ + ( + surface.pos2pix( + lidar_observation.origin[0] + r[i] * np.cos(psi[i]), + lidar_observation.origin[1] + r[i] * np.sin(psi[i]), + ) + ) + for i in range(np.size(psi)) + ] pygame.draw.lines(surface, ObservationGraphics.COLOR, True, points, 1)
diff --git a/main/_modules/highway_env/envs/common/observation/index.html b/main/_modules/highway_env/envs/common/observation/index.html index 6df9d763f..33288dc47 100644 --- a/main/_modules/highway_env/envs/common/observation/index.html +++ b/main/_modules/highway_env/envs/common/observation/index.html @@ -293,17 +293,17 @@

Source code for highway_env.envs.common.observation

 from collections import OrderedDict
 from itertools import product
-from typing import List, Dict, TYPE_CHECKING, Optional, Union, Tuple
-from gymnasium import spaces
+from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
+
 import numpy as np
 import pandas as pd
+from gymnasium import spaces
 
 from highway_env import utils
 from highway_env.envs.common.finite_mdp import compute_ttc_grid
 from highway_env.envs.common.graphics import EnvViewer
 from highway_env.road.lane import AbstractLane
-from highway_env.utils import distance_to_circle, Vector
-from highway_env.vehicle.controller import MDPVehicle
+from highway_env.utils import Vector
 from highway_env.vehicle.kinematics import Vehicle
 
 if TYPE_CHECKING:
@@ -311,7 +311,7 @@ 

Source code for highway_env.envs.common.observation

class ObservationType(object): - def __init__(self, env: 'AbstractEnv', **kwargs) -> None: + def __init__(self, env: "AbstractEnv", **kwargs) -> None: self.env = env self.__observer_vehicle = None @@ -357,28 +357,34 @@

Source code for highway_env.envs.common.observation

} """ - def __init__(self, env: 'AbstractEnv', - observation_shape: Tuple[int, int], - stack_size: int, - weights: List[float], - scaling: Optional[float] = None, - centering_position: Optional[List[float]] = None, - **kwargs) -> None: + def __init__( + self, + env: "AbstractEnv", + observation_shape: Tuple[int, int], + stack_size: int, + weights: List[float], + scaling: Optional[float] = None, + centering_position: Optional[List[float]] = None, + **kwargs + ) -> None: super().__init__(env) self.observation_shape = observation_shape - self.shape = (stack_size, ) + self.observation_shape + self.shape = (stack_size,) + self.observation_shape self.weights = weights self.obs = np.zeros(self.shape, dtype=np.uint8) # The viewer configuration can be different between this observation and env.render() (typically smaller) viewer_config = env.config.copy() - viewer_config.update({ - "offscreen_rendering": True, - "screen_width": self.observation_shape[0], - "screen_height": self.observation_shape[1], - "scaling": scaling or viewer_config["scaling"], - "centering_position": centering_position or viewer_config["centering_position"] - }) + viewer_config.update( + { + "offscreen_rendering": True, + "screen_width": self.observation_shape[0], + "screen_height": self.observation_shape[1], + "scaling": scaling or viewer_config["scaling"], + "centering_position": centering_position + or viewer_config["centering_position"], + } + ) self.viewer = EnvViewer(env, config=viewer_config)
@@ -406,34 +412,42 @@

Source code for highway_env.envs.common.observation

class TimeToCollisionObservation(ObservationType): - def __init__(self, env: 'AbstractEnv', horizon: int = 10, **kwargs: dict) -> None: + def __init__(self, env: "AbstractEnv", horizon: int = 10, **kwargs: dict) -> None: super().__init__(env) self.horizon = horizon def space(self) -> spaces.Space: try: - return spaces.Box(shape=self.observe().shape, low=0, high=1, dtype=np.float32) + return spaces.Box( + shape=self.observe().shape, low=0, high=1, dtype=np.float32 + ) except AttributeError: return spaces.Space() def observe(self) -> np.ndarray: if not self.env.road: - return np.zeros((3, 3, int(self.horizon * self.env.config["policy_frequency"]))) - grid = compute_ttc_grid(self.env, vehicle=self.observer_vehicle, - time_quantization=1/self.env.config["policy_frequency"], horizon=self.horizon) + return np.zeros( + (3, 3, int(self.horizon * self.env.config["policy_frequency"])) + ) + grid = compute_ttc_grid( + self.env, + vehicle=self.observer_vehicle, + time_quantization=1 / self.env.config["policy_frequency"], + horizon=self.horizon, + ) padding = np.ones(np.shape(grid)) padded_grid = np.concatenate([padding, grid, padding], axis=1) obs_lanes = 3 l0 = grid.shape[1] + self.observer_vehicle.lane_index[2] - obs_lanes // 2 lf = grid.shape[1] + self.observer_vehicle.lane_index[2] + obs_lanes // 2 - clamped_grid = padded_grid[:, l0:lf+1, :] + clamped_grid = padded_grid[:, l0 : lf + 1, :] repeats = np.ones(clamped_grid.shape[0]) repeats[np.array([0, -1])] += clamped_grid.shape[0] padded_grid = np.repeat(clamped_grid, repeats.astype(int), axis=0) obs_speeds = 3 v0 = grid.shape[0] + self.observer_vehicle.speed_index - obs_speeds // 2 vf = grid.shape[0] + self.observer_vehicle.speed_index + obs_speeds // 2 - clamped_grid = padded_grid[v0:vf + 1, :, :] + clamped_grid = padded_grid[v0 : vf + 1, :, :] return clamped_grid.astype(np.float32) @@ -443,20 +457,23 @@

Source code for highway_env.envs.common.observation

"""Observe the kinematics of nearby vehicles.""" - FEATURES: List[str] = ['presence', 'x', 'y', 'vx', 'vy'] - - def __init__(self, env: 'AbstractEnv', - features: List[str] = None, - vehicles_count: int = 5, - features_range: Dict[str, List[float]] = None, - absolute: bool = False, - order: str = "sorted", - normalize: bool = True, - clip: bool = True, - see_behind: bool = False, - observe_intentions: bool = False, - include_obstacles: bool = True, - **kwargs: dict) -> None: + FEATURES: List[str] = ["presence", "x", "y", "vx", "vy"] + + def __init__( + self, + env: "AbstractEnv", + features: List[str] = None, + vehicles_count: int = 5, + features_range: Dict[str, List[float]] = None, + absolute: bool = False, + order: str = "sorted", + normalize: bool = True, + clip: bool = True, + see_behind: bool = False, + observe_intentions: bool = False, + include_obstacles: bool = True, + **kwargs: dict + ) -> None: """ :param env: The environment to observe :param features: Names of features used in the observation @@ -484,7 +501,12 @@

Source code for highway_env.envs.common.observation

[docs] def space(self) -> spaces.Space: - return spaces.Box(shape=(self.vehicles_count, len(self.features)), low=-np.inf, high=np.inf, dtype=np.float32)
+ return spaces.Box( + shape=(self.vehicles_count, len(self.features)), + low=-np.inf, + high=np.inf, + dtype=np.float32, + )
@@ -497,12 +519,17 @@

Source code for highway_env.envs.common.observation

:param Dataframe df: observation data """ if not self.features_range: - side_lanes = self.env.road.network.all_side_lanes(self.observer_vehicle.lane_index) + side_lanes = self.env.road.network.all_side_lanes( + self.observer_vehicle.lane_index + ) self.features_range = { "x": [-5.0 * Vehicle.MAX_SPEED, 5.0 * Vehicle.MAX_SPEED], - "y": [-AbstractLane.DEFAULT_WIDTH * len(side_lanes), AbstractLane.DEFAULT_WIDTH * len(side_lanes)], - "vx": [-2*Vehicle.MAX_SPEED, 2*Vehicle.MAX_SPEED], - "vy": [-2*Vehicle.MAX_SPEED, 2*Vehicle.MAX_SPEED] + "y": [ + -AbstractLane.DEFAULT_WIDTH * len(side_lanes), + AbstractLane.DEFAULT_WIDTH * len(side_lanes), + ], + "vx": [-2 * Vehicle.MAX_SPEED, 2 * Vehicle.MAX_SPEED], + "vy": [-2 * Vehicle.MAX_SPEED, 2 * Vehicle.MAX_SPEED], } for feature, f_range in self.features_range.items(): if feature in df: @@ -521,17 +548,22 @@

Source code for highway_env.envs.common.observation

# Add ego-vehicle df = pd.DataFrame.from_records([self.observer_vehicle.to_dict()]) # Add nearby traffic - close_vehicles = self.env.road.close_objects_to(self.observer_vehicle, - self.env.PERCEPTION_DISTANCE, - count=self.vehicles_count - 1, - see_behind=self.see_behind, - sort=self.order == "sorted", - vehicles_only=not self.include_obstacles) + close_vehicles = self.env.road.close_objects_to( + self.observer_vehicle, + self.env.PERCEPTION_DISTANCE, + count=self.vehicles_count - 1, + see_behind=self.see_behind, + sort=self.order == "sorted", + vehicles_only=not self.include_obstacles, + ) if close_vehicles: origin = self.observer_vehicle if not self.absolute else None vehicles_df = pd.DataFrame.from_records( - [v.to_dict(origin, observe_intentions=self.observe_intentions) - for v in close_vehicles[-self.vehicles_count + 1:]]) + [ + v.to_dict(origin, observe_intentions=self.observe_intentions) + for v in close_vehicles[-self.vehicles_count + 1 :] + ] + ) df = pd.concat([df, vehicles_df], ignore_index=True) df = df[self.features] @@ -542,7 +574,9 @@

Source code for highway_env.envs.common.observation

# Fill missing rows if df.shape[0] < self.vehicles_count: rows = np.zeros((self.vehicles_count - df.shape[0], len(self.features))) - df = pd.concat([df, pd.DataFrame(data=rows, columns=self.features)], ignore_index=True) + df = pd.concat( + [df, pd.DataFrame(data=rows, columns=self.features)], ignore_index=True + ) # Reorder df = df[self.features] obs = df.values.copy() @@ -560,21 +594,23 @@

Source code for highway_env.envs.common.observation

"""Observe an occupancy grid of nearby vehicles.""" - FEATURES: List[str] = ['presence', 'vx', 'vy', 'on_road'] - GRID_SIZE: List[List[float]] = [[-5.5*5, 5.5*5], [-5.5*5, 5.5*5]] + FEATURES: List[str] = ["presence", "vx", "vy", "on_road"] + GRID_SIZE: List[List[float]] = [[-5.5 * 5, 5.5 * 5], [-5.5 * 5, 5.5 * 5]] GRID_STEP: List[int] = [5, 5] - def __init__(self, - env: 'AbstractEnv', - features: Optional[List[str]] = None, - grid_size: Optional[Tuple[Tuple[float, float], Tuple[float, float]]] = None, - grid_step: Optional[Tuple[float, float]] = None, - features_range: Dict[str, List[float]] = None, - absolute: bool = False, - align_to_vehicle_axes: bool = False, - clip: bool = True, - as_image: bool = False, - **kwargs: dict) -> None: + def __init__( + self, + env: "AbstractEnv", + features: Optional[List[str]] = None, + grid_size: Optional[Tuple[Tuple[float, float], Tuple[float, float]]] = None, + grid_step: Optional[Tuple[float, float]] = None, + features_range: Dict[str, List[float]] = None, + absolute: bool = False, + align_to_vehicle_axes: bool = False, + clip: bool = True, + as_image: bool = False, + **kwargs: dict + ) -> None: """ :param env: The environment to observe :param features: Names of features used in the observation @@ -588,10 +624,16 @@

Source code for highway_env.envs.common.observation

""" super().__init__(env) self.features = features if features is not None else self.FEATURES - self.grid_size = np.array(grid_size) if grid_size is not None else np.array(self.GRID_SIZE) - self.grid_step = np.array(grid_step) if grid_step is not None else np.array(self.GRID_STEP) - grid_shape = np.asarray(np.floor((self.grid_size[:, 1] - self.grid_size[:, 0]) / self.grid_step), - dtype=np.uint8) + self.grid_size = ( + np.array(grid_size) if grid_size is not None else np.array(self.GRID_SIZE) + ) + self.grid_step = ( + np.array(grid_step) if grid_step is not None else np.array(self.GRID_STEP) + ) + grid_shape = np.asarray( + np.floor((self.grid_size[:, 1] - self.grid_size[:, 0]) / self.grid_step), + dtype=np.uint8, + ) self.grid = np.zeros((len(self.features), *grid_shape)) self.features_range = features_range self.absolute = absolute @@ -605,7 +647,9 @@

Source code for highway_env.envs.common.observation

if self.as_image: return spaces.Box(shape=self.grid.shape, low=0, high=255, dtype=np.uint8) else: - return spaces.Box(shape=self.grid.shape, low=-np.inf, high=np.inf, dtype=np.float32)
+ return spaces.Box( + shape=self.grid.shape, low=-np.inf, high=np.inf, dtype=np.float32 + )
@@ -619,8 +663,8 @@

Source code for highway_env.envs.common.observation

""" if not self.features_range: self.features_range = { - "vx": [-2*Vehicle.MAX_SPEED, 2*Vehicle.MAX_SPEED], - "vy": [-2*Vehicle.MAX_SPEED, 2*Vehicle.MAX_SPEED] + "vx": [-2 * Vehicle.MAX_SPEED, 2 * Vehicle.MAX_SPEED], + "vy": [-2 * Vehicle.MAX_SPEED, 2 * Vehicle.MAX_SPEED], } for feature, f_range in self.features_range.items(): if feature in df: @@ -642,7 +686,8 @@

Source code for highway_env.envs.common.observation

# Get nearby traffic data df = pd.DataFrame.from_records( - [v.to_dict(self.observer_vehicle) for v in self.env.road.vehicles]) + [v.to_dict(self.observer_vehicle) for v in self.env.road.vehicles] + ) # Normalize df = self.normalize(df) # Fill-in features @@ -652,11 +697,28 @@

Source code for highway_env.envs.common.observation

x, y = vehicle["x"], vehicle["y"] # Recover unnormalized coordinates for cell index if "x" in self.features_range: - x = utils.lmap(x, [-1, 1], [self.features_range["x"][0], self.features_range["x"][1]]) + x = utils.lmap( + x, + [-1, 1], + [ + self.features_range["x"][0], + self.features_range["x"][1], + ], + ) if "y" in self.features_range: - y = utils.lmap(y, [-1, 1], [self.features_range["y"][0], self.features_range["y"][1]]) + y = utils.lmap( + y, + [-1, 1], + [ + self.features_range["y"][0], + self.features_range["y"][1], + ], + ) cell = self.pos_to_index((x, y), relative=not self.absolute) - if 0 <= cell[1] < self.grid.shape[-2] and 0 <= cell[0] < self.grid.shape[-1]: + if ( + 0 <= cell[1] < self.grid.shape[-2] + and 0 <= cell[0] < self.grid.shape[-1] + ): self.grid[layer, cell[1], cell[0]] = vehicle[feature] elif feature == "on_road": self.fill_road_layer_by_lanes(layer) @@ -689,20 +751,26 @@

Source code for highway_env.envs.common.observation

if not relative: position -= self.observer_vehicle.position if self.align_to_vehicle_axes: - c, s = np.cos(self.observer_vehicle.heading), np.sin(self.observer_vehicle.heading) + c, s = np.cos(self.observer_vehicle.heading), np.sin( + self.observer_vehicle.heading + ) position = np.array([[c, s], [-s, c]]) @ position - return int(np.floor((position[0] - self.grid_size[0, 0]) / self.grid_step[0])),\ - int(np.floor((position[1] - self.grid_size[1, 0]) / self.grid_step[1]))
+ return int( + np.floor((position[0] - self.grid_size[0, 0]) / self.grid_step[0]) + ), int(np.floor((position[1] - self.grid_size[1, 0]) / self.grid_step[1]))
def index_to_pos(self, index: Tuple[int, int]) -> np.ndarray: - - position = np.array([ - (index[1] + 0.5) * self.grid_step[0] + self.grid_size[0, 0], - (index[0] + 0.5) * self.grid_step[1] + self.grid_size[1, 0] - ]) + position = np.array( + [ + (index[1] + 0.5) * self.grid_step[0] + self.grid_size[0, 0], + (index[0] + 0.5) * self.grid_step[1] + self.grid_size[1, 0], + ] + ) if self.align_to_vehicle_axes: - c, s = np.cos(-self.observer_vehicle.heading), np.sin(-self.observer_vehicle.heading) + c, s = np.cos(-self.observer_vehicle.heading), np.sin( + -self.observer_vehicle.heading + ) position = np.array([[c, s], [-s, c]]) @ position position += self.observer_vehicle.position @@ -710,7 +778,9 @@

Source code for highway_env.envs.common.observation

[docs] - def fill_road_layer_by_lanes(self, layer_index: int, lane_perception_distance: float = 100) -> None: + def fill_road_layer_by_lanes( + self, layer_index: int, lane_perception_distance: float = 100 + ) -> None: """ A layer to encode the onroad (1) / offroad (0) information @@ -727,12 +797,17 @@

Source code for highway_env.envs.common.observation

for _to in road.network.graph[_from].keys(): for lane in road.network.graph[_from][_to]: origin, _ = lane.local_coordinates(self.observer_vehicle.position) - waypoints = np.arange(origin - lane_perception_distance, - origin + lane_perception_distance, - lane_waypoints_spacing).clip(0, lane.length) + waypoints = np.arange( + origin - lane_perception_distance, + origin + lane_perception_distance, + lane_waypoints_spacing, + ).clip(0, lane.length) for waypoint in waypoints: cell = self.pos_to_index(lane.position(waypoint, 0)) - if 0 <= cell[1] < self.grid.shape[-2] and 0 <= cell[0] < self.grid.shape[-1]: + if ( + 0 <= cell[1] < self.grid.shape[-2] + and 0 <= cell[0] < self.grid.shape[-1] + ): self.grid[layer_index, cell[1], cell[0]] = 1
@@ -759,7 +834,7 @@

Source code for highway_env.envs.common.observation

[docs] class KinematicsGoalObservation(KinematicObservation): - def __init__(self, env: 'AbstractEnv', scales: List[float], **kwargs: dict) -> None: + def __init__(self, env: "AbstractEnv", scales: List[float], **kwargs: dict) -> None: self.scales = np.array(scales) super().__init__(env, **kwargs) @@ -768,11 +843,28 @@

Source code for highway_env.envs.common.observation

def space(self) -> spaces.Space: try: obs = self.observe() - return spaces.Dict(dict( - desired_goal=spaces.Box(-np.inf, np.inf, shape=obs["desired_goal"].shape, dtype=np.float64), - achieved_goal=spaces.Box(-np.inf, np.inf, shape=obs["achieved_goal"].shape, dtype=np.float64), - observation=spaces.Box(-np.inf, np.inf, shape=obs["observation"].shape, dtype=np.float64), - )) + return spaces.Dict( + dict( + desired_goal=spaces.Box( + -np.inf, + np.inf, + shape=obs["desired_goal"].shape, + dtype=np.float64, + ), + achieved_goal=spaces.Box( + -np.inf, + np.inf, + shape=obs["achieved_goal"].shape, + dtype=np.float64, + ), + observation=spaces.Box( + -np.inf, + np.inf, + shape=obs["observation"].shape, + dtype=np.float64, + ), + ) + ) except AttributeError: return spaces.Space()
@@ -781,50 +873,61 @@

Source code for highway_env.envs.common.observation

[docs] def observe(self) -> Dict[str, np.ndarray]: if not self.observer_vehicle: - return OrderedDict([ - ("observation", np.zeros((len(self.features),))), - ("achieved_goal", np.zeros((len(self.features),))), - ("desired_goal", np.zeros((len(self.features),))) - ]) - - obs = np.ravel(pd.DataFrame.from_records([self.observer_vehicle.to_dict()])[self.features]) - goal = np.ravel(pd.DataFrame.from_records([self.env.goal.to_dict()])[self.features]) - obs = OrderedDict([ - ("observation", obs / self.scales), - ("achieved_goal", obs / self.scales), - ("desired_goal", goal / self.scales) - ]) + return OrderedDict( + [ + ("observation", np.zeros((len(self.features),))), + ("achieved_goal", np.zeros((len(self.features),))), + ("desired_goal", np.zeros((len(self.features),))), + ] + ) + + obs = np.ravel( + pd.DataFrame.from_records([self.observer_vehicle.to_dict()])[self.features] + ) + goal = np.ravel( + pd.DataFrame.from_records([self.env.goal.to_dict()])[self.features] + ) + obs = OrderedDict( + [ + ("observation", obs / self.scales), + ("achieved_goal", obs / self.scales), + ("desired_goal", goal / self.scales), + ] + ) return obs
class AttributesObservation(ObservationType): - def __init__(self, env: 'AbstractEnv', attributes: List[str], **kwargs: dict) -> None: + def __init__( + self, env: "AbstractEnv", attributes: List[str], **kwargs: dict + ) -> None: self.env = env self.attributes = attributes def space(self) -> spaces.Space: try: obs = self.observe() - return spaces.Dict({ - attribute: spaces.Box(-np.inf, np.inf, shape=obs[attribute].shape, dtype=np.float64) - for attribute in self.attributes - }) + return spaces.Dict( + { + attribute: spaces.Box( + -np.inf, np.inf, shape=obs[attribute].shape, dtype=np.float64 + ) + for attribute in self.attributes + } + ) except AttributeError: return spaces.Space() def observe(self) -> Dict[str, np.ndarray]: - return OrderedDict([ - (attribute, getattr(self.env, attribute)) for attribute in self.attributes - ]) + return OrderedDict( + [(attribute, getattr(self.env, attribute)) for attribute in self.attributes] + ) class MultiAgentObservation(ObservationType): - def __init__(self, - env: 'AbstractEnv', - observation_config: dict, - **kwargs) -> None: + def __init__(self, env: "AbstractEnv", observation_config: dict, **kwargs) -> None: super().__init__(env) self.observation_config = observation_config self.agents_observation_types = [] @@ -834,19 +937,23 @@

Source code for highway_env.envs.common.observation

self.agents_observation_types.append(obs_type) def space(self) -> spaces.Space: - return spaces.Tuple([obs_type.space() for obs_type in self.agents_observation_types]) + return spaces.Tuple( + [obs_type.space() for obs_type in self.agents_observation_types] + ) def observe(self) -> tuple: return tuple(obs_type.observe() for obs_type in self.agents_observation_types) class TupleObservation(ObservationType): - def __init__(self, - env: 'AbstractEnv', - observation_configs: List[dict], - **kwargs) -> None: + def __init__( + self, env: "AbstractEnv", observation_configs: List[dict], **kwargs + ) -> None: super().__init__(env) - self.observation_types = [observation_factory(self.env, obs_config) for obs_config in observation_configs] + self.observation_types = [ + observation_factory(self.env, obs_config) + for obs_config in observation_configs + ] def space(self) -> spaces.Space: return spaces.Tuple([obs_type.space() for obs_type in self.observation_types]) @@ -874,23 +981,37 @@

Source code for highway_env.envs.common.observation

df = pd.DataFrame.from_records([ego_dict])[self.features] # Add nearby traffic - close_vehicles = self.env.road.close_vehicles_to(self.observer_vehicle, - self.env.PERCEPTION_DISTANCE, - count=self.vehicles_count - 1, - see_behind=self.see_behind) + close_vehicles = self.env.road.close_vehicles_to( + self.observer_vehicle, + self.env.PERCEPTION_DISTANCE, + count=self.vehicles_count - 1, + see_behind=self.see_behind, + ) if close_vehicles: origin = self.observer_vehicle if not self.absolute else None - df = pd.concat([df, pd.DataFrame.from_records( - [v.to_dict(origin, observe_intentions=self.observe_intentions) - for v in close_vehicles[-self.vehicles_count + 1:]])[self.features]], - ignore_index=True) + df = pd.concat( + [ + df, + pd.DataFrame.from_records( + [ + v.to_dict( + origin, observe_intentions=self.observe_intentions + ) + for v in close_vehicles[-self.vehicles_count + 1 :] + ] + )[self.features], + ], + ignore_index=True, + ) # Normalize and clip if self.normalize: df = self.normalize_obs(df) # Fill missing rows if df.shape[0] < self.vehicles_count: rows = np.zeros((self.vehicles_count - df.shape[0], len(self.features))) - df = pd.concat([df, pd.DataFrame(data=rows, columns=self.features)], ignore_index=True) + df = pd.concat( + [df, pd.DataFrame(data=rows, columns=self.features)], ignore_index=True + ) # Reorder df = df[self.features] obs = df.values.copy() @@ -906,17 +1027,20 @@

Source code for highway_env.envs.common.observation

DISTANCE = 0 SPEED = 1 - def __init__(self, env, - cells: int = 16, - maximum_range: float = 60, - normalize: bool = True, - **kwargs): + def __init__( + self, + env, + cells: int = 16, + maximum_range: float = 60, + normalize: bool = True, + **kwargs + ): super().__init__(env, **kwargs) self.cells = cells self.maximum_range = maximum_range self.normalize = normalize self.angle = 2 * np.pi / self.cells - self.grid = np.ones((self.cells, 1)) * float('inf') + self.grid = np.ones((self.cells, 1)) * float("inf") self.origin = None def space(self) -> spaces.Space: @@ -924,7 +1048,9 @@

Source code for highway_env.envs.common.observation

return spaces.Box(shape=(self.cells, 2), low=-high, high=high, dtype=np.float32) def observe(self) -> np.ndarray: - obs = self.trace(self.observer_vehicle.position, self.observer_vehicle.velocity).copy() + obs = self.trace( + self.observer_vehicle.position, self.observer_vehicle.velocity + ).copy() if self.normalize: obs /= self.maximum_range return obs @@ -948,16 +1074,22 @@

Source code for highway_env.envs.common.observation

self.grid[center_index, :] = [distance, velocity] # Angular sector covered by the obstacle - corners = utils.rect_corners(obstacle.position, obstacle.LENGTH, obstacle.WIDTH, obstacle.heading) + corners = utils.rect_corners( + obstacle.position, obstacle.LENGTH, obstacle.WIDTH, obstacle.heading + ) angles = [self.position_to_angle(corner, origin) for corner in corners] min_angle, max_angle = min(angles), max(angles) - if min_angle < -np.pi/2 < np.pi/2 < max_angle: # Object's corners are wrapping around +pi - min_angle, max_angle = max_angle, min_angle + 2*np.pi + if ( + min_angle < -np.pi / 2 < np.pi / 2 < max_angle + ): # Object's corners are wrapping around +pi + min_angle, max_angle = max_angle, min_angle + 2 * np.pi start, end = self.angle_to_index(min_angle), self.angle_to_index(max_angle) if start < end: - indexes = np.arange(start, end+1) + indexes = np.arange(start, end + 1) else: # Object's corners are wrapping around 0 - indexes = np.hstack([np.arange(start, self.cells), np.arange(0, end + 1)]) + indexes = np.hstack( + [np.arange(start, self.cells), np.arange(0, end + 1)] + ) # Actual distance computation for these sections for index in indexes: @@ -970,7 +1102,10 @@

Source code for highway_env.envs.common.observation

return self.grid def position_to_angle(self, position: np.ndarray, origin: np.ndarray) -> float: - return np.arctan2(position[1] - origin[1], position[0] - origin[0]) + self.angle/2 + return ( + np.arctan2(position[1] - origin[1], position[0] - origin[0]) + + self.angle / 2 + ) def position_to_index(self, position: np.ndarray, origin: np.ndarray) -> int: return self.angle_to_index(self.position_to_angle(position, origin)) @@ -982,7 +1117,7 @@

Source code for highway_env.envs.common.observation

return np.array([np.cos(index * self.angle), np.sin(index * self.angle)]) -def observation_factory(env: 'AbstractEnv', config: dict) -> ObservationType: +def observation_factory(env: "AbstractEnv", config: dict) -> ObservationType: if config["type"] == "TimeToCollision": return TimeToCollisionObservation(env, **config) elif config["type"] == "Kinematics": diff --git a/main/_modules/highway_env/envs/highway_env/index.html b/main/_modules/highway_env/envs/highway_env/index.html index d686e9e1f..e42242034 100644 --- a/main/_modules/highway_env/envs/highway_env/index.html +++ b/main/_modules/highway_env/envs/highway_env/index.html @@ -321,30 +321,30 @@

Source code for highway_env.envs.highway_env

@classmethod
     def default_config(cls) -> dict:
         config = super().default_config()
-        config.update({
-            "observation": {
-                "type": "Kinematics"
-            },
-            "action": {
-                "type": "DiscreteMetaAction",
-            },
-            "lanes_count": 4,
-            "vehicles_count": 50,
-            "controlled_vehicles": 1,
-            "initial_lane_id": None,
-            "duration": 40,  # [s]
-            "ego_spacing": 2,
-            "vehicles_density": 1,
-            "collision_reward": -1,    # The reward received when colliding with a vehicle.
-            "right_lane_reward": 0.1,  # The reward received when driving on the right-most lanes, linearly mapped to
-                                       # zero for other lanes.
-            "high_speed_reward": 0.4,  # The reward received when driving at full speed, linearly mapped to zero for
-                                       # lower speeds according to config["reward_speed_range"].
-            "lane_change_reward": 0,   # The reward received at each lane change action.
-            "reward_speed_range": [20, 30],
-            "normalize_reward": True,
-            "offroad_terminal": False
-        })
+        config.update(
+            {
+                "observation": {"type": "Kinematics"},
+                "action": {
+                    "type": "DiscreteMetaAction",
+                },
+                "lanes_count": 4,
+                "vehicles_count": 50,
+                "controlled_vehicles": 1,
+                "initial_lane_id": None,
+                "duration": 40,  # [s]
+                "ego_spacing": 2,
+                "vehicles_density": 1,
+                "collision_reward": -1,  # The reward received when colliding with a vehicle.
+                "right_lane_reward": 0.1,  # The reward received when driving on the right-most lanes, linearly mapped to
+                # zero for other lanes.
+                "high_speed_reward": 0.4,  # The reward received when driving at full speed, linearly mapped to zero for
+                # lower speeds according to config["reward_speed_range"].
+                "lane_change_reward": 0,  # The reward received at each lane change action.
+                "reward_speed_range": [20, 30],
+                "normalize_reward": True,
+                "offroad_terminal": False,
+            }
+        )
         return config
@@ -354,13 +354,20 @@

Source code for highway_env.envs.highway_env

def _create_road(self) -> None:
         """Create a road composed of straight adjacent lanes."""
-        self.road = Road(network=RoadNetwork.straight_road_network(self.config["lanes_count"], speed_limit=30),
-                         np_random=self.np_random, record_history=self.config["show_trajectories"])
+        self.road = Road(
+            network=RoadNetwork.straight_road_network(
+                self.config["lanes_count"], speed_limit=30
+            ),
+            np_random=self.np_random,
+            record_history=self.config["show_trajectories"],
+        )
 
     def _create_vehicles(self) -> None:
         """Create some new random vehicles of a given type, and add them on the road."""
         other_vehicles_type = utils.class_from_path(self.config["other_vehicles_type"])
-        other_per_controlled = near_split(self.config["vehicles_count"], num_bins=self.config["controlled_vehicles"])
+        other_per_controlled = near_split(
+            self.config["vehicles_count"], num_bins=self.config["controlled_vehicles"]
+        )
 
         self.controlled_vehicles = []
         for others in other_per_controlled:
@@ -368,14 +375,18 @@ 

Source code for highway_env.envs.highway_env

self.road,
                 speed=25,
                 lane_id=self.config["initial_lane_id"],
-                spacing=self.config["ego_spacing"]
+                spacing=self.config["ego_spacing"],
+            )
+            vehicle = self.action_type.vehicle_class(
+                self.road, vehicle.position, vehicle.heading, vehicle.speed
             )
-            vehicle = self.action_type.vehicle_class(self.road, vehicle.position, vehicle.heading, vehicle.speed)
             self.controlled_vehicles.append(vehicle)
             self.road.vehicles.append(vehicle)
 
             for _ in range(others):
-                vehicle = other_vehicles_type.create_random(self.road, spacing=1 / self.config["vehicles_density"])
+                vehicle = other_vehicles_type.create_random(
+                    self.road, spacing=1 / self.config["vehicles_density"]
+                )
                 vehicle.randomize_behavior()
                 self.road.vehicles.append(vehicle)
 
@@ -386,33 +397,47 @@ 

Source code for highway_env.envs.highway_env

        :return: the corresponding reward
         """
         rewards = self._rewards(action)
-        reward = sum(self.config.get(name, 0) * reward for name, reward in rewards.items())
+        reward = sum(
+            self.config.get(name, 0) * reward for name, reward in rewards.items()
+        )
         if self.config["normalize_reward"]:
-            reward = utils.lmap(reward,
-                                [self.config["collision_reward"],
-                                 self.config["high_speed_reward"] + self.config["right_lane_reward"]],
-                                [0, 1])
-        reward *= rewards['on_road_reward']
+            reward = utils.lmap(
+                reward,
+                [
+                    self.config["collision_reward"],
+                    self.config["high_speed_reward"] + self.config["right_lane_reward"],
+                ],
+                [0, 1],
+            )
+        reward *= rewards["on_road_reward"]
         return reward
 
     def _rewards(self, action: Action) -> Dict[Text, float]:
         neighbours = self.road.network.all_side_lanes(self.vehicle.lane_index)
-        lane = self.vehicle.target_lane_index[2] if isinstance(self.vehicle, ControlledVehicle) \
+        lane = (
+            self.vehicle.target_lane_index[2]
+            if isinstance(self.vehicle, ControlledVehicle)
             else self.vehicle.lane_index[2]
+        )
         # Use forward speed rather than speed, see https://github.com/eleurent/highway-env/issues/268
         forward_speed = self.vehicle.speed * np.cos(self.vehicle.heading)
-        scaled_speed = utils.lmap(forward_speed, self.config["reward_speed_range"], [0, 1])
+        scaled_speed = utils.lmap(
+            forward_speed, self.config["reward_speed_range"], [0, 1]
+        )
         return {
             "collision_reward": float(self.vehicle.crashed),
             "right_lane_reward": lane / max(len(neighbours) - 1, 1),
             "high_speed_reward": np.clip(scaled_speed, 0, 1),
-            "on_road_reward": float(self.vehicle.on_road)
+            "on_road_reward": float(self.vehicle.on_road),
         }
 
     def _is_terminated(self) -> bool:
         """The episode is over if the ego vehicle crashed."""
-        return (self.vehicle.crashed or
-                self.config["offroad_terminal"] and not self.vehicle.on_road)
+        return (
+            self.vehicle.crashed
+            or self.config["offroad_terminal"]
+            and not self.vehicle.on_road
+        )
 
     def _is_truncated(self) -> bool:
         """The episode is truncated if the time limit is reached."""
@@ -427,16 +452,19 @@ 

Source code for highway_env.envs.highway_env

        - fewer vehicles in the scene (and fewer lanes, shorter episode duration)
         - only check collision of controlled vehicles with others
     """
+
     @classmethod
     def default_config(cls) -> dict:
         cfg = super().default_config()
-        cfg.update({
-            "simulation_frequency": 5,
-            "lanes_count": 3,
-            "vehicles_count": 20,
-            "duration": 30,  # [s]
-            "ego_spacing": 1.5,
-        })
+        cfg.update(
+            {
+                "simulation_frequency": 5,
+                "lanes_count": 3,
+                "vehicles_count": 20,
+                "duration": 30,  # [s]
+                "ego_spacing": 1.5,
+            }
+        )
         return cfg
 
     def _create_vehicles(self) -> None:
diff --git a/main/_modules/highway_env/envs/intersection_env/index.html b/main/_modules/highway_env/envs/intersection_env/index.html
index 17cf9fe86..e4a1b2aee 100644
--- a/main/_modules/highway_env/envs/intersection_env/index.html
+++ b/main/_modules/highway_env/envs/intersection_env/index.html
@@ -291,28 +291,22 @@
           

Source code for highway_env.envs.intersection_env

-from typing import Dict, Tuple, Text
+from typing import Dict, Text, Tuple
 
 import numpy as np
 
 from highway_env import utils
 from highway_env.envs.common.abstract import AbstractEnv, MultiAgentWrapper
-from highway_env.road.lane import LineType, StraightLane, CircularLane, AbstractLane
+from highway_env.road.lane import AbstractLane, CircularLane, LineType, StraightLane
 from highway_env.road.regulation import RegulatedRoad
 from highway_env.road.road import RoadNetwork
 from highway_env.vehicle.kinematics import Vehicle
-from highway_env.vehicle.controller import ControlledVehicle
 
 
 
[docs] class IntersectionEnv(AbstractEnv): - - ACTIONS: Dict[int, str] = { - 0: 'SLOWER', - 1: 'IDLE', - 2: 'FASTER' - } + ACTIONS: Dict[int, str] = {0: "SLOWER", 1: "IDLE", 2: "FASTER"} ACTIONS_INDEXES = {v: k for k, v in ACTIONS.items()}
@@ -320,88 +314,103 @@

Source code for highway_env.envs.intersection_env

@classmethod def default_config(cls) -> dict: config = super().default_config() - config.update({ - "observation": { - "type": "Kinematics", - "vehicles_count": 15, - "features": ["presence", "x", "y", "vx", "vy", "cos_h", "sin_h"], - "features_range": { - "x": [-100, 100], - "y": [-100, 100], - "vx": [-20, 20], - "vy": [-20, 20], + config.update( + { + "observation": { + "type": "Kinematics", + "vehicles_count": 15, + "features": ["presence", "x", "y", "vx", "vy", "cos_h", "sin_h"], + "features_range": { + "x": [-100, 100], + "y": [-100, 100], + "vx": [-20, 20], + "vy": [-20, 20], + }, + "absolute": True, + "flatten": False, + "observe_intentions": False, + }, + "action": { + "type": "DiscreteMetaAction", + "longitudinal": True, + "lateral": False, + "target_speeds": [0, 4.5, 9], }, - "absolute": True, - "flatten": False, - "observe_intentions": False - }, - "action": { - "type": "DiscreteMetaAction", - "longitudinal": True, - "lateral": False, - "target_speeds": [0, 4.5, 9] - }, - "duration": 13, # [s] - "destination": "o1", - "controlled_vehicles": 1, - "initial_vehicle_count": 10, - "spawn_probability": 0.6, - "screen_width": 600, - "screen_height": 600, - "centering_position": [0.5, 0.6], - "scaling": 5.5 * 1.3, - "collision_reward": -5, - "high_speed_reward": 1, - "arrived_reward": 1, - "reward_speed_range": [7.0, 9.0], - "normalize_reward": False, - "offroad_terminal": False - }) + "duration": 13, # [s] + "destination": "o1", + "controlled_vehicles": 1, + "initial_vehicle_count": 10, + "spawn_probability": 0.6, + "screen_width": 600, + "screen_height": 600, + "centering_position": [0.5, 0.6], + "scaling": 5.5 * 1.3, + "collision_reward": -5, + "high_speed_reward": 1, + "arrived_reward": 1, + "reward_speed_range": [7.0, 9.0], + "normalize_reward": False, + "offroad_terminal": False, + } + ) return config
def _reward(self, action: int) -> float: """Aggregated reward, for cooperative agents.""" - return sum(self._agent_reward(action, vehicle) for vehicle in self.controlled_vehicles - ) / len(self.controlled_vehicles) + return sum( + self._agent_reward(action, vehicle) for vehicle in self.controlled_vehicles + ) / len(self.controlled_vehicles) def _rewards(self, action: int) -> Dict[Text, float]: """Multi-objective rewards, for cooperative agents.""" - agents_rewards = [self._agent_rewards(action, vehicle) for vehicle in self.controlled_vehicles] + agents_rewards = [ + self._agent_rewards(action, vehicle) for vehicle in self.controlled_vehicles + ] return { - name: sum(agent_rewards[name] for agent_rewards in agents_rewards) / len(agents_rewards) + name: sum(agent_rewards[name] for agent_rewards in agents_rewards) + / len(agents_rewards) for name in agents_rewards[0].keys() } def _agent_reward(self, action: int, vehicle: Vehicle) -> float: """Per-agent reward signal.""" rewards = self._agent_rewards(action, vehicle) - reward = sum(self.config.get(name, 0) * reward for name, reward in rewards.items()) + reward = sum( + self.config.get(name, 0) * reward for name, reward in rewards.items() + ) reward = self.config["arrived_reward"] if rewards["arrived_reward"] else reward reward *= rewards["on_road_reward"] if self.config["normalize_reward"]: - reward = utils.lmap(reward, [self.config["collision_reward"], self.config["arrived_reward"]], [0, 1]) + reward = utils.lmap( + reward, + [self.config["collision_reward"], self.config["arrived_reward"]], + [0, 1], + ) return reward def _agent_rewards(self, action: int, vehicle: Vehicle) -> Dict[Text, float]: """Per-agent per-objective reward signal.""" - scaled_speed = utils.lmap(vehicle.speed, self.config["reward_speed_range"], [0, 1]) + scaled_speed = utils.lmap( + vehicle.speed, self.config["reward_speed_range"], [0, 1] + ) return { "collision_reward": vehicle.crashed, "high_speed_reward": np.clip(scaled_speed, 0, 1), "arrived_reward": self.has_arrived(vehicle), - "on_road_reward": vehicle.on_road + "on_road_reward": vehicle.on_road, } def _is_terminated(self) -> bool: - return any(vehicle.crashed for vehicle in self.controlled_vehicles) \ - or all(self.has_arrived(vehicle) for vehicle in self.controlled_vehicles) \ - or (self.config["offroad_terminal"] and not self.vehicle.on_road) + return ( + any(vehicle.crashed for vehicle in self.controlled_vehicles) + or all(self.has_arrived(vehicle) for vehicle in self.controlled_vehicles) + or (self.config["offroad_terminal"] and not self.vehicle.on_road) + ) def _agent_is_terminal(self, vehicle: Vehicle) -> bool: """The episode is over when a collision occurs or when the access ramp has been passed.""" - return (vehicle.crashed or - self.has_arrived(vehicle)) + return vehicle.crashed or self.has_arrived(vehicle) def _is_truncated(self) -> bool: """The episode is truncated if the time limit is reached.""" @@ -409,8 +418,12 @@

Source code for highway_env.envs.intersection_env

def _info(self, obs: np.ndarray, action: int) -> dict: info = super()._info(obs, action) - info["agents_rewards"] = tuple(self._agent_reward(action, vehicle) for vehicle in self.controlled_vehicles) - info["agents_dones"] = tuple(self._agent_is_terminal(vehicle) for vehicle in self.controlled_vehicles) + info["agents_rewards"] = tuple( + self._agent_reward(action, vehicle) for vehicle in self.controlled_vehicles + ) + info["agents_dones"] = tuple( + self._agent_is_terminal(vehicle) for vehicle in self.controlled_vehicles + ) return info def _reset(self) -> None: @@ -453,34 +466,87 @@

Source code for highway_env.envs.intersection_env

angle = np.radians(90 * corner) is_horizontal = corner % 2 priority = 3 if is_horizontal else 1 - rotation = np.array([[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]]) + rotation = np.array( + [[np.cos(angle), -np.sin(angle)], [np.sin(angle), np.cos(angle)]] + ) # Incoming - start = rotation @ np.array([lane_width / 2, access_length + outer_distance]) + start = rotation @ np.array( + [lane_width / 2, access_length + outer_distance] + ) end = rotation @ np.array([lane_width / 2, outer_distance]) - net.add_lane("o" + str(corner), "ir" + str(corner), - StraightLane(start, end, line_types=[s, c], priority=priority, speed_limit=10)) + net.add_lane( + "o" + str(corner), + "ir" + str(corner), + StraightLane( + start, end, line_types=[s, c], priority=priority, speed_limit=10 + ), + ) # Right turn r_center = rotation @ (np.array([outer_distance, outer_distance])) - net.add_lane("ir" + str(corner), "il" + str((corner - 1) % 4), - CircularLane(r_center, right_turn_radius, angle + np.radians(180), angle + np.radians(270), - line_types=[n, c], priority=priority, speed_limit=10)) + net.add_lane( + "ir" + str(corner), + "il" + str((corner - 1) % 4), + CircularLane( + r_center, + right_turn_radius, + angle + np.radians(180), + angle + np.radians(270), + line_types=[n, c], + priority=priority, + speed_limit=10, + ), + ) # Left turn - l_center = rotation @ (np.array([-left_turn_radius + lane_width / 2, left_turn_radius - lane_width / 2])) - net.add_lane("ir" + str(corner), "il" + str((corner + 1) % 4), - CircularLane(l_center, left_turn_radius, angle + np.radians(0), angle + np.radians(-90), - clockwise=False, line_types=[n, n], priority=priority - 1, speed_limit=10)) + l_center = rotation @ ( + np.array( + [ + -left_turn_radius + lane_width / 2, + left_turn_radius - lane_width / 2, + ] + ) + ) + net.add_lane( + "ir" + str(corner), + "il" + str((corner + 1) % 4), + CircularLane( + l_center, + left_turn_radius, + angle + np.radians(0), + angle + np.radians(-90), + clockwise=False, + line_types=[n, n], + priority=priority - 1, + speed_limit=10, + ), + ) # Straight start = rotation @ np.array([lane_width / 2, outer_distance]) end = rotation @ np.array([lane_width / 2, -outer_distance]) - net.add_lane("ir" + str(corner), "il" + str((corner + 2) % 4), - StraightLane(start, end, line_types=[s, n], priority=priority, speed_limit=10)) + net.add_lane( + "ir" + str(corner), + "il" + str((corner + 2) % 4), + StraightLane( + start, end, line_types=[s, n], priority=priority, speed_limit=10 + ), + ) # Exit - start = rotation @ np.flip([lane_width / 2, access_length + outer_distance], axis=0) + start = rotation @ np.flip( + [lane_width / 2, access_length + outer_distance], axis=0 + ) end = rotation @ np.flip([lane_width / 2, outer_distance], axis=0) - net.add_lane("il" + str((corner - 1) % 4), "o" + str((corner - 1) % 4), - StraightLane(end, start, line_types=[n, c], priority=priority, speed_limit=10)) - - road = RegulatedRoad(network=net, np_random=self.np_random, record_history=self.config["show_trajectories"]) + net.add_lane( + "il" + str((corner - 1) % 4), + "o" + str((corner - 1) % 4), + StraightLane( + end, start, line_types=[n, c], priority=priority, speed_limit=10 + ), + ) + + road = RegulatedRoad( + network=net, + np_random=self.np_random, + record_history=self.config["show_trajectories"], + ) self.road = road def _make_vehicles(self, n_vehicles: int = 10) -> None: @@ -500,50 +566,80 @@

Source code for highway_env.envs.intersection_env

for t in range(n_vehicles - 1): self._spawn_vehicle(np.linspace(0, 80, n_vehicles)[t]) for _ in range(simulation_steps): - [(self.road.act(), self.road.step(1 / self.config["simulation_frequency"])) for _ in range(self.config["simulation_frequency"])] + [ + ( + self.road.act(), + self.road.step(1 / self.config["simulation_frequency"]), + ) + for _ in range(self.config["simulation_frequency"]) + ] # Challenger vehicle - self._spawn_vehicle(60, spawn_probability=1, go_straight=True, position_deviation=0.1, speed_deviation=0) + self._spawn_vehicle( + 60, + spawn_probability=1, + go_straight=True, + position_deviation=0.1, + speed_deviation=0, + ) # Controlled vehicles self.controlled_vehicles = [] for ego_id in range(0, self.config["controlled_vehicles"]): - ego_lane = self.road.network.get_lane(("o{}".format(ego_id % 4), "ir{}".format(ego_id % 4), 0)) - destination = self.config["destination"] or "o" + str(self.np_random.integers(1, 4)) + ego_lane = self.road.network.get_lane( + ("o{}".format(ego_id % 4), "ir{}".format(ego_id % 4), 0) + ) + destination = self.config["destination"] or "o" + str( + self.np_random.integers(1, 4) + ) ego_vehicle = self.action_type.vehicle_class( - self.road, - ego_lane.position(60 + 5*self.np_random.normal(1), 0), - speed=ego_lane.speed_limit, - heading=ego_lane.heading_at(60)) + self.road, + ego_lane.position(60 + 5 * self.np_random.normal(1), 0), + speed=ego_lane.speed_limit, + heading=ego_lane.heading_at(60), + ) try: ego_vehicle.plan_route_to(destination) - ego_vehicle.speed_index = ego_vehicle.speed_to_index(ego_lane.speed_limit) - ego_vehicle.target_speed = ego_vehicle.index_to_speed(ego_vehicle.speed_index) + ego_vehicle.speed_index = ego_vehicle.speed_to_index( + ego_lane.speed_limit + ) + ego_vehicle.target_speed = ego_vehicle.index_to_speed( + ego_vehicle.speed_index + ) except AttributeError: pass self.road.vehicles.append(ego_vehicle) self.controlled_vehicles.append(ego_vehicle) for v in self.road.vehicles: # Prevent early collisions - if v is not ego_vehicle and np.linalg.norm(v.position - ego_vehicle.position) < 20: + if ( + v is not ego_vehicle + and np.linalg.norm(v.position - ego_vehicle.position) < 20 + ): self.road.vehicles.remove(v) - def _spawn_vehicle(self, - longitudinal: float = 0, - position_deviation: float = 1., - speed_deviation: float = 1., - spawn_probability: float = 0.6, - go_straight: bool = False) -> None: + def _spawn_vehicle( + self, + longitudinal: float = 0, + position_deviation: float = 1.0, + speed_deviation: float = 1.0, + spawn_probability: float = 0.6, + go_straight: bool = False, + ) -> None: if self.np_random.uniform() > spawn_probability: return route = self.np_random.choice(range(4), size=2, replace=False) route[1] = (route[0] + 2) % 4 if go_straight else route[1] vehicle_type = utils.class_from_path(self.config["other_vehicles_type"]) - vehicle = vehicle_type.make_on_lane(self.road, ("o" + str(route[0]), "ir" + str(route[0]), 0), - longitudinal=(longitudinal + 5 - + self.np_random.normal() * position_deviation), - speed=8 + self.np_random.normal() * speed_deviation) + vehicle = vehicle_type.make_on_lane( + self.road, + ("o" + str(route[0]), "ir" + str(route[0]), 0), + longitudinal=( + longitudinal + 5 + self.np_random.normal() * position_deviation + ), + speed=8 + self.np_random.normal() * speed_deviation, + ) for v in self.road.vehicles: if np.linalg.norm(v.position - vehicle.position) < 15: return @@ -553,16 +649,25 @@

Source code for highway_env.envs.intersection_env

return vehicle def _clear_vehicles(self) -> None: - is_leaving = lambda vehicle: "il" in vehicle.lane_index[0] and "o" in vehicle.lane_index[1] \ - and vehicle.lane.local_coordinates(vehicle.position)[0] \ - >= vehicle.lane.length - 4 * vehicle.LENGTH - self.road.vehicles = [vehicle for vehicle in self.road.vehicles if - vehicle in self.controlled_vehicles or not (is_leaving(vehicle) or vehicle.route is None)] + is_leaving = ( + lambda vehicle: "il" in vehicle.lane_index[0] + and "o" in vehicle.lane_index[1] + and vehicle.lane.local_coordinates(vehicle.position)[0] + >= vehicle.lane.length - 4 * vehicle.LENGTH + ) + self.road.vehicles = [ + vehicle + for vehicle in self.road.vehicles + if vehicle in self.controlled_vehicles + or not (is_leaving(vehicle) or vehicle.route is None) + ] def has_arrived(self, vehicle: Vehicle, exit_distance: float = 25) -> bool: - return "il" in vehicle.lane_index[0] \ - and "o" in vehicle.lane_index[1] \ - and vehicle.lane.local_coordinates(vehicle.position)[0] >= exit_distance
+ return ( + "il" in vehicle.lane_index[0] + and "o" in vehicle.lane_index[1] + and vehicle.lane.local_coordinates(vehicle.position)[0] >= exit_distance + )
@@ -570,45 +675,58 @@

Source code for highway_env.envs.intersection_env

@classmethod def default_config(cls) -> dict: config = super().default_config() - config.update({ - "action": { - "type": "MultiAgentAction", - "action_config": { - "type": "DiscreteMetaAction", - "lateral": False, - "longitudinal": True - } - }, - "observation": { - "type": "MultiAgentObservation", - "observation_config": { - "type": "Kinematics" - } - }, - "controlled_vehicles": 2 - }) + config.update( + { + "action": { + "type": "MultiAgentAction", + "action_config": { + "type": "DiscreteMetaAction", + "lateral": False, + "longitudinal": True, + }, + }, + "observation": { + "type": "MultiAgentObservation", + "observation_config": {"type": "Kinematics"}, + }, + "controlled_vehicles": 2, + } + ) return config + class ContinuousIntersectionEnv(IntersectionEnv): @classmethod def default_config(cls) -> dict: config = super().default_config() - config.update({ - "observation": { - "type": "Kinematics", - "vehicles_count": 5, - "features": ["presence", "x", "y", "vx", "vy", "long_off", "lat_off", "ang_off"], - }, - "action": { - "type": "ContinuousAction", - "steering_range": [-np.pi / 3, np.pi / 3], - "longitudinal": True, - "lateral": True, - "dynamical": True - }, - }) + config.update( + { + "observation": { + "type": "Kinematics", + "vehicles_count": 5, + "features": [ + "presence", + "x", + "y", + "vx", + "vy", + "long_off", + "lat_off", + "ang_off", + ], + }, + "action": { + "type": "ContinuousAction", + "steering_range": [-np.pi / 3, np.pi / 3], + "longitudinal": True, + "lateral": True, + "dynamical": True, + }, + } + ) return config + TupleMultiAgentIntersectionEnv = MultiAgentWrapper(MultiAgentIntersectionEnv)
diff --git a/main/_modules/highway_env/envs/merge_env/index.html b/main/_modules/highway_env/envs/merge_env/index.html index 084a30d4f..a675b5685 100644 --- a/main/_modules/highway_env/envs/merge_env/index.html +++ b/main/_modules/highway_env/envs/merge_env/index.html @@ -297,7 +297,7 @@

Source code for highway_env.envs.merge_env

 
 from highway_env import utils
 from highway_env.envs.common.abstract import AbstractEnv
-from highway_env.road.lane import LineType, StraightLane, SineLane
+from highway_env.road.lane import LineType, SineLane, StraightLane
 from highway_env.road.road import Road, RoadNetwork
 from highway_env.vehicle.controller import ControlledVehicle
 from highway_env.vehicle.objects import Obstacle
@@ -320,14 +320,16 @@ 

Source code for highway_env.envs.merge_env

     @classmethod
     def default_config(cls) -> dict:
         cfg = super().default_config()
-        cfg.update({
-            "collision_reward": -1,
-            "right_lane_reward": 0.1,
-            "high_speed_reward": 0.2,
-            "reward_speed_range": [20, 30],
-            "merging_speed_reward": -0.5,
-            "lane_change_reward": -0.05,
-        })
+        cfg.update(
+            {
+                "collision_reward": -1,
+                "right_lane_reward": 0.1,
+                "high_speed_reward": 0.2,
+                "reward_speed_range": [20, 30],
+                "merging_speed_reward": -0.5,
+                "lane_change_reward": -0.05,
+            }
+        )
         return cfg
@@ -340,14 +342,23 @@

Source code for highway_env.envs.merge_env

         :param action: the action performed
         :return: the reward of the state-action transition
         """
-        reward = sum(self.config.get(name, 0) * reward for name, reward in self._rewards(action).items())
-        return utils.lmap(reward,
-                          [self.config["collision_reward"] + self.config["merging_speed_reward"],
-                           self.config["high_speed_reward"] + self.config["right_lane_reward"]],
-                          [0, 1])
+        reward = sum(
+            self.config.get(name, 0) * reward
+            for name, reward in self._rewards(action).items()
+        )
+        return utils.lmap(
+            reward,
+            [
+                self.config["collision_reward"] + self.config["merging_speed_reward"],
+                self.config["high_speed_reward"] + self.config["right_lane_reward"],
+            ],
+            [0, 1],
+        )
 
     def _rewards(self, action: int) -> Dict[Text, float]:
-        scaled_speed = utils.lmap(self.vehicle.speed, self.config["reward_speed_range"], [0, 1])
+        scaled_speed = utils.lmap(
+            self.vehicle.speed, self.config["reward_speed_range"], [0, 1]
+        )
         return {
             "collision_reward": self.vehicle.crashed,
             "right_lane_reward": self.vehicle.lane_index[2] / 1,
@@ -356,14 +367,15 @@ 

Source code for highway_env.envs.merge_env

             "merging_speed_reward": sum(  # Altruistic penalty
                 (vehicle.target_speed - vehicle.speed) / vehicle.target_speed
                 for vehicle in self.road.vehicles
-                if vehicle.lane_index == ("b", "c", 2) and isinstance(vehicle, ControlledVehicle)
-            )
+                if vehicle.lane_index == ("b", "c", 2)
+                and isinstance(vehicle, ControlledVehicle)
+            ),
         }
 
     def _is_terminated(self) -> bool:
         """The episode is over when a collision occurs or when the access ramp has been passed."""
         print("crash" + str(self.vehicle.crashed))
-        print("over"  + str(self.vehicle.position[0] > 370))
+        print("over" + str(self.vehicle.position[0] > 370))
         return self.vehicle.crashed or bool(self.vehicle.position[0] > 370)
 
     def _is_truncated(self) -> bool:
@@ -388,21 +400,56 @@ 

Source code for highway_env.envs.merge_env

         line_type = [[c, s], [n, c]]
         line_type_merge = [[c, s], [n, s]]
         for i in range(2):
-            net.add_lane("a", "b", StraightLane([0, y[i]], [sum(ends[:2]), y[i]], line_types=line_type[i]))
-            net.add_lane("b", "c", StraightLane([sum(ends[:2]), y[i]], [sum(ends[:3]), y[i]], line_types=line_type_merge[i]))
-            net.add_lane("c", "d", StraightLane([sum(ends[:3]), y[i]], [sum(ends), y[i]], line_types=line_type[i]))
+            net.add_lane(
+                "a",
+                "b",
+                StraightLane([0, y[i]], [sum(ends[:2]), y[i]], line_types=line_type[i]),
+            )
+            net.add_lane(
+                "b",
+                "c",
+                StraightLane(
+                    [sum(ends[:2]), y[i]],
+                    [sum(ends[:3]), y[i]],
+                    line_types=line_type_merge[i],
+                ),
+            )
+            net.add_lane(
+                "c",
+                "d",
+                StraightLane(
+                    [sum(ends[:3]), y[i]], [sum(ends), y[i]], line_types=line_type[i]
+                ),
+            )
 
         # Merging lane
         amplitude = 3.25
-        ljk = StraightLane([0, 6.5 + 4 + 4], [ends[0], 6.5 + 4 + 4], line_types=[c, c], forbidden=True)
-        lkb = SineLane(ljk.position(ends[0], -amplitude), ljk.position(sum(ends[:2]), -amplitude),
-                       amplitude, 2 * np.pi / (2*ends[1]), np.pi / 2, line_types=[c, c], forbidden=True)
-        lbc = StraightLane(lkb.position(ends[1], 0), lkb.position(ends[1], 0) + [ends[2], 0],
-                           line_types=[n, c], forbidden=True)
+        ljk = StraightLane(
+            [0, 6.5 + 4 + 4], [ends[0], 6.5 + 4 + 4], line_types=[c, c], forbidden=True
+        )
+        lkb = SineLane(
+            ljk.position(ends[0], -amplitude),
+            ljk.position(sum(ends[:2]), -amplitude),
+            amplitude,
+            2 * np.pi / (2 * ends[1]),
+            np.pi / 2,
+            line_types=[c, c],
+            forbidden=True,
+        )
+        lbc = StraightLane(
+            lkb.position(ends[1], 0),
+            lkb.position(ends[1], 0) + [ends[2], 0],
+            line_types=[n, c],
+            forbidden=True,
+        )
         net.add_lane("j", "k", ljk)
         net.add_lane("k", "b", lkb)
         net.add_lane("b", "c", lbc)
-        road = Road(network=net, np_random=self.np_random, record_history=self.config["show_trajectories"])
+        road = Road(
+            network=net,
+            np_random=self.np_random,
+            record_history=self.config["show_trajectories"],
+        )
         road.objects.append(Obstacle(road, lbc.position(ends[2], 0)))
         self.road = road
 
@@ -413,9 +460,9 @@ 

Source code for highway_env.envs.merge_env

         :return: the ego-vehicle
         """
         road = self.road
-        ego_vehicle = self.action_type.vehicle_class(road,
-                                                     road.network.get_lane(("a", "b", 1)).position(30, 0),
-                                                     speed=30)
+        ego_vehicle = self.action_type.vehicle_class(
+            road, road.network.get_lane(("a", "b", 1)).position(30, 0), speed=30
+        )
         road.vehicles.append(ego_vehicle)
 
         other_vehicles_type = utils.class_from_path(self.config["other_vehicles_type"])
@@ -426,7 +473,9 @@ 

Source code for highway_env.envs.merge_env

             speed += self.np_random.uniform(-1, 1)
             road.vehicles.append(other_vehicles_type(road, position, speed=speed))
 
-        merging_v = other_vehicles_type(road, road.network.get_lane(("j", "k", 0)).position(110, 0), speed=20)
+        merging_v = other_vehicles_type(
+            road, road.network.get_lane(("j", "k", 0)).position(110, 0), speed=20
+        )
         merging_v.target_speed = 30
         road.vehicles.append(merging_v)
         self.vehicle = ego_vehicle
diff --git a/main/_modules/highway_env/envs/parking_env/index.html b/main/_modules/highway_env/envs/parking_env/index.html index 9a098b3c1..6af923f7e 100644 --- a/main/_modules/highway_env/envs/parking_env/index.html +++ b/main/_modules/highway_env/envs/parking_env/index.html @@ -294,12 +294,15 @@

Source code for highway_env.envs.parking_env

from abc import abstractmethod
 from typing import Optional
 
-from gymnasium import Env
 import numpy as np
+from gymnasium import Env
 
 from highway_env.envs.common.abstract import AbstractEnv
-from highway_env.envs.common.observation import MultiAgentObservation, observation_factory
-from highway_env.road.lane import StraightLane, LineType
+from highway_env.envs.common.observation import (
+    MultiAgentObservation,
+    observation_factory,
+)
+from highway_env.road.lane import LineType, StraightLane
 from highway_env.road.road import Road, RoadNetwork
 from highway_env.vehicle.graphics import VehicleGraphics
 from highway_env.vehicle.kinematics import Vehicle
@@ -325,7 +328,9 @@ 

Source code for highway_env.envs.parking_env

    """
 
     @abstractmethod
-    def compute_reward(self, achieved_goal: np.ndarray, desired_goal: np.ndarray, info: dict) -> float:
+    def compute_reward(
+        self, achieved_goal: np.ndarray, desired_goal: np.ndarray, info: dict
+    ) -> float:
         """Compute the step reward. This externalizes the reward function and makes
         it dependent on a desired goal and the one that was achieved. If you wish to include
         additional rewards that are independent of the goal, you can include the necessary values
@@ -358,12 +363,14 @@ 

Source code for highway_env.envs.parking_env

# For parking env with GrayscaleObservation, the env need
     # this PARKING_OBS to calculate the reward and the info.
     # Bug fixed by Mcfly(https://github.com/McflyWZX)
-    PARKING_OBS = {"observation": {
+    PARKING_OBS = {
+        "observation": {
             "type": "KinematicsGoal",
-            "features": ['x', 'y', 'vx', 'vy', 'cos_h', 'sin_h'],
+            "features": ["x", "y", "vx", "vy", "cos_h", "sin_h"],
             "scales": [100, 100, 5, 5, 1, 1],
-            "normalize": False
-        }}
+            "normalize": False,
+        }
+    }
 
     def __init__(self, config: dict = None, render_mode: Optional[str] = None) -> None:
         super().__init__(config, render_mode)
@@ -374,31 +381,31 @@ 

Source code for highway_env.envs.parking_env

@classmethod
     def default_config(cls) -> dict:
         config = super().default_config()
-        config.update({
-            "observation": {
-                "type": "KinematicsGoal",
-                "features": ['x', 'y', 'vx', 'vy', 'cos_h', 'sin_h'],
-                "scales": [100, 100, 5, 5, 1, 1],
-                "normalize": False
-            },
-            "action": {
-                "type": "ContinuousAction"
-            },
-            "reward_weights": [1, 0.3, 0, 0, 0.02, 0.02],
-            "success_goal_reward": 0.12,
-            "collision_reward": -5,
-            "steering_range": np.deg2rad(45),
-            "simulation_frequency": 15,
-            "policy_frequency": 5,
-            "duration": 100,
-            "screen_width": 600,
-            "screen_height": 300,
-            "centering_position": [0.5, 0.5],
-            "scaling": 7,
-            "controlled_vehicles": 1,
-            "vehicles_count": 0,
-            "add_walls": True
-        })
+        config.update(
+            {
+                "observation": {
+                    "type": "KinematicsGoal",
+                    "features": ["x", "y", "vx", "vy", "cos_h", "sin_h"],
+                    "scales": [100, 100, 5, 5, 1, 1],
+                    "normalize": False,
+                },
+                "action": {"type": "ContinuousAction"},
+                "reward_weights": [1, 0.3, 0, 0, 0.02, 0.02],
+                "success_goal_reward": 0.12,
+                "collision_reward": -5,
+                "steering_range": np.deg2rad(45),
+                "simulation_frequency": 15,
+                "policy_frequency": 5,
+                "duration": 100,
+                "screen_width": 600,
+                "screen_height": 300,
+                "centering_position": [0.5, 0.5],
+                "scaling": 7,
+                "controlled_vehicles": 1,
+                "vehicles_count": 0,
+                "add_walls": True,
+            }
+        )
         return config
@@ -409,16 +416,21 @@

Source code for highway_env.envs.parking_env

        Set the types and spaces of observation and action from config.
         """
         super().define_spaces()
-        self.observation_type_parking = observation_factory(self, self.PARKING_OBS["observation"])
+ self.observation_type_parking = observation_factory( + self, self.PARKING_OBS["observation"] + )
def _info(self, obs, action) -> dict: info = super(ParkingEnv, self)._info(obs, action) if isinstance(self.observation_type, MultiAgentObservation): - success = tuple(self._is_success(agent_obs['achieved_goal'], agent_obs['desired_goal']) for agent_obs in obs) + success = tuple( + self._is_success(agent_obs["achieved_goal"], agent_obs["desired_goal"]) + for agent_obs in obs + ) else: obs = self.observation_type_parking.observe() - success = self._is_success(obs['achieved_goal'], obs['desired_goal']) + success = self._is_success(obs["achieved_goal"], obs["desired_goal"]) info.update({"is_success": success}) return info @@ -440,12 +452,26 @@

Source code for highway_env.envs.parking_env

length = 8
         for k in range(spots):
             x = (k + 1 - spots // 2) * (width + x_offset) - width / 2
-            net.add_lane("a", "b", StraightLane([x, y_offset], [x, y_offset+length], width=width, line_types=lt))
-            net.add_lane("b", "c", StraightLane([x, -y_offset], [x, -y_offset-length], width=width, line_types=lt))
-
-        self.road = Road(network=net,
-                         np_random=self.np_random,
-                         record_history=self.config["show_trajectories"])
+            net.add_lane(
+                "a",
+                "b",
+                StraightLane(
+                    [x, y_offset], [x, y_offset + length], width=width, line_types=lt
+                ),
+            )
+            net.add_lane(
+                "b",
+                "c",
+                StraightLane(
+                    [x, -y_offset], [x, -y_offset - length], width=width, line_types=lt
+                ),
+            )
+
+        self.road = Road(
+            network=net,
+            np_random=self.np_random,
+            record_history=self.config["show_trajectories"],
+        )
 
     def _create_vehicles(self) -> None:
         """Create some new random vehicles of a given type, and add them on the road."""
@@ -454,7 +480,9 @@ 

Source code for highway_env.envs.parking_env

# Controlled vehicles
         self.controlled_vehicles = []
         for i in range(self.config["controlled_vehicles"]):
-            vehicle = self.action_type.vehicle_class(self.road, [i*20, 0], 2*np.pi*self.np_random.uniform(), 0)
+            vehicle = self.action_type.vehicle_class(
+                self.road, [i * 20, 0], 2 * np.pi * self.np_random.uniform(), 0
+            )
             vehicle.color = VehicleGraphics.EGO_COLOR
             self.road.vehicles.append(vehicle)
             self.controlled_vehicles.append(vehicle)
@@ -463,7 +491,9 @@ 

Source code for highway_env.envs.parking_env

# Goal
         lane_index = empty_spots[self.np_random.choice(np.arange(len(empty_spots)))]
         lane = self.road.network.get_lane(lane_index)
-        self.goal = Landmark(self.road, lane.position(lane.length/2, 0), heading=lane.heading)
+        self.goal = Landmark(
+            self.road, lane.position(lane.length / 2, 0), heading=lane.heading
+        )
         self.road.objects.append(self.goal)
         empty_spots.remove(lane_index)
 
@@ -477,7 +507,7 @@ 

Source code for highway_env.envs.parking_env

empty_spots.remove(lane_index)
 
         # Walls
-        if self.config['add_walls']:
+        if self.config["add_walls"]:
             width, height = 70, 42
             for y in [-height / 2, height / 2]:
                 obstacle = Obstacle(self.road, [0, y])
@@ -492,7 +522,13 @@ 

Source code for highway_env.envs.parking_env

 [docs]
-    def compute_reward(self, achieved_goal: np.ndarray, desired_goal: np.ndarray, info: dict, p: float = 0.5) -> float:
+    def compute_reward(
+        self,
+        achieved_goal: np.ndarray,
+        desired_goal: np.ndarray,
+        info: dict,
+        p: float = 0.5,
+    ) -> float:
         """
         Proximity to the goal is rewarded
 
@@ -504,25 +540,44 @@ 

Source code for highway_env.envs.parking_env

        :param p: the Lp^p norm used in the reward. Use p<1 to have high kurtosis for rewards in [0, 1]
         :return: the corresponding reward
         """
-        return -np.power(np.dot(np.abs(achieved_goal - desired_goal), np.array(self.config["reward_weights"])), p)
+ return -np.power( + np.dot( + np.abs(achieved_goal - desired_goal), + np.array(self.config["reward_weights"]), + ), + p, + )
def _reward(self, action: np.ndarray) -> float: obs = self.observation_type_parking.observe() obs = obs if isinstance(obs, tuple) else (obs,) - reward = sum(self.compute_reward(agent_obs['achieved_goal'], agent_obs['desired_goal'], {}) for agent_obs in obs) - reward += self.config['collision_reward'] * sum(v.crashed for v in self.controlled_vehicles) + reward = sum( + self.compute_reward( + agent_obs["achieved_goal"], agent_obs["desired_goal"], {} + ) + for agent_obs in obs + ) + reward += self.config["collision_reward"] * sum( + v.crashed for v in self.controlled_vehicles + ) return reward def _is_success(self, achieved_goal: np.ndarray, desired_goal: np.ndarray) -> bool: - return self.compute_reward(achieved_goal, desired_goal, {}) > -self.config["success_goal_reward"] + return ( + self.compute_reward(achieved_goal, desired_goal, {}) + > -self.config["success_goal_reward"] + ) def _is_terminated(self) -> bool: """The episode is over if the ego vehicle crashed or the goal is reached or time is over.""" crashed = any(vehicle.crashed for vehicle in self.controlled_vehicles) obs = self.observation_type_parking.observe() obs = obs if isinstance(obs, tuple) else (obs,) - success = all(self._is_success(agent_obs['achieved_goal'], agent_obs['desired_goal']) for agent_obs in obs) + success = all( + self._is_success(agent_obs["achieved_goal"], agent_obs["desired_goal"]) + for agent_obs in obs + ) return bool(crashed or success) def _is_truncated(self) -> bool: diff --git a/main/_modules/highway_env/envs/racetrack_env/index.html b/main/_modules/highway_env/envs/racetrack_env/index.html index e5364b49d..c27438074 100644 --- a/main/_modules/highway_env/envs/racetrack_env/index.html +++ b/main/_modules/highway_env/envs/racetrack_env/index.html @@ -291,14 +291,13 @@

Source code for highway_env.envs.racetrack_env

-from itertools import repeat, product
-from typing import Tuple, Dict, Text
+from typing import Dict, Text
 
 import numpy as np
 
 from highway_env import utils
 from highway_env.envs.common.abstract import AbstractEnv
-from highway_env.road.lane import LineType, StraightLane, CircularLane, SineLane
+from highway_env.road.lane import CircularLane, LineType, StraightLane
 from highway_env.road.road import Road, RoadNetwork
 from highway_env.vehicle.behavior import IDMVehicle
 
@@ -322,40 +321,44 @@ 

Source code for highway_env.envs.racetrack_env

@classmethod def default_config(cls) -> dict: config = super().default_config() - config.update({ - "observation": { - "type": "OccupancyGrid", - "features": ['presence', 'on_road'], - "grid_size": [[-18, 18], [-18, 18]], - "grid_step": [3, 3], - "as_image": False, - "align_to_vehicle_axes": True - }, - "action": { - "type": "ContinuousAction", - "longitudinal": False, - "lateral": True, - "target_speeds": [0, 5, 10] - }, - "simulation_frequency": 15, - "policy_frequency": 5, - "duration": 300, - "collision_reward": -1, - "lane_centering_cost": 4, - "lane_centering_reward": 1, - "action_reward": -0.3, - "controlled_vehicles": 1, - "other_vehicles": 1, - "screen_width": 600, - "screen_height": 600, - "centering_position": [0.5, 0.5], - }) + config.update( + { + "observation": { + "type": "OccupancyGrid", + "features": ["presence", "on_road"], + "grid_size": [[-18, 18], [-18, 18]], + "grid_step": [3, 3], + "as_image": False, + "align_to_vehicle_axes": True, + }, + "action": { + "type": "ContinuousAction", + "longitudinal": False, + "lateral": True, + "target_speeds": [0, 5, 10], + }, + "simulation_frequency": 15, + "policy_frequency": 5, + "duration": 300, + "collision_reward": -1, + "lane_centering_cost": 4, + "lane_centering_reward": 1, + "action_reward": -0.3, + "controlled_vehicles": 1, + "other_vehicles": 1, + "screen_width": 600, + "screen_height": 600, + "centering_position": [0.5, 0.5], + } + ) return config

def _reward(self, action: np.ndarray) -> float: rewards = self._rewards(action) - reward = sum(self.config.get(name, 0) * reward for name, reward in rewards.items()) + reward = sum( + self.config.get(name, 0) * reward for name, reward in rewards.items() + ) reward = utils.lmap(reward, [self.config["collision_reward"], 1], [0, 1]) reward *= rewards["on_road_reward"] return reward @@ -363,7 +366,8 @@

Source code for highway_env.envs.racetrack_env

def _rewards(self, action: np.ndarray) -> Dict[Text, float]: _, lateral = self.vehicle.lane.local_coordinates(self.vehicle.position) return { - "lane_centering_reward": 1/(1+self.config["lane_centering_cost"]*lateral**2), + "lane_centering_reward": 1 + / (1 + self.config["lane_centering_cost"] * lateral**2), "action_reward": np.linalg.norm(action), "collision_reward": self.vehicle.crashed, "on_road_reward": self.vehicle.on_road, @@ -386,98 +390,270 @@

Source code for highway_env.envs.racetrack_env

speedlimits = [None, 10, 10, 10, 10, 10, 10, 10, 10] # Initialise First Lane - lane = StraightLane([42, 0], [100, 0], line_types=(LineType.CONTINUOUS, LineType.STRIPED), width=5, speed_limit=speedlimits[1]) + lane = StraightLane( + [42, 0], + [100, 0], + line_types=(LineType.CONTINUOUS, LineType.STRIPED), + width=5, + speed_limit=speedlimits[1], + ) self.lane = lane # Add Lanes to Road Network - Straight Section net.add_lane("a", "b", lane) - net.add_lane("a", "b", StraightLane([42, 5], [100, 5], line_types=(LineType.STRIPED, LineType.CONTINUOUS), width=5, speed_limit=speedlimits[1])) + net.add_lane( + "a", + "b", + StraightLane( + [42, 5], + [100, 5], + line_types=(LineType.STRIPED, LineType.CONTINUOUS), + width=5, + speed_limit=speedlimits[1], + ), + ) # 2 - Circular Arc #1 center1 = [100, -20] radii1 = 20 - net.add_lane("b", "c", - CircularLane(center1, radii1, np.deg2rad(90), np.deg2rad(-1), width=5, - clockwise=False, line_types=(LineType.CONTINUOUS, LineType.NONE), - speed_limit=speedlimits[2])) - net.add_lane("b", "c", - CircularLane(center1, radii1+5, np.deg2rad(90), np.deg2rad(-1), width=5, - clockwise=False, line_types=(LineType.STRIPED, LineType.CONTINUOUS), - speed_limit=speedlimits[2])) + net.add_lane( + "b", + "c", + CircularLane( + center1, + radii1, + np.deg2rad(90), + np.deg2rad(-1), + width=5, + clockwise=False, + line_types=(LineType.CONTINUOUS, LineType.NONE), + speed_limit=speedlimits[2], + ), + ) + net.add_lane( + "b", + "c", + CircularLane( + center1, + radii1 + 5, + np.deg2rad(90), + np.deg2rad(-1), + width=5, + clockwise=False, + line_types=(LineType.STRIPED, LineType.CONTINUOUS), + speed_limit=speedlimits[2], + ), + ) # 3 - Vertical Straight - net.add_lane("c", "d", StraightLane([120, -20], [120, -30], - line_types=(LineType.CONTINUOUS, LineType.NONE), width=5, - speed_limit=speedlimits[3])) - net.add_lane("c", "d", StraightLane([125, -20], [125, -30], - line_types=(LineType.STRIPED, LineType.CONTINUOUS), width=5, - speed_limit=speedlimits[3])) + net.add_lane( + "c", + "d", + StraightLane( + [120, -20], + [120, -30], + line_types=(LineType.CONTINUOUS, LineType.NONE), + width=5, + speed_limit=speedlimits[3], + ), + ) + net.add_lane( + "c", + "d", + StraightLane( + [125, -20], + [125, -30], + line_types=(LineType.STRIPED, LineType.CONTINUOUS), + width=5, + speed_limit=speedlimits[3], + ), + ) # 4 - Circular Arc #2 center2 = [105, -30] radii2 = 15 - net.add_lane("d", "e", - CircularLane(center2, radii2, np.deg2rad(0), np.deg2rad(-181), width=5, - clockwise=False, line_types=(LineType.CONTINUOUS, LineType.NONE), - speed_limit=speedlimits[4])) - net.add_lane("d", "e", - CircularLane(center2, radii2+5, np.deg2rad(0), np.deg2rad(-181), width=5, - clockwise=False, line_types=(LineType.STRIPED, LineType.CONTINUOUS), - speed_limit=speedlimits[4])) + net.add_lane( + "d", + "e", + CircularLane( + center2, + radii2, + np.deg2rad(0), + np.deg2rad(-181), + width=5, + clockwise=False, + line_types=(LineType.CONTINUOUS, LineType.NONE), + speed_limit=speedlimits[4], + ), + ) + net.add_lane( + "d", + "e", + CircularLane( + center2, + radii2 + 5, + np.deg2rad(0), + np.deg2rad(-181), + width=5, + clockwise=False, + line_types=(LineType.STRIPED, LineType.CONTINUOUS), + speed_limit=speedlimits[4], + ), + ) # 5 - Circular Arc #3 center3 = [70, -30] radii3 = 15 - net.add_lane("e", "f", - CircularLane(center3, radii3+5, np.deg2rad(0), np.deg2rad(136), width=5, - clockwise=True, line_types=(LineType.CONTINUOUS, LineType.STRIPED), - speed_limit=speedlimits[5])) - net.add_lane("e", "f", - CircularLane(center3, radii3, np.deg2rad(0), np.deg2rad(137), width=5, - clockwise=True, line_types=(LineType.NONE, LineType.CONTINUOUS), - speed_limit=speedlimits[5])) + net.add_lane( + "e", + "f", + CircularLane( + center3, + radii3 + 5, + np.deg2rad(0), + np.deg2rad(136), + width=5, + clockwise=True, + line_types=(LineType.CONTINUOUS, LineType.STRIPED), + speed_limit=speedlimits[5], + ), + ) + net.add_lane( + "e", + "f", + CircularLane( + center3, + radii3, + np.deg2rad(0), + np.deg2rad(137), + width=5, + clockwise=True, + line_types=(LineType.NONE, LineType.CONTINUOUS), + speed_limit=speedlimits[5], + ), + ) # 6 - Slant - net.add_lane("f", "g", StraightLane([55.7, -15.7], [35.7, -35.7], - line_types=(LineType.CONTINUOUS, LineType.NONE), width=5, - speed_limit=speedlimits[6])) - net.add_lane("f", "g", StraightLane([59.3934, -19.2], [39.3934, -39.2], - line_types=(LineType.STRIPED, LineType.CONTINUOUS), width=5, - speed_limit=speedlimits[6])) + net.add_lane( + "f", + "g", + StraightLane( + [55.7, -15.7], + [35.7, -35.7], + line_types=(LineType.CONTINUOUS, LineType.NONE), + width=5, + speed_limit=speedlimits[6], + ), + ) + net.add_lane( + "f", + "g", + StraightLane( + [59.3934, -19.2], + [39.3934, -39.2], + line_types=(LineType.STRIPED, LineType.CONTINUOUS), + width=5, + speed_limit=speedlimits[6], + ), + ) # 7 - Circular Arc #4 - Bugs out when arc is too large, hence written in 2 sections center4 = [18.1, -18.1] radii4 = 25 - net.add_lane("g", "h", - CircularLane(center4, radii4, np.deg2rad(315), np.deg2rad(170), width=5, - clockwise=False, line_types=(LineType.CONTINUOUS, LineType.NONE), - speed_limit=speedlimits[7])) - net.add_lane("g", "h", - CircularLane(center4, radii4+5, np.deg2rad(315), np.deg2rad(165), width=5, - clockwise=False, line_types=(LineType.STRIPED, LineType.CONTINUOUS), - speed_limit=speedlimits[7])) - net.add_lane("h", "i", - CircularLane(center4, radii4, np.deg2rad(170), np.deg2rad(56), width=5, - clockwise=False, line_types=(LineType.CONTINUOUS, LineType.NONE), - speed_limit=speedlimits[7])) - net.add_lane("h", "i", - CircularLane(center4, radii4+5, np.deg2rad(170), np.deg2rad(58), width=5, - clockwise=False, line_types=(LineType.STRIPED, LineType.CONTINUOUS), - speed_limit=speedlimits[7])) + net.add_lane( + "g", + "h", + CircularLane( + center4, + radii4, + np.deg2rad(315), + np.deg2rad(170), + width=5, + clockwise=False, + line_types=(LineType.CONTINUOUS, LineType.NONE), + speed_limit=speedlimits[7], + ), + ) + net.add_lane( + "g", + "h", + CircularLane( + center4, + radii4 + 5, + np.deg2rad(315), + np.deg2rad(165), + width=5, + clockwise=False, + line_types=(LineType.STRIPED, LineType.CONTINUOUS), + speed_limit=speedlimits[7], + ), + ) + net.add_lane( + "h", + "i", + CircularLane( + center4, + radii4, + np.deg2rad(170), + np.deg2rad(56), + width=5, + clockwise=False, + line_types=(LineType.CONTINUOUS, LineType.NONE), + speed_limit=speedlimits[7], + ), + ) + net.add_lane( + "h", + "i", + CircularLane( + center4, + radii4 + 5, + np.deg2rad(170), + np.deg2rad(58), + width=5, + clockwise=False, + line_types=(LineType.STRIPED, LineType.CONTINUOUS), + speed_limit=speedlimits[7], + ), + ) # 8 - Circular Arc #5 - Reconnects to Start center5 = [43.2, 23.4] radii5 = 18.5 - net.add_lane("i", "a", - CircularLane(center5, radii5+5, np.deg2rad(240), np.deg2rad(270), width=5, - clockwise=True, line_types=(LineType.CONTINUOUS, LineType.STRIPED), - speed_limit=speedlimits[8])) - net.add_lane("i", "a", - CircularLane(center5, radii5, np.deg2rad(238), np.deg2rad(268), width=5, - clockwise=True, line_types=(LineType.NONE, LineType.CONTINUOUS), - speed_limit=speedlimits[8])) - - road = Road(network=net, np_random=self.np_random, record_history=self.config["show_trajectories"]) + net.add_lane( + "i", + "a", + CircularLane( + center5, + radii5 + 5, + np.deg2rad(240), + np.deg2rad(270), + width=5, + clockwise=True, + line_types=(LineType.CONTINUOUS, LineType.STRIPED), + speed_limit=speedlimits[8], + ), + ) + net.add_lane( + "i", + "a", + CircularLane( + center5, + radii5, + np.deg2rad(238), + np.deg2rad(268), + width=5, + clockwise=True, + line_types=(LineType.NONE, LineType.CONTINUOUS), + speed_limit=speedlimits[8], + ), + ) + + road = Road( + network=net, + np_random=self.np_random, + record_history=self.config["show_trajectories"], + ) self.road = road def _make_vehicles(self) -> None: @@ -489,32 +665,40 @@

Source code for highway_env.envs.racetrack_env

# Controlled vehicles self.controlled_vehicles = [] for i in range(self.config["controlled_vehicles"]): - lane_index = ("a", "b", rng.integers(2)) if i == 0 else \ - self.road.network.random_lane_index(rng) - controlled_vehicle = self.action_type.vehicle_class.make_on_lane(self.road, lane_index, speed=None, - longitudinal=rng.uniform(20, 50)) + lane_index = ( + ("a", "b", rng.integers(2)) + if i == 0 + else self.road.network.random_lane_index(rng) + ) + controlled_vehicle = self.action_type.vehicle_class.make_on_lane( + self.road, lane_index, speed=None, longitudinal=rng.uniform(20, 50) + ) self.controlled_vehicles.append(controlled_vehicle) self.road.vehicles.append(controlled_vehicle) # Front vehicle - vehicle = IDMVehicle.make_on_lane(self.road, ("b", "c", lane_index[-1]), - longitudinal=rng.uniform( - low=0, - high=self.road.network.get_lane(("b", "c", 0)).length - ), - speed=6+rng.uniform(high=3)) + vehicle = IDMVehicle.make_on_lane( + self.road, + ("b", "c", lane_index[-1]), + longitudinal=rng.uniform( + low=0, high=self.road.network.get_lane(("b", "c", 0)).length + ), + speed=6 + rng.uniform(high=3), + ) self.road.vehicles.append(vehicle) # Other vehicles for i in range(rng.integers(self.config["other_vehicles"])): random_lane_index = self.road.network.random_lane_index(rng) - vehicle = IDMVehicle.make_on_lane(self.road, random_lane_index, - longitudinal=rng.uniform( - low=0, - high=self.road.network.get_lane(random_lane_index).length - ), - speed=6+rng.uniform(high=3)) + vehicle = IDMVehicle.make_on_lane( + self.road, + random_lane_index, + longitudinal=rng.uniform( + low=0, high=self.road.network.get_lane(random_lane_index).length + ), + speed=6 + rng.uniform(high=3), + ) # Prevent early collisions for v in self.road.vehicles: if np.linalg.norm(vehicle.position - v.position) < 20: diff --git a/main/_modules/highway_env/envs/roundabout_env/index.html b/main/_modules/highway_env/envs/roundabout_env/index.html index 3a57c6659..3cfc3332e 100644 --- a/main/_modules/highway_env/envs/roundabout_env/index.html +++ b/main/_modules/highway_env/envs/roundabout_env/index.html @@ -291,13 +291,13 @@

Source code for highway_env.envs.roundabout_env

-from typing import Tuple, Dict, Text
+from typing import Dict, Text
 
 import numpy as np
 
 from highway_env import utils
 from highway_env.envs.common.abstract import AbstractEnv
-from highway_env.road.lane import LineType, StraightLane, CircularLane, SineLane
+from highway_env.road.lane import CircularLane, LineType, SineLane, StraightLane
 from highway_env.road.road import Road, RoadNetwork
 from highway_env.vehicle.controller import MDPVehicle
 
@@ -305,51 +305,60 @@ 

Source code for highway_env.envs.roundabout_env

<
[docs] class RoundaboutEnv(AbstractEnv): -
[docs] @classmethod def default_config(cls) -> dict: config = super().default_config() - config.update({ - "observation": { - "type": "Kinematics", - "absolute": True, - "features_range": {"x": [-100, 100], "y": [-100, 100], "vx": [-15, 15], "vy": [-15, 15]}, - }, - "action": { - "type": "DiscreteMetaAction", - "target_speeds": [0, 8, 16] - }, - "incoming_vehicle_destination": None, - "collision_reward": -1, - "high_speed_reward": 0.2, - "right_lane_reward": 0, - "lane_change_reward": -0.05, - "screen_width": 600, - "screen_height": 600, - "centering_position": [0.5, 0.6], - "duration": 11, - "normalize_reward": True - }) + config.update( + { + "observation": { + "type": "Kinematics", + "absolute": True, + "features_range": { + "x": [-100, 100], + "y": [-100, 100], + "vx": [-15, 15], + "vy": [-15, 15], + }, + }, + "action": {"type": "DiscreteMetaAction", "target_speeds": [0, 8, 16]}, + "incoming_vehicle_destination": None, + "collision_reward": -1, + "high_speed_reward": 0.2, + "right_lane_reward": 0, + "lane_change_reward": -0.05, + "screen_width": 600, + "screen_height": 600, + "centering_position": [0.5, 0.6], + "duration": 11, + "normalize_reward": True, + } + ) return config
def _reward(self, action: int) -> float: rewards = self._rewards(action) - reward = sum(self.config.get(name, 0) * reward for name, reward in rewards.items()) + reward = sum( + self.config.get(name, 0) * reward for name, reward in rewards.items() + ) if self.config["normalize_reward"]: - reward = utils.lmap(reward, [self.config["collision_reward"], self.config["high_speed_reward"]], [0, 1]) + reward = utils.lmap( + reward, + [self.config["collision_reward"], self.config["high_speed_reward"]], + [0, 1], + ) reward *= rewards["on_road_reward"] return reward def _rewards(self, action: int) -> Dict[Text, float]: return { "collision_reward": self.vehicle.crashed, - "high_speed_reward": - MDPVehicle.get_speed_index(self.vehicle) / (MDPVehicle.DEFAULT_TARGET_SPEEDS.size - 1), + "high_speed_reward": MDPVehicle.get_speed_index(self.vehicle) + / (MDPVehicle.DEFAULT_TARGET_SPEEDS.size - 1), "lane_change_reward": action in [0, 2], - "on_road_reward": self.vehicle.on_road + "on_road_reward": self.vehicle.on_road, } def _is_terminated(self) -> bool: @@ -369,64 +378,244 @@

Source code for highway_env.envs.roundabout_env

< alpha = 24 # [deg] net = RoadNetwork() - radii = [radius, radius+4] + radii = [radius, radius + 4] n, c, s = LineType.NONE, LineType.CONTINUOUS, LineType.STRIPED line = [[c, s], [n, c]] for lane in [0, 1]: - net.add_lane("se", "ex", - CircularLane(center, radii[lane], np.deg2rad(90 - alpha), np.deg2rad(alpha), - clockwise=False, line_types=line[lane])) - net.add_lane("ex", "ee", - CircularLane(center, radii[lane], np.deg2rad(alpha), np.deg2rad(-alpha), - clockwise=False, line_types=line[lane])) - net.add_lane("ee", "nx", - CircularLane(center, radii[lane], np.deg2rad(-alpha), np.deg2rad(-90 + alpha), - clockwise=False, line_types=line[lane])) - net.add_lane("nx", "ne", - CircularLane(center, radii[lane], np.deg2rad(-90 + alpha), np.deg2rad(-90 - alpha), - clockwise=False, line_types=line[lane])) - net.add_lane("ne", "wx", - CircularLane(center, radii[lane], np.deg2rad(-90 - alpha), np.deg2rad(-180 + alpha), - clockwise=False, line_types=line[lane])) - net.add_lane("wx", "we", - CircularLane(center, radii[lane], np.deg2rad(-180 + alpha), np.deg2rad(-180 - alpha), - clockwise=False, line_types=line[lane])) - net.add_lane("we", "sx", - CircularLane(center, radii[lane], np.deg2rad(180 - alpha), np.deg2rad(90 + alpha), - clockwise=False, line_types=line[lane])) - net.add_lane("sx", "se", - CircularLane(center, radii[lane], np.deg2rad(90 + alpha), np.deg2rad(90 - alpha), - clockwise=False, line_types=line[lane])) + net.add_lane( + "se", + "ex", + CircularLane( + center, + radii[lane], + np.deg2rad(90 - alpha), + np.deg2rad(alpha), + clockwise=False, + line_types=line[lane], + ), + ) + net.add_lane( + "ex", + "ee", + CircularLane( + center, + radii[lane], + np.deg2rad(alpha), + np.deg2rad(-alpha), + clockwise=False, + line_types=line[lane], + ), + ) + net.add_lane( + "ee", + "nx", + CircularLane( + center, + radii[lane], + np.deg2rad(-alpha), + np.deg2rad(-90 + alpha), + clockwise=False, + line_types=line[lane], + ), + ) + net.add_lane( + "nx", + "ne", + CircularLane( + center, + radii[lane], + np.deg2rad(-90 + alpha), + np.deg2rad(-90 - alpha), + clockwise=False, + line_types=line[lane], + ), + ) + net.add_lane( + "ne", + "wx", + CircularLane( + center, + radii[lane], + np.deg2rad(-90 - alpha), + np.deg2rad(-180 + alpha), + clockwise=False, + line_types=line[lane], + ), + ) + net.add_lane( + "wx", + "we", + CircularLane( + center, + radii[lane], + np.deg2rad(-180 + alpha), + np.deg2rad(-180 - alpha), + clockwise=False, + line_types=line[lane], + ), + ) + net.add_lane( + "we", + "sx", + CircularLane( + center, + radii[lane], + np.deg2rad(180 - alpha), + np.deg2rad(90 + alpha), + clockwise=False, + line_types=line[lane], + ), + ) + net.add_lane( + "sx", + "se", + CircularLane( + center, + radii[lane], + np.deg2rad(90 + alpha), + np.deg2rad(90 - alpha), + clockwise=False, + line_types=line[lane], + ), + ) # Access lanes: (r)oad/(s)ine access = 170 # [m] dev = 85 # [m] a = 5 # [m] - delta_st = 0.2*dev # [m] - - delta_en = dev-delta_st - w = 2*np.pi/dev - net.add_lane("ser", "ses", StraightLane([2, access], [2, dev/2], line_types=(s, c))) - net.add_lane("ses", "se", SineLane([2+a, dev/2], [2+a, dev/2-delta_st], a, w, -np.pi/2, line_types=(c, c))) - net.add_lane("sx", "sxs", SineLane([-2-a, -dev/2+delta_en], [-2-a, dev/2], a, w, -np.pi/2+w*delta_en, line_types=(c, c))) - net.add_lane("sxs", "sxr", StraightLane([-2, dev / 2], [-2, access], line_types=(n, c))) - - net.add_lane("eer", "ees", StraightLane([access, -2], [dev / 2, -2], line_types=(s, c))) - net.add_lane("ees", "ee", SineLane([dev / 2, -2-a], [dev / 2 - delta_st, -2-a], a, w, -np.pi / 2, line_types=(c, c))) - net.add_lane("ex", "exs", SineLane([-dev / 2 + delta_en, 2+a], [dev / 2, 2+a], a, w, -np.pi / 2 + w * delta_en, line_types=(c, c))) - net.add_lane("exs", "exr", StraightLane([dev / 2, 2], [access, 2], line_types=(n, c))) - - net.add_lane("ner", "nes", StraightLane([-2, -access], [-2, -dev / 2], line_types=(s, c))) - net.add_lane("nes", "ne", SineLane([-2 - a, -dev / 2], [-2 - a, -dev / 2 + delta_st], a, w, -np.pi / 2, line_types=(c, c))) - net.add_lane("nx", "nxs", SineLane([2 + a, dev / 2 - delta_en], [2 + a, -dev / 2], a, w, -np.pi / 2 + w * delta_en, line_types=(c, c))) - net.add_lane("nxs", "nxr", StraightLane([2, -dev / 2], [2, -access], line_types=(n, c))) - - net.add_lane("wer", "wes", StraightLane([-access, 2], [-dev / 2, 2], line_types=(s, c))) - net.add_lane("wes", "we", SineLane([-dev / 2, 2+a], [-dev / 2 + delta_st, 2+a], a, w, -np.pi / 2, line_types=(c, c))) - net.add_lane("wx", "wxs", SineLane([dev / 2 - delta_en, -2-a], [-dev / 2, -2-a], a, w, -np.pi / 2 + w * delta_en, line_types=(c, c))) - net.add_lane("wxs", "wxr", StraightLane([-dev / 2, -2], [-access, -2], line_types=(n, c))) - - road = Road(network=net, np_random=self.np_random, record_history=self.config["show_trajectories"]) + delta_st = 0.2 * dev # [m] + + delta_en = dev - delta_st + w = 2 * np.pi / dev + net.add_lane( + "ser", "ses", StraightLane([2, access], [2, dev / 2], line_types=(s, c)) + ) + net.add_lane( + "ses", + "se", + SineLane( + [2 + a, dev / 2], + [2 + a, dev / 2 - delta_st], + a, + w, + -np.pi / 2, + line_types=(c, c), + ), + ) + net.add_lane( + "sx", + "sxs", + SineLane( + [-2 - a, -dev / 2 + delta_en], + [-2 - a, dev / 2], + a, + w, + -np.pi / 2 + w * delta_en, + line_types=(c, c), + ), + ) + net.add_lane( + "sxs", "sxr", StraightLane([-2, dev / 2], [-2, access], line_types=(n, c)) + ) + + net.add_lane( + "eer", "ees", StraightLane([access, -2], [dev / 2, -2], line_types=(s, c)) + ) + net.add_lane( + "ees", + "ee", + SineLane( + [dev / 2, -2 - a], + [dev / 2 - delta_st, -2 - a], + a, + w, + -np.pi / 2, + line_types=(c, c), + ), + ) + net.add_lane( + "ex", + "exs", + SineLane( + [-dev / 2 + delta_en, 2 + a], + [dev / 2, 2 + a], + a, + w, + -np.pi / 2 + w * delta_en, + line_types=(c, c), + ), + ) + net.add_lane( + "exs", "exr", StraightLane([dev / 2, 2], [access, 2], line_types=(n, c)) + ) + + net.add_lane( + "ner", "nes", StraightLane([-2, -access], [-2, -dev / 2], line_types=(s, c)) + ) + net.add_lane( + "nes", + "ne", + SineLane( + [-2 - a, -dev / 2], + [-2 - a, -dev / 2 + delta_st], + a, + w, + -np.pi / 2, + line_types=(c, c), + ), + ) + net.add_lane( + "nx", + "nxs", + SineLane( + [2 + a, dev / 2 - delta_en], + [2 + a, -dev / 2], + a, + w, + -np.pi / 2 + w * delta_en, + line_types=(c, c), + ), + ) + net.add_lane( + "nxs", "nxr", StraightLane([2, -dev / 2], [2, -access], line_types=(n, c)) + ) + + net.add_lane( + "wer", "wes", StraightLane([-access, 2], [-dev / 2, 2], line_types=(s, c)) + ) + net.add_lane( + "wes", + "we", + SineLane( + [-dev / 2, 2 + a], + [-dev / 2 + delta_st, 2 + a], + a, + w, + -np.pi / 2, + line_types=(c, c), + ), + ) + net.add_lane( + "wx", + "wxs", + SineLane( + [dev / 2 - delta_en, -2 - a], + [-dev / 2, -2 - a], + a, + w, + -np.pi / 2 + w * delta_en, + line_types=(c, c), + ), + ) + net.add_lane( + "wxs", "wxr", StraightLane([-dev / 2, -2], [-access, -2], line_types=(n, c)) + ) + + road = Road( + network=net, + np_random=self.np_random, + record_history=self.config["show_trajectories"], + ) self.road = road def _make_vehicles(self) -> None: @@ -440,10 +629,12 @@

Source code for highway_env.envs.roundabout_env

< # Ego-vehicle ego_lane = self.road.network.get_lane(("ser", "ses", 0)) - ego_vehicle = self.action_type.vehicle_class(self.road, - ego_lane.position(125, 0), - speed=8, - heading=ego_lane.heading_at(140)) + ego_vehicle = self.action_type.vehicle_class( + self.road, + ego_lane.position(125, 0), + speed=8, + heading=ego_lane.heading_at(140), + ) try: ego_vehicle.plan_route_to("nxs") except AttributeError: @@ -454,10 +645,12 @@

Source code for highway_env.envs.roundabout_env

< # Incoming vehicle destinations = ["exr", "sxr", "nxr"] other_vehicles_type = utils.class_from_path(self.config["other_vehicles_type"]) - vehicle = other_vehicles_type.make_on_lane(self.road, - ("we", "sx", 1), - longitudinal=5 + self.np_random.normal()*position_deviation, - speed=16 + self.np_random.normal() * speed_deviation) + vehicle = other_vehicles_type.make_on_lane( + self.road, + ("we", "sx", 1), + longitudinal=5 + self.np_random.normal() * position_deviation, + speed=16 + self.np_random.normal() * speed_deviation, + ) if self.config["incoming_vehicle_destination"] is not None: destination = destinations[self.config["incoming_vehicle_destination"]] @@ -469,19 +662,23 @@

Source code for highway_env.envs.roundabout_env

< # Other vehicles for i in list(range(1, 2)) + list(range(-1, 0)): - vehicle = other_vehicles_type.make_on_lane(self.road, - ("we", "sx", 0), - longitudinal=20*i + self.np_random.normal()*position_deviation, - speed=16 + self.np_random.normal() * speed_deviation) + vehicle = other_vehicles_type.make_on_lane( + self.road, + ("we", "sx", 0), + longitudinal=20 * i + self.np_random.normal() * position_deviation, + speed=16 + self.np_random.normal() * speed_deviation, + ) vehicle.plan_route_to(self.np_random.choice(destinations)) vehicle.randomize_behavior() self.road.vehicles.append(vehicle) # Entering vehicle - vehicle = other_vehicles_type.make_on_lane(self.road, - ("eer", "ees", 0), - longitudinal=50 + self.np_random.normal() * position_deviation, - speed=16 + self.np_random.normal() * speed_deviation) + vehicle = other_vehicles_type.make_on_lane( + self.road, + ("eer", "ees", 0), + longitudinal=50 + self.np_random.normal() * position_deviation, + speed=16 + self.np_random.normal() * speed_deviation, + ) vehicle.plan_route_to(self.np_random.choice(destinations)) vehicle.randomize_behavior() self.road.vehicles.append(vehicle)
diff --git a/main/_modules/highway_env/road/graphics/index.html b/main/_modules/highway_env/road/graphics/index.html index df859a6f1..4c5559c42 100644 --- a/main/_modules/highway_env/road/graphics/index.html +++ b/main/_modules/highway_env/road/graphics/index.html @@ -291,16 +291,16 @@

Source code for highway_env.road.graphics

-from typing import List, Tuple, Union, TYPE_CHECKING
+from typing import TYPE_CHECKING, List, Tuple, Union
 
 import numpy as np
 import pygame
 
-from highway_env.road.lane import LineType, AbstractLane
+from highway_env.road.lane import AbstractLane, LineType
 from highway_env.road.road import Road
 from highway_env.utils import Vector
 from highway_env.vehicle.graphics import VehicleGraphics
-from highway_env.vehicle.objects import Obstacle, Landmark
+from highway_env.vehicle.objects import Landmark, Obstacle
 
 if TYPE_CHECKING:
     from highway_env.vehicle.objects import RoadObject
@@ -324,7 +324,9 @@ 

Source code for highway_env.road.graphics

     SCALING_FACTOR = 1.3
     MOVING_FACTOR = 0.1
 
-    def __init__(self, size: Tuple[int, int], flags: object, surf: pygame.SurfaceType) -> None:
+    def __init__(
+        self, size: Tuple[int, int], flags: object, surf: pygame.SurfaceType
+    ) -> None:
         super().__init__(size, flags, surf)
         self.origin = np.array([0, 0])
         self.scaling = self.INITIAL_SCALING
@@ -377,7 +379,10 @@ 

Source code for highway_env.road.graphics

         :return: whether the position is visible
         """
         x, y = self.vec2pix(vec)
-        return -margin < x < self.get_width() + margin and -margin < y < self.get_height() + margin
+ return ( + -margin < x < self.get_width() + margin + and -margin < y < self.get_height() + margin + )
@@ -389,8 +394,11 @@

Source code for highway_env.road.graphics

         :param position: a world position [m]
         """
         self.origin = position - np.array(
-            [self.centering_position[0] * self.get_width() / self.scaling,
-             self.centering_position[1] * self.get_height() / self.scaling])
+ [ + self.centering_position[0] * self.get_width() / self.scaling, + self.centering_position[1] * self.get_height() / self.scaling, + ] + )
@@ -440,9 +448,15 @@

Source code for highway_env.road.graphics

         :param lane: the lane to be displayed
         :param surface: the pygame surface
         """
-        stripes_count = int(2 * (surface.get_height() + surface.get_width()) / (cls.STRIPE_SPACING * surface.scaling))
+        stripes_count = int(
+            2
+            * (surface.get_height() + surface.get_width())
+            / (cls.STRIPE_SPACING * surface.scaling)
+        )
         s_origin, _ = lane.local_coordinates(surface.origin)
-        s0 = (int(s_origin) // cls.STRIPE_SPACING - stripes_count // 2) * cls.STRIPE_SPACING
+        s0 = (
+            int(s_origin) // cls.STRIPE_SPACING - stripes_count // 2
+        ) * cls.STRIPE_SPACING
         for side in range(2):
             if lane.line_types[side] == LineType.STRIPED:
                 cls.striped_line(lane, surface, stripes_count, s0, side)
@@ -455,8 +469,14 @@ 

Source code for highway_env.road.graphics

 
[docs] @classmethod - def striped_line(cls, lane: AbstractLane, surface: WorldSurface, stripes_count: int, longitudinal: float, - side: int) -> None: + def striped_line( + cls, + lane: AbstractLane, + surface: WorldSurface, + stripes_count: int, + longitudinal: float, + side: int, + ) -> None: """ Draw a striped line on one side of a lane, on a surface. @@ -467,7 +487,11 @@

Source code for highway_env.road.graphics

         :param side: which side of the road to draw [0:left, 1:right]
         """
         starts = longitudinal + np.arange(stripes_count) * cls.STRIPE_SPACING
-        ends = longitudinal + np.arange(stripes_count) * cls.STRIPE_SPACING + cls.STRIPE_LENGTH
+        ends = (
+            longitudinal
+            + np.arange(stripes_count) * cls.STRIPE_SPACING
+            + cls.STRIPE_LENGTH
+        )
         lats = [(side - 0.5) * lane.width_at(s) for s in starts]
         cls.draw_stripes(lane, surface, starts, ends, lats)
@@ -475,8 +499,14 @@

Source code for highway_env.road.graphics

 
[docs] @classmethod - def continuous_curve(cls, lane: AbstractLane, surface: WorldSurface, stripes_count: int, - longitudinal: float, side: int) -> None: + def continuous_curve( + cls, + lane: AbstractLane, + surface: WorldSurface, + stripes_count: int, + longitudinal: float, + side: int, + ) -> None: """ Draw a striped line on one side of a lane, on a surface. @@ -487,7 +517,11 @@

Source code for highway_env.road.graphics

         :param side: which side of the road to draw [0:left, 1:right]
         """
         starts = longitudinal + np.arange(stripes_count) * cls.STRIPE_SPACING
-        ends = longitudinal + np.arange(stripes_count) * cls.STRIPE_SPACING + cls.STRIPE_SPACING
+        ends = (
+            longitudinal
+            + np.arange(stripes_count) * cls.STRIPE_SPACING
+            + cls.STRIPE_SPACING
+        )
         lats = [(side - 0.5) * lane.width_at(s) for s in starts]
         cls.draw_stripes(lane, surface, starts, ends, lats)
@@ -495,8 +529,14 @@

Source code for highway_env.road.graphics

 
[docs] @classmethod - def continuous_line(cls, lane: AbstractLane, surface: WorldSurface, stripes_count: int, longitudinal: float, - side: int) -> None: + def continuous_line( + cls, + lane: AbstractLane, + surface: WorldSurface, + stripes_count: int, + longitudinal: float, + side: int, + ) -> None: """ Draw a continuous line on one side of a lane, on a surface. @@ -515,8 +555,14 @@

Source code for highway_env.road.graphics

 
[docs] @classmethod - def draw_stripes(cls, lane: AbstractLane, surface: WorldSurface, - starts: List[float], ends: List[float], lats: List[float]) -> None: + def draw_stripes( + cls, + lane: AbstractLane, + surface: WorldSurface, + starts: List[float], + ends: List[float], + lats: List[float], + ) -> None: """ Draw a set of stripes along a lane. @@ -530,24 +576,44 @@

Source code for highway_env.road.graphics

         ends = np.clip(ends, 0, lane.length)
         for k, _ in enumerate(starts):
             if abs(starts[k] - ends[k]) > 0.5 * cls.STRIPE_LENGTH:
-                pygame.draw.line(surface, surface.WHITE,
-                                 (surface.vec2pix(lane.position(starts[k], lats[k]))),
-                                 (surface.vec2pix(lane.position(ends[k], lats[k]))),
-                                 max(surface.pix(cls.STRIPE_WIDTH), 1))
+ pygame.draw.line( + surface, + surface.WHITE, + (surface.vec2pix(lane.position(starts[k], lats[k]))), + (surface.vec2pix(lane.position(ends[k], lats[k]))), + max(surface.pix(cls.STRIPE_WIDTH), 1), + )
@classmethod - def draw_ground(cls, lane: AbstractLane, surface: WorldSurface, color: Tuple[float], width: float, - draw_surface: pygame.Surface = None) -> None: + def draw_ground( + cls, + lane: AbstractLane, + surface: WorldSurface, + color: Tuple[float], + width: float, + draw_surface: pygame.Surface = None, + ) -> None: draw_surface = draw_surface or surface - stripes_count = int(2 * (surface.get_height() + surface.get_width()) / (cls.STRIPE_SPACING * surface.scaling)) + stripes_count = int( + 2 + * (surface.get_height() + surface.get_width()) + / (cls.STRIPE_SPACING * surface.scaling) + ) s_origin, _ = lane.local_coordinates(surface.origin) - s0 = (int(s_origin) // cls.STRIPE_SPACING - stripes_count // 2) * cls.STRIPE_SPACING + s0 = ( + int(s_origin) // cls.STRIPE_SPACING - stripes_count // 2 + ) * cls.STRIPE_SPACING dots = [] for side in range(2): - longis = np.clip(s0 + np.arange(stripes_count) * cls.STRIPE_SPACING, 0, lane.length) + longis = np.clip( + s0 + np.arange(stripes_count) * cls.STRIPE_SPACING, 0, lane.length + ) lats = [2 * (side - 0.5) * width for _ in longis] - new_dots = [surface.vec2pix(lane.position(longi, lat)) for longi, lat in zip(longis, lats)] + new_dots = [ + surface.vec2pix(lane.position(longi, lat)) + for longi, lat in zip(longis, lats) + ] new_dots = reversed(new_dots) if side else new_dots dots.extend(new_dots) pygame.draw.polygon(draw_surface, color, dots, 0)
@@ -580,8 +646,12 @@

Source code for highway_env.road.graphics

 
[docs] @staticmethod - def display_traffic(road: Road, surface: WorldSurface, simulation_frequency: int = 15, offscreen: bool = False) \ - -> None: + def display_traffic( + road: Road, + surface: WorldSurface, + simulation_frequency: int = 15, + offscreen: bool = False, + ) -> None: """ Display the road vehicles on a surface. @@ -592,7 +662,9 @@

Source code for highway_env.road.graphics

         """
         if road.record_history:
             for v in road.vehicles:
-                VehicleGraphics.display_history(v, surface, simulation=simulation_frequency, offscreen=offscreen)
+                VehicleGraphics.display_history(
+                    v, surface, simulation=simulation_frequency, offscreen=offscreen
+                )
         for v in road.vehicles:
             VehicleGraphics.display(v, surface, offscreen=offscreen)
@@ -600,7 +672,9 @@

Source code for highway_env.road.graphics

 
[docs] @staticmethod - def display_road_objects(road: Road, surface: WorldSurface, offscreen: bool = False) -> None: + def display_road_objects( + road: Road, surface: WorldSurface, offscreen: bool = False + ) -> None: """ Display the road objects on a surface. @@ -630,8 +704,13 @@

Source code for highway_env.road.graphics

 
[docs] @classmethod - def display(cls, object_: 'RoadObject', surface: WorldSurface, transparent: bool = False, - offscreen: bool = False): + def display( + cls, + object_: "RoadObject", + surface: WorldSurface, + transparent: bool = False, + offscreen: bool = False, + ): """ Display a road objects on a pygame surface. @@ -643,30 +722,51 @@

Source code for highway_env.road.graphics

         :param offscreen: whether the rendering should be done offscreen or not
         """
         o = object_
-        s = pygame.Surface((surface.pix(o.LENGTH), surface.pix(o.LENGTH)), pygame.SRCALPHA)  # per-pixel alpha
-        rect = (0, surface.pix(o.LENGTH / 2 - o.WIDTH / 2), surface.pix(o.LENGTH), surface.pix(o.WIDTH))
+        s = pygame.Surface(
+            (surface.pix(o.LENGTH), surface.pix(o.LENGTH)), pygame.SRCALPHA
+        )  # per-pixel alpha
+        rect = (
+            0,
+            surface.pix(o.LENGTH / 2 - o.WIDTH / 2),
+            surface.pix(o.LENGTH),
+            surface.pix(o.WIDTH),
+        )
         pygame.draw.rect(s, cls.get_color(o, transparent), rect, 0)
         pygame.draw.rect(s, cls.BLACK, rect, 1)
-        if not offscreen:  # convert_alpha throws errors in offscreen mode TODO() Explain why
+        if (
+            not offscreen
+        ):  # convert_alpha throws errors in offscreen mode TODO() Explain why
             s = pygame.Surface.convert_alpha(s)
         h = o.heading if abs(o.heading) > 2 * np.pi / 180 else 0
         # Centered rotation
-        position = (surface.pos2pix(o.position[0], o.position[1]))
+        position = surface.pos2pix(o.position[0], o.position[1])
         cls.blit_rotate(surface, s, position, np.rad2deg(-h))
[docs] @staticmethod - def blit_rotate(surf: pygame.SurfaceType, image: pygame.SurfaceType, pos: Vector, angle: float, - origin_pos: Vector = None, show_rect: bool = False) -> None: + def blit_rotate( + surf: pygame.SurfaceType, + image: pygame.SurfaceType, + pos: Vector, + angle: float, + origin_pos: Vector = None, + show_rect: bool = False, + ) -> None: """Many thanks to https://stackoverflow.com/a/54714144.""" # calculate the axis aligned bounding box of the rotated image w, h = image.get_size() box = [pygame.math.Vector2(p) for p in [(0, 0), (w, 0), (w, -h), (0, -h)]] box_rotate = [p.rotate(angle) for p in box] - min_box = (min(box_rotate, key=lambda p: p[0])[0], min(box_rotate, key=lambda p: p[1])[1]) - max_box = (max(box_rotate, key=lambda p: p[0])[0], max(box_rotate, key=lambda p: p[1])[1]) + min_box = ( + min(box_rotate, key=lambda p: p[0])[0], + min(box_rotate, key=lambda p: p[1])[1], + ) + max_box = ( + max(box_rotate, key=lambda p: p[0])[0], + max(box_rotate, key=lambda p: p[1])[1], + ) # calculate the translation of the pivot if origin_pos is None: @@ -676,8 +776,10 @@

Source code for highway_env.road.graphics

         pivot_move = pivot_rotate - pivot
 
         # calculate the upper left origin of the rotated image
-        origin = (pos[0] - origin_pos[0] + min_box[0] - pivot_move[0],
-                  pos[1] - origin_pos[1] - max_box[1] + pivot_move[1])
+        origin = (
+            pos[0] - origin_pos[0] + min_box[0] - pivot_move[0],
+            pos[1] - origin_pos[1] - max_box[1] + pivot_move[1],
+        )
         # get a rotated image
         rotated_image = pygame.transform.rotate(image, angle)
         # rotate and blit the image
@@ -688,7 +790,7 @@ 

Source code for highway_env.road.graphics

 
 
     @classmethod
-    def get_color(cls, object_: 'RoadObject', transparent: bool = False):
+    def get_color(cls, object_: "RoadObject", transparent: bool = False):
         color = cls.DEFAULT_COLOR
 
         if isinstance(object_, Obstacle):
diff --git a/main/_modules/highway_env/road/lane/index.html b/main/_modules/highway_env/road/lane/index.html
index 1ef36e035..16f1a748b 100644
--- a/main/_modules/highway_env/road/lane/index.html
+++ b/main/_modules/highway_env/road/lane/index.html
@@ -292,13 +292,13 @@
             
             

Source code for highway_env.road.lane

 from abc import ABCMeta, abstractmethod
-from copy import deepcopy
-from typing import Tuple, List, Optional, Union
+from typing import List, Optional, Tuple, Union
+
 import numpy as np
 
 from highway_env import utils
 from highway_env.road.spline import LinearSpline2D
-from highway_env.utils import wrap_to_pi, Vector, get_class_path, class_from_path
+from highway_env.utils import Vector, class_from_path, get_class_path, wrap_to_pi
 
 
 
@@ -392,8 +392,13 @@

Source code for highway_env.road.lane

 
 
[docs] - def on_lane(self, position: np.ndarray, longitudinal: float = None, lateral: float = None, margin: float = 0) \ - -> bool: + def on_lane( + self, + position: np.ndarray, + longitudinal: float = None, + lateral: float = None, + margin: float = 0, + ) -> bool: """ Whether a given world position is on the lane. @@ -405,8 +410,10 @@

Source code for highway_env.road.lane

         """
         if longitudinal is None or lateral is None:
             longitudinal, lateral = self.local_coordinates(position)
-        is_on = np.abs(lateral) <= self.width_at(longitudinal) / 2 + margin and \
-            -self.VEHICLE_LENGTH <= longitudinal < self.length + self.VEHICLE_LENGTH
+        is_on = (
+            np.abs(lateral) <= self.width_at(longitudinal) / 2 + margin
+            and -self.VEHICLE_LENGTH <= longitudinal < self.length + self.VEHICLE_LENGTH
+        )
         return is_on
@@ -422,12 +429,16 @@

Source code for highway_env.road.lane

         if self.forbidden:
             return False
         longitudinal, lateral = self.local_coordinates(position)
-        is_close = np.abs(lateral) <= 2 * self.width_at(longitudinal) and \
-            0 <= longitudinal < self.length + self.VEHICLE_LENGTH
+        is_close = (
+            np.abs(lateral) <= 2 * self.width_at(longitudinal)
+            and 0 <= longitudinal < self.length + self.VEHICLE_LENGTH
+        )
         return is_close
- def after_end(self, position: np.ndarray, longitudinal: float = None, lateral: float = None) -> bool: + def after_end( + self, position: np.ndarray, longitudinal: float = None, lateral: float = None + ) -> bool: if not longitudinal: longitudinal, _ = self.local_coordinates(position) return longitudinal > self.length - self.VEHICLE_LENGTH / 2 @@ -442,13 +453,18 @@

Source code for highway_env.road.lane

 
 
[docs] - def distance_with_heading(self, position: np.ndarray, heading: Optional[float], heading_weight: float = 1.0): + def distance_with_heading( + self, + position: np.ndarray, + heading: Optional[float], + heading_weight: float = 1.0, + ): """Compute a weighted distance in position and heading to the lane.""" if heading is None: return self.distance(position) s, r = self.local_coordinates(position) angle = np.abs(self.local_angle(heading, s)) - return abs(r) + max(s - self.length, 0) + max(0 - s, 0) + heading_weight*angle
+ return abs(r) + max(s - self.length, 0) + max(0 - s, 0) + heading_weight * angle
@@ -479,14 +495,16 @@

Source code for highway_env.road.lane

 
     """A lane going in straight line."""
 
-    def __init__(self,
-                 start: Vector,
-                 end: Vector,
-                 width: float = AbstractLane.DEFAULT_WIDTH,
-                 line_types: Tuple[LineType, LineType] = None,
-                 forbidden: bool = False,
-                 speed_limit: float = 20,
-                 priority: int = 0) -> None:
+    def __init__(
+        self,
+        start: Vector,
+        end: Vector,
+        width: float = AbstractLane.DEFAULT_WIDTH,
+        line_types: Tuple[LineType, LineType] = None,
+        forbidden: bool = False,
+        speed_limit: float = 20,
+        priority: int = 0,
+    ) -> None:
         """
         New straight lane.
 
@@ -500,7 +518,9 @@ 

Source code for highway_env.road.lane

         self.start = np.array(start)
         self.end = np.array(end)
         self.width = width
-        self.heading = np.arctan2(self.end[1] - self.start[1], self.end[0] - self.start[0])
+        self.heading = np.arctan2(
+            self.end[1] - self.start[1], self.end[0] - self.start[0]
+        )
         self.length = np.linalg.norm(self.end - self.start)
         self.line_types = line_types or [LineType.STRIPED, LineType.STRIPED]
         self.direction = (self.end - self.start) / self.length
@@ -512,7 +532,11 @@ 

Source code for highway_env.road.lane

 
[docs] def position(self, longitudinal: float, lateral: float) -> np.ndarray: - return self.start + longitudinal * self.direction + lateral * self.direction_lateral
+ return ( + self.start + + longitudinal * self.direction + + lateral * self.direction_lateral + )
@@ -557,8 +581,8 @@

Source code for highway_env.road.lane

                 "line_types": self.line_types,
                 "forbidden": self.forbidden,
                 "speed_limit": self.speed_limit,
-                "priority": self.priority
-            }
+                "priority": self.priority,
+            },
         }
@@ -570,17 +594,19 @@

Source code for highway_env.road.lane

 
     """A sinusoidal lane."""
 
-    def __init__(self,
-                 start: Vector,
-                 end: Vector,
-                 amplitude: float,
-                 pulsation: float,
-                 phase: float,
-                 width: float = StraightLane.DEFAULT_WIDTH,
-                 line_types: List[LineType] = None,
-                 forbidden: bool = False,
-                 speed_limit: float = 20,
-                 priority: int = 0) -> None:
+    def __init__(
+        self,
+        start: Vector,
+        end: Vector,
+        amplitude: float,
+        pulsation: float,
+        phase: float,
+        width: float = StraightLane.DEFAULT_WIDTH,
+        line_types: List[LineType] = None,
+        forbidden: bool = False,
+        speed_limit: float = 20,
+        priority: int = 0,
+    ) -> None:
         """
         New sinusoidal lane.
 
@@ -590,7 +616,9 @@ 

Source code for highway_env.road.lane

         :param pulsation: the lane pulsation [rad/m]
         :param phase: the lane initial phase [rad]
         """
-        super().__init__(start, end,  width, line_types, forbidden, speed_limit, priority)
+        super().__init__(
+            start, end, width, line_types, forbidden, speed_limit, priority
+        )
         self.amplitude = amplitude
         self.pulsation = pulsation
         self.phase = phase
@@ -598,22 +626,30 @@ 

Source code for highway_env.road.lane

 
[docs] def position(self, longitudinal: float, lateral: float) -> np.ndarray: - return super().position(longitudinal, - lateral + self.amplitude * np.sin(self.pulsation * longitudinal + self.phase))
+ return super().position( + longitudinal, + lateral + + self.amplitude * np.sin(self.pulsation * longitudinal + self.phase), + )
[docs] def heading_at(self, longitudinal: float) -> float: return super().heading_at(longitudinal) + np.arctan( - self.amplitude * self.pulsation * np.cos(self.pulsation * longitudinal + self.phase))
+ self.amplitude + * self.pulsation + * np.cos(self.pulsation * longitudinal + self.phase) + )
[docs] def local_coordinates(self, position: np.ndarray) -> Tuple[float, float]: longitudinal, lateral = super().local_coordinates(position) - return longitudinal, lateral - self.amplitude * np.sin(self.pulsation * longitudinal + self.phase)
+ return longitudinal, lateral - self.amplitude * np.sin( + self.pulsation * longitudinal + self.phase + )
@@ -629,14 +665,18 @@

Source code for highway_env.road.lane

 [docs]
     def to_config(self) -> dict:
         config = super().to_config()
-        config.update({
-            "class_path": get_class_path(self.__class__),
-        })
-        config["config"].update({
-            "amplitude": self.amplitude,
-            "pulsation": self.pulsation,
-            "phase": self.phase
-        })
+        config.update(
+            {
+                "class_path": get_class_path(self.__class__),
+            }
+        )
+        config["config"].update(
+            {
+                "amplitude": self.amplitude,
+                "pulsation": self.pulsation,
+                "phase": self.phase,
+            }
+        )
         return config
@@ -648,17 +688,19 @@

Source code for highway_env.road.lane

 
     """A lane going in circle arc."""
 
-    def __init__(self,
-                 center: Vector,
-                 radius: float,
-                 start_phase: float,
-                 end_phase: float,
-                 clockwise: bool = True,
-                 width: float = AbstractLane.DEFAULT_WIDTH,
-                 line_types: List[LineType] = None,
-                 forbidden: bool = False,
-                 speed_limit: float = 20,
-                 priority: int = 0) -> None:
+    def __init__(
+        self,
+        center: Vector,
+        radius: float,
+        start_phase: float,
+        end_phase: float,
+        clockwise: bool = True,
+        width: float = AbstractLane.DEFAULT_WIDTH,
+        line_types: List[LineType] = None,
+        forbidden: bool = False,
+        speed_limit: float = 20,
+        priority: int = 0,
+    ) -> None:
         super().__init__()
         self.center = np.array(center)
         self.radius = radius
@@ -669,7 +711,7 @@ 

Source code for highway_env.road.lane

         self.width = width
         self.line_types = line_types or [LineType.STRIPED, LineType.STRIPED]
         self.forbidden = forbidden
-        self.length = radius*(end_phase - start_phase) * self.direction
+        self.length = radius * (end_phase - start_phase) * self.direction
         self.priority = priority
         self.speed_limit = speed_limit
 
@@ -677,14 +719,16 @@ 

Source code for highway_env.road.lane

 [docs]
     def position(self, longitudinal: float, lateral: float) -> np.ndarray:
         phi = self.direction * longitudinal / self.radius + self.start_phase
-        return self.center + (self.radius - lateral * self.direction)*np.array([np.cos(phi), np.sin(phi)])
+ return self.center + (self.radius - lateral * self.direction) * np.array( + [np.cos(phi), np.sin(phi)] + )
[docs] def heading_at(self, longitudinal: float) -> float: phi = self.direction * longitudinal / self.radius + self.start_phase - psi = phi + np.pi/2 * self.direction + psi = phi + np.pi / 2 * self.direction return psi
@@ -701,8 +745,8 @@

Source code for highway_env.road.lane

         phi = np.arctan2(delta[1], delta[0])
         phi = self.start_phase + utils.wrap_to_pi(phi - self.start_phase)
         r = np.linalg.norm(delta)
-        longitudinal = self.direction*(phi - self.start_phase)*self.radius
-        lateral = self.direction*(self.radius - r)
+        longitudinal = self.direction * (phi - self.start_phase) * self.radius
+        lateral = self.direction * (self.radius - r)
         return longitudinal, lateral
@@ -729,8 +773,8 @@

Source code for highway_env.road.lane

                 "line_types": self.line_types,
                 "forbidden": self.forbidden,
                 "speed_limit": self.speed_limit,
-                "priority": self.priority
-            }
+                "priority": self.priority,
+            },
         }
diff --git a/main/_modules/highway_env/road/regulation/index.html b/main/_modules/highway_env/road/regulation/index.html index 57b24d8a7..f890dc602 100644 --- a/main/_modules/highway_env/road/regulation/index.html +++ b/main/_modules/highway_env/road/regulation/index.html @@ -298,7 +298,8 @@

Source code for highway_env.road.regulation

 from highway_env import utils
 from highway_env.road.road import Road, RoadNetwork
 from highway_env.vehicle.controller import ControlledVehicle, MDPVehicle
-from highway_env.vehicle.kinematics import Vehicle, Obstacle
+from highway_env.vehicle.kinematics import Vehicle
+from highway_env.vehicle.objects import Obstacle
 
 
 
@@ -306,10 +307,16 @@

Source code for highway_env.road.regulation

 class RegulatedRoad(Road):
     YIELDING_COLOR: Tuple[float, float, float] = None
     REGULATION_FREQUENCY: int = 2
-    YIELD_DURATION: float = 0.
-
-    def __init__(self, network: RoadNetwork = None, vehicles: List[Vehicle] = None, obstacles: List[Obstacle] = None,
-                 np_random: np.random.RandomState = None, record_history: bool = False) -> None:
+    YIELD_DURATION: float = 0.0
+
+    def __init__(
+        self,
+        network: RoadNetwork = None,
+        vehicles: List[Vehicle] = None,
+        obstacles: List[Obstacle] = None,
+        np_random: np.random.RandomState = None,
+        record_history: bool = False,
+    ) -> None:
         super().__init__(network, vehicles, obstacles, np_random, record_history)
         self.steps = 0
 
@@ -339,12 +346,16 @@ 

Source code for highway_env.road.regulation

 
         # Find new conflicts and resolve them
         for i in range(len(self.vehicles) - 1):
-            for j in range(i+1, len(self.vehicles)):
+            for j in range(i + 1, len(self.vehicles)):
                 if self.is_conflict_possible(self.vehicles[i], self.vehicles[j]):
-                    yielding_vehicle = self.respect_priorities(self.vehicles[i], self.vehicles[j])
-                    if yielding_vehicle is not None and \
-                            isinstance(yielding_vehicle, ControlledVehicle) and \
-                            not isinstance(yielding_vehicle, MDPVehicle):
+                    yielding_vehicle = self.respect_priorities(
+                        self.vehicles[i], self.vehicles[j]
+                    )
+                    if (
+                        yielding_vehicle is not None
+                        and isinstance(yielding_vehicle, ControlledVehicle)
+                        and not isinstance(yielding_vehicle, MDPVehicle)
+                    ):
                         yielding_vehicle.color = self.YIELDING_COLOR
                         yielding_vehicle.target_speed = 0
                         yielding_vehicle.is_yielding = True
@@ -371,19 +382,28 @@ 

Source code for highway_env.road.regulation

 
 
     @staticmethod
-    def is_conflict_possible(v1: ControlledVehicle, v2: ControlledVehicle, horizon: int = 3, step: float = 0.25) -> bool:
+    def is_conflict_possible(
+        v1: ControlledVehicle,
+        v2: ControlledVehicle,
+        horizon: int = 3,
+        step: float = 0.25,
+    ) -> bool:
         times = np.arange(step, horizon, step)
         positions_1, headings_1 = v1.predict_trajectory_constant_speed(times)
         positions_2, headings_2 = v2.predict_trajectory_constant_speed(times)
 
-        for position_1, heading_1, position_2, heading_2 in zip(positions_1, headings_1, positions_2, headings_2):
+        for position_1, heading_1, position_2, heading_2 in zip(
+            positions_1, headings_1, positions_2, headings_2
+        ):
             # Fast spherical pre-check
             if np.linalg.norm(position_2 - position_1) > v1.LENGTH:
                 continue
 
             # Accurate rectangular check
-            if utils.rotated_rectangles_intersect((position_1, 1.5*v1.LENGTH, 0.9*v1.WIDTH, heading_1),
-                                                  (position_2, 1.5*v2.LENGTH, 0.9*v2.WIDTH, heading_2)):
+            if utils.rotated_rectangles_intersect(
+                (position_1, 1.5 * v1.LENGTH, 0.9 * v1.WIDTH, heading_1),
+                (position_2, 1.5 * v2.LENGTH, 0.9 * v2.WIDTH, heading_2),
+            ):
                 return True
diff --git a/main/_modules/highway_env/road/road/index.html b/main/_modules/highway_env/road/road/index.html index aaf71e350..fb6ef1cf8 100644 --- a/main/_modules/highway_env/road/road/index.html +++ b/main/_modules/highway_env/road/road/index.html @@ -291,11 +291,12 @@

Source code for highway_env.road.road

-import numpy as np
-import logging
-from typing import List, Tuple, Dict, TYPE_CHECKING, Optional
+import logging
+from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
 
-from highway_env.road.lane import LineType, StraightLane, AbstractLane, lane_from_config
+import numpy as np
+
+from highway_env.road.lane import AbstractLane, LineType, StraightLane, lane_from_config
 from highway_env.vehicle.objects import Landmark
 
 if TYPE_CHECKING:
@@ -341,7 +342,9 @@ 

Source code for highway_env.road.road

             _id = 0
         return self.graph[_from][_to][_id]
 
-    def get_closest_lane_index(self, position: np.ndarray, heading: Optional[float] = None) -> LaneIndex:
+    def get_closest_lane_index(
+        self, position: np.ndarray, heading: Optional[float] = None
+    ) -> LaneIndex:
         """
         Get the index of the lane closest to a world position.
 
@@ -357,8 +360,13 @@ 

Source code for highway_env.road.road

                     indexes.append((_from, _to, _id))
         return indexes[int(np.argmin(distances))]
 
-    def next_lane(self, current_index: LaneIndex, route: Route = None, position: np.ndarray = None,
-                  np_random: np.random.RandomState = np.random) -> LaneIndex:
+    def next_lane(
+        self,
+        current_index: LaneIndex,
+        route: Route = None,
+        position: np.ndarray = None,
+        np_random: np.random.RandomState = np.random,
+    ) -> LaneIndex:
         """
         Get the index of the next lane that should be followed after finishing the current lane.
 
@@ -376,12 +384,20 @@ 

Source code for highway_env.road.road

         next_to = next_id = None
         # Pick next road according to planned route
         if route:
-            if route[0][:2] == current_index[:2]:  # We just finished the first step of the route, drop it.
+            if (
+                route[0][:2] == current_index[:2]
+            ):  # We just finished the first step of the route, drop it.
                 route.pop(0)
-            if route and route[0][0] == _to:  # Next road in route is starting at the end of current road.
+            if (
+                route and route[0][0] == _to
+            ):  # Next road in route is starting at the end of current road.
                 _, next_to, next_id = route[0]
             elif route:
-                logger.warning("Route {} does not start after current road {}.".format(route[0], current_index))
+                logger.warning(
+                    "Route {} does not start after current road {}.".format(
+                        route[0], current_index
+                    )
+                )
 
         # Compute current projected (desired) position
         long, lat = self.get_lane(current_index).local_coordinates(position)
@@ -390,19 +406,34 @@ 

Source code for highway_env.road.road

         if not next_to:
             # Pick the one with the closest lane to projected target position
             try:
-                lanes_dists = [(next_to,
-                                *self.next_lane_given_next_road(_from, _to, _id, next_to, next_id, projected_position))
-                               for next_to in self.graph[_to].keys()]  # (next_to, next_id, distance)
+                lanes_dists = [
+                    (
+                        next_to,
+                        *self.next_lane_given_next_road(
+                            _from, _to, _id, next_to, next_id, projected_position
+                        ),
+                    )
+                    for next_to in self.graph[_to].keys()
+                ]  # (next_to, next_id, distance)
                 next_to, next_id, _ = min(lanes_dists, key=lambda x: x[-1])
             except KeyError:
                 return current_index
         else:
             # If it is known, follow it and get the closest lane
-            next_id, _ = self.next_lane_given_next_road(_from, _to, _id, next_to, next_id, projected_position)
+            next_id, _ = self.next_lane_given_next_road(
+                _from, _to, _id, next_to, next_id, projected_position
+            )
         return _to, next_to, next_id
 
-    def next_lane_given_next_road(self, _from: str, _to: str, _id: int,
-                                  next_to: str, next_id: int, position: np.ndarray) -> Tuple[int, float]:
+    def next_lane_given_next_road(
+        self,
+        _from: str,
+        _to: str,
+        _id: int,
+        next_to: str,
+        next_id: int,
+        position: np.ndarray,
+    ) -> Tuple[int, float]:
         # If next road has same number of lane, stay on the same lane
         if len(self.graph[_from][_to]) == len(self.graph[_to][next_to]):
             if next_id is None:
@@ -410,8 +441,9 @@ 

Source code for highway_env.road.road

         # Else, pick closest lane
         else:
             lanes = range(len(self.graph[_to][next_to]))
-            next_id = min(lanes,
-                          key=lambda l: self.get_lane((_to, next_to, l)).distance(position))
+            next_id = min(
+                lanes, key=lambda l: self.get_lane((_to, next_to, l)).distance(position)
+            )
         return next_id, self.get_lane((_to, next_to, next_id)).distance(position)
 
     def bfs_paths(self, start: str, goal: str) -> List[List[str]]:
@@ -427,7 +459,9 @@ 

Source code for highway_env.road.road

             (node, path) = queue.pop(0)
             if node not in self.graph:
                 yield []
-            for _next in sorted([key for key in self.graph[node].keys() if key not in path]):
+            for _next in sorted(
+                [key for key in self.graph[node].keys() if key not in path]
+            ):
                 if _next == goal:
                     yield path + [_next]
                 elif _next in self.graph:
@@ -448,13 +482,16 @@ 

Source code for highway_env.road.road

         :param lane_index: the index of a lane.
         :return: all lanes belonging to the same road.
         """
-        return [(lane_index[0], lane_index[1], i) for i in range(len(self.graph[lane_index[0]][lane_index[1]]))]
+        return [
+            (lane_index[0], lane_index[1], i)
+            for i in range(len(self.graph[lane_index[0]][lane_index[1]]))
+        ]
 
     def side_lanes(self, lane_index: LaneIndex) -> List[LaneIndex]:
         """
-                :param lane_index: the index of a lane.
-                :return: indexes of lanes next to a an input lane, to its right or left.
-                """
+        :param lane_index: the index of a lane.
+        :return: indexes of lanes next to a an input lane, to its right or left.
+        """
         _from, _to, _id = lane_index
         lanes = []
         if _id > 0:
@@ -464,17 +501,31 @@ 

Source code for highway_env.road.road

         return lanes
 
     @staticmethod
-    def is_same_road(lane_index_1: LaneIndex, lane_index_2: LaneIndex, same_lane: bool = False) -> bool:
+    def is_same_road(
+        lane_index_1: LaneIndex, lane_index_2: LaneIndex, same_lane: bool = False
+    ) -> bool:
         """Is lane 1 in the same road as lane 2?"""
-        return lane_index_1[:2] == lane_index_2[:2] and (not same_lane or lane_index_1[2] == lane_index_2[2])
+        return lane_index_1[:2] == lane_index_2[:2] and (
+            not same_lane or lane_index_1[2] == lane_index_2[2]
+        )
 
     @staticmethod
-    def is_leading_to_road(lane_index_1: LaneIndex, lane_index_2: LaneIndex, same_lane: bool = False) -> bool:
+    def is_leading_to_road(
+        lane_index_1: LaneIndex, lane_index_2: LaneIndex, same_lane: bool = False
+    ) -> bool:
         """Is lane 1 leading to of lane 2?"""
-        return lane_index_1[1] == lane_index_2[0] and (not same_lane or lane_index_1[2] == lane_index_2[2])
-
-    def is_connected_road(self, lane_index_1: LaneIndex, lane_index_2: LaneIndex, route: Route = None,
-                          same_lane: bool = False, depth: int = 0) -> bool:
+        return lane_index_1[1] == lane_index_2[0] and (
+            not same_lane or lane_index_1[2] == lane_index_2[2]
+        )
+
+    def is_connected_road(
+        self,
+        lane_index_1: LaneIndex,
+        lane_index_2: LaneIndex,
+        route: Route = None,
+        same_lane: bool = False,
+        depth: int = 0,
+    ) -> bool:
         """
         Is the lane 2 leading to a road within lane 1's route?
 
@@ -486,55 +537,86 @@ 

Source code for highway_env.road.road

         :param depth: search depth from lane 1 along its route
         :return: whether the roads are connected
         """
-        if RoadNetwork.is_same_road(lane_index_2, lane_index_1, same_lane) \
-                or RoadNetwork.is_leading_to_road(lane_index_2, lane_index_1, same_lane):
+        if RoadNetwork.is_same_road(
+            lane_index_2, lane_index_1, same_lane
+        ) or RoadNetwork.is_leading_to_road(lane_index_2, lane_index_1, same_lane):
             return True
         if depth > 0:
             if route and route[0][:2] == lane_index_1[:2]:
                 # Route is starting at current road, skip it
-                return self.is_connected_road(lane_index_1, lane_index_2, route[1:], same_lane, depth)
+                return self.is_connected_road(
+                    lane_index_1, lane_index_2, route[1:], same_lane, depth
+                )
             elif route and route[0][0] == lane_index_1[1]:
                 # Route is continuing from current road, follow it
-                return self.is_connected_road(route[0], lane_index_2, route[1:], same_lane, depth - 1)
+                return self.is_connected_road(
+                    route[0], lane_index_2, route[1:], same_lane, depth - 1
+                )
             else:
                 # Recursively search all roads at intersection
                 _from, _to, _id = lane_index_1
-                return any([self.is_connected_road((_to, l1_to, _id), lane_index_2, route, same_lane, depth - 1)
-                            for l1_to in self.graph.get(_to, {}).keys()])
+                return any(
+                    [
+                        self.is_connected_road(
+                            (_to, l1_to, _id), lane_index_2, route, same_lane, depth - 1
+                        )
+                        for l1_to in self.graph.get(_to, {}).keys()
+                    ]
+                )
         return False
 
     def lanes_list(self) -> List[AbstractLane]:
-        return [lane for to in self.graph.values() for ids in to.values() for lane in ids]
+        return [
+            lane for to in self.graph.values() for ids in to.values() for lane in ids
+        ]
 
     def lanes_dict(self) -> Dict[str, AbstractLane]:
-        return {(from_, to_, i): lane
-                for from_, tos in self.graph.items() for to_, ids in tos.items() for i, lane in enumerate(ids)}
+        return {
+            (from_, to_, i): lane
+            for from_, tos in self.graph.items()
+            for to_, ids in tos.items()
+            for i, lane in enumerate(ids)
+        }
 
     @staticmethod
-    def straight_road_network(lanes: int = 4,
-                              start: float = 0,
-                              length: float = 10000,
-                              angle: float = 0,
-                              speed_limit: float = 30,
-                              nodes_str: Optional[Tuple[str, str]] = None,
-                              net: Optional['RoadNetwork'] = None) \
-            -> 'RoadNetwork':
+    def straight_road_network(
+        lanes: int = 4,
+        start: float = 0,
+        length: float = 10000,
+        angle: float = 0,
+        speed_limit: float = 30,
+        nodes_str: Optional[Tuple[str, str]] = None,
+        net: Optional["RoadNetwork"] = None,
+    ) -> "RoadNetwork":
         net = net or RoadNetwork()
         nodes_str = nodes_str or ("0", "1")
         for lane in range(lanes):
             origin = np.array([start, lane * StraightLane.DEFAULT_WIDTH])
             end = np.array([start + length, lane * StraightLane.DEFAULT_WIDTH])
-            rotation = np.array([[np.cos(angle), np.sin(angle)], [-np.sin(angle), np.cos(angle)]])
+            rotation = np.array(
+                [[np.cos(angle), np.sin(angle)], [-np.sin(angle), np.cos(angle)]]
+            )
             origin = rotation @ origin
             end = rotation @ end
-            line_types = [LineType.CONTINUOUS_LINE if lane == 0 else LineType.STRIPED,
-                          LineType.CONTINUOUS_LINE if lane == lanes - 1 else LineType.NONE]
-            net.add_lane(*nodes_str, StraightLane(origin, end, line_types=line_types, speed_limit=speed_limit))
+            line_types = [
+                LineType.CONTINUOUS_LINE if lane == 0 else LineType.STRIPED,
+                LineType.CONTINUOUS_LINE if lane == lanes - 1 else LineType.NONE,
+            ]
+            net.add_lane(
+                *nodes_str,
+                StraightLane(
+                    origin, end, line_types=line_types, speed_limit=speed_limit
+                )
+            )
         return net
 
-    def position_heading_along_route(self, route: Route, longitudinal: float, lateral: float,
-                                     current_lane_index: LaneIndex) \
-            -> Tuple[np.ndarray, float]:
+    def position_heading_along_route(
+        self,
+        route: Route,
+        longitudinal: float,
+        lateral: float,
+        current_lane_index: LaneIndex,
+    ) -> Tuple[np.ndarray, float]:
         """
         Get the absolute position and heading along a route composed of several lanes at some local coordinates.
 
@@ -544,13 +626,18 @@ 

Source code for highway_env.road.road

         :param current_lane_index: current lane index of the vehicle
         :return: position, heading
         """
+
         def _get_route_head_with_id(route_):
             lane_index_ = route_[0]
             if lane_index_[2] is None:
                 # We know which road segment will be followed by the vehicle, but not which lane.
                 # Hypothesis: the vehicle will keep the same lane_id as the current one.
-                id_ = (current_lane_index[2]
-                       if current_lane_index[2] < len(self.graph[current_lane_index[0]][current_lane_index[1]]) else 0)
+                id_ = (
+                    current_lane_index[2]
+                    if current_lane_index[2]
+                    < len(self.graph[current_lane_index[0]][current_lane_index[1]])
+                    else 0
+                )
                 lane_index_ = (lane_index_[0], lane_index_[1], id_)
             return lane_index_
 
@@ -560,8 +647,9 @@ 

Source code for highway_env.road.road

             route = route[1:]
             lane_index = _get_route_head_with_id(route)
 
-        return self.get_lane(lane_index).position(longitudinal, lateral),\
-               self.get_lane(lane_index).heading_at(longitudinal)
+        return self.get_lane(lane_index).position(longitudinal, lateral), self.get_lane(
+            lane_index
+        ).heading_at(longitudinal)
 
     def random_lane_index(self, np_random: np.random.RandomState) -> LaneIndex:
         _from = np_random.choice(list(self.graph.keys()))
@@ -577,9 +665,7 @@ 

Source code for highway_env.road.road

             for _to, lanes_dict in to_dict.items():
                 net.graph[_from][_to] = []
                 for lane_dict in lanes_dict:
-                    net.graph[_from][_to].append(
-                        lane_from_config(lane_dict)
-                    )
+                    net.graph[_from][_to].append(lane_from_config(lane_dict))
         return net
 
     def to_config(self) -> dict:
@@ -589,9 +675,7 @@ 

Source code for highway_env.road.road

             for _to, lanes in to_dict.items():
                 graph_dict[_from][_to] = []
                 for lane in lanes:
-                    graph_dict[_from][_to].append(
-                        lane.to_config()
-                    )
+                    graph_dict[_from][_to].append(lane.to_config())
         return graph_dict
 
 
@@ -601,12 +685,14 @@ 

Source code for highway_env.road.road

 
     """A road is a set of lanes, and a set of vehicles driving on these lanes."""
 
-    def __init__(self,
-                 network: RoadNetwork = None,
-                 vehicles: List['kinematics.Vehicle'] = None,
-                 road_objects: List['objects.RoadObject'] = None,
-                 np_random: np.random.RandomState = None,
-                 record_history: bool = False) -> None:
+    def __init__(
+        self,
+        network: RoadNetwork = None,
+        vehicles: List["kinematics.Vehicle"] = None,
+        road_objects: List["objects.RoadObject"] = None,
+        np_random: np.random.RandomState = None,
+        record_history: bool = False,
+    ) -> None:
         """
         New road.
 
@@ -622,15 +708,28 @@ 

Source code for highway_env.road.road

         self.np_random = np_random if np_random else np.random.RandomState()
         self.record_history = record_history
 
-    def close_objects_to(self, vehicle: 'kinematics.Vehicle', distance: float, count: Optional[int] = None,
-                         see_behind: bool = True, sort: bool = True, vehicles_only: bool = False) -> object:
-        vehicles = [v for v in self.vehicles
-                    if np.linalg.norm(v.position - vehicle.position) < distance
-                    and v is not vehicle
-                    and (see_behind or -2 * vehicle.LENGTH < vehicle.lane_distance_to(v))]
-        obstacles = [o for o in self.objects
-                     if np.linalg.norm(o.position - vehicle.position) < distance
-                     and -2 * vehicle.LENGTH < vehicle.lane_distance_to(o)]
+    def close_objects_to(
+        self,
+        vehicle: "kinematics.Vehicle",
+        distance: float,
+        count: Optional[int] = None,
+        see_behind: bool = True,
+        sort: bool = True,
+        vehicles_only: bool = False,
+    ) -> object:
+        vehicles = [
+            v
+            for v in self.vehicles
+            if np.linalg.norm(v.position - vehicle.position) < distance
+            and v is not vehicle
+            and (see_behind or -2 * vehicle.LENGTH < vehicle.lane_distance_to(v))
+        ]
+        obstacles = [
+            o
+            for o in self.objects
+            if np.linalg.norm(o.position - vehicle.position) < distance
+            and -2 * vehicle.LENGTH < vehicle.lane_distance_to(o)
+        ]
 
         objects_ = vehicles if vehicles_only else vehicles + obstacles
 
@@ -640,9 +739,17 @@ 

Source code for highway_env.road.road

             objects_ = objects_[:count]
         return objects_
 
-    def close_vehicles_to(self, vehicle: 'kinematics.Vehicle', distance: float, count: Optional[int] = None,
-                          see_behind: bool = True, sort: bool = True) -> object:
-        return self.close_objects_to(vehicle, distance, count, see_behind, sort, vehicles_only=True)
+    def close_vehicles_to(
+        self,
+        vehicle: "kinematics.Vehicle",
+        distance: float,
+        count: Optional[int] = None,
+        see_behind: bool = True,
+        sort: bool = True,
+    ) -> object:
+        return self.close_objects_to(
+            vehicle, distance, count, see_behind, sort, vehicles_only=True
+        )
 
 
[docs] @@ -663,7 +770,7 @@

Source code for highway_env.road.road

         for vehicle in self.vehicles:
             vehicle.step(dt)
         for i, vehicle in enumerate(self.vehicles):
-            for other in self.vehicles[i+1:]:
+            for other in self.vehicles[i + 1 :]:
                 vehicle.handle_collisions(other, dt)
             for other in self.objects:
                 vehicle.handle_collisions(other, dt)
@@ -671,8 +778,9 @@

Source code for highway_env.road.road

 
 
[docs] - def neighbour_vehicles(self, vehicle: 'kinematics.Vehicle', lane_index: LaneIndex = None) \ - -> Tuple[Optional['kinematics.Vehicle'], Optional['kinematics.Vehicle']]: + def neighbour_vehicles( + self, vehicle: "kinematics.Vehicle", lane_index: LaneIndex = None + ) -> Tuple[Optional["kinematics.Vehicle"], Optional["kinematics.Vehicle"]]: """ Find the preceding and following vehicles of a given vehicle. @@ -690,7 +798,9 @@

Source code for highway_env.road.road

         s_front = s_rear = None
         v_front = v_rear = None
         for v in self.vehicles + self.objects:
-            if v is not vehicle and not isinstance(v, Landmark):  # self.network.is_connected_road(v.lane_index,
+            if v is not vehicle and not isinstance(
+                v, Landmark
+            ):  # self.network.is_connected_road(v.lane_index,
                 # lane_index, same_lane=True):
                 s_v, lat_v = lane.local_coordinates(v.position)
                 if not lane.on_lane(v.position, s_v, lat_v, margin=1):
diff --git a/main/_modules/highway_env/vehicle/behavior/index.html b/main/_modules/highway_env/vehicle/behavior/index.html
index cf29cfd9b..636d77965 100644
--- a/main/_modules/highway_env/vehicle/behavior/index.html
+++ b/main/_modules/highway_env/vehicle/behavior/index.html
@@ -291,14 +291,14 @@
           

Source code for highway_env.vehicle.behavior

-from typing import Tuple, Union
+from typing import Union
 
 import numpy as np
 
-from highway_env.road.road import Road, Route, LaneIndex
+from highway_env import utils
+from highway_env.road.road import LaneIndex, Road, Route
 from highway_env.utils import Vector
 from highway_env.vehicle.controller import ControlledVehicle
-from highway_env import utils
 from highway_env.vehicle.kinematics import Vehicle
 
 
@@ -335,27 +335,33 @@ 

Source code for highway_env.vehicle.behavior

    """Range of delta when chosen randomly."""
 
     # Lateral policy parameters
-    POLITENESS = 0.  # in [0, 1]
+    POLITENESS = 0.0  # in [0, 1]
     LANE_CHANGE_MIN_ACC_GAIN = 0.2  # [m/s2]
     LANE_CHANGE_MAX_BRAKING_IMPOSED = 2.0  # [m/s2]
     LANE_CHANGE_DELAY = 1.0  # [s]
 
-    def __init__(self,
-                 road: Road,
-                 position: Vector,
-                 heading: float = 0,
-                 speed: float = 0,
-                 target_lane_index: int = None,
-                 target_speed: float = None,
-                 route: Route = None,
-                 enable_lane_change: bool = True,
-                 timer: float = None):
-        super().__init__(road, position, heading, speed, target_lane_index, target_speed, route)
+    def __init__(
+        self,
+        road: Road,
+        position: Vector,
+        heading: float = 0,
+        speed: float = 0,
+        target_lane_index: int = None,
+        target_speed: float = None,
+        route: Route = None,
+        enable_lane_change: bool = True,
+        timer: float = None,
+    ):
+        super().__init__(
+            road, position, heading, speed, target_lane_index, target_speed, route
+        )
         self.enable_lane_change = enable_lane_change
-        self.timer = timer or (np.sum(self.position)*np.pi) % self.LANE_CHANGE_DELAY
+        self.timer = timer or (np.sum(self.position) * np.pi) % self.LANE_CHANGE_DELAY
 
     def randomize_behavior(self):
-        self.DELTA = self.road.np_random.uniform(low=self.DELTA_RANGE[0], high=self.DELTA_RANGE[1])
+        self.DELTA = self.road.np_random.uniform(
+            low=self.DELTA_RANGE[0], high=self.DELTA_RANGE[1]
+        )
 
 
[docs] @@ -369,9 +375,16 @@

Source code for highway_env.vehicle.behavior

        :param vehicle: a vehicle
         :return: a new vehicle at the same dynamical state
         """
-        v = cls(vehicle.road, vehicle.position, heading=vehicle.heading, speed=vehicle.speed,
-                target_lane_index=vehicle.target_lane_index, target_speed=vehicle.target_speed,
-                route=vehicle.route, timer=getattr(vehicle, 'timer', None))
+        v = cls(
+            vehicle.road,
+            vehicle.position,
+            heading=vehicle.heading,
+            speed=vehicle.speed,
+            target_lane_index=vehicle.target_lane_index,
+            target_speed=vehicle.target_speed,
+            route=vehicle.route,
+            timer=getattr(vehicle, "timer", None),
+        )
         return v
@@ -393,24 +406,36 @@

Source code for highway_env.vehicle.behavior

self.follow_road()
         if self.enable_lane_change:
             self.change_lane_policy()
-        action['steering'] = self.steering_control(self.target_lane_index)
-        action['steering'] = np.clip(action['steering'], -self.MAX_STEERING_ANGLE, self.MAX_STEERING_ANGLE)
+        action["steering"] = self.steering_control(self.target_lane_index)
+        action["steering"] = np.clip(
+            action["steering"], -self.MAX_STEERING_ANGLE, self.MAX_STEERING_ANGLE
+        )
 
         # Longitudinal: IDM
-        front_vehicle, rear_vehicle = self.road.neighbour_vehicles(self, self.lane_index)
-        action['acceleration'] = self.acceleration(ego_vehicle=self,
-                                                   front_vehicle=front_vehicle,
-                                                   rear_vehicle=rear_vehicle)
+        front_vehicle, rear_vehicle = self.road.neighbour_vehicles(
+            self, self.lane_index
+        )
+        action["acceleration"] = self.acceleration(
+            ego_vehicle=self, front_vehicle=front_vehicle, rear_vehicle=rear_vehicle
+        )
         # When changing lane, check both current and target lanes
         if self.lane_index != self.target_lane_index:
-            front_vehicle, rear_vehicle = self.road.neighbour_vehicles(self, self.target_lane_index)
-            target_idm_acceleration = self.acceleration(ego_vehicle=self,
-                                                        front_vehicle=front_vehicle,
-                                                        rear_vehicle=rear_vehicle)
-            action['acceleration'] = min(action['acceleration'], target_idm_acceleration)
+            front_vehicle, rear_vehicle = self.road.neighbour_vehicles(
+                self, self.target_lane_index
+            )
+            target_idm_acceleration = self.acceleration(
+                ego_vehicle=self, front_vehicle=front_vehicle, rear_vehicle=rear_vehicle
+            )
+            action["acceleration"] = min(
+                action["acceleration"], target_idm_acceleration
+            )
         # action['acceleration'] = self.recover_from_stop(action['acceleration'])
-        action['acceleration'] = np.clip(action['acceleration'], -self.ACC_MAX, self.ACC_MAX)
-        Vehicle.act(self, action)  # Skip ControlledVehicle.act(), or the command will be overriden.
+ action["acceleration"] = np.clip( + action["acceleration"], -self.ACC_MAX, self.ACC_MAX + ) + Vehicle.act( + self, action + ) # Skip ControlledVehicle.act(), or the command will be overriden.
@@ -429,10 +454,12 @@

Source code for highway_env.vehicle.behavior

 [docs]
-    def acceleration(self,
-                     ego_vehicle: ControlledVehicle,
-                     front_vehicle: Vehicle = None,
-                     rear_vehicle: Vehicle = None) -> float:
+    def acceleration(
+        self,
+        ego_vehicle: ControlledVehicle,
+        front_vehicle: Vehicle = None,
+        rear_vehicle: Vehicle = None,
+    ) -> float:
         """
         Compute an acceleration command with the Intelligent Driver Model.
 
@@ -451,20 +478,33 @@ 

Source code for highway_env.vehicle.behavior

return 0
         ego_target_speed = getattr(ego_vehicle, "target_speed", 0)
         if ego_vehicle.lane and ego_vehicle.lane.speed_limit is not None:
-            ego_target_speed = np.clip(ego_target_speed, 0, ego_vehicle.lane.speed_limit)
-        acceleration = self.COMFORT_ACC_MAX * (1 - np.power(
-            max(ego_vehicle.speed, 0) / abs(utils.not_zero(ego_target_speed)), self.DELTA))
+            ego_target_speed = np.clip(
+                ego_target_speed, 0, ego_vehicle.lane.speed_limit
+            )
+        acceleration = self.COMFORT_ACC_MAX * (
+            1
+            - np.power(
+                max(ego_vehicle.speed, 0) / abs(utils.not_zero(ego_target_speed)),
+                self.DELTA,
+            )
+        )
 
         if front_vehicle:
             d = ego_vehicle.lane_distance_to(front_vehicle)
-            acceleration -= self.COMFORT_ACC_MAX * \
-                np.power(self.desired_gap(ego_vehicle, front_vehicle) / utils.not_zero(d), 2)
+            acceleration -= self.COMFORT_ACC_MAX * np.power(
+                self.desired_gap(ego_vehicle, front_vehicle) / utils.not_zero(d), 2
+            )
         return acceleration
[docs] - def desired_gap(self, ego_vehicle: Vehicle, front_vehicle: Vehicle = None, projected: bool = True) -> float: + def desired_gap( + self, + ego_vehicle: Vehicle, + front_vehicle: Vehicle = None, + projected: bool = True, + ) -> float: """ Compute the desired distance between a vehicle and its leading vehicle. @@ -476,9 +516,14 @@

Source code for highway_env.vehicle.behavior

d0 = self.DISTANCE_WANTED
         tau = self.TIME_WANTED
         ab = -self.COMFORT_ACC_MAX * self.COMFORT_ACC_MIN
-        dv = np.dot(ego_vehicle.velocity - front_vehicle.velocity, ego_vehicle.direction) if projected \
+        dv = (
+            np.dot(ego_vehicle.velocity - front_vehicle.velocity, ego_vehicle.direction)
+            if projected
             else ego_vehicle.speed - front_vehicle.speed
-        d_star = d0 + ego_vehicle.speed * tau + ego_vehicle.speed * dv / (2 * np.sqrt(ab))
+        )
+        d_star = (
+            d0 + ego_vehicle.speed * tau + ego_vehicle.speed * dv / (2 * np.sqrt(ab))
+        )
         return d_star
@@ -498,10 +543,12 @@

Source code for highway_env.vehicle.behavior

# If we are on correct route but bad lane: abort it if someone else is already changing into the same lane
             if self.lane_index[:2] == self.target_lane_index[:2]:
                 for v in self.road.vehicles:
-                    if v is not self \
-                            and v.lane_index != self.target_lane_index \
-                            and isinstance(v, ControlledVehicle) \
-                            and v.target_lane_index == self.target_lane_index:
+                    if (
+                        v is not self
+                        and v.lane_index != self.target_lane_index
+                        and isinstance(v, ControlledVehicle)
+                        and v.target_lane_index == self.target_lane_index
+                    ):
                         d = self.lane_distance_to(v)
                         d_star = self.desired_gap(self, v)
                         if 0 < d < d_star:
@@ -517,7 +564,9 @@ 

Source code for highway_env.vehicle.behavior

# decide to make a lane change
         for lane_index in self.road.network.side_lanes(self.lane_index):
             # Is the candidate lane close enough?
-            if not self.road.network.get_lane(lane_index).is_reachable_from(self.position):
+            if not self.road.network.get_lane(lane_index).is_reachable_from(
+                self.position
+            ):
                 continue
             # Only change lane when the vehicle is moving
             if np.abs(self.speed) < 1:
@@ -542,8 +591,12 @@ 

Source code for highway_env.vehicle.behavior

        """
         # Is the maneuver unsafe for the new following vehicle?
         new_preceding, new_following = self.road.neighbour_vehicles(self, lane_index)
-        new_following_a = self.acceleration(ego_vehicle=new_following, front_vehicle=new_preceding)
-        new_following_pred_a = self.acceleration(ego_vehicle=new_following, front_vehicle=self)
+        new_following_a = self.acceleration(
+            ego_vehicle=new_following, front_vehicle=new_preceding
+        )
+        new_following_pred_a = self.acceleration(
+            ego_vehicle=new_following, front_vehicle=self
+        )
         if new_following_pred_a < -self.LANE_CHANGE_MAX_BRAKING_IMPOSED:
             return False
 
@@ -552,7 +605,9 @@ 

Source code for highway_env.vehicle.behavior

self_pred_a = self.acceleration(ego_vehicle=self, front_vehicle=new_preceding)
         if self.route and self.route[0][2] is not None:
             # Wrong direction
-            if np.sign(lane_index[2] - self.target_lane_index[2]) != np.sign(self.route[0][2] - self.target_lane_index[2]):
+            if np.sign(lane_index[2] - self.target_lane_index[2]) != np.sign(
+                self.route[0][2] - self.target_lane_index[2]
+            ):
                 return False
             # Unsafe braking required
             elif self_pred_a < -self.LANE_CHANGE_MAX_BRAKING_IMPOSED:
@@ -561,10 +616,23 @@ 

Source code for highway_env.vehicle.behavior

# Is there an acceleration advantage for me and/or my followers to change lane?
         else:
             self_a = self.acceleration(ego_vehicle=self, front_vehicle=old_preceding)
-            old_following_a = self.acceleration(ego_vehicle=old_following, front_vehicle=self)
-            old_following_pred_a = self.acceleration(ego_vehicle=old_following, front_vehicle=old_preceding)
-            jerk = self_pred_a - self_a + self.POLITENESS * (new_following_pred_a - new_following_a
-                                                             + old_following_pred_a - old_following_a)
+            old_following_a = self.acceleration(
+                ego_vehicle=old_following, front_vehicle=self
+            )
+            old_following_pred_a = self.acceleration(
+                ego_vehicle=old_following, front_vehicle=old_preceding
+            )
+            jerk = (
+                self_pred_a
+                - self_a
+                + self.POLITENESS
+                * (
+                    new_following_pred_a
+                    - new_following_a
+                    + old_following_pred_a
+                    - old_following_a
+                )
+            )
             if jerk < self.LANE_CHANGE_MIN_ACC_GAIN:
                 return False
 
@@ -586,10 +654,13 @@ 

Source code for highway_env.vehicle.behavior

# Is the vehicle stopped on the wrong lane?
         if self.target_lane_index != self.lane_index and self.speed < stopped_speed:
             _, rear = self.road.neighbour_vehicles(self)
-            _, new_rear = self.road.neighbour_vehicles(self, self.road.network.get_lane(self.target_lane_index))
+            _, new_rear = self.road.neighbour_vehicles(
+                self, self.road.network.get_lane(self.target_lane_index)
+            )
             # Check for free room behind on both lanes
-            if (not rear or rear.lane_distance_to(self) > safe_distance) and \
-                    (not new_rear or new_rear.lane_distance_to(self) > safe_distance):
+            if (not rear or rear.lane_distance_to(self) > safe_distance) and (
+                not new_rear or new_rear.lane_distance_to(self) > safe_distance
+            ):
                 # Reverse
                 return -self.COMFORT_ACC_MAX / 2
         return acceleration
@@ -604,27 +675,50 @@

Source code for highway_env.vehicle.behavior

    """A Vehicle whose longitudinal and lateral controllers are linear with respect to parameters."""
 
     ACCELERATION_PARAMETERS = [0.3, 0.3, 2.0]
-    STEERING_PARAMETERS = [ControlledVehicle.KP_HEADING, ControlledVehicle.KP_HEADING * ControlledVehicle.KP_LATERAL]
-
-    ACCELERATION_RANGE = np.array([0.5*np.array(ACCELERATION_PARAMETERS), 1.5*np.array(ACCELERATION_PARAMETERS)])
-    STEERING_RANGE = np.array([np.array(STEERING_PARAMETERS) - np.array([0.07, 1.5]),
-                               np.array(STEERING_PARAMETERS) + np.array([0.07, 1.5])])
+    STEERING_PARAMETERS = [
+        ControlledVehicle.KP_HEADING,
+        ControlledVehicle.KP_HEADING * ControlledVehicle.KP_LATERAL,
+    ]
+
+    ACCELERATION_RANGE = np.array(
+        [
+            0.5 * np.array(ACCELERATION_PARAMETERS),
+            1.5 * np.array(ACCELERATION_PARAMETERS),
+        ]
+    )
+    STEERING_RANGE = np.array(
+        [
+            np.array(STEERING_PARAMETERS) - np.array([0.07, 1.5]),
+            np.array(STEERING_PARAMETERS) + np.array([0.07, 1.5]),
+        ]
+    )
 
     TIME_WANTED = 2.5
 
-    def __init__(self,
-                 road: Road,
-                 position: Vector,
-                 heading: float = 0,
-                 speed: float = 0,
-                 target_lane_index: int = None,
-                 target_speed: float = None,
-                 route: Route = None,
-                 enable_lane_change: bool = True,
-                 timer: float = None,
-                 data: dict = None):
-        super().__init__(road, position, heading, speed, target_lane_index, target_speed, route,
-                         enable_lane_change, timer)
+    def __init__(
+        self,
+        road: Road,
+        position: Vector,
+        heading: float = 0,
+        speed: float = 0,
+        target_lane_index: int = None,
+        target_speed: float = None,
+        route: Route = None,
+        enable_lane_change: bool = True,
+        timer: float = None,
+        data: dict = None,
+    ):
+        super().__init__(
+            road,
+            position,
+            heading,
+            speed,
+            target_lane_index,
+            target_speed,
+            route,
+            enable_lane_change,
+            timer,
+        )
         self.data = data if data is not None else {}
         self.collecting_data = True
 
@@ -638,17 +732,22 @@ 

Source code for highway_env.vehicle.behavior

def randomize_behavior(self):
         ua = self.road.np_random.uniform(size=np.shape(self.ACCELERATION_PARAMETERS))
-        self.ACCELERATION_PARAMETERS = self.ACCELERATION_RANGE[0] + ua*(self.ACCELERATION_RANGE[1] -
-                                                                        self.ACCELERATION_RANGE[0])
+        self.ACCELERATION_PARAMETERS = self.ACCELERATION_RANGE[0] + ua * (
+            self.ACCELERATION_RANGE[1] - self.ACCELERATION_RANGE[0]
+        )
         ub = self.road.np_random.uniform(size=np.shape(self.STEERING_PARAMETERS))
-        self.STEERING_PARAMETERS = self.STEERING_RANGE[0] + ub*(self.STEERING_RANGE[1] - self.STEERING_RANGE[0])
+        self.STEERING_PARAMETERS = self.STEERING_RANGE[0] + ub * (
+            self.STEERING_RANGE[1] - self.STEERING_RANGE[0]
+        )
 
 
[docs] - def acceleration(self, - ego_vehicle: ControlledVehicle, - front_vehicle: Vehicle = None, - rear_vehicle: Vehicle = None) -> float: + def acceleration( + self, + ego_vehicle: ControlledVehicle, + front_vehicle: Vehicle = None, + rear_vehicle: Vehicle = None, + ) -> float: """ Compute an acceleration command with a Linear Model. @@ -664,17 +763,27 @@

Source code for highway_env.vehicle.behavior

        :param rear_vehicle: the vehicle following the ego-vehicle
         :return: the acceleration command for the ego-vehicle [m/s2]
         """
-        return float(np.dot(self.ACCELERATION_PARAMETERS,
-                            self.acceleration_features(ego_vehicle, front_vehicle, rear_vehicle)))
- - - def acceleration_features(self, ego_vehicle: ControlledVehicle, - front_vehicle: Vehicle = None, - rear_vehicle: Vehicle = None) -> np.ndarray: + return float( + np.dot( + self.ACCELERATION_PARAMETERS, + self.acceleration_features(ego_vehicle, front_vehicle, rear_vehicle), + ) + )
+ + + def acceleration_features( + self, + ego_vehicle: ControlledVehicle, + front_vehicle: Vehicle = None, + rear_vehicle: Vehicle = None, + ) -> np.ndarray: vt, dv, dp = 0, 0, 0 if ego_vehicle: vt = ego_vehicle.target_speed - ego_vehicle.speed - d_safe = self.DISTANCE_WANTED + np.maximum(ego_vehicle.speed, 0) * self.TIME_WANTED + d_safe = ( + self.DISTANCE_WANTED + + np.maximum(ego_vehicle.speed, 0) * self.TIME_WANTED + ) if front_vehicle: d = ego_vehicle.lane_distance_to(front_vehicle) dv = min(front_vehicle.speed - ego_vehicle.speed, 0) @@ -692,7 +801,12 @@

Source code for highway_env.vehicle.behavior

        :param target_lane_index: index of the lane to follow
         :return: a steering wheel angle command [rad]
         """
-        return float(np.dot(np.array(self.STEERING_PARAMETERS), self.steering_features(target_lane_index)))
+ return float( + np.dot( + np.array(self.STEERING_PARAMETERS), + self.steering_features(target_lane_index), + ) + )
@@ -708,41 +822,28 @@

Source code for highway_env.vehicle.behavior

lane_coords = lane.local_coordinates(self.position)
         lane_next_coords = lane_coords[0] + self.speed * self.TAU_PURSUIT
         lane_future_heading = lane.heading_at(lane_next_coords)
-        features = np.array([utils.wrap_to_pi(lane_future_heading - self.heading) *
-                             self.LENGTH / utils.not_zero(self.speed),
-                             -lane_coords[1] * self.LENGTH / (utils.not_zero(self.speed) ** 2)])
+        features = np.array(
+            [
+                utils.wrap_to_pi(lane_future_heading - self.heading)
+                * self.LENGTH
+                / utils.not_zero(self.speed),
+                -lane_coords[1] * self.LENGTH / (utils.not_zero(self.speed) ** 2),
+            ]
+        )
         return features
def longitudinal_structure(self): # Nominal dynamics: integrate speed - A = np.array([ - [0, 0, 1, 0], - [0, 0, 0, 1], - [0, 0, 0, 0], - [0, 0, 0, 0] - ]) + A = np.array([[0, 0, 1, 0], [0, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]]) # Target speed dynamics - phi0 = np.array([ - [0, 0, 0, 0], - [0, 0, 0, 0], - [0, 0, -1, 0], - [0, 0, 0, -1] - ]) + phi0 = np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, -1, 0], [0, 0, 0, -1]]) # Front speed control - phi1 = np.array([ - [0, 0, 0, 0], - [0, 0, 0, 0], - [0, 0, -1, 1], - [0, 0, 0, 0] - ]) + phi1 = np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, -1, 1], [0, 0, 0, 0]]) # Front position control - phi2 = np.array([ - [0, 0, 0, 0], - [0, 0, 0, 0], - [-1, 1, -self.TIME_WANTED, 0], - [0, 0, 0, 0] - ]) + phi2 = np.array( + [[0, 0, 0, 0], [0, 0, 0, 0], [-1, 1, -self.TIME_WANTED, 0], [0, 0, 0, 0]] + ) # Disable speed control front_vehicle, _ = self.road.neighbour_vehicles(self) if not front_vehicle or self.speed < front_vehicle.speed: @@ -760,18 +861,9 @@

Source code for highway_env.vehicle.behavior

return A, phi
 
     def lateral_structure(self):
-        A = np.array([
-            [0, 1],
-            [0, 0]
-        ])
-        phi0 = np.array([
-            [0, 0],
-            [0, -1]
-        ])
-        phi1 = np.array([
-            [0, 0],
-            [-1, 0]
-        ])
+        A = np.array([[0, 1], [0, 0]])
+        phi0 = np.array([[0, 0], [0, -1]])
+        phi1 = np.array([[0, 0], [-1, 0]])
         phi = np.array([phi0, phi1])
         return A, phi
 
@@ -783,7 +875,6 @@ 

Source code for highway_env.vehicle.behavior

def add_features(self, data, lane_index, output_lane=None):
-
         front_vehicle, rear_vehicle = self.road.neighbour_vehicles(self)
         features = self.acceleration_features(self, front_vehicle, rear_vehicle)
         output = np.dot(self.ACCELERATION_PARAMETERS, features)
@@ -811,9 +902,11 @@ 

Source code for highway_env.vehicle.behavior

MERGE_ACC_GAIN = 0.8
     MERGE_VEL_RATIO = 0.75
     MERGE_TARGET_VEL = 30
-    ACCELERATION_PARAMETERS = [MERGE_ACC_GAIN / ((1 - MERGE_VEL_RATIO) * MERGE_TARGET_VEL),
-                               MERGE_ACC_GAIN / (MERGE_VEL_RATIO * MERGE_TARGET_VEL),
-                               0.5]
+ ACCELERATION_PARAMETERS = [ + MERGE_ACC_GAIN / ((1 - MERGE_VEL_RATIO) * MERGE_TARGET_VEL), + MERGE_ACC_GAIN / (MERGE_VEL_RATIO * MERGE_TARGET_VEL), + 0.5, + ]
@@ -824,9 +917,11 @@

Source code for highway_env.vehicle.behavior

MERGE_ACC_GAIN = 1.2
     MERGE_VEL_RATIO = 0.75
     MERGE_TARGET_VEL = 30
-    ACCELERATION_PARAMETERS = [MERGE_ACC_GAIN / ((1 - MERGE_VEL_RATIO) * MERGE_TARGET_VEL),
-                               MERGE_ACC_GAIN / (MERGE_VEL_RATIO * MERGE_TARGET_VEL),
-                               2.0]
+ ACCELERATION_PARAMETERS = [ + MERGE_ACC_GAIN / ((1 - MERGE_VEL_RATIO) * MERGE_TARGET_VEL), + MERGE_ACC_GAIN / (MERGE_VEL_RATIO * MERGE_TARGET_VEL), + 2.0, + ]
diff --git a/main/_modules/highway_env/vehicle/controller/index.html b/main/_modules/highway_env/vehicle/controller/index.html index 9b7ce1478..74bf52f0d 100644 --- a/main/_modules/highway_env/vehicle/controller/index.html +++ b/main/_modules/highway_env/vehicle/controller/index.html @@ -291,12 +291,13 @@

Source code for highway_env.vehicle.controller

-from typing import List, Tuple, Union, Optional
+import copy
+from typing import List, Optional, Tuple, Union
 
 import numpy as np
-import copy
+
 from highway_env import utils
-from highway_env.road.road import Road, LaneIndex, Route
+from highway_env.road.road import LaneIndex, Road, Route
 from highway_env.utils import Vector
 from highway_env.vehicle.kinematics import Vehicle
 
@@ -326,14 +327,16 @@ 

Source code for highway_env.vehicle.controller

MAX_STEERING_ANGLE = np.pi / 3 # [rad] DELTA_SPEED = 5 # [m/s] - def __init__(self, - road: Road, - position: Vector, - heading: float = 0, - speed: float = 0, - target_lane_index: LaneIndex = None, - target_speed: float = None, - route: Route = None): + def __init__( + self, + road: Road, + position: Vector, + heading: float = 0, + speed: float = 0, + target_lane_index: LaneIndex = None, + target_speed: float = None, + route: Route = None, + ): super().__init__(road, position, heading, speed) self.target_lane_index = target_lane_index or self.lane_index self.target_speed = target_speed or self.speed @@ -351,9 +354,15 @@

Source code for highway_env.vehicle.controller

:param vehicle: a vehicle :return: a new vehicle at the same dynamical state """ - v = cls(vehicle.road, vehicle.position, heading=vehicle.heading, speed=vehicle.speed, - target_lane_index=vehicle.target_lane_index, target_speed=vehicle.target_speed, - route=vehicle.route) + v = cls( + vehicle.road, + vehicle.position, + heading=vehicle.heading, + speed=vehicle.speed, + target_lane_index=vehicle.target_lane_index, + target_speed=vehicle.target_speed, + route=vehicle.route, + ) return v

@@ -370,7 +379,9 @@

Source code for highway_env.vehicle.controller

except KeyError: path = [] if path: - self.route = [self.lane_index] + [(path[i], path[i + 1], None) for i in range(len(path) - 1)] + self.route = [self.lane_index] + [ + (path[i], path[i + 1], None) for i in range(len(path) - 1) + ] else: self.route = [self.lane_index] return self

@@ -394,18 +405,34 @@

Source code for highway_env.vehicle.controller

self.target_speed -= self.DELTA_SPEED elif action == "LANE_RIGHT": _from, _to, _id = self.target_lane_index - target_lane_index = _from, _to, np.clip(_id + 1, 0, len(self.road.network.graph[_from][_to]) - 1) - if self.road.network.get_lane(target_lane_index).is_reachable_from(self.position): + target_lane_index = ( + _from, + _to, + np.clip(_id + 1, 0, len(self.road.network.graph[_from][_to]) - 1), + ) + if self.road.network.get_lane(target_lane_index).is_reachable_from( + self.position + ): self.target_lane_index = target_lane_index elif action == "LANE_LEFT": _from, _to, _id = self.target_lane_index - target_lane_index = _from, _to, np.clip(_id - 1, 0, len(self.road.network.graph[_from][_to]) - 1) - if self.road.network.get_lane(target_lane_index).is_reachable_from(self.position): + target_lane_index = ( + _from, + _to, + np.clip(_id - 1, 0, len(self.road.network.graph[_from][_to]) - 1), + ) + if self.road.network.get_lane(target_lane_index).is_reachable_from( + self.position + ): self.target_lane_index = target_lane_index - action = {"steering": self.steering_control(self.target_lane_index), - "acceleration": self.speed_control(self.target_speed)} - action['steering'] = np.clip(action['steering'], -self.MAX_STEERING_ANGLE, self.MAX_STEERING_ANGLE) + action = { + "steering": self.steering_control(self.target_lane_index), + "acceleration": self.speed_control(self.target_speed), + } + action["steering"] = np.clip( + action["steering"], -self.MAX_STEERING_ANGLE, self.MAX_STEERING_ANGLE + ) super().act(action)

@@ -414,10 +441,12 @@

Source code for highway_env.vehicle.controller

def follow_road(self) -> None: """At the end of a lane, automatically switch to a next one.""" if self.road.network.get_lane(self.target_lane_index).after_end(self.position): - self.target_lane_index = self.road.network.next_lane(self.target_lane_index, - route=self.route, - position=self.position, - np_random=self.road.np_random)

+ self.target_lane_index = self.road.network.next_lane( + self.target_lane_index, + route=self.route, + position=self.position, + np_random=self.road.np_random, + )
@@ -440,16 +469,30 @@

Source code for highway_env.vehicle.controller

lane_future_heading = target_lane.heading_at(lane_next_coords) # Lateral position control - lateral_speed_command = - self.KP_LATERAL * lane_coords[1] + lateral_speed_command = -self.KP_LATERAL * lane_coords[1] # Lateral speed to heading - heading_command = np.arcsin(np.clip(lateral_speed_command / utils.not_zero(self.speed), -1, 1)) - heading_ref = lane_future_heading + np.clip(heading_command, -np.pi/4, np.pi/4) + heading_command = np.arcsin( + np.clip(lateral_speed_command / utils.not_zero(self.speed), -1, 1) + ) + heading_ref = lane_future_heading + np.clip( + heading_command, -np.pi / 4, np.pi / 4 + ) # Heading control - heading_rate_command = self.KP_HEADING * utils.wrap_to_pi(heading_ref - self.heading) + heading_rate_command = self.KP_HEADING * utils.wrap_to_pi( + heading_ref - self.heading + ) # Heading rate to steering angle - slip_angle = np.arcsin(np.clip(self.LENGTH / 2 / utils.not_zero(self.speed) * heading_rate_command, -1, 1)) + slip_angle = np.arcsin( + np.clip( + self.LENGTH / 2 / utils.not_zero(self.speed) * heading_rate_command, + -1, + 1, + ) + ) steering_angle = np.arctan(2 * np.tan(slip_angle)) - steering_angle = np.clip(steering_angle, -self.MAX_STEERING_ANGLE, self.MAX_STEERING_ANGLE) + steering_angle = np.clip( + steering_angle, -self.MAX_STEERING_ANGLE, self.MAX_STEERING_ANGLE + ) return float(steering_angle)

@@ -483,8 +526,11 @@

Source code for highway_env.vehicle.controller

else: return [self.route] next_destinations_from = list(next_destinations.keys()) - routes = [self.route[0:index+1] + [(self.route[index][1], destination, self.route[index][2])] - for destination in next_destinations_from] + routes = [ + self.route[0 : index + 1] + + [(self.route[index][1], destination, self.route[index][2])] + for destination in next_destinations_from + ] return routes

@@ -508,7 +554,9 @@

Source code for highway_env.vehicle.controller

[docs] - def predict_trajectory_constant_speed(self, times: np.ndarray) -> Tuple[List[np.ndarray], List[float]]: + def predict_trajectory_constant_speed( + self, times: np.ndarray + ) -> Tuple[List[np.ndarray], List[float]]: """ Predict the future positions of the vehicle along its planned route, under constant speed @@ -517,11 +565,12 @@

Source code for highway_env.vehicle.controller

""" coordinates = self.lane.local_coordinates(self.position) route = self.route or [self.lane_index] - pos_heads = [self.road.network.position_heading_along_route(route, - coordinates[0] + self.speed * t, - 0, - self.lane_index) - for t in times] + pos_heads = [ + self.road.network.position_heading_along_route( + route, coordinates[0] + self.speed * t, 0, self.lane_index + ) + for t in times + ] return tuple(zip(*pos_heads))

@@ -532,17 +581,20 @@

Source code for highway_env.vehicle.controller

class MDPVehicle(ControlledVehicle): """A controlled vehicle with a specified discrete range of allowed target speeds.""" + DEFAULT_TARGET_SPEEDS = np.linspace(20, 30, 3) - def __init__(self, - road: Road, - position: List[float], - heading: float = 0, - speed: float = 0, - target_lane_index: Optional[LaneIndex] = None, - target_speed: Optional[float] = None, - target_speeds: Optional[Vector] = None, - route: Optional[Route] = None) -> None: + def __init__( + self, + road: Road, + position: List[float], + heading: float = 0, + speed: float = 0, + target_lane_index: Optional[LaneIndex] = None, + target_speed: Optional[float] = None, + target_speeds: Optional[Vector] = None, + route: Optional[Route] = None, + ) -> None: """ Initializes an MDPVehicle @@ -555,8 +607,14 @@

Source code for highway_env.vehicle.controller

:param target_speeds: the discrete list of speeds the vehicle is able to track, through faster/slower actions :param route: the planned route of the vehicle, to handle intersections """ - super().__init__(road, position, heading, speed, target_lane_index, target_speed, route) - self.target_speeds = np.array(target_speeds) if target_speeds is not None else self.DEFAULT_TARGET_SPEEDS + super().__init__( + road, position, heading, speed, target_lane_index, target_speed, route + ) + self.target_speeds = ( + np.array(target_speeds) + if target_speeds is not None + else self.DEFAULT_TARGET_SPEEDS + ) self.speed_index = self.speed_to_index(self.target_speed) self.target_speed = self.index_to_speed(self.speed_index) @@ -578,7 +636,9 @@

Source code for highway_env.vehicle.controller

else: super().act(action) return - self.speed_index = int(np.clip(self.speed_index, 0, self.target_speeds.size - 1)) + self.speed_index = int( + np.clip(self.speed_index, 0, self.target_speeds.size - 1) + ) self.target_speed = self.index_to_speed(self.speed_index) super().act()

@@ -606,8 +666,16 @@

Source code for highway_env.vehicle.controller

:param speed: an input speed [m/s] :return: the index of the closest speed allowed [] """ - x = (speed - self.target_speeds[0]) / (self.target_speeds[-1] - self.target_speeds[0]) - return np.int64(np.clip(np.round(x * (self.target_speeds.size - 1)), 0, self.target_speeds.size - 1))

+ x = (speed - self.target_speeds[0]) / ( + self.target_speeds[-1] - self.target_speeds[0] + ) + return np.int64( + np.clip( + np.round(x * (self.target_speeds.size - 1)), + 0, + self.target_speeds.size - 1, + ) + )
@@ -622,19 +690,33 @@

Source code for highway_env.vehicle.controller

:param speed: an input speed [m/s] :return: the index of the closest speed allowed [] """ - x = (speed - cls.DEFAULT_TARGET_SPEEDS[0]) / (cls.DEFAULT_TARGET_SPEEDS[-1] - cls.DEFAULT_TARGET_SPEEDS[0]) - return np.int64(np.clip( - np.round(x * (cls.DEFAULT_TARGET_SPEEDS.size - 1)), 0, cls.DEFAULT_TARGET_SPEEDS.size - 1))

+ x = (speed - cls.DEFAULT_TARGET_SPEEDS[0]) / ( + cls.DEFAULT_TARGET_SPEEDS[-1] - cls.DEFAULT_TARGET_SPEEDS[0] + ) + return np.int64( + np.clip( + np.round(x * (cls.DEFAULT_TARGET_SPEEDS.size - 1)), + 0, + cls.DEFAULT_TARGET_SPEEDS.size - 1, + ) + )
@classmethod def get_speed_index(cls, vehicle: Vehicle) -> int: - return getattr(vehicle, "speed_index", cls.speed_to_index_default(vehicle.speed)) + return getattr( + vehicle, "speed_index", cls.speed_to_index_default(vehicle.speed) + )
[docs] - def predict_trajectory(self, actions: List, action_duration: float, trajectory_timestep: float, dt: float) \ - -> List[ControlledVehicle]: + def predict_trajectory( + self, + actions: List, + action_duration: float, + trajectory_timestep: float, + dt: float, + ) -> List[ControlledVehicle]: """ Predict the future trajectory of the vehicle given a sequence of actions. diff --git a/main/_modules/highway_env/vehicle/kinematics/index.html b/main/_modules/highway_env/vehicle/kinematics/index.html index 68fab820c..d08ca01d1 100644 --- a/main/_modules/highway_env/vehicle/kinematics/index.html +++ b/main/_modules/highway_env/vehicle/kinematics/index.html @@ -291,15 +291,15 @@

Source code for highway_env.vehicle.kinematics

-from typing import Union, Optional, Tuple, List
-import numpy as np
-import copy
+import copy
 from collections import deque
+from typing import List, Optional, Tuple, Union
+
+import numpy as np
 
-from highway_env import utils
-from highway_env.road.road import Road, LaneIndex
-from highway_env.vehicle.objects import RoadObject, Obstacle, Landmark
+from highway_env.road.road import Road
 from highway_env.utils import Vector
+from highway_env.vehicle.objects import RoadObject
 
 
 
@@ -319,22 +319,24 @@

Source code for highway_env.vehicle.kinematics

""" Vehicle width [m] """ DEFAULT_INITIAL_SPEEDS = [23, 25] """ Range for random initial speeds [m/s] """ - MAX_SPEED = 40. + MAX_SPEED = 40.0 """ Maximum reachable speed [m/s] """ - MIN_SPEED = -40. + MIN_SPEED = -40.0 """ Minimum reachable speed [m/s] """ HISTORY_SIZE = 30 """ Length of the vehicle state history, for trajectory display""" - def __init__(self, - road: Road, - position: Vector, - heading: float = 0, - speed: float = 0, - predition_type: str = 'constant_steering'): + def __init__( + self, + road: Road, + position: Vector, + heading: float = 0, + speed: float = 0, + predition_type: str = "constant_steering", + ): super().__init__(road, position, heading, speed) self.prediction_type = predition_type - self.action = {'steering': 0, 'acceleration': 0} + self.action = {"steering": 0, "acceleration": 0} self.crashed = False self.impact = None self.log = [] @@ -343,13 +345,15 @@

Source code for highway_env.vehicle.kinematics

[docs] @classmethod - def create_random(cls, road: Road, - speed: float = None, - lane_from: Optional[str] = None, - lane_to: Optional[str] = None, - lane_id: Optional[int] = None, - spacing: float = 1) \ - -> "Vehicle": + def create_random( + cls, + road: Road, + speed: float = None, + lane_from: Optional[str] = None, + lane_to: Optional[str] = None, + lane_id: Optional[int] = None, + spacing: float = 1, + ) -> "Vehicle": """ Create a random vehicle on the road. @@ -366,17 +370,32 @@

Source code for highway_env.vehicle.kinematics

""" _from = lane_from or road.np_random.choice(list(road.network.graph.keys())) _to = lane_to or road.np_random.choice(list(road.network.graph[_from].keys())) - _id = lane_id if lane_id is not None else road.np_random.choice(len(road.network.graph[_from][_to])) + _id = ( + lane_id + if lane_id is not None + else road.np_random.choice(len(road.network.graph[_from][_to])) + ) lane = road.network.get_lane((_from, _to, _id)) if speed is None: if lane.speed_limit is not None: - speed = road.np_random.uniform(0.7*lane.speed_limit, 0.8*lane.speed_limit) + speed = road.np_random.uniform( + 0.7 * lane.speed_limit, 0.8 * lane.speed_limit + ) else: - speed = road.np_random.uniform(Vehicle.DEFAULT_INITIAL_SPEEDS[0], Vehicle.DEFAULT_INITIAL_SPEEDS[1]) - default_spacing = 12+1.0*speed - offset = spacing * default_spacing * np.exp(-5 / 40 * len(road.network.graph[_from][_to])) - x0 = np.max([lane.local_coordinates(v.position)[0] for v in road.vehicles]) \ - if len(road.vehicles) else 3*offset + speed = road.np_random.uniform( + Vehicle.DEFAULT_INITIAL_SPEEDS[0], Vehicle.DEFAULT_INITIAL_SPEEDS[1] + ) + default_spacing = 12 + 1.0 * speed + offset = ( + spacing + * default_spacing + * np.exp(-5 / 40 * len(road.network.graph[_from][_to])) + ) + x0 = ( + np.max([lane.local_coordinates(v.position)[0] for v in road.vehicles]) + if len(road.vehicles) + else 3 * offset + ) x0 += offset * road.np_random.uniform(0.9, 1.1) v = cls(road, lane.position(x0, 0), lane.heading_at(x0), speed) return v

@@ -395,7 +414,7 @@

Source code for highway_env.vehicle.kinematics

:return: a new vehicle at the same dynamical state """ v = cls(vehicle.road, vehicle.position, vehicle.heading, vehicle.speed) - if hasattr(vehicle, 'color'): + if hasattr(vehicle, "color"): v.color = vehicle.color return v

@@ -425,43 +444,52 @@

Source code for highway_env.vehicle.kinematics

:param dt: timestep of integration of the model [s] """ self.clip_actions() - delta_f = self.action['steering'] + delta_f = self.action["steering"] beta = np.arctan(1 / 2 * np.tan(delta_f)) - v = self.speed * np.array([np.cos(self.heading + beta), - np.sin(self.heading + beta)]) + v = self.speed * np.array( + [np.cos(self.heading + beta), np.sin(self.heading + beta)] + ) self.position += v * dt if self.impact is not None: self.position += self.impact self.crashed = True self.impact = None self.heading += self.speed * np.sin(beta) / (self.LENGTH / 2) * dt - self.speed += self.action['acceleration'] * dt + self.speed += self.action["acceleration"] * dt self.on_state_update()

def clip_actions(self) -> None: if self.crashed: - self.action['steering'] = 0 - self.action['acceleration'] = -1.0*self.speed - self.action['steering'] = float(self.action['steering']) - self.action['acceleration'] = float(self.action['acceleration']) + self.action["steering"] = 0 + self.action["acceleration"] = -1.0 * self.speed + self.action["steering"] = float(self.action["steering"]) + self.action["acceleration"] = float(self.action["acceleration"]) if self.speed > self.MAX_SPEED: - self.action['acceleration'] = min(self.action['acceleration'], 1.0 * (self.MAX_SPEED - self.speed)) + self.action["acceleration"] = min( + self.action["acceleration"], 1.0 * (self.MAX_SPEED - self.speed) + ) elif self.speed < self.MIN_SPEED: - self.action['acceleration'] = max(self.action['acceleration'], 1.0 * (self.MIN_SPEED - self.speed)) + self.action["acceleration"] = max( + self.action["acceleration"], 1.0 * (self.MIN_SPEED - self.speed) + ) def on_state_update(self) -> None: if self.road: - self.lane_index = self.road.network.get_closest_lane_index(self.position, self.heading) + self.lane_index = self.road.network.get_closest_lane_index( + self.position, self.heading + ) self.lane = self.road.network.get_lane(self.lane_index) if self.road.record_history: self.history.appendleft(self.create_from(self)) - def predict_trajectory_constant_speed(self, times: np.ndarray) -> Tuple[List[np.ndarray], List[float]]: - if self.prediction_type == 'zero_steering': - action = {'acceleration': 0.0, 'steering': 0.0} - elif self.prediction_type == 'constant_steering': - action = {'acceleration': 0.0, 'steering': self.action['steering']} + def predict_trajectory_constant_speed( + self, times: np.ndarray + ) -> Tuple[List[np.ndarray], List[float]]: + if self.prediction_type == "zero_steering": + action = {"acceleration": 0.0, "steering": 0.0} + elif self.prediction_type == "constant_steering": + action = {"acceleration": 0.0, "steering": self.action["steering"]} else: raise ValueError("Unknown predition type") @@ -485,7 +513,11 @@

Source code for highway_env.vehicle.kinematics

def destination(self) -> np.ndarray: if getattr(self, "route", None): last_lane_index = self.route[-1] - last_lane_index = last_lane_index if last_lane_index[-1] is not None else (*last_lane_index[:-1], 0) + last_lane_index = ( + last_lane_index + if last_lane_index[-1] is not None + else (*last_lane_index[:-1], 0) + ) last_lane = self.road.network.get_lane(last_lane_index) return last_lane.position(last_lane.length, 0) else: @@ -494,7 +526,9 @@

Source code for highway_env.vehicle.kinematics

@property def destination_direction(self) -> np.ndarray: if (self.destination != self.position).any(): - return (self.destination - self.position) / np.linalg.norm(self.destination - self.position) + return (self.destination - self.position) / np.linalg.norm( + self.destination - self.position + ) else: return np.zeros((2,)) @@ -507,40 +541,49 @@

Source code for highway_env.vehicle.kinematics

else: return np.zeros((3,)) - def to_dict(self, origin_vehicle: "Vehicle" = None, observe_intentions: bool = True) -> dict: + def to_dict( + self, origin_vehicle: "Vehicle" = None, observe_intentions: bool = True + ) -> dict: d = { - 'presence': 1, - 'x': self.position[0], - 'y': self.position[1], - 'vx': self.velocity[0], - 'vy': self.velocity[1], - 'heading': self.heading, - 'cos_h': self.direction[0], - 'sin_h': self.direction[1], - 'cos_d': self.destination_direction[0], - 'sin_d': self.destination_direction[1], - 'long_off': self.lane_offset[0], - 'lat_off': self.lane_offset[1], - 'ang_off': self.lane_offset[2], + "presence": 1, + "x": self.position[0], + "y": self.position[1], + "vx": self.velocity[0], + "vy": self.velocity[1], + "heading": self.heading, + "cos_h": self.direction[0], + "sin_h": self.direction[1], + "cos_d": self.destination_direction[0], + "sin_d": self.destination_direction[1], + "long_off": self.lane_offset[0], + "lat_off": self.lane_offset[1], + "ang_off": self.lane_offset[2], } if not observe_intentions: d["cos_d"] = d["sin_d"] = 0 if origin_vehicle: origin_dict = origin_vehicle.to_dict() - for key in ['x', 'y', 'vx', 'vy']: + for key in ["x", "y", "vx", "vy"]: d[key] -= origin_dict[key] return d def __str__(self): - return "{} #{}: {}".format(self.__class__.__name__, id(self) % 1000, self.position) + return "{} #{}: {}".format( + self.__class__.__name__, id(self) % 1000, self.position + ) def __repr__(self): return self.__str__()

[docs] - def predict_trajectory(self, actions: List, action_duration: float, trajectory_timestep: float, dt: float) \ - -> List['Vehicle']: + def predict_trajectory( + self, + actions: List, + action_duration: float, + trajectory_timestep: float, + dt: float, + ) -> List["Vehicle"]: """ Predict the future trajectory of the vehicle given a sequence of actions. diff --git a/main/observations/index.html b/main/observations/index.html index f242e39ae..fd365171e 100644 --- a/main/observations/index.html +++ b/main/observations/index.html @@ -557,25 +557,25 @@

Example configuration

-
[[ 1.          1.          0.          1.          0.          1.
+
[[ 1.          1.          0.04        1.          0.          1.
    0.        ]
- [ 1.          0.20323725  0.04       -0.07361443  0.          1.
+ [ 1.          0.2116441  -0.04       -0.07987082  0.          1.
    0.        ]
- [ 1.          0.39618185  0.08       -0.11105874  0.          1.
+ [ 1.          0.40037498 -0.04       -0.14375238  0.          1.
    0.        ]
- [ 1.          0.6169058   0.04       -0.17033932  0.          1.
+ [ 1.          0.5924493  -0.04       -0.14188124  0.          1.
    0.        ]
- [ 1.          0.83093834  0.08       -0.0526074   0.          1.
+ [ 1.          0.81080985  0.         -0.17013432  0.          1.
    0.        ]
- [ 1.          1.          0.12       -0.18704522  0.          1.
+ [ 1.          1.          0.04       -0.12747008  0.          1.
    0.        ]
- [ 1.          1.          0.04       -0.1492452   0.          1.
+ [ 1.          1.          0.04       -0.08804176  0.          1.
    0.        ]
- [ 1.          1.          0.08       -0.05019206  0.          1.
+ [ 1.          1.          0.         -0.11419602  0.          1.
    0.        ]
- [ 1.          1.          0.         -0.07072275  0.          1.
+ [ 1.          1.          0.         -0.13449906  0.          1.
    0.        ]
- [ 1.          1.          0.08       -0.18716832  0.          1.
+ [ 1.          1.          0.04       -0.19995664  0.          1.
    0.        ]
  [ 0.          0.          0.          0.          0.          0.
    0.        ]
diff --git a/main/searchindex.js b/main/searchindex.js
index 7590d8d4a..827b5ae39 100644
--- a/main/searchindex.js
+++ b/main/searchindex.js
@@ -1 +1 @@
-Search.setIndex({"docnames": ["404", "actions/index", "bibliography/index", "dynamics/index", "dynamics/road/lane", "dynamics/road/regulation", "dynamics/road/road", "dynamics/vehicle/behavior", "dynamics/vehicle/controller", "dynamics/vehicle/kinematics", "environments/highway", "environments/index", "environments/intersection", "environments/merge", "environments/parking", "environments/racetrack", "environments/roundabout", "faq", "graphics/index", "index", "installation", "make_your_own", "multi_agent", "observations/index", "quickstart", "rewards/index", "user_guide"], "filenames": ["404.md", "actions/index.md", "bibliography/index.md", "dynamics/index.md", "dynamics/road/lane.md", "dynamics/road/regulation.md", "dynamics/road/road.md", "dynamics/vehicle/behavior.md", "dynamics/vehicle/controller.md", "dynamics/vehicle/kinematics.md", "environments/highway.md", "environments/index.md", "environments/intersection.md", "environments/merge.md", "environments/parking.md", "environments/racetrack.md", "environments/roundabout.md", "faq.md", "graphics/index.md", "index.md", "installation.md", "make_your_own.md", "multi_agent.md", "observations/index.md", "quickstart.md", "rewards/index.md", "user_guide.md"], "titles": ["404", "Actions", "Bibliography", "Dynamics", "Lane", "Road regulation", "Road", "Behavior", "Control", "Kinematics", "Highway", "The environments", "Intersection", "Merge", "Parking", "Racetrack", "Roundabout", "Frequently Asked Questions", "Graphics", "Welcome to highway-env\u2019s documentation!", "Installation", "Make your own environment", "The Multi-Agent setting", "Observations", "Getting Started", "Rewards", "User Guide"], "terms": {"similarli": 1, "observ": [1, 2, 10, 12, 13, 14, 15, 16, 21, 24, 25, 26], "sever": [1, 7, 10, 12, 17, 21, 23, 24], "type": [1, 4, 10, 12, 13, 14, 15, 16, 21, 22, 23, 24], "can": [1, 4, 6, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25], "us": [1, 7, 8, 9, 14, 18, 19, 20, 21, 23, 24, 25], "everi": [1, 3, 25], "environ": [1, 3, 10, 12, 13, 14, 15, 16, 18, 19, 22, 23, 26], "thei": [1, 5, 7, 13, 18, 23, 25], "ar": [1, 3, 4, 5, 6, 7, 8, 9, 10, 18, 21, 22, 23, 24, 25], "defin": [1, 4, 6, 10, 12, 13, 14, 15, 16, 18, 21, 23, 24, 25], "modul": [1, 21, 23], "each": [1, 5, 6, 8, 9, 12, 17, 18, 22, 23], "come": [1, 12, 23], "default": [1, 7, 8, 9, 18, 21, 23, 24], "which": [1, 4, 5, 6, 7, 8, 12, 14, 17, 18, 20, 21, 22, 23, 24, 25], "chang": [1, 2, 4, 7, 8, 16, 17, 21, 23, 24, 26], "customis": [1, 23], "configur": [1, 18, 22, 25, 26], "For": [1, 6, 7, 17, 22, 23, 24], "instanc": [1, 4, 6, 7, 8, 9, 23, 24], "import": [1, 3, 17, 21, 22, 23, 24], "gymnasium": [1, 18, 21, 22, 23, 24], "gym": [1, 10, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24], "env": [1, 10, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24], "make": [1, 2, 10, 12, 13, 14, 15, 16, 18, 19, 22, 23, 26], "highwai": [1, 11, 13, 15, 18, 20, 22, 23, 24], "v0": [1, 10, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24], "config": [1, 4, 10, 12, 13, 14, 15, 16, 18, 21, 22, 23, 24], "continuousact": [1, 14, 15], "The": [1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 13, 15, 16, 18, 19, 20, 21, 23, 24, 25, 26], "allow": [1, 7, 8, 21], "agent": [1, 10, 12, 13, 14, 15, 18, 21, 23, 25, 26], "directli": [1, 23, 25], "set": [1, 2, 4, 5, 6, 8, 14, 18, 23, 26], "low": [1, 8], "level": [1, 2, 4, 8, 17], "vehicl": [1, 2, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 24, 25, 26], "kinemat": [1, 2, 3, 6, 8, 10, 12, 22, 24, 26], "name": [1, 23], "throttl": [1, 8], "steer": [1, 7, 8, 9, 14], "angl": [1, 4, 7, 8, 9, 18, 23], "delta": [1, 7, 8, 9], "enabl": [1, 23], "disabl": 1, "through": [1, 2, 3, 5, 8, 21, 25], "longitudin": [1, 4, 9, 12, 15, 16, 18, 23], "later": [1, 4, 12, 15, 18, 23], "respect": [1, 7, 8, 18, 25], "thu": [1, 17, 25], "space": [1, 7, 9, 14, 18, 21, 23, 26], "either": 1, "1d": [1, 7], "2d": [1, 4, 7], "discreteact": 1, "i": [1, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 21, 22, 24, 25], "uniform": [1, 8, 23], "quantiz": 1, "abov": 1, "actions_per_axi": 1, "paramet": [1, 4, 5, 6, 7, 8, 9, 12, 14, 18, 21, 23, 25], "step": [1, 5, 6, 7, 9, 12, 16, 17, 21, 22, 23, 24], "axi": [1, 7, 8, 9, 23], "separ": [1, 18], "discretemetaact": [1, 10, 12, 13, 16, 22, 24], "add": [1, 21], "layer": [1, 23], "speed": [1, 7, 8, 9, 10, 13, 14, 21, 25], "top": [1, 8, 23], "so": [1, 7, 13, 14, 17, 18, 21, 23], "ego": [1, 7, 10, 12, 13, 14, 16, 18, 21, 25], "automat": [1, 8, 16, 21], "follow": [1, 2, 6, 7, 8, 15, 16, 17, 18, 21, 23, 24], "road": [1, 4, 7, 8, 9, 10, 12, 13, 18, 21, 23, 25, 26], "desir": [1, 7, 8, 14, 21, 23, 25], "veloc": [1, 5, 7, 8, 23, 25], "Then": 1, "avail": [1, 10, 24], "consist": [1, 2], "target": [1, 5, 7, 8], "lane": [1, 2, 3, 5, 6, 7, 8, 9, 10, 16, 17, 18, 21, 22, 23, 24], "setpoint": 1, "full": [1, 24], "correspond": [1, 4, 8, 14, 17, 18, 21, 23], "actions_al": [1, 22], "0": [1, 4, 5, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 25], "lane_left": 1, "1": [1, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 22, 23, 24, 25], "idl": [1, 23, 24], "2": [1, 2, 7, 8, 9, 10, 20, 22, 23, 24], "lane_right": 1, "3": [1, 7, 10, 12, 13, 15, 18, 20, 23, 24], "faster": [1, 8, 23], "4": [1, 7, 10, 15, 18, 23, 24], "slower": [1, 8], "some": [1, 5, 8, 13, 25], "might": 1, "alwai": [1, 18, 23], "edg": [1, 6], "acceler": [1, 7, 8, 9, 14], "decelr": 1, "beyond": 1, "maximum": [1, 7, 9, 21, 23, 25], "minimum": [1, 7, 9, 25], "list": [1, 3, 4, 5, 6, 7, 8, 9, 17, 18, 21, 23, 24], "access": [1, 13, 21, 24], "get_available_act": 1, "method": [1, 4, 5, 7, 8, 9, 16, 21, 25], "take": [1, 5, 7, 23, 24], "an": [1, 5, 6, 7, 8, 9, 12, 18, 19, 21, 22, 23, 25], "unavail": 1, "equival": 1, "intersect": [1, 5, 6, 8, 11, 24], "onli": [1, 7, 9, 21, 22, 24, 25], "while": [1, 9, 10, 13, 15, 16, 17, 21, 22, 24], "perform": [1, 7, 8, 12, 21, 23, 24], "track": [1, 8, 15], "simul": [1, 2, 7, 8, 9, 12, 17, 18, 21, 23], "manual_control": [1, 24], "true": [1, 4, 7, 10, 12, 13, 14, 15, 16, 17, 23, 24], "reset": [1, 17, 18, 21, 22, 23, 24], "done": [1, 16, 17, 18, 22, 23, 24], "fals": [1, 4, 5, 6, 10, 12, 13, 14, 15, 16, 17, 18, 22, 23, 24], "action_spac": [1, 17, 21], "sampl": [1, 17, 21], "ignor": 1, "direct": [1, 7, 8, 9, 23], "arrow": 1, "kei": [1, 16, 18, 23], "eventhandl": 1, "class": [1, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 21, 22, 23], "highway_env": [1, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24], "common": [1, 18, 21, 22, 23], "actiontyp": 1, "abstractenv": [1, 18, 21, 23], "kwarg": [1, 23], "sourc": [1, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 21, 23], "A": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 15, 18, 21, 22, 23, 24], "specifi": [1, 8, 21, 25], "its": [1, 4, 6, 7, 8, 9, 16, 17, 22, 24], "definit": 1, "how": [1, 3, 7, 22, 24], "execut": [1, 7, 12, 21, 22], "properti": [1, 7, 8, 9, 21], "vehicle_class": [1, 21], "callabl": [1, 18], "abl": [1, 8, 17, 21], "must": [1, 6, 14, 18, 20, 21, 22, 24, 25], "return": [1, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 21, 22, 23, 25], "subclass": 1, "act": [1, 6, 7, 8, 9], "int": [1, 4, 6, 7, 8, 9, 12, 18, 21, 23, 24], "ndarrai": [1, 4, 7, 8, 9, 12, 14, 18, 21, 23], "none": [1, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 21, 23, 24], "most": [1, 5, 22, 26], "mechan": 1, "actual": [1, 6, 17, 22], "implement": [1, 4, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24], "where": [1, 6, 7, 8, 9, 14, 15, 21, 23, 25], "pre": 1, "process": [1, 2], "appli": [1, 8], "base": [1, 5, 7, 9, 24], "controlled_vehicl": [1, 15, 22, 24], "upon": 1, "If": [1, 7, 8, 9, 16, 19, 21, 23], "first": [1, 5, 17, 18, 21, 22, 23], "acceleration_rang": 1, "tupl": [1, 4, 6, 7, 8, 12, 18, 21, 22, 23], "float": [1, 4, 5, 6, 7, 8, 9, 12, 14, 18, 21, 23], "steering_rang": 1, "speed_rang": 1, "bool": [1, 4, 5, 6, 7, 12, 18, 21, 23], "dynam": [1, 5, 6, 7, 8, 9, 12, 21, 24, 26], "clip": [1, 23], "both": [1, 4, 7, 22, 23], "thi": [1, 4, 7, 10, 12, 13, 16, 17, 20, 21, 22, 23, 24, 25], "order": [1, 9, 17, 22, 23, 25], "interv": 1, "map": [1, 10, 23], "creat": [1, 4, 7, 8, 9, 18, 24, 26], "rang": [1, 7, 8, 9, 10, 23, 24, 25], "valu": [1, 16, 21, 23, 24], "m": [1, 4, 7, 8, 9, 10, 16, 18, 21, 23], "s\u00b2": 1, "rad": [1, 4, 7, 8], "reachabl": [1, 4, 9], "": [1, 5, 6, 7, 8, 9, 10, 12, 13, 16, 17, 18, 21, 22, 23, 24, 25], "whether": [1, 4, 5, 6, 7, 18, 21, 23], "e": [1, 2, 17], "friction": 1, "rather": [1, 25], "than": [1, 7, 17, 23, 25], "5": [1, 7, 9, 10, 12, 13, 14, 15, 16, 20, 22, 23, 24], "x": [1, 4, 9, 12, 14, 18, 23, 25], "7853981633974483": 1, "box": 1, "target_spe": [1, 7, 8], "sequenc": [1, 4, 7, 8, 9, 18, 23], "cruis": [1, 8], "point": [1, 2, 4], "includ": [1, 5, 6, 22], "index": [1, 6, 7, 8, 23], "label": 1, "actions_longi": 1, "actions_lat": 1, "get": [1, 4, 8, 20, 22, 23], "current": [1, 6, 8, 9, 20, 21, 23, 25], "boundari": 1, "maxim": [1, 7], "minim": [1, 7], "multiagentact": [1, 22], "action_config": [1, 22], "dict": [1, 4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 21, 23, 24], "awr": [2, 24], "17": [2, 24], "marcin": 2, "andrychowicz": 2, "filip": 2, "wolski": 2, "alex": 2, "rai": 2, "jona": 2, "schneider": 2, "rachel": 2, "fong": 2, "peter": 2, "welind": 2, "bob": 2, "mcgrew": 2, "josh": 2, "tobin": 2, "pieter": 2, "abbeel": 2, "wojciech": 2, "zaremba": 2, "hindsight": [2, 24], "experi": [2, 22, 24], "replai": [2, 24], "In": [2, 7, 10, 13, 16, 17, 21, 22, 23, 25], "advanc": 2, "neural": 2, "inform": [2, 14, 17, 21, 23], "system": [2, 4, 9, 12, 18], "2017": 2, "arxiv": 2, "1707": 2, "01495": 2, "hm08": [2, 24], "jean": 2, "fran": 2, "\u00e7": 2, "oi": 2, "hren": 2, "r": [2, 7, 8, 25], "\u00e9": 2, "mi": 2, "muno": 2, "optimist": 2, "plan": [2, 8, 16, 24], "determinist": [2, 24], "lectur": 2, "note": [2, 25], "comput": [2, 4, 7, 8, 21], "scienc": 2, "2008": 2, "kth07": [2, 7], "arn": 2, "kest": 2, "martin": 2, "treiber": 2, "dirk": 2, "helb": 2, "gener": [2, 5, 6, 17, 21, 22, 25], "model": [2, 3, 7, 8, 9, 21, 22, 24], "mobil": [2, 7], "car": 2, "transport": 2, "research": 2, "record": [2, 5, 6, 17], "2007": 2, "doi": 2, "10": [2, 7, 12, 23], "3141": 2, "1999": 2, "lm19": [2, 17, 24], "edouard": [2, 19], "leurent": [2, 19], "mercat": 2, "social": [2, 24], "attent": [2, 24], "autonom": [2, 19], "decis": [2, 7, 12, 19, 21], "dens": [2, 12], "traffic": [2, 12, 13, 16], "machin": 2, "learn": [2, 15, 24, 25], "drive": [2, 5, 6, 8, 9, 10, 13, 18, 19, 21, 24, 25], "workshop": 2, "thirti": 2, "third": 2, "confer": 2, "neurip": 2, "2019": [2, 24], "montreal": 2, "canada": 2, "decemb": 2, "1911": 2, "12250": 2, "mk": [2, 25], "15": [2, 10, 12, 13, 14, 15, 16, 17, 18, 23, 24, 25], "volodymyr": 2, "mnih": 2, "korai": 2, "kavukcuoglu": 2, "david": 2, "silver": 2, "andrei": 2, "rusu": 2, "joel": 2, "veness": 2, "marc": 2, "g": [2, 17], "bellemar": 2, "grave": 2, "riedmil": 2, "andrea": 2, "k": [2, 16, 18], "fidjeland": 2, "georg": 2, "ostrovski": 2, "stig": 2, "petersen": 2, "charl": 2, "beatti": 2, "amir": 2, "sadik": 2, "ioanni": 2, "antonogl": 2, "helen": 2, "king": 2, "dharshan": 2, "kumaran": 2, "daan": 2, "wierstra": 2, "shane": 2, "legg": 2, "demi": 2, "hassabi": 2, "human": 2, "control": [2, 3, 7, 14, 15, 16, 21, 26], "deep": [2, 24, 25], "reinforc": [2, 24, 25], "natur": [2, 23], "518": 2, "7540": 2, "529": 2, "533": 2, "2015": 2, "paltchedandrean17": [2, 9], "philip": 2, "polack": 2, "florent": 2, "altch": 2, "brigitt": 2, "d": [2, 7], "andr": 2, "novel": [2, 17], "bicycl": [2, 9], "feasibl": 2, "trajectori": [2, 5, 6, 8, 9, 24, 25], "ieee": 2, "intellig": [2, 7], "symposium": 2, "page": [2, 24], "6": [2, 7, 12, 16, 23], "8": [2, 23, 24], "qsmg17": [2, 17], "qi": 2, "hao": 2, "su": 2, "kaichun": 2, "mo": 2, "leonida": 2, "j": [2, 23], "guiba": 2, "pointnet": 2, "3d": 2, "classif": 2, "segment": 2, "1612": 2, "00593": 2, "thh00": [2, 7], "ansgar": 2, "henneck": 2, "congest": 2, "state": [2, 7, 8, 9, 17, 21, 22, 23, 25], "empir": 2, "microscop": 2, "physic": [2, 3], "review": 2, "statist": 2, "plasma": 2, "fluid": 2, "relat": 2, "interdisciplinari": 2, "topic": 2, "62": 2, "1805": 2, "1824": 2, "2000": 2, "describ": [3, 4, 5, 6, 10, 17, 19, 21, 22, 23], "move": [3, 9, 18, 23], "behav": [3, 5], "time": [3, 5, 7, 8, 16, 25, 26], "There": [3, 24], "two": [3, 5, 7, 8, 15, 17, 18, 22, 23, 25], "section": 3, "affect": 3, "descript": [3, 19, 23, 24], "behavior": [3, 5, 10, 12, 13, 16, 21, 24], "compos": [3, 6, 25], "roadnetwork": [3, 5, 6, 21], "regul": 3, "geometri": [4, 6, 21], "abstractlan": [4, 6, 18], "object": [4, 5, 6, 7, 8, 9, 10, 13, 18, 21, 23], "parametr": [4, 24], "center": [4, 7, 8, 9, 18, 23], "line": [4, 8, 18], "curv": [4, 24], "provid": [4, 8, 17, 18, 19, 21, 24], "local": [4, 6, 17, 18], "coordin": [4, 6, 18, 23], "convers": [4, 23], "between": [4, 5, 7, 8, 9, 18, 23, 25], "longi": 4, "lat": [4, 8, 18], "frenet": 4, "frame": [4, 17, 18, 21, 23], "global": 4, "y": [4, 9, 12, 14, 18, 20, 23, 25], "ensur": 4, "posit": [4, 6, 7, 9, 14, 18, 23], "local_coordin": 4, "main": [4, 13], "straightlan": 4, "sinelan": 4, "circularlan": 4, "central": [4, 12, 22], "metaclass__": 4, "alia": 4, "abcmeta": 4, "abstract": [4, 21], "convert": [4, 8, 18, 23], "world": [4, 23, 26], "heading_at": 4, "head": [4, 7, 9, 14, 23], "given": [4, 6, 7, 8, 9, 14, 17, 18, 21], "width_at": 4, "width": [4, 9, 16, 18], "classmethod": [4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 21], "from_config": 4, "from": [4, 6, 7, 8, 9, 10, 14, 21, 22, 23, 24, 25], "json": [4, 22], "to_config": 4, "write": 4, "serial": 4, "on_lan": 4, "margin": [4, 18], "option": [4, 19, 21], "known": 4, "supplementari": [4, 14], "around": [4, 18, 23], "is_reachable_from": 4, "distanc": [4, 7, 18, 21, 23, 25], "l1": 4, "distance_with_head": 4, "heading_weight": 4, "weight": [4, 7, 14, 23, 25], "local_angl": 4, "long_offset": 4, "non": [4, 7, 8, 23], "normalis": [4, 23], "linetyp": 4, "side": [4, 10, 18], "start": [4, 6, 9, 13, 18, 19], "end": [4, 6, 8, 9, 12, 18, 21, 22], "default_width": 4, "line_typ": 4, "forbidden": 4, "speed_limit": 4, "20": [4, 10, 12, 23, 24], "prioriti": [4, 5], "go": [4, 6], "straight": [4, 10, 23], "new": [4, 5, 6, 7, 8, 9, 17, 21], "determin": [4, 5], "who": [4, 5], "ha": [4, 15, 16, 20, 21, 22, 23, 24, 25], "right": [4, 5, 7, 8, 10, 18, 22, 23], "wai": [4, 5, 12, 17, 24], "amplitud": 4, "pulsat": 4, "phase": 4, "sinusoid": 4, "oscil": 4, "initi": [4, 8, 9, 14, 15, 18, 21, 22], "radiu": 4, "start_phas": 4, "end_phas": 4, "clockwis": 4, "circl": 4, "arc": 4, "polylanefixedwidth": 4, "lane_point": 4, "fix": [4, 21, 23], "approxim": [4, 7], "hermit": 4, "polynomi": 4, "polylan": 4, "left_boundary_point": 4, "right_boundary_point": 4, "regulatedroad": 5, "give": [5, 6, 21, 23], "attribut": [5, 24], "On": 5, "rule": 5, "enforc": 5, "usual": [5, 17], "howev": [5, 17, 24, 25], "try": [5, 7], "predict": [5, 8, 9, 12, 22, 23, 24], "collis": [5, 10, 12, 13, 15, 16, 25, 26], "other": [5, 7, 8, 9, 10, 12, 15, 21, 22, 23], "is_conflict_poss": 5, "when": [5, 7, 8, 10], "case": [5, 6, 17, 23], "arbitr": 5, "respect_prior": 5, "yield": [5, 8, 24, 25], "until": [5, 9, 12, 21], "conflict": 5, "resolv": 5, "network": [5, 6, 8, 21, 23], "obstacl": [5, 6, 23], "np_random": [5, 6], "randomst": [5, 6], "record_histori": [5, 6], "road_object": [5, 6], "landmark": [5, 6], "np": [5, 6], "random": [5, 6, 9, 24], "number": [5, 6, 9, 16, 18, 23, 24, 26], "behaviour": [5, 6, 7, 12, 18, 21, 25], "recent": [5, 6], "should": [5, 6, 7, 17, 18, 21, 22, 23, 25], "displai": [5, 6, 9, 16, 18], "dt": [5, 6, 7, 8, 9], "entiti": [5, 6], "timestep": [5, 6, 7, 8, 9, 12, 21], "enforce_road_rul": 5, "find": [5, 6, 8], "them": [5, 18, 24, 25], "assign": 5, "stop": [5, 7, 9], "static": [5, 18], "v1": 5, "v2": 5, "second": [5, 6, 16, 21, 22], "topologi": [6, 21], "infrastructur": 6, "graph": 6, "repres": [6, 9, 18, 23], "node": [6, 8, 9], "It": [6, 7, 8, 9, 12, 13, 14, 16], "contain": [6, 21, 22, 23], "dictionari": [6, 21, 23, 24], "store": [6, 7, 9], "laneindex": 6, "string": 6, "identifi": 6, "integ": 6, "uniqu": 6, "lab": 6, "pub": 6, "obtain": [6, 24], "road_network": 6, "roadobject": [6, 18], "decid": [6, 7, 22], "action": [6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 21, 24, 26], "neighbour_vehicl": 6, "lane_index": [6, 7], "str": [6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 21, 23], "preced": [6, 7], "whose": [6, 7], "neighbour": [6, 10], "found": [6, 25], "look": [6, 23], "doesn": [6, 7], "t": [6, 7, 16, 23], "have": [6, 7, 14, 21, 25], "also": [6, 10, 13, 17, 18, 23, 24, 25], "anoth": 6, "project": [6, 7, 19, 20, 25], "consid": [6, 19, 23], "simpl": [7, 8, 12, 25], "realist": [7, 25], "dictat": 7, "idmvehicl": [7, 10, 13, 16, 21, 24], "driver": 7, "idm": 7, "dot": [7, 8, 9], "v": [7, 8, 9, 23, 25], "left": [7, 8, 18, 22, 23], "frac": [7, 8, 9, 25], "v_0": 7, "d_0": 7, "tv": 7, "sqrt": 7, "ab": 7, "front": [7, 8, 9, 25], "parametris": 7, "target_veloc": 7, "gap": 7, "time_w": 7, "jam": 7, "distance_w": 7, "b": [7, 25], "deceler": 7, "comfort_acc_max": 7, "comfort_acc_min": 7, "expon": 7, "discret": [7, 8, 26], "overal": 7, "brake": [7, 9, 25], "induc": 7, "accord": 7, "safe": [7, 13, 25], "do": [7, 17, 25], "cut": 7, "tild": 7, "_n": 7, "geq": 7, "b_": 7, "text": [7, 8, 25], "incent": 7, "possibli": 7, "underbrac": 7, "_c": 7, "a_c": 7, "_": [7, 22, 23, 24, 25], "p": [7, 8, 14, 25], "a_n": 7, "_o": 7, "a_o": 7, "old": 7, "a_": 7, "th": 7, "c": [7, 18, 23], "o": [7, 18], "befor": [7, 22], "n": 7, "after": [7, 22, 24], "polit": 7, "coeffici": [7, 25], "gain": [7, 8], "requir": [7, 20, 21], "trigger": 7, "lane_change_min_acc_gain": 7, "impos": 7, "dure": [7, 18], "lane_change_max_braking_impos": 7, "linearvehicl": 7, "linear": [7, 8], "featur": [7, 12, 14, 15, 25], "differ": [7, 17, 23], "lead": [7, 23, 25], "target_lane_index": [7, 8], "rout": [7, 8, 16], "enable_lane_chang": 7, "timer": 7, "polici": [7, 21, 22, 24, 25], "nearbi": [7, 23], "place": [7, 8, 9, 23], "cartesian": [7, 8, 9], "surfac": [7, 8, 9, 26], "horizont": [7, 8, 9], "acc_max": 7, "term": [7, 25], "delta_rang": 7, "chosen": [7, 9, 18], "randomli": [7, 9], "create_from": [7, 8, 9], "controlledvehicl": [7, 8], "exist": [7, 8, 9, 21, 23], "one": [7, 8, 9, 18, 22], "copi": [7, 8, 9, 17, 21], "same": [7, 8, 9], "now": [7, 13, 21, 22, 23], "support": [7, 22], "becaus": [7, 17], "all": [7, 12, 17, 21, 23], "own": [7, 12, 22, 26], "increas": [7, 23, 26], "ego_vehicl": 7, "front_vehicl": 7, "rear_vehicl": 7, "command": [7, 8, 9], "reach": [7, 10, 14], "maintain": [7, 13], "safeti": 7, "w": [7, 18, 23, 25], "doe": [7, 17, 24], "why": 7, "reason": [7, 12, 17], "about": [7, 17, 24], "even": [7, 18], "though": 7, "mai": [7, 23, 25], "s2": [7, 8], "desired_gap": 7, "being": [7, 9, 25], "change_lane_polici": 7, "frequenc": [7, 17, 18, 21], "close": [7, 17, 18, 21], "more": [7, 10, 12, 13, 14, 15, 16, 17, 21], "unsaf": 7, "candid": 7, "recover_from_stop": 7, "wrong": 7, "revers": 7, "maneuv": 7, "suggest": [7, 17], "recov": 7, "stuck": 7, "data": [7, 21, 23], "resp": 7, "lower": [7, 21], "higher": 7, "steering_control": [7, 8], "overrid": 7, "wheel": [7, 8, 9], "steering_featur": 7, "collect": [7, 19, 23], "arrai": [7, 18, 22, 23], "collect_data": 7, "output": [7, 17], "regress": 7, "aggressivevehicl": 7, "defensivevehicl": 7, "call": [8, 10, 12, 13, 14, 15, 16, 17, 18, 21], "proport": 8, "k_p": 8, "v_r": 8, "refer": [8, 21], "kp_a": 8, "speed_control": 8, "deriv": 8, "combin": 8, "invert": 8, "those": [8, 24], "v_": [8, 25], "k_": 8, "delta_": 8, "psi_": 8, "arcsin": 8, "psi_r": 8, "psi_l": 8, "psi": [8, 9, 25], "_r": 8, "l": [8, 9, 18, 23], "variat": 8, "lookahead": 8, "anticip": 8, "turn": 8, "yaw": 8, "rate": 8, "pilot": 8, "high": [8, 10, 13, 14], "cascad": 8, "plan_route_to": 8, "destin": [8, 12, 23, 25], "updat": [8, 9, 18, 20, 22, 23], "follow_road": 8, "At": 8, "switch": 8, "next": [8, 12, 21, 23], "get_routes_at_intersect": 8, "set_route_at_intersect": 8, "_to": 8, "eras": 8, "predict_trajectory_constant_spe": 8, "futur": [8, 9], "along": [8, 18, 23], "under": 8, "constant": [8, 21, 23], "mdpvehicl": 8, "handl": [8, 16, 18], "choos": [8, 25], "els": [8, 23], "forward": [8, 9, 18], "handler": 8, "index_to_spe": 8, "among": 8, "speed_to_index": 8, "closest": [8, 23], "assum": [8, 23], "avoid": [8, 10, 12, 13, 15, 16, 25], "search": 8, "input": [8, 9, 18], "speed_to_index_default": 8, "predict_trajectori": [8, 9], "action_dur": [8, 9], "trajectory_timestep": [8, 9], "durat": [8, 9, 10, 12, 15, 16, 24], "save": [8, 9, 24], "co": [9, 25], "beta": 9, "sin": [9, 25], "tan": 9, "slip": 9, "graviti": 9, "These": [9, 21, 23], "calcul": 9, "appear": 9, "predition_typ": 9, "constant_st": 9, "modifi": [9, 21], "propag": 9, "depend": [9, 17, 20, 21], "length": [9, 18], "default_initial_spe": 9, "23": 9, "25": [9, 23], "max_spe": 9, "40": [9, 10, 24], "min_spe": 9, "history_s": 9, "30": [9, 10, 24], "histori": 9, "create_random": 9, "lane_from": 9, "lane_to": 9, "lane_id": 9, "behind": [9, 23], "last": [9, 21, 23], "densiti": 9, "spawn": 9, "id": [9, 21], "ratio": 9, "repeat": 9, "integr": 9, "1st": 9, "respons": 9, "crash": [9, 16], "overridden": 9, "errat": 9, "complet": 9, "task": [10, 12, 13, 14, 16, 21, 24], "multilan": 10, "popul": [10, 21], "reward": [10, 12, 13, 14, 17, 21, 22, 23, 24, 26], "lanes_count": [10, 24], "vehicles_count": [10, 12, 22, 23, 24], "50": [10, 18, 24], "initial_spac": 10, "collision_reward": [10, 12, 15, 24], "receiv": 10, "collid": [10, 23], "reward_speed_rang": [10, 24], "linearli": 10, "highwayenv": 10, "high_speed_reward": [10, 24], "simulation_frequ": [10, 13, 14, 15, 16, 18, 24], "hz": [10, 13, 16, 17], "policy_frequ": [10, 13, 14, 15, 16, 23, 24], "other_vehicles_typ": [10, 13, 16, 24], "screen_width": [10, 12, 13, 14, 15, 16, 18, 24], "600": [10, 12, 13, 14, 15, 16, 24], "px": [10, 13, 16, 18], "screen_height": [10, 12, 13, 14, 15, 16, 18, 24], "150": [10, 13, 24], "centering_posit": [10, 12, 13, 14, 15, 16, 18, 23, 24], "scale": [10, 12, 13, 14, 15, 16, 18, 23, 24, 25], "show_trajectori": [10, 13, 14, 15, 16, 24], "render_ag": [10, 13, 14, 15, 16, 24], "offscreen_rend": [10, 13, 14, 15, 16, 24], "specif": [10, 12, 13, 14, 15, 16, 18, 23], "default_config": [10, 12, 13, 14, 15, 16, 21], "overload": [10, 12, 13, 14, 15, 16, 21, 25], "x15": 10, "speedup": 10, "fast": [10, 16, 24], "detail": [10, 19], "here": [10, 17, 21, 22, 23, 24], "render_mod": [10, 12, 13, 14, 15, 16, 21, 22, 23, 24], "stai": [10, 23], "rightmost": 10, "merg": [11, 24], "roundabout": [11, 18, 24], "park": [11, 23, 24, 25], "racetrack": [11, 24], "negoti": [12, 13], "quit": 12, "hard": 12, "up": [12, 26], "good": 12, "decentr": 12, "Of": 12, "cours": 12, "could": [12, 22, 25], "achiev": [12, 14, 21], "sophist": 12, "schedul": 12, "light": 12, "keep": [12, 25], "thing": 12, "rudimentari": 12, "wa": [12, 14, 18], "ad": [12, 21], "sometim": 12, "fail": 12, "result": [12, 24], "block": 12, "figur": [12, 22, 23, 24], "fine": 12, "my": [12, 24], "purpos": [12, 19], "sinc": [12, 22, 23, 25], "did": [12, 21], "happen": 12, "too": 12, "often": [12, 25], "expect": [12, 23, 25], "simpli": 12, "wait": 12, "episod": [12, 17, 21, 22, 24, 25], "situat": 12, "But": 12, "agre": 12, "ideal": 12, "welcom": [12, 21], "ani": [12, 14, 21, 23, 25], "contribut": [12, 19], "matter": 12, "presenc": [12, 15], "vx": [12, 14, 23], "vy": [12, 14, 23], "cos_h": [12, 14, 23], "sin_h": [12, 14, 23], "features_rang": [12, 23], "100": [12, 14, 23], "absolut": [12, 23], "flatten": 12, "observe_intent": [12, 23], "13": [12, 23], "o1": 12, "initial_vehicle_count": 12, "spawn_prob": 12, "intersectionenv": [12, 22], "normalize_reward": [12, 24], "intersection_env": 12, "termin": [12, 21, 25], "truncat": [12, 16, 17, 21, 22, 23, 24], "info": [12, 14, 17, 21, 22, 23, 24], "soon": 13, "approach": [13, 16, 23], "junction": 13, "incom": 13, "ramp": 13, "room": 13, "timetocollis": [13, 16, 23], "mergeenv": 13, "merge_env": 13, "goal": [14, 24, 26], "condit": [14, 24], "continu": [14, 15, 18, 26], "appropri": [14, 25], "kinematicsgo": 14, "normal": [14, 23, 25], "300": [14, 15], "7": [14, 15], "parkingenv": 14, "parking_env": 14, "credit": [14, 15], "munir": 14, "jojo": 14, "verg": 14, "idea": [14, 15], "define_spac": [14, 21], "compute_reward": 14, "achieved_go": 14, "desired_go": 14, "proxim": 14, "we": [14, 17, 18, 20, 21, 23, 25], "norm": [14, 25], "lp": 14, "kurtosi": 14, "he": 15, "mani": [15, 18], "thank": [15, 18], "supperted825": 15, "occupancygrid": [15, 23], "on_road": 15, "grid_siz": [15, 23], "18": [15, 23], "grid_step": [15, 23], "as_imag": [15, 23], "align_to_vehicle_ax": [15, 23], "lane_centering_cost": 15, "action_reward": 15, "other_vehicl": 15, "racetrackenv": 15, "racetrack_env": 15, "need": [15, 17], "skill": 15, "see": [15, 17, 21, 22, 23, 24, 25], "http": [15, 18, 19, 20], "github": [15, 19, 20], "com": [15, 18, 19, 20], "eleur": [15, 19, 20, 22, 24], "issu": 15, "231": 15, "flow": 16, "pass": [16, 22, 23], "possibl": [16, 17, 25], "incoming_vehicle_destin": 16, "11": 16, "run": [16, 17, 21, 22, 24], "still": [16, 21], "hasn": 16, "express": 16, "variabl": 16, "equal": 16, "pygam": [16, 18, 20], "window": [16, 18], "height": 16, "smaller": 16, "southeast": 16, "area": [16, 18], "roundaboutenv": 16, "roundabout_env": 16, "feel": 17, "free": 17, "entri": 17, "probabl": 17, "you": [17, 19, 21, 23], "instal": [17, 18, 21], "instead": [17, 25], "work": 17, "repositori": [17, 19], "code": [17, 22], "regist": [17, 26], "register_highway_env": [17, 21], "tend": 17, "sub": 17, "pair": [17, 21, 23], "argu": 17, "inde": 17, "revisit": 17, "scene": [17, 23, 26], "reus": 17, "past": 17, "struggl": 17, "address": [17, 25], "permut": 17, "invari": [17, 25], "architectur": [17, 24], "sensit": 17, "exampl": [17, 21, 22], "dqn": [17, 22, 23, 24], "sb3": [17, 24], "ppo": 17, "grayscal": [17, 26], "imag": [17, 18, 21, 24, 26], "cnn": [17, 24], "suitabl": 17, "singl": [17, 21, 22, 25], "typic": 17, "long": 17, "render": [17, 18, 21, 22, 23, 24], "intermedi": [17, 21], "wrap": [17, 21, 26], "recordvideo": [17, 21], "wrapper": [17, 21], "video_fold": 17, "episode_trigg": 17, "lambda": 17, "send": [17, 22], "unwrap": 17, "set_record_video_wrapp": 17, "ob": [17, 21, 22, 23, 24], "Its": 18, "dimens": 18, "640": 18, "480": 18, "roadsurfac": 18, "locat": [18, 23], "zoom": 18, "By": 18, "offset": [18, 23], "roadgraph": 18, "vehiclegraph": 18, "envview": 18, "viewer": [18, 21], "set_agent_displai": 18, "agent_displai": 18, "callback": 18, "dedic": 18, "set_agent_action_sequ": 18, "handle_ev": 18, "event": 18, "get_imag": 18, "rgb": [18, 23], "channel": [18, 23], "convent": [18, 25], "h": [18, 23], "window_posit": 18, "worldsurfac": 18, "size": [18, 22, 23, 24], "flag": 18, "surf": 18, "pix": 18, "pixel": 18, "pos2pix": 18, "vec2pix": 18, "vec": 18, "is_vis": 18, "visibl": 18, "param": [18, 23], "test": [18, 24], "move_display_window_to": 18, "origin": 18, "lanegraph": 18, "visual": 18, "stripe_spac": 18, "33": 18, "stripe": 18, "stripe_length": 18, "stripe_width": 18, "striped_lin": 18, "stripes_count": 18, "draw": 18, "continuous_curv": 18, "continuous_lin": 18, "would": [18, 23, 25], "drawn": 18, "draw_strip": 18, "display_traff": 18, "offscreen": 18, "without": 18, "screen": 18, "display_road_object": 18, "roadobjectgraph": 18, "object_": 18, "transpar": 18, "color": 18, "rotat": 18, "rectangl": [18, 23], "slightli": 18, "blit_rot": 18, "po": 18, "origin_po": 18, "show_rect": 18, "stackoverflow": 18, "54714144": 18, "gather": 19, "quick": [19, 24], "guid": 19, "custom": 19, "nut": 19, "bolt": 19, "packag": 19, "pleas": 19, "piec": 19, "bibtex": 19, "misc": 19, "author": 19, "titl": [19, 22], "year": 19, "2018": 19, "publish": 19, "journal": 19, "howpublish": 19, "url": 19, "python3": 20, "graphic": [20, 26], "itself": 20, "manual": [20, 21, 26], "sudo": 20, "apt": 20, "python": [20, 21, 22], "dev": 20, "libsdl": 20, "image1": 20, "mixer1": 20, "ttf2": 20, "libsdl1": 20, "libsmpeg": 20, "numpi": 20, "subvers": 20, "libportmidi": 20, "ffmpeg": 20, "libswscal": 20, "libavformat": 20, "libavcodec": 20, "libfreetype6": 20, "gcc": 20, "recommend": 20, "anaconda": 20, "To": [20, 21, 22], "latest": 20, "pip": 20, "user": 20, "git": 20, "pull": 21, "request": 21, "your_env": 21, "py": [21, 22], "yourenv": 21, "inherit": 21, "function": [21, 24, 25], "choic": [21, 25], "_make_road": 21, "self": [21, 22], "field": [21, 22, 23], "action_typ": [21, 23, 24], "freeli": 21, "part": [21, 23], "config_kei": 21, "onc": 21, "other_valu": 21, "__init__": 21, "entry_point": 21, "registr": 21, "hook": 21, "reinstal": 21, "setup": 21, "altern": 21, "That": 21, "themselv": 21, "variou": 21, "involv": 21, "perception_dist": 21, "200": [21, 24], "present": 21, "_reward": [21, 25], "associ": 21, "multi": [21, 26], "vector": 21, "aggreg": 21, "scalar": 21, "insid": [21, 25], "reward_nam": 21, "reward_valu": 21, "_is_termin": 21, "check": [21, 23], "_is_trunc": 21, "_info": 21, "addit": 21, "seed": [21, 22, 24], "prng": 21, "_reset": 21, "_simul": 21, "Will": 21, "_automatic_rend": 21, "ongo": 21, "whole": 21, "video": [21, 22, 24], "been": [21, 22, 25], "captur": 21, "simplifi": 21, "distant": 21, "remov": 21, "meant": 21, "load": [21, 24], "preserv": 21, "optim": [21, 25], "change_vehicl": 21, "vehicle_class_path": 21, "path": [21, 22], "multiagentwrapp": 21, "obstyp": 21, "acttyp": 21, "modular": 21, "transform": 21, "overwritten": 21, "version": 22, "rgb_arrai": [22, 23, 24], "sake": 22, "visualis": 22, "matplotlib": [22, 23, 24], "pyplot": [22, 23, 24], "plt": [22, 23, 24], "inlin": [22, 23, 24], "imshow": [22, 23, 24], "green": 22, "show": [22, 23, 24], "640x480": [22, 23, 24], "ax": [22, 23, 24], "accept": 22, "standard": 22, "ax1": 22, "ax2": 22, "subplot": [22, 23], "nrow": 22, "set_titl": 22, "action_1": 22, "action_2": 22, "what": [22, 23], "As": 22, "far": 22, "multiagentobserv": 22, "observation_config": 22, "pprint": [22, 24], "90797305": 22, "3125": 22, "10906096": 22, "04341291": 22, "33000726": 22, "dtype": 22, "float32": 22, "pseudo": 22, "train": 22, "dummi": 22, "rl": [22, 24], "algorithm": 22, "transit": 22, "def": 22, "next_ob": 22, "dispatch": 22, "obs_i": 22, "action_i": 22, "next_obs_i": 22, "zip": 22, "cd": 22, "script": [22, 24], "evalu": 22, "env_multi_ag": 22, "dqnagent": 22, "ego_attention_2h": 22, "3000": 22, "27": 23, "observation_factori": 23, "kinematicobserv": 23, "f": 23, "v_y": [23, 25], "12": 23, "22": 23, "row": 23, "within": 23, "05": 23, "04": 23, "75": 23, "08": 23, "675": 23, "222": 23, "105": 23, "9": 23, "025": 23, "rel": 23, "except": 23, "075": 23, "172": 23, "065": 23, "fewer": 23, "placehold": 23, "fill": 23, "zero": 23, "detect": 23, "disambigu": 23, "radian": 23, "trigonometr": 23, "cos_d": 23, "sin_d": 23, "long_": 23, "off": 23, "lat_": 23, "ang_": 23, "angular": 23, "sort": 23, "print": 23, "20323725": 23, "07361443": 23, "39618185": 23, "11105874": 23, "6169058": 23, "17033932": 23, "83093834": 23, "0526074": 23, "18704522": 23, "1492452": 23, "05019206": 23, "07072275": 23, "18716832": 23, "grayscaleobserv": 23, "observation_shap": 23, "sum": 23, "stack_siz": 23, "customari": 23, "128": 23, "64": 23, "2989": 23, "5870": 23, "1140": 23, "fig": 23, "ncol": 23, "figsiz": 23, "enumer": 23, "flat": 23, "cmap": 23, "get_cmap": 23, "grai": 23, "1200x500": 23, "three": 23, "actions_index": [23, 24], "occupancygridobserv": 23, "shape": 23, "discretis": 23, "cell": 23, "resolut": 23, "like": 23, "timetocollisionobserv": 23, "hot": 23, "encod": 23, "over": 23, "bin": 23, "25m": 23, "infti": 23, "middl": 23, "bottom": 23, "horizon": 23, "lidarobserv": 23, "divid": 23, "sector": 23, "per": 23, "column": 23, "nearest": 23, "compon": 23, "south": 23, "west": 23, "meter": 23, "awai": 23, "toward": 23, "1m": 23, "maximum_rang": 23, "84": 23, "see_behind": 23, "include_obstacl": 23, "min": [23, 25], "max": [23, 25], "shuffl": 23, "normalize_ob": 23, "df": 23, "datafram": 23, "real": 23, "min_x": 23, "max_x": 23, "min_i": 23, "max_i": 23, "step_x": 23, "step_i": 23, "align": 23, "pos_to_index": 23, "otherwis": 23, "alreadi": 23, "fill_road_layer_by_lan": 23, "layer_index": 23, "lane_perception_dist": 23, "onroad": 23, "offroad": 23, "iter": 23, "regularli": 23, "waypoint": 23, "larg": 23, "small": 23, "fill_road_layer_by_cel": 23, "kinematicsgoalobserv": 23, "exitobserv": 23, "exit_env": 23, "exit": 23, "creation": 24, "ego_spac": 24, "initial_lane_id": 24, "lane_change_reward": 24, "offroad_termin": 24, "real_time_rend": 24, "right_lane_reward": 24, "vehicles_dens": 24, "effect": 24, "librari": 24, "openai": 24, "baselin": 24, "stabl": 24, "baselines3": 24, "mlp": 24, "stable_baselines3": 24, "mlppolici": 24, "policy_kwarg": 24, "net_arch": 24, "256": 24, "learning_r": 24, "5e": 24, "buffer_s": 24, "15000": 24, "learning_start": 24, "batch_siz": 24, "32": 24, "gamma": 24, "train_freq": 24, "gradient_step": 24, "target_update_interv": 24, "verbos": 24, "tensorboard_log": 24, "highway_dqn": 24, "2e4": 24, "_state": 24, "25mn": 24, "laptop": 24, "fp": 24, "14": 24, "better": 24, "vanilla": 24, "q": 24, "extens": 24, "doubl": 24, "duel": 24, "priorit": 24, "improv": 24, "faq": 24, "notebook": 24, "few": 24, "opd": 24, "tutori": 24, "written": 24, "rlss": 24, "demonstr": 24, "principl": 24, "her": 24, "cross": 24, "challeng": 25, "problem": 25, "particular": 25, "wish": 25, "aspect": 25, "straightforward": 25, "adequ": 25, "emerg": 25, "perspect": 25, "robust": 25, "against": 25, "uncertain": 25, "focu": 25, "progress": 25, "quickli": 25, "bound": 25, "shift": 25, "practic": 25, "benefici": 25, "forbid": 25, "neg": 25, "encourag": 25, "prefer": 25, "earli": 25, "caus": 25, "risk": 25, "suffer": 25, "satisfi": 25, "penalti": 25, "collision_penalti": 25, "replac": 25, "s_g": 25, "v_x": 25, "x_g": 25, "y_g": 25, "psi_g": 25, "sum_i": 25, "w_i": 25, "x_i": 25, "euclidean": 25, "narrow": 25, "spike": 25, "occup": 26, "grid": 26, "lidar": 26, "api": 26, "meta": 26, "your": 26, "file": 26, "profit": 26}, "objects": {"highway_env": [[21, 0, 0, "-", "__init__"]], "highway_env.__init__": [[21, 1, 1, "", "register_highway_envs"]], "highway_env.envs.common": [[21, 0, 0, "-", "abstract"], [1, 0, 0, "-", "action"], [18, 0, 0, "-", "graphics"], [23, 0, 0, "-", "observation"]], "highway_env.envs.common.abstract": [[21, 2, 1, "", "AbstractEnv"], [21, 2, 1, "", "MultiAgentWrapper"]], "highway_env.envs.common.abstract.AbstractEnv": [[21, 3, 1, "", "PERCEPTION_DISTANCE"], [21, 4, 1, "", "_automatic_rendering"], [21, 4, 1, "", "_info"], [21, 4, 1, "", "_is_terminated"], [21, 4, 1, "", "_is_truncated"], [21, 4, 1, "", "_reset"], [21, 4, 1, "", "_reward"], [21, 4, 1, "", "_rewards"], [21, 4, 1, "", "_simulate"], [21, 4, 1, "", "change_vehicles"], [21, 4, 1, "", "close"], [21, 4, 1, "", "default_config"], [21, 4, 1, "", "define_spaces"], [21, 4, 1, "", "render"], [21, 4, 1, "", "reset"], [21, 4, 1, "", "simplify"], [21, 4, 1, "", "step"], [21, 5, 1, "", "vehicle"]], "highway_env.envs.common.abstract.MultiAgentWrapper": [[21, 4, 1, "", "step"]], "highway_env.envs.common.action": [[1, 2, 1, "", "ActionType"], [1, 2, 1, "", "ContinuousAction"], [1, 2, 1, "", "DiscreteAction"], [1, 2, 1, "", "DiscreteMetaAction"], [1, 2, 1, "", "MultiAgentAction"]], "highway_env.envs.common.action.ActionType": [[1, 4, 1, "", "act"], [1, 5, 1, "", "controlled_vehicle"], [1, 4, 1, "", "get_available_actions"], [1, 4, 1, "", "space"], [1, 5, 1, "", "vehicle_class"]], "highway_env.envs.common.action.ContinuousAction": [[1, 3, 1, "", "ACCELERATION_RANGE"], [1, 3, 1, "", "STEERING_RANGE"], [1, 4, 1, "", "act"], [1, 4, 1, "", "space"], [1, 5, 1, "", "vehicle_class"]], "highway_env.envs.common.action.DiscreteAction": [[1, 4, 1, "", "act"], [1, 4, 1, "", "space"]], "highway_env.envs.common.action.DiscreteMetaAction": [[1, 3, 1, "", "ACTIONS_ALL"], [1, 3, 1, "", "ACTIONS_LAT"], [1, 3, 1, "", "ACTIONS_LONGI"], [1, 4, 1, "", "act"], [1, 4, 1, "", "get_available_actions"], [1, 4, 1, "", "space"], [1, 5, 1, "", "vehicle_class"]], "highway_env.envs.common.action.MultiAgentAction": [[1, 4, 1, "", "act"], [1, 4, 1, "", "get_available_actions"], [1, 4, 1, "", "space"], [1, 5, 1, "", "vehicle_class"]], "highway_env.envs.common.graphics": [[18, 2, 1, "", "EnvViewer"]], "highway_env.envs.common.graphics.EnvViewer": [[18, 4, 1, "", "close"], [18, 4, 1, "", "display"], [18, 4, 1, "", "get_image"], [18, 4, 1, "", "handle_events"], [18, 4, 1, "", "set_agent_action_sequence"], [18, 4, 1, "", "set_agent_display"], [18, 4, 1, "", "window_position"]], "highway_env.envs.common.observation": [[23, 2, 1, "", "ExitObservation"], [23, 2, 1, "", "GrayscaleObservation"], [23, 2, 1, "", "KinematicObservation"], [23, 2, 1, "", "KinematicsGoalObservation"], [23, 2, 1, "", "OccupancyGridObservation"]], "highway_env.envs.common.observation.ExitObservation": [[23, 4, 1, "", "observe"]], "highway_env.envs.common.observation.GrayscaleObservation": [[23, 4, 1, "", "observe"], [23, 4, 1, "", "space"]], "highway_env.envs.common.observation.KinematicObservation": [[23, 4, 1, "", "normalize_obs"], [23, 4, 1, "", "observe"], [23, 4, 1, "", "space"]], "highway_env.envs.common.observation.KinematicsGoalObservation": [[23, 4, 1, "", "observe"], [23, 4, 1, "", "space"]], "highway_env.envs.common.observation.OccupancyGridObservation": [[23, 4, 1, "", "fill_road_layer_by_cell"], [23, 4, 1, "", "fill_road_layer_by_lanes"], [23, 4, 1, "", "normalize"], [23, 4, 1, "", "observe"], [23, 4, 1, "", "pos_to_index"], [23, 4, 1, "", "space"]], "highway_env.envs.highway_env": [[10, 2, 1, "", "HighwayEnv"]], "highway_env.envs.highway_env.HighwayEnv": [[10, 4, 1, "", "default_config"]], "highway_env.envs.intersection_env": [[12, 2, 1, "", "IntersectionEnv"]], "highway_env.envs.intersection_env.IntersectionEnv": [[12, 4, 1, "", "default_config"], [12, 4, 1, "", "step"]], "highway_env.envs.merge_env": [[13, 2, 1, "", "MergeEnv"]], "highway_env.envs.merge_env.MergeEnv": [[13, 4, 1, "", "default_config"]], "highway_env.envs.parking_env": [[14, 2, 1, "", "ParkingEnv"]], "highway_env.envs.parking_env.ParkingEnv": [[14, 4, 1, "", "compute_reward"], [14, 4, 1, "", "default_config"], [14, 4, 1, "", "define_spaces"]], "highway_env.envs.racetrack_env": [[15, 2, 1, "", "RacetrackEnv"]], "highway_env.envs.racetrack_env.RacetrackEnv": [[15, 4, 1, "", "default_config"]], "highway_env.envs.roundabout_env": [[16, 2, 1, "", "RoundaboutEnv"]], "highway_env.envs.roundabout_env.RoundaboutEnv": [[16, 4, 1, "", "default_config"]], "highway_env.road": [[18, 0, 0, "-", "graphics"], [4, 0, 0, "-", "lane"], [5, 0, 0, "-", "regulation"], [6, 0, 0, "-", "road"]], "highway_env.road.graphics": [[18, 2, 1, "", "LaneGraphics"], [18, 2, 1, "", "RoadGraphics"], [18, 2, 1, "", "RoadObjectGraphics"], [18, 2, 1, "", "WorldSurface"]], "highway_env.road.graphics.LaneGraphics": [[18, 3, 1, "", "STRIPE_LENGTH"], [18, 3, 1, "", "STRIPE_SPACING"], [18, 3, 1, "", "STRIPE_WIDTH"], [18, 4, 1, "", "continuous_curve"], [18, 4, 1, "", "continuous_line"], [18, 4, 1, "", "display"], [18, 4, 1, "", "draw_stripes"], [18, 4, 1, "", "striped_line"]], "highway_env.road.graphics.RoadGraphics": [[18, 4, 1, "", "display"], [18, 4, 1, "", "display_road_objects"], [18, 4, 1, "", "display_traffic"]], "highway_env.road.graphics.RoadObjectGraphics": [[18, 4, 1, "", "blit_rotate"], [18, 4, 1, "", "display"]], "highway_env.road.graphics.WorldSurface": [[18, 4, 1, "", "handle_event"], [18, 4, 1, "", "is_visible"], [18, 4, 1, "", "move_display_window_to"], [18, 4, 1, "", "pix"], [18, 4, 1, "", "pos2pix"], [18, 4, 1, "", "vec2pix"]], "highway_env.road.lane": [[4, 2, 1, "", "AbstractLane"], [4, 2, 1, "", "CircularLane"], [4, 2, 1, "", "LineType"], [4, 2, 1, "", "PolyLane"], [4, 2, 1, "", "PolyLaneFixedWidth"], [4, 2, 1, "", "SineLane"], [4, 2, 1, "", "StraightLane"]], "highway_env.road.lane.AbstractLane": [[4, 4, 1, "", "distance"], [4, 4, 1, "", "distance_with_heading"], [4, 4, 1, "", "from_config"], [4, 4, 1, "", "heading_at"], [4, 4, 1, "", "is_reachable_from"], [4, 4, 1, "", "local_angle"], [4, 4, 1, "", "local_coordinates"], [4, 3, 1, "", "metaclass__"], [4, 4, 1, "", "on_lane"], [4, 4, 1, "", "position"], [4, 4, 1, "", "to_config"], [4, 4, 1, "", "width_at"]], "highway_env.road.lane.CircularLane": [[4, 4, 1, "", "from_config"], [4, 4, 1, "", "heading_at"], [4, 4, 1, "", "local_coordinates"], [4, 4, 1, "", "position"], [4, 4, 1, "", "to_config"], [4, 4, 1, "", "width_at"]], "highway_env.road.lane.PolyLane": [[4, 4, 1, "", "to_config"], [4, 4, 1, "", "width_at"]], "highway_env.road.lane.PolyLaneFixedWidth": [[4, 4, 1, "", "from_config"], [4, 4, 1, "", "heading_at"], [4, 4, 1, "", "local_coordinates"], [4, 4, 1, "", "position"], [4, 4, 1, "", "to_config"], [4, 4, 1, "", "width_at"]], "highway_env.road.lane.SineLane": [[4, 4, 1, "", "from_config"], [4, 4, 1, "", "heading_at"], [4, 4, 1, "", "local_coordinates"], [4, 4, 1, "", "position"], [4, 4, 1, "", "to_config"]], "highway_env.road.lane.StraightLane": [[4, 4, 1, "", "from_config"], [4, 4, 1, "", "heading_at"], [4, 4, 1, "", "local_coordinates"], [4, 4, 1, "", "position"], [4, 4, 1, "", "to_config"], [4, 4, 1, "", "width_at"]], "highway_env.road.regulation": [[5, 2, 1, "", "RegulatedRoad"]], "highway_env.road.regulation.RegulatedRoad": [[5, 4, 1, "", "enforce_road_rules"], [5, 4, 1, "", "respect_priorities"], [5, 4, 1, "", "step"]], "highway_env.road.road": [[6, 2, 1, "", "Road"]], "highway_env.road.road.Road": [[6, 4, 1, "", "act"], [6, 4, 1, "", "neighbour_vehicles"], [6, 4, 1, "", "step"]], "highway_env.vehicle": [[7, 0, 0, "-", "behavior"], [8, 0, 0, "-", "controller"], [18, 0, 0, "-", "graphics"], [9, 0, 0, "-", "kinematics"]], "highway_env.vehicle.behavior": [[7, 2, 1, "", "AggressiveVehicle"], [7, 2, 1, "", "DefensiveVehicle"], [7, 2, 1, "", "IDMVehicle"], [7, 2, 1, "", "LinearVehicle"]], "highway_env.vehicle.behavior.AggressiveVehicle": [[7, 3, 1, "", "target_speed"]], "highway_env.vehicle.behavior.DefensiveVehicle": [[7, 3, 1, "", "target_speed"]], "highway_env.vehicle.behavior.IDMVehicle": [[7, 3, 1, "", "ACC_MAX"], [7, 3, 1, "", "COMFORT_ACC_MAX"], [7, 3, 1, "", "COMFORT_ACC_MIN"], [7, 3, 1, "", "DELTA"], [7, 3, 1, "", "DELTA_RANGE"], [7, 3, 1, "", "DISTANCE_WANTED"], [7, 3, 1, "", "TIME_WANTED"], [7, 4, 1, "", "acceleration"], [7, 4, 1, "", "act"], [7, 4, 1, "", "change_lane_policy"], [7, 4, 1, "", "create_from"], [7, 4, 1, "", "desired_gap"], [7, 4, 1, "", "mobil"], [7, 4, 1, "", "recover_from_stop"], [7, 4, 1, "", "step"], [7, 3, 1, "", "target_speed"]], "highway_env.vehicle.behavior.LinearVehicle": [[7, 3, 1, "", "TIME_WANTED"], [7, 4, 1, "", "acceleration"], [7, 4, 1, "", "act"], [7, 4, 1, "", "collect_data"], [7, 4, 1, "", "steering_control"], [7, 4, 1, "", "steering_features"], [7, 3, 1, "", "target_speed"]], "highway_env.vehicle.controller": [[8, 2, 1, "", "ControlledVehicle"], [8, 2, 1, "", "MDPVehicle"]], "highway_env.vehicle.controller.ControlledVehicle": [[8, 4, 1, "", "act"], [8, 4, 1, "", "create_from"], [8, 4, 1, "", "follow_road"], [8, 4, 1, "", "get_routes_at_intersection"], [8, 4, 1, "", "plan_route_to"], [8, 4, 1, "", "predict_trajectory_constant_speed"], [8, 4, 1, "", "set_route_at_intersection"], [8, 4, 1, "", "speed_control"], [8, 4, 1, "", "steering_control"], [8, 3, 1, "", "target_speed"]], "highway_env.vehicle.controller.MDPVehicle": [[8, 4, 1, "", "act"], [8, 4, 1, "", "index_to_speed"], [8, 4, 1, "", "predict_trajectory"], [8, 4, 1, "", "speed_to_index"], [8, 4, 1, "", "speed_to_index_default"], [8, 3, 1, "", "target_speed"]], "highway_env.vehicle.kinematics": [[9, 2, 1, "", "Vehicle"]], "highway_env.vehicle.kinematics.Vehicle": [[9, 3, 1, "", "DEFAULT_INITIAL_SPEEDS"], [9, 3, 1, "", "HISTORY_SIZE"], [9, 3, 1, "", "LENGTH"], [9, 3, 1, "", "MAX_SPEED"], [9, 3, 1, "", "MIN_SPEED"], [9, 3, 1, "", "WIDTH"], [9, 4, 1, "", "act"], [9, 4, 1, "", "create_from"], [9, 4, 1, "", "create_random"], [9, 4, 1, "", "predict_trajectory"], [9, 4, 1, "", "step"]]}, "objtypes": {"0": "py:module", "1": "py:function", "2": "py:class", "3": "py:attribute", "4": "py:method", "5": "py:property"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "function", "Python function"], "2": ["py", "class", "Python class"], "3": ["py", "attribute", "Python attribute"], "4": ["py", "method", "Python method"], "5": ["py", "property", "Python property"]}, "titleterms": {"404": 0, "page": 0, "Not": 0, "found": 0, "action": [1, 22], "continu": 1, "discret": 1, "meta": 1, "manual": 1, "control": [1, 8, 22], "api": [1, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 21, 23], "bibliographi": 2, "dynam": 3, "road": [3, 5, 6], "vehicl": [3, 21, 22, 23], "lane": 4, "regul": 5, "behavior": 7, "longitudin": [7, 8], "later": [7, 8], "posit": 8, "head": 8, "kinemat": [9, 17, 23], "highwai": [10, 17, 19], "usag": [10, 12, 13, 14, 15, 16], "default": [10, 12, 13, 14, 15, 16], "configur": [10, 12, 13, 14, 15, 16, 21, 23, 24], "faster": 10, "variant": 10, "The": [11, 22], "environ": [11, 17, 21, 24, 25], "intersect": 12, "merg": 13, "park": 14, "racetrack": 15, "roundabout": 16, "frequent": 17, "ask": 17, "question": 17, "when": 17, "i": [17, 23], "try": 17, "make": [17, 21, 24], "an": [17, 24], "get": [17, 24], "error": 17, "gymnasium": 17, "namenotfound": 17, "doesn": 17, "t": 17, "exist": 17, "train": [17, 24], "agent": [17, 22, 24], "us": 17, "observ": [17, 22, 23], "mlp": 17, "model": 17, "result": 17, "polici": 17, "optim": 17, "why": 17, "my": 17, "video": 17, "ar": 17, "too": 17, "fast": 17, "have": 17, "low": 17, "framer": 17, "graphic": 18, "world": 18, "surfac": 18, "scene": [18, 21], "welcom": 19, "env": 19, "": 19, "document": 19, "how": 19, "cite": 19, "thi": 19, "work": 19, "instal": 20, "prerequisit": 20, "ubuntu": 20, "window": 20, "10": 20, "stabl": 20, "releas": 20, "develop": 20, "version": 20, "your": 21, "own": 21, "set": [21, 22], "up": [21, 22], "file": 21, "creat": 21, "regist": 21, "profit": 21, "multi": 22, "increas": 22, "number": 22, "chang": 22, "space": 22, "wrap": 22, "exampl": [23, 24], "grayscal": 23, "imag": 23, "illustr": 23, "stack": 23, "mechan": 23, "occup": 23, "grid": 23, "presenc": 23, "featur": 23, "one": 23, "close": 23, "north": 23, "farther": 23, "east": 23, "v_x": 23, "drive": 23, "same": 23, "speed": 23, "ego": 23, "bit": 23, "slower": 23, "time": 23, "collis": 23, "lidar": 23, "start": 24, "all": 24, "googl": 24, "colab": 24, "reward": 25, "most": 25, "goal": 25, "user": 26, "guid": 26}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.viewcode": 1, "sphinxcontrib.bibtex": 9, "sphinx": 60}, "alltitles": {"404": [[0, "id1"]], "Page Not Found": [[0, "page-not-found"]], "Actions": [[1, "actions"]], "Continuous Actions": [[1, "continuous-actions"]], "Discrete Actions": [[1, "discrete-actions"]], "Discrete Meta-Actions": [[1, "discrete-meta-actions"]], "Manual control": [[1, "manual-control"]], "API": [[1, "module-highway_env.envs.common.action"], [4, "module-highway_env.road.lane"], [5, "module-highway_env.road.regulation"], [6, "module-highway_env.road.road"], [7, "module-highway_env.vehicle.behavior"], [8, "module-highway_env.vehicle.controller"], [9, "module-highway_env.vehicle.kinematics"], [10, "api"], [12, "api"], [13, "api"], [14, "api"], [15, "api"], [16, "api"], [18, "module-highway_env.envs.common.graphics"], [21, "module-highway_env.__init__"], [23, "module-highway_env.envs.common.observation"]], "Bibliography": [[2, "bibliography"]], "Dynamics": [[3, "dynamics"]], "Roads": [[3, "roads"]], "Vehicles": [[3, "vehicles"]], "Lane": [[4, "lane"]], "Road regulation": [[5, "road-regulation"]], "Road": [[6, "road"]], "Behavior": [[7, "behavior"]], "Longitudinal Behavior": [[7, "longitudinal-behavior"]], "Lateral Behavior": [[7, "lateral-behavior"]], "Control": [[8, "control"]], "Longitudinal controller": [[8, "longitudinal-controller"]], "Lateral controller": [[8, "lateral-controller"]], "Position control": [[8, "position-control"]], "Heading control": [[8, "heading-control"]], "Kinematics": [[9, "kinematics"], [23, "kinematics"]], "Highway": [[10, "highway"]], "Usage": [[10, "usage"], [12, "usage"], [13, "usage"], [14, "usage"], [15, "usage"], [16, "usage"]], "Default configuration": [[10, "default-configuration"], [12, "default-configuration"], [13, "default-configuration"], [14, "default-configuration"], [15, "default-configuration"], [16, "default-configuration"]], "Faster variant": [[10, "faster-variant"]], "The environments": [[11, "the-environments"]], "Intersection": [[12, "intersection"]], "Merge": [[13, "merge"]], "Parking": [[14, "parking"]], "Racetrack": [[15, "racetrack"]], "Roundabout": [[16, "roundabout"]], "Frequently Asked Questions": [[17, "frequently-asked-questions"]], "When I try to make an environment, I get an error gymnasium.error.NameNotFound: Environment highway doesn't exist.": [[17, "when-i-try-to-make-an-environment-i-get-an-error-gymnasium-error-namenotfound-environment-highway-doesn-t-exist"]], "I try to train an agent using the Kinematics Observation and an MLP model, but the resulting policy is not optimal. Why?": [[17, "i-try-to-train-an-agent-using-the-kinematics-observation-and-an-mlp-model-but-the-resulting-policy-is-not-optimal-why"]], "My videos are too fast / have a low framerate.": [[17, "my-videos-are-too-fast-have-a-low-framerate"]], "Graphics": [[18, "id1"]], "World surface": [[18, "world-surface"]], "Scene graphics": [[18, "scene-graphics"]], "Welcome to highway-env\u2019s documentation!": [[19, "welcome-to-highway-env-s-documentation"]], "How to cite this work?": [[19, "how-to-cite-this-work"]], "Installation": [[20, "installation"]], "Prerequisites": [[20, "prerequisites"]], "Ubuntu": [[20, "ubuntu"]], "Windows 10": [[20, "windows-10"]], "Stable release": [[20, "stable-release"]], "Development version": [[20, "development-version"]], "Make your own environment": [[21, "make-your-own-environment"]], "Set up files": [[21, "set-up-files"]], "Create the scene": [[21, "create-the-scene"]], "Create the vehicles": [[21, "create-the-vehicles"]], "Make the environment configurable": [[21, "make-the-environment-configurable"]], "Register the environment": [[21, "register-the-environment"]], "Profit": [[21, "profit"]], "The Multi-Agent setting": [[22, "the-multi-agent-setting"]], "Increase the number of controlled vehicles": [[22, "increase-the-number-of-controlled-vehicles"]], "Change the action space": [[22, "change-the-action-space"]], "Change the observation space": [[22, "change-the-observation-space"]], "Wrapping it up": [[22, "wrapping-it-up"]], "Observations": [[23, "id1"]], "Example configuration": [[23, "example-configuration"], [23, "grayscale-example-configuration"], [23, "id4"], [23, "id5"], [23, "id6"]], "Grayscale Image": [[23, "grayscale-image"]], "Illustration of the stack mechanism": [[23, "illustration-of-the-stack-mechanism"]], "Occupancy grid": [[23, "occupancy-grid"]], "presence feature: one vehicle is close to the north, and one is farther to the east.": [[23, "id7"]], "v_x feature: the north vehicle drives at the same speed as the ego-vehicle, and the east vehicle a bit slower": [[23, "id8"]], "Time to collision": [[23, "time-to-collision"]], "Lidar": [[23, "lidar"]], "the Lidar observation": [[23, "id9"]], "Getting Started": [[24, "getting-started"]], "Making an environment": [[24, "making-an-environment"]], "All the environments": [[24, "all-the-environments"]], "Configuring an environment": [[24, "configuring-an-environment"]], "Training an agent": [[24, "training-an-agent"]], "Examples on Google Colab": [[24, "examples-on-google-colab"]], "Rewards": [[25, "rewards"]], "Most environments": [[25, "most-environments"]], "Goal environments": [[25, "goal-environments"]], "User Guide": [[26, "user-guide"]]}, "indexentries": {"acceleration_range (highway_env.envs.common.action.continuousaction attribute)": [[1, "highway_env.envs.common.action.ContinuousAction.ACCELERATION_RANGE"]], "actions_all (highway_env.envs.common.action.discretemetaaction attribute)": [[1, "highway_env.envs.common.action.DiscreteMetaAction.ACTIONS_ALL"]], "actions_lat (highway_env.envs.common.action.discretemetaaction attribute)": [[1, "highway_env.envs.common.action.DiscreteMetaAction.ACTIONS_LAT"]], "actions_longi (highway_env.envs.common.action.discretemetaaction attribute)": [[1, "highway_env.envs.common.action.DiscreteMetaAction.ACTIONS_LONGI"]], "actiontype (class in highway_env.envs.common.action)": [[1, "highway_env.envs.common.action.ActionType"]], "continuousaction (class in highway_env.envs.common.action)": [[1, "highway_env.envs.common.action.ContinuousAction"]], "discreteaction (class in highway_env.envs.common.action)": [[1, "highway_env.envs.common.action.DiscreteAction"]], "discretemetaaction (class in highway_env.envs.common.action)": [[1, "highway_env.envs.common.action.DiscreteMetaAction"]], "multiagentaction (class in highway_env.envs.common.action)": [[1, "highway_env.envs.common.action.MultiAgentAction"]], "steering_range (highway_env.envs.common.action.continuousaction attribute)": [[1, "highway_env.envs.common.action.ContinuousAction.STEERING_RANGE"]], "act() (highway_env.envs.common.action.actiontype method)": [[1, "highway_env.envs.common.action.ActionType.act"]], "act() (highway_env.envs.common.action.continuousaction method)": [[1, "highway_env.envs.common.action.ContinuousAction.act"]], "act() (highway_env.envs.common.action.discreteaction method)": [[1, "highway_env.envs.common.action.DiscreteAction.act"]], "act() (highway_env.envs.common.action.discretemetaaction method)": [[1, "highway_env.envs.common.action.DiscreteMetaAction.act"]], "act() (highway_env.envs.common.action.multiagentaction method)": [[1, "highway_env.envs.common.action.MultiAgentAction.act"]], "controlled_vehicle (highway_env.envs.common.action.actiontype property)": [[1, "highway_env.envs.common.action.ActionType.controlled_vehicle"]], "get_available_actions() (highway_env.envs.common.action.actiontype method)": [[1, "highway_env.envs.common.action.ActionType.get_available_actions"]], "get_available_actions() (highway_env.envs.common.action.discretemetaaction method)": [[1, "highway_env.envs.common.action.DiscreteMetaAction.get_available_actions"]], "get_available_actions() (highway_env.envs.common.action.multiagentaction method)": [[1, "highway_env.envs.common.action.MultiAgentAction.get_available_actions"]], "highway_env.envs.common.action": [[1, "module-highway_env.envs.common.action"]], "module": [[1, "module-highway_env.envs.common.action"], [4, "module-highway_env.road.lane"], [5, "module-highway_env.road.regulation"], [6, "module-highway_env.road.road"], [7, "module-highway_env.vehicle.behavior"], [8, "module-highway_env.vehicle.controller"], [9, "module-highway_env.vehicle.kinematics"], [18, "module-highway_env.envs.common.graphics"], [18, "module-highway_env.road.graphics"], [18, "module-highway_env.vehicle.graphics"], [21, "module-highway_env.__init__"], [21, "module-highway_env.envs.common.abstract"], [23, "module-highway_env.envs.common.observation"]], "space() (highway_env.envs.common.action.actiontype method)": [[1, "highway_env.envs.common.action.ActionType.space"]], "space() (highway_env.envs.common.action.continuousaction method)": [[1, "highway_env.envs.common.action.ContinuousAction.space"]], "space() (highway_env.envs.common.action.discreteaction method)": [[1, "highway_env.envs.common.action.DiscreteAction.space"]], "space() (highway_env.envs.common.action.discretemetaaction method)": [[1, "highway_env.envs.common.action.DiscreteMetaAction.space"]], "space() (highway_env.envs.common.action.multiagentaction method)": [[1, "highway_env.envs.common.action.MultiAgentAction.space"]], "vehicle_class (highway_env.envs.common.action.actiontype property)": [[1, "highway_env.envs.common.action.ActionType.vehicle_class"]], "vehicle_class (highway_env.envs.common.action.continuousaction property)": [[1, "highway_env.envs.common.action.ContinuousAction.vehicle_class"]], "vehicle_class (highway_env.envs.common.action.discretemetaaction property)": [[1, "highway_env.envs.common.action.DiscreteMetaAction.vehicle_class"]], "vehicle_class (highway_env.envs.common.action.multiagentaction property)": [[1, "highway_env.envs.common.action.MultiAgentAction.vehicle_class"]], "abstractlane (class in highway_env.road.lane)": [[4, "highway_env.road.lane.AbstractLane"]], "circularlane (class in highway_env.road.lane)": [[4, "highway_env.road.lane.CircularLane"]], "linetype (class in highway_env.road.lane)": [[4, "highway_env.road.lane.LineType"]], "polylane (class in highway_env.road.lane)": [[4, "highway_env.road.lane.PolyLane"]], "polylanefixedwidth (class in highway_env.road.lane)": [[4, "highway_env.road.lane.PolyLaneFixedWidth"]], "sinelane (class in highway_env.road.lane)": [[4, "highway_env.road.lane.SineLane"]], "straightlane (class in highway_env.road.lane)": [[4, "highway_env.road.lane.StraightLane"]], "distance() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.distance"]], "distance_with_heading() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.distance_with_heading"]], "from_config() (highway_env.road.lane.abstractlane class method)": [[4, "highway_env.road.lane.AbstractLane.from_config"]], "from_config() (highway_env.road.lane.circularlane class method)": [[4, "highway_env.road.lane.CircularLane.from_config"]], "from_config() (highway_env.road.lane.polylanefixedwidth class method)": [[4, "highway_env.road.lane.PolyLaneFixedWidth.from_config"]], "from_config() (highway_env.road.lane.sinelane class method)": [[4, "highway_env.road.lane.SineLane.from_config"]], "from_config() (highway_env.road.lane.straightlane class method)": [[4, "highway_env.road.lane.StraightLane.from_config"]], "heading_at() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.heading_at"]], "heading_at() (highway_env.road.lane.circularlane method)": [[4, "highway_env.road.lane.CircularLane.heading_at"]], "heading_at() (highway_env.road.lane.polylanefixedwidth method)": [[4, "highway_env.road.lane.PolyLaneFixedWidth.heading_at"]], "heading_at() (highway_env.road.lane.sinelane method)": [[4, "highway_env.road.lane.SineLane.heading_at"]], "heading_at() (highway_env.road.lane.straightlane method)": [[4, "highway_env.road.lane.StraightLane.heading_at"]], "highway_env.road.lane": [[4, "module-highway_env.road.lane"]], "is_reachable_from() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.is_reachable_from"]], "local_angle() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.local_angle"]], "local_coordinates() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.local_coordinates"]], "local_coordinates() (highway_env.road.lane.circularlane method)": [[4, "highway_env.road.lane.CircularLane.local_coordinates"]], "local_coordinates() (highway_env.road.lane.polylanefixedwidth method)": [[4, "highway_env.road.lane.PolyLaneFixedWidth.local_coordinates"]], "local_coordinates() (highway_env.road.lane.sinelane method)": [[4, "highway_env.road.lane.SineLane.local_coordinates"]], "local_coordinates() (highway_env.road.lane.straightlane method)": [[4, "highway_env.road.lane.StraightLane.local_coordinates"]], "metaclass__ (highway_env.road.lane.abstractlane attribute)": [[4, "highway_env.road.lane.AbstractLane.metaclass__"]], "on_lane() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.on_lane"]], "position() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.position"]], "position() (highway_env.road.lane.circularlane method)": [[4, "highway_env.road.lane.CircularLane.position"]], "position() (highway_env.road.lane.polylanefixedwidth method)": [[4, "highway_env.road.lane.PolyLaneFixedWidth.position"]], "position() (highway_env.road.lane.sinelane method)": [[4, "highway_env.road.lane.SineLane.position"]], "position() (highway_env.road.lane.straightlane method)": [[4, "highway_env.road.lane.StraightLane.position"]], "to_config() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.to_config"]], "to_config() (highway_env.road.lane.circularlane method)": [[4, "highway_env.road.lane.CircularLane.to_config"]], "to_config() (highway_env.road.lane.polylane method)": [[4, "highway_env.road.lane.PolyLane.to_config"]], "to_config() (highway_env.road.lane.polylanefixedwidth method)": [[4, "highway_env.road.lane.PolyLaneFixedWidth.to_config"]], "to_config() (highway_env.road.lane.sinelane method)": [[4, "highway_env.road.lane.SineLane.to_config"]], "to_config() (highway_env.road.lane.straightlane method)": [[4, "highway_env.road.lane.StraightLane.to_config"]], "width_at() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.width_at"]], "width_at() (highway_env.road.lane.circularlane method)": [[4, "highway_env.road.lane.CircularLane.width_at"]], "width_at() (highway_env.road.lane.polylane method)": [[4, "highway_env.road.lane.PolyLane.width_at"]], "width_at() (highway_env.road.lane.polylanefixedwidth method)": [[4, "highway_env.road.lane.PolyLaneFixedWidth.width_at"]], "width_at() (highway_env.road.lane.straightlane method)": [[4, "highway_env.road.lane.StraightLane.width_at"]], "regulatedroad (class in highway_env.road.regulation)": [[5, "highway_env.road.regulation.RegulatedRoad"]], "enforce_road_rules() (highway_env.road.regulation.regulatedroad method)": [[5, "highway_env.road.regulation.RegulatedRoad.enforce_road_rules"]], "highway_env.road.regulation": [[5, "module-highway_env.road.regulation"]], "respect_priorities() (highway_env.road.regulation.regulatedroad static method)": [[5, "highway_env.road.regulation.RegulatedRoad.respect_priorities"]], "step() (highway_env.road.regulation.regulatedroad method)": [[5, "highway_env.road.regulation.RegulatedRoad.step"]], "road (class in highway_env.road.road)": [[6, "highway_env.road.road.Road"]], "act() (highway_env.road.road.road method)": [[6, "highway_env.road.road.Road.act"]], "highway_env.road.road": [[6, "module-highway_env.road.road"]], "neighbour_vehicles() (highway_env.road.road.road method)": [[6, "highway_env.road.road.Road.neighbour_vehicles"]], "step() (highway_env.road.road.road method)": [[6, "highway_env.road.road.Road.step"]], "acc_max (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.ACC_MAX"]], "aggressivevehicle (class in highway_env.vehicle.behavior)": [[7, "highway_env.vehicle.behavior.AggressiveVehicle"]], "comfort_acc_max (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.COMFORT_ACC_MAX"]], "comfort_acc_min (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.COMFORT_ACC_MIN"]], "delta (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.DELTA"]], "delta_range (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.DELTA_RANGE"]], "distance_wanted (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.DISTANCE_WANTED"]], "defensivevehicle (class in highway_env.vehicle.behavior)": [[7, "highway_env.vehicle.behavior.DefensiveVehicle"]], "idmvehicle (class in highway_env.vehicle.behavior)": [[7, "highway_env.vehicle.behavior.IDMVehicle"]], "linearvehicle (class in highway_env.vehicle.behavior)": [[7, "highway_env.vehicle.behavior.LinearVehicle"]], "time_wanted (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.TIME_WANTED"]], "time_wanted (highway_env.vehicle.behavior.linearvehicle attribute)": [[7, "highway_env.vehicle.behavior.LinearVehicle.TIME_WANTED"]], "acceleration() (highway_env.vehicle.behavior.idmvehicle method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.acceleration"]], "acceleration() (highway_env.vehicle.behavior.linearvehicle method)": [[7, "highway_env.vehicle.behavior.LinearVehicle.acceleration"]], "act() (highway_env.vehicle.behavior.idmvehicle method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.act"]], "act() (highway_env.vehicle.behavior.linearvehicle method)": [[7, "highway_env.vehicle.behavior.LinearVehicle.act"]], "change_lane_policy() (highway_env.vehicle.behavior.idmvehicle method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.change_lane_policy"]], "collect_data() (highway_env.vehicle.behavior.linearvehicle method)": [[7, "highway_env.vehicle.behavior.LinearVehicle.collect_data"]], "create_from() (highway_env.vehicle.behavior.idmvehicle class method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.create_from"]], "desired_gap() (highway_env.vehicle.behavior.idmvehicle method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.desired_gap"]], "highway_env.vehicle.behavior": [[7, "module-highway_env.vehicle.behavior"]], "mobil() (highway_env.vehicle.behavior.idmvehicle method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.mobil"]], "recover_from_stop() (highway_env.vehicle.behavior.idmvehicle method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.recover_from_stop"]], "steering_control() (highway_env.vehicle.behavior.linearvehicle method)": [[7, "highway_env.vehicle.behavior.LinearVehicle.steering_control"]], "steering_features() (highway_env.vehicle.behavior.linearvehicle method)": [[7, "highway_env.vehicle.behavior.LinearVehicle.steering_features"]], "step() (highway_env.vehicle.behavior.idmvehicle method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.step"]], "target_speed (highway_env.vehicle.behavior.aggressivevehicle attribute)": [[7, "highway_env.vehicle.behavior.AggressiveVehicle.target_speed"]], "target_speed (highway_env.vehicle.behavior.defensivevehicle attribute)": [[7, "highway_env.vehicle.behavior.DefensiveVehicle.target_speed"]], "target_speed (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.target_speed"]], "target_speed (highway_env.vehicle.behavior.linearvehicle attribute)": [[7, "highway_env.vehicle.behavior.LinearVehicle.target_speed"]], "controlledvehicle (class in highway_env.vehicle.controller)": [[8, "highway_env.vehicle.controller.ControlledVehicle"]], "mdpvehicle (class in highway_env.vehicle.controller)": [[8, "highway_env.vehicle.controller.MDPVehicle"]], "act() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.act"]], "act() (highway_env.vehicle.controller.mdpvehicle method)": [[8, "highway_env.vehicle.controller.MDPVehicle.act"]], "create_from() (highway_env.vehicle.controller.controlledvehicle class method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.create_from"]], "follow_road() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.follow_road"]], "get_routes_at_intersection() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.get_routes_at_intersection"]], "highway_env.vehicle.controller": [[8, "module-highway_env.vehicle.controller"]], "index_to_speed() (highway_env.vehicle.controller.mdpvehicle method)": [[8, "highway_env.vehicle.controller.MDPVehicle.index_to_speed"]], "plan_route_to() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.plan_route_to"]], "predict_trajectory() (highway_env.vehicle.controller.mdpvehicle method)": [[8, "highway_env.vehicle.controller.MDPVehicle.predict_trajectory"]], "predict_trajectory_constant_speed() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.predict_trajectory_constant_speed"]], "set_route_at_intersection() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.set_route_at_intersection"]], "speed_control() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.speed_control"]], "speed_to_index() (highway_env.vehicle.controller.mdpvehicle method)": [[8, "highway_env.vehicle.controller.MDPVehicle.speed_to_index"]], "speed_to_index_default() (highway_env.vehicle.controller.mdpvehicle class method)": [[8, "highway_env.vehicle.controller.MDPVehicle.speed_to_index_default"]], "steering_control() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.steering_control"]], "target_speed (highway_env.vehicle.controller.controlledvehicle attribute)": [[8, "highway_env.vehicle.controller.ControlledVehicle.target_speed"]], "target_speed (highway_env.vehicle.controller.mdpvehicle attribute)": [[8, "highway_env.vehicle.controller.MDPVehicle.target_speed"]], "default_initial_speeds (highway_env.vehicle.kinematics.vehicle attribute)": [[9, "highway_env.vehicle.kinematics.Vehicle.DEFAULT_INITIAL_SPEEDS"]], "history_size (highway_env.vehicle.kinematics.vehicle attribute)": [[9, "highway_env.vehicle.kinematics.Vehicle.HISTORY_SIZE"]], "length (highway_env.vehicle.kinematics.vehicle attribute)": [[9, "highway_env.vehicle.kinematics.Vehicle.LENGTH"]], "max_speed (highway_env.vehicle.kinematics.vehicle attribute)": [[9, "highway_env.vehicle.kinematics.Vehicle.MAX_SPEED"]], "min_speed (highway_env.vehicle.kinematics.vehicle attribute)": [[9, "highway_env.vehicle.kinematics.Vehicle.MIN_SPEED"]], "vehicle (class in highway_env.vehicle.kinematics)": [[9, "highway_env.vehicle.kinematics.Vehicle"]], "width (highway_env.vehicle.kinematics.vehicle attribute)": [[9, "highway_env.vehicle.kinematics.Vehicle.WIDTH"]], "act() (highway_env.vehicle.kinematics.vehicle method)": [[9, "highway_env.vehicle.kinematics.Vehicle.act"]], "create_from() (highway_env.vehicle.kinematics.vehicle class method)": [[9, "highway_env.vehicle.kinematics.Vehicle.create_from"]], "create_random() (highway_env.vehicle.kinematics.vehicle class method)": [[9, "highway_env.vehicle.kinematics.Vehicle.create_random"]], "highway_env.vehicle.kinematics": [[9, "module-highway_env.vehicle.kinematics"]], "predict_trajectory() (highway_env.vehicle.kinematics.vehicle method)": [[9, "highway_env.vehicle.kinematics.Vehicle.predict_trajectory"]], "step() (highway_env.vehicle.kinematics.vehicle method)": [[9, "highway_env.vehicle.kinematics.Vehicle.step"]], "highwayenv (class in highway_env.envs.highway_env)": [[10, "highway_env.envs.highway_env.HighwayEnv"]], "default_config() (highway_env.envs.highway_env.highwayenv class method)": [[10, "highway_env.envs.highway_env.HighwayEnv.default_config"]], "intersectionenv (class in highway_env.envs.intersection_env)": [[12, "highway_env.envs.intersection_env.IntersectionEnv"]], "default_config() (highway_env.envs.intersection_env.intersectionenv class method)": [[12, "highway_env.envs.intersection_env.IntersectionEnv.default_config"]], "step() (highway_env.envs.intersection_env.intersectionenv method)": [[12, "highway_env.envs.intersection_env.IntersectionEnv.step"]], "mergeenv (class in highway_env.envs.merge_env)": [[13, "highway_env.envs.merge_env.MergeEnv"]], "default_config() (highway_env.envs.merge_env.mergeenv class method)": [[13, "highway_env.envs.merge_env.MergeEnv.default_config"]], "parkingenv (class in highway_env.envs.parking_env)": [[14, "highway_env.envs.parking_env.ParkingEnv"]], "compute_reward() (highway_env.envs.parking_env.parkingenv method)": [[14, "highway_env.envs.parking_env.ParkingEnv.compute_reward"]], "default_config() (highway_env.envs.parking_env.parkingenv class method)": [[14, "highway_env.envs.parking_env.ParkingEnv.default_config"]], "define_spaces() (highway_env.envs.parking_env.parkingenv method)": [[14, "highway_env.envs.parking_env.ParkingEnv.define_spaces"]], "racetrackenv (class in highway_env.envs.racetrack_env)": [[15, "highway_env.envs.racetrack_env.RacetrackEnv"]], "default_config() (highway_env.envs.racetrack_env.racetrackenv class method)": [[15, "highway_env.envs.racetrack_env.RacetrackEnv.default_config"]], "roundaboutenv (class in highway_env.envs.roundabout_env)": [[16, "highway_env.envs.roundabout_env.RoundaboutEnv"]], "default_config() (highway_env.envs.roundabout_env.roundaboutenv class method)": [[16, "highway_env.envs.roundabout_env.RoundaboutEnv.default_config"]], "envviewer (class in highway_env.envs.common.graphics)": [[18, "highway_env.envs.common.graphics.EnvViewer"]], "lanegraphics (class in highway_env.road.graphics)": [[18, "highway_env.road.graphics.LaneGraphics"]], "roadgraphics (class in highway_env.road.graphics)": [[18, "highway_env.road.graphics.RoadGraphics"]], "roadobjectgraphics (class in highway_env.road.graphics)": [[18, "highway_env.road.graphics.RoadObjectGraphics"]], "stripe_length (highway_env.road.graphics.lanegraphics attribute)": [[18, "highway_env.road.graphics.LaneGraphics.STRIPE_LENGTH"]], "stripe_spacing (highway_env.road.graphics.lanegraphics attribute)": [[18, "highway_env.road.graphics.LaneGraphics.STRIPE_SPACING"]], "stripe_width (highway_env.road.graphics.lanegraphics attribute)": [[18, "highway_env.road.graphics.LaneGraphics.STRIPE_WIDTH"]], "worldsurface (class in highway_env.road.graphics)": [[18, "highway_env.road.graphics.WorldSurface"]], "blit_rotate() (highway_env.road.graphics.roadobjectgraphics static method)": [[18, "highway_env.road.graphics.RoadObjectGraphics.blit_rotate"]], "close() (highway_env.envs.common.graphics.envviewer method)": [[18, "highway_env.envs.common.graphics.EnvViewer.close"]], "continuous_curve() (highway_env.road.graphics.lanegraphics class method)": [[18, "highway_env.road.graphics.LaneGraphics.continuous_curve"]], "continuous_line() (highway_env.road.graphics.lanegraphics class method)": [[18, "highway_env.road.graphics.LaneGraphics.continuous_line"]], "display() (highway_env.envs.common.graphics.envviewer method)": [[18, "highway_env.envs.common.graphics.EnvViewer.display"]], "display() (highway_env.road.graphics.lanegraphics class method)": [[18, "highway_env.road.graphics.LaneGraphics.display"]], "display() (highway_env.road.graphics.roadgraphics static method)": [[18, "highway_env.road.graphics.RoadGraphics.display"]], "display() (highway_env.road.graphics.roadobjectgraphics class method)": [[18, "highway_env.road.graphics.RoadObjectGraphics.display"]], "display_road_objects() (highway_env.road.graphics.roadgraphics static method)": [[18, "highway_env.road.graphics.RoadGraphics.display_road_objects"]], "display_traffic() (highway_env.road.graphics.roadgraphics static method)": [[18, "highway_env.road.graphics.RoadGraphics.display_traffic"]], "draw_stripes() (highway_env.road.graphics.lanegraphics class method)": [[18, "highway_env.road.graphics.LaneGraphics.draw_stripes"]], "get_image() (highway_env.envs.common.graphics.envviewer method)": [[18, "highway_env.envs.common.graphics.EnvViewer.get_image"]], "handle_event() (highway_env.road.graphics.worldsurface method)": [[18, "highway_env.road.graphics.WorldSurface.handle_event"]], "handle_events() (highway_env.envs.common.graphics.envviewer method)": [[18, "highway_env.envs.common.graphics.EnvViewer.handle_events"]], "highway_env.envs.common.graphics": [[18, "module-highway_env.envs.common.graphics"]], "highway_env.road.graphics": [[18, "module-highway_env.road.graphics"]], "highway_env.vehicle.graphics": [[18, "module-highway_env.vehicle.graphics"]], "is_visible() (highway_env.road.graphics.worldsurface method)": [[18, "highway_env.road.graphics.WorldSurface.is_visible"]], "move_display_window_to() (highway_env.road.graphics.worldsurface method)": [[18, "highway_env.road.graphics.WorldSurface.move_display_window_to"]], "pix() (highway_env.road.graphics.worldsurface method)": [[18, "highway_env.road.graphics.WorldSurface.pix"]], "pos2pix() (highway_env.road.graphics.worldsurface method)": [[18, "highway_env.road.graphics.WorldSurface.pos2pix"]], "set_agent_action_sequence() (highway_env.envs.common.graphics.envviewer method)": [[18, "highway_env.envs.common.graphics.EnvViewer.set_agent_action_sequence"]], "set_agent_display() (highway_env.envs.common.graphics.envviewer method)": [[18, "highway_env.envs.common.graphics.EnvViewer.set_agent_display"]], "striped_line() (highway_env.road.graphics.lanegraphics class method)": [[18, "highway_env.road.graphics.LaneGraphics.striped_line"]], "vec2pix() (highway_env.road.graphics.worldsurface method)": [[18, "highway_env.road.graphics.WorldSurface.vec2pix"]], "window_position() (highway_env.envs.common.graphics.envviewer method)": [[18, "highway_env.envs.common.graphics.EnvViewer.window_position"]], "abstractenv (class in highway_env.envs.common.abstract)": [[21, "highway_env.envs.common.abstract.AbstractEnv"]], "multiagentwrapper (class in highway_env.envs.common.abstract)": [[21, "highway_env.envs.common.abstract.MultiAgentWrapper"]], "perception_distance (highway_env.envs.common.abstract.abstractenv attribute)": [[21, "highway_env.envs.common.abstract.AbstractEnv.PERCEPTION_DISTANCE"]], "_automatic_rendering() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._automatic_rendering"]], "_info() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._info"]], "_is_terminated() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._is_terminated"]], "_is_truncated() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._is_truncated"]], "_reset() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._reset"]], "_reward() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._reward"]], "_rewards() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._rewards"]], "_simulate() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._simulate"]], "change_vehicles() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.change_vehicles"]], "close() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.close"]], "default_config() (highway_env.envs.common.abstract.abstractenv class method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.default_config"]], "define_spaces() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.define_spaces"]], "highway_env.__init__": [[21, "module-highway_env.__init__"]], "highway_env.envs.common.abstract": [[21, "module-highway_env.envs.common.abstract"]], "register_highway_envs() (in module highway_env.__init__)": [[21, "highway_env.__init__.register_highway_envs"]], "render() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.render"]], "reset() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.reset"]], "simplify() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.simplify"]], "step() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.step"]], "step() (highway_env.envs.common.abstract.multiagentwrapper method)": [[21, "highway_env.envs.common.abstract.MultiAgentWrapper.step"]], "vehicle (highway_env.envs.common.abstract.abstractenv property)": [[21, "highway_env.envs.common.abstract.AbstractEnv.vehicle"]], "exitobservation (class in highway_env.envs.common.observation)": [[23, "highway_env.envs.common.observation.ExitObservation"]], "grayscaleobservation (class in highway_env.envs.common.observation)": [[23, "highway_env.envs.common.observation.GrayscaleObservation"]], "kinematicobservation (class in highway_env.envs.common.observation)": [[23, "highway_env.envs.common.observation.KinematicObservation"]], "kinematicsgoalobservation (class in highway_env.envs.common.observation)": [[23, "highway_env.envs.common.observation.KinematicsGoalObservation"]], "occupancygridobservation (class in highway_env.envs.common.observation)": [[23, "highway_env.envs.common.observation.OccupancyGridObservation"]], "fill_road_layer_by_cell() (highway_env.envs.common.observation.occupancygridobservation method)": [[23, "highway_env.envs.common.observation.OccupancyGridObservation.fill_road_layer_by_cell"]], "fill_road_layer_by_lanes() (highway_env.envs.common.observation.occupancygridobservation method)": [[23, "highway_env.envs.common.observation.OccupancyGridObservation.fill_road_layer_by_lanes"]], "highway_env.envs.common.observation": [[23, "module-highway_env.envs.common.observation"]], "normalize() (highway_env.envs.common.observation.occupancygridobservation method)": [[23, "highway_env.envs.common.observation.OccupancyGridObservation.normalize"]], "normalize_obs() (highway_env.envs.common.observation.kinematicobservation method)": [[23, "highway_env.envs.common.observation.KinematicObservation.normalize_obs"]], "observe() (highway_env.envs.common.observation.exitobservation method)": [[23, "highway_env.envs.common.observation.ExitObservation.observe"]], "observe() (highway_env.envs.common.observation.grayscaleobservation method)": [[23, "highway_env.envs.common.observation.GrayscaleObservation.observe"]], "observe() (highway_env.envs.common.observation.kinematicobservation method)": [[23, "highway_env.envs.common.observation.KinematicObservation.observe"]], "observe() (highway_env.envs.common.observation.kinematicsgoalobservation method)": [[23, "highway_env.envs.common.observation.KinematicsGoalObservation.observe"]], "observe() (highway_env.envs.common.observation.occupancygridobservation method)": [[23, "highway_env.envs.common.observation.OccupancyGridObservation.observe"]], "pos_to_index() (highway_env.envs.common.observation.occupancygridobservation method)": [[23, "highway_env.envs.common.observation.OccupancyGridObservation.pos_to_index"]], "space() (highway_env.envs.common.observation.grayscaleobservation method)": [[23, "highway_env.envs.common.observation.GrayscaleObservation.space"]], "space() (highway_env.envs.common.observation.kinematicobservation method)": [[23, "highway_env.envs.common.observation.KinematicObservation.space"]], "space() (highway_env.envs.common.observation.kinematicsgoalobservation method)": [[23, "highway_env.envs.common.observation.KinematicsGoalObservation.space"]], "space() (highway_env.envs.common.observation.occupancygridobservation method)": [[23, "highway_env.envs.common.observation.OccupancyGridObservation.space"]]}})
\ No newline at end of file
+Search.setIndex({"docnames": ["404", "actions/index", "bibliography/index", "dynamics/index", "dynamics/road/lane", "dynamics/road/regulation", "dynamics/road/road", "dynamics/vehicle/behavior", "dynamics/vehicle/controller", "dynamics/vehicle/kinematics", "environments/highway", "environments/index", "environments/intersection", "environments/merge", "environments/parking", "environments/racetrack", "environments/roundabout", "faq", "graphics/index", "index", "installation", "make_your_own", "multi_agent", "observations/index", "quickstart", "rewards/index", "user_guide"], "filenames": ["404.md", "actions/index.md", "bibliography/index.md", "dynamics/index.md", "dynamics/road/lane.md", "dynamics/road/regulation.md", "dynamics/road/road.md", "dynamics/vehicle/behavior.md", "dynamics/vehicle/controller.md", "dynamics/vehicle/kinematics.md", "environments/highway.md", "environments/index.md", "environments/intersection.md", "environments/merge.md", "environments/parking.md", "environments/racetrack.md", "environments/roundabout.md", "faq.md", "graphics/index.md", "index.md", "installation.md", "make_your_own.md", "multi_agent.md", "observations/index.md", "quickstart.md", "rewards/index.md", "user_guide.md"], "titles": ["404", "Actions", "Bibliography", "Dynamics", "Lane", "Road regulation", "Road", "Behavior", "Control", "Kinematics", "Highway", "The environments", "Intersection", "Merge", "Parking", "Racetrack", "Roundabout", "Frequently Asked Questions", "Graphics", "Welcome to highway-env\u2019s documentation!", "Installation", "Make your own environment", "The Multi-Agent setting", "Observations", "Getting Started", "Rewards", "User Guide"], "terms": {"similarli": 1, "observ": [1, 2, 10, 12, 13, 14, 15, 16, 21, 24, 25, 26], "sever": [1, 7, 10, 12, 17, 21, 23, 24], "type": [1, 4, 10, 12, 13, 14, 15, 16, 21, 22, 23, 24], "can": [1, 4, 6, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25], "us": [1, 7, 8, 9, 14, 18, 19, 20, 21, 23, 24, 25], "everi": [1, 3, 25], "environ": [1, 3, 10, 12, 13, 14, 15, 16, 18, 19, 22, 23, 26], "thei": [1, 5, 7, 13, 18, 23, 25], "ar": [1, 3, 4, 5, 6, 7, 8, 9, 10, 18, 21, 22, 23, 24, 25], "defin": [1, 4, 6, 10, 12, 13, 14, 15, 16, 18, 21, 23, 24, 25], "modul": [1, 21, 23], "each": [1, 5, 6, 8, 9, 12, 17, 18, 22, 23], "come": [1, 12, 23], "default": [1, 7, 8, 9, 18, 21, 23, 24], "which": [1, 4, 5, 6, 7, 8, 12, 14, 17, 18, 20, 21, 22, 23, 24, 25], "chang": [1, 2, 4, 7, 8, 16, 17, 21, 23, 24, 26], "customis": [1, 23], "configur": [1, 18, 22, 25, 26], "For": [1, 6, 7, 17, 22, 23, 24], "instanc": [1, 4, 6, 7, 8, 9, 23, 24], "import": [1, 3, 17, 21, 22, 23, 24], "gymnasium": [1, 18, 21, 22, 23, 24], "gym": [1, 10, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24], "env": [1, 10, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24], "make": [1, 2, 10, 12, 13, 14, 15, 16, 18, 19, 22, 23, 26], "highwai": [1, 11, 13, 15, 18, 20, 22, 23, 24], "v0": [1, 10, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24], "config": [1, 4, 10, 12, 13, 14, 15, 16, 18, 21, 22, 23, 24], "continuousact": [1, 14, 15], "The": [1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 13, 15, 16, 18, 19, 20, 21, 23, 24, 25, 26], "allow": [1, 7, 8, 21], "agent": [1, 10, 12, 13, 14, 15, 18, 21, 23, 25, 26], "directli": [1, 23, 25], "set": [1, 2, 4, 5, 6, 8, 14, 18, 23, 26], "low": [1, 8], "level": [1, 2, 4, 8, 17], "vehicl": [1, 2, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 24, 25, 26], "kinemat": [1, 2, 3, 6, 8, 10, 12, 22, 24, 26], "name": [1, 23], "throttl": [1, 8], "steer": [1, 7, 8, 9, 14], "angl": [1, 4, 7, 8, 9, 18, 23], "delta": [1, 7, 8, 9], "enabl": [1, 23], "disabl": 1, "through": [1, 2, 3, 5, 8, 21, 25], "longitudin": [1, 4, 9, 12, 15, 16, 18, 23], "later": [1, 4, 12, 15, 18, 23], "respect": [1, 7, 8, 18, 25], "thu": [1, 17, 25], "space": [1, 7, 9, 14, 18, 21, 23, 26], "either": 1, "1d": [1, 7], "2d": [1, 4, 7], "discreteact": 1, "i": [1, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 21, 22, 24, 25], "uniform": [1, 8, 23], "quantiz": 1, "abov": 1, "actions_per_axi": 1, "paramet": [1, 4, 5, 6, 7, 8, 9, 12, 14, 18, 21, 23, 25], "step": [1, 5, 6, 7, 9, 12, 16, 17, 21, 22, 23, 24], "axi": [1, 7, 8, 9, 23], "separ": [1, 18], "discretemetaact": [1, 10, 12, 13, 16, 22, 24], "add": [1, 21], "layer": [1, 23], "speed": [1, 7, 8, 9, 10, 13, 14, 21, 25], "top": [1, 8, 23], "so": [1, 7, 13, 14, 17, 18, 21, 23], "ego": [1, 7, 10, 12, 13, 14, 16, 18, 21, 25], "automat": [1, 8, 16, 21], "follow": [1, 2, 6, 7, 8, 15, 16, 17, 18, 21, 23, 24], "road": [1, 4, 7, 8, 9, 10, 12, 13, 18, 21, 23, 25, 26], "desir": [1, 7, 8, 14, 21, 23, 25], "veloc": [1, 5, 7, 8, 23, 25], "Then": 1, "avail": [1, 10, 24], "consist": [1, 2], "target": [1, 5, 7, 8], "lane": [1, 2, 3, 5, 6, 7, 8, 9, 10, 16, 17, 18, 21, 22, 23, 24], "setpoint": 1, "full": [1, 24], "correspond": [1, 4, 8, 14, 17, 18, 21, 23], "actions_al": [1, 22], "0": [1, 4, 5, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 25], "lane_left": 1, "1": [1, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 22, 23, 24, 25], "idl": [1, 23, 24], "2": [1, 2, 7, 8, 9, 10, 20, 22, 23, 24], "lane_right": 1, "3": [1, 7, 10, 12, 13, 15, 18, 20, 23, 24], "faster": [1, 8, 23], "4": [1, 7, 10, 15, 18, 23, 24], "slower": [1, 8], "some": [1, 5, 8, 13, 25], "might": 1, "alwai": [1, 18, 23], "edg": [1, 6], "acceler": [1, 7, 8, 9, 14], "decelr": 1, "beyond": 1, "maximum": [1, 7, 9, 21, 23, 25], "minimum": [1, 7, 9, 25], "list": [1, 3, 4, 5, 6, 7, 8, 9, 17, 18, 21, 23, 24], "access": [1, 13, 21, 24], "get_available_act": 1, "method": [1, 4, 5, 7, 8, 9, 16, 21, 25], "take": [1, 5, 7, 23, 24], "an": [1, 5, 6, 7, 8, 9, 12, 18, 19, 21, 22, 23, 25], "unavail": 1, "equival": 1, "intersect": [1, 5, 6, 8, 11, 24], "onli": [1, 7, 9, 21, 22, 24, 25], "while": [1, 9, 10, 13, 15, 16, 17, 21, 22, 24], "perform": [1, 7, 8, 12, 21, 23, 24], "track": [1, 8, 15], "simul": [1, 2, 7, 8, 9, 12, 17, 18, 21, 23], "manual_control": [1, 24], "true": [1, 4, 7, 10, 12, 13, 14, 15, 16, 17, 23, 24], "reset": [1, 17, 18, 21, 22, 23, 24], "done": [1, 16, 17, 18, 22, 23, 24], "fals": [1, 4, 5, 6, 10, 12, 13, 14, 15, 16, 17, 18, 22, 23, 24], "action_spac": [1, 17, 21], "sampl": [1, 17, 21], "ignor": 1, "direct": [1, 7, 8, 9, 23], "arrow": 1, "kei": [1, 16, 18, 23], "eventhandl": 1, "class": [1, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 21, 22, 23], "highway_env": [1, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24], "common": [1, 18, 21, 22, 23], "actiontyp": 1, "abstractenv": [1, 18, 21, 23], "kwarg": [1, 23], "sourc": [1, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 21, 23], "A": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 13, 14, 15, 18, 21, 22, 23, 24], "specifi": [1, 8, 21, 25], "its": [1, 4, 6, 7, 8, 9, 16, 17, 22, 24], "definit": 1, "how": [1, 3, 7, 22, 24], "execut": [1, 7, 12, 21, 22], "properti": [1, 7, 8, 9, 21], "vehicle_class": [1, 21], "callabl": [1, 18], "abl": [1, 8, 17, 21], "must": [1, 6, 14, 18, 20, 21, 22, 24, 25], "return": [1, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 21, 22, 23, 25], "subclass": 1, "act": [1, 6, 7, 8, 9], "int": [1, 4, 6, 7, 8, 9, 12, 18, 21, 23, 24], "ndarrai": [1, 4, 7, 8, 9, 12, 14, 18, 21, 23], "none": [1, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 21, 23, 24], "most": [1, 5, 22, 26], "mechan": 1, "actual": [1, 6, 17, 22], "implement": [1, 4, 7, 8, 10, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24], "where": [1, 6, 7, 8, 9, 14, 15, 21, 23, 25], "pre": 1, "process": [1, 2], "appli": [1, 8], "base": [1, 5, 7, 9, 24], "controlled_vehicl": [1, 15, 22, 24], "upon": 1, "If": [1, 7, 8, 9, 16, 19, 21, 23], "first": [1, 5, 17, 18, 21, 22, 23], "acceleration_rang": 1, "tupl": [1, 4, 6, 7, 8, 12, 18, 21, 22, 23], "float": [1, 4, 5, 6, 7, 8, 9, 12, 14, 18, 21, 23], "steering_rang": 1, "speed_rang": 1, "bool": [1, 4, 5, 6, 7, 12, 18, 21, 23], "dynam": [1, 5, 6, 7, 8, 9, 12, 21, 24, 26], "clip": [1, 23], "both": [1, 4, 7, 22, 23], "thi": [1, 4, 7, 10, 12, 13, 16, 17, 20, 21, 22, 23, 24, 25], "order": [1, 9, 17, 22, 23, 25], "interv": 1, "map": [1, 10, 23], "creat": [1, 4, 7, 8, 9, 18, 24, 26], "rang": [1, 7, 8, 9, 10, 23, 24, 25], "valu": [1, 16, 21, 23, 24], "m": [1, 4, 7, 8, 9, 10, 16, 18, 21, 23], "s\u00b2": 1, "rad": [1, 4, 7, 8], "reachabl": [1, 4, 9], "": [1, 5, 6, 7, 8, 9, 10, 12, 13, 16, 17, 18, 21, 22, 23, 24, 25], "whether": [1, 4, 5, 6, 7, 18, 21, 23], "e": [1, 2, 17], "friction": 1, "rather": [1, 25], "than": [1, 7, 17, 23, 25], "5": [1, 7, 9, 10, 12, 13, 14, 15, 16, 20, 22, 23, 24], "x": [1, 4, 9, 12, 14, 18, 23, 25], "7853981633974483": 1, "box": 1, "target_spe": [1, 7, 8], "sequenc": [1, 4, 7, 8, 9, 18, 23], "cruis": [1, 8], "point": [1, 2, 4], "includ": [1, 5, 6, 22], "index": [1, 6, 7, 8, 23], "label": 1, "actions_longi": 1, "actions_lat": 1, "get": [1, 4, 8, 20, 22, 23], "current": [1, 6, 8, 9, 20, 21, 23, 25], "boundari": 1, "maxim": [1, 7], "minim": [1, 7], "multiagentact": [1, 22], "action_config": [1, 22], "dict": [1, 4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 21, 23, 24], "awr": [2, 24], "17": [2, 24], "marcin": 2, "andrychowicz": 2, "filip": 2, "wolski": 2, "alex": 2, "rai": 2, "jona": 2, "schneider": 2, "rachel": 2, "fong": 2, "peter": 2, "welind": 2, "bob": 2, "mcgrew": 2, "josh": 2, "tobin": 2, "pieter": 2, "abbeel": 2, "wojciech": 2, "zaremba": 2, "hindsight": [2, 24], "experi": [2, 22, 24], "replai": [2, 24], "In": [2, 7, 10, 13, 16, 17, 21, 22, 23, 25], "advanc": 2, "neural": 2, "inform": [2, 14, 17, 21, 23], "system": [2, 4, 9, 12, 18], "2017": 2, "arxiv": 2, "1707": 2, "01495": 2, "hm08": [2, 24], "jean": 2, "fran": 2, "\u00e7": 2, "oi": 2, "hren": 2, "r": [2, 7, 8, 25], "\u00e9": 2, "mi": 2, "muno": 2, "optimist": 2, "plan": [2, 8, 16, 24], "determinist": [2, 24], "lectur": 2, "note": [2, 25], "comput": [2, 4, 7, 8, 21], "scienc": 2, "2008": 2, "kth07": [2, 7], "arn": 2, "kest": 2, "martin": 2, "treiber": 2, "dirk": 2, "helb": 2, "gener": [2, 5, 6, 17, 21, 22, 25], "model": [2, 3, 7, 8, 9, 21, 22, 24], "mobil": [2, 7], "car": 2, "transport": 2, "research": 2, "record": [2, 5, 6, 17], "2007": 2, "doi": 2, "10": [2, 7, 12, 23], "3141": 2, "1999": 2, "lm19": [2, 17, 24], "edouard": [2, 19], "leurent": [2, 19], "mercat": 2, "social": [2, 24], "attent": [2, 24], "autonom": [2, 19], "decis": [2, 7, 12, 19, 21], "dens": [2, 12], "traffic": [2, 12, 13, 16], "machin": 2, "learn": [2, 15, 24, 25], "drive": [2, 5, 6, 8, 9, 10, 13, 18, 19, 21, 24, 25], "workshop": 2, "thirti": 2, "third": 2, "confer": 2, "neurip": 2, "2019": [2, 24], "montreal": 2, "canada": 2, "decemb": 2, "1911": 2, "12250": 2, "mk": [2, 25], "15": [2, 10, 12, 13, 14, 15, 16, 17, 18, 23, 24, 25], "volodymyr": 2, "mnih": 2, "korai": 2, "kavukcuoglu": 2, "david": 2, "silver": 2, "andrei": 2, "rusu": 2, "joel": 2, "veness": 2, "marc": 2, "g": [2, 17], "bellemar": 2, "grave": 2, "riedmil": 2, "andrea": 2, "k": [2, 16, 18], "fidjeland": 2, "georg": 2, "ostrovski": 2, "stig": 2, "petersen": 2, "charl": 2, "beatti": 2, "amir": 2, "sadik": 2, "ioanni": 2, "antonogl": 2, "helen": 2, "king": 2, "dharshan": 2, "kumaran": 2, "daan": 2, "wierstra": 2, "shane": 2, "legg": 2, "demi": 2, "hassabi": 2, "human": 2, "control": [2, 3, 7, 14, 15, 16, 21, 26], "deep": [2, 24, 25], "reinforc": [2, 24, 25], "natur": [2, 23], "518": 2, "7540": 2, "529": 2, "533": 2, "2015": 2, "paltchedandrean17": [2, 9], "philip": 2, "polack": 2, "florent": 2, "altch": 2, "brigitt": 2, "d": [2, 7], "andr": 2, "novel": [2, 17], "bicycl": [2, 9], "feasibl": 2, "trajectori": [2, 5, 6, 8, 9, 24, 25], "ieee": 2, "intellig": [2, 7], "symposium": 2, "page": [2, 24], "6": [2, 7, 12, 16, 23], "8": [2, 23, 24], "qsmg17": [2, 17], "qi": 2, "hao": 2, "su": 2, "kaichun": 2, "mo": 2, "leonida": 2, "j": [2, 23], "guiba": 2, "pointnet": 2, "3d": 2, "classif": 2, "segment": 2, "1612": 2, "00593": 2, "thh00": [2, 7], "ansgar": 2, "henneck": 2, "congest": 2, "state": [2, 7, 8, 9, 17, 21, 22, 23, 25], "empir": 2, "microscop": 2, "physic": [2, 3], "review": 2, "statist": 2, "plasma": 2, "fluid": 2, "relat": 2, "interdisciplinari": 2, "topic": 2, "62": 2, "1805": 2, "1824": 2, "2000": 2, "describ": [3, 4, 5, 6, 10, 17, 19, 21, 22, 23], "move": [3, 9, 18, 23], "behav": [3, 5], "time": [3, 5, 7, 8, 16, 25, 26], "There": [3, 24], "two": [3, 5, 7, 8, 15, 17, 18, 22, 23, 25], "section": 3, "affect": 3, "descript": [3, 19, 23, 24], "behavior": [3, 5, 10, 12, 13, 16, 21, 24], "compos": [3, 6, 25], "roadnetwork": [3, 5, 6, 21], "regul": 3, "geometri": [4, 6, 21], "abstractlan": [4, 6, 18], "object": [4, 5, 6, 7, 8, 9, 10, 13, 18, 21, 23], "parametr": [4, 24], "center": [4, 7, 8, 9, 18, 23], "line": [4, 8, 18], "curv": [4, 24], "provid": [4, 8, 17, 18, 19, 21, 24], "local": [4, 6, 17, 18], "coordin": [4, 6, 18, 23], "convers": [4, 23], "between": [4, 5, 7, 8, 9, 18, 23, 25], "longi": 4, "lat": [4, 8, 18], "frenet": 4, "frame": [4, 17, 18, 21, 23], "global": 4, "y": [4, 9, 12, 14, 18, 20, 23, 25], "ensur": 4, "posit": [4, 6, 7, 9, 14, 18, 23], "local_coordin": 4, "main": [4, 13], "straightlan": 4, "sinelan": 4, "circularlan": 4, "central": [4, 12, 22], "metaclass__": 4, "alia": 4, "abcmeta": 4, "abstract": [4, 21], "convert": [4, 8, 18, 23], "world": [4, 23, 26], "heading_at": 4, "head": [4, 7, 9, 14, 23], "given": [4, 6, 7, 8, 9, 14, 17, 18, 21], "width_at": 4, "width": [4, 9, 16, 18], "classmethod": [4, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 21], "from_config": 4, "from": [4, 6, 7, 8, 9, 10, 14, 21, 22, 23, 24, 25], "json": [4, 22], "to_config": 4, "write": 4, "serial": 4, "on_lan": 4, "margin": [4, 18], "option": [4, 19, 21], "known": 4, "supplementari": [4, 14], "around": [4, 18, 23], "is_reachable_from": 4, "distanc": [4, 7, 18, 21, 23, 25], "l1": 4, "distance_with_head": 4, "heading_weight": 4, "weight": [4, 7, 14, 23, 25], "local_angl": 4, "long_offset": 4, "non": [4, 7, 8, 23], "normalis": [4, 23], "linetyp": 4, "side": [4, 10, 18], "start": [4, 6, 9, 13, 18, 19], "end": [4, 6, 8, 9, 12, 18, 21, 22], "default_width": 4, "line_typ": 4, "forbidden": 4, "speed_limit": 4, "20": [4, 10, 12, 23, 24], "prioriti": [4, 5], "go": [4, 6], "straight": [4, 10, 23], "new": [4, 5, 6, 7, 8, 9, 17, 21], "determin": [4, 5], "who": [4, 5], "ha": [4, 15, 16, 20, 21, 22, 23, 24, 25], "right": [4, 5, 7, 8, 10, 18, 22, 23], "wai": [4, 5, 12, 17, 24], "amplitud": 4, "pulsat": 4, "phase": 4, "sinusoid": 4, "oscil": 4, "initi": [4, 8, 9, 14, 15, 18, 21, 22], "radiu": 4, "start_phas": 4, "end_phas": 4, "clockwis": 4, "circl": 4, "arc": 4, "polylanefixedwidth": 4, "lane_point": 4, "fix": [4, 21, 23], "approxim": [4, 7], "hermit": 4, "polynomi": 4, "polylan": 4, "left_boundary_point": 4, "right_boundary_point": 4, "regulatedroad": 5, "give": [5, 6, 21, 23], "attribut": [5, 24], "On": 5, "rule": 5, "enforc": 5, "usual": [5, 17], "howev": [5, 17, 24, 25], "try": [5, 7], "predict": [5, 8, 9, 12, 22, 23, 24], "collis": [5, 10, 12, 13, 15, 16, 25, 26], "other": [5, 7, 8, 9, 10, 12, 15, 21, 22, 23], "is_conflict_poss": 5, "when": [5, 7, 8, 10], "case": [5, 6, 17, 23], "arbitr": 5, "respect_prior": 5, "yield": [5, 8, 24, 25], "until": [5, 9, 12, 21], "conflict": 5, "resolv": 5, "network": [5, 6, 8, 21, 23], "obstacl": [5, 6, 23], "np_random": [5, 6], "randomst": [5, 6], "record_histori": [5, 6], "road_object": [5, 6], "landmark": [5, 6], "np": [5, 6], "random": [5, 6, 9, 24], "number": [5, 6, 9, 16, 18, 23, 24, 26], "behaviour": [5, 6, 7, 12, 18, 21, 25], "recent": [5, 6], "should": [5, 6, 7, 17, 18, 21, 22, 23, 25], "displai": [5, 6, 9, 16, 18], "dt": [5, 6, 7, 8, 9], "entiti": [5, 6], "timestep": [5, 6, 7, 8, 9, 12, 21], "enforce_road_rul": 5, "find": [5, 6, 8], "them": [5, 18, 24, 25], "assign": 5, "stop": [5, 7, 9], "static": [5, 18], "v1": 5, "v2": 5, "second": [5, 6, 16, 21, 22], "topologi": [6, 21], "infrastructur": 6, "graph": 6, "repres": [6, 9, 18, 23], "node": [6, 8, 9], "It": [6, 7, 8, 9, 12, 13, 14, 16], "contain": [6, 21, 22, 23], "dictionari": [6, 21, 23, 24], "store": [6, 7, 9], "laneindex": 6, "string": 6, "identifi": 6, "integ": 6, "uniqu": 6, "lab": 6, "pub": 6, "obtain": [6, 24], "road_network": 6, "roadobject": [6, 18], "decid": [6, 7, 22], "action": [6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 21, 24, 26], "neighbour_vehicl": 6, "lane_index": [6, 7], "str": [6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 21, 23], "preced": [6, 7], "whose": [6, 7], "neighbour": [6, 10], "found": [6, 25], "look": [6, 23], "doesn": [6, 7], "t": [6, 7, 16, 23], "have": [6, 7, 14, 21, 25], "also": [6, 10, 13, 17, 18, 23, 24, 25], "anoth": 6, "project": [6, 7, 19, 20, 25], "consid": [6, 19, 23], "simpl": [7, 8, 12, 25], "realist": [7, 25], "dictat": 7, "idmvehicl": [7, 10, 13, 16, 21, 24], "driver": 7, "idm": 7, "dot": [7, 8, 9], "v": [7, 8, 9, 23, 25], "left": [7, 8, 18, 22, 23], "frac": [7, 8, 9, 25], "v_0": 7, "d_0": 7, "tv": 7, "sqrt": 7, "ab": 7, "front": [7, 8, 9, 25], "parametris": 7, "target_veloc": 7, "gap": 7, "time_w": 7, "jam": 7, "distance_w": 7, "b": [7, 25], "deceler": 7, "comfort_acc_max": 7, "comfort_acc_min": 7, "expon": 7, "discret": [7, 8, 26], "overal": 7, "brake": [7, 9, 25], "induc": 7, "accord": 7, "safe": [7, 13, 25], "do": [7, 17, 25], "cut": 7, "tild": 7, "_n": 7, "geq": 7, "b_": 7, "text": [7, 8, 25], "incent": 7, "possibli": 7, "underbrac": 7, "_c": 7, "a_c": 7, "_": [7, 22, 23, 24, 25], "p": [7, 8, 14, 25], "a_n": 7, "_o": 7, "a_o": 7, "old": 7, "a_": 7, "th": 7, "c": [7, 18, 23], "o": [7, 18], "befor": [7, 22], "n": 7, "after": [7, 22, 24], "polit": 7, "coeffici": [7, 25], "gain": [7, 8], "requir": [7, 20, 21], "trigger": 7, "lane_change_min_acc_gain": 7, "impos": 7, "dure": [7, 18], "lane_change_max_braking_impos": 7, "linearvehicl": 7, "linear": [7, 8], "featur": [7, 12, 14, 15, 25], "differ": [7, 17, 23], "lead": [7, 23, 25], "target_lane_index": [7, 8], "rout": [7, 8, 16], "enable_lane_chang": 7, "timer": 7, "polici": [7, 21, 22, 24, 25], "nearbi": [7, 23], "place": [7, 8, 9, 23], "cartesian": [7, 8, 9], "surfac": [7, 8, 9, 26], "horizont": [7, 8, 9], "acc_max": 7, "term": [7, 25], "delta_rang": 7, "chosen": [7, 9, 18], "randomli": [7, 9], "create_from": [7, 8, 9], "controlledvehicl": [7, 8], "exist": [7, 8, 9, 21, 23], "one": [7, 8, 9, 18, 22], "copi": [7, 8, 9, 17, 21], "same": [7, 8, 9], "now": [7, 13, 21, 22, 23], "support": [7, 22], "becaus": [7, 17], "all": [7, 12, 17, 21, 23], "own": [7, 12, 22, 26], "increas": [7, 23, 26], "ego_vehicl": 7, "front_vehicl": 7, "rear_vehicl": 7, "command": [7, 8, 9], "reach": [7, 10, 14], "maintain": [7, 13], "safeti": 7, "w": [7, 18, 23, 25], "doe": [7, 17, 24], "why": 7, "reason": [7, 12, 17], "about": [7, 17, 24], "even": [7, 18], "though": 7, "mai": [7, 23, 25], "s2": [7, 8], "desired_gap": 7, "being": [7, 9, 25], "change_lane_polici": 7, "frequenc": [7, 17, 18, 21], "close": [7, 17, 18, 21], "more": [7, 10, 12, 13, 14, 15, 16, 17, 21], "unsaf": 7, "candid": 7, "recover_from_stop": 7, "wrong": 7, "revers": 7, "maneuv": 7, "suggest": [7, 17], "recov": 7, "stuck": 7, "data": [7, 21, 23], "resp": 7, "lower": [7, 21], "higher": 7, "steering_control": [7, 8], "overrid": 7, "wheel": [7, 8, 9], "steering_featur": 7, "collect": [7, 19, 23], "arrai": [7, 18, 22, 23], "collect_data": 7, "output": [7, 17], "regress": 7, "aggressivevehicl": 7, "defensivevehicl": 7, "call": [8, 10, 12, 13, 14, 15, 16, 17, 18, 21], "proport": 8, "k_p": 8, "v_r": 8, "refer": [8, 21], "kp_a": 8, "speed_control": 8, "deriv": 8, "combin": 8, "invert": 8, "those": [8, 24], "v_": [8, 25], "k_": 8, "delta_": 8, "psi_": 8, "arcsin": 8, "psi_r": 8, "psi_l": 8, "psi": [8, 9, 25], "_r": 8, "l": [8, 9, 18, 23], "variat": 8, "lookahead": 8, "anticip": 8, "turn": 8, "yaw": 8, "rate": 8, "pilot": 8, "high": [8, 10, 13, 14], "cascad": 8, "plan_route_to": 8, "destin": [8, 12, 23, 25], "updat": [8, 9, 18, 20, 22, 23], "follow_road": 8, "At": 8, "switch": 8, "next": [8, 12, 21, 23], "get_routes_at_intersect": 8, "set_route_at_intersect": 8, "_to": 8, "eras": 8, "predict_trajectory_constant_spe": 8, "futur": [8, 9], "along": [8, 18, 23], "under": 8, "constant": [8, 21, 23], "mdpvehicl": 8, "handl": [8, 16, 18], "choos": [8, 25], "els": [8, 23], "forward": [8, 9, 18], "handler": 8, "index_to_spe": 8, "among": 8, "speed_to_index": 8, "closest": [8, 23], "assum": [8, 23], "avoid": [8, 10, 12, 13, 15, 16, 25], "search": 8, "input": [8, 9, 18], "speed_to_index_default": 8, "predict_trajectori": [8, 9], "action_dur": [8, 9], "trajectory_timestep": [8, 9], "durat": [8, 9, 10, 12, 15, 16, 24], "save": [8, 9, 24], "co": [9, 25], "beta": 9, "sin": [9, 25], "tan": 9, "slip": 9, "graviti": 9, "These": [9, 21, 23], "calcul": 9, "appear": 9, "predition_typ": 9, "constant_st": 9, "modifi": [9, 21], "propag": 9, "depend": [9, 17, 20, 21], "length": [9, 18], "default_initial_spe": 9, "23": 9, "25": [9, 23], "max_spe": 9, "40": [9, 10, 24], "min_spe": 9, "history_s": 9, "30": [9, 10, 24], "histori": 9, "create_random": 9, "lane_from": 9, "lane_to": 9, "lane_id": 9, "behind": [9, 23], "last": [9, 21, 23], "densiti": 9, "spawn": 9, "id": [9, 21], "ratio": 9, "repeat": 9, "integr": 9, "1st": 9, "respons": 9, "crash": [9, 16], "overridden": 9, "errat": 9, "complet": 9, "task": [10, 12, 13, 14, 16, 21, 24], "multilan": 10, "popul": [10, 21], "reward": [10, 12, 13, 14, 17, 21, 22, 23, 24, 26], "lanes_count": [10, 24], "vehicles_count": [10, 12, 22, 23, 24], "50": [10, 18, 24], "initial_spac": 10, "collision_reward": [10, 12, 15, 24], "receiv": 10, "collid": [10, 23], "reward_speed_rang": [10, 24], "linearli": 10, "highwayenv": 10, "high_speed_reward": [10, 24], "simulation_frequ": [10, 13, 14, 15, 16, 18, 24], "hz": [10, 13, 16, 17], "policy_frequ": [10, 13, 14, 15, 16, 23, 24], "other_vehicles_typ": [10, 13, 16, 24], "screen_width": [10, 12, 13, 14, 15, 16, 18, 24], "600": [10, 12, 13, 14, 15, 16, 24], "px": [10, 13, 16, 18], "screen_height": [10, 12, 13, 14, 15, 16, 18, 24], "150": [10, 13, 24], "centering_posit": [10, 12, 13, 14, 15, 16, 18, 23, 24], "scale": [10, 12, 13, 14, 15, 16, 18, 23, 24, 25], "show_trajectori": [10, 13, 14, 15, 16, 24], "render_ag": [10, 13, 14, 15, 16, 24], "offscreen_rend": [10, 13, 14, 15, 16, 24], "specif": [10, 12, 13, 14, 15, 16, 18, 23], "default_config": [10, 12, 13, 14, 15, 16, 21], "overload": [10, 12, 13, 14, 15, 16, 21, 25], "x15": 10, "speedup": 10, "fast": [10, 16, 24], "detail": [10, 19], "here": [10, 17, 21, 22, 23, 24], "render_mod": [10, 12, 13, 14, 15, 16, 21, 22, 23, 24], "stai": [10, 23], "rightmost": 10, "merg": [11, 24], "roundabout": [11, 18, 24], "park": [11, 23, 24, 25], "racetrack": [11, 24], "negoti": [12, 13], "quit": 12, "hard": 12, "up": [12, 26], "good": 12, "decentr": 12, "Of": 12, "cours": 12, "could": [12, 22, 25], "achiev": [12, 14, 21], "sophist": 12, "schedul": 12, "light": 12, "keep": [12, 25], "thing": 12, "rudimentari": 12, "wa": [12, 14, 18], "ad": [12, 21], "sometim": 12, "fail": 12, "result": [12, 24], "block": 12, "figur": [12, 22, 23, 24], "fine": 12, "my": [12, 24], "purpos": [12, 19], "sinc": [12, 22, 23, 25], "did": [12, 21], "happen": 12, "too": 12, "often": [12, 25], "expect": [12, 23, 25], "simpli": 12, "wait": 12, "episod": [12, 17, 21, 22, 24, 25], "situat": 12, "But": 12, "agre": 12, "ideal": 12, "welcom": [12, 21], "ani": [12, 14, 21, 23, 25], "contribut": [12, 19], "matter": 12, "presenc": [12, 15], "vx": [12, 14, 23], "vy": [12, 14, 23], "cos_h": [12, 14, 23], "sin_h": [12, 14, 23], "features_rang": [12, 23], "100": [12, 14, 23], "absolut": [12, 23], "flatten": 12, "observe_intent": [12, 23], "13": [12, 23], "o1": 12, "initial_vehicle_count": 12, "spawn_prob": 12, "intersectionenv": [12, 22], "normalize_reward": [12, 24], "intersection_env": 12, "termin": [12, 21, 25], "truncat": [12, 16, 17, 21, 22, 23, 24], "info": [12, 14, 17, 21, 22, 23, 24], "soon": 13, "approach": [13, 16, 23], "junction": 13, "incom": 13, "ramp": 13, "room": 13, "timetocollis": [13, 16, 23], "mergeenv": 13, "merge_env": 13, "goal": [14, 24, 26], "condit": [14, 24], "continu": [14, 15, 18, 26], "appropri": [14, 25], "kinematicsgo": 14, "normal": [14, 23, 25], "300": [14, 15], "7": [14, 15], "parkingenv": 14, "parking_env": 14, "credit": [14, 15], "munir": 14, "jojo": 14, "verg": 14, "idea": [14, 15], "define_spac": [14, 21], "compute_reward": 14, "achieved_go": 14, "desired_go": 14, "proxim": 14, "we": [14, 17, 18, 20, 21, 23, 25], "norm": [14, 25], "lp": 14, "kurtosi": 14, "he": 15, "mani": [15, 18], "thank": [15, 18], "supperted825": 15, "occupancygrid": [15, 23], "on_road": 15, "grid_siz": [15, 23], "18": [15, 23], "grid_step": [15, 23], "as_imag": [15, 23], "align_to_vehicle_ax": [15, 23], "lane_centering_cost": 15, "action_reward": 15, "other_vehicl": 15, "racetrackenv": 15, "racetrack_env": 15, "need": [15, 17], "skill": 15, "see": [15, 17, 21, 22, 23, 24, 25], "http": [15, 18, 19, 20], "github": [15, 19, 20], "com": [15, 18, 19, 20], "eleur": [15, 19, 20, 22, 24], "issu": 15, "231": 15, "flow": 16, "pass": [16, 22, 23], "possibl": [16, 17, 25], "incoming_vehicle_destin": 16, "11": 16, "run": [16, 17, 21, 22, 24], "still": [16, 21], "hasn": 16, "express": 16, "variabl": 16, "equal": 16, "pygam": [16, 18, 20], "window": [16, 18], "height": 16, "smaller": 16, "southeast": 16, "area": [16, 18], "roundaboutenv": 16, "roundabout_env": 16, "feel": 17, "free": 17, "entri": 17, "probabl": 17, "you": [17, 19, 21, 23], "instal": [17, 18, 21], "instead": [17, 25], "work": 17, "repositori": [17, 19], "code": [17, 22], "regist": [17, 26], "register_highway_env": [17, 21], "tend": 17, "sub": 17, "pair": [17, 21, 23], "argu": 17, "inde": 17, "revisit": 17, "scene": [17, 23, 26], "reus": 17, "past": 17, "struggl": 17, "address": [17, 25], "permut": 17, "invari": [17, 25], "architectur": [17, 24], "sensit": 17, "exampl": [17, 21, 22], "dqn": [17, 22, 23, 24], "sb3": [17, 24], "ppo": 17, "grayscal": [17, 26], "imag": [17, 18, 21, 24, 26], "cnn": [17, 24], "suitabl": 17, "singl": [17, 21, 22, 25], "typic": 17, "long": 17, "render": [17, 18, 21, 22, 23, 24], "intermedi": [17, 21], "wrap": [17, 21, 26], "recordvideo": [17, 21], "wrapper": [17, 21], "video_fold": 17, "episode_trigg": 17, "lambda": 17, "send": [17, 22], "unwrap": 17, "set_record_video_wrapp": 17, "ob": [17, 21, 22, 23, 24], "Its": 18, "dimens": 18, "640": 18, "480": 18, "roadsurfac": 18, "locat": [18, 23], "zoom": 18, "By": 18, "offset": [18, 23], "roadgraph": 18, "vehiclegraph": 18, "envview": 18, "viewer": [18, 21], "set_agent_displai": 18, "agent_displai": 18, "callback": 18, "dedic": 18, "set_agent_action_sequ": 18, "handle_ev": 18, "event": 18, "get_imag": 18, "rgb": [18, 23], "channel": [18, 23], "convent": [18, 25], "h": [18, 23], "window_posit": 18, "worldsurfac": 18, "size": [18, 22, 23, 24], "flag": 18, "surf": 18, "pix": 18, "pixel": 18, "pos2pix": 18, "vec2pix": 18, "vec": 18, "is_vis": 18, "visibl": 18, "param": [18, 23], "test": [18, 24], "move_display_window_to": 18, "origin": 18, "lanegraph": 18, "visual": 18, "stripe_spac": 18, "33": 18, "stripe": 18, "stripe_length": 18, "stripe_width": 18, "striped_lin": 18, "stripes_count": 18, "draw": 18, "continuous_curv": 18, "continuous_lin": 18, "would": [18, 23, 25], "drawn": 18, "draw_strip": 18, "display_traff": 18, "offscreen": 18, "without": 18, "screen": 18, "display_road_object": 18, "roadobjectgraph": 18, "object_": 18, "transpar": 18, "color": 18, "rotat": 18, "rectangl": [18, 23], "slightli": 18, "blit_rot": 18, "po": 18, "origin_po": 18, "show_rect": 18, "stackoverflow": 18, "54714144": 18, "gather": 19, "quick": [19, 24], "guid": 19, "custom": 19, "nut": 19, "bolt": 19, "packag": 19, "pleas": 19, "piec": 19, "bibtex": 19, "misc": 19, "author": 19, "titl": [19, 22], "year": 19, "2018": 19, "publish": 19, "journal": 19, "howpublish": 19, "url": 19, "python3": 20, "graphic": [20, 26], "itself": 20, "manual": [20, 21, 26], "sudo": 20, "apt": 20, "python": [20, 21, 22], "dev": 20, "libsdl": 20, "image1": 20, "mixer1": 20, "ttf2": 20, "libsdl1": 20, "libsmpeg": 20, "numpi": 20, "subvers": 20, "libportmidi": 20, "ffmpeg": 20, "libswscal": 20, "libavformat": 20, "libavcodec": 20, "libfreetype6": 20, "gcc": 20, "recommend": 20, "anaconda": 20, "To": [20, 21, 22], "latest": 20, "pip": 20, "user": 20, "git": 20, "pull": 21, "request": 21, "your_env": 21, "py": [21, 22], "yourenv": 21, "inherit": 21, "function": [21, 24, 25], "choic": [21, 25], "_make_road": 21, "self": [21, 22], "field": [21, 22, 23], "action_typ": [21, 23, 24], "freeli": 21, "part": [21, 23], "config_kei": 21, "onc": 21, "other_valu": 21, "__init__": 21, "entry_point": 21, "registr": 21, "hook": 21, "reinstal": 21, "setup": 21, "altern": 21, "That": 21, "themselv": 21, "variou": 21, "involv": 21, "perception_dist": 21, "200": [21, 24], "present": 21, "_reward": [21, 25], "associ": 21, "multi": [21, 26], "vector": 21, "aggreg": 21, "scalar": 21, "insid": [21, 25], "reward_nam": 21, "reward_valu": 21, "_is_termin": 21, "check": [21, 23], "_is_trunc": 21, "_info": 21, "addit": 21, "seed": [21, 22, 24], "prng": 21, "_reset": 21, "_simul": 21, "Will": 21, "_automatic_rend": 21, "ongo": 21, "whole": 21, "video": [21, 22, 24], "been": [21, 22, 25], "captur": 21, "simplifi": 21, "distant": 21, "remov": 21, "meant": 21, "load": [21, 24], "preserv": 21, "optim": [21, 25], "change_vehicl": 21, "vehicle_class_path": 21, "path": [21, 22], "multiagentwrapp": 21, "obstyp": 21, "acttyp": 21, "modular": 21, "transform": 21, "overwritten": 21, "version": 22, "rgb_arrai": [22, 23, 24], "sake": 22, "visualis": 22, "matplotlib": [22, 23, 24], "pyplot": [22, 23, 24], "plt": [22, 23, 24], "inlin": [22, 23, 24], "imshow": [22, 23, 24], "green": 22, "show": [22, 23, 24], "640x480": [22, 23, 24], "ax": [22, 23, 24], "accept": 22, "standard": 22, "ax1": 22, "ax2": 22, "subplot": [22, 23], "nrow": 22, "set_titl": 22, "action_1": 22, "action_2": 22, "what": [22, 23], "As": 22, "far": 22, "multiagentobserv": 22, "observation_config": 22, "pprint": [22, 24], "90797305": 22, "3125": 22, "10906096": 22, "04341291": 22, "33000726": 22, "dtype": 22, "float32": 22, "pseudo": 22, "train": 22, "dummi": 22, "rl": [22, 24], "algorithm": 22, "transit": 22, "def": 22, "next_ob": 22, "dispatch": 22, "obs_i": 22, "action_i": 22, "next_obs_i": 22, "zip": 22, "cd": 22, "script": [22, 24], "evalu": 22, "env_multi_ag": 22, "dqnagent": 22, "ego_attention_2h": 22, "3000": 22, "27": 23, "observation_factori": 23, "kinematicobserv": 23, "f": 23, "v_y": [23, 25], "12": 23, "22": 23, "row": 23, "within": 23, "05": 23, "04": 23, "75": 23, "08": 23, "675": 23, "222": 23, "105": 23, "9": 23, "025": 23, "rel": 23, "except": 23, "075": 23, "172": 23, "065": 23, "fewer": 23, "placehold": 23, "fill": 23, "zero": 23, "detect": 23, "disambigu": 23, "radian": 23, "trigonometr": 23, "cos_d": 23, "sin_d": 23, "long_": 23, "off": 23, "lat_": 23, "ang_": 23, "angular": 23, "sort": 23, "print": 23, "2116441": 23, "07987082": 23, "40037498": 23, "14375238": 23, "5924493": 23, "14188124": 23, "81080985": 23, "17013432": 23, "12747008": 23, "08804176": 23, "11419602": 23, "13449906": 23, "19995664": 23, "grayscaleobserv": 23, "observation_shap": 23, "sum": 23, "stack_siz": 23, "customari": 23, "128": 23, "64": 23, "2989": 23, "5870": 23, "1140": 23, "fig": 23, "ncol": 23, "figsiz": 23, "enumer": 23, "flat": 23, "cmap": 23, "get_cmap": 23, "grai": 23, "1200x500": 23, "three": 23, "actions_index": [23, 24], "occupancygridobserv": 23, "shape": 23, "discretis": 23, "cell": 23, "resolut": 23, "like": 23, "timetocollisionobserv": 23, "hot": 23, "encod": 23, "over": 23, "bin": 23, "25m": 23, "infti": 23, "middl": 23, "bottom": 23, "horizon": 23, "lidarobserv": 23, "divid": 23, "sector": 23, "per": 23, "column": 23, "nearest": 23, "compon": 23, "south": 23, "west": 23, "meter": 23, "awai": 23, "toward": 23, "1m": 23, "maximum_rang": 23, "84": 23, "see_behind": 23, "include_obstacl": 23, "min": [23, 25], "max": [23, 25], "shuffl": 23, "normalize_ob": 23, "df": 23, "datafram": 23, "real": 23, "min_x": 23, "max_x": 23, "min_i": 23, "max_i": 23, "step_x": 23, "step_i": 23, "align": 23, "pos_to_index": 23, "otherwis": 23, "alreadi": 23, "fill_road_layer_by_lan": 23, "layer_index": 23, "lane_perception_dist": 23, "onroad": 23, "offroad": 23, "iter": 23, "regularli": 23, "waypoint": 23, "larg": 23, "small": 23, "fill_road_layer_by_cel": 23, "kinematicsgoalobserv": 23, "exitobserv": 23, "exit_env": 23, "exit": 23, "creation": 24, "ego_spac": 24, "initial_lane_id": 24, "lane_change_reward": 24, "offroad_termin": 24, "real_time_rend": 24, "right_lane_reward": 24, "vehicles_dens": 24, "effect": 24, "librari": 24, "openai": 24, "baselin": 24, "stabl": 24, "baselines3": 24, "mlp": 24, "stable_baselines3": 24, "mlppolici": 24, "policy_kwarg": 24, "net_arch": 24, "256": 24, "learning_r": 24, "5e": 24, "buffer_s": 24, "15000": 24, "learning_start": 24, "batch_siz": 24, "32": 24, "gamma": 24, "train_freq": 24, "gradient_step": 24, "target_update_interv": 24, "verbos": 24, "tensorboard_log": 24, "highway_dqn": 24, "2e4": 24, "_state": 24, "25mn": 24, "laptop": 24, "fp": 24, "14": 24, "better": 24, "vanilla": 24, "q": 24, "extens": 24, "doubl": 24, "duel": 24, "priorit": 24, "improv": 24, "faq": 24, "notebook": 24, "few": 24, "opd": 24, "tutori": 24, "written": 24, "rlss": 24, "demonstr": 24, "principl": 24, "her": 24, "cross": 24, "challeng": 25, "problem": 25, "particular": 25, "wish": 25, "aspect": 25, "straightforward": 25, "adequ": 25, "emerg": 25, "perspect": 25, "robust": 25, "against": 25, "uncertain": 25, "focu": 25, "progress": 25, "quickli": 25, "bound": 25, "shift": 25, "practic": 25, "benefici": 25, "forbid": 25, "neg": 25, "encourag": 25, "prefer": 25, "earli": 25, "caus": 25, "risk": 25, "suffer": 25, "satisfi": 25, "penalti": 25, "collision_penalti": 25, "replac": 25, "s_g": 25, "v_x": 25, "x_g": 25, "y_g": 25, "psi_g": 25, "sum_i": 25, "w_i": 25, "x_i": 25, "euclidean": 25, "narrow": 25, "spike": 25, "occup": 26, "grid": 26, "lidar": 26, "api": 26, "meta": 26, "your": 26, "file": 26, "profit": 26}, "objects": {"highway_env": [[21, 0, 0, "-", "__init__"]], "highway_env.__init__": [[21, 1, 1, "", "register_highway_envs"]], "highway_env.envs.common": [[21, 0, 0, "-", "abstract"], [1, 0, 0, "-", "action"], [18, 0, 0, "-", "graphics"], [23, 0, 0, "-", "observation"]], "highway_env.envs.common.abstract": [[21, 2, 1, "", "AbstractEnv"], [21, 2, 1, "", "MultiAgentWrapper"]], "highway_env.envs.common.abstract.AbstractEnv": [[21, 3, 1, "", "PERCEPTION_DISTANCE"], [21, 4, 1, "", "_automatic_rendering"], [21, 4, 1, "", "_info"], [21, 4, 1, "", "_is_terminated"], [21, 4, 1, "", "_is_truncated"], [21, 4, 1, "", "_reset"], [21, 4, 1, "", "_reward"], [21, 4, 1, "", "_rewards"], [21, 4, 1, "", "_simulate"], [21, 4, 1, "", "change_vehicles"], [21, 4, 1, "", "close"], [21, 4, 1, "", "default_config"], [21, 4, 1, "", "define_spaces"], [21, 4, 1, "", "render"], [21, 4, 1, "", "reset"], [21, 4, 1, "", "simplify"], [21, 4, 1, "", "step"], [21, 5, 1, "", "vehicle"]], "highway_env.envs.common.abstract.MultiAgentWrapper": [[21, 4, 1, "", "step"]], "highway_env.envs.common.action": [[1, 2, 1, "", "ActionType"], [1, 2, 1, "", "ContinuousAction"], [1, 2, 1, "", "DiscreteAction"], [1, 2, 1, "", "DiscreteMetaAction"], [1, 2, 1, "", "MultiAgentAction"]], "highway_env.envs.common.action.ActionType": [[1, 4, 1, "", "act"], [1, 5, 1, "", "controlled_vehicle"], [1, 4, 1, "", "get_available_actions"], [1, 4, 1, "", "space"], [1, 5, 1, "", "vehicle_class"]], "highway_env.envs.common.action.ContinuousAction": [[1, 3, 1, "", "ACCELERATION_RANGE"], [1, 3, 1, "", "STEERING_RANGE"], [1, 4, 1, "", "act"], [1, 4, 1, "", "space"], [1, 5, 1, "", "vehicle_class"]], "highway_env.envs.common.action.DiscreteAction": [[1, 4, 1, "", "act"], [1, 4, 1, "", "space"]], "highway_env.envs.common.action.DiscreteMetaAction": [[1, 3, 1, "", "ACTIONS_ALL"], [1, 3, 1, "", "ACTIONS_LAT"], [1, 3, 1, "", "ACTIONS_LONGI"], [1, 4, 1, "", "act"], [1, 4, 1, "", "get_available_actions"], [1, 4, 1, "", "space"], [1, 5, 1, "", "vehicle_class"]], "highway_env.envs.common.action.MultiAgentAction": [[1, 4, 1, "", "act"], [1, 4, 1, "", "get_available_actions"], [1, 4, 1, "", "space"], [1, 5, 1, "", "vehicle_class"]], "highway_env.envs.common.graphics": [[18, 2, 1, "", "EnvViewer"]], "highway_env.envs.common.graphics.EnvViewer": [[18, 4, 1, "", "close"], [18, 4, 1, "", "display"], [18, 4, 1, "", "get_image"], [18, 4, 1, "", "handle_events"], [18, 4, 1, "", "set_agent_action_sequence"], [18, 4, 1, "", "set_agent_display"], [18, 4, 1, "", "window_position"]], "highway_env.envs.common.observation": [[23, 2, 1, "", "ExitObservation"], [23, 2, 1, "", "GrayscaleObservation"], [23, 2, 1, "", "KinematicObservation"], [23, 2, 1, "", "KinematicsGoalObservation"], [23, 2, 1, "", "OccupancyGridObservation"]], "highway_env.envs.common.observation.ExitObservation": [[23, 4, 1, "", "observe"]], "highway_env.envs.common.observation.GrayscaleObservation": [[23, 4, 1, "", "observe"], [23, 4, 1, "", "space"]], "highway_env.envs.common.observation.KinematicObservation": [[23, 4, 1, "", "normalize_obs"], [23, 4, 1, "", "observe"], [23, 4, 1, "", "space"]], "highway_env.envs.common.observation.KinematicsGoalObservation": [[23, 4, 1, "", "observe"], [23, 4, 1, "", "space"]], "highway_env.envs.common.observation.OccupancyGridObservation": [[23, 4, 1, "", "fill_road_layer_by_cell"], [23, 4, 1, "", "fill_road_layer_by_lanes"], [23, 4, 1, "", "normalize"], [23, 4, 1, "", "observe"], [23, 4, 1, "", "pos_to_index"], [23, 4, 1, "", "space"]], "highway_env.envs.highway_env": [[10, 2, 1, "", "HighwayEnv"]], "highway_env.envs.highway_env.HighwayEnv": [[10, 4, 1, "", "default_config"]], "highway_env.envs.intersection_env": [[12, 2, 1, "", "IntersectionEnv"]], "highway_env.envs.intersection_env.IntersectionEnv": [[12, 4, 1, "", "default_config"], [12, 4, 1, "", "step"]], "highway_env.envs.merge_env": [[13, 2, 1, "", "MergeEnv"]], "highway_env.envs.merge_env.MergeEnv": [[13, 4, 1, "", "default_config"]], "highway_env.envs.parking_env": [[14, 2, 1, "", "ParkingEnv"]], "highway_env.envs.parking_env.ParkingEnv": [[14, 4, 1, "", "compute_reward"], [14, 4, 1, "", "default_config"], [14, 4, 1, "", "define_spaces"]], "highway_env.envs.racetrack_env": [[15, 2, 1, "", "RacetrackEnv"]], "highway_env.envs.racetrack_env.RacetrackEnv": [[15, 4, 1, "", "default_config"]], "highway_env.envs.roundabout_env": [[16, 2, 1, "", "RoundaboutEnv"]], "highway_env.envs.roundabout_env.RoundaboutEnv": [[16, 4, 1, "", "default_config"]], "highway_env.road": [[18, 0, 0, "-", "graphics"], [4, 0, 0, "-", "lane"], [5, 0, 0, "-", "regulation"], [6, 0, 0, "-", "road"]], "highway_env.road.graphics": [[18, 2, 1, "", "LaneGraphics"], [18, 2, 1, "", "RoadGraphics"], [18, 2, 1, "", "RoadObjectGraphics"], [18, 2, 1, "", "WorldSurface"]], "highway_env.road.graphics.LaneGraphics": [[18, 3, 1, "", "STRIPE_LENGTH"], [18, 3, 1, "", "STRIPE_SPACING"], [18, 3, 1, "", "STRIPE_WIDTH"], [18, 4, 1, "", "continuous_curve"], [18, 4, 1, "", "continuous_line"], [18, 4, 1, "", "display"], [18, 4, 1, "", "draw_stripes"], [18, 4, 1, "", "striped_line"]], "highway_env.road.graphics.RoadGraphics": [[18, 4, 1, "", "display"], [18, 4, 1, "", "display_road_objects"], [18, 4, 1, "", "display_traffic"]], "highway_env.road.graphics.RoadObjectGraphics": [[18, 4, 1, "", "blit_rotate"], [18, 4, 1, "", "display"]], "highway_env.road.graphics.WorldSurface": [[18, 4, 1, "", "handle_event"], [18, 4, 1, "", "is_visible"], [18, 4, 1, "", "move_display_window_to"], [18, 4, 1, "", "pix"], [18, 4, 1, "", "pos2pix"], [18, 4, 1, "", "vec2pix"]], "highway_env.road.lane": [[4, 2, 1, "", "AbstractLane"], [4, 2, 1, "", "CircularLane"], [4, 2, 1, "", "LineType"], [4, 2, 1, "", "PolyLane"], [4, 2, 1, "", "PolyLaneFixedWidth"], [4, 2, 1, "", "SineLane"], [4, 2, 1, "", "StraightLane"]], "highway_env.road.lane.AbstractLane": [[4, 4, 1, "", "distance"], [4, 4, 1, "", "distance_with_heading"], [4, 4, 1, "", "from_config"], [4, 4, 1, "", "heading_at"], [4, 4, 1, "", "is_reachable_from"], [4, 4, 1, "", "local_angle"], [4, 4, 1, "", "local_coordinates"], [4, 3, 1, "", "metaclass__"], [4, 4, 1, "", "on_lane"], [4, 4, 1, "", "position"], [4, 4, 1, "", "to_config"], [4, 4, 1, "", "width_at"]], "highway_env.road.lane.CircularLane": [[4, 4, 1, "", "from_config"], [4, 4, 1, "", "heading_at"], [4, 4, 1, "", "local_coordinates"], [4, 4, 1, "", "position"], [4, 4, 1, "", "to_config"], [4, 4, 1, "", "width_at"]], "highway_env.road.lane.PolyLane": [[4, 4, 1, "", "to_config"], [4, 4, 1, "", "width_at"]], "highway_env.road.lane.PolyLaneFixedWidth": [[4, 4, 1, "", "from_config"], [4, 4, 1, "", "heading_at"], [4, 4, 1, "", "local_coordinates"], [4, 4, 1, "", "position"], [4, 4, 1, "", "to_config"], [4, 4, 1, "", "width_at"]], "highway_env.road.lane.SineLane": [[4, 4, 1, "", "from_config"], [4, 4, 1, "", "heading_at"], [4, 4, 1, "", "local_coordinates"], [4, 4, 1, "", "position"], [4, 4, 1, "", "to_config"]], "highway_env.road.lane.StraightLane": [[4, 4, 1, "", "from_config"], [4, 4, 1, "", "heading_at"], [4, 4, 1, "", "local_coordinates"], [4, 4, 1, "", "position"], [4, 4, 1, "", "to_config"], [4, 4, 1, "", "width_at"]], "highway_env.road.regulation": [[5, 2, 1, "", "RegulatedRoad"]], "highway_env.road.regulation.RegulatedRoad": [[5, 4, 1, "", "enforce_road_rules"], [5, 4, 1, "", "respect_priorities"], [5, 4, 1, "", "step"]], "highway_env.road.road": [[6, 2, 1, "", "Road"]], "highway_env.road.road.Road": [[6, 4, 1, "", "act"], [6, 4, 1, "", "neighbour_vehicles"], [6, 4, 1, "", "step"]], "highway_env.vehicle": [[7, 0, 0, "-", "behavior"], [8, 0, 0, "-", "controller"], [18, 0, 0, "-", "graphics"], [9, 0, 0, "-", "kinematics"]], "highway_env.vehicle.behavior": [[7, 2, 1, "", "AggressiveVehicle"], [7, 2, 1, "", "DefensiveVehicle"], [7, 2, 1, "", "IDMVehicle"], [7, 2, 1, "", "LinearVehicle"]], "highway_env.vehicle.behavior.AggressiveVehicle": [[7, 3, 1, "", "target_speed"]], "highway_env.vehicle.behavior.DefensiveVehicle": [[7, 3, 1, "", "target_speed"]], "highway_env.vehicle.behavior.IDMVehicle": [[7, 3, 1, "", "ACC_MAX"], [7, 3, 1, "", "COMFORT_ACC_MAX"], [7, 3, 1, "", "COMFORT_ACC_MIN"], [7, 3, 1, "", "DELTA"], [7, 3, 1, "", "DELTA_RANGE"], [7, 3, 1, "", "DISTANCE_WANTED"], [7, 3, 1, "", "TIME_WANTED"], [7, 4, 1, "", "acceleration"], [7, 4, 1, "", "act"], [7, 4, 1, "", "change_lane_policy"], [7, 4, 1, "", "create_from"], [7, 4, 1, "", "desired_gap"], [7, 4, 1, "", "mobil"], [7, 4, 1, "", "recover_from_stop"], [7, 4, 1, "", "step"], [7, 3, 1, "", "target_speed"]], "highway_env.vehicle.behavior.LinearVehicle": [[7, 3, 1, "", "TIME_WANTED"], [7, 4, 1, "", "acceleration"], [7, 4, 1, "", "act"], [7, 4, 1, "", "collect_data"], [7, 4, 1, "", "steering_control"], [7, 4, 1, "", "steering_features"], [7, 3, 1, "", "target_speed"]], "highway_env.vehicle.controller": [[8, 2, 1, "", "ControlledVehicle"], [8, 2, 1, "", "MDPVehicle"]], "highway_env.vehicle.controller.ControlledVehicle": [[8, 4, 1, "", "act"], [8, 4, 1, "", "create_from"], [8, 4, 1, "", "follow_road"], [8, 4, 1, "", "get_routes_at_intersection"], [8, 4, 1, "", "plan_route_to"], [8, 4, 1, "", "predict_trajectory_constant_speed"], [8, 4, 1, "", "set_route_at_intersection"], [8, 4, 1, "", "speed_control"], [8, 4, 1, "", "steering_control"], [8, 3, 1, "", "target_speed"]], "highway_env.vehicle.controller.MDPVehicle": [[8, 4, 1, "", "act"], [8, 4, 1, "", "index_to_speed"], [8, 4, 1, "", "predict_trajectory"], [8, 4, 1, "", "speed_to_index"], [8, 4, 1, "", "speed_to_index_default"], [8, 3, 1, "", "target_speed"]], "highway_env.vehicle.kinematics": [[9, 2, 1, "", "Vehicle"]], "highway_env.vehicle.kinematics.Vehicle": [[9, 3, 1, "", "DEFAULT_INITIAL_SPEEDS"], [9, 3, 1, "", "HISTORY_SIZE"], [9, 3, 1, "", "LENGTH"], [9, 3, 1, "", "MAX_SPEED"], [9, 3, 1, "", "MIN_SPEED"], [9, 3, 1, "", "WIDTH"], [9, 4, 1, "", "act"], [9, 4, 1, "", "create_from"], [9, 4, 1, "", "create_random"], [9, 4, 1, "", "predict_trajectory"], [9, 4, 1, "", "step"]]}, "objtypes": {"0": "py:module", "1": "py:function", "2": "py:class", "3": "py:attribute", "4": "py:method", "5": "py:property"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "function", "Python function"], "2": ["py", "class", "Python class"], "3": ["py", "attribute", "Python attribute"], "4": ["py", "method", "Python method"], "5": ["py", "property", "Python property"]}, "titleterms": {"404": 0, "page": 0, "Not": 0, "found": 0, "action": [1, 22], "continu": 1, "discret": 1, "meta": 1, "manual": 1, "control": [1, 8, 22], "api": [1, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 21, 23], "bibliographi": 2, "dynam": 3, "road": [3, 5, 6], "vehicl": [3, 21, 22, 23], "lane": 4, "regul": 5, "behavior": 7, "longitudin": [7, 8], "later": [7, 8], "posit": 8, "head": 8, "kinemat": [9, 17, 23], "highwai": [10, 17, 19], "usag": [10, 12, 13, 14, 15, 16], "default": [10, 12, 13, 14, 15, 16], "configur": [10, 12, 13, 14, 15, 16, 21, 23, 24], "faster": 10, "variant": 10, "The": [11, 22], "environ": [11, 17, 21, 24, 25], "intersect": 12, "merg": 13, "park": 14, "racetrack": 15, "roundabout": 16, "frequent": 17, "ask": 17, "question": 17, "when": 17, "i": [17, 23], "try": 17, "make": [17, 21, 24], "an": [17, 24], "get": [17, 24], "error": 17, "gymnasium": 17, "namenotfound": 17, "doesn": 17, "t": 17, "exist": 17, "train": [17, 24], "agent": [17, 22, 24], "us": 17, "observ": [17, 22, 23], "mlp": 17, "model": 17, "result": 17, "polici": 17, "optim": 17, "why": 17, "my": 17, "video": 17, "ar": 17, "too": 17, "fast": 17, "have": 17, "low": 17, "framer": 17, "graphic": 18, "world": 18, "surfac": 18, "scene": [18, 21], "welcom": 19, "env": 19, "": 19, "document": 19, "how": 19, "cite": 19, "thi": 19, "work": 19, "instal": 20, "prerequisit": 20, "ubuntu": 20, "window": 20, "10": 20, "stabl": 20, "releas": 20, "develop": 20, "version": 20, "your": 21, "own": 21, "set": [21, 22], "up": [21, 22], "file": 21, "creat": 21, "regist": 21, "profit": 21, "multi": 22, "increas": 22, "number": 22, "chang": 22, "space": 22, "wrap": 22, "exampl": [23, 24], "grayscal": 23, "imag": 23, "illustr": 23, "stack": 23, "mechan": 23, "occup": 23, "grid": 23, "presenc": 23, "featur": 23, "one": 23, "close": 23, "north": 23, "farther": 23, "east": 23, "v_x": 23, "drive": 23, "same": 23, "speed": 23, "ego": 23, "bit": 23, "slower": 23, "time": 23, "collis": 23, "lidar": 23, "start": 24, "all": 24, "googl": 24, "colab": 24, "reward": 25, "most": 25, "goal": 25, "user": 26, "guid": 26}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.viewcode": 1, "sphinxcontrib.bibtex": 9, "sphinx": 60}, "alltitles": {"404": [[0, "id1"]], "Page Not Found": [[0, "page-not-found"]], "Actions": [[1, "actions"]], "Continuous Actions": [[1, "continuous-actions"]], "Discrete Actions": [[1, "discrete-actions"]], "Discrete Meta-Actions": [[1, "discrete-meta-actions"]], "Manual control": [[1, "manual-control"]], "API": [[1, "module-highway_env.envs.common.action"], [4, "module-highway_env.road.lane"], [5, "module-highway_env.road.regulation"], [6, "module-highway_env.road.road"], [7, "module-highway_env.vehicle.behavior"], [8, "module-highway_env.vehicle.controller"], [9, "module-highway_env.vehicle.kinematics"], [10, "api"], [12, "api"], [13, "api"], [14, "api"], [15, "api"], [16, "api"], [18, "module-highway_env.envs.common.graphics"], [21, "module-highway_env.__init__"], [23, "module-highway_env.envs.common.observation"]], "Bibliography": [[2, "bibliography"]], "Dynamics": [[3, "dynamics"]], "Roads": [[3, "roads"]], "Vehicles": [[3, "vehicles"]], "Lane": [[4, "lane"]], "Road regulation": [[5, "road-regulation"]], "Road": [[6, "road"]], "Behavior": [[7, "behavior"]], "Longitudinal Behavior": [[7, "longitudinal-behavior"]], "Lateral Behavior": [[7, "lateral-behavior"]], "Control": [[8, "control"]], "Longitudinal controller": [[8, "longitudinal-controller"]], "Lateral controller": [[8, "lateral-controller"]], "Position control": [[8, "position-control"]], "Heading control": [[8, "heading-control"]], "Kinematics": [[9, "kinematics"], [23, "kinematics"]], "Highway": [[10, "highway"]], "Usage": [[10, "usage"], [12, "usage"], [13, "usage"], [14, "usage"], [15, "usage"], [16, "usage"]], "Default configuration": [[10, "default-configuration"], [12, "default-configuration"], [13, "default-configuration"], [14, "default-configuration"], [15, "default-configuration"], [16, "default-configuration"]], "Faster variant": [[10, "faster-variant"]], "The environments": [[11, "the-environments"]], "Intersection": [[12, "intersection"]], "Merge": [[13, "merge"]], "Parking": [[14, "parking"]], "Racetrack": [[15, "racetrack"]], "Roundabout": [[16, "roundabout"]], "Frequently Asked Questions": [[17, "frequently-asked-questions"]], "When I try to make an environment, I get an error gymnasium.error.NameNotFound: Environment highway doesn't exist.": [[17, "when-i-try-to-make-an-environment-i-get-an-error-gymnasium-error-namenotfound-environment-highway-doesn-t-exist"]], "I try to train an agent using the Kinematics Observation and an MLP model, but the resulting policy is not optimal. Why?": [[17, "i-try-to-train-an-agent-using-the-kinematics-observation-and-an-mlp-model-but-the-resulting-policy-is-not-optimal-why"]], "My videos are too fast / have a low framerate.": [[17, "my-videos-are-too-fast-have-a-low-framerate"]], "Graphics": [[18, "id1"]], "World surface": [[18, "world-surface"]], "Scene graphics": [[18, "scene-graphics"]], "Welcome to highway-env\u2019s documentation!": [[19, "welcome-to-highway-env-s-documentation"]], "How to cite this work?": [[19, "how-to-cite-this-work"]], "Installation": [[20, "installation"]], "Prerequisites": [[20, "prerequisites"]], "Ubuntu": [[20, "ubuntu"]], "Windows 10": [[20, "windows-10"]], "Stable release": [[20, "stable-release"]], "Development version": [[20, "development-version"]], "Make your own environment": [[21, "make-your-own-environment"]], "Set up files": [[21, "set-up-files"]], "Create the scene": [[21, "create-the-scene"]], "Create the vehicles": [[21, "create-the-vehicles"]], "Make the environment configurable": [[21, "make-the-environment-configurable"]], "Register the environment": [[21, "register-the-environment"]], "Profit": [[21, "profit"]], "The Multi-Agent setting": [[22, "the-multi-agent-setting"]], "Increase the number of controlled vehicles": [[22, "increase-the-number-of-controlled-vehicles"]], "Change the action space": [[22, "change-the-action-space"]], "Change the observation space": [[22, "change-the-observation-space"]], "Wrapping it up": [[22, "wrapping-it-up"]], "Observations": [[23, "id1"]], "Example configuration": [[23, "example-configuration"], [23, "grayscale-example-configuration"], [23, "id4"], [23, "id5"], [23, "id6"]], "Grayscale Image": [[23, "grayscale-image"]], "Illustration of the stack mechanism": [[23, "illustration-of-the-stack-mechanism"]], "Occupancy grid": [[23, "occupancy-grid"]], "presence feature: one vehicle is close to the north, and one is farther to the east.": [[23, "id7"]], "v_x feature: the north vehicle drives at the same speed as the ego-vehicle, and the east vehicle a bit slower": [[23, "id8"]], "Time to collision": [[23, "time-to-collision"]], "Lidar": [[23, "lidar"]], "the Lidar observation": [[23, "id9"]], "Getting Started": [[24, "getting-started"]], "Making an environment": [[24, "making-an-environment"]], "All the environments": [[24, "all-the-environments"]], "Configuring an environment": [[24, "configuring-an-environment"]], "Training an agent": [[24, "training-an-agent"]], "Examples on Google Colab": [[24, "examples-on-google-colab"]], "Rewards": [[25, "rewards"]], "Most environments": [[25, "most-environments"]], "Goal environments": [[25, "goal-environments"]], "User Guide": [[26, "user-guide"]]}, "indexentries": {"acceleration_range (highway_env.envs.common.action.continuousaction attribute)": [[1, "highway_env.envs.common.action.ContinuousAction.ACCELERATION_RANGE"]], "actions_all (highway_env.envs.common.action.discretemetaaction attribute)": [[1, "highway_env.envs.common.action.DiscreteMetaAction.ACTIONS_ALL"]], "actions_lat (highway_env.envs.common.action.discretemetaaction attribute)": [[1, "highway_env.envs.common.action.DiscreteMetaAction.ACTIONS_LAT"]], "actions_longi (highway_env.envs.common.action.discretemetaaction attribute)": [[1, "highway_env.envs.common.action.DiscreteMetaAction.ACTIONS_LONGI"]], "actiontype (class in highway_env.envs.common.action)": [[1, "highway_env.envs.common.action.ActionType"]], "continuousaction (class in highway_env.envs.common.action)": [[1, "highway_env.envs.common.action.ContinuousAction"]], "discreteaction (class in highway_env.envs.common.action)": [[1, "highway_env.envs.common.action.DiscreteAction"]], "discretemetaaction (class in highway_env.envs.common.action)": [[1, "highway_env.envs.common.action.DiscreteMetaAction"]], "multiagentaction (class in highway_env.envs.common.action)": [[1, "highway_env.envs.common.action.MultiAgentAction"]], "steering_range (highway_env.envs.common.action.continuousaction attribute)": [[1, "highway_env.envs.common.action.ContinuousAction.STEERING_RANGE"]], "act() (highway_env.envs.common.action.actiontype method)": [[1, "highway_env.envs.common.action.ActionType.act"]], "act() (highway_env.envs.common.action.continuousaction method)": [[1, "highway_env.envs.common.action.ContinuousAction.act"]], "act() (highway_env.envs.common.action.discreteaction method)": [[1, "highway_env.envs.common.action.DiscreteAction.act"]], "act() (highway_env.envs.common.action.discretemetaaction method)": [[1, "highway_env.envs.common.action.DiscreteMetaAction.act"]], "act() (highway_env.envs.common.action.multiagentaction method)": [[1, "highway_env.envs.common.action.MultiAgentAction.act"]], "controlled_vehicle (highway_env.envs.common.action.actiontype property)": [[1, "highway_env.envs.common.action.ActionType.controlled_vehicle"]], "get_available_actions() (highway_env.envs.common.action.actiontype method)": [[1, "highway_env.envs.common.action.ActionType.get_available_actions"]], "get_available_actions() (highway_env.envs.common.action.discretemetaaction method)": [[1, "highway_env.envs.common.action.DiscreteMetaAction.get_available_actions"]], "get_available_actions() (highway_env.envs.common.action.multiagentaction method)": [[1, "highway_env.envs.common.action.MultiAgentAction.get_available_actions"]], "highway_env.envs.common.action": [[1, "module-highway_env.envs.common.action"]], "module": [[1, "module-highway_env.envs.common.action"], [4, "module-highway_env.road.lane"], [5, "module-highway_env.road.regulation"], [6, "module-highway_env.road.road"], [7, "module-highway_env.vehicle.behavior"], [8, "module-highway_env.vehicle.controller"], [9, "module-highway_env.vehicle.kinematics"], [18, "module-highway_env.envs.common.graphics"], [18, "module-highway_env.road.graphics"], [18, "module-highway_env.vehicle.graphics"], [21, "module-highway_env.__init__"], [21, "module-highway_env.envs.common.abstract"], [23, "module-highway_env.envs.common.observation"]], "space() (highway_env.envs.common.action.actiontype method)": [[1, "highway_env.envs.common.action.ActionType.space"]], "space() (highway_env.envs.common.action.continuousaction method)": [[1, "highway_env.envs.common.action.ContinuousAction.space"]], "space() (highway_env.envs.common.action.discreteaction method)": [[1, "highway_env.envs.common.action.DiscreteAction.space"]], "space() (highway_env.envs.common.action.discretemetaaction method)": [[1, "highway_env.envs.common.action.DiscreteMetaAction.space"]], "space() (highway_env.envs.common.action.multiagentaction method)": [[1, "highway_env.envs.common.action.MultiAgentAction.space"]], "vehicle_class (highway_env.envs.common.action.actiontype property)": [[1, "highway_env.envs.common.action.ActionType.vehicle_class"]], "vehicle_class (highway_env.envs.common.action.continuousaction property)": [[1, "highway_env.envs.common.action.ContinuousAction.vehicle_class"]], "vehicle_class (highway_env.envs.common.action.discretemetaaction property)": [[1, "highway_env.envs.common.action.DiscreteMetaAction.vehicle_class"]], "vehicle_class (highway_env.envs.common.action.multiagentaction property)": [[1, "highway_env.envs.common.action.MultiAgentAction.vehicle_class"]], "abstractlane (class in highway_env.road.lane)": [[4, "highway_env.road.lane.AbstractLane"]], "circularlane (class in highway_env.road.lane)": [[4, "highway_env.road.lane.CircularLane"]], "linetype (class in highway_env.road.lane)": [[4, "highway_env.road.lane.LineType"]], "polylane (class in highway_env.road.lane)": [[4, "highway_env.road.lane.PolyLane"]], "polylanefixedwidth (class in highway_env.road.lane)": [[4, "highway_env.road.lane.PolyLaneFixedWidth"]], "sinelane (class in highway_env.road.lane)": [[4, "highway_env.road.lane.SineLane"]], "straightlane (class in highway_env.road.lane)": [[4, "highway_env.road.lane.StraightLane"]], "distance() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.distance"]], "distance_with_heading() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.distance_with_heading"]], "from_config() (highway_env.road.lane.abstractlane class method)": [[4, "highway_env.road.lane.AbstractLane.from_config"]], "from_config() (highway_env.road.lane.circularlane class method)": [[4, "highway_env.road.lane.CircularLane.from_config"]], "from_config() (highway_env.road.lane.polylanefixedwidth class method)": [[4, "highway_env.road.lane.PolyLaneFixedWidth.from_config"]], "from_config() (highway_env.road.lane.sinelane class method)": [[4, "highway_env.road.lane.SineLane.from_config"]], "from_config() (highway_env.road.lane.straightlane class method)": [[4, "highway_env.road.lane.StraightLane.from_config"]], "heading_at() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.heading_at"]], "heading_at() (highway_env.road.lane.circularlane method)": [[4, "highway_env.road.lane.CircularLane.heading_at"]], "heading_at() (highway_env.road.lane.polylanefixedwidth method)": [[4, "highway_env.road.lane.PolyLaneFixedWidth.heading_at"]], "heading_at() (highway_env.road.lane.sinelane method)": [[4, "highway_env.road.lane.SineLane.heading_at"]], "heading_at() (highway_env.road.lane.straightlane method)": [[4, "highway_env.road.lane.StraightLane.heading_at"]], "highway_env.road.lane": [[4, "module-highway_env.road.lane"]], "is_reachable_from() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.is_reachable_from"]], "local_angle() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.local_angle"]], "local_coordinates() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.local_coordinates"]], "local_coordinates() (highway_env.road.lane.circularlane method)": [[4, "highway_env.road.lane.CircularLane.local_coordinates"]], "local_coordinates() (highway_env.road.lane.polylanefixedwidth method)": [[4, "highway_env.road.lane.PolyLaneFixedWidth.local_coordinates"]], "local_coordinates() (highway_env.road.lane.sinelane method)": [[4, "highway_env.road.lane.SineLane.local_coordinates"]], "local_coordinates() (highway_env.road.lane.straightlane method)": [[4, "highway_env.road.lane.StraightLane.local_coordinates"]], "metaclass__ (highway_env.road.lane.abstractlane attribute)": [[4, "highway_env.road.lane.AbstractLane.metaclass__"]], "on_lane() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.on_lane"]], "position() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.position"]], "position() (highway_env.road.lane.circularlane method)": [[4, "highway_env.road.lane.CircularLane.position"]], "position() (highway_env.road.lane.polylanefixedwidth method)": [[4, "highway_env.road.lane.PolyLaneFixedWidth.position"]], "position() (highway_env.road.lane.sinelane method)": [[4, "highway_env.road.lane.SineLane.position"]], "position() (highway_env.road.lane.straightlane method)": [[4, "highway_env.road.lane.StraightLane.position"]], "to_config() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.to_config"]], "to_config() (highway_env.road.lane.circularlane method)": [[4, "highway_env.road.lane.CircularLane.to_config"]], "to_config() (highway_env.road.lane.polylane method)": [[4, "highway_env.road.lane.PolyLane.to_config"]], "to_config() (highway_env.road.lane.polylanefixedwidth method)": [[4, "highway_env.road.lane.PolyLaneFixedWidth.to_config"]], "to_config() (highway_env.road.lane.sinelane method)": [[4, "highway_env.road.lane.SineLane.to_config"]], "to_config() (highway_env.road.lane.straightlane method)": [[4, "highway_env.road.lane.StraightLane.to_config"]], "width_at() (highway_env.road.lane.abstractlane method)": [[4, "highway_env.road.lane.AbstractLane.width_at"]], "width_at() (highway_env.road.lane.circularlane method)": [[4, "highway_env.road.lane.CircularLane.width_at"]], "width_at() (highway_env.road.lane.polylane method)": [[4, "highway_env.road.lane.PolyLane.width_at"]], "width_at() (highway_env.road.lane.polylanefixedwidth method)": [[4, "highway_env.road.lane.PolyLaneFixedWidth.width_at"]], "width_at() (highway_env.road.lane.straightlane method)": [[4, "highway_env.road.lane.StraightLane.width_at"]], "regulatedroad (class in highway_env.road.regulation)": [[5, "highway_env.road.regulation.RegulatedRoad"]], "enforce_road_rules() (highway_env.road.regulation.regulatedroad method)": [[5, "highway_env.road.regulation.RegulatedRoad.enforce_road_rules"]], "highway_env.road.regulation": [[5, "module-highway_env.road.regulation"]], "respect_priorities() (highway_env.road.regulation.regulatedroad static method)": [[5, "highway_env.road.regulation.RegulatedRoad.respect_priorities"]], "step() (highway_env.road.regulation.regulatedroad method)": [[5, "highway_env.road.regulation.RegulatedRoad.step"]], "road (class in highway_env.road.road)": [[6, "highway_env.road.road.Road"]], "act() (highway_env.road.road.road method)": [[6, "highway_env.road.road.Road.act"]], "highway_env.road.road": [[6, "module-highway_env.road.road"]], "neighbour_vehicles() (highway_env.road.road.road method)": [[6, "highway_env.road.road.Road.neighbour_vehicles"]], "step() (highway_env.road.road.road method)": [[6, "highway_env.road.road.Road.step"]], "acc_max (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.ACC_MAX"]], "aggressivevehicle (class in highway_env.vehicle.behavior)": [[7, "highway_env.vehicle.behavior.AggressiveVehicle"]], "comfort_acc_max (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.COMFORT_ACC_MAX"]], "comfort_acc_min (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.COMFORT_ACC_MIN"]], "delta (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.DELTA"]], "delta_range (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.DELTA_RANGE"]], "distance_wanted (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.DISTANCE_WANTED"]], "defensivevehicle (class in highway_env.vehicle.behavior)": [[7, "highway_env.vehicle.behavior.DefensiveVehicle"]], "idmvehicle (class in highway_env.vehicle.behavior)": [[7, "highway_env.vehicle.behavior.IDMVehicle"]], "linearvehicle (class in highway_env.vehicle.behavior)": [[7, "highway_env.vehicle.behavior.LinearVehicle"]], "time_wanted (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.TIME_WANTED"]], "time_wanted (highway_env.vehicle.behavior.linearvehicle attribute)": [[7, "highway_env.vehicle.behavior.LinearVehicle.TIME_WANTED"]], "acceleration() (highway_env.vehicle.behavior.idmvehicle method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.acceleration"]], "acceleration() (highway_env.vehicle.behavior.linearvehicle method)": [[7, "highway_env.vehicle.behavior.LinearVehicle.acceleration"]], "act() (highway_env.vehicle.behavior.idmvehicle method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.act"]], "act() (highway_env.vehicle.behavior.linearvehicle method)": [[7, "highway_env.vehicle.behavior.LinearVehicle.act"]], "change_lane_policy() (highway_env.vehicle.behavior.idmvehicle method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.change_lane_policy"]], "collect_data() (highway_env.vehicle.behavior.linearvehicle method)": [[7, "highway_env.vehicle.behavior.LinearVehicle.collect_data"]], "create_from() (highway_env.vehicle.behavior.idmvehicle class method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.create_from"]], "desired_gap() (highway_env.vehicle.behavior.idmvehicle method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.desired_gap"]], "highway_env.vehicle.behavior": [[7, "module-highway_env.vehicle.behavior"]], "mobil() (highway_env.vehicle.behavior.idmvehicle method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.mobil"]], "recover_from_stop() (highway_env.vehicle.behavior.idmvehicle method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.recover_from_stop"]], "steering_control() (highway_env.vehicle.behavior.linearvehicle method)": [[7, "highway_env.vehicle.behavior.LinearVehicle.steering_control"]], "steering_features() (highway_env.vehicle.behavior.linearvehicle method)": [[7, "highway_env.vehicle.behavior.LinearVehicle.steering_features"]], "step() (highway_env.vehicle.behavior.idmvehicle method)": [[7, "highway_env.vehicle.behavior.IDMVehicle.step"]], "target_speed (highway_env.vehicle.behavior.aggressivevehicle attribute)": [[7, "highway_env.vehicle.behavior.AggressiveVehicle.target_speed"]], "target_speed (highway_env.vehicle.behavior.defensivevehicle attribute)": [[7, "highway_env.vehicle.behavior.DefensiveVehicle.target_speed"]], "target_speed (highway_env.vehicle.behavior.idmvehicle attribute)": [[7, "highway_env.vehicle.behavior.IDMVehicle.target_speed"]], "target_speed (highway_env.vehicle.behavior.linearvehicle attribute)": [[7, "highway_env.vehicle.behavior.LinearVehicle.target_speed"]], "controlledvehicle (class in highway_env.vehicle.controller)": [[8, "highway_env.vehicle.controller.ControlledVehicle"]], "mdpvehicle (class in highway_env.vehicle.controller)": [[8, "highway_env.vehicle.controller.MDPVehicle"]], "act() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.act"]], "act() (highway_env.vehicle.controller.mdpvehicle method)": [[8, "highway_env.vehicle.controller.MDPVehicle.act"]], "create_from() (highway_env.vehicle.controller.controlledvehicle class method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.create_from"]], "follow_road() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.follow_road"]], "get_routes_at_intersection() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.get_routes_at_intersection"]], "highway_env.vehicle.controller": [[8, "module-highway_env.vehicle.controller"]], "index_to_speed() (highway_env.vehicle.controller.mdpvehicle method)": [[8, "highway_env.vehicle.controller.MDPVehicle.index_to_speed"]], "plan_route_to() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.plan_route_to"]], "predict_trajectory() (highway_env.vehicle.controller.mdpvehicle method)": [[8, "highway_env.vehicle.controller.MDPVehicle.predict_trajectory"]], "predict_trajectory_constant_speed() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.predict_trajectory_constant_speed"]], "set_route_at_intersection() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.set_route_at_intersection"]], "speed_control() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.speed_control"]], "speed_to_index() (highway_env.vehicle.controller.mdpvehicle method)": [[8, "highway_env.vehicle.controller.MDPVehicle.speed_to_index"]], "speed_to_index_default() (highway_env.vehicle.controller.mdpvehicle class method)": [[8, "highway_env.vehicle.controller.MDPVehicle.speed_to_index_default"]], "steering_control() (highway_env.vehicle.controller.controlledvehicle method)": [[8, "highway_env.vehicle.controller.ControlledVehicle.steering_control"]], "target_speed (highway_env.vehicle.controller.controlledvehicle attribute)": [[8, "highway_env.vehicle.controller.ControlledVehicle.target_speed"]], "target_speed (highway_env.vehicle.controller.mdpvehicle attribute)": [[8, "highway_env.vehicle.controller.MDPVehicle.target_speed"]], "default_initial_speeds (highway_env.vehicle.kinematics.vehicle attribute)": [[9, "highway_env.vehicle.kinematics.Vehicle.DEFAULT_INITIAL_SPEEDS"]], "history_size (highway_env.vehicle.kinematics.vehicle attribute)": [[9, "highway_env.vehicle.kinematics.Vehicle.HISTORY_SIZE"]], "length (highway_env.vehicle.kinematics.vehicle attribute)": [[9, "highway_env.vehicle.kinematics.Vehicle.LENGTH"]], "max_speed (highway_env.vehicle.kinematics.vehicle attribute)": [[9, "highway_env.vehicle.kinematics.Vehicle.MAX_SPEED"]], "min_speed (highway_env.vehicle.kinematics.vehicle attribute)": [[9, "highway_env.vehicle.kinematics.Vehicle.MIN_SPEED"]], "vehicle (class in highway_env.vehicle.kinematics)": [[9, "highway_env.vehicle.kinematics.Vehicle"]], "width (highway_env.vehicle.kinematics.vehicle attribute)": [[9, "highway_env.vehicle.kinematics.Vehicle.WIDTH"]], "act() (highway_env.vehicle.kinematics.vehicle method)": [[9, "highway_env.vehicle.kinematics.Vehicle.act"]], "create_from() (highway_env.vehicle.kinematics.vehicle class method)": [[9, "highway_env.vehicle.kinematics.Vehicle.create_from"]], "create_random() (highway_env.vehicle.kinematics.vehicle class method)": [[9, "highway_env.vehicle.kinematics.Vehicle.create_random"]], "highway_env.vehicle.kinematics": [[9, "module-highway_env.vehicle.kinematics"]], "predict_trajectory() (highway_env.vehicle.kinematics.vehicle method)": [[9, "highway_env.vehicle.kinematics.Vehicle.predict_trajectory"]], "step() (highway_env.vehicle.kinematics.vehicle method)": [[9, "highway_env.vehicle.kinematics.Vehicle.step"]], "highwayenv (class in highway_env.envs.highway_env)": [[10, "highway_env.envs.highway_env.HighwayEnv"]], "default_config() (highway_env.envs.highway_env.highwayenv class method)": [[10, "highway_env.envs.highway_env.HighwayEnv.default_config"]], "intersectionenv (class in highway_env.envs.intersection_env)": [[12, "highway_env.envs.intersection_env.IntersectionEnv"]], "default_config() (highway_env.envs.intersection_env.intersectionenv class method)": [[12, "highway_env.envs.intersection_env.IntersectionEnv.default_config"]], "step() (highway_env.envs.intersection_env.intersectionenv method)": [[12, "highway_env.envs.intersection_env.IntersectionEnv.step"]], "mergeenv (class in highway_env.envs.merge_env)": [[13, "highway_env.envs.merge_env.MergeEnv"]], "default_config() (highway_env.envs.merge_env.mergeenv class method)": [[13, "highway_env.envs.merge_env.MergeEnv.default_config"]], "parkingenv (class in highway_env.envs.parking_env)": [[14, "highway_env.envs.parking_env.ParkingEnv"]], "compute_reward() (highway_env.envs.parking_env.parkingenv method)": [[14, "highway_env.envs.parking_env.ParkingEnv.compute_reward"]], "default_config() (highway_env.envs.parking_env.parkingenv class method)": [[14, "highway_env.envs.parking_env.ParkingEnv.default_config"]], "define_spaces() (highway_env.envs.parking_env.parkingenv method)": [[14, "highway_env.envs.parking_env.ParkingEnv.define_spaces"]], "racetrackenv (class in highway_env.envs.racetrack_env)": [[15, "highway_env.envs.racetrack_env.RacetrackEnv"]], "default_config() (highway_env.envs.racetrack_env.racetrackenv class method)": [[15, "highway_env.envs.racetrack_env.RacetrackEnv.default_config"]], "roundaboutenv (class in highway_env.envs.roundabout_env)": [[16, "highway_env.envs.roundabout_env.RoundaboutEnv"]], "default_config() (highway_env.envs.roundabout_env.roundaboutenv class method)": [[16, "highway_env.envs.roundabout_env.RoundaboutEnv.default_config"]], "envviewer (class in highway_env.envs.common.graphics)": [[18, "highway_env.envs.common.graphics.EnvViewer"]], "lanegraphics (class in highway_env.road.graphics)": [[18, "highway_env.road.graphics.LaneGraphics"]], "roadgraphics (class in highway_env.road.graphics)": [[18, "highway_env.road.graphics.RoadGraphics"]], "roadobjectgraphics (class in highway_env.road.graphics)": [[18, "highway_env.road.graphics.RoadObjectGraphics"]], "stripe_length (highway_env.road.graphics.lanegraphics attribute)": [[18, "highway_env.road.graphics.LaneGraphics.STRIPE_LENGTH"]], "stripe_spacing (highway_env.road.graphics.lanegraphics attribute)": [[18, "highway_env.road.graphics.LaneGraphics.STRIPE_SPACING"]], "stripe_width (highway_env.road.graphics.lanegraphics attribute)": [[18, "highway_env.road.graphics.LaneGraphics.STRIPE_WIDTH"]], "worldsurface (class in highway_env.road.graphics)": [[18, "highway_env.road.graphics.WorldSurface"]], "blit_rotate() (highway_env.road.graphics.roadobjectgraphics static method)": [[18, "highway_env.road.graphics.RoadObjectGraphics.blit_rotate"]], "close() (highway_env.envs.common.graphics.envviewer method)": [[18, "highway_env.envs.common.graphics.EnvViewer.close"]], "continuous_curve() (highway_env.road.graphics.lanegraphics class method)": [[18, "highway_env.road.graphics.LaneGraphics.continuous_curve"]], "continuous_line() (highway_env.road.graphics.lanegraphics class method)": [[18, "highway_env.road.graphics.LaneGraphics.continuous_line"]], "display() (highway_env.envs.common.graphics.envviewer method)": [[18, "highway_env.envs.common.graphics.EnvViewer.display"]], "display() (highway_env.road.graphics.lanegraphics class method)": [[18, "highway_env.road.graphics.LaneGraphics.display"]], "display() (highway_env.road.graphics.roadgraphics static method)": [[18, "highway_env.road.graphics.RoadGraphics.display"]], "display() (highway_env.road.graphics.roadobjectgraphics class method)": [[18, "highway_env.road.graphics.RoadObjectGraphics.display"]], "display_road_objects() (highway_env.road.graphics.roadgraphics static method)": [[18, "highway_env.road.graphics.RoadGraphics.display_road_objects"]], "display_traffic() (highway_env.road.graphics.roadgraphics static method)": [[18, "highway_env.road.graphics.RoadGraphics.display_traffic"]], "draw_stripes() (highway_env.road.graphics.lanegraphics class method)": [[18, "highway_env.road.graphics.LaneGraphics.draw_stripes"]], "get_image() (highway_env.envs.common.graphics.envviewer method)": [[18, "highway_env.envs.common.graphics.EnvViewer.get_image"]], "handle_event() (highway_env.road.graphics.worldsurface method)": [[18, "highway_env.road.graphics.WorldSurface.handle_event"]], "handle_events() (highway_env.envs.common.graphics.envviewer method)": [[18, "highway_env.envs.common.graphics.EnvViewer.handle_events"]], "highway_env.envs.common.graphics": [[18, "module-highway_env.envs.common.graphics"]], "highway_env.road.graphics": [[18, "module-highway_env.road.graphics"]], "highway_env.vehicle.graphics": [[18, "module-highway_env.vehicle.graphics"]], "is_visible() (highway_env.road.graphics.worldsurface method)": [[18, "highway_env.road.graphics.WorldSurface.is_visible"]], "move_display_window_to() (highway_env.road.graphics.worldsurface method)": [[18, "highway_env.road.graphics.WorldSurface.move_display_window_to"]], "pix() (highway_env.road.graphics.worldsurface method)": [[18, "highway_env.road.graphics.WorldSurface.pix"]], "pos2pix() (highway_env.road.graphics.worldsurface method)": [[18, "highway_env.road.graphics.WorldSurface.pos2pix"]], "set_agent_action_sequence() (highway_env.envs.common.graphics.envviewer method)": [[18, "highway_env.envs.common.graphics.EnvViewer.set_agent_action_sequence"]], "set_agent_display() (highway_env.envs.common.graphics.envviewer method)": [[18, "highway_env.envs.common.graphics.EnvViewer.set_agent_display"]], "striped_line() (highway_env.road.graphics.lanegraphics class method)": [[18, "highway_env.road.graphics.LaneGraphics.striped_line"]], "vec2pix() (highway_env.road.graphics.worldsurface method)": [[18, "highway_env.road.graphics.WorldSurface.vec2pix"]], "window_position() (highway_env.envs.common.graphics.envviewer method)": [[18, "highway_env.envs.common.graphics.EnvViewer.window_position"]], "abstractenv (class in highway_env.envs.common.abstract)": [[21, "highway_env.envs.common.abstract.AbstractEnv"]], "multiagentwrapper (class in highway_env.envs.common.abstract)": [[21, "highway_env.envs.common.abstract.MultiAgentWrapper"]], "perception_distance (highway_env.envs.common.abstract.abstractenv attribute)": [[21, "highway_env.envs.common.abstract.AbstractEnv.PERCEPTION_DISTANCE"]], "_automatic_rendering() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._automatic_rendering"]], "_info() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._info"]], "_is_terminated() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._is_terminated"]], "_is_truncated() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._is_truncated"]], "_reset() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._reset"]], "_reward() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._reward"]], "_rewards() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._rewards"]], "_simulate() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv._simulate"]], "change_vehicles() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.change_vehicles"]], "close() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.close"]], "default_config() (highway_env.envs.common.abstract.abstractenv class method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.default_config"]], "define_spaces() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.define_spaces"]], "highway_env.__init__": [[21, "module-highway_env.__init__"]], "highway_env.envs.common.abstract": [[21, "module-highway_env.envs.common.abstract"]], "register_highway_envs() (in module highway_env.__init__)": [[21, "highway_env.__init__.register_highway_envs"]], "render() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.render"]], "reset() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.reset"]], "simplify() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.simplify"]], "step() (highway_env.envs.common.abstract.abstractenv method)": [[21, "highway_env.envs.common.abstract.AbstractEnv.step"]], "step() (highway_env.envs.common.abstract.multiagentwrapper method)": [[21, "highway_env.envs.common.abstract.MultiAgentWrapper.step"]], "vehicle (highway_env.envs.common.abstract.abstractenv property)": [[21, "highway_env.envs.common.abstract.AbstractEnv.vehicle"]], "exitobservation (class in highway_env.envs.common.observation)": [[23, "highway_env.envs.common.observation.ExitObservation"]], "grayscaleobservation (class in highway_env.envs.common.observation)": [[23, "highway_env.envs.common.observation.GrayscaleObservation"]], "kinematicobservation (class in highway_env.envs.common.observation)": [[23, "highway_env.envs.common.observation.KinematicObservation"]], "kinematicsgoalobservation (class in highway_env.envs.common.observation)": [[23, "highway_env.envs.common.observation.KinematicsGoalObservation"]], "occupancygridobservation (class in highway_env.envs.common.observation)": [[23, "highway_env.envs.common.observation.OccupancyGridObservation"]], "fill_road_layer_by_cell() (highway_env.envs.common.observation.occupancygridobservation method)": [[23, "highway_env.envs.common.observation.OccupancyGridObservation.fill_road_layer_by_cell"]], "fill_road_layer_by_lanes() (highway_env.envs.common.observation.occupancygridobservation method)": [[23, "highway_env.envs.common.observation.OccupancyGridObservation.fill_road_layer_by_lanes"]], "highway_env.envs.common.observation": [[23, "module-highway_env.envs.common.observation"]], "normalize() (highway_env.envs.common.observation.occupancygridobservation method)": [[23, "highway_env.envs.common.observation.OccupancyGridObservation.normalize"]], "normalize_obs() (highway_env.envs.common.observation.kinematicobservation method)": [[23, "highway_env.envs.common.observation.KinematicObservation.normalize_obs"]], "observe() (highway_env.envs.common.observation.exitobservation method)": [[23, "highway_env.envs.common.observation.ExitObservation.observe"]], "observe() (highway_env.envs.common.observation.grayscaleobservation method)": [[23, "highway_env.envs.common.observation.GrayscaleObservation.observe"]], "observe() (highway_env.envs.common.observation.kinematicobservation method)": [[23, "highway_env.envs.common.observation.KinematicObservation.observe"]], "observe() (highway_env.envs.common.observation.kinematicsgoalobservation method)": [[23, "highway_env.envs.common.observation.KinematicsGoalObservation.observe"]], "observe() (highway_env.envs.common.observation.occupancygridobservation method)": [[23, "highway_env.envs.common.observation.OccupancyGridObservation.observe"]], "pos_to_index() (highway_env.envs.common.observation.occupancygridobservation method)": [[23, "highway_env.envs.common.observation.OccupancyGridObservation.pos_to_index"]], "space() (highway_env.envs.common.observation.grayscaleobservation method)": [[23, "highway_env.envs.common.observation.GrayscaleObservation.space"]], "space() (highway_env.envs.common.observation.kinematicobservation method)": [[23, "highway_env.envs.common.observation.KinematicObservation.space"]], "space() (highway_env.envs.common.observation.kinematicsgoalobservation method)": [[23, "highway_env.envs.common.observation.KinematicsGoalObservation.space"]], "space() (highway_env.envs.common.observation.occupancygridobservation method)": [[23, "highway_env.envs.common.observation.OccupancyGridObservation.space"]]}})
\ No newline at end of file