miércoles, 29 de julio de 2015

ANÁLISIS DE LA COMPLEJIDAD DE MÉTODOS DE ORDENACIÓN Y SU IMPLEMENTACIÓN

La tarea de la programación esta ligada al objetivo de obtener algoritmos que resuelvan un problema con la mayor eficiencia posible; de hecho es sorprendente comprobar las múltiples formas como podemos resolver un mismo problema y las ventajas que conseguimos , en términos de eficiencia , al buscar soluciones alternativas a las ya conocidas o consideradas como evidentes.
Para comparar y analizar la eficiencia de los algoritmos , estos los consideramos escritos en un lenguaje de programación de alto nivel , pero aun empleando la misma representación , establecer una medida precisa de la eficiencia de un algoritmo no es fácil.En efecto , fijémonos en que una definición de eficiencia podría ser el numero de instrucciones que tiene el programa ; sin embargo esto no se correspondería , con el concepto intuitivo que tenemos de eficiencia(según el cual,el algoritmo mas eficiente seria aquel que tardase menos tiempo en resolver el problema sobre una misma maquina), dado que todas las instrucciones no utilizan el mismo tiempo de procesador aun realizando la misma función.

MÉTODOS DE ORDENACIÓN:
En computación y matemáticas un algoritmo de ordenamiento es un algoritmo que pone elementos de una lista o un vector en una secuencia dada por una relación de orden, es decir, el resultado de salida ha de ser una permutación  o reordenamiento de la entrada que satisfaga la relación de orden dada. Los ordenamientos eficientes son importantes para optimizar el uso de otros algoritmos (como los de búsqueda y fusión) que requieren listas ordenadas para una ejecución rápida. También es útil para poner datos en forma canónica y para generar resultados legibles por humanos.



MÉTODO DE ORDENAMIENTO BURBUJA:

Este es uno de los métodos de ordenamiento mas usados .aunque no de los mas eficaces.
Consiste en recorrer la lista de valores a ordenar y compararlos dos a dos.Si los elementos están bien ordenados, pasamos al siguiente , hasta llegar al final de la lista.El proceso completo se repite hasta que la lista este ordenada.




Algoritmo:
DESDE I=1 hasta N-1 hacer
    DESDE J=1 hasta N-1 hacer
          Si v[J]>V[J+1] entonces
                Aux= V[J]
                V[J]=V[J+1]
                V[J+1]=Aux
           FIN SI
     FIN DESDE
FIN DESDE

Análisis de Complejidad:











El ciclo interno se ejecuta n veces para una lista de n elementos. El ciclo externo también se ejecuta n veces. Es decir, la complejidad es n * n = O(n2). El comportamiento del caso promedio depende del orden de entrada de los datos, pero es sólo un poco mejor que el del peor caso, y sigue siendo O(n2).

Implementación
public int burbuja(int[] arreglo)
    {  
        int aux,num_intercambios=0;  
        for(int i=1;i <  arreglo.length;i++)
        {  
            for (int j=0 ; j <  arreglo.length- 1; j++)
            {  
                if (arreglo[j] > arreglo[j+1])
                {  
                    aux = arreglo[j];  
                    arreglo[j] = arreglo[j+1];  
                    arreglo[j+1] = aux;  
                    num_intercambios++;
                }  
            }  
        }  
        //Nos retorna el numero de operaciones que hace referencia a la complejidad
        //Si desea obtener la lista de valores ordenados , recuperar este valor a través de un método get
        return num_intercambios;
    }  

MÉTODO DE ORDENACIÓN INSERCIÓN:
La idea de este algoritmo de ordenación consiste en ir insertando un elemento de la lista o un arreglo en la parte ordenada de la misma, asumiendo que el primer elemento es la parte ordenada, el algoritmo ira comparando un elemento de la parte desordenada de la lista con los elementos de la parte ordenada, insertando el elemento en la posición correcta dentro de la parte ordenada, y así sucesivamente hasta obtener la lista ordenada. Para explicarlo mejor nos basaremos en el siguiente enunciado:
“Para cada elemento de la lista después del primero, comparar los elementos con los anteriores desplazando una posición a la derecha a todos los elementos anteriores que cumplan con la comparación y luego colocar el elemento en la posición del último elemento anterior desplazado.”

Algoritmo:
for (i=1; i<TAM; i++)
      aux = array[i];
      j = i - 1;
      while ( (array[j] > aux) && (j >= 0) )
          array[j+1] = array[j];
           j--;
      array[j+1] = aux;

Análisis de la Complejidad:


Para una lista de n elementos el ciclo externo se ejecuta n-1 veces. El ciclo interno se ejecuta como máximo una vez en la primera iteración, 2 veces en la segunda, 3 veces en la tercera, etc. Esto produce una complejidad O(n2).

Implementación:
//METODO DE ORDENACION : INSERCION
    public int Insercion(int[] array){
        int aux,num_intercambios=0;
        for (int i = 1; i <  array.length; i++) {
            aux = array[i];
            for (int j = i-1; j   > =0 && array[j]  > aux; j--) {
                array[j+1]=array[j];
                array[j]=aux;
                num_intercambios++;
            }
        }
        //Nos retorna el numero de operaciones que hace referencia a la complejidad
        //Si desea obtener la lista de valores ordenados , recuperar este valor a través de un método get
return num_intercambios; }

MÉTODO DE ORDENACIÓN QUICKSORT:


Sin duda, este algoritmo es uno de los más eficientes. Este método es el más rápido gracias a sus llamadas recursivas, basándose en la teoría de divide y vencerás.
Lo que hace este algoritmo es dividir recursivamente el vector en partes iguales, indicando un elemento de inicio, fin y un pivote (o comodín) que nos permitirá segmentar nuestra lista. Una vez dividida, lo que hace, es dejar todos los mayores que el pivote a su derecha y todos los menores a su izquierda Al finalizar el algoritmo, nuestros elementos están ordenados.
Por ejemplo, si tenemos 3 5 4 8 básicamente lo que hace el algoritmo es dividir la lista de 4 elementos en partes iguales, por un lado 3, por otro lado 4 8 y como comodín o pivote el 5. Luego pregunta, 3 es mayor o menor que el comodín? Es menor, entonces lo deja al lado izquierda Y como se acabaron los elementos de ese lado, vamos al otro lado. 4 Es mayor o menor que el pivote? Menor, entonces lo tira a su izquierda. Luego pregunta por el 8, al ser mayor lo deja donde está, quedando algo así: 3 4 5 8.
En esta figura se ilustra de mejor manera un vector con más elementos, usando como pivote el primer elemento:


