<İj | kl> iki parçacık integrali için verimli indeksleme fonksiyonu nasıl uygulanır?


11

Bu basit bir simetri numaralandırma problemidir. Burada tam bir arka plan veriyorum, ama kuantum kimyası bilgisi gerekli değil.

İki parçacık integrali geçerli: i j | k l = ψ * ı ( x ) ψ * j ( X ' ) ψ k ( x ) ψ l ( x ' )ij|kl Ve Aşağıdaki 4 simetrileri vardır: i j | k l = j i | l k = k l | i j = l k | j i bir 1D dizideki tamamlayıcı ve saklar hesaplayan bir fonksiyonu olan, aşağıdaki gibi, dizin:

ij|kl=ψi(x)ψj(x)ψk(x)ψl(x)|xx|d3xd3x
ij|kl=ji|lk=kl|ij=lk|ji
int2
int2(ijkl2intindex2(i, j, k, l))

burada fonksiyon ijkl2intindex2, yukarıdaki simetrileri dikkate alarak benzersiz bir dizin döndürür. Tek gereksinim, i, j, k, l (her biri 1'den n'ye kadar) tüm kombinasyonları üzerinde döngü yaparsanız, int2diziyi art arda doldurur ve yukarıdakilerle ilgili tüm ijkl kombinasyonlarına aynı dizini atar. 4 simetri.

Fortran'daki şu anki uygulamam burada . Çok yavaş. Bunu nasıl etkili bir şekilde yapacağınızı bilen var mı? (Herhangi bir dilde.)

ψi(x)ikjl

ij|kl=ji|lk=kj|il=il|kj=
=kl|ij=lk|ji=il|kj=kj|il

ijkl(ij|kl)=ik|jljk


d3x

1
d3xdx1dx2dx3x=(x1,x2,x3)d3x

xx=(x1,x2,x3)dx

d3x

Yanıtlar:


5

[Düzenle: 4. kez cazibe, sonunda mantıklı bir şey]

nn2(n2+3)t(t(n))+t(t(n1))t(a)at(a)=a(a+1)/2

ijtid(i,j)tid(k,l)tid(a,b)a,b

def ascendings(n):
    idx = 0
    for i in range(1,n+1):
        for j in range(1,i+1):
            for k in range(1,i):
                for l in range(1,k+1):
                    idx = idx + 1
                    print(i,j,k,l)
            k=i
            for l in range(1,j+1):
                idx = idx + 1
                print(i,j,k,l)
    return idx

llk

t(t(n1))

def mixcendings(n):
    idx = 0
    for j in range(2,n+1):
        for i in range(1,j):
            for k in range(1,j):
                for l in range(1,k):
                    print(i,j,k,l)
                    idx = idx + 1
            k=j
            for l in range(1,i+1):
                print(i,j,k,l)
                idx = idx + 1
    return idx

Bunların her ikisinin kombinasyonu tam seti verir, bu nedenle her iki döngüyü bir araya getirmek bize tam indeks setini verir.

n

Python'da her bir farklı senaryo için idx ve i, j, k, l değerlerini vermek üzere aşağıdaki yineleyiciyi yazabiliriz:

def iterate_quad(n):
    idx = 0
    for i in range(1,n+1):
        for j in range(1,i+1):
            for k in range(1,i):
                for l in range(1,k+1):
                    idx = idx + 1
                    yield (idx,i,j,k,l)
                    #print(i,j,k,l)
            k=i
            for l in range(1,j+1):
                idx = idx + 1
                yield (idx,i,j,k,l)

    for i in range(2,n+1):
        for j in range(1,i):
            for k in range(1,i):
                for l in range(1,k):
                    idx = idx + 1
                    yield (idx,i,j,k,l)
            k=i
            for l in range(1,j+1):
                idx = idx + 1
                yield (idx,i,j,k,l)

in3+jn2+kn+l

integer function squareindex(i,j,k,l,n)
    integer,intent(in)::i,j,k,l,n
    squareindex = (((i-1)*n + (j-1))*n + (k-1))*n + l
end function

integer function generate_order_array(n,arr)
    integer,intent(in)::n,arr(*)
    integer::total,idx,i,j,k,l
    total = n**2 * (n**2 + 3)
    reshape(arr,total)
    idx = 0
    do i=1,n
      do j=1,i
        do k=1,i-1
          do l=1,k
            idx = idx+1
            arr(idx) = squareindex(i,j,k,l,n)
          end do
        end do
        k=i
        do l=1,j
          idx = idx+1
          arr(idx) = squareindex(i,j,k,l,n)
        end do
      end do
    end do

    do i=2,n
      do j=1,i-1
        do k=1,i-1
          do l=1,j
            idx = idx+1
            arr(idx) = squareindex(i,j,k,l,n)
          end do
        end do
        k=i
        do l=1,j
          idx = idx+1
          arr(idx) = squareindex(i,j,k,l,n)
        end do
      end do
    end do

    generate_order_array = idx
  end function

Ve sonra bunun üzerine döngü yapın:

maxidx = generate_order_array(n,arr)
do idx=1,maxidx
  i = idx/(n**3) + 1
  t_idx = idx - (i-1)*n**3
  j = t_idx/(n**2) + 1
  t_idx = t_idx - (j-1)*n**2
  k = t_idx/n + 1
  t_idx = t_idx - (k-1)*n
  l = t_idx

  ! now have i,j,k,l, so do stuff
  ! ...
end do

