PyDiffGame 0.1.1__py3-none-any.whl → 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. PyDiffGame/ContinuousPyDiffGame.py +2 -2
  2. PyDiffGame/DiscretePyDiffGame.py +8 -9
  3. PyDiffGame/PyDiffGame.py +19 -12
  4. PyDiffGame/PyDiffGameLQRComparison.py +9 -10
  5. PyDiffGame/examples/InvertedPendulumComparison.py +257 -0
  6. PyDiffGame/examples/MassesWithSpringsComparison.py +218 -0
  7. PyDiffGame/examples/PVTOL.py +222 -0
  8. PyDiffGame/examples/PVTOLComparison.py +111 -0
  9. PyDiffGame/examples/QuadRotorControl.py +548 -0
  10. PyDiffGame/examples/figures/2/2-players_large_1.png +0 -0
  11. PyDiffGame/examples/figures/2/2-players_large_2.png +0 -0
  12. PyDiffGame/examples/figures/2/LQR_large_1.png +0 -0
  13. PyDiffGame/examples/figures/2/LQR_large_2.png +0 -0
  14. PyDiffGame/examples/figures/2/two_masses_tikz.png +0 -0
  15. PyDiffGame/examples/figures/4/4-players_large_1.png +0 -0
  16. PyDiffGame/examples/figures/4/4-players_large_2.png +0 -0
  17. PyDiffGame/examples/figures/4/LQR_large_1.png +0 -0
  18. PyDiffGame/examples/figures/4/LQR_large_2.png +0 -0
  19. PyDiffGame/examples/figures/8/8-players_large_1.png +0 -0
  20. PyDiffGame/examples/figures/8/8-players_large_2.png +0 -0
  21. PyDiffGame/examples/figures/8/LQR_large_1.png +0 -0
  22. PyDiffGame/examples/figures/8/LQR_large_2.png +0 -0
  23. PyDiffGame/examples/figures/PVTOL/PVTOL1.png +0 -0
  24. PyDiffGame/examples/figures/PVTOL/PVTOL10.png +0 -0
  25. PyDiffGame/examples/figures/PVTOL/PVTOL100.png +0 -0
  26. PyDiffGame/examples/figures/PVTOL/PVTOL1000.png +0 -0
  27. PyDiffGame/examples/figures/PVTOL0001.png +0 -0
  28. PyDiffGame/examples/figures/PVTOL001.png +0 -0
  29. PyDiffGame/examples/figures/PVTOL01.png +0 -0
  30. PyDiffGame/examples/figures/PVTOL1.png +0 -0
  31. {PyDiffGame-0.1.1.dist-info → pydiffgame-1.0.0.dist-info}/METADATA +46 -35
  32. pydiffgame-1.0.0.dist-info/RECORD +37 -0
  33. {PyDiffGame-0.1.1.dist-info → pydiffgame-1.0.0.dist-info}/WHEEL +1 -2
  34. {PyDiffGame-0.1.1.dist-info → pydiffgame-1.0.0.dist-info/licenses}/LICENSE +1 -1
  35. PyDiffGame-0.1.1.dist-info/RECORD +0 -12
  36. PyDiffGame-0.1.1.dist-info/top_level.txt +0 -1
@@ -4,7 +4,7 @@ import sys
4
4
  import numpy as np
5
5
  from scipy.integrate import odeint
6
6
  from numpy.linalg import eigvals, inv
7
- from typing import Sequence, Optional
7
+ from typing import Sequence, Optional, Union
8
8
 
9
9
  from PyDiffGame.PyDiffGame import PyDiffGame
10
10
  from PyDiffGame.Objective import Objective
@@ -30,7 +30,7 @@ class ContinuousPyDiffGame(PyDiffGame):
30
30
  x_0: Optional[np.array] = None,
31
31
  x_T: Optional[np.array] = None,
32
32
  T_f: Optional[float] = None,