Algoritmo

// Inicialización de variables
    elem_div = lista[sup];
    i = inf - 1;
    j = sup;
    cont = 1;
    
    // Verificamos que no se crucen los límites
    if (inf >= sup)
          retornar;
    
    //  Clasificamos la sublista
    while (cont)
          while (lista[++i] < elem_div);
          while (lista[--j] > elem_div);
         if (i < j)
              temp = lista[i];
              lista[i] = lista[j];
              lista[j] = temp;
         else
              cont = 0;
   
   // Copiamos el elemento de división
   // en su posición final
    temp = lista[i];
    lista[i] = lista[sup];
    lista[sup] = temp;
   
   // Aplicamos el procedimiento
   // recursivamente a cada sublista
    OrdRap (lista, inf, i - 1);
    OrdRap (lista, i + 1, sup);

Análisis de la Complejidad:

Caso promedio: La complejidad para dividir una lista de n es O(n). Cada sublista genera en promedio dos sublistas más de largo n/2. Por lo tanto la complejidad se define en forma recurrente como:
f(1) = 1
f(n) = n + 2 f(n/2)
La forma cerrada de esta expresión es:
f(n) = n log2n
Es decir, la complejidad es O(n log2n).
El peor caso ocurre cuando la lista ya está ordenada, porque cada llamada genera sólo una sublista (todos los elementos son menores que el elemento de división). En este caso el rendimiento se degrada a O(n2). 
Implementación

//METODO DE ORDENACION: QUICKSORT
    public  int ordenacionRapida(int[] v) {
        final int N = v.length;
        quicksort(v,0,N-1);
        return num_intercambios_qs;
    }
 
    public void quicksort(int A[], int izq, int der) {
    int pivote=A[izq]; // tomamos primer elemento como pivote
    int i=izq; // i realiza la búsqueda de izquierda a derecha
    int j=der; // j realiza la búsqueda de derecha a izquierda
    int aux;

    while(i< j){            // mientras no se crucen las búsquedas
       while(A[i]< =pivote && i< j) i++; // busca elemento mayor que pivote
       while(A[j] > pivote) j--;         // busca elemento menor que pivote
       if (i< j) {                      // si no se han cruzado                      
           aux= A[i];                  // los intercambia
           A[i]=A[j];
           A[j]=aux;
       }
       num_intercambios_qs++;
        
     }
     A[izq]=A[j]; // se coloca el pivote en su lugar de forma que tendremos
     A[j]=pivote; // los menores a su izquierda y los mayores a su derecha
     if(izq< j-1)
        quicksort(A,izq,j-1); // ordenamos subarray izquierdo
     if(j+1 < der)
        quicksort(A,j+1,der); // ordenamos subarray derecho
    }
    

MÉTODO DE ORDENACIÓN MERGESORT:
Este algoritmo consiste básicamente en dividir en partes iguales la lista de números y luego mezclarlos comparándolos, dejándolos ordenados.
Si se piensa en este algoritmo recursivamente, podemos imaginar que dividirá la lista hasta tener un elemento en cada lista, luego lo compara con el que está a su lado y según corresponda, lo sitúa donde corresponde.
En la siguiente figura podemos ver cómo funciona:



Análisis de la Complejidad:












La complejidad para dividir una lista de n es O(n). Cada sublista genera en promedio dos sublistas más de largo n/2. Por lo tanto la complejidad se define en forma recurrente como:
f(1) = 1
f(n) = n + 2 f(n/2)
La forma cerrada de esta expresión es:
f(n) = n log2n
Es decir, la complejidad es O(n log2n).




Implementación:

//METODO DE ORDENACION: MERGESORT     
    public int MergeSort(int a[], int iMin, int iMax) 
    {
        mergeSort (a,iMin,iMax) ;
        return num_intercambios_ms;
    }
    public void mergeSort (int a[], int iMin, int iMax) 
    {
        // Caso Base
    if(iMin  >= iMax) 
        {
            return;
    }
    // Cortamos para aplicar mergeSort recursivamente
    int k = (iMin+iMax) / 2;
    mergeSort(a, iMin, k);
    mergeSort(a, k+1, iMax);
    // Utilizamos un arreglo temporal
    int l = iMax-iMin+1;
    int temp[] = new int[l];
    for(int i = 0; i <  l; i++)
        {
        temp[i] = a[iMin+i];
        }
    // Mezclamos
    int i1 = 0;
    int i2 = k-iMin+1;
    for(int i = 0; i <  l; i++) 
        {
            if(i2 < = iMax-iMin) 
            {
                if(i1 < = k-iMin) 
                {
                    if(temp[i1]  > temp[i2]) 
                    {
                        a[i+iMin] = temp[i2++];
                    }
                    else
                    {
                        a[i+iMin] = temp[i1++];
                    }
                }
                else
                {
                    a[i+iMin] = temp[i2++];
                }
                
                num_intercambios_ms++;
            }
            else 
            {
                a[i+iMin] = temp[i1++];
                
                num_intercambios_ms++;
            }
        }
    }

MÉTODO DE ORDENACIÓN HEAPSORT


Este algoritmo consiste en almacenar todos los elementos del vector a ordenar en un montículo (heap), y luego extraer el nodo que queda como nodo raíz del montículo (cima) en sucesivas iteracciones obteniendo el conjunto ordenado. Basa su funcionamiento en una propiedad de los montículos, por la cual, la cima contiene siempre el menor elemento (o el mayor, según se haya definido el montículo) de todos los almacenados en él. El algoritmo, después de cada extracción, re coloca en el nodo raíz o cima, la última hoja por la derecha del último nivel. Lo cual destruye la propiedad heap del árbol. Pero, a continuación realiza un proceso de "descenso" del número insertado de forma que se elige a cada movimiento el mayor de sus dos hijos, con el que se intercambia. Este intercambio, realizado sucesivamente "hunde" el nodo en el árbol restaurando la propiedad montículo del árbol y dejando paso a la siguiente extracción del nodo raíz.


