The code I’m working with involves a few dozen matrices, let’s call them a, b, etc. They all end up being used in quite different fashions, so it makes sense to keep them separate rather than packing them all into one large array. However, they are all matrices of the same size and are all initialized in the same way. Is there any cleaner way to do this than just a long list of initializations:
a = zeros(Float64, 10, 10)
b = zeros(Float64, 10, 10)
...
y = zeros(Float64, 10, 10)
z = zeros(Float64, 10, 10)
I would like to keep the arrays as separate variables; the actual names are more verbose and substantially increases readability. However, your solution should work if I just do a, b, .... z = [zeros( 10, 10) for _ in 1:26] - thanks!
You could try using a generator instead of an array comprehension:
a, b, .... z = (zeros( 10, 10) for _ in 1:26)
Then you avoid allocating the outer array.
Generators are lazy, so I think you could even make it infinitely long, and it will still only create the same number of matrices as the number of variables on the left hand side. In other words, you don’t need to count the variables, which I somehow find more satisfying.
Another option is to use NamedTuples. This keeps the readable names, but allows access through both names and indices and perhaps more importantly, passing and saving of the tuple of matrices. In code:
If the matrices are of known sizes, then consider also using SArrays or MArrays which for smaller matrices provide more optimization (see StaticArrays package).
I would think that the macros used to slurp part of a NamedTuple could be adapted to this situation, where rest=() and on the right hand side is a tuple with n repeating values.
I’d be curious to see what this macro would look like?
Speaking of Struct-utally similar questions. Would a struct be better than a NamedTuple in a general situation such as this? Is there a go-to package for conversions/initialization between NamedTuples and structs? As they seem similar to me in many ways.
maybe I overlooked the ‘,’ before the ='.
Can anyone explain the difference with and without.
I guess it’s something analogous to the fact that (1,) is a tuple of only the value 1, while (1) is only the value 1.
But perhaps in the context of the expressions there is something else
I found this way to render in the form of a macro to the solution via generator, but I’m sure there is a simpler and faster way to achieve the same result via macro.
macro assigngen(ex)
vars = ex.args[1].args
val = ex.args[2]
n=length(vars)
itr = Expr(
:(=),
:_,
esc(:(1:($n)))
)
gen= Expr(
:generator,
esc(:($val)),
itr
)
Expr(
:(=),
esc(:($(vars...),)),
gen
)
end
Some solutions with functions had already been proposed and I wanted to try, for my exercise, to make some macros that after a lot of effort, I managed to get out.
On the merits of the question, the expression that best responds to the OP’s request, in my opinion, is the one @DNF’s with the generator.
As for macros, I’ve read that anything a macro does can be done by some function, so strictly speaking macros are never needed.
But in some cases they can be convenient.
In this case, @DNF’s solution seems to be more functional and convenient than a macro.
The solution with a generator seems like it could be more problematic, or at least less flexible.
The problem is that the length of the generator is a run-time value, while the number of your matrices is akin to the length of a Tuple, which is a compilation-time value. The mismatch might not matter in a lot of cases due to Julia’s smart type inference and constant propagation, however it seems like it could cause run time dispatch and slow things down in some cases if used carelessly.