3 votes

Comment puis-je insérer une tranche d'une matrice dans un tableau 3D avec un type de structure interne SMatrix ?

Supposons que j'ai cette Matrice:

julia> mat = [
       1 2 3 4
       5 6 7 8
       9 8 7 6
       ];

Ensuite, je veux mettre des tranches de cette Matrice dans un Array 3D avec des types de SMatrix{Int64}, comme ci-dessous:

julia> using StaticArrays

julia> arr = Array{SMatrix{Int64}, 3}(undef, 3, 2, 3);

julia> col_idx = [1, 2, 3];

julia> foreach(x->arr[:, :, x] = mat[:, x:x+1], col_idx)
ERROR: MethodError: Cannot `convert` an object of type
  Int64 to an object of type
  SMatrix{Int64}
Closest candidates are:
  convert(::Type{T}, ::LinearAlgebra.Factorization) where T<:AbstractArray at C:\Users\JUL\.julia\juliaup\julia-1.8.3+0.x64\share\julia\stdlib\v1.8\LinearAlgebra\src\factorization.jl:58
  convert(::Type{SA}, ::Tuple) where SA<:StaticArray at C:\Users\JUL\.julia\packages\StaticArrays\x7lS0\src\convert.jl:179
  convert(::Type{SA}, ::SA) where SA<:StaticArray at C:\Users\JUL\.julia\packages\StaticArrays\x7lS0\src\convert.jl:178
  ...
Stacktrace:
  [1] setindex!
    @ .\array.jl:968 [inlined]
  [2] macro expansion
    @ .\multidimensional.jl:946 [inlined]
  [3] macro expansion
    @ .\cartesian.jl:64 [inlined]
  [4] macro expansion
    @ .\multidimensional.jl:941 [inlined]
  [5] _unsafe_setindex!(::IndexLinear, ::Array{SMatrix{Int64}, 3}, ::Matrix{Int64}, ::Base.Slice{Base.OneTo{Int64}}, ::Base.Slice{Base.OneTo{Int64}}, ::Int64)
    @ Base .\multidimensional.jl:953
  [6] _setindex!
    @ .\multidimensional.jl:930 [inlined]
  [7] setindex!(::Array{SMatrix{Int64}, 3}, ::Matrix{Int64}, ::Function, ::Function, ::Int64)
    @ Base .\abstractarray.jl:1344
  [8] (::var"#5#6")(x::Int64)
    @ Main .\REPL[20]:1
  [9] foreach(f::var"#5#6", itr::Vector{Int64})
    @ Base .\abstractarray.jl:2774
 [10] top-level scope
    @ REPL[20]:1

Comment puis-je y arriver?

P.S.:
Il ne s'agit que d'un exemple minimal et reproductible. Dans le sens pratique, j'ai une taille de (10, 10, 2000) pour arr et une grande taille pour mat également (10x2000, je suppose)!

3voto

Shayan Points 83

Ensuite, que se passe-t-il si je dis :

julia> using StaticArrays

julia> mat = [
       1 2 3 4
       5 6 7 8
       9 8 7 6
       ];

julia> arr = Array{Int64, 3}(undef, 3, 2, 3);

julia> foreach(x->arr[:, :, x] = mat[:, x:x+1], [1, 2, 3]);

julia> sarr = SArray{Tuple{3, 2, 3}}(arr)
3×2×3 SArray{Tuple{3, 2, 3}, Int64, 3, 18} with indices SOneTo(3)×SOneTo(2)×SOneTo(3):
[:, :, 1] =
 1  2
 5  6
 9  8

[:, :, 2] =
 2  3
 6  7
 8  7

[:, :, 3] =
 3  4
 7  8
 7  6

julia> typeof(sarr[:, :, 1])
SMatrix{3, 2, Int64, 6} (alias for SArray{Tuple{3, 2}, Int64, 2, 6})

Tout d'abord, j'ai créé un Array 3D régulier, puis j'ai construit un SArray basé sur celui-ci.
Cependant, dans le cas de votre situation pratique, j'ai essayé ce qui suit :

julia> mat = rand(10, 2000);

julia> arr = Array{Float64, 3}(undef, 10, 2, 1999);

julia> foreach(x->arr[:, :, x] = mat[:, x:x+1], 1:1999);

julia> sarr = SArray{Tuple{10, 2, 1999}}(arr);

Mais cela prend trop de temps pour construire un tel conteneur. (Je l'ai déjà annulé, et je ne connais pas sa durée d'exécution.). Par conséquent, dans ces cas, il est préférable de suivre le conseil d'@AboAmmar.

2voto

AboAmmar Points 437

Si j'ai bien compris, voulez-vous un tableau de SMatrices ?

mat = [ 1 2 3 4
        5 6 7 8
        9 8 7 6 ];

using StaticArrays

col_idx = [1, 2, 3];

arr = [SMatrix{3,2}(mat[:, x:x+1]) for x in col_idx]
3-element Vector{SMatrix{3, 2, Int64, 6}}:
 [1 2; 5 6; 9 8]
 [2 3; 6 7; 8 7]
 [3 4; 7 8; 7 6]

0voto

Dan Getz Points 11818

Inspiré par @Shayan et @AboAmmar, cette réponse explore l'utilisation du package BlockArrays.jl pour construire le résultat souhaité. BlockArrays place des tableaux existants dans un 'méta-tableau'. Les sous-tableaux peuvent être de type SMatrix.

En code:

using StaticArrays, BlockArrays

mat = rand(10,2000)   # matrice de démonstration aléatoire

# transformer toutes les tranches en SArrays
arr = [SArray{Tuple{10,2,1}, Float64, 3}(mat[:,i:i+1])
  for i=1:1999]
arr = reshape(arr,1,1,1999)

# les assembler dans un BlockArray
bricked = mortar(arr)

Après maintenant:

julia> size(bricked)
(10, 2, 1999)

julia> bricked[:,:,25]
1×1-bloqué 10×2 BlocMatrix{Float64}:
 0.265972  0.258414 
 0.396142  0.863366 
 0.41708   0.648276 
 0.960283  0.773064 
 0.62513   0.268989 
 0.132796  0.0493077
 0.844674  0.791772 
 0.59638   0.0769661
 0.221536  0.388623 
 0.595742  0.50732  

En espérant que cette méthode vous offre le compromis de performances souhaité (ou du moins introduit de nouvelles idées).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X