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

Avoid overflow in p norms #12571

Merged
merged 1 commit into from
Sep 3, 2015
Merged

Avoid overflow in p norms #12571

merged 1 commit into from
Sep 3, 2015

Conversation

andreasnoack
Copy link
Member

Use division instead of multiplication with reciprocal when scaling elements in vecnorm methods. This fixes JuliaLang/LinearAlgebra.jl#222 and supersedes #11789. The logic used here is a little different from the other generic_vecnorms. I try to use the element type of the array when the input is an AbstractVector{T<:Number} and for general iterables I have to require that they are non-empty.

cc: @stevengj

@stevengj
Copy link
Member

Didn't the old implementation work for Array{T} for any T that defines norm(x::T)? See #11043. (I should have added a test case for that, grrr.) The new implementation loses this because it requires zero(T) (not to mention abs instead of norm); I don't think that should be necessary.

@stevengj stevengj added the linear algebra Linear algebra label Aug 11, 2015
@andreasnoack
Copy link
Member Author

The new version doesn't require zero(T). It only uses zero(T) when T<:Number. For all other element types it uses zero(x[1]).

@andreasnoack
Copy link
Member Author

...but I'm fine with using norm instead of abs. I'll change that now.

@stevengj
Copy link
Member

Can you add a test case for the vecnorm of an array of arrays, if we don't have one yet?

end
return convert(T, maxabs * sqrt(sum))
scale = zero(norm(x[1]))
Copy link
Member

Choose a reason for hiding this comment

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

It's kind of annoying to compute norm(x[1]) twice in this case. Maybe add an i0 argument to generic_vecnorm2 and loop from i = i0:n. That way you can pass i0 == 2 to avoid recomputing the first element, which can be passed via ssq.

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 don't think norm will actually be computed here. E.g. for a Vector{Complex{Float64}} I get that

julia> @code_llvm zero(norm(x2[1]))

define double @julia_zero_21182(double) {
top:
  ret double 0.000000e+00
}

Copy link
Contributor

Choose a reason for hiding this comment

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

@code_llvm compute the argument before getting its type.

Copy link
Contributor

Choose a reason for hiding this comment

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

Even with inbounds,

julia> a = Complex128[1, 2, 3]
3-element Array{Complex{Float64},1}:                                              
 1.0+0.0im                                                                        
 2.0+0.0im                                                                        
 3.0+0.0im                                                                        

julia> f(x) = (@inbounds v = zero(norm(x[1])); v)
f (generic function with 1 method)

julia> @code_llvm f(a)

define double @julia_f_21134(%jl_value_t*) {
top:
  %1 = alloca %Complex.12, align 8
  %2 = bitcast %jl_value_t* %0 to %Complex.12**
  %3 = load %Complex.12** %2, align 8
  %4 = load %Complex.12* %3, align 8
  store %Complex.12 %4, %Complex.12* %1, align 8
  %5 = call double @julia_norm_21121(%Complex.12* %1)
  ret double 0.000000e+00
}

I don't think type inference or llvm is smart enough to figure out norm(::Complex) is effect free. There's even more junk emitted without @inbounds.

Copy link
Member

Choose a reason for hiding this comment

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

I'm mostly worried about it for something like an array of matrices, where norm is expensive.

@StefanKarpinski
Copy link
Member

@stevengj, should we just merge this and fix the issues in a separate change?

@andreasnoack
Copy link
Member Author

Hold on a bit. I'll add the tests @stevengj asked for and there might also be few other adjustments based on the Slack discussion this evening.

@staticfloat
Copy link
Member

@andreasnoack bumping this since it's slated for 0.4.

@andreasnoack
Copy link
Member Author

I'm on it. I've been reading up on why BLAS implementation and some critique of it. Scaling all elements even when it's not necessary is expensive. I might just fix the overflow problem problem for now and then we can reconsider the algorithm in 0.5.

…cnorm2

to avoid potential overflow and fewer rounding errors. Fixes #11789.

Make sure that norm(Number) is inlined.
@andreasnoack
Copy link
Member Author

This one works now. I've patched the existing versions to handle underflow without being dead slow because of the division, i.e. the value are only scaled when necessary. This is also the reason to avoid the BLAS implementation because it scales even when it is not necessary and therefore it is very slow.

cc: @stevengj

@stevengj
Copy link
Member

stevengj commented Sep 3, 2015

LGTM.

andreasnoack added a commit that referenced this pull request Sep 3, 2015
@andreasnoack andreasnoack merged commit 097801b into master Sep 3, 2015
@andreasnoack andreasnoack deleted the anj/nrm2 branch September 3, 2015 19:55
stevengj added a commit to stevengj/julia that referenced this pull request Sep 3, 2015
@stevengj
Copy link
Member

stevengj commented Sep 3, 2015

Oh, darn it, I forgot to check whether you added a test for the array-of-arrays case (you didn't) like I had suggested.

It looks like you broke norm for this case, because you call one, which isn't defined for a general Banach space. e.g. norm(Vector{Int}[[1,2], [3,4]]) no longer works. This is a regression, and needs to be fixed.

@andreasnoack
Copy link
Member Author

I'll look into it.

Den torsdag den 3. september 2015 skrev Steven G. Johnson <
notifications@github.com>:

Oh, darn it, I forgot to check whether you added a test for the
array-of-arrays case (you didn't).

It looks like you broke norm for this case, because you call one, which
isn't defined for a general Banach space. e.g. norm(Vector{Int}[[1,2],
[3,4]]) is broken.


Reply to this email directly or view it on GitHub
#12571 (comment).

stevengj added a commit to stevengj/julia that referenced this pull request Sep 3, 2015
@stevengj
Copy link
Member

stevengj commented Sep 3, 2015

I have PR almost ready.

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

Successfully merging this pull request may close these issues.

Error in 2-norm computation
5 participants