2011-02-06 29 views
5

Ben Table[expr,{x,...}]xStandart olmayan değerlendirme ve PackedArray

Ben aralıklı başarısız kullanarak sona erdi tarifi korur aynı şekilde geçerli bağlamda değerlendirme tutucu sembolü x korur allTrue[{x,list},test] fonksiyonunu nasıl asked önceki var ve sorunların otomatik olarak PackedArrays'e otomatik olarak dönüştürülmesinden kaynaklandığını gördüm. İşte otomatik PackedArray dönüştürülmüş olur bakılmaksızın {1,2,3} ait True dönmek allTrue[{x,{1,2,3}},x>0] istiyorum başarısız bir örnek

SetAttributes[allTrue, HoldAll]; 
allTrue[{var_, lis_}, expr_] := 
    LengthWhile[lis, 
    TrueQ[ReleaseHold[Hold[expr] /. HoldPattern[var] -> #]] &] == 
    Length[lis]; 
allTrue[{y, Developer`ToPackedArray[{1, 1, 1}]}, y > 0] 

var, bunu uygulamak için daha iyi bir yolu nedir?

+0

'LengthWhile [FromPackedArray @ lis', ... –

+0

çalışır Evet, şu anda kullanıyorum, ancak bu tür bir görev için iyi bir genel stil daha ilgimi çekiyor –

+2

Dokümanlardan ** ToPackedArray kullanmak Mathematica ** tarafından üretilen sonuçları değiştirmeyecek ... lier! lier! Pantolonlar ateş içinde! –

cevap

7

Oldukça uzun süredir kullandığım bir süredir (kitabımın ikinci bir baskısı için yazdım, ancak çok kullanıyorum). Eğer argümanlar bazı değerlendirilmemiş kodları gösteriyorsa, o zaman test edilmemiş formunda (istenebilir ya da olmayabilir) belirli bir maddeyi temsil eden tek bir kod parçası istiyorsak test fonksiyonunun HoldAll ya da HoldFirst özniteliklerine sahip olması gerekir.

ClearAll[fastOr]; 
Attributes[fastOr] = {HoldRest}; 
fastOr[test_, {args___}] := fastOr[test, args]; 
fastOr[test_, args___] := 
TrueQ[Scan[ 
     Function[arg, If[test[arg], Return[True]], HoldAll], 
     Hold[args]]]; 

Düzenleme: Ben sadece söz konusu bağlantılı sayfanın alt kısmında Daniel Reeves tarafından çözüm, buna çok benzer olduğunu gördük. En önemli fark şudur: hem kısa devreler hem de argümanları değerlendirilmemişken (aşağıya bakınız), Daniel sadece kısa devre yapan parçalara odaklanırken.

Kısa devre davranışı var. Bağımsız değişken formundaki argümanları korumak istediğimiz için HoldRest özniteliğine ihtiyacımız var. Ayrıca, test'a geçirilene kadar bağımsız olarak değerlendirilen argümanların her birini korumak için HoldAll (veya HoldFirst) özniteliğine de ihtiyacımız var. test gövdesinde kullanılmadan önce değerlendirilip değerlendirilmeyeceği test'un özelliklerine bağlıdır. Bir örnek olarak: burada

Clear[fullSquareQ]; 
fullSquareQ[x_Integer] := IntegerQ[Sqrt[x]]; 

In[13]:= Or @@ Map[fullSquareQ, Range[50000]] // Timing 

Out[13]= {0.594, True} 

In[14]:= fastOr[fullSquareQ, Evaluate[Range[10000]]] // Timing 

Out[14]= {0., True} 

biz bağımsız değişken olarak kod indükleyici yan etkiler (baskı) bazı parçaları geçen bir örnektir. fastOr Or için maddelerinde olarak unevaluated kod genel parçalarını kabul beri
In[15]:= fastOr[# &, Print["*"]; False, Print["**"]; False, 
    Print["***"]; True, Print["****"]; False] 

During evaluation of In[15]:= * 

During evaluation of In[15]:= ** 

During evaluation of In[15]:= *** 

Out[15]= True 

Not

, etmelisin ki: sonuç zaten önceki maddede belirlenen beri geçen tartışmanın kodu çalıştırmak için şansı yok Başlangıç ​​değerlerinde değerlendirileceklerini umursamadığınız takdirde Evaluate numaralı değerler listenizde sarın (yukarıdaki Range örneğinde olduğu gibi). Son olarak, nasıl kullanılabileceğini göstermek için fastOr için tutulan kodun programlı yapısını göstereceğim (dilerseniz tuttuğunuz ifadelerle çalışmayla ilgili küçük bir çarpışma kursu düşünün).bekletilen ifadelerle çalışırken aşağıdaki fonksiyonu çok kullanışlıdır:

joinHeld[a___Hold] := Hold @@ Replace[Hold[a], Hold[x___] :> Sequence[x], {1}]; 

Örnek:

İşte
In[26]:= joinHeld[Hold[Print[1]], Hold[Print[2], Print[3]], Hold[], Hold[Print[4]]] 

Out[26]= Hold[Print[1], Print[2], Print[3], Print[4]] 

programlı Baskı-s ile örnek kullanılmıştır düzenlenen argümanlar oluşturmak için kullanabilirsiniz nasıl yukarıda:

In[27]:= 
held = joinHeld @@ MapThread[Hold[Print[#]; #2] &, 
     {NestList[# <> "*" &, "*", 3], {False, False, True, False}}] 

Out[27]= Hold[Print["*"]; False, Print["**"]; False, Print["***"]; True, Print["****"]; False] 

fastOr onu geçmek için, başka kullanışlı deyim kullanır: hepimizin elde edene kadar Hold[args] eklenecek (veya başa) fonksiyon argümanları ve ardından Apply kullanmak (genel deyim Append[Hold[parts___],Unevaluated[newpart]] benziyor bu yüzden biz sonuna ekliyorsunuz parça istemiyorsanız, genel olarak, dikkat/değerlendirmek için prepending, biz Unevaluated sarın olmalıdır):

In[28]:= fastOr @@ Prepend[held, # &] 

During evaluation of In[28]:= * 

During evaluation of In[28]:= ** 

During evaluation of In[28]:= *** 

Out[28]= True 

Başvurduğunuz orijinal uygulama ile ilgili olarak, bir süre önce yaptığım yorumuma bakabilirsiniz. Sorun TakeWhile ve LengthWhile 8.0.0 paketlenmiş diziler için hatalar var, 8.0.1 kaynaklarda sabit - yani, 8.0.1'den başlayarak, benim ya da Michael'ın sürümünü kullanabilirsiniz.

HTH

Düzenleme:

Sadece anılan yayında, farklı bir sözdizimi istediğini fark

. Bu duruma, fastOr numaralı kuralı kabul etmek çok zor olmasa da, burada bu söz dizimi için mevcut dil yapıları ile daha yakın bir ilişki içinde olan farklı bir uygulama var. Table ve istisnaları kullanmanızı öneririm, çünkü yinelemeler Table'da istediğiniz gibi aynı sözdizimini kabul eder. İşte burada: açıklama

ClearAll[AnyTrue, AllTrue]; 
SetAttributes[{AnyTrue, AllTrue}, HoldAll]; 
Module[{exany, exall}, 
AnyTrue[iter : {var_Symbol, lis_List}, expr_] := 
    TrueQ[Catch[Table[If[TrueQ[expr], Throw[True, exany]], iter], exany]]; 
AllTrue[iter : {var_Symbol, lis_List}, expr_] := 
    Catch[Table[If[! TrueQ[expr], Throw[False, exall]], iter], exall] =!= False; 
]; 

birkaç kelime: Ben sadece bir kez tanımlamak gereken özel durum etiketleri beri üst düzeyde Modülü kullanmak, hem de tanım zamanında bunu yapabilir. Tablodan çıkmanın yolu istisnalardır. Çok zarif değil ve küçük bir performans artışı tetikliyor, ancak Table tarafından yapılan yineleyici değişkenlerinizin otomatik dinamik lokalizasyonunu ve basitliğini satın alıyoruz. Bunu güvenli bir şekilde yapmak için, bir istisnayı benzersiz bir etiketle etiketlemeliyiz, bu nedenle yanlışlıkla başka bir istisna yakalamayız. Genel olarak çok yararlı bir hile olmak için kalıcı istisna etiketlerini oluşturmak için Modülü kullanarak buluyorum. Şimdi, bazı örnekler: - Bu Table tarafından halledilir

In[40]:= i = 1 

Out[40]= 1 

In[41]:= AnyTrue[{i, {1, 2, 3, 4, 5}}, i > 3] 

Out[41]= True 

In[42]:= AnyTrue[{i, {1, 2, 3, 4, 5}}, i > 6] 

Out[42]= False 

In[43]:= AllTrue[{i, {1, 2, 3, 4, 5}}, i > 3] 

Out[43]= False 

In[44]:= AllTrue[{i, {1, 2, 3, 4, 5}}, i < 6] 

Out[44]= True 

In[45]:= AllTrue[{a, {1, 3, 5}}, AnyTrue[{b, {2, 4, 5}}, EvenQ[a + b]]] 

Out[45]= True 

In[46]:= AnyTrue[{a, {1, 3, 5}}, AllTrue[{b, {2, 4, 5}}, EvenQ[a + b]]] 

Out[46]= False 

Ben yineleyici değişkenlerinin olası küresel değerler önemi yok olduğunu göstermek için i bir atama ile başladı. Son olarak, (başka yerde yorumladı gibi), AllTrue için, orijinal imzaları dikkat ve AnyTrue aşağıdaki çalışmıyor anlamında, biraz fazla kısıtlayıcı:

In[47]:= lst = Range[5]; 
AllTrue[{i, lst}, i > 3] 

Out[48]= AllTrue[{i, lst}, i > 3] 

(lst bir listesini temsil gerçeği beri HoldAll özniteliği nedeniyle desen eşleştirme zamanında bilinmez. Orada bu davranışı tutmak için iyi bir neden, bu nedenle sadece _List kontrolleri kaldırabilirsiniz: AnyTrue[iter : {var_Symbol, lis_}, expr_] ve benzer AllTrue için ve kullanım durumları bu sınıf işlenecektir. performans üzerindeki etkileri hakkında emin, ama neredeyse emin değil

+0

Bu gerçekten şaşırtıcı. Yerleşik Mathematica işlevsel programlama yapıları, her biri "her" ve "bazı" öğelerini elde etmek için bu kadar çok şey yapmaları gerekiyorsa biraz fakirleşmiştir. – Harold

+0

@Harold Bunlar her zaman ve herşey değil, çünkü önceden hesaplanmış ifadelerle değil, derecelendirilmemiş kod parçalarıyla uğraşırlar. Ve bu o kadar fazla iş değildi, yazının çoğu pedagojik ve sadece uygulamalardan ziyade açıklamalara adanmış. Ayrıca, benim kodumun çok fazla karmaşık olduğu da olabilir. –

+0

Oh? Her 've' bazı 'için daha' normal 'tanımlamalar var mı? Resmi belgelerde yerleşik bir şey görmedim. (Yine de, orada bir şeyler bulmaya devam ediyorum) Belki de bunu Mathematica.stackexchange.com adresine bir soru olarak eklemeliyim ... – Harold

İlgili konular