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

domingo, 5 de abril de 2020

JavaFX. Inecuación de Gott. Calcular fechas del pasado.

Continuando con un post anterior relacionado con la inecuación de Gott, se procede a realizar la misma aplicación pero esta vez utilizando las librerías de JavaFX en las que aparecen nuevos componentes como por ejemplo los "DataPicker" que son utilizados para facilitar selección de fechas.

Se comentó en el post anterior que la "Inecuación de Gott" intentaba calcular el tiempo "de vida" de un evento histórico elegido al azar partiendo de un solo dato que era la fecha del inicio del evento.
En resumidas cuentas la fórmula predice la fecha del fin de un suceso que aún sigue en activo y que finalizará en un futuro aparentemente indeterminado.


Inecuación de Gott:



Ahora la idea NO es calcular cosas que van a suceder en el futuro, sino fechas del pasado, que por otra parte son fáciles de comprobar si los resultados obtenidos corresponden con la realidad consultando en la Wikipedia del hecho histórico en cuestión. Ejemplo:

Un ejemplo claro de un hecho histórico son las caídas de las Torres Gemelas de Nueva York. Todo el mundo se acuerda del año y día de la desaparición de las torres (11S de 2001), pero seguramente la mayoría no sabe la fecha de su inauguración. Imaginemos que no tenemos acceso a internet ni a hemerotecas para consultar año de su inauguración. Sólo disponemos de la fecha actual (04/04/2020) y fecha del fin de las Torres (11/09/2001).

Aplicando la fórmula con una fiabilidad del 50%:
Resultado obtenido: Fecha de inauguración de las Torres Gemelas entre 1946 y 1992
Realidad (consultando Wikipedia): "...Torres Gemelas, inauguradas el 4 de abril de 1973..."
Conclusión: Resultado satisfactorio ya que se encuentra dentro del rango fechas obtenido.

 

Inecuación de Gott aplicada al cálculo de fecha inauguración de las Torres Gemelas:





Ejemplo 2 -> Muro de Berlin (f = 50%):

Hecho histórico: Muro de Berlin
fecha actual: 04/04/2020
fecha caída del muro: 09/11/1989
fecha inauguración: ? (no lo sabemos)

Aplicando la fórmula con una fiabilidad del 50%:
Resultado obtenido: Fecha de inauguración entre 1898 y 1979
Realidad (consultando Wikipedia): "...formó parte de la frontera interalemana desde el 13 de agosto de 1961..."
Conclusión: Resultado satisfactorio ya que se encuentra dentro del rango de fechas obtenido.



Inecuación de Gott aplicada al cálculo de fecha inauguración del Muro de Berlín:

 


Cabe destacar que la "fiabilidad" es inversamente proporcional al grado de precisión. Es decir si queremos ganar en precisión (reducir el rango de fechas en el resultado) debemos bajar la fiabilidad.
Es algo parecido al principio de incertidumbre de Heisenberg que establece que a mayor certeza de la posición de una partícula, menor conocimiento de su momento o cantidad de movimiento y viceversa.


Ejemplo 3 -> Muro de Berlín (f = 1%):

Ahora aplicando a la fórmula una fiabilidad de sólo un 1% (más exactitud pero menos probabilidad):
Resultado obtenido: Fecha de comienzo entre 1958 y 1960
Realidad: Inaugurado en 1961
Conclusión: Como vemos da un resultado casi exacto pero esta fuera del rango obtenido (+exacto -fiable)


Notas varias:
 

Se recomienda dejar una fiabilidad del 50% para que haya un equilibrio entre grado de fiabilidad y grado de precisión.
Se observa que para obtener las fechas del pasado hay que poner en "Fecha_actual" la fecha de finalización. Y en "Fecha de inicio" la fecha actual (inversión de datos de entrada para pasar del futuro al pasado).



Código Java 1 (NewFXMain.java):

package inecuaciongottfx;

import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class NewFXMain extends Application {

    @Override
    public void start(Stage primaryStage) throws IOException {
        Parent root = FXMLLoader.load(getClass().getResource("FXML.fxml"));
        Scene scene = new Scene(root);
        Stage stage = new Stage();
        stage.setScene(scene);
        stage.setResizable(false);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}


Código Java 2 (FXMLController.java):

package inecuaciongottfx;

import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.input.MouseEvent;

public class FXMLController implements Initializable {

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

    double f, fa, tmin, tmax;

    @FXML
    private DatePicker Fecha_Actual;
    @FXML
    private DatePicker Fecha_Inicio;
    @FXML
    private Label Tiempo_Transcurrido;
    @FXML
    private Label Fiabilidad;
    @FXML
    private Slider Slider_Fiabilidad;
    @FXML
    private Label Fecha_Minima;
    @FXML
    private Label Fecha_Maxima;
    @FXML
    private Label lb_fechas;
    @FXML
    private Button Calcular;
    @FXML
    private Button Limpiar;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        limpiar();
        Calcular.setOnMouseClicked((MouseEvent me) -> {
            calcular();
        });
        Limpiar.setOnMouseClicked((MouseEvent me) -> {
            limpiar();
        });
        // control arrastrar -clicar Slider
        Slider_Fiabilidad.setOnMouseClicked((MouseEvent me) -> {
            Fiabilidad.setText(Math.round(Slider_Fiabilidad.getValue()) + " %");
            calcular();
        });
        Slider_Fiabilidad.setOnMouseDragged((MouseEvent me) -> {
            Fiabilidad.setText(Math.round(Slider_Fiabilidad.getValue()) + " %");
            calcular();
        });
    }

    private void limpiar() {
        Fecha_Inicio.setValue(LocalDate.now());
        Fecha_Actual.setValue(LocalDate.now());
        Tiempo_Transcurrido.setText("0");
        Slider_Fiabilidad.setValue(50d);
        Fiabilidad.setText(Slider_Fiabilidad.getValue() + " %");
        Fecha_Minima.setText("00/00/0000");
        Fecha_Maxima.setText("00/00/0000");
        lb_fechas.setText("Resultado:");
    }

    private void calcular() {

        try {
            fa = ((dateFormat.parse(Fecha_Actual.getValue().toString()).getTime() - dateFormat.parse(Fecha_Inicio.getValue().toString()).getTime()) / 86400000);
        } catch (ParseException ex) {
        }

        f = Slider_Fiabilidad.getValue() / 100d;

        Tiempo_Transcurrido.setText("" + (int) Math.round(fa));

        tmin = fa * (Math.abs((f - 1) / (f + 1)));
        tmax = fa * (Math.abs((f + 1) / (f - 1)));

        Fecha_Minima.setText(sumarRestarDiasFecha(Fecha_Actual.getValue(), (int) Math.round(tmin)));
        Fecha_Maxima.setText(sumarRestarDiasFecha(Fecha_Actual.getValue(), (int) Math.round(tmax)));

        lb_fechas.setText("Resultado: Duración entre " + Math.round(tmin) + " y " + Math.round(tmax) + " días.");

    }

    public String sumarRestarDiasFecha(LocalDate ld, int dias) {

        // convertir Localdate a Date
        Instant instant = Instant.from(ld.atStartOfDay(ZoneId.systemDefault()));
        Date date = Date.from(instant);

        // sumar dias a la fecha
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_YEAR, dias);

        // convertir Date a Localdate
        instant = calendar.getTime().toInstant();
        ld = instant.atZone(ZoneId.systemDefault()).toLocalDate();

        // formato dd-mm-yyy
        String[] aux = ld.toString().split("-");
        return aux[2] + "/" + aux[1] + "/" + aux[0];

    }

}


