Categorías
Austra

Mejoras importantes en Austra

Después de un largo impasse, provocado por un proyecto complicado, volvemos a la carga con Austra.

Primero, las labores típicas de mantenimiento: migrar a .NET 10, comprobar que todo sigue bien, corregir algún error y simplificar el analizador sintáctico.

Luego, hemos implementado por completo los vectores y secuencias de fechas. Vamos a añadir más funcionalidad en las siguientes versiones, como el movimiento de fechas por días festivos, calendarios de días festivos. Mi idea es poder usar directamente Austra para generar cupones para productos financieros como bonos y swaps. Eso ya es posible usando directamente la librería, pero se puede simplificar su uso desde el lenguaje.

Finalmente, la novedad más importante en la versión que estoy preparando es la posibilidad de leer vectores, series y matrices desde un fichero CSV. Esto es importante para reducir la dependencia actual de la aplicación (no de la librería ni del lenguaje) de un fichero data.austra. En realidad, la idea siempre ha sido poder usar adaptadores configurables para leer series desde una fuente de datos financieros elegida por el usuario. El problema es que la principal fuente gratuita está en caída libre (no mencionaré nombres) y las restantes cobran una pasta considerable por la suscripción. Sin esto, el uso práctico de la aplicación se limita bastante. Al poder leer series, vectores y matrices desde ficheros CSV, hacemos posible inicializar Austra desde un script inicial, que se podría incluso ejecutar automáticamente, sin abandonar la posibilidad de cargar luego un data.austra.

Y si finalmente me compro un portátil con procesador ARM, miraré cuán simple o complicado sería ampliar la funcionalidad de procesamiento vectorial a este modelo. Sospecho que buena parte ya funcionaría casi automáticamente, al realizar buena parte de la optimización con las últimas clases de .NET. Pero hay que comprobarlo.

Categorías
C#

No tan bueno

Entusiasmado por las noticias, monté .NET 10 y Visual Studio 2026 Insiders, en paralelo con mi actual VS. Cargué entonces mi viejo y muy optimizado ray tracer, y me puse a enredar. Efectivamente, no tardé mucho en ver que, sin tocar mucho código, el runtime de .NET 10 hace que mi aplicación sea ligeramente más rápida. Un benchmark que se lleva unos 3 segundos, ahora termina en 2.9, aproximadamente. No es para tirar cohetes, pero, ¡eh!, no tuve que hacer nada, aparte de actualizar.

Pero lo que realmente quería probar. Ahora está de moda todo lo que se relacione con AI. Busqué un método que consumiese CPU, y elegí la generación de ruido de Perlin. Abrí el chat de Copilot GitHub (hasta ahora, yo pagaba mi suscripción) y le pedí que le echase un ojo al método. El amable señor se tiró unos quince minutos y reapareció con un par de recetas. ¿Quieres aplicarlas?, dijo. Sí, por supuesto. Y allá se lanzó a modificar código.

Resultados:

1- El método sin turbulencias es ahora dos nanosegundos más lento (de 23 ns a 25 ns).
2- El método con turbulencias es ahora dos nanosegundos (¡curioso!) más rápido. De 125 ns a 123 ns.

Entonces respondí: «Borra todos los cambios».

AI sigue significando Artificial Idiocy.

Quizás algún día cambien las cosas. Ese día no es hoy.

Categorías
Insights

No lo digo yo…

Sinceramente, he abandonado toda esperanza de dejar un mundo un poco menos estúpido cuando la diñe… La Verdad es fea. Las Mentiras son más bonitas. Pero sólo la Verdad es fértil.

Categorías
Música

The Mage

(The Mage: Spotify)

You, who try to understand
Symbols chiseled in the dark
Don’t give up, my friend,
Though you’re crying in the wilderness.

White shadows from the Moon
Trace a road back through the past
But your proudness breaks the spell
And the vision fades away in a thunderstorm.

Are we made of dusty matter and emotions?
Are our souls an empty web of silly notions?
It’s all the same…

Don’t ever think our past
Is deeply buried down the sands
When the whispers from the wind
Reveal some crazy secrets left behind.

It’s so easy to believe there is no meaning!
Are the bruises on your soul already healing?
Is there a turning back?

An old man looks into our darkness
While the shadows cry in silence
Cause they know he’s waiting for a light to spark.
It may seem he’s all alone
That his journey has no point
The sun sinks all the way down
And the shadows win another round.

Is it true that there’s a tree of life and knowledge?
Are our wishes and our love all going nowhere?
Did someone ever care?

An old man looks at the horizon
While the world is growing older
And the evil towers crumble to the ground.
Arms are raised up to the heavens
As he climbs his flaming vessel
The old man turns to say goodbye
And we wonder if he will come back.

Categorías
Música

Der Ravenmeister

