Voy a resolver el problema que indicamos en la sesión anterior, que era calcular la matriz de cambio de base entre dos bases cualesquiera en $\ℝ^2=\ℝ$x$\ℝ$. En esa entrada previa vimos el caso particular en que una de las bases es la cánonica, es decir la dada por los vectores $e_1=(1,0)$ y $e_2=(0,1)$. Pero esto ya nos da una idea de como resolver el problema entre dos bases arbitrarias $u=(u_1,u_2)$, $v=(v_1,v_2)$. Pasamos de u a la base canónica y de esta a v.
Creando un projecto
Lo primero es crear el projecto:
> dune init project ocaml5
y vamos a editar el código inicialmente en bin/main.ml
. Y el archivo dune será:
(executable
(public_name ocaml5)
(name main)
(libraries ocaml5 owl)
(flags (:standard -warn-error "-unused-value-declaration")))
Y vamos a compilar con dune build
y ejecutar con _build/install/default/bin/main.exe
Solución con comentarios
(* -- Objectivo:
dar las coordenadas de un vector en una nueva base conociendo
las coordenadas en otra base y ambas bases.
-- Input:
base_u = u1, u2
base_v = v1, v2
c_vect_u = (a1, a2) -> coordenadas en base u
-- Output:
c_vect_v = (b1, b2) -> coordenadas en base v
m_uv = matriz de cambio de base
-- Estrategia:
Para hacerlo pasamos primero de la base u a la base canonica
y desde esta a la base v.
*)
(* Expresamos u1 y u2 en la base canonica, recordar que si ponemos
estos vectores como columnas tendremos la matriz de cambio de base
de un vector a la base (u1,u2). n es la dimension de los vectores *)
let m_BxBc x1 x2 =
let x1_x2 = Owl_utils_array.concat [x1 ; x2] in
Owl.Mat.of_array x1_x2 2 2
let m_BcBx x1 x2 = Owl.Mat.( inv (m_BxBc x1 x2) )
(* Expresamos la matriz de cambio de base de (u1,u2) a (v1,v2) como el
el cambio de base de (u1,u2) -> (e1, e2) -> (v1,v2).
El primer cambio esta dado por: m_BxBc u1 u2
El segund cambio esta dado por: (m_BxBc v1 v2)^(-1) es decir la matriz
inversa que podemos calcular con la funciton m_BcBx v1 v2 *)
let m_BuBv u1 u2 v1 v2 =
let mBB_uc = m_BxBc u1 u2 in
let mBB_cv = m_BcBx v1 v2 in
Owl.Mat.(mBB_uc *@ mBB_cv)
(* Ejemplo ----------------------------- *)
(* Base u1,u2 *)
let u1 = [| 4.0; 0.0 |]
let u2 = [| 0.0; -3.0 |]
(* Base v1,v2 *)
let v1 = [| -2.0; 0.0 |]
let v2 = [| 0.0; 1.0 |]
(* Vector input en base u1,u2 *)
let vec_u = Owl.Mat.of_array [| 1.0; 2.0 |] 2 1
(* Como el vector u tiene coordenadas 1.0 2.0, sabemos de
antemano que debe tener coordendas 4.0, -6.0 en la base
canónica. Como la segunda base tiene signos opuestos y
escala v1 con un factor 2, el resultado debe ser
-2.0, -6.0. Veamos que es así. *)
(* Matriz de cambio de base u1,u2 a base v1,v2 *)
let mBB_uv = m_BuBv u1 u2 v1 v2
(* Solucion de vector en base v1,v2 *)
let vec_v = Owl.Mat.(mBB_uv *@ vec_u)
let () = print_endline "Programa de matriz de cambio de base en RxR:";
Owl.Mat.(mBB_uv |> print) ; flush_all() ;
Owl.Mat.(vec_u |> print) ; flush_all() ;
Owl.Mat.(vec_v |> print) ; flush_all() ;
El código anterior funciona, y no sería dificil hacer una extensión que tenga vectores de n elementos, es decir, vectores de $\ℝ^n$. Podemos hacer que nuestras funciones acepten un array de n arrays (cada uno de dimension n). Pero tendríamos que tener cuidado, ya que habría que comprobar que la base que introducimos es realmente una base, es decir, que forman un conjunto de n vectores linearmente independientes. Sino es el caso deberemos indicar que bases introducidas son incorrectas, y tal vez dar el número de vectores linearmente independientes. Pero creo que para próximas sesiones puede ser más util explorar otras partes de la libreria Owl.