Análisis de Complejidad:





Implementación:


 // METODO DE ORDENACION: HEAP SORT
    public int ordenacionMonticulos(int[] v) 
    {
        final int N = v.length;
        for(int nodo = N/2; nodo >=0; nodo--) hacerMonticulo(v, nodo, N-1);
        for(int nodo = N-1; nodo >=0; nodo--) {
            int tmp = v[0];
            v[0]    = v[nodo];
            v[nodo] = tmp;
            hacerMonticulo(v, 0, nodo-1);
        }
        return num_intercambios_hs;
    }
    public void hacerMonticulo(int[] v, int nodo, int fin)
    {
        int izq = 2*nodo+1;
        int der = izq+1;
        int may;
        if(izq >fin) return;
        if(der >fin) 
        {
            may=izq;  
            num_intercambios_hs++;
        }
        else
        {
            if(v[izq] >v[der])
                may= izq;
            else
                may=der; 
            num_intercambios_hs++;
        }
        if(v[nodo] <  v[may]) 
        {
            int tmp = v[nodo];
            v[nodo] = v[may];
            v[may]  = tmp; 
            num_intercambios_hs++;
            hacerMonticulo(v, may, fin); 
            num_intercambios_hs++;
        }
    }
Fuente Teóricas: Wikipedia, algunos documentos de Prezzi, apuntes de Clase.

sábado, 25 de julio de 2015

CIFRADO DE CESAR

En criptografía, el cifrado César, también conocido como cifrado por desplazamiento, código de César o desplazamiento de César, es una de las técnicas de cifrado más simples y más usadas. Es un tipo de cifrado por sustitución en el que una letra en el texto original es reemplazada por otra letra que se encuentra un número fijo de posiciones más adelante en el alfabeto. Por ejemplo, con un desplazamiento de 3, la A sería sustituida por la D (situada 3 lugares a la derecha de la A ), la B sería reemplazada por la E, etc. Este método debe su nombre a Julio César, que lo usaba para comunicarse con sus generales.


El cifrado César muchas veces puede formar parte de sistemas más complejos de codificación, como el cifrado Vigenère, e incluso tiene aplicación en el sistema ROT13. Como todos los cifrados de sustitución alfabética simple, el cifrado César se descifra con facilidad y en la práctica no ofrece mucha seguridad en la comunicación.

EXPLICACIÓN DEL ALGORITMO:


El proceso  empieza  transformando las letras  del alfabeto en números, por ello considerando a P  como el equivalente numérico  de una  letra  en el texto plano,  y C como el equivalente  de la correspondiente letra  en el texto  cifrado, tenemos  la siguiente expresión denominada transformación del César:




IMPLEMENTACIÓN:
Nota el presente algoritmo recibe como parámetro el numero de desplazamientos a realizar, el algoritmo por defecto realiza 3.


public class Cesar{ 
 
    public String cifrado(String frase, int n){ 
 
        int i,j; 
 
        char fraseCifrada[] = new char[frase.length()]; 
 
        fraseCifrada = frase.toCharArray(); 
 
        for(i=0;i< frase.length();i++){ 
            for(j=0;j< n;j++){ 
                if((fraseCifrada[i] > =65 && fraseCifrada[i] < 90) || (fraseCifrada[i] > =97 && fraseCifrada[i] < 122)){ 
                    fraseCifrada[i]++;               
                } 
                else if(fraseCifrada[i]==90) 
                    fraseCifrada[i]='A'; 
                else if(fraseCifrada[i]==122) 
                    fraseCifrada[i]='a'; 
            } 
        } 
 
        frase = String.valueOf(fraseCifrada); 
 
        return frase; 
    } 
 
     
        public String descifrado(String frase, int n){ 
 
        int i,j; 
 
        char fraseDescifrada[] = new char[frase.length()]; 
 
        fraseDescifrada = frase.toCharArray(); 
 
        for(i=0;i< frase.length();i++){ 
            for(j=0;j< n;j++){ 
                if((fraseDescifrada[i] > 65 && fraseDescifrada[i] < = 90) || (fraseDescifrada[i] > 97 && fraseDescifrada[i] < =122)){ 
                    fraseDescifrada[i]--;               
                } 
                else if(fraseDescifrada[i]==65) 
                    fraseDescifrada[i]='Z'; 
                else if(fraseDescifrada[i]==97) 
                    fraseDescifrada[i]='z'; 
            } 
        } 
 
        frase = String.valueOf(fraseDescifrada); 
 
        return frase; 
    } 
} 

TEOREMA DEL CHINO RESTANTE

Tanto en teoría y práctica se presentan problemas de encontrar un número que tiene restos prescrito cuando es dividido por dos o más módulos. Tales problemas aparecen en adivinanzas chinas antiguas y su solución es conocida como teorema chino de los restos.
El teorema chino de los restos conocido por Sun Tse (alrededor del año 250 después de J.C)- dice lo siguiente:
Un sistema de dos o más congruencias que pueden resolverse separadamente con solución única, pueden resolverse también  simultáneamente si lo módulos son relativamente primos dos a dos.

Teorema chino de los restos 
























El teorema del Chino Restante hace uso del inverso multiplicativo, por lo que recomendamos que revise la siguiente publicación:



Implementacion:
import java.util.Scanner;
import Controladores.Inverso;