33
- P_f: Optional[Sequence[np.array] | np.array] = None,
33
+ P_f: Optional[Union[Sequence[np.array], np.array]] = None,
34
34
  show_legend: Optional[bool] = True,
35
35
  state_variables_names: Optional[Sequence[str]] = None,
36
36
  epsilon_x: Optional[float] = PyDiffGame._epsilon_x_default,
@@ -1,7 +1,7 @@
1
1
  import numpy as np
2
2
  import scipy as sp
3
- import quadpy
4
- from typing import Sequence, Optional
3
+
4
+ from typing import Sequence, Optional, Union
5
5
 
6
6
  from PyDiffGame.PyDiffGame import PyDiffGame
7
7
  from PyDiffGame.Objective import Objective
@@ -37,14 +37,13 @@ class DiscretePyDiffGame(PyDiffGame):
37
37
  x_0: Optional[np.array] = None,
38
38
  x_T: Optional[np.array] = None,
39
39
  T_f: Optional[float] = None,
40
- P_f: Optional[Sequence[np.array] | np.array] = None,
40
+ P_f: Optional[Union[Sequence[np.array], np.array]] = None,
41
41
  show_legend: Optional[bool] = True,
42
42
  state_variables_names: Optional[Sequence] = None,
43
43
  epsilon_x: Optional[float] = PyDiffGame._epsilon_x_default,
44
44
  epsilon_P: Optional[float] = PyDiffGame._epsilon_P_default,
45
45
  L: Optional[int] = PyDiffGame._L_default,
46
46
  eta: Optional[int] = PyDiffGame._eta_default,
47
- force_finite_horizon: Optional[bool] = False,
48
47
  debug: Optional[bool] = False):
49
48
 
50
49
  super().__init__(A=A,
@@ -64,7 +63,6 @@ class DiscretePyDiffGame(PyDiffGame):
64
63
  epsilon_P=epsilon_P,
65
64
  L=L,
66
65
  eta=eta,
67
- force_finite_horizon=force_finite_horizon,
68
66
  debug=debug
69
67
  )
70
68
 
