Charlie Harvey

Seven More Languages: Julia Day One

Today, I began working on learning a little bit of Julia. On the Julia website, the language is described as an high-level, high-performance dynamic programming language for technical computing, with syntax that is familiar to users of other technical computing environments. Which sounds pretty nice.

The first blog that the developers posted announcing Julia to the world, Why we created Julia describes the goals of the language

We want the speed of C with the dynamism of Ruby. We want a language that’s homoiconic, with true macros like Lisp, but with obvious, familiar mathematical notation like Matlab. We want something as usable for general programming as Python, as easy for statistics as R, as natural for string processing as Perl, as powerful for linear algebra as Matlab, as good at gluing programs together as the shell

That is sounding pretty interesting not to mention pretty ambitious. It will be good to see in the coming days if Julia lives up to that promise not to mention meeting some of the other goals the developers have set.

The first day is a now familiar trawl through the type system and the various operators of the language.

Of particular interest were the fancy arrays that Julia provides and which give native support for linear algebra operations — think APL. Linear algebra is very much not my area of expertise, but if that was something you needed to do a lot of it would certainly be handy to have it baked into the language.

Exercises

Easy exercises

Use typeof to find the types of types. Try Symbol or Int64. Can you find the types of operators?

OK, fine Types are DataTypes and operators are just Functions.

julia> typeof(+) Function julia> typeof(Symbol) DataType julia> typeof(Int64) DataType julia> typeof(-) Function julia> typeof(typeof) Function

Create a typed dict with keys that are symbols and values that are floats. What happens when you add ::thisis => :notanumber to the Dict.

julia> mydict = [:a => 1, :b => 2, :c => 3] Dict{Symbol,Int64} with 3 entries: :b => 2 :c => 3 :a => 1 julia> mydict[:thisis]=:notanumber ERROR: `convert` has no method matching convert(::Type{Int64}, ::Symbol) in setindex! at ./dict.jl:551

It looks like Julia has a crack at coercing the types, but gives up when it cannot or if we lose data. For example:

julia> mydict[:thisis]=:notanumber ERROR: `convert` has no method matching convert(::Type{Int64}, ::Symbol) in setindex! at ./dict.jl:551 julia> mydict[:thisis]=9.0 9.0 julia> mydict[:thisis]=9.23 ERROR: InexactError() in setindex! at ./dict.jl:556

Create a 5x5x5 array where each 5x5 block in the first 2 dimensions is a single number but that number increases for each block.

OK well I initialized an all zero array, then populated it in a for loop. There might be a way to do this in one step I guess.

a = fill(0,(5,5,5)) for i in 1:5 a[:,:,i]=i end println(a)

Run some arrays of various types through functions like sin and round. What happens?

Nice. It basically does what I think it should -- applying the function to each element of the array and type failing where it should.

julia> a=fill(1.9,(2,3)) 2x3 Array{Float64,2}: 1.9 1.9 1.9 1.9 1.9 1.9 julia> sin(cos(a)) 2x3 Array{Float64,2}: -0.317687 -0.317687 -0.317687 -0.317687 -0.317687 -0.317687 julia> a=fill(:hat,(2,3)) 2x3 Array{Symbol,2}: :hat :hat :hat :hat :hat :hat julia> sin(cos(a)) ERROR: `cos` has no method matching cos(::Array{Symbol,2})

Medium exrcises

Create a matrix and multiply it by its inverse. Hint: inv computes the inverse of a matrix, but not all matrices are invertible.

I had a look at the post on matix inversion on math is fun.

The inverse of a matrix is kind of like the reciprocal of a number and used if you want to do something like division. In order to have an inverse, the matrix better have the same number of rows and columns and a non-zero determinant. You can find the determinant using det(M) in Julia.

Note here that Julia figures out that I will need Float64s in the resulting matrix for the invertible matrix and sorts that out for me. Cool.

