# Fun One Liners

It would be interesting to see an example.

I have the opposite view (but I recognize it is possible for rational people to disagree about these things, it is mostly a matter of taste). To make this concrete, consider the

e^{-\frac{1}{2} (X - \mu)^T \Sigma^{-1} (X - \mu)}

in the PDF of a normal distribution. For practical purposes, I would always introduce z = X - \mu and code it that way. I find code like this more maintainable.

2 Likes

That’s a good example - I would often prefer the “textbook” mathematical form in the code in such cases - having the code closer to the math helps readability, in my opinion. I don’t see why this would be more readable if broken up into several lines.

Though in this specific case, automatic elimination of common sub-expressions wouldn’t be enough - I would rewrite this completely to also avoid the creation of short-lived temporary arrays (esp. if \Sigma is smallish).

In practical code I would try to work with (ie store) the Cholesky decomposition \Sigma = LL^T, eg

exp(0.5 * sum(abs2, L \ (x .- mu)))


I think that most “textbook” formulas facilitate proof techniques, not computation (unless, of course, the textbook is on numerical methods ) So preserving them in code is not always a good choice. YMMV.

3 Likes

In practical code I would try to work with (ie store) the Cholesky decomposition

Yes, obviously, in this specific case.

I think that most “textbook” formulas facilitate proof techniques … So preserving them in code is not always a good choice

Certainly - not always. An you’re right, in cases like the above, as soon as a bit of linear algebra is concerned, the actual implementation one would choose is often very different from the textbook - and that’s a bit much to ask from the compiler

However, there are certainly also many cases where the only optimization that will happen is manual extraction of common sub-expression into variables. That, a compiler can do.

Of course it’s not just adding an “ispure” tag to a function - with multiple dispatch, the purity may be hard for the function’s author to guarantee, depending on what code the function uses internally. Still conventions like bang-functions may be sufficient to make this workable.

YMMV.

Indeed - i would be surprised if there wouldn’t be quite a lot of cases in which optimizations based on compiler knowledge about purity of functions would be beneficial.

My posting wasn’t intended as a feature request in any way, I was just wondering if there was work going on in this direction.

1 Like

I wouldn’t call this “not very well documented” https://docs.julialang.org/en/latest/base/base/#Base.@pure :

@pure gives the compiler a hint for the definition of a pure function, helping for type inference.

A pure function can only depend on immutable information. This also means a @pure function cannot use any global mutable state, including generic functions. Calls to generic functions depend on method tables which are mutable global state. Use with caution, incorrect @pure annotation of a function may introduce hard to identify bugs. Double check for calls to generic functions. This macro is intended for internal compiler use and may be subject to changes.

In particular, I think it is very clear that you can’t use generic functions inside @pure functions. Please notice that this is incompatible with your usage:

I think it’s OK to depend on implementation details in some private code or maybe even in public code if you are aware that is an implementation detail and hence cannot rely on the semver promises. For example, ForwardDiff.jl uses Threads.atomic_add! inside @generated generator which also is documented that it must be pure. Also, there are (many?) packages using @generated to hoist out argument checking to compile time. Since throw is a side-effect, this is arguably not a valid use case. CUDAnative.jl is mentioning that it can be a real trouble if you want to use it with GPU: https://juliagpu.gitlab.io/CUDAnative.jl/man/hacking/#Generated-functions-1

@NHDaly’s JuliaCon talk is a great summary of the current status on this topic and explaining why you can’t use @pure or @generated in this way safely:

Personally, I often just lift values to type domain as soon as possible and compute things using recursion.

5 Likes

Ha, I like the frog problem.

Here’s a progression of solutions:

Experimental solution:

frog2(n) = n==0 ? 0 : frog2(rand(0:n-1)) + 1
mean(frog2(10) for _ in 1:10^8)


Analytic solution:

frog3(n) = n==0 ? 0 : sum(1 + frog3(n-i) for i = 1:n) / n


Or with exact rational result:

frog3(n) = n==0 ? 0 : sum(1 + frog3(n-i) for i = 1:n) // n


And for the mathematicians:

frog4(n) = sum(1/i for i = 1:n)

3 Likes

Find indexes of elements in array b matching those of array a

I wonder if there is a built in method for this?
(m-> findfirst(x -> x = m ,b)).(a)

b= [ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8]
a = [1, 2, 6, 3]

julia> (m-> findfirst(x -> x >= m ,b)).(a)
4-element Array{Int64,1}:
3
4
8
5


I use this to bulk plot PDE solutions at particular times t as f(x,t) vs x

1 Like

indexin:

julia> b = [ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8];
a =  [1, 2, 6, 3];

julia> indexin(a, b)
4-element Array{Union{Nothing, Int64},1}:
3
4
8
5

5 Likes

Ok… cool, but is there is also a method returning the indexes of values close to the given ones like :

b= [-1, 0, 1.2, 2.1, 3.5, 4.87, 5.1, 6, 7, 8]
a = [1, 2, 6, 3]
julia> indexnear(a, b)
4-element Array{Union{Nothing, Int64},1}:
3
4
8
5


here i can simply use (m-> findfirst(x -> x >= m ,b)).(a)
how ever this solution is far from being perfect

EDIT: Find indexes of elements in array b close to those in array a
With the help of this thread
we can do:

(m-> findmin(abs.(a.-m))).(b)

1 Like

Here’s one I found funny,
2 ^ 64

1 Like

Why is it funny?

2 ^ 64

First of all the number 2 has type Int64
when you raise it to 64th power, it becomes a large number
but the first bit is about whether it is a negative number

so it represent a negative number in Int64

Also the largest number in Int64 is 2^64 - 1
just like the largest number in a byte is 2^8 - 1 (aka 255)

When in doubt use BigInt

julia> big(2)^64
18446744073709551616

4 Likes

I am in favour of a solutions thread. That is solutions you discovered on your own and think they are useful enough to share with the community and spark further discussions. It would superset one liners.

1 Like

@StevenSiew - I think it’s funny because a very large number is interpreted as zero. This thing called humor has a Personal element to it. It wasn’t expected to me - in Python if you do 2**100 you get a long/BigInt of the appropriate size.

@dataDiver - I like that idea. sharing nifty and elegant solutions could lead to a good learning experience and show off the actual power of Julia (which is not in 1 liners).

1 Like

Of course what you find funny can be subjective, just note that overflow behavior in Julia is documented very early in the manual:

https://docs.julialang.org/en/latest/manual/integers-and-floating-point-numbers/#Overflow-behavior-1

2 Likes

Well, I thought it was funny, even though I knew about integer overflow. It’s an odd and interesting way to write zero. Seems to be in the spirit of the thread.

5 Likes

r = 0; while true print("$r "); r = 1//(1 + floor( r ) - r + trunc( r )) end This is an enumeration of the rational numbers which I learned on this blog. The creation of numbers out of nothing. 3 Likes Really cool! But the code didn’t run for me I wrote it like this and it did though r = 0 while true global r print("$r "); r = 1//(1 + floor( r ) - r + trunc( r ))
end


Neat one though!!

2 Likes

One of my favorite “golfs” I like to show people new to Julia is the dot product of vectors:

dot(x,y) = x'y


For example, if you want to normalize a vector so it has Euclidean norm 1:

unitize(x) = x/√(x'x)
`

Before someone lectures me about golfing: I’m aware it’s not good practice. That doesn’t take away the fun!

8 Likes

@TheCedarPrince Nice one!

@Deidre_House no lectures just fun one liners 2 Likes