# Specifying the numerical precision and ranks of the array arguments of a function

Following is a Fortran function for matrix vector multiplication. It specifies that `a(:,:)` is a rank-2 array of 64-bit floats and that `x(:)` and `b(:)` are rank-1 arrays of 64-bit floats.

``````function matrix_vec_mult(a,x) result(b)
! return the product of matrix a and vector x
use iso_fortran_env, only: real64
real(kind=real64), intent(in) :: a(:,:)
real(kind=real64), intent(in) :: x(:)
real(kind=real64)             :: b(size(a,1))
integer                       :: i
do i=1,size(a,1)
b(i) = sum(a(i,:)*x)
end do
end function matrix_vec_mult
``````

I know that arguments can be declared `Array{Number}` in Julia, but is it possible to be as specific as the code above regarding argument rank and numerical precision?

The `intent(in)` designation means that the argument cannot be changed within the procedure. Is there a Julia analog for that?

Yes, that would be `Array{Float64, 2}` and `Array{Float64, 1}` respectively (or the aliases `Matrix{Float64}` and `Vector{Float64}`).

No, this isnâ€™t really possible in Julia. Immutable `struct`s can help organize data and control mutability, but thereâ€™s nothing you can do in a function definition to enforce that the function wonâ€™t mutate some mutable input (other than documenting that fact).

5 Likes

Note that while you can specify what types your functions take, there is not a performance advantage in doing so.

``````function matrix_vec_mult(a,x)
b = Vector{eltype(a)}(undef, size(a,1))
for i=1:size(a,1)
b[i] = sum(a[i,:]*x)
end
return b
end
``````

will have the exact same performance as

``````function matrix_vec_mult(a::Matrix{Float64},x::Vector{Float64})
b = Vector{Float64}(undef, size(a,1))
for i=1:size(a,1)
b[i] = sum(a[i,:]*x)
end
return b
end
``````

because Julia always compiles a specialized version of your code for the argument types provided.

5 Likes

Note that this will give an error in Julia, because a 1d slice like `a[i,:]` creates a 1d array, not a row vector.

You can use `sum(a[i,:] .* x)`, though this is suboptimal because it creates a temporary array before summing. To avoid that temporary array, you can use `dot(a[i,:], x)` from the `LinearAlgebra` package (noting that `dot` conjugates the first argument if it is complex), or `a[i,:]' * x` (same as `dot`) or `transpose(a[i,:]) * x` (which doesnâ€™t conjugate). `a[i,:]` also creates a copy for the slice, but you can avoid that by putting `@views` (e.g. before `function`).

(Of course, in reality you would just use `b = a * x` for a matrixâ€“vector multiplication.)

3 Likes