#ifndef MXLIB_H_INCLUDED
#define MXLIB_H_INCLUDED

/** See mxlib.c for readme */

typedef struct matrix {
    int k; /* Number of rows */
    int n; /* Number of columns */
    double **d; /* Data */
} Matrix;

#include "mxlib.h"

/** ------------------------------------------------- */
/** ---------------- MATRIX CREATION ---------------- */
/** ------------------------------------------------- */

Matrix *Matrix_delete(Matrix *M);
Matrix *Matrix_create_nullmatrix(int k, int n);
Matrix *Matrix_create_unitmatrix(int n);
Matrix *Matrix_create(int k, int n, ...);

/** ------------------------------------------------- */
/** -------------- DISPLAYING MATRICES -------------- */
/** ------------------------------------------------- */

void Matrix_display(Matrix *M, int precision);
void Matrix_display_with_separator(Matrix *M, int precision, int separator_placement);

/** ------------------------------------------------- */
/** ---------------- FILE OPERATIONS ---------------- */
/** ------------------------------------------------- */

void Matrix_file_write(char *filename, Matrix *M);
Matrix *Matrix_file_read(char *filename, int k, int n);

/** ------------------------------------------------- */
/** ------------- MATRIX ROW OPERATIONS ------------- */
/** ------------------------------------------------- */

Matrix *Matrix_row_multiply(Matrix *M, int i, double c);
Matrix *Matrix_row_add(Matrix *M, int i1, int i2);
Matrix *Matrix_row_multiply_and_add(Matrix *M, int i1, int i2, double c);
Matrix *Matrix_row_switch(Matrix *M, int i1, int i2);
Matrix *Matrix_row_delete(Matrix *M, int i);

/** ------------------------------------------------- */
/** -------------- GAUSSIAN ELIMINATION ------------- */
/** ------------------------------------------------- */

int Matrix_linear_equations_solve(Matrix *M);
double Matrix_determinant(Matrix *M);

/** ------------------------------------------------- */
/** -------------- MISC MATRIX FUNCTIONS ------------ */
/** ------------------------------------------------- */

int Matrix_is_upper_triangular(Matrix *M);
int Matrix_is_lower_triangular(Matrix *M);
int Matrix_rank(Matrix *M);

/** ------------------------------------------------- */
/** --------------- MATRIX OPERATIONS --------------- */
/** ------------------------------------------------- */

Matrix *Matrix_copy(Matrix *M);
Matrix *Matrix_add(Matrix *A, Matrix *B);
Matrix *Matrix_subtract(Matrix *A, Matrix *B);
Matrix *Matrix_multiply_by_scalar(Matrix *M, double c);
Matrix *Matrix_transpose(Matrix *M);
Matrix *Matrix_multiply(Matrix *A, Matrix *B);
Matrix *Matrix_inverse(Matrix *M);
Matrix *Matrix_augment(Matrix *A, Matrix *B);

/** ------------------------------------------------- */
/** ----------- ADVANCED MATRIX FUNCTIONS ----------- */
/** ------------------------------------------------- */

void Matrix_adv_display(int delM, Matrix *M, int precision);
void Matrix_adv_display_with_separator(int delM, Matrix *M, int precision, int separator_placement);
Matrix *Matrix_adv_add(short delA, Matrix *A, short delB, Matrix *B);
Matrix *Matrix_adv_subtract(short delA, Matrix *A, short delB, Matrix *B);
Matrix *Matrix_adv_multiply_by_scalar(short delM, Matrix *M, double c);
Matrix *Matrix_adv_transpose(short delM, Matrix *M);
Matrix *Matrix_adv_multiply(short delA, Matrix *A, short delB, Matrix *B);
Matrix *Matrix_adv_inverse(int delM, Matrix *M);
Matrix *Matrix_adv_augment(int delA, Matrix *A, int delB, Matrix *B);

#endif // MXLIB_H_INCLUDED
