Monday, August 28, 2017

Julia - Language - Functions - Passing arrays as Arguments

Normally, if we want to use the elements of an array in a function as input, we do this by using loops. Julia provides us a cleaner way. For this, we use the map function. Let us see the usage of map function:

$ julia
               _
   _       _ _(_)_     |  A fresh approach to technical computing
  (_)     | (_) (_)    |  Documentation: https://docs.julialang.org
   _ _   _| |_  __ _   |  Type "?help" for help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 0.6.0 (2017-06-19 13:05 UTC)
 _/ |\__'_|_|_|\__'_|  |  Official http://julialang.org/ release
|__/                   |  x86_64-pc-linux-gnu

julia> inputArr = [-3,-2.5,-2,-1.5,-1,-0.5,0,0.5,1.0,1.5,2.0,2.5,3];

julia> function mySquare(a)
                      return a*a
                     end
mySquare (generic function with 1 method)




Now Let us map the array to the mySquare function:

julia> map(mySquare,inputArr)
13-element Array{Float64,1}:
 9.0 
 6.25
 4.0 
 2.25
 1.0 
 0.25
 0.0 
 0.25
 1.0 
 2.25
 4.0 
 6.25
 9.0 

julia> 


Voila! We have recieved the squared outputs of the all the values in the array without using a loop. But, mapping is not always required some inbuilt Julia functions do element wise operations on arrays anyways. It is also a lot faster. In the first example we will map the array of integers from 1 to 10000 to the trigonometric sine function. We will use @time macro to time how long the mapping takes and then repeat the exercise using the inbuilt element-wise operation of the sine function. 


julia> map(sin,collect(1:10))
10-element Array{Float64,1}:
  0.841471
  0.909297
  0.14112 
 -0.756802
 -0.958924
 -0.279415
  0.656987
  0.989358
  0.412118
 -0.544021



julia> sin.(collect(1:10))
10-element Array{Float64,1}:
  0.841471
  0.909297
  0.14112 
 -0.756802
 -0.958924
 -0.279415
  0.656987
  0.989358
  0.412118
 -0.544021

julia>

Referhttps://docs.julialang.org/en/stable/manual/functions/#man-vectorized-1
Let us time these function using the @time macro.

julia> @time map(sin,collect(1:100000000));
 46.356702 seconds (11 allocations: 1.490 GiB, 0.40% gc time)

julia> @time sin.(collect(1:100000000));
 46.524224 seconds (33 allocations: 1.490 GiB, 0.34% gc time)

julia> 


Now, say we create an array and tuple of two elements:

julia> array_2inp = [3,4]
2-element Array{Int64,1}:
 3
 4

julia> tuple_2inp = (3,4)
(3, 4)

julia> 


We have a function which accepts 2 inputs as arguments:

julia> function LinearCompute(x,y)
              5*x+2*y
              end
LinearCompute (generic function with 1 method)

julia>

Now, let us pass the array and tuple to the function:

julia> LinearCompute(array_2inp)
ERROR: MethodError: no method matching LinearCompute(::Array{Int64,1})
Closest candidates are:
  LinearCompute(::Any, ::Any) at REPL[4]:2

julia> LinearCompute(tuple_2inp)
ERROR: MethodError: no method matching LinearCompute(::Tuple{Int64,Int64})
Closest candidates are:
  LinearCompute(::Any, ::Any) at REPL[4]:2

julia> 


Errors are received. To avoid this problem, we can use Ellipses or splat:

julia> LinearCompute(array_2inp...)
23

julia> LinearCompute(tuple_2inp...)
23

julia> 

We have received the correct output. 

With the exception of numbers and characters (or other plain data), values of arguments are passed by reference only and are not copied. They can therefore be altered. We find a good example in arrays. Have a look at this example:

julia> function add_myEle(a)
              push!(a,14)
              end
add_myEle (generic function with 1 method)

julia>

Here, push with a bang means that I am going to alter the array.

julia> add_myEle(array_2inp)
3-element Array{Int64,1}:
  3
  4
 14

julia> array_2inp
3-element Array{Int64,1}:
  3
  4
 14

julia> 


No comments:

Post a Comment