Esto es un espacio para hablar de programación, algoritmos y tecnología. Aquí trato de publicar artículos que contengan un valor adicional y (ojalá) de utilidad para todos lo que los lean.

El Proyecto Medio

September 12th, 2007

La primera vez que vi esta imagen, hace varios años, me resultó muy graciosa. Ahora que la vuelvo a ver sólo puedo decir que nada refleja la realidad mejor que esto. Sobre todo que el cliente jamás sabe lo que quiere y la documentación del proyecto. Espero que no se identifiquen demasiado.

El Proyecto Medio

Ya que el proyecto Beryl está descontinuado, es hora de actualizar nuestro ambiente gráfico a lo que es el futuro del eyecandy, esto es, Compiz Fusion. Si aún no sabes qué es Beryl o Compiz Fusion, he aquí un video demostrativo:

Después de ver lo que se puede hacer con este magnífico ambiente gráfico; pongamos manos a la obra. Este tutorial te servirá para instalar la más reciente versión de Ubuntu, los controladores propietarios de ATI (los únicos que proveen a las tarjetas de la serie X1000 con aceleración 3D), XGL y Compiz Fusion.

NOTA: Si ya tienes tienes funcionando Beryl, no tendrás que hacer todo de nuevo, solo salta al paso 17.

NOTA IMPORTANTE: Este tutorial fue compilado gracias a todos estos sitios y con algunas modificaciones mías. Los créditos se quedan con sus respectivos autores.

  1. Para la instalación usaremos el CD alterno de instalación. Lo puedes encontrar aquí. Bájate el que sea más apropiado de acuerdo al tipo de intalación que
    deseas tener. Lo más seguro es que necesites la versión Intel x86.
  2. Inicia tu computadora desde el CD que recién bajaste y selecciona la instalación en modo texto (la primera opción). Este modo de instalación es muy parecida a la forma que se usaba en Ubuntu 5.10 y anteriores.
  3. Completa la instalación y reinicia tu computadora.
    Leer más »

TopCoder Collegiate Challenge

August 12th, 2007

El próximo jueves 16 se cierran las inscripciones al concurso universitario de programación de TopCoder (TCCC). Así que si te las das de que programas muy chido, date la oportunidad (así como yo) de comprobar que no es así, jaja.

TopCoder Collegiate Challenge

Yo diría que después del ICPC en la fase final, aquí vive la gente más enferma para programar. Bueno, a decir verdad es la misma gente. Por cierto, ya se acercan las fechas de registro para el ICPC reginal.

Si no estás familiarizado con este tipo de concursos, de manera muy general:

  • Recibes un texto (en inglés) describiendo un problema, que generalmente necesitará de tus conocimientos de las Ciencias Computacionales para resolverlo.
  • Tienes un tiempo limitado para enviar la solución.
  • El participante que envíe la solución en el menor tiempo, gana.

Así que ya lo sabes, si quieres llevarte una parte de los USD$250,000 de premios, inscríbete y compartenos tu experiencia.

Java 6: Script Engines

August 12th, 2007

Después de una larga espera, finalmente se me quitó la flojera y decidí cumplir con uno de los posts prometidos acerca de Java 6. Se trata de la nueva especificación (JSR-223) que provee una interfaz estadarizada para la interacción con lenguajes de Scripting, tales como JavaScript, PHP, Python y Ruby.

Para los propósitos de este post usaremos JavaScript y PHP. Java 6 ya trae soporte para JavaScript; pero si queremos usar PHP u otro lenguaje, tendremos que conseguir la implementación del JSR-223 específica del lenguaje. Para este caso usaremos Quercus y un par de paquetes en los que Quercus tiene dependencias.

He aquí los paquetes que necesitaremos (vienen las ligas a los sitios donde se pueden conseguir las versiones más actuales. Si lo prefieres puedes bajar este paquete, que contiene las versiones disponibles al momento de escribir este post):

  • quercus.jar: Está dentro del paquete de Quercus.
  • resin-util.jar: Está dentro del paquete de Quercus.
  • servlet-api.jar: Se puede conseguir de la carpeta lib del Tomcat.
  • mail-x.x.jar: Solo para que el Quercus no mande warnings, JavaMail.

