Boyutsal agnostik kodu nasıl yazarım?


19

Kendimi genellikle belirli bir işlem / algoritmanın bir, iki ve üç boyutlu sürümleri için çok benzer kod yazarken buluyorum. Tüm bu sürümleri korumak sıkıcı olabilir. Basit kod üretimi oldukça iyi çalışır, ancak daha iyi bir yol olması gerektiği düşünülmektedir.

Bir işlemi bir kez yazmanın ve daha yüksek veya daha düşük boyutlara genellemesini sağlamanın nispeten basit bir yolu var mı?

Somut bir örnek: varsayalım ki spektral uzayda bir hız alanının gradyanını hesaplamalıyım. Üç boyutta, Fortran döngüleri şöyle görünecektir:

do k = 1, n
  do j = 1, n
    do i = 1, n
      phi(i,j,k) = ddx(i)*u(i,j,k) + ddx(j)*v(i,j,k) + ddx(k)*w(i,j,k)
    end do
  end do
end do

burada ddxdizi uygun tanımlanır. (Bunu matris çarpanları ile de yapabilirsiniz.) İki boyutlu bir akış için kod neredeyse tamamen aynıdır, ancak: üçüncü boyut döngülerden, dizinlerden ve bileşen sayısından çıkarılır. Bunu ifade etmenin daha iyi bir yolu var mı?

Başka bir örnek: varsayalım ki, üç boyutlu bir ızgara üzerinde noktasal olarak tanımlanan sıvı hızlarım var. Hızı keyfi bir konuma enterpole etmek için (örn. Izgara noktalarına karşılık gelmez), tek boyutlu Neville algoritmasını üç boyutun tamamında (yani boyutsal küçültme) art arda kullanabilir . Basit bir algoritmanın tek boyutlu olarak uygulanmasıyla boyutsal küçültme yapmanın kolay bir yolu var mı?

Yanıtlar:


13

Deal.II'nin ( http://www.dealii.org/ ) bunu nasıl yaptığına bakıyorsunuz - orada, boyut bağımsızlığı kütüphanenin tam kalbinde yer alıyor ve çoğu veri türü için bir şablon argümanı olarak modelleniyor. Örneğin, 4. adımdaki öğretici programdaki boyutsal agnostik Laplace çözücüsüne bakın:

http://www.dealii.org/developer/doxygen/deal.II/step_4.html

Ayrıca bakınız

https://github.com/dealii/dealii/wiki/Frequently-Asked-Questions#why-use-templates-for-the-space-dimension


Kesinlikle katılıyorum. Deal.II'den daha iyi bir yaklaşım bulamadım. Bu sorunu çözmek için şablonları çok ilginç bir şekilde kullanırlar.
Eldila

1
İyi bir kaynak, ancak C ++ şablonlarını büyütmezseniz oldukça korkutucu.
meawoppl

@Wolfgang Bangerth: deal.ii şablonlar kullanarak da yineleyicileri tanımlar mı?
Matthew Emmett

@MatthewEmmett: Evet.
Wolfgang Bangerth

@meawoppl: Aslında hayır. Dersleri düzenli olarak anlaşmayla öğretiyorum. II ve başlangıçta öğrencilere ClassWhatever <2> diyen her şeyin 2d, ClassWhatever <3> 3D ve ClassWhatever <dim> dim-d olduğunu söyleyin. Şablonlar dersini 3. haftada bir yere getiriyorum ve öğrencilerin muhtemelen bundan önce nasıl çalıştığını anlamadıkları halde, yine de bunu kullanarak tamamen işlevseller .
Wolfgang Bangerth

12

Soru, çoğu "düz" programlama dilinin (en azından C, Fortran,) bunu temiz bir şekilde yapmanıza izin vermediğini vurgulamaktadır. Ek bir kısıtlama, notasyonel rahatlık ve iyi performans istemenizdir .

Bu nedenle, boyuta özgü bir kod yazmak yerine, boyuta özgü bir kod üreten bir kod yazmayı düşünün . Bu jeneratör, hesaplama kodu olmasa bile boyuttan bağımsızdır. Başka bir deyişle, gösteriminiz ile hesaplamayı ifade eden kod arasına bir mantık katmanı eklersiniz. C ++ şablonları aynı anlama gelir: Tersine, doğrudan dile yerleştirilirler. Olumsuz, yazmak biraz hantal. Bu, kod üretecinin pratik olarak nasıl gerçekleştirileceği sorusunu azaltır.

OpenCL, çalışma zamanında kod oluşturmayı oldukça temiz bir şekilde yapmanızı sağlar. Ayrıca 'dış kontrol programı' ve 'iç döngüler / çekirdekler' arasında çok temiz bir ayrım yapar. Dış, üreten program çok daha az performans kısıtlıdır ve bu nedenle Python gibi rahat bir dilde de yazılabilir. PyOpenCL'in nasıl kullanılacağına dair umudum - yenilenmiş utanmaz fiş için özür dilerim.


Andreas! Scicomp'a Hoşgeldiniz! Sizi sitede ziyaret etmekten memnunum, herhangi bir sorunuz varsa benimle nasıl iletişime geçeceğinizi bildiğinizi düşünüyorum.
Aron Ahmadia

2
C ++ büyüsü yerine bu soruna bir çözüm olarak otomatik kod üretimi için +10000.
Jeff

9

