Ejercicio obligatorio 2

Fecha de entrega: Lunes 4 de mayo

Nota

Nunca es buena idea empezar por un ejercicio integrador antes de tener practicados los temas que el trabajo integra.

Se sugiere antes de desarrollar este trabajo resolver, al menos, los siguientes ejercicios de la guía de Memoria dinámica:

  • Ejercicio 12 (combinar vectores).

  • Ejercicio 14.a (matriz identidad).

  • Ejercicio 16 con el 1.b y 1.c de la guía de estructuras (dirección y persona).

Introducción

Queremos modelar una matriz, para ello definimos la estructura:

typedef struct {
    float *m;
    size_t filas, columnas;
} matriz_t;

que permite almacenar en memoria una matriz según el siguiente esquema:

../_images/20261_ej2.png

Trabajo

Creación y destrucción

Se pide implementar una función auxuliar matriz_t *_matriz_crear(size_t n, size_t m); que genere la memoria necesaria para almacenar una matriz de n x m valores. Los valores no deben ser inicializados. La función debe devolver la matriz creada o NULL en caso de falla.

Se pide implementar la función void matriz_destruir(matriz_t *matriz); que libere la memoria asociada a la matriz previamente creada.

Acceso a los datos

Se pide implementar una función size_t matriz_filas(const matriz_t *matriz); que devuelva el número de filas de la matriz.

Se pide implementar una función size_t matriz_columnas(const matriz_t *matriz); que devuelva el número de columnas de la matriz.

Se pide implementar una función void matriz_dimensiones(const matriz_t *matriz, size_t *filas, size_t *columnas); que devuelva por la interfaz la cantidad de filas y de columnas de la matriz.

Se pide implementar una función float matriz_obtener(const matriz_t *matriz, size_t fila, size_t columna); que devuelva el valor almacenado en la posición fila, columna de la matriz.

Se pide implementar una función void matriz_establecer(matriz_t *matriz, size_t fila, size_t columna, float valor); que establezca el valor en la posición fila, columna de la matriz.

Nota

Siendo que la matriz está linealizada en el arreglo, en principio no puede accederse con sintaxis de doble corchete.

Ahora bien, si el arreglo se asigna sobre un puntero de tipo float (*m)[columnas] puede utilizarse m como una matriz.

Es indistinto para este trabajo si se elige sintaxis de vectores o de matrices para acceder a los elementos individuales.

Creación de matrices

Implementar una función matriz_t *matriz_crear_mn(size_t n); que devuelva una matriz \(M^n\) como la de la función inicializar() del EJ1.

Implementar una función matriz_t *matriz_crear_mc(double ac); que devuelva una matriz \(M_c\) como la siguiente:

../_images/20261_ej2_mc.png

Implementar una función matriz_t *matriz_crear_mb(double ab); que devuelva una matriz \(M_b\) como la siguiente:

../_images/20261_ej2_mb.png

Implementar una función matriz_t *matriz_crear_mt(const float vector[3]); que dado un vector \((x, y, z)\) devuelva una matriz \(M_t\) como la siguiente:

../_images/20261_ej2_mt.png

Nota

Notar que las cuatro matrices pedidas son muy similares a la matriz identidad, tal vez tenga sentido desarrollar una función auxiliar que cree una matriz identidad y luego modificar los valores que difieren de ella.

Multiplicación de matrices

Implementar una función matriz_t *matriz_multiplicar(const matriz_t *a, const matriz_t *b); que devuelva \(A\times B\). En caso de falla o de no ser compatibles las matrices recibidas debe devolver NULL.

Aplicar

Implementar una función matriz_t *matriz_aplicar(const matriz_t *matriz, const matriz_t *ps);. La matriz es una matriz de \(4\times4\) mientras que ps es de \(n\times3\). Cada una de las filas de ps es un vector p como los de la función aplicar_vector() del EJ1. La función debe aplicar la matriz en cada uno de los p, según las fórmulas del EJ1, y devolver una matriz de \(n\times2\) con cada uno de los vectores aplicados, quedándose sólo con las dos primeras columnas, o sea, las componentes \((x, y)\), ya sabemos que \(z = -1\) y podemos descartarlo.

Agregar fila

Implementar una función bool matriz_agregar_fila(matriz_t *matriz, float fila[]); que agregue una nueva fila en la matriz. Se asume que la fila tiene matriz->columnas elementos. La función debe devolver true si puede realizar la acción y false en caso contrario.

Programa

Implementar un programa que primero cree una matriz \(M = M^4 \times M_c \times M_t \times M_b\) con \(a_c = 0.1\), \(a_b = 0.3\) y el vector de \(M_t\) como \((0, 0, -50)\). (Mismos parámetros que el EJ1, para sorpresa de nadie.)

Luego que lea de stdin coordenadas de vectores en \(\mathbb R^3\) de a una por vez y las vaya almacenando en una matriz por filas.

Finalmente que aplique la matriz \(M\) a esos vectores e imprima sus coordenadas \(x, y\) por stdout.

La salida tendrá que ser exactamente igual a la del EJ1 para los mismos datos de entrada.

La matriz \(M\) debería dar {{0.950564, -0.099833 ,0.294044, 0.000000}, {0.095375, 0.995004, 0.029503, 0.000000}, {-0.295520, 0.000000, 0.955337, -50.000000}, {0.295520, 0.000000, -0.955337, 50.000000}}.

Entrega

Deberá entregarse el código fuente del programa desarrollado.

El programa debe:

  1. Compilar correctamente con los flags:

    -Wall -Werror -std=c99 -pedantic -fno-extended-identifiers
    
  2. y pasar Valgrind correctamente

La entrega se realiza a través del sistema de entregas.

El ejercicio es de entrega individual.