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

[WIP] initial implementation of sqrt_spd and inv_sqrt_spd #1145

Closed
wants to merge 11 commits into from

Conversation

bgoodri
Copy link
Contributor

@bgoodri bgoodri commented Mar 7, 2019

Summary

This implements the symmetric square root of a positive definite matrix (sqrt_spd) and its inverse (inv_sqrt_spd) and fixes #1144 .

These call the operatorSqrt and operatorInverseSqrt methods of Eigen's self-adjoint eigensolver http://eigen.tuxfamily.org/dox/classEigen_1_1SelfAdjointEigenSolver.html .

Tests

There are tests that the difference between an arbitrary positive definite matrix and its sqrt_spd multiplied by itself are zero, but there is an assert when evaluating adj_jac_apply that I am hoping @bbbales2 knows about. Same thing for the inverse square root.

Side Effects

No

Checklist

  • Math issue Math does not have the matrix (inverse) square root #1144

  • Copyright holder: Trustees of Columbia University

    The copyright holder is typically you or your assignee, such as a university or company. By submitting this pull request, the copyright holder is agreeing to the license the submitted work under the following licenses:
    - Code: BSD 3-clause (https://opensource.org/licenses/BSD-3-Clause)
    - Documentation: CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/)

  • the basic tests are passing (Not for the new tests)

    • unit tests pass (to run, use: ./runTests.py test/unit)
    • header checks pass, (make test-headers)
    • docs build, (make doxygen)
    • code passes the built in C++ standards checks (make cpplint)
  • the code is written in idiomatic C++ and changes are documented in the doxygen

  • the new changes are tested

adj_jac_apply() and jacobian() seem to not work together
Copy link
Member

@bbbales2 bbbales2 left a comment

Choose a reason for hiding this comment

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

Is there an assert happening in the sqrt_spd_tests that are causing this to puke? Is that why they're commented out?

There's a specialization for sqrt_spd, but is there a specialization for inv_sqrt_spd?

stan/math/rev/mat/fun/sqrt_spd.hpp Show resolved Hide resolved
@bbbales2
Copy link
Member

bbbales2 commented Mar 7, 2019

I reread the commit, looks like the answer is yes. I'll check this out in the afternoooooon.

@bgoodri
Copy link
Contributor Author

bgoodri commented Mar 7, 2019 via email

@bgoodri
Copy link
Contributor Author

bgoodri commented Mar 7, 2019

Someone can kill the continuous integration tests for this. It is not ready to be merged and isn't necessary for 2.19.0.

bbbales2 and others added 3 commits March 7, 2019 16:46
#1144)

Rearranged some includes in stan/math/rev/mat.hpp to get rid of some type traits errors. Not sure why these were moved around. Might need moved back.
@bbbales2
Copy link
Member

bbbales2 commented Mar 8, 2019

I wiggled around the types on the multiply_adjoint_jacobian. I dunno if I got the Kronecker stuff right. The sqrt_spd tests run now.

There was also some includes that got shuffled in stan/math/rev/mat.hpp. I moved them back. I was getting weird type traits errors.

@bbbales2
Copy link
Member

bbbales2 commented Mar 8, 2019

The type of the thing passed to multiply_adjoint_jacobian in one of these functors matches the output type of operator(). The return type of multiply_adjoint_jacobian is a tuple of the input types to operator() (excluding is_var), so that's where the type stuff came from.

using Eigen::kroneckerProduct;
using Eigen::MatrixXd;
Eigen::MatrixXd output(K_, K_);
Eigen::Map<const Eigen::VectorXd> map_input(adj.data(), adj.size());
Copy link
Contributor Author

Choose a reason for hiding this comment

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

And if adj is a MatrixXd, how can it be mapped to a VectorXd?

Copy link
Member

Choose a reason for hiding this comment

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