Ahora que tenemos todo lo necesario abramos nuestro editor Java favorito (Eclipse, por supuesto) y asegurémonos de que los archivos JAR recién bajados se encuentren en el CLASSPATH del proyecto o del sistema. Solo para probar que lo hicimos bien, agreguemos las siguientes líneas de código (sin olvidar sus respectivos includes [javax.script]).

public static void main(String[] args) {
	ScriptEngineManager manager = new ScriptEngineManager();
	ScriptEngine engine = manager.getEngineByExtension(”php”);
	engine.getContext();
}

Si tu código no compila y corre sin problemas, entonces asegúrate por segunda vez que las librerías sean visibles para tu código.

La clase ScriptEngine tiene algunos métodos bastante prácticos para intercambiar información con el intérprete del lenguaje de scripting; A mi parecer, tres de ellos son indispensables:

  • put(String key, Object value): Sirve para asignar un valor a una variable dentro del intérprete.
  • get(String key): Sirve para obtener el valor de una variable dentro del intérprete.
  • eval(): Que tiene algunas variantes muy prácticas que permiten introducir el script como un String o desde un archivo.

Ya que conocemos un poco más de la clase ScriptEngine, hagamos algo útil con ella.

public static void main(String[] args) {

	PrintWriter out = new PrintWriter(System.out, true);
	ScriptEngineManager manager = new ScriptEngineManager();
	ScriptEngine engine = manager.getEngineByExtension(”php”);
	engine.getContext().setWriter(out);
	String phpCode = “”;

	try {
		engine.put(”msg”, “chido!”);

		phpCode = “<?php ” +
			“if ($msg == ‘chido!’) {” +
				“echo(’bien!’);” +
			“}” +
			“else {” +
				“echo(’mal!’);” +
			“}” +
			” ?>”;

		engine.eval(phpCode);
		out.flush();
	}
	catch (ScriptException se) {
		se.printStackTrace();
	}
}

Con el código anterior podemos ejecutar cualquier código PHP; por lo que podemos beneficiarnos de la versatilidad del lenguaje y de muchas de sus funciones y librerías.

Ahora hagamos lo mismo con JavaScript. Es sorprendente lo poco que debemos modificar en el código Java para usar un lenguaje diferente.

public static void main(String[] args) {

	PrintWriter out = new PrintWriter(System.out, true);
	ScriptEngineManager manager = new ScriptEngineManager();
	ScriptEngine engine = manager.getEngineByExtension(”js”);
	engine.getContext().setWriter(out);
	String jsCode = “”;

	try {
		engine.put(”msg”, “chido!”);

		jsCode = “if (msg == ‘chido!’) {” +
				“print(’bien!’);” +
			“}” +
			“else {” +
				“print(’mal!’)” +
			“}”;

		engine.eval(jsCode);
		out.flush();
	}
	catch (ScriptException se) {
		se.printStackTrace();
	}
}

Bueno, eso fue lo básico para comenzar a integrar JavaScript o PHP con tus clases de Java. Si sabes como hacerlo con Ruby, Python u otro lenguaje comparte con nosotros tu solución mendiante un comentario con una liga a tu sitio.

¡Half Life 2 Gratis!

June 10th, 2007

Valve anunció que todos los poseedores de tarjetas gráficas ATI de la serie Radeon (la más común) pueden bajarse de manera gratuita los siguientes títulos de su repertorio vía Steam (una plataforma de distribución en línea de juegos).

  • Half-Life 2: Lost Coast.
  • Half-Life 2: Deathmatch.

Los cuales son expansiones del popular juego Half Life 2 y puedes acceder a ellos siguiendo esta liga. Esperemos que no sea necesario contar con una licencia del Half Life 2 para poder usar las expansiones.

Me parece que de esta estrategia de mercadeo todo mundo sale beneficiado:

  • Los consumidores ganamos: Tenemos juegos gratis.
  • ATI: Supongo que habrá más de uno que se decida por esta marca solo por la promoción. Además mantienen contentos a sus clientes actuales.
  • Steam: En adelante el software de Steam acompañará al manejador de drivers de ATI (Catalyst™), por lo que tendrá mayor difusión.
  • Valve: Solo veo que gana en publicidad.

Ojalá que más compañías de juegos sigan el ejemplo, jaja; aunque sea con los títulos viejitos.