Código FMXL.fxml (generado con Scene Builder):

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.DatePicker?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.effect.Glow?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.text.Font?>

<AnchorPane id="AnchorPane" prefHeight="580.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="inecuaciongottfx.FXMLController">
   <children>
      <Label alignment="CENTER" contentDisplay="TEXT_ONLY" layoutX="70.0" layoutY="14.0" text="Inecuación de Gott. ¿cuánto tiempo dura algo?" textAlignment="CENTER" textFill="#077034" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="16.0">
         <font>
            <Font name="Tw Cen MT Condensed Bold" size="29.0" />
         </font>
         <opaqueInsets>
            <Insets />
         </opaqueInsets>
         <padding>
            <Insets bottom="10.0" />
         </padding>
         <effect>
            <Glow />
         </effect>
      </Label>
      <Pane layoutX="56.0" layoutY="92.0" prefHeight="364.0" prefWidth="494.0" translateY="5.0" AnchorPane.leftAnchor="50.0" AnchorPane.rightAnchor="50.0">
         <children>
            <Label alignment="CENTER" contentDisplay="TEXT_ONLY" text="Entrada de datos:" textAlignment="CENTER" textFill="#067235" underline="true">
               <font>
                  <Font name="Verdana Bold" size="14.0" />
               </font>
               <opaqueInsets>
                  <Insets />
               </opaqueInsets>
            </Label>
            <GridPane layoutY="29.0" prefHeight="122.0" prefWidth="493.0">
              <columnConstraints>
                <ColumnConstraints hgrow="SOMETIMES" maxWidth="195.4000244140625" minWidth="10.0" prefWidth="186.60003662109375" />
                <ColumnConstraints hgrow="SOMETIMES" maxWidth="160.199951171875" minWidth="10.0" prefWidth="143.39996337890625" />
                  <ColumnConstraints hgrow="SOMETIMES" minWidth="75.0" prefWidth="75.0" />
              </columnConstraints>
              <rowConstraints>
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
              </rowConstraints>
               <children>
                  <Label depthTest="ENABLE" text="Fecha inicio:">
                     <font>
                        <Font name="Verdana" size="14.0" />
                     </font>
                     <opaqueInsets>
                        <Insets />
                     </opaqueInsets>
                     <padding>
                        <Insets right="10.0" />
                     </padding>
                     <GridPane.margin>
                        <Insets left="10.0" right="10.0" />
                     </GridPane.margin>
                  </Label>
                  <Label text="Fecha actual:" GridPane.rowIndex="1">
                     <font>
                        <Font name="Verdana" size="14.0" />
                     </font>
                     <opaqueInsets>
                        <Insets />
                     </opaqueInsets>
                     <padding>
                        <Insets right="10.0" />
                     </padding>
                     <GridPane.margin>
                        <Insets left="10.0" right="10.0" />
                     </GridPane.margin>
                  </Label>
                  <Label text="Tiempo transcurrido:" GridPane.rowIndex="2">
                     <font>
                        <Font name="Verdana" size="14.0" />
                     </font>
                     <opaqueInsets>
                        <Insets />
                     </opaqueInsets>
                     <padding>
                        <Insets right="10.0" />
                     </padding>
                     <GridPane.margin>
                        <Insets left="10.0" right="10.0" />
                     </GridPane.margin>
                  </Label>
                  <Label text="Fiabilidad (%):" GridPane.rowIndex="3">
                     <font>
                        <Font name="Verdana" size="14.0" />
                     </font>
                     <opaqueInsets>
                        <Insets />
                     </opaqueInsets>
                     <padding>
                        <Insets right="10.0" />
                     </padding>
                     <GridPane.margin>
                        <Insets left="10.0" right="10.0" />
                     </GridPane.margin>
                  </Label>
                  <DatePicker fx:id="Fecha_Inicio" promptText="1/1/2000" GridPane.columnIndex="1" />
                  <DatePicker fx:id="Fecha_Actual" promptText="1/1/2000" GridPane.columnIndex="1" GridPane.rowIndex="1" />
                  <Label fx:id="Tiempo_Transcurrido" alignment="CENTER" contentDisplay="CENTER" prefHeight="18.0" prefWidth="163.0" text="0" GridPane.columnIndex="1" GridPane.rowIndex="2">
                     <font>
                        <Font name="Verdana" size="14.0" />
                     </font>
                  </Label>
                  <Slider fx:id="Slider_Fiabilidad" blockIncrement="1.0" snapToTicks="true" value="50.0" GridPane.columnIndex="1" GridPane.rowIndex="3" />
                  <Label fx:id="Fiabilidad" text="50 %" GridPane.columnIndex="2" GridPane.rowIndex="3">
                     <font>
                        <Font name="Verdana" size="14.0" />
                     </font>
                     <opaqueInsets>
                        <Insets />
                     </opaqueInsets>
                     <padding>
                        <Insets right="10.0" />
                     </padding>
                     <GridPane.margin>
                        <Insets left="10.0" right="10.0" />
                     </GridPane.margin>
                  </Label>
                  <Label contentDisplay="CENTER" text="días" textAlignment="CENTER" GridPane.columnIndex="2" GridPane.rowIndex="2">
                     <font>
                        <Font name="Verdana" size="14.0" />
                     </font>
                     <opaqueInsets>
                        <Insets />
                     </opaqueInsets>
                     <padding>
                        <Insets left="10.0" right="10.0" />
                     </padding>
                  </Label>
               </children>
               <opaqueInsets>
                  <Insets />
               </opaqueInsets>
            </GridPane>
            <Label alignment="CENTER" contentDisplay="TEXT_ONLY" layoutY="191.0" text="Intervalo de duración del evento:" textAlignment="CENTER" textFill="#067235" translateY="-20.0" underline="true">
               <font>
                  <Font name="Verdana Bold" size="14.0" />
               </font>
               <opaqueInsets>
                  <Insets />
               </opaqueInsets>
            </Label>
            <GridPane layoutY="219.0" prefHeight="143.0" prefWidth="493.0" translateY="-15.0">
               <columnConstraints>
                  <ColumnConstraints hgrow="SOMETIMES" maxWidth="195.4000244140625" minWidth="10.0" prefWidth="186.60003662109375" />
                  <ColumnConstraints hgrow="SOMETIMES" maxWidth="160.199951171875" minWidth="10.0" prefWidth="143.39996337890625" />
                  <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
               </columnConstraints>
               <rowConstraints>
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
               </rowConstraints>
               <children>
                  <Label text="Fecha mínima:" GridPane.rowIndex="1">
                     <font>
                        <Font name="Verdana" size="14.0" />
                     </font>
                     <opaqueInsets>
                        <Insets />
                     </opaqueInsets>
                     <padding>
                        <Insets right="10.0" />
                     </padding>
                     <GridPane.margin>
                        <Insets left="10.0" right="10.0" />
                     </GridPane.margin>
                  </Label>
                  <Label text="Fecha máxima:" GridPane.rowIndex="2">
                     <font>
                        <Font name="Verdana" size="14.0" />
                     </font>
                     <opaqueInsets>
                        <Insets />
                     </opaqueInsets>
                     <padding>
                        <Insets right="10.0" />
                     </padding>
                     <GridPane.margin>
                        <Insets left="10.0" right="10.0" />
                     </GridPane.margin>
                  </Label>
                  <Label fx:id="Fecha_Minima" alignment="CENTER" prefWidth="163.0" text="00/00/0000" GridPane.columnIndex="1" GridPane.rowIndex="1">
                     <font>
                        <Font name="Verdana" size="14.0" />
                     </font>
                  </Label>
                  <Label fx:id="Fecha_Maxima" alignment="CENTER" prefWidth="163.0" text="00/00/0000" GridPane.columnIndex="1" GridPane.rowIndex="2">
                     <font>
                        <Font name="Verdana" size="14.0" />
                     </font>
                  </Label>
                  <Label fx:id="lb_fechas" prefHeight="18.0" prefWidth="501.0" text="Resultado: " GridPane.columnSpan="3" GridPane.rowIndex="4">
                     <font>
                        <Font name="Verdana" size="14.0" />
                     </font>
                     <GridPane.margin>
                        <Insets left="10.0" />
                     </GridPane.margin>
                  </Label>
                  <Separator prefWidth="200.0" GridPane.columnSpan="3" GridPane.rowIndex="3" />
                  <Separator prefWidth="200.0" GridPane.columnSpan="3" />
               </children>
               <opaqueInsets>
                  <Insets />
               </opaqueInsets>
            </GridPane>
         </children>
      </Pane>
      <HBox layoutX="389.0" layoutY="383.0" prefHeight="28.0" prefWidth="161.0" translateX="-10.0" translateY="100.0" AnchorPane.bottomAnchor="150.0">
         <children>
            <Button fx:id="Calcular" mnemonicParsing="false" text="Calcular" textAlignment="CENTER">
               <font>
                  <Font name="Verdana" size="14.0" />
               </font>
            </Button>
            <Button fx:id="Limpiar" alignment="CENTER_RIGHT" contentDisplay="RIGHT" mnemonicParsing="false" text="Limpiar" textAlignment="CENTER">
               <font>
                  <Font name="Verdana" size="14.0" />
               </font>
               <opaqueInsets>
                  <Insets />
               </opaqueInsets>
               <HBox.margin>
                  <Insets left="10.0" />
               </HBox.margin>
            </Button>
         </children>
      </HBox>
   </children>
