GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Prepare for removal of dependency on numpy.matrix class by murrayrm · Pull Request #292 · python-control/python-control

Conversation

@murrayrm

@murrayrm murrayrm commented Apr 16, 2019 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

This PR prepares for removal the dependency of the control package on the numpy.matrix class, which is planned for deprecation at some point in the future. To handle this, a number of changes have been made:

  • A new StateSpaceMatrix class, derived from numpy.ndarray, was created that is used to store the A, B, C, D matrices for a StateSpace system. This class maintains elements as a 2D matrix, so B[:,1] returns a column matrix (shape = (n, 1)). As an ndarray, this expression would normally return a 1D array. The StateSpaceMatrix class also overrides the * and ^ operators to give matrix multiplication and matrix powers (same as numpy.matlab does). This gives better compatibility with (user) code that was using those constructs to operate directly on matrices associated with a system. A new unit test file for the class is also included. There is also a function ssmatrix() that can be used to create a StateSpaceMatrix object (similar to the use of numpy.array to create an numpy.ndarray object).

  • Functions that used to return numpy.matrix objects now return a user-configurable type, set using the use_numpy_matrix or set_ss_matrix_type functions. By default the return type is currently numpy.matrix (for backward compatibility), but calling use_numpy_matrix(False) changes the return type to StateSpaceMatrix. Using set_ss_matrix_type, it is possible to use other subclasses derived from numpy.ndarray (including ndarray itself). A UserWarning is issued whenever numpy.matrix is set or used as the output type.

  • The code in the package as been updated to remove unneeded dependencies on the numpy.matrix class. This mainly involved changing numpy.matrix to numpy.array, but in some cases some additional changes were needed because of the differences between matrices and numpy. With the exception of extracting elements of submatrices, the main package code does not explicitly use the functionality of the StateSpaceMatrix class, so the main use of this class is to provide some backward compatibility for user code that users * and ^ operators (which is fairly common in my own code).

  • All unit test code (in control/tests) has been scrubbed of unnecessary dependence on the numpy.matrix class (except for testing that warning messages are generated and a few other checks for backward compatibility).

  • I did some PEP8 cleaning on statesp.py since there were lots of changes in this file already.

The changes were tested with the old unit test files, the new unit test files, and all examples and everything continues to work across all of those variants.

Net impact of this PR is that all numpy.matrix deprecation warnings can be removed by calling use_numpy_matrix(False), addressing issue #233. This behavior can be made the default in a future release or when numpy.matrix goes away.

There are two situations in which the numpy.matrix deprecation warning can still appear:

  • For backward compatibility, I set things up so that if you pass the StateSpaceMatrix constructor a string then it will call numpy.matrix. This allows all old examples to work without change (but does generate a warning message).

  • It's possible that if a user creates a numpy.matrix object to one of the python-control functions that it could end up generating a copy and that could trigger a warning message. I figure that is the user's fault -:).

(Note: this description was updated on 8 Jun 2019 to reflect the changes made in response to comments and responses below.)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
murrayrm added 5 commits April 15, 2019 23:26
@murrayrm
add StateSpaceMatrix class
a4986b6
@murrayrm
remove np.matrix dependencies from module code
f010542
@murrayrm
remove np.matrix dependencies from tests
afc4ef4
@murrayrm
add matrix power operation (**) to StateSpaceMatrix
14d5c3a
@murrayrm
code cleanup (including PEP8)
08f1c51
@murrayrm murrayrm mentioned this pull request Apr 16, 2019
Decide on how to handle (to be deprecated?) np.matrix class #233
Closed
@coveralls

coveralls commented Apr 16, 2019 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Coverage Status

Coverage increased (+0.3%) to 81.228% when pulling a5126f8 on murrayrm:np.matrix into 8a11cd3 on python-control:master.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@moorepants

moorepants commented Apr 16, 2019

Copy link
Copy Markdown

One overall comment: If control functions, methods, and attributes now return numpy arrays instead of numpy matrices, this change could break lots of code in the wild. If a user gets these matrix outputs and then operates on them with operations that assume a matrix type (e.g. overloaded *), then their code will now break or return incorrect results. It would probably be best to deprecate this in the control package so that users see warnings that output types will change in the next release. A 6 month deprecation time might be the minimum for this to register for average users.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

moorepants
moorepants reviewed Apr 16, 2019
View reviewed changes
Comment thread control/statesp.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@moorepants @murrayrm
Fix typo in control/statesp.py
ce42c1c
Co-Authored-By: murrayrm <[email protected]>
@murrayrm

murrayrm commented Apr 16, 2019

Copy link
Copy Markdown
Member Author

@moorepants Good point. Most of these changes are internal and so shouldn't affect any user outputs. But I'll go through and check to see whether the output of any function actually changed pre/post PR. The only think that might have changed are some of the functions that return matrices (eg, Gramians).