Bu, aşağıdaki kaba zihinsel prototiple herhangi bir dilde gerçekleştirilebilir:

  1. Her boyutun boyutlarının bir listesini oluşturun (sanırım MATLAB'de şekil () gibi bir şey)
  2. Her boyutta geçerli konumunuzun bir listesini oluşturun.
  3. Dış döngüye göre boyut değişiklikleri üzerinde bir döngü içeren her boyutun üzerine bir döngü yazın.

Oradan, kodunuzu uyumlu tutmak için belirli bir dilin sözdizimiyle mücadele etmek söz konusudur.

N-boyutlu bir akışkan-dinamik çözücü yazdıktan sonra , bir işlevin argümanları olarak nesne gibi bir listenin paketini açmayı destekleyen bir dile sahip olmanın yararlı olduğunu buldum. Yani a = (1,2,3) f (a *) -> f (1,2,3). Buna ek olarak, gelişmiş yineleyiciler ( sayısal olarak ütumerat gibi ) kodu daha büyük bir temizliğe dönüştürür.


Bunu yapmak için Python sözdizimi hoş ve özlü görünüyor. ... Fortran ile bunu yapmak için güzel bir yol olup olmadığını merak
Matthew Emmett

1
Fortran'daki dinamik bellekle uğraşmak biraz acı verici. Muhtemelen benim dil ile büyük şikayet.
meawoppl

5

n1×n2×n3nj=1


Boyuttan bağımsız olmak için, kodunuzun maxdim + 1 boyutları için yazılması gerekir; burada maxdim, kullanıcının karşılaşabileceği maksimum boyuttur. Diyelim ki maxdim = 100. Ortaya çıkan kod ne kadar yararlı?
Jeff

4

Fortran'ın hızını korumak istiyorsanız açık cevaplar Julia veya C ++ gibi uygun kod oluşturma özelliğine sahip bir dil kullanmaktır. C ++ şablonlarından daha önce bahsedilmişti, bu yüzden Julia'nın araçlarından bahsedeceğim. Julia'nın oluşturduğu işlevler , meta bilgileri kullanarak tür bilgisi yoluyla isteğe bağlı işlevler oluşturmanıza olanak tanır. Yani aslında burada yapabilecekleriniz

@generated function f(x)
   N = ndims(x)
   quote
     # build the code for the function
   end
end

ve sonra boyutsal Nolduğu için yürütmek istediğiniz kodu programlı olarak oluşturmak için kullanın N. Daha sonra Julia'nın Kartezyen kütüphanesi veya Einsum.jl ifadeleri gibi paketler Nboyutsal işlev için kolayca oluşturulabilir .

Julia ile ilgili güzel olan şey, bu fonksiyonun kullandığınız her yeni boyutlu dizi için statik olarak derlenmiş ve optimize edilmiş olmasıdır, bu yüzden ihtiyacınız olandan daha fazlasını derlemeyecektir, ancak size C / Fortran hızını alacaktır. Sonunda bu C ++ şablonlarını kullanmaya benzer, ancak daha kolay hale getirmek için birçok araçla daha üst düzey bir dildir (bu, bir undergrad için güzel bir ödev problemi olacak kadar kolay).

Bunun için iyi olan bir diğer dil de Lisp benzeri Common Lisp'dir. Kullanımı kolaydır çünkü Julia gibi derlenmiş AST'ye çok sayıda yerleşik introspection aracı verir, ancak Julia'nın aksine otomatik olarak derlemez (çoğu dağıtımda).


1

Aynı (Fortran) gemideyim. 1D, 2D, 3D ve 4D (projektif geometri yapıyorum) öğelerimi aldıktan sonra, her tip için aynı operatörleri oluşturuyorum ve sonra mantığımı, neler olduğunu netleştiren yüksek seviyeli denklemlerle yazıyorum. Her işlemin ayrı döngülerine ve çok sayıda bellek kopyasına sahip olabileceğinizi düşündüğünüz kadar yavaş değildir. Derleyicinin / işlemcinin optimizasyon yapmasına izin verdim.

Örneğin

interface operator (.x.)
    module procedure cross_product_1x2
    module procedure cross_product_2x1
    module procedure cross_product_2x2
    module procedure cross_product_3x3
end interface 

subroutine cross_product_1x2(a,b,c)
    real(dp), intent(in) :: a(1), b(2)
    real(dp), intent(out) :: c(2)

    c = [ -a(1)*b(2), a(1)*b(1) ]
end subroutine

subroutine cross_product_2x1(a,b,c)
    real(dp), intent(in) :: a(2), b(1)
    real(dp), intent(out) :: c(2)

    c = [ a(2)*b(1), -a(1)*b(1) ]
end subroutine

subroutine cross_product_2x2(a,b,c)
    real(dp), intent(in) :: a(2), b(2)
    real(dp), intent(out) :: c(1)

    c = [ a(1)*b(2)-a(2)*b(1) ]
end subroutine

subroutine cross_product_3x3(a,b,c)
    real(dp), intent(in) :: a(3), b(3)
    real(dp), intent(out) :: c(3)

    c = [a(2)*b(3)-a(3)*b(2), a(3)*b(1)-a(1)*b(3), a(1)*b(2)-a(2)*b(1)]
end subroutine

Gibi denklemlerde kullanılacak

m = e .x. (r .x. g)  ! m = e×(r×g)

nerede eve rve gmatematiksel mantıklı herhangi bir boyutsallığa sahip olabilir.

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.