public class Chino {
    int num_ec;
    Scanner aux_num_ec = new Scanner(System.in);
    Scanner aux_a = new Scanner(System.in);
    Scanner aux_m = new Scanner(System.in);
    public void CalcularChinoRestante()
    {
        System.out.print("INGRESAR EL NUMERO DE ECUACIONES: ");
        num_ec=aux_num_ec.nextInt();
        System.out.println("");
        int a[]=new int[num_ec],m[]=new int[num_ec],M[]=new int[num_ec],y[]=new int[num_ec];
        int x=0;
        // a sub i
        for(int i=0;i< num_ec;i++){
            System.out.print("INGRESE a"+(i+1)+": ");
            a[i]=aux_a.nextInt();
            System.out.println("");
        }
        // m sub i
        for(int i=0;i< num_ec;i++){
            System.out.print("INGRESE m"+(i+1)+": ");
            m[i]=aux_m.nextInt();
            System.out.println("");
        }

        int prod=1;

        // calculamos el producto = M
        for(int i=0;i< num_ec;i++){
            prod*=m[i];
        }
        // calculo de los Mi= M/m sub i
        for(int i=0;i< num_ec;i++)
        {
            M[i]=prod/m[i];
        }
        int ban=0;
        // inversos 
        Inverso inverso=new Inverso();
        for(int i=0;i< num_ec;i++){
            y[i]=(int) inverso.CalcularInverso(M[i],m[i]);
            if(y[i]==-1)
            {
                ban=1;
            }
            System.out.println("INVERSO: "+y[i]);
        }
        if(ban==0)
        {
            for(int i=0;i< num_ec;i++)
            {
                x+=a[i]*M[i]*y[i];
            }

            x%=prod;
            System.out.println("EL VALOR DE X ES: "+x);
        }
        else
        {
            System.out.println("EL SISTEMA NO TIENE SOLUCIONES");
        }
    }
}

martes, 21 de julio de 2015

ALGORITMO QUADRATIC SIEVE


Es un algoritmo de factorización de enteros y, en la práctica, el segundo método más rápido conocido (después de Number field Sieve). Es todavía el más rápido para enteros que tienen 100 o menos dígitos decimales, y es considerado mucho más sencillo que la NFS. Es un algoritmo de factorización de propósito general, lo que significa que su tiempo de ejecución únicamente depende el tamaño del entero a ser factorizado, y no sobre una estructura especial o propiedades.

Algoritmo:







Ejemplo Aplicativo:
Nota: El valor de X, es un numero aleatorio, en este caso elegimos el 12






Observación: si al momento de hallar el mcd(x-y,n) este nos da un valor de 1 o n , debemos volver a buscar otra combinación de filas a sumar.

Implementación:
La siguiente implementación fue realizada en conjunto con uno de los autores de este Blog (Rafael Larco Buchelli).

Clase QuadraticSieve
import java.util.ArrayList;

public class QuadraticSieve {
    
    public static int base=40;
    
    EsPrimo esPrimo = new EsPrimo();
    Jacobi jacobi = new Jacobi();
    
    public ArrayList< Long > QS(int n){
        //***************CALCULO DE LA BASE DE FACTORES************//
        int jac=0,raiz=0;
        ArrayList< Long > solucion = new ArrayList<  >();
        ArrayList< Integer > factoresBase = new ArrayList<  >();
        ArrayList< Integer > valoresX = new ArrayList<  >();
        ArrayList< Integer > valoresY = new ArrayList<  >();
        ArrayList< Boolean > ySuaves = new ArrayList<  >();
        ArrayList< Integer > valoresSuaves = new ArrayList<  >();
        factoresBase.add(-1);
        
        for (int i = 2; i <  base; i++) {
            if(esPrimo.esPrimo(i)){
                jac=jacobi.Jacobi(n, i);
                if(jac==1){
                    factoresBase.add(i);
                }
            }
        }
        System.out.println("Mostrando Base De Factores");
        for (int i = 0; i <  factoresBase.size(); i++) {
            System.out.println(factoresBase.get(i));
        }
        
        //*********************RAIZ CUADRADA DE N*************//
        raiz=(int) Math.sqrt(n);
        System.out.println("\nRaiz Cuadrada De "+n+" : "+raiz);
        
        //*******************BUSQUEDA DE VALORES*************//
        for (int i = -base; i < = base; i++) {
            valoresX.add(raiz+i);
        }
        
        for (int i = -base ; i < = base; i++) {
            valoresY.add((int)Math.pow((raiz+i), 2)-n);  
        }

        //**********HALLANDO LOS Y'S SUAVES*************//
        int i,j,valor,p;
        int []a= new int[50];
        for (int k = 0; k <  valoresY.size(); k++) {
            valor=Math.abs(valoresY.get(k));
            i=2;
            j=0;
            while(valor >1){
               if(valor%i==0){
                  valor=valor/i;
                  a[j]=i;
                  j++;
                  i=2;
               }
               else
                  i++;
            }
            p=0;
            for (int l = 0; l <  j; l++) {
                boolean band=true;
                for (int m = 0; m <  factoresBase.size() && band==true; m++) {
                    if(a[l]==factoresBase.get(m)){
                        band=false;
                        p++;
                    }
                }
                
            }
            
            if(p==j){
                System.out.println(valoresY.get(k)+" | Suave"+" X: "+Math.sqrt(valoresY.get(k)+n));
                ySuaves.add(true);
                valoresSuaves.add(valoresY.get(k));
                
            }
            else{
//                System.out.println(valoresY.get(k)+" | No Suave");
                ySuaves.add(false);
            }  
        }
        
        //**************CALCULANDO LA MATRIZ*************//
        int [][]matrizInicial = new int [valoresSuaves.size()][factoresBase.size()];
        int conRep,filaMI=0,columnaMI=0;
        ArrayList< Integer > factorizacionN = new ArrayList<  >();
        Factorizar factorizar=new Factorizar();
        
        for (int k = 0; k <  valoresSuaves.size(); k++) {
            conRep=0;
            columnaMI=0;
            factorizacionN=factorizar.factorizarN(Math.abs(valoresSuaves.get(k)));
            if(valoresSuaves.get(k)< 0){
                factorizacionN.add(-1);
            }
            for (int l = 0; l <  factoresBase.size(); l++) {
                conRep=0;
                for (int m = 0; m <  factorizacionN.size(); m++) {
                    if(factoresBase.get(l)==factorizacionN.get(m)){
                        conRep++;
                    }
                }
                matrizInicial[filaMI][columnaMI]=conRep%2;
                columnaMI++;
            }
            filaMI++;
        }
        

        //*******************ELIMINACION GAUSSIANA*************//
        System.out.println("Gaussiana");
        /**********************************************************/
        /***Eliminacion de gauss: escoger las filas de la matriz***/
        /*identidad cuya fila en la matriz inicial son todos ceros*/
        /**********************************************************/
        
        int filas, columnas;
        filas=valoresSuaves.size();
        columnas=factoresBase.size();
        
        Identidad identidad = new Identidad();
        
        int [][]MI=new int[filas][filas];
        
        identidad.crearMatrizIdentidad(MI, filas);
        
        Gaussiana gaussiana = new Gaussiana();
        
        gaussiana.Gaussiana(matrizInicial, MI, filas, columnas);
        

        //**************OBTENIENDO LAS FILAS A USAR (CEROS)***********//
        boolean banderaCeros=true;
        ArrayList< Integer > FilasUsar = new ArrayList<  >();
        for(int q=0;q< filas;q++){
            banderaCeros=true;
            for(int w=0;w< columnas && banderaCeros==true;w++){
                if(matrizInicial[q][w]==1){
                    banderaCeros=false;
                }
        }
            if(banderaCeros==true){
                System.out.println("Usar Filas: "+q);
            }
            if(banderaCeros==true){
                FilasUsar.add(q);
            }
        }
        
        /***************CALCULANDO RESULTADO***********/
        int filaUsar;
        long resultadoX,resultadoY,valorXSuave,respuestaVerdad_Uno,respuestaVerdad_Dos;
        boolean bandSolucion=true;
        for (int k = 0; k <  FilasUsar.size() && bandSolucion==true; k++) {
            resultadoX=1;
            resultadoY=1;
            respuestaVerdad_Uno=0;
            respuestaVerdad_Dos=0;
            filaUsar=FilasUsar.get(k);
            for (int l = 0; l <  MI.length; l++) {
                if(MI[filaUsar][l]==1){
                    valorXSuave=(long) Math.sqrt(valoresSuaves.get(l)+n);
                    resultadoX=resultadoX*valorXSuave;
                    resultadoY=resultadoY*valoresSuaves.get(l);
                }
            }
            System.out.println("Resultado Y Sin Modulo: "+resultadoY);
            resultadoX=resultadoX%n;
            System.out.println("Resultado X: "+resultadoX);
            resultadoY=(long) ((Math.sqrt(resultadoY)))%n;
            System.out.println("Resultado Y: "+resultadoY);
            
            MCD gcd = new MCD();
            
            respuestaVerdad_Uno=gcd.mcd((resultadoX-resultadoY), n);
            respuestaVerdad_Dos=gcd.mcd((resultadoX+resultadoY), n);
            
            if(respuestaVerdad_Uno*respuestaVerdad_Dos==n && respuestaVerdad_Uno!=1 && respuestaVerdad_Dos!=1){
                System.out.println("\nValor No Trivial: "+respuestaVerdad_Uno);
                System.out.println("\nEl Otro Valor: "+respuestaVerdad_Dos);
                solucion.add(0,respuestaVerdad_Uno);
                solucion.add(1,respuestaVerdad_Dos);
                bandSolucion=false;
            }     
        }
        return solucion;
    }
}


