タイトルの ”複合n進数” というのは便宜上の用語で正式名称は知らない。 ここでは各桁ごとに繰り上がる数が違う数字列のことを "複合n進数" と呼ぶこととする。 例えば、 の0桁目*1は2進数、1桁目が3進数だとすると 00, 01, 10, 11, 20, 21 と数が増えていく。
配列をディラック表記で表示するという地味なJuliaのパッケージを作っているときにある問題に直面した
と。
放っておくと忘れそうなので記録に残しておく。
Qubits 系の場合
量子コンピュータで扱われるような n-qubit 系なら話は簡単。 配列のi番目の要素は ( は i の二進数表記を意味する) の係数となる。
例えば 2-qubit 状態を計算基底 で展開すると となるが、行列の成分を 0 始まりで数えれば 2番目の成分は の係数となる。
このようにqubit 系の場合は10進数を2進数に直すだけで基底がわかるので簡単。 問題は qudits系 *2の場合である。
Qudits 系の場合
今、n-qudit系の i 番目の標準基底を とし、j 桁目の qudit の次元を とする。
冒頭で述べたように、qutrit-qubit 系の場合の標準基底は である。
そして、今私がやりたいことは と の情報から の各桁の数を求めることである。 全ての qudit の次元が同じならば、qubit 程ではないが簡単に求めることができるが、より一般の状態では各 qudit の次元が違うので中々面倒な計算になる。
関係式を考える
とりあえず表にまとめてみた。
qutrit-qubit の場合
0 | 0 | 0 |
1 | 0 | 1 |
2 | 1 | 0 |
3 | 1 | 1 |
4 | 2 | 0 |
5 | 2 | 1 |
qubit-qutrit-qubit の場合
0 | 0 | 0 | 0 |
1 | 0 | 0 | 1 |
2 | 0 | 1 | 0 |
3 | 0 | 1 | 1 |
4 | 0 | 2 | 0 |
5 | 0 | 2 | 1 |
6 | 1 | 0 | 0 |
7 | 1 | 0 | 1 |
8 | 1 | 1 | 0 |
9 | 1 | 1 | 1 |
10 | 1 | 2 | 0 |
11 | 1 | 2 | 1 |
表と にらめっこして次のような関係式が成り立つと予測。
上記の表の値を具体的に代入してみても良さそう。
これより、 は次のように求められそうだと予測。 \begin{align} i_{n-1} &= \mathrm{div} \left(i, ~~\prod_{k=0}^{n-2} d_k \right) \\ i &\leftarrow i - i_{n-1} \prod_{k=0}^{n-2} d_k \end{align}
\begin{align} i_{n-2} &= \mathrm{div} \left(i, ~~\prod_{k=0}^{n-3} d_k \right) \\ i &\leftarrow i - i_{n-2} \prod_{k=0}^{n-3} d_k \\ &~~~~\vdots\\ i_1 &= \mathrm{div}(i, d_0)\\ i_0 &= i - i_1 d_0 \end{align}
これで無事に求めたいものが得られた。
Julia*3 で書いてみると以下のよう
julia> versioninfo() Julia Version 0.7.0-alpha.217 Commit f90d674057 (2018-06-21 10:01 UTC) Platform Info: OS: Linux (x86_64-pc-linux-gnu) CPU: Intel(R) Core(TM) i5-4460T CPU @ 1.90GHz WORD_SIZE: 64 LIBM: libopenlibm LLVM: libLLVM-6.0.0 (ORCJIT, haswell) Environment: JULIA_SHELL = /usr/bin/zsh julia> function ind2Nary(m::Int, dims::Vector{Int}) m = m - 1 nq = length(dims) ar = zeros(Int, nq) product = prod(dims[2:end]) for ith in 1:nq-1 d = div(m, product) m = m - d * product product = div(product, dims[ith+1]) ar[ith] = d end ar[end] = m return ar end julia> d = [2,3,2]; julia> for i in 1:prod(d) println(i-1, ": ", ind2Nary(i, d)) end 0: [0, 0, 0] 1: [0, 0, 1] 2: [0, 1, 0] 3: [0, 1, 1] 4: [0, 2, 0] 5: [0, 2, 1] 6: [1, 0, 0] 7: [1, 0, 1] 8: [1, 1, 0] 9: [1, 1, 1] 10: [1, 2, 0] 11: [1, 2, 1]
いい感じ♪
せっかくなのでこれを使って QuantumOptics.jl に プルリクを投げたら一応マージしてもらえた。
ちょっとだけ OSS に貢献したかもしれない。