x3 - compactly storing banded matrices

  double amat[4][4] = {
    {-2,1,0,0},
    {2,-2,2,0},
    {0,3,-2,3},
    {0,0,4,-2}
  };
struct band_mat{
	long ncol;                  // matrix size (n × n)
	long nbrows;            // number of stored diagonals
	long nbands_up;    // diagonals above main
	long nbands_low;  // diagonals below main
	double *array;        // compact band storage
	
	// LAPACK-specific storage for solving
	long nbrows_inv;
	double *array_inv;
	int *ipiv;
};

tyedef struct band_mat band_mat;

int init_band_mat(band_mat *bmat, long nbands_lower, long nbands_upper, long n_columns) {
	bmat->nbrows = nbands_lower + nbands_upper + 1;
	bmat->ncol   = n_columns;
	bmat->nbands_up = nbands_upper;
	bmat->nbands_low= nbands_lower;
	bmat->array      = (double *) malloc(sizeof(double)*bmat->nbrows*bmat->ncol);
	bmat->nbrows_inv = bmat->nbands_up*2 + bmat->nbands_low + 1;
	bmat->array_inv  = (double *) malloc(sizeof(double)*(bmat->nbrows+bmat->nbands_low)*bmat->ncol);
	bmat->ipiv       = (int *) malloc(sizeof(int)*bmat->ncol);
	if (bmat->array==NULL||bmat->array_inv==NULL) {
		return 0;
  }  
  /* Initialise array to zero */
  long i;
  for (i=0;i<bmat->nbrows*bmat->ncol;i++) {
	bmat->array[i] = 0.0;
  }
  return 1;
};

void finalise_band_mat(band_mat *bmat) {
	free(bmat->array);
	free(bmat->array_inv);
	free(bmat->ipiv);
}
band_mat bmat;
long ncols = 4;
long nbands_low = 1;
long nbands_up = 1;
init_band_mat(&bmat, nbands_low, nbands_up, ncols);
 0   1   2   3  <- upper band
-2 -2 -2 -2  <- main diagonal
 2   3   4   0 <- lower band
/* get pointer to a location in the band matrix */
double *getp(band_mat *bmat, long row, long column) {
	int bandno = bmat->nbands_up + row - column;
	if(row<0 || column<0 || row>=bmat->ncol || column>=bmat->ncol ) {
		printf("Indexes out of bounds in getp: %ld %ld %ld \n",row,column,bmat->ncol);
		exit(1);
	}
	return &bmat->array[bmat->nbrows*column + bandno];
}

double setv(band_mat *bmat, long row, long column, double val) {
	*getp(bmat,row,column) = val;
	return val;
}

double getv(band_mat *bmat, long row, long column) {
	return *getp(bmat,row,column);
}
long i, j;
for(i=0; i<ncols; i++) {
	if(i > 0){setv(&bmat, i, i-1, 1.0 * (i + 1));};
	setv(&bmat, i, i, -2.0);
	if(i<ncols-1) {setv(&bmat,i,i+1,1.0*(i+1));}
	/* Uniform source term in heat equation */
	b[i] = 1.0;   
}
int solve_Ax_eq_b(band_mat *bmat, double *x, double *b) {
	/* copy bmat array into the temporary store */
	int i, bandno;
	for(i=0; i<bmat->ncol; i++) { 
		for (bandno=0; bandno<bmat->nbrows; bandno++) {
			  bmat->array_inv[bmat->nbrows_inv*i+(bandno+bmat->nbands_low)] = bmat->array[bmat->nbrows*i+bandno];
		}
		x[i] = b[i];
	}
	
	long nrhs = 1;
	long ldab = bmat->nbands_low*2 + bmat->nbands_up + 1;
	int info = LAPACKE_dgbsv( LAPACK_COL_MAJOR, bmat->ncol, bmat->nbands_low, bmat->nbands_up, nrhs, bmat->array_inv, ldab, bmat->ipiv, x, bmat->ncol);
	return info;
}