Clase CalcularExponente
public class EsPrimo {
    
    public boolean esPrimo(int numero){
        int contador = 2;
        boolean primo=true;
        while ((primo) && (contador!=numero)){
            if (numero % contador == 0)
                primo = false;
            contador++;
        }
        return primo;
    }
}
Clase Factorizar
import java.util.ArrayList;


public class Factorizar {
    public ArrayList< Integer >  factorizarN(int n){
        int i,j;
        ArrayList< Integer >  factores = new ArrayList<  > ();
        i=2;
        j=0;
        while(n > 1){
            if(n%i==0){
                n=n/i;
                factores.add(i);
                j++;
                i=2;
            }
            else
                i++;
        }
        return factores;
    }
}


Clase Gaussiana
public class Gaussiana {
    public void Gaussiana(int M[][], int Identidad[][], int filas, int columnas){
        int i=0;
    int k=0;
    boolean band=true;
        
    while(i< filas-1){   
            for(int j=0;j< columnas && band==true;j++){       
                if(M[i][j]==1){           
                    k=j;         
                    band=false;
                }
            }
     
            if(band==false){
                for(int u=i+1;u< filas;u++){
                    if(M[u][k]==1){
                        for(int w=0;w< columnas;w++){
                            M[u][w]^=M[i][w];
                            if(w< u){
                            Identidad[u][w]^=Identidad[i][w];
                            }
                        }  
                    }       
                }
            }
            band=true;
            i++;
        }
    }
}


Clase Identidad
public class Identidad {
    public void crearMatrizIdentidad(int I[][],int filas){
        for(int i=0;i< filas;i++){
            for(int j=0;j< filas;j++){      
            if(i==j){
                    I[i][j]=1;
                }
                else{
                    I[i][j]=0;
                }
        }
        }
    }
}

Clase Jacobi
public class Jacobi {
    
    CalcularExponente calcularExponente = new CalcularExponente();
    SonCongruentes sonCongruentes = new SonCongruentes();
    
    public int Jacobi(int a, int n){
        int e=0,a1=1,n1=0,s=-2;
    
        if(a==0 || a==1)
            return a;

        e=calcularExponente.hallarExponente(a);

        a1=(int)(a/Math.pow(2,e));

        if(e%2==0) // si 'e' es par
            s=1;
        else{
            if((sonCongruentes.son_congruentes(n,1,8))||(sonCongruentes.son_congruentes(n,7,8)))
                s=1;
            else
            if((sonCongruentes.son_congruentes(n,3,8))||(sonCongruentes.son_congruentes(n,5,8)))
                s=-1;
        }

        if((sonCongruentes.son_congruentes(n,3,4))&&(sonCongruentes.son_congruentes(a1,3,4)))
            s=-1*s;

        n1=n%a1;

        if(a1==1)
            return s;
        else
            return (s*Jacobi(n1,a1));
    }

}

Clase MCD
public class MCD {
    public long mcd(long a, long b){
        return (b == 0)? a : mcd(b, a % b);
    }
}


Clase Potencia Prima
import java.util.ArrayList;