</AnchorPane>


martes, 31 de marzo de 2020

Patrón I: Cuadros dentro cuadro.

Código Java (InCuadros.java):

package incuadros;

import java.util.Scanner;

public class InCuadros {

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.print("Entra número de cuadros: ");
        int n = in.nextInt();

        for (int i = 0; i <= n * 2; i++) {
            for (int j = 0; j <= n * 2; j++) {
                if ((i % 2 == 0 && i >= j) || (j % 2 == 0 && j >= i) || i == 0 || j == 0) {
                    System.out.print("*  ");
                } else {
                    System.out.print("   ");
                }
            }
            System.out.println("");
        }
    }

}



Resultado:

run:
Entra número de cuadros: 5
*  *  *  *  *  *  *  *  *  *  * 
*     *     *     *     *     * 
*  *  *     *     *     *     * 
*           *     *     *     * 
*  *  *  *  *     *     *     * 
*                 *     *     * 
*  *  *  *  *  *  *     *     * 
*                       *     * 
*  *  *  *  *  *  *  *  *     * 
*                             * 
*  *  *  *  *  *  *  *  *  *  * 
BUILD SUCCESSFUL (total time: 6 seconds)



domingo, 8 de marzo de 2020

JavaFX + Scene Builder. Instalación e integración en Netbeans 11.3

