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.
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,..])
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.
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.
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).
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.
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 SVector
s 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.
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)
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With