#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <rc/math/vector.h>
#include <rc/math/matrix.h>
#include <rc/math/algebra.h>
#include "algebra_common.h"
#define DEFAULT_ZERO_TOLERANCE 1e-8
double zero_tolerance=DEFAULT_ZERO_TOLERANCE;
static int __householder_reflection(int step, rc_matrix_t* Q, rc_matrix_t* R)
{
int i,j,k;
double norm, tau, taui, dot;
int n = R->rows-step;
int Rrows = R->rows;
int p=R->rows-n;
double x[n];
double H[n][n];
double tmp[R->cols-p][R->rows-p];
double tmp2[Q->rows][n];
double col[n];
int q = Q->cols-n;
for(j=step;j<Rrows;j++) x[j-step]=R->d[j][step];
norm = 0.0;
for(i=0;i<n;i++) norm += x[i]*x[i];
norm=sqrt(norm);
if(x[0]>=0.0){
x[0]=(x[0]+norm);
norm = -norm;
}
else x[0]=(x[0]-norm);
dot = __vectorized_square_accumulate(x,n);
tau = -2.0/dot;
for(i=0;i<n;i++){
taui = tau*x[i];
H[i][i] = 1.0 + taui*x[i];
for(j=i+1;j<n;j++){
H[i][j] = taui*x[j];
}
}
for(i=1;i<n;i++){
for(j=0;j<i;j++){
H[i][j] = H[j][i];
}
}
for(i=0;i<R->rows-p;i++){
for(j=0;j<R->cols-p;j++){
tmp[j][i]=R->d[i+p][j+p];
}
}
for(i=0;i<(R->rows-p);i++){
if(i==0) R->d[i+p][p]=norm;
else R->d[i+p][p]=0.0;
for(j=1;j<(R->cols-p);j++){
R->d[i+p][j+p]=__vectorized_mult_accumulate(H[i],tmp[j],n);
}
}
for(i=0;i<Q->rows;i++){
for(j=0;j<n;j++) tmp2[i][j]=Q->d[i][j+q];
}
for(j=0;j<(Q->cols-q);j++){
for(k=0;k<n;k++) col[k]=H[k][j];
for(i=0;i<Q->rows;i++){
Q->d[i][j+q]=__vectorized_mult_accumulate(tmp2[i],col,n);
}
}
return 0;
}
int rc_algebra_qr_decomp(rc_matrix_t A, rc_matrix_t* Q, rc_matrix_t* R)
{
int i,steps;
if(unlikely(!A.initialized)){
fprintf(stderr,"ERROR in rc_algebra_qr_decomp, matrix not initialized yet\n");
return -1;
}
if(unlikely(rc_matrix_duplicate(A,R))){
fprintf(stderr,"ERROR in rc_algebra_qr_decomp, failed to duplicate A\n");
return -1;
}
rc_matrix_identity(Q,A.rows);
if(A.rows==A.cols) steps=A.cols-1; else if(A.rows>A.cols) steps=A.cols; else steps=A.rows-1;
for(i=0;i<steps;i++){
if(__householder_reflection(i,Q,R)==-1) return -1;
}
return 0;
}
int rc_algebra_lup_decomp(rc_matrix_t A, rc_matrix_t* L, rc_matrix_t* U, rc_matrix_t* P)
{
int i,j,k,m,index,tmpint;
double s1, s2;
int* ptmp;
void* rowtmp;
rc_matrix_t Adup = RC_MATRIX_INITIALIZER;
if(unlikely(!A.initialized)){
fprintf(stderr,"ERROR in rc_algebra_lup_decomp, matrix not initialized yet\n");
return -1;
}
if(unlikely(A.cols!=A.rows)){
fprintf(stderr,"ERROR in rc_algebra_lup_decomp, matrix is not square\n");
return -1;
}
m = A.cols;
if(unlikely(rc_matrix_duplicate(A, &Adup))){
fprintf(stderr,"ERROR in rc_algebra_lup_decomp, failed to duplicate A\n");
return -1;
}
if(unlikely(rc_matrix_identity(L,m))){
fprintf(stderr,"ERROR in rc_algebra_lup_decomp, failed to allocate identity matrix\n");
rc_matrix_free(&Adup);
return -1;
}
if(unlikely(rc_matrix_alloc(U,m,m))){
fprintf(stderr,"ERROR in rc_algebra_lup_decomp, failed to allocate U\n");
rc_matrix_free(&Adup);
rc_matrix_free(L);
return -1;
}
if(unlikely(rc_matrix_zeros(P,m,m))){
fprintf(stderr,"ERROR in rc_algebra_lup_decomp, failed to allocate matrix of zeros\n");
rc_matrix_free(&Adup);
rc_matrix_free(L);
rc_matrix_free(U);
return -1;
}
ptmp = alloca(m*sizeof(int));
rowtmp = alloca(m*sizeof(double));
if(unlikely(ptmp==NULL || rowtmp==NULL)){
fprintf(stderr,"ERROR in rc_algebra_lup_decomp, alloca failed, stack overflow\n");
rc_matrix_free(&Adup);
rc_matrix_free(L);
rc_matrix_free(U);
rc_matrix_free(P);
return -1;
}
for(i=0;i<m;i++) ptmp[i]=i;
for(i=0;i<m-1;i++){
index = i;
for(j=i;j<m;j++){
if(fabs(A.d[j][i])>=fabs(A.d[index][i])) index=j;
}
if(index!=i){
tmpint = ptmp[index];
ptmp[index]=ptmp[i];
ptmp[i]=tmpint;
memcpy(rowtmp,Adup.d[index],m*sizeof(double));
memcpy(Adup.d[index],Adup.d[i],m*sizeof(double));
memcpy(Adup.d[i],rowtmp,m*sizeof(double));
}
}
for(i=0;i<m;i++) P->d[i][ptmp[i]]=1.0;
for(i=0;i<m;i++){
for(j=0;j<m;j++){
s1 = 0.0;
s2 = 0.0;
for(k=0;k<i;k++) s1 += U->d[k][j] * L->d[i][k];
for(k=0;k<j;k++) s2 += U->d[k][j] * L->d[i][k];
if(j>=i) U->d[i][j] = (Adup.d[i][j]-s1);
if(i>=j) L->d[i][j] = (Adup.d[i][j]-s2)/U->d[j][j];
}
}
rc_matrix_free(&Adup);
return 0;
}
int rc_algebra_invert_matrix(rc_matrix_t A, rc_matrix_t* Ainv)
{
int i,j,k;
rc_matrix_t L = RC_MATRIX_INITIALIZER;
rc_matrix_t U = RC_MATRIX_INITIALIZER;
rc_matrix_t P = RC_MATRIX_INITIALIZER;
rc_matrix_t D = RC_MATRIX_INITIALIZER;
rc_matrix_t tmp = RC_MATRIX_INITIALIZER;
if(unlikely(!A.initialized)){
fprintf(stderr,"ERROR in rc_matrix_inverse, matrix uninitialized\n");
return -1;
}
if(unlikely(A.cols!=A.rows)){
fprintf(stderr,"ERROR in rc_matrix_inverse, nonsquare matrix\n");
return -1;
}
if(fabs(rc_matrix_determinant(A)) < zero_tolerance){
fprintf(stderr,"ERROR in rc_matrix_inverse, matrix is singular\n");
return -1;
}
if(unlikely(rc_matrix_identity(&D,A.cols))){
fprintf(stderr,"ERROR in rc_matrix_inverse, failed to alloc identity\n");
return -1;
}
if(unlikely(rc_matrix_alloc(&tmp,A.rows,A.rows))){
fprintf(stderr,"ERROR in rc_matrix_inverse, failed to alloc matrix\n");
rc_matrix_free(&D);
return -1;
}
if(unlikely(rc_algebra_lup_decomp(A,&L,&U,&P))){
fprintf(stderr,"ERROR in rc_matrix_inverse, failed to LUP decomp\n");
rc_matrix_free(&D);
rc_matrix_free(&tmp);
return -1;
}
for(j=0;j<A.cols;j++){
for(i=0;i<A.cols;i++){
for(k=0;k<i;k++){
D.d[i][j] -= L.d[i][k] * D.d[k][j];
}
}
for(i=A.cols-1;i>=0;i--){
tmp.d[i][j] = D.d[i][j];
for(k=i+1;k<A.cols;k++){
tmp.d[i][j] -= U.d[i][k] * tmp.d[k][j];
}
tmp.d[i][j] = tmp.d[i][j] / U.d[i][i];
}
}
rc_matrix_free(&L);
rc_matrix_free(&U);
rc_matrix_free(&D);
i=0;
if(unlikely(rc_matrix_multiply(tmp, P, Ainv))){
fprintf(stderr,"ERROR in rc_matrix_inverse, failed to multiply matrix\n");
i=-1;
}
rc_matrix_free(&tmp);
rc_matrix_free(&P);
return i;
}
int rc_algebra_invert_matrix_inplace(rc_matrix_t* A)
{
rc_matrix_t Atmp = RC_MATRIX_INITIALIZER;
if(unlikely(rc_algebra_invert_matrix(*A,&Atmp))){
fprintf(stderr, "ERROR in rc_algebra_invert_matrix_inplace, failed to invert\n");
return -1;
}
rc_matrix_free(A);
*A = Atmp;
return 0;
}
int rc_algebra_lin_system_solve(rc_matrix_t A, rc_vector_t b, rc_vector_t* x)
{
double fMaxElem, fAcc;
int nDim,i,j,k,m;
rc_matrix_t Atemp = RC_MATRIX_INITIALIZER;
rc_vector_t btemp = RC_VECTOR_INITIALIZER;
if(!A.initialized || !b.initialized){
fprintf(stderr,"ERROR in rc_algebra_lin_system_solve, matrix or vector uninitialized\n");
return -1;
}
if(A.cols != b.len){
fprintf(stderr,"ERROR in rc_algebra_lin_system_solve, dimension mismatch\n");
return -1;
}
nDim = A.cols;
if(unlikely(rc_vector_alloc(x,nDim))){
fprintf(stderr,"ERROR in rc_algebra_lin_system_solve, failed to alloc vector\n");
return -1;
}
if(unlikely(rc_matrix_duplicate(A, &Atemp))){
fprintf(stderr,"ERROR in rc_algebra_lin_system_solve, failed to duplicate matrix\n");
rc_vector_free(x);
return -1;
}
if(unlikely(rc_vector_duplicate(b, &btemp))){
fprintf(stderr,"ERROR in rc_algebra_lin_system_solve, failed to duplicate vector\n");
rc_vector_free(x);
rc_matrix_free(&Atemp);
return -1;
}
for(k=0;k<(nDim-1);k++){ fMaxElem=fabs(Atemp.d[k][k]);
m=k;
for(i=k+1;i<nDim;i++){
if(fMaxElem<fabs(Atemp.d[i][k])){
fMaxElem=Atemp.d[i][k];
m=i;
}
}
if(m!=k){
for(i=k;i<nDim;i++){
fAcc=Atemp.d[k][i];
Atemp.d[k][i]=Atemp.d[m][i];
Atemp.d[m][i]=fAcc;
}
fAcc=btemp.d[k];
btemp.d[k]=btemp.d[m];
btemp.d[m]=fAcc;
}
if(unlikely(fabs(Atemp.d[k][k])<zero_tolerance)){
fprintf(stderr,"ERROR in rc_algebra_lin_system_solve, matrix not full rank\n");
rc_matrix_free(&Atemp);
rc_vector_free(&btemp);
rc_vector_free(x);
return -1;
}
for(j=(k+1);j<nDim;j++){ fAcc = -Atemp.d[j][k]/Atemp.d[k][k];
for(i=k;i<nDim;i++){
Atemp.d[j][i]=Atemp.d[j][i]+fAcc*Atemp.d[k][i];
}
btemp.d[j] = btemp.d[j] + (fAcc*btemp.d[k]);
}
}
for(k=nDim-1;k>=0;k--){
x->d[k]=btemp.d[k];
for(i=k+1;i<nDim;i++) x->d[k]-=Atemp.d[k][i]*x->d[i];
x->d[k]=x->d[k]/Atemp.d[k][k];
}
rc_matrix_free(&Atemp);
rc_vector_free(&btemp);
return 0;
}
void rc_algebra_set_zero_tolerance(double tol){
zero_tolerance=tol;
return;
}
int rc_algebra_lin_system_solve_qr(rc_matrix_t A, rc_vector_t b, rc_vector_t* x)
{
int i,k;
rc_vector_t temp = RC_VECTOR_INITIALIZER;
rc_matrix_t Q = RC_MATRIX_INITIALIZER;
rc_matrix_t R = RC_MATRIX_INITIALIZER;
if(unlikely(!A.initialized || !b.initialized)){
fprintf(stderr,"ERROR in rc_algebra_lin_system_solve_qr, matrix or vector uninitialized\n");
return -1;
}
if(unlikely(rc_algebra_qr_decomp(A,&Q,&R))){
fprintf(stderr,"ERROR in rc_algebra_lin_system_solve_qr, failed to perform QR decomp\n");
return -1;
}
if(unlikely(rc_matrix_row_vec_times_matrix(b,Q,&temp))){
fprintf(stderr,"ERROR in rc_algebra_lin_system_solve_qr, failed to multiply vec by matrix\n");
rc_matrix_free(&Q);
rc_matrix_free(&R);
return -1;
}
if(unlikely(rc_vector_alloc(x,R.cols))){
fprintf(stderr,"ERROR in rc_algebra_lin_system_solve_qr, failed to alloc vector\n");
rc_matrix_free(&Q);
rc_matrix_free(&R);
rc_vector_free(&temp);
return -1;
}
for(k=R.cols-1;k>=0;k--){
x->d[k]=temp.d[k];
for(i=k+1;i<R.cols;i++) x->d[k]-=R.d[k][i]*x->d[i];
x->d[k] = x->d[k]/R.d[k][k];
}
rc_matrix_free(&Q);
rc_matrix_free(&R);
rc_vector_free(&temp);
return 0;
}
int rc_algebra_fit_ellipsoid(rc_matrix_t pts, rc_vector_t* ctr, rc_vector_t* lens)
{
int i,p;
rc_matrix_t A = RC_MATRIX_INITIALIZER;
rc_vector_t b = RC_VECTOR_INITIALIZER;
rc_vector_t f = RC_VECTOR_INITIALIZER;
if(unlikely(!pts.initialized)){
fprintf(stderr,"ERROR in rc_fit_ellipsoid, matrix not initialized\n");
return -1;
}
if(unlikely(pts.cols!=3)){
fprintf(stderr,"ERROR in rc_fit_ellipsoid, matrix pts must have 3 columns\n");
return -1;
}
p = pts.rows;
if(p<6){
fprintf(stderr,"ERROR in rc_fit_ellipsoid, matrix pts must have at least 6 rows\n");
return -1;
}
if(unlikely(rc_vector_ones(&b,p))){
fprintf(stderr,"ERROR in rc_fit_ellipsoid, failed to alloc vector\n");
return -1;
}
if(unlikely(rc_matrix_alloc(&A,p,6))){
fprintf(stderr,"ERROR in rc_fit_ellipsoid, failed to alloc matrix\n");
rc_vector_free(&b);
return -1;
}
for(i=0;i<p;i++){
A.d[i][0] = pts.d[i][0] * pts.d[i][0];
A.d[i][1] = pts.d[i][0];
A.d[i][2] = pts.d[i][1] * pts.d[i][1];
A.d[i][3] = pts.d[i][1];
A.d[i][4] = pts.d[i][2] * pts.d[i][2];
A.d[i][5] = pts.d[i][2];
}
if(unlikely(rc_algebra_lin_system_solve_qr(A,b,&f))){
fprintf(stderr,"ERROR in rc_fit_ellipsoid, failed to solve QR\n");
rc_matrix_free(&A);
rc_vector_free(&b);
rc_vector_free(&f);
return -1;
}
rc_matrix_free(&A);
rc_vector_free(&b);
if(unlikely(rc_vector_alloc(ctr,3))){
fprintf(stderr,"ERROR in rc_fit_ellipsoid, failed to allocate ctr\n");
rc_vector_free(&f);
return -1;
}
ctr->d[0] = -f.d[1]/(2.0*f.d[0]);
ctr->d[1] = -f.d[3]/(2.0*f.d[2]);
ctr->d[2] = -f.d[5]/(2.0*f.d[4]);
if(unlikely(rc_vector_alloc(&b,3))){
fprintf(stderr,"ERROR in rc_fit_ellipsoid, failed to alloc vector\n");
return -1;
}
if(unlikely(rc_matrix_alloc(&A,3,3))){
fprintf(stderr,"ERROR in rc_fit_ellipsoid, failed to alloc matrix\n");
rc_vector_free(&b);
return -1;
}
A.d[0][0] = (f.d[0] * ctr->d[0] * ctr->d[0]) + 1.0;
A.d[0][1] = (f.d[0] * ctr->d[1] * ctr->d[1]);
A.d[0][2] = (f.d[0] * ctr->d[2] * ctr->d[2]);
A.d[1][0] = (f.d[2] * ctr->d[0] * ctr->d[0]);
A.d[1][1] = (f.d[2] * ctr->d[1] * ctr->d[1]) + 1.0;
A.d[1][2] = (f.d[2] * ctr->d[2] * ctr->d[2]);
A.d[2][0] = (f.d[4] * ctr->d[0] * ctr->d[0]);
A.d[2][1] = (f.d[4] * ctr->d[1] * ctr->d[1]);
A.d[2][2] = (f.d[4] * ctr->d[2] * ctr->d[2]) + 1.0;
b.d[0] = f.d[0];
b.d[1] = f.d[2];
b.d[2] = f.d[4];
if(unlikely(rc_algebra_lin_system_solve(A,b,lens))){
fprintf(stderr,"ERROR in rc_fit_ellipsoid, failed to solve linear system\n");
rc_matrix_free(&A);
rc_vector_free(&b);
rc_vector_free(&f);
return -1;
}
lens->d[0] = 1.0/sqrt(lens->d[0]);
lens->d[1] = 1.0/sqrt(lens->d[1]);
lens->d[2] = 1.0/sqrt(lens->d[2]);
rc_matrix_free(&A);
rc_vector_free(&b);
rc_vector_free(&f);
return 0;
}