Skip to content

Commit 8c28ff3

Browse files
author
Shunichi09
committed
Add nonlinear sample system
1 parent 8f4ba9a commit 8c28ff3

13 files changed

+434
-35
lines changed

PythonLinearNonlinearControl/common/utils.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,17 +91,17 @@ def func_x(self, x_1, x_2, u):
9191
for i, func in enumerate(functions):
9292
k3[i] = dt * func(state + k2, u)
9393

94-
return (k0 + 2. * k1 + 2. * k2 + k3) / 6.
94+
return state + (k0 + 2. * k1 + 2. * k2 + k3) / 6.
9595

9696
else:
9797
batch_size, state_size = state.shape
9898
assert state_size == len(functions), \
9999
"Invalid functions length, You need to give the state size functions"
100100

101-
k0 = np.zeros(batch_size, state_size)
102-
k1 = np.zeros(batch_size, state_size)
103-
k2 = np.zeros(batch_size, state_size)
104-
k3 = np.zeros(batch_size, state_size)
101+
k0 = np.zeros((batch_size, state_size))
102+
k1 = np.zeros((batch_size, state_size))
103+
k2 = np.zeros((batch_size, state_size))
104+
k3 = np.zeros((batch_size, state_size))
105105

106106
for i, func in enumerate(functions):
107107
k0[:, i] = dt * func(state, u)
@@ -115,4 +115,4 @@ def func_x(self, x_1, x_2, u):
115115
for i, func in enumerate(functions):
116116
k3[:, i] = dt * func(state + k2, u)
117117

118-
return (k0 + 2. * k1 + 2. * k2 + k3) / 6.
118+
return state + (k0 + 2. * k1 + 2. * k2 + k3) / 6.

PythonLinearNonlinearControl/configs/make_configs.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from .first_order_lag import FirstOrderLagConfigModule
22
from .two_wheeled import TwoWheeledConfigModule
33
from .cartpole import CartPoleConfigModule
4+
from .nonlinear_sample_system import NonlinearSampleSystemConfigModule
45

56