Merhaba Phil, cevap için çok teşekkürler! Test ettim ve iki sorun var. Örneğin idx_all (1, 2, 3, 4, 4) == idx_all (1, 2, 4, 3, 4) = 76. Fakat <12 | 34> / = <12 | 43>. Sadece yörüngeler gerçekse eşittir. Yani çözümünüz 8 simetri durumunda gibi görünüyor (daha basit bir sürüm için yukarıdaki Fortran örneğime bakın, ijkl2intindex ()). İkinci sorun, endekslerin ardışık olmaması, sonuçları buraya yapıştırdım: gist.github.com/2703756 . Yukarıdaki benim ijkl2intindex2 () rutininden doğru sonuçlar: gist.github.com/2703767 .
Ondřej Čertík

1
@ OndřejČertík: İlişkili bir işaret mi istiyorsunuz? Sipariş değiştirdiyseniz idxpair bir işaret döndürür.
Deathbreath

OndřejČertík: Farkı şimdi görüyorum. @Deathbreath'in işaret ettiği gibi, dizini reddedebilirsiniz, ancak bu genel döngü için temiz olmayacaktır. Bir düşüneceğim ve güncelleyeceğim.
Phil H

Aslında, idxpair değeri yanlış alacağından dizini reddetmek tam olarak çalışmaz.
Phil H

<ij|kl>=<ji|kl>=<ij|lk>=<ji|lk>
ijkl[idxpair(indexij,indexkl,,)]signijsignkl

3

Simetri durumları için aynı anahtarı döndürmek için değiştirilmiş basit bir boşluk doldurma eğrisi kullanma fikri (tüm kod snippet'leri python'dur).

# Simple space-filling curve
def forge_key(i, j, k, l, n): 
  return i + j*n + k*n**2 + l*n**3

# Considers the possible symmetries of a key
def forge_key_symmetry(i, j, k, l, n): 
  return min(forge_key(i, j, k, l, n), 
             forge_key(j, i, l, k, n), 
             forge_key(k, l, i, j, n), 
             forge_key(l, k, j, i, n)) 

Notlar:

  • Örnek python'dur, ancak fonksiyonları fortran kodunuza satır içine alır ve iç döngünüzü (i, j, k, l) için açarsanız, iyi bir performans elde etmelisiniz.
  • Anahtarı float kullanarak hesaplayabilir ve ardından anahtarı dizin olarak kullanmak için tamsayıya dönüştürebilirsiniz, bu da derleyicinin kayan nokta birimlerini kullanmasına izin verir (örn. AVX kullanılabilir).
  • N, 2'lik bir güçse, çarpmalar sadece biraz kayma olur.
  • Simetriler için işlem bellekte etkili değildir (yani sürekli bir indeksleme üretmez) ve toplam indeks dizisi girişlerinin yaklaşık 1 / 4'ünü kullanır.

İşte n = 2 için bir test örneği:

for i in range(n):
  for j in range(n):
    for k in range(n):
      for l in range(n):
        key = forge_key_symmetry(i, j, k, l, n)
        print i, j, k , l, key

N = 2 için çıkış:

i j k l key
0 0 0 0 0
0 0 0 1 1
0 0 1 0 1
0 0 1 1 3
0 1 0 0 1
0 1 0 1 5
0 1 1 0 6
0 1 1 1 7
1 0 0 0 1
1 0 0 1 6
1 0 1 0 5
1 0 1 1 7
1 1 0 0 3
1 1 0 1 7
1 1 1 0 7
1 1 1 1 15

İlgileniyorsanız, forge_key öğesinin ters işlevi:

# Inverse of forge_key
def split_key(key, n): 
  d = key / n**3
  c = (key - d*n**3) / n**2
  b = (key - c*n**2 - d*n**3) / n 
  a = (key - b*n - c*n**2 - d*n**3)
  return (a, b, c, d)

Şunu mu demek istediniz: "n, 2'nin gücü ise 2" yerine?
Aron Ahmadia

evet, teşekkürler Aron. Bu cevabı akşam yemeğine gitmeden hemen önce yazdım ve Hulk yazıyordu.
fcruz

Zeki! Ancak, maksimum dizin n ^ 4 (veya 0'dan başlarsanız n ^ 4-1) değil mi? Sorun, yapmak istediğim temel boyut için, belleğe sığmayacak olmasıdır. Ardışık dizinde, dizinin boyutu n ^ 2 * (n ^ 2 + 3) / 4. Hm'dir, bu zaten tam boyutun sadece 1 / 4'ü kadardır. Bu yüzden belki de bellek tüketimindeki 4 faktörü hakkında endişelenmemeliyim. Yine de, sadece bu 4 simetriyi (çift döngüler yapmam gereken çirkin çözümümden daha iyi) kullanarak ardışık dizini kodlamanın bir yolu olmalı.
Ondřej Čertík

evet, bu doğru! Nasıl dizin (sıralama ve yeniden numaralandırma) zarif çözmek için nasıl bilmiyorum ama bellek kullanımında önde gelen terim O (N ^ 4). 4 faktörü büyük N için bellekte küçük bir fark
yaratmalıdır

0

Bu sadece paketlenmiş simetrik matris indeksleme probleminin genelleştirilmesi değil mi? Oradaki çözüm ofset (i, j) = i * (i + 1) / 2 + j, değil mi? Bunu iki katına çıkaramaz ve çift simetrik bir 4D dizisini indeksleyemez misiniz? Dallanma gerektiren uygulama gereksiz gözükmektedir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.