Halo, Habr! Today adalah tutorial miniatur tentang cara mengurai string dengan ekspresi matematika dan menghitungnya menggunakan angka segitiga fuzzy. Dengan perubahan yang sesuai pada kode, tutorial akan bekerja dengan variabel "khusus" lainnya. Bantuan: angka segitiga fuzzy - kasus khusus angka fuzzy (variabel fuzzy pada sumbu numerik). Saya merekomendasikan untuk berkenalan
di sini secara lebih rinci di
sini dan di
sini .
Persyaratan:
- Bahasa pemrograman python 3.x (kode yang disediakan dalam artikel diuji pada python 3.5)
- perpustakaan sympy , dapat diinstal melalui terminal (konsol):
pip install sympy
Prosedur untuk memecahkan masalah:
- Kami menghubungkan perpustakaan
from fractions import Fraction import re from typing import Iterable from random import random import sympy
Fraksi koneksi adalah opsional, kami akan menggunakan Fraksi untuk menyimpan bilangan real dalam bentuk fraksi (untuk meminimalkan hilangnya keakuratan). Kami akan menggunakan pustaka ulang untuk string parsing dan secara otomatis menghasilkan daftar variabel karakter.
Menggunakan perpustakaan pengetikan adalah opsional, kami menggunakannya untuk secara eksplisit menunjukkan jenis parameter fungsi. Pustaka acak akan digunakan untuk menghasilkan nilai tes untuk variabel fuzzy. sympy adalah pustaka hebat untuk perhitungan karakter dengan Python, dengan itu kita akan bekerja dengan string ekspresi itu sendiri.
- Kami menggambarkan kelas angka segitiga fuzzy dan operasi pada mereka. Dalam contoh ini, tiga operasi sudah cukup (penjumlahan, pengurangan dan pembagian). Kami akan memperkenalkan operasi menggunakan metode "sihir" yang berlebihan dari kelas terkait:
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)
Bentuk representasi bilangan segitiga fuzzy bisa berbeda, kita tidak akan masuk jauh. Dalam kode yang disajikan, kami akan memperhatikan metode __add__ (operator tambahan), __sub__ (operator pengurangan), __mul__ (operator multiplikasi). Jika Anda mencoba menambahkan bilangan real ke bilangan segitiga fuzzy, itu akan dikonversi menjadi bilangan segitiga fuzzy. Situasi serupa dengan tupel atau daftar bilangan real - tiga angka pertama akan dianggap sebagai fuzzy triangular (dan juga dikonversi ke kelas FuzzyTriangular). Metode __pos__ menimpa operator unary "+". Metode __neg__ adalah unary "-". Metode __eq__ menimpa operator ==. Jika diinginkan, Anda juga dapat mendefinisikan kembali operasi seperti:
- pembagian
- eksponensial
- modulus angka
- perbandingan (lebih / kurang, lebih atau sama / kurang atau sama)
- skalarisasi (dilemparkan ke int, float, bilangan kompleks, pembulatan)
- inversi dan lainnya ...
Anda dapat memeriksa kecukupan operasi yang dimasukkan dengan serangkaian tes, misalnya, seperti:
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))
Operasi verifikasi penambahan, pembagian, dan penggandaan ini ditentukan dalam kode dan dilakukan sesuai dengan redefinisi metode "ajaib". Kami ingin dapat melakukan operasi yang sama menggunakan variabel simbol dalam ekspresi yang sebelumnya tidak diketahui. Ini membutuhkan pengenalan beberapa fungsi tambahan. - Kami memperkenalkan fungsi bantu:
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
Kami akan menggunakan fungsi ini untuk mencari variabel karakter dalam string ekspresi (template default adalah karakter dari A hingga Z atau dari a ke z dan integer setelahnya hingga 2 karakter (atau tidak adanya angka). 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)
Fungsi ini memungkinkan Anda untuk menghitung nilai ekspresi string dengan substitusi alih-alih variabel variabel simbolik dari jenis apa pun yang valid (jika operasi yang terkandung dalam ekspresi string itu sendiri ditimpa). Ini dimungkinkan berkat fungsi sympy.lambdify, yang mengubah ekspresi sympy menjadi fungsi lambda yang menerima metode "ajaib". Kondisi penting agar fungsi berfungsi dengan baik adalah urutan elemen yang benar dalam simbol dan nilai (korespondensi simbol dan nilai yang diganti).- Setiap kali membuat fungsi lambda mahal. Jika diperlukan beberapa penggunaan ekspresi yang sama, disarankan untuk menggunakan dua fungsi berikut:
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)
Yang pertama mengembalikan fungsi lambda itu sendiri, dan yang kedua memungkinkan Anda untuk menghitung nilai yang dihasilkan dengan mengganti daftar nilai. Sekali lagi, perhatian difokuskan pada fakta bahwa nilai yang digunakan tidak harus berupa angka fuzzy segitiga.
- Kami membaca baris rumus dari file
with open('expr.txt', 'r') as file: expr_str = file.read() print('expr_str', expr_str)
Sesuatu seperti ini dapat digunakan sebagai rumus baris untuk file 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
- Kami mendapatkan variabel karakter dari ekspresi string:
symbols = symbols_from_expr(expr_str) print('AutoSymbols', symbols)
- Kami menghasilkan angka segitiga acak uji:
values = tuple([FuzzyTriangular(sorted([random(),random(),random()]))\ for i in range(len(symbols))])
Pengurutan nilai acak diperlukan untuk mencocokkan urutan nilai kiri "0", tengah dan kanan "0". - Ubah string rumus menjadi ekspresi:
func = lambda_func(expr_str, symbols) print('func', '=', func)
- Kami menghitung nilai rumus menggunakan fungsi lambda (kami menggunakan func_subs dan expr_subs untuk memastikan hasilnya cocok):
print('func_subs', '=', func_subs(func, values)) print('expr_subs', '=', expr_subs(expr_str, symbols, values))
Contoh Keluaran:
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]
Tutorial sudah berakhir. Saya harap Anda menemukan sesuatu yang berguna di sini!
PS: "fitur" utama dari pendekatan yang dijelaskan adalah kemampuan untuk melampaui jenis variabel standar dan operasi pada mereka untuk python dan sympy. Dengan mendeklarasikan kelas Anda dan membebani metode "ajaib", Anda dapat menghitung ekspresi matematika yang sebelumnya tidak dikenal menggunakan sympy (membuat fungsi lambda yang menerima baik tipe dan operasi standar maupun pengguna).
Terima kasih atas perhatian anda!