ããã«ã¡ã¯ãã»ãããã§ãã
大å¦ã§ç©ç*1ãåãã æ¹ãªããããã§ãããEinsteinã®ç¸®ç´è¨å·ã è¨ç®ã®ä¸ã§è²ã çç¥ã§ãããã¨ã«ããæ £ããã°è²ã 便å©ãªè¨æ³ã§ãï¼
ç©çå¦è 以å¤ã«ã¯é¦´æã¿ããªãå¾®å¦ããããã¾ããããã便å©ããã ãªãããã¨æã£ã¦ä½¿ã£ã¦ã¿ãã試ãã¦ã¿ããããã®ã§ãã¡ã¢ã¨ãã¦ã¾ã¨ãã¦ããã¾ãã誰ãã®åèã«ãªãã°å¹¸ãã§ãã
- einsum
- 縮ç´è¨æ³ã¨ã¯
- ä¾
- ææ³
- è¡å(åä½)
- è¡åæ¼ç®ãã®â
- ãã¯ãã«æ¼ç®ãã®â¡
- ã¬ãããã¿è¨å·ã¨ãã®å¿ç¨(è¡åå¼ãéè¡åãå¤ç©)
- æ§è½æ¯è¼
- ã¾ã¨ãã¨ææ³
einsum
Einstein(ã¢ã¤ã³ã·ã¥ã¿ã¤ã³)ã®ç¸®ç´è¨æ³é¢¨ã«è¶³ãåãããã§ããnumpyã®é¢æ°
縮ç´è¨æ³ã¨ã¯
ãã¨ãã°ãè¡å 㨠ã£ã¦ããã®ããã£ã¦ãè¡åã®æ¼ç®ããããã¨ããã«æ£ç´ã«æ¸ã㨠ã¨ãã風ã«è¨ç®ãããã ããããæ¼ç®ã§ãã大éã«åºã¦ããããã®ã§ãããããç¥ãã¦ãã¾ããã¨ãªã£ãã
ã«ã¼ã«ã¯
- åãè¨å·ã®ã¨ããã¯è¶³ãåãããã
ããã ãããã£ãã®è¶³(ã®ã®é¨å)ã
- 0å ã¹ã«ã©ã¼
- 1å ãã¯ãã«
- 2å è¡å
- 3åä»¥ä¸ é«éãã³ã½ã«
便å©ãªã®ã¯ã足ã®æ°ã3ã¤ä»¥ä¸ã¤ãã¦ãã*2ãã³ã½ã«è¨ç®ãç°¡åã«ã§ããã¨ãããã¨ã ç©çå¦ã®ä¸ç(ç¸å¯¾è«ãªã©)ã§ã¯ããã®é«æ¬¡ãã³ã½ã«ã§ã®è¨ç®ãããããåºã¦ãããã
ããããªã«æ¸ãã¦ããããï¼ã
ã¨ãããã¨ã§ãç¥ãããã
ä¾
- è¡åæ¼ç®(è¡å) ->
- ãã¯ãã«ã¨ã®å ç© ->
- è¡åã®ãã¬ã¼ã¹ ->
ææ³
np.einsum('ä»ãã足'->'æ®ããã足')
ããã ããããã¾ãã¡ããããªãã¨æãã®ã§ãå®éã«ä½¿ã£ã¦ã¿ãã
è¡å(åä½)
1ã¤ã®è¡åã§è²ã è¨ç®ãã¦ã¿ã
import numpy as np # è¡åãä½ã a = np.arange(25).reshape(5,5) b = np.arange(25).reshape(5,5)*2 print("A = ",a) print("B =", b) >>> A = [[ 0 1 2 3 4] >>> [ 5 6 7 8 9] >>> [10 11 12 13 14] >>> [15 16 17 18 19] >>> [20 21 22 23 24]] >>>B = [[ 0 2 4 6 8] >>> [10 12 14 16 18] >>> [20 22 24 26 28] >>> [30 32 34 36 38] >>> [40 42 44 46 48]]
np.einsum("ii",a) #60 np.einsum("ii->i",a) #[ 0, 6, 12, 18, 24] np.einsum("ij->i",a) #[ 10, 35, 60, 85, 110] np.einsum("ij->j",a) #[50, 55, 60, 65, 70] np.einsum("ij->ji",a) >>> array([[ 0, 5, 10, 15, 20], >>> [ 1, 6, 11, 16, 21], >>> [ 2, 7, 12, 17, 22], >>> [ 3, 8, 13, 18, 23], >>> [ 4, 9, 14, 19, 24]])
è¡åæ¼ç®ãã®â
2ã¤ä»¥ä¸ã®è¡åã®æ¼ç®ãè¡ã(使ãã®ã¯ãã£ãã®A,B)
np.einsum("ij,jk->ik",a,b) #AB np.einsum("ij,jk->ki",a,b) #BA 足(ik)ãå¤ãã£ãã®ã«æ³¨æ np.einsum("ij,ij->ij",a,b) #ããããã¢ããã¼ã«ç©
ãã¯ãã«æ¼ç®ãã®â¡
ãã¯ãã«ã®æ¼ç®ããè¡åã¨ã»ã¼åæ§ã«ã§ãã
v1 = np.arange(3) #[0,1,2] v2 = np.arange(3)+1 #[1,2,3]
np.einsum("i,i",v1,v2) #å ç© np.einsum("i,j->ij",v1,v2) #ç´ç©
ã¬ãããã¿è¨å·ã¨ãã®å¿ç¨(è¡åå¼ãéè¡åãå¤ç©)
ãã³ã½ã«è¡¨è¨ã®æã«æ°ã«ãªãã®ããè¡åå¼ãéè¡åãå¤ç©ã®è¨ç®ã£ã¦ã©ãããã®ãï¼ï¼ã¨ãããã¨ã ããããæã«ä¾¿å©ãªã®ãã¬ãããã¿(Levi Civita)è¨å·ãå®ç¾©ã¯ä»¥ä¸ã®éã
hogehoge
3次å
以ä¸ç©ºéã®æã«ã¯ããã®è¨å·ãè¨ç®ãã¹ãããªã¾ã¨ãããã¦ä¾¿å©ã
ããã使ãã¨ãeinsum
ã®æ çµã¿ã§ããå¤æ§ãªè¨ç®ãå®ç¾ã§ãã
ãã ããã¬ãããã¿è¨å·ã¯èª¿ã¹ãç¯å²ã§ã¯å®è£ ããã¦ãªãããï¼*3ãªã®ã§èªåã§ã¤ãã
# using "Levi civita symbols" (As long as I search, there is no built-in function) eijk = np.zeros((3, 3, 3)) eijk[0, 1, 2] = eijk[1, 2, 0] = eijk[2, 0, 1] = 1 eijk[0, 2, 1] = eijk[2, 1, 0] = eijk[1, 0, 2] = -1
å¤ç©(Cross Product)
v1 = np.arange(3) v2 = np.arange(3)+1 cross_numpy = np.cross(v1,v2)) cross_einsum = np.einsum('ijk,i,j->k', eijk, v1, v2))
è¡åå¼(Determinant)
- Levi Civitaã使ã£ãè¡åå¼ã®å ¬å¼(3Ã3)
A = np.arange(9).reshape(3,3) det_numpy = np.linalg.det(A) det_einsum = np.einsum('ijk,i,j,k',eijk,A[0],A[1],A[2]) #0
â» ã¡ãã£ã¨ã ããããããï¼ã§ãã¹ãããªã¯ãã¦ããããè¦åæ§ãããããæ¡å¼µã容æã
éè¡å
ããããããããCramer's fomula
ããã¤ã使ãã¨ãLevi-Civitaè¨å·ã使ã£ã¦è¡åæ¼ç®ã§éè¡åãæ±ãããã (4次å 以ä¸ã¯é«æ¬¡ã®Levi-Civitaè¨å·ã¸ã®æ¡å¼µãå¿ è¦(å¾è¿°))
# inverse(éè¡å) A = np.arange(9).reshape(3,3) A[0,0] = 1 # numpyã®å®é¨ã³ã¼ã http://d.hatena.ne.jp/sleepy_yoshi/20120513/p1 inv_numpy1 = np.linalg.inv(A) #numpy inv_numpy2 = np.linalg.solve(A, np.identity(3)) det_einsum = np.einsum('ijk,i,j,k',eijk,A[0],A[1],A[2]) inv_einsum = np.einsum('ijk,pqr,qj,rk->ip',eijk,eijk,A,A)/(2.0*det_einsum)
é«é/é«æ¬¡ã¸ã®æ¡å¼µ
é«é(足ã®æ°ãå¤ã)ãã¤é«æ¬¡å ã®ãã³ã½ã«ã«å¯¾ãã¦ããã¤ãã·ãã³ãå®ç¾©ãããã¨ã«ãããè¨ç®ãå¯è½(Generalized Edinton's Epsilon) Wikipediaã«æ¸ãã¦ãã(ã¨ãã£ã³ãã³ã®ã¤ãã·ãã³) ããã§ä»»æã®æ¬¡å ã§ä¸è¨å¼ã使ãã*4
æ§è½æ¯è¼
é度ãå®éã®ã¨ããbuilt-inã®numpyã¨æ¯ã¹ã¦ã©ããªã®ããã¡ãã£ã¨æ¸¬ã£ã¦ã¿ã ä»å測ãã®ã¯
- å ç©è¨ç® : (1,1,....,1)å士ã®å ç©ã10000åè¨ç®ããæã®æé(1-100次å )
- è¡åæ¼ç®1 : è¦ç´ ã1ã®NÃNè¡åã®ç©ã10000åè¨ç®
- è¡åæ¼ç®2 : è¦ç´ ã1ã®NÃNã®è¡å(AB)Cã100åè¨ç®
- å¤ç© : (1,1,1)Ã(1,1,1) ã10000åè¨ç®
- è¡åå¼ : np.arange(9).reshape(3,3)ã®è¡åå¼ã10000åè¨ç®
- éè¡å : np.arange(9).reshape(3,3)ã®[0,0]æåã ã1ã«å¤æããè¡åã®éè¡åã10000åè¨ç®
ã¾ãã測ã£ãPCã®ã¹ããã¯ã¯ - OS : Mac OSX - ããã»ããµ : 1.3GHz Intel Core M - ã¡ã¢ãª 8GB 1600MHz DDR3
å¼±ãã¹ããã¯ã®ãã·ã³ãªã®ã§ãåèç¨åº¦ã«ã©ãã
å ç©è¨ç®
numpyã®æ¹ã2åãããæ©ãã
ã³ã¼ã*5
%matplotlib inline import matplotlib.pyplot as plt import time ### å ç© time_num = [] time_ein = [] d = 101 iteration = 10000 for N in range(d): a = np.ones(N) b = np.ones(N) np_start = time.time() for _ in range(iteration): np.dot(a,b) time_num.append(time.time()-np_start) ein_start = time.time() for _ in range(iteration): np.einsum("i,i",a,b) time_ein.append(time.time()-ein_start) plt.plot(range(d),time_num,label="builtin") plt.plot(range(d),time_ein,label="einsum") plt.xlabel("dimension") plt.ylabel("time") plt.xlim(0,100) plt.savefig("inner.png") plt.legend()
è¡åæ¼ç®1 : è¦ç´ ã1ã®NÃNè¡åã®ç©
å·¦ã1-100次å ãå³ã1-20次å ã次å ãé«ãã¨ããã§ã¯numpyã®å§å
è¡åæ¼ç®2 : è¦ç´ ã1ã®NÃNã®è¡åã®(AB)C(3ã¤ã®ç©)
å·¦ã1-100次å ãå³ã1-5次å ãå§åå ·åãããã«ã²ã©ã
ã¡ãªã¿ã«3ã¤ã®è¡åã®ç©ãeinsumã§ããã¨ãã
np.einsum("ij,jk,kl->il",a,b,c)
å¤ç© : (1,1,1)Ã(1,1,1)
numpy : 0.21898913383483887 einsum: 0.04619288444519043
einsumã«è»é ã
è¡åå¼ : np.arange(9).reshape(3,3)ã®è¡åå¼
numpy : 0.14093804359436035 einsum: 0.06131696701049805
einsumã«è»é ã
éè¡å : np.arange(9).reshape(3,3)ã®[0,0]æåã ã1ã«å¤æããè¡åã®éè¡å
np.linalg.inv : 0.15855097770690918 np.linalg.solve : 0.27668190002441406 einsum : 0.45436620712280273
numpyã«è»é
ã¾ã¨ãã¨ææ³
- é«æ¬¡å ã«ãªãã¨å§åçã«è¨ç®æéãããã
- ä½æ¬¡å (d<10)ç¨åº¦ãªã2ã¢ãã¤ç¨åº¦ã®è¨ç®æé
- å¤ç©ã¨è¡åå¼ã ãã¯çµã¿è¾¼ã¿ããæ©ã
- ãã ããã¬ãããã¿ãã¤ãã£ã¦è¡åæ¼ç®ãnumpyã§ããã¨ãã½ããã®ã»ããæ©ãããã
é«æ¬¡ã®è¡åæ¼ç®ããã³ãã³åºã¦ããæ©æ¢°å¦ç¿ãªã©ã«ã¯å°ãä¸åãããªã¨æãã ãã ã â - ä½æ¬¡å ã§ã¯éè²ãªãè¨ç®é - ç´æçãªè¡¨è¨ã§ã®è¨ç®ãå¯è½ â ãªãã¨ãèããã¨ãç©çç³»ã®æ¼ç®ã§ç¨ããã®ã¯ãããããããªãã§ããã é«éã®ãã³ã½ã«ã«ãªãã¨ãã©ã®è¶³ãæ¶ããã ã£ãï¼ã¨ãé¢åãªãã¨ã«ãªãã®ã§ã â æ £ãã¦ãã表è¨æ³ã§ãã®ã¾ã¾è¨ç®ã§ããã®ã¯ããã¹ãå°ãªããªãã¾ãããã â ä½ãã®ç©çè¨ç®ãã¡ããã£ã¨ç¢ºãããæã¨ãã«ã使ã£ã¦ã¿ã¦ã¯ãããã§ãããããã§ã¯ã§ã¯ã£ï¼ â