#ifndef _MAT_VEC_H
#define __MAT_VEC_H

//Parameters
#define MAX_ZZ_SIZE 10
#define MAX_INT_PART_SIZE 14  // 0-99 / byte
#define MAX_DEC_PART_SIZE 16  // 0-99 / byte
#define MAX_TAYLOR_TIMES 20
#define PI_DOUBLE 3.141593


#define MAX_VECTOR_SIZE 1000
#define MAX_ROW_SIZE 50
#define MAX_COLUMN_SIZE 50

#include <stdio.h>
#include <stdlib.h>

//ZZ, RR, vec, mat


typedef struct vec_ZZ_p {
	char column_flag;
	unsigned long long length;
	int *entry[MAX_VECTOR_SIZE];
} vec_ZZ_p;


typedef struct mat_ZZ {
	unsigned long long row_size;
	unsigned long long column_size;
	ZZ *entry[MAX_ROW_SIZE][MAX_COLUMN_SIZE];
} mat_ZZ;



void print_ZZ(ZZ a);
void print_RR(RR a);

//Computation
ZZ Long_Long_to_ZZ(long long a);
RR Double_to_RR(double a);
double RR_to_Double(RR a);
ZZ RR_to_ZZ(RR a);
RR ZZ_to_RR(ZZ a);
ZZ RR_Round_to_ZZ(RR a);

ZZ negate_ZZ(ZZ a);
RR negate_RR(RR a);

char compare_ZZ_ZZ(ZZ a, ZZ b);
char compare_RR_RR(RR a, RR b);

ZZ add_ZZ_ZZ(ZZ a, ZZ b);
RR add_RR_RR(RR a, RR b);
ZZ sub_abs_ZZ_ZZ(ZZ a, ZZ b);
RR sub_abs_RR_RR(RR a, RR b);
ZZ mul_ZZ_ZZ(ZZ a, ZZ b);
RR mul_RR_RR(RR a, RR b);
ZZ div_ZZ_ZZ(ZZ a, ZZ b, ZZ *remainder);
RR div_RR_RR(RR a, RR b);
RR div_INT_RR_RR(RR a, RR b);	//without decimal part
ZZ mod_ZZ_ZZ(ZZ a, ZZ b);
RR power_RR(RR a, long b);
RR sqrt_RR(RR a);
RR cos_RR(RR a);
RR ln_RR(RR a);

//vec & mat
//Input

//Output

void print_vec_ZZ(vec_ZZ a);
void print_vec_RR(vec_RR a);

void print_mat_ZZ(mat_ZZ a);
void print_mat_RR(mat_RR a);

//Computation
vec_ZZ vec_RR_to_vec_ZZ(vec_RR a);
vec_RR vec_ZZ_to_vec_RR(vec_ZZ a);

mat_ZZ mat_RR_to_mat_ZZ(mat_RR a);
mat_RR mat_ZZ_to_mat_RR(mat_ZZ a);

mat_ZZ transpose_mat_ZZ(mat_ZZ a);
mat_RR transpose_mat_RR(mat_RR a);

vec_ZZ add_vec_ZZ_vec_ZZ(vec_ZZ a, vec_ZZ b);
vec_RR add_vec_RR_vec_RR(vec_RR a, vec_RR b);
vec_ZZ sub_vec_ZZ_vec_ZZ(vec_ZZ a, vec_ZZ b);
vec_RR sub_vec_RR_vec_RR(vec_RR a, vec_RR b);
vec_ZZ mul_scalar_vec_ZZ(vec_ZZ a, ZZ b);
vec_RR mul_scalar_vec_RR(vec_RR a, RR b);

mat_ZZ add_mat_ZZ_mat_ZZ(mat_ZZ a, mat_ZZ b);
mat_RR add_mat_RR_mat_RR(mat_RR a, mat_RR b);
mat_ZZ sub_mat_ZZ_mat_ZZ(mat_ZZ a, mat_ZZ b);
mat_RR sub_mat_RR_mat_RR(mat_RR a, mat_RR b);
mat_ZZ mul_scalar_mat_ZZ(mat_ZZ a, ZZ b);
mat_RR mul_scalar_mat_RR(mat_RR a, RR b);

mat_ZZ mul_mat_ZZ_mat_ZZ(mat_ZZ a, mat_ZZ b);
mat_RR mul_mat_RR_mat_RR(mat_RR a, mat_RR b);

vec_ZZ mul_mat_ZZ_column_vec_ZZ(mat_ZZ a, vec_ZZ b);    //ONLY COLUMN VECTOR
vec_RR mul_mat_RR_column_vec_RR(mat_RR a, vec_RR b);    //ONLY COLUMN VECTOR

#endif
