Base.Cartesian

Cartesian modülü, çok boyutlu algoritmalar yazmayı kolaylaştıran makrolar sağlar. Genellikle bu tür algoritmaları straightforward techniques ile yazabilirsiniz; ancak Base.Cartesian'ın hala faydalı veya gerekli olduğu birkaç durum vardır.

Principles of usage

Kullanımın basit bir örneği:

@nloops 3 i A begin
    s += @nref 3 A i
end

hangi aşağıdaki kodu üretir:

for i_3 = axes(A, 3)
    for i_2 = axes(A, 2)
        for i_1 = axes(A, 1)
            s += A[i_1, i_2, i_3]
        end
    end
end

Genel olarak, Cartesian, bu örnekteki gibi iç içe döngüler gibi tekrarlayan öğeler içeren genel kod yazmanıza olanak tanır. Diğer uygulamalar arasında tekrarlanan ifadeler (örneğin, döngü açma) veya "splat" yapısını (i...) kullanmadan değişken sayıda argümanla fonksiyon çağrıları oluşturma yer alır.

Basic syntax

@nloops'un (temel) sözdizimi aşağıdaki gibidir:

  • İlk argüman, döngü sayısını belirten bir tam sayı olmalıdır (değişken değil).
  • İkinci argüman, yineleyici değişkeni için kullanılan sembol-ön ekidir. Burada i kullandık ve i_1, i_2, i_3 değişkenleri oluşturuldu.
  • Üçüncü argüman, her bir yineleyici değişkeni için aralığı belirtir. Burada bir değişken (sembol) kullanırsanız, bu axes(A, dim) olarak alınır. Daha esnek bir şekilde, aşağıda açıklanan anonim fonksiyon ifade sözdizimini kullanabilirsiniz.
  • Son argüman döngünün gövdesidir. Burada, bu begin...end arasında görünen şeydir.

@nloops'un bazı ek özellikleri reference section'de açıklanmıştır.

@nref, benzer bir deseni takip eder ve @nref 3 A i ifadesinden A[i_1,i_2,i_3] üretir. Genel uygulama soldan sağa okumaktır, bu yüzden @nloops ifadesi @nloops 3 i A expr şeklindedir (örneğin for i_2 = axes(A, 2), burada i_2 solda ve aralık sağdadır) oysa @nref ifadesi @nref 3 A i şeklindedir (örneğin A[i_1,i_2,i_3], burada dizi önce gelir).

Eğer Cartesian ile kod geliştiriyorsanız, oluşturulan kodu inceleyerek hata ayıklamanın daha kolay olduğunu görebilirsiniz, @macroexpand kullanarak:

julia> @macroexpand @nref 2 A i
:(A[i_1, i_2])

Supplying the number of expressions

Bu makroların her ikisine de ilk argüman, bir tam sayı olması gereken ifade sayısıdır. Birden fazla boyutta çalışmasını istediğiniz bir fonksiyon yazarken, bu durumu sabit kodlamak istemeyebilirsiniz. Önerilen yaklaşım, bir @generated function kullanmaktır. İşte bir örnek:

@generated function mysum(A::Array{T,N}) where {T,N}
    quote
        s = zero(T)
        @nloops $N i A begin
            s += @nref $N A i
        end
        s
    end
end

Doğal olarak, quote bloğundan önce ifadeler hazırlayabilir veya hesaplamalar yapabilirsiniz.

Anonymous-function expressions as macro arguments

Belki de Cartesian'ın en güçlü özelliği, anonim fonksiyon ifadeleri sağlamanın ve bunların ayrıştırma zamanında değerlendirilmesinin mümkün olmasıdır. Basit bir örneği ele alalım:

@nexprs 2 j->(i_j = 1)

@nexprs n ifadeleri üreten bir yapıdır. Bu kod aşağıdaki ifadeleri üretecektir:

i_1 = 1
i_2 = 1

Her üretilen ifadede, "izole" bir j (anonim fonksiyonun değişkeni) 1:2 aralığındaki değerlerle değiştirilir. Genel olarak, Cartesian LaTeX benzeri bir sözdizimi kullanır. Bu, j indeksinde matematik yapmanıza olanak tanır. İşte bir dizinin adımlarını hesaplayan bir örnek:

s_1 = 1
@nexprs 3 j->(s_{j+1} = s_j * size(A, j))

ifade üretecek

s_1 = 1
s_2 = s_1 * size(A, 1)
s_3 = s_2 * size(A, 2)
s_4 = s_3 * size(A, 3)

Anonim fonksiyon ifadelerinin pratikte birçok kullanımı vardır.

Macro reference

Base.Cartesian.@nloopsMacro
@nloops N itersym rangeexpr bodyexpr
@nloops N itersym rangeexpr preexpr bodyexpr
@nloops N itersym rangeexpr preexpr postexpr bodyexpr

N iç içe döngüleri oluşturur, itersym döngü değişkenleri için önek olarak kullanılır. rangeexpr bir anonim fonksiyon ifadesi veya basit bir sembol var olabilir; bu durumda aralık axes(var, d) şeklindedir ve d boyutunu temsil eder.

