# DeltaNet 계열 선형 어텐션 변형 살펴보기

> Clean Markdown view of GeekNews topic #31925. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=31925](https://news.hada.io/topic?id=31925)
- GeekNews Markdown: [https://news.hada.io/topic/31925.md](https://news.hada.io/topic/31925.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2026-07-29T08:36:40+09:00
- Updated: 2026-07-29T08:36:40+09:00
- Original source: [blog.doubleword.ai](https://blog.doubleword.ai/you-could-have-come-up-with-kimi-delta-attention)
- Points: 3
- Comments: 1

## Topic Body

- 소프트맥스 어텐션에서 출발해 **고정 크기 상태**를 쓰는 선형 어텐션, 오류만 기록하는 DeltaNet, 전체 상태를 감쇠하는 Gated DeltaNet, 채널별로 감쇠하는 Kimi Delta Attention(KDA)까지 단계적으로 유도함
- 기본 선형 어텐션은 과거 key-value 외적의 합을 상태 \(S_t\)에 저장해 시퀀스 길이에 선형으로 동작하지만, 새 값을 대입하지 않고 기존 연관에 더하는 **가산 쓰기 간섭**이 발생함
- **DeltaNet**은 현재 key에서 예측한 값과 목표 value의 차이에 \(\beta_t\)를 곱해 기록하며, 즉시 재구성 조건·온라인 경사하강·랭크 1 상태 갱신이라는 세 해석이 같은 수식으로 이어짐
- **Gated DeltaNet**은 스칼라 \(\alpha_t\)로 상태 전체를 먼저 감쇠하고, KDA는 이를 대각 행렬 \(D_t=\operatorname{Diag}(\alpha_t)\)로 확장해 key 채널마다 서로 다른 비율로 정보를 유지하거나 삭제함
- 같은 KDA 점화식을 디코드용 **융합 순환 Triton 커널**과 학습·긴 프리필용 청크 방식으로 실행하며, 청크 방식은 토큰 내부 의존성을 삼각 풀이로 복원해 행렬 곱으로 재구성함

---

### 표기법과 전개 순서
- bra-ket 표기에서 \(\lvert q\rangle\)는 열벡터, \(\langle k\rvert\)는 행벡터, \(\langle k\vert q\rangle\)는 스칼라, \(\lvert v\rangle\langle k\rvert\)는 행렬임
- 하나의 인과적 어텐션 헤드와 실수 벡터를 사용하고, **DeltaNet key는 정규화**되어 있으며 상태는 key 공간에서 value 공간으로 사상한다고 가정함
- 전개 순서는 소프트맥스 어텐션 → 선형 어텐션 → [DeltaNet](https://arxiv.org/abs/2406.06484) → [Gated DeltaNet](https://arxiv.org/abs/2412.06464) → [KDA](https://arxiv.org/abs/2510.26692)이며, 마지막에 순환 및 청크형 Triton 구현으로 연결됨
- DeltaNet 계열 가운데 두 변형은 최신 **Qwen과 Kimi 모델 계열**에서 사용됨

### 이차 복잡도 어텐션에서 선형 상태로
- 일반적인 인과적 소프트맥스 어텐션은 key와 query의 유사도를 계산하고, 모든 과거 key에 대한 점수를 분포로 정규화한 뒤 value 벡터의 가중합을 출력함
- 길이 \(T\)인 시퀀스에는 \(T^2\)개의 key-query 쌍이 있음
  - 자동회귀 추론에서는 key와 value를 캐시할 수 있지만 캐시 크기가 시퀀스와 함께 늘어남
  - 새로운 query도 전체 과거를 확인해야 함
- 소프트맥스 분모는 현재 query와 모든 이전 key에 공동으로 의존하므로 계산 순서를 단순히 재배치하기 어려움
- 소프트맥스를 제거하면 출력을 과거 key-value 외적의 합으로 묶을 수 있음
  - \(S_t=\sum_{i\le t}\lvert v_i\rangle\langle k_i\rvert\)
  - \(S_t=S_{t-1}+\lvert v_t\rangle\langle k_t\rvert\)
  - \(\lvert o_t\rangle=S_t\lvert q_t\rangle\)
- 핵심 항등식은 \((\lvert v\rangle\langle k\rvert)\lvert q\rangle=\langle k\vert q\rangle\lvert v\rangle\)이며, 모든 과거 key와 value 대신 합산된 외적을 **고정 크기 \(d_v\times d_k\) 상태**에 저장함
- 토큰을 한 번 순회하므로 시퀀스 길이에 선형으로 동작하지만, 그 대가로 소프트맥스의 정규화와 선택성을 잃음
  - 더 정교한 선형 어텐션은 특징 맵과 정규화 항을 사용함

### 선형 어텐션의 가산 쓰기 문제
- 정규화된 현재 key에 \(\lvert v_t\rangle\langle k_t\rvert\)를 기록한 직후 같은 key로 읽으면 \(S_t\lvert k_t\rangle=S_{t-1}\lvert k_t\rangle+\lvert v_t\rangle\)가 됨
- 새 쓰기는 메모리가 \(v_t\)를 반환하도록 대입하지 않고 기존 반환값에 \(v_t\)를 **`+=` 방식으로 더함**
- 이전 상태가 이미 올바른 값을 반환한다면 같은 value가 두 배가 되며, key들이 서로 직교하지 않으므로 각 쓰기가 기존 쓰기와 간섭할 수 있음
- 선형 어텐션은 압축된 연관 메모리를 제공하지만, 필요한 `=`에 가까운 갱신 대신 가산 갱신을 수행함

### DeltaNet: 값 대신 예측 오류 쓰기
- [DeltaNet](https://arxiv.org/abs/2406.06484)은 새 key에 대한 기존 예측 \(\widehat v_t=S_{t-1}k_t\)를 먼저 읽고 전체 value 대신 차이만 기록함
  - \(e_t=\beta_t(v_t-S_{t-1}k_t)\)
  - \(S_t=S_{t-1}+e_tk_t^\mathsf T\)
  - 학습된 쓰기 강도 \(\beta_t\)는 \([0,1]\) 범위임
- 같은 key로 즉시 다시 읽으면 \((1-\beta_t)S_{t-1}k_t+\beta_tv_t\)가 됨
  - \(\beta_t=1\)이면 정확히 \(v_t\)를 반환함
  - 더 작은 값은 기존 예측을 목표 방향으로 일부만 이동시킴
- 갱신은 **key 공간에 국소적**임
  - 현재 key와 직교하는 query 방향에서는 외적 갱신이 0이므로 응답이 바뀌지 않음
  - 현재 key 방향의 연관만 선택적으로 교체함
- ## 재구성 손실로 유도하기
  - 상태 \(S\)를 선형 사상으로 보고 현재 key-value 쌍의 손실을 \(\frac12\lVert Sk_t-v_t\rVert_2^2\)로 두면 기울기는 \((Sk_t-v_t)k_t^\mathsf T\)임
  - \(S_{t-1}\)에서 크기 \(\beta_t\)로 경사하강 한 단계를 수행하면 DeltaNet의 갱신식과 정확히 같아짐
  - 같은 갱신을 세 방식으로 해석할 수 있음
    - 메모리 연산에서 \(\beta_t\)는 **기존 연관 교체 강도**임
    - 온라인 학습에서 \(\beta_t\)는 학습률임
    - 선형대수에서는 예측 오류와 key의 랭크 1 외적임
- ## 구조화된 상태 전이
  - 갱신을 전개하면 \(S_t=S_{t-1}(I-\beta_tk_tk_t^\mathsf T)+\beta_tv_tk_t^\mathsf T\)가 됨
  - 단위 key에 대해 \(I-\beta_tk_tk_t^\mathsf T\)는 현재 key 방향에서 고윳값 \(1-\beta_t\), 모든 직교 방향에서 고윳값 1을 가짐
  - 기존 key 방향의 연관을 먼저 제거하고 새 연관을 더하지만, **상태 전체의 수명 관리**는 아직 해결하지 못함

### Gated DeltaNet: 상태 전체를 먼저 잊기
- 하나의 행렬에 전체 과거를 압축하면 이미 상태에 합쳐진 개별 토큰만 선택해 건너뛸 수 없음
- DeltaNet은 현재 key 주변을 교정하지만, 다른 방향의 오래된 정보는 남아 향후 읽기에 계속 기여할 수 있음
- [Gated DeltaNet](https://arxiv.org/abs/2412.06464)은 학습된 스칼라 유지 게이트 \(\alpha_t\in[0,1]\)를 적용함
  1. \(\widetilde S_t=\alpha_tS_{t-1}\)로 잊음
  2. \(\widehat v_t=\widetilde S_tk_t\)로 예측함
  3. \(e_t=\beta_t(v_t-\widehat v_t)\)로 교정함
  4. \(S_t=\widetilde S_t+e_tk_t^\mathsf T\)로 기록함
- **잊기 → 예측 → 교정 → 쓰기** 순서가 중요함
  - 감쇠 전에 예측하면 오류를 계산한 메모리와 실제로 갱신하는 메모리가 달라짐
- 델타 규칙은 목표 key에 대한 교체를, 스칼라 게이트는 전역 삭제를 담당해 서로 다른 문제를 해결함
- 다만 하나의 \(\alpha_t\)가 행렬 전체에 적용되므로 모든 key 채널을 같은 비율로 유지하거나 잊어야 함

### Kimi Delta Attention: 채널별 감쇠
- [Kimi Delta Attention](https://arxiv.org/abs/2510.26692)은 스칼라 \(\alpha_t\)를 \(d_k\)차원 벡터로 바꾸고 \(D_t=\operatorname{Diag}(\alpha_t)\)를 구성함
- 상태가 key 공간에서 value 공간으로 사상되므로 key 채널은 \(S\)의 열에 해당하며, 오른쪽 곱 \(S_{t-1}D_t\)가 각 열에 서로 다른 유지율을 적용함
- KDA는 다음 순서로 동작함
  1. \(\widetilde S_t=S_{t-1}D_t\)로 key 채널별 감쇠
  2. \(\widehat v_t=\widetilde S_tk_t\)로 예측
  3. \(e_t=\beta_t(v_t-\widehat v_t)\)로 교정
  4. \(S_t=\widetilde S_t+e_tk_t^\mathsf T\)로 기록
  5. \(o_t=S_t(d_k^{-1/2}q_t)\)로 읽기
- Gated DeltaNet에서 KDA로의 개념적 변화는 \(\alpha_t\)를 \(D_t\)로 승격한 것뿐이지만, 한 채널을 지우면서 다른 채널은 유지할 수 있음
- ## 대각-저랭크 전이
  - KDA를 전개하면 \(S_t=S_{t-1}A_t+\beta_tv_tk_t^\mathsf T\)이며, \(A_t=D_t(I-\beta_tk_tk_t^\mathsf T)\)임
  - \(A_t=D_t-b_ta_t^\mathsf T\), \(b_t=D_tk_t\), \(a_t^\mathsf T=\beta_tk_t^\mathsf T\)로 쓸 수 있어 **대각-저랭크(DPLR)** 전이가 됨
  - DPLR은 key 공간에서 작용하는 \(d_k\times d_k\) 전이를 뜻하며, 메모리 상태 자체는 여전히 \(d_v\times d_k\) 행렬임
  - 계열마다 다음 기능이 추가됨
    - 선형 어텐션: 고정 크기 순환 메모리
    - DeltaNet: 목표 방향의 선택적 교체
    - Gated DeltaNet: 상태 전체 감쇠
    - KDA: key 채널별 감쇠
  - 구현은 보통 \(g_t=\log\alpha_t\le0\)를 저장한 뒤 \(\exp(g_t)\)로 유지율을 구함
  - 전치된 \(d_k\times d_v\) 레이아웃의 5단계 참조 구현은 [`naive_recurrent_kda`](https://github.com/fla-org/flash-linear-attention/blob/main/fla/ops/kda/naive.py#L59-L63)에서 확인할 수 있음

### 디코드용 융합 순환 Triton 커널
- KDA에는 두 가지 주요 실행 방식이 있음
  - **융합 순환 방식**: 디코드, 짧은 시퀀스, 상태 유지형 서빙에 적합함
  - **청크 방식**: 학습과 긴 프리필에 적합함
- [`fused_recurrent_kda_fwd`](https://github.com/fla-org/flash-linear-attention/blob/main/fla/ops/kda/fused_recurrent.py#L234-L332)는 시퀀스·value head·32폭 value 타일마다 하나의 Triton 프로그램을 실행함
  - `BK`는 일반적인 지원 구성에서 key 차원을 덮음
  - 각 프로그램은 전치 상태의 `[BK, BV]` 타일을 소유하고 토큰을 순서대로 순회함
  - 서로 다른 value 타일, head, 시퀀스는 독립적으로 실행됨
- 커널은 상태 감쇠, key에 대한 예측 축약, residual 계산, 외적 쓰기, query 읽기 축약을 점화식 그대로 수행함
- 한 번에 새 토큰 하나만 들어오는 디코드에는 적합하지만, 벡터 연산을 Tensor Core에 효율적인 큰 행렬 곱으로 바꾸지 못해 **학습과 긴 프리필에는 불리함**

### Chunkwise KDA: 점화식을 행렬 곱으로 재배치
- Chunkwise KDA는 \(C\)개 토큰을 함께 처리하면서 토큰별 순환 방식과 정확히 같은 상태와 출력을 만들어야 함
- 각 청크는 두 결과를 계산함
  - 들어오는 상태 \(S_c\)에서 청크 전체를 처리한 뒤의 \(S_{c+1}\)
  - 청크 내부 모든 토큰의 인과적 출력
- 각 토큰의 델타 오류가 같은 청크 안의 이전 쓰기에 의존한다는 점이 핵심 난점임
- ## 누적 감쇠와 임시 오류
  - 토큰 \(i\)의 대각 감쇠를 \(D_i\), 청크 경계부터 토큰 \(i\)까지의 누적 감쇠를 \(D_{0:i}=D_0D_1\cdots D_i\)로 둠
  - 토큰 \(j\)의 쓰기가 토큰 \(i\)까지 전달될 때는 \(D_{j+1:i}\)가 적용되며, 대각 행렬이므로 감쇠 행렬끼리는 교환 가능함
  - 먼저 청크 내부의 다른 쓰기를 무시한 임시 오류를 병렬 계산함
    - \(\bar e_i=\beta_i(v_i-S_cD_{0:i}k_i)\)
  - 첫 토큰을 제외한 임시 오류는 이전 청크 내부 쓰기의 영향을 빠뜨렸으므로 그대로 사용할 수 없음
- ## 인과 의존성 복원
  - 이전 토큰 \(j\)가 현재 토큰 \(i\)의 오류에 미치는 계수를 \(\rho_{ij}=\beta_i k_j^\mathsf TD_{j+1:i}k_i\)로 정의함
  - 실제 오류는 \(e_i=\bar e_i-\sum_{j<i}\rho_{ij}e_j\) 형태로 순차 의존성을 가짐
  - \(\rho_{ij}\)를 엄격한 하삼각 행렬 \(R_c\)에 넣으면, 쌓아 놓은 오류 행렬은 \(E_c=\bar E_c(A_c^{kk})^\mathsf T\), \(A_c^{kk}=(I+R_c)^{-1}\)로 계산됨
  - 일반적인 밀집 역행렬은 필요하지 않음
    - \(I+R_c\)는 대각 원소가 1인 삼각 행렬임
    - 각 value 채널에 대해 **인과적 삼각 풀이**를 수행하면 됨
- ## 청크 종료 상태 계산
  - 들어오는 상태는 청크의 모든 감쇠를 통과하고, 각 청크 내부 쓰기는 자신보다 뒤에 있는 감쇠만 통과함
  - 청크 끝까지 감쇠된 key들을 \(K_c^{\mathrm{end}}\)에 행으로 쌓으면 상태를 다음 행렬 곱으로 정리할 수 있음
    - \(S_{c+1}=S_cD_{0:C-1}+E_cK_c^{\mathrm{end}}\)
  - 여러 랭크 1 외적 쓰기를 하나의 행렬 곱으로 합쳐 **청크 전체 상태를 한 번에 전진**시킴
- ## 청크 내부의 모든 출력 계산
  - KDA는 현재 토큰을 쓴 뒤 읽으므로 토큰 \(i\)의 출력에는 자신의 쓰기도 포함됨
  - 이전 쓰기 \(j\)가 query \(i\)에 미치는 계수를 \(\chi_{ij}=s\,k_j^\mathsf TD_{j+1:i}q_i\), \(j\le i\)로 정의함
  - 계수를 하삼각 읽기 행렬 \(A_c^{qk}\)에 배치함
    - 상삼각의 0은 미래 토큰의 기여를 차단함
    - 대각 원소는 현재 토큰이 자신의 쓰기 이후 읽는 동작을 반영함
  - 경계에서 각 query까지 감쇠된 벡터를 \(Q_c^{\mathrm{boundary}}\)에 쌓으면 전체 출력은 다음과 같음
    - \(O_c=sS_cQ_c^{\mathrm{boundary}}+E_c(A_c^{qk})^\mathsf T\)
  - 첫 행렬 곱은 감쇠된 청크 진입 상태를 읽고, 두 번째 곱은 청크 내부의 인과적 쓰기 기여를 더함

### Chunkwise Triton 파이프라인
- 청크 구현은 하나의 거대한 커널이 아니라 여러 커널 호출로 이어지는 **파이프라인**임
- 먼저 청크 내부 누적 로그 감쇠를 계산함
  - 두 prefix sum의 차이로 유지 벡터를 길게 곱하지 않고 \(D_{j+1:i}\)를 표현함
- 이어서 인과적 \(A^{qk}\)와 \(A^{kk}\) 상호작용 행렬을 만들고, \(A^{kk}\)로 청크의 교정된 쓰기에 대한 WY 형태를 구성함
- 상태 커널은 유일한 청크 간 순회를 수행함
  - 각 청크로 들어오는 상태를 생성함
  - 청크의 델타 오류를 해소함
- 진입 상태가 계산된 뒤에는 출력 커널이 서로 다른 청크와 타일의 토큰을 병렬 처리할 수 있음
- 실제 구현은 먼저 **16토큰 대각 상호작용 블록**을 계산한 뒤 융합된 비대각 및 삼각 풀이 커널을 실행함
- [`chunk_kda_fwd`](https://github.com/fla-org/flash-linear-attention/blob/main/fla/ops/kda/chunk_fwd.py#L20-L123)가 단계를 조정하며 주요 진입점은 `chunk_kda_fwd_intra`, `chunk_gated_delta_rule_fwd_h`, `chunk_gla_fwd_o_gk`임
  - 코드의 `v_new`는 해소된 오류임
  - `h`는 청크 진입 상태임
  - `kg`는 청크 끝까지 감쇠된 key임
- 순환 방식과 청크 방식은 서로 다른 어텐션이 아니라 **동일한 KDA 점화식의 두 실행 스케줄**임
  - 순환 방식은 저지연 디코드를 위한 직렬 벡터 연산임
  - 청크 방식은 Tensor Core 중심의 학습과 프리필을 위한 행렬 연산임

## Comments



### Comment 62549

- Author: neo
- Created: 2026-07-29T08:36:42+09:00
- Points: 1

###### [Hacker News 의견들](https://news.ycombinator.com/item?id=49085909) 
- 지난 15년간 머신러닝에는 **통일된 수학 표기법**이 필요했고, 아마 계속 필요했을 것임. 예전에는 세계 각지 연구자들의 논문마다 기상천외한 표기법이 등장해 더 심했음  
  논문마다 표기법이 달라지면 이해에 마찰이 생김. 적어도 이 글은 처음부터 표기법을 명시적으로 설명하는데, 이렇게 하는 논문은 드문 편임. 처음에는 표기법 전환 기능도 알아채지 못했지만 매우 유용함
  - 한 글자 기호나 명시적인 자료형 대신 `∣q⟩` 같은 문자를 쓰는 **전통적 수학 표기법**을 선호하는 이유를 이해하지 못하겠음. 간결하다는 장점은 있겠지만, 수식을 의사 코드나 Python 같은 실제 프로그래밍 언어로 쓰면 훨씬 이해하기 쉬울 듯함
  - 이 글은 표기법의 한 측면만 설명할 뿐, 사용한 **변수의 정의**는 제공하지 않음. `k`, `q`, `S`가 무엇인지 머신러닝을 공부했다면 알거나 추측할 수 있지만, 관련 배경지식이 없으면 글 대부분이 불투명해짐
  - 예전에는 나도 그렇게 생각했지만, 코드보다 수식을 들여다보는 시간이 훨씬 길기 때문에 기호의 의미를 알고 나면 **간결한 표기**가 읽기 훨씬 쉬움. 문자로 쓰면 어렵기로 유명한 이름 짓기까지 피할 수 있음

- “직접 생각해낼 수도 있었던…”이라고 하지만, 존재하지 않던 무언가를 만들거나 결합하는 일은 **엄청나게 어려움**  
  누군가 어려운 작업을 끝내 공개하면 곧바로 “별로 어렵지 않네”, “나도 할 수 있었어” 같은 반응이 나오며 모든 것이 단순해 보이기 시작함. 개발하다 새것을 발명했다고 생각했는데, 이미 1970년대에 만들어져 널리 쓰이던 것임을 나중에 발견하는 일도 흔함. 단지 내 경로와 마주치지 않아 존재를 몰랐을 뿐임

- 내게는 **브라-켓 표기법**이 모든 내용을 단순하고 직관적으로 만들어 줌. 벡터 표기에서는 어느 쪽이 가로이고 세로인지 헷갈려 덩어리만 따라가다 집중력을 잃곤 했지만, 브라-켓으로는 전체가 매우 직관적이었음  
  놓친 좋은 글이 많을 것 같아 다른 글도 이 표기법으로 변환해 볼 생각임. 참고로 물리학 박사이며 가벼운 난독증이 있음

- “바깥곱은 행렬이고 안쪽곱은 숫자다. 과거의 모든 키와 값을 저장하는 대신 고정 크기 상태 `S_t`에 바깥곱의 합을 저장한다” 같은 문체를 보면 **LLM이 작성한 글**로 확신하게 됨
  - 아마 유행어가 들어간 제목을 요청하는 것부터 시작했을 듯함
  - Claude에게 대시(`–`)를 쓰지 말라고 프롬프트하면 이런 결과가 나옴

- 시각화된 튜토리얼도 있음: [https://snowchord.com/blog/linear-attention-visualized/](<https://snowchord.com/blog/linear-attention-visualized/>)

- 이런 글과 제목을 볼 때마다 나보다 훨씬 똑똑한 수많은 사람에게 **깊은 감사와 겸손함**을 느낌. 고등학교와 학부에서는 매우 똑똑한 사람으로 통했고 평균보다는 영리하지만, 나를 풋내기로 보이게 할 사람도 수백만 명은 분명히 있음  
  여기서 똑똑하다는 것은 거대하고 복잡한 개념과 시스템을 머릿속에 담고 추론하는 능력을 뜻하며, 수학자에게 특히 중요한 재능으로 보임
  - AI 도구가 작업을 점점 더 가속하더라도, **새로운 아이디어 대부분의 원천**은 계속 인간일 것으로 봄  
    친구와 술을 마시며 해본 사고실험은 아이들을 화면과 알고리즘이 공급하는 대중적 콘텐츠에서 격리하고, 최첨단 모델을 훈련하듯 매체와 자료의 품질을 엄격히 통제하는 학습 친화적 환경에서 키우는 것이었음. 아이들을 위한 수도원처럼 만들고 수학, 공학, 컴퓨터과학, 딥러닝 등을 통해 현실에 관한 최신 지식을 가르치는 방식임  
    결국 첨단 AI 도구를 활용해 지식의 경계를 넓히려면 여전히 매우 똑똑하고 사고가 크게 오염되지 않은 사람이 필요함. AI가 인간을 완전히 대체하리라는 생각은 잘못된 방향임

- 참고로 **브라-켓 표기법**이라는 이름은 실제로 괄호(bracket)에서 유래함  
  [https://en.wikipedia.org/wiki/Bra-ket_notation](<https://en.wikipedia.org/wiki/Bra-ket_notation/>)

- 처음에는 망설였지만 **켓 표기법** 덕분에 연산이 훨씬 명확해져 마음에 들었음. 다만 이차 어텐션의 `d_k`처럼 일부 변수에 관한 간단한 복습도 있었으면 좋았을 듯함

- 처음에는 이 해법을 떠올리지 못했다는 사실에 낙담했지만, JavaScript로 **이진 탐색**을 직접 작성하는 데도 어려움을 겪는다는 사실을 깨닫고 바로 마음이 편해졌음. Kimi Delta Attention을 내가 생각해냈을 가능성은 전혀 없음
  - 선형대수 코드는 의외로 작성하기 쉬운 측면이 있음. 일반적인 컴퓨터과학 코드처럼 재귀가 복잡하게 얽히지 않고, 모든 변수 사이에 수학적 관계가 있으며, 흔한 수학 개념은 이미 잘 구현된 라이브러리를 이용할 수 있음  
    반복문도 두세 단계 이상 깊어질 일이 드물고, 그보다 복잡하다면 어차피 라이브러리로 넘기는 편이 나음