Note also that the StateSpaceMatrix class does define the "standard" overloaded operators (*,^, [,]) so user code operating on state space matrices should function normally. But I completely agree this is something we want to be careful about.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@murrayrm

murrayrm commented Apr 16, 2019

Copy link
Copy Markdown
Member Author

I checked through the code. Most functions that return matrices were already returning ndarrays (typically via a call to scipy.linalg.*). The one set that I found that could have compatibility problems is:

  • ctrb and obsv used to return matrix objects and now return ndarray objects.

Thoughts on the best approach to handling this? We could:

  • Keep the return type as matrix for now, with a deprecation warning. Change to ndarray in a future release.

  • Return a StateSpaceMatrix object, which would be compatible for most (all?) operations and allow matrix-like manipulation of the observability or controllability gramians.

  • Return an ndarray object and let people rewrite their code as they discover the change.

We could also allow a subtype keyword for the function and return an ndarray of the listed subtype (with a default to either matrix, StateSpaceMatrix, or ndarray, depending on how we resolve the issue).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

murrayrm added 2 commits April 16, 2019 21:52
@murrayrm
add return_type keyword to functions that previously returned np.matrix
fbc58ec
@murrayrm
Merge branch 'np.matrix' of https://github.com/murrayrm/python-control …
2dafd5c
…into np.matrix
@murrayrm

murrayrm commented Apr 17, 2019

Copy link
Copy Markdown
Member Author

Updated the code so that all functions that used to return an ndarray of subtype numpy.matrix return that type by default, with a user warning that this will be deprecated in the future. This can be overridden using the return_type keyword.

Once we are OK with the code changing (perhaps in the next major or minor release), we can change the code to return numpy.ndarray by default (user will still be able to override using return_type keyword).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@murrayrm murrayrm mentioned this pull request May 19, 2019
Change to code for ctrb and obsv #300
Merged
@murrayrm
Merge branch 'master' into np.matrix
e492f2b
@murrayrm

murrayrm commented May 19, 2019

Copy link
Copy Markdown
Member Author

