مرحبا يا هبر! اليوم هو برنامج تعليمي مصغر حول كيفية تحليل سلسلة مع تعبير رياضي وحسابها باستخدام أرقام ثلاثية غامضة. مع التغييرات المناسبة على الكود ، سيعمل البرنامج التعليمي مع المتغيرات "المخصصة" الأخرى. مساعدة: أرقام ثلاثية غامضة - حالة خاصة من أرقام غامض (المتغيرات غامض على المحور العددي). أوصي بالتعرف
هنا بمزيد من التفاصيل
هنا وهنا .
المتطلبات:
- لغة البرمجة python 3.x (تم اختبار الكود الموجود في المقالة على python 3.5)
- مكتبة sympy ، يمكن تثبيتها من خلال المحطة (وحدة التحكم):
pip install sympy
الإجراء الخاص بحل المشكلة:
- نحن نربط المكتبات
from fractions import Fraction import re from typing import Iterable from random import random import sympy
كسور الاتصال اختيارية ، سنستخدم الكسر لتخزين الأرقام الحقيقية في شكل الكسر (من أجل تقليل فقدان الدقة). سنستخدم مكتبة re لإعادة تحليل السلاسل وإنشاء قائمة متغيرات الأحرف تلقائيًا.
يعد استخدام مكتبة الكتابة أمرًا اختياريًا ؛ فنحن نستخدمها للإشارة بوضوح إلى أنواع معلمات الوظيفة. سيتم استخدام المكتبة العشوائية لإنشاء قيم اختبار للمتغيرات غامض. sympy هي مكتبة رائعة لحسابات الشخصيات في بيثون ، حيث سنعمل مع سلسلة التعبير نفسها.
- وصفنا فئة الأرقام المثلثة الغامضة والعمليات عليها. في هذا المثال ، ثلاث عمليات كافية (الجمع والطرح والقسمة). سنقدم العمليات باستخدام الحمل الزائد للطرق "السحرية" للفئة المقابلة:
class FuzzyTriangular(object): """ FuzzyTriangular""" def __init__(self, floatdigit = None, ABC = None, CAB = None, CDD = None): super(FuzzyTriangular, self).__init__() if ABC or floatdigit: if isinstance(floatdigit, (int, float)): self._a = Fraction(floatdigit)
أشكال تمثيل الأرقام الثلاثية الغامضة يمكن أن تكون مختلفة ، فلن نمضي عميقًا. في التعليمة البرمجية المقدمة ، سننتبه إلى الطرق __add__ (مشغل الإضافة) ، __sub__ (عامل الطرح) ، __mul__ (مشغل الضرب). إذا حاولت إضافة رقم حقيقي إلى رقم مثلث غامض ، فسيتم تحويله إلى رقم مثلث غامض. حالة مماثلة مع tuple أو قائمة بالأرقام الحقيقية - سيتم اعتبار أول ثلاثة أرقام على شكل مثلث غامض (وتحويلها أيضًا إلى فئة FuzzyTriangular). يتجاوز الأسلوب __pos__ العامل الأحادي "+". أسلوب __neg__ أحادي "-". يتجاوز الأسلوب __eq__ العامل ==. إذا رغبت في ذلك ، يمكنك أيضًا إعادة تعريف العمليات مثل:
- الانقسام
- الأس
- معامل الرقم
- مقارنات (أكثر / أقل ، أكثر أو متساوية / أقل أو متساوية)
- تحجيم (يلقي إلى كثافة العمليات ، تعويم ، أعداد معقدة ، التقريب)
- انقلاب وغيرها ...
يمكنك التحقق من كفاية العمليات التي تم إدخالها باستخدام مجموعة صغيرة من الاختبارات ، على سبيل المثال ،
ZERO = FuzzyTriangular((0,0,0)) ONE = FuzzyTriangular((1,1,1)) A = FuzzyTriangular((0.3,0.5,0.9)) B = FuzzyTriangular((0.2,0.4,0.67)) C = FuzzyTriangular((0,0.33,0.72)) print('ZERO = '+str(ZERO)) print('ONE = '+str(ONE)) print('A = '+str(A)) print('B = '+str(B)) print('C = '+str(C))
يتم تحديد عمليات التحقق من الجمع والقسمة والضرب في التعليمات البرمجية ويتم تنفيذها وفقًا لإعادة تعريف الطرق "السحرية". نود أن نكون قادرين على تنفيذ نفس العمليات باستخدام متغيرات الرمز في تعبيرات غير معروفة سابقًا. هذا يتطلب إدخال العديد من الوظائف المساعدة. - نقدم وظائف مساعدة:
def symbols_from_expr(expr_str: str, pattern=r"[A-Za-z]\d{,2}") -> tuple: """ """ symbols_set = set(re.findall(pattern, expr_str)) symbols_set = sorted(symbols_set) symbols_list = tuple(sympy.symbols(symbols_set)) return symbols_list
سنستخدم هذه الوظيفة للبحث عن متغيرات الأحرف في سلسلة تعبير (القالب الافتراضي هو حرف من A إلى Z أو من a إلى z و عدد صحيح بعد طوله يصل إلى حرفين) (أو عدم وجود رقم). def expr_subs(expr_str: str, symbols: Iterable, values: Iterable): """ values symbols - expr_str""" expr = sympy.sympify(expr_str) func = sympy.lambdify(tuple(symbols), expr, 'sympy') return func(*values)
تسمح لك هذه الوظيفة بحساب قيمة تعبير السلسلة باستخدام الإحلال بدلاً من المتغيرات الرمزية المتغيرات من أي نوع صالح (إذا تم إعادة تعريف العمليات الموجودة في تعبير السلسلة نفسه). هذا ممكن بفضل وظيفة sympy.lambdify ، التي تحول تعبير sympy إلى دالة lambda تقبل الأساليب "السحرية". الشرط المهم لكي تعمل الوظيفة بشكل صحيح هو الترتيب الصحيح للعناصر في الرموز والقيم (مراسلة الرموز والقيم البديلة).- كل مرة إنشاء وظيفة lambda مكلفة. إذا كان الاستخدام المتعدد لنفس التعبير مطلوبًا ، فمن المستحسن استخدام الدالتين التاليتين:
def lambda_func(expr_str: str, symbols: Iterable) -> callable: """ -, - expr_str symbols""" expr = sympy.sympify(expr_str) func = sympy.lambdify(tuple(symbols), expr, 'sympy') return func def func_subs(expr_func: callable, values: Iterable): """ - expr_func values""" return expr_func(*values)
أول واحد إرجاع وظيفة lambda نفسها ، والثاني يسمح لك لحساب القيم الناتجة عن طريق استبدال قائمة القيم. مرة أخرى ، يركز الانتباه على حقيقة أن القيم المستخدمة لا يجب أن تكون أرقامًا غامضة ثلاثية.
- نقرأ خط الصيغة من الملف
with open('expr.txt', 'r') as file: expr_str = file.read() print('expr_str', expr_str)
يمكن استخدام شيء من هذا القبيل كصيغة سطر لملف expr.txt:
p36*q67*p57*p26*p25*p13*q12*q15 + + p36*q67*p47*p26*p24*p13*q12 + + p67*q57*p26*p25*q12*p15 + + q57*p47*p25*p24*q12*p15 + + p57*p25*p12*q15 + + p36*p67*p13 + + p67*p26*p12 + + p47*p24*p12 + + p57*p15 - - p57*p47*p24*p12*p15 - - p67*p47*p26*p24*p12 - - p67*p57*p26*p12*p15 + + p67*p57*p47*p26*p24*p12*p15 - - p36*p67*p26*p13*p12 - - p36*p67*p47*p24*p13*p12 - - p36*p67*p57*p13*p15 + + p36*p67*p57*p47*p24*p13*p12*p15 + + p36*p67*p47*p26*p24*p13*p12 + + p36*p67*p57*p26*p13*p12*p15 - - p36*p67*p57*p47*p26*p24*p13*p12*p15 - - p36*p67*p57*p25*p13*p12*q15 - - p67*p57*p26*p25*p12*q15 - - p57*p47*p25*p24*p12*q15 + + p67*p57*p47*p26*p25*p24*p12*q15 + + p36*p67*p57*p26*p25*p13*p12*q15 + + p36*p67*p57*p47*p25*p24*p13*p12*q15 - - p36*p67*p57*p47*p26*p25*p24*p13*p12*q15 - - p36*p67*q57*p47*q26*p25*p24*p13*q12*p15 - - p67*q57*p47*p26*p25*p24*q12*p15 - - p36*p67*q57*p26*p25*p13*q12*p15 - - p36*q67*q57*p47*p26*p25*p24*p13*q12*p15 - - p36*q67*p57*p47*p26*p24*p13*q12*p15 - - p36*q67*p57*p47*p26*p25*p24*p13*q12*q15
- نحصل على متغيرات الأحرف من تعبير السلسلة:
symbols = symbols_from_expr(expr_str) print('AutoSymbols', symbols)
- نحن نولد اختبار أرقام ثلاثية عشوائية:
values = tuple([FuzzyTriangular(sorted([random(),random(),random()]))\ for i in range(len(symbols))])
يلزم فرز القيم العشوائية لمطابقة ترتيب قيم اليسار "0" والوسط واليمين "0". - تحويل سلسلة الصيغة إلى تعبير:
func = lambda_func(expr_str, symbols) print('func', '=', func)
- نحسب قيمة الصيغة باستخدام دالة lambda (نستخدم func_subs و expr_subs للتأكد من تطابق النتائج):
print('func_subs', '=', func_subs(func, values)) print('expr_subs', '=', expr_subs(expr_str, symbols, values))
مثال الإخراج:
expr_str p36*q67*p57*p26*p25*p13*q12*q15 + + p36*q67*p47*p26*p24*p13*q12 + + p67*q57*p26*p25*q12*p15 + + q57*p47*p25*p24*q12*p15 + + p57*p25*p12*q15 + + p36*p67*p13 + + p67*p26*p12 + + p47*p24*p12 + + p57*p15 - - p57*p47*p24*p12*p15 - - p67*p47*p26*p24*p12 - - p67*p57*p26*p12*p15 + + p67*p57*p47*p26*p24*p12*p15 - - p36*p67*p26*p13*p12 - - p36*p67*p47*p24*p13*p12 - - p36*p67*p57*p13*p15 + + p36*p67*p57*p47*p24*p13*p12*p15 + + p36*p67*p47*p26*p24*p13*p12 + + p36*p67*p57*p26*p13*p12*p15 - - p36*p67*p57*p47*p26*p24*p13*p12*p15 - - p36*p67*p57*p25*p13*p12*q15 - - p67*p57*p26*p25*p12*q15 - - p57*p47*p25*p24*p12*q15 + + p67*p57*p47*p26*p25*p24*p12*q15 + + p36*p67*p57*p26*p25*p13*p12*q15 + + p36*p67*p57*p47*p25*p24*p13*p12*q15 - - p36*p67*p57*p47*p26*p25*p24*p13*p12*q15 - - p36*p67*q57*p47*q26*p25*p24*p13*q12*p15 - - p67*q57*p47*p26*p25*p24*q12*p15 - - p36*p67*q57*p26*p25*p13*q12*p15 - - p36*q67*q57*p47*p26*p25*p24*p13*q12*p15 - - p36*q67*p57*p47*p26*p24*p13*q12*p15 - - p36*q67*p57*p47*p26*p25*p24*p13*q12*q15 AutoSymbols (p12, p13, p15, p24, p25, p26, p36, p47, p57, p67, q12, q15, q26, q57, q67) func = <function <lambda> at 0x06129C00> func_subs = (-0.391482058715, 0.812813114469, 2.409570627378) expr_subs = (-0.391482058715, 0.812813114469, 2.409570627378) [Finished in 1.5s]
انتهى البرنامج التعليمي. أتمنى أن تجد شيئًا مفيدًا هنا!
ملاحظة: تتمثل "الميزة" الرئيسية للنهج الموصوف في القدرة على تجاوز الأنواع القياسية للمتغيرات والعمليات عليها من أجل بيثون و sympy. من خلال الإعلان عن فصلك وزيادة التحميل على الأساليب "السحرية" ، يمكنك حساب التعبيرات الرياضية غير المعروفة سابقًا باستخدام sympy (إنشاء وظائف lambda التي تقبل كل من أنواع وأنواع وعمليات التشغيل القياسية).
شكرا لاهتمامكم!