Ho dovuto accantonare il progetto per alcuni esami universitari. Ora che li ho finiti, vorrei concludere il tutto.
Innanzitutto, diciamo che ho risolto in modo un pochino diverso da come pensavo di strutturarlo inizialmente. Divido la stringa in ingresso tramite regular expression, splittando la stringa in una lista.
Copio qua sotto il codice, funzionante:
#
# La funzione principale e' derive(). Accetta in ingresso una stringa e una variabile.
# Trasforma l'espressione da derivare, che e' sottoforma di stringa, in una lista in cui il primo e il terzo elemento sono operandi
# mentre il secondo e' l'operatore.
# Chiama poi la funzione di derivazione vera e propria, derivative() che applica le regole di derivazione sugli operatori.
# Infine, derive_solver() calcola la derivata sui singoli operandi.
#
import string
import re
def exp_split(mystring): # prende in input una espressione matematica (sottoforma di stringa) e la memorizza in una lista, dividendo gli operandi e operatori
exp_splitted = re.split("([+-/*])", mystring.replace(" ", ""), maxsplit = 1)
if len(exp_splitted[0]) > 2:
exp_splitted[0] = exp_split(exp_splitted[0])
if len(exp_splitted) > 2:
if len(exp_splitted[2]) > 2:
exp_splitted[2] = exp_split(exp_splitted[2])
return exp_splitted
def rimuovi_parentesi(lista): # da chiamare solo quando l'intera espressione e' gia' scomposta in liste
lunghezza = len(lista)
for x in range(lunghezza):
if type(lista[x]) == type([]):
rimuovi_parentesi(lista[x])
else:
lista[x] = lista[x].replace("(", "")
lista[x] = lista[x].replace(")", "")
return lista
def derive_solver(elemento, var):
if type(elemento) == type(0):
return "0"
elif elemento == var:
return "1"
else:
return "0"
def derivative(lst, var):
if len(lst) == 1: # Se viene chiamata la funzione derivative() su un singolo elemento, quest'ultimo viene passato a derive_solver() e risolto.
return derive_solver(lst[0], var)
if lst[1] == '+':
return [derivative(lst[0], var), '+', derivative(lst[2], var)]
if lst[1] == '*':
return [[derivative(lst[0], var), '*', lst[2]], '+', [lst[0], '*', derivative(lst[2], var)]]
def lst_to_str(lst): # prende in input una espressione memorizzata in una lista, e la converte in stringa
if type(lst) != type([]):
return lst
elif type(lst[0]) == type([]):
lst[0] = lst_to_str(lst[0])
elif type(lst[2]) == type([]):
lst[2] = lst_to_str(lst[2])
return "(" + str(lst[0]) + " " + str(lst[1]) + " " + str(lst[2]) + ")"
def calculate_result(lst): # data in input una espressione (sottoforma di lista) gia' derivata, effettua i calcoli per semplificarla
if len(lst) == 1: # Se e' gia' un singolo elemento, restituisce l'elemento stesso senza fare nulla.
return lst
letter = string.lowercase + string.uppercase # creo una stringa contenente tutte le lettere (maiuscole e minuscole). La usero' dopo per verificare che l'operando sia un simbolo
if type(lst[0]) == type([]): # Se il primo operando e' una lista, prima risolvo quella
lst[0] = calculate_result(lst[0])
if type(lst[2]) == type([]):
lst[2] = calculate_result(lst[2]) # Se il secondo operando e' una lista, prima risolvo quella
if lst[1] == '+':
if (string.find(string.digits, str(lst[0])) != -1) and (string.find(string.digits, str(lst[2])) != -1): # vero se gli operandi della lista sono numeri
return int(lst[0]) + int(lst[2])
if lst[0] == '0':
return lst[2]
if lst[2] == '0':
return lst[0]
if (string.find(letter, str(lst[0])) != -1) or (string.find(letter, str(lst[2])) != -1): # vero se almeno un operando e' un simbolo
return [lst[0], lst[1], lst[2]]
if type(lst[0]) == type([]): # se il primo operando e' una lista, valuto solo il secondo
if lst[2] == '0':
return lst[0]
else:
return [lst[0], lst[1], lst[2]]
if type(lst[2]) == type([]): # se il secondo operando e' una lista, valuto solo il primo
if lst[0] == '0':
return lst[2]
else:
return [lst[0], lst[1], lst[2]]
if lst[1] == '*':
if (string.find(string.digits, str(lst[0])) != -1) and (string.find(string.digits, str(lst[2])) != -1): # vero se gli operandi della lista sono numeri
return int(lst[0]) * int(lst[2])
if (lst[0] == '0') or (lst[2] == '0'): # se un operando e' 0, ritorna 0
return 0
if (lst[0] == '1'): # se il primo operando e' 1, ritorna il secondo
return lst[2]
if (lst[2] == '1'): # se il secondo operando e' 1, ritorna il primo
return lst[0]
if (string.find(letter, str(lst[0])) != -1) or (string.find(letter, str(lst[2])) != -1): # vero se almeno un operando e' un simbolo
return [lst[0], lst[1], lst[2]]
if type(lst[0]) == type([]): # se il primo operando e' una lista, valuto solo il secondo
if lst[2] == '0':
return '0'
else:
return [lst[0], lst[1], lst[2]]
if type(lst[2]) == type([]): # se il secondo operando e' una lista, valuto solo il primo
if lst[0] == '0':
return '0'
else:
return [lst[0], lst[1], lst[2]]
def derive(exp_raw, var):
lst = exp_split(exp_raw) # Prende la stringa dell'espressione in input e la converte in una lista
lst = rimuovi_parentesi(lst) # Rimuove le parentesi tonde
risultato_lista = derivative(lst, var) # Effettua la funzione di derivazione vera e propria
return lst_to_str(calculate_result(risultato_lista))
print derive('1 + (3 * x)', 'x')
Ora il problema è un altro: vorrei provare a renderlo multithreading. La funzione su cui chiamare i thread è derivative, che esegue la risoluzione della derivata dei due operandi in parallelo.
Ho provato a informarmi in rete, e poi a mettere in pratica, ma mi da errore.
Copio qua sotto il codice modificato, per renderlo multithread:
#
# La funzione principale e' derive(). Accetta in ingresso una stringa e una variabile.
# Trasforma l'espressione da derivare, che e' sottoforma di stringa, in una lista in cui il primo e il terzo elemento sono operandi
# mentre il secondo e' l'operatore.
# Chiama poi la funzione di derivazione vera e propria, derivative() che applica le regole di derivazione sugli operatori.
# Infine, derive_solver() calcola la derivata sui singoli operandi.
#
import string
import re
import threading
def exp_split(mystring): # prende in input una espressione matematica (sottoforma di stringa) e la memorizza in una lista, dividendo gli operandi e operatori
exp_splitted = re.split("([+-/*])", mystring.replace(" ", ""), maxsplit = 1)
if len(exp_splitted[0]) > 2:
exp_splitted[0] = exp_split(exp_splitted[0])
if len(exp_splitted) > 2:
if len(exp_splitted[2]) > 2:
exp_splitted[2] = exp_split(exp_splitted[2])
return exp_splitted
def rimuovi_parentesi(lista): # da chiamare solo quando l'intera espressione e' gia' scomposta in liste
lunghezza = len(lista)
for x in range(lunghezza):
if type(lista[x]) == type([]):
rimuovi_parentesi(lista[x])
else:
lista[x] = lista[x].replace("(", "")
lista[x] = lista[x].replace(")", "")
return lista
def derive_solver(elemento, var):
if type(elemento) == type(0):
return "0"
elif elemento == var:
return "1"
else:
return "0"
def derivative(lst, var):
t1 = threading.Thread(target = derivative, args=(lst[0], var))
t2 = threading.Thread(target = derivative, args=(lst[2], var))
if len(lst) == 1: # Se viene chiamata la funzione derivative() su un singolo elemento, quest'ultimo viene passato a derive_solver() e risolto.
return derive_solver(lst[0], var)
if lst[1] == '+':
return [t1.start(), '+', t2.start()]
if lst[1] == '*':
return [[t1.start(), '*', lst[2]], '+', [lst[0], '*', t2.start()]]
def lst_to_str(lst): # prende in input una espressione memorizzata in una lista, e la converte in stringa
if type(lst) != type([]):
return lst
elif type(lst[0]) == type([]):
lst[0] = lst_to_str(lst[0])
elif type(lst[2]) == type([]):
lst[2] = lst_to_str(lst[2])
return "(" + str(lst[0]) + " " + str(lst[1]) + " " + str(lst[2]) + ")"
def calculate_result(lst): # data in input una espressione (sottoforma di lista) gia' derivata, effettua i calcoli per semplificarla
if len(lst) == 1: # Se e' gia' un singolo elemento, restituisce l'elemento stesso senza fare nulla.
return lst
letter = string.lowercase + string.uppercase # creo una stringa contenente tutte le lettere (maiuscole e minuscole). La usero' dopo per verificare che l'operando sia un simbolo
if type(lst[0]) == type([]): # Se il primo operando e' una lista, prima risolvo quella
lst[0] = calculate_result(lst[0])
if type(lst[2]) == type([]):
lst[2] = calculate_result(lst[2]) # Se il secondo operando e' una lista, prima risolvo quella
if lst[1] == '+':
if (string.find(string.digits, str(lst[0])) != -1) and (string.find(string.digits, str(lst[2])) != -1): # vero se gli operandi della lista sono numeri
return int(lst[0]) + int(lst[2])
if lst[0] == '0':
return lst[2]
if lst[2] == '0':
return lst[0]
if (string.find(letter, str(lst[0])) != -1) or (string.find(letter, str(lst[2])) != -1): # vero se almeno un operando e' un simbolo
return [lst[0], lst[1], lst[2]]
if type(lst[0]) == type([]): # se il primo operando e' una lista, valuto solo il secondo
if lst[2] == '0':
return lst[0]
else:
return [lst[0], lst[1], lst[2]]
if type(lst[2]) == type([]): # se il secondo operando e' una lista, valuto solo il primo
if lst[0] == '0':
return lst[2]
else:
return [lst[0], lst[1], lst[2]]
if lst[1] == '*':
if (string.find(string.digits, str(lst[0])) != -1) and (string.find(string.digits, str(lst[2])) != -1): # vero se gli operandi della lista sono numeri
return int(lst[0]) * int(lst[2])
if (lst[0] == '0') or (lst[2] == '0'): # se un operando e' 0, ritorna 0
return 0
if (lst[0] == '1'): # se il primo operando e' 1, ritorna il secondo
return lst[2]
if (lst[2] == '1'): # se il secondo operando e' 1, ritorna il primo
return lst[0]
if (string.find(letter, str(lst[0])) != -1) or (string.find(letter, str(lst[2])) != -1): # vero se almeno un operando e' un simbolo
return [lst[0], lst[1], lst[2]]
if type(lst[0]) == type([]): # se il primo operando e' una lista, valuto solo il secondo
if lst[2] == '0':
return '0'
else:
return [lst[0], lst[1], lst[2]]
if type(lst[2]) == type([]): # se il secondo operando e' una lista, valuto solo il primo
if lst[0] == '0':
return '0'
else:
return [lst[0], lst[1], lst[2]]
def derive(exp_raw, var):
lst = exp_split(exp_raw) # Prende la stringa dell'espressione in input e la converte in una lista
lst = rimuovi_parentesi(lst) # Rimuove le parentesi tonde
t = threading.Thread(target = derivative, args=(lst, var))
risultato_lista = derivative(lst, var) # Effettua la funzione di derivazione vera e propria
return lst_to_str(calculate_result(risultato_lista))
print derive('1 + (3 * x)', 'x')
Ma come accennavo, mi restituisce un sacco di errori.
Gli esempi in rete, applicano tutti la definizione e chiamata del thread tramite ciclo for. Però nel mio caso, per non stravolgere l'intera struttura del programma, pensavo di chiamare i thread singolarmente, senza fare uso di cicli for.