Empezamos aplicando el algoritmo a la ecuación del calor en una dimensión:
Con difusividad térmica . Así pues, tenemos que:
o, más en concreto:
Para empezar, es el orden de la máxima derivada y es el número de ecuaciones que tenemos.
Paso 1:
Paso 2:
Paso 3:
Paso 4:
Paso 5:
Soluciones invariantes:
Paso 1: Aplicar el generador infinitesimal extendido a la EDP según lo establecido en el teorema del post anterior: .
Paso 2: Derivar los infinitesimales extendidos necesarios, dados por las ecuaciones (3.59), utilizando la derivada total, D_i, definida en (3.60).
Paso 3: Insertar los infinitesimales extendidos en el resultado obtenido en el Paso 1 y agrupar los infinitesimales según las variables dependientes y sus derivadas. La condición F=0 debería ser introducida en este paso.
Paso 4: Resolver el sistema de ecuaciones diferenciales obtenidas al igualar cada corchete a 0.
Paso 5: Formular el generador infinitesimal multiparamétrico de todas las simetrías y dividirlas en simetrías de Lie uniparamétricas.
Soluciones invariantes: una vez que se han obtenido las simetrías de Lie uniparamétricas, el último paso consiste en obtener soluciones invariantes del sistema de EDPs utilizando las simetrías obtenidas. En el campo de la dinámica de fluidos, estas soluciones invariantes son conocidas como leyes de escala.
El grupo de Lie uniparamétrico de transformaciones
,
deja invariante un sistema de PDEs (o, equivalentemente, es un punto de simetrias admitido por el mismo sistema) si y solo si su extensión k-ésima
deja invariante las superficies en el espacio definido por dicho sistema de PDEs.
El correspondiente generador de la extensión infinitesimal k-ésima del grupo de Lie de transformaciones (compuesto por ) se define como
Las derivadas de variables dependientes que aparecen en las ecuaciones diferenciales se consideran como variables dependientes extra y su transformación debe tenerse en cuenta y pueden ser calculadas mediante la regla de la cadena.
Las transformaciones que teniamos eran:
Las transformaciones extendidas son:
donde las funciones son las k-ésimas extensiones infinitesimales, el número del paréntesis indica el orden de la derivada y se calculan como:
,
para y , con y donde el operador es el operador derivada total definido como:
Tenemos ahora
donde y son los infinitesimales de variables independientes y dependientes. Como generador infinitesimal tenemos:
Sean las variables independientes y las variables dependientes del sistema de PDEs que dependen de las variables independientes (superíndices indicando componentes).
Entonces, las ecuaciones del sistema de PDEs pueden representarse como
con , donde indica la derivada más alta que aparece en la PDE y representa todas las posibles derivadas de cualquier con respecto cualquier combinación de . Por ejemplo, para las primeras derivadas tenemos:
Y también la notación para derivadas superiores:
con , , .
En el último post antes del verano, hablamos de la generalización de grupos de Lie actuando no solo sobre una PDE sino sobre un sistema de PDEs y enumeramos algunas de las generalizaciones que debíamos hacer. En estos próximos post trataremos de abordar cada una de las generalizaciones enumeradas.
La idea de función invariante introducida en el post anterior puede generalizarse a sistemas de ecuaciones en derivadas parciales.
Primero que nada, habrá que definir la notación que utilizaremos.
Lo primero generalizable será el concepto de grupo de Lie de transformaciones actuando sobre un sistema de PDEs.
A continuación, podremos definir el generador infinitesimal.
En la búsqueda de simetrías de Lie, hay que tener en cuenta que las derivadas de las variables dependientes que aparecen en las ecuaciones diferenciales se considerarán como variables dependientes extra.
Hablaremos de transformaciones extendidas cuando tratamos con las transformaciones de las derivadas de las variables dependientes.
Dada una función , diremos que es una función invariante del grupo de Lie de tranformaciones si y sólo si para cualquier grupo de transformaciones del grupo se cumple que
Existen un teorema al respecto que nos dice que es invariante bajo un grupo de Lie de transformaciones si y sólo si .
Por ejemplo, dada la función , és invariante bajo el grupo de escalados. El grupo de escalados representa escalados de las variables en los ejes e :
,
,
con , ley de composición y elemento identidad . Para que sea un grupo de Lie uniparamétrico, necesitamos que la identidad sea , por lo que necesitamos hacer una reparametrización , de manera que:
,
,
y con y .
Por el post anterior, podemos identificar al grupo de Lie con donde en . Además, también puede escribirse como
donde es el generador infinitesimal y viene dado por .
Aplicamos al grupo traslacion…
El operador
donde es el operador gradiente:
Dada una función diferenciable , la aplicación del operador queda:
Para el caso particular de tenemos que .
Dado el grupo de Lie uniparamétrico de transformaciones (1), existe una parametrización tal que (1) es equivalente a la solución de un problema de valor inicial de un sistema de ecuaciones diferenciales de primer orden dado por:
con cuando (recordemos la notación que estamos utilizando para las derivadas: ).
En particular,
donde
Como ejemplo, imaginemos el grupo de translaciones en el eje de las :
donde la ley de composición es y . Si entonces y
Llegados a este punto, dado el problema de valor inicial
con , en , por el primer teorema fundamental de Lie, el grupo de transformaciones:
es solución del mismo.
Dado un grupo de Lie uniparamétrico de transformaciones (donde hemos cambiando el punto y coma por otra coma) con identidad y ley de composición , podemos desarrollarla mediante Taylor, a primer orden, para varias variables , tenemos variables) alrededor de .
Si definimos:
como el infinitesimal del grupo de Lie uniparamétrico, podemos definir la transfomación infinitesimal como
La idea que hay detrás de los grupos infinitesimales, parece que originalmente atribuible a Lie, es que, hablando en un caso particular, rotar grados (lo que nos interesa) es lo mismo que rotar veces grado (como lo podemos hacer con infinitesimales). De ahí que se diga que los infinitesimales capturan la información del grupo. En realidad, algo como
Una simetría de Lie o transformación de Lie es un grupo (matemáticamente hablando) de transformaciones con algunas propiedades.
Un grupo es un conjunto de elementos con una ley de composición tal que es cerrada, asociativa y posee elementos identidad e inverso para cada elemento .
Dado un en la región , el conjunto de transformaciones
definido para cada y con parámetro y con definiendo una ley de composición de parámetros y . Tenemos un grupo uniparamétrico de transformaciones en si a) sea cual sea el parametro en punto transformado sigue en , b) con forma un grupo , c) si el parametro es el neutro de entonces el punto sobre el que aplicamos la transformación no varía ; y si y entonces .
Además, tendremos un grupo de Lie uniparamétrico de transformaciones si a) es un parámetro continuo, b) es y analítica de en y c) es una función analítica de y de .
Ejemplos en el plano, para entender la nomenclatura, podrian ser 1) rotación de angulo alrededor del origen: ; 2) translacion a distancia : en donde seria la suma de reales y el neutro (si tuvieramos escalados, la operación sería el producto y necesitariamos un cambió de variable para que el neutro se trasladara a ). Con esta notación, podriamos reescribir como . Sin embargo, como se puede confundir con la notación de derivadas que estamos utilizando, se hará de la anterior manera.
Por una parte, es difícil resolver (sistemas de) ecuaciones en derivadas parciales (EDPs). Por otra, aparecen en multitud de problemas físico-matemáticos, pues son una de las herramientas más potentes a la hora de modelar sistemas.
Una de las aproximaciones seguidas en todos los trabajos realizados hasta el momento a lo largo de este blog es la utilización de los métodos numéricos para la obtención de soluciones.
Vamos a dedicar unas cuantas entradas a trabajar sobre un método general de integración, las simetrías de Lie que, por un lado, son una generalización de muchos métodos particulares conocidos hasta el momento de su introducción y, por otro, está basado en la invariancia de estos sistemas de EDPs bajo un grupo continuo de simetrías.
El método trata de encontrar las simetrías de una EDP calculando el grupo uniparamétrico de transformaciones que la dejan invariante, convirtiendo el conjunto de soluciones en soluciones.
Para ejemplificar esta técnica, encontraremos las simetrias de dos ecuaciones unidimensionales: la ecuación del calor , y la ecuación que describe el comportamiento del medio viscoelástico .
Sabemos que, de forma general,
y
Recordemos que, bajo ciertas condiciones de continuidad y diferenciabilidad, existe commutatividad en las derivadas de orden superior, es decir:
donde si cada entero de a aparece la misma cantidad de veces en que en .
Así pues, en realidad, tenemos:
y
Retomo el blog despues de mucho tiempo inactivo. Empecé con astrofísica y relatividad numérica, dediqué unas pocas entradas a programación básica y ahora lo retomo en una área muy de moda y en la que me encuentro trabajando: Machine Learning.
La última construcción iterativa es el para
, que se utiliza cuando sabemos, a priori, el número de iteraciones que vamos a realizar
La sintaxis en C++ es:
para @ hasta hacer
En C++ tenemos:
for ( contador = valor_inicial; condicion;
Un sistema es autónomo cuando la variable no aparece explícitamente en la parte derecha de la EDO (). Es no-autónomo cuando si lo hace ().
El espacio de fases es el conjunto de todas las posibles configuraciones de un sistema. Si el sistema depende de un número de variables, y cada una de ellas puede tomar cualquier valor posible de su dominio de definición, la dimensión del espacio de fases es el número de variables dependiente . A los espacios de fase también se les llama espacios de configuración.
Si estudiando un gas de partículas en el espacio, su espacio de fases tiene dimensiones.
Si el sistema es autonomo, cada punto del espacio de fases siempre tiene el mismo vector de velocidad asociado.
Para autovalores reales, cada autovector correspondiente define una recta invariante en el espacio de fases que pasan por el punto de equilibrio, siendo estos aquellos puntos donde se anula la derivada. Si el autovalor es positivo, el punto de equilibrio es repulsivo, mientras que si es negativo entonces es atractivo.
Para autovalores puramente imaginarios, tenemos círculos alrededor de los puntos de equilibrio, mientras que si son complejos, en función de si la parte real es positiva o negativa, tendremos espirales que escapan del punto de equilibrio o que se acercan a el respectivamente.
Para los sistemas no lineales, linealizamos alrededor de los puntos de equilibrio mediante el jacobiano.
composicion iterativa
mientras
repetir
composicion secuencial
composicion alternativa
alternativa simple
alternativa doble
alternativa multiple
Los lenguajes de programación nos van a permitir escribir programas, es decir, escribir algoritmos en un lenguaje capaz de ser procesado por un computador.
Los lenguajes de programación son lenguajes y, por lo tanto, constan de un léxico, una sintaxis y una semántica.
El léxico es el conjunto de palabras que forman el lenguaje (en C++, por ejemplo, tenemos if
, else
, +
, -
, 2
, 7.89
, etc). La sintaxis es el conjunto de reglas que nos indican como construir frases (C++: if (i>0) { i--;}
). La semántica es lo que dota de significado a cada una de esas frases.
Podemos clasificar los lenguajes de programación de diferentes maneras.
En función de su proximidad a la computadora, su arquitectura, o al programador, tenemos lenguajes de bajo nivel y lenguajes de alto nivel.
Los lenguajes de bajo nivel son muy cercanos a la arquitectura del computador (su juego de instrucciones) lo que los hace muy difíciles de programar a la vez que poco portables. Dos ejemplos son el lenguaje máquina (es en binario) y el ensamblador (se utilizan mnemotécnicos en lugar de secuencias de ceros y unos).
Los lenguajes de alto nivel son independientes de la arquitectura (basados en máquinas abstractas) y son mucho más próximos (en cuanto a léxico, sintaxis y semántica) a las personas. Todo esto los hace mas sencillos, flexibles y potentes. Sin embargo, como el computador no los entiende directamente, necesitamos de un traductor (interprete o compilador).
En función del paradigma, la filosofía que hay detrás, tenemos lenguajes de programación procedurales y lenguajes de programación declarativos. En los primeros se describe la secuencia de pasos para resolver el problema (COMO) mientras que en los segundos simplemente se describen los mismos (QUE). Para los primeros tenemos lenguajes imperativos (prima el procedimiento) y lenguajes orientados a objetos (prima el dato). Para los segundos tenemos los funcionales (funciones matemáticas) y los lógicos (predicados lógicos).
Finalmente, en función de si se traducen todas las sentencias de golpe para su posterior ejecución, compilados, o si se va traduciendo y ejecutando instrucción a instrucción, interpretados.
¿Qué elementos forman el léxico de un lenguaje? En primer lugar, las palabras reservadas: tienen un significado especial dentro del lenguaje, son sus instrucciones más básicas, y no se pueden utilizar para nada mas (listas para C#, C++ y Java). En segundo lugar, los símbolos, que pueden ser operadores (C++: =
, +
, -
, …), delimitadores (C++: [
, ]
, (
, )
, {
,…), comentarios (C++: /* */
, //
) o directivas de preprocesado, que son ordenes especiales para el compilador (C++: #
). En tercer lugar, los identificadores, que nos permiten dar nombres a constantes, variables y procedimientos (en C++ aparecen caracteres alfanuméricos, es decir, letras y números junto con el símbolo _
. Han de empezar por una letra o por _
y se distinguen las mayúsculas de las minúsculas). Finalmente, tenemos los valores constantes: numéricos (3.56
), carácter ('b'
) o cadena ("hola"
).
Las variables son «cajas» donde vamos a poder almacenar datos. El tipo de dato que almacenan va a ser fijo, pero el valor puede ser «variable», de aquí su nombre. Estas cajas se corresponden con zonas de memoria accesibles mediante nombre. Se identifican con un nombre y tienen cuatro atributos: su tipo, su valor, su ámbito y su tiempo de vida. Con ella podemos consultar (indirección) su valor o modificarlo (asingación). En la mayoria de lenguajes se tienen que declarar (se fija el tipo y el nombre) antes de utilizarlas (C++: float a, b=1.2, c;
).
Las constantes, a diferencia de las variables, almacenan un valor de un tipo que ya no se podrá modificar (C++: const double PI = 3.141592;
). Ayudan a la legibilidad del programa, a su mantenimiento…
Vamos a hablar de programación en lenguajes de alto nivel.
Para empezar, repasamos los conceptos de algoritmo y de programa.
Un algoritmo es una secuencia de pasos a seguir para resolver un problema. Es un concepto previo a la programación (algoritmo de multiplicación, algoritmo de Euclides, etc.). La secuencia tiene que ser finita, y el tiempo de ejecución (y por lo tanto, cada uno de los pasos) también. Generará una o más resultados (salidas) y necesitará ninguno o más datos (entradas) para poder generar los primeros.
Un programa es la traducción de un algoritmo a un lenguaje de programación, es decir, a un lenguaje que un ordenador «entiende».
Por ejemplo, en el caso del algoritmo de Euclides, que calcula el MCD de dos números A y B, utilizamos las propiedad 1) MCD(D,d) = MCD(d,r), donde D es el Dividendo, d es el divisor y r es el resto de la división entera entre D y d. Y que, si r=0 entonces MCD(d,r)=d. Con esto, un posible algoritmo sería:
Datos de entrada: dos enteros A y B
Datos de salida: el MCD
1.- Calcular el resto r de dividir A entre B
2.- Si la r es 0, el MCD es B y acabamos
3.- Colocamos el valor de B en A y el de r en B
4.- Volvemos a 1
Fijémonos que, la primera vez que se ejecuta el paso 1, en el caso de que B fuera mayor que A, el calculo de la división entera hace el swap entre las dos variables.
Ya veremos mas adelante que evitaremos sentencias del tipo 4 (equivalentes al GOTO) simplemente utilizando un bucle.
Con respecto a las fases de creación de programas, hemos visto el modelo en cascada, utilizado en ingeniería del software. La fase de análisis contesta a la pregunta de que debe hacer mi programa, la de diseño a como debo hacerlo (describir el algoritmo) y la implementación no es mas que la traducción de nuestro algoritmo a un programa. La fase de validación consiste en eliminar errores (que pueden ser léxicos, sintácticos o semánticos y que nos harán volver a alguna de las fases anteriores).
Para terminar, y con respecto a la representación de algoritmos (necesaria en el diseño de los mismos) utilizaremos pseudocódigo, aunque también podríamos hacerlo mediante el uso de diagramas de flujo u organigramas. Al final necesitamos una representación (textual o gráfica) de las estructuras secuencial, alternativa e iterativa junto con las operaciones de entrada/salida de los datos.
Un ordenador o computador es una máquina (electrónica) de propósito general: sirve para muchas cosas en función del programa que ejecute. Ordenador viene de ordenar, y computador viene de computar. Básicamente, lo que queremos es resolver problemas.
Un algoritmo es una secuencia ordenada de pasos. La idea existe de mucho antes que los ordenadores: algoritmo de Euclides (como calcular el MCD de dos números, propuesto a.C.), la formula de la ecuación de segundo grado es un algoritmo. Pero una receta de cocina también es un algoritmo.
Un programa es la codificación de un algoritmo de manera que pueda ser llevado a cabo por un ordenador. Se debe escribir en un lenguaje que un ordenador entienda. Los lenguajes de programación son «idiomas» que entiende un ordenador. Como cualquier otro lenguaje, tienen un léxico (palabras del lenguaje), tienen una sintaxis (reglas para construir frases) y poseen una semántica.
Todos los ordenadores actuales están basados en la máquina de Von Neumann: Hay una Unidad Central de Proceso (CPU), una Memória (M) y unos dispositivos de Entrada/Salida (E/S) todos interconectados mediante un Bus. Todo esto forma el hardware (la parte tangible) del ordenador. Pero hay toda una parte no tangible, el software, necesaria para el funcionamiento de mismo: los programas de los que hablábamos.
La CPU es el «cerebro» del computador, o sea, es la que sabe hacer las cosas. Por una parte, sabe hacer cálculos (aritméticos, como sumas, restas, … y lógicos, como and, or, not, etc.), mediante la Unidad Aritmetico-Lógica (ALU), que forma parte de la Unidad de Proceso (PU). Por otra, es la que marca el ciclo de ejecución de las instrucciones, conteniendo la Unidad de Control (CU).
En la memoria es donde se almacena la información. La información fundamental que se guardan son los programas. Pero además, estos programas necesitan datos. Toda esta información está codificada.
Los dispositivos de E/S nos permiten hacer del computador un sistema abierto, ya que nos permite, por una parte, introducir nueva información al sistema, mediante los dispositivos de entrada (un teclado, un ratón, …), y por otra, que el sistema nos pueda hacer llegar la información procesada, mediante los dispositivos de salida (pantalla, …).
El bus permite el flujo de información entre los diferentes componentes.
Con respecto al software, tenemos de dos tipos: software de sistema, necesario para el funcionamiento del mismo: programa de arranque, el sistema operativo, compiladores, depuradores, herramientas de mantenimiento y diagnostico; software de usuario, cualquier programa/aplicación útil para resolver un problema determinado: editor de textos, gestor de bases de datos, navegador, hoja de calculo, herramientas CAD/CAM, etc.