Julia Language

[Julia] array와 scalar 간의 대입연산 (no method matching)

공부하는백수 2021. 5. 13. 09:41

※ 다음 링크에서 줄리아 프로그래밍과 관련한 글 목록을 확인하실 수 있습니다.

Julia 프로그래밍 관련 글 목록


문제: Singleton Array를 배열 요소에 대입하고자 할 경우

  Julia로 기존에 선언한 array에 singleton array를 대입할 때 "no method matching" 에러가 발생한다. 예를 들어, 아래와 같은 경우를 생각해보자. 아래 코드에서 x라는 complex array를 미리 선언하고 x의 첫 번째 성분에 Gaussian noise를 더하려고 한다. 이때, noise는 설명을 위해 singleton array로 생성하였다. 참고로 randn 함수는 항상 array 형태로 출력을 주기 때문에 하나의 랜덤값만을 생성하였다하더라도 이는 scalar가 아닌 array로 정의된다. (참고로 Julia에서 complex value는 a+im*b 형태로 선언할 수 있다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
julia> x=zeros(Complex{Float64}, 10,1)
10×1 Array{Complex{Float64},2}:
 0.0 + 0.0im
 0.0 + 0.0im
 0.0 + 0.0im
 0.0 + 0.0im
 0.0 + 0.0im
 0.0 + 0.0im
 0.0 + 0.0im
 0.0 + 0.0im
 0.0 + 0.0im
 0.0 + 0.0im
 
julia> n = sqrt(0.1)*(randn(1+ 1im*randn(1))
1-element Array{Complex{Float64},1}:
 0.10801427104082759 + 0.3305434470486299im
 
julia> x[1+= n
ERROR: MethodError: no method matching +(::Complex{Float64}, ::Array{Complex{Float64},1})
For element-wise addition, use broadcasting with dot syntax: scalar .+ array
Closest candidates are:
  +(::Any, ::Any, ::Any, ::Any...) at operators.jl:538
  +(::Complex) at complex.jl:273
  +(::Complex, ::Complex) at complex.jl:275
  ...
Stacktrace:
 [1] top-level scope at none:1
 
cs

 

  x[1]의 값에 n을 더하려고 했더니 "ERROR: MethodError: no method matching +(::Complex{Float64}, ::Array{Complex{Float64},1})" 라는 에러가 발생하였다. 에러가 발생한 원인은 x[1]은 Complex{Float64} 타입인 것에 반해 n은 singleton array이기 때문에 array를 scalar로 대입하였기 때문이다. array의 크기가 1이라하더라도 Julia에서는 array가 항상 scalar보다 높은 차원으로 정의되기 때문에 고차원의 데이터를 저차원의 데이터에 대입할 수 없게 되는 것이다. MATLAB, Python, R 등에서는 이러한 연산을 허용하기 때문에 문제가 되지 않는데 Julia에서는 속도 때문인지 모르겠으나 좌우지간 이러한 연산을 허용하지 않는다. 


해결방법: slicing

  난 아직 Julia 초심자이기 때문에 이 문제를 해결하는데 30분 가까이 걸렸다. 처음에는 type casting을 하기 위해 Complex(n)이나 convert 함수를 사용하여 singleton array를 scalar로 변환하려고 해 보았으나 이 역시 에러가 발생하여 사용할 수 없었다. 그런데 의외로 문제의 해결 방법은 어이없을 정도로 너무나 간단하였다. n이 array이기 때문에 slicing을 사용하여 대입하면 아무런 문제가 되지 않았다. 즉, 다음과 같은 방법을 사용하면 문제가 바로 해결된다.

1
2
julia> x[1+= n[1]
0.10801427104082759 + 0.3305434470486299im
cs

반대의 경우: Scalar를 Array에 브로드캐스팅하여 대입하고자 할 때

  위와는 반대로 아래와 같이 x라는 scalar 변수를 A라는 array의 특정 요소들에 대입하는 경우에도 에러가 발생한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ulia> A = zeros(5,1)
5×1 Array{Float64,2}:
 0.0
 0.0
 0.0
 0.0
 0.0
 
julia> x=3
3
 
julia> A[1:2:end] = x # 에러 발생!!
ERROR: ArgumentError: indexed assignment with a single value to many locations is not supported; perhaps use broadcasting `.=` instead?
Stacktrace:
 [1] setindex_shape_check(::Int64, ::Int64) at .\indices.jl:258
 [2] macro expansion at .\multidimensional.jl:795 [inlined]
 [3] _unsafe_setindex!(::IndexLinear, ::Array{Float64,2}, ::Int64, ::StepRange{Int64,Int64}) at .\multidimensional.jl:789
 [4] _setindex! at .\multidimensional.jl:785 [inlined]
 [5] setindex!(::Array{Float64,2}, ::Int64, ::StepRange{Int64,Int64}) at .\abstractarray.jl:1153
 [6] top-level scope at none:1
cs

 

  위와 같이 하나의 scalar 값을 array의 다중 요소에 대입하고자 할 경우에는 아래와 같이 벡터 도트 연산자를 사용하여야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
julia> A[1:2:end] .= x
3-element view(::Array{Float64,1}, 1:2:5with eltype Float64:
 3.0
 3.0
 3.0
 
julia> A
5×1 Array{Float64,2}:
 3.0
 0.0
 3.0
 0.0
 3.0
cs

 

데이터 분석에 사용되는 다른 언어들처럼 위와 같은 문제를 언어 자체적으로 처리해주지 못하는 것이 아쉽기는 하지만 익숙함의 문제이므로 그냥 받아들이는 수 밖에...ㅜ