# How to give an one-time assignment to a large parametric matrix?

One-time assignment means something essentially equal to this:

``````function Mf(t)
M=[t t^2;t^3 t^4]    #assignment, just list all its entries in the bracket
end
``````

but not this:

``````function Mf(t)
M=zeros(2,2)    #assignment
M[1,1]=t    #mutation
M[1,2]=t^2
M[2,1]=t^3
M[2,2]=t^4
M
end
``````

When a large parametric matrix(e.g. M(t) is 1000x1000) is needed, I can’t assign it by the first way(list all 1000x1000 entries), but to use the second way

``````function Mf(t)
M=zeros(1000,1000)    #assignment
for i=1:1000
for j=1:1000
M[i,j]=m_ij(t)      #mutation, m_ij(t) is an explicit expression depends on i,j,t
end
end
M
end
``````

However, if I need to compute gradient of a loss function of M(t) by Zygote, e.g. L(t)=det(M(t))

``````gradient(t->det(Mf(t)), t0)
``````

an error will occur since mutating array in differetiated function is not allowed, means that I shouldn’t adopt the second way

``````ERROR: LoadError: Mutating arrays is not supported -- called setindex!(::Matrix{Float64}, _...)
``````

So I wonder if there is a method of assigning a large parametric matrix at one-time without mutating it (the explicit expression of m_ij(t) is known)
I failed to find the answer by searching and watching tutorials. I would be grateful if someone tells the solution.

You can do this, though I don’t know if that solves the specific error you are facing:

``````julia> M = [ exp(i*j) for i in 1:10, j in 1:10 ]
10×10 Matrix{Float64}:
2.71828      7.38906      20.0855        54.5982      …  1096.63        2980.96        8103.08        22026.5
7.38906     54.5982      403.429       2980.96              1.2026e6       8.88611e6      6.566e7         4.85165e8
20.0855     403.429      8103.08           1.62755e5         1.31882e9      2.64891e10     5.32048e11      1.06865e13
54.5982    2980.96          1.62755e5      8.88611e6         1.44626e12     7.8963e13      4.31123e15      2.35385e17
148.413    22026.5           3.26902e6      4.85165e8         1.58601e15     2.35385e17     3.49343e19      5.18471e21
403.429        1.62755e5     6.566e7        2.64891e10  …     1.73927e18     7.01674e20     2.83075e23      1.14201e26
1096.63         1.2026e6      1.31882e9      1.44626e12        1.90735e21     2.09166e24     2.29378e27      2.51544e30
2980.96         8.88611e6     2.64891e10     7.8963e13         2.09166e24     6.23515e27     1.85867e31      5.54062e34
8103.08         6.566e7       5.32048e11     4.31123e15        2.29378e27     1.85867e31     1.5061e35       1.2204e39
22026.5          4.85165e8     1.06865e13     2.35385e17        2.51544e30     5.54062e34     1.2204e39       2.68812e43

``````
1 Like

I ignore the actual matrix types involved. Would the following work for you?
The overhead of one-time allocation should be amortized over the full run.

• generate a first matrix with your mutating method
• create a second, non-mutating matrix as (deep) copy
• use the second one in Zygote

This actually working, thanks sir!

``````using Zygote

function Mf(t)
M=[t^(2i+j-2) for i in 1:2, j in 1:2]
end

``````
2 Likes

I am not sure if you mean to do this

``````using Zygote

function Nf(t)
N=zeros(2,2)
N[1,1]=t
N[1,2]=t^2
N[2,1]=t^3
N[2,2]=t^4
N2=deepcopy(N)
end