Hacker News new | ask | show | jobs
by ianhorn 1828 days ago
I got bored with trying to find an analytical boost, but I benchmarked a couple IMO super readable python versions (basically what's in my original comment after making the (100+i)i change):

https://colab.research.google.com/drive/1ABrZJlm8pwB6_Sd6ayO...

On my macbook, using XLA's jit in python gave about a 12-15x speedup on CPU over OP's solution, which was pretty cool, but I'm too lazy to figure out how to install and benchmark Julia on my machine. Applying a 12-15x speedup would at least beat the Julia MT solution in OP, and you've got to admit `exp(CONST * sqrt(A**2 + A.T**2))` is a pretty clean way to do it.

Then I ran on whatever GPU colab decided to give me (a P100), and for just adding a decorator, it's a 1000x-1900x speedup (better as n goes up). Hence my current honeymoon period with jax. I love the speed vs readability tradeoff.

2 comments

> I'm too lazy to figure out how to install and benchmark Julia on my machine.

Assuming you're eager to try once you've found out:

You should be able to simply download and unpack a binary from: https://julialang.org/downloads/ I'd strongly recommend going with the current stable release (1.6.1).

To start the Julia REPL:

  bin/julia

To install packages:

  using Pkg
  Pkg.add("BenchmarkTools")
  Pkg.add("LoopVectorization")
then you can copy/paste code from eigenspaces link to discourse to run Julia benchmarks. E.g., you can copy/paste from https://discourse.julialang.org/t/i-just-decided-to-migrate-... if you define

  using LoopVectorization
  const var"@tvectorize" = var"@tturbo"
(because `@tvectorize` has since been renamed on the latest releases)
Also, note that Julia starts with only a single thread by default. You'd either need to add `-t4` when starting julia, e.g. `julia -t4`, or set the environmental variable `JULIA_NUM_THREADS=4` for 4 threads, for example.
Looks good, but I actually love that Julia gets at least the same performance right out of the box, with full interoperability and the great multiple dispatch logic.

Would be interesting to run your optimized code against the Julia optimized code that was linked to in this thread. Or run a Julia GPU benchmark as well.

As for loops versus vectorization - I personally am used to vectorized code as it has always been a requirement. Sometimes it makes sense to use (e.g. Matrix Algebra stuff).

On the other hand, I have also been in many situations where I could not vectorize my code. More code than I'm happy to admit includes list or dict comprehensions or even loops. Sure, not all performance critical. Nevertheless, the prospect of performance no matter what is pretty exciting.

Finally, threading and multiprocessing in python is a headache compared to Julia imo. Sometimes I just miss the good ol' "parfor" from Matlab.

All in all, Julia is a really appealing value proposition to people doing numeric computing.

> the great multiple dispatch logic

Curiously, as much as I love the Julia language, I cannot stand multiple dispatch. I find it extremely confusing, ugly, and downright disturbing. Why would you ever want two different functions with the same name? And if this is good, why stop here? Why not two different variables with the same name but different types? Depending on the context where they are used, the language could pick one or the other.

But this is what most languages do, except they have _singular_ dispatch. Every OOP language has different behaviour for different input types, except it only works for the _first_ input argument. Julia simply extends this to every argument.

How would you feel about having to write `sqrt_int32(x)`, `sqrt_int64(x)`, `sqrt_float64(x)`, `sqrt_rational_complex_float16(x)`, etc, etc, etc, etc, instead of just `sqrt`, and let dispatch or overloading take care of the different implementations?

> Every OOP language has different behaviour for different input types

Yeah. And I find OOP horrific.

> How would you feel about having to write `sqrt_int32(x)`, `sqrt_int64(x)`, `sqrt_float64(x)`,

What kind of savage wants the square root of an integer? I'd prefer if the language only had a single number type (maybe configurable at once by an external option) and a single sqrt function.

But if you talk about the general problem of naming functions differently according to their types, I feel that it's perfectly OK. A tiny price that I'm eager to pay for the large benefit of being able to identify which function is called just by looking at its name (and not at the---possibly yet undetermined---types of its arguments).

But this is precisely what Julia allows you to do.

Your function may be written for numeric, and you use your favorite kind exclusively.

Now person B from this thread comes along, using both ints and floats. Well guess what, your package still works seamlessly. And where it doesn't, it must be due to a particularity that you yourself don't care about. In any case, the function can then be extended without namespace issues. In other languages, one would have to rewrite your package since you are using an obscure numeric type which others don't agree with.

Consider for example how people have used solvers for differential equations with entirely new datatypes, simply because the compatibility comes for free.

I think it's really neat!

I think it's great!

> I'd prefer if the language only had a single number type (maybe configurable at once by an external option) and a single sqrt function.

If you meant a numeric single type class, like haskell's Num, I think it's a great option. If you mean a single numeric type, like javascript, it unfortunately leads to a bunch of issues. Integers and floats really are both necessary very frequently. For example floats to represent something like speed, and ints to represent your bank balance. And you need different sizes of them (like float32 vs float64) are still necessary in a ton of applications, so you'll need them eventually if you want the language/numerics library to be truly general purpose.

It's also a huge convenience to be able to apply e.g. `+` to arrays as well as numbers and other polymorphism niceties.

> What kind of savage wants the square root of an integer?

It comes up moderately frequently (e.g., in prime sieves). It's usually defined as the largest integer X whose square X^2 is no greater than N. Search any sufficiently large codebase (postgres or something) and you'll probably find one or more functions called something like "isqrt".

My favorite implementation just takes Newton's method and blindly applies it to integers. It happens to converge for at least one starting value.

good point! but notice that this is an entirely different function than flotaing-point sqrt; and it has, appropriately, a different name.
> I'd prefer if the language only had a single number type

> But if you talk about the general problem of naming functions differently according to their types, I feel that it's perfectly OK.

You and I have nothing in common in this entire world.

Why on earth would you even want to touch Julia with 12 lightyear stick? The whole point of Julia is diametrically opposite to your preferences.

Being opposed to multiple dispatch, polymorphism and generic programming, while 'liking' Julia, is similar to loving bycicles, but abhorring wheels.

But I really love Julia! I was seduced by the idea of "like octave, but with fast loops", which is exactly what I need and the interpreter pretty much lives to that ambition. Also I love the examples with single-letter greek variables, the "f.(x)" notation, everything. And the fact that it feels like a well thought out language for numerical computing, cleaner and more beautiful than matlab/octave, and not an ugly kludge like numpy.

The multiple dispatch and oo features are some unfortunate warts, but I can live with those. Following your analogy, I love bikes and Julia is an electrically assisted bike. Sure, I would prefer if it was lighter and without the stupid motor, but it's still a bike. Not like numpy which is a horse carriage.

> You and I have nothing in common in this entire world.

for one, I 100% agree with your views on variable naming elsewhere on this thread ;)