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 vei_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.@nloops
— Macro@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.
Base.Cartesian.@nref
— Macro@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])
Base.Cartesian.@nextract
— Macro@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]
Base.Cartesian.@nexprs
— Macro@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
Base.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 expr
Bir 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 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.
Base.Cartesian.@nany
— Macro@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.
Base.Cartesian.@nif
— Macro@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