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
endhangi 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
endGenel 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
ikullandık vei_1, i_2, i_3değ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...endarası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
endDoğ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 = 1Her ü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.@nloops — Macro@nloops N itersym rangeexpr bodyexpr
@nloops N itersym rangeexpr preexpr bodyexpr
@nloops N itersym rangeexpr preexpr postexpr bodyexprN 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
endSadece bir son ifadesi istiyorsanız, ön ifadesi için nothing sağlayabilirsiniz. Parantezler ve noktalı virgüller kullanarak çoklu ifade sağlayabilirsiniz.
Base.Cartesian.@nref — Macro@nref N A indexexprA[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])Base.Cartesian.@nextract — Macro@nextract N esym isymisym'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]Base.Cartesian.@nexprs — Macro@nexprs N exprN 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]
endBase.Cartesian.@ncall — Macro@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])Base.Cartesian.@ncallkw — Macro@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
Base.Cartesian.@ntuple — Macro@ntuple N exprBir N-demet oluşturur. @ntuple 2 i (i_1, i_2) oluştururken, @ntuple 2 k->k+1 (2,3) oluşturur.
Base.Cartesian.@nall — Macro@nall N exprAnonim 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.
Base.Cartesian.@nany — Macro@nany N exprAnonim 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.
Base.Cartesian.@nif — Macro@nif N conditionexpr expr
@nif N conditionexpr expr elseexprif ... 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