public class PotenciaPrima {
    public boolean potenciaPrima(int n){
        int i;
        ArrayList< Integer > A = new ArrayList< >();
        i=2;
        while(n >1){
           if(n%i==0){
              n=n/i;
              A.add(i);
              i=2;
           }
           else
              i++;
        }

        boolean band=true;

        for(i=0;i < A.size()&&band==true;i++){
            for(int o=0;o < A.size();o++){
                if(A.get(i)!=A.get(o)){
                    band=false;
                }
            }
        }

        return band;
        }
}

Clase Congruencia
public class SonCongruentes {
    
    public boolean son_congruentes(long a, long b, long n){
        if((a-b)%n==0)
            return true;
        else
            return false;
    }
    
}

martes, 30 de junio de 2015

IMPLEMENTACIÓN DEL ALGORITMO BIG MCD


Con la implementación de este algoritmo podemos realizar operaciones mcd pero con números de n cifras y con una velocidad considerable

Por medio de teoría matemática usamos el modulo de una parte del numero para reemplazar el numero grande por uno mas pequeño de esta manera reducimos la complejidad y tiempo del problema

Ejemplo:

Paso 1: BIG_MCD(3421689512460,1442)
 
    big_num=3421689512460
    small=1442
 
Paso 2: Usamos un temporal para partir el numero big_num
 
    temp=342168951
    big_num=2460

Paso 3: Y buscamos su mod con small

    temp=temp%small
    temp=1097

Paso 4: Luego concatenamos el nuevo temporal con el big_num

    big_num=concatenar(temp,big_num)
    big_num=concatenar(1097,2460)
    big_num=10972460

Paso  5: Con los nuevos números en el MCD verificamos si los números resultantes son operables computacionalmente o si es necesario regresar al Paso 2 y aplicar otra vez el algoritmo para reducir big_num a menos cifras

    En este caso aplicamos mcd directamente


Ahora si el código en Java

Private void calcularActionPerformed(java.awt.event.ActionEvent evt) {                                         
        // TODO add your handling code here:
        String a,b,aux_b = null,aux,resul = "No Econtrado :(";
        boolean bucle=true;
        int cif1,cif2;
        a=n1.getText();
        b=n2.getText();
        Operaciones operar =new Operaciones();
        while(bucle)
        {
            if (a.compareTo(b)==0) {
                bucle=false;
                resul=a;
            } 
            else if(a.compareTo("0")==0)
            {
                bucle=false;
                resul=b;
            }
            else if(b.compareTo("0")==0)
            {
                bucle=false;
                resul=a;
            }            
            else if((a.length()>9)&&(b.length()>9))
            {
                resul = "No Econtrado :(";
            }
            else 
            {
                if(a.length()>9)
                {
                    //System.out.println("EL NUMERO 1 TIENEN MAS DE 9 CIFRAS");
                    //System.out.println(a);
                    a=operar.modular(a,b);
                    //System.out.println("EL nuevo A es : "+a);
                    //System.out.println("EL nuevo B es : "+b);
                }
                else if(b.length()>9)
                {
                    //System.out.println("EL NUMERO 2 TIENEN MAS DE 9 CIFRAS");
                    //System.out.println(b);
                    aux=a;        
                    a=b;
                    b=aux;
                    //System.out.println("EL nuevo A es : "+a);
                    //System.out.println("EL nuevo B es : "+b);
                }
                else
                {
                    //System.out.println("YA TERMINO :)");
                    //System.out.println(a+" , "+b);
                    resul=operar.mcd(a,b);
                    bucle=false;
                }
            }
        }
        resultado.setText(resul);
    }                                        

    private void limpiarActionPerformed(java.awt.event.ActionEvent evt) {                                        
        // TODO add your handling code here:
        n1.setText("");
        n2.setText("");
        resultado.setText("");
    }      

    public boolean mayor(String a, String b) {
        if(a.length()>b.length())
        { 
            return true;
        }
        else if(a.length()==b.length())
        { 
            int i=0;
            while(i<=a.length()-1)
            { 
                if(sacarnumero(a,i)>sacarnumero(b,i))
                { 
                    return true; 
                }
                if(sacarnumero(a,i)<sacarnumero(b,i))
                { 
                    return false;
                }
                else
                    i++;
                
            }
        }
        return false;
    }

    public String restar(String a, String b) {
        int i=a.length()-1;
        int j=b.length()-1;
        int an,bn,acarreo = 0;
        String res = ""; 
        while(i>=0)
        {    
            an=sacarnumero(a,i);
            if (j>=0) {
                bn=sacarnumero(b,j);
            }
            else
                bn=0; 
            if(an>=bn)
            { 
                    if (an-bn-acarreo<0) { 
                        res=res+String.valueOf(10+an-bn-acarreo); 
                        acarreo=1;
                    }
                    else
                    {
                        res=res+String.valueOf(an-bn-acarreo); 
                        acarreo=0;
                    }
            }
            else
            { 
                res=res+String.valueOf(10+an-bn-acarreo); 
                acarreo=1;
            }
            i--;
            j--;
        }
        StringBuilder builder=new StringBuilder(res);
        return builder.reverse().toString();
    }
    
    public String limpiador(String a) {
        String b="";
        char cero='0';
        int i = 0;
        while(a.charAt(i)==cero&&i<a.length()) 
        {
            i++;
        }
        while(i<a.length()) 
        {
            b=b+a.charAt(i); 
            i++;
        }
        return b;
    }
    
    public String modular(String a, String b) { 
        String temp,nBig;
        int n1,n2;
        temp=a.substring(0, 9);
        nBig=a.substring(9, a.length());
        n1=Integer.parseInt(temp);
        n2=Integer.parseInt(b); 
        if (n1>n2) {
            nBig=String.valueOf(n1%n2)+nBig;
        }
        return nBig;
    }

    public String mcd(String n1, String n2) {
        int a,b;
        a=Integer.parseInt(n1);
        b=Integer.parseInt(n2);
        while(b>0){
            if(a>b)
            {
                a=a-b;
            }
            else
            {
                b=b-a;
            }
 }
        n1=String.valueOf(a);
        return n1;
    }
    
    private static int sacarnumero(String a, int i) {
        return Integer.parseInt(String.valueOf(a.charAt(i)));
    }

