# Varargs of vectors and scalars under modulo

How would I go about expanding the following code for any number of vectors (possibly using `Iterators` or `@nloops`)? My code below shows it working for the first three vectors.

``````function list_span(u̲::Vector{T}, v̲::Vector{T}, modulo::Int) where T <: Number
span = Vector{T}[]

for λ in 0:(modulo - 1), γ in 0:(modulo - 1)
w̲ = mod.(λ*u̲ + γ*v̲, modulo)
if w̲ ∉ span
push!(span, w̲)
end
end

return span
end
​
function list_span(u̲::Vector{T}, v̲::Vector{T}, t̲::Vector{T}, modulo::Int) where T <: Number
span = Vector{T}[]

for λ in 0:(modulo - 1), γ in 0:(modulo - 1), α in 0:(modulo - 1)
w̲ = mod.(λ*u̲ + γ*v̲ + α*t̲, modulo)
if w̲ ∉ span
push!(span, w̲)
end
end
​
return span
end
``````

I would first switch the order of `modulo` and the vectors, replace the list of vectors by a single vector argument followed by trailing dots, get the number of vectors with `length(u̲)` and replace the loop accordingly.

Something like this:

``````function list_span(modulo::Int, u̲::Vector{T}...) where T <: Number
span = Vector{T}[]
n_vec = length(u̲)

for j in 0:modulo^n_vec-1
w̲ =mod.(sum(λ .* u̲), modulo)
if w̲ ∉ span
push!(span, w̲)
end
end
return span
end
``````
2 Likes

An alternative way is to loop over the number of vectors and keep adding the multiples of each vector to the span of the previous vectors:

``````function list_span_alt(modulo::Int, u̲::Vector{T}...) where T <: Number
n_vec = length(u̲)
span = Vector{T}[zero(u̲[1])]
for n=1:n_vec
new_span = copy(span)
for v in span, λ=1:modulo-1
w̲ = mod.(v + λ * u̲[n], modulo)
if w̲ ∉ new_span
push!(new_span, w̲)
end
end
span = new_span
end
return span
end
``````

It seems more efficient:

``````julia> @btime list_span(3, [1,2,1], [3,1,2]);
12.523 μs (106 allocations: 7.77 KiB)

julia> @btime list_span_alt(3, [1,2,1], [3,1,2]);
2.272 μs (33 allocations: 3.47 KiB)

julia> Set(list_span(3, [1,2,1], [3,1,2])) == Set(list_span_alt(3, [1,2,1], [3,1,2]))
true
``````

But the other way with `digits` and was cooler, rsrsrs.

1 Like

If you like the other way of ordering the input arguments, you can make an outer method

``````span_list(args...) = list_span(last(args), args[1:end-1])
``````

and then you get to pass the modulo after all the vectors.

2 Likes

Nice.

Hmm, but then you don’t get to enforce the type of each argument.

You enforce it in the inner function.