Una forma sencilla y rápida de aprender JAVA, observando y deduciendo cómo se comporta el lenguaje a través de ejemplos prácticos.

Archivo del blog

martes, 29 de diciembre de 2015

Problema del viajante de comercio TSP (I.1). Cálculo mediante método circundante.

El proyecto trata de resolver el problema de viajante de comercio (TSP) mediante método circundante, que consiste en unir todos los nodos externos. Para este ejemplo utilizaré un sistema de organización mediante el uso de "packages", donde se irán añadiendo clases que posteriormente se importarán al proyecto principal.

* Estructura del proyecto:














Para añadir un nuevo package al proyecto, botón derecho del mouse sobre "Source Packages" - New - Java Package - Package Name: Utilidades.


















Código (Ruta.java):

package Tsp;

import Utilidades.Mostrar;
import Utilidades.BuscarRuta;

public class Ruta {

    public static void main(String[] args) {

        Mostrar m = new Mostrar();
        BuscarRuta br = new BuscarRuta();

        //Coordenadas cartesianas (x,y)
        double[][] coordenadas_XY = {
            {20, 18, 22, 13, 3, 18, 30, 5, 14, 26, 23},     // X
            {3, 26, 27, 31, 32, 37, 35, 42, 52, 45, 12}};   // Y

        int nodos = coordenadas_XY[0].length;
        double[] ruta = new double[nodos];

        //Ruta         
        for (int i = 0; i < br.getRuta(coordenadas_XY).size(); i++) {
            if (!br.getRuta(coordenadas_XY).contains(ruta[i])) {
                ruta[i] = br.getRuta(coordenadas_XY).get(i);
            }
        }

        //Muestreos
        m.mostrarCoordenadas(coordenadas_XY);
        m.mostrarRuta(ruta, "\nRuta:\n");
    }
}


Código (Angulo.java):

package Utilidades;

public class Angulo {

    public double getAngle(double x, double y, double x2, double y2, double px, double py, double px2, double py2) {

        double pendent1, pendent2, radians, graus;

        pendent1 = (y2 - y) / (x2 - x);
        pendent2 = (py2 - py) / (px2 - px);

        radians = Math.atan((pendent2 - pendent1) / (1 + (pendent2 * pendent1)));
        graus = (180 * radians) / Math.PI;
        
        //cuadrante4
        if (px2 >= x && py2 <= y) {
            graus = 360 + graus;
            if (px2 == x) {
                graus = 270;
            }
            if (py2 == y) {
                graus = 360;
            }
        }
        //cuadrante3        
        if (px2 <= x && py2 <= y) {
            graus = 180 + graus;
            if (px2 == x) {
                graus = 270;
            }
            if (py2 == y) {
                graus = 180;
            }
        }
        //cuadrante2
        if (px2 <= x && py2 >= y) {
            graus = 180 + graus;
            if (px2 == x) {
                graus = 90;
            }
            if (py2 == y) {
                graus = 180;
            }
        }
        //cuadrante1
        if (px2 >= x && py2 >= y) {
            if (px2 == x) {
                graus = 90;
            }
            if (py2 == y) {
                graus = 0;
            }
        }
        return graus;
    }
}


Código (BuscarRuta.java):

package Utilidades;

import java.util.ArrayList;
import java.util.List;

public class BuscarRuta {

    public List<Integer> getRuta(double[][] xy) {
        Ordenar orden = new Ordenar();
        double[] base;
        double[][] tg = new double[xy.length][xy[0].length];
        double graus = 1;
        int id;
        base = BuscarMinY(xy);

        List<Integer> lista = new ArrayList<>();
        lista.add((int) base[2]);
        Angulo grau = new Angulo();

        while (true) {
            for (int i = 0; i < xy[0].length; i++) {
                tg[0][i] = i;
                tg[1][i] = grau.getAngle(
                        base[0], base[1], base[0] + 1, base[1], //base
                        base[0], base[1], xy[0][i], xy[1][i]);
            }            
            //descarta angulos inferiores
            for (int i = 0; i < tg[0].length; i++) {
                if (tg[1][i] < graus) {
                    tg[1][i] = 999;
                }
            }
            tg = orden.getOrdenacio(tg);
            graus = tg[1][0];
            if (graus >= 999) {
                break;
            }
            id = (int) tg[0][0];
            lista.add(id);
            base[0] = xy[0][id];
            base[1] = xy[1][id];
        }
        return lista;
    }