JavaFX combinado con Java permite una mejora substancial a nivel visual y de rendimiento de nuestras aplicaciones.
También hace una marcada separación entre el diseño visual y el desarroyo de la aplicación como veremos más adelante. 

Por otra parte Scene Builder permite crear la interfaz gráfica de Java de forma más simple y cómoda.
 


> Instalación en base al siguiente software:

Windows 10
Apache NetBeans IDE 11.3


> Lo que vamos a instalar:

JavaFX Windows SDK 13.0.2
JavaFX Scene Builder 11.0.0


1- Descargar e instalar:


> Java FX:


https://gluonhq.com/products/javafx/


Una vez descargado, descomprimir el fichero "openjfx-13.0.2_windows-x64_bin-sdk.zip" en la raiz de la unidad C:

"C:\java fx-sdk-13.0.2\"

> Scene Builder:


https://openjfx.io/


Una vez descargado se instala todo por defecto.


2- Integrar "Javafx-sdk" en Netbeans:

Iniciamos NetBeans -> Tools -> Libraries -> [New Library]


Library Name: JavaFX
Library Type: Class Libreries

 
[OK]

Seleccionamos en la columna lateral izquierda la librería que acabamos de crear: JavaFX
Nos vamos a la pestaña "ClassPath" y pulsamos [Add Jar/Folder...]

Buscamos la carpeta donde tenemos puesto
Javafx-sdk. En este caso fue guardado en:

C:\javafx-sdk-13.0.2\


Dentro la carpeta .\lib\, seleccionamos todos los ficheros con extensión ".jar" y pulsamos [Add Jar/Folder].

Finalmente salimos pulsando [Ok]





2.1- Añadir librerías al proyecto:

Creamos nuevo proyecto:
 
File -> New Proyect -> Java with Ant -> Java Aplication -> [Next]
 

Project name: PrimerJavaFX -> [Finish]

Le añadimos las librerías (click derecho sobre el proyecto):

Properties -> Libraries -> Compile -> Class-path -> [+] -> Add Library -> JavaFX [Add Library]





Y añadimos un código en la VM (click derecho sobre el proyecto)

Properties -> Libraries -> Run -> 

VM Options
--module-path "C:\java fx-sdk-13.0.2\lib" --add-modules javafx.controls,javafx.fxml




3- Integrar "Scene Builder" en Netbeans:

Iniciamos NetBeans -> Tools -> Options -> Java -> JavaFX -> 

Scene Builder Home: C:\Program Files\SceneBuilder






sábado, 29 de febrero de 2020

¿Cuánto tiempo dura algo? Coronavirus y la Inecuación de Gott.

Principio de mediocridad viene a decir que "cualquier cosa seleccionada al azar que observemos en un momento determinado no estará ni al comienzo ni al final de su vida, lo más probable es que esté en algún punto alrededor de la mitad de su vida". Partiendo de esta premisa sería posible calcular matemáticamente el tiempo que puede durar algo, y ese algo que vamos a intentar calcular va a ser el tiempo de vida que le queda a la epidemia del Coronavirus (o COVID-19).
Podría considerarse algo profético o mágico pero la "Inecuación de Gott" intenta calcular ese tiempo partiendo de un solo dato: el tiempo transcurrido desde el inicio del evento.



Fórmula:

ta * |(f - 1)/(f + 1)| < tr < ta * |(f + 1)/(f - 1)|

ta = tiempo transcurrido

tr = tiempo restante
f  = fiabilidad que le queremos dar al resultado (%)


Datos recopilados para el cálculo:

1- Primer infectado: 12 de diciembre de 2019
2- Fecha actual: 29 de febrero de 2020
3- Tiempo transcurrido desde la fecha del primer infectado hasta fecha de hoy:
    19 días (diciembre) + 31 días (enero) + 29 días (febrero) = 117 días
4- Se decide aplicar una fiabilidad del 50%


Resultado aplicando la fórmula:

Fin de la epidemia con una fiabilidad del 50%: 


  -> entre 9 de abril del 2020 y el 14 de febrero del 2021

Ahora solo hace falta esperar si el resultado se va ajustar a la realidad, el tiempo dirá...



Empecemos el proyecto desde Netbeans:

Crearemos un JFrame (ventana) al que añadiremos:


 · 4 jTextField con sus respectivas labels
 · 1 jSlider

 · 2 jButton



Código java:


import java.text.DecimalFormat;

public class Main extends javax.swing.JFrame {

    // Definicion variables
    double ta1, tr0, tr1, f;
    DecimalFormat df = new DecimalFormat("#.00");