julia> noninvertibleNotSquare = [1 1 2; 1 1 2] 2x3 Array{Int64,2}: 1 1 2 1 1 2 julia> noninvertibleZeroDeterminant = [1 1; 1 1] 2x2 Array{Int64,2}: 1 1 1 1 julia> det(noninvertibleZeroDeterminant) 0.0 julia> inv(noninvertibleZeroDeterminant) ERROR: SingularException(2) in inv at ./linalg/lu.jl:149 in inv at ./linalg/dense.jl:328 julia> invertible = [2 4; 6 8] 2x2 Array{Int64,2}: 2 4 6 8 julia> det(invertible) -8.0 julia> inv(invertible) 2x2 Array{Float64,2}: -1.0 0.5 0.75 -0.25

Create 2 dictionaries and merge them. Hint: Look up merge in the manual.

julia> d1 = {:cider => 9, :beer => 7, :coffee => 8} Dict{Any,Any} with 3 entries: :beer => 7 :coffee => 8 :cider => 9 julia> d2 = {:wine => 2, :baileys => -1} Dict{Any,Any} with 2 entries: :wine => 2 :baileys => -1 julia> merge(d1,d2) Dict{Any,Any} with 5 entries: :beer => 7 :coffee => 8 :wine => 2 :cider => 9 :baileys => -1

sort and sort! both operate on arrays. what is the difference between them?

Just like Ruby, sort will return a sorted copy of your array and sort! will sort it in place.

Hard exercises

Brush off your linear algebra knowledge and construct a 90-degree rotation matrix. Try rotating the unit vector [1;0;0] by multiplying it by your matrix.

OK, this was pretty hard, mainly because I don’t know linear algebra. However the interwebs provided.

I had initially thought, after reading the Wikipedia article, that I would have to be partially applying the functions or something. But then I watched a much more useful explanation on Khan academy. Here is the video.

Once I grokked that, it seemed to me like the transformation matrix for rotating 90 degrees about the x-axis ought to be something like this, because my theta is 90 degrees and everything else falls out of that.

julia> x90antiClockwise = [1 0 0; 0 cos(90) sin(90); 0 -sin(90) cos(90)] 3x3 Array{Float64,2}: 1.0 0.0 0.0 0.0 -0.448074 0.893997 0.0 -0.893997 -0.448074

julia> y90antiClockwise = [ cos(90) 0 sin(90); 0 1 0; -sin(90) 0 cos(90) ] 3x3 Array{Float64,2}: -0.448074 0.0 0.893997 0.0 1.0 0.0 -0.893997 0.0 -0.448074 julia> z90antiClockwise = [ cos(90) -sin(90) 0; sin(90) cos(90) 0; 0 0 1 ] 3x3 Array{Float64,2}: -0.448074 -0.893997 0.0 0.893997 -0.448074 0.0 0.0 0.0 1.0

Now multiplying the unit vecotr by my various matrices goes thus.

julia> x90antiClockwise * unit 3-element Array{Float64,1}: 1.0 0.0 0.0 julia> y90antiClockwise * unit 3-element Array{Float64,1}: -0.448074 0.0 -0.893997 julia> z90antiClockwise * unit 3-element Array{Float64,1}: -0.448074 0.893997 0.0

It seems to make sense. In my own imagination at least. Any mathemeticians reading?

Conclusion

Day one was pretty easy going apart from the linear algebra bit. Nonetheless Julia seemed a very nicely thought out and sensible language. It felt familiar and straightforward to use and would clearly be super productive for scientific computing work.

It is a little early to be able to say for sure that I am a fan, however early indications are good, especially the glimpses we have had of a nice type system that doesn’t get in your way too much..


Comments

  • Be respectful. You may want to read the comment guidelines before posting.
  • You can use Markdown syntax to format your comments. You can only use level 5 and 6 headings.
  • You can add class="your language" to code blocks to help highlight.js highlight them correctly.

Privacy note: This form will forward your IP address, user agent and referrer to the Akismet, StopForumSpam and Botscout spam filtering services. I don’t log these details. Those services will. I do log everything you type into the form. Full privacy statement.