Rとjuliaとpythonとrubyで
様々な言語で角運動量演算子
角運動量演算子の行列を求めるプログラムを4つの言語で書いてみたので,メモがてら公開しておこうと思う.言語名と角運動量演算子で検索してもあまりヒットしないので,誰かの役に立つかもしれないし.
Rについては,以前もブログに書いたことがあるが,j=0の場合にも対応できるように一部を書き直した.
mjz<-function(j) diag(j:-j,2*j+1) mjp<-function(j) matrix(diag(sqrt(diffinv(j:-j)*2))[-1,-2*j-2],2*j+1) mjm<-function(j) t(mjp(j)) mjx<-function(j) (mjp(j)+mjm(j))/2 mjy<-function(j) (mjp(j)-mjm(j))/2i me<-function(j) diag(2*j+1)
juliaは,比較的新しい言語だが,数値計算には便利かも知れないので,書いてみた.いつかこのルーチンを使ってみたい.
using LinearAlgebra mjz(j)=diagm(j:-1:-j) mjp(j)=diagm(1=>2j:-2:2-2j|>cumsum.|>sqrt) mjm(j)=mjp(j)' mjx(j)=(mjp(j)+mjm(j))/2 mjy(j)=(mjp(j)-mjm(j))/2im me(j)=I(2j+1)
pythonはなぜか人気が衰えない言語で,書きにくいけど需要があるかも知れないので,書いてみた.
import numpy as np def mjz(j):return np.diag(j-np.arange(2*j+1)) def mjp(j):return np.diag(np.sqrt(np.cumsum((j-np.arange(2*j))*2)),1) def mjm(j):return mjp(j).T def mjx(j):return (mjp(j)+mjm(j))/2 def mjy(j):return (mjp(j)-mjm(j))/2j def me(j):return np.identity(int(2*j+1))
rubyは数値計算にはあまり向かない言語だと思っていたが,numoを使えば数値計算もできそうなので,書いてみた.
require "numo/linalg" def mjz(j) (j-Numo::DFloat[0..2*j]).diag end def mjp(j) Numo::NMath.sqrt((j-Numo::DFloat[0...2*j]).cumsum*2).diag(1) end def mjm(j) mjp(j).transpose end def mjx(j) (mjp(j)+mjm(j))/2 end def mjy(j) (mjp(j)-mjm(j))/2i end def me(j) Numo::DFloat.eye(2*j+1) end
Rはそのままで実行可能だが,それ以外の3つの言語では,何らかのライブラリを組み込まないといけないのが,少し面倒だ.Rやjuliaは半整数をあまり意識しなくても動くが,pythonとrubyは,rangeが半整数だと動かないので,2*jが整数であることを生かして少し工夫しないといけなかった.R以外の3つの言語では,対角要素の一つ上に成分を並んだ行列を簡単に作れるので,上昇演算子を簡単に書けるが,Rだとそこに工夫が必要で,もう少し良い手法もあるかも知れない.