Skip to content

Commit

Permalink
nova interface nominal,incerteza
Browse files Browse the repository at this point in the history
  • Loading branch information
viniciusdutra314 committed Jan 20, 2025
1 parent aae088b commit 97eae47
Show file tree
Hide file tree
Showing 27 changed files with 269 additions and 290 deletions.
5 changes: 2 additions & 3 deletions LabIFSC2/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
'''


from ._arrays import (arrayM, curva_max, curva_min, incertezas, linspace,
nominais)
from ._matematica import (aceitamedida, acos, acosh, arccos, arccosh, arcseno,
arcsin, arcsinh, arctan, arctanh, arctg, asenh, asin,
asinh, atan, atanh, atgh, cbrt, cos, cosh, exp, exp2,
ln, log, log2, log10, pow, power, senh, seno, sin,
sinh, sqrt, tan, tanh, tg, tgh)
from ._medida import Comparacao, Medida, comparar_medidas, montecarlo
from ._operacoes_em_arrays import (arrayM, converter_array, converter_array_si,
curva_max, curva_min, incertezas, linspace,
nominais)
from ._regressões import (MExponencial, MPolinomio, regressao_exponencial,
regressao_linear, regressao_polinomial,
regressao_potencia)
Expand Down
30 changes: 8 additions & 22 deletions LabIFSC2/_operacoes_em_arrays.py → LabIFSC2/_arrays.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


@obrigar_tipos
def nominais(arrayMedidas : np.ndarray) -> np.ndarray:
def nominais(arrayMedidas : np.ndarray,unidade:str) -> np.ndarray:
'''*get_nominais* Transforma um array/lista (Sequência) de medidas em
um arrays somente com seus valores nominais
Expand All @@ -32,10 +32,10 @@ def nominais(arrayMedidas : np.ndarray) -> np.ndarray:
if not (isinstance(arrayMedidas[0],Medida)):
raise TypeError('Os valores do array não são Medidas')

return np.array([medida.nominal for medida in arrayMedidas],dtype=float)
return np.array([medida._nominal.to(unidade).magnitude for medida in arrayMedidas],dtype=float)

@obrigar_tipos
def incertezas(arrayMedidas : np.ndarray) -> np.ndarray:
def incertezas(arrayMedidas : np.ndarray,unidade:str) -> np.ndarray:
'''*get_incertezas* Transforma um array/lista (Sequência) de medidas em
um arrays somente com suas incertezas
Expand All @@ -54,10 +54,10 @@ def incertezas(arrayMedidas : np.ndarray) -> np.ndarray:
'''
if not (isinstance(arrayMedidas[0],Medida)):
raise TypeError('Os valores do array não são Medidas')
return np.array([medida.incerteza for medida in arrayMedidas],dtype=float)
return np.array([medida.incerteza(unidade) for medida in arrayMedidas],dtype=float)

@obrigar_tipos
def curva_min(arrayMedidas : np.ndarray,sigma: float | int =2) -> np.ndarray:
def curva_min(arrayMedidas : np.ndarray,unidade:str,sigma: float | int =2) -> np.ndarray:
'''Usada para auxiliar o plot de curvas teóricas
com erros, com quantidade de sigmas usados personalizável
Expand All @@ -73,11 +73,11 @@ def curva_min(arrayMedidas : np.ndarray,sigma: float | int =2) -> np.ndarray:
'''
if not (isinstance(arrayMedidas[0],Medida)):
raise TypeError('Os valores do array não são Medidas')
result:np.ndarray=nominais(arrayMedidas) -sigma*incertezas(arrayMedidas)
result:np.ndarray=nominais(arrayMedidas,unidade) -sigma*incertezas(arrayMedidas,unidade)
return result

@obrigar_tipos
def curva_max(arrayMedidas : np.ndarray,sigma:float | int=2)-> np.ndarray:
def curva_max(arrayMedidas : np.ndarray,unidade:str,sigma:float | int=2)-> np.ndarray:
'''Usada para auxiliar o plot de curvas teóricas
com erros, quantidade de sigmas usados personalizável
Expand All @@ -93,7 +93,7 @@ def curva_max(arrayMedidas : np.ndarray,sigma:float | int=2)-> np.ndarray:
'''
if not (isinstance(arrayMedidas[0],Medida)):
raise TypeError('Os valores do array não são Medidas')
result:np.ndarray=nominais(arrayMedidas) +sigma*incertezas(arrayMedidas)
result:np.ndarray=nominais(arrayMedidas,unidade) +sigma*incertezas(arrayMedidas,unidade)
return result