Después de hacer la comparación entre mi implementación chafa y la de Java, me quedé pensando como hacerle para reducir un poco la diferencia sin quitarle la simplicidad (más bien sin tener que aprender un QuickSort optimizado, jaja).

Entonces se me ocurrió que podría aprovechar las bondades de los, cada vez más comunes, procesadores con HT o doble núcleo. La solución es muy sencilla, solo hay que poner la mitad del arreglo en un hilo y la otra mitad, pues en otro hilo.

Pero me di cuenta de que este enfoque también es aplicable a código que utilice las librerías de Java. Solo hay que usar el método sort(int[] a, int fromIndex, int toIndex) en lugar de sort(int[] a).

De esta forma quedaría algo así para dos hilos:

new Thread() {
	public void run() {
		 Arrays.sort(arr, 0, arr.length / 2);
	}
}.start();

new Thread() {
	public void run() {
		 Arrays.sort(arr, arr.length / 2, arr.length);
	}
}.start();

Sin embargo, este código tiene un pequeño problema; cada hilo ordenará una mitad del arreglo independientemente, así que al final nuestro arreglo no estará globalmente ordenado. Por lo cual recurrí al principio del MergeSort, que se basa en combinar dos arreglos ordenados para tener como resultado un arreglo más grande tabién ordenado. Solamente necesitamos una iteración del Merge y saber donde se hizo el corte del arreglo original y todo quedará resuelto. A continuación, una versión del merge:

merge(int arr[], cuts[]) {
	int index1 = cuts[0];
	int index2 = cuts[1];
	int src[] = arr.clone();

	for (int i = 0; i < src.length; i++) {
 		if (index1 >= cuts[1]) {
 			arr[i] = src[index2++];
 		}
 		else if (index2 >= cuts[2]) {
 			arr[i] = src[index1++];
 		}
 		else {
 			if (src[index1] < src[index2]) {
 				arr[i] = src[index1++];
 			}
 			else {
 				arr[i] = src[index2++];
 			}
 		}
	}
}

NOTA: El arreglo cuts contiene estos valores {0, arr.length / 2}.

Mientras estaba programando este algoritmo pensé de repente: ya que ando en esto, ¿por qué parar aquí? Debería programar algo que sirva para más que solo enteros. Así que le puse genéricos y ahora se puede ordenar cualquier colección de objetos que implementen la interfaz Comparable. Quedó un poco más lento; porque ahora se manejan colecciones y no arreglos, objetos y no tipos de datos primitivos. Pero bueno, todo sea por la cohesión balanceada.

Ya que me sentía tan espléndido, pensé: los procesadores de doble núcleo van a pasar de moda el próximo año, ¿por qué no hacemos el asunto escalable? La solución más obvia para el número de hilos que manejaría es la tendencia del número de núcleos que tienen los procesadores: 2, 4, 8, … Pero, después pensé: ¿qué tal si alguien que tiene un servidor con un montón de núcleos quiere usar mi clase? La tarea de ordenamiento consumiría todos los recursos disponibles o una fracción tal vez inadecuada. Si tengo 8 núcleos ¿qué tal si me da la gana tener a 5 ordenando, 1 para el servidor de aplicaciones, 1 para el servidor de bases de datos y otro para ver una película?

Decidí entonces hacer que aceptara cualquier número de hilos para realizar el ordenamiento. Sin embargo, esto introduce otro problema; el Merge clásico trabaja uniendo pares de arreglos. Lo cual fue resuelto ideando un Merge ad-hoc que juntase cualquier cantidad de arreglos. Lo cual tiene un poquito de overhead, pero realmente no resulta muy grave.

Finalmente, hice alguas pruebas de desempeño. Puse a ordenar 1,000 veces un Vector con 1,000,000 de objetos Integer; todo esto sobre un procesador Intel Core Duo a 1.66 Ghz. A continuación está el tiempo promedio que tardó cada implementación. Cada liga lleva al código fuente en Java.

DualSort (usa dos hilos y el Merge clásico).
ScalableSort (usando dos hilos y el Merge ad-hoc).
Collections.sort (usa un hilo, implementación de Java).

Desempeño de ScalableSort

También puedes descargar un archivo JAR y usar las clases como librerías.