Skip to content

Commit

Permalink
Merge branch 'solver-testing' into beta1
Browse files Browse the repository at this point in the history
  • Loading branch information
xmagor committed Dec 26, 2020
2 parents 89b1b96 + ab06e0e commit 56e4298
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 30 deletions.
28 changes: 20 additions & 8 deletions entrada.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ def entradaTexto(ecuaciones, pyENL_timeout, varsObj=None, tol=None, method='hybr
pyENL_solved = False
try:
pyENL_solucion = solver(lista, variables_salida, tol=tol, method=method)
pyENL_solved = True
pyENL_final = time()
pyENL_transcurrido = pyENL_final - pyENL_inicio
pyENL_solved = pyENL_solucion[2]
if pyENL_solved == False:
raise Exception("Gordillo y los chulos")
except Exception as e:
# exit(0)
# Intento aleatorio
Expand Down Expand Up @@ -197,21 +197,33 @@ def entradaTexto(ecuaciones, pyENL_timeout, varsObj=None, tol=None, method='hybr
raise Exception(er)
if 'debe tener unidades' in er:
raise Exception(er)
if "Gordillo y los chulos" in er:
# Significa que la cagó pero aún lo puede volver a intentar ;)!
pass
pyENL_final = time()
pyENL_transcurrido = pyENL_final - pyENL_inicio
# Creería que el siguiente while ya no sería necesario por lo que ahora se itera
# el bloque especifico que falla
while pyENL_transcurrido < pyENL_timeout:
# Encontrar nuevos valores de guesses:
for cont, objetoVar in enumerate(variables_salida):
obtemp = objetoVar # Objeto variable temporal
# TODO: Solo buscar random si es variable no resuelta
if not objetoVar.solved:
obtemp.guess = random_lim(objeto.lowerlim, objeto.upperlim) * objetoVar.units
obtemp.guess = random_lim(objeto.lowerlim, objeto.upperlim) # * objetoVar.units
variables_salida[cont] = obtemp
# Termina de actualizar, ahora:
try:
pyENL_solucion = solver(lista, variables_salida,
tol=1.49012e-08)
pyENL_solved = True
tol=1.49012e-08,pyENL_timeout = pyENL_timeout)
pyENL_solved = pyENL_solucion[2]
# Por ahora si en el primer intento del solver no encuentra solución
# Se continua el bucle while y se cambian los guesses para re intentar
# hasta que se agote el tiempo limite del bucle
if pyENL_solved==False:
pyENL_final = time()
pyENL_transcurrido = pyENL_final - pyENL_inicio
continue
break
except Exception as e:
er = str(e)
Expand Down Expand Up @@ -242,8 +254,8 @@ def entradaTexto(ecuaciones, pyENL_timeout, varsObj=None, tol=None, method='hybr
if 'Error de unidades' in er:
raise Exception(er)
# Actualiza el tiempo que ha transcurido:
pyENL_final = time()
pyENL_transcurrido = pyENL_final - pyENL_inicio
pyENL_final = time()
pyENL_transcurrido = pyENL_final - pyENL_inicio
if pyENL_solved == False:
raise Exception(
'El tiempo de espera ha sido superado, verifique las ecuaciones')
Expand Down
63 changes: 62 additions & 1 deletion pyENL.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ def __init__(self, parent, theme):
self.cajaTexto.cursorPositionChanged.connect(self.originCursor)
self.cleanVarButton.clicked.connect(self.showVarsTable)
self.Actualizar_Button.clicked.connect(self.actualizaVarsTable)
self.varsTable.cellChanged.connect(self.verificarNewUnitVarsTable)
self.solve_button.clicked.connect(self.solve)
self.solveTableButton.clicked.connect(self.calculateTable)
self.actionTermodinamicas.triggered.connect(self.propWindow)
Expand Down Expand Up @@ -338,6 +339,7 @@ def limpiaTrasCierre(self):
self.variables = []
self.solucion = []
self.imprimeSol(self.format)
self.actualizaVars()

def guardaArchivoComo(self):
try:
Expand Down Expand Up @@ -755,6 +757,9 @@ def showVarsTable(self):
'''
Imprime en tabla las variables del programa.
'''
# Se bloquean las señales de la tabla para no llamar funciones
# como verificarNewUnitVarsTable
self.varsTable.blockSignals(True)
self.varsTable.resizeColumnsToContents()
self.varsTable.resizeRowsToContents()
# La cantidad de filas es pues igual a la cantidad de variables.
Expand Down Expand Up @@ -802,6 +807,7 @@ def showVarsTable(self):
# newitem = QtWidgets.QTableWidgetItem(item)
# self.varsTable.setItem(m, n, newitem)
self.varsTable.setHorizontalHeaderLabels(horHeaders)
self.varsTable.blockSignals(False)
# print(dir(newitem))
# self.varsTable.show()
# self.infoLabel.setText('Pollo')
Expand All @@ -812,6 +818,9 @@ def actualizaVarsTable(self):
los parámetros de las variables de programa.
'''
try:
# Se bloquean las señales de la tabla para no llamar funciones
# como verificarNewUnitVarsTable
self.varsTable.blockSignals(True)
#Inicialmente se revisa que no la hayan embarrado repitiendo Variables
#Ojalá se encuentre una mejor manera de hacer esto , y no con un for repetido xD
list_names = []
Expand Down Expand Up @@ -884,9 +893,61 @@ def actualizaVarsTable(self):
self.variables[i].comment = comment
except Exception as e:
QtWidgets.QMessageBox.about(self, "Error", str(e))
self.varsTable.blockSignals(False)
self.showVarsTable()
self.archivoModificado = True

def keyPressEvent(self, e):
'''Función heredada, es llamada cuando una tecla se presiona'''

# Detecta cuando se use la tecla enter
# para usarla para ir bajando en las filas de la tabla de variables
# y poder editarla
if e.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]:

item = self.varsTable.currentItem()
row, col = item.row() , item.column()

if row +1 < self.varsTable.rowCount():
self.varsTable.setCurrentCell(row+1,col)
self.varsTable.edit(self.varsTable.currentIndex())
def verificarNewUnitVarsTable(self,row,col):
'''
En el momento que el usuario cambia la unidad de una variable especifica
se verifica si es válida
'''
# Check que la modificación sea en la columna de unidades

if col!=4:
return
units = self.varsTable.item(row, col).text() # Nueva unidad tentativa

# Como es posible que se modifiquen celdas, se debe bloquear los signals
# para evitar falsos positivos en esta función
self.varsTable.blockSignals(True)
try:
# Si eval sin error entonces breves pase a la siguiente linea
temp_unit = eval('pyENLu.parse_units("' + units + '")')

#Escribir la unidad en todas las selecciones válidas hechas
list_selected = self.varsTable.selectedItems()
if len(list_selected)>1:
for item in list_selected:
# Se valida que el item pertenezca a la columna de unidades
if item.column() == col:
item.setText(units)

if row +1 < self.varsTable.rowCount():
self.varsTable.setCurrentCell(row+1,col)
self.varsTable.edit(self.varsTable.currentIndex())
# self.varsTable.set
self.varsTable.blockSignals(False)
except Exception as e:
QtWidgets.QMessageBox.about(self, "Error", str(e))
# vuelve a dejar la unidad como estaba (realmente vuelve a imprimir la tabla, pero shhh)
self.showVarsTable()
self.varsTable.blockSignals(False)

def actualizarNumeroLinea(self):
'''
Actualiza cada cierto tiempo la numeración de las lineas
Expand Down Expand Up @@ -1088,7 +1149,7 @@ def findText(self,whole=False,replace=False):
'''
Resalta todos los resultados encontrados en la busqueda
'''
print(whole)
# print(whole)
word= self.textFind.text() #texto a buscar en self.cajaTexto

cajaTexto = self.cajaTexto.toPlainText()
Expand Down
3 changes: 2 additions & 1 deletion pyENL_fcns/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@
'TMIN': pyENLu.K, 'T_MIN': pyENLu.K, 'T_min': pyENLu.K, 'Tmin': pyENLu.K,
'TTRIPLE': pyENLu.K, 'T_TRIPLE': pyENLu.K, 'T_triple': pyENLu.K, 'Ttriple': pyENLu.K,
'T_FREEZE': pyENLu.K, 'T_freeze': pyENLu.K, 'T_REDUCING': pyENLu.K, 'T_reducing': pyENLu.K,
'V': parse('Pa*s'), 'VISCOSITY': parse('Pa*s'), 'viscosity': parse('Pa*s')}
'V': parse('Pa*s'), 'VISCOSITY': parse('Pa*s'), 'viscosity': parse('Pa*s'),'PRANDTL':parse('dimensionless'),
'Prandtl':parse('dimensionless')}
# TODO: Agregar las adimensionales!

