#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Tue Dec 22 11:06:10 2020 @author: andrea """ # rappresentazione di espressioni algebriche con alberi binari # - calcolo # - semplificazione # - parsing # espressione: numero intero # espressione: (espressione operando espressione) class Numero: def __init__(self, V): self.V = V def __repr__(self): return f"{self.V}" def calcola(self): return self.V def __eq__(self, other): return type(other) == Numero and other.V == self.V def semplifica(self): return self class Espressione: commutativo = ['*', '+'] def __init__(self, sx, op, dx): self.sx = sx self.dx = dx self.op = op def __repr__(self): return f"({self.sx}{self.op}{self.dx})" def calcola(self): if self.op == '-': return self.sx.calcola() - self.dx.calcola() if self.op == '+': return self.sx.calcola() + self.dx.calcola() if self.op == '*': return self.sx.calcola() * self.dx.calcola() if self.op == '/': return self.sx.calcola() / self.dx.calcola() if self.op == '^': return self.sx.calcola() ** self.dx.calcola() if self.op == '%': return self.sx.calcola() % self.dx.calcola() def __eq__(self, other): if self.op in self.commutativo: return type(other) == Espressione \ and (self.sx == other.sx and self.dx == other.dx or self.sx == other.dx and self.dx == other.sx ) return type(other) == Espressione \ and self.sx == other.sx and self.dx == other.dx # semplificazioni: # e1 * 1 => e1 # e1 * 0 => 0 # e1 + 0 => e1 # e1 - 0 => e1 # e1 / 1 => e1 # e1 ^ 1 => e1 # e1 ^ 0 => 1 # 1 ^ e2 => 1 # 0 ^ e2 => 0 # ((e1 ^ e2) * (e1 ^ e3)) => (e1 ^ (e2 + e3) ) # ((e1 ^ 2) - (e2 ^ 2)) = ((e1 - e2) * (e1 + e2)) def semplifica_un_livello(self): if self.op == '*': if self.dx == Numero(1): return self.sx if self.sx == Numero(1): return self.dx if self.dx == Numero(0): return Numero(0) if self.sx == Numero(0): return Numero(0) if self.op == '+': if self.dx == Numero(0): return self.sx if self.sx == Numero(0): return self.dx if self.op == '-': if self.dx == Numero(0): return self.sx if self.sx == Numero(0): return Espressione(Numero(-1), '*', self.dx) if self.op == '/': if self.dx == Numero(1): return self.sx if self.sx == Numero(0): return Numero(0) if self.op == '^': if self.dx == Numero(0): return Numero(1) if self.sx == Numero(0): return Numero(0) if self.dx == Numero(1): return self.sx if self.sx == Numero(1): return Numero(1) return self def semplifica(self): nuova = Espressione(self.sx.semplifica(), self.op, self.dx.semplifica()) return nuova.semplifica_un_livello() n1= Numero(1) n2= Numero(2) n3= Numero(0) n4= Numero(4) n5= Numero(-1) n6= Numero(-17) e1 = Espressione(n1, '*', n2) e2 = Espressione(n3, '/', e1) e3 = Espressione(e2, '-', n2) e4 = Espressione(e3, '+', e2) ''' e4 / + \ e3 e2 / - \ / / \ e2 n2 n3 e1 / / \ 2 0 / * \ n3 e1 n1 n2 0 / * \ 1 2 n1 n2 1 2 (((0 / (1 * 2)) - 2) + (0 / (1 * 2))) ''' print(e4, '=', e4.calcola()) print(e4, '=\n', e4.semplifica()) # per riconoscere una espressione come testo # se il primo carattere è '(' allora è una espressione # ovvero (espressione1 op espressione1) # e il risultato è Espressione(espressione1, op, espressione2) # altrimenti la parte che segue è un numero # e devo tornare Numero(espressione) def parse(testo): if testo[0] == '(': e1, resto = parse(testo[1:]) op = resto[0] e2, resto2 = parse(resto[1:]) assert resto2[0]==')', "Manca la parentesi di chiusura" return Espressione(e1, op, e2), resto2[1:] else: numero, resto = leggiNumero(testo) return Numero(numero), resto # per leggere un numero dal testo # scandisco tutte le cifre iniziali e calcolo il valore # ritorno il valore e il testo rimanente che non è fatto di cifre def leggiNumero(testo): valore = 0 moltiplicatore = 1 assert testo[0] in '+-0123456789' if testo[0] == '-': moltiplicatore = -1 testo = testo[1:] elif testo[0] == '+': moltiplicatore = 1 testo = testo[1:] for i, cifra in enumerate(testo): if cifra in '0123456789': valore *= 10 valore += int(cifra) else: return moltiplicatore*valore, testo[i:] return moltiplicatore*valore, '' print('\n\n\n', parse('(-23+45)')) testo = '(((0/(-1*+2))--2)+(0/(1*2)))' espr,_ = parse(testo) sempl = espr.semplifica() calc = sempl.calcola() print('\n\n\n', testo, espr, sempl, calc, sep='\n')