En 1684, Jan Cornelius Maarten, organista de la catedral de Delft, visitó Londres en busca de piezas de repuesto para su instrumento. En una de las muchas tabernas de la ciudad, conoció a un ciego, que se presentó como Benedict Crowell, cuidador de los cuervos de la London Tower. Tras unas cuantas jarras de cerveza, Crowell invitó a Jan a conocer sus cuervos al día siguiente.

Al parecer, Jan Cornelius quedó impresionado con el trabajo de Crowell, porque escribió una larga carta a su hermano Felix, que todavía se conserva. El ciego había entrenado a los cuervos para que pidiesen comida dejando caer una piedra sobre una bandeja metálica. Así podía distinguir estas llamadas de los graznidos habituales, y podía pasar más tiempo bajo techo. Lo interesante es que los cuervos, por cuenta propia, habían elegido cada uno una piedra de tamaño diferente, y el ciego podía casi siempre distinguir de cuál cuervo se trataba por el sonido. Esta habilidad fascinó al músico.

Lo mejor de todo es que Jack, uno de los cuervos, a veces lanzaba la piedra de Eva para que la hembra comiese primero. Esto confundió durante un tiempo al bueno de Benedict, hasta que cayó en cuenta de lo que pasaba.

De regreso en Delft, Jan Cornelius escribió una fughetta, o pequeña fuga a tres voces, y la tituló «De Ravenmeester». Es decir, el Amo de los Cuervos, en holandés. Incluyó una copia manuscrita de la partitura en su carta a Felix Maarten, residente en Valladolid, y por este motivo conocemos la breve pieza.

Este es un modesto arreglo moderno, que cubre algunas de las partes que se han perdido del manuscrito original:

Categorías
Austra

Lambdas sobre operadores binarios

Esta es una pequeña mejora al lenguaje de Austra. Supongamos que queremos sumar los números del 1 al 100. Creamos una secuencia de enteros y le aplicamos el método reduce:

iseq(1, 100).reduce(0, (x, y) => x + y) 

En realidad, nos bastaría llamar a sum, pero el ejemplo me interesa por el uso de la función lambda.

El caso es que ahora podemos escribirlo así:

iseq(1, 100).reduce(0, int::+) 

El truco es sencillo, y Java lo usa a manos llenas al manejar streams. De momento, sólo he activado la equivalencia para operadores binarios, pero si encuentro más casos útiles, puedo ampliarla. Hay que tener presente que Austra ya permite declarar funciones con parámetros lambda arbitrarios. Que no haya un método en la librería que utilice determinado patrón de función, no quiere decir que el usuario no pueda usarlo por su cuenta.

Categorías
Música

Prayer

Soy consciente de que hace tiempo que no escribo sobre informática, que es de lo que, en definitiva, trata este blog. Es que me aburre lo que estoy haciendo y, lo peor, me está robando mucho tiempo. De cuando en cuando tengo la tentación de decir lo que opino, pero me la guardo con cuidado. Hay opiniones que explotan.

De momento, éste es mi último invento al piano:

Hay a quien le ha parecido un gospel, por el título y porque el tiempo es un vals tocado con eso que los músicos llaman, técnicamente hablando, «swing». Es decir, cada negra se divide irregularmente en casi tres partes. No era mi intención. Compuse una canción de enamoramientos y esas cosas, y esto es lo que ha salido. Disfrutadla. O detestadla. Estas son cosas que pasan cuando me aburro.

Categorías
Insights Música

Family Album

Mientras preparo el primer borrador de Nyx, le he dedicado un rato a la versión de Logic Pro para iPad. Normalmente, uso Sonar (el antiguo Cakewalk, que creo que vuelve a llamarse así), pero es mucho más cómodo usar un iPad mientras vas en tren a la oficina.

Esta es una pieza antigua, pero me gusta más como ha quedado esta vez:

Es una pieza sencilla, sin pretensiones, y es fácil de tocar. He mejorado un poco las dinámicas (cuánta fuerza usas con cada nota, y el volumen general de los pasajes) respecto a la subida original.

Mi rutina de grabación

Como sé que hay muchos programadores que tienen la música como afición, os cuento cómo hago estas cosas, ya sea por si a alguien le interesa o si alguien tiene consejos interesantes.

Ahora mismo, me he pasado, como decía, al Logic Pro para iPad. Me he comprado el iPad Pro de once pulgadas con un procesador M4. Elegí el de un terabyte de disco, porque los de menos capacidad tenían menos RAM. De todos modos, cuentan por ahí que la RAM adicional no se nota mucho en la mayoría de los benchmarks.

Logic Pro viene con un piano de estudio muy bueno. Ya había probado los pianos de Native Instruments, pero personalmente me gusta más éste. No me hagáis mucho caso.

Tengo desde hace unos años un Roland HP704. Buena acción de teclado y, lo que me resulta más cómodo ahora mismo, puedo conectarme al MIDI por Bluetooth.