@@ -134,12 +132,13 @@ class DiscretePyDiffGame(PyDiffGame):
134
132
  """
135
133
 
136
134
  A_tilda = np.exp(self._A * self._delta)
137
- e_AT = quadpy.quad(f=lambda T: np.array([np.exp(t * self._A) for t in T]).swapaxes(0, 2).swapaxes(0, 1),
138
- a=0,
139
- b=self._delta)[0]
135
+ e_AT = sp.integrate.quad(lambda T: np.array([
136
+ np.exp(t * self._A) for t in T]).swapaxes(0, 2).swapaxes(0, 1),
137
+ a=0,
138
+ b=self._delta)[0]
140
139
 
141
140
  self._A = A_tilda
142
- B_tilda = e_AT
141
+ B_tilda = np.array(e_AT)
143
142
  self._Bs = [B_tilda @ B_i for B_i in self._Bs]
144
143
  self._Q = [Q_i * self._delta for Q_i in self._Q]
145
144
  self._R = [R_i / self._delta for R_i in self._Rs]
PyDiffGame/PyDiffGame.py CHANGED
@@ -9,7 +9,7 @@ import matplotlib.pyplot as plt
9
9
  import scipy as sp
10
10
  import sympy
11
11
  import warnings
12
- from typing import Callable, Final, ClassVar, Optional, Sequence
12
+ from typing import Callable, Final, ClassVar, Optional, Sequence, Union
13
13
  from abc import ABC, abstractmethod
14
14
 
15
15
  from PyDiffGame.Objective import Objective, GameObjective, LQRObjective
@@ -122,7 +122,7 @@ class PyDiffGame(ABC, Callable, Sequence):
122
122
  x_0: Optional[np.array] = None,
123
123
  x_T: Optional[np.array] = None,
124
124
  T_f: Optional[float] = None,
125
- P_f: Optional[Sequence[np.array] | np.array] = None,
125
+ P_f: Optional[Union[Sequence[np.array], np.array]] = None,
126
126
  show_legend: Optional[bool] = True,
127
127
  state_variables_names: Optional[Sequence[str]] = None,
128
128
  epsilon_x: Optional[float] = _epsilon_x_default,
@@ -162,7 +162,6 @@ class PyDiffGame(ABC, Callable, Sequence):
162
162
  self._M_inv = np.linalg.inv(self._M)
163
163
  except np.linalg.LinAlgError:
164
164
  self._M_inv = np.linalg.pinv(self._M)
165
- print(np.linalg.matrix_rank(self._M_inv))
166
165
  l = 0
167
166
  self._Bs = []
168
167
 
@@ -445,7 +444,15 @@ class PyDiffGame(ABC, Callable, Sequence):
445
444
  self._fig = plt.figure(dpi=150)
446
445
  self._fig.set_size_inches(8, 6)
447
446
  plt.plot(t[:temporal_variables.shape[0]], temporal_variables)
448
- plt.xlabel('Time $[s]$')
447
+ plt.xlabel('Time $[s]$', fontsize=18)
448
+ plt.xticks(fontsize=18)
449
+ plt.yticks(fontsize=18)
450
+ plt.subplots_adjust(wspace=0)
451
+
452
+ if not is_P and max(np.max(temporal_variables, axis=0)) > 1e3:
453
+ plt.ticklabel_format(style='sci', axis='y', scilimits=(0, 0))
454
+ plt.gca().yaxis.get_offset_text().set_size(18)
455
+
449
456
 
450
457
  if title:
451
458
  plt.title(title)
@@ -467,10 +474,10 @@ class PyDiffGame(ABC, Callable, Sequence):
467
474
 
468
475
  plt.legend(labels=labels,
469
476
  loc='upper left' if is_P else 'right',
470
- ncol=2,
471
- prop={'size': 14},
472
- bbox_to_anchor=(1, 0.75),
473
- # framealpha=0.3
477
+ ncol=4 if self._n > 8 else 2,
478
+ prop={'size': 26},
479
+ bbox_to_anchor=(1, 0.55),
480
+ framealpha=0.3
474
481
  )
475
482
 
476
483
  plt.grid()
@@ -529,7 +536,7 @@ class PyDiffGame(ABC, Callable, Sequence):
529
536
  self.__plot_temporal_variables(t=self._forward_time,
530
537
  temporal_variables=state_variables,
531
538
  is_P=False,
532
- title=self.__get_temporal_state_variables_title(linear_system=linear_system),
539
+ # title=self.__get_temporal_state_variables_title(linear_system=linear_system),
533
540
  output_variables_names=output_variables_names)
534
541
 
535
542
  def __plot_x(self):
@@ -543,7 +550,7 @@ class PyDiffGame(ABC, Callable, Sequence):
543
550
  C: np.array,
544
551
  output_variables_names: Optional[Sequence[str]] = None,
545
552
  save_figure: Optional[bool] = False,
546
- figure_path: Optional[str | Path] = _default_figures_filename,
553
+ figure_path: Optional[Union[str, Path]] = _default_figures_filename,
547
554
  figure_filename: Optional[str] = _default_figures_filename):
548
555
  """
549
556
  Plots an output vector y = C x^T wth respect to time
@@ -572,7 +579,7 @@ class PyDiffGame(ABC, Callable, Sequence):
572
579
 
573
580
  @_post_convergence
574
581
  def __save_figure(self,
575
- figure_path: Optional[str | Path] = _default_figures_filename,
582
+ figure_path: Optional[Union[str, Path]] = _default_figures_filename,
576
583
  figure_filename: Optional[str] = _default_figures_filename):
