Empezamos aplicando el algoritmo a la ecuación del calor en una dimensión:

u_t - \alpha u_{xx} = 0

Con difusividad térmica \alpha = 1. Así pues, tenemos que:

F(t,x,u,u_t,u_{tt},u_{tx},u_{xx}) = u_t - u_{xx}

o, más en concreto:

F(u_t,u_{xx}) = u_t - u_{xx}

Para empezar, k=2 es el orden de la máxima derivada y \sigma = 1 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: X^{(k)}F^\sigma = 0.

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.

X^{(k)} F^\sigma (\pmb{x},\pmb{u},\partial \pmb{u},\ldots,\partial^k \pmb{u}) = 0

El grupo de Lie uniparamétrico de transformaciones

\pmb{x}^{*} = X(\pmb{x},\pmb{u};\varepsilon),

\pmb{u}^{*} = U(\pmb{x},\pmb{u};\varepsilon)

deja invariante un sistema de PDEs F^\sigma = (\pmb{x}, \pmb{u}, \partial \pmb{u},\partial^2 \pmb{u}, \ldots ,\partial^k \pmb{u}) (o, equivalentemente, es un punto de simetrias admitido por el mismo sistema) si y solo si su extensión k-ésima

(u^\mu_i)^* = U^\mu_i(\pmb{x},\pmb{u},\partial \pmb{u};\varepsilon) = u_i^\mu + \varepsilon \eta_i^{(1)\mu}(\pmb{x},\pmb{u},\partial \pmb{u}) + O(\varepsilon^2)

\vdots

(u^\mu_{i_1,i_2,\ldots,i_k})^* = U^\mu_{i_1,i_2,\ldots,i_k}(\pmb{x},\pmb{u},\partial \pmb{u},\ldots,\partial^k \pmb{u};\varepsilon) =

= u_{i_1,i_2,\ldots,i_k}^\mu + \varepsilon \eta_{i_1,i_2,\ldots,i_k}^{(k)\mu}(\pmb{x},\pmb{u},\partial \pmb{u},\ldots,\partial^k \pmb{u}) + O(\varepsilon^2)

deja invariante las N superficies en el espacio (\pmb{x},\pmb{u},\partial \pmb{u},\partial^2 \pmb{u}), \ldots, \partial^k \pmb{u} definido por dicho sistema de PDEs.

El correspondiente generador de la extensión infinitesimal k-ésima del grupo de Lie de transformaciones (compuesto por \pmb{x}^{*}, \pmb{u}^{*},  (u^\mu_i)^*, \ldots, (u^\mu_{i_1,i_2,\ldots,i_k})^*) se define como

X^{(k)} = \xi_i(\pmb{x},\pmb{u}) \frac{\partial}{\partial x_i} + \eta^\mu(\pmb{x},\pmb{u}) \frac{\partial}{\partial u^\mu} + \eta^{(1)\mu}_i(\pmb{x},\pmb{u},\partial \pmb{u}) \frac{\partial}{\partial u_i^\mu} + \ldots

\ldots + \eta^{(k)\mu}_{i_1,i_2,\ldots,i_k}(\pmb{x},\pmb{u},\partial \pmb{u},\ldots,\partial^k \pmb{u}) \frac{\partial}{\partial u^\mu_{i_1,i_2,\ldots,i_k}}

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:

\pmb{x^*} = X(\pmb{x},\pmb{u};\varepsilon) = \pmb{x} + \varepsilon \pmb{\xi}(\pmb{x},\pmb{u}) + O(\varepsilon^2)

\pmb{u^*} = U(\pmb{x},\pmb{u};\varepsilon) = \pmb{u} + \varepsilon \pmb{\eta}(\pmb{x},\pmb{u}) + O(\varepsilon^2)

Las transformaciones extendidas son:

(u^\mu_i)^* = U^\mu_i(\pmb{x},\pmb{u},\partial \pmb{u};\varepsilon) = u_i^\mu + \varepsilon \eta_i^{(1)\mu}(\pmb{x},\pmb{u},\partial \pmb{u}) + O(\varepsilon^2)

\vdots

(u^\mu_{i_1,i_2,\ldots,i_k})^* = U^\mu_{i_1,i_2,\ldots,i_k}(\pmb{x},\pmb{u},\partial \pmb{u},\ldots,\partial^k \pmb{u};\varepsilon) =

= u_{i_1,i_2,\ldots,i_k}^\mu + \varepsilon \eta_{i_1,i_2,\ldots,i_k}^{(k)\mu}(\pmb{x},\pmb{u},\partial \pmb{u},\ldots,\partial^k \pmb{u}) + O(\varepsilon^2)