Merged changes from current version of master (including implementing updated ctrb and obsv computations in PR #300).

@billtubbs FYI. Perhaps worth waiting until this PR is merged before making any more changes to ctrb and obsv. I took your recent update and applied that same change here (but without using the matrix class).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@murrayrm murrayrm added the quality assurance label May 27, 2019
murrayrm added 2 commits May 31, 2019 09:23
@murrayrm
Merge updates to master and update additional unit tests
2304807
@murrayrm
merge latest master + fix simple conflict
fe528a8
@roryyorke

roryyorke commented Jun 2, 2019

Copy link
Copy Markdown
Contributor

StateSpaceMatrix should probably have an __imul__ method.
Using __new__ here seems unusual to me; is it obvious why it's necessary?

Putting return_type=np.matrix arguably makes a long-term commitment to this interface (i.e., the "return_type" argument will be expected in the future); an alternative might be a config option for return types of the relevant functions. It also suggests more generality than is on offer; that is, a naive user might expect return_type=StateSpaceMatrix to work (it might, though I assume it's not what's intended) Perhaps a flag instead, "return_npmatrix=True"?

The code for turning Matlab-style matrix strings into nd.arrays is in numpy.matrixlib.defmatrix._convert_from_string -- it's not all that long or complicated, one could copy it if necessary.

Less importantly, if we didn't have to support Python 2.7 this refactoring could have used @ to be a bit tidier. Pity there's no tidy "matrix-power" operator.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@murrayrm

murrayrm commented Jun 3, 2019

Copy link
Copy Markdown
Member Author

Thanks for the comments @roryyorke. Responses (no actions yet):

  • The code for __new__ is based on the numpy.matrix.__new__ function. I'm pretty sure we need to use __new__ instead of __init__ because we are creating the object (via a call to np.ndarray.__new__) with the desired storage type, shape, etc. If we just call __init__ then that information will have already been created by numpy.ndarray (since __init__ gets called after __new__).

  • I'm pretty sure that return_type=StateSpaceMatrix will actually work. You can also use return_type=numpy.ndarray, if you wanted to make sure you got a NumPy array and not a StateSpace object. But I agree that we may want the simpler behavior of just turning off the matrix class. Need to think on that one.

  • I hadn't thought about what other operators to implement. In addition to __imul__ there are things like __iadd__ and __isub__ as well. Implementing all of them is tedious, but not implementing them means that you get the default numpy.ndarray behavior, which could be confusing. Another alternative would be to define all of those to raise a NotImplementedError exception, so at least you couldn't "accidentally" use it.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@roryyorke

roryyorke commented Jun 4, 2019

Copy link
Copy Markdown
Contributor

np.matrix inherits most numeric dunder methods from np.ndarray, except mul and pow (see below). Raising NotImplementedError for unimplemented mul and pow methods is an easy, safe option.

prefixes = ['','r','i']                                                                                       
bases = ['add','sub','mul','matmul','truediv','floordiv','mod','divmod','pow','lshift','rshift','and','or','xor']
makemeth = lambda p, b: '__' + p + b + '__'
# there's no such thing as __idivmod__; otherwise all exist
methods = [makemeth(p,b) for p,b in itertools.product(prefixes, bases) if hasattr(np.ndarray, makemeth(p,b))]
matonly = [m for m in methods if getattr(np.matrix, m) is not getattr(np.ndarray, m)]                          
print(matonly)
# output: ['__mul__', '__pow__', '__rmul__', '__rpow__', '__imul__', '__ipow__']
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

murrayrm added 3 commits June 7, 2019 19:24
@murrayrm
implement remaining dunder methods for StateSpace
d93ea5e
@murrayrm
Create config options for using numpy.matrix as state space return type
dc333a6
@murrayrm
skip np.matrix warning checks in py2.7 due to bug in repeated warnings
4bba186
@murrayrm

murrayrm commented Jun 8, 2019

Copy link
Copy Markdown
Member Author

Committed a new set of changes to address the issues raised by @roryyorke. Most recent updates:

  • The use of numpy.matrix as a return type is now set as a configuration option. The default is for functions in statesp.py and (hsvd in modelsimp.py) to return numpy.matrix objects (for backward compatibility), but the call use_numpy_matrix(False) will change the return type to StateSpaceMatrix. There is also a function set_ss_return_type that can set the return type to any subclass of numpy.ndarray (including ndarray itself).

  • New unit test code to test the functionality of use_numpy_matrix(False) and set_ss_return_type.

  • Added code to raise theNotImplementedError exception for dunder methods ipow and imul, so that they don't fall back to the (incompatible) numpy.ndarray methods.

In a future release, we can change the defaults in config.py to return either StateSpaceMatrix objects or numpy.ndarray objects and the dependence on numpy.matrix will be removed.

I decided not to copy the string processing code from numpy.matrixintopython-control though we may eventually want to put that into the matlab submodule. I think the main module should follow whatever Numpy does in terms of allowing string initialization (my guess is that it will go away).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@murrayrm murrayrm changed the title Remove dependency on numpy.matrix class Prepare for removal of dependency on numpy.matrix class Jun 8, 2019
@murrayrm
TRV: docstring updates
a5126f8
@murrayrm

murrayrm commented Jun 8, 2019 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

In looking through the code just now, I see what we have some inconsistencies in how we return matrix objects. In some place we are returning matrix objects (now convertible to StateSpaceMatrix via changes in this PR) but in other place we return ndarray objects. For example, place and lqr return ndarray objects, but ctrb, obsv, and acker return matrix-like objects (either numpy.matrix or StateSpaceMatrix, depending on settings).

On the one hand, it seems useful to have functions that return a gain matrix sending back something that can be used like the numpy.matrix class, so that you can say (for example)

K = lqr(A, B, Q, R)
Acl = A - B * K

(note that this won't actually work in the current code, tthough if you used acker instead of lqr then it would!).

On the other hand, at some point we should probably just bite the bullet and use ndarray everywhere, so that we are compatible with Numpy. If we did that, we could just get rid of the new StateSpaceMatrix class in this PR completely.

Any thoughts?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@moorepants

moorepants commented Jun 8, 2019

Copy link
Copy Markdown

Will this work?

K = lqr(A, B, Q, R)
Acl = A - B @ K

Using @ should be what we move towards.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@murrayrm

murrayrm commented Jun 8, 2019

Copy link
Copy Markdown
Member Author

Yes, that will work (though not in python 2.7, of course).

moorepants reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

This was referenced Jun 8, 2019
Updated examples to be PEP compliant #307
Merged
Allow np.array or np.matrix for state space matrices, operations #314
Merged
@murrayrm

murrayrm commented Jun 15, 2019

Copy link
Copy Markdown
Member Author

Following the discussion in issue #233, this PR is being abandoned in favor of PR #314, which is aligned with the approach in issue #233 (and is much more straightforward).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@murrayrm murrayrm closed this Jun 15, 2019
@murrayrm
murrayrm deleted the np.matrix branch January 3, 2020 01:48
@murrayrm murrayrm added this to the 0.8.3 milestone Jan 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

1 more reviewer
@moorepants moorepants moorepants left review comments
Reviewers whose approvals may not affect merge requirements

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

quality assurance

Projects

None yet

Milestone

0.8.3

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

4 participants

@murrayrm @coveralls @moorepants @roryyorke
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.