    // Cálculo medidas rectangulo áureo
    final double Aureo = ((1 + Math.sqrt(5)) / 2);
    int a = 512;
    int b = (int) (a / Aureo);
    final int width = a + b;
    final int height = a;

    public Main() {
        initComponents();
        this.setBounds(0, 0, width, height);
        this.jPanel1.setBounds(0, 0, width, height);
        this.setLocationRelativeTo(null);
    }

    private void initComponents() { ... aqui va el código generado automáticamente por NetBeans al crear la GUI ... }

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

    private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt) {                                     
        jTextField_Fiabilidad.setText("" + jSlider1.getValue());
        calcular();
    }                                    

    private void jButtonLimpiarActionPerformed(java.awt.event.ActionEvent evt) {

        jTextField_TA1.setText("1");
        jSlider1.setValue(50);
        jTextField_Fiabilidad.setText("50");
        // Intervalo
        jTextField_TR0.setText(df.format(0d));
        jTextField_TR1.setText(df.format(0d));
    }                                             

    private void calcular() {
        ta1 = Double.parseDouble(jTextField_TA1.getText());
        f = Double.parseDouble(jTextField_Fiabilidad.getText()) / 100d;

        // Inecuación de Gott
        tr0 = ta1 * (Math.abs((f - 1) / (f + 1)));
        tr1 = ta1 * (Math.abs((f + 1) / (f - 1)));

        // Mostrar
        jTextField_TR0.setText(df.format(tr0));
        jTextField_TR1.setText(df.format(tr1));
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(() -> {
            new Main().setVisible(true);
        });
    }

}



Resultado:





martes, 27 de agosto de 2019

Perceptrón Multicapa. Proceso de entrenamiento (beta)

Se muestra diagrama conceptual para entrenamiento de una red neuronal multicapa.


El proceso por pasos:

01- Obtener un Dataset en bruto(raw).
02- Discretizar Dataset [Dataset -> Dataset'].
03- Extraer Entradas(E) y Salidas(D) del Dataset'.
04- Pasar Entradas(E) por la Red Neuronal(RN).
05- Obtener Salidas(Y) de la RN.
06- Calcular Error(δ) en base a las Salidas(Y) de la RN y Salida(D) del Dataset'.
07- En base al cálculo del Error(δ), ajustar pesos(W) de la RN.
08- Pasar al siguiente registro del Dataset' volviendo de nuevo al punto 03. Si no existen más registros se pasa al punto 09.
09- Finalizados los registros del Dataset' volver a posicionarse en el 1º registro y volver a empezar desde punto 03, siempre y cuando el Error(δ) general sea inferior o igual (<=) alumbral especificado por el usuario. En tal caso da por finalizado el entrenaminento.









domingo, 7 de julio de 2019

Perceptrón multicapa. Cálculo real de todas las variables partiendo de un dataset básico.

Tras los posts anteriores (visualizaciones esquemáticas de formulas) el siguiente paso pasa por realizar el cálculo real de todas las variables (salidas, errores y pesos actualizados) partiendo de un dataset(D) de un sólo registro.



Código Java:

package perceptron_p;

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

public class Perceptron_p {

   public static void main(String[] args) {

      //sketch: num neuronas
      List<Integer> nN = new ArrayList<>();
      nN.add(2);
      nN.add(3);
      nN.add(2);
      nN.add(1);

      double µ = 0.001;
      int r = 0; // num. registro del dataset
      int nK = nN.size(); // num. de capas = 4
      int nE = nN.get(0); // num. de entradas = 2
      int nS = nN.get(nK - 1); // num. de salidas = 1

      int max = nN.stream().mapToInt(i -> i).max().getAsInt(); // num. max. neuronas por capa
      String tmp;
      double d_tmp;


      // Inicializar dataset (sólo 1 registro o fila)

      double[][] D = new double[1][3];
      D[0][0] = 0.48d; // entrada 1
      D[0][1] = 0.33d; // entrada 2
      D[0][2] = 0.81d; // salida  1

      // Inicializar pesos W, WBias, Y
      double[][][] W = new double[nK][max][max];
      double[][] WB = new double[nK][max];
      double[][] Y = new double[nK][max];
      double[][] E = new double[nK][max];

      System.out.println("Inicializar pesos con valores aleatorios:\n");
      for (int k = 1; k < nK; k++) {
         for (int j = 0; j < nN.get(k); j++) {
            for (int i = 0; i < nN.get(k - 1); i++) {
               W[k][j][i] = Math.random();
               System.out.format("W[%d][%d][%d] = %f\n", k, j, i, W[k][j][i]);
            }
            WB[k][j] = Math.random();
            System.out.format("WB[%d][%d] = %f\n\n", k, j, WB[k][j]);
            Y[k][j] = 0.f;
            E[k][j] = 0.f;
         }
      }

      // 0.0:-------------------------------------------------------------------
      System.out.println("Forward:\n");
      int k = 1;
      for (int j = 0; j < nN.get(k); j++) {
         tmp = "";
         d_tmp = 0f;
         for (int i = 0; i < nE; i++) {
            tmp += String.format("( D[%d][%d] * W[%d][%d][%d] ) + ", r, i, k, j, i);
            d_tmp += D[r][i] * W[k][j][i];
         }
         Y[k][j] = F(d_tmp + (-1 * WB[k][j]), 0);
         System.out.format("Y[%d][%d] = F{ %s( -1 * WB[%d][%d] ) } = ", k, j, tmp, k, j);
         System.out.println(Y[k][j]);
      }

      // 0.1:-------------------------------------------------------------------
      System.out.println("");
      for (k = 2; k < nK; k++) {
         for (int j = 0; j < nN.get(k); j++) {
            tmp = "";
            d_tmp = 0f;
            for (int i = 0; i < nN.get(k - 1); i++) {
               tmp += String.format("( Y[%d][%d] * W[%d][%d][%d] ) + ", k - 1, i, k, j, i);
               d_tmp += Y[k - 1][i] * W[k][j][i];
            }
            System.out.format("Y[%d][%d] = F{ %s( -1 * WB[%d][%d] ) } = ", k, j, tmp, k, j);
            Y[k][j] = F(d_tmp + (-1 * WB[k][j]), 0);
            System.out.println(Y[k][j]);
         }
         System.out.println("");
      }

      // 1.0:-------------------------------------------------------------------
      System.out.println("Backward:\n");
      k = nK - 1;
      for (int j = 0; j < nS; j++) {
         E[k][j] = D[r][nE + j] - Y[k][j];
         System.out.format("E[%d][%d] = ( D[%d][%d] - Y[%d][%d] ) = ", k, j, r, nE + j, k, j);
         System.out.println(E[k][j]);
      }

      // 1.1:-------------------------------------------------------------------
      System.out.println("");
      for (k = k - 1; k > 0; k--) {
         for (int j = nN.get(k); j > 0; j--) {
            tmp = "";
            d_tmp = 0.d;
            for (int i = nN.get(k + 1); i > 0; i--) {
               tmp += String.format("( E[%d][%d] * W[%d][%d][%d] ) + ", k + 1, i - 1, k + 1, i - 1, j - 1);
               d_tmp += E[k + 1][i - 1] * W[k + 1][i - 1][j - 1];
            }
            System.out.format("E[%d][%d] = %s%s = ", k, j - 1, tmp, "0 ");
            System.out.println(d_tmp);
            E[k][j - 1] = d_tmp;
         }
         System.out.println("");
      }

      // 2.0:-------------------------------------------------------------------
      System.out.println("Ajuste pesos:\n");
      k = 1;
      for (int j = 0; j < nN.get(k); j++) {
         for (int i = 0; i < nE; i++) {
            W[k][j][i] += (µ * E[k][j] * F(Y[k][j], 1) * D[r][i]);
            System.out.format("W'[%d][%d][%d] = W[%d][%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * D[%d][%d] ) = ", k, j, i, k, j, i, k, j, k, j, r, i);
            System.out.println(W[k][j][i]);
         }
         WB[k][j] += (µ * E[k][j] * F(Y[k][j], 1) * -1);
         System.out.format("WB'[%d][%d] = WB[%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * (%d) ) = ", k, j, k, j, k, j, k, j, - 1);
         System.out.println(WB[k][j] + "\n");
      }

      // 2.1:-------------------------------------------------------------------
      System.out.println("");
      for (k = 2; k < nK; k++) {
         for (int j = 0; j < nN.get(k); j++) {
            for (int i = 0; i < nN.get(k - 1); i++) {
               W[k][j][i] += (µ * E[k][j] * F(Y[k][j], 1) * Y[k - 1][i]);
               System.out.format("W'[%d][%d][%d] = W[%d][%d][%d] + ( µ * E[%d][%d] * F'( Y[%d][%d] ) * Y[%d][%d] ) = ", k, j, i, k, j, i, k, j, k, j, k - 1, i);
               System.out.println(W[k][j][i]);
            }
            WB[k][j] += (µ * E[k][j] * F(Y[k][j], 2) * (-1));
            System.out.format("WB'[%d][%d] = WB[%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * (%d) ) = ", k, j, k, j, k, j, k, j, -1);
            System.out.println(WB[k][j] + "\n");
         }
         System.out.println("");
      }
   }

   // Función Activación - Derivada
   private static double F(double n, int op) {
      double fx;
      switch (op) {
         case 0: // función sigmoide
            fx = 1.0 / (1.0 + Math.pow(Math.E, -n));
            break;
         case 1: // derivada función sigmoide
            fx = 1.0 / (1.0 + Math.pow(Math.E, -n));
            fx = fx * (1 - fx);
            break;
         default:
            fx = 0.f;
            break;
      }
      return fx;
   }

}



Resultado:

run:
Inicializar pesos con valores aleatorios:

W[1][0][0] = 0,835049
W[1][0][1] = 0,308429
WB[1][0] = 0,052288

W[1][1][0] = 0,217787
W[1][1][1] = 0,348034
WB[1][1] = 0,588298

W[1][2][0] = 0,961801
W[1][2][1] = 0,796138
WB[1][2] = 0,044188

W[2][0][0] = 0,994101
W[2][0][1] = 0,211034
W[2][0][2] = 0,711812
WB[2][0] = 0,952732

W[2][1][0] = 0,423756
W[2][1][1] = 0,953356
W[2][1][2] = 0,249125
WB[2][1] = 0,973105

W[3][0][0] = 0,842807
W[3][0][1] = 0,794736
WB[3][0] = 0,290240

Forward:

Y[1][0] = F{ ( D[0][0] * W[1][0][0] ) + ( D[0][1] * W[1][0][1] ) + ( -1 * WB[1][0] ) } = 0.6107146316470909
Y[1][1] = F{ ( D[0][0] * W[1][1][0] ) + ( D[0][1] * W[1][1][1] ) + ( -1 * WB[1][1] ) } = 0.40880474360914854
Y[1][2] = F{ ( D[0][0] * W[1][2][0] ) + ( D[0][1] * W[1][2][1] ) + ( -1 * WB[1][2] ) } = 0.6637837549590786

Y[2][0] = F{ ( Y[1][0] * W[2][0][0] ) + ( Y[1][1] * W[2][0][1] ) + ( Y[1][2] * W[2][0][2] ) + ( -1 * WB[2][0] ) } = 0.5530844896875817
Y[2][1] = F{ ( Y[1][0] * W[2][1][0] ) + ( Y[1][1] * W[2][1][1] ) + ( Y[1][2] * W[2][1][2] ) + ( -1 * WB[2][1] ) } = 0.46028147962310223

Y[3][0] = F{ ( Y[2][0] * W[3][0][0] ) + ( Y[2][1] * W[3][0][1] ) + ( -1 * WB[3][0] ) } = 0.6322090580829307

Backward:

E[3][0] = ( D[0][2] - Y[3][0] ) = 0.17779094191706935

E[2][1] = ( E[3][0] * W[3][0][1] ) + 0  = 0.14129683962211012
E[2][0] = ( E[3][0] * W[3][0][0] ) + 0  = 0.1498433870202291

E[1][2] = ( E[2][1] * W[2][1][2] ) + ( E[2][0] * W[2][0][2] ) + 0  = 0.1418609770496571
E[1][1] = ( E[2][1] * W[2][1][1] ) + ( E[2][0] * W[2][0][1] ) + 0  = 0.16632825764793913
E[1][0] = ( E[2][1] * W[2][1][0] ) + ( E[2][0] * W[2][0][0] ) + 0  = 0.2088347664166445

Ajuste pesos:

W'[1][0][0] = W[1][0][0] + ( µ * E[1][0] * F'(Y[1][0]) * D[0][0] ) = 0.8350717767495889
W'[1][0][1] = W[1][0][1] + ( µ * E[1][0] * F'(Y[1][0]) * D[0][1] ) = 0.3084447906938308
WB'[1][0] = WB[1][0] + ( µ * E[1][0] * F'(Y[1][0]) * (-1) ) = 0.05224031629899943