İsteğe bağlı olarak, "ön" ve "son" ifadeleri sağlayabilirsiniz. Bu ifadeler, her döngünün gövdesinde ilk ve son olarak yürütülür. Örneğin:

@nloops 2 i A d -> j_d = min(i_d, 5) begin
    s += @nref 2 A j
end

şu şekilde bir çıktı üretecektir:

for i_2 = axes(A, 2)
    j_2 = min(i_2, 5)
    for i_1 = axes(A, 1)
        j_1 = min(i_1, 5)
        s += A[j_1, j_2]
    end
end

Sadece bir son ifadesi istiyorsanız, ön ifadesi için nothing sağlayabilirsiniz. Parantezler ve noktalı virgüller kullanarak çoklu ifade sağlayabilirsiniz.

source
Base.Cartesian.@nrefMacro
@nref N A indexexpr

A[i_1, i_2, ...] gibi ifadeler oluşturur. indexexpr ya bir iterasyon sembolü öneki ya da anonim fonksiyon ifadesi olabilir.

Örnekler

julia> @macroexpand Base.Cartesian.@nref 3 A i
:(A[i_1, i_2, i_3])
source
Base.Cartesian.@nextractMacro
@nextract N esym isym

isym'den değerleri çıkarmak için esym_1, esym_2, ..., esym_N değişkenlerini oluşturur. isym ya bir Symbol ya da anonim fonksiyon ifadesi olabilir.

@nextract 2 x y şu sonucu üretir:

x_1 = y[1]
x_2 = y[2]

@nextract 3 x d->y[2d-1] ise şu sonucu verir:

x_1 = y[1]
x_2 = y[3]
x_3 = y[5]
source
Base.Cartesian.@nexprsMacro
@nexprs N expr

N ifadeleri oluşturur. expr anonim-fonksiyon ifadesi olmalıdır.

Örnekler

julia> @macroexpand Base.Cartesian.@nexprs 4 i -> y[i] = A[i+j]
quote
    y[1] = A[1 + j]
    y[2] = A[2 + j]
    y[3] = A[3 + j]
    y[4] = A[4 + j]
end
source
Base.Cartesian.@ncallMacro
@ncall N f sym...

Fonksiyon çağrısı ifadesi oluşturun. sym, herhangi bir sayıda fonksiyon argümanını temsil eder; bunların sonuncusu bir anonim fonksiyon ifadesi olabilir ve N argümanına genişletilir.

Örneğin, @ncall 3 func a şu sonucu üretir:

func(a_1, a_2, a_3)

@ncall 2 func a b i->c[i] ise şu sonucu verir:

func(a, b, c[1], c[2])
source
Base.Cartesian.@ncallkwMacro
@ncallkw N f kw sym...

Anahtar argümanlar kw... ile bir fonksiyon çağrısı ifadesi oluşturun. @ncall durumunda olduğu gibi, sym herhangi bir sayıda fonksiyon argümanını temsil eder, bunların sonuncusu bir anonim fonksiyon ifadesi olabilir ve N argümanına genişletilir.

Örnekler

julia> using Base.Cartesian

julia> f(x...; a, b = 1, c = 2, d = 3) = +(x..., a, b, c, d);

julia> x_1, x_2 = (-1, -2); b = 0; kw = (c = 0, d = 0);

julia> @ncallkw 2 f (; a = 0, b, kw...) x
-3
source
Base.Cartesian.@ntupleMacro
@ntuple N expr

Bir N-demet oluşturur. @ntuple 2 i (i_1, i_2) oluştururken, @ntuple 2 k->k+1 (2,3) oluşturur.

source
Base.Cartesian.@nallMacro
@nall N expr

Anonim fonksiyon ifadesi expr tarafından üretilen tüm ifadelerin true değerine sahip olup olmadığını kontrol edin.

@nall 3 d->(i_d > 1) ifadesi (i_1 > 1 && i_2 > 1 && i_3 > 1) ifadesini üretecektir. Bu, sınır kontrolü için kullanışlı olabilir.

source
Base.Cartesian.@nanyMacro
@nany N expr

Anonim fonksiyon ifadesi expr tarafından üretilen ifadelerden herhangi birinin true değerine eşit olup olmadığını kontrol eder.

@nany 3 d->(i_d > 1) ifadesi (i_1 > 1 || i_2 > 1 || i_3 > 1) ifadesini üretecektir.

source
Base.Cartesian.@nifMacro
@nif N conditionexpr expr
@nif N conditionexpr expr elseexpr

if ... elseif ... else ... end ifadelerinin bir dizisini oluşturur. Örneğin:

@nif 3 d->(i_d >= size(A,d)) d->(error("Boyut ", d, " çok büyük")) d->println("Her şey tamam")

şu şekilde oluşturulacaktır:

if i_1 > size(A, 1)
    error("Boyut ", 1, " çok büyük")
elseif i_2 > size(A, 2)
    error("Boyut ", 2, " çok büyük")
else
    println("Her şey tamam")
end
source