donde las funciones n_i^{(1)\mu}, \ldots, n_{i_1,i_2,\ldots,i_k}^{(k)\mu} son las k-ésimas extensiones infinitesimales, el número del paréntesis indica el orden de la derivada y se calculan como:

n_i^{(1)\mu} = D_i \eta^\mu - (D_i \xi_j)u_j^\mu,

n_{i_1,i_2,\ldots,i_k}^{(k)\mu} = D_{i_k} \eta^{(k-1)\mu}_{i_1,i_2,\ldots,i_k} - (D_{i_k} \xi_j)u^\mu_{i_1,i_2,\ldots,i_k}

para i_j = 1, 2, \ldots, n y j=1,2,\ldots,k, con k \geq 2 y donde el operador D_i es el operador derivada total definido como:

D_i = \frac{\partial}{\partial x_i} + u_i^\mu \frac{\partial}{\partial u^\mu} + u_{ij}^\mu \frac{\partial}{\partial u_j^\mu} + \ldots + u^\mu_{i_1,i_2,\ldots,i_k} \frac{\partial}{\partial u^\mu_{i_1,i_2,\ldots,i_k}} + \ldots

Tenemos ahora

\pmb{x^*} = X(\pmb{x},\pmb{u};\varepsilon) = \pmb{x} + \varepsilon \pmb{\xi}(\pmb{x},\pmb{u}) + O(\varepsilon^2)

\pmb{u^*} = U(\pmb{x},\pmb{u};\varepsilon) = \pmb{u} + \varepsilon \pmb{\eta}(\pmb{x},\pmb{u}) + O(\varepsilon^2)

donde \pmb{\xi}(\pmb{x},\pmb{u}) y \pmb{\eta}(\pmb{x},\pmb{u}) son los infinitesimales de variables independientes y dependientes. Como generador infinitesimal tenemos:

X = \xi_i(\pmb{x},\pmb{u}) \frac{\partial}{\partial x_i} + \eta_j(\pmb{x},\pmb{u})\frac{\partial}{\partial u_j}

Sean \pmb{x} = (x_1, x_2, \ldots , x_n) las n variables independientes y \pmb{u} = (u^1,u^2,\ldots,u^m) las m variables dependientes del sistema de PDEs que dependen de las variables independientes (superíndices indicando componentes).

Entonces, las N ecuaciones del sistema de PDEs pueden representarse como

F^\sigma = (\pmb{x}, \pmb{u}, \partial \pmb{u},\partial^2 \pmb{u}, \ldots ,\partial^k \pmb{u})

con \sigma = 1, 2, \ldots, N, donde k indica la derivada más alta que aparece en la PDE y \partial^l \pmb{u} representa todas las posibles derivadas de cualquier u^i con respecto cualquier combinación de x_j. Por ejemplo, para las primeras derivadas tenemos:

\partial \pmb{u} = (\frac{\partial u^1}{\partial x_1},\ldots,\frac{\partial u^1}{\partial x_n},\frac{\partial u^2}{\partial x_1},\ldots,\frac{\partial u^2}{\partial x_n},\ldots,\frac{\partial u^m}{\partial x_1},\ldots,\frac{\partial u^m}{\partial x_n})

Y también la notación para derivadas superiores:

u^{\mu}_{i_1 i_2 \ldots i_k} = \frac{\partial^k u^\mu}{\partial x_{i_1},\ldots,\partial x_{i_k}}

con \mu = 1,\ldots,m, i_j=1,\ldots,n, j=1,\ldots,k.

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 F(\pmb{x}) \in C^{\infty}, diremos que es una función invariante del grupo de Lie de tranformaciones \pmb{x^*}=\pmb{X}(\pmb{x};\varepsilon) si y sólo si para cualquier grupo de transformaciones del grupo se cumple que

F(\pmb{x^*}) = F(\pmb{x})

Existen un teorema al respecto que nos dice que F(\pmb{x}) es invariante bajo un grupo de Lie de transformaciones si y sólo si \pmb{X}F(\pmb{x})=0.

Por ejemplo, dada la función F(x,y)=\frac{x^2}{y}, és invariante bajo el grupo de escalados. El grupo de escalados representa escalados de las variables en los ejes x e y:

x^* = \alpha x,

y^* = \alpha^2 y,

con \alpha \in (0,\infty), ley de composición \phi(\alpha, \beta) = \alpha \beta y elemento identidad \alpha = 1. Para que sea un grupo de Lie uniparamétrico, necesitamos que la identidad sea 0, por lo que necesitamos hacer una reparametrización \varepsilon = \alpha -1, de manera que:

x^* = (1+\varepsilon)x,

y^* = (1 + \varepsilon)^2 y,

