Diseño y Programación Orientados a Objetos
1er. Sem 2013
Tarea 1: Compuertas Digitales como Objetos de Software

Recomendación: Lea detenidamente la tarea. Si algo no lo entiende, consulte en clases. Si es preciso, se incorporarán aclaraciones al final.
Esta tarea tiene por objetivos:
* Ejercitar la configuración de un ambiente de trabajo para desarrollo de aplicaciones en lenguaje Java (se ha sugerido trabajar con Jgrasp, Eclipse o NetBeans )
* Reconocer objetos de software como modelos de objetos reales.
* Reconocer clases y relaciones entre ellas en códigos fuentes Java.
* Ejercitar el diseño e implementación de una clase simple.
* Ejercitar la extensión de clases dadas para satisfacer nuevos requerimientos. 
* Ejercitar la entrada y salida de datos.
* Conocer el formato .csv y su importación a planillas electrónicas.
* Ejercitar la preparación y entrega de resultados de software (creación de readme, documentación y agrupación de una colección de archivos en uno "tar" o "zip").
* Aprender una estrategia para programar simulaciones de fenómenos discretos.

Descripción General
  En esta tarea se modela la interacción entre compuertas digitales básicas: NOT, OR, AND, NAND y NOR. Cada compuerta se modela según su función lógica y un retardo fijo para cada compuerta. A partir de estos modelos se construyen clases en Java que permiten crear objetos de software para representar compuertas reales. Decimos que las clases representan un modelo de la realidad pues no incorporamos todos los elementos presentes en compuertas reales; por ejemplo, las transiciones entre los niveles digitales se supondrán instantáneas. Veremos cómo este modelo genera resultados "curiosos" cuando analizamos el circuito de la figura 1:

Figura 1: Inversores interconectados: almacena 1 bit, sin control.

Modelos para los Objetos del Problema

Modelo de compuertas: Para modelar cada compuerta usaremos una etapa de entrada y otra de salida. La de entrada conoce el número de entradas de la compuerta y qué tiene conectada cada una.  La otra etapa tiene sólo una señal de salida, el retardo de propagación de la compuerta y un punto de conexión externo. Todas las compuertas comparten la etapa de salida. Así podemos definir la clase abstracta Gate para representar los aspectos comunes de toda compuerta e incluir en ella al menos un método abstaracto que permita calcular el valor lógico de salida que dependerá del número de entrada y lógica de cada compuerta en particular. Será responsabilidad de cada subclase (Not, And, Or, etc) impementar ese método. En archivo Gate.java usted encontrará un modelo para la parte común de toda compuerta lógica.

Modelo para la señales de entrada: las entradas provendrán de un archivo de texto con líneas con el siguiente formato:
<tiempo>  <valor>
Se propone modelar cada fuente digital como una salida que varía según los valores del archivo de entrada y cambia conforme pasa el tiempo. En archivo Source.java usted encontrará el modelo para las fuentes digitales.

Modelos para las interconexiones (cables): En los circuitos digitales los cables tienen un flujo causal bien definido. Así identificamos un punto desde cual proviene la señal (from) y por ende está conectado a alguna salida digital y otro extremo conectado a una entrada digital (to). Cabe destacar que no tiene sentido considerar dos exitaciones para un mismo cable, pero en general sí varias entradas digitales donde éste está conectado. Un cable es un mero transportador de los valores lógicos desde una salida digital a una o más entradas. Lo modelaremos sin retardo y sin estado lógico propio. Cuando alguien se lo pida, éste lo obtendrá del valor lógico de la salida digital que lo alimenta. En archivo Wire.java usted encontrará el modelo para los cables.

Modelo para un instrumento de medición: Para observar el valor de las señales en el tiempo es conveniente crear algún modelo para un instrumento que registre la evolución de ciertas variables lógicas. Es así como se modela un instrumento medidor a cuya entrada se conectan los cables de interés registrar en el tiempo. Este instrumento grabará en archivo los cambios de estado en el tiempo. En archivo Meter.java usted encontrará un modelo para el instrumento registrador.

Modelo para el avance del tiempo: El tiempo es una variable continua; sin embargo, en los circuitos digitales los estados cambian sólo cuando hay transiciones en las entradas y éstas se dan en tiempos discretos. Así los cambios ocurren en instantes discretos y no hay cambios de interés en otros instantes. En presencia de variables contínuas, como la velocidad, aceleración, o posición, las simulaciones consideran avances regulares del tiempo; por ejemplo, con incrementos en valor delta (fijo o variable según el detalle que queramos). En casos continuos la idea básica es discretizar el tiempo; para cada instante discreto, se congela el tiempo y se pide a cada objeto del modelo calcular cuál será su estado futuro (delta t más tarde) a partir del estado actual y las condiciones a que está sometido. Es importante congelar el tiempo y hacer este cálculo para cada objeto. Luego se pide a todos actualizar su estado basado en lo calculado y entonces se avanza el tiempo en ese delta. Esta idea simple trabaja bien en muchas situaciones. 
El algoritmo para un simulador de variables contínuas es del tipo: 
simulate ( double delta_t, double endTime)  {   // Se presenta por completitud, pero no se requeirirá en la tarea.
      for (ElementoModelado e: listaDeTodosLosElementos)
         e.setInitialState();
      for (double t=0; t < endTime; t+=delta_t)  {
         for (ElementoModelado e: listaDeTodosLosElementos)  // for each element
            e.computeNextState(delta_t);                                      //     compute next state
         for (ElementoModelado e: listaDeTodosLosElementos)  //  for each element
            e.updateState();                                                           //     update its state
     }
}
En presencia de variables con cambios discretos en el tiempo, como en las señales digitales, las simulaciones consideran avances no regulares del tiempo y definidos según el evento de interés futuro más próximo. En estos casos el algoritmo de simulación calcula los cambios de estado por demanda de los objetos modelados que requieren cambio. En cada iteración se pide actualización del objeto de actualización más próximo en el futuro. Para ello el algoritmo hace uso de la esturtura de datos Cola de Prioridad. Ésta es una cola donde los objetos insertados deben tener una relación de orden. Se insertan en la cola según se necesite y la operación para sacar elementos siempre extrae el más pequeño de los insertados. Si la relación de orden es el tiempo en que los cambios tendrán lugar, entonces al sacar objetos de la cola obtendremos el primero cuyo estado debe ser actualizado.
   En el caso de esta tarea, esa actualización afectará la entrada de  otras compuertas que deberán insertar eventos de actualización futura en el cola. El tiempo futuro de actualización depende del retardo de propagación de cada compuerta.
  El algoritmo para un simulador de eventos discretos es del tipo:
  simulate(PriorityQueue pq) {
      ChangeEvent e;                             // Objeto ChangeEvent almacena referencia a objeto involucrado y tiempo de cambio futuro.
      insertar_eventos_de_partida(pq); // primer cambio para cada fuente digital.
      while ( (e=pq.poll())!=null) {         // mientras aún haya eventos por procesar
            e.update(pq);                          // el evento más próximo pide actualizar su estado,
      }                                                   //  este proceso genera la inserción de nuevos eventos en pq.
   }

Resultados Esperados de su Grupo
Si bien usted puede usar un IDE (Integrated Development Environment), usted debe saber cómo compilar y correr su tarea dese la línea de comandos.
Su tarea debe ser ejecutable en aragorn.elo.utfsm.cl usando:
  $ java DigitalCircuit <First input signal filename>  <Second input signal filename> <Output signal filename>
Luego el programa corre hasta generar toda la salida indicada.

Usted deberá entregar los siguientes archivos:
- readme
- Archivo de Documentación: En éste usted responda las siguientes preguntas:
a) Para el código entregado analice el código del método simulate() de la clase Simulator. Haga los gráficos de las señales para ver el efecto de dejar sólo un llamado a meter.log() o dos (uno antes y otro después de e.update()). ¿Cuál es la ventaja de poner dos llamados en lugar de uno?
b) Para el código entregado para DigitalCircuit.java, vea el efecto de incluir o no las líneas de código marcadas con /* b) */. Describa la diferencia observada y por qué se produce.
  b2) Para el circuito original entregado en DigitalCircuit.java,  vea el efecto de las condiciones:
        "if (output != newValue)" en método update() e "if (output != computeOutput())" en método inputChanged() , ambas en la clase Gate. ¿Se pueden eliminar? ¿Qué se gana con tenerlas?
c) Cambie y el archivo DigitalCircuit.java para  simular el circuito de la figura  1. Utilice 2 [ns] (en realidad las unidades de tiempo son irrelevantes) como retardo de cada inversor.
Muestre un diagrama temporal para la salida de ambos inversores. ¿Obtiene usted un estado estable? ¿Cómo explica usted el resultado?
d) Cree la clase And.java. Utilice los mismos tipos de constructores de Or.java
e) Cree la clase Nand.java, en este caso incluya el método:
void connectInput(Wire w);
   Éste puede ser invocado cuantas veces desemos para crear así compuertas NAND de un número de entradas cualquiera.
   Usando esta implementación para la conpuerta nand, cree un DigitalCircuit.java para el siguiente circuito:

Figura 2: FlipFlip D de canto positivo de reloj (tomado de Wikipedia).
 En su documentación muestre el diagrama temporal generado cuando el reloj es de frecuencia igual a 20 veces el mayor retardo por usted considerado y la señal D también es cuadrada y de la mitad de la frecuencia del reloj. Muestre un 1,5 periodos de la señal D. No se espera que su programa genere el diagrama temporal. Puede usar el dibujo aquí incluido y el gráfico lo puede generar con una planilla de cálculo a partir de los datos de salida de su programa.
-  Códigos fuentes correspondiente a  DigitaCircuit.java de la pregunta c), And.java de pregunta d), Nand.java y DigitalCircuit.java de pregunta e). Cree directorios de nombre PreguntaC, PreguntaD, etc, para poner los códigos de cada pregunta.
- La entrega de la tarea será a través de Assembla usando GIT. Para ello revise esta documentación.

Ayudas
* Dé una mirada a la solución parcial del problema. Si encuentra errores o algo que pueda ser mejorado, avise al profesor.
* Como extensión para el archivo de salida use .csv. Luego trate este archivo como si fuera planilla electrónica. Usted podrá usar "tabs" como separador de columnas.

* No dude en consultar al profesor o ayudante sobre dudas de esta tarea.
* Espero esta tarea sea de su interés y lo motive a hacer pruebas adicionales a las aquí pedidas. Se agradece; si embargo, sea cuidadoso, este ramo no es el único donde usted debe rendir bien.