कई बिंदुओं पर एक फ़ंक्शन का मूल्यांकन करने का इष्टतम तरीका

Dec 12 2020

मेरे पिछले प्रश्न पर यह गुल्लक-पीठ: पैरामीटर स्थान खोज दिनचर्या बहुत तेज़ है?

मैं कई बिंदुओं पर एक प्रतीकात्मक सूची का मूल्यांकन करने के लिए एक तेज़ तरीके की तलाश कर रहा हूं। तो आइए हम बताते हैं जैसे कि प्रतीकात्मक अभिव्यक्तियों की एक सूची है

ListA={a*b*c>0, a*b*(c+1)>0, a*b*(c-1)>0, etc.}

और फार्म के tuples की एक सूची

ListB={{1,1,1}, {1,1,2}, {1,2,1}, {1,2,2}< etc.}

और मैं ListB के प्रत्येक टपल पर ListA का मूल्यांकन करना चाहता हूं

ListA/.Thread[{a,b,c} -> ListB[[1]]]
ListA /.Thread[{a,b,c} -> ListB[[2]]]

अब, मेरी सूची में दसियों हजार अंक हो सकते हैं और प्रत्येक अभिव्यक्ति सौ से अधिक हो सकती है। माई लिस्टबी भी गेनॉर्मस हो सकता है, जैसे कि दसियों अंकों के ऊपर। लेकिन प्रत्येक टपल में केवल ~ 5 तत्व होते हैं और मैंने इसे लगभग 100-1000 टुपल्स के आकार में चुना है। मेरा सवाल यह है कि इस प्रकार के प्रतिस्थापन / संघ को जल्दी से करने का सबसे अच्छा तरीका क्या होगा?

मेरे पहले प्रयास का उपयोग किया गया था ParallelMapलेकिन इसने अभी भी उम्र ली। फिर मैंने देखा Associationsऔर इसने समय को घटा दिया लेकिन लिस्ट बी के एक तत्व के प्रत्येक प्रतिस्थापन में अभी भी 1.5 - 2 सेकंड लगते हैं, जिसे मुझे काफी कम करना होगा। यहाँ संदर्भ के लिए एक MWE है:

func = (-2^(1 - px) (-1 + px) px Coth[
       rx sx]^2 (-2 sx y Sech[sx (-rx + x^2 + y^2)]^2 + 
        2 sx y Sech[sx (rx + x^2 + y^2)]^2)^2 (Coth[
         rx sx] (-Tanh[sx (-rx + x^2 + y^2)] + 
          Tanh[sx (rx + x^2 + y^2)]))^(-2 + px) - 
    2^(1 - px) px Coth[
      rx sx] (Coth[
         rx sx] (-Tanh[sx (-rx + x^2 + y^2)] + 
          Tanh[sx (rx + x^2 + y^2)]))^(-1 + 
        px) (-2 sx Sech[sx (-rx + x^2 + y^2)]^2 + 
       2 sx Sech[sx (rx + x^2 + y^2)]^2 + 
       8 sx^2 y^2 Sech[sx (-rx + x^2 + y^2)]^2 Tanh[
         sx (-rx + x^2 + y^2)] - 
       8 sx^2 y^2 Sech[sx (rx + x^2 + y^2)]^2 Tanh[
         sx (rx + x^2 + y^2)]) + 
    2^-px (-1 + px) px Coth[
       rx sx]^2 (-2 sx y Sech[sx (-R - rx + x^2 + y^2)]^2 + 
        2 sx y Sech[sx (-R + rx + x^2 + y^2)]^2)^2 (Coth[
         rx sx] (-Tanh[sx (-R - rx + x^2 + y^2)] + 
          Tanh[sx (-R + rx + x^2 + y^2)]))^(-2 + px) + 
    2^-px px Coth[
      rx sx] (Coth[
         rx sx] (-Tanh[sx (-R - rx + x^2 + y^2)] + 
          Tanh[sx (-R + rx + x^2 + y^2)]))^(-1 + 
        px) (-2 sx Sech[sx (-R - rx + x^2 + y^2)]^2 + 
       2 sx Sech[sx (-R + rx + x^2 + y^2)]^2 + 
       8 sx^2 y^2 Sech[sx (-R - rx + x^2 + y^2)]^2 Tanh[
         sx (-R - rx + x^2 + y^2)] - 
       8 sx^2 y^2 Sech[sx (-R + rx + x^2 + y^2)]^2 Tanh[
         sx (-R + rx + x^2 + y^2)]) + 
    2^-px (-1 + px) px Coth[
       rx sx]^2 (-2 sx y Sech[sx (R - rx + x^2 + y^2)]^2 + 
        2 sx y Sech[sx (R + rx + x^2 + y^2)]^2)^2 (Coth[
         rx sx] (-Tanh[sx (R - rx + x^2 + y^2)] + 
          Tanh[sx (R + rx + x^2 + y^2)]))^(-2 + px) + 
    2^-px px Coth[
      rx sx] (Coth[
         rx sx] (-Tanh[sx (R - rx + x^2 + y^2)] + 
          Tanh[sx (R + rx + x^2 + y^2)]))^(-1 + 
        px) (-2 sx Sech[sx (R - rx + x^2 + y^2)]^2 + 
       2 sx Sech[sx (R + rx + x^2 + y^2)]^2 + 
       8 sx^2 y^2 Sech[sx (R - rx + x^2 + y^2)]^2 Tanh[
         sx (R - rx + x^2 + y^2)] - 
       8 sx^2 y^2 Sech[sx (R + rx + x^2 + y^2)]^2 Tanh[
         sx (R + rx + x^2 + y^2)]));

parameters = {px, pz, R, rx, rz, sx, sz}
variables = {x, y, z}