67
def make_config(args):
@@ -14,3 +15,5 @@ def make_config(args):
1415
return TwoWheeledConfigModule()
1516
elif args.env == "CartPole":
1617
return CartPoleConfigModule()
18+
elif args.env == "NonlinearSample":
19+
return NonlinearSampleSystemConfigModule()
Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
import numpy as np
2+
3+
4+
class NonlinearSampleSystemConfigModule():
5+
# parameters
6+
ENV_NAME = "NonlinearSampleSystem-v0"
7+
PLANNER_TYPE = "Const"
8+
TYPE = "Nonlinear"
9+
TASK_HORIZON = 2500
10+
PRED_LEN = 10
11+
STATE_SIZE = 2
12+
INPUT_SIZE = 1
13+
DT = 0.01
14+
R = np.diag([0.01])
15+
Q = None
16+
Sf = None
17+
# bounds
18+
INPUT_LOWER_BOUND = np.array([-0.5])
19+
INPUT_UPPER_BOUND = np.array([0.5])
20+
21+
def __init__(self):
22+
"""
23+
"""
24+
# opt configs
25+
self.opt_config = {
26+
"Random": {
27+
"popsize": 5000
28+
},
29+
"CEM": {
30+
"popsize": 500,
31+
"num_elites": 50,
32+
"max_iters": 15,
33+
"alpha": 0.3,
34+
"init_var": 9.,
35+
"threshold": 0.001
36+
},
37+
"MPPI": {
38+
"beta": 0.6,
39+
"popsize": 5000,
40+
"kappa": 0.9,
41+
"noise_sigma": 0.5,
42+
},
43+
"MPPIWilliams": {
44+
"popsize": 5000,
45+
"lambda": 1.,
46+
"noise_sigma": 0.9,
47+
},
48+
"iLQR": {
49+
"max_iter": 500,
50+
"init_mu": 1.,
51+
"mu_min": 1e-6,
52+
"mu_max": 1e10,
53+
"init_delta": 2.,
54+
"threshold": 1e-6,
55+
},
56+
"DDP": {
57+
"max_iter": 500,
58+
"init_mu": 1.,
59+
"mu_min": 1e-6,
60+
"mu_max": 1e10,
61+
"init_delta": 2.,
62+
"threshold": 1e-6,
63+
},
64+
"NMPC-CGMRES": {
65+
},
66+
"NMPC-Newton": {
67+
},
68+
}
69+
70+
@staticmethod
71+
def input_cost_fn(u):
72+
""" input cost functions
73+
74+
Args:
75+
u (numpy.ndarray): input, shape(pred_len, input_size)
76+
or shape(pop_size, pred_len, input_size)
77+
Returns:
78+
cost (numpy.ndarray): cost of input, shape(pred_len, input_size) or
79+
shape(pop_size, pred_len, input_size)
80+
"""
81+
return (u**2) * np.diag(NonlinearSampleSystemConfigModule.R)
82+
83+
@staticmethod
84+
def state_cost_fn(x, g_x):
85+
""" state cost function
86+
87+
Args:
88+
x (numpy.ndarray): state, shape(pred_len, state_size)
89+
or shape(pop_size, pred_len, state_size)
90+
g_x (numpy.ndarray): goal state, shape(pred_len, state_size)
91+
or shape(pop_size, pred_len, state_size)
92+
Returns:
93+
cost (numpy.ndarray): cost of state, shape(pred_len, 1) or
94+
shape(pop_size, pred_len, 1)
95+
"""
96+
97+
if len(x.shape) > 2:
98+
return (0.5 * (x[:, :, 0]**2) +
99+
0.5 * (x[:, :, 1]**2))[:, :, np.newaxis]
100+
101+
elif len(x.shape) > 1:
102+
return (0.5 * (x[:, 0]**2) + 0.5 * (x[:, 1]**2))[:, np.newaxis]
103+
104+
return 0.5 * (x[0]**2) + 0.5 * (x[1]**2)
105+
106+
@ staticmethod
107+
def terminal_state_cost_fn(terminal_x, terminal_g_x):
108+
"""
109+
110+
Args:
111+
terminal_x (numpy.ndarray): terminal state,
112+
shape(state_size, ) or shape(pop_size, state_size)
113+
terminal_g_x (numpy.ndarray): terminal goal state,
114+
shape(state_size, ) or shape(pop_size, state_size)
115+
Returns:
116+
cost (numpy.ndarray): cost of state, shape(pred_len, ) or
117+
shape(pop_size, pred_len)
118+
"""
119+
120+
if len(terminal_x.shape) > 1:
121+
return (0.5 * (terminal_x[:, 0]**2) +
122+
0.5 * (terminal_x[:, 1]**2))[:, np.newaxis]
123+
124+
return 0.5 * (terminal_x[0]**2) + 0.5 * (terminal_x[1]**2)
125+
126+
@ staticmethod
127+
def gradient_cost_fn_with_state(x, g_x, terminal=False):
128+
""" gradient of costs with respect to the state
129+
130+
Args:
131+
x (numpy.ndarray): state, shape(pred_len, state_size)
132+
g_x (numpy.ndarray): goal state, shape(pred_len, state_size)
133+
134+
Returns:
135+
l_x (numpy.ndarray): gradient of cost, shape(pred_len, state_size)
136+
or shape(1, state_size)
137+
"""
138+
if not terminal:
139+
cost_dx0 = x[:, 0]
140+
cost_dx1 = x[:, 1]
141+
cost_dx = np.stack((cost_dx0, cost_dx1), axis=1)
142+
return cost_dx
143+
144+
cost_dx0 = x[0]
145+
cost_dx1 = x[1]
146+
cost_dx = np.array([[cost_dx0, cost_dx1]])
147+
148+
return cost_dx
149+
150+
@ staticmethod
151+
def gradient_cost_fn_with_input(x, u):
152+
""" gradient of costs with respect to the input
153+
154+
Args:
155+
x (numpy.ndarray): state, shape(pred_len, state_size)
156+
u (numpy.ndarray): goal state, shape(pred_len, input_size)
157+
Returns:
158+
l_u (numpy.ndarray): gradient of cost, shape(pred_len, input_size)
159+
"""
160+
return 2. * u * np.diag(NonlinearSampleSystemConfigModule.R)
161+
162+
@ staticmethod
163+
def hessian_cost_fn_with_state(x, g_x, terminal=False):
164+
""" hessian costs with respect to the state
165+
166+
Args:
167+
x (numpy.ndarray): state, shape(pred_len, state_size)
168+
g_x (numpy.ndarray): goal state, shape(pred_len, state_size)
169+
Returns:
170+
l_xx (numpy.ndarray): gradient of cost,
171+
shape(pred_len, state_size, state_size) or
172+
shape(1, state_size, state_size) or
173+
"""
174+
if not terminal:
175+
(pred_len, state_size) = x.shape
176+
hessian = np.eye(state_size)
177+
hessian = np.tile(hessian, (pred_len, 1, 1))
178+
hessian[:, 0, 0] = 1.
179+
hessian[:, 1, 1] = 1.
180+
181+
return hessian
182+
183+
state_size = len(x)
184+
hessian = np.eye(state_size)
185+
hessian[0, 0] = 1.
186+
hessian[1, 1] = 1.
187+
188+
return hessian[np.newaxis, :, :]
189+
190+
@ staticmethod
191+
def hessian_cost_fn_with_input(x, u):
192+
""" hessian costs with respect to the input
193+
194+
Args:
195+
x (numpy.ndarray): state, shape(pred_len, state_size)
196+
u (numpy.ndarray): goal state, shape(pred_len, input_size)
197+
Returns:
198+
l_uu (numpy.ndarray): gradient of cost,
199+
shape(pred_len, input_size, input_size)
200+
"""
201+
(pred_len, _) = u.shape
202+
203+
return np.tile(NonlinearSampleSystemConfigModule.R, (pred_len, 1, 1))
204+
205+
@ staticmethod
206+
def hessian_cost_fn_with_input_state(x, u):
207+
""" hessian costs with respect to the state and input
208+
209+
Args:
210+
x (numpy.ndarray): state, shape(pred_len, state_size)
211+
u (numpy.ndarray): goal state, shape(pred_len, input_size)
212+
Returns:
213+
l_ux (numpy.ndarray): gradient of cost ,
214+
shape(pred_len, input_size, state_size)
215+
"""
216+
(_, state_size) = x.shape
217+
(pred_len, input_size) = u.shape
218+
219+
return np.zeros((pred_len, input_size, state_size))