domingo, 28 de junio de 2015

IMPLEMENTACION DEL ALGORITMO RHO POLLARD EN JAVA



El algoritmo rho de Pollard es un algoritmo especializado de factorización de números enteros. Fue inventado por John Pollard en 1975. Es especialmente efectivo a la hora de factorizar números compuestos que tengan factores pequeños.
El algoritmo rho emplea pues una función módulo n a modo de generador de una secuencia pseudoaleatoria. Hace funcionar una de las secuencias el doble de rápido que la otra, es decir, por cada iteración de una de las copias de la secuencia, la otra hace dos iteraciones. Sea x el estado actual de una secuencia e y el estado actual de la otra. En cada paso se toma el máximo común divisor (MCD) de |x − y| y n. Si este MCD llega a ser n, entonces finaliza el algoritmo con el resultado de fracaso, ya que esto significa que x = y y, por el algoritmo de la liebre y la tortuga, la secuencia ya ha completado su ciclo y seguir más allá sólo conseguiría repetir trabajo ya realizado.

Algoritmo:

Entrada:  Un número entero  “n” que no sea una potencia prima. 
Salida : Factor no trivial de «n»
a ← 2;
b ← 2;
PARA (i = 1, 2, . . .);
a ← a2 + 1 mod n;
b ← b2 + 1 mod n;
b ← b2 + 1 mod n;
d ← mcd(abs(a – b), n);
SI (1 < d < n)
Retornar d; 
SI (d >= n)
Retornar Sin exito; 
FIN PARA;
//Observación: Una potencia prima es una potencia entera y positiva de un
// número primo. Por ejemplo 5=5¹, 9=3² son potencias primas, 
//mientras que 6=2×3, 15=3×5 y 36=6²=2²×3² no lo son.
Implementación: 

Nota:La función rho usa como función auxiliar una llamada mcd, puedes usar cualquiera que ya hallas implementado en mi caso yo use el algoritmo de euclides extendido (ver publicación acerca de euclides extendido).

Función rho:
public boolean rho()
    {
        int a=2, b=2,d=1;
        boolean bandera;
        while(d==1)
        {
            a=((a*a)+1)%numero;
            b=((b*b)+1)%numero;
            b=((b*b)+1)%numero;
            d=(int) EuclidesIterativo(abs(a-b),numero);
            ca.add(a);
            cb.add(b);
            cd.add(d);
        }
        if(d>1 && d < numero)
        {
            bandera=true;
            return  bandera;
        }
        else
        {
            //NO EXISTE FACTOR TRIVIAL
            bandera=false;
            return bandera;
        }
    }
//Estoy almacenando cada valor que toma a,b y d para mostrarlo posteriormente
//en una interfaz, pero si deseas obtener el primer factor directamente , basta
//con imprimir el ultimo valor de "d".
Ejemplo:
Sea n = 8051 un número entero, el algoritmo reporta el factor no trivial 97. El otro factor es 83(Este factor se obtiene dividiendo n entre el factor no trivial obtenido por el algoritmo de Rho Pollard).




sábado, 27 de junio de 2015

ALGORITMO DE LA RAÍZ CUADRADA MODULAR CUANDO N ES NUMERO COMPUESTO EN JAVA



En una publicación anterior pudimos observar tanto el algoritmo que se usa para obtener la raíz cuadrada si es que la hubiera así como la implementación , claro esta esto fue cuando N era numero Primo , en esta oportunidad lo  haremos cuando N es numero Compuesto, cabe recalcar que para mayor comodidad de mi parte habrá partes en la implementación que solo mencionare las funciones usadas ya que como indique en la publicación anterior , la raíz cuadrada abarca muchas operaciones extra que ya hemos implementado anteriormente por lo que les dejare el link correspondiente a estas cuando se les haga mención, bueno comencemos.

Algoritmo



Básicamente el algoritmo para números compuestos consiste en factorizar a N en dos factores primos distintos e impares(p y q, donde p>q) y aplicarle el algoritmo de raíz cuadrada cuando  N es primo   por separado en la cual obtendremos las raíces (r,-r)  y (s,-s) para luego continuar con lo que resta del algoritmo.