def prop(des, *args):
Expand Down
54 changes: 40 additions & 14 deletions solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
log = log10
import warnings
from pint import _DEFAULT_REGISTRY as pyENLu
from utils import variables , bloques, variables_string
from utils import variables , bloques, variables_string,random_lim
from time import time
pyENLu.load_definitions(pyENL_path + "units.txt")
# from time import time as pyENL_time

Expand Down Expand Up @@ -107,13 +108,21 @@ def pyENL_sistema(pyENL, pyENL_variables, pyENL_eqns, indices = None):
# variables para operar
raise Exception(er + ' en la ecuación ' + str(indices[cont] + 1))
elif 'debe tener unidades' in er:
raise Exception(er + ' en la ecuación ' + str(indices[cont] + 1))
raise Exception(er + ' en la ecuación ' + str(cont + 1))
elif ('invalid value encountered in sqrt' in er
or 'invalid value encountered in log10' in er
or 'invalid value encountered in double_scalars' in er) :
# TODO conteo de error para notificar a usuario si es muy repetitivo (puede que el usuario
# se haya equivocado al escribir la ecuación)
pass
elif 'missing unary operator "*"' in er:
raise Exception(er + 'en la ecuación' + eqn)
else:
raise Exception
raise Exception(er)
return salidapyENL