    public double[] BuscarMinY(double[][] xy) {
        double[] pos_max = new double[3];
        double max = 9999;
        for (int i = 0; i < xy[0].length; i++) {
            if (xy[1][i] < max) {
                max = xy[1][i];
                pos_max[0] = xy[0][i];
                pos_max[1] = xy[1][i];
                pos_max[2] = i;
            }
        }
        return pos_max;
    }
}


Código (Mostrar.java):

package Utilidades;

public class Mostrar {

    public String nodos = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    public void mostrarCoordenadas(double[][] t1) {
        char nodo;
        int x, y;
        System.out.println("Coordenadas nodos (x,y):");
        for (int i = 0; i < t1[0].length; i++) {
            nodo = nodos.charAt(i);
            x = (int) t1[0][i];
            y = (int) t1[1][i];
            System.out.println(nodo + " [" + x + ", " + y + "]");
        }
    }

    public void mostrarRuta(double[] az, String msg) {
        String aux = "";
        String aux2;
        for (int i = 0; i < az.length; i++) {
            aux2 = "" + nodos.charAt((int) az[i]);
            //evitar nodos repetidos 
            if (!aux.contains(aux2)) {
                aux += " ? " + aux2;
            }
        }
        System.out.println(msg + aux + " ?");
    }
}


Código (Ordenar.java):

package Utilidades;

public class Ordenar {
    public double[][] getOrdenacio(double[][] xy) {
        double [][] t = xy;
        //ordenar de menor a mayor
        int cont = 0;
        double aux;
        while (cont < t[0].length) {
            for (int i = 0; i < t[0].length - 1; i++) {
                if (t[1][i] > t[1][i + 1]) {
                    aux = t[1][i];
                    t[1][i] = t[1][i + 1];
                    t[1][i + 1] = aux;                    
                    aux = t[0][i];
                    t[0][i] = t[0][i + 1];
                    t[0][i + 1] = aux;                    
                    cont = 1;
                }
                cont++;
            }
        }
        return t;
    }
}


Resultado:

run:
Coordenadas nodos (x,y):
A [20, 3]
B [18, 26]
C [22, 27]
D [13, 31]
E [3, 32]
F [18, 37]
G [30, 35]
H [5, 42]
I [14, 52]
J [26, 45]
K [23, 12]

Ruta:
? A ? K ? G ? J ? I ? H ? E ?
BUILD SUCCESSFUL (total time: 0 seconds)

miércoles, 24 de junio de 2015

El Año del Juicio Final. Cálculo probabilístico.

En este artículo trataremos de calcular el tiempo que le queda a la humanidad para la extinción. En base al "Principio Antrópico" y aplicándolo adecuadamente se puede hacer una predicción probabilística (no exacta) del año de extinción de nuestra especie tal y como la conocemos.
El argumento principal para este cálculo es que si la raza humana fuera a extenderse durante millones de años, la probabilidad de que hayamos nacido en este momento sería muchísimo más pequeña que si no fuera a durar mucho tiempo.


* Formula Principio Antrópico (Juicio Final versión 1):

   pa = población antigua (personas que han existido)
pppoblación presente (personas vivas actualmente)
pfpoblación futura (previsión personas vivas en el año "x")
es = esperanza de vida (en años)
EXP = expectativa de extinción


   EXP 1 - [(pa + pp) - 1 / (pa + pp)] ^ {(pf - pp) / es) * [(pp + pf) / 2]}




En modo de diseño generamos la siguiente interfaz gráfica:









































Código (JuicioFinal2.java):

package juiciofinal2;

import java.text.DecimalFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;

public class JucioFinal2 extends javax.swing.JFrame {

    Calendar fecha = new GregorianCalendar();

    double pmuerta;
    double pviva;
    double ptotal = pmuerta + pviva;

    double pmax;
    double esp;

    double presente;
    double futuro;
    double expectativa;

    public JucioFinal2() {
        initComponents();
        this.setLocationRelativeTo(null);//centrar
    }
    
