void check_matrix(const char*name, ambix_matrixtype_t typ, uint32_t rows, uint32_t cols) { ambix_matrix_t*mtx=NULL; ambix_matrix_t*result=NULL; ambix_matrix_t*zeros=NULL; float32_t errf=0.f; float32_t eps=1e-20; STARTTEST(name); mtx=ambix_matrix_init(rows, cols, mtx); result=ambix_matrix_fill(mtx, typ); fail_if((result==NULL), __LINE__, "matrix_fill returned NULL"); fail_if((result!=mtx ), __LINE__, "matrix_fill did not return matrix %p (got %p)", mtx, result); zeros=ambix_matrix_init(result->rows, result->cols, zeros); zeros=ambix_matrix_fill(zeros, AMBIX_MATRIX_ZERO); errf=matrix_check_diff(name, result, zeros); if(AMBIX_MATRIX_ZERO==typ) { fail_if(!(errf<eps), __LINE__, "zero matrix non-zero (%f>%f)", errf, eps); } else { fail_if((errf<eps), __LINE__, "non-zero matrix zero (%f<%f)", errf, eps); } ambix_matrix_destroy(mtx); ambix_matrix_destroy(zeros); }
void mtxmul_eye_tests(float32_t eps) { float32_t errf; ambix_matrix_t *left, *result, *eye; STARTTEST(""); eye=ambix_matrix_init(4, 4, NULL); fail_if((eye!=ambix_matrix_fill(eye, AMBIX_MATRIX_IDENTITY)), __LINE__, "filling unity matrix %p did not return original matrix %p", eye); left=ambix_matrix_init(4, 2, NULL); fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_fill_data(left, resultdata_4_2), __LINE__, "filling left data failed"); result=ambix_matrix_init(4, 2, NULL); fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_fill_data(result, resultdata_4_2), __LINE__, "filling result data failed"); fail_if((result!=ambix_matrix_multiply(eye, left, result)), __LINE__, "multiplication into matrix did not return original matrix"); #if 0 matrix_print(eye); matrix_print(result); matrix_print(left); #endif errf=matrix_diff(__LINE__, left, result, eps); fail_if((errf>eps), __LINE__, "diffing matrix M with E*M returned %f (>%f)", errf, eps); ambix_matrix_destroy(left); ambix_matrix_destroy(result); ambix_matrix_destroy(eye); }
void datamul_eye_tests(float32_t eps) { float32_t errf; uint64_t frames=4096; uint32_t channels=16; float32_t*inputdata; float32_t*outputdata; float32_t freq=500; ambix_matrix_t eye = {0, 0, NULL}; STARTTEST(""); inputdata =data_sine(frames, channels, freq); outputdata=(float32_t*)malloc(sizeof(float32_t)*frames*channels); fail_if((NULL==outputdata), __LINE__, "couldn't mallocate outputdata"); ambix_matrix_init(channels, channels, &eye); ambix_matrix_fill(&eye, AMBIX_MATRIX_IDENTITY); fail_if(AMBIX_ERR_SUCCESS!=ambix_matrix_multiply_float32(outputdata, &eye, inputdata, frames), __LINE__, "data multilplication failed"); errf=data_diff(__LINE__, inputdata, outputdata, frames*channels, eps); fail_if(!(errf<eps), __LINE__, "diffing data multiplication returned %f (>%f)", errf, eps); #if 0 printf("matrix:\n"); matrix_print(&eye); printf("input :\n"); data_print(inputdata, frames*channels); printf("output:\n"); data_print(outputdata,frames*channels); #endif free(inputdata); free(outputdata); ambix_matrix_deinit(&eye); }
ambix_matrix_t*inverse_matrices(ambix_matrixtype_t typ, uint32_t rows, uint32_t cols) { ambix_matrixtype_t pyt = (ambix_matrixtype_t)(AMBIX_MATRIX_TO_AMBIX | typ); ambix_matrix_t*mtx=ambix_matrix_init(rows, cols, NULL); ambix_matrix_t*xtm=ambix_matrix_init(cols, rows, NULL); ambix_matrix_t*a2f=ambix_matrix_fill(mtx, typ); ambix_matrix_t*f2a=ambix_matrix_fill(xtm, pyt); // ambix_matrix_t*result=ambix_matrix_multiply(a2f, f2a, NULL); ambix_matrix_t*result=ambix_matrix_multiply(f2a, a2f, NULL); if(a2f!=mtx) ambix_matrix_destroy(a2f); ambix_matrix_destroy(mtx); if(f2a!=xtm) ambix_matrix_destroy(f2a); ambix_matrix_destroy(xtm); return result; }
int test_defaultmatrix(const char*name, uint32_t rows, uint32_t cols, ambix_matrixtype_t mtyp, uint32_t xtrachannels, uint32_t chunksize, float32_t eps) { int result=0; ambix_matrix_t*mtx=0; STARTTEST("%s\n", name); mtx=ambix_matrix_init(rows,cols,mtx); if(!mtx)return 1; ambix_matrix_fill(mtx, mtyp); result=check_create_b2e(FILENAME_FILE, AMBIX_SAMPLEFORMAT_PCM16, mtx,xtrachannels, chunksize, FLOAT32, eps); ambix_matrix_destroy(mtx); return result; }
static void mtxinverse_test(const ambix_matrix_t *mtx, const ambix_matrix_t *result, float32_t eps) { ambix_matrix_t *pinv = 0; ambix_matrix_t *mul=0; ambix_matrix_t *eye=0; float32_t errf; int min_rowcol=(mtx->cols<mtx->rows)?mtx->cols:mtx->rows; fail_if((NULL==mtx), __LINE__, "cannot invert NULL-matrix"); eye=ambix_matrix_init(min_rowcol, min_rowcol, eye); eye=ambix_matrix_fill(eye, AMBIX_MATRIX_IDENTITY); fail_if((NULL==eye), __LINE__, "cannot create eye-matrix for pinv-verification"); pinv=ambix_matrix_pinv(mtx, pinv); if(NULL==pinv)matrix_print(mtx); fail_if((NULL==pinv), __LINE__, "could not invert matrix"); if(mtx->cols < mtx->rows) mul=ambix_matrix_multiply(pinv, mtx, 0); else mul=ambix_matrix_multiply(mtx, pinv, 0); #if 0 matrix_print(mtx); matrix_print(pinv); matrix_print(mul); if(result)matrix_print(result); printf("------------\n"); #endif if(result) { errf=matrix_diff(__LINE__, pinv, result, eps); fail_if((errf>eps), __LINE__, "diffing (pseudo)inverse returned %g (>%g)", errf, eps); errf=matrix_diff(__LINE__, mul, eye, eps); fail_if((errf>eps), __LINE__, "diffing mtx*pinv(mtx) returned %g (>%g)", errf, eps); } else { errf=matrix_diff(__LINE__, mul, eye, eps); fail_if((!(isnan(errf) || isinf(errf) || (errf>eps))), __LINE__, "diffing invalid mtx*pinv(mtx) returned %g (!>%g)", errf, eps); } ambix_matrix_destroy(pinv); ambix_matrix_destroy(mul); ambix_matrix_destroy(eye); }
void check_inversion(const char*name, ambix_matrixtype_t typ, uint32_t rows, uint32_t cols) { ambix_matrix_t*eye=NULL; ambix_matrix_t*result=NULL; float32_t errf; float32_t eps=1e-6; STARTTEST(name); result=inverse_matrices(typ, rows, cols); eye=ambix_matrix_init(result->rows, result->cols, eye); eye=ambix_matrix_fill(eye, AMBIX_MATRIX_IDENTITY); errf=matrix_check_diff(name, result, eye); if(!(errf<eps)){ matrix_print(result); } fail_if(!(errf<eps), __LINE__, "diffing matrices (%s) returned %g-%g=%g", name, errf, eps, errf-eps); ambix_matrix_destroy(result); ambix_matrix_destroy(eye); }
void check_create_extended(const char*path, ambix_sampleformat_t format, uint32_t chunksize, float32_t eps) { ambix_info_t info, rinfo, winfo; ambix_t*ambix=NULL; float32_t*orgambidata,*ambidata,*resultambidata; float32_t*orgotherdata,*otherdata,*resultotherdata; uint32_t framesize=441000; uint32_t ambichannels=4; uint32_t extrachannels=2; float32_t periods=20000; ambix_matrix_t eye={0,0,NULL}; const ambix_matrix_t*eye2=NULL; int64_t err64, gotframes; float32_t diff=0.; STARTTEST("\n"); printf("test using '%s' [%d] with chunks of %d and eps=%f\n", path, (int)format, (int)chunksize, eps); resultambidata=(float32_t*)calloc(ambichannels*framesize, sizeof(float32_t)); ambidata=(float32_t*)calloc(ambichannels*framesize, sizeof(float32_t)); resultotherdata=(float32_t*)calloc(extrachannels*framesize, sizeof(float32_t)); otherdata=(float32_t*)calloc(extrachannels*framesize, sizeof(float32_t)); ambix_matrix_init(ambichannels, ambichannels, &eye); ambix_matrix_fill(&eye, AMBIX_MATRIX_IDENTITY); memset(&winfo, 0, sizeof(winfo)); memset(&info, 0, sizeof(info)); info.fileformat=AMBIX_EXTENDED; info.ambichannels=ambichannels; info.extrachannels=extrachannels; info.samplerate=44100; info.sampleformat=format; memcpy(&rinfo, &info, sizeof(info)); ambix=ambix_open(path, AMBIX_WRITE, &rinfo); fail_if((NULL==ambix), __LINE__, "couldn't create ambix file '%s' for writing", path); orgambidata=data_sine (FLOAT32, framesize, ambichannels, periods); orgotherdata=data_ramp(FLOAT32, framesize, extrachannels); //data_print(FLOAT32, orgdata, 100); fail_if((NULL==orgambidata), __LINE__, "couldn't create ambidata %dx%d sine @ %f", (int)framesize, (int)ambichannels, (float)periods); fail_if((NULL==orgotherdata), __LINE__, "couldn't create otherdata %dx%d sine @ %f", (int)framesize, (int)extrachannels, (float)periods); memcpy(ambidata, orgambidata, framesize*ambichannels*sizeof(float32_t)); memcpy(otherdata, orgotherdata, framesize*extrachannels*sizeof(float32_t)); fail_if((AMBIX_ERR_SUCCESS!=ambix_set_adaptormatrix(ambix, &eye)), __LINE__, "failed setting adaptor matrix"); if(chunksize>0) { uint32_t subframe=chunksize; uint32_t chunks = framesize/chunksize; uint32_t framesleft=framesize; uint32_t frame; printf("writing %d chunks of %d frames\n", (int)chunks, (int)chunksize); for(frame=0; frame<chunks; frame++) { err64=ambix_writef_float32(ambix, ambidata+ambichannels*frame*chunksize, otherdata+extrachannels*frame*chunksize, chunksize); fail_if((err64!=chunksize), __LINE__, "wrote only %d chunksize of %d", (int)err64, (int)chunksize); framesleft-=chunksize; } subframe=framesleft; printf("writing rest of %d frames\n", (int)subframe); err64=ambix_writef_float32(ambix, ambidata+ambichannels*frame*chunksize, otherdata+extrachannels*frame*chunksize, subframe); fail_if((err64!=subframe), __LINE__, "wrote only %d subframe of %d", (int)err64, (int)subframe); } else { err64=ambix_writef_float32(ambix, ambidata, otherdata, framesize); fail_if((err64!=framesize), __LINE__, "wrote only %d frames of %d", (int)err64, (int)framesize); } diff=data_diff(__LINE__, FLOAT32, orgambidata, ambidata, framesize*ambichannels, eps); fail_if((diff>eps), __LINE__, "ambidata diff %f > %f", diff, eps); diff=data_diff(__LINE__, FLOAT32, orgotherdata, otherdata, framesize*extrachannels, eps); fail_if((diff>eps), __LINE__, "otherdata diff %f > %f", diff, eps); fail_if((AMBIX_ERR_SUCCESS!=ambix_close(ambix)), __LINE__, "closing ambix file %p", ambix); ambix=NULL; /* read data back */ ambix=ambix_open(path, AMBIX_READ, &rinfo); fail_if((NULL==ambix), __LINE__, "couldn't create ambix file '%s' for reading", path); fail_if((info.fileformat!=rinfo.fileformat), __LINE__, "fileformat mismatch %d!=%d", (int)info.fileformat, (int)rinfo.fileformat); fail_if((info.samplerate!=rinfo.samplerate), __LINE__, "samplerate mismatch %g!=%g", (float)info.samplerate, (float)rinfo.samplerate); fail_if((info.sampleformat!=rinfo.sampleformat), __LINE__, "sampleformat mismatch %d!=%d", (int)info.sampleformat, (int)rinfo.sampleformat); fail_if((info.ambichannels!=rinfo.ambichannels), __LINE__, "ambichannels mismatch %d!=%d", (int)info.ambichannels, (int)rinfo.ambichannels); fail_if((info.extrachannels!=rinfo.extrachannels), __LINE__, "extrachannels mismatch %d!=%d", (int)info.extrachannels, (int)rinfo.extrachannels); eye2=ambix_get_adaptormatrix(ambix); fail_if((NULL==eye2), __LINE__, "failed reading adaptor matrix"); diff=matrix_diff(__LINE__, &eye, eye2, eps); fail_if((diff>eps), __LINE__, "adaptormatrix diff %f > %f", diff, eps); gotframes=0; do { //err64=ambix_readf_float32(ambix, resultambidata, resultotherdata, framesize); err64=ambix_readf_float32(ambix, resultambidata +(gotframes*ambichannels ), resultotherdata+(gotframes*extrachannels), (framesize-gotframes)); fail_if((err64<0), __LINE__, "reading frames failed after %d/%d frames", (int)gotframes, (int)framesize); gotframes+=err64; } while(err64>0 && gotframes<framesize); diff=data_diff(__LINE__, FLOAT32, orgambidata, resultambidata, framesize*ambichannels, eps); fail_if((diff>eps), __LINE__, "ambidata diff %f > %f", diff, eps); diff=data_diff(__LINE__, FLOAT32, orgotherdata, resultotherdata, framesize*extrachannels, eps); fail_if((diff>eps), __LINE__, "otherdata diff %f > %f", diff, eps); fail_if((AMBIX_ERR_SUCCESS!=ambix_close(ambix)), __LINE__, "closing ambix file %p", ambix); ambix=NULL; free(resultambidata); free(ambidata); free(resultotherdata); free(otherdata); free(orgambidata); free(orgotherdata); ambix_matrix_deinit(&eye); ambixtest_rmfile(path); }
/* this modifies the input matrix! */ ambix_matrix_t* _ambix_matrix_invert_gaussjordan(ambix_matrix_t*input, ambix_matrix_t*inverse, float32_t eps) { ambix_matrix_t*inverse_org = inverse; int i, k; float32_t *a1, *b1, *a2, *b2; int errors=0; /* error counter */ if(input==0) { // no input matrix return NULL; } if (input->cols != input->rows) {// matrix is not squared return NULL; } int col=input->cols, row=input->rows; /* 1a reserve space for the inverted matrix */ if(!inverse) { inverse=ambix_matrix_init(row, col, NULL); } float32_t **original=input->data; float32_t **inverted=inverse->data; /* 1b make an eye-shaped float-buf for B */ ambix_matrix_fill(inverse, AMBIX_MATRIX_IDENTITY); /* 2. do the Gauss-Jordan */ //printf("GaussJordan\n"); for (k=0; k<row; k++) { /* adjust current row */ float32_t diagel = original[k][k]; float32_t i_diagel = 0; if(diagel>-eps && diagel<eps) errors++; else i_diagel = 1./diagel; /* normalize current row (set the diagonal-element to 1 */ for (i=0; i < row; i++) { original[k][i] *= i_diagel; inverted[k][i] *= i_diagel; } /* eliminate the k-th element in each row by adding the weighted normalized row */ for (i=0; i < row; i++) { if (i-k) { float32_t f =-original[i][k]; int j; for (j=row-1; j >= 0; j--) { original[i][j] += f * original[k][j]; inverted[i][j] += f * inverted[k][j]; } } } } if (errors > 0) { if(inverse != inverse_org) /* if the 'inverse' was locally allocated, free it */ ambix_matrix_destroy(inverse); inverse=NULL; } return inverse; }
ambix_err_t _ambix_open (ambix_t*ambix, const char *path, const ambix_filemode_t mode, const ambix_info_t*ambixinfo) { int sfmode=0; int caf=0; ambix->private_data=calloc(1, sizeof(ambixsndfile_private_t)); ambix2sndfile_info(ambixinfo, &PRIVATE(ambix)->sf_info); if((mode & AMBIX_READ) & (mode & AMBIX_WRITE)) sfmode= SFM_RDWR; else if (mode & AMBIX_WRITE) sfmode= SFM_WRITE; else if (mode & AMBIX_READ) sfmode= SFM_READ; PRIVATE(ambix)->sf_file=sf_open(path, sfmode, &PRIVATE(ambix)->sf_info) ; if(!PRIVATE(ambix)->sf_file) return AMBIX_ERR_INVALID_FILE; memset(&ambix->realinfo, 0, sizeof(*ambixinfo)); sndfile2ambix_info(&PRIVATE(ambix)->sf_info, &ambix->realinfo); ambix->byteswap=(sf_command(PRIVATE(ambix)->sf_file, SFC_RAW_DATA_NEEDS_ENDSWAP, NULL, 0) == SF_TRUE); ambix->channels = PRIVATE(ambix)->sf_info.channels; caf=((SF_FORMAT_CAF == (SF_FORMAT_TYPEMASK & PRIVATE(ambix)->sf_info.format)) != 0); if(caf) { ambix->is_AMBIX=1; if(read_uuidchunk(ambix) == AMBIX_ERR_SUCCESS) { ambix->format=AMBIX_EXTENDED; } else { ambix->format=AMBIX_BASIC; } } else { // check whether this is an .amb file or the like... if(0) { } else if(sf_command(PRIVATE(ambix)->sf_file, SFC_WAVEX_GET_AMBISONIC, NULL, 0) == SF_AMBISONIC_B_FORMAT) { /* The four B-format signals are interleaved for each sample frame in the order W,X,Y,Z. If the extended six-channel B-Format is used, the U and V signals will occupy the fifth and sixth slots: W,X,Y,Z,U,V. If horizontal-only B-format is to be represented, a three or five-channel file will suffice, with signals interleaved as W,X,Y (First Order), or W,X,Y,U,V (Second-order). However, four and -six-channel files are also acceptable, with the Z channel empty. Higher-order configurations are possible in theory, but are not addressed here. A decoder program should either 'degrade gracefully', or reject formats it cannot handle. For all B-format configurations, the dwChannelMask field should be set to zero. Though strictly speaking an optional chunk, it is recommended that the PEAK chunk be used for all B-Format files. Apart from its general utility, it has the special virtue for B-format in that applications can determine from the peak value for the Z channel whether the file is indeed full periphonic B-format (with height information), or 'Horizontal-only' (Z channel present but empty). */ switch(ambix->channels) { case 3: /* h = 1st order 2-D */ ambix_matrix_init(ambix_order2channels(1), ambix->channels, &ambix->matrix); break; case 4: /* f = 1st order 3-D */ ambix_matrix_init(ambix_order2channels(1), ambix->channels, &ambix->matrix); break; case 5: /* hh = 2nd order 2-D */ ambix_matrix_init(ambix_order2channels(2), ambix->channels, &ambix->matrix); break; case 6: /* fh = 2nd order 2-D + 1st order 3-D (formerly called 2.5 order) */ ambix_matrix_init(ambix_order2channels(2), ambix->channels, &ambix->matrix); break; case 7: /* hhh = 3rd order 2-D */ ambix_matrix_init(ambix_order2channels(3), ambix->channels, &ambix->matrix); break; case 8: /* fhh = 3rd order 2-D + 1st order 3-D */ ambix_matrix_init(ambix_order2channels(3), ambix->channels, &ambix->matrix); break; case 9: /* ff = 2nd order 3-D */ ambix_matrix_init(ambix_order2channels(2), ambix->channels, &ambix->matrix); break; case 11: /* ffh = 3rd order 2-D + 2nd order 3-D */ ambix_matrix_init(ambix_order2channels(3), ambix->channels, &ambix->matrix); break; case 16: /* fff = 3rd order 3-D */ ambix_matrix_init(ambix_order2channels(3), ambix->channels, &ambix->matrix); break; } if(NULL != ambix_matrix_fill(&ambix->matrix, AMBIX_MATRIX_FUMA)) { ambix->is_AMBIX=1; ambix->format=AMBIX_EXTENDED; } else { ambix->is_AMBIX=0; ambix->format=AMBIX_NONE; } } else { ambix->is_AMBIX=0; ambix->format=AMBIX_NONE; } } if(0) { print_sfinfo( &PRIVATE(ambix)->sf_info); } return AMBIX_ERR_SUCCESS; }
ambix_t* ambix_open (const char *path, const ambix_filemode_t mode, ambix_info_t*ambixinfo) { ambix_t*ambix=NULL; ambix_err_t err = AMBIX_ERR_UNKNOWN; int32_t ambichannels=0, otherchannels=0; if((AMBIX_WRITE & mode) && (AMBIX_READ & mode)) { /* RDRW not yet implemented */ return NULL; } if(AMBIX_WRITE & mode) { err=_check_write_ambixinfo(ambixinfo); if(err!=AMBIX_ERR_SUCCESS) return NULL; ambichannels=ambixinfo->ambichannels; otherchannels=ambixinfo->extrachannels; } ambix=(ambix_t*)calloc(1, sizeof(ambix_t)); if(AMBIX_ERR_SUCCESS == _ambix_open(ambix, path, mode, ambixinfo)) { const ambix_fileformat_t wantformat=ambixinfo->fileformat; ambix_fileformat_t haveformat; uint32_t channels = ambix->channels; /* successfully opened, initialize common stuff... */ if(ambix->is_AMBIX) { if(AMBIX_WRITE & mode) { switch(wantformat) { case(AMBIX_NONE): _ambix_info_set(ambix, AMBIX_NONE, channels, 0, 0); break; case(AMBIX_BASIC): _ambix_info_set(ambix, AMBIX_BASIC, 0, channels, channels); break; case(AMBIX_EXTENDED): /* the number of full channels is not clear yet! * the user has to call setAdaptorMatrix() first */ _ambix_info_set(ambix, AMBIX_EXTENDED, otherchannels, ambichannels, 0); break; } } else { if(ambix->format>AMBIX_BASIC) { /* check whether channels are (N+1)^2 * if so, we have a simple-ambix file, else it is just an ordinary caf */ if(ambix->matrix.cols <= channels && /* reduced set must be fully present */ ambix_is_fullset(ambix->matrix.rows)) { /* expanded set must be a full set */ /* it's a simple AMBIX! */ _ambix_info_set(ambix, AMBIX_EXTENDED, channels-ambix->matrix.cols, ambix->matrix.cols, ambix->matrix.rows); } else { /* ouch! matrix is not valid! */ _ambix_info_set(ambix, AMBIX_NONE, channels, 0, 0); } } else { /* no uuid chunk found, it's probably a BASIC ambix file */ /* check whether channels are (N+1)^2 * if so, we have a simple-ambix file, else it is just an ordinary caf */ if(ambix_is_fullset(channels)) { /* expanded set must be a full set */ /* it's a simple AMBIX! */ _ambix_info_set(ambix, AMBIX_BASIC, 0, channels, channels); } else { /* it's an ordinary CAF file */ _ambix_info_set(ambix, AMBIX_NONE, channels, 0, 0); } } } } else { /* it's not a CAF file.... */ _ambix_info_set(ambix, AMBIX_NONE, channels, 0, 0); } haveformat=ambix->realinfo.fileformat; ambix->filemode=mode; memcpy(&ambix->info, &ambix->realinfo, sizeof(ambix->info)); if(0) { } else if(AMBIX_BASIC==wantformat && AMBIX_EXTENDED==haveformat) { ambix->info.fileformat=AMBIX_BASIC; ambix->use_matrix=1; ambix->info.ambichannels=ambix->matrix.rows; } else if(AMBIX_EXTENDED==wantformat && AMBIX_BASIC==haveformat) { ambix_matrix_init(ambix->realinfo.ambichannels, ambix->realinfo.ambichannels, &ambix->matrix); ambix_matrix_fill(&ambix->matrix, AMBIX_MATRIX_IDENTITY); ambix->info.fileformat=AMBIX_EXTENDED; ambix->use_matrix=0; } memcpy(ambixinfo, &ambix->info, sizeof(ambix->info)); if(_ambix_adaptorbuffer_resize(ambix, DEFAULT_ADAPTORBUFFER_SIZE, sizeof(float32_t)) == AMBIX_ERR_SUCCESS) return ambix; } ambix_close(ambix); return NULL; }
void mtxinverse_tests(float32_t eps) { float32_t errf; ambix_matrix_t *mtx=0, *testresult=0; float32_t*transposedata = (float32_t*)calloc(3*4, sizeof(float32_t)); STARTTEST("\n"); /* fill in some test data 4x4 */ STARTTEST("[4x4]\n"); mtx=ambix_matrix_init(4, 4, mtx); ambix_matrix_fill_data(mtx, leftdata_4_4); testresult=ambix_matrix_init(4, 4, testresult); ambix_matrix_fill_data(testresult, resultpinv_4_4); mtxinverse_test(mtx, testresult, eps); /* fill in some test data 4x3 */ STARTTEST("[4x3]\n"); mtx=ambix_matrix_init(4, 3, mtx); ambix_matrix_fill_data(mtx, leftdata_4_3); testresult=ambix_matrix_init(3, 4, testresult); ambix_matrix_fill_data(testresult, resultpinv_4_3); mtxinverse_test(mtx, testresult, eps); /* fill in some test data 3x4 */ STARTTEST("[3x4]\n"); data_transpose(transposedata, leftdata_4_3, 4, 3); mtx=ambix_matrix_init(3, 4, mtx); ambix_matrix_fill_data(mtx, transposedata); data_transpose(transposedata, resultpinv_4_3, 3, 4); testresult=ambix_matrix_init(4, 3, testresult); ambix_matrix_fill_data(testresult, transposedata); mtxinverse_test(mtx, testresult, eps); /* fill in some test data 4x4 */ STARTTEST("[identity:4x4]\n"); mtx=ambix_matrix_init(4, 4, mtx); ambix_matrix_fill(mtx, AMBIX_MATRIX_IDENTITY); testresult=ambix_matrix_init(4, 4, testresult); ambix_matrix_fill(testresult, AMBIX_MATRIX_IDENTITY); mtxinverse_test(mtx, testresult, eps); STARTTEST("[one:4x4]\n"); mtx=ambix_matrix_init(4, 4, mtx); ambix_matrix_fill(mtx, AMBIX_MATRIX_ONE); mtxinverse_test(mtx, NULL, eps); STARTTEST("[zero:4x4]\n"); mtx=ambix_matrix_init(4, 4, mtx); ambix_matrix_fill(mtx, AMBIX_MATRIX_ZERO); mtxinverse_test(mtx, NULL, eps); STARTTEST("[SID:4x4]\n"); mtx=ambix_matrix_init(4, 4, mtx); ambix_matrix_fill(mtx, AMBIX_MATRIX_SID); testresult=ambix_matrix_init(4, 4, testresult); ambix_matrix_fill(testresult, AMBIX_MATRIX_TO_SID); mtxinverse_test(mtx, testresult, eps); STARTTEST("[N3D:4x4]\n"); mtx=ambix_matrix_init(4, 4, mtx); ambix_matrix_fill(mtx, AMBIX_MATRIX_N3D); testresult=ambix_matrix_init(4, 4, testresult); ambix_matrix_fill(testresult, AMBIX_MATRIX_TO_N3D); mtxinverse_test(mtx, testresult, eps); STARTTEST("[FUMA:4x4]\n"); mtx=ambix_matrix_init(4, 4, mtx); ambix_matrix_fill(mtx, AMBIX_MATRIX_FUMA); testresult=ambix_matrix_init(4, 4, testresult); ambix_matrix_fill(testresult, AMBIX_MATRIX_TO_FUMA); mtxinverse_test(mtx, testresult, eps); ambix_matrix_destroy(mtx); ambix_matrix_destroy(testresult); free(transposedata); STOPTEST("\n"); }