W'[1][1][0] = W[1][1][0] + ( µ * E[1][1] * F'(Y[1][1]) * D[0][0] ) = 0.21780595558207116
W'[1][1][1] = W[1][1][1] + ( µ * E[1][1] * F'(Y[1][1]) * D[0][1] ) = 0.34804701774866154
WB'[1][1] = WB[1][1] + ( µ * E[1][1] * F'(Y[1][1]) * (-1) ) = 0.5882576504954621

W'[1][2][0] = W[1][2][0] + ( µ * E[1][2] * F'(Y[1][2]) * D[0][0] ) = 0.9618160101133663
W'[1][2][1] = W[1][2][1] + ( µ * E[1][2] * F'(Y[1][2]) * D[0][1] ) = 0.7961484238865005
WB'[1][2] = WB[1][2] + ( µ * E[1][2] * F'(Y[1][2]) * (-1) ) = 0.04415614986229021


W'[2][0][0] = W[2][0][0] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][0] ) = 0.9941217290526374
W'[2][0][1] = W[2][0][1] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][1] ) = 0.21104869817169436
W'[2][0][2] = W[2][0][2] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][2] ) = 0.7118355488714299
WB'[2][0] = WB[2][0] + ( µ * E[2][0] * F'(Y[2][0]) * (-1) ) = 0.9527319900854492

W'[2][1][0] = W[2][1][0] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][0] ) = 0.4237764313332067
W'[2][1][1] = W[2][1][1] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][1] ) = 0.953369304782218
W'[2][1][2] = W[2][1][2] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][2] ) = 0.2491472992670435
WB'[2][1] = WB[2][1] + ( µ * E[2][1] * F'(Y[2][1]) * (-1) ) = 0.9731049511389623


W'[3][0][0] = W[3][0][0] + ( µ * E[3][0] * F'( Y[3][0] ) * Y[2][0] ) = 0.8428289253648974
W'[3][0][1] = W[3][0][1] + ( µ * E[3][0] * F'( Y[3][0] ) * Y[2][1] ) = 0.7947544171128877
WB'[3][0] = WB[3][0] + ( µ * E[3][0] * F'(Y[3][0]) * (-1) ) = 0.29024004297076156


BUILD SUCCESSFUL (total time: 2 seconds)



sábado, 22 de junio de 2019

Perceptrón multicapa. Ajuste pesos.

Siguiendo el hilo anterior en esta ocasión se procede ajustar los pesos (W) para minimizar el error. Para ello son utilizadas las siguientes variables:

μ  = Tasa de aprendizaje
δ  = Error neurona (E)
Ø  = Bias (-1)
ʄ  = Función de activación
ʄ' = Derivada de la función de activación
ΔW = Delta de los pesos




Función Sigmoide:

ʄ(x)  = 1 / ( 1 + e^(-x) )


Derivada función Sigmoide:

ʄ'(x) = ʄ(x) * ( 1 - ʄ(x) )


Cálculo deltas(Δ) de los pesos:

ΔW = µ * δ * ʄ'(x) * Y
ΔW = µ * δ * ʄ'(x) * Ø -> para ajuste pesos del Bias(Ø)


Ajuste pesos:

W' = W + ΔW




Código Java:


package ajustePesos;

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

public class AjustePesos {

   public static void main(String[] args) {

      //sketch: num neuronas
      List<Integer> nN = new ArrayList<>();
      nN.add(2);
      nN.add(3);
      nN.add(2);
      nN.add(1);

      double µ = 0.001;
      int r = 0; // num. registro del dataset
      int nK = nN.size(); // num. de capas = 4
      int nE = nN.get(0); // num. de entradas = 2
      int nS = nN.get(nK - 1); // num. de salidas = 1
      String tmp;

      // 2.0:-------------------------------------------------------------------
      System.out.println("Ajuste pesos:\n");
      k = 1;
      for (int j = 0; j < nN.get(k); j++) {
         for (int i = 0; i < nE; i++) {
            System.out.format("W'[%d][%d][%d] = W[%d][%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * D[%d][%d] )\n", k, j, i, k, j, i, k, j, k, j, r, i);
         }
         System.out.format("WB'[%d][%d] = WB[%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * %d)\n\n", k, j, k, j, k, j, k, j, - 1);
      }

      // 2.1:-------------------------------------------------------------------
      System.out.println("");
      for (k = 2; k < nK; k++) {
         for (int j = 0; j < nN.get(k); j++) {
            for (int i = 0; i < nN.get(k - 1); i++) {
               System.out.format("W'[%d][%d][%d] = W[%d][%d][%d] + ( µ * E[%d][%d] * F'( Y[%d][%d] ) * Y[%d][%d] )\n", k, j, i, k, j, i, k, j, k, j, k - 1, i);
            }
            System.out.format("WB'[%d][%d] = WB[%d][%d] + ( µ * E[%d][%d] * F'(Y[%d][%d]) * (%d) )\n\n", k, j, k, j, k, j, k, j, -1);
         }
         System.out.println("");
      }

   }

}