    // Código generado automáticamente al crear la interface gráfica en modo de diseño
    private void initComponents() { ...

    private void jSpinnerAñoFuturoStateChanged(javax.swing.event.ChangeEvent evt) { 
        actualitzar();
    }

    private void jButtonCalcularActionPerformed(java.awt.event.ActionEvent evt) {
        actualitzar();
    }

    private void jButtonRestablecerActionPerformed(java.awt.event.ActionEvent evt) {
        jTextFieldMuerta.setText("106500");
        jTextFieldMaxima.setText("11500");
        jTextFieldEsperanza.setText("72");
        jTextFieldAñoPresente.setText("" + fecha.get(Calendar.YEAR));
        jSpinnerAñoFuturo.setValue(2100);
        jTextFieldExpectativa.setText("");
    }                                                  

    private void jButtonCerrarActionPerformed(java.awt.event.ActionEvent evt) {   
        System.exit(0);
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new JucioFinal2().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    private javax.swing.JButton jButtonCalcular;
    private javax.swing.JButton jButtonCerrar;
    private javax.swing.JButton jButtonRestablecer;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel11;
    private javax.swing.JLabel jLabel12;
    private javax.swing.JLabel jLabel15;
    private javax.swing.JLabel jLabel17;
    private javax.swing.JLabel jLabel18;
    private javax.swing.JLabel jLabel19;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel22;
    private javax.swing.JLabel jLabel23;
    private javax.swing.JLabel jLabel25;
    private javax.swing.JLabel jLabel26;
    private javax.swing.JLabel jLabel27;
    private javax.swing.JLabel jLabel28;
    private javax.swing.JLabel jLabel29;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JSeparator jSeparator2;
    private javax.swing.JSeparator jSeparator3;
    private javax.swing.JSpinner jSpinnerAñoFuturo;
    private javax.swing.JTextField jTextFieldAñoPresente;
    private javax.swing.JTextField jTextFieldEsperanza;
    private javax.swing.JTextField jTextFieldExpectativa;
    private javax.swing.JTextField jTextFieldMaxima;
    private javax.swing.JTextField jTextFieldMuerta;
    // End of variables declaration                   

    private void actualitzar() {
       
        DecimalFormat df = new DecimalFormat("#.##");

        pmuerta = Double.parseDouble(jTextFieldMuerta.getText());
        pviva = 6500;
        ptotal = pmuerta + pviva;

        pmax = Double.parseDouble(jTextFieldMaxima.getText());
        esp = Double.parseDouble(jTextFieldEsperanza.getText());
        presente = Double.parseDouble(jTextFieldAñoPresente.getText());
        futuro = Double.parseDouble(jSpinnerAñoFuturo.getValue().toString());

        double potencia = ((futuro - presente) / esp) * pmax;
        double expectativa = 1 - (Math.pow((ptotal - 1) / ptotal, potencia));
        expectativa *= 100;
        jTextFieldExpectativa.setText(df.format(expectativa));

    }
}


miércoles, 17 de diciembre de 2014

Red neuronal artificial (V): Añadiendo entradas manualmente en tiempo de ejecución.

Añadir entradas en una red neuronal manualmente y en tiempo de ejecución podría ser considerado como el órgano de los sentidos (vista, tacto...). Cuando la neurona recibe la acción directa del "medio externo", el estímulo recibido afectará a los valores de las salidas de la red. Ese cambio se verá reflejado en la gráfica.


Primero añadiré al proyecto un jTable1 de 4 columnas con estas características:

Title    Type     Editable
Act      Boolean     V 
Id       Integer     -
Entrada  Float       V
Salida   Double      -



























Código (RedNeuronalG.java):

package redNeuronalG1;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.Timer;
import javax.swing.table.DefaultTableModel;
import org.jfree.data.xy.XYSeries;

public class RedNeuronalG extends javax.swing.JFrame {

    int nNeuronas;
    int nEnlaces;
    int ciclos = 1;  
    
    ArrayList<Integer>[] E;
    ArrayList<Integer>[] S;
    ArrayList<Double>[] w;     
    double[] y;
    
    Random r1;
    Timer timer;
    
    Grafica g;
    XYSeries[] series;    
    DefaultTableModel model;

    public RedNeuronalG() {
        initComponents();
        model = (DefaultTableModel) jTable1.getModel();
        g = new Grafica(jTable1, jPanelGrafica1, series, false);
        restablecer();
        actualizar();
    }

    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() { ... }// </editor-fold> 

    private void jButtonResetActionPerformed(java.awt.event.ActionEvent evt) {                                             
        try {
            timer.stop();
        } catch (Exception ex) {
        }
        restablecer();
        jPanelGrafica1.removeAll();
        jPanelGrafica1.repaint();
        g = new Grafica(jTable1, jPanelGrafica1, series, false);
    }
    
    private void jButtonGenerarActionPerformed(java.awt.event.ActionEvent evt) {                                               
        if (jButtonPlay.isEnabled() == false && jButtonDetener.isEnabled() == false) {
            jButtonPlay.setEnabled(true);
            jButtonDetener.setEnabled(true);
            jButtonReset.setEnabled(true);
        }
        actualizar();
        ejecutar();
    }                                              


    private void jButtonPlayActionPerformed(java.awt.event.ActionEvent evt) {                                            
        if (jButtonPlay.isEnabled()) {
            jButtonPlay.setEnabled(false);
            jButtonDetener.setEnabled(true);
        }
        actualizar();
        timer = new Timer(0, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                Calcular();
            }
        });
        timer.start();
    }                                           

