def add_random_constraints(self): """Add the random constraints in the docplex models""" for index, subroot in enumerate(self._subroots(self.scenario_tree), 1): model = self._docplex_models[subroot.address] rand_cts = [] with _timeit(self, f"\r Add random constraints at subtree #{index}... ", 3, index): # indicator constraints try: ct_type = ('random', 'indicator') next(self._gen_constraints(subroot, ct_type, model)) # test whether generator is empty rand_cts += model.add_indicators(*zip(*self._gen_constraints(subroot, ct_type, model))) except StopIteration: pass # quadratic constraints (must be added last) try: ct_type = ('random', 'quadratic') next(self._gen_constraints(subroot, ct_type, model)) # test whether generator is empty for ct in self._gen_constraints(subroot, ct_type, model): rand_cts.append(model.add_constraint(ct)) # one by one except StopIteration: pass # linear constraints (must be added last) try: ct_type = ('random', 'linear') next(self._gen_constraints(subroot, ct_type, model)) # test whether generator is empty rand_cts += model.add_constraints(self._gen_constraints(subroot, ct_type, model)) except StopIteration: pass self._random_cts[subroot.address] = rand_cts
def add_deterministic_constraints(self): """Add the deterministic constraints in the docplex models""" for index, subroot in enumerate(self._subroots(self.scenario_tree), 1): model = self._docplex_models[subroot.address] with _timeit(self, f"\rAdd deterministic constraints at subroot #{index}... ", 2, index): # indicator constraints try: ct_type = ('deterministic', 'indicator') next(self._gen_constraints(subroot, ct_type, model)) # test whether generator is empty model.add_indicators(*zip(*self._gen_constraints(subroot, ct_type, model))) except StopIteration: pass # linear constraints (must be added last) try: ct_type = ('deterministic', 'linear') next(self._gen_constraints(subroot, ct_type, model)) # test whether generator is empty model.add_constraints(self._gen_constraints(subroot, ct_type, model)) model.add_constraints(self._gen_constraints_fixing_variables(subroot)) except StopIteration: pass
def do_highlevel_control(self, params): """Decide parameters. TODO finish description """ segs_polytopes, goal, seg_psi_bounds = self.compute_segs_polytopes_and_goal( params) """Apply motion planning problem""" n_segs = len(segs_polytopes) Gamma, nu, nx = params.Gamma, params.nu, params.nx T = self.__control_horizon max_a, max_delta = self.__params.max_a, self.__params.max_delta model = docplex.mp.model.Model(name="proposed_problem") min_u = np.vstack((np.zeros(T), np.full(T, -0.5 * max_delta))).T.ravel() max_u = np.vstack( (np.full(T, max_a), np.full(T, 0.5 * max_delta))).T.ravel() u = np.array(model.continuous_var_list(nu * T, lb=min_u, ub=max_u, name='u'), dtype=object) # State variables X = (params.initial_rollout.local + util.obj_matmul(Gamma, u)).reshape( T + 1, nx) X = params.transform(X) X = X[1:] # Control variables U = u.reshape(T, nu) """Apply motion dynamics constraints""" model.add_constraints( self.compute_dyamics_constraints(params, X[:, 3], X[:, 4])) """Apply road boundary constraints""" if self.road_boundary_constraints: # Slack variables from road obstacles Omicron = np.array(model.binary_var_list(n_segs * T, name="omicron"), dtype=object).reshape(n_segs, T) M_big, diag = self.__params.M, self.__params.diag psi_0 = params.initial_state.world[2] for t in range(self.__control_horizon): for seg_idx, (A, b) in enumerate(segs_polytopes): lhs = util.obj_matmul(A, X[t, :2]) - np.array( M_big * (1 - Omicron[seg_idx, t])) rhs = b + diag """Constraints on road boundaries""" model.add_constraints([l <= r for (l, r) in zip(lhs, rhs)]) """Constraints on angle boundaries""" # lhs = X[t, 2] - psi_0 - M_big*(1 - Omicron[seg_idx, t]) # model.add_constraint(lhs <= seg_psi_bounds[seg_idx][1]) # lhs = X[t, 2] - psi_0 + M_big*(1 - Omicron[seg_idx, t]) # model.add_constraint(lhs >= seg_psi_bounds[seg_idx][0]) model.add_constraint(np.sum(Omicron[:, t]) >= 1) """Start from current vehicle position and minimize the objective""" w_ch_accel = 0. w_ch_turning = 0. w_accel = 0. w_turning = 0. # final destination objective cost = (X[-1, 0] - goal[0])**2 + (X[-1, 1] - goal[1])**2 # change in acceleration objective for u1, u2 in util.pairwise(U[:, 0]): _u = (u1 - u2) cost += w_ch_accel * _u * _u # change in turning rate objective for u1, u2 in util.pairwise(U[:, 1]): _u = (u1 - u2) cost += w_ch_turning * _u * _u cost += w_accel * np.sum(U[:, 0]**2) # turning rate objective cost += w_turning * np.sum(U[:, 1]**2) model.minimize(cost) # TODO: warmstarting # if self.U_warmstarting is not None: # # Warm start inputs if past iteration was run. # warm_start = model.new_solution() # for i, u in enumerate(self.U_warmstarting[self.__control_horizon:]): # warm_start.add_var_value(f"u_{2*i}", u[0]) # warm_start.add_var_value(f"u_{2*i + 1}", u[1]) # # add delta_0 as hotfix to MIP warmstart as it needs # # at least 1 integer value set. # warm_start.add_var_value('delta_0', 0) # model.add_mip_start(warm_start) # model.print_information() # model.parameters.read.datacheck = 1 if self.log_cplex: model.parameters.mip.display = 2 s = model.solve(log_output=True) else: model.solve() # model.print_solution() f = lambda x: x if isinstance(x, numbers.Number) else x.solution_value cost = cost.solution_value U_star = util.obj_vectorize(f, U) X_star = util.obj_vectorize(f, X) return util.AttrDict(cost=cost, U_star=U_star, X_star=X_star, goal=goal)
def do_highlevel_control(self, params, ovehicles): """Decide parameters. Since we're doing multiple coinciding, we want to compute... TODO finish description """ vertices = self.__compute_vertices(params, ovehicles) A_unions, b_unions = self.__compute_overapproximations( vertices, params, ovehicles) """Apply motion planning problem""" N_traj, L, T, K, O, Gamma, nu, nx = params.N_traj, self.__params.L, self.__params.T, params.K, \ params.O, self.__params.Gamma, self.__params.nu, self.__params.nx model = docplex.mp.model.Model(name='obstacle_avoidance') # set up controls variables for each trajectory u = np.array( model.continuous_var_list(N_traj * T * nu, lb=-np.inf, ub=np.inf, name='control')) Delta = np.array( model.binary_var_list(O * L * N_traj * T, name='delta')).reshape(N_traj, T, O, L) # U has shape (N_traj, T*nu) U = u.reshape(N_traj, -1) # Gamma has shape (nx*(T + 1), nu*T) so X has shape (N_traj, nx*(T + 1)) X = util.obj_matmul(U, Gamma.T) # X, U have shapes (N_traj, T, nx) and (N_traj, T, nu) resp. X = (X + params.States_free_init).reshape(N_traj, -1, nx)[..., 1:, :] U = U.reshape(N_traj, -1, nu) for _U, _X in zip(U, X): # _X, _U have shapes (T, nx) and (T, nu) resp. p_x, p_y = _X[..., 0], _X[..., 1] v_x, v_y = _X[..., 2], _X[..., 3] u_x, u_y = _U[..., 0], _U[..., 1] model.add_constraints(self.compute_boundary_constraints(p_x, p_y)) model.add_constraints(self.compute_velocity_constraints(v_x, v_y)) model.add_constraints( self.compute_acceleration_constraints(u_x, u_y)) # set up obstacle constraints M_big, N_traj, T, diag = self.__params.M_big, params.N_traj, self.__params.T, self.__params.diag for n in range(N_traj): # for each obstacle/trajectory A_union, b_union = A_unions[n], b_unions[n] for t in range(T): # for each timestep As, bs = A_union[t], b_union[t] for o, (A, b) in enumerate(zip(As, bs)): lhs = util.obj_matmul( A, X[n, t, :2]) + M_big * (1 - Delta[n, t, o]) rhs = b + diag model.add_constraints([l >= r for (l, r) in zip(lhs, rhs)]) model.add_constraint(np.sum(Delta[n, t, o]) >= 1) # set up coinciding constraints for t in range(0, self.__n_coincide): for x1, x2 in util.pairwise(X[:, t]): model.add_constraints([l == r for (l, r) in zip(x1, x2)]) # start from current vehicle position and minimize the objective p_x, p_y, _ = carlautil.to_location_ndarray(self.__ego_vehicle, flip_y=True) if self.__goal.is_relative: goal_x, goal_y = p_x + self.__goal.x, p_y + self.__goal.y else: goal_x, goal_y = self.__goal.x, self.__goal.y start = np.array([p_x, p_y]) goal = np.array([goal_x, goal_y]) cost = np.sum((X[:, -1, :2] - goal)**2) model.minimize(cost) # model.print_information() if self.log_cplex: model.parameters.mip.display = 5 s = model.solve(log_output=True) else: model.solve() # model.print_solution() f = lambda x: x if isinstance(x, numbers.Number) else x.solution_value U_star = util.obj_vectorize(f, U) cost = cost.solution_value X_star = util.obj_vectorize(f, X) return util.AttrDict(cost=cost, U_star=U_star, X_star=X_star, A_unions=A_unions, b_unions=b_unions, vertices=vertices, start=start, goal=goal)
def do_single_control(self, params, ovehicles): """Decide parameters. TODO: acceleration limit is hardcoded to 8 m/s^2 TODO finish description """ vertices = self.__compute_vertices(params, ovehicles) A_union, b_union = self.__compute_overapproximations( vertices, params, ovehicles) segs_polytopes, goal = self.compute_segs_polytopes_and_goal(params) """Apply motion planning problem""" n_segs = len(segs_polytopes) L, T, K, Gamma, nu, nx = self.__params.L, self.__params.T, params.K, \ self.__params.Gamma, self.__params.nu, self.__params.nx u_max = self.__params.u_max model = docplex.mp.model.Model(name="proposed_problem") u = np.array(model.continuous_var_list(nu * T, lb=-u_max, ub=u_max, name='u'), dtype=object) Delta = np.array(model.binary_var_list(L * np.sum(K) * T, name='delta'), dtype=object).reshape(np.sum(K), T, L) Omicron = np.array(model.binary_var_list(n_segs * T, name="omicron"), dtype=object).reshape(n_segs, T) X = (params.States_free_init + util.obj_matmul(Gamma, u)).reshape( T + 1, nx) X = X[1:] U = u.reshape(T, nu) """Apply motion dynamics constraints""" model.add_constraints( self.compute_velocity_constraints(X[:, 2], X[:, 3])) model.add_constraints( self.compute_acceleration_constraints(U[:, 0], U[:, 1])) """Apply road boundaries constraints""" M_big, T, diag = self.__params.M_big, self.__params.T, self.__params.diag for t in range(T): for seg_idx, (A, b) in enumerate(segs_polytopes): lhs = util.obj_matmul(A, X[t, :2]) - np.array( M_big * (1 - Omicron[seg_idx, t])) rhs = b + diag model.add_constraints([l <= r for (l, r) in zip(lhs, rhs)]) model.add_constraint(np.sum(Omicron[:, t]) >= 1) """Apply collision constraints""" T, K, diag, M_big = self.__params.T, params.K, \ self.__params.diag, self.__params.M_big for ov_idx, ovehicle in enumerate(ovehicles): n_states = ovehicle.n_states sum_clu = np.sum(K[:ov_idx]) for latent_idx in range(n_states): for t in range(T): A_obs = A_union[t][latent_idx][ov_idx] b_obs = b_union[t][latent_idx][ov_idx] indices = sum_clu + latent_idx lhs = util.obj_matmul( A_obs, X[t, :2]) + M_big * (1 - Delta[indices, t]) rhs = b_obs + diag model.add_constraints([l >= r for (l, r) in zip(lhs, rhs)]) model.add_constraint(np.sum(Delta[indices, t]) >= 1) """Start from current vehicle position and minimize the objective""" start = params.x0[:2] cost = (X[-1, 0] - goal[0])**2 + (X[-1, 1] - goal[1])**2 model.minimize(cost) # TODO: warmstarting # if self.U_warmstarting is not None: # # Warm start inputs if past iteration was run. # warm_start = model.new_solution() # for i, u in enumerate(self.U_warmstarting[self.__control_horizon:]): # warm_start.add_var_value(f"u_{2*i}", u[0]) # warm_start.add_var_value(f"u_{2*i + 1}", u[1]) # # add delta_0 as hotfix to MIP warmstart as it needs # # at least 1 integer value set. # warm_start.add_var_value('delta_0', 0) # model.add_mip_start(warm_start) # model.print_information() # model.parameters.read.datacheck = 1 if self.log_cplex: model.parameters.mip.display = 2 s = model.solve(log_output=True) else: model.solve() # model.print_solution() f = lambda x: x if isinstance(x, numbers.Number) else x.solution_value cost = cost.solution_value U_star = util.obj_vectorize(f, U) X_star = util.obj_vectorize(f, X) return util.AttrDict(cost=cost, U_star=U_star, X_star=X_star, A_union=A_union, b_union=b_union, vertices=vertices, start=start, goal=goal)
def do_multiple_control(self, params, ovehicles): """Decide parameters. Since we're doing multiple coinciding, we want to compute... TODO finish description """ vertices = self.__compute_vertices(params, ovehicles) A_unions, b_unions = self.__compute_overapproximations( vertices, params, ovehicles) segs_polytopes, goal = self.compute_segs_polytopes_and_goal(params) """Optimize all trajectories if MCC, else partial trajectories.""" # params.N_select params.N_traj params.subtraj_indices N_select = params.N_select if self.__agent_type == "rmcc" else params.N_traj """Common to MCC+RMCC: setup CPLEX variables""" L, T, K, O, Gamma, nu, nx = self.__params.L, self.__params.T, \ params.K, params.O, self.__params.Gamma, self.__params.nu, self.__params.nx n_segs = len(segs_polytopes) u_max = self.__params.u_max model = docplex.mp.model.Model(name='obstacle_avoidance') # set up controls variables for each trajectory u = np.array( model.continuous_var_list(N_select * T * nu, lb=-u_max, ub=u_max, name='control')) Delta = np.array( model.binary_var_list(O * L * N_select * T, name='delta')).reshape(N_select, T, O, L) Omicron = np.array(model.binary_var_list(N_select * n_segs * T, name="omicron"), dtype=object).reshape(N_select, n_segs, T) """Common to MCC+RMCC: compute state from input variables""" # U has shape (N_select, T*nu) U = u.reshape(N_select, -1) # Gamma has shape (nx*(T + 1), nu*T) so X has shape (N_select, nx*(T + 1)) X = util.obj_matmul(U, Gamma.T) # X, U have shapes (N_select, T, nx) and (N_select, T, nu) resp. X = (X + params.States_free_init).reshape(N_select, -1, nx)[..., 1:, :] U = U.reshape(N_select, -1, nu) """Common to MCC+RMCC: apply dynamics constraints to trajectories""" for _U, _X in zip(U, X): # _X, _U have shapes (T, nx) and (T, nu) resp. v_x, v_y = _X[..., 2], _X[..., 3] u_x, u_y = _U[..., 0], _U[..., 1] model.add_constraints(self.compute_velocity_constraints(v_x, v_y)) model.add_constraints( self.compute_acceleration_constraints(u_x, u_y)) """Common to MCC+RMCC: apply road boundaries constraints to trajectories""" M_big, T, diag = self.__params.M_big, self.__params.T, self.__params.diag for n in range(N_select): # for each trajectory for t in range(T): for seg_idx, (A, b) in enumerate(segs_polytopes): lhs = util.obj_matmul(A, X[n, t, :2]) - np.array( M_big * (1 - Omicron[n, seg_idx, t])) rhs = b + diag model.add_constraints([l <= r for (l, r) in zip(lhs, rhs)]) model.add_constraint(np.sum(Omicron[n, :, t]) >= 1) """Apply collision constraints""" traj_indices = params.subtraj_indices if self.__agent_type == "rmcc" else range( N_select) M_big, T, diag = self.__params.M_big, self.__params.T, self.__params.diag for n, i in enumerate(traj_indices): # select outerapprox. by index i # if MCC then iterates through every combination of obstacles A_union, b_union = A_unions[i], b_unions[i] for t in range(T): # for each timestep As, bs = A_union[t], b_union[t] for o, (A, b) in enumerate(zip(As, bs)): lhs = util.obj_matmul( A, X[n, t, :2]) + M_big * (1 - Delta[n, t, o]) rhs = b + diag model.add_constraints([l >= r for (l, r) in zip(lhs, rhs)]) model.add_constraint(np.sum(Delta[n, t, o]) >= 1) """Common to MCC+RMCC: set up coinciding constraints""" for t in range(0, self.__n_coincide): for x1, x2 in util.pairwise(X[:, t]): model.add_constraints([l == r for (l, r) in zip(x1, x2)]) """Common to MCC+RMCC: set objective and run solver""" start = params.x0[:2] cost = np.sum((X[:, -1, :2] - goal)**2) model.minimize(cost) # model.print_information() if self.log_cplex: model.parameters.mip.display = 5 s = model.solve(log_output=True) else: model.solve() # model.print_solution() f = lambda x: x if isinstance(x, numbers.Number) else x.solution_value U_star = util.obj_vectorize(f, U) cost = cost.solution_value X_star = util.obj_vectorize(f, X) return util.AttrDict(cost=cost, U_star=U_star, X_star=X_star, A_unions=A_unions, b_unions=b_unions, vertices=vertices, start=start, goal=goal)
def do_highlevel_control(self, params, ovehicles): """Decide parameters""" # TODO: assign eps^k_o and beta^k_o to the vehicles. # Skipping that for now. """Compute the approximation of the union of obstacle sets""" # Find vertices of sampled obstacle sets T, K, n_ov, truck = params.T, params.K, params.O, params.truck vertices = np.empty((T, np.max(K), n_ov), dtype=object).tolist() for ov_idx, ovehicle in enumerate(ovehicles): for latent_idx in range(ovehicle.n_states): for t in range(T): ps = ovehicle.pred_positions[latent_idx] yaws = ovehicle.pred_yaws[latent_idx] n_p = ps.shape[0] vertices[t][latent_idx][ov_idx] = np.zeros((n_p, 8)) for k in range(n_p): vertices[t][latent_idx][ov_idx][ k] = get_vertices_from_center( ps[k, t], yaws[k, t], truck.d) plot_vertices = False if plot_vertices: latent_idx = 0 ov_idx = 0 fig, axes = plt.subplots(2, 2, figsize=(10, 10)) axes = axes.ravel() for t, ax in zip(range(1, params.T, 2), axes): # for ovehicle in scene.ovehicles: X = vertices[t][latent_idx][ov_idx][:, 0:2].T ax.scatter(X[0], X[1], c='r', s=2) X = vertices[t][latent_idx][ov_idx][:, 2:4].T ax.scatter(X[0], X[1], c='b', s=2) X = vertices[t][latent_idx][ov_idx][:, 4:6].T ax.scatter(X[0], X[1], c='g', s=2) X = vertices[t][latent_idx][ov_idx][:, 6:8].T ax.scatter(X[0], X[1], c='orange', s=2) ax.set_title(f"t = {t}") ax.set_aspect('equal') plt.show() """Cluster the samples""" T, K, n_ov = params.T, params.K, params.O A_union = np.empty(( T, np.max(K), n_ov, ), dtype=object).tolist() b_union = np.empty(( T, np.max(K), n_ov, ), dtype=object).tolist() for ov_idx, ovehicle in enumerate(ovehicles): for latent_idx in range(ovehicle.n_states): for t in range(T): yaws = ovehicle.pred_yaws[latent_idx][:, t] vertices_k = vertices[t][latent_idx][ov_idx] mean_theta_k = np.mean(yaws) A_union_k, b_union_k = get_approx_union( mean_theta_k, vertices_k) A_union[t][latent_idx][ov_idx] = A_union_k b_union[t][latent_idx][ov_idx] = b_union_k """Plot the overapproximation""" plot_overapprox = False if plot_overapprox: fig, ax = plt.subplots() t = 7 ov_idx = 0 ovehicle = ovehicles[ov_idx] for latent_idx in range(ovehicle.n_states): ps = ovehicle.pred_positions[latent_idx][:, t].T ax.scatter(ps[0], ps[1], c='r', s=2) try: plot_h_polyhedron(ax, A_union[t][latent_idx][ov_idx], b_union[t][0][ov_idx], ec='k', alpha=0.3) except scipy.spatial.qhull.QhullError as e: print(e) ax.set_aspect('equal') plt.show() """Apply motion planning problem""" model = docplex.mp.model.Model(name="proposed_problem") L, T, K, Gamma, nu, nx = params.L, params.T, params.K, params.Gamma, params.nu, params.nx u = np.array(model.continuous_var_list(nu * T, lb=-np.inf, name='u'), dtype=object) delta_tmp = model.binary_var_matrix(L * np.sum(K), T, name='delta') delta = np.empty(( L * np.sum(K), T, ), dtype=object) for k, v in delta_tmp.items(): delta[k] = v x_future = params.States_free_init + obj_matmul(Gamma, u) big_M = 1000 # conservative upper-bound x1 = x_future[nx::nx] x2 = x_future[nx + 1::nx] x3 = x_future[nx + 2::nx] x4 = x_future[nx + 3::nx] # 3rd and 4th states have COUPLED CONSTRAINTS # x4 - c1*x3 <= - c3 # x4 - c1*x3 >= - c2 # x4 + c1*x3 <= c2 # x4 + c1*x3 >= c3 c1, c2, c3 = params.c1, params.c2, params.c3 model.add_constraints([z <= -c3 for z in x4 - c1 * x3]) model.add_constraints([z <= c2 for z in -x4 + c1 * x3]) model.add_constraints([z <= c2 for z in x4 + c1 * x3]) model.add_constraints([z <= -c3 for z in -x4 - c1 * x3]) u1 = u[0::nu] u2 = u[1::nu] # Inputs have COUPLED CONSTRAINTS: # u2 - t1*u1 <= - t3 # u2 - t1*u1 >= - t2 # u2 + t1*u1 <= t2 # u2 + t1*u1 >= t3 t1, t2, t3 = params.t1, params.t2, params.t3 model.add_constraints([z <= -t3 for z in u2 - t1 * u1]) model.add_constraints([z <= t2 for z in -u2 + t1 * u1]) model.add_constraints([z <= t2 for z in u2 + t1 * u1]) model.add_constraints([z <= -t3 for z in -u2 - t1 * u1]) X = np.stack([x1, x2], axis=1) T, K, diag = params.T, params.K, params.diag for ov_idx, ovehicle in enumerate(ovehicles): n_states = ovehicle.n_states sum_clu = np.sum(K[:ov_idx]) for latent_idx in range(n_states): for t in range(T): A_obs = A_union[t][latent_idx][ov_idx] b_obs = b_union[t][latent_idx][ov_idx] indices = 4 * (sum_clu + latent_idx) + np.arange(0, 4) lhs = obj_matmul(A_obs, X[t]) + big_M * (1 - delta[indices, t]) rhs = b_obs + diag model.add_constraints([l >= r for (l, r) in zip(lhs, rhs)]) model.add_constraint(np.sum(delta[indices, t]) >= 1) # start from current vehicle position and minimize the objective p_x, p_y, _ = carlautil.actor_to_location_ndarray(self.__ego_vehicle) p_y = -p_y # need to flip about x-axis if self.__goal.is_relative: goal_x, goal_y = p_x + self.__goal.x, p_y + self.__goal.y else: goal_x, goal_y = self.__goal.x, self.__goal.y start = np.array([p_x, p_y]) goal = np.array([goal_x, goal_y]) cost = (x1[-1] - goal_x)**2 + (x2[-1] - goal_y)**2 model.minimize(cost) # model.print_information() s = model.solve() # model.print_solution() u_star = np.array([ui.solution_value for ui in u]) cost = cost.solution_value x1 = np.array([x1i.solution_value for x1i in x1]) x2 = np.array([x2i.solution_value for x2i in x2]) X_star = np.stack((x1, x2)).T return util.AttrDict(cost=cost, u_star=u_star, X_star=X_star, A_union=A_union, b_union=b_union, vertices=vertices, start=start, goal=goal)
def do_highlevel_control(self, params, ovehicles): """Decide parameters""" # TODO: assign eps^k_o and beta^k_o to the vehicles. # Skipping that for now. vertices = self.__compute_vertices(params, ovehicles) A_union, b_union = self.__compute_overapproximations( vertices, params, ovehicles) """Apply motion planning problem""" L, T, K, Gamma, nu, nx = self.__params.L, self.__params.T, params.K, \ self.__params.Gamma, self.__params.nu, self.__params.nx u_max = self.__params.u_max model = docplex.mp.model.Model(name="proposed_problem") u = np.array(model.continuous_var_list(nu * T, lb=-u_max, ub=u_max, name='u'), dtype=object) Delta = np.array(model.binary_var_list(L * np.sum(K) * T, name='delta'), dtype=object).reshape(np.sum(K), T, L) X = (params.States_free_init + util.obj_matmul(Gamma, u)).reshape( T + 1, nx) X = X[1:] U = u.reshape(T, nu) """Apply motion constraints""" model.add_constraints( self.compute_boundary_constraints(X[:, 0], X[:, 1])) model.add_constraints( self.compute_velocity_constraints(X[:, 2], X[:, 3])) model.add_constraints( self.compute_acceleration_constraints(U[:, 0], U[:, 1])) """Apply collision constraints""" T, K, diag, M_big = self.__params.T, params.K, \ self.__params.diag, self.__params.M_big for ov_idx, ovehicle in enumerate(ovehicles): n_states = ovehicle.n_states sum_clu = np.sum(K[:ov_idx]) for latent_idx in range(n_states): for t in range(T): A_obs = A_union[t][latent_idx][ov_idx] b_obs = b_union[t][latent_idx][ov_idx] indices = sum_clu + latent_idx lhs = util.obj_matmul( A_obs, X[t, :2]) + M_big * (1 - Delta[indices, t]) rhs = b_obs + diag model.add_constraints([l >= r for (l, r) in zip(lhs, rhs)]) model.add_constraint(np.sum(Delta[indices, t]) >= 1) """Start from current vehicle position and minimize the objective""" p_x, p_y, _ = carlautil.actor_to_location_ndarray(self.__ego_vehicle, flip_y=True) if self.__goal.is_relative: goal_x, goal_y = p_x + self.__goal.x, p_y + self.__goal.y else: goal_x, goal_y = self.__goal.x, self.__goal.y start = np.array([p_x, p_y]) goal = np.array([goal_x, goal_y]) cost = (X[-1, 0] - goal_x)**2 + (X[-1, 1] - goal_y)**2 model.minimize(cost) if self.U_warmstarting is not None: # Warm start inputs if past iteration was run. warm_start = model.new_solution() for i, u in enumerate( self.U_warmstarting[self.__control_horizon:]): warm_start.add_var_value(f"u_{2*i}", u[0]) warm_start.add_var_value(f"u_{2*i + 1}", u[1]) # add delta_0 as hotfix to MIP warmstart as it needs # at least 1 integer value set. warm_start.add_var_value('delta_0', 0) model.add_mip_start(warm_start) # model.print_information() # model.parameters.read.datacheck = 1 if self.log_cplex: model.parameters.mip.display = 2 s = model.solve(log_output=True) else: model.solve() # model.print_solution() f = lambda x: x if isinstance(x, numbers.Number) else x.solution_value cost = cost.solution_value U_star = util.obj_vectorize(f, U) X_star = util.obj_vectorize(f, X) return util.AttrDict(cost=cost, U_star=U_star, X_star=X_star, A_union=A_union, b_union=b_union, vertices=vertices, start=start, goal=goal)
def do_highlevel_control(self, params, ovehicles): """Decide parameters""" # TODO: assign eps^k_o and beta^k_o to the vehicles. # Skipping that for now. vertices = self.__compute_vertices(params, ovehicles) A_union, b_union = self.__compute_overapproximations( vertices, params, ovehicles) """Apply motion planning problem""" model = docplex.mp.model.Model(name="proposed_problem") L, T, K, Gamma, nu, nx = self.__params.L, self.__params.T, params.K, \ self.__params.Gamma, self.__params.nu, self.__params.nx u = np.array(model.continuous_var_list(nu * T, lb=-np.inf, name='u'), dtype=object) delta_tmp = model.binary_var_matrix(L * np.sum(K), T, name='delta') delta = np.empty(( L * np.sum(K), T, ), dtype=object) for k, v in delta_tmp.items(): delta[k] = v x_future = params.States_free_init + obj_matmul(Gamma, u) # TODO: hardcoded value, need to specify better big_M = 1000 # conservative upper-bound x1 = x_future[nx::nx] x2 = x_future[nx + 1::nx] x3 = x_future[nx + 2::nx] x4 = x_future[nx + 3::nx] u1 = u[0::nu] u2 = u[1::nu] model.add_constraints(self.compute_boundary_constraints(x1, x2)) model.add_constraints(self.compute_velocity_constraints(x3, x4)) model.add_constraints(self.compute_acceleration_constraints(u1, u2)) X = np.stack([x1, x2], axis=1) T, K, diag = self.__params.T, params.K, self.__params.diag for ov_idx, ovehicle in enumerate(ovehicles): n_states = ovehicle.n_states sum_clu = np.sum(K[:ov_idx]) for latent_idx in range(n_states): for t in range(T): A_obs = A_union[t][latent_idx][ov_idx] b_obs = b_union[t][latent_idx][ov_idx] indices = 4 * (sum_clu + latent_idx) + np.arange(0, 4) lhs = obj_matmul(A_obs, X[t]) + big_M * (1 - delta[indices, t]) rhs = b_obs + diag model.add_constraints([l >= r for (l, r) in zip(lhs, rhs)]) model.add_constraint(np.sum(delta[indices, t]) >= 1) # start from current vehicle position and minimize the objective p_x, p_y, _ = carlautil.actor_to_location_ndarray(self.__ego_vehicle) p_y = -p_y # need to flip about x-axis if self.__goal.is_relative: goal_x, goal_y = p_x + self.__goal.x, p_y + self.__goal.y else: goal_x, goal_y = self.__goal.x, self.__goal.y start = np.array([p_x, p_y]) goal = np.array([goal_x, goal_y]) cost = (x1[-1] - goal_x)**2 + (x2[-1] - goal_y)**2 model.minimize(cost) # model.print_information() # model.parameters.read.datacheck = 1 if self.log_cplex: model.parameters.mip.display = 5 s = model.solve(log_output=True) else: model.solve() # model.print_solution() u_star = np.array([ui.solution_value for ui in u]) cost = cost.solution_value x1 = np.array([x1i.solution_value for x1i in x1]) x2 = np.array([x2i.solution_value for x2i in x2]) X_star = np.stack((x1, x2)).T return util.AttrDict(cost=cost, u_star=u_star, X_star=X_star, A_union=A_union, b_union=b_union, vertices=vertices, start=start, goal=goal)
def do_highlevel_control(self, params, ovehicles): """Decide parameters.""" """Compute road segments and goal.""" (segs_polytopes, goal, seg_psi_bounds) = self.compute_segs_polytopes_and_goal(params) """Apply motion planning problem""" N_select = params.N_select x_bar, u_bar, Gamma = params.x_bar, params.u_bar, params.Gamma nx, nu = params.nx, params.nu T = self.__control_horizon max_a, min_a = self.__params.max_a, self.__params.min_a max_delta = self.__params.max_delta """Model, control and state variables""" model = docplex.mp.model.Model(name="proposed_problem") min_u = np.vstack((np.full(T, min_a), np.full(T, -max_delta))).T min_u = np.repeat(min_u[None], N_select, axis=0).ravel() max_u = np.vstack((np.full(T, max_a), np.full(T, max_delta))).T max_u = np.repeat(max_u[None], N_select, axis=0).ravel() # Slack variables for control u = model.continuous_var_list(N_select * nu * T, lb=min_u, ub=max_u, name="u") # U has shape (N_select, T*nu) U = np.array(u, dtype=object).reshape(N_select, -1) U_delta = U - u_bar x = util.obj_matmul(U_delta, Gamma.T) + x_bar # State variables x, y, psi, v X = x.reshape(N_select, T, nx) # Control variables a, delta U = U.reshape(N_select, T, nu) """Apply state constraints""" for _X in X: model.add_constraints(self.compute_state_constraints(params, _X)) """Apply road boundary constraints""" if self.road_boundary_constraints: n_segs = len(segs_polytopes) # Slack variables from road obstacles Omicron = model.binary_var_list(N_select * n_segs * T, name="omicron") Omicron = np.array(Omicron, dtype=object).reshape(N_select, n_segs, T) M_big = self.__params.M_big # diag = self.__params.diag psi_0 = params.initial_state.world[2] T = self.__control_horizon for n in range(N_select): for t in range(T): for seg_idx, (A, b) in enumerate(segs_polytopes): lhs = util.obj_matmul(A, X[n, t, :2]) - np.array( M_big * (1 - Omicron[n, seg_idx, t])) rhs = b # - diag """Constraints on road boundaries""" model.add_constraints( [l <= r for (l, r) in zip(lhs, rhs)]) """Constraints on angle boundaries""" if self.angle_boundary_constraints: lhs = X[n, t, 2] - psi_0 - M_big * ( 1 - Omicron[seg_idx, t]) model.add_constraint( lhs <= seg_psi_bounds[n, seg_idx][1]) lhs = X[n, t, 2] - psi_0 + M_big * ( 1 - Omicron[n, seg_idx, t]) model.add_constraint( lhs >= seg_psi_bounds[seg_idx][0]) model.add_constraint(np.sum(Omicron[n, :, t]) >= 1) """Apply vehicle collision constraints""" if params.O > 0: vertices = self.__compute_vertices(params, ovehicles) A_unions, b_unions = self.__compute_overapproximations( vertices, params, ovehicles) O, L = params.O, self.__params.L # Slack variables for vehicle obstacles Delta = model.binary_var_list(O * L * N_select * T, name='delta') Delta = np.array(Delta, dtype=object).reshape(N_select, T, O, L) M_big = self.__params.M_big diag = self.__params.diag # for n, i in enumerate(params.subtraj_indices): # # select outerapprox. by index i # A_union, b_union = A_unions[i], b_unions[i] # for t in range(T): # As, bs = A_union[t], b_union[t] # for o, (A, b) in enumerate(zip(As, bs)): # lhs = util.obj_matmul(A, X[n,t,:2]) + M_big*(1 - Delta[n,t,o]) # rhs = b + diag # model.add_constraints([l >= r for (l,r) in zip(lhs, rhs)]) # model.add_constraint(np.sum(Delta[n,t,o]) >= 1) for n in range(N_select): # select outerapprox. by index n A_union, b_union = A_unions[n], b_unions[n] for t in range(T): As, bs = A_union[t], b_union[t] for o, (A, b) in enumerate(zip(As, bs)): lhs = util.obj_matmul( A, X[n, t, :2]) + M_big * (1 - Delta[n, t, o]) rhs = b + diag model.add_constraints( [l >= r for (l, r) in zip(lhs, rhs)]) model.add_constraint(np.sum(Delta[n, t, o]) >= 1) else: vertices = A_unions = b_unions = None """Set up coinciding constraints""" for t in range(0, self.__n_coincide): for u1, u2 in util.pairwise(U[:, t]): model.add_constraints([l == r for (l, r) in zip(u1, u2)]) """Compute and minimize objective""" cost = 0 for _U, _X in zip(U, X): cost += self.compute_objective(_X, _U, goal) model.minimize(cost) # TODO: add warmstarting to MCC # if self.road_boundary_constraints and self.__U_warmstarting is not None: # # Warm start inputs if past iteration was run. # warm_start = model.new_solution() # for i, u in enumerate(self.__U_warmstarting[self.__step_horizon :]): # warm_start.add_var_value(f"u_{2*i}", u[0]) # warm_start.add_var_value(f"u_{2*i + 1}", u[1]) # # add omicron_0 as hotfix to MIP warmstart as it needs # # at least 1 integer value set. # warm_start.add_var_value("omicron_0", 1) # model.add_mip_start( # warm_start, write_level=docplex.mp.constants.WriteLevel.AllVars # ) # model.print_information() # model.parameters.read.datacheck = 1 if self.log_cplex: model.parameters.mip.display = 2 s = model.solve(log_output=True) else: model.parameters.mip.display = 0 model.solve() # model.print_solution() """Extract solution""" cost = cost.solution_value f = lambda x: x if isinstance(x, numbers.Number) else x.solution_value U_star = util.obj_vectorize(f, U) X_star = util.obj_vectorize(f, X) return util.AttrDict(cost=cost, U_star=U_star, X_star=X_star, goal=goal, A_unions=A_unions, b_unions=b_unions, vertices=vertices)
def do_highlevel_control(self, params, ovehicles): """Decide parameters.""" """Compute road segments and goal.""" segments, goal = self.compute_segs_polytopes_and_goal(params) """Apply motion planning problem""" x_bar, u_bar, Gamma = params.x_bar, params.u_bar, params.Gamma nx, nu = params.nx, params.nu T = self.__control_horizon max_a, min_a = self.__params.max_a, self.__params.min_a max_delta = self.__params.max_delta """Model, control and state variables""" model = docplex.mp.model.Model(name="proposed_problem") min_u = np.vstack((np.full(T, min_a), np.full(T, -max_delta))).T.ravel() max_u = np.vstack((np.full(T, max_a), np.full(T, max_delta))).T.ravel() # Slack variables for control u = model.continuous_var_list(nu * T, lb=min_u, ub=max_u, name="u") u = np.array(u, dtype=object) u_delta = u - u_bar x = util.obj_matmul(Gamma, u_delta) + x_bar # State variables x, y, psi, v X = x.reshape(T, nx) # Control variables a, delta U = u.reshape(T, nu) """Apply state constraints""" model.add_constraints(self.compute_state_constraints(params, X)) """Apply road boundary constraints""" if self.road_boundary_constraints: T = self.__control_horizon I = len(segments.polytopes) # Slack variables from road obstacles Omicron = model.binary_var_list(I * T, name="omicron") Omicron = np.array(Omicron, dtype=object).reshape(I, T) model.add_constraints( self.compute_road_boundary_constraints(params, X, Omicron, segments) ) else: Omicron = None if params.O > 0: T = self.__control_horizon L, K = self.__params.L, params.K # Slack variables for vehicle obstacles Delta = model.binary_var_list(L * np.sum(K) * T, name="delta") Delta = np.array(Delta, dtype=object).reshape(np.sum(K), T, L) ( constraints, vertices, A_union, b_union, ) = self.compute_obstacle_constraints( params, ovehicles, X, Delta, Omicron, segments ) model.add_constraints(constraints) else: vertices = A_union = b_union = None """Compute and minimize objective""" cost = self.compute_objective(X, U, goal) model.minimize(cost) if self.road_boundary_constraints and self.__U_warmstarting is not None: # Warm start inputs if past iteration was run. warm_start = model.new_solution() for i, u in enumerate(self.__U_warmstarting[self.__step_horizon :]): warm_start.add_var_value(f"u_{2*i}", u[0]) warm_start.add_var_value(f"u_{2*i + 1}", u[1]) # add omicron_0 as hotfix to MIP warmstart as it needs # at least 1 integer value set. warm_start.add_var_value("omicron_0", 1) model.add_mip_start( warm_start, write_level=docplex.mp.constants.WriteLevel.AllVars ) # model.print_information() # model.parameters.read.datacheck = 1 if self.log_cplex: model.parameters.mip.display = 2 s = model.solve(log_output=True) else: model.parameters.mip.display = 0 model.solve() # model.print_solution() """Extract solution""" try: cost = cost.solution_value f = lambda x: x if isinstance(x, numbers.Number) else x.solution_value U_star = util.obj_vectorize(f, U) X_star = util.obj_vectorize(f, X) return ( util.AttrDict( cost=cost, U_star=U_star, X_star=X_star, goal=goal, A_union=A_union, b_union=b_union, vertices=vertices, segments=segments, ), None, ) except docplex.mp.utils.DOcplexException as e: # TODO: check model for infeasible solution # docplex.util.environment.logger:environment.py:627 Notify end solve, # status=JobSolveStatus.INFEASIBLE_SOLUTION, solve_time=None return util.AttrDict( cost=None, U_star=None, X_star=None, goal=goal, A_union=A_union, b_union=b_union, vertices=vertices, segments=segments, ), InSimulationException("Optimizer failed to find a solution")
def do_highlevel_control(self, params): """Decide parameters.""" segs_polytopes, goal, seg_psi_bounds = self.compute_segs_polytopes_and_goal( params) """Apply motion planning problem""" n_segs = len(segs_polytopes) Gamma, nu, nx = params.Gamma, params.nu, params.nx T = self.__control_horizon max_a, min_a = self.__params.max_a, self.__params.min_a max_delta = self.__params.max_delta model = docplex.mp.model.Model(name="proposed_problem") min_u = np.vstack((np.full(T, min_a), np.full(T, -max_delta))).T.ravel() max_u = np.vstack((np.full(T, max_a), np.full(T, max_delta))).T.ravel() # Slack variables for control u = np.array(model.continuous_var_list(nu * T, lb=min_u, ub=max_u, name='u'), dtype=object) # State variables x, y, psi, v X = (params.initial_rollout.local + util.obj_matmul(Gamma, u)).reshape( T + 1, nx) X = params.transform(X) X = X[1:] # Control variables a, delta U = u.reshape(T, nu) """Apply motion dynamics constraints""" model.add_constraints(self.compute_dyamics_constraints( params, X[:, 3])) """Apply road boundary constraints""" if self.road_boundary_constraints: # Slack variables from road obstacles Omicron = np.array(model.binary_var_list(n_segs * T, name="omicron"), dtype=object).reshape(n_segs, T) M_big, diag = self.__params.M_big, self.__params.diag psi_0 = params.initial_state.world[2] for t in range(self.__control_horizon): for seg_idx, (A, b) in enumerate(segs_polytopes): lhs = util.obj_matmul(A, X[t, :2]) \ - np.array(M_big*(1 - Omicron[seg_idx, t])) rhs = b # - diag """Constraints on road boundaries""" model.add_constraints([l <= r for (l, r) in zip(lhs, rhs)]) """Constraints on angle boundaries""" if self.angle_boundary_constraints: lhs = X[t, 2] - psi_0 - M_big * (1 - Omicron[seg_idx, t]) model.add_constraint(lhs <= seg_psi_bounds[seg_idx][1]) lhs = X[t, 2] - psi_0 + M_big * (1 - Omicron[seg_idx, t]) model.add_constraint(lhs >= seg_psi_bounds[seg_idx][0]) model.add_constraint(np.sum(Omicron[:, t]) >= 1) """Compute and minimize objective""" cost = self.compute_objective(X, U, goal) model.minimize(cost) if self.road_boundary_constraints and self.__U_warmstarting is not None: # Warm start inputs if past iteration was run. warm_start = model.new_solution() for i, u in enumerate(self.__U_warmstarting[self.__step_horizon:]): warm_start.add_var_value(f"u_{2*i}", u[0]) warm_start.add_var_value(f"u_{2*i + 1}", u[1]) # add omicron_0 as hotfix to MIP warmstart as it needs # at least 1 integer value set. warm_start.add_var_value("omicron_0", 1) model.add_mip_start( warm_start, write_level=docplex.mp.constants.WriteLevel.AllVars) # model.print_information() # model.parameters.read.datacheck = 1 if self.log_cplex: model.parameters.mip.display = 2 s = model.solve(log_output=True) else: model.parameters.mip.display = 0 model.solve() # model.print_solution() cost = cost.solution_value f = lambda x: x if isinstance(x, numbers.Number) else x.solution_value U_star = util.obj_vectorize(f, U) X_star = util.obj_vectorize(f, X) return util.AttrDict(cost=cost, U_star=U_star, X_star=X_star, goal=goal)
def do_highlevel_control(self, params, ovehicles): """Decide parameters.""" """Compute road segments and goal.""" segments, goal = self.compute_segs_polytopes_and_goal(params) """Apply motion planning problem""" N_select = params.N_select x_bar, u_bar, Gamma = params.x_bar, params.u_bar, params.Gamma nx, nu = params.nx, params.nu T = self.__control_horizon max_a, min_a = self.__params.max_a, self.__params.min_a max_delta = self.__params.max_delta """Model, control and state variables""" model = docplex.mp.model.Model(name="proposed_problem") min_u = np.vstack((np.full(T, min_a), np.full(T, -max_delta))).T min_u = np.repeat(min_u[None], N_select, axis=0).ravel() max_u = np.vstack((np.full(T, max_a), np.full(T, max_delta))).T max_u = np.repeat(max_u[None], N_select, axis=0).ravel() # Slack variables for control u = model.continuous_var_list(N_select * nu * T, lb=min_u, ub=max_u, name="u") # U has shape (N_select, T*nu) U = np.array(u, dtype=object).reshape(N_select, -1) U_delta = U - u_bar x = util.obj_matmul(U_delta, Gamma.T) + x_bar # State variables x, y, psi, v X = x.reshape(N_select, T, nx) # Control variables a, delta U = U.reshape(N_select, T, nu) """Apply state constraints""" model.add_constraints(self.compute_state_constraints(params, X)) """Apply road boundary constraints""" if self.road_boundary_constraints: N_select = params.N_select T = self.__control_horizon I = len(segments.polytopes) # Slack variables from road obstacles Omicron = model.binary_var_list(N_select * I * T, name="omicron") Omicron = np.array(Omicron, dtype=object).reshape(N_select, I, T) model.add_constraints( self.compute_road_boundary_constraints(params, X, Omicron, segments)) else: Omicron = None """Apply vehicle collision constraints""" if params.O > 0: N_select = params.N_select T = self.__control_horizon O, L = params.O, self.__params.L # Slack variables for vehicle obstacles Delta = model.binary_var_list(O * L * N_select * T, name='delta') Delta = np.array(Delta, dtype=object).reshape(N_select, T, O, L) (constraints, vertices, A_unions, b_unions) = self.compute_obstacle_constraints( params, ovehicles, X, Delta, Omicron, segments) model.add_constraints(constraints) else: Delta = None vertices = A_unions = b_unions = None """Set up coinciding constraints""" for t in range(0, self.__n_coincide): for u1, u2 in util.pairwise(U[:, t]): model.add_constraints([l == r for (l, r) in zip(u1, u2)]) # TODO: constraints on binary variables actually makes optimization slower. Why? # if Omicron is not None: # for o1, o2 in util.pairwise(Omicron[:,:,t]): # model.add_constraints([l == r for (l, r) in zip(o1, o2)]) # if Delta is not None: # for d1, d2 in util.pairwise(Delta[:,t]): # d1 = d1.reshape(-1) # d2 = d2.reshape(-1) # model.add_constraints([l == r for (l, r) in zip(d1, d2)]) """Compute and minimize objective""" cost = self.compute_mean_objective(X, U, goal) model.minimize(cost) # TODO: add warmstarting to MCC # if self.road_boundary_constraints and self.__U_warmstarting is not None: # # Warm start inputs if past iteration was run. # warm_start = model.new_solution() # for i, u in enumerate(self.__U_warmstarting[self.__step_horizon :]): # warm_start.add_var_value(f"u_{2*i}", u[0]) # warm_start.add_var_value(f"u_{2*i + 1}", u[1]) # # add omicron_0 as hotfix to MIP warmstart as it needs # # at least 1 integer value set. # warm_start.add_var_value("omicron_0", 1) # model.add_mip_start( # warm_start, write_level=docplex.mp.constants.WriteLevel.AllVars # ) # model.print_information() # model.parameters.read.datacheck = 1 if self.log_cplex: model.parameters.mip.display = 2 s = model.solve(log_output=True) else: model.parameters.mip.display = 0 model.solve() # model.print_solution() """Extract solution""" try: cost = cost.solution_value f = lambda x: x if isinstance(x, numbers.Number ) else x.solution_value U_star = util.obj_vectorize(f, U) X_star = util.obj_vectorize(f, X) return util.AttrDict(cost=cost, U_star=U_star, X_star=X_star, goal=goal, A_unions=A_unions, b_unions=b_unions, vertices=vertices, segments=segments), None except docplex.mp.utils.DOcplexException as e: # TODO: check model for infeasible solution # docplex.util.environment.logger:environment.py:627 Notify end solve, # status=JobSolveStatus.INFEASIBLE_SOLUTION, solve_time=None return util.AttrDict(cost=None, U_star=None, X_star=None, goal=goal, A_unions=A_unions, b_unions=b_unions, vertices=vertices, segments=segments), InSimulationException( "Optimizer failed to find a solution")
def do_highlevel_control(self, params, ovehicles): """Decide parameters.""" """Compute road segments and goal.""" segs_polytopes, goal, seg_psi_bounds = self.compute_segs_polytopes_and_goal( params ) """Apply motion planning problem""" x_bar, u_bar, Gamma = params.x_bar, params.u_bar, params.Gamma nx, nu = params.nx, params.nu T = self.__control_horizon max_a, min_a = self.__params.max_a, self.__params.min_a max_delta = self.__params.max_delta """Model, control and state variables""" model = docplex.mp.model.Model(name="proposed_problem") min_u = np.vstack((np.full(T, min_a), np.full(T, -max_delta))).T.ravel() max_u = np.vstack((np.full(T, max_a), np.full(T, max_delta))).T.ravel() # Slack variables for control u = model.continuous_var_list(nu * T, lb=min_u, ub=max_u, name="u") u = np.array(u, dtype=object) u_delta = u - u_bar x = util.obj_matmul(Gamma, u_delta) + x_bar # State variables x, y, psi, v X = x.reshape(T, nx) # Control variables a, delta U = u.reshape(T, nu) """Apply state constraints""" model.add_constraints(self.compute_state_constraints(params, X)) """Apply road boundary constraints""" if self.road_boundary_constraints: n_segs = len(segs_polytopes) # Slack variables from road obstacles Omicron = model.binary_var_list(n_segs*T, name="omicron") Omicron = np.array(Omicron, dtype=object).reshape(n_segs, T) M_big = self.__params.M_big # diag = self.__params.diag psi_0 = params.initial_state.world[2] T = self.__control_horizon for t in range(T): for seg_idx, (A, b) in enumerate(segs_polytopes): lhs = util.obj_matmul(A, X[t, :2]) - np.array( M_big * (1 - Omicron[seg_idx, t]) ) rhs = b # - diag """Constraints on road boundaries""" model.add_constraints([l <= r for (l, r) in zip(lhs, rhs)]) """Constraints on angle boundaries""" if self.angle_boundary_constraints: lhs = X[t, 2] - psi_0 - M_big * (1 - Omicron[seg_idx, t]) model.add_constraint(lhs <= seg_psi_bounds[seg_idx][1]) lhs = X[t, 2] - psi_0 + M_big * (1 - Omicron[seg_idx, t]) model.add_constraint(lhs >= seg_psi_bounds[seg_idx][0]) model.add_constraint(np.sum(Omicron[:, t]) >= 1) """Apply vehicle collision constraints""" if params.O > 0: vertices = self.__compute_vertices(params, ovehicles) A_union, b_union = self.__compute_overapproximations(vertices, params, ovehicles) L, K = self.__params.L, params.K # Slack variables for vehicle obstacles Delta = model.binary_var_list(L*np.sum(K)*T, name='delta') Delta = np.array(Delta, dtype=object).reshape(np.sum(K), T, L) M_big = self.__params.M_big diag = self.__params.diag for ov_idx, ovehicle in enumerate(ovehicles): n_states = ovehicle.n_states sum_clu = np.sum(K[:ov_idx]) for latent_idx in range(n_states): for t in range(self.__control_horizon): A_obs = A_union[t][latent_idx][ov_idx] b_obs = b_union[t][latent_idx][ov_idx] indices = sum_clu + latent_idx lhs = util.obj_matmul(A_obs, X[t, :2]) + M_big*(1 - Delta[indices, t]) rhs = b_obs + diag model.add_constraints([l >= r for (l,r) in zip(lhs, rhs)]) model.add_constraint(np.sum(Delta[indices, t]) >= 1) else: vertices = A_union = b_union = None """Compute and minimize objective""" cost = self.compute_objective(X, U, goal) model.minimize(cost) if self.road_boundary_constraints and self.__U_warmstarting is not None: # Warm start inputs if past iteration was run. warm_start = model.new_solution() for i, u in enumerate(self.__U_warmstarting[self.__step_horizon :]): warm_start.add_var_value(f"u_{2*i}", u[0]) warm_start.add_var_value(f"u_{2*i + 1}", u[1]) # add omicron_0 as hotfix to MIP warmstart as it needs # at least 1 integer value set. warm_start.add_var_value("omicron_0", 1) model.add_mip_start( warm_start, write_level=docplex.mp.constants.WriteLevel.AllVars ) # model.print_information() # model.parameters.read.datacheck = 1 if self.log_cplex: model.parameters.mip.display = 2 s = model.solve(log_output=True) else: model.parameters.mip.display = 0 model.solve() # model.print_solution() """Extract solution""" try: cost = cost.solution_value f = lambda x: x if isinstance(x, numbers.Number) else x.solution_value U_star = util.obj_vectorize(f, U) X_star = util.obj_vectorize(f, X) return util.AttrDict( cost=cost, U_star=U_star, X_star=X_star, goal=goal, A_union=A_union, b_union=b_union, vertices=vertices ), None except docplex.mp.utils.DOcplexException as e: # TODO: check model for infeasible solution # docplex.util.environment.logger:environment.py:627 Notify end solve, # status=JobSolveStatus.INFEASIBLE_SOLUTION, solve_time=None return util.AttrDict( cost=None, U_star=None, X_star=None, goal=goal, A_union=A_union, b_union=b_union, vertices=vertices ), InSimulationException("Optimizer failed to find a solution")