Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Uniform processing of time response and optimization parameters#1125

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged

Conversation

@murrayrm
Copy link
Member

This PR regularizes the use of various keywords for time responses and optimization routines, while maintaining backward compatibility with existing code. The motivation for the PR is that over time we have introduced different terms to refer to parameters that have the same purpose. This can be confusing for people trying to use the package.

For example:

  • The named parametersx0 andX0 are used in different places for the initial state in simulation and optimization functions.
  • The parameterreturn_x is used when a function should return the state as part of a tuple, though sometimereturn_states is used instead.
  • Responses use thestates property (notx) and setting the the state names is done viastates.
  • Similar issues arise for inputs (u0,U,inputs) and outputs (y0,outputs).
  • Time points for simulation and optimization are sometimes referred to astimepts but other times asT.
  • In the optimization and flatness modules, cost functions are referred to ascost,trajectory_cost orintegral cost, depending on the function, and constraints are referred to astrajectory_constraints in some places asconstraints in others.
  • Other parameters have names that don't seem to fit existing python-control naming patterns:t_eval,yfinal, etc.

To address these issues, this PR introduces a common set of terms across various time response and optimal control functions, with the following more consistent usage patterns and functionality:

  • Parameters specifying the inputs, outputs, and states are referred to asinputs,outputs, andstates consistently throughout the functions.
  • Variables associated with inputs, outputs, states and time use those words plus an appropriate modifier:initial_state,final_output,input_indices etc.
  • Aliases are used both to maintain backward compatibility and to allow shorthand descriptions: e.g.,U,Y,X0. Short form aliases are documented in docstrings by listing the parameter aslong_form (or sf) : type.
  • Existing legacy keywords are allowed and generate aPendingDeprecationWarning.
  • Specifying a parameter value in two different ways (eg, via long form and an alias) generates aTypeError.

The implementation is done in a manner that can later be utilized for other functions where we want to have aliases and legacy keys, as documented in the Developer Notes section of the Reference Manual:

[P]arameter names are generally longer strings that describe the purpose fo the paramater. Similar tomatplotlib (e.g., the use oflw as an alias forlinewidth), some commonly used parameter names can be specified using an “alias” that allows the use of a shorter key.

Named parameter and keyword variable aliases are processed using theconfig._process_kwargs() andconfig._process_param() functions. These functions allow the specification of a list of aliases and a list of legacy keys for a given named parameter or keyword. To make use of these functions, the_process_kwargs() is first called to update the kwargs variable by replacing aliases with the full key:

_process_kwargs(kwargs, aliases)

The values for named parameters can then be assigned to a local variable using a call to process_param() of the form:

var = _process_kwargs('param', param, kwargs, aliases)

whereparam is the named parameter used in the function signature andvar is the local variable in the function (may also be param, but doesn’t have to be).

...

The alias mapping is a dictionary that returns a tuple consisting of valid aliases and legacy aliases:

alias_mapping = {    'argument_name_1', (['alias', ...], ['legacy', ...]),     ...}

If an alias is present in the dictionary of keywords, it will be used to set the value of the argument. If a legacy keyword is used, a warning is issued.

Two primary tables have been created in this PR. The first is a
dictionary of aliases and legacy names for time response commands (fromtimeresp.py):

