Multiple dispatch
Al hacer un desarrollo de Taylor \[f(x+\delta) = f(x) + f'(x) \delta + \delta^2 \left( \frac{f''(x)}{2} + ... \right)\] Para entender la derivada querríamos poder “tirar” los términos superiores
Sea \(\varepsilon\) un elemento formal no-nulo tal que \(\varepsilon^2=0\).
Podemos construir los números duales \(a + b \varepsilon\) con \(a,b \in \mathbb R\) y \(\varepsilon \notin \mathbb R\).
Ejemplo tomado de Video de Youtube del Prof Alan Edelman (MIT)
Creamos una estructura de pares \((a,b)\) y la nombramos Dual
El constructor se genera de manera automática
Extendemos las funciones suma y resta a este tipo de elementos
Bajo la premisa \(\varepsilon^2 = 0\), para multiplicar: \[(a+b\varepsilon)(c+d\varepsilon) = ac + (bc + ad)\varepsilon + bd \varepsilon^2 = ac + (bc + ad)\varepsilon.\]
Para dividir hay un truco sencillo \[ \frac{a+b\varepsilon}{c+d\varepsilon} = \frac{(a+b\varepsilon)(c-d\varepsilon)}{(c+d\varepsilon)(c-d\varepsilon)} = \frac{(a+b\varepsilon)(c-d\varepsilon)}{c^2-d^2 \varepsilon^2} = = \frac{(a+b\varepsilon)(c-d\varepsilon)}{c^2} \]
Finalmente \[ \frac{a+b\varepsilon}{c+d\varepsilon} = \frac{a}{c} + \frac{bc - ad}{c^2} \varepsilon \]
Nótese si \(f(x) = a + bx, g(x) = c + dx\) entonces \(\frac{d}{dx} \frac{f}{g} = \frac{bc - ad}{c^2}\).
Recordamos el conjunto de números complejos \(\mathbb C\) es
\(a + b i\) donde \(i \notin \mathbb R\)
y coincide con
\[ \mathbb R[x] / \langle x^2 + 1 \rangle \]
Del mismo modo, \(a + b \varepsilon\) donde \(\varepsilon \notin \mathbb R\) y \(\varepsilon^2 = 0\) es lo mismo que
\[ \mathbb R[x] / \langle x^2 \rangle \]
Definimos una variable llamada \(\varepsilon\)
Añadimos una función de convertir, por defecto
Con la construcción que hemos hecho, si f es una función racional \[ g(x + \varepsilon) = g(x) + g'(x) \varepsilon \]
Utilizando estos números duales, muchas funciones se pueden derivar de esta forma.
Por ejemplo, tomemos la raíz cuadrada con la formula babilonia
Los números duales están implementados en el paquete DualNumbers.jl
Hablaremos más adelante del paquete ForwardDiff.jl
Podemos extender gcd
a cualquier lugar con iszero
y mod
.
Queremos extender la funciones anteriores anterior, de modo que gcd
funcione sin cambios
Por esto julia es uno de los lenguajes con más reciclaje de código.
Creamos una estructura para polinomios de coeficientes reales.
Basta con almacenar los coeficientes
Creamos una estructura para polinomios, que almacena los coeficientes.
Añadimos un constructor que elimina los ceros
Vamos a hacer una función iszero
para polinomios
import Base: *
function *(a::Poly,b::Poly)
da = degree(a); db = degree(b);
prodcoeffs = zeros(da+db+1);
for k=0:(da+db)
rangei = max(0,k-db):min(k,da)
prodcoeffs[k+1] = sum( a.coeff[1 .+ rangei] .*
b.coeff[k+1 .- rangei]);
end
return Poly(prodcoeffs)
end
* (generic function with 373 methods)
mod
import Base: mod
function mod(a::Poly,b::Poly)
if degree(a) < 0 # El polinomio de grado negativo es el 0
error("¡No dividas por 0!")
end
r = a # En cada paso a = b × q + r
while degree(r) ≥ degree(b)
s = Poly([ zeros(degree(r)-degree(b)) ; lead(r)/lead(b) ])
r = r - s*b
end
return r
end
mod (generic function with 25 methods)
Lanzamos la función gcd ¡que nunca oyó hablar de polinomios! Y obtenemos