PythonLinearNonlinearControl/configs/nonlinear_system_sample.py

Whitespace-only changes.

PythonLinearNonlinearControl/envs/make_envs.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from .two_wheeled import TwoWheeledConstEnv
33
from .two_wheeled import TwoWheeledTrackEnv
44
from .cartpole import CartPoleEnv
5+
from .nonlinear_sample_system import NonlinearSampleSystemEnv
56

67

78
def make_env(args):
@@ -14,5 +15,7 @@ def make_env(args):
1415
return TwoWheeledTrackEnv()
1516
elif args.env == "CartPole":
1617
return CartPoleEnv()
18+
elif args.env == "NonlinearSample":
19+
return NonlinearSampleSystemEnv()
1720

1821
raise NotImplementedError("There is not {} Env".format(args.env))

PythonLinearNonlinearControl/envs/nonlinear_sample_system.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from ..common.utils import update_state_with_Runge_Kutta
66

77

8-
class NonlinearSampleEnv(Env):
8+
class NonlinearSampleSystemEnv(Env):
99
""" Nonlinear Sample Env
1010
"""
1111

@@ -15,12 +15,12 @@ def __init__(self):
1515
self.config = {"state_size": 2,
1616
"input_size": 1,
1717
"dt": 0.01,
18-
"max_step": 250,
18+
"max_step": 2000,
1919
"input_lower_bound": [-0.5],
2020
"input_upper_bound": [0.5],
2121
}
2222

23-
super(NonlinearSampleEnv, self).__init__(self.config)
23+
super(NonlinearSampleSystemEnv, self).__init__(self.config)
2424

2525
def reset(self, init_x=np.array([2., 0.])):
2626
""" reset state
@@ -62,7 +62,8 @@ def step(self, u):
6262
functions = [self._func_x_1, self._func_x_2]
6363

6464
next_x = update_state_with_Runge_Kutta(self.curr_x, u,
65-
functions, self.config["dt"])
65+
functions, self.config["dt"],
66+
batch=False)
6667

6768
# cost
6869
cost = 0
@@ -83,18 +84,14 @@ def step(self, u):
8384
{"goal_state": self.g_x}
8485

8586
def _func_x_1(self, x, u):
86-
"""
87-
"""
8887
x_dot = x[1]
8988
return x_dot
9089

9190
def _func_x_2(self, x, u):
92-
"""
93-
"""
94-
x_dot = (1. - x[0]**2 - x[1]**2) * x[1] - x[0] + u
91+
x_dot = (1. - x[0]**2 - x[1]**2) * x[1] - x[0] + u[0]
9592
return x_dot
9693

9794
def plot_func(self, to_plot, i=None, history_x=None, history_g_x=None):
9895
"""
9996
"""
100-
raise ValueError("NonlinearSampleEnv does not have animation")
97+
raise ValueError("NonlinearSampleSystemEnv does not have animation")

PythonLinearNonlinearControl/models/make_models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from .first_order_lag import FirstOrderLagModel
22
from .two_wheeled import TwoWheeledModel
33
from .cartpole import CartPoleModel
4+
from .nonlinear_sample_system import NonlinearSampleSystemModel
45

56

67
def make_model(args, config):
@@ -11,5 +12,7 @@ def make_model(args, config):
1112
return TwoWheeledModel(config)
1213
elif args.env == "CartPole":
1314
return CartPoleModel(config)
15+
elif args.env == "NonlinearSample":
16+
return NonlinearSampleSystemModel(config)
1417

1518
raise NotImplementedError("There is not {} Model".format(args.env))

0 commit comments

Comments
 (0)