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

Reenable and fix example 5.5 from Smiley et al. #153

Merged
merged 7 commits into from
Jun 26, 2020

Conversation

gwater
Copy link
Contributor

@gwater gwater commented Apr 26, 2020

No description provided.

@gwater
Copy link
Contributor Author

gwater commented Apr 26, 2020

fix for #86

@gwater
Copy link
Contributor Author

gwater commented Apr 26, 2020

unfortunately, the example takes to long to solve and some CI tests time out. So we might have to create a faster test for CI

@gwater
Copy link
Contributor Author

gwater commented Apr 26, 2020

implements the idea described in JuliaArrays/StaticArrays.jl#450

J = jacobian(X)

if contains_zero(det(J))
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this very expensive? This should basically come out of the \ or LU factorization.

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 cant imagine the determinant is as expensive as LU - its just a fixed number of multiplicaitons and additions without any memory allocations

Copy link
Member

Choose a reason for hiding this comment

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

As far as I understand, the determinant does exactly an LU decomposition.

Copy link
Member

Choose a reason for hiding this comment

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

(ah, maybe not if this is for small StaticArrays?)

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Collaborator

Choose a reason for hiding this comment

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

The fact that this check is even necessary is disturbing as we overload \ for intervals with custom methods in

https://github.com/JuliaIntervals/IntervalRootFinding.jl/blob/master/src/linear_eq.jl

Either something is broken there or somehow the wrong method is picked.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe line 165 needs to have StaticVector instead of StaticArray?

We should definitely test if this is actually getting called.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

maybe it makes more sense to call gaussian_elimination explicitely (instead of the \ operator) to make sure and obvious that no external algorithm should be called here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The fact that this check is even necessary is disturbing as we overload \ for intervals with custom methods in

https://github.com/JuliaIntervals/IntervalRootFinding.jl/blob/master/src/linear_eq.jl

Either something is broken there or somehow the wrong method is picked.

I can confirm that the internal method is not getting called – in fact it is broken for StaticArrays. And fixing the Array / Vector mixup is not sufficient either…

Copy link
Member

Choose a reason for hiding this comment

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

Are we just not actually importing \ from Base?

@gwater
Copy link
Contributor Author

gwater commented Apr 27, 2020

Ok, given that there apparently is no way to test whether LU decomposition will work, I dont see a solution. The fundamental problem remains that IntervalArithmetic tolerates silent failures in external algorithms. I spent a few hours generalizing (and cleaning up) IntervalRootFinding to support NumberIntervals and then the solution is easy:

function 𝒩(f::Function, jacobian::Function, X::AbstractVector{T}, α) where T # multidimensional Newton operator
    m = T.(mid.(X, α))
    J = jacobian(X)
    try
        return convert(typeof(X), m .- (J \ f(m)))
    catch
        return X  Inf
    end
end

I've tested it: The exception is triggered (disturbingly often) and eventually all roots in Smiley 5.5 are discovered.

@gwater
Copy link
Contributor Author

gwater commented Apr 27, 2020

ok, this version uses the internal algorithm and finally finds all the roots for Smiley 5.5

@gwater gwater force-pushed the dev_smiley55 branch 2 times, most recently from 623fff3 to 39994d9 Compare April 28, 2020 08:36
@gwater
Copy link
Contributor Author

gwater commented Apr 28, 2020

not sure I trust the internal solver – for the matrix discussed above, it basically just returns this hard-coded value from

x .= -1e16..1e16

@gwater
Copy link
Contributor Author

gwater commented Apr 28, 2020

not sure I trust the internal solver – for the matrix discussed above, it basically just returns this hard-coded value from

x .= -1e16..1e16

It's also breaking the Julia naming convention – this function is marked as mutating but it doesn't

function gauss_elimination_interval!(x::AbstractArray, A::AbstractMatrix, b::AbstractArray; precondition=true)

@gwater
Copy link
Contributor Author

gwater commented Apr 28, 2020

cleaned up the commit log a bit. this PR contains a few more changes than strictly necessary, lmk if I should separate them into other PRs

Copy link
Member

@dpsanders dpsanders left a comment

Choose a reason for hiding this comment

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

Many thanks for fixing this and sorry for the long delay.

I added a couple of comments but other than that LGTM!

test/roots.jl Outdated
@@ -62,7 +62,7 @@ end

# Bisection
rts = roots(f, X, Bisection, 1e-3)
@test length(rts) == 4
Copy link
Member

Choose a reason for hiding this comment

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

I do get 4 boxes here (even though there are only 2 roots).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it gives an incorrect answer. Marking it as @test_broken makes transparent that Bisection is unreliable and probably should never be used in practise. In addition, it will notify us if Bisection ever starts to give the correct result here. (I admit, this is not really related to the topic of this PR–I think I just noticed this inconsistency while I was working on it.)

Copy link
Member

@dpsanders dpsanders Jun 24, 2020

Choose a reason for hiding this comment

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

I see what you mean, but I don't agree that the result is unreliable. It is reliably giving you a set of boxes that are guaranteed to contain all of the roots in the original box, and correctly telling you that it is unable to guarantee whether or not there are actually roots there.

The test is testing what the function returns, not what we would like it to ideally return ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, that makes sense. But testing for the result 4 seems overly specific if any number above 2 would acceptable. Maybe it would be better to test that the exact solutions are contained in whatever boxes are returned? I've created a separate PR #156 for that.

A = similar(A)
b = similar(b)
A .= _A
b .= _b
Copy link
Member

Choose a reason for hiding this comment

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

Is this different / better than _A = A; A = copy(_A)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I recall correctly, calling similar() on a StaticArray gives a MutableArray which is required for the setindex!() calls below.

@dpsanders dpsanders merged commit 9272e39 into JuliaIntervals:master Jun 26, 2020
@dpsanders
Copy link
Member

Thanks a lot!

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.

3 participants