That mapping is doing this (https://en.wikipedia.org/wiki/Vectorization_(mathematics)). I was just pattern-matching the eqs in the Stackoverflow link. I'm not really familiar with that. I was just double checking myself and Abhishek makes a note at the end of his post that the Jacobian he wrote is in terms of the vectorization, which I assume is the Wikipedia definition.

Copy link
Member

Choose a reason for hiding this comment

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

Oh yeah fair warning, I was just kinda guessing on the math stuff to make things compile. Maybe add in a diagonal matrix test (with things that aren't 1 on the diagonal) so we know the answer and gradients and all just to make sure things are in the right direction.

using Eigen::kroneckerProduct;
using Eigen::MatrixXd;
Eigen::MatrixXd output(K_, K_);
Eigen::Map<const Eigen::VectorXd> map_input(adj.data(), adj.size());
Eigen::Map<Eigen::VectorXd> map_output(output.data(), output.size());
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Similar, how can map_output be a Map<VectorXd> but output be a square MatrixXd?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And why is map_output necessary? Can we just do the linear algebra to form output and do std::make_tuple(output)?

Copy link
Member

Choose a reason for hiding this comment

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

The maps are just an eigen thing for mapping one data structure onto another. So the math happens in terms of the vectors like Abhishek had it but it just ends up in the right place in the matrices. I think it should be okay in terms of efficiency?

@bgoodri
Copy link
Contributor Author

bgoodri commented Mar 8, 2019 via email

@bgoodri
Copy link
Contributor Author

bgoodri commented Mar 8, 2019

@bbbales2 Is there a way to automate the "second check" mentioned before the conclusions section of https://people.maths.ox.ac.uk/gilesm/files/NA-08-01.pdf when utilizing adj_jac_apply?

@bbbales2
Copy link
Member

bbbales2 commented Mar 9, 2019

Is there a way to automate the "second check" mentioned before the conclusions section of https://people.maths.ox.ac.uk/gilesm/files/NA-08-01.pdf when utilizing adj_jac_apply?

Yeah, looks like it'd work (in a hand-wavy I didn't actually think through the code kinda way). Looks like something that would be handy in other places too. @bob-carpenter, you seen this?

@bgoodri
Copy link
Contributor Author

bgoodri commented Mar 9, 2019 via email

@bob-carpenter
Copy link
Contributor

I have not seen that. My matrix fu is weak.

It says that if A, B lead to an output C, then the identity

Tr(transpose(bar(C)) * dot(C) 
= Tr(transpose(bar(A)) * dot(A))
  + Tr(transpose(bar(B)) * dot(B))   

where I think the bar operation is gradient.

@bgoodri
Copy link
Contributor Author

bgoodri commented Mar 11, 2019

It is the same Giles paper cited in the Stan Math paper on archiv.org. The notation is given at the start of section 2.1
image

@serban-nicusor-toptal serban-nicusor-toptal added this to the 2.20.0++ milestone Jul 18, 2019
@syclik
Copy link
Member

syclik commented Oct 24, 2019

Closing due to inactivity. @bgoodri, I hope you get a chance to finish this.

@syclik syclik closed this Oct 24, 2019
@serban-nicusor-toptal serban-nicusor-toptal modified the milestones: 3.0.0++, 3.1.0 Jan 24, 2020
@mcol mcol removed this from the 3.1.0 milestone Feb 3, 2020
@bbbales2
Copy link
Member

@bgoodri just pinging you in case you want to resurrect this.

@bgoodri bgoodri reopened this Apr 24, 2020
@SteveBronder
Copy link
Collaborator

@bgoodri are you still working on this?

@bgoodri
Copy link
Contributor Author

bgoodri commented Jul 16, 2020 via email

@syclik
Copy link
Member

syclik commented Jul 31, 2020

Thanks, @bgoodri. I'm going to convert it to a draft so we know it's not ready yet.

@syclik syclik marked this pull request as draft July 31, 2020 04:54
@syclik syclik added the WIP label Nov 10, 2020
@syclik
Copy link
Member

syclik commented Nov 10, 2020

@bgoodri, I'm going to close this with a WIP label so it can be found again. If you'd like to continue on it, please feel free to reopen.

@syclik syclik closed this Nov 10, 2020
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.

Math does not have the matrix (inverse) square root
9 participants