Resultado:

run:
Ajuste pesos:

W'[1][0][0] = W[1][0][0] + ( µ * E[1][0] * F'(Y[1][0]) * D[0][0] )
W'[1][0][1] = W[1][0][1] + ( µ * E[1][0] * F'(Y[1][0]) * D[0][1] )
WB'[1][0] = WB[1][0] + ( µ * E[1][0] * F'(Y[1][0]) * -1)

W'[1][1][0] = W[1][1][0] + ( µ * E[1][1] * F'(Y[1][1]) * D[0][0] )
W'[1][1][1] = W[1][1][1] + ( µ * E[1][1] * F'(Y[1][1]) * D[0][1] )
WB'[1][1] = WB[1][1] + ( µ * E[1][1] * F'(Y[1][1]) * -1)

W'[1][2][0] = W[1][2][0] + ( µ * E[1][2] * F'(Y[1][2]) * D[0][0] )
W'[1][2][1] = W[1][2][1] + ( µ * E[1][2] * F'(Y[1][2]) * D[0][1] )
WB'[1][2] = WB[1][2] + ( µ * E[1][2] * F'(Y[1][2]) * -1)


W'[2][0][0] = W[2][0][0] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][0] )
W'[2][0][1] = W[2][0][1] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][1] )
W'[2][0][2] = W[2][0][2] + ( µ * E[2][0] * F'( Y[2][0] ) * Y[1][2] )
WB'[2][0] = WB[2][0] + ( µ * E[2][0] * F'(Y[2][0]) * (-1) )

W'[2][1][0] = W[2][1][0] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][0] )
W'[2][1][1] = W[2][1][1] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][1] )
W'[2][1][2] = W[2][1][2] + ( µ * E[2][1] * F'( Y[2][1] ) * Y[1][2] )
WB'[2][1] = WB[2][1] + ( µ * E[2][1] * F'(Y[2][1]) * (-1) )


W'[3][0][0] = W[3][0][0] + ( µ * E[3][0] * F'( Y[3][0] ) * Y[2][0] )
W'[3][0][1] = W[3][0][1] + ( µ * E[3][0] * F'( Y[3][0] ) * Y[2][1] )
WB'[3][0] = WB[3][0] + ( µ * E[3][0] * F'(Y[3][0]) * (-1) )


BUILD SUCCESSFUL (total time: 5 seconds)


miércoles, 12 de junio de 2019

Perceptrón multicapa. Propagación hacia atrás.




Descripción:

En base al valor de salida del dataset (D02), se visualiza la base conceptual para el cálculo de los errores (Exx) de cada neurona (Yxx) de una red neuronal tipo perceptrón multicapa. Todo ese proceso se le llama propagación hacia atrás.



Nomenclatura:

Y[k][j]: Salida neurona (capa, posición j-enésima)

E[k][j]: Error neurona (δ) (capa, posición j-enésima)
W[k][j][i]: Peso (capa, neurona destino, neurona origen)



Código Java:

package backward;

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

public class Backward
{

   public static void main(String[] args) {

      //sketch: num neuronas
      List<Integer> nN = new ArrayList<>();
      nN.add(2);
      nN.add(3);
      nN.add(2);
      nN.add(1);

      int r = 0; // num. registro del dataset
      int nK = nN.size(); // num. de capas = 4
      int nE = nN.get(0); // num. de entradas = 2
      int nS = nN.get(nK - 1); // num. de salidas = 1
      String tmp;

      // 1.0:-------------------------------------------------------------------
      System.out.println("Backward:\n");
      int k = nK - 1;
      for (int j = 0; j < nS; j++) {
         System.out.format("E[%d][%d] = ( D[%d][%d] - Y[%d][%d] )\n", k, j, r, nE + j, k, j);
      }

      // 1.1:-------------------------------------------------------------------
      System.out.println("");
      for (k = k - 1; k > 0; k--) {
         for (int j = nN.get(k); j > 0; j--) {
            tmp = "";
            for (int i = nN.get(k + 1); i > 0; i--) {
               tmp += String.format("( E[%d][%d] * W[%d][%d][%d] ) + ", k + 1, i - 1, k + 1, i - 1, j - 1);
            }
            System.out.format("E[%d][%d] = %s%s\n", k, j - 1, tmp, "0 ");
         }
         System.out.println("");
      }

   }

}



Resultado:

run:
Backward:

E[3][0] = ( D[0][2] - Y[3][0] )

E[2][1] = ( E[3][0] * W[3][0][1] ) + 0
E[2][0] = ( E[3][0] * W[3][0][0] ) + 0

E[1][2] = ( E[2][1] * W[2][1][2] ) + ( E[2][0] * W[2][0][2] ) + 0
E[1][1] = ( E[2][1] * W[2][1][1] ) + ( E[2][0] * W[2][0][1] ) + 0
E[1][0] = ( E[2][1] * W[2][1][0] ) + ( E[2][0] * W[2][0][0] ) + 0 



BUILD SUCCESSFUL (total time: 1 second)



Con la tecnología de Blogger.