_timeresp_aliases = {    # param:            ([alias, ...], [legacy, ...])    'timepts':          (['T'],        []),    'inputs':           (['U'],        ['u']),    'outputs':          (['Y'],        ['y']),    'initial_state':    (['X0'],       ['x0']),    'final_output':     (['yfinal'],   []),    'return_states':    (['return_x'], []),    'evaluation_times': (['t_eval'],   []),    'timepts_num':      (['T_num'],    []),    'input_indices':    (['input'],    []),    'output_indices':   (['output'],   []),}

The second is a dictionary of aliases for optimal control functions (fromoptimal.py):

_optimal_aliases = {    # param:                  ([alias, ...],                [legacy, ...])    'integral_cost':          (['trajectory_cost', 'cost'], []),    'initial_state':          (['x0', 'X0'],                []),    'initial_input':          (['u0', 'U0'],                []),    'final_state':            (['xf'],                      []),    'final_input':            (['uf'],                      []),    'initial_time':           (['T0'],                      []),    'trajectory_constraints': (['constraints'],             []),    'return_states':          (['return_x'],                []),}

@coveralls
Copy link

Coverage Status

coverage: 94.715% (-0.04%) from 94.751%
when pullingfc9fadb on murrayrm:keyword_aliases-07Feb2025
intocf77f99 on python-control:main.

@slivingstonslivingston self-requested a reviewFebruary 10, 2025 03:10
Copy link
Member

@slivingstonslivingston left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Good work! There are still several places where_process_legacy_keyword() is called (statefbk.py, pzmap.py, ...), but we can change those later.

I marked several small items to correct.

-----------------

As described above, parameter names are generally longer strings that
describe the purpose fo the paramater. Similar to `matplotlib` (e.g.,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
describe the purposefo theparamater. Similar to `matplotlib` (e.g.,
describe the purposefor theparameter. Similar to `matplotlib` (e.g.,


var = _process_kwargs('param', param, kwargs, aliases)

where 'param` is the named parameter used in the function signature
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
where'param` is the named parameter used in the function signature
where`param` is the named parameter used in the function signature

param = _process_param('param', defval, kwargs, function_aliases)
If `param` is a variable keyword argument (in `kwargs`), `defval` can
be pssed as either None or the default value to use if `param` is not
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
bepssedaseitherNoneorthedefaultvaluetouseif`param`isnot
bepassedaseitherNoneorthedefaultvaluetouseif`param`isnot

defval : object or dict
Default value for the parameter.
kwargs : dict
Dictionary of varaible keyword arguments.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
Dictionaryofvaraiblekeywordarguments.
Dictionaryofvariablekeywordarguments.

Raises
------
TypeError
If multiple keyword aliased are used for the same parameter.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
Ifmultiplekeywordaliasedareusedforthesameparameter.
Ifmultiplekeywordaliasesareusedforthesameparameter.

self.states=response.states


# Parameter and keyword aliases
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This dictionary is better placed near the top of the file, next to other module-level variables like_optimal_defaults. The motivation for this practice is clarity: the variable has module-level scope, so it is in-scope for functions defined before it, too. In my experience, it is easier to have all of these variables in the same part of file, just after imports.

returnControlPlot(lines,cplt.axes,cplt.figure)

# Dictionary of aliases for time response commands
_timeresp_aliases= {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Same comment here as for_optimal_aliases: I recommend to move the definition of_timeresp_aliases to the top of the file, just after__all__.


# Aliases
resp_short=ct.input_output_response(sys,timepts,1,X0=[1,1])
np.testing.assert_allclose(resp_long.states,resp_posn.states)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
np.testing.assert_allclose(resp_long.states,resp_posn.states)
np.testing.assert_allclose(resp_short.states,resp_posn.states)


elifnot (match:=re.search(
"\n"+r"((\w+|\.{3}), )*"+argname+r"(, (\w+|\.{3}))* :",
"\n"+r"((\w+|\.{3}), )*"+argname_+r"(, (\w+|\.{3}))* :",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

There is a search for duplicates below on line 658. Shouldargname there also be changed toargname_ ?

# Legacy
withpytest.warns(PendingDeprecationWarning,match="legacy"):
resp_legacy=ct.input_output_response(sys,timepts,1,x0=[1,1])
np.testing.assert_allclose(resp_long.states,resp_posn.states)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
np.testing.assert_allclose(resp_long.states,resp_posn.states)
np.testing.assert_allclose(resp_legacy.states,resp_posn.states)

@murrayrmmurrayrm merged commita042895 intopython-control:mainFeb 12, 2025
14 checks passed
@murrayrmmurrayrm added this to the0.10.2 milestoneFeb 19, 2025
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@slivingstonslivingstonslivingston approved these changes

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

0.10.2

Development

Successfully merging this pull request may close these issues.

3 participants

@murrayrm@coveralls@slivingston

[8]ページ先頭

©2009-2025 Movatter.jp