Expand Down Expand Up @@ -151,18 +151,4 @@ def arrayM(nominais:np.ndarray | Sequence ,incerteza:Real,unidade:str) ->np.ndar

return np.array([Medida(nominal,incerteza,unidade) for nominal in nominais],dtype=Medida)

@obrigar_tipos
def converter_array(arrayM:np.ndarray,unidade:str)->None:
if not (isinstance(arrayM[0],Medida)):
raise TypeError('Os valores do array não são Medidas')

for medida in arrayM: medida._converter_para(unidade)
return None

@obrigar_tipos
def converter_array_si(arrayM:np.ndarray)->None:
if not (isinstance(arrayM[0],Medida)):
raise TypeError('Os valores do array não são Medidas')

for medida in arrayM: medida._converter_para_si()
return None
118 changes: 47 additions & 71 deletions LabIFSC2/_medida.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import numpy as np
from pint import Quantity, UnitRegistry
from pint.facets.plain import PlainQuantity
from pint.util import UnitsContainer

from ._tipagem_forte import obrigar_tipos

Expand All @@ -26,7 +28,6 @@ def montecarlo(func : Callable,
std=np.std(histograma,mean=mean)
resultado=Medida(mean.magnitude,std.magnitude,str(histograma.units))
resultado._histograma=histograma
resultado._gaussiana=False
return resultado

class Medida:
Expand All @@ -48,8 +49,7 @@ def __init__(self,nominal:Real,incerteza : Real,
if incerteza<0: raise ValueError("Incerteza não pode ser negativa")
self._nominal= ureg.Quantity(nominal,unidade).to_reduced_units()
self._incerteza=ureg.Quantity(incerteza,unidade).to_reduced_units()
self._gaussiana=True
self._histograma=None
self._histograma:Any=None
self._nominal.ito_reduced_units
self._incerteza.ito_reduced_units

Expand All @@ -60,49 +60,30 @@ def _erro_por_mudar_atributo(self: 'Medida') -> None:
Caso precise de uma nova Medida, crie outra com o \
construtor padrão Medida(nominal, incerteza, unidade)")

@property
def nominal(self:'Medida') -> float:
return float(self._nominal.magnitude)

@nominal.setter
def nominal(self:'Medida', value:Any)-> None:
self._erro_por_mudar_atributo()

@nominal.deleter
def nominal(self:'Medida') -> None:
self._erro_por_mudar_atributo()
def nominal(self:'Medida',unidade:str) -> float:
if unidade.lower()=='si':
return float(self._nominal.to_base_units().magnitude)
else:
return float(self._nominal.to(unidade).magnitude)

@property
def incerteza(self:'Medida') -> float:
return float(self._incerteza.magnitude)

@incerteza.setter
def incerteza(self:'Medida', value:Any) -> None:
self._erro_por_mudar_atributo()
def incerteza(self:'Medida',unidade:str) -> float:
if unidade.lower()=='si':
return float(self._incerteza.to_base_units().magnitude)
else:
return float(self._incerteza.to(unidade).magnitude)

@incerteza.deleter
def incerteza(self:'Medida') -> None:
self._erro_por_mudar_atributo()

@property
def unidade(self:'Medida') -> str:
return str(self._nominal.units)
def dimensao(self:'Medida') -> UnitsContainer:
return self._nominal.dimensionality

@unidade.setter
def unidade(self:'Medida', value:Any) -> None:
self._erro_por_mudar_atributo()

@unidade.deleter
def unidade(self:'Medida') -> None:
self._erro_por_mudar_atributo()

@property
def histograma(self:'Medida') -> Any:
if self._histograma is None:
if self.incerteza!=0:
self._histograma=np.random.normal(self.nominal,self.incerteza,size=100_000)*self._nominal.units
if self._incerteza.magnitude!=0:
self._histograma=np.random.normal(self._nominal.magnitude,
self._incerteza.magnitude,size=100_000)*self._nominal.units
else:
self._histograma=self.nominal*self._nominal.units
self._histograma=self._nominal
return self._histograma

@histograma.setter
Expand All @@ -111,18 +92,8 @@ def histograma(self:'Medida',value:Any) -> None:

@histograma.deleter
def histograma(self:'Medida') -> None:
self._erro_por_mudar_atributo()


def _converter_para_si(self:'Medida')->None:
self._nominal.ito_base_units()
self._incerteza.ito_base_units()
if self._histograma is not None: self._histograma.ito_base_units()

def _converter_para(self:'Medida',unidade:str)->None:
self._nominal.ito(unidade)
self._incerteza.ito(unidade)
if self._histograma is not None: self._histograma.ito(unidade)
self._erro_por_mudar_atributo()


def __format__(self, format_spec:str) -> str:

Expand All @@ -134,7 +105,7 @@ def __format__(self, format_spec:str) -> str:
unidade=format_spec.split('_')[0]

if unidade=='':
unidade=self.unidade
unidade=str(self._nominal.units)
nominal_pint = self._nominal
incerteza_pint = self._incerteza
elif unidade=='si':
Expand All @@ -146,7 +117,7 @@ def __format__(self, format_spec:str) -> str:
else:
nominal_pint = self._nominal
incerteza_pint = self._incerteza
unidade=self.unidade
unidade=str(self._nominal.units)
nominal=Decimal(nominal_pint.magnitude)
incerteza=Decimal(incerteza_pint.magnitude)

Expand Down Expand Up @@ -213,9 +184,9 @@ def _adicao_subtracao(self,outro: 'Medida',positivo:bool) -> 'Medida':

if self._nominal.is_compatible_with(outro._nominal):
if self is outro:
return 2*self if positivo else Medida(0,0,self.unidade)
return 2*self if positivo else Medida(0,0,str(self._nominal.units))

elif (self._gaussiana and outro._gaussiana):
elif (self._histograma is None and outro._histograma is None):
#Como existe solução analítica da soma/subtração entre duas gaussianas
#iremos usar esse resultado para otimizar o código
if positivo: media=self._nominal+outro._nominal
Expand All @@ -241,17 +212,20 @@ def __mul__(self:'Medida',outro:Any)-> 'Medida':
elif isinstance(outro,Medida):
return montecarlo(lambda x,y: x*y,self,outro)
elif isinstance(outro,Real):
resultado=Medida(self.nominal*outro,abs(self.incerteza*outro),self.unidade)
resultado=Medida(self._nominal.magnitude*outro,
abs(self._incerteza.magnitude*outro),str(self._nominal.units))
if self._histograma is not None:
resultado._histograma=self._histograma*outro
return resultado
else:
return NotImplemented

def __truediv__(self:'Medida', outro:Any) -> 'Medida':
if self is outro: return Medida(1,0,self.unidade)
if self is outro: return Medida(1,0,str(self._nominal.units))
elif isinstance(outro,Real):
resultado=Medida(self.nominal/float(outro),self.incerteza/abs(float(outro)),self.unidade)
resultado=Medida(self._nominal.magnitude/float(outro),
self._incerteza.magnitude/abs(float(outro)),
str(self._nominal.units))
if self._histograma is not None:
resultado._histograma=self._histograma/float(outro)
return resultado
Expand Down Expand Up @@ -297,21 +271,23 @@ def __ne__(self:'Medida',outro:Any)->bool:
__rpow__=__pow__

def __abs__(self:'Medida') -> 'Medida':
resultado=Medida(abs(self.nominal),self.incerteza,self.unidade)
resultado=Medida(abs(self._nominal.magnitude),
self._incerteza.magnitude,
str(self._nominal.units))
if self._histograma is not None:
resultado._histograma=abs(self._histograma)
return resultado

def __neg__(self:'Medida') -> 'Medida':
resultado=Medida(-self.nominal,self.incerteza,self.unidade)
resultado=Medida(-(self._nominal.magnitude),
self._incerteza.magnitude,
str(self._nominal.units))
if self._histograma is not None:
resultado._histograma=-self._histograma
return resultado

def __pos__(self) -> 'Medida':
resultado=Medida(self.nominal,self.incerteza,self.unidade)
resultado._histograma=self._histograma
return resultado
return self

@obrigar_tipos
def probabilidade_de_estar_entre(self,a:Real,b:Real,unidade:str) -> float:
Expand All @@ -334,7 +310,7 @@ def probabilidade_de_estar_entre(self,a:Real,b:Real,unidade:str) -> float:
if not self._nominal.is_compatible_with(unidade):
raise ValueError(f"Unidade {unidade} não é compatível com a unidade da medida")

if self._gaussiana:
if self._histograma is None:
#estamos resolvendo de maneira análitica
mu=self._nominal.to(unidade).magnitude
sigma=self._incerteza.to(unidade).magnitude
Expand All @@ -346,8 +322,7 @@ def probabilidade_de_estar_entre(self,a:Real,b:Real,unidade:str) -> float:
probabilidade= np.mean((self._histograma >= a_quantidade) & (self._histograma <= b_quantidade),dtype=float)
return float(probabilidade)

@obrigar_tipos
def intervalo_de_confiança(self,p:Real) -> list[float]:
def intervalo_de_confiança(self:'Medida',p:Real,unidade:str) -> list[float]:
''' Retorna o intervalo de confiança para a Medida
com base no histograma
Expand All @@ -364,7 +339,7 @@ def intervalo_de_confiança(self,p:Real) -> list[float]:

elif p==1: return [float(min(self.histograma.magnitude)),float(max(self.histograma.magnitude))]

elif self._gaussiana:
elif self._histograma is None:
#estamos resolvendo de maneira analítica
mu=self._nominal.magnitude
sigma=self._incerteza.magnitude
Expand All @@ -373,15 +348,16 @@ def intervalo_de_confiança(self,p:Real) -> list[float]:
limite_superior=gaussiana.inv_cdf((1+float(p))/2)
return [limite_inferior,limite_superior]
else:
self.histograma.sort()
num_elements = len(self.histograma)
self._histograma.sort()
self._histograma.ito(unidade)
num_elements = len(self._histograma)
selected_elements = int(np.floor(float(p) * num_elements))
magnitudes = np.array([item.magnitude for item in self.histograma])
magnitudes = np.array([item.magnitude for item in self._histograma])
intervals = magnitudes[selected_elements:] - magnitudes[:-selected_elements]

shortest_interval_index = np.argmin(intervals)
shortest_interval = [float(self.histograma[shortest_interval_index].magnitude),
float(self.histograma[shortest_interval_index + selected_elements].magnitude)]
shortest_interval = [float(self._histograma[shortest_interval_index].magnitude),
float(self._histograma[shortest_interval_index + selected_elements].magnitude)]
return shortest_interval


Expand Down
10 changes: 5 additions & 5 deletions LabIFSC2/_regressões.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
import numpy as np
from numpy.polynomial import Polynomial

from ._arrays import arrayM, nominais
from ._matematica import aceitamedida, exp, log, power
from ._medida import Medida
from ._operacoes_em_arrays import arrayM, nominais
from ._tipagem_forte import obrigar_tipos


Expand Down Expand Up @@ -90,8 +90,8 @@ def regressao_polinomial(x_medidas:np.ndarray,y_medidas:np.ndarray,grau:int) ->
raise ValueError("Não há dados suficientes para um polinômio de grau {grau} (overfitting)")
if not (isinstance(x_medidas[0],Medida) and isinstance(y_medidas[0],Medida)):
raise TypeError('x_medidas e y_medidas precisam ser np.ndarray de medidas')
x_medidas=nominais(x_medidas)
y_medidas=nominais(y_medidas)
x_medidas=np.array([x._nominal.magnitude for x in x_medidas])
y_medidas=np.array([y._nominal.magnitude for y in y_medidas])
p, cov = np.polyfit(x_medidas.astype(float), y_medidas.astype(float), grau, cov=True)
medidas_coeficientes = np.array([Medida(valor, np.sqrt(cov[i, i]),'') for i, valor in enumerate(p)],dtype=Medida)
return MPolinomio(medidas_coeficientes)
Expand All @@ -106,7 +106,7 @@ def regressao_linear(x_medidas:np.ndarray,
def regressao_exponencial(x_medidas:np.ndarray,y_medidas:np.ndarray,
base:Real=np.exp(1)) -> MExponencial:

if not np.all(nominais(y_medidas)>0):
if not np.all([y._nominal.magnitude>0 for y in y_medidas]):
raise ValueError('Todos y precisam ser positivos para uma modelagem exponencial')

if base<1: raise ValueError('Base precisa ser maior que 1')
Expand All @@ -119,7 +119,7 @@ def regressao_exponencial(x_medidas:np.ndarray,y_medidas:np.ndarray,
@obrigar_tipos
def regressao_potencia(x_medidas:np.ndarray, y_medidas:np.ndarray) -> MLeiDePotencia:

if not bool(np.all(nominais(y_medidas)>0) and np.all(nominais(x_medidas)>0)):
if not bool(np.all([y._nominal.magnitude>0 for y in y_medidas]) and np.all([x._nominal.magnitude>0 for x in x_medidas])):
raise ValueError('Todos x e y precisam ser positivos para uma modelagem exponencial')
polinomio=regressao_linear(log(x_medidas),log(y_medidas))
a=exp(polinomio.b)
Expand Down
Loading

0 comments on commit 97eae47

Please sign in to comment.