logo

줄리아의 심볼릭 연산 패키지 Symbolics.jl 소개 📂줄리아

줄리아의 심볼릭 연산 패키지 Symbolics.jl 소개

개요

줄리아에서 심볼릭 대수 체계symbolic algebra system를 지원하는 패키지인 Symbolics.jl에 대해 소개한다1. 이 패키지는 특히 줄리아의 기본 문법과 더불어 대단히 직관적이고 강력한 인터페이스를 제공한다.

SymEngine.jl과의 차이점

Symbolics.jl는 네이티브하게 줄리아로 구현되어 있으며 성능적으로나 인터페이스로나 더 좋은 측면이 많다. 줄리아에서 심볼릭 연산 하는 방법이라는 포스트에서 소개된 SymEngine.jl는 원래 C++로 작성된 라이브러리를 줄리아로 래핑한 것이다. 래핑인만큼 당시에는 별도의 기능 개발 없이 즉전감이어서 쓸만했겠지만 지금 와서는 원래 SymEngine를 익숙하게 써오던 입장이 아니라면 굳이 SymEngine.jl를 쓸 이유는 없다.

코드

변수 선언 @variables

julia> using Symbolics

julia> @variables t x y z
4-element Vector{Num}:
 t
 x
 y
 z

julia> w = log(y) + cos(x) + 2t^3
log(y) + cos(x) + 2(t^3)

심볼릭하게 사용할 변수들은 @variables 뒤에 나열하는 식으로 선언할 수 있다. 이 변수들은 자연스럽게 초월 함수의 인수 등으로도 사용할 수 있다.

전개 expand

julia> (x + y)^3
(x + y)^3

julia> expand((x + y)^3)
x^3 + 3(x^2)*y + 3x*(y^2) + y^3

expand 함수를 통해 전개를 할 수 있다. 함수를 취하지 않으면 성능 상의 이유 등으로 굳이 시키지도 않은 전개를 하지는 않는다.

축약 simplify

julia> simplify(2x + (cos(x))^2 + 3x + (sin(x))^2)
1 + 5x

simplify 함수를 통해 0이 될 항을 제거하거나 계수끼리 더해서 간단하게 만들 수 있다. 예시에서 볼 수 있듯 삼각함수의 제곱의 합은 1이 되는 것을 알아서 계산해내기도 한다.

치환과 대입 substitute

substitute 함수를 통해 변수를 치환하거나 대입할 수 있다. 어떻게 치환이 이루어지는지는 딕셔너리를 만들어서 넣어주면 된다. $$ w = \log y + \cos x + 2t^3 $$ 이 $w$ 에 치환과 대입을 해보자.

julia> substitute(w, Dict(t => x))
log(y) + cos(x) + 2(x^3)

심볼릭 변수끼리의 치환은 당연히 가능하다.

julia> substitute(w, Dict(t => 2, x => π, y => exp(1)))
16.0

$t = 2$, $x = \pi$, $y = e$ 로 대입한 결과는 수치적으로 계산해서 리턴된다.

미분 Differential

julia> Dt = Differential(t)
(::Differential) (generic function with 3 methods)

julia> Dt(w)
Differential(t)(log(y) + cos(x) + 2(t^3))

julia> expand_derivatives(Dt(w))
6(t^2)

특이하게도 Symbolics에서는 직접 미분하는 함수에 인수로써 적분할 변수를 전달하지 않고 특정 변수에 대한 미분을 하는 미분 작용소을 정의하고 여기에 심볼을 전달하는 방식으로 미분을 한다. 언뜻 보면 코드가 지저분해지고 복잡한 것 같지만 수학자의 관점으로 보면 아주 직관적이고 타당한 인터페이스라고 할 수 있다. 미분한 결과는 전개와 마찬가지로 바로 계산되지 않고 게으르게lazy 기다리다가 expand_derivatives 함수를 통해 결과가 리턴된다.

julia> Dx = Differential(x)
(::Differential) (generic function with 3 methods)

julia> Dy = Differential(y)
(::Differential) (generic function with 3 methods)

julia> Dx(w) |> expand_derivatives
-sin(x)

julia> Dy(w) |> expand_derivatives
1 / y

작용소를 정의한다는 관점에서 봤을 때 편미분 역시 아주 자연스럽게 구현된다.

벡터와 행렬

julia> @variables σ ρ β
3-element Vector{Num}:
 σ
 ρ
 β

julia> Lorenz = [-σ*x + σ*y
                 -x*y + ρ*x - y
                  x*y - β*z]
3-element Vector{Num}:
     -x*σ + y*σ
 -y - x*y + x*ρ
      x*y - z*β

줄리아 문법 그대로 벡터를 만들면 된다. 예로써 로렌츠 어트랙터의 우변도 위와 같이 간단히 심볼로 표현할 수 있다.

julia> M = [x*y y^2
             2x   9]
2×2 Matrix{Num}:
 x*y  y^2
  2x    9

행렬 역시 매우 직관적으로 정의된다.

자코비안

julia> Symbolics.jacobian(Lorenz, [x, y, z])
3×3 Matrix{Num}:
     -σ       σ   0
 -y + ρ  -1 - x   0
      y       x  -β

자코비안 행렬은 Symbolics.jacobian를 통해 간단히 구할 수 있다.

전체 코드

using Symbolics

@variables t x y z
w = log(y) + cos(x) + 2t^3

(x + y)^3
expand((x + y)^3)

simplify(2x + (cos(x))^2 + 3x + (sin(x))^2)

substitute(w, Dict(t => x))
substitute(w, Dict(t => 2, x => π, y => exp(1)))

Dt = Differential(t)
Dt(w)
expand_derivatives(Dt(w))

Dx = Differential(x)
Dy = Differential(y)
Dx(w) |> expand_derivatives
Dy(w) |> expand_derivatives

@variables σ ρ β
Lorenz = [-σ*x + σ*y
          -x*y + ρ*x - y
           x*y - β*z]

M = [x*y y^2
      2x   9]

Symbolics.jacobian(Lorenz, [x, y, z])

환경

  • OS: Windows
  • julia: v1.10.0
  • Symbolics v5.16.1