y con \phi(\alpha,\beta) =\alpha \beta = (1+\varepsilon)(1+\delta) = 1 + \varepsilon + \delta + \varepsilon \delta  y \varepsilon = 0.

Por el post anterior, podemos identificar al grupo de Lie \pmb{x^*}=\pmb{X}(\pmb{x};\varepsilon) con \frac{d}{d \varepsilon} \pmb{x^*} = \pmb{\xi}(\pmb{x^*}) donde \pmb{x^*} = \pmb{x} en \varepsilon = 0. Además, \pmb{x^*}=\pmb{X}(\pmb{x};\varepsilon) también puede escribirse como

\pmb{x^*} = e^{\varepsilon X} \pmb{x} =  \pmb{x} + \varepsilon X \pmb{x} + \frac{1}{2} \varepsilon^2 X^2 \pmb{x} + \ldots =

donde X = X(\pmb{x}) es el generador infinitesimal y X^k = X^k{\pmb{x}} viene dado por X^k = X X^{k-1}.

Aplicamos al grupo traslacion…

El operador

X = X(\pmb{x}) = \pmb{\xi}(\pmb{x}) \cdot \nabla = \sum_{i=1}^{n} \xi_i(\pmb{x})_{x_i} (=\sum_{i=1}^{n} \xi_i(\pmb{x}) \frac{\partial}{\partial x_i})

donde \nabla es el operador gradiente:

\nabla = (\frac{\partial}{\partial x_1},\frac{\partial}{\partial x_2},\ldots,\frac{\partial}{\partial x_n})

Dada una función diferenciable F(\pmb{x}) = F(x_1,x_2,\ldots,x_n), la aplicación del operador X queda:

XF(\pmb{x}) = \pmb{\xi}(\pmb{x}) \cdot \nabla F(\pmb{x}) =\sum_{i=1}^{n} \xi_i(\pmb{x}) \frac{\partial}{\partial x_i} F(\pmb{x})

Para el caso particular de F(\pmb{x}) = \pmb{x} tenemos que X \pmb{x} = \pmb{\xi}(\pmb{x}).

Dado el grupo de Lie uniparamétrico de transformaciones \pmb{x^*}=\pmb{X}(\pmb{x};\varepsilon) (1), existe una parametrización \tau(\varepsilon) 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:

\pmb{x^*}_\tau = \pmb{\xi}(\pmb{x^*})

con \pmb{x^*} = \pmb{x} cuando \tau = 0 (recordemos la notación que estamos utilizando para las derivadas: \pmb{x^*}_\tau \equiv \frac{\partial}{\partial \tau}\pmb{x^*}).

En particular,

\tau(\varepsilon) = \int_{}^{} \Gamma(\varepsilon ') d\varepsilon '

donde

\Gamma(\varepsilon) = \phi(a,b)_b |_{(a,b)=(\varepsilon^{-1},\varepsilon)}

Como ejemplo, imaginemos el grupo de translaciones en el eje de las x:

x^{*} = x + \varepsilon

y^{*} = y

donde la ley de composición \phi(a,b) es a + b y \varepsilon^{-1} = -\varepsilon. Si \pmb{x} = (x,y) entonces \pmb{X}(\pmb{x};\varepsilon) = (x+\varepsilon,y) y

\pmb{\xi}(\pmb{x}) = \pmb{X}(\pmb{x};\varepsilon)_\varepsilon |_{\varepsilon=0} = (x+\varepsilon,y)_\varepsilon |_{\varepsilon = 0} = (1,0)

Llegados a este punto, dado el problema de valor inicial

x^*_\varepsilon = 1

y^*_\varepsilon = 0

con x^* = x, y^*=y en \varepsilon = 0, por el primer teorema fundamental de Lie, el grupo de transformaciones:

x^{*} = x + \varepsilon

y^{*} = y

es solución del mismo.

Dado un grupo de Lie uniparamétrico de transformaciones \pmb{X}(\pmb{x},\varepsilon) (donde hemos cambiando el punto y coma por otra coma) con identidad 0 y ley de composición \phi, podemos desarrollarla mediante Taylor, a primer orden, para varias variables , tenemos n+1 variables) alrededor de \varepsilon = 0.

\pmb{x^*} = \pmb{x} + \varepsilon \cdot (\pmb{X}_\varepsilon(\pmb{x};\varepsilon)|_{\varepsilon=0}) + O(\varepsilon^2)

Si definimos:

\pmb{\xi}(\pmb{x}) = \pmb{X}_\varepsilon(\pmb{x};\varepsilon)|_{\varepsilon=0}

como el infinitesimal del grupo de Lie uniparamétrico, podemos definir la transfomación infinitesimal como

\pmb{x^*} = \pmb{x} + \varepsilon \pmb{\xi}(\pmb{x})

La idea que hay detrás de los grupos infinitesimales, parece que originalmente atribuible a Lie, es que, hablando en un caso particular, rotar N grados (lo que nos interesa) es lo mismo que rotar N veces 1 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 \pmb{R}(\alpha) =  [ \pmb{R}(\frac{\alpha}{N})]^N

Una simetría de Lie o transformación de Lie es un grupo (matemáticamente hablando) de transformaciones con algunas propiedades.

Un grupo G es un conjunto de elementos con una ley de composición \phi tal que es cerrada, asociativa y posee elementos identidad e e inverso a^{-1} para cada elemento a.

Dado un \pmb{x} = (x_1,\ldots,x_n) en la región D \subset \mathbb{R}^n, el conjunto de transformaciones

\pmb{x^*}=\pmb{X}(\pmb{x};\varepsilon)

definido para cada \pmb{x} \in D y con parámetro \varepsilon \in S \subset \mathbb{R} y con \phi(\varepsilon,\delta) definiendo una ley de composición de parámetros \varepsilon y \delta. Tenemos un grupo uniparamétrico de transformaciones en D si a) sea cual sea el parametro \varepsilon en punto transformado \pmb{x^*} sigue en D, b) S con \phi forma un grupo G, c) si el parametro \varepsilon es el neutro e de G entonces el punto sobre el que aplicamos la transformación no varía \pmb{X}(\pmb{x};e) = \pmb{x} ; y si \pmb{x^*} = \pmb{X}(\pmb{x};\varepsilon) y \pmb{x^{**}} = \pmb{X}(\pmb{x^*};\delta) entonces \pmb{x^{**}} = \pmb{X}(\pmb{x};\phi(\varepsilon,\delta)).

Además, tendremos un grupo de Lie uniparamétrico de transformaciones si a) \varepsilon es un parámetro continuo, b) \pmb{X} es C^\infty y analítica de \varepsilon en S y c) \phi(\varepsilon,\delta) es una función analítica de \varepsilon y de \delta.

Ejemplos en el plano, para entender la nomenclatura, podrian ser 1) rotación de angulo \alpha alrededor del origen: \pmb{R}(\alpha) = \pmb{R}(\pmb{x};\alpha) (SO(n)); 2) translacion a distancia d: \pmb{T}(d) = \pmb{T}(\pmb{x};d) en donde \phi seria la suma de reales y 0 el neutro (si tuvieramos escalados, la operación sería el producto y necesitariamos un cambió de variable para que el neutro 1 se trasladara a 0). Con esta notación, podriamos reescribir \pmb{X}(\pmb{x};\varepsilon) como \pmb{X}_\varepsilon. 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 u_t-u_{xx} = 0, y la ecuación que describe el comportamiento del medio viscoelástico u_{xx}+c u_{xxt} = g(u)_{tt}.

Sabemos que, de forma general,

F(t,x,u,u_t,u_x,u_{tt},u_{tx},u_{xt},u_{xx})=u_t - u_{xx}

y

F(t,x,u,u_t,u_x,u_{tt},u_{tx},u_{xx},u_{ttt},u_{ttx},u_{txt},u_{txx},u_{xtt},u_{xtx},u_{xxt},u_{xxx})

=u_{xx}+c u_{xxt}

Recordemos que, bajo ciertas condiciones de continuidad y diferenciabilidad, existe commutatividad en las derivadas de orden superior, es decir:

F_{x_{i_k} \ldots x_{i_1}} = F_{x_{j_k} \ldots x_{j_1}}

donde i_1,\ldots,i_k,j_1,\ldots,j_k \in \{1,\ldots,n\} si cada entero de 1 a n aparece la misma cantidad de veces en i_1,\ldots,i_k que en j_1,\ldots,j_k.

Así pues, en realidad, tenemos:

F(t,x,u,u_t,u_x,u_{tt},u_{tx},u_{xx})=u_t - u_{xx}

y

F(t,x,u,u_t,u_x,u_{tt},u_{tx},u_{xx},u_{ttt},u_{ttx},u_{txx},u_{xxx})=u_{xx}+c u_{xxt}

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 t no aparece explícitamente en la parte derecha de la EDO (\dot{x}=ax). Es no-autónomo cuando si lo hace (\ddot{x}=-c x -\sin{x} + \rho \sin{t}).

El espacio de fases es el conjunto de todas las posibles configuraciones de un sistema. Si el sistema depende de un número n 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 n. A los espacios de fase también se les llama espacios de configuración.

Si estudiando un gas de n partículas en el espacio, su espacio de fases tiene 3n 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.

May 2024
L M X J V S D
 12345
6789101112
13141516171819
20212223242526
2728293031