Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 19547 is positive semidefinite incorrect #19573

Merged

Conversation

galbwe
Copy link
Contributor

@galbwe galbwe commented Jun 17, 2020

This PR adds more efficient algorithms for determining if a matrix is symmetric positive semidefinite than Sylvester's criterion. The first method tried is Cholesky factorization with complete pivoting as described here. If that fails, an eigenvalue criterion is used. If that also fails, Sylvester's criterion is used as a last resort.

References to other Issues or PRs

Related issue
Follow up to this PR

Brief description of what is fixed or changed

Adds two new private functions to eigen.py

  1. _is_positive_semidefinite_cholesky
  2. _is_positive_semidefinite_evals

Also changes the logic of _is_positive_semidefinite to attempt Cholesky factorization first, then eigenvalue method, then the original approach.

Adds tests for the individual positive semidefinite test cases to help ensure all the methods are correct.

Other comments

Release Notes

  • matrices
    • Use more efficient Cholesky factorization method to check if matrices are positive semidefinite.

@sympy-bot
Copy link

sympy-bot commented Jun 17, 2020

Hi, I am the SymPy bot (v160). I'm here to help you write a release notes entry. Please read the guide on how to write release notes.

Your release notes are in good order.

Here is what the release notes will look like:

  • matrices
    • Use more efficient Cholesky factorization method to check if matrices are positive semidefinite. (#19573 by @galbwe)

This will be added to https://github.com/sympy/sympy/wiki/Release-Notes-for-1.7.

Note: This comment will be updated with the latest check if you edit the pull request. You need to reload the page to see it.

Click here to see the pull request description that was parsed.

<!-- Your title above should be a short description of what
was changed. Do not include the issue number in the title. -->
This PR adds more efficient algorithms for determining if a matrix is symmetric positive semidefinite than Sylvester's criterion. The first method tried is Cholesky factorization with complete pivoting as described [here](http://eprints.ma.man.ac.uk/1199/1/covered/MIMS_ep2008_116.pdf). If that fails, an eigenvalue criterion is used. If that also fails, Sylvester's criterion is used as a last resort. 
#### References to other Issues or PRs
<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact
format, e.g. "Fixes #1234" (see
https://tinyurl.com/auto-closing for more information). Also, please
write a comment on that issue linking back to this pull request once it is
open. -->
[Related issue](https://github.com/sympy/sympy/issues/19547)
[Follow up to this PR](https://github.com/sympy/sympy/pull/19556)

#### Brief description of what is fixed or changed
Adds two new private functions to `eigen.py`

 1. `_is_positive_semidefinite_cholesky`
 2. `_is_positive_semidefinite_evals`

Also changes the logic of `_is_positive_semidefinite` to attempt Cholesky factorization first, then eigenvalue method, then the original approach.

Adds tests for the individual positive semidefinite test cases to help ensure all the methods are correct.

#### Other comments


#### Release Notes

<!-- Write the release notes for this release below. See
https://github.com/sympy/sympy/wiki/Writing-Release-Notes for more information
on how to write release notes. The bot will check your release notes
automatically to see if they are formatted correctly. -->

<!-- BEGIN RELEASE NOTES -->
* matrices
  * Use more efficient Cholesky factorization method to check if matrices are positive semidefinite.
<!-- END RELEASE NOTES -->

Update

The release notes on the wiki have been updated.

@@ -493,13 +498,19 @@ def test_definite():
m = Matrix([[2, -1, 0], [-1, 2, -1], [0, -1, 2]])
assert m.is_positive_definite == True
assert m.is_positive_semidefinite == True
assert _is_positive_semidefinite_by_cholesky_factorization_with_pivots(m)
assert _is_positive_semidefinite_by_eigenvalues(m)
assert _is_positive_semidefinite_by_minors(m)
Copy link
Contributor

Choose a reason for hiding this comment

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

There is a trailing whitespace at the end of line 503 which is causing quality tests to fail, please fix that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My bad there. I removed whitespace and updated the flake8 part of setup.cfg to catch it earlier next time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess adding whitespace to setup.cfg was a bad idea, since it caused a whole bunch of linting errors in the pipeline. Removed in latest commit.

return all(eigenvalue.is_nonnegative for eigenvalue in M.eigenvals())


def _is_positive_semidefinite_by_cholesky_factorization_with_pivots(M):
Copy link
Member

Choose a reason for hiding this comment

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

These are too long names that can easily exceed 80 characters.
What about making them shorter like _is_positive_semidefinite_cholesky.
I don't think that it should need much mathematical meaning, especially if these functions are only used internaly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree they are a bit verbose. I tend to err on the side of more specificity in my variable names and comments. I shortened them.

@sylee957
Copy link
Member

I think that going through all the tests can be too exhaustive.
Should everything be determined from cholesky?

If cholesky can’t decide about symbolic values, I have doubts whether eigenvalues or sylvester is going to be more reliable for that.

@galbwe
Copy link
Contributor Author

galbwe commented Jun 17, 2020

I think that going through all the tests can be too exhaustive.
Should everything be determined from cholesky?

If cholesky can’t decide about symbolic values, I have doubts whether eigenvalues or sylvester is going to be more reliable for that.

I thought using fallback methods would be the most robust approach, but I'm okay with just having it use Cholesky if you think using eigenvalues and Sylvester won't help much with the failing cases.

@codecov
Copy link

codecov bot commented Jun 17, 2020

Codecov Report

Merging #19573 into master will increase coverage by 0.010%.
The diff coverage is 100.000%.

@@              Coverage Diff              @@
##            master    #19573       +/-   ##
=============================================
+ Coverage   75.663%   75.673%   +0.010%     
=============================================
  Files          654       654               
  Lines       169932    169941        +9     
  Branches     40062     40066        +4     
=============================================
+ Hits        128576    128601       +25     
+ Misses       35739     35724       -15     
+ Partials      5617      5616        -1     

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants