sábado, 11 de diciembre de 2010

Cómo evaluar integrales múltiples utilizando Wolfram Alpha

Wolfram Alpha es una herramienta muy versátil. Además de poder evaluar derivadas e integrales simples, también permite conocer el resultado de integrales múltiples. Solamente hay que acostumbrarse a la notación utilizada para poder introducir una de estas integrales. Por ejemplo, si queremos conocer el resultado de evaluar la siguiente integral en Wolfram Alpha:

Debemos introducirla en el recuadro naranja donde se llevan a cabo las consultas y cálculos de la siguiente manera:

int (z) dz dx dy, z = 0 to sqrt(4 - x - y^2), x=0 to sqrt(1 - y^2), y=0 to 1

Donde "int" representa la operación de integración, el argumento entre paréntesis siguiente al operando int es el integrando (si es que lo hay), seguido por las diferenciales de las variables (en este caso x, y, y z) y finalmente los límites para cada variable comenzando con aquélla cuya diferencial aparezca enseguida del integrando. Los límites para cada variable se separan por comas.

El resultado en la página de Wolfram Alpha luciría de la siguiente manera:

Porción de la página de Wolfram Alpha que contiene la operación realizada




En ocasiones es posible obtener un procedimiento y una gráfica, sin embargo, cuando esto no es posible, aún podemos utilizar Wolfram Alpha para corroborar los resultados obtenidos en nuestros cálculos al aplicar técnicas conocidas de integración. Si das click en el letrero "More digits", Wolfram Alpha te proporcionará varias decenas de los dígitos que corresponden al resultado si es que éste es un número irracional.

Dentro de las funciones que también podemos utilizar se encuentran las trigonométricas (como el seno que se  escribe sin), las exponenciales (únicamente introduciendo la letra "e" seguida del símbolo de exponente y lo que se desea que constituya el exponente para la base e), las logarítmicas (Wolfram Alpha utiliza el símbolo "log" para identificar al logaritmo natural) e inclusive las hiperbólicas (ejemplo: sinh es el seno hiperbólico).

Para poder introducir una integral fácilmente, es posible utilizar como plantillas los ejemplos que ya proporciona Wolfram Alpha, para ello, hay que dirigirse desde la página principal al enlace que dice "Examples by Topic", de ahí a "Mathematics" -> "Calculus" -> "Integrals" y en el apartado de "Multiple Integrals", utiliza la plantilla que más se parezca al ejemplo que deseas evaluar.

¿Qué hacer si Wolfram Alpha no muestra los pasos intermedios para llegar a un resultado?

Ahora bien, en ocasiones Wolfram Alpha no despliega los pasos intermedios que sigue para obtener un resultado. Esto puede deberse a que utiliza técnicas que quizá desde el punto de vista de una computadora son más sencillas (por ejemplo a través de aproximaciones), mientras que nosotros obtenemos el resultado de la operación de manera simbólica (a través de identidades, fórmulas, despejes sencillos).

Sea cual sea el caso, si no existen pasos intermedios, podemos utilizar Wolfram Alpha para verificar el resultado de nuestros cálculos. Independientemente de la técnica que utilicemos o las operaciones intermedias que realicemos para obtener una respuesta, podemos comparar nuestros resultados con los que nos ofrece Wolfram Alpha para verificarlos.

Por ejemplo, podemos descomponer la integral múltiple que se planteó al principio y utilizar Wolfram Alpha para calcular la más interna de la siguiente manera:

int (z) dz, z = 0 to sqrt(4 - x - y^2)

El resultado es el siguiente:

En esta ocasión Wolfram Alpha no muestra los pasos intermedios porque se trata de un caso básico de integracion. Lo que podemos hacer es realizar la integral y verificar que obtengamos el mismo resultado. Una vez que verificamos esta parte, podemos ahora sustituir este resultado para encontrar la integral siguiente en la integral múltiple original:

int (1/2(-x - y^2 + 4)) dx, x=0 to sqrt(1 - y^2)

Para obtener:

Y finalmente, el resultado de esta integral utilizarlo para resolver la última integral con respecto a y:

int (1/4((1 - 2*sqrt(1 - y^2))y^2 + 8*sqrt(1 - y^2) - 1)) dy, y=0 to 1

Y así verificar el resultado final:

De esta manera, si existe alguna duda acerca del resultado de una integral múltiple como esta, puede ser de más ayuda el observar cómo se van resolviendo cada una de las integrales mediante la sustitución del resultado de cada una de ellas desde la más interna hasta la última o más externa.

Cómo utilizar el cambio de ejes para resolver una integral múltiple (ejemplo)

Supongamos que se pide evaluar la siguiente integral:

Tal parece que para esta integral es inútil recurrir a la sustitución simple, la sustitución trigonométrica, las fórmulas de integración contenidas en los formularios más usuales y por supuesto, es virtualmente imposible realizarla de manera directa, así que, ¿Qué podemos hacer para simplificar la tarea de evaluar una integral semejante? La respuesta es muy simple: realizar un cambio de ejes. 

Primero debemos reconocer que al tratarse de una integral doble que posee un integrando, en realidad estamos ante una integral triple, es decir, debemos pensar en tres dimensiones. La gráfica de las curvas en cuestión se obtiene mediante el análisis de la expresión, observándola en términos de las dimensiones x y y, podemos apreciar que y está delimitada por una línea recta en y = 1 y cero y  x está delimitada por la curva "raíz de y" y la recta x = 1. La curva que representa el integrando se levanta sobre el eje z a partir de z = 1. De modo que si nos situamos hipotéticamente sobre el eje z y observamos la base de estas gráficas, este sería el resultado:



Gráfica realizada con ayuda de Wolfram Alpha


La base del volumen que se pretende evaluar por medio de esta integral está marcada en azul. Ahora bien, si observamos la integral tal y como está, nos encontraremos en serios problemas a la hora de encontrar una solución apropiada, sin embargo, podemos invertir el orden en el que están evaluando las variables x y y y obtener como resultado la siguiente expresión:


Ahora, el diferencial de x se evalúa desde cero hasta 1, por lo tanto, para poder obtener la expresión que corresponde a los límites del diferencial de y, es necesario despejar a y. Despejando la raíz de y obtenemos y = x^2, por lo que éste es el nuevo límite aplicable a y.


Esta expresión resulta muy sencilla de evaluar, ya que el integrando se encuentra en términos de x y la variable respecto de la que hay que integrar es y, por lo tanto, el integrando se convierte en una constante y se puede integrar como tal. El resultado es el siguiente:




miércoles, 8 de diciembre de 2010

Prueba Unitaria (Unit Testing) con Netbeans

¿Cómo pruebo mis programas de Estructura de Datos? ¿Existe algo mejor que imprimir resultados en la consola y analizar visualmente si el programa funcionó bien?

Por supuesto, desarrollando pruebas unitarias para tu código aseguras que tu implementación se comporta como esperas y mejor aún, si realizas algún cambio en el código, puedes correr tu prueba nuevamente para validar que todo siga funcionando correctamente. En resumen, una prueba unitaria es código que evalúa partes específicas de otro programa.

Suena como trabajo doble ¿Aparte de mi implementación tengo que hacer otro programa para probarlo?

Realmente no, ya que existen librerías que te ayudan a desarrollar las pruebas rápidamente. Es más, IDE´s como Netbeans incluyen atajos y opciones para generar y ejecutar las pruebas. La siguiente imagen muestra cómo el proyecto por default de Neatbeans ya incluye folders y librerías para desarrollar pruebas.

¿Cómo puedo probar una lista que tiene como tipo de datos enteros e inserta los valores en orden?

Supongamos que los métodos iniciales de la lista son los siguientes:

public class ListaDoble {
   public void insertar(int n){...}
   public NodoDoble remover(int valor){...}
   public boolean isEmpty(){...}
   public static void main(String args[]){...}
}

Primero, borrar el método main, ya que eso está fuera de las responsabilidades de la clase. Vamos hacer dos cambios a la clase:

  1. Agregar una variable privada que mantenga el número de elementos en la lista: numElementos. Se incrementará cuando se inserte un elemento y se drecrementará en el método remover.
  2. Adicionar un método que nos retorne la lista como un arreglo de enteros. Esta es una posible implementación:
        public int[] toArray(){
           int[] array = new int[numElementos];
           int i = 0;
           NodoDoble auxiliar = inicio;
           while (auxiliar != null) {
               array[i] = auxiliar.getDatos();
               auxiliar = auxiliar.getSiguienteNodo();
               i++;
           }
           return array;
       }

Ahora veamos lo rápido y fácil que es agregar una prueba.

  1. Da clic derecho en la clase que queremos probar, selecciona la opcion Tools (Herramientas) > Create JUnit Tests
  2. Aparece un diálogo con opciones para crear la clase que ejecutará las pruebas. Para esta prueba seleccioné lo mínimo, como puedes ver en la figura.
  3. Borra el método por default que genera Netbeans y agrega el siguiente método.
        @Test
       public void testEscenario01() {
           ListaDoble lista = new ListaDoble();
           // La lista debe estar vacia al inicio
           assertTrue(lista.isEmpty());
    
           // Insertemos 5 elementos
           lista.insertar(100);
           lista.insertar(50);
           lista.insertar(200);
           lista.insertar(-50);
           lista.insertar(0);
           assertArrayEquals(lista.toArray(),
                   new int[]{-50,0,50,100,200});
       }
    Como puedes ver, este método crea una instancia de ListaDoble. Los métodos assert son parte de la librería JUnit, y sirven para verificar si cierta condición se cumple. Por ejemplo, recién creada la lista, se espera que esté vacía, esto lo logramos con assertTrue(lista.isEmpty()). Después insertamos 5 elementos y verificamos con assertArrayEquals que el contenido de la lista sea igual al arreglo que pasamos como segundo parámetro. Nota que el segundo arreglo está ordenado, ya que es lo que esperamos de la lista.
  4. Para ejecutar la prueba, simplemente da clic derecho en el archivo de prueba (en este caso ListaDobleTest) y selecciona Test File
    Si tu implementación es correcta, aparecerá un mensaje como el siguiente.
    Para la siguiente imagen, introduje un error en la prueba para ver la salida de JUnit.

NOTA

Esto nos lleva a reflexionar, que pueden existir errores tanto en la implementación como en la prueba. Pero es importante notar que sin pruebas confiamos ciegamente en la implementación. Si hay un error al correr las pruebas, el error puede estar en la implementación o en las pruebas. Si las pruebas corrieron exitosamente, entonces la implementación cumple con los casos presentados en las pruebas; en otras palabras, puede que tanto la implementación como las pruebas estén mal. Obviamente, es más difícil equivocarse en dos lugares (implementación y pruebas) que sólo en uno (implementación).

También es importante mencionar que las pruebas sólo garantizan que nuestro programa cumple con los escenarios mencionados, más no que está 100% libre de errores.

¿Con una sola prueba basta para la clase ListaDoble?

El objetivo no es crear tantas pruebas como sea posible. Más bien, es crear el mínimo número de pruebas que cubran el mayor número de casos o escenarios de nuestra implementación. Por ejemplo, supongamos que en la prueba uno insertamos 20,19, 18, 17, 16 y en la prueba dos insertamos 10,9,8,7,6. Realmente, en las dos pruebas estamos insertando elementos en orden descendente; es decir, las dos cubren el mismo escenario (son redundantes).

Con esto en mente, recomiendo crear escenarios que se complementen. Para el caso de la inserción en la lista doble: 1) insertar elementos en order ascendente, 2) insertar elementos en orden descendente, 3) insertar elementos tal que un elemento se inserte al inicio de la lista, el siguiente elemento al final de lista, y otro elemento en un punto medio de la lista y así sucesivamente, 4) insertar sólo elementos iguales.

Observa que estos casos son para la inserción, casos similares deben ser creados para el borrado. Y por último recomendaría un conjunto de casos que mezclaran operaciones de inserción y borrado.

Veo que al comparar la lista en forma de arreglo usamos un arreglo que nosotros calculamos new int[]{-50,0,50,100,200}, ¿cómo difiere esto de imprimirlo en la consola e inspeccionarlo visualmente?

Quizá las primeras dos o tres veces de inspeccionar el resultado visualmente resulte práctico, pero después de un buen rato de estar desarrollando verás que resulta demasiado tedioso y propenso a errores. Imagina que tienes una lista de 100 números, no suena muy divertido inspeccionar visualmente los 100 números cada vez que realices un cambio a la lista.

Además, como menciono en el punto anterior, es necesario probar varios escenarios. Si creas tus pruebas unitarias, entonces cada vez que las ejecutes estarás evaluando todos los escenarios en un abrir y cerrar de ojos. Esto te ayuda a tener más confianza al realizar cambios o mejoras en tu implementación, ya que puedes ir probando continuamente para validar si algo deja de funcionar o si algo ya está funcionando.

miércoles, 1 de diciembre de 2010

Fundamentos de Bases de Datos: Bases de Datos Orientadas a Objetos (apuntes)

He aquí una breve introducción a las Bases de Datos Orientadas a Objetos para el curso de Fundamentos de Bases de Datos del Instituto Tecnológico de Toluca. La práctica la pueden descargar en el link que se encuentra al final de la misma.

A las Bases de Datos Orientadas a Objetos también se les conoce como Sistemas de Manejo de Bases de Datos de Objetos (ODBMS, por sus siglas en inglés: Object Database Management Systems). Este tipo de bases de datos almacenan objetos en lugar de datos como enteros, cadenas o números reales. Los objetos ss utilizan en lenguajes de programación orientados a objetos tales como C++, Java y otros. Los objetos consisten básicamente en lo siguiente:

  • Atributos. Es la información que define las características de un objeto. Puede ser de tipo simple como por ejemplo enteros, booleanos o caracteres o puede hacer referencia a otros objetos.
  • Métodos. Los métodos definen el comportamiento de un objeto, son el equivalente a lo que se conoce como funciones o procedimientos en C, por ejemplo.
Otro término que vale la pena considerar es el de Clases. Las clases se utilizan en lenguajes de programación orientados a objetos para definir los datos y los métodos (características y comportamientos) que los objetos posean. Una clase es como una plantilla para crear un objeto y es usada para crear (instanciar) el objeto. Las clases pueden ser empleadas en bases de datos orientadas a objetos para re-crear partes de un objeto que puedan no estar almacenadas dentro de la base de datos como por ejemplo, los métodos.

Existen ventajas y desventajas de las Bases de Datos Orientadas a Objetos sobre las Bases de Datos de tipo Relacional, entre las ventajas cabe mencionar el hecho de que la navegación a través de la información en las primeras es más fácil que en las segundas, además de que el modelo de datos en las Orientadas a Objetos está basado y se ajusta mejor al mundo real. Entre las desventajas de las Orientadas a Objetos se encuentran la existencia de más herramientas para las Relacionales, la mayor estabilidad de los estándares de las Relacionales y una eficiencia más baja cuando se presentan datos y relaciones simples.

Fuente:
Object Oriented Databases
http://www.comptechdoc.org/independent/database/basicdb/dataobject.html 


DESCARGA LOS APUNTES DE LA PRÁCTICA DE LA CLASE AQUÍ!!!

martes, 30 de noviembre de 2010

Archivo para probar algoritmos de Ordenamiento Externo

En esta ocasión me gustaría proporcionarles a través de este medio, un archivo en formato binario que contiene más de 5000 nombres y con el cual se puede realizar una prueba confiable de los algoritmos de ordenamiento externo Mezcla natural y Mezcla directa o de intercalación que hemos revisado en la clase de Estructuras de Datos en el Instituto Tecnológico de Toluca.

Dicho archivo proviene de un proyecto denominado "Project Euler", que es un proyecto donde se convoca a la comunidad apasionada de la programación a resolver acertijos de distinto nivel con el fin divertirse por medio de la programación. El proyecto se nombró en honor al matemático Leonard Euler. En uno de los problemas (concretamente, en el problema 22) se proporciona un archivo con los más de 5000 nombres pero en formato de archivo de texto. Para nuestros proyectos, lo convertí a archivo binario.

Dicho archivo contiene los nombres en completo desorden, de modo que se pueda apreciar el buen funcionamiento de los métodos de ordenamiento de los que nos hemos encontrado.

Aquí puedes descargar el archivo.

Aquí puedes encontrar el código de la mezcla natural.

Si desean más información acerca del Proyecto Euler, pueden visitar su página web: http://projecteuler.net/

domingo, 28 de noviembre de 2010

SQL: Filtrar por Columna Resultado de Agrupado

Nota: Para poder seguir mejor este ejemplo y poder ejecutar las consultas, te recomiendo seguir las instrucciones para configurar el ambiente de trabajo en la parte 1 del tutorial de SQL.

En este post analizaremos una pregunta que recibí en la parte 3 (Consultas con agrupados) del tutorial de SQL. La siguiente consulta obtiene lo que ha gastado en total cada cliente en la renta de films.

SELECT customer.customer_id, first_name, last_name, SUM(amount) 
FROM customer 
INNER JOIN payment ON (customer.customer_id=payment.customer_id) 
GROUP BY customer.customer_id, first_name, last_name;

Pero, ¿cómo podemos filtrar por columnas que son resultado de agrupados? Específicamente, en la consulta anterior, ¿cómo desplegamos sólo los clientes que hayan gastado 100 o más? Este dato es resultado de usar una función de agrupado; es decir, no es una columna directa de la tabla. Por ello, no lo podemos usar directamente en la cláusula where. Lo que vamos a usar son consultas anidadas. La consulta original servirá como la tabla de otra consulta. Veamos la consulta que obtiene el resultado deseado:

SELECT *
FROM
(
   SELECT customer.customer_id, first_name, last_name, 
          SUM(amount) AS gasto_total
   FROM customer
   INNER JOIN payment ON (customer.customer_id=payment.customer_id)
   GROUP BY customer.customer_id, first_name, last_name
) ClientesConPagoTotal
WHERE gasto_total >= 100;

Como puedes observar, el resultado de la consulta original se usa como la tabla fuente de la consulta externa - nota que asignamos un nombre a esta tabla interna: ClientesConPagoTotal. También nombramos la columna que contiene el resultado agregado: gasto_total. Ahora, todos las columnas de la tabla temporal ClientesConPagoTotal son visibles en la consulta externa y las podemos usar para realizar filtros, como en: WHERE gasto_total >= 100.

Saludos,
Toño.

jueves, 25 de noviembre de 2010

Apuntes Circuitos Eléctricos Unidad3

Hola,

En los siguientes links encontrarán los apuntes de la unidad 3 para la materia de Circuitos Eléctricos y Electrónicos impartida para Ingeniería en Sistemas Computacionales aquí en el Instituto Tecnológico de Toluca.

Apuntes parte1 (aquí está incluida la tabla de los teoremas de álgebra booleana)
Apuntes parte 2 (comienza con los mapas de Karnaugh)

Saludos y suerte mañana en el examen.