    private void jButtonDetenerActionPerformed(java.awt.event.ActionEvent evt) {                                               
        if (jButtonDetener.isEnabled()) {
            jButtonDetener.setEnabled(false);
            jButtonPlay.setEnabled(true);
        }
        timer.stop();
    }                                              

    private void jTable1MouseClicked(java.awt.event.MouseEvent evt) {                                     
        Calcular();
    }                                    

    public static void main(String args[]) {
        
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new RedNeuronalG().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    private javax.swing.JButton jButtonDetener;
    private javax.swing.JButton jButtonGenerar;
    private javax.swing.JButton jButtonPlay;
    private javax.swing.JButton jButtonReset;
    private javax.swing.JLabel jLabelCiclos;
    private javax.swing.JLabel jLabelNumeroNeuronas;
    private javax.swing.JLabel jLabelNumeroSinapsis;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanelGrafica1;
    private javax.swing.JPanel jPanelTable1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JSpinner jSpinnerCiclos;
    private javax.swing.JSpinner jSpinnerNumeroEnlaces;
    private javax.swing.JSpinner jSpinnerNumeroNeuronas;
    private javax.swing.JTable jTable1;
    // End of variables declaration                   

    private void actualizar() {

        //Actualizar tamaño del jTable
        int nFilas = (int) jSpinnerNumeroNeuronas.getValue();
        while (nFilas != jTable1.getRowCount()) {
            if (nFilas > jTable1.getRowCount()) {
                model.addRow(new Object[]{false, null, null, null, null, null});
            } else if (nFilas < jTable1.getRowCount()) {
                model.removeRow(jTable1.getRowCount() - 1);
            }
        }

        //Actualizar valores variables de entrada
        nNeuronas = (int) jSpinnerNumeroNeuronas.getValue();
        nEnlaces = (int) jSpinnerNumeroEnlaces.getValue();
        ciclos = (int) jSpinnerCiclos.getValue();

        // Control rango maximos minimos jSpinners
        if (nNeuronas <= 1) {
            jSpinnerNumeroNeuronas.setValue(1);
        } else if (nEnlaces <= 1) {
            jSpinnerNumeroEnlaces.setValue(1);
        } else if (ciclos <= 0) {
            jSpinnerCiclos.setValue(1);
        }

    }

    private void restablecer() {

        //Configuracion inicial por defecto
        jButtonPlay.setEnabled(false);
        jButtonDetener.setEnabled(false);

        jSpinnerNumeroNeuronas.setValue(50);
        jSpinnerNumeroEnlaces.setValue(300);
        jSpinnerCiclos.setValue(100);

        for (int i = 0; i < jTable1.getRowCount(); i++) {
            jTable1.setValueAt(false, i, 0);
            jTable1.setValueAt(null, i, 2);
        }

        jTable1.setValueAt(true, 0, 0);
        jTable1.setValueAt(true, 1, 0);
        jTable1.setValueAt(true, 2, 0);

    }

    private void ejecutar() {

        S = new ArrayList[nNeuronas];
        E = new ArrayList[nNeuronas];

        AleatoriedadCondicionada ac = new AleatoriedadCondicionada();
        r1 = new Random();
        int nSalidas = 1; //una salida como mínimo
        int neurona;

        //Crea red neuronal aleatoria
        for (int i = 0; i < S.length; i++) {
            S[i] = new ArrayList();
            E[i] = new ArrayList();

            //Salidas maxima por neurona            
            nSalidas = r1.nextInt(nEnlaces / nNeuronas) + 1;

            for (int j = 0; j < nSalidas; j++) {

                neurona = r1.nextInt(nNeuronas);

                //Aplicación de la Aleatoriedad Condicionada
                neurona = (int) Math.rint(ac.getSalida((double) nNeuronas, neurona));
                if (r1.nextBoolean()) {
                    //conexión hacia delante
                    neurona = i + neurona;
                    if (neurona > nNeuronas) {
                        neurona = neurona - nNeuronas;
                    }
                } else {
                    //conexión hacia atrás
                    neurona = i - neurona;
                    if (neurona < 0) {
                        neurona = neurona + nNeuronas;
                    }
                }
                //evita repeticiones de enlaces a la misma neurona
                if (S[i].contains(neurona) == false) {
                    S[i].add(neurona);
                }
            }
        }

        //agrega los enlaces que faltan para llegar al número exacto
        int recuento = RecuentoEnlaces();
        while (recuento < nEnlaces) {
            int aux = r1.nextInt(nNeuronas);
            int aux2 = r1.nextInt(nNeuronas);
            S[aux].add(aux2);
            recuento++;
        }

        RecuentoEnlaces();

        //Busqueda enlaces de entrada de cada neurona
        for (int i = 0; i < S.length; i++) {
            for (int j = 0; j < E.length; j++) {
                if (S[i].contains(j)) {
                    E[j].add(i);
                }
            }
        }

        //Añadiendo Pesos (w) a los enlaces
        w = new ArrayList[nNeuronas];
        int aux = 0;
        for (int i = 0; i < E.length; i++) {
            w[i] = new ArrayList();
            aux = E[i].size();
            for (int j = 0; j < aux; j++) {
                //Rango bipolar entre -1 y 1
                int tmp = r1.nextBoolean() ? 1 : -1;
                w[i].add(r1.nextDouble() * tmp);
            }
        }

        //Calculo de salidas     
        //Inicializando valores de salida (y)
        y = new double[nNeuronas];
        for (int i = 0; i < nNeuronas; i++) {
            y[i] = 1;
        }
        Calcular();
    }

    private void Calcular() {
        series = new XYSeries[nNeuronas];

        //Inicializando array de series
        for (int i = 0; i < nNeuronas; i++) {
            series[i] = new XYSeries("" + i);
        }

        int cont = 0;
        while (cont < (int) jSpinnerCiclos.getValue()) {
            for (int i = 0; i < nNeuronas; i++) {
                double tmp = 0;
                for (int j = 0; j < E[i].size(); j++) {
                    tmp += (y[E[i].get(j)] * w[i].get(j));
                }
                
                //entrada manual de datos
                tmp = AgregarEntradas(i, tmp);

                y[i] = Math.tanh(tmp);
                series[i].add(cont, y[i]);
            }
            cont++;
        }
        
        FillTable1(); // Llenar jTable1 con los datos actualizados
        g = new Grafica(jTable1, jPanelGrafica1, series, true);
    }

    private void FillTable1() {
        for (int i = 0; i < nNeuronas; i++) {
            jTable1.setValueAt(i, i, 1); // Id neurona
            jTable1.setValueAt(y[i], i, 3); // Resultado salida
        }
    }

    private int RecuentoEnlaces() {
        int nEnlaces = 0;
        for (ArrayList<Integer> S1 : S) {
            nEnlaces += S1.size();
        }
        return nEnlaces;
    }

    private double AgregarEntradas(int i, double tmp) {
        if (jTable1.getValueAt(i, 2) != null) {
            tmp += (float) jTable1.getValueAt(i, 2);
        }
        return tmp;
    }


}


Código 2 (AleatoriedadCondicionada.java):

package redNeuronalG1;

public class AleatoriedadCondicionada {
    public double getSalida(double x, double y) {
        double c = Math.atan(10);
        return ((Math.atan(((y*100/x)/10)-10)*100/c)+100)*x/100;
    }    
}


Código 3 (Grafica.java):

package redNeuronalG1;

import javax.swing.JPanel;
import javax.swing.JTable;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

public class Grafica {

    public Grafica(JTable jTable1, JPanel jPanel1, XYSeries[] series, boolean x) {

        XYSeriesCollection dataset = new XYSeriesCollection();

        int aux = jTable1.getRowCount();

        if (x) {
            //se agrega a la gráfica las neuronas marcadas con el checkbox del jTable1
            for (int i = 0; i < aux; i++) {
                if ((boolean) jTable1.getValueAt(i, 0)) {
                    dataset.addSeries(series[i]);
                }
            }
        }

        JFreeChart chart = ChartFactory.createXYLineChart(
                "",
                "",
                "",
                dataset,
                PlotOrientation.VERTICAL,
                true,
                false,
                false
        );

        //Mostramos la grafica dentro del jPanel1
        ChartPanel panel = new ChartPanel(chart);
        jPanel1.removeAll();
        jPanel1.setLayout(new java.awt.BorderLayout());
        jPanel1.add(panel);
        jPanel1.validate();
    }


}


Con la tecnología de Blogger.