Skip to content

Commit ef95d8f

Browse files
committed
address doc-related TODOs; rename optimal_{ocp,oep}
1 parent 03b6836 commit ef95d8f

18 files changed

+108
-144
lines changed

control/flatsys/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
using the `BasisFamily` class. The resulting trajectory is return
1717
as a `SystemTrajectory` object and can be evaluated using the
1818
`SystemTrajectory.eval` member function. Alternatively, the
19-
`solve_flat_ocp` function can be used to solve an optimal control
19+
`solve_flat_optimal` function can be used to solve an optimal control
2020
problem with trajectory and final costs or constraints.
2121
2222
The docstring examples assume that the following import commands::
@@ -32,7 +32,8 @@
3232
from .bezier import BezierFamily
3333
from .bspline import BSplineFamily
3434
# Package functions
35-
from .flatsys import FlatSystem, flatsys, point_to_point, solve_flat_ocp
35+
from .flatsys import FlatSystem, flatsys, point_to_point, solve_flat_ocp, \
36+
solve_flat_optimal
3637
from .linflat import LinearFlatSystem
3738
from .poly import PolyFamily
3839
# Classes

control/flatsys/flatsys.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ def traj_const(null_coeffs):
656656

657657

658658
# Solve a point to point trajectory generation problem for a flat system
659-
def solve_flat_ocp(
659+
def solve_flat_optimal(
660660
sys, timepts, x0=0, u0=0, trajectory_cost=None, basis=None,
661661
terminal_cost=None, trajectory_constraints=None,
662662
initial_guess=None, params=None, **kwargs):
@@ -997,3 +997,7 @@ def traj_const(null_coeffs):
997997

998998
# Return a function that computes inputs and states as a function of time
999999
return systraj
1000+
1001+
1002+
# Convenience aliases
1003+
solve_flat_ocp = solve_flat_optimal

control/flatsys/systraj.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class SystemTrajectory:
1818
1919
The `SystemTrajectory` class is used to represent the trajectory
2020
of a (differentially flat) system. Used by the `point_to_point`
21-
and `solve_flat_ocp` functions to return a trajectory.
21+
and `solve_flat_optimal` functions to return a trajectory.
2222
2323
Parameters
2424
----------

control/lti.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ def __init__(self, inputs=1, outputs=1, states=None, name=None, **kwargs):
4040
super().__init__(
4141
name=name, inputs=inputs, outputs=outputs, states=states, **kwargs)
4242

43-
# TODO: update ss, tf docstrings to use this one as the primary
4443
def __call__(self, x, squeeze=None, warn_infinite=True):
4544
"""Evaluate system transfer function at point in complex plane.
4645

control/optimal.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
88
This module provides support for optimization-based controllers for
99
nonlinear systems with state and input constraints. An optimal
10-
control problem can be solved using the `solve_ocp` function or set up
11-
using the `OptimalControlProblem` class and then solved using the
12-
`~OptimalControlProblem.compute_trajectory` method. Utility functions
13-
are available to define common cost functions and input/state
14-
constraints. Optimal estimation problems can be solved using the
15-
`solve_oep` function or by using the `OptimalEstimationProblem` class
16-
and the `~OptimalEstimationProblem.compute_estimate` method..
10+
control problem can be solved using the `solve_optimal_trajectory`
11+
function or set up using the `OptimalControlProblem` class and then
12+
solved using the `~OptimalControlProblem.compute_trajectory` method.
13+
Utility functions are available to define common cost functions and
14+
input/state constraints. Optimal estimation problems can be solved
15+
using the `solve_optimal_estimate` function or by using the
16+
`OptimalEstimationProblem` class and the
17+
`~OptimalEstimationProblem.compute_estimate` method..
1718
1819
The docstring examples assume the following import commands::
1920
@@ -762,7 +763,6 @@ def _simulate_states(self, x0, inputs):
762763
#
763764

764765
# Compute the optimal trajectory from the current state
765-
# TODO: update docstring to refer to primary function (?)
766766
def compute_trajectory(
767767
self, x, squeeze=None, transpose=None, return_states=True,
768768
initial_guess=None, print_summary=True, **kwargs):
@@ -1019,7 +1019,7 @@ def __init__(
10191019

10201020

10211021
# Compute the input for a nonlinear, (constrained) optimal control problem
1022-
def solve_ocp(
1022+
def solve_optimal_trajectory(
10231023
sys, timepts, X0, cost, trajectory_constraints=None,
10241024
terminal_cost=None, terminal_constraints=None, initial_guess=None,
10251025
basis=None, squeeze=None, transpose=None, return_states=True,
@@ -1222,7 +1222,7 @@ def create_mpc_iosystem(
12221222
12231223
constraints : list of tuples, optional
12241224
List of constraints that should hold at each point in the time
1225-
vector. See `solve_ocp` for more details.
1225+
vector. See `solve_optimal_trajectory` for more details.
12261226
12271227
terminal_cost : callable, optional
12281228
Function that returns the terminal cost given the final state
@@ -2022,7 +2022,7 @@ def __init__(
20222022

20232023

20242024
# Compute the finite horizon estimate for a nonlinear system
2025-
def solve_oep(
2025+
def solve_optimal_estimate(
20262026
sys, timepts, Y, U, trajectory_cost, X0=None,
20272027
trajectory_constraints=None, initial_guess=None,
20282028
squeeze=None, print_summary=True, **kwargs):
@@ -2049,7 +2049,7 @@ def solve_oep(
20492049
Mean value of the initial condition (defaults to 0).
20502050
trajectory_constraints : list of tuples, optional
20512051
List of constraints that should hold at each point in the time
2052-
vector. See `solve_ocp` for more information.
2052+
vector. See `solve_optimal_trajectory` for more information.
20532053
control_indices : int, slice, or list of int or string, optional
20542054
Specify the indices in the system input vector that correspond to
20552055
the control inputs. For more information on possible values, see
@@ -2546,3 +2546,8 @@ def _process_constraints(clist, name):
25462546
constraint.lb, constraint.ub))
25472547

25482548
return constraint_list
2549+
2550+
2551+
# Convenience aliases
2552+
solve_ocp = solve_optimal_trajectory
2553+
solve_oep = solve_optimal_estimate

control/statesp.py

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -785,34 +785,7 @@ def __call__(self, x, squeeze=None, warn_infinite=True):
785785
in the complex plane, where `x` is `s` for continuous-time systems
786786
and `z` for discrete-time systems.
787787
788-
By default, a (complex) scalar will be returned for SISO systems
789-
and a p x m array will be return for MIMO systems with m inputs and
790-
p outputs. This can be changed using the `squeeze` keyword.
791-
792-
To evaluate at a frequency `omega` in radians per second,
793-
enter ``x = omega * 1j`` for continuous-time systems,
794-
``x = exp(1j * omega * dt)`` for discrete-time systems, or
795-
use the `~LTI.frequency_response` method.
796-
797-
Parameters
798-
----------
799-
x : complex or complex 1D array_like
800-
Complex value(s) at which transfer function will be evaluated.
801-
squeeze : bool, optional
802-
Squeeze output, as described below. Default value can be set
803-
using `config.defaults['control.squeeze_frequency_response']`.
804-
warn_infinite : bool, optional If set to False, turn off
805-
divide by zero warning.
806-
807-
Returns
808-
-------
809-
fresp : complex ndarray
810-
The value of the system transfer function at `x`. If the system
811-
is SISO and `squeeze` is not True, the shape of the array matches
812-
the shape of `x`. If the system is not SISO or `squeeze` is
813-
False, the first two dimensions of the array are indices for the
814-
output and input and the remaining dimensions match `x`. If
815-
`squeeze` is True then single-dimensional axes are removed.
788+
See `LTI.__call__` for details.
816789
817790
Examples
818791
--------

control/stochsys.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ def create_estimator_iosystem(
430430
References
431431
----------
432432
.. [1] R. M. Murray, `Optimization-Based Control
433-
<https://fbswiki.org/OBC`_, 2013.
433+
<https://fbswiki.org/OBC>`_, 2013.
434434
435435
"""
436436

control/tests/docstrings_test.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@
4848
keyword_skiplist = {
4949
control.input_output_response: ['method'],
5050
control.nyquist_plot: ['color'], # separate check
51-
control.optimal.solve_ocp: ['method', 'return_x'], # deprecated
51+
control.optimal.solve_optimal_trajectory:
52+
['method', 'return_x'], # deprecated
5253
control.sisotool: ['kvect'], # deprecated
5354
control.nyquist_response: ['return_contour'], # deprecated
5455
control.create_estimator_iosystem: ['state_labels'], # deprecated
@@ -61,7 +62,7 @@
6162
control.flatsys.point_to_point: [
6263
'method', 'options', # minimize_kwargs
6364
],
64-
control.flatsys.solve_flat_ocp: [
65+
control.flatsys.solve_flat_optimal: [
6566
'method', 'options', # minimize_kwargs
6667
],
6768
control.optimal.OptimalControlProblem: [

control/tests/flatsys_test.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ def test_kinematic_car_ocp(
198198
with warnings.catch_warnings():
199199
warnings.filterwarnings(
200200
'ignore', message="unable to solve", category=UserWarning)
201-
traj_ocp = fs.solve_flat_ocp(
201+
traj_ocp = fs.solve_flat_optimal(
202202
vehicle_flat, timepts, x0, u0,
203203
trajectory_cost=traj_cost,
204204
trajectory_constraints=input_constraints,
@@ -384,7 +384,7 @@ def test_flat_solve_ocp(self, basis):
384384
terminal_cost = opt.quadratic_cost(
385385
flat_sys, 1e3, 1e3, x0=xf, u0=uf)
386386

387-
traj_cost = fs.solve_flat_ocp(
387+
traj_cost = fs.solve_flat_optimal(
388388
flat_sys, timepts, x0, u0,
389389
terminal_cost=terminal_cost, basis=basis)
390390

@@ -398,7 +398,7 @@ def test_flat_solve_ocp(self, basis):
398398
# Solve with trajectory and terminal cost functions
399399
trajectory_cost = opt.quadratic_cost(flat_sys, 0, 1, x0=xf, u0=uf)
400400

401-
traj_cost = fs.solve_flat_ocp(
401+
traj_cost = fs.solve_flat_optimal(
402402
flat_sys, timepts, x0, u0, terminal_cost=terminal_cost,
403403
trajectory_cost=trajectory_cost, basis=basis)
404404

@@ -421,7 +421,7 @@ def test_flat_solve_ocp(self, basis):
421421
assert np.any(x_cost[0, :] < lb[0]) or np.any(x_cost[0, :] > ub[0]) \
422422
or np.any(x_cost[1, :] < lb[1]) or np.any(x_cost[1, :] > ub[1])
423423

424-
traj_const = fs.solve_flat_ocp(
424+
traj_const = fs.solve_flat_optimal(
425425
flat_sys, timepts, x0, u0,
426426
terminal_cost=terminal_cost, trajectory_cost=trajectory_cost,
427427
trajectory_constraints=constraints, basis=basis,
@@ -444,7 +444,7 @@ def test_flat_solve_ocp(self, basis):
444444
# Use alternative keywords as well
445445
nl_constraints = [
446446
(sp.optimize.NonlinearConstraint, lambda x, u: x, lb, ub)]
447-
traj_nlconst = fs.solve_flat_ocp(
447+
traj_nlconst = fs.solve_flat_optimal(
448448
flat_sys, timepts, x0, u0,
449449
trajectory_cost=trajectory_cost, terminal_cost=terminal_cost,
450450
trajectory_constraints=nl_constraints, basis=basis,
@@ -640,7 +640,7 @@ def test_solve_flat_ocp_errors(self):
640640
# Solving without basis specified should be OK (may generate warning)
641641
with warnings.catch_warnings():
642642
warnings.simplefilter("ignore")
643-
traj = fs.solve_flat_ocp(flat_sys, timepts, x0, u0, cost_fcn)
643+
traj = fs.solve_flat_optimal(flat_sys, timepts, x0, u0, cost_fcn)
644644
x, u = traj.eval(timepts)
645645
np.testing.assert_array_almost_equal(x0, x[:, 0])
646646
if not traj.success:
@@ -653,40 +653,40 @@ def test_solve_flat_ocp_errors(self):
653653

654654
# Solving without a cost function generates an error
655655
with pytest.raises(TypeError, match="cost required"):
656-
traj = fs.solve_flat_ocp(flat_sys, timepts, x0, u0)
656+
traj = fs.solve_flat_optimal(flat_sys, timepts, x0, u0)
657657

658658
# Try to optimize with insufficient degrees of freedom
659659
with pytest.raises(ValueError, match="basis set is too small"):
660-
traj = fs.solve_flat_ocp(
660+
traj = fs.solve_flat_optimal(
661661
flat_sys, timepts, x0, u0, trajectory_cost=cost_fcn,
662662
basis=fs.PolyFamily(2))
663663

664664
# Solve with the errors in the various input arguments
665665
with pytest.raises(ValueError, match="Initial state: Wrong shape"):
666-
traj = fs.solve_flat_ocp(
666+
traj = fs.solve_flat_optimal(
667667
flat_sys, timepts, np.zeros(3), u0, cost_fcn)
668668
with pytest.raises(ValueError, match="Initial input: Wrong shape"):
669-
traj = fs.solve_flat_ocp(
669+
traj = fs.solve_flat_optimal(
670670
flat_sys, timepts, x0, np.zeros(3), cost_fcn)
671671

672672
# Constraint that isn't a constraint
673673
with pytest.raises(TypeError, match="must be a list"):
674-
traj = fs.solve_flat_ocp(
674+
traj = fs.solve_flat_optimal(
675675
flat_sys, timepts, x0, u0, cost_fcn,
676676
trajectory_constraints=np.eye(2), basis=fs.PolyFamily(8))
677677

678678
# Unknown constraint type
679679
with pytest.raises(TypeError, match="unknown constraint type"):
680-
traj = fs.solve_flat_ocp(
680+
traj = fs.solve_flat_optimal(
681681
flat_sys, timepts, x0, u0, cost_fcn,
682682
trajectory_constraints=[(None, 0, 0, 0)],
683683
basis=fs.PolyFamily(8))
684684

685685
# Method arguments, parameters
686-
traj_method = fs.solve_flat_ocp(
686+
traj_method = fs.solve_flat_optimal(
687687
flat_sys, timepts, x0, u0, trajectory_cost=cost_fcn,
688688
basis=fs.PolyFamily(6), minimize_method='slsqp')
689-
traj_kwarg = fs.solve_flat_ocp(
689+
traj_kwarg = fs.solve_flat_optimal(
690690
flat_sys, timepts, x0, u0, trajectory_cost=cost_fcn,
691691
basis=fs.PolyFamily(6), minimize_kwargs={'method': 'slsqp'})
692692
np.testing.assert_allclose(
@@ -695,7 +695,7 @@ def test_solve_flat_ocp_errors(self):
695695

696696
# Unrecognized keywords
697697
with pytest.raises(TypeError, match="unrecognized keyword"):
698-
traj_method = fs.solve_flat_ocp(
698+
traj_method = fs.solve_flat_optimal(
699699
flat_sys, timepts, x0, u0, cost_fcn, solve_ivp_method=None)
700700

701701
@pytest.mark.parametrize(

control/tests/kwargs_test.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,11 +308,15 @@ def test_response_plot_kwargs(data_fcn, plot_fcn, mimo):
308308
'zpk': test_unrecognized_kwargs,
309309
'flatsys.point_to_point':
310310
flatsys_test.TestFlatSys.test_point_to_point_errors,
311+
'flatsys.solve_flat_optimal':
312+
flatsys_test.TestFlatSys.test_solve_flat_ocp_errors,
311313
'flatsys.solve_flat_ocp':
312314
flatsys_test.TestFlatSys.test_solve_flat_ocp_errors,
313315
'flatsys.FlatSystem.__init__': test_unrecognized_kwargs,
314316
'optimal.create_mpc_iosystem': optimal_test.test_mpc_iosystem_rename,
317+
'optimal.solve_optimal_trajectory': optimal_test.test_ocp_argument_errors,
315318
'optimal.solve_ocp': optimal_test.test_ocp_argument_errors,
319+
'optimal.solve_optimal_estimate': optimal_test.test_oep_argument_errors,
316320
'optimal.solve_oep': optimal_test.test_oep_argument_errors,
317321
'ControlPlot.set_plot_title': freqplot_test.test_suptitle,
318322
'FrequencyResponseData.__init__':

0 commit comments

Comments
 (0)