From 139c80ff909003c658c689a7b33de2358e9b3aed Mon Sep 17 00:00:00 2001 From: sidwat Date: Fri, 14 Jun 2024 01:57:31 +0530 Subject: [PATCH 1/2] added the environment file --- __pycache__/PPO.cpython-310.pyc | Bin 0 -> 7116 bytes imperfect_envs/README.md | 0 imperfect_envs/driving/__init__.py | 9 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 531 bytes .../__pycache__/agents.cpython-310.pyc | Bin 0 -> 2579 bytes .../__pycache__/entities.cpython-310.pyc | Bin 0 -> 7115 bytes .../__pycache__/geometry.cpython-310.pyc | Bin 0 -> 7673 bytes .../__pycache__/graphics.cpython-310.pyc | Bin 0 -> 25769 bytes .../__pycache__/visualizer.cpython-310.pyc | Bin 0 -> 2621 bytes .../driving/__pycache__/world.cpython-310.pyc | Bin 0 -> 3042 bytes imperfect_envs/driving/agents.py | 62 ++ imperfect_envs/driving/entities.py | 241 +++++ imperfect_envs/driving/envs/__init__.py | 1 + .../envs/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 374 bytes .../gridworld_continuous.cpython-310.pyc | Bin 0 -> 8188 bytes .../driving/envs/gridworld_continuous.py | 260 +++++ imperfect_envs/driving/geometry.py | 243 +++++ imperfect_envs/driving/graphics.py | 904 ++++++++++++++++++ imperfect_envs/driving/visualizer.py | 82 ++ imperfect_envs/driving/world.py | 83 ++ imperfect_envs/imperfect.egg-info/PKG-INFO | 10 + imperfect_envs/imperfect.egg-info/SOURCES.txt | 7 + .../imperfect.egg-info/dependency_links.txt | 1 + .../imperfect.egg-info/requires.txt | 3 + .../imperfect.egg-info/top_level.txt | 1 + imperfect_envs/reacher/__init__.py | 35 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 750 bytes imperfect_envs/reacher/envs/__init__.py | 2 + .../envs/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 388 bytes .../envs/__pycache__/reacher.cpython-310.pyc | Bin 0 -> 4792 bytes .../reacher/envs/assets/reacher.xml | 39 + .../reacher/envs/assets/reacher_action1.xml | 39 + .../reacher/envs/assets/reacher_action2.xml | 39 + imperfect_envs/reacher/envs/reacher.py | 97 ++ imperfect_envs/setup.py | 6 + 35 files changed, 2164 insertions(+) create mode 100644 __pycache__/PPO.cpython-310.pyc create mode 100644 imperfect_envs/README.md create mode 100644 imperfect_envs/driving/__init__.py create mode 100644 imperfect_envs/driving/__pycache__/__init__.cpython-310.pyc create mode 100644 imperfect_envs/driving/__pycache__/agents.cpython-310.pyc create mode 100644 imperfect_envs/driving/__pycache__/entities.cpython-310.pyc create mode 100644 imperfect_envs/driving/__pycache__/geometry.cpython-310.pyc create mode 100644 imperfect_envs/driving/__pycache__/graphics.cpython-310.pyc create mode 100644 imperfect_envs/driving/__pycache__/visualizer.cpython-310.pyc create mode 100644 imperfect_envs/driving/__pycache__/world.cpython-310.pyc create mode 100644 imperfect_envs/driving/agents.py create mode 100644 imperfect_envs/driving/entities.py create mode 100644 imperfect_envs/driving/envs/__init__.py create mode 100644 imperfect_envs/driving/envs/__pycache__/__init__.cpython-310.pyc create mode 100644 imperfect_envs/driving/envs/__pycache__/gridworld_continuous.cpython-310.pyc create mode 100644 imperfect_envs/driving/envs/gridworld_continuous.py create mode 100644 imperfect_envs/driving/geometry.py create mode 100644 imperfect_envs/driving/graphics.py create mode 100644 imperfect_envs/driving/visualizer.py create mode 100644 imperfect_envs/driving/world.py create mode 100644 imperfect_envs/imperfect.egg-info/PKG-INFO create mode 100644 imperfect_envs/imperfect.egg-info/SOURCES.txt create mode 100644 imperfect_envs/imperfect.egg-info/dependency_links.txt create mode 100644 imperfect_envs/imperfect.egg-info/requires.txt create mode 100644 imperfect_envs/imperfect.egg-info/top_level.txt create mode 100644 imperfect_envs/reacher/__init__.py create mode 100644 imperfect_envs/reacher/__pycache__/__init__.cpython-310.pyc create mode 100644 imperfect_envs/reacher/envs/__init__.py create mode 100644 imperfect_envs/reacher/envs/__pycache__/__init__.cpython-310.pyc create mode 100644 imperfect_envs/reacher/envs/__pycache__/reacher.cpython-310.pyc create mode 100644 imperfect_envs/reacher/envs/assets/reacher.xml create mode 100644 imperfect_envs/reacher/envs/assets/reacher_action1.xml create mode 100644 imperfect_envs/reacher/envs/assets/reacher_action2.xml create mode 100644 imperfect_envs/reacher/envs/reacher.py create mode 100644 imperfect_envs/setup.py diff --git a/__pycache__/PPO.cpython-310.pyc b/__pycache__/PPO.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..00b2a8a17af285630460f02de2e6734b1214c522 GIT binary patch literal 7116 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 literal 0 HcmV?d00001 diff --git a/imperfect_envs/driving/__pycache__/entities.cpython-310.pyc b/imperfect_envs/driving/__pycache__/entities.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3298097ef386d12caa4c781e5681855879e8bd2f GIT binary patch literal 7115 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 literal 0 HcmV?d00001 diff --git a/imperfect_envs/driving/__pycache__/geometry.cpython-310.pyc b/imperfect_envs/driving/__pycache__/geometry.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8027f5fc6ea4901c9a0e71ba78761bf6be82baa0 GIT binary patch literal 7673 zcma)BO>7*;mF}wU`D@M$|3(x=J5JkiVojnS>nD3sWUVDTact3vr9=w?!C*Yqq-Hcf zRP~THXNMQdK#T=)*xMe-qYiu7%VM#I1#-+G=SA-&K@cFm1W9x=f@Ht%^-Rx?$iz)l zP4%nls`p;K_q|ueUa90ec;5Zr#qF(^9OpNDnSSzkxrGvaipn@fwVf@6U)|Oncgt1I zcOByz?^DNkPxO{&GNEU(C^?jTnAy&og7H7~wz6|QIrJ=;B6{+ep=8RKp^O;{cw00} zcw54okGEyBg0~gCEf{srsjhwwPMpoEiZegzHhbL$U#Fi8UT&d8KSvb`yIb0*&^0=A zw>@FkBdaF+sk4XPgm*EO}c#gmg{bI2f~PDxfS( zQO=k(P>NHOvt}KX5-4SJ?i}Y@#Frc91yGlS`l3*|=2y&1pe~!QLf}{8%ny3aZa-EZ z$LgTrLaOn@wnn*)60M`^J45wE4V{`oOG`@|=brOaZC2elv)%61`_{uiOD%!qMPYk; zLV4=g0y@5U|MJ6LC%hbW>b8IRy|8Y(7vJgZhITt_^e_InZV#H>or`x4y7f-85nXPM zyJ}%~Ke}veb07VecS6k3w+EMY58`~S*6cR>wOSU_N94d)Wi=>^WS7RB4TX;J!!`w^ zaL)o%hC(?l2zV9-c$UICEeMG>_bi00dYgl+OnCkaeIfWlRUx1o_3e~=%F?1m$fTnA z$GKV!!)i6YJflJbH7Jc)lb$%!>pu)_oV8(p&vqLeG=A8oM6wGTXe4Y7RST?G`s}tf#!JPk6CsxZGO0rmUXo zWbeaTZHaxfttpL={yD{t)$Vi4kM}Hk5d$DTOmdaKioe(^{J!9<(kS)j4u;_Q!y8Za zL><+UI$l7}ygIyY&vvM%h|9mI27a7x5}H7F$Of%@EXsSR*EYyf`9MdVjkzNF4Od+l2793~I}*QPdGdY)S})iyV6=p13W zW58r$Xv)3}>WOl}A+5~FU6Qr@DR)e|o?9%Husm8U*-TlG^VnBTTW+CN>)XB1H1}(@ zuZ~v)04$HaEbV;?Pa>{7|C}ddo%I?R!TVlzQ)Vb&1|u{0_-+B;d84=S ze4wJIh@On}EXYb(=)%Li`dE3utw*Z&zPx+K>XGVd?I@?$z?cliWYaNqdCzdnJwUmF zK?)ZoaIq(xm)D)vqS40v8Kqj{xc>4d3Sei6kd}b+R9QMpbtU$jQL`ICZH>@=1Eg5* zUO~AU>+WuxYetQBFA8I~{$XUf4RN*|c6a&@?Q1f&fw2vYZCtbGNl+b&qyWD*Uft~V z5dzv_C+zk^^Om(eTg^>yE7t#bH`aIG#4pO5w^8oSJ8!-jz0-}FCZw4}WZYLp`~}L_ zWnDx-D5~#iU#}}qk3+-wld6}1CWR7ig~J((Ahr_S=@QYOP^A`8`V2MzJt7S-`e)Q2 zZ3Q-AZ$PIWN@m?T)EvbYErhm_{J!A8a&kv`!@6KRSdKo1RdDRk8^W{CI-fbu&F*9N z2cJ1du$5zFzh}IAoV^H}$sLt`>TD}XK=Q-P9p{O-tnh>!$TpL8@a-bLSOO=iwY)AC zI>-*y(c)*$v3dYY@tpq3!N&?#qn!TgC+Z`on%fkEuvLivx!4D*nYc>eWb_vlB~+Ifq3tuJB z`i`loz=J5U)Zd7La|!=4>Eq&BB!cmr!06Ox?02Mdr>XA z5_|oJ^?sb`Lv|ahw-Qqpu?e&?JLidLkG@)h1sC;(s;CXLeC4UET1RU`X_pr6DgD>M z(!4r0Vbl`yX|cA#imj@WJ%l#{q>*BUwOZ`gYMq|hYqMRf)gJHF+ewcl2HFKy%dF0_ zV*H3*$S3ZbXiy@-*Vy|iD_TM9ec0=@E%leEOLlZpiKOI+<|6rJ-dRz3&v$*d;;xMT z*4&LsvU|j!SUnbni#X3EtDNXIC;KNC%cbofRHvqbYVbJKc5mf3n*kvvq1-lo5#}@*70o`G+z1MB@ zah3=g55vZzC}?g6GJ%W@9tZ7a7zOC&6hRd35CenPcI|7)uxchrUTCD2;@LM@QP`?0 z$ZUT|0u6B<6AQiWy=1}<&>JzZu4OAQmx|VZskr*jmh>4#G76`W_&vN(WmFe3Jk2z# z1+1%(DjA4SWelmnId|w9^+?;7c%G8BXJ0jNdE+vP9{jh+e!mxNH@hb2*(Ri|i+Xz7 zcr~F7P0+VZ1cQEXex%6ir9>C^r`4Gx%Tci1YqxtJ;Y<+h*V}v0rL6FJaPi_z*@&Qy zg=|o_Q~M-CuE>zvK#fNqHKQ>3?rK8p?I92$Etu&`V&Zq8l*EU$?1F3$oJ}&ybSq*P z+|2LC!j!x7X2~R!oV}9)GW)T(|FXZjVuZ-ZCGcXCEcHg~~_dP5z1=BX3bHxt^+cDEu82 zFUc}7G7n460&YoJVcxka7B(xxO#Z}#ivC6461;}`og+dmlE$%TxrtSa#PrS+P5X6p zJmoBO)v_Ke$kL;Xoaw-fS<|G`bzi{?*F^!?!=xDk1o&at8gUZGn+Y$%fovUvLYK(`4Bm?w2(NzYkRoD z>K|C@J;|FSw-gR0Sj9EmZTdz__?j z%o&%7ze7V-W;4uCp-Vo zhZllLsa7*_b{qFXxbmFiavO7==#k6l_#bu#s0PdF)ZkMh&I}MRzoS-#%{yoSQ+dq= zCUG~ATviIZc+=7+jN{FfH;<$7hLdCxeRd#H5||U~I*D!Mn$%^iL-=h7cnkrL;q`gN zlbxTVM9ksKx{R|mPuGLRiAZu_nh}V|mI_4t0fVVXXuBzcHbn198jN#|p6vque}Msl zYZX1M$5HPjawq2m8s_*R2Pqdnz>9<`UhGU^iO_I>k1Eo_KOgKjz+nbRs3q(n$p!B4 z=>4@(*gMA*x1U95b2sn5jk^oMAo{rA!{kyy!kC;A$3{-1lmKLJu{FU8YFEDgB^nV` zMxd(b>9~TJvOdxJY+(7@NNVexo}OSoWOW)!{vSIDMT5#@p~gjK zFC`EEn@Rph1E36ZGbwW(Nim=>?2BB41hnD~pRJo}wA0Q-6Ay{)8(qTyr5cbXrI@Te-8i z*u@$!QS$_h(!?ds-$*WtZW7T)*$b{$-Hp2&rSf9=ot5hU15?D7 AI{*Lx literal 0 HcmV?d00001 diff --git a/imperfect_envs/driving/__pycache__/graphics.cpython-310.pyc b/imperfect_envs/driving/__pycache__/graphics.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..775b2158ab74d1ea9a13ad4796c972aa6253f4ee GIT binary patch literal 25769 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 literal 0 HcmV?d00001 diff --git a/imperfect_envs/driving/__pycache__/visualizer.cpython-310.pyc b/imperfect_envs/driving/__pycache__/visualizer.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7d3898fd25494bf4d81ad57a8e5d1c83842e4024 GIT binary patch literal 2621 zcmai0-ESL35Z~SV%-K%d#7&d7(1OZ`5lt$A5JFYeHf^ek$}LS4BumxldV6**obTM- zOHxN?36V(f$~zC~W8cdY{{oLZpnZg=ivNHj#LQmoIHFQ7+VSkp?#}GYZ)TF!Y94{_ z%im`@ztjl%6DO0O0h8-6DyTiE4rw**P!{>MDPHHN4oKVM z9vIqC-bO69gCyRIgtB&Ho^L99Gm5*Lxib3wUTA{i(T6;a6&UghAcav7pX9Wlh0!4U z6gXCLjDZA)!6{I)OMqG&sm;k6dCpp^O-D?@CCZ4?T-A6i`$;hHOB<#~(<57^cjJ_2 zyM8F5Adk43*%_J5{kYea%76_`Q<*YKIs)A$TqLOAIT5q)^Y>TFn^`Yfmc2ma%lD!{ zq?hmZ`jO~BcrI@QVi2d@%eMw;(2GO49FIhPl2A^M1?&Gc>W=SSO2B$_J@?#I*gh@fR;3YumA$vx| zgJj8B0$$e zfW!D3r4r&(B4#ly9yvpbp(tpB{K%fLwGzZlS{4eX*wPh6!{@Ywx<Fqv;(&U#=Ub>oOVUWmcz>E(5&paD0(dJzQMw?e1(j1K2LL(Xc z8W^ofLrrBp$gp10r)8qjfp`~Ai}#R>?G^9C^ivqx(2GQ%XI>&vW)jG}d0wZqvN5@X zT}Z%wKT5gsVi~6rnpGGHOYg?!Bt8JPtkrf1i5dyk9x||k%I2i>nggU zEO@qnriX4Y6ELjwruM6bK~W zph4&9v~h`Eq8{_g9p6sw_DuVg=~hP)cA{FIP<#SK7*T|x?#O3>(cKoihVB=%>;(q) z0fF7AX-;$iE5!P*fiMA|V+^grf%`Bd;uJd?^tAc};Pr7xozr+RYqgpc?1#`kBi~n^ z@AopkogiQJ{U`80#*xJ8Bw3J)3Y-!RAj*)r5a*BszXN|8C8&I&%N$#!jRB$Vwl0~c z^~!=%{Y>C`t7)tHQKw!S6^i2(08pIAkraqWjW!K(ee`v@lzX*&!!`7?c7sbAbk_V2 D9rkl! literal 0 HcmV?d00001 diff --git a/imperfect_envs/driving/__pycache__/world.cpython-310.pyc b/imperfect_envs/driving/__pycache__/world.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0ffd2224c9043640bb2d9986eb94d4f7bc8616ca GIT binary patch literal 3042 zcmZ`*TW=gS6t+E=oy=a6hBl!WiVzpEKof+JkRYlM6cDruh;k7tRio+JNoG4cv++!t zCYqHH2@)?n@DGy5{v+g9p86M%xO~U6lP00e$e!b|eSCbr?;Jbtc0-2e_V4o>VVki( zsB!vn(D)Fg_!^aDlBaCU2b_~EQZaDwby9ci4ZN{G@W-t|%l5fxFrFLCS=md&aeL6_ z>@y~P**avhbsz>EDekg<@C15UpBwMnEXlL=zGIw^V{O8(lvG8jlQ=WMM>|O>lWY^i z{7s~W;-YxU*$AvX-oTZC z@-~E=li{H|@MT+e4%wh3ugRXAKjecz&B+CM;gB8hL8!t}TP~io=HzqoqV4I(7vv?m zgz;UuET4ylp1drt;5#q7*z0xUeV^-8J_%rz5wbMiZX(Mq<8P^CbE`DYWHKIl=xiR6 zseFu5yoG9$RV=D&E;(dTQSFp&B`T+KrTEoB+mj6IIqRBZPM_;8eSFiCds#eAhEcq! zva&GUqKwO@O^dt4Y%psqA5~Ds}P@{j0m=ot4R+38E;;k}`@2 z$byXWdHr7G`#tN#m1c>SCy1EF-II)xq5DFia&lmWD*q^IS zMbD6sXdbf8MLB^LcCcIQUNGeqKLVg5K^ATUN*5MV`#mNAGr_8tF|+U1#<_s+L5&No zJ+sev7T|Lh>Z=$*mRk!$-s5m)SX)SH)`#S=<{|lndas~CHjY3#Pz<(F3!WqEcqNV< z3Uo_3<8JDh;xo9v84dF^*Rb^h=9}(NtGHCrZj#A-*K~I#lA1Fv`t`T(SPz@_FxMK~ zi6(hrf=oTK(zzWOUjrFsH&&2CdwhxScj_(GU1$7G7@YW>JW;YEyQ4$ekGO^KKIV28 zXQnk|x{DbF;ZIR`&m*u#>^HHEJZ24}EJhKf`of5nxAip)J#TTimL^3x%*T_PFOfRZ zy~y@otZlZlSJu*e7^lTe2+dfeMUhR&E7=eWWGI#Zk9keVvs~1#LhFl-`X#a7KBfLl zoKUErpe)fS$rJp5PZ1>}A^Bxii6x}{2clT`g8jrx;NASc3V%%<$)_&O0e>${J+Q&W z>nyXM#bq}2E5Gt0`{zA2b+@k*OCF0^V)BfWs;p+RS8T--Wt=1{t@-^{O$7ePgxSux zp~<49Nn{-rVe%%W&wOK}P^I;^nXdS$oM>9xZc7Jgm5-d_K1nmp{!H@~(29+G(opdo zt`C|PEIvT$Bl~PGv>wc?OGr=OU4KGoeDi6)Wjq~cn@ZDpSaT;to=Fo)IootZ)54iY|*65P$ow_|fJ2OLf4VSNZ?!BD*Sf#Et=qJ>)IqM-H`5Wqs^j5!LB1s1eF2pmXP$%YT55uTW+O zBE?s;yxj!uC3L*^#rk@ErY+F9j|+;5A`?c@IF~yq$(<hy?5!@3jIy z^n{D--~i?s#@&zia$*Z-UE{_!@2fL;dRa2B}%D85s t>9*IGL=|>7X0iGG^!{ZpWOlh{S!{x}+EX_vKnhAz9iV-YcknJc{{kA!eD?qV literal 0 HcmV?d00001 diff --git a/imperfect_envs/driving/agents.py b/imperfect_envs/driving/agents.py new file mode 100644 index 0000000..afd3c2b --- /dev/null +++ b/imperfect_envs/driving/agents.py @@ -0,0 +1,62 @@ +from driving.entities import RectangleEntity, CircleEntity +from driving.geometry import Point + +# For colors, we use tkinter colors. See http://www.science.smith.edu/dftwiki/index.php/Color_Charts_for_TKinter + + +class Car(RectangleEntity): + def __init__( + self, + center: Point, + heading: float, + color: str = "red", + min_acc: float = -4.0, + max_acc: float = 4.0, + ): + size = Point(2.0, 1.0) + movable = True + friction = 0.06 + super(Car, self).__init__( + center, heading, size, movable, friction, min_acc=min_acc, max_acc=max_acc + ) + self.color = color + self.collidable = True + + +class Pedestrian(CircleEntity): + def __init__(self, center: Point, heading: float, color: str = "LightSalmon2"): + radius = 0.4 + movable = True + friction = 0.2 + super(Pedestrian, self).__init__(center, heading, radius, movable, friction) + self.color = color + self.collidable = True + + +class Building(RectangleEntity): + def __init__(self, center: Point, size: Point, color: str = "gray26", heading=0.0): + movable = False + friction = 0.0 + super(Building, self).__init__(center, heading, size, movable, friction) + self.color = color + self.collidable = True + + +class Painting(RectangleEntity): + def __init__(self, center: Point, size: Point, color: str = "gray26"): + heading = 0.0 + movable = False + friction = 0.0 + super(Painting, self).__init__(center, heading, size, movable, friction) + self.color = color + self.collidable = False + + +class Goal(RectangleEntity): + def __init__(self, center: Point, radius: float, heading: float, color: str = "LightSalmon2"): + size = Point(radius, radius) + movable = True + friction = 0.2 + super(Goal, self).__init__(center, heading, size, movable, friction) + self.color = color + self.collidable = True diff --git a/imperfect_envs/driving/entities.py b/imperfect_envs/driving/entities.py new file mode 100644 index 0000000..aa58c7a --- /dev/null +++ b/imperfect_envs/driving/entities.py @@ -0,0 +1,241 @@ +import math +from typing import Text, Union +import numpy as np +from driving.geometry import Point, Rectangle, Circle +import copy + + +def get_entity_dynamics(friction, min_speed, max_speed, min_acc, max_acc, xnp=np): + # xnp: Either numpy or jax.numpy. + + def entity_dynamics(x, u, dt): + # x: (x, y, xp, yp, theta, ang_vel, acceleration) + # u: (steering angle, acceleration) + center = x[:2] + velocity = x[2:4] + speed = xnp.linalg.norm(velocity, ord=2) + heading = x[4] + angular_velocity = x[5] + old_acceleration = x[6] + steering_angle = u[0] + acceleration = xnp.clip(u[1], min_acc, max_acc) + + new_angular_velocity = speed * steering_angle + new_acceleration = acceleration - friction * speed + + new_heading = heading + (angular_velocity + new_angular_velocity) * dt / 2.0 + new_speed = xnp.clip( + speed + (old_acceleration + new_acceleration) * dt / 2.0, min_speed, max_speed + ) + + next_speed = (speed + new_speed) / 2.0 + next_heading = (new_heading + heading) / 2.0 + new_velocity = next_speed * xnp.array((xnp.cos(next_heading), xnp.sin(next_heading))) + + new_center = center + (velocity + new_velocity) * dt / 2.0 + return xnp.concatenate( + ( + new_center, + new_velocity, + xnp.stack([new_heading, new_angular_velocity, new_acceleration]), + ) + ) + + return entity_dynamics + + +class Entity: + def __init__( + self, + center: Point, + heading: float, + movable: bool = True, + friction: float = 0.0, + min_speed: float = 0.0, + max_speed: float = math.inf, + min_acc: float = -math.inf, + max_acc: float = math.inf, + ): + self.center = center # this is x, y + self.heading = heading + self.movable = movable + self.color = "ghost white" + self.collidable = True + self.obj = None # MUST be set by subclasses. + if movable: + self.friction = friction + self.velocity = Point(0, 0) # this is xp, yp + self.acceleration = 0 # this is vp (or speedp) + self.angular_velocity = 0 # this is headingp + self.inputSteering = 0 + self.inputAcceleration = 0 + self.min_speed = min_speed + self.max_speed = max_speed + self.min_acc = min_acc + self.max_acc = max_acc + self.entity_dynamics = get_entity_dynamics( + friction, self.min_speed, self.max_speed, self.min_acc, self.max_acc, xnp=np + ) + + @property + def speed(self) -> float: + return self.velocity.norm(p=2) if self.movable else 0 + + def set_control(self, inputSteering: float, inputAcceleration: float): + self.inputSteering = inputSteering + self.inputAcceleration = inputAcceleration + + @property + def state(self): + return np.array( + ( + self.x, + self.y, + self.xp, + self.yp, + self.heading, + self.angular_velocity, + self.acceleration, + ) + ) + + @state.setter + def state(self, new_x): + self.center = Point(new_x[0], new_x[1]) + self.velocity = Point(new_x[2], new_x[3]) + self.heading = new_x[4] + self.angular_velocity = new_x[5] + self.acceleration = new_x[6] + self.buildGeometry() + + def tick(self, dt: float): + if self.movable: + x = self.state + u = np.array((self.inputSteering, self.inputAcceleration)) + new_x = self.entity_dynamics(x, u, dt) + self.state = new_x + + def buildGeometry(self): # builds the obj + raise NotImplementedError + + def collidesWith(self, other: Union["Point", "Entity"]) -> bool: + if isinstance(other, Entity): + return self.obj.intersectsWith(other.obj) + elif isinstance(other, Point): + return self.obj.intersectsWith(other) + else: + raise NotImplementedError + + def distanceTo(self, other: Union["Point", "Entity"]) -> float: + if isinstance(other, Entity): + return self.obj.distanceTo(other.obj) + elif isinstance(other, Point): + return self.obj.distanceTo(other) + else: + raise NotImplementedError + + def copy(self): + return copy.deepcopy(self) + + @property + def x(self): + return self.center.x + + @property + def y(self): + return self.center.y + + @property + def xp(self): + return self.velocity.x + + @property + def yp(self): + return self.velocity.y + + +class RectangleEntity(Entity): + def __init__( + self, + center: Point, + heading: float, + size: Point, + movable: bool = True, + friction: float = 0, + **kwargs + ): + super(RectangleEntity, self).__init__(center, heading, movable, friction, **kwargs) + self.size = size + self.buildGeometry() + + @property + def edge_centers(self): + edge_centers = np.zeros((4, 2), dtype=np.float32) + x = self.center.x + y = self.center.y + w = self.size.x + h = self.size.y + edge_centers[0] = [ + x + w / 2.0 * np.cos(self.heading), + y + w / 2.0 * np.sin(self.heading), + ] + edge_centers[1] = [ + x - h / 2.0 * np.sin(self.heading), + y + h / 2.0 * np.cos(self.heading), + ] + edge_centers[2] = [ + x - w / 2.0 * np.cos(self.heading), + y - w / 2.0 * np.sin(self.heading), + ] + edge_centers[3] = [ + x + h / 2.0 * np.sin(self.heading), + y - h / 2.0 * np.cos(self.heading), + ] + return edge_centers + + @property + def corners(self): + ec = self.edge_centers + c = np.array([self.center.x, self.center.y]) + corners = [] + corners.append(Point(*(ec[1] + ec[0] - c))) + corners.append(Point(*(ec[2] + ec[1] - c))) + corners.append(Point(*(ec[3] + ec[2] - c))) + corners.append(Point(*(ec[0] + ec[3] - c))) + return corners + + def buildGeometry(self): + C = self.corners + self.obj = Rectangle(*C[:-1]) # pylint: disable=no-value-for-parameter + + #def distanceTo(self, other): + # return np.linalg.norm(np.array([self.center.x, self.center.y]) - np.array([other.center.x, other.center.y]), ord=1) + + +class CircleEntity(Entity): + def __init__( + self, + center: Point, + heading: float, + radius: float, + movable: bool = True, + friction: float = 0, + **kwargs + ): + super(CircleEntity, self).__init__(center, heading, movable, friction, **kwargs) + self.radius = radius + self.buildGeometry() + + def buildGeometry(self): + self.obj = Circle(self.center, self.radius) + + +class TextEntity(Entity): + def __init__(self, center: Point, **kwargs): + heading = 0 + super(TextEntity, self).__init__(center, heading, movable=False, **kwargs) + self.text = "" + + def buildGeometry(self): + # Represent text geometry as a tiny circle. Not accurate. + self.obj = Circle(self.center, 0.01) diff --git a/imperfect_envs/driving/envs/__init__.py b/imperfect_envs/driving/envs/__init__.py new file mode 100644 index 0000000..58a2929 --- /dev/null +++ b/imperfect_envs/driving/envs/__init__.py @@ -0,0 +1 @@ +from driving.envs.gridworld_continuous import GridworldContinuousEnv, GridworldContinuousSlowRandomInitEnv, GridworldContinuousFastRandomInitEnv, PidVelPolicy diff --git a/imperfect_envs/driving/envs/__pycache__/__init__.cpython-310.pyc b/imperfect_envs/driving/envs/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..23e7d878f2ff96ea8e616445a6db733a3068d3cd GIT binary patch literal 374 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 Lq5ZJ3QM>woGolJk literal 0 HcmV?d00001 diff --git a/imperfect_envs/driving/envs/gridworld_continuous.py b/imperfect_envs/driving/envs/gridworld_continuous.py new file mode 100644 index 0000000..eecd7f6 --- /dev/null +++ b/imperfect_envs/driving/envs/gridworld_continuous.py @@ -0,0 +1,260 @@ +import io +from typing import Text +import gym +from gym import spaces +from PIL import Image +import numpy as np +import scipy.special +from driving.world import World +from driving.entities import TextEntity, Entity +from driving.agents import Car, Building, Goal +from driving.geometry import Point +from typing import Tuple +import sys +import random + +class PidVelPolicy: + """PID controller for H that maintains its initial velocity.""" + + def __init__(self, dt: float, params: Tuple[float, float, float] = (3.0, 1.0, 6.0)): + self._target_vel = None + self.previous_error = 0 + self.integral = 0 + self.errors = [] + self.dt = dt + self.Kp, self.Ki, self.Kd = params + + def action(self, obs): + my_y_dot = obs[3] + if self._target_vel is None: + self._target_vel = my_y_dot + error = self._target_vel - my_y_dot + derivative = (error - self.previous_error) * self.dt + self.integral = self.integral + self.dt * error + acc = self.Kp * error + self.Ki * self.integral + self.Kd * derivative + self.previous_error = error + self.errors.append(error) + return acc + + def reset(self, seed = None): + if seed is not None: + random.seed(seed) + self._target_vel = None + self.previous_error = 0 + self.integral = 0 + self.errors = [] + + def __str__(self): + return "PidVelPolicy({})".format(self.dt) + +class GridworldContinuousEnv(gym.Env): + + def __init__(self, + dt: float = 0.1, + width: int = 30, + height: int = 40, + time_limit: float = 300.0): + super(GridworldContinuousEnv, self).__init__() + self.dt = dt + self.width = width + self.height = height + self.world = World(self.dt, width=width, height=height, ppm=6) + self.accelerate = PidVelPolicy(self.dt) + self.step_num = 0 + self.time_limit = time_limit + self.action_space = spaces.Box( + np.array([-1.]), np.array([1.]), dtype=np.float32 + ) + self.goal_radius = 2. + self.observation_space = spaces.Box(-np.inf, np.inf, shape=(14,)) + self.start = np.array([self.width/2.,self.goal_radius]) + self.goal = np.array([self.width/2., self.height-self.goal_radius]) + self.max_dist = np.linalg.norm(self.goal-self.start,2) + + self.target = [self.height/5., self.height*2./5., self.height*3./5., self.height*4./5., np.inf] + self.obstacle_width = 6. + self.initial_speed = 3. + + def step(self, action: np.ndarray, verbose: bool = False): + self.step_num += 1 + # for i in range(len(action)): + # action[i] = action[i]*0.1 + action = action * 0.1 + # print(action) + car = self.world.dynamic_agents[0] + goal_loc = self.world.dynamic_agents[1] + acc = self.accelerate.action(self._get_obs()) + action = np.append(action, acc) + if self.stop: + action = np.array([0, -5]) + # print(type(car)) + car.set_control(*action) + goal_loc.set_control(0, 0) + self.world.tick() + + reward = self.reward(verbose) + + done = False + if car.y >= self.height or car.y <= 0 or car.x <= 0 or car.x >= self.width: + reward -= 10000 + done = True + if self.step_num >= self.time_limit: + done = True + if self.car.collidesWith(self.goal_obj): + done = True + self.stop = True + #if self.step_num < 6: + # done = False + return self._get_obs(), reward, done, True, {'episode': {'r': reward, 'l': self.step_num}} + + def reset(self, seed = None): + self.world.reset() + self.stop = False + self.target_count = 0 + if seed is not None: + random.seed(seed) + self.buildings = [ + Building(Point(self.width/2., self.height/2.-3), Point(self.obstacle_width,1), "gray80"), + ] + random_dis = random.random()*2. + random_angle = random.random()*2*np.pi + init_x = self.start[0] + random_dis*np.cos(random_angle) + init_y = self.start[1] + random_dis*np.sin(random_angle) + self.car = Car(Point(init_x, init_y), np.pi/2., "blue") + self.car.velocity = Point(0, self.initial_speed) + + self.goal_obj = Goal(Point(self.goal[0], self.goal[1]), self.goal_radius, 0.0) + + for building in self.buildings: + self.world.add(building) + self.world.add(self.car) + self.world.add(self.goal_obj) + + self.last_heading = np.pi / 2 + + self.step_num = 0 + return self._get_obs() + + def reset_with_obs(self, obs): + self.world.reset() + self.stop = False + self.target_count = 0 + + self.buildings = [ + Building(Point(self.width/2., self.height/2.-3), Point(self.obstacle_width,1), "gray80"), + ] + + init_x = (obs[0]/2.+0.5)*self.width + init_y = (obs[1]/2.+0.5)*self.height + self.car = Car(Point(init_x, init_y), np.pi/2., "blue") + self.car.velocity = Point(0, self.initial_speed) + + self.goal_obj = Goal(Point(self.goal[0], self.goal[1]), self.goal_radius, 0.0) + + for building in self.buildings: + self.world.add(building) + self.world.add(self.car) + self.world.add(self.goal_obj) + + self.last_heading = np.pi / 2 + + self.step_num = 0 + return self._get_obs() + + def _get_obs(self): + """ + Get state of car + """ + return_state = np.array(self.world.state) + #print(return_state) + return_state[1] = 2.* ((return_state[1] / self.height) - 0.5) + return_state[0] = 2.* ((return_state[0] / self.width) - 0.5) + return_state[2] /= self.initial_speed + return_state[3] /= self.initial_speed + # print("get_obs return state ", return_state) + return return_state + + def inverse_dynamic(self, state, next_state): + return (next_state[-2] / np.linalg.norm(self.initial_speed*state[2:4], ord=2))/self.dt + + def reward(self, verbose, weight=10.0): + dist_rew = -1. # * (self.car.center.distanceTo(self.goal_obj)/self.max_dist) + coll_rew = 0 + for building in self.buildings: + if self.car.collidesWith(building): + coll_rew = -1000. + break + + goal_rew = 0.0 + if self.car.collidesWith(self.goal_obj) and (not self.stop): + goal_rew = 100. + + extra_rew = 0. + #if self.car.x < self.width / 4.: + # extra_rew = (self.width / 4. - self.car.x)/(self.width/4.) * (-1.) + #elif self.car.x > self.width * 3. / 4.: + # extra_rew = (self.car.x-self.width * 3. / 4.)/(self.width/4.) * (-1.) + + reward = sum([dist_rew, coll_rew, extra_rew, goal_rew]) + if verbose: print("dist reward: ", dist_rew, + "goal reward: ", goal_rew, + "extra reward: ", extra_rew, + "reward: ", reward) + return reward + + def render(self): + self.world.render() + + def set_goal(self, x, y): + self.goal = np.array([x, y]) + +class GridworldContinuousSlowRandomInitEnv(GridworldContinuousEnv): + def reset(self, seed = None): + + if seed is not None: + random.seed(seed) + + self.world.reset() + + self.stop = False + self.target_count = 0 + + self.buildings = [ + Building(Point(self.width/2., self.height/2.-3), Point(self.obstacle_width,1), "gray80"), + ] + + while True: + random_w = random.random() + random_h = random.random() + init_x = self.width/2.-(self.obstacle_width/2.+2.) + random_w*(self.obstacle_width+4.) + init_y = self.goal_radius + (self.height-3*self.goal_radius)*random_h + cond1 = abs(init_x - self.width/2.) < (self.obstacle_width/2.+2.) and init_y-self.height/2. < 3. and init_y-self.height/2.>-13. + slope = ((self.height - self.goal_radius) - (self.height/2.-3))/(self.width/4.) + #print(slope, init_x, ((self.width/4.-abs(init_x - self.width/2.)) * slope + (self.height/2.-3.))) + cond2 = init_y < ((self.width/4.-abs(init_x - self.width/2.)) * slope + (self.height/2.-3.)) + if cond2 and not cond1: + break + init_heading = np.pi/2. # np.arctan2(self.goal[1] - init_y, self.goal[0]-init_x) + self.car = Car(Point(init_x, init_y), init_heading, "blue") + self.car.velocity = Point(0, self.initial_speed) + + self.goal_obj = Goal(Point(self.goal[0], self.goal[1]), self.goal_radius, 0.0) + + for building in self.buildings: + self.world.add(building) + self.world.add(self.car) + self.world.add(self.goal_obj) + + self.last_heading = np.pi / 2 + + self.step_num = 0 + return self._get_obs() + +class GridworldContinuousFastRandomInitEnv(GridworldContinuousSlowRandomInitEnv): + def __init__(self, + dt: float = 0.1, + width: int = 30, + height: int = 40, + time_limit: float = 300.0): + super(GridworldContinuousFastRandomInitEnv, self).__init__(dt, width, height, time_limit) + self.initial_speed = 9. diff --git a/imperfect_envs/driving/geometry.py b/imperfect_envs/driving/geometry.py new file mode 100644 index 0000000..196b0fa --- /dev/null +++ b/imperfect_envs/driving/geometry.py @@ -0,0 +1,243 @@ +import numpy as np +from typing import Union + + +class Point: + def __init__(self, x: float, y: float): + self.x = float(x) + self.y = float(y) + + def __str__(self): + return "Point(" + str(self.x) + ", " + str(self.y) + ")" + + def __add__(self, other: "Point") -> "Point": + return Point(self.x + other.x, self.y + other.y) + + def __sub__(self, other: "Point") -> "Point": + return Point(self.x - other.x, self.y - other.y) + + def norm(self, p: int = 2) -> float: + return (self.x ** p + self.y ** p) ** (1.0 / p) + + def dot(self, other: "Point") -> float: + return self.x * other.x + self.y * other.y + + def __mul__(self, other: float) -> "Point": + return Point(other * self.x, other * self.y) + + def __rmul__(self, other: float) -> "Point": + return self.__mul__(other) + + def __truediv__(self, other: float) -> "Point": + return self.__mul__(1.0 / other) + + def isInside(self, other: Union["Line", "Rectangle", "Circle"]) -> bool: + if isinstance(other, Line): + AM = Line(other.p1, self) + MB = Line(self, other.p2) + return np.isclose(np.abs(AM.dot(MB)), AM.length * MB.length) + + elif isinstance(other, Rectangle): + # Based on https://stackoverflow.com/a/2763387 + AB = Line(other.c1, other.c2) + AM = Line(other.c1, self) + BC = Line(other.c2, other.c3) + BM = Line(other.c2, self) + + return 0 <= AB.dot(AM) <= AB.dot(AB) and 0 <= BC.dot(BM) <= BC.dot(BC) + + elif isinstance(other, Circle): + return (self - other.m).norm(p=2) <= other.r + + raise NotImplementedError + + def distanceTo(self, other: Union["Point", "Line", "Rectangle", "Circle"]) -> float: + if isinstance(other, Point): + return (self - other).norm(p=2) + + elif isinstance(other, Line): + # Based on https://math.stackexchange.com/a/330329 + s2_minus_s1 = other.p2 - other.p1 + that = (self - other.p1).dot(s2_minus_s1) / s2_minus_s1.dot(s2_minus_s1) + tstar = np.minimum(1, np.maximum(0, that)) + return (other.p1 + tstar * s2_minus_s1 - self).norm(p=2) + + elif isinstance(other, Rectangle): + if self.isInside(other): + return 0 + E = other.edges + return np.min([self.distanceTo(e) for e in E]) + + elif isinstance(other, Circle): + return np.maximum(0, self.distanceTo(other.m) - other.r) + + else: + try: + return other.distanceTo(self) + except NameError: + raise NotImplementedError + print("Something went wrong!") + + +def onSegment(p: Point, q: Point, r: Point) -> bool: + """ + Given three colinear points p, q, r, the function checks if + point q lies on line segment 'pr' + """ + return ( + q.x <= np.maximum(p.x, r.x) + and q.x >= np.minimum(p.x, r.x) + and q.y <= np.maximum(p.y, r.y) + and q.y >= np.minimum(p.y, r.y) + ) + + +def orientation(p: Point, q: Point, r: Point) -> int: + """ + To find orientation of ordered triplet (p, q, r). + The function returns following values + 0 --> p, q and r are colinear + 1 --> Clockwise + 2 --> Counterclockwise + """ + # See https://www.geeksforgeeks.org/orientation-3-ordered-points/ for details of below formula. + val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y) + if val == 0: + return 0 # colinear + return 1 if val > 0 else 2 # clock or counterclock wise + + +class Line: + def __init__(self, p1: Point, p2: Point): + self.p1 = p1 + self.p2 = p2 + + def __str__(self): + return "Line(" + str(self.p1) + ", " + str(self.p2) + ")" + + def intersectsWith(self, other: Union["Line", "Rectangle", "Circle"]): + if isinstance(other, Line): + p1 = self.p1 + q1 = self.p2 + p2 = other.p1 + q2 = other.p2 + + # Based on https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ + # Find the four orientations needed for general and special cases + o1 = orientation(p1, q1, p2) + o2 = orientation(p1, q1, q2) + o3 = orientation(p2, q2, p1) + o4 = orientation(p2, q2, q1) + + # General case + if o1 != o2 and o3 != o4: + return True + + # Special Cases + # p1, q1 and p2 are colinear and p2 lies on segment p1q1 + if o1 == 0 and onSegment(p1, p2, q1): + return True + + # p1, q1 and q2 are colinear and q2 lies on segment p1q1 + if o2 == 0 and onSegment(p1, q2, q1): + return True + + # p2, q2 and p1 are colinear and p1 lies on segment p2q2 + if o3 == 0 and onSegment(p2, p1, q2): + return True + + # p2, q2 and q1 are colinear and q1 lies on segment p2q2 + if o4 == 0 and onSegment(p2, q1, q2): + return True + + return False # Doesn't fall in any of the above cases + + elif isinstance(other, Rectangle): + if self.p1.isInside(other) or self.p2.isInside(other): + return True + E = other.edges + for edge in E: + if self.intersectsWith(edge): + return True + return False + + elif isinstance(other, Circle): + return other.m.distanceTo(self) <= other.r + + raise NotImplementedError + + @property + def length(self): + return self.p1.distanceTo(self.p2) + + def dot(self, other: "Line") -> float: # assumes Line is a vector from p1 to p2 + v1 = self.p2 - self.p1 + v2 = other.p2 - other.p1 + return v1.dot(v2) + + def distanceTo(self, other: "Point") -> float: + if isinstance(other, Point): + return other.distanceTo(self) + + +class Rectangle: + # 3 points are enough to represent a rectangle + def __init__(self, c1: Point, c2: Point, c3: Point): + self.c1 = c1 + self.c2 = c2 + self.c3 = c3 + self.c4 = c3 + c1 - c2 + + def __str__(self): + return "Rectangle({}, {}, {}, {})".format(self.c1, self.c2, self.c3, self.c4) + + @property + def edges(self): + e1 = Line(self.c1, self.c2) + e2 = Line(self.c2, self.c3) + e3 = Line(self.c3, self.c4) + e4 = Line(self.c4, self.c1) + return [e1, e2, e3, e4] + + @property + def corners(self): + return [self.c1, self.c2, self.c3, self.c4] + + def intersectsWith(self, other: Union["Line", "Rectangle", "Circle"]) -> bool: + if isinstance(other, Line): + return other.intersectsWith(self) + + elif isinstance(other, Rectangle) or isinstance(other, Circle): + E = self.edges + for e in E: + if e.intersectsWith(other): + return True + return False + + raise NotImplementedError + + def distanceTo(self, other: "Point") -> float: + if isinstance(other, Point): + return other.distanceTo(self) + + +class Circle: + def __init__(self, m: Point, r: float): + self.m = m + self.r = r + + def __str__(self): + return "Circle(" + str(self.m) + ", radius = " + str(self.r) + ")" + + def intersectsWith(self, other: Union["Line", "Rectangle", "Circle"]): + if isinstance(other, Line) or isinstance(other, Rectangle): + return other.intersectsWith(self) + + elif isinstance(other, Circle): + return self.m.distanceTo(other.m) <= self.r + other.r + + raise NotImplementedError + + def distanceTo(self, other: "Point") -> float: + if isinstance(other, Point): + return other.distanceTo(self) diff --git a/imperfect_envs/driving/graphics.py b/imperfect_envs/driving/graphics.py new file mode 100644 index 0000000..4207252 --- /dev/null +++ b/imperfect_envs/driving/graphics.py @@ -0,0 +1,904 @@ +# graphics.py +"""Simple object oriented graphics library + +The library is designed to make it very easy for novice programmers to +experiment with computer graphics in an object oriented fashion. It is +written by John Zelle for use with the book "Python Programming: An +Introduction to Computer Science" (Franklin, Beedle & Associates). + +LICENSE: This is open-source software released under the terms of the +GPL (http://www.gnu.org/licenses/gpl.html). + +PLATFORMS: The package is a wrapper around Tkinter and should run on +any platform where Tkinter is available. + +INSTALLATION: Put this file somewhere where Python can see it. + +OVERVIEW: There are two kinds of objects in the library. The GraphWin +class implements a window where drawing can be done and various +GraphicsObjects are provided that can be drawn into a GraphWin. As a +simple example, here is a complete program to draw a circle of radius +10 centered in a 100x100 window: + +-------------------------------------------------------------------- +from graphics import * + +def main(): + win = GraphWin("My Circle", 100, 100) + c = Circle(Point(50,50), 10) + c.draw(win) + win.getMouse() # Pause to view result + win.close() # Close window when done + +main() +-------------------------------------------------------------------- +GraphWin objects support coordinate transformation through the +setCoords method and pointer-based input through getMouse. + +The library provides the following graphical objects: + Point + Line + Circle + Oval + Rectangle + Polygon + Text + Entry (for text-based input) + Image + +Various attributes of graphical objects can be set such as +outline-color, fill-color and line-width. Graphical objects also +support moving and hiding for animation effects. + +The library also provides a very simple class for pixel-based image +manipulation, Pixmap. A pixmap can be loaded from a file and displayed +using an Image object. Both getPixel and setPixel methods are provided +for manipulating the image. + +DOCUMENTATION: For complete documentation, see Chapter 4 of "Python +Programming: An Introduction to Computer Science" by John Zelle, +published by Franklin, Beedle & Associates. Also see +http://mcsp.wartburg.edu/zelle/python for a quick reference""" + +# Version 4.2 5/26/2011 +# * Modified Image to allow multiple undraws like other GraphicsObjects +# Version 4.1 12/29/2009 +# * Merged Pixmap and Image class. Old Pixmap removed, use Image. +# Version 4.0.1 10/08/2009 +# * Modified the autoflush on GraphWin to default to True +# * Autoflush check on close, setBackground +# * Fixed getMouse to flush pending clicks at entry +# Version 4.0 08/2009 +# * Reverted to non-threaded version. The advantages (robustness, +# efficiency, ability to use with other Tk code, etc.) outweigh +# the disadvantage that interactive use with IDLE is slightly more +# cumbersome. +# * Modified to run in either Python 2.x or 3.x (same file). +# * Added Image.getPixmap() +# * Added update() -- stand alone function to cause any pending +# graphics changes to display. +# +# Version 3.4 10/16/07 +# Fixed GraphicsError to avoid "exploded" error messages. +# Version 3.3 8/8/06 +# Added checkMouse method to GraphWin +# Version 3.2.3 +# Fixed error in Polygon init spotted by Andrew Harrington +# Fixed improper threading in Image constructor +# Version 3.2.2 5/30/05 +# Cleaned up handling of exceptions in Tk thread. The graphics package +# now raises an exception if attempt is made to communicate with +# a dead Tk thread. +# Version 3.2.1 5/22/05 +# Added shutdown function for tk thread to eliminate race-condition +# error "chatter" when main thread terminates +# Renamed various private globals with _ +# Version 3.2 5/4/05 +# Added Pixmap object for simple image manipulation. +# Version 3.1 4/13/05 +# Improved the Tk thread communication so that most Tk calls +# do not have to wait for synchonization with the Tk thread. +# (see _tkCall and _tkExec) +# Version 3.0 12/30/04 +# Implemented Tk event loop in separate thread. Should now work +# interactively with IDLE. Undocumented autoflush feature is +# no longer necessary. Its default is now False (off). It may +# be removed in a future version. +# Better handling of errors regarding operations on windows that +# have been closed. +# Addition of an isClosed method to GraphWindow class. + +# Version 2.2 8/26/04 +# Fixed cloning bug reported by Joseph Oldham. +# Now implements deep copy of config info. +# Version 2.1 1/15/04 +# Added autoflush option to GraphWin. When True (default) updates on +# the window are done after each action. This makes some graphics +# intensive programs sluggish. Turning off autoflush causes updates +# to happen during idle periods or when flush is called. +# Version 2.0 +# Updated Documentation +# Made Polygon accept a list of Points in constructor +# Made all drawing functions call TK update for easier animations +# and to make the overall package work better with +# Python 2.3 and IDLE 1.0 under Windows (still some issues). +# Removed vestigial turtle graphics. +# Added ability to configure font for Entry objects (analogous to Text) +# Added setTextColor for Text as an alias of setFill +# Changed to class-style exceptions +# Fixed cloning of Text objects + +# Version 1.6 +# Fixed Entry so StringVar uses _root as master, solves weird +# interaction with shell in Idle +# Fixed bug in setCoords. X and Y coordinates can increase in +# "non-intuitive" direction. +# Tweaked wm_protocol so window is not resizable and kill box closes. + +# Version 1.5 +# Fixed bug in Entry. Can now define entry before creating a +# GraphWin. All GraphWins are now toplevel windows and share +# a fixed root (called _root). + +# Version 1.4 +# Fixed Garbage collection of Tkinter images bug. +# Added ability to set text atttributes. +# Added Entry boxes. + +import time, os, sys + +try: # import as appropriate for 2.x vs. 3.x + import tkinter as tk +except: + import Tkinter as tk + + +########################################################################## +# Module Exceptions + + +class GraphicsError(Exception): + """Generic error class for graphics module exceptions.""" + + pass + + +OBJ_ALREADY_DRAWN = "Object currently drawn" +UNSUPPORTED_METHOD = "Object doesn't support operation" +BAD_OPTION = "Illegal option value" +DEAD_THREAD = "Graphics thread quit unexpectedly" + +try: + _root = tk.Tk() + _root.withdraw() +except: + _root = None + + +def update(): + _root.update() + + +############################################################################ +# Graphics classes start here + + +class GraphWin(tk.Canvas): + + """A GraphWin is a toplevel window for displaying graphics.""" + + def __init__(self, title="Graphics Window", width=200, height=200, autoflush=True): + master = tk.Toplevel(_root) + master.protocol("WM_DELETE_WINDOW", self.close) + tk.Canvas.__init__(self, master, width=width, height=height) + self.master.title(title) + self.pack() + master.resizable(0, 0) + self.foreground = "black" + self.items = [] + self.mouseX = None + self.mouseY = None + self.bind("", self._onClick) + self.height = height + self.width = width + self.autoflush = autoflush + self._mouseCallback = None + self.trans = None + self.closed = False + master.lift() + if autoflush: + _root.update() + + def __checkOpen(self): + if self.closed: + raise GraphicsError("window is closed") + + def setBackground(self, color): + """Set background color of the window""" + self.__checkOpen() + self.config(bg=color) + self.__autoflush() + + def setCoords(self, x1, y1, x2, y2): + """Set coordinates of window to run from (x1,y1) in the + lower-left corner to (x2,y2) in the upper-right corner.""" + self.trans = Transform(self.width, self.height, x1, y1, x2, y2) + + def close(self): + """Close the window""" + + if self.closed: + return + self.closed = True + self.master.destroy() + self.__autoflush() + + def isClosed(self): + return self.closed + + def isOpen(self): + return not self.closed + + def __autoflush(self): + if self.autoflush: + _root.update() + + def plot(self, x, y, color="black"): + """Set pixel (x,y) to the given color""" + self.__checkOpen() + xs, ys = self.toScreen(x, y) + self.create_line(xs, ys, xs + 1, ys, fill=color) + self.__autoflush() + + def plotPixel(self, x, y, color="black"): + """Set pixel raw (independent of window coordinates) pixel + (x,y) to color""" + self.__checkOpen() + self.create_line(x, y, x + 1, y, fill=color) + self.__autoflush() + + def flush(self): + """Update drawing to the window""" + self.__checkOpen() + self.update_idletasks() + + def getMouse(self): + """Wait for mouse click and return Point object representing + the click""" + self.update() # flush any prior clicks + self.mouseX = None + self.mouseY = None + while self.mouseX == None or self.mouseY == None: + self.update() + if self.isClosed(): + raise GraphicsError("getMouse in closed window") + time.sleep(0.1) # give up thread + x, y = self.toWorld(self.mouseX, self.mouseY) + self.mouseX = None + self.mouseY = None + return Point(x, y) + + def checkMouse(self): + """Return last mouse click or None if mouse has + not been clicked since last call""" + if self.isClosed(): + raise GraphicsError("checkMouse in closed window") + self.update() + if self.mouseX != None and self.mouseY != None: + x, y = self.toWorld(self.mouseX, self.mouseY) + self.mouseX = None + self.mouseY = None + return Point(x, y) + else: + return None + + def getHeight(self): + """Return the height of the window""" + return self.height + + def getWidth(self): + """Return the width of the window""" + return self.width + + def toScreen(self, x, y): + trans = self.trans + if trans: + return self.trans.screen(x, y) + else: + return x, y + + def toWorld(self, x, y): + trans = self.trans + if trans: + return self.trans.world(x, y) + else: + return x, y + + def setMouseHandler(self, func): + self._mouseCallback = func + + def _onClick(self, e): + self.mouseX = e.x + self.mouseY = e.y + if self._mouseCallback: + self._mouseCallback(Point(e.x, e.y)) + + +class Transform: + + """Internal class for 2-D coordinate transformations""" + + def __init__(self, w, h, xlow, ylow, xhigh, yhigh): + # w, h are width and height of window + # (xlow,ylow) coordinates of lower-left [raw (0,h-1)] + # (xhigh,yhigh) coordinates of upper-right [raw (w-1,0)] + xspan = xhigh - xlow + yspan = yhigh - ylow + self.xbase = xlow + self.ybase = yhigh + self.xscale = xspan / float(w - 1) + self.yscale = yspan / float(h - 1) + + def screen(self, x, y): + # Returns x,y in screen (actually window) coordinates + xs = (x - self.xbase) / self.xscale + ys = (self.ybase - y) / self.yscale + return int(xs + 0.5), int(ys + 0.5) + + def world(self, xs, ys): + # Returns xs,ys in world coordinates + x = xs * self.xscale + self.xbase + y = self.ybase - ys * self.yscale + return x, y + + +# Default values for various item configuration options. Only a subset of +# keys may be present in the configuration dictionary for a given item +DEFAULT_CONFIG = { + "fill": "", + "outline": "black", + "width": "1", + "arrow": "none", + "text": "", + "justify": "center", + "font": ("helvetica", 12, "normal"), +} + + +class GraphicsObject: + + """Generic base class for all of the drawable objects""" + + # A subclass of GraphicsObject should override _draw and + # and _move methods. + + def __init__(self, options): + # options is a list of strings indicating which options are + # legal for this object. + + # When an object is drawn, canvas is set to the GraphWin(canvas) + # object where it is drawn and id is the TK identifier of the + # drawn shape. + self.canvas = None + self.id = None + + # config is the dictionary of configuration options for the widget. + config = {} + for option in options: + config[option] = DEFAULT_CONFIG[option] + self.config = config + + def setFill(self, color): + """Set interior color to color""" + self._reconfig("fill", color) + + def setOutline(self, color): + """Set outline color to color""" + self._reconfig("outline", color) + + def setWidth(self, width): + """Set line weight to width""" + self._reconfig("width", width) + + def draw(self, graphwin): + + """Draw the object in graphwin, which should be a GraphWin + object. A GraphicsObject may only be drawn into one + window. Raises an error if attempt made to draw an object that + is already visible.""" + + if self.canvas and not self.canvas.isClosed(): + raise GraphicsError(OBJ_ALREADY_DRAWN) + if graphwin.isClosed(): + raise GraphicsError("Can't draw to closed window") + self.canvas = graphwin + self.id = self._draw(graphwin, self.config) + if graphwin.autoflush: + _root.update() + + def undraw(self): + + """Undraw the object (i.e. hide it). Returns silently if the + object is not currently drawn.""" + + if not self.canvas: + return + if not self.canvas.isClosed(): + self.canvas.delete(self.id) + if self.canvas.autoflush: + _root.update() + self.canvas = None + self.id = None + + def move(self, dx, dy): + + """move object dx units in x direction and dy units in y + direction""" + + self._move(dx, dy) + canvas = self.canvas + if canvas and not canvas.isClosed(): + trans = canvas.trans + if trans: + x = dx / trans.xscale + y = -dy / trans.yscale + else: + x = dx + y = dy + self.canvas.move(self.id, x, y) + if canvas.autoflush: + _root.update() + + def _reconfig(self, option, setting): + # Internal method for changing configuration of the object + # Raises an error if the option does not exist in the config + # dictionary for this object + if option not in self.config: + raise GraphicsError(UNSUPPORTED_METHOD) + options = self.config + options[option] = setting + if self.canvas and not self.canvas.isClosed(): + self.canvas.itemconfig(self.id, options) + if self.canvas.autoflush: + _root.update() + + def _draw(self, canvas, options): + """draws appropriate figure on canvas with options provided + Returns Tk id of item drawn""" + pass # must override in subclass + + def _move(self, dx, dy): + """updates internal state of object to move it dx,dy units""" + pass # must override in subclass + + +class Point(GraphicsObject): + def __init__(self, x, y): + GraphicsObject.__init__(self, ["outline", "fill"]) + self.setFill = self.setOutline + self.x = x + self.y = y + + def _draw(self, canvas, options): + x, y = canvas.toScreen(self.x, self.y) + return canvas.create_rectangle(x, y, x + 1, y + 1, options) + + def _move(self, dx, dy): + self.x = self.x + dx + self.y = self.y + dy + + def clone(self): + other = Point(self.x, self.y) + other.config = self.config.copy() + return other + + def getX(self): + return self.x + + def getY(self): + return self.y + + +class _BBox(GraphicsObject): + # Internal base class for objects represented by bounding box + # (opposite corners) Line segment is a degenerate case. + + def __init__(self, p1, p2, options=["outline", "width", "fill"]): + GraphicsObject.__init__(self, options) + self.p1 = p1.clone() + self.p2 = p2.clone() + + def _move(self, dx, dy): + self.p1.x = self.p1.x + dx + self.p1.y = self.p1.y + dy + self.p2.x = self.p2.x + dx + self.p2.y = self.p2.y + dy + + def getP1(self): + return self.p1.clone() + + def getP2(self): + return self.p2.clone() + + def getCenter(self): + p1 = self.p1 + p2 = self.p2 + return Point((p1.x + p2.x) / 2.0, (p1.y + p2.y) / 2.0) + + +class Rectangle(_BBox): + def __init__(self, p1, p2): + _BBox.__init__(self, p1, p2) + + def _draw(self, canvas, options): + p1 = self.p1 + p2 = self.p2 + x1, y1 = canvas.toScreen(p1.x, p1.y) + x2, y2 = canvas.toScreen(p2.x, p2.y) + return canvas.create_rectangle(x1, y1, x2, y2, options) + + def clone(self): + other = Rectangle(self.p1, self.p2) + other.config = self.config.copy() + return other + + +class Oval(_BBox): + def __init__(self, p1, p2): + _BBox.__init__(self, p1, p2) + + def clone(self): + other = Oval(self.p1, self.p2) + other.config = self.config.copy() + return other + + def _draw(self, canvas, options): + p1 = self.p1 + p2 = self.p2 + x1, y1 = canvas.toScreen(p1.x, p1.y) + x2, y2 = canvas.toScreen(p2.x, p2.y) + return canvas.create_oval(x1, y1, x2, y2, options) + + +class Circle(Oval): + def __init__(self, center, radius): + p1 = Point(center.x - radius, center.y - radius) + p2 = Point(center.x + radius, center.y + radius) + Oval.__init__(self, p1, p2) + self.radius = radius + + def clone(self): + other = Circle(self.getCenter(), self.radius) + other.config = self.config.copy() + return other + + def getRadius(self): + return self.radius + + +class Line(_BBox): + def __init__(self, p1, p2): + _BBox.__init__(self, p1, p2, ["arrow", "fill", "width"]) + self.setFill(DEFAULT_CONFIG["outline"]) + self.setOutline = self.setFill + + def clone(self): + other = Line(self.p1, self.p2) + other.config = self.config.copy() + return other + + def _draw(self, canvas, options): + p1 = self.p1 + p2 = self.p2 + x1, y1 = canvas.toScreen(p1.x, p1.y) + x2, y2 = canvas.toScreen(p2.x, p2.y) + return canvas.create_line(x1, y1, x2, y2, options) + + def setArrow(self, option): + if not option in ["first", "last", "both", "none"]: + raise GraphicsError(BAD_OPTION) + self._reconfig("arrow", option) + + +class Polygon(GraphicsObject): + def __init__(self, *points): + # if points passed as a list, extract it + if len(points) == 1 and type(points[0]) == type([]): + points = points[0] + self.points = list(map(Point.clone, points)) + GraphicsObject.__init__(self, ["outline", "width", "fill"]) + + def clone(self): + other = Polygon(*self.points) + other.config = self.config.copy() + return other + + def getPoints(self): + return list(map(Point.clone, self.points)) + + def _move(self, dx, dy): + for p in self.points: + p.move(dx, dy) + + def _draw(self, canvas, options): + args = [canvas] + for p in self.points: + x, y = canvas.toScreen(p.x, p.y) + args.append(x) + args.append(y) + args.append(options) + return GraphWin.create_polygon(*args) + + +class Text(GraphicsObject): + def __init__(self, p, text): + GraphicsObject.__init__(self, ["justify", "fill", "text", "font"]) + self.setText(text) + self.anchor = p.clone() + self.setFill(DEFAULT_CONFIG["outline"]) + self.setOutline = self.setFill + + def _draw(self, canvas, options): + p = self.anchor + x, y = canvas.toScreen(p.x, p.y) + return canvas.create_text(x, y, options) + + def _move(self, dx, dy): + self.anchor.move(dx, dy) + + def clone(self): + other = Text(self.anchor, self.config["text"]) + other.config = self.config.copy() + return other + + def setText(self, text): + self._reconfig("text", text) + + def getText(self): + return self.config["text"] + + def getAnchor(self): + return self.anchor.clone() + + def setFace(self, face): + if face in ["helvetica", "arial", "courier", "times roman"]: + f, s, b = self.config["font"] + self._reconfig("font", (face, s, b)) + else: + raise GraphicsError(BAD_OPTION) + + def setSize(self, size): + if 5 <= size <= 36: + f, s, b = self.config["font"] + self._reconfig("font", (f, size, b)) + else: + raise GraphicsError(BAD_OPTION) + + def setStyle(self, style): + if style in ["bold", "normal", "italic", "bold italic"]: + f, s, b = self.config["font"] + self._reconfig("font", (f, s, style)) + else: + raise GraphicsError(BAD_OPTION) + + def setTextColor(self, color): + self.setFill(color) + + +class Entry(GraphicsObject): + def __init__(self, p, width): + GraphicsObject.__init__(self, []) + self.anchor = p.clone() + # print self.anchor + self.width = width + self.text = tk.StringVar(_root) + self.text.set("") + self.fill = "gray" + self.color = "black" + self.font = DEFAULT_CONFIG["font"] + self.entry = None + + def _draw(self, canvas, options): + p = self.anchor + x, y = canvas.toScreen(p.x, p.y) + frm = tk.Frame(canvas.master) + self.entry = tk.Entry( + frm, + width=self.width, + textvariable=self.text, + bg=self.fill, + fg=self.color, + font=self.font, + ) + self.entry.pack() + # self.setFill(self.fill) + return canvas.create_window(x, y, window=frm) + + def getText(self): + return self.text.get() + + def _move(self, dx, dy): + self.anchor.move(dx, dy) + + def getAnchor(self): + return self.anchor.clone() + + def clone(self): + other = Entry(self.anchor, self.width) + other.config = self.config.copy() + other.text = tk.StringVar() + other.text.set(self.text.get()) + other.fill = self.fill + return other + + def setText(self, t): + self.text.set(t) + + def setFill(self, color): + self.fill = color + if self.entry: + self.entry.config(bg=color) + + def _setFontComponent(self, which, value): + font = list(self.font) + font[which] = value + self.font = tuple(font) + if self.entry: + self.entry.config(font=self.font) + + def setFace(self, face): + if face in ["helvetica", "arial", "courier", "times roman"]: + self._setFontComponent(0, face) + else: + raise GraphicsError(BAD_OPTION) + + def setSize(self, size): + if 5 <= size <= 36: + self._setFontComponent(1, size) + else: + raise GraphicsError(BAD_OPTION) + + def setStyle(self, style): + if style in ["bold", "normal", "italic", "bold italic"]: + self._setFontComponent(2, style) + else: + raise GraphicsError(BAD_OPTION) + + def setTextColor(self, color): + self.color = color + if self.entry: + self.entry.config(fg=color) + + +class Image(GraphicsObject): + + idCount = 0 + imageCache = {} # tk photoimages go here to avoid GC while drawn + + def __init__(self, p, *pixmap): + GraphicsObject.__init__(self, []) + self.anchor = p.clone() + self.imageId = Image.idCount + Image.idCount = Image.idCount + 1 + if len(pixmap) == 1: # file name provided + self.img = tk.PhotoImage(file=pixmap[0], master=_root) + else: # width and height provided + width, height = pixmap + self.img = tk.PhotoImage(master=_root, width=width, height=height) + + def _draw(self, canvas, options): + p = self.anchor + x, y = canvas.toScreen(p.x, p.y) + self.imageCache[self.imageId] = self.img # save a reference + return canvas.create_image(x, y, image=self.img) + + def _move(self, dx, dy): + self.anchor.move(dx, dy) + + def undraw(self): + try: + del self.imageCache[self.imageId] # allow gc of tk photoimage + except KeyError: + pass + GraphicsObject.undraw(self) + + def getAnchor(self): + return self.anchor.clone() + + def clone(self): + other = Image(Point(0, 0), 0, 0) + other.img = self.img.copy() + other.anchor = self.anchor.clone() + other.config = self.config.copy() + return other + + def getWidth(self): + """Returns the width of the image in pixels""" + return self.img.width() + + def getHeight(self): + """Returns the height of the image in pixels""" + return self.img.height() + + def getPixel(self, x, y): + """Returns a list [r,g,b] with the RGB color values for pixel (x,y) + r,g,b are in range(256) + + """ + + value = self.img.get(x, y) + if type(value) == type(0): + return [value, value, value] + else: + return list(map(int, value.split())) + + def setPixel(self, x, y, color): + """Sets pixel (x,y) to the given color + + """ + self.img.put("{" + color + "}", (x, y)) + + def save(self, filename): + """Saves the pixmap image to filename. + The format for the save image is determined from the filname extension. + + """ + + path, name = os.path.split(filename) + ext = name.split(".")[-1] + self.img.write(filename, format=ext) + + +def color_rgb(r, g, b): + """r,g,b are intensities of red, green, and blue in range(256) + Returns color specifier string for the resulting color""" + return "#%02x%02x%02x" % (r, g, b) + + +def test(): + win = GraphWin() + win.setCoords(0, 0, 10, 10) + t = Text(Point(5, 5), "Centered Text") + t.draw(win) + p = Polygon(Point(1, 1), Point(5, 3), Point(2, 7)) + p.draw(win) + e = Entry(Point(5, 6), 10) + e.draw(win) + win.getMouse() + p.setFill("red") + p.setOutline("blue") + p.setWidth(2) + s = "" + for pt in p.getPoints(): + s = s + "(%0.1f,%0.1f) " % (pt.getX(), pt.getY()) + t.setText(e.getText()) + e.setFill("green") + e.setText("Spam!") + e.move(2, 0) + win.getMouse() + p.move(2, 3) + s = "" + for pt in p.getPoints(): + s = s + "(%0.1f,%0.1f) " % (pt.getX(), pt.getY()) + t.setText(s) + win.getMouse() + p.undraw() + e.undraw() + t.setStyle("bold") + win.getMouse() + t.setStyle("normal") + win.getMouse() + t.setStyle("italic") + win.getMouse() + t.setStyle("bold italic") + win.getMouse() + t.setSize(14) + win.getMouse() + t.setFace("arial") + t.setSize(20) + win.getMouse() + win.close() + + +if __name__ == "__main__": + test() diff --git a/imperfect_envs/driving/visualizer.py b/imperfect_envs/driving/visualizer.py new file mode 100644 index 0000000..d7c3b1f --- /dev/null +++ b/imperfect_envs/driving/visualizer.py @@ -0,0 +1,82 @@ +from driving.graphics import * +from driving.entities import RectangleEntity, CircleEntity, TextEntity + + + +class Visualizer: + def __init__(self, width: float, height: float, ppm: int): + # width (meters) + # height (meters) + # ppm is the number of pixels per meters + + self.ppm = ppm + self.display_width, self.display_height = int(width * ppm), int(height * ppm) + self.window_created = False + self.visualized_imgs = [] + self.win = None + + def create_window(self, bg_color: str = "gray80"): + if not self.window_created or self.win.isClosed(): + self.win = GraphWin("CARLO", self.display_width, self.display_height) + self.win.setBackground(bg_color) + self.window_created = True + self.visualized_imgs = [] + + def update_agents(self, agents: list, correct_pos: list=None, next_pos: list=None): + new_visualized_imgs = [] + + # Remove the movable agents from the window + for imgItem in self.visualized_imgs: + if imgItem["movable"]: + imgItem["graphics"].undraw() + else: + new_visualized_imgs.append({"movable": False, "graphics": imgItem["graphics"]}) + + # Add the updated movable agents (and the unmovable ones if they were not rendered before) + for agent in agents: + if isinstance(agent, TextEntity): + img = Text( + Point( + self.ppm * agent.center.x, + self.display_height - self.ppm * agent.center.y, + ), + agent.text, + ) + img.setSize(15) + img.draw(self.win) + # TODO(allanz): Hack: set movable=True so text is erased each iteration. + new_visualized_imgs.append({"movable": True, "graphics": img}) + elif agent.movable or not self.visualized_imgs: + if isinstance(agent, RectangleEntity): + C = [self.ppm * c for c in agent.corners] + img = Polygon([Point(c.x, self.display_height - c.y) for c in C]) + + # arrow + if agent.movable and (correct_pos and next_pos): + start = Point(self.ppm * agent.center.x, self.display_height - self.ppm * agent.center.y) + end = Point(self.ppm * correct_pos[0], self.display_height - self.ppm * correct_pos[1]) + #print("ACTION??: ", correct_pos) + line = Line(start, end) + line.setArrow("last") + line.draw(self.win) + new_visualized_imgs.append({"movable": agent.movable, "graphics": line}) + elif isinstance(agent, CircleEntity): + img = Circle( + Point( + self.ppm * agent.center.x, + self.display_height - self.ppm * agent.center.y, + ), + self.ppm * agent.radius, + ) + else: + raise NotImplementedError + img.setFill(agent.color) + img.draw(self.win) + new_visualized_imgs.append({"movable": agent.movable, "graphics": img}) + + self.visualized_imgs = new_visualized_imgs + + def close(self): + self.window_created = False + self.win.close() + self.visualized_imgs = [] diff --git a/imperfect_envs/driving/world.py b/imperfect_envs/driving/world.py new file mode 100644 index 0000000..2757471 --- /dev/null +++ b/imperfect_envs/driving/world.py @@ -0,0 +1,83 @@ +from typing import Union +import numpy as np +from driving.agents import Car, Pedestrian, Building +from driving.entities import Entity +from driving.visualizer import Visualizer + + +class World: + def __init__(self, dt: float, width: float, height: float, ppm: float = 8): + self.dynamic_agents = [] + self.static_agents = [] + self.t = 0 # simulation time + self.dt = dt # simulation time step + self.visualizer = Visualizer(width, height, ppm=ppm) + + def add(self, entity: Entity): + if entity.movable: + self.dynamic_agents.append(entity) + else: + self.static_agents.append(entity) + + def tick(self): + for agent in self.dynamic_agents: + agent.tick(self.dt) + self.t += self.dt + + def render(self, correct_pos=None, next_pos=None): + self.visualizer.create_window(bg_color="gray") + self.visualizer.update_agents(self.agents, correct_pos, next_pos) + + @property + def state(self): + return np.concatenate([agent.state for agent in self.dynamic_agents]) + + @state.setter + def state(self, x): + num_agents = len(self.dynamic_agents) + assert x.shape[0] % num_agents == 0 + agent_state_length = int(x.shape[0] / num_agents) + offset = 0 + for agent in self.dynamic_agents: + agent_new_state = x[offset : offset + agent_state_length] + agent.state = agent_new_state + offset += agent_state_length + + @property + def agents(self): + return self.static_agents + self.dynamic_agents + + def collision_exists(self, agent=None): + if agent is None: + for i in range(len(self.dynamic_agents)): + for j in range(i + 1, len(self.dynamic_agents)): + if self.dynamic_agents[i].collidable and self.dynamic_agents[j].collidable: + if self.dynamic_agents[i].collidesWith(self.dynamic_agents[j]): + return True + for j in range(len(self.static_agents)): + if self.dynamic_agents[i].collidable and self.static_agents[j].collidable: + if self.dynamic_agents[i].collidesWith(self.static_agents[j]): + return True + return False + + if not agent.collidable: + return False + + for i in range(len(self.agents)): + if ( + self.agents[i] is not agent + and self.agents[i].collidable + and agent.collidesWith(self.agents[i]) + ): + return True + return False + + def close(self): + self.reset() + self.static_agents = [] + self.visualizer.close() + + def reset(self): + self.dynamic_agents = [] + self.static_agents = [] + self.t = 0 diff --git a/imperfect_envs/imperfect.egg-info/PKG-INFO b/imperfect_envs/imperfect.egg-info/PKG-INFO new file mode 100644 index 0000000..75eeb17 --- /dev/null +++ b/imperfect_envs/imperfect.egg-info/PKG-INFO @@ -0,0 +1,10 @@ +Metadata-Version: 2.1 +Name: imperfect +Version: 0.0.1 +Summary: UNKNOWN +Home-page: UNKNOWN +License: UNKNOWN +Platform: UNKNOWN + +UNKNOWN + diff --git a/imperfect_envs/imperfect.egg-info/SOURCES.txt b/imperfect_envs/imperfect.egg-info/SOURCES.txt new file mode 100644 index 0000000..1a9d17b --- /dev/null +++ b/imperfect_envs/imperfect.egg-info/SOURCES.txt @@ -0,0 +1,7 @@ +README.md +setup.py +imperfect.egg-info/PKG-INFO +imperfect.egg-info/SOURCES.txt +imperfect.egg-info/dependency_links.txt +imperfect.egg-info/requires.txt +imperfect.egg-info/top_level.txt \ No newline at end of file diff --git a/imperfect_envs/imperfect.egg-info/dependency_links.txt b/imperfect_envs/imperfect.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/imperfect_envs/imperfect.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/imperfect_envs/imperfect.egg-info/requires.txt b/imperfect_envs/imperfect.egg-info/requires.txt new file mode 100644 index 0000000..01ef558 --- /dev/null +++ b/imperfect_envs/imperfect.egg-info/requires.txt @@ -0,0 +1,3 @@ +gym +numpy +reacher diff --git a/imperfect_envs/imperfect.egg-info/top_level.txt b/imperfect_envs/imperfect.egg-info/top_level.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/imperfect_envs/imperfect.egg-info/top_level.txt @@ -0,0 +1 @@ + diff --git a/imperfect_envs/reacher/__init__.py b/imperfect_envs/reacher/__init__.py new file mode 100644 index 0000000..4f42dff --- /dev/null +++ b/imperfect_envs/reacher/__init__.py @@ -0,0 +1,35 @@ +from gym.envs.registration import register + +register( + id='reacher_custom-v0', + entry_point='reacher.envs:ReacherCustomEnv', + max_episode_steps=50, + reward_threshold=-3.75, +) + +register( + id='reacher_custom-action1-v0', + entry_point='reacher.envs:ReacherCustomAction1Env', + max_episode_steps=50, + reward_threshold=-3.75, +) + +register( + id='reacher_custom-action2-v0', + entry_point='reacher.envs:ReacherCustomAction2Env', + max_episode_steps=50, + reward_threshold=-3.75, +) +register( + id='reacher_custom-raction1-v0', + entry_point='reacher.envs:ReacherCustomRAction1Env', + max_episode_steps=50, + reward_threshold=-3.75, +) + +register( + id='reacher_custom-raction2-v0', + entry_point='reacher.envs:ReacherCustomRAction2Env', + max_episode_steps=50, + reward_threshold=-3.75, +) diff --git a/imperfect_envs/reacher/__pycache__/__init__.cpython-310.pyc b/imperfect_envs/reacher/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f82214dfb8a251ba32db0994ae8b6654a9a46a5c GIT binary patch literal 750 zcma)3J5B>J5cMu0Kk_XoK%#>pMY50*p$G&N2m}&H6g0-#84^pecV(Nv<_;W$TW}1t zEmf|7DDZBANDwQq<*}c~dhdBAs8-9wj?>rr-R=@0ZwZ(mc?;!!&&?N0Y9l=qEgc)LvS-*yRwfpfoC?VZfz{n}R)347m;f zsTB!z+)((y6i_ozs0YCi#%n)xnQwR?cM|>0Z2g1jD{CWzp!+X^ZbGpB!-1N!u$67$ za?V2rMQY-2ip0fv%Z*q2kw|OZnRZ37q!h}v1%4)~WVbZDUwDH+pr-{>#ydl%Wcx&f zsP51=?Q5nYF8l4HNHW2F?eVV^McYPi_92f_F1ew!6Gm}yPXus3#GYd{bkBwgab4G$ Q&isd4$T;VJyDxuy0!9Yn00000 literal 0 HcmV?d00001 diff --git a/imperfect_envs/reacher/envs/__init__.py b/imperfect_envs/reacher/envs/__init__.py new file mode 100644 index 0000000..8ab022f --- /dev/null +++ b/imperfect_envs/reacher/envs/__init__.py @@ -0,0 +1,2 @@ +from reacher.envs.reacher import ReacherCustomEnv +from reacher.envs.reacher import ReacherCustomAction1Env, ReacherCustomAction2Env, ReacherCustomRAction1Env, ReacherCustomRAction2Env diff --git a/imperfect_envs/reacher/envs/__pycache__/__init__.cpython-310.pyc b/imperfect_envs/reacher/envs/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f95ddcbc03e09427ec23a5f5ce0e823d3001c5d9 GIT binary patch literal 388 zcmd1j<>g`k0`D9AX*+=QV-N=!FabFZKwPW=BvKes7;_kM8KW2(L2M=bPYGQImYLRnkaY=rzYhIZq%PnyfF~{VR%=|n< zpcGaKBanmyijE*8Em&nhdi*rmZiy5@EZ0lTD=XH6a*9AcDq;o^EFgjvM6dygl?+83 zAU25j6{4S!pPQ;*oSRrwqVJQMSd^#hnOl%rl$M%Yq8pZ2RGFEVuIo~nmzbNGT&$l7 ulZpq~qz|=8AIyo5&&CAHLY zNzX22i=p}fJIKksrzi@t=tY;J*PeXNq5r^~TJ#X;RzNowsQY`fq(sVM4qaj2&YO8N z^X7g0=26|HrILZi{rkD*XDf#BFJfjN8_adQ=^sIaAy{lQ7`|p~c6fs`>f^E1u^YB- zv)F8y=(8~HG@MCap;6Ft-G+P15Vmk08Nvzeb}{7b(nG6JMsGp5=yk*LL*A%>FNzZQ zlIEAdmqi79Me|kgOQH(Cs`+KX?i#h_1L$bfYfRbwEQ(V!N}YbY8+5%e*#YOIJwFK3 zfW&4W4(2-E^aGGkAFyGzaM(XFVG8~Sv%$p~tu|{|xuOj_SFqvais67-p@u7##mXb2 zQ4}vgrL$_~PUr_)p?tfaX5G$B=)sk})$jO;D$3TT=S%7DsNK&Msw2i*tCOnQn(NmCV? zao5k@ysBR4Zlc$Yv#6(>4Au*?cMk|x5bKCl*i(2S zO0y#-$YgxPggbs*E2#=*d7E9a>jmA8d71P?ydO%%1HYrnne>BgvQH#xOdsi_c9mS-Lz4A-m$61l`&8NB z<>$1Tm7EKyDS~M29$`A^HezD~Sb;FgK@lio4mC7>VqS!VN4Q`OO<@V+6Z0C)K|r;g zc7Z?>Euf4jJmv^AE?f$zi5wGL6!jYD7o~jes5CT(d=iG`G1;VC-?zSiGWwA>@Hr+2 zr1Alw-obyLJ$v@W$E$z2_0K`}WZKx+=aS4UmqFmcXb@@xA5g|g@?))nn2I{emLW`+ zhn}6|veoMPu_|i7xwjLdne;sAC!*U?g?ss3I2d(#+37`6jJw<*~N4HN^kOGPZ9RcLGQKs1<$4)a)UR0IT>6VI2l=c{#j9eTHZ{~0}hdopco98i+T zTSTZeiH?77w7}r`$HqkR^XZh&H{?4QkT;3E3sNgKB3N&C&Ku6nba{(ZsRN7;iHL~#n&&Sj*(04`-f56z zINcsCdrXCuRo8hUzljay>map~d>UuW=v$CVQHBCq2~b^jM*lhgIqgQApgf8XS)tWSR2onf;d!d$k=6TDKd6f5 z;o^uVBW?$KYqja>mER|_LF8vdenEtMJENV}ll&=d5V~)*iY}0~#N47=ak*Qrtmx4I zqjL{sAU%hdK&GYTr$&~R1Sc{5=!xup^ zBZGGznr%~dEMAJSB7}*4;E0O)&L-OnB*k`Kf zc|nY#4Yk&>5y))s;XR~Se31<Egbbv&QcIJ?gD{S#8|YnP64CZ1 zy?%)IkPhr3D72=FZTtqrPPZ}a4Sa*WEp2ZqTWobne?~V#eUkvB5Lo zTiec1Spy$ULc)?!~a|HuM z0p$e+`r%hW=!yaOBfQ5PSY&3nQXZOl)k$GqmsF|hBi8KvvbBOZ>dhREl5!e~-zDJ_ zO4B&uv5pI>!A?{-Gp<~t`fJ}gEdul0@6r0&9-15nADNlleMruC4P3yMHvPizlOY5b zr18}+OJhlQ77TMTS+7#E0^NS2hjaV<8g1=-xyYOPB1#~3YG#rmM~;+TTJ5yM(>D5A zyGIhlEk3ry=%Q>o_1s6EaWRZR8cGKB%W?{C>8F^v0$X%>N`EY}_BV{M~AP3Z;b6sn!@2HQd z@02|FCG`(MPR{|Y3gv*@Bf-;rO?zll{fZ=r!*6pt>38t+^d;)j#-cn|%K)4;`U$(1 z|6fJ_rq1nnmd251R2s`yXxarL1P%H9qG3yiuRheVCb~s + + + + + +