<jupyter_start><jupyter_text>Definición de los Interpoladores  1.- Lagrange parte real (a partir de forma compleja)<jupyter_code>class PartReLagrange2D:
    def __init__(self, X, Y, Z):
        # Metodo para inicializar el interpolador
        self.X = X
        self.Y = Y
        self.Zre = Z[0,:]
        self.Zim = Z[1,:]
        
        self.n_puntos = X.size
        
        # Valores que solo es necesario calcular al generar el interpolador
        self.L1_den = np.zeros(self.n_puntos, dtype=float)
        self.L2_neg = np.zeros(self.n_puntos, dtype=float)
        
        # Itera sobre cada uno de los puntos
        for k in range(self.n_puntos):
            k_dif_X = X[k] - self.X
            k_dif_Y = Y[k] - self.Y
            k_dif_X[k] = 1.0
            k_dif_Y[k] = 1.0
            
            L1k_den_X = np.square(k_dif_X)
            L1k_den_Y = np.square(k_dif_Y)
            L1k_den = np.sqrt(np.prod(L1k_den_X + L1k_den_Y))
            self.L1_den[k] = L1k_den
            
            k_dif_X[k] = 0
            k_dif_Y[k] = 0
            L2k_neg = np.sum(np.arctan2(k_dif_Y,k_dif_X))
            self.L2_neg[k] = L2k_neg
        
        # Agrega terminos correspondientes a cada Z
        Z_abs = np.sqrt(np.square(self.Zre) + np.square(self.Zim))
        Z_ang = np.arctan2(self.Zim, self.Zre)
        self.L1_den = np.divide(Z_abs, self.L1_den)
        self.L2_neg = self.L2_neg - Z_ang
    
    def interp(self, x, y):
        # Metodo para interpolar un punto dado (x,y)
        L1_num = np.zeros(self.n_puntos, dtype=float)
        L2_pos = np.zeros(self.n_puntos, dtype=float)
        
        # Itera sobre cada uno de los puntos
        for k in range(self.n_puntos):
            k_dif_X = x - self.X
            k_dif_Y = y - self.Y
            k_dif_X[k] = 1.0
            k_dif_Y[k] = 1.0
            
            L1k_num_X = np.square(k_dif_X)
            L1k_num_Y = np.square(k_dif_Y)
            L1k_num = np.sqrt(np.prod(L1k_num_X + L1k_num_Y))
            L1_num[k] = L1k_num
            
            k_dif_X[k] = 0
            k_dif_Y[k] = 0
            L2k_pos = np.sum(np.arctan2(k_dif_Y,k_dif_X))
            L2_pos[k] = L2k_pos
        
        L1 = np.multiply(L1_num, self.L1_den)
        L2 = np.cos(L2_pos - self.L2_neg)
        L = np.multiply(L1,L2)
        z = np.sum(L)
        
        return z<jupyter_output><empty_output><jupyter_text>2.- Barycentric Lagrange<jupyter_code>class BarLagrange2D:
    def __init__(self, X, Y, Z):
        # Metodo para inicializar el interpolador
        self.X = X
        self.Y = Y
        self.Zre = Z[0,:]
        self.Zim = Z[1,:]
        
        self.n_puntos = X.size
        self.W = np.zeros(self.n_puntos, dtype=float)
        self.W_noZ = np.zeros(self.n_puntos, dtype=float)
        self.alfa = np.zeros(self.n_puntos, dtype=float)
        self.alfa_noZ = np.zeros(self.n_puntos, dtype=float)
        
        for k in range(self.n_puntos):
            k_dif_X = X[k] - self.X
            k_dif_Y = Y[k] - self.Y
            k_dif_X[k] = 1.0
            k_dif_Y[k] = 1.0
            
            Wk_X = np.square(k_dif_X)
            Wk_Y = np.square(k_dif_Y)
            Wk = 1/np.sqrt(np.prod(Wk_X + Wk_Y))
            self.W[k] = Wk
            self.W_noZ[k] = Wk
            
            k_dif_X[k] = 0
            k_dif_Y[k] = 0
            alfak = np.sum(np.arctan2(k_dif_Y, k_dif_X))
            self.alfa[k] = alfak
            self.alfa_noZ[k] = alfak
        
        # Agrega terminos correspondientes a cada Z
        Z_abs = np.sqrt(np.square(self.Zre) + np.square(self.Zim))
        self.W = np.multiply(self.W, Z_abs)
        self.alfa = self.alfa - np.arctan2(self.Zim, self.Zre)
        
        # Valores utiles derivados de alfa:
        self.s_alfa = np.sin(self.alfa)
        self.c_alfa = np.cos(self.alfa)
        self.s_alfa_noZ = np.sin(self.alfa_noZ)
        self.c_alfa_noZ = np.cos(self.alfa_noZ)
    
    def interp(self, x, y):
        # Verificar que el punto no se encuentra entre los datos iniciales
        if (x in self.X) and (y in self.Y):
            ind_x = np.where(self.X==x)[0]
            ind_y = np.where(self.Y==y)[0]
            intersec = np.intersect1d(ind_x,ind_y)
            if intersec.shape[0] > 0:
                return self.Zre[intersec[0]]
        
        # Metodo para interpolar un punto dado (x,y)
        X_dif = x - self.X
        Y_dif = y - self.Y
        ang = np.arctan2(Y_dif, X_dif)
        c_t = np.cos(ang)
        s_t = np.sin(ang)
        
        suma_cuad = np.square(X_dif) + np.square(Y_dif)
        
        theta = np.sum(ang)
        c_theta = np.cos(theta)
        s_theta = np.sin(theta)
        
        # Se calculan los Lk
        Lk_t1 = s_theta*c_t - c_theta*s_t
        Lk_t2 = c_theta*c_t + s_theta*s_t
        Lk = np.multiply(self.s_alfa,Lk_t1) + np.multiply(self.c_alfa,Lk_t2)
        Lk_noZ = np.multiply(self.s_alfa_noZ,Lk_t1) + np.multiply(self.c_alfa_noZ,Lk_t2)
        
        # Se calcula el valor usando 2da forma baricentrica
        div = np.sqrt(suma_cuad)
        num = np.sum(np.divide(np.multiply(self.W, Lk), div))
        den = np.sum(np.divide(np.multiply(self.W_noZ, Lk_noZ), div))
        z = num/den
        
        return z<jupyter_output><empty_output><jupyter_text>Corrección imaginaria<jupyter_code>def EstInteg(X, Y, Z):
    # Estima la integral con cuadratura por regla del rectangulo
    # X - Matriz con el valor x de cada punto
    # Y - Matriz con el valor y de cada punto
    # Z - Matriz con el valor z de cada punto
    
    n_pts = Z.shape[0] * Z.shape[1]
    vol = (X.max()-X.min())*(Y.max()-Y.min())*Z.sum()/n_pts
    return vol
