MAT * block_diagonal_MAT( const MAT mat, const int n){ validate(NULL!=mat,NULL); validate(mat->ncol==mat->nrow,NULL); // Ensure symmetry const int nelts = mat->ncol / n; // Number of blocks on diagonal validate((mat->ncol % n)==0,NULL); // Is parameter valid? // Create memory MAT * mats = calloc(nelts,sizeof(*mats)); if(NULL==mats){ goto cleanup; } for ( int i=0 ; i<nelts ; i++){ mats[i] = new_MAT(n,n); if(NULL==mats[i]){ goto cleanup;} } // Copy into diagonals for ( int i=0 ; i<nelts ; i++){ for ( int col=0 ; col<n ; col++){ const int oldcol = i*n+col; for ( int row=0 ; row<n ; row++){ const int oldrow = i*n+row; mats[i]->x[col*n+row] = mat->x[oldcol*mat->nrow+oldrow]; } } } return mats; cleanup: if(NULL!=mats){ for ( int i=0 ; i<nelts ; i++){ free_MAT(mats[i]); } } xfree(mats); return NULL; }
/** * Process intensities. * ip = Minv %*% (Intensities-N) %*% Pinv * - Uses identity: Vec(ip) = ( Pinv^t kronecker Minv) Vec(Intensities-N) * - Storing Intensities-N as an intermediate saved < 3% * - Calculating ip^t rather than ip (pcol loop is over minor index) made no difference * - Using Pinv rather than Pinv^t makes little appreciable difference */ MAT process_intensities(const MAT intensities, const MAT Minv_t, const MAT Pinv_t, const MAT N, MAT ip) { validate(NULL != intensities, NULL); validate(NULL != Minv_t, NULL); validate(NULL != Pinv_t, NULL); validate(NULL != N, NULL); const uint_fast32_t ncycle = Pinv_t->nrow; if (NULL==ip) { ip = new_MAT(NBASE, ncycle); validate(NULL != ip, NULL); } memset(ip->x, 0, ip->nrow * ip->ncol * sizeof(real_t)); // pre-calculate I - N, especially as I now integer real_t *tmp = calloc(NBASE * ncycle, sizeof(real_t)); if (NULL==tmp) { goto cleanup; } for (uint_fast32_t i = 0; i < (NBASE * ncycle); i++) { tmp[i] = intensities->xint[i] - N->x[i]; } for (uint_fast32_t icol = 0; icol < ncycle; icol++) { // Columns of Intensity for (uint_fast32_t base = 0; base < NBASE; base++) { // Bases (rows of Minv, cols of Minv_t) real_t dp = 0; for (uint_fast32_t chan = 0; chan < NBASE; chan++) { // Channels dp += Minv_t->x[base * NBASE + chan] * tmp[icol * NBASE + chan]; } for (uint_fast32_t pcol = 0; pcol < ncycle; pcol++) { // Columns of ip ip->x[pcol * NBASE + base] += Pinv_t->x[icol * ncycle + pcol] * dp; } } } free(tmp); return ip; cleanup: free_MAT(ip); return NULL; }