Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Julia: Making a type for a specific size of vector

I am trying to define a type (structure?) in Julia for a vector with three elements. I think the closest thing I found Optimally passing dimensions of fixed size array in julia and Declare the size of an array attribute in a type definition, however these are pre-0.6 since immutables are no longer a thing. Also, it just seems wrong.

The use case is that I know the size of the vectors my function will be taking and want to have

function myFunc(v::threeVec,u::threeVec)
    Do stuff to u and v
end

Further searching led me constructors. https://docs.julialang.org/en/stable/manual/constructors/ In particular I saw the example

struct OrderedPair
           x::Real
           y::Real
           OrderedPair(x,y) = x > y ? error("out of order") : new(x,y)
       end

However this is a separate object, and even then, I'm not sure how I'd pass something like that into a function. I considered instead using triples since those have type Tuple(Int,Int,Int) however I'm going to be doing vector/matrix arithmetic on u and v so I'm rather not have to convert them.

I could have the vector length checked inside the function, but I read in the tips that its preferred that you use types for this due to the dispatcher. For this particular function, that is a reasonable way of doing it in this case, but in other use cases this might not be such a great idea so I'd like to do it the "right way" now.

like image 562
Nero gris Avatar asked Jul 06 '18 21:07

Nero gris


People also ask

How do you write a vector in Julia?

A Vector in Julia can be created with the use of a pre-defined keyword Vector() or by simply writing Vector elements within square brackets([]). There are different ways of creating Vector. vector_name = [value1, value2, value3,..] or vector_name = Vector{Datatype}([value1, value2, value3,..])

How do you type in Julia?

You can get the type of any Julia object o by typeof(o) . In your line of code all dots just mean "apply the operation element-wise". Therefore the types (and sizes) don't change.

What is mutable struct in Julia?

type and immutable are valid up to julia 0.6, mutable struct and struct are the names of the same objects in julia 0.6 and forward. mutable in mutable struct means that the fields can change - which is actually fairly rarely used so being immutable is the default. mutable struct 's are slower than struct s.

How do you create a matrix in Julia?

Julia provides a very simple notation to create matrices. A matrix can be created using the following notation: A = [1 2 3; 4 5 6]. Spaces separate entries in a row and semicolons separate rows. We can also get the size of a matrix using size(A).


1 Answers

There are many ways to deal with this type of scenario; I'll outline a few of them below based on the ideas you provided.

Option 1: StaticArrays

The StaticArrays.jl package provides support for fixed-length arrays.

using StaticArrays
const ThreeVec{T} = SVector{3,T}

function myFunc(u::ThreeVec, v::ThreeVec)
    u .+ v  # example functionality
end

This implementation allows myFunc to be called only when both arguments are SVectors of length 3.

julia> myFunc(SVector(1, 2, 3), SVector(4, 5, 6))
3-element SArray{Tuple{3},Int64,1,3}:
 5
 7
 9

julia> myFunc(SVector(1, 2, 3), SVector(4, 5))
ERROR: MethodError: no method matching myFunc(::SArray{Tuple{3},Int64,1,3}, ::SArray{Tuple{2},Int64,1,2})
Closest candidates are:
  myFunc(::SArray{Tuple{3},T,1,3} where T, ::SArray{Tuple{3},T,1,3} where T) at REPL[13]:2

It's also possible to define a custom type with an inner constructor to assert that the length is correct. However, in addition to potential inefficiencies, this will require that you overload various methods to support your custom type, which StaticArrays already handles.

Option 2: Tuples

Depending on what vector/matrix arithmetic you plan on performing, it's possible that tuples will already support the functionality natively through broadcasting. For example, although tuples can't be added, addition can be broadcasted over their elements.

julia> u = (1, 2, 3);
       v = (4, 5, 6);

julia> u + v  # not allowed
ERROR: MethodError: no method matching +(::Tuple{Int64,Int64,Int64}, ::Tuple{Int64,Int64,Int64})
Closest candidates are:
  +(::Any, ::Any, ::Any, ::Any...) at operators.jl:502
Stacktrace:
 [1] top-level scope at none:0

julia> u .+ v  # element-wise broadcasting
(5, 7, 9)

Option 3: Runtime Error

If you would like to operate on the built-in Vector type, you can simply throw an error whenever the input is invalid, moving your error handling from compilation to runtime.

function myFunc(u::Vector, v::Vector)
    length(u) == 3 || throw(ArgumentError("Invalid length of (u = $u), should be 3"))
    length(v) == 3 || throw(ArgumentError("Invalid length of (v = $v), should be 3"))
    u .+ v  # example functionality
end
like image 104
Harrison Grodin Avatar answered Nov 03 '22 00:11

Harrison Grodin