def solver(pyENL_eqns, pyENL_variables, tol=None, method='hybr'):
def solver(pyENL_eqns, pyENL_variables, tol=None, method='hybr',pyENL_timeout=10):
'''
Acá llegan como parámetros la lista de funciones a hallar raíces como string
La segunda entrada consiste en los objetos pyENL_variables en lista.
Expand Down Expand Up @@ -175,18 +184,35 @@ def solver(pyENL_eqns, pyENL_variables, tol=None, method='hybr'):
varsBloque = variables(recVars)
varsBloque = [x for x in pyENL_variables if x.name in varsBloque]
guessBloque = [x.guess for x in varsBloque]
# print("Bloque número:",j)
# print(varsBloque, guessBloque,eqnsBloque)
solBloque = opt.root(pyENL_sistema, guessBloque,
args=(varsBloque, eqnsBloque, bloque), tol=tol, method=method)
asegura_convergencia = True
# print(solBloque['success'])
if solBloque['success'] == False:
asegura_convergencia = False
raise Exception("Gordillo y los chulos")
tiempo_bloque = 0
tiempo_inicio = time()
while tiempo_bloque < pyENL_timeout:
# print("Bloque número:",j)
# print(varsBloque, guessBloque,eqnsBloque)
solBloque = opt.root(pyENL_sistema, guessBloque,
args=(varsBloque, eqnsBloque), tol=tol, method=method)
asegura_convergencia = True
# print(solBloque['success'])
if solBloque['success'] == False:
asegura_convergencia = False

# Si no fue capaz de solucionar el bloque le cambia los guess
# a las variables que no estan solucionadas en ese bloque
for jj, varBloque in enumerate(varsBloque):
obtemp = varBloque
if not varBloque.solved:
obtemp.guess = random_lim(varBloque.lowerlim, varBloque.upperlim) # * objetoVar.units
varsBloque[jj] = obtemp
tiempo_fin = time()
tiempo_bloque = tiempo_fin - tiempo_inicio
else:
print('Bloque ', j, 'Resuelto!')
# return [],[],asegura_convergencia
# raise Exception("Gordillo y los chulos")
break
# Actualizar el atributo solved
for i, varBloque in enumerate(varsBloque):
print(varBloque.guess)
# print(varBloque.guess)
if not varBloque.solved:
varBloque.guess = solBloque['x'][i]
varBloque.solved = True
Expand Down
29 changes: 23 additions & 6 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,33 +346,50 @@ def funcion_e(Diccionario):
return Diccionario_orga

def onevsone(matriz):
'''Asociación de ecuaciones con variables 1 a 1 (opción matricial)'''
'''Asociación de ecuaciones con variables 1 a 1 (opción matricial)
La matriz de entra está formada por un array de listas donde cada lista
representan una ecuación y contiene n booleanos , donde n es el número total
de variables de todo el sistema de ecuaciones
Return:
'''
m =matriz.copy()
size = m.shape[0]
size = m.shape[0] # Representa el numero de eqn

# A cada
for a in range(size):

# Lista de número de veces que se repite cada variable
sumCol = sum(m,axis = 0) #sumar columnas
# Lista de cantidad de variables que tiene cada ecuación
sumRow = sum(m,axis=1) #sumar filas


minSumCol = sumCol.min()
# Se busca la variable que se repite la menor cantidad de veces
# y almacena el num de repeticiones y la posición en la lista
minSumCol = sumCol.min() # Si hay varias tomará la primera que encuentre
yminSumCol = sumCol.argmin()

# Se identifica la ecuación con menor num de variables
minSumRow = sumRow.min()
xminSumRow = sumRow.argmin()

# Revisión de un sistema de ecuaciones valido
# Se identifica si hay variables unicas o eqn con solo una variable
# Variables que se encuentran una sola vez en todo el sistema
checkCol=argwhere(sumCol== 1)
# Eqn que solo continene una variable
checkRow = argwhere(sumRow==1)

VcheckCol = zeros(size)
VcheckRow = zeros(size)
for b in checkCol:
VcheckCol = VcheckCol + m[:,b]

for c in checkRow:
VcheckRow =VcheckRow + m[c,:]
if True in (VcheckCol>1) or True in (VcheckCol>1):
if True in (VcheckCol>1): #or True in (VcheckCol>1):
# Significa que el sistema de eqns es inconsistente
# TODO de acá podemso detectar fallos en el sistema de eqns y notificar a usuario
# para que los arregle como doble declaración de variables
return m ,-1

if minSumRow == 1:
Expand Down

0 comments on commit 56e4298

Please sign in to comment.