Quantifier[coords_, params_] := 
 Function[Evaluate@Join[variables, parameters], Evaluate@(func > 0)][
  Sequence @@ Join[coords, params]]

SpaceA = Tuples[Range[-2, 2, 0.2], 3];

ListA = Quantifier[#1, parameters] & /@ SpaceA;
ListB = Tuples[Range[1, 4, 0.4], 7];
(*ListB contains~2 million elements*)

अब, मूल्यांकन ListAअधिक की ListBतरह होगा

(AllTrue[ListA /. Thread[parameters -> #], TrueQ]) & /@ ListB
(*Careful running this, it will probably take a few months :( *)

मेरी समस्या यह है कि एक भी संघ की तरह

ListA/.Thread[parameters->{1,1,1,1,1,1,1}]

लगभग 2 सेकंड लगते हैं। इसलिए इसे ~ 2 मिलियन अंकों की सूची में दोहराने से एक सदी लग जाएगी।

एक संकलित समारोह उपयोगी होगा? मुझे संकलन की कार्यक्षमता का उपयोग करने का अधिक अनुभव नहीं है, इसलिए मैं सोच रहा हूं कि क्या यह पता लगाने के लिए लाभप्रद होगा। मैं किसी भी अंतर्दृष्टि की सराहना करता हूं!

अपडेट करें

@Flinty सुझाव के लिए धन्यवाद, उपयोग करने से Withलगता है कि असाइनमेंट में काफी तेजी आई है। एक छोटा समय प्रयोग प्रयोग:

यहाँ, ऊपर MWE में QuantifieroverSpaceमेल खाती है ListA

ClearAll[\[Epsilon], px, pz, R, rx, rz, sx, sz]
ByteCount[QuantifieroverSpace]

With[{\[Epsilon] = 2, px = 1, pz = 5, R = 1, rx = 2, rz = 2, sx = 2, 
   sz = 2},
  Evaluate@AllTrue[QuantifieroverSpace, TrueQ]] // Timing

AllTrue[QuantifieroverSpace /. 
   Thread[{\[Epsilon], px, pz, R, rx, rz, sx, sz} -> {2, 1, 5, 1, 2, 
      2, 2, 2}], TrueQ] // Timing

(*126992696*)
(*{0.000026, False}*)

(*{2.08846, False}*)

इसलिए Withइसके बजाय का उपयोग करना ReplaceAllतीव्रता के कई आदेश हैं, जो दिलचस्प है। मैं इसे अपनी खोज रूटीन में लागू करूंगा और देखूंगा कि इसमें कितना सुधार हुआ है।

अपडेट २

तो मेरा अगला मुद्दा यह है कि मुझे तर्कों की Withसंख्या के लिए पहले तर्क की आवश्यकता है, अर्थात इसे {a = 1, b = 1, c = 1} या 3 चर सेट में लेने में सक्षम होना चाहिए। एक अलग संख्या जैसे {a = 1}। मेरा पहला हालांकि ऐसा कुछ करना होगा

With[
     {Thread[SymbolList = ArrayofValues]}, 
     ...
     ]

लेकिन गणितज्ञ ArrayofValuesप्रतीकों में मानों को असाइन कर रहा है SymbolListताकि aउदाहरण के लिए चर का मान 1 हो। मैंने तब कोशिश की थी

init = MapThread[HoldForm[#1=#2]&, {SymbolList, ArrayofValues}];
With[
     Evaluate@ReleaseHold[init],
     ...
     ]

लेकिन यह वही काम करता है, जो प्रतीकों को मान प्रदान करता है। दिलचस्प है, गणितज्ञ अभी भी withपहले तर्क में मूल्यों का उपयोग करके अभिव्यक्ति को निष्पादित करता है, लेकिन इसके प्रतीक को मूल्य अभी भी असाइन कर रहा है, जो कि अगर मैं असाइनमेंट को पूर्ववत करना चाहता था, तो मेरी खोज दिनचर्या के निष्पादन को धीमा कर देगा। मुझे किसी तरह Setआईएनजी असाइनमेंट को रोकने की जरूरत है, लेकिन अभी भी a=1एक तरह से वेरिएबल्स की संख्या को गतिशील बनाए रखता है ।

अपडेट ३

अच्छी तरह से आगे के निरीक्षण पर, मुझे लगा कि Withइतना तेज क्यों प्रतीत होता है। इसका कारण यह है कि वास्तव में अभिव्यक्ति में पहले तर्क के मूल्यों को सदस्यता नहीं दी जाती है। उदाहरण के लिए,

a = {l, s};
With[{l = 3, s = 12},
  Print[Evaluate[a]]
  ];

(*{l,s}*)

इसलिए मुझे लगता है कि मैं एक बड़े प्रतीकात्मक सरणी के अंदर मापदंडों को मान असाइन करने का एक तेज़ तरीका खोजने की कोशिश कर रहा हूँ।

जवाब

1 SimonWoods Dec 13 2020 at 02:19

यह केवल एक आंशिक उत्तर है, लेकिन ...

आपका कार्य बहुत जटिल है, और इसे तेज़ करना शायद इससे अधिक महत्वपूर्ण है कि आप इसे कैसे मान देते हैं। Compileयहाँ आपका दोस्त है

cfunc = Compile @@ {Join[variables, parameters], func, 
   CompilationTarget -> "C", "RuntimeOptions" -> "Speed", 
   RuntimeAttributes -> {Listable}}

RepeatedTiming[AllTrue[cfunc @@ Join[SpaceA // Transpose, ListB[[1]]], Positive]]
{0.0051, False}

की एक पंक्ति के लिए 5ms पर ListB, यह अभी भी एक लंबा समय लेने वाला है, हालांकि यह अधिक यथार्थवादी हो रहा है।