6.17. الحلَّالات والأعداد العشوائية¶
عندما تكون الدالة قيد الدراسة مُعرّفةً بشيفرة Python بدلًا من مخزن مؤقت من العينات، تكون عائلةٌ مختلفةٌ من الأدوات هي الاختيار الصحيح: أين جذر الدالة، وأين أصغريّتها، وما تكاملها على مجال معطى؟ تغطي الوحدتان الفرعيتان scipy.integrate و scipy.optimize هذا العمل. وتستدعي كل خوارزمية دالة Python التي يوفرها المستخدم، فتكون التكلفة لكل تكرار أعلى من تخفيض مخزن مؤقت؛ والراحة تكمن في عدم الاضطرار إلى كتابة الحلَّال.
تغطي الوحدة الفرعية scipy.special الدوال الإحصائية الخاصة (دالة الخطأ، ودالة غاما) التي تظهر عند حساب دالة التوزيع التراكمي (CDF، احتمال أن تكون العينة على الأكثر قيمةً معطاة) أو دالة كثافة الاحتمال (PDF، الأرجحية النسبية عند قيمة معطاة) لتوزيع احتمالي ما. وتغطي numpy.random المولّد شبه العشوائي للتذبيب والمحاكاة وبيانات الاختبار الاصطناعية.
6.17.1. التكامل العددي لكائن قابل للاستدعاء¶
عندما يكون المُكامَل دالةَ Python بدلًا من مخزن مؤقت من العينات، تكشف scipy.integrate أربع خوارزميات تربيع:
quad()-- غاوس-كرونرود التكيفية. الافتراضي الصحيح للمُكامَلات الناعمة. تُعيد(value, error).romberg()-- رومبيرغ / نيوتن-كوتس الكلاسيكية. تُعيد عددًا عشريًا واحدًا. مُهملة في المنبع؛ مُضمّنة للتوافق.simpson()-- قاعدة سيمبسون التكيفية. تُعيد عددًا عشريًا واحدًا.tanhsinh()-- التربيع الأُسّي المزدوج. استخدمها عندما يكون للمُكامَل شذوذات عند الطرفين أو حدٌّ لانهائي. تُعيد(value, error).
التكامل الغاوسي مُقيَّمًا بالقاعدة الأُسّية المزدوجة (tanhsinh):
from math import exp
from math import pi
from math import sqrt
from ulab import numpy as np
from ulab import scipy as sp
f = lambda x: exp(-x * x)
value, err = sp.integrate.tanhsinh(f, -np.inf, np.inf)
print("approx:", value, " exact:", sqrt(pi))
الخرج:
approx: 1.7724538... exact: 1.7724538...
6.17.2. إيجاد الجذور والتصغير¶
تغطي scipy.optimize ثلاثة حلَّالات كلاسيكية أحادية المتغير. ويستدعي كل تكرار دالة Python التي يوفرها المستخدم، فيكون التسريع مقارنةً بحلَّال مكتوب بـ Python خالص متواضعًا (نحو الضِّعفين)؛ والراحة تكمن في عدم الاضطرار إلى كتابة الحلَّال.
bisect()-- إيجاد جذر لـfعلى[a, b]بتنصيف المجال. ويجب أن تكون لـf(a)وf(b)إشارتان متعاكستان:def f(x): return x * x - 1 sp.optimize.bisect(f, 0, 4) # ~1.0
newton()-- إيجاد جذر باستخدام تكرار القاطع / نيوتن-رافسون:def f(x): return x * x * x - 2.0 sp.optimize.newton(f, 3., tol=0.001, rtol=0.01) # ~1.260
fmin()-- إيجاد أصغريّة محلية باستخدام طريقة المُجسَّم البسيط المنحدر (نيلدر-ميد):def f(x): return (x - 1) ** 2 - 1 sp.optimize.fmin(f, 3.0) # ~1.0
النطاق أحادي المتغير كافٍ لمعظم عمليات التحسين من جانب الكاميرا -- ثابت معايرة مستشعر، أو الكسب الذي يُعظّم قياس تباين، أو العتبة التي يكون عندها التوزيع ثنائي القمة في المدرج التكراري أكثرَ حدّة. أما بالنسبة للمسائل متعددة المتغيرات، فالجواب الصحيح عادةً هو إعادة صياغة المسألة بوصفها حلَّ جبر خطي صغيرًا بدلًا من اللجوء إلى مُحسِّن لاخطي عام.
6.17.3. الدوال الخاصة¶
تكشف scipy.special حفنةً من الدوال الإحصائية والاحتمالية التي تتصرف كدوال شاملة -- إذ تقبل قيمةً قياسيةً، أو كائنًا قابلًا للتكرار، أو ndarray وتُعيد ndarray عشرية:
x = np.linspace(0, 4, num=8)
sp.special.erf(x) # error function
sp.special.erfc(x) # complementary error function
sp.special.gamma(x + 1) # gamma function
sp.special.gammaln(x + 1) # log-gamma function
تظهر دالة الخطأ ومتممتها في الـ CDF لتوزيع غاوسي -- وهو التطبيق المُفضّل للتحويل بين درجة z مقيسة واحتمال، أو لحساب التكامل الذيلي لتوزيع طبيعي. وتظهر دالتا غاما ولوغاريتم غاما في حسابات بيتا / مربع كاي / ستيودنت-t؛ والصيغة gammaln هي الصورة المستقرة عدديًا للوسائط الكبيرة حيث تطفح gamma نفسها.
6.17.4. الأعداد العشوائية¶
توفر numpy.random صنفًا Generator يسحب عينات من التوزيعات الشائعة. والمولّد ذو حالة: إذ يُقدّم كل استدعاء حالتَه الداخلية، بحيث تُعيد الاستدعاءات المتتالية عينات مستقلة:
from ulab import numpy as np
rng = np.random.Generator(seed=42)
rng.random(size=5) # 5 uniform [0.0, 1.0) samples
rng.uniform(low=-1.0, high=1.0, size=10)
rng.normal(loc=0.0, scale=1.0, size=(2, 4))
نوع بيانات الخرج هو دائمًا float. وتقبل size= عددًا صحيحًا (خرج أحادي البُعد) أو صفًّا (خرج متعدد الأبعاد)؛ وعند حذفها، يُعاد عدد Python عشري واحد.
المولّد مناسب للمحاكاة والتذبيب وبيانات الاختبار الاصطناعية وأي تطبيق آخر لا تُشترط فيه القوة التعميية. وهو غير مناسب للمفاتيح أو الرموز؛ استخدم مصدر النظام العشوائي عبر os لتلك الأغراض.
6.17.5. التوافر وقت البناء¶
يعتمد ما إذا كانت كل وحدة فرعية موجودةً فعلًا على كيفية بناء الكاميرا. فالوحدتان scipy.optimize و scipy.special غير مُفعّلتين على كل كاميرا؛ واستدعاء دالة لا تتضمنها الكاميرا يطلق AttributeError. وتُبلّغ dir(sp) و dir(sp.optimize) و dir(np.random) وأخواتها عمّا هو متاح على الكاميرا المستهدفة.