Skip to content
This repository has been archived by the owner on Nov 25, 2018. It is now read-only.

Add Jacobian #33

Merged
merged 4 commits into from
Apr 19, 2016
Merged

Add Jacobian #33

merged 4 commits into from
Apr 19, 2016

Conversation

vladimir-ch
Copy link
Member

No description provided.

@vladimir-ch vladimir-ch force-pushed the jacobian branch 5 times, most recently from 2d2b4a2 to 719f21c Compare April 6, 2016 00:59
@vladimir-ch
Copy link
Member Author

This is ready for review. PTAL @btracey

fmt.Printf("J ≈ %v\n", mat64.Formatted(jac, mat64.Prefix(" ")))

// Output:
// J ≈ ⎡ 0.9999999999917482 0 0⎤
Copy link
Member

Choose a reason for hiding this comment

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

Maybe make it %0.4v or %0.6v? This level of precision might not be robust to different go editions.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done with %0.6v.

@@ -44,3 +45,24 @@ func ExampleDerivative() {
// f'(0) ≈ 0.9999998333333416
// f''(0) ≈ -2.999999981767587
}

func ExampleJacobian() {
f := func(y, x []float64) {
Copy link
Member

Choose a reason for hiding this comment

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

maybe f := func(output, input)? The current code is clear for you and me, but for those who aren't aware of the convention

Copy link
Member Author

Choose a reason for hiding this comment

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

Changed to f := func(dst, x []float64) {, how about it?

Copy link
Member

Choose a reason for hiding this comment

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

Good.

@vladimir-ch vladimir-ch force-pushed the jacobian branch 2 times, most recently from 62475ff to 7d9ad67 Compare April 13, 2016 06:22
//
// Jacobian panics if dst is not nil and its size is not m × len(x), or if the
// derivative order of the formula is not 1.
func Jacobian(dst *mat64.Dense, f func(y, x []float64), m int, x []float64, settings *JacobianSettings) *mat64.Dense {
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure if I like m being singled out in the signature but I see no other simpler way of communicating it to the function. I thought about binding it with f in a struct like

type VectorFunction struct {
    Func func(dst, x []float64)
    M    int
    N    int
}

and changing Jacobian to
func Jacobian(dst *mat64.Dense, f VectorFunction, x []float64, settings *JacobianSettings) *mat64.Dense
but perhaps it's not worth it. On the other hand the dimensions would be explicit and together with f.

Copy link
Member

Choose a reason for hiding this comment

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

The other option is to require that dst is non nil. This way the proper size information is contained in dst.Dims()

Copy link
Member Author

Choose a reason for hiding this comment

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

I was looking for something consistent with how Gradient behaves but yes, this would be a good option.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll leave it for another PR.

Copy link
Member

Choose a reason for hiding this comment

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

Okay.

@vladimir-ch vladimir-ch force-pushed the jacobian branch 3 times, most recently from 4647480 to ef3d31d Compare April 13, 2016 08:10
@vladimir-ch
Copy link
Member Author

PTAL @btracey

xcopy[job.j] += job.pt.Loc * step
f(y, xcopy)
} else {
once.Do(func() {
Copy link
Member

Choose a reason for hiding this comment

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

This looks correct, and I assume you tested with -race?

Copy link
Member

Choose a reason for hiding this comment

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

See above note.

Copy link
Member Author

Choose a reason for hiding this comment

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

I assume you tested with -race?

Now I have.

@vladimir-ch
Copy link
Member Author

PTAL @btracey

if pt.Loc == 0 {
hasOrigin = true
originCoeff = pt.Coeff
if origin == nil {
Copy link
Member

Choose a reason for hiding this comment

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

Are you sure you tested with -race? This looks like a race condition to me. Multiple workerOrigin goroutines can be started, since making the origin non-nil does not happen before any part of the loop. Thus origin can be set several times, and it's not clear which will be the last.

This is easily fixed by changing the loop to if !hasOrigin, and then setting it below launching the goroutine.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I did test with -race but no test has a formula with multiple pt.Loc == 0. I silently assumed that locations (here only origin matters) in formulas are unique, although we do not check it, enforce it, or say nothing in respect in the docs. The formula d^k f(x) ≈ ... in the comment for Formula does not rule out repeated locations even with different coefficients, it just leads to unnecessary function evaluations.

I made a change that avoids (hopefully, please check) the racy behaviour and always uses the last occurrence of origin location in a Formula but it doesn't feel satisfactory, the rest of the logic still assumes that origin is not repeated. The simplest thing to do would be prohibit repeated origin locations in formulas completely.

@vladimir-ch vladimir-ch force-pushed the jacobian branch 2 times, most recently from abef9f5 to 7b7dbc1 Compare April 18, 2016 06:07
@btracey
Copy link
Member

btracey commented Apr 18, 2016

LGTM

I agree we should check about repeated locations. In the meantime, good to be defensive about race conditions.

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

Successfully merging this pull request may close these issues.

3 participants