577
584
  """
578
585
  Saves the current figure
@@ -1150,7 +1157,7 @@ class PyDiffGame(ABC, Callable, Sequence):
1150
1157
  M: Optional[np.array] = None,
1151
1158
  output_variables_names: Optional[Sequence[str]] = None,
1152
1159
  save_figure: Optional[bool] = False,
1153
- figure_path: Optional[str | Path] = _default_figures_path,
1160
+ figure_path: Optional[Union[str, Path]] = _default_figures_path,
1154
1161
  figure_filename: Optional[str] = _default_figures_filename,
1155
1162
  print_characteristic_polynomials: Optional[bool] = False,
1156
1163
  print_eigenvalues: Optional[bool] = False):
@@ -1,13 +1,12 @@
1
1
  import numpy as np
2
2
  from tqdm import tqdm
3
3
  from time import time
4
- from termcolor import colored
5
4
  from pathlib import Path
6
5
  import itertools
7
6
  from concurrent.futures import ProcessPoolExecutor
8
7
 
9
8
  import inspect
10
- from typing import Sequence, Any, Optional, Callable
9
+ from typing import Sequence, Any, Optional, Callable, Union
11
10
  from abc import ABC
12
11
 
13
12
  from PyDiffGame.PyDiffGame import PyDiffGame
@@ -35,9 +34,9 @@ class PyDiffGameLQRComparison(ABC, Callable, Sequence):
35
34
  def __init__(self,
36
35
  args: dict[str, Any],
37
36
  games_objectives: Sequence[Sequence[GameObjective]],
38
- M: np.array,
37
+ M: np.array = None,
39
38
  continuous: bool = True):
40
- GameClass = ContinuousPyDiffGame if continuous else DiscretePyDiffGame
39
+ game_class = ContinuousPyDiffGame if continuous else DiscretePyDiffGame
41
40
 
42
41
  self.__args = args
43
42
  self.__verify_input()
@@ -47,7 +46,7 @@ class PyDiffGameLQRComparison(ABC, Callable, Sequence):
47
46
  self.__M = M
48
47
 
49
48
  for i, game_i_objectives in enumerate(games_objectives):
50
- game_i = GameClass(**self.__args | {'objectives': [o for o in game_i_objectives]})
49
+ game_i = game_class(**self.__args | {'objectives': [o for o in game_i_objectives]})
51
50
  self._games[i] = game_i
52
51
 
53
52
  if game_i.is_LQR():
@@ -110,8 +109,9 @@ class PyDiffGameLQRComparison(ABC, Callable, Sequence):
110
109
  plot_Mx: Optional[bool] = False,
111
110
  output_variables_names: Optional[Sequence[str]] = None,
112
111
  save_figure: Optional[bool] = False,
113
- figure_path: Optional[str | Path] = PyDiffGame.default_figures_path,
114
- figure_filename: Optional[str | Callable[[PyDiffGame], str]] = PyDiffGame.default_figures_filename,
112
+ figure_path: Optional[Union[str, Path]] = PyDiffGame.default_figures_path,
113
+ figure_filename: Optional[Union[str, Callable[[PyDiffGame], str]]] =
114
+ PyDiffGame.default_figures_filename,
115
115
  run_animations: Optional[bool] = True,
116
116
  print_characteristic_polynomials: Optional[bool] = False,
117
117
  print_eigenvalues: Optional[bool] = False):
@@ -134,7 +134,7 @@ class PyDiffGameLQRComparison(ABC, Callable, Sequence):
134
134
  self.__run_animation(i=i)
135
135
 
136
136
  @staticmethod
137
- def run_multiprocess(multiprocess_worker_function: Callable[[Any], None],
137
+ def run_multiprocess(multiprocess_worker_function: Callable,
138
138
  values: Sequence[Sequence]):
139
139
  t_start = time()
140
140
  combos = list(itertools.product(*values))
@@ -147,8 +147,7 @@ class PyDiffGameLQRComparison(ABC, Callable, Sequence):
147
147
 
148
148
  for combo, submittal in tqdm(iterable=submittals.items(), total=len(submittals)):
149
149
  values = combo[1:-1].split(delimiter)
150
- print_str = f"""{colored(text=f"{delimiter.join([f'{n}={v}' for n, v in zip(names, values)])}",
151
- color='blue')}"""
150
+ print_str = f"{delimiter.join([f'{n}={v}' for n, v in zip(names, values)])}"
152
151
  print(print_str)
153
152
  submittal.result()
154
153
 
@@ -0,0 +1,257 @@
1
+ from __future__ import annotations
2
+
3
+ import numpy as np
4
+ import scipy as sp
5
+ from time import time
6
+ import matplotlib
7
+ import matplotlib.pyplot as plt
8
+
9
+ from typing import Optional
10
+
11
+ from PyDiffGame.PyDiffGame import PyDiffGame
12
+ from PyDiffGame.PyDiffGameLQRComparison import PyDiffGameLQRComparison
13
+ from PyDiffGame.Objective import GameObjective, LQRObjective
14
+
15
+
16
+ class InvertedPendulumComparison(PyDiffGameLQRComparison):
17
+ def __init__(self,
18
+ m_c: float,
19
+ m_p: float,
20
+ p_L: float,
21
+ q: float,
22
+ r: Optional[float] = 1,
23
+ x_0: Optional[np.array] = None,
24
+ x_T: Optional[np.array] = None,
25
+ T_f: Optional[float] = None,
26
+ epsilon_x: Optional[float] = PyDiffGame.epsilon_x_default,
27
+ epsilon_P: Optional[float] = PyDiffGame.epsilon_P_default,
28
+ L: Optional[int] = PyDiffGame.L_default,
29
+ eta: Optional[int] = PyDiffGame.eta_default):
30
+ self.__m_c = m_c
31
+ self.__m_p = m_p
32
+ self.__p_L = p_L
33
+ self.__l = self.__p_L / 2 # CoM of uniform rod
34
+ self.__I = 1 / 12 * self.__m_p * self.__p_L ** 2 # center mass moment of inertia of uniform rod
35
+
36
+ # # original linear system
37
+ linearized_D = self.__m_c * self.__m_p * self.__l ** 2 + self.__I * (self.__m_c + self.__m_p)
38
+ a32 = self.__m_p * PyDiffGame.g * self.__l ** 2 / linearized_D
39
+ a42 = self.__m_p * PyDiffGame.g * self.__l * (self.__m_c + self.__m_p) / linearized_D
40
+ A = np.array([[0, 0, 1, 0],
41
+ [0, 0, 0, 1],
42
+ [0, a32, 0, 0],
43
+ [0, a42, 0, 0]])
44
+
45
+ b21 = (m_p * self.__l ** 2 + self.__I) / linearized_D
46
+ b31 = m_p * self.__l / linearized_D
47
+ b22 = b31
48
+ b32 = (m_c + m_p) / linearized_D
49
+ B = np.array([[0, 0],
50
+ [0, 0],
51
+ [b21, b22],
52
+ [b31, b32]])
53
+
54
+ M1 = B[2, :].reshape(1, 2)
55
+ M2 = B[3, :].reshape(1, 2)
56
+ Ms = [M1, M2]
57
+
58
+ Q_x = q * np.array([[1, 0, 2, 0],
59
+ [0, 0, 0, 0],
60
+ [2, 0, 4, 0],
61
+ [0, 0, 0, 0]])
62
+ Q_theta = q * np.array([[0, 0, 0, 0],
63
+ [0, 1, 0, 2],
64
+ [0, 0, 0, 0],
65
+ [0, 2, 0, 4]])
66
+ Q_lqr = Q_theta + Q_x
67
+ Qs = [Q_x, Q_theta]
68
+
69
+ R_lqr = np.diag([r] * 2)
70
+ Rs = [np.array([r])] * 2
71
+
72
+ self.__origin = (0.0, 0.0)
73
+
74
+ state_variables_names = ['x',
75
+ '\\theta',
76
+ '\\dot{x}',
77
+ '\\dot{\\theta}']
78
+
79
+ args = {'A': A,
80
+ 'B': B,
81
+ 'x_0': x_0,
82
+ 'x_T': x_T,
83
+ 'T_f': T_f,
84
+ 'state_variables_names': state_variables_names,
85
+ 'epsilon_x': epsilon_x,
86
+ 'epsilon_P': epsilon_P,
87
+ 'L': L,
88
+ 'eta': eta,
89
+ 'force_finite_horizon': T_f is not None}
90
+
91
+ lqr_objective = [LQRObjective(Q=Q_lqr, R_ii=R_lqr)]
92
+ game_objectives = [GameObjective(Q=Q, R_ii=R, M_i=M_i) for Q, R, M_i in zip(Qs, Rs, Ms)]
93
+ games_objectives = [lqr_objective, game_objectives]
94
+
95
+ super().__init__(args=args,
96
+ games_objectives=games_objectives,
97
+ continuous=True)
98
+
99
+ def __simulate_non_linear_system(self,
100
+ i: int,
101
+ plot: bool = False) -> np.array:
102
+ game = self._games[i]
103
+ K = game.K
104
+ x_T = game.x_T
105
+
106
+ def nonlinear_state_space(_, x_t: np.array) -> np.array:
107
+ x_t = x_t - x_T
108
+
109
+ if game.is_LQR():
110
+ u_t = - K[0] @ x_t
111
+ F_t, M_t = u_t.T
112
+ else:
113
+ K_x, K_theta = K
114
+ v_x = - K_x @ x_t
115
+ v_theta = - K_theta @ x_t
116
+ v = np.array([v_x, v_theta])
117
+ F_t, M_t = game.M_inv @ v
118
+
119
+ x, theta, x_dot, theta_dot = x_t
120
+
121
+ theta_ddot = 1 / (
122
+ self.__m_p * self.__l ** 2 + self.__I - (self.__m_p * self.__l) ** 2 * np.cos(theta) ** 2 /
123
+ (self.__m_p + self.__m_c)) * (M_t - self.__m_p * self.__l *
124
+ (np.cos(theta) / (self.__m_p + self.__m_c) *
125
+ (F_t + self.__m_p * self.__l * np.sin(theta)
126
+ * theta_dot ** 2) + PyDiffGame.g * np.sin(theta)))
127
+ x_ddot = 1 / (self.__m_p + self.__m_c) * (F_t + self.__m_p * self.__l * (np.sin(theta) * theta_dot ** 2 -
128
+ np.cos(theta) * theta_ddot))
129
+ if isinstance(theta_ddot, np.ndarray):
130
+ theta_ddot = theta_ddot[0]
131
+ x_ddot = x_ddot[0]
132
+
133
+ non_linear_x = np.array([x_dot, theta_dot, x_ddot, theta_ddot],
134
+ dtype=float)
135
+
136
+ return non_linear_x
137
+
138
+ pendulum_state = sp.integrate.solve_ivp(fun=nonlinear_state_space,
139
+ t_span=[0.0, game.T_f],
140
+ y0=game.x_0,
141
+ t_eval=game.forward_time,
142
+ rtol=game.epsilon)
143
+
144
+ Y = pendulum_state.y
145
+
146
+ if plot:
147
+ game.plot_state_variables(state_variables=Y.T,
148
+ linear_system=False)
149
+
150
+ return Y
151
+
152
+ def __run_animation(self,
153
+ i: int) -> (matplotlib.lines.Line2D, matplotlib.patches.Rectangle):
154
+ game = self._games[i]
155
+ game._x_non_linear = self.__simulate_non_linear_system(i=i,
156
+ plot=True)
157
+ x_t, theta_t, x_dot_t, theta_dot_t = game._x_non_linear
158
+
159
+ pendulumArm = matplotlib.lines.Line2D(xdata=self.__origin,
160
+ ydata=self.__origin,
161
+ color='r')
162
+ cart = matplotlib.patches.Rectangle(xy=self.__origin,
163
+ width=0.5,
164
+ height=0.15,
165
+ color='b')
166
+
167
+ fig = plt.figure()
168
+ x_max = max(abs(max(x_t)), abs(min(x_t)))
169
+ square_side = 1.1 * min(max(self.__p_L, x_max), 3 * self.__p_L)
170
+
171
+ ax = fig.add_subplot(111,
172
+ aspect='equal',
173
+ xlim=(-square_side, square_side),
174
+ ylim=(-square_side, square_side),
175
+ title=f"Inverted Pendulum {'LQR' if game.is_LQR() else 'Game'} Simulation")
176
+
177
+ def init() -> (matplotlib.lines.Line2D, matplotlib.patches.Rectangle):
178
+ ax.add_patch(cart)
179
+ ax.add_line(pendulumArm)
180
+
181
+ return pendulumArm, cart
182
+
183
+ def animate(i: int) -> (matplotlib.lines.Line2D, matplotlib.patches.Rectangle):
184
+ x_i, theta_i = x_t[i], theta_t[i]
185
+ pendulum_x_coordinates = [x_i, x_i + self.__p_L * np.sin(theta_i)]
186
+ pendulum_y_coordinates = [0, - self.__p_L * np.cos(theta_i)]
187
+ pendulumArm.set_xdata(x=pendulum_x_coordinates)
188
+ pendulumArm.set_ydata(y=pendulum_y_coordinates)
189
+
190
+ cart_x_y = [x_i - cart.get_width() / 2, - cart.get_height()]
191
+ cart.set_xy(xy=cart_x_y)
192
+
193
+ return pendulumArm, cart
194
+
195
+ ax.grid()
196
+ t0 = time()
197
+ animate(0)
198
+ t1 = time()
199
+
200
+ frames = game.L
201
+ interval = game.T_f - (t1 - t0)
202
+
203
+ anim = matplotlib.animationFuncAnimation(fig=fig,
204
+ func=animate,
205
+ init_func=init,
206
+ frames=frames,
207
+ interval=interval,
208
+ blit=True)
209
+ plt.show()
210
+
211
+
212
+ def multiprocess_worker_function(x_T: float,
213
+ theta_0: float,
214
+ m_c: float,
215
+ m_p: float,
216
+ p_L: float,
217
+ q: float,
218
+ epsilon_x: float,
219
+ epsilon_P: float) -> int:
220
+ x_T = np.array([x_T, # x
221
+ theta_0, # theta
222
+ 0, # x_dot
223
+ 0] # theta_dot
224
+ )
225
+ x_0 = np.zeros_like(x_T)
226
+
227
+ inverted_pendulum_comparison = \
228
+ InvertedPendulumComparison(m_c=m_c,
229
+ m_p=m_p,
230
+ p_L=p_L,
231
+ q=q,
232
+ x_0=x_0,
233
+ x_T=x_T,
234
+ epsilon_x=epsilon_x,
235
+ epsilon_P=epsilon_P) # game class
236
+ is_max_lqr = \
237
+ inverted_pendulum_comparison(plot_state_spaces=False,
238
+ run_animations=False
239
+ )
240
+
241
+ # inverted_pendulum_comparison.plot_two_state_spaces(non_linear=True)
242
+ return int(is_max_lqr)
243
+
244
+
245
+ if __name__ == '__main__':
246
+ x_Ts = [10 ** p for p in [2]]
247
+ theta_Ts = [np.pi / 2 + np.pi / n for n in [10]]
248
+ m_cs = [10 ** p for p in [1, 2]]
249
+ m_ps = [10 ** p for p in [0, 1, 2]]
250
+ p_Ls = [10 ** p for p in [0, 1]]
251
+ qs = [10 ** p for p in [-2, -1, 0, 1]]
252
+ epsilon_xs = [10 ** (-7)]
253
+ epsilon_Ps = [10 ** (-3)]
254
+ params = [x_Ts, theta_Ts, m_cs, m_ps, p_Ls, qs, epsilon_xs, epsilon_Ps]
255
+
256
+ PyDiffGameLQRComparison.run_multiprocess(multiprocess_worker_function=multiprocess_worker_function,
257
+ values=params)