Implementación:
Clase Factorización:
public class Factorizacion {
    public ArrayList< integer > factorizar(int numero)
    {
        ArrayList< integer > factores = new ArrayList<>();
        int i=3;
        while(numero!=1)
        {
            while(numero%2==0)
            {
                factores.add(2);
                numero=numero/2;
            }
            while(numero%i==0)
            {
                factores.add(i);
                numero=numero/i;
            }
            i++;
        }
        return factores;
    }
}
Clase Raíz Cuadrada Compuesta:
public class RaizCompuesta {
    int p,q,a,c,d,x,y,r,s,n;
    int raicesF[]=new int[4];
    ArrayList< Integer > factores = new ArrayList<  >();
    int raizP1[]=new int[2],raizP2[]=new int[2];
    Factorizacion obj= new Factorizacion();
    boolean aux1,aux2;//Sirven para validar la existencia de las raices
    public int[] CalcularRaizCompuesta(int p1,int a1)
    {
        factores=obj.factorizar(p1);
        p=factores.get(1);
        q=factores.get(0);
        a=a1;
        n=p*q;
        System.out.println("p: "+p);
        System.out.println("q: "+q);
        //System.out.println("p: "+p);
        //System.out.println("q: "+q);
        Raiz objRaiz1 = new Raiz();
        Raiz objRaiz2 = new Raiz();
        aux1=objRaiz1.CalcularRaiz(p,a);
        aux2=objRaiz2.CalcularRaiz(q,a);
        if(aux1==false||aux2==false)
        {
            return null;
        }
        else
        {
            raizP1=objRaiz1.getRaiz();
            raizP2=objRaiz2.getRaiz();
            Euclides objEuclides= new Euclides();
            long mcd[]=new long[3];
            mcd= objEuclides.euclidesExtendido((long)p, (long)q);
            c=(int) mcd[1];
            d=(int) mcd[2];
            //System.out.println("c:"+c);
            //System.out.println("d:"+d);
            r=raizP1[0];
            s=raizP2[0];
            //System.out.println("r: "+r);
            //System.out.println("s: "+s);
            x=(r*d*q+s*c*p)%(n);
            y=(r*d*q-s*c*p)%(n);
            //System.out.println("X: "+x);
            //System.out.println("Y: "+y);
            raicesF[0]=x%n;
            raicesF[1]=-1*raicesF[0];
            raicesF[2]=y%n;
            raicesF[3]=-1*raicesF[2];
            for(int i=0;i< 4;i++)
            {
                if(raicesF[i]< 0)
                {
                    raicesF[i]=raicesF[i]+n;
                }
            }
            return raicesF;
        }    
    }
    
}
Fragmento del código de la Interfaz Principal:
public class Factorizacion {
        RaizCompuesta obj= new RaizCompuesta();
        int raices[]=new int[4];
        raices=obj.CalcularRaizCompuesta(Integer.parseInt(numero_p.getText()),Integer.parseInt(numero_a.getText()));
        if(raices==null)
        {
            JOptionPane.showMessageDialog(null, "NO EXISTEN RAICES");
        }
        else
        {
            raiz_1.setText(""+raices[0]);
            raiz_2.setText(""+raices[1]);
            raiz_3.setText(""+raices[2]);
            raiz_4.setText(""+raices[3]);
        }
Espero les sea de utilidad y hasta la siguiente Publicación.

viernes, 26 de junio de 2015

RAIZ CUADRADA MODULAR CUANDO N ES NUMERO PRIMO



El problema de la raíz cuadrada modulo «n» es muy usado en criptografía, donde para hallar la raíz se debe tener en cuenta que un número entero «n» es primo o tal vez compuesto. Si «n» es primo, entonces la raíz cuadrada módulo n es fácilmente obtenida, pero si «n» es un número compuesto entonces hallar tal raíz es difícil ya que sus factores primos son desconocidos.
En este post veremos la implementación  de la raíz cuadrada cuando n es primo.

Algoritmo:





Implementación:
La operación de Raíz cuadrada es una que combina varios conocimientos previos como son:


Por lo que recomendamos ver las publicaciones referentes a cada una ya que por motivos de comodidad solo mencionare cada función:

Función Multiplicación Modular:
public int CalcularMultiplicacion(int a,int b,int z)
    {
        int respuesta;
        respuesta=(a*b)%z;
        return respuesta;
    }
Función Exponencial:
public int funcion_exponencial(int a)
    {
        int c=0;
        while(a%2==0)
        {
            a=a/2;
            c++;
        }
        return c;
    }
Función Raíz Cuadrara:
public class Raiz {
    boolean bandera=true;
    int raiz[]= new int[2];

    public int[] getRaiz() {
        return raiz;
    }

    public int funcion_exponencial(int a)
    {
        int c=0;
        while(a%2==0)
        {
            a=a/2;
            c++;
        }
        return c;
    }
    public boolean CalcularRaiz(int p,int a)
    {
       int aux=0,auxc=0,b = 0,s=0,t,Ia=0,c=0,r=0,d=0,base=0,exponente=0,aux_exp;
        Jacobi obj = new Jacobi();
        if(obj.Opjacobi(a,p)==-1)
        {
            bandera=false;
            return bandera;
        }
        
        while(aux!=-1)
        {
            auxc++;
            aux=obj.Opjacobi(auxc, p);
            b=auxc;
        }
        
        s=funcion_exponencial(p-1);
        aux_exp=(int)Math.pow(2,s);
        t= ((p-1)/aux_exp);
        Inverso inv= new Inverso();
        Ia=(int) inv.CalcularInverso((long)a, (long)p);
        Exponenciacion exp = new Exponenciacion();
        c=exp.CalcularExp(b, t, p);
        r=exp.CalcularExp(a, ((t+1)/2), p);
        for(int i=1;i<=s-1;i++)
        {
            base=r*r*Ia;
            exponente=(int) Math.pow(2,s-i-1);
            d=exp.CalcularExp(base,exponente,p);
            if((d+1)%p==0)
            {
                Multiplicacion mul=new Multiplicacion();
                r=mul.CalcularMultiplicacion(r, c, p);
            }
        }
        System.out.println(r);
        c=exp.CalcularExp(c, 2, p);
        this.raiz[0]=r;
        this.raiz[1]=-r;
        return bandera;
    }
}
Fragmento de codigo de Interfaz Principal
        boolean rpta;
        int raices[]=new int[2];
        Raiz obj = new Raiz();
        rpta=obj.CalcularRaiz(Integer.parseInt(numero_p.getText()),Integer.parseInt(numero_a.getText()));
        if(rpta==false)
        {
            JOptionPane.showMessageDialog(null, "NO EXISTEN RAICES");
        }
        else
        {
            raices=obj.getRaiz();
            raiz_1.setText(String.valueOf(raices[0]));
            raiz_2.setText(String.valueOf(raices[1]));
        }
Bueno espero que les sea de utilidad esta es una de las operaciones mas importantes de la criptografía , en otra publicación realizare la implementación de la raíz cuadrada pero para números compuestos.

Actualización

Aquí les dejo la implementacion cuando N es un numero compuesto:



IMPLEMENTACIÓN DE LA EXPONENCIACIÓN MODULAR EN Z


La exponenciación modular es un tipo de exponenciación realizada sobre un módulo. Es particularmente útil en ciencias de la computación, especialmente en el campo de la criptografía.

Algoritmo:
Entrada:  a E Zn , k E Z  tal que 0 ≤ k < n
Salida : ak mod n
 int exp=1;
 int xp= a%n;
 Mientras (k>0) Hacer     
     si(k%2!=0) 
                         exp= (exp*xp)%n;
             fin si
     xp=(xp*xp)%n;
     k= k/2;
     Fin Mientras
 Retornar (exp)
Implementación:

public int CalcularExp(int a,int k,int z)
    {
        int exp=1;
        int xp=a%z;
        while(k>0)
        {
            if((k%2)!=0)
            {
                exp=(exp*xp)%z;
            }
            xp=(xp*xp)%z;
            k=k/2;
        }
        return exp;
    }