Skip to content

Matrix eigendecomposition#95

Merged
alejandro-isaza merged 10 commits into
Jounce:masterfrom
loufranco:matrix-eigendecomposition
Feb 9, 2019
Merged

Matrix eigendecomposition#95
alejandro-isaza merged 10 commits into
Jounce:masterfrom
loufranco:matrix-eigendecomposition

Conversation

@loufranco

Copy link
Copy Markdown
Contributor

This PR tries to bring the almost-done eigendecomposition branch into Surge

I expect there to be some comments (it is not lint warning free right now)

  1. I got the older branch updated and fixed conflicts
  2. I changed the interface to support complex vector and matrix returns
  3. I added tests based on Intel LAPACK and numpy docs

But,

  1. My return is a 3-tuple, which generates a lint warning
  2. I am using (Double, Double) for complex numbers. I don't see a convention in Surge for this, but if there is one, let me know
  3. I can't use Matrix with that, so I use [[(Double, Double)]]

@alejandro-isaza alejandro-isaza left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks! Just a few style comments.

Comment thread Sources/Surge/Matrix.swift Outdated
// https://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_lapack_examples/dgeev.htm
private func buildEigenVector(wi: [Double], v: [Double], result: inout [[(Double, Double)]]) {
let n = wi.count
for r in 0..<n {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not a fan of one-letter variable names, let use better names.

Comment thread Sources/Surge/Matrix.swift Outdated
// .0: The eigenvalues represented as an array of complex numbers
// .1: The left eigenvectors represented as a 2-dimensional array of complex numbers
// .2: The right eigenvectors represented as a 2-dimensional array of complex numbers
public func eigendecompostion(_ x: Matrix<Float>) -> ([(Float, Float)], [[(Float, Float)]], [[(Float, Float)]]) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Use three slashes for doc comments /// also use swift doc comment style. See https://nshipster.com/swift-documentation/

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's define a struct for the return type.

Comment thread Sources/Surge/Matrix.swift Outdated
// .0: The eigenvalues represented as an array of complex numbers
// .1: The left eigenvectors represented as a 2-dimensional array of complex numbers
// .2: The right eigenvectors represented as a 2-dimensional array of complex numbers
public func eigendecompostion(_ x: Matrix<Double>) -> ([(Double, Double)], [[(Double, Double)]], [[(Double, Double)]]) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same comments as above.

Comment thread Sources/Surge/Matrix.swift Outdated
// dgeev_ needs column-major matrices
var mat: [__CLPK_doublereal] = transpose(x).grid

var N1 = __CLPK_integer(x.rows)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

variable names should be lowercase, also let's use better names.

@loufranco

loufranco commented Feb 9, 2019

Copy link
Copy Markdown
Contributor Author

The build failure is because of strict lint issues with the 3-tuples I used

I'd like some guidance on the lint warning about using a tuple of 3 items. I could

  1. Suppress it
  2. Make a struct to hold the return
  3. Only return the right eigenvector (this is what numpy does), and use a 2-tuple -- this would make the function have a very analogous signature to numpy. I don't know how important having the left eigenvector is.

- better variable names
- use a struct for the decomposition result
- use standard Swift doc comments
@loufranco

Copy link
Copy Markdown
Contributor Author

@alejandro-isaza I implemented your suggestions.

@alejandro-isaza alejandro-isaza left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just a couple more things.

Comment thread Sources/Surge/Matrix.swift Outdated
/// - x: a square matrix
/// - Returns: a struct with the eigen values and left and right eigen vectors using (Double, Double)
/// to represent a complex number.
public func eigendecompostion(_ x: Matrix<Double>) -> MatrixEigenDecompositionResult<Double> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is a lot better. Let's make this function a verb. What about decompose? or eigenDecompose? or decomposeSpectrally? Also missing triple slash in the first three lines.

Comment thread Sources/Surge/Matrix.swift Outdated
let decompositionJobV = UnsafeMutablePointer<Int8>(mutating: ("V" as NSString).utf8String)
// Call dgeev to find out how much workspace to allocate
dgeev_(decompositionJobV, decompositionJobV, &matrixRowCount, &matrixGrid, &eigenValueCount, &eigenValueRealParts, &eigenValueImaginaryParts, &leftEigenVectorWork, &leftEigenVectorCount, &rightEigenVectorWork, &rightEigenVectorCount, &workspaceQuery, &workspaceSize, &error)
assert(error == 0, "Matrix not eigen decomposable")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Asserts are bad here because they will be ignored in release build which will probably make the below code crash. Let's make a enum EigenDecompositionError and throw that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I will fix -- I was trying to follow the conventions in the rest of the file (and Surge seems generally not to throw), but I agree that it's better.

- rename func to eigenDecompose
- fix some doc comments
- throw instead of asserting
- added a test for non-square matrices
@loufranco

Copy link
Copy Markdown
Contributor Author

@alejandro-isaza ok -- throw is in (with a test for non-square). As far as I can tell, there is no real matrix that isn't decomposable to complex results, but since DGEEV could return an error, I throw -- there is no test I could write to test it, though.

@alejandro-isaza alejandro-isaza merged commit a6dd5f6 into Jounce:master Feb 9, 2019
@alejandro-isaza

Copy link
Copy Markdown
Collaborator

Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants