#ifndef _SINGULAR_SVD_H
#define _SINGULAR_SVD_H

#include "DiagonalMatrix.h"
#include "Matrix.h"
#include "Reflector.h"
#include "Rotator.h"
//#include "singular.h"

//#include <algorithm>
//#include <cassert>
//#include <tuple>

typedef struct Svd Svd_t;
struct Svd {
	//USV decomposeUSV(const Matrix< M, N >& m) 
	bool (*isFullRank)(Svd_t *p, DiagonalMatrix_t singularValues, const int size);
};

typedef struct class_BidiagonalMatrix BidiagonalMatrix_t;
struct class_BidiagonalMatrix {
	double* pBlock;
	double (*operator)(struct class_BidiagonalMatrix *p, int i, int j);
	double (*applyFirstRotatorFromRight)(struct class_BidiagonalMatrix *p, Rotator_t *r);
	double (*applyRotatorFromRight)(struct class_BidiagonalMatrix *p, Rotator_t *r, int n, double bulge);
	double (*applyRotatorFromLeft)(struct class_BidiagonalMatrix *p, Rotator_t *r, int n, double bulge); 
	BidiagonalMatrix_t (*bidiagonalize)(struct class_BidiagonalMatrix *p, Matrix_t m);
	void (*doFrancis)(struct class_BidiagonalMatrix  *m,int n);
	double (*calculateShift)(struct class_BidiagonalMatrix  *m, int n);
	void (*releases)(struct class_BidiagonalMatrix  *p);
};

void BidiagonalMatrix_doFrancis(BidiagonalMatrix_t *m, int n);
double BidiagonalMatrix_calculateShift(BidiagonalMatrix_t *m, int n);
double BidiagonalMatrix_applyRotatorFromLeft(BidiagonalMatrix_t *ptr, Rotator_t *r, int n, double bulge); 
double BidiagonalMatrix_applyRotatorFromRight(BidiagonalMatrix_t *ptr, Rotator_t *r, int n, double bulge);
double BidiagonalMatrix_applyFirstRotatorFromRight(BidiagonalMatrix_t *p, Rotator_t *r); 
double BidiagonalMatrix_operator(BidiagonalMatrix_t *p, int i, int j);
void BidiagonalMatrix_release(BidiagonalMatrix_t *p);
void BidiagonalMatrix_init(BidiagonalMatrix_t *p, Matrix_t *m);
void BidiagonalMatrix_def(BidiagonalMatrix_t *p);
BidiagonalMatrix_t BidiagonalMatrix_bidiagonalize(BidiagonalMatrix_t *p, Matrix_t m);


#endif