Normalmente grabo MIDI, por si tengo que corregir algún pasaje complicado. Divido las notas en dos pistas, para ampliar la panorámica estéreo. He utilizado el asistente de masterización de Logic Pro, para mejorar los bajos y la banda de más de 10KHz.

Debería usar monitores de referencia profesionales, pero la idea era aprovechar el viaje en tren.

Categorías
Música

The Tiger

Me encanta este tema de Babelle:

Es más movidillo. Además, está en una tonalidad mayor. A mi edad, empieza uno a valorar cada día de sol.

Categorías
Austra

Destrucción creativa

El compilador de Austra sigue mejorando. Y la librería también, que todo hay que decirlo.

Finalmente, he podido añadir generación de valores aleatorios con AVX2, además de la que ya había implementado con AVX512. La dificultad residía en la necesidad de rotar circularmente un entero largo. AVX512 te da la instrucción. Pero es fácil ver que en AVX2 es posible hacer lo mismo con dos desplazamientos lógicos y una conjunción lógica.

El otro avance importante es la vectorización del algoritmo de Box-Muller para generar distribuciones normales. Ya teníamos un logaritmo natural para vectores de 256 y de 512 bits. Ahora añadimos una función que calcula simultáneamente el seno y el coseno para estos dos tipos de vectores. De hecho, hay una variante especial que es la que usa Box-Muller, en la que todos los valores están entre cero y dos veces pi, y es un poco más rápida. Añadí esta función, la utilicé en el código del generador normal y, finalmente, se ha usado en las clases de vectores, matrices y secuencias.

Operaciones in situ

El compilador intenta ahora optimizar expresiones como la siguiente:

vector1 + vector2 + vector3

¿Qué hay aquí para optimizar? A primera vista, parecería que esa expresión es candidata para reescribirse mediante un combinador lineal, que de hecho existe y se usa para algunas optimizaciones ya:

vec([1, 1, 1, vector1, vector2, vector3)

Se podría utilizar, pero este constructor añadiría tres multiplicaciones escalares innecesarias. Lo que sí nos ahorraríamos sería la creación de dos búferes temporales como resultado de las dos sumas de la expresión original. Lo que ha aprendido a hacer el compilador es a modificar la expresión original a este otro patrón, que es más general:

(vector1 + vector2).InplaceAdd(vector3)

InplaceAdd no se puede llamar directamente desde el lenguaje: es una instrucción peligrosa, porque sobrescribe el búfer del primer operando. El compilador tiene que detectar que el primer operando es de tipo temporal, y no va a utilizarse en el resto de la fórmula, o en el peor de los casos, en el resto de la sesión. Pero en el ejemplo mostrado, la primera suma es evidentemente una construcción temporal, independientemente del sitio de donde estemos sacando las tres variables usadas.

Naturalmente, podemos hacerlo mejor si ya sabemos qué son vector1 y sus dos amigos. Si son variables de sesión, no hay nada más que podamos hacer. Lo mismo ocurre si son parámetros de una función definida por el usuario o variables locales, introducidas por una cláusula let. Pero supongamos que la expresión original fuese la siguiente:

vec::random(10) + vector2 + vector3

En ese caso, el primer operando se crea en un constructor y sólo se usa en esa expresión. El compilador puede entonces crear el siguiente código equivalente:

vec::random(10).InplaceAdd(vector2).InplaceAdd(vector3)

No importa de dónde salgan vector2 y vector3. El búfer del primer operando puede ser reutilizado, y eso es lo que hacemos. El resultado de InplaceAdd, dicho sea de paso, también se puede sobrescribir con total seguridad.

Este tipo de optimizaciones es mejor que las haga un compilador, y no la librería. Es el compilador quien tiene toda la información sobre el uso de un operando. De momento, nos movemos sobre terreno seguro. Hay algunas operaciones que podrían optimizarse con este truco, pero de momento no lo hacemos. Por ejemplo, si una variable local sólo se utiliza una vez, no hay memoria compartida que tengamos que respetar. De momento, no contamos el número de usos de cada variable local.

Finalmente, hemos ampliado las optimizaciones que hacíamos sobre vectores reales a vectores complejos. Es un poco más de código, pero no se hace más lenta la compilación.

Se supone que la señorita de la imagen es Freya bailando sobre calaveras. Eran Kali y Shiva quienes practicaban este tipo de danza, pero estaba seguro de que la tía que la IA iba a generar para Freya iba a ser más guapa. ¿Y las calaveras? Pues están debajo. Pero los generadores de Inteligencia Artificial siguen teniendo problemas para generar manos humanas. De hecho, la imagen que utilizo para Austra la llamo en mi cabeza «la chica del eccema». Llevo meses haciendo retoques a sus manos, y todavía tienen problemas. Pero me gusta el tono del pelo, el óvalo facial y la postura. No se puede tener todo.