@@ -50,44 +50,48 @@ class OptimalControlProblem():
5050 integral_cost : callable
5151 Function that returns the integral cost given the current state
5252 and input. Called as integral_cost(x, u).
53- trajectory_constraints : list of tuples , optional
53+ trajectory_constraints : list of constraints , optional
5454 List of constraints that should hold at each point in the time
55- vector. Each element of the list should consist of a tuple with
56- first element given by :meth:`~scipy.optimize.LinearConstraint` or
57- :meth:`~scipy.optimize.NonlinearConstraint` and the remaining
58- elements of the tuple are the arguments that would be passed to
59- those functions. The constraints will be applied at each time
60- point along the trajectory.
55+ vector. Each element of the list should be an object of type
56+ :class:`~scipy.optimize.LinearConstraint` with arguments `(A, lb,
57+ ub)` or :class:`~scipy.optimize.NonlinearConstraint` with arguments
58+ `(fun, lb, ub)`. The constraints will be applied at each time point
59+ along the trajectory.
6160 terminal_cost : callable, optional
6261 Function that returns the terminal cost given the current state
6362 and input. Called as terminal_cost(x, u).
64- initial_guess : 1D or 2D array_like
65- Initial inputs to use as a guess for the optimal input. The
66- inputs should either be a 2D vector of shape (ninputs, horizon)
67- or a 1D input of shape (ninputs,) that will be broadcast by
68- extension of the time axis.
6963 trajectory_method : string, optional
7064 Method to use for carrying out the optimization. Currently supported
7165 methods are 'shooting' and 'collocation' (continuous time only). The
7266 default value is 'shooting' for discrete time systems and
7367 'collocation' for continuous time systems
68+ initial_guess : (tuple of) 1D or 2D array_like
69+ Initial states and/or inputs to use as a guess for the optimal
70+ trajectory. For shooting methods, an array of inputs for each time
71+ point should be specified. For collocation methods, the initial
72+ guess is either the input vector or a tuple consisting guesses for
73+ the state and the input. Guess should either be a 2D vector of
74+ shape (ninputs, ntimepts) or a 1D input of shape (ninputs,) that
75+ will be broadcast by extension of the time axis.
7476 log : bool, optional
7577 If `True`, turn on logging messages (using Python logging module).
76- Use ``logging.basicConfig`` to enable logging output (e.g., to a file).
77- kwargs : dict, optional
78- Additional parameters (passed to :func:`scipy.optimal.minimize`).
78+ Use :py:func:`logging.basicConfig` to enable logging output
79+ (e.g., to a file).
7980
8081 Returns
8182 -------
8283 ocp : OptimalControlProblem
8384 Optimal control problem object, to be used in computing optimal
8485 controllers.
8586
86- Additional parameters
87- ---------------------
87+ Other Parameters
88+ ----------------
8889 basis : BasisFamily, optional
8990 Use the given set of basis functions for the inputs instead of
9091 setting the value of the input at each point in the timepts vector.
92+ terminal_constraints : list of constraints, optional
93+ List of constraints that should hold at the terminal point in time,
94+ in the same form as `trajectory_constraints`.
9195 solve_ivp_method : str, optional
9296 Set the method used by :func:`scipy.integrate.solve_ivp`.
9397 solve_ivp_kwargs : str, optional
@@ -174,20 +178,6 @@ def __init__(
174178 if kwargs :
175179 raise TypeError ("unrecognized keyword(s): " , str (kwargs ))
176180
177- # Process trajectory constraints
178- def _process_constraints (constraint_list , name ):
179- if isinstance (constraint_list , tuple ):
180- constraint_list = [constraint_list ]
181- elif not isinstance (constraint_list , list ):
182- raise TypeError (f"{ name } constraints must be a list" )
183-
184- # Make sure that we recognize all of the constraint types
185- for ctype , fun , lb , ub in constraint_list :
186- if not ctype in [opt .LinearConstraint , opt .NonlinearConstraint ]:
187- raise TypeError (f"unknown { name } constraint type { ctype } " )
188-
189- return constraint_list
190-
191181 self .trajectory_constraints = _process_constraints (
192182 trajectory_constraints , "trajectory" )
193183 self .terminal_constraints = _process_constraints (
@@ -1005,9 +995,6 @@ def solve_ocp(
1005995 If True, assume that 2D input arrays are transposed from the standard
1006996 format. Used to convert MATLAB-style inputs to our format.
1007997
1008- kwargs : dict, optional
1009- Additional parameters (passed to :func:`scipy.optimal.minimize`).
1010-
1011998 Returns
1012999 -------
10131000 res : OptimalControlResult
@@ -1443,3 +1430,45 @@ def _evaluate_output_range_constraint(x, u):
14431430
14441431 # Return a nonlinear constraint object based on the polynomial
14451432 return (opt .NonlinearConstraint , _evaluate_output_range_constraint , lb , ub )
1433+
1434+ #
1435+ # Utility functions
1436+ #
1437+
1438+ #
1439+ # Process trajectory constraints
1440+ #
1441+ # Constraints were originally specified as a tuple with the type of
1442+ # constraint followed by the arguments. However, they are now specified
1443+ # directly as SciPy constraint objects.
1444+ #
1445+ # The _process_constraints() function will covert everything to a consistent
1446+ # internal representation (currently a tuple with the constraint type as the
1447+ # first element.
1448+ #
1449+ def _process_constraints (clist , name ):
1450+ if isinstance (
1451+ clist , (tuple , opt .LinearConstraint , opt .NonlinearConstraint )):
1452+ clist = [clist ]
1453+ elif not isinstance (clist , list ):
1454+ raise TypeError (f"{ name } constraints must be a list" )
1455+
1456+ # Process individual list elements
1457+ constraint_list = []
1458+ for constraint in clist :
1459+ if isinstance (constraint , tuple ):
1460+ # Original style of constraint
1461+ ctype , fun , lb , ub = constraint
1462+ if not ctype in [opt .LinearConstraint , opt .NonlinearConstraint ]:
1463+ raise TypeError (f"unknown { name } constraint type { ctype } " )
1464+ constraint_list .append (constraint )
1465+ elif isinstance (constraint , opt .LinearConstraint ):
1466+ constraint_list .append (
1467+ (opt .LinearConstraint , constraint .A ,
1468+ constraint .lb , constraint .ub ))
1469+ elif isinstance (constraint , opt .NonlinearConstraint ):
1470+ constraint_list .append (
1471+ (opt .NonlinearConstraint , constraint .fun ,
1472+ constraint .lb , constraint .ub ))
1473+
1474+ return constraint_list
0 commit comments