def CorrIm(X, Y, phi1, phi2, psi1, psi2, psi3):
    # Genera la correccion imaginaria
    # X - Vector de valores de x
    # Y - Vector de valores de y
    # phi/psi parametros de la funcion usada en la correccion
    
    T1 = 2 * phi1 * np.multiply(X,Y)
    T2 = phi2 * Y
    T3 = psi1 * (np.power(X,2) - np.power(Y,2))
    T4 = psi2 * X
    res = T1 + T2 + T3 + T4 + psi3
    
    return res
def EstOscil(arr_param):
    # Estima las oscilaciones a partir de una serie de puntos y
    #  una correccion dadas
    # arr_param - Arreglo de valores [phi1,phi2,psi1,psi2,psi3]
    
    # Genera correccion imaginaria
    Zim = CorrIm(X_GLOB, Y_GLOB, arr_param[0], arr_param[1], arr_param[2], arr_param[3], arr_param[4])
    
    # Genera interpolador a partir de los puntos + correccion
    barLag = BarLagrange2D(X_GLOB, Y_GLOB, np.array([Z_GLOB, Zim]))
    vInterp = np.vectorize(barLag.interp)
    
    # Generar grilla densa
    step_x = (MAX_X_GLOB-MIN_X_GLOB)/N_PTS_GLOB
    step_y = (MAX_Y_GLOB-MIN_Y_GLOB)/N_PTS_GLOB
    MG = np.mgrid[MIN_X_GLOB:(MAX_X_GLOB+step_x):step_x, MIN_Y_GLOB:(MAX_Y_GLOB+step_y):step_y]
    X_test = MG[0]
    Y_test = MG[1]
    
    # Evaluar oscilaciones
    Z_test = vInterp(X_test.flatten(), Y_test.flatten())
    Z_test_rs = np.reshape(Z_test,(N_PTS_GLOB+1,N_PTS_GLOB+1))
    dX = np.gradient(Z_test_rs, step_x, axis=0)
    dY = np.gradient(Z_test_rs, step_y, axis=1)
    sumCuad = np.power(dX,2) + np.power(dY,2)
    est_osc = EstInteg(X_test,Y_test,sumCuad)
    
    return est_osc<jupyter_output><empty_output><jupyter_text>Función que permite generar el interpolador:<jupyter_code>def GenerarInterpoladorLagrange2D(X,Y,Z,x_min=0,x_max=1,y_min=0,y_max=1,n_param=5,n_pts_grilla_oscil=20):
    # Genera interpolador usando propuesta de Lagrange 2D en
    #  forma baricentrica, con la correcion imaginaria que
    #  minimice las oscilaciones.
    # X - Arreglo de valores de x
    # Y - Arreglo de valores de y
    # Z - Arreglo de valores de z
    # x_min/x_max - Dominio en el eje x
    # y_min/y_max - Dominio en el eje y
    # n_pts_grilla_oscil - Densidad de la grilla usada en la
    #  estimacion de las oscilaciones
    
    # Param globales dan param extra a la func a minimizar
    global X_GLOB
    global Y_GLOB
    global Z_GLOB
    global MIN_X_GLOB
    global MAX_X_GLOB
    global MIN_Y_GLOB
    global MAX_Y_GLOB
    global N_PTS_GLOB
    X_GLOB = X
    Y_GLOB = Y
    Z_GLOB = Z
    MIN_X_GLOB = x_min
    MAX_X_GLOB = x_max
    MIN_Y_GLOB = y_min
    MAX_Y_GLOB = y_max
    N_PTS_GLOB = n_pts_grilla_oscil
    
    # Optimiza la correccion imaginaria
    arr_param = np.zeros(n_param)
    min_out = minimize(EstOscil, arr_param)
    arr_param = min_out.x
    print(min_out.message)
    
    # Aplica correccion y genera el interpolador
    Zim = CorrIm(X,Y,arr_param[0],arr_param[1],arr_param[2],arr_param[3],arr_param[4])
    barLag = BarLagrange2D(X, Y, np.array([Z, Zim]))
    vInterp = np.vectorize(barLag.interp)
    
    return vInterp<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1076109450448379, 'fraction_numerical': 0.015980685214991953, 'mean_word_length': 2.073851590106007, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '524355', 'license': 'MIT', 'n_tokens_mistral': 3719, 'n_tokens_neox': 3636, 'n_words': 696, 'path': 'Algoritmo Lagrange 2D.ipynb', 'repo_name': 'Lucas18496/Interpolacion-Lagrange-2D', 'size': '8698'}