IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
May 3, 2010, 8:41:49 AM (16 years ago)
Author:
eugene
Message:

updates from trunk

Location:
branches/tap_branches
Files:
3 deleted
42 edited
3 copied

Legend:

Unmodified
Added
Removed
  • branches/tap_branches

  • branches/tap_branches/psLib

  • branches/tap_branches/psLib/share/Makefile.am

    r10093 r27838  
    77        tab5.2b.dat \
    88        tab5.2c.dat \
    9         finals2000A.dat \
    10         finals_all.dat
     9        finals2000A.dat
    1110
  • branches/tap_branches/psLib/src/fits/psFits.c

    r25478 r27838  
    149149            int thisErrno = errno;      // Error number
    150150            char errorBuf[MAX_STRING_LENGTH], *errorMsg;
    151 #if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE)
     151#if (((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE) ||  __APPLE__)
    152152            strerror_r(thisErrno, errorBuf, MAX_STRING_LENGTH);
    153153            errorMsg = errorBuf;
     
    208208                int thisErrno = errno;
    209209                char errorBuf[64], *errorMsg;
    210 # if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE)
     210#if (((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE) ||  __APPLE__)
    211211                strerror_r (errno, errorBuf, 64);
    212212                errorMsg = errorBuf;
  • branches/tap_branches/psLib/src/fits/psFitsHeader.c

    r25087 r27838  
    570570            // to preserve NAXISn etc for reference, so we don't do this.
    571571
     572            if (keywordInList(name, noWriteFitsKeys) ||
     573                (keyStarts && keywordStartsWith(name, noWriteFitsKeyStarts))) {
     574                psTrace("psLib.fits", 3, "Not writing FITS keyword %s", name);
     575                continue;
     576            }
     577
    572578            // Options for compression
    573579            if (compressing) {
     
    582588            } else if (keywordInList(name, noWriteCompressedKeys) ||
    583589                       (keyStarts && keywordStartsWith(name, noWriteCompressedKeyStarts))) {
    584                 psTrace("psLib.fits", 3, "Not writing FITS keyword %s", name);
    585                 continue;
    586             }
    587 
    588             if (keywordInList(name, noWriteFitsKeys) ||
    589                 (keyStarts && keywordStartsWith(name, noWriteFitsKeyStarts))) {
    590590                psTrace("psLib.fits", 3, "Not writing FITS keyword %s", name);
    591591                continue;
  • branches/tap_branches/psLib/src/fits/psFitsImage.c

    r25002 r27838  
    498498    psImage *inImage;                   // Image to read in
    499499    if (floatType == PS_FITS_FLOAT_NONE) {
    500         inImage = psImageRecycle(outImage, numCols, numRows, info->psDatatype);
    501         outImage = psMemIncrRefCounter(inImage);
     500        if (!outImage || outImage->type.type == info->psDatatype) {
     501            outImage = psImageRecycle(outImage, numCols, numRows, info->psDatatype);
     502            inImage = psMemIncrRefCounter(outImage);
     503        } else {
     504            outImage = psImageRecycle(outImage, numCols, numRows, outImage->type.type);
     505            inImage = psImageAlloc(numCols, numRows, info->psDatatype);
     506        }
    502507    } else {
    503508        inImage = psImageAlloc(numCols, numRows, info->psDatatype);
     
    511516        return NULL;
    512517    }
    513     psFree(info);
    514518
    515519    if (floatType != PS_FITS_FLOAT_NONE) {
    516520        outImage = psFitsFloatImageFromDisk(outImage, inImage, floatType);
    517     }
     521    } else if (outImage->type.type != info->psDatatype) {
     522        outImage = psImageCopy(outImage, inImage, outImage->type.type);
     523    }
     524    psFree(info);
    518525    psFree(inImage);
    519526
  • branches/tap_branches/psLib/src/fits/psFitsScale.c

    r25439 r27838  
    1515#include "psImage.h"
    1616#include "psFits.h"
     17#include "psStats.h"
     18#include "psImageStats.h"
    1719#include "psImageBackground.h"
    18 #include "psStats.h"
    1920#include "psImageStructManip.h"
    2021
     
    2930#define MEAN_STAT PS_STAT_ROBUST_MEDIAN // Statistic to use for mean
    3031#define STDEV_STAT PS_STAT_ROBUST_STDEV // Statistic to use for stdev
     32
     33#define DESPERATE_MEAN_STAT PS_STAT_SAMPLE_MEDIAN // Statistic to use for mean when deperate
     34#define DESPERATE_STDEV_STAT PS_STAT_SAMPLE_QUARTILE // Statistic to use for stdev when desperate
    3135
    3236
     
    118122    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS);
    119123    psStats *stats = psStatsAlloc(MEAN_STAT | STDEV_STAT); // Statistics object
     124    double mean, stdev;                                    // Mean and standard deviation
    120125    if (!psImageBackground(stats, NULL, image, mask, maskVal, rng)) {
    121         psError(PS_ERR_UNKNOWN, false, "Unable to perform statistics on image");
    122         psFree(rng);
    123         psFree(stats);
    124         return false;
     126        // It could be because the image is entirely masked, in which case we don't want to error
     127        bool good = false;              // Any good pixels?
     128
     129
     130// Find good pixels in an image, by image type
     131#define GOOD_PIXELS_CASE(TYPE) \
     132      case PS_TYPE_##TYPE: \
     133        for (int y = 0; y < image->numRows && !good; y++) { \
     134            for (int x = 0; x < image->numCols && !good; x++) { \
     135                if (mask && (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal)) { \
     136                    continue; \
     137                } \
     138                if (!isfinite(image->data.TYPE[y][x])) { \
     139                    continue; \
     140                } \
     141                good = true; \
     142            } \
     143        } \
     144        break;
     145
     146        switch (image->type.type) {
     147            GOOD_PIXELS_CASE(F32);
     148            GOOD_PIXELS_CASE(F64);
     149          default:
     150            psAbort("Unsupported case: %x", image->type.type);
     151        }
     152
     153        if (!good) {
     154            psLogMsg("psLib.fits", PS_LOG_DETAIL, "Image has no good pixels, setting BSCALE = 1, BZERO = 0");
     155            psErrorClear();
     156            *bscale = 1.0;
     157            *bzero = 0.0;
     158            psFree(rng);
     159            psFree(stats);
     160            return true;
     161        }
     162
     163        // There are some good pixels in there somewhere; psImageBackground just didn't find them
     164        psLogMsg("psLib.fits", PS_LOG_DETAIL,
     165                 "Couldn't measure background statistics for image quantisation; retrying.");
     166        psErrorClear();
     167        // Retry using all the available pixels
     168        stats->nSubsample = image->numCols * image->numRows + 1;
     169        if (!psImageStats(stats, image, mask, maskVal)) {
     170            psLogMsg("psLib.fits", PS_LOG_DETAIL,
     171                     "Couldn't measure background statistics for image quantisation (attempt 2); retrying.");
     172            psErrorClear();
     173            // Retry with desperate statistic
     174            stats->options = DESPERATE_MEAN_STAT | DESPERATE_STDEV_STAT;
     175            if (!psImageStats(stats, image, mask, maskVal)) {
     176                psError(PS_ERR_UNKNOWN, false, "Unable to measure background statistics for image");
     177                psFree(rng);
     178                psFree(stats);
     179                return false;
     180            } else {
     181                // Desperate retry
     182                mean = psStatsGetValue(stats, DESPERATE_MEAN_STAT);
     183                stdev = psStatsGetValue(stats, DESPERATE_STDEV_STAT);
     184            }
     185        } else {
     186            // Retry with all available pixels
     187            mean = psStatsGetValue(stats, MEAN_STAT);
     188            stdev = psStatsGetValue(stats, STDEV_STAT);
     189        }
     190    } else {
     191        // First attempt
     192        mean = psStatsGetValue(stats, MEAN_STAT);
     193        stdev = psStatsGetValue(stats, STDEV_STAT);
    125194    }
    126195    psFree(rng);
    127 
    128     double mean = psStatsGetValue(stats, MEAN_STAT); // Mean
    129     double stdev = psStatsGetValue(stats, STDEV_STAT); // Standard deviation
    130196    psFree(stats);
    131197    if (!isfinite(mean) || !isfinite(stdev)) {
     
    318384                } else { \
    319385                    value = (value - zero) * scale; \
    320                     if (options->fuzz) { \
     386                    if (options->fuzz && (value - (int)value != 0.0)) { \
    321387                       /* Add random factor [-0.5,0.5): adds a variance of 1/12, */ \
    322388                       /* but preserves the expectation value */ \
  • branches/tap_branches/psLib/src/fits/psFitsTable.c

    r24512 r27838  
    162162
    163163        switch (typecode) {
     164           // TBYTE and TSHORT fall though to read into psS32
    164165          case TBYTE:
    165166          case TSHORT:
    166           case TLONGLONG:
    167167            READ_TABLE_ROW_CASE(TLONG, long, S32, S32);
     168            READ_TABLE_ROW_CASE(TLONGLONG, long, S64, S64);
    168169            READ_TABLE_ROW_CASE(TFLOAT, float, F32, F32);
    169170            READ_TABLE_ROW_CASE(TDOUBLE, double, F64, F64);
  • branches/tap_branches/psLib/src/imageops/psImageBackground.c

    r24481 r27838  
    1515#include "psRandom.h"
    1616#include "psError.h"
     17
     18static int nFailures = 0;
     19
     20void psImageBackgroundInit() {
     21    nFailures = 0;
     22    return;
     23}
    1724
    1825// XXX allow the user to choose the stats method?
     
    3946    long ny = image->numRows;
    4047
    41     const int Npixels = nx*ny;                // Total number of pixels
     48    psImage *bad = psImageAlloc(nx, ny, PS_TYPE_U8); // Image with bad pixels
     49    psImageInit(bad, 0);
     50
     51    int Npixels = 0;                    // Total number of pixels
     52    for (int y = 0; y < ny; y++) {
     53        for (int x = 0; x < nx; x++) {
     54            if (!isfinite(image->data.F32[y][x]) ||
     55                (mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskValue)) {
     56                bad->data.U8[y][x] = 0xFF;
     57            }
     58            Npixels++;
     59        }
     60    }
     61
    4262    const int Nsubset = (stats->nSubsample == 0) ? Npixels : PS_MIN(stats->nSubsample, Npixels); // Number of pixels in subset
    4363
     
    5878    long n = 0;                         // Number of actual pixels in subset
    5979    if (Nsubset >= Npixels) {
    60         // if we have an image smaller than Nsubset, just loop over the image pixels
    61         for (int iy = 0; iy < ny; iy++) {
    62             for (int ix = 0; ix < nx; ix++) {
    63                 if (!isfinite(image->data.F32[iy][ix]) || (mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskValue)) {
    64                     continue;
    65                 }
     80        // if we have an image smaller than Nsubset, just loop over the (good) image pixels
     81        for (int iy = 0; iy < ny; iy++) {
     82            for (int ix = 0; ix < nx; ix++) {
     83                if (bad->data.U8[iy][ix]) {
     84                    continue;
     85                }
    6686
    67                 float value = image->data.F32[iy][ix];
    68                 min = PS_MIN(value, min);
    69                 max = PS_MAX(value, max);
    70                 values->data.F32[n] = value;
    71                 n++;
    72             }
    73         }
     87                float value = image->data.F32[iy][ix];
     88                min = PS_MIN(value, min);
     89                max = PS_MAX(value, max);
     90                values->data.F32[n] = value;
     91                n++;
     92            }
     93        }
    7494    } else {
    75         for (long i = 0; i < Nsubset; i++) {
    76             double frnd = psRandomUniform(rng);
    77             int pixel = Npixels * frnd;
    78             int ix = pixel % nx;
    79             int iy = pixel / nx;
     95        // Subsample all pixels
     96        // This is not optimal, since there may be a large masked fraction that leaves us with few good pixels.
     97        // In that case, you should have set Nsubset.......
     98        Npixels = nx * ny;
     99        for (long i = 0; i < Nsubset; i++) {
     100            double frnd = psRandomUniform(rng);
     101            int pixel = Npixels * frnd;
     102            int ix = pixel % nx;
     103            int iy = pixel / nx;
    80104
    81             if (!isfinite(image->data.F32[iy][ix]) || (mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskValue)) {
    82                 continue;
    83             }
     105            if (bad->data.U8[iy][ix]) {
     106                continue;
     107            }
    84108
    85             float value = image->data.F32[iy][ix];
    86             min = PS_MIN(value, min);
    87             max = PS_MAX(value, max);
    88             values->data.F32[n] = value;
    89             n++;
    90         }
     109            float value = image->data.F32[iy][ix];
     110            min = PS_MIN(value, min);
     111            max = PS_MAX(value, max);
     112            values->data.F32[n] = value;
     113            n++;
     114        }
    91115    }
     116
     117    psFree(bad);
     118
    92119    if (n < 0.01*Nsubset) {
    93         psLogMsg("psLib.psImageBackground", PS_LOG_DETAIL,
    94                  "Unable to measure image background: too few data points (%ld)", n);
     120        if ((nFailures < 3) || (nFailures % 100 == 0)) {
     121            psLogMsg("psLib.psImageBackground", PS_LOG_DETAIL, "Unable to measure image background: too few data points (%ld) (%d failures)", n, nFailures);
     122        }
     123        nFailures ++;
    95124        psFree(values);
    96125        return false;
     
    108137
    109138        if (!psVectorSort(values, values)) {
    110             psError(PS_ERR_UNKNOWN, false, "Unable to sort values.\n");
     139            if ((nFailures < 3) || (nFailures % 100 == 0)) {
     140                psError(PS_ERR_UNKNOWN, false, "Unable to sort values.(%d failures)\n", nFailures);
     141            }
     142            nFailures ++;
    111143            psFree(values);
    112144            return false;
     
    132164                fclose (f);
    133165            }
    134             psError(PS_ERR_UNKNOWN, false, "Unable to measure statistics for image background "
    135                     "(%dx%d, (row0,col0) = (%d,%d)",
    136                     image->numRows, image->numCols, image->row0, image->col0);
     166            if ((nFailures < 3) || (nFailures % 100 == 0)) {
     167                psError(PS_ERR_UNKNOWN, false, "Unable to measure statistics for image background "
     168                        "(%dx%d, (row0,col0) = (%d,%d) (%d failures)\n",
     169                        image->numRows, image->numCols, image->row0, image->col0, nFailures);
     170            }
     171            nFailures ++;
    137172            psFree(values);
    138173            return false;
  • branches/tap_branches/psLib/src/imageops/psImageBackground.h

    r21183 r27838  
    2222#include <psRandom.h>
    2323
     24void psImageBackgroundInit();
     25
    2426// Get the background for an image
    2527bool psImageBackground(psStats *stats, // desired measurement and options
  • branches/tap_branches/psLib/src/imageops/psImageConvolve.c

    r25383 r27838  
    246246    return kernel;
    247247}
     248
     249bool psKernelTruncate(psKernel *kernel, float frac)
     250{
     251    PS_ASSERT_KERNEL_NON_NULL(kernel, false);
     252    PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(frac, 0.0, false);
     253    PS_ASSERT_FLOAT_LESS_THAN(frac, 1.0, false);
     254
     255    if (frac == 0.0) {
     256        // Nothing to do
     257        return true;
     258    }
     259
     260    int xMin = kernel->xMin, xMax = kernel->xMax, yMin = kernel->yMin, yMax = kernel->yMax; // Bounds
     261    int maxSize = PS_MAX(PS_MAX(PS_MAX(-xMin, xMax), -yMin), yMax); // Maximum size
     262
     263    // Determine the threshold
     264    // Summing absolute values because large negative deviations have power as well
     265    double sumKernel = 0.0;             // Sum of the kernel
     266    for (int y = yMin; y <= yMax; y++) {
     267        for (int x = xMin; x <= xMax; x++) {
     268            sumKernel += fabsf(kernel->kernel[y][x]);
     269        }
     270    }
     271
     272    float threshold = sumKernel * (1.0 - frac); // Threshold for truncation
     273
     274    // Find truncation size
     275    int truncate = 0;                     // Truncation radius
     276    for (int radius = 1; truncate == 0 && radius < maxSize; radius++) {
     277        int uMin = PS_MAX(-radius, xMin);
     278        int uMax = PS_MIN(radius, xMax);
     279        int vMin = PS_MAX(-radius, yMin);
     280        int vMax = PS_MIN(radius, yMax);
     281        int r2 = PS_SQR(radius);
     282        double sum = 0.0;
     283        for (int v = vMin; v <= vMax; v++) {
     284            int v2 = PS_SQR(v);
     285            for (int u = uMin; u <= uMax; u++) {
     286                int u2 = PS_SQR(u);
     287                if (u2 + v2 <= r2) {
     288                    sum += fabsf(kernel->kernel[v][u]);
     289                }
     290            }
     291        }
     292        if (sum > threshold) {
     293            // This is the truncation radius
     294            truncate = radius;
     295        }
     296    }
     297    if (truncate == maxSize) {
     298        // No truncation possible
     299        return true;
     300    }
     301
     302    // Truncate the kernel
     303    {
     304        int uMin = PS_MAX(-truncate, xMin);
     305        int uMax = PS_MIN(truncate, xMax);
     306        int vMin = PS_MAX(-truncate, yMin);
     307        int vMax = PS_MIN(truncate, yMax);
     308        int r2 = PS_SQR(truncate);
     309        for (int v = vMin; v <= vMax; v++) {
     310            int v2 = PS_SQR(v);
     311            for (int u = uMin; u <= uMax; u++) {
     312                int u2 = PS_SQR(u);
     313                if (u2 + v2 > r2) {
     314                    kernel->kernel[v][u] = 0.0;
     315                }
     316            }
     317        }
     318    }
     319    kernel->xMin = PS_MAX(-truncate, kernel->xMin);
     320    kernel->xMax = PS_MIN(truncate, kernel->xMax);
     321    kernel->yMin = PS_MAX(-truncate, kernel->yMin);
     322    kernel->yMax = PS_MIN(truncate, kernel->yMax);
     323
     324    return true;
     325    }
     326
     327
    248328
    249329psImage *psImageConvolveDirect(psImage *out, const psImage *in, const psKernel *kernel)
  • branches/tap_branches/psLib/src/imageops/psImageConvolve.h

    r25383 r27838  
    138138);
    139139
     140/// Truncate a kernel
     141///
     142/// Truncates the outer parts of the kernel where the contribution is below the nominated fraction of the
     143/// total kernel.
     144bool psKernelTruncate(
     145    psKernel *in,                       ///< Kernel to be truncated
     146    float frac                          ///< Fraction for truncation threshold
     147    );
     148
     149
    140150/// Convolve an image with a kernel, using a direct convolution
    141151///
  • branches/tap_branches/psLib/src/imageops/psImageCovariance.c

    r24832 r27838  
    1414#include "psTrace.h"
    1515#include "psBinaryOp.h"
     16#include "psScalar.h"
     17#include "psThread.h"
    1618
    1719#include "psImageCovariance.h"
     20
     21static bool threaded = false;           // Run threaded?
     22
    1823
    1924psKernel *psImageCovarianceNone(void)
     
    2429}
    2530
    26 
    27 psKernel *psImageCovarianceCalculate(const psKernel *kernel, const psKernel *covariance)
    28 {
    29     PS_ASSERT_KERNEL_NON_NULL(kernel, NULL);
    30 
    31     // See http://en.wikipedia.org/wiki/Error_propagation
    32     //
    33     // If
    34     //     f_k = sum_i A_ik x_i
    35     // is a set of functions, then the covariance matrix for f is given by:
    36     //     M^f_ij = sum_k sum_l A_ik M^x_kl A_lj
    37     // where M^x is the covariance matrix for x.
    38     // Note that the errors in f are correlated (covariance) even if the errors in x are not.
    39 
    40     psKernel *covar;                    // Covariance matrix to use
    41     if (covariance) {
    42         covar = psMemIncrRefCounter((psKernel*)covariance); // Casting away const
    43     } else {
    44         covar = psImageCovarianceNone();
    45     }
    46 
    47     // Check for non-finite elements
    48     for (int y = kernel->yMin; y <= kernel->yMax; y++) {
    49         for (int x = kernel->xMin; x <= kernel->xMax; x++) {
    50             if (!isfinite(kernel->kernel[y][x])) {
    51                 psError(PS_ERR_BAD_PARAMETER_VALUE, true,
    52                         "Non-finite covariance matrix element in kernel at %d,%d", x, y);
    53                 psFree(covar);
    54                 return NULL;
    55             }
    56         }
    57     }
    58     for (int y = covar->yMin; y <= covar->yMax; y++) {
    59         for (int x = covar->xMin; x <= covar->xMax; x++) {
    60             if (!isfinite(covar->kernel[y][x])) {
    61                 psError(PS_ERR_BAD_PARAMETER_VALUE, true,
    62                         "Non-finite covariance matrix element in covariance matrix at %d,%d", x, y);
    63                 psFree(covar);
    64                 return NULL;
    65             }
    66         }
    67     }
    68 
    69     // The above (double) sum for the covariance matrix means that, for each point in the output covariance
    70     // matrix, we need to work out all combinations of getting to the central point via a kernel, input
    71     // covariance matrix and another kernel.  This means that the resultant covariance matrix has twice the
    72     // size of the kernel plus the size of the input covariance matrix.
    73     int xMin = kernel->xMin - kernel->xMax + covar->xMin, xMax = kernel->xMax - kernel->xMin + covar->xMax;
    74     int yMin = kernel->yMin - kernel->yMax + covar->yMin, yMax = kernel->yMax - kernel->yMin + covar->yMax;
    75     psKernel *out = psKernelAlloc(xMin, xMax, yMin, yMax); // Covariance matrix for output
     31/// Calculation of covariance matrix element when convolving
     32static float imageCovarianceCalculate(const psKernel *covar, // Original covariance matrix
     33                                      const psKernel *kernel, // Convolution kernel
     34                                      int x, int y            // Coordinates in output covariance matrix
     35                                      )
     36{
     37    psAssert(covar, "Require covariance matrix");
     38    psAssert(kernel, "Require kernel");
    7639
    7740    // Need to go:
     
    8952    // from the source coordinate), we take the smallest possible (because everything else is zero outside).
    9053
    91     double total = 0.0;                 // Total covariance
     54    // Range for v
     55    int vMin = PS_MAX(kernel->yMin + covar->yMin, y + kernel->yMin);
     56    int vMax = PS_MIN(kernel->yMax + covar->yMax, y + kernel->yMax);
     57    // Range for u
     58    int uMin = PS_MAX(kernel->xMin + covar->xMin, x + kernel->xMin);
     59    int uMax = PS_MIN(kernel->xMax + covar->xMax, x + kernel->xMax);
     60
     61    double sum = 0.0;           // Sum for value of covariance matrix at (x,y)
     62    for (int v = vMin; v <= vMax; v++) {
     63        // Range for q
     64        int qMin = PS_MAX(v + covar->yMin, kernel->yMin);
     65        int qMax = PS_MIN(v + covar->yMax, kernel->yMax);
     66        for (int u = uMin; u <= uMax; u++) {
     67            // Range for p
     68            int pMin = PS_MAX(u + covar->xMin, kernel->xMin);
     69            int pMax = PS_MIN(u + covar->xMax, kernel->xMax);
     70
     71            double xyuvValue = kernel->kernel[v-y][u-x]; // Value for (x,y) --> (u,v)
     72
     73            double uvpqValue = 0.0; // Value for (u,v) --> (p,q) --> (0,0)
     74            for (int q = qMin; q <= qMax; q++) {
     75                for (int p = pMin; p <= pMax; p++) {
     76                    uvpqValue += (double)covar->kernel[q-v][p-u] * (double)kernel->kernel[q][p];
     77                }
     78            }
     79            sum += xyuvValue * uvpqValue;
     80        }
     81    }
     82
     83    return sum;
     84}
     85
     86/// Thread entry point for calculation of covariance matrix element when convolving
     87static bool imageCovarianceCalculateThread(psThreadJob *job)
     88{
     89    PS_ASSERT_THREAD_JOB_NON_NULL(job, false);
     90    psAssert(job->args, "No job arguments");
     91    psAssert(job->args->n == 5, "Wrong number of job arguments: %ld", job->args->n);
     92
     93    psKernel *out = job->args->data[0]; // Output covariance matrix
     94    const psKernel *covar = job->args->data[1]; // Input covariance matrix
     95    const psKernel *kernel = job->args->data[2]; // Convolution kernel
     96    int x = PS_SCALAR_VALUE(job->args->data[3], S32); // x coordinate in output covariance matrix
     97    int y = PS_SCALAR_VALUE(job->args->data[4], S32); // y coordinate in output covariance matrix
     98
     99    out->kernel[y][x] = imageCovarianceCalculate(covar, kernel, x, y);
     100
     101    return true;
     102}
     103
     104
     105
     106psKernel *psImageCovarianceCalculate(const psKernel *kernel, const psKernel *covariance)
     107{
     108    PS_ASSERT_KERNEL_NON_NULL(kernel, NULL);
     109
     110    // See http://en.wikipedia.org/wiki/Error_propagation
     111    //
     112    // If
     113    //     f_k = sum_i A_ik x_i
     114    // is a set of functions, then the covariance matrix for f is given by:
     115    //     M^f_ij = sum_k sum_l A_ik M^x_kl A_lj
     116    // where M^x is the covariance matrix for x.
     117    // Note that the errors in f are correlated (covariance) even if the errors in x are not.
     118
     119    psKernel *covar;                    // Covariance matrix to use
     120    if (covariance) {
     121        covar = psMemIncrRefCounter((psKernel*)covariance); // Casting away const
     122    } else {
     123        covar = psImageCovarianceNone();
     124    }
     125
     126    // Check for non-finite elements
     127    for (int y = kernel->yMin; y <= kernel->yMax; y++) {
     128        for (int x = kernel->xMin; x <= kernel->xMax; x++) {
     129            if (!isfinite(kernel->kernel[y][x])) {
     130                psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     131                        "Non-finite covariance matrix element in kernel at %d,%d", x, y);
     132                psFree(covar);
     133                return NULL;
     134            }
     135        }
     136    }
     137    for (int y = covar->yMin; y <= covar->yMax; y++) {
     138        for (int x = covar->xMin; x <= covar->xMax; x++) {
     139            if (!isfinite(covar->kernel[y][x])) {
     140                psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     141                        "Non-finite covariance matrix element in covariance matrix at %d,%d", x, y);
     142                psFree(covar);
     143                return NULL;
     144            }
     145        }
     146    }
     147
     148    // The above (double) sum for the covariance matrix means that, for each point in the output covariance
     149    // matrix, we need to work out all combinations of getting to the central point via a kernel, input
     150    // covariance matrix and another kernel.  This means that the resultant covariance matrix has twice the
     151    // size of the kernel plus the size of the input covariance matrix.
     152    int xMin = kernel->xMin - kernel->xMax + covar->xMin, xMax = kernel->xMax - kernel->xMin + covar->xMax;
     153    int yMin = kernel->yMin - kernel->yMax + covar->yMin, yMax = kernel->yMax - kernel->yMin + covar->yMax;
     154    psKernel *out = psKernelAlloc(xMin, xMax, yMin, yMax); // Covariance matrix for output
     155
    92156    for (int y = yMin; y <= yMax; y++) {
    93         // Range for v
    94         int vMin = PS_MAX(kernel->yMin + covar->yMin, y + kernel->yMin);
    95         int vMax = PS_MIN(kernel->yMax + covar->yMax, y + kernel->yMax);
    96157        for (int x = xMin; x <= xMax; x++) {
    97             // Range for u
    98             int uMin = PS_MAX(kernel->xMin + covar->xMin, x + kernel->xMin);
    99             int uMax = PS_MIN(kernel->xMax + covar->xMax, x + kernel->xMax);
    100 
    101             double sum = 0.0;           // Sum for value of covariance matrix at (x,y)
    102             for (int v = vMin; v <= vMax; v++) {
    103                 // Range for q
    104                 int qMin = PS_MAX(v + covar->yMin, kernel->yMin);
    105                 int qMax = PS_MIN(v + covar->yMax, kernel->yMax);
    106                 for (int u = uMin; u <= uMax; u++) {
    107                     // Range for p
    108                     int pMin = PS_MAX(u + covar->xMin, kernel->xMin);
    109                     int pMax = PS_MIN(u + covar->xMax, kernel->xMax);
    110 
    111                     double xyuvValue = kernel->kernel[v-y][u-x]; // Value for (x,y) --> (u,v)
    112 
    113                     double uvpqValue = 0.0; // Value for (u,v) --> (p,q) --> (0,0)
    114                     for (int q = qMin; q <= qMax; q++) {
    115                         for (int p = pMin; p <= pMax; p++) {
    116                             uvpqValue += (double)covar->kernel[q-v][p-u] * (double)kernel->kernel[q][p];
    117                         }
    118                     }
    119                     sum += xyuvValue * uvpqValue;
     158            if (threaded) {
     159                psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_COVARIANCE_CALCULATE");
     160                psArrayAdd(job->args, 1, out);
     161                psArrayAdd(job->args, 1, covar);
     162                psArrayAdd(job->args, 1, (psKernel*)kernel); // Casting away const
     163                PS_ARRAY_ADD_SCALAR(job->args, x, PS_TYPE_S32);
     164                PS_ARRAY_ADD_SCALAR(job->args, y, PS_TYPE_S32);
     165                if (!psThreadJobAddPending(job)) {
     166                    psFree(covar);
     167                    return NULL;
    120168                }
    121             }
    122             out->kernel[y][x] = sum;
    123             total += sum;
    124         }
    125     }
    126     psTrace("psLib.imageops", 3, "Total covariance: %lf ; Central variance: %f\n", total, out->kernel[0][0]);
    127 
     169                psFree(job);
     170            } else {
     171                out->kernel[y][x] = imageCovarianceCalculate(covar, kernel, x, y);
     172            }
     173        }
     174    }
    128175    psFree(covar);
     176
     177    if (threaded && !psThreadPoolWait(true)) {
     178        psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
     179        return false;
     180    }
     181
    129182    return out;
    130183}
     184
     185float psImageCovarianceCalculateFactor(const psKernel *kernel, const psKernel *covariance)
     186{
     187    psKernel *covar;                    // Covariance matrix to use
     188    if (covariance) {
     189        covar = psMemIncrRefCounter((psKernel*)covariance); // Casting away const
     190    } else {
     191        covar = psImageCovarianceNone();
     192    }
     193
     194    // Check for non-finite elements
     195    for (int y = kernel->yMin; y <= kernel->yMax; y++) {
     196        for (int x = kernel->xMin; x <= kernel->xMax; x++) {
     197            if (!isfinite(kernel->kernel[y][x])) {
     198                psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     199                        "Non-finite covariance matrix element in kernel at %d,%d", x, y);
     200                psFree(covar);
     201                return NAN;
     202            }
     203        }
     204    }
     205    for (int y = covar->yMin; y <= covar->yMax; y++) {
     206        for (int x = covar->xMin; x <= covar->xMax; x++) {
     207            if (!isfinite(covar->kernel[y][x])) {
     208                psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     209                        "Non-finite covariance matrix element in covariance matrix at %d,%d", x, y);
     210                psFree(covar);
     211                return NAN;
     212            }
     213        }
     214    }
     215
     216    float factor = imageCovarianceCalculate(covar, kernel, 0, 0); // Covariance factor
     217    psFree(covar);
     218    return factor;
     219}
     220
     221// Calculation of covariance matrix element when binning
     222static float imageCovarianceBin(const psKernel *covar, // Original covariance matrix
     223                                int bin,               // Binning factor
     224                                float binVal,          // Convolution kernel value for binning
     225                                int x, int y           // Coordinates in output covariance matrix
     226    )
     227{
     228    psAssert(covar, "Require covariance matrix");
     229    psAssert(bin > 0 && binVal > 0, "Require binning: %d %f", bin, binVal);
     230
     231    int binMin = -(bin - 1) / 2, binMax = bin / 2; // Range of "kernel"
     232
     233    // Range for v
     234    int vMin = PS_MAX(binMin + covar->yMin, bin * y + binMin);
     235    int vMax = PS_MIN(binMax + covar->yMax, bin * y + binMax);
     236    // Range for u
     237    int uMin = PS_MAX(binMin + covar->xMin, bin * x + binMin);
     238    int uMax = PS_MIN(binMax + covar->xMax, bin * x + binMax);
     239
     240    double sum = 0.0;           // Sum for value of covariance matrix at (x,y)
     241    for (int v = vMin; v <= vMax; v++) {
     242        // Range for q
     243        int qMin = PS_MAX(v + covar->yMin, binMin);
     244        int qMax = PS_MIN(v + covar->yMax, binMax);
     245        for (int u = uMin; u <= uMax; u++) {
     246            // Range for p
     247            int pMin = PS_MAX(u + covar->xMin, binMin);
     248            int pMax = PS_MIN(u + covar->xMax, binMax);
     249
     250            double xyuvValue = binVal; // Value for (x,y) --> (u,v)
     251
     252            double uvpqValue = 0.0; // Value for (u,v) --> (p,q) --> (0,0)
     253            for (int q = qMin; q <= qMax; q++) {
     254                for (int p = pMin; p <= pMax; p++) {
     255                    uvpqValue += (double)covar->kernel[q-v][p-u] * (double)binVal;
     256                }
     257            }
     258            sum += xyuvValue * uvpqValue;
     259        }
     260    }
     261
     262    return sum;
     263}
     264
     265/// Thread entry point for calculation of covariance matrix element when binning
     266static bool imageCovarianceBinThread(psThreadJob *job)
     267{
     268    PS_ASSERT_THREAD_JOB_NON_NULL(job, false);
     269    psAssert(job->args, "No job arguments");
     270    psAssert(job->args->n == 6, "Wrong number of job arguments: %ld", job->args->n);
     271
     272    psKernel *out = job->args->data[0]; // Output covariance matrix
     273    const psKernel *covar = job->args->data[1]; // Input covariance matrix
     274    int bin = PS_SCALAR_VALUE(job->args->data[2], S32); // Binning factor
     275    float binVal = PS_SCALAR_VALUE(job->args->data[3], F32); // Convolution kernel value for binning
     276    int x = PS_SCALAR_VALUE(job->args->data[4], S32); // x coordinate in output covariance matrix
     277    int y = PS_SCALAR_VALUE(job->args->data[5], S32); // y coordinate in output covariance matrix
     278
     279    out->kernel[y][x] = imageCovarianceBin(covar, bin, binVal, x, y);
     280
     281    return true;
     282}
     283
    131284
    132285psKernel *psImageCovarianceBin(int bin, const psKernel *covariance, bool average)
     
    165318    psKernel *out = psKernelAlloc(xMin, xMax, yMin, yMax); // Covariance matrix for output
    166319
    167     double total = 0.0;                 // Total covariance
    168320    for (int y = yMin; y <= yMax; y++) {
    169         // Range for v
    170         int vMin = PS_MAX(binMin + covar->yMin, bin * y + binMin);
    171         int vMax = PS_MIN(binMax + covar->yMax, bin * y + binMax);
    172321        for (int x = xMin; x <= xMax; x++) {
    173             // Range for u
    174             int uMin = PS_MAX(binMin + covar->xMin, bin * x + binMin);
    175             int uMax = PS_MIN(binMax + covar->xMax, bin * x + binMax);
    176 
    177             double sum = 0.0;           // Sum for value of covariance matrix at (x,y)
    178             for (int v = vMin; v <= vMax; v++) {
    179                 // Range for q
    180                 int qMin = PS_MAX(v + covar->yMin, binMin);
    181                 int qMax = PS_MIN(v + covar->yMax, binMax);
    182                 for (int u = uMin; u <= uMax; u++) {
    183                     // Range for p
    184                     int pMin = PS_MAX(u + covar->xMin, binMin);
    185                     int pMax = PS_MIN(u + covar->xMax, binMax);
    186 
    187                     double xyuvValue = binVal; // Value for (x,y) --> (u,v)
    188 
    189                     double uvpqValue = 0.0; // Value for (u,v) --> (p,q) --> (0,0)
    190                     for (int q = qMin; q <= qMax; q++) {
    191                         for (int p = pMin; p <= pMax; p++) {
    192                             uvpqValue += (double)covar->kernel[q-v][p-u] * (double)binVal;
    193                         }
    194                     }
    195                     sum += xyuvValue * uvpqValue;
     322            if (threaded) {
     323                psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_COVARIANCE_BIN");
     324                psArrayAdd(job->args, 1, out);
     325                psArrayAdd(job->args, 1, covar);
     326                PS_ARRAY_ADD_SCALAR(job->args, bin, PS_TYPE_S32);
     327                PS_ARRAY_ADD_SCALAR(job->args, binVal, PS_TYPE_F32);
     328                PS_ARRAY_ADD_SCALAR(job->args, x, PS_TYPE_S32);
     329                PS_ARRAY_ADD_SCALAR(job->args, y, PS_TYPE_S32);
     330                if (!psThreadJobAddPending(job)) {
     331                    psFree(covar);
     332                    return NULL;
    196333                }
    197             }
    198             out->kernel[y][x] = sum;
    199             total += sum;
    200         }
    201     }
    202     psTrace("psLib.imageops", 3, "Total covariance: %lf ; Central variance: %f\n", total, out->kernel[0][0]);
    203 
     334                psFree(job);
     335            } else {
     336                out->kernel[y][x] = imageCovarianceBin(covar, bin, binVal, x, y);
     337            }
     338        }
     339    }
    204340    psFree(covar);
    205341
     342    if (threaded && !psThreadPoolWait(true)) {
     343        psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
     344        return false;
     345    }
     346
    206347    return out;
    207348}
     
    212353}
    213354
    214 psKernel *psImageCovarianceSum(const psArray *array)
     355float psImageCovarianceFactorForAperture(const psKernel *covar, float radius)
     356{
     357    if (!covar) return 1.0;
     358
     359    float Sum = 0.0;
     360
     361    for (int y = covar->yMin; y <= covar->yMax; y++) {
     362        if (y < -radius) continue;
     363        if (y > +radius) continue;
     364        for (int x = covar->xMin; x <= covar->xMax; x++) {
     365            if (x < -radius) continue;
     366            if (x > +radius) continue;
     367
     368            if (hypot(x, y) > radius) continue;
     369
     370            psAssert (isfinite(covar->kernel[y][x]), "invalid NAN in covariance matrix");
     371            Sum += covar->kernel[y][x];
     372        }
     373    }
     374
     375    return Sum;
     376}
     377
     378float psImageCovarianceSum(const psKernel *covar)
     379{
     380    PS_ASSERT_KERNEL_NON_NULL(covar, NAN);
     381
     382    int xMin = covar->xMin, xMax = covar->xMax, yMin = covar->yMin, yMax = covar->yMax; // Range for covariance
     383    double sum = 0.0;                                                                   // Sum of covariance
     384    for (int y = yMin; y <= yMax; y++) {
     385        for (int x = xMin; x <= xMax; x++) {
     386            sum += covar->kernel[y][x];
     387        }
     388    }
     389
     390    return sum;
     391}
     392
     393
     394psKernel *psImageCovarianceAverage(const psArray *array)
    215395{
    216396    PS_ASSERT_ARRAY_NON_NULL(array, NULL);
    217397    PS_ASSERT_ARRAY_NON_EMPTY(array, NULL);
    218398
    219     int xMin = INT_MAX, xMax = INT_MIN, yMin = INT_MAX, yMax = INT_MIN; // Range for covariance
    220     int num = 0;                        // Number of good matrices to sum
    221     for (int i = 0; i < array->n; i++) {
    222         psKernel *covar = array->data[i]; // Covariance matrix
    223         if (!covar) {
    224             continue;
    225         }
    226         xMin = PS_MIN(xMin, covar->xMin);
    227         xMax = PS_MAX(xMax, covar->xMax);
    228         yMin = PS_MIN(yMin, covar->yMin);
    229         yMax = PS_MAX(yMax, covar->yMax);
    230         num++;
    231     }
    232     if (num == 0) {
    233         psError(PS_ERR_BAD_PARAMETER_SIZE, true, "No covariance matrices supplied for summation");
    234         return NULL;
    235     }
    236 
    237     psKernel *sum = psKernelAlloc(xMin, xMax, yMin, yMax); // Summed covariance
    238     for (int i = 0; i < array->n; i++) {
    239         psKernel *covar = array->data[i]; // Covariance matrix
    240         if (!covar) {
    241             continue;
    242         }
    243         for (int y = covar->yMin; y <= covar->yMax; y++) {
    244             for (int x = covar->xMin; x <= covar->xMax; x++) {
    245                 if (!isfinite(covar->kernel[y][x])) {
    246                     psError(PS_ERR_BAD_PARAMETER_VALUE, true,
    247                             "Non-finite covariance matrix element at %d,%d for input %d",
    248                             x, y, i);
    249                     psFree(sum);
    250                     return NULL;
    251                 }
    252                 sum->kernel[y][x] += covar->kernel[y][x];
    253             }
    254         }
    255     }
    256 
    257     return sum;
    258 }
    259 
    260 
    261 psKernel *psImageCovarianceAverage(const psArray *array)
    262 {
    263     PS_ASSERT_ARRAY_NON_NULL(array, NULL);
    264     PS_ASSERT_ARRAY_NON_EMPTY(array, NULL);
    265 
    266     int num = 0;                        // Number of good matrices to average
    267     for (int i = 0; i < array->n; i++) {
    268         psKernel *covar = array->data[i]; // Covariance matrix
    269         if (covar) {
    270             num++;
    271         }
    272     }
    273     if (num == 0) {
    274         psError(PS_ERR_BAD_PARAMETER_SIZE, true, "No covariance matrices supplied for averaging.");
    275         return NULL;
    276     }
    277 
    278     psKernel *sum = psImageCovarianceSum(array); // Sum of covariances
    279     psBinaryOp(sum->image, sum->image, "/", psScalarAlloc(num, PS_TYPE_F32));
    280 
    281     return sum;
     399    psVector *weights = psVectorAlloc(array->n, PS_TYPE_F32); // Weights to apply
     400    psVectorInit(weights, 1.0);
     401    psKernel *out = psImageCovarianceAverageWeighted(array, weights);
     402    psFree(weights);
     403    return out;
    282404}
    283405
     
    310432
    311433    psKernel *sum = psKernelAlloc(xMin, xMax, yMin, yMax); // Summed covariance
     434    psImageInit(sum->image, 0.0);
    312435    for (int i = 0; i < array->n; i++) {
    313436        psKernel *covar = array->data[i]; // Covariance matrix
     
    405528    return true;
    406529}
     530
     531
     532bool psImageCovarianceSetThreads(bool set)
     533{
     534    bool old = threaded;                // Old value
     535    if (set && !threaded) {
     536        {
     537            psThreadTask *task = psThreadTaskAlloc("PSLIB_IMAGE_COVARIANCE_CALCULATE", 5);
     538            task->function = &imageCovarianceCalculateThread;
     539            psThreadTaskAdd(task);
     540            psFree(task);
     541        }
     542        {
     543            psThreadTask *task = psThreadTaskAlloc("PSLIB_IMAGE_COVARIANCE_BIN", 6);
     544            task->function = &imageCovarianceBinThread;
     545            psThreadTaskAdd(task);
     546            psFree(task);
     547        }
     548    } else if (!set && threaded) {
     549        psThreadTaskRemove("PSLIB_IMAGE_COVARIANCE_CALCULATE");
     550        psThreadTaskRemove("PSLIB_IMAGE_COVARIANCE_BIN");
     551    }
     552    threaded = set;
     553    return old;
     554}
     555
     556bool psImageCovarianceGetThreads(void)
     557{
     558    return threaded;
     559}
  • branches/tap_branches/psLib/src/imageops/psImageCovariance.h

    r24832 r27838  
    4747    );
    4848
    49 /// Sum multiple covariance pseudo-matrices
    50 psKernel *psImageCovarianceSum(
    51     const psArray *array                ///< Array of covariance pseudo-matrices
     49/// Return the pixel-to-pixel covariance factor following calculation
     50///
     51/// This doesn't require calculation of the entire covariance matrix, so is much faster.
     52float psImageCovarianceCalculateFactor(
     53    const psKernel *kernel,             ///< Convolution kernel
     54    const psKernel *covariance          ///< Current covariance pseudo-matrix
     55    );
     56
     57
     58/// Return the covariance factor for an aperture of a given radius
     59float psImageCovarianceFactorForAperture(const psKernel *covar, float radius);
     60
     61/// Return the sum of the covariance pseudo-matrix
     62float psImageCovarianceSum(
     63    const psKernel *covariance          ///< Covariance pseudo-matrix
    5264    );
    5365
     
    7890    );
    7991
     92/// Control threading for image covariance functions
     93///
     94/// Returns old threading status
     95bool psImageCovarianceSetThreads(bool threaded ///< Run image covariance functions threaded?
     96    );
     97
     98/// Return whether image covariance functions are threaded
     99bool psImageCovarianceGetThreads(void);
    80100
    81101/// @}
  • branches/tap_branches/psLib/src/imageops/psImageInterpolate.c

    r23231 r27838  
    197197{
    198198    // Casting away const
    199     psFree((psImage*)interp->image);
    200     psFree((psImage*)interp->mask);
    201     psFree((psImage*)interp->variance);
    202     psFree((psImage*)interp->kernel);
    203     psFree((psImage*)interp->kernel2);
    204     psFree((psVector*)interp->sumKernel2);
     199    psFree(interp->image);
     200    psFree(interp->mask);
     201    psFree(interp->variance);
     202    psFree(interp->kernel);
     203    psFree(interp->kernel2);
     204    psFree(interp->sumKernel2);
    205205}
    206206
  • branches/tap_branches/psLib/src/jpeg/psImageJpeg.c

    r24220 r27838  
    202202            if (isfinite(row[i])) {
    203203                pixel = PS_JPEG_SCALEVALUE(row[i],zero,scale);
    204                 outPix[0] = Rpix[pixel];
    205                 outPix[1] = Gpix[pixel];
    206                 outPix[2] = Bpix[pixel];
     204                outPix[0] = Rpix[pixel];
     205                outPix[1] = Gpix[pixel];
     206                outPix[2] = Bpix[pixel];
    207207            } else {
    208                 // XXX NAN value should be set per-color map
    209                 outPix[0] = 0xff;
    210                 outPix[1] = 0x00;
    211                 outPix[2] = 0xff;
    212             }
    213         }
    214         jpeg_write_scanlines(&cinfo, jpegLineList, 1);
     208                // XXX NAN value should be set per-color map
     209                outPix[0] = 0xff;
     210                outPix[1] = 0x00;
     211                outPix[2] = 0xff;
     212            }
     213        }
     214        if (jpeg_write_scanlines(&cinfo, jpegLineList, 1) == 0) {
     215            psError(PS_ERR_IO, true, "Unable to write line %d to JPEG", j);
     216            psFree(jpegLine);
     217            return false;
     218        }
    215219    }
    216220
    217221    jpeg_finish_compress(&cinfo);
    218     fclose(f);
     222    if (fclose(f) == EOF) {
     223        psError(PS_ERR_IO, true, "Failed to close %s", filename);
     224        psFree(jpegLine);
     225        return false;
     226    }
    219227    jpeg_destroy_compress(&cinfo);
    220228
  • branches/tap_branches/psLib/src/math/psBinaryOp.c

    r17050 r27838  
    379379}
    380380
    381 psMathType* psBinaryOp(psPtr out, const psPtr in1, const char *op, const psPtr in2)
     381psMathType* psBinaryOp(psPtr out, psPtr in1, const char *op, psPtr in2)
    382382{
    383383
  • branches/tap_branches/psLib/src/math/psBinaryOp.h

    r11248 r27838  
    5555psMathType* psBinaryOp(
    5656    psPtr out,                         ///< Output type, either psImage or psVector.
    57     const psPtr in1,                   ///< First input, either psImage or psVector.
     57    psPtr in1,                   ///< First input, either psImage or psVector.
    5858    const char *op,                    ///< Operator.
    59     const psPtr in2                    ///< Second input, either psImage or psVector.
     59    psPtr in2                    ///< Second input, either psImage or psVector.
    6060);
    6161
  • branches/tap_branches/psLib/src/math/psHistogram.c

    r21183 r27838  
    5858    psTrace("psLib.math", 3, "---- %s() begin  ----\n", __func__);
    5959    psTrace("psLib.math", 5, "(lower, upper, n) is (%f, %f, %d)\n", lower, upper, n);
    60     PS_ASSERT_INT_POSITIVE(n, NULL);
    61     PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(upper, lower, NULL);
     60    psAssert(n > 0, "Number of bins must be positive");
     61    psAssert(upper >= lower, "Bounds must be sensical");
    6262
    6363    // Allocate memory for the new histogram structure.  If there are N bins, then there are N+1 bounds to
     
    127127static void histogramFree(psHistogram* myHist)
    128128{
    129     psFree((void *)myHist->bounds);
     129    psFree(myHist->bounds);
    130130    psFree(myHist->nums);
    131131}
     
    287287                    double binSize = (out->bounds->data.F32[out->nums->n] - out->bounds->data.F32[0]) / (float) out->nums->n; // Histogram bin size
    288288                    binNum = (inF32->data.F32[i] - out->bounds->data.F32[0]) / binSize;
    289                     binNum = PS_MAX (binNum, 0);
    290                     binNum = PS_MIN (binNum, numBins - 1);
    291 
    292                     // value is in bin 'i' if bound[i] <= value < bound[i]
    293 
    294                     // we may slightly overshoot or undershoot.  creep up or down on the true bin
    295                     if (inF32->data.F32[i] < out->bounds->data.F32[binNum]) {
    296                         psTrace("psLib.math", 6, "missed target bin, adjusting: %f vs %f to %f\n", inF32->data.F32[i], out->bounds->data.F32[binNum], out->bounds->data.F32[binNum+1]);
    297                         while ((inF32->data.F32[i] < out->bounds->data.F32[binNum]) && (binNum > 0)) {
    298                             binNum --;
    299                         }
    300                        
    301                     }
    302                     if (inF32->data.F32[i] >= out->bounds->data.F32[binNum+1]) {
    303                         psTrace("psLib.math", 6, "missed target bin, adjusting: %f vs %f to %f\n", inF32->data.F32[i], out->bounds->data.F32[binNum], out->bounds->data.F32[binNum+1]);
    304                         while ((inF32->data.F32[i] >= out->bounds->data.F32[binNum+1]) && (binNum < numBins - 1)) {
    305                             binNum ++;
    306                         }
    307                     }
     289                    binNum = PS_MAX (binNum, 0);
     290                    binNum = PS_MIN (binNum, numBins - 1);
     291
     292                    // value is in bin 'i' if bound[i] <= value < bound[i]
     293
     294                    // we may slightly overshoot or undershoot.  creep up or down on the true bin
     295                    if (inF32->data.F32[i] < out->bounds->data.F32[binNum]) {
     296                        psTrace("psLib.math", 6, "missed target bin, adjusting: %f vs %f to %f\n", inF32->data.F32[i], out->bounds->data.F32[binNum], out->bounds->data.F32[binNum+1]);
     297                        while ((inF32->data.F32[i] < out->bounds->data.F32[binNum]) && (binNum > 0)) {
     298                            binNum --;
     299                        }
     300
     301                    }
     302                    if (inF32->data.F32[i] >= out->bounds->data.F32[binNum+1]) {
     303                        psTrace("psLib.math", 6, "missed target bin, adjusting: %f vs %f to %f\n", inF32->data.F32[i], out->bounds->data.F32[binNum], out->bounds->data.F32[binNum+1]);
     304                        while ((inF32->data.F32[i] >= out->bounds->data.F32[binNum+1]) && (binNum < numBins - 1)) {
     305                            binNum ++;
     306                        }
     307                    }
    308308
    309309                    if (errorsF32) {
     
    326326                    // correct bin number requires a bit more work.
    327327                    tmpScalar.data.F32 = inF32->data.F32[i];
    328                     psVectorBinaryDisectResult result;
     328                    psVectorBinaryDisectResult result;
    329329                    binNum = psVectorBinaryDisect(&result, out->bounds, &tmpScalar);
    330                     if (result != PS_BINARY_DISECT_PASS) {
    331                         continue;
    332                     }
    333                     if (errorsF32 != NULL) {
    334                         if (!UpdateHistogramBins(binNum, out, inF32->data.F32[i], errors->data.F32[i])) {
    335                             psLogMsg(__func__, PS_LOG_WARN, "WARNING: Failed to update the histogram "
    336                                      "bins with the errors vector.\n");
    337                         }
    338                     } else {
    339                         out->nums->data.F32[binNum] += 1.0;
    340                     }
     330                    if (result != PS_BINARY_DISECT_PASS) {
     331                        continue;
     332                    }
     333                    if (errorsF32 != NULL) {
     334                        if (!UpdateHistogramBins(binNum, out, inF32->data.F32[i], errors->data.F32[i])) {
     335                            psLogMsg(__func__, PS_LOG_WARN, "WARNING: Failed to update the histogram "
     336                                     "bins with the errors vector.\n");
     337                        }
     338                    } else {
     339                        out->nums->data.F32[binNum] += 1.0;
     340                    }
    341341                }
    342342            }
  • branches/tap_branches/psLib/src/math/psMatrix.c

    r24122 r27838  
    9494LHS_NAME.data  = RHS_NAME;
    9595
    96 
    97 /*****************************************************************************/
    98 /* FILE STATIC FUNCTIONS                                                     */
    99 /*****************************************************************************/
    100 
    101 static void  psVectorToGslVector(gsl_vector *outGslVector, const psVector *inVector);
    102 static void gslVectorToPsVector(psVector *outVector, gsl_vector *inGslVector);
    103 static void  psImageToGslMatrix(gsl_matrix *outGslMatrix, const psImage *inImage);
    104 static void gslMatrixToPsImage(psImage *outImage, gsl_matrix *inGslMatrix);
     96////////////////////////////////////////////////////////////////////////////////
     97// Conversion functions
     98////////////////////////////////////////////////////////////////////////////////
     99
     100// gsl_vector holds *doubles*, so we can directly copy F64, but need to convert F32
    105101
    106102/** Static function to copy psF32 or psF64 vector data to a GSL vector */
    107 static void  psVectorToGslVector(gsl_vector *outGslVector,
    108                                  const psVector *inVector)
    109 {
    110     psU32 i = 0;
    111     psU32 n = 0;
    112 
    113 
    114     n = inVector->n;
    115     for(i=0; i<n; i++) {
    116         if(inVector->type.type == PS_TYPE_F32) {
    117             outGslVector->data[i] = (psF64)inVector->data.F32[i];
     103static void vectorPStoGSL(gsl_vector *out, const psVector *in)
     104{
     105    psAssert(out->size == in->n, "Sizes don't match!");
     106
     107    long n = in->n;                     // Size of input
     108    switch (in->type.type) {
     109      case PS_TYPE_F32:
     110        for (long i = 0; i < n; i++) {
     111            out->data[i] = in->data.F32[i];
     112        }
     113        break;
     114      case PS_TYPE_F64:
     115        memcpy(out->data, in->data.F64, n * PSELEMTYPE_SIZEOF(PS_TYPE_F64));
     116        break;
     117      default:
     118        psAbort("Unsupported vector type: %x\n", in->type.type);
     119    }
     120    return;
     121}
     122
     123/** Static function to copy GSL vector data to a psF32 or psF64 vector */
     124static void vectorGSLtoPS(psVector *out, const gsl_vector *in)
     125{
     126    psAssert(in->size == out->n, "Sizes don't match!");
     127
     128    long n = out->n;                    // Size of output
     129    switch (out->type.type) {
     130      case PS_TYPE_F32:
     131        for (long i = 0; i < n; i++) {
     132            out->data.F32[i] = in->data[i];
     133        }
     134        break;
     135      case PS_TYPE_F64:
     136        memcpy(out->data.F64, in->data, n * PSELEMTYPE_SIZEOF(PS_TYPE_F64));
     137        break;
     138      default:
     139        psAbort("Unsupported vector type: %x\n", out->type.type);
     140    }
     141    return;
     142}
     143
     144
     145/** Static function to copy psF32 or psF64 image data to a GSL matrix */
     146static void matrixPStoGSL(gsl_matrix *out, const psImage *in)
     147{
     148    psAssert(out->size1 == in->numRows && out->size2 == in->numCols, "Sizes don't match!");
     149
     150    int numCols = in->numCols, numRows = in->numRows; // Size of matrix
     151    switch (in->type.type) {
     152      case PS_TYPE_F32:
     153        for (int y = 0, i = 0; y < numRows; y++) {
     154            for (int x = 0; x < numCols; x++, i++) {
     155                out->data[i] = in->data.F32[y][x];
     156            }
     157        }
     158        break;
     159      case PS_TYPE_F64:
     160        if (in->parent|| out->tda != out->size1) {
     161            for (int y = 0, i = 0; y < numRows; y++, i += numCols) {
     162                memcpy(&out->data[i], in->data.F64[y], numCols * PSELEMTYPE_SIZEOF(PS_TYPE_F64));
     163            }
    118164        } else {
    119             outGslVector->data[i] = inVector->data.F64[i];
    120         }
    121     }
    122 }
    123 
    124 /** Static function to copy GSL vector data to a psF32 or psF64 vector */
    125 static void gslVectorToPsVector(psVector *outVector,
    126                                 gsl_vector *inGslVector)
    127 {
    128     psU32 i = 0;
    129     psU32 n = 0;
    130 
    131 
    132     n = outVector->n;
    133     for(i=0; i<n; i++) {
    134         if(outVector->type.type == PS_TYPE_F32) {
    135             outVector->data.F32[i] = (psF32)inGslVector->data[i];
     165            memcpy(out->data, in->p_rawDataBuffer, numCols * numRows * PSELEMTYPE_SIZEOF(PS_TYPE_F64));
     166        }
     167        break;
     168      default:
     169        psAbort("Unsupported vector type: %x\n", in->type.type);
     170    }
     171    return;
     172}
     173
     174/** Static function to copy GSL matrix data to a psF32 or psF64 image */
     175static void matrixGSLtoPS(psImage *out, const gsl_matrix *in)
     176{
     177    psAssert(in->size1 == out->numRows && in->size2 == out->numCols, "Sizes don't match!");
     178
     179    int numCols = out->numCols, numRows = out->numRows; // Size of matrix
     180    switch (out->type.type) {
     181      case PS_TYPE_F32:
     182        for (int y = 0, i = 0; y < numRows; y++) {
     183            for (int x = 0; x < numCols; x++, i++) {
     184                out->data.F32[y][x] = in->data[i];
     185            }
     186        }
     187        break;
     188      case PS_TYPE_F64:
     189        if (out->parent || in->tda != in->size1) {
     190            for (int y = 0, i = 0; y < numRows; y++, i += numCols) {
     191                memcpy(out->data.F64[y], &in->data[i], numCols * PSELEMTYPE_SIZEOF(PS_TYPE_F64));
     192            }
    136193        } else {
    137             outVector->data.F64[i] = inGslVector->data[i];
    138         }
    139     }
    140 }
    141 
    142 /** Static function to copy psF32 or psF64 image data to a GSL matrix */
    143 static void  psImageToGslMatrix(gsl_matrix *outGslMatrix,
    144                                 const psImage *inImage)
    145 {
    146     psU32 i = 0;
    147     psU32 j = 0;
    148     psU32 numRows = 0;
    149     psU32 numCols = 0;
    150 
    151 
    152     numRows = inImage->numRows;
    153     numCols = inImage->numCols;
    154     if(inImage->type.type == PS_TYPE_F32) {
    155         for(i=0; i<numRows; i++) {
    156             for(j=0; j<numCols; j++) {
    157                 outGslMatrix->data[i*numCols+j] = inImage->data.F32[i][j];
    158             }
    159         }
    160     } else {
    161         for(i=0; i<numRows; i++) {
    162             for(j=0; j<numCols; j++) {
    163                 outGslMatrix->data[i*numCols+j] = inImage->data.F64[i][j];
    164             }
    165         }
    166     }
    167 }
    168 
    169 /** Static function to copy GSL matrix data to a psF32 or psF64 image */
    170 static void gslMatrixToPsImage(psImage *outImage,
    171                                gsl_matrix *inGslMatrix)
    172 {
    173     psU32 i = 0;
    174     psU32 j = 0;
    175     psU32 numRows = 0;
    176     psU32 numCols = 0;
    177 
    178 
    179     numRows = outImage->numRows;
    180     numCols = outImage->numCols;
    181     if(outImage->type.type == PS_TYPE_F32) {
    182         for(i=0; i<numRows; i++) {
    183             for(j=0; j<numCols; j++) {
    184                 outImage->data.F32[i][j] = inGslMatrix->data[i*numCols+j];
    185             }
    186         }
    187     } else {
    188         for(i=0; i<numRows; i++) {
    189             for(j=0; j<numCols; j++) {
    190                 outImage->data.F64[i][j] = inGslMatrix->data[i*numCols+j];
    191             }
    192         }
    193     }
     194            memcpy(out->p_rawDataBuffer, in->data, numCols * numRows * PSELEMTYPE_SIZEOF(PS_TYPE_F64));
     195        }
     196        break;
     197      default:
     198        psAbort("Unsupported vector type: %x\n", out->type.type);
     199    }
     200    return;
    194201}
    195202
     
    245252
    246253    // Copy psImage data into GSL matrix data
    247     psImageToGslMatrix(lu, in);
     254    matrixPStoGSL(lu, in);
    248255
    249256    // Calculate LU decomposition
     
    251258
    252259    // Copy GSL matrix data to psImage data
    253     gslMatrixToPsImage(out, lu);
     260    matrixGSLtoPS(out, lu);
    254261
    255262    // Free GSL data
     
    293300    // Initialize GSL data
    294301    lu = gsl_matrix_alloc(numRows, numCols);
    295     psImageToGslMatrix(lu, LU);
     302    matrixPStoGSL(lu, LU);
    296303    b = gsl_vector_alloc(RHS->n);
    297     psVectorToGslVector(b, RHS);
     304    vectorPStoGSL(b, RHS);
    298305    x = gsl_vector_alloc(RHS->n);
    299306
     
    306313
    307314    // Copy GSL vector data to psVector data
    308     gslVectorToPsVector(out, x);
     315    vectorGSLtoPS(out, x);
    309316
    310317    // Free GSL data
     
    341348    // Initialize GSL data
    342349    lu = gsl_matrix_alloc(numRows, numCols);
    343     psImageToGslMatrix(lu, LU);
     350    matrixPStoGSL(lu, LU);
    344351
    345352    permGSL.size = perm->n;
     
    352359
    353360    // Copy GSL vector data to psVector data
    354     gslMatrixToPsImage(out, inverse);
     361    matrixGSLtoPS(out, inverse);
    355362
    356363    // Free GSL data
     
    379386    switch (a->type.type) {
    380387      case PS_TYPE_F32: {
    381           psF32 **values = a->data.F32; /* Dereference */
    382           int numCols = a->numCols, numRows = a->numRows; /* Size of matrix */
    383           for (int i = 0; i < numRows; i++) {
    384               for (int j = 0; j < numCols; j++) {
    385                   if (!isfinite(values[i][j])) {
    386                       // psError(PS_ERR_BAD_PARAMETER_VALUE, 3,
    387                       // "Input matrix contains non-finite elements: matrix[%d][%d] is %.2f\n",
    388                       // i, j, values[i][j]);
    389                       return false;
    390                   }
    391               }
    392           }
    393           break;
     388          psF32 **values = a->data.F32; /* Dereference */
     389          int numCols = a->numCols, numRows = a->numRows; /* Size of matrix */
     390          for (int i = 0; i < numRows; i++) {
     391              for (int j = 0; j < numCols; j++) {
     392                  if (!isfinite(values[i][j])) {
     393                      // psError(PS_ERR_BAD_PARAMETER_VALUE, 3,
     394                      // "Input matrix contains non-finite elements: matrix[%d][%d] is %.2f\n",
     395                      // i, j, values[i][j]);
     396                      return false;
     397                  }
     398              }
     399          }
     400          break;
    394401      }
    395402      case PS_TYPE_F64: {
    396           psF64 **values = a->data.F64; /* Dereference */
    397           int numCols = a->numCols, numRows = a->numRows; /* Size of matrix */
    398           for (int i = 0; i < numRows; i++) {
    399               for (int j = 0; j < numCols; j++) {
    400                   if (!isfinite(values[i][j])) {
    401                       // psError(PS_ERR_BAD_PARAMETER_VALUE, 3,
    402                       // "Input matrix contains non-finite elements: matrix[%d][%d] is %.2f\n",
    403                       // i, j, values[i][j]);
    404                       return false;
    405                   }
    406               }
    407           }
    408           break;
     403          psF64 **values = a->data.F64; /* Dereference */
     404          int numCols = a->numCols, numRows = a->numRows; /* Size of matrix */
     405          for (int i = 0; i < numRows; i++) {
     406              for (int j = 0; j < numCols; j++) {
     407                  if (!isfinite(values[i][j])) {
     408                      // psError(PS_ERR_BAD_PARAMETER_VALUE, 3,
     409                      // "Input matrix contains non-finite elements: matrix[%d][%d] is %.2f\n",
     410                      // i, j, values[i][j]);
     411                      return false;
     412                  }
     413              }
     414          }
     415          break;
    409416      }
    410         // MATRIX_CHECK_NONFINITE_CASE(F32, a);
    411         // MATRIX_CHECK_NONFINITE_CASE(F64, a);
     417        // MATRIX_CHECK_NONFINITE_CASE(F32, a);
     418        // MATRIX_CHECK_NONFINITE_CASE(F64, a);
    412419      default:
    413         psAbort("Should never get here.");
     420        psAbort("Should never get here.");
    414421    }
    415422
     
    471478    switch (a->type.type) {
    472479      case PS_TYPE_F32: {
    473           psF32 **values = a->data.F32; /* Dereference */
    474           int numCols = a->numCols, numRows = a->numRows; /* Size of matrix */
    475           for (int i = 0; i < numRows; i++) {
    476               for (int j = 0; j < numCols; j++) {
    477                   if (!isfinite(values[i][j])) {
    478                       return false;
    479                   }
    480               }
    481           }
    482           break;
     480          psF32 **values = a->data.F32; /* Dereference */
     481          int numCols = a->numCols, numRows = a->numRows; /* Size of matrix */
     482          for (int i = 0; i < numRows; i++) {
     483              for (int j = 0; j < numCols; j++) {
     484                  if (!isfinite(values[i][j])) {
     485                      return false;
     486                  }
     487              }
     488          }
     489          break;
    483490      }
    484491      case PS_TYPE_F64: {
    485           psF64 **values = a->data.F64; /* Dereference */
    486           int numCols = a->numCols, numRows = a->numRows; /* Size of matrix */
    487           for (int i = 0; i < numRows; i++) {
    488               for (int j = 0; j < numCols; j++) {
    489                   if (!isfinite(values[i][j])) {
    490                       return false;
    491                   }
    492               }
    493           }
    494           break;
     492          psF64 **values = a->data.F64; /* Dereference */
     493          int numCols = a->numCols, numRows = a->numRows; /* Size of matrix */
     494          for (int i = 0; i < numRows; i++) {
     495              for (int j = 0; j < numCols; j++) {
     496                  if (!isfinite(values[i][j])) {
     497                      return false;
     498                  }
     499              }
     500          }
     501          break;
    495502      }
    496503      default:
    497         psAbort("Should never get here.");
    498     }
    499  
     504        psAbort("Should never get here.");
     505    }
     506
    500507    // Following the algorithm laid out by Press et al., we loop along the matrix diagonal, but
    501508    // we do not operate on the diagonal elements in order.  Instead, we are looking for the
     
    511518
    512519    if (a->type.type == PS_TYPE_F32) {
    513         psF32 **A = a->data.F32;
    514         psF32  *B = b->data.F32;
    515         int *colIndex = colIndexV->data.S32;
    516         int *rowIndex = rowIndexV->data.S32;
    517         int *pivot    = pivotV->data.S32;
    518         psF32 growth = 1.0;
    519 
    520         for (int diag = 0; diag < nSquare; diag++) {
    521 
    522             psF32 maxval = 0.0;
    523             int maxrow = 0;
    524             int maxcol = 0;
    525 
    526             // search for the next pivot
    527             for (int row = 0; row < nSquare; row++) {
    528                 if (!isfinite(A[row][diag])) goto escape;
    529 
    530                 // if we have already operated on this row (pivot[row] is true), skip it
    531                 if (pivot[row]) continue;
    532 
    533                 // if we have not yet operated on this row (pivot[row] is false), look for pivot for this row
    534                 for (int col = 0; col < nSquare; col++) {
    535                     if (pivot[col]) continue;
    536                     if (fabs (A[row][col]) < maxval) continue;
    537                     maxval = fabs (A[row][col]);
    538                     maxrow = row;
    539                     maxcol = col;
    540                 }
    541             }
    542 
    543             // if pivot[maxcol] is set, we have already done this row: this implies a singular matrix
    544             if (pivot[maxcol]) goto escape;
    545             pivot[maxcol] = 1;
    546 
    547             // if the selected pivot is off the diagonal, do a row swap
    548             if (maxrow != maxcol) {
    549                 for (int col = 0; col < nSquare; col++) PS_SWAP (A[maxrow][col], A[maxcol][col]);
    550                 PS_SWAP (B[maxrow], B[maxcol]);
    551             }
    552             rowIndex[diag] = maxrow;
    553             colIndex[diag] = maxcol;
    554             if (A[maxcol][maxcol] == 0.0) goto escape;
    555             // Kahan replaces the 0.0 pivot with epsilon*(largest element in column) + underFlow.
    556             // Here we are going to raise an error if the dynamic range is too large.
    557 
    558             /* rescale by pivot reciprocal */
    559             psF32 tmpval = 1.0 / A[maxcol][maxcol];
    560             A[maxcol][maxcol] = 1.0;
    561             for (int col = 0; col < nSquare; col++) A[maxcol][col] *= tmpval;
    562             B[maxcol] *= tmpval;
    563 
    564             // check for ill-conditioned matrix: measure the pivot growth and trigger on over/under flow
    565             growth *= tmpval;
    566             psTrace ("psLib.math", 4, "growth : %e\n", growth);
    567             if (fabs(growth) > MAX_RANGE) goto escape;
    568 
    569             /* adjust the elements above the pivot */
    570             for (int row = 0; row < nSquare; row++) {
    571                 if (row == maxcol) continue;
    572                 tmpval = A[row][maxcol];
    573                 A[row][maxcol] = 0.0;
    574                 for (int col = 0; col < nSquare; col++) A[row][col] -= A[maxcol][col]*tmpval;
    575                 B[row] -= B[maxcol]*tmpval;
    576             }
    577         }
    578 
    579         // swap back the inverse matrix based on the row swaps above
    580         for (int col = nSquare - 1; col >= 0; col--) {
    581             if (rowIndex[col] != colIndex[col]) {
    582                 for (int row = 0; row < nSquare; row++) PS_SWAP (A[row][rowIndex[col]], A[row][colIndex[col]]);
    583             }
    584         }
     520        psF32 **A = a->data.F32;
     521        psF32  *B = b->data.F32;
     522        int *colIndex = colIndexV->data.S32;
     523        int *rowIndex = rowIndexV->data.S32;
     524        int *pivot    = pivotV->data.S32;
     525        psF32 growth = 1.0;
     526
     527        for (int diag = 0; diag < nSquare; diag++) {
     528
     529            psF32 maxval = 0.0;
     530            int maxrow = 0;
     531            int maxcol = 0;
     532
     533            // search for the next pivot
     534            for (int row = 0; row < nSquare; row++) {
     535                if (!isfinite(A[row][diag])) goto escape;
     536
     537                // if we have already operated on this row (pivot[row] is true), skip it
     538                if (pivot[row]) continue;
     539
     540                // if we have not yet operated on this row (pivot[row] is false), look for pivot for this row
     541                for (int col = 0; col < nSquare; col++) {
     542                    if (pivot[col]) continue;
     543                    if (fabs (A[row][col]) < maxval) continue;
     544                    maxval = fabs (A[row][col]);
     545                    maxrow = row;
     546                    maxcol = col;
     547                }
     548            }
     549
     550            // if pivot[maxcol] is set, we have already done this row: this implies a singular matrix
     551            if (pivot[maxcol]) goto escape;
     552            pivot[maxcol] = 1;
     553
     554            // if the selected pivot is off the diagonal, do a row swap
     555            if (maxrow != maxcol) {
     556                for (int col = 0; col < nSquare; col++) PS_SWAP (A[maxrow][col], A[maxcol][col]);
     557                PS_SWAP (B[maxrow], B[maxcol]);
     558            }
     559            rowIndex[diag] = maxrow;
     560            colIndex[diag] = maxcol;
     561            if (A[maxcol][maxcol] == 0.0) goto escape;
     562            // Kahan replaces the 0.0 pivot with epsilon*(largest element in column) + underFlow.
     563            // Here we are going to raise an error if the dynamic range is too large.
     564
     565            /* rescale by pivot reciprocal */
     566            psF32 tmpval = 1.0 / A[maxcol][maxcol];
     567            A[maxcol][maxcol] = 1.0;
     568            for (int col = 0; col < nSquare; col++) A[maxcol][col] *= tmpval;
     569            B[maxcol] *= tmpval;
     570
     571            // check for ill-conditioned matrix: measure the pivot growth and trigger on over/under flow
     572            growth *= tmpval;
     573            psTrace ("psLib.math", 4, "growth : %e\n", growth);
     574            if (fabs(growth) > MAX_RANGE) goto escape;
     575
     576            /* adjust the elements above the pivot */
     577            for (int row = 0; row < nSquare; row++) {
     578                if (row == maxcol) continue;
     579                tmpval = A[row][maxcol];
     580                A[row][maxcol] = 0.0;
     581                for (int col = 0; col < nSquare; col++) A[row][col] -= A[maxcol][col]*tmpval;
     582                B[row] -= B[maxcol]*tmpval;
     583            }
     584        }
     585
     586        // swap back the inverse matrix based on the row swaps above
     587        for (int col = nSquare - 1; col >= 0; col--) {
     588            if (rowIndex[col] != colIndex[col]) {
     589                for (int row = 0; row < nSquare; row++) PS_SWAP (A[row][rowIndex[col]], A[row][colIndex[col]]);
     590            }
     591        }
    585592    } else {
    586         psF64 **A = a->data.F64;
    587         psF64  *B = b->data.F64;
    588         int *colIndex = colIndexV->data.S32;
    589         int *rowIndex = rowIndexV->data.S32;
    590         int *pivot    = pivotV->data.S32;
    591         psF64 growth = 1.0;
    592 
    593         for (int diag = 0; diag < nSquare; diag++) {
    594 
    595             psF64 maxval = 0.0;
    596             int maxrow = 0;
    597             int maxcol = 0;
    598 
    599             // search for the next pivot
    600             for (int row = 0; row < nSquare; row++) {
    601                 if (!isfinite(A[row][diag])) goto escape;
    602 
    603                 // if we have already operated on this row (pivot[row] is true), skip it
    604                 if (pivot[row]) continue;
    605 
    606                 // if we have not yet operated on this row (pivot[row] is false), look for pivot for this row
    607                 for (int col = 0; col < nSquare; col++) {
    608                     if (pivot[col]) continue;
    609                     if (fabs (A[row][col]) < maxval) continue;
    610                     maxval = fabs (A[row][col]);
    611                     maxrow = row;
    612                     maxcol = col;
    613                 }
    614             }
    615 
    616             // if pivot[maxcol] is set, we have already done this row: this implies a singular matrix
    617             if (pivot[maxcol]) goto escape;
    618             pivot[maxcol] = 1;
    619 
    620             // if the selected pivot is off the diagonal, do a row swap
    621             if (maxrow != maxcol) {
    622                 for (int col = 0; col < nSquare; col++) PS_SWAP (A[maxrow][col], A[maxcol][col]);
    623                 PS_SWAP (B[maxrow], B[maxcol]);
    624             }
    625             rowIndex[diag] = maxrow;
    626             colIndex[diag] = maxcol;
    627             if (A[maxcol][maxcol] == 0.0) goto escape;
    628             // Kahan replaces the 0.0 pivot with epsilon*(largest element in column) + underFlow.
    629             // Here we are going to raise an error if the dynamic range is too large.
    630 
    631             /* rescale by pivot reciprocal */
    632             psF64 tmpval = 1.0 / A[maxcol][maxcol];
    633             A[maxcol][maxcol] = 1.0;
    634             for (int col = 0; col < nSquare; col++) A[maxcol][col] *= tmpval;
    635             B[maxcol] *= tmpval;
    636 
    637             // check for ill-conditioned matrix: measure the pivot growth and trigger on over/under flow
    638             growth *= tmpval;
    639             psTrace ("psLib.math", 4, "growth : %e\n", growth);
    640             if (fabs(growth) > MAX_RANGE) goto escape;
    641 
    642             /* adjust the elements above the pivot */
    643             for (int row = 0; row < nSquare; row++) {
    644                 if (row == maxcol) continue;
    645                 tmpval = A[row][maxcol];
    646                 A[row][maxcol] = 0.0;
    647                 for (int col = 0; col < nSquare; col++) A[row][col] -= A[maxcol][col]*tmpval;
    648                 B[row] -= B[maxcol]*tmpval;
    649             }
    650         }
    651 
    652         // swap back the inverse matrix based on the row swaps above
    653         for (int col = nSquare - 1; col >= 0; col--) {
    654             if (rowIndex[col] != colIndex[col]) {
    655                 for (int row = 0; row < nSquare; row++) PS_SWAP (A[row][rowIndex[col]], A[row][colIndex[col]]);
    656             }
    657         }
     593        psF64 **A = a->data.F64;
     594        psF64  *B = b->data.F64;
     595        int *colIndex = colIndexV->data.S32;
     596        int *rowIndex = rowIndexV->data.S32;
     597        int *pivot    = pivotV->data.S32;
     598        psF64 growth = 1.0;
     599
     600        for (int diag = 0; diag < nSquare; diag++) {
     601
     602            psF64 maxval = 0.0;
     603            int maxrow = 0;
     604            int maxcol = 0;
     605
     606            // search for the next pivot
     607            for (int row = 0; row < nSquare; row++) {
     608                if (!isfinite(A[row][diag])) goto escape;
     609
     610                // if we have already operated on this row (pivot[row] is true), skip it
     611                if (pivot[row]) continue;
     612
     613                // if we have not yet operated on this row (pivot[row] is false), look for pivot for this row
     614                for (int col = 0; col < nSquare; col++) {
     615                    if (pivot[col]) continue;
     616                    if (fabs (A[row][col]) < maxval) continue;
     617                    maxval = fabs (A[row][col]);
     618                    maxrow = row;
     619                    maxcol = col;
     620                }
     621            }
     622
     623            // if pivot[maxcol] is set, we have already done this row: this implies a singular matrix
     624            if (pivot[maxcol]) goto escape;
     625            pivot[maxcol] = 1;
     626
     627            // if the selected pivot is off the diagonal, do a row swap
     628            if (maxrow != maxcol) {
     629                for (int col = 0; col < nSquare; col++) PS_SWAP (A[maxrow][col], A[maxcol][col]);
     630                PS_SWAP (B[maxrow], B[maxcol]);
     631            }
     632            rowIndex[diag] = maxrow;
     633            colIndex[diag] = maxcol;
     634            if (A[maxcol][maxcol] == 0.0) goto escape;
     635            // Kahan replaces the 0.0 pivot with epsilon*(largest element in column) + underFlow.
     636            // Here we are going to raise an error if the dynamic range is too large.
     637
     638            /* rescale by pivot reciprocal */
     639            psF64 tmpval = 1.0 / A[maxcol][maxcol];
     640            A[maxcol][maxcol] = 1.0;
     641            for (int col = 0; col < nSquare; col++) A[maxcol][col] *= tmpval;
     642            B[maxcol] *= tmpval;
     643
     644            // check for ill-conditioned matrix: measure the pivot growth and trigger on over/under flow
     645            growth *= tmpval;
     646            psTrace ("psLib.math", 4, "growth : %e\n", growth);
     647            if (fabs(growth) > MAX_RANGE) goto escape;
     648
     649            /* adjust the elements above the pivot */
     650            for (int row = 0; row < nSquare; row++) {
     651                if (row == maxcol) continue;
     652                tmpval = A[row][maxcol];
     653                A[row][maxcol] = 0.0;
     654                for (int col = 0; col < nSquare; col++) A[row][col] -= A[maxcol][col]*tmpval;
     655                B[row] -= B[maxcol]*tmpval;
     656            }
     657        }
     658
     659        // swap back the inverse matrix based on the row swaps above
     660        for (int col = nSquare - 1; col >= 0; col--) {
     661            if (rowIndex[col] != colIndex[col]) {
     662                for (int row = 0; row < nSquare; row++) PS_SWAP (A[row][rowIndex[col]], A[row][colIndex[col]]);
     663            }
     664        }
    658665    }
    659666
     
    701708    lu = gsl_matrix_alloc(numRows, numCols);
    702709    inv = gsl_matrix_alloc(numRows, numCols);
    703     psImageToGslMatrix(lu, in);
     710    matrixPStoGSL(lu, in);
    704711
    705712    // Invert data and calculate determinant
     
    708715    if (determinant) {
    709716      // XXX this is getting the wrong value: is it the wrong calculation?
    710       // it disagrees with the results of 
     717      // it disagrees with the results of
    711718      // det = (psF32)gsl_linalg_LU_det(lu, signum);
    712719      // used in psMatrixDeterminatn
     
    716723
    717724    // Copy GSL matrix data to psImage data
    718     gslMatrixToPsImage(out, inv);
     725    matrixGSLtoPS(out, inv);
    719726
    720727    // Free GSL structs
     
    749756    perm = gsl_permutation_alloc(numRows);
    750757    lu = gsl_matrix_alloc(numRows, numCols);
    751     psImageToGslMatrix(lu, in);
     758    matrixPStoGSL(lu, in);
    752759
    753760    // Calculate determinant
    754761    gsl_linalg_LU_decomp(lu, perm, &signum);
    755     det = (psF32)gsl_linalg_LU_det(lu, signum);
     762    det = (psF32)gsl_linalg_LU_lndet(lu);
    756763
    757764    // Free GSL structs
     
    877884
    878885    inGSL = gsl_matrix_alloc(numRows, numCols);
    879     psImageToGslMatrix(inGSL, in);
     886    matrixPStoGSL(inGSL, in);
    880887    outGSL = gsl_matrix_alloc(numRows, numCols);
    881888
     
    892899
    893900    // Copy GSL matrix data to psImage data
    894     gslMatrixToPsImage(out, outGSL);
     901    matrixGSLtoPS(out, outGSL);
    895902
    896903    // Free GSL structs
     
    10261033}
    10271034
     1035psVector *psMatrixSolveSVD(psVector *out, const psImage *matrix, const psVector *vector, float thresh)
     1036{
     1037    #define psMatrixSolveSVD_EXIT {psFree(out); return NULL; }
     1038    PS_ASSERT_GENERAL_IMAGE_NON_NULL(matrix, psMatrixSolveSVD_EXIT);
     1039    PS_CHECK_DIMEN_AND_TYPE(matrix, PS_DIMEN_IMAGE, psMatrixSolveSVD_EXIT);
     1040    PS_ASSERT_GENERAL_VECTOR_NON_NULL(vector, psMatrixSolveSVD_EXIT);
     1041    PS_CHECK_DIMEN_AND_TYPE(vector, PS_DIMEN_VECTOR, psMatrixSolveSVD_EXIT);
     1042
     1043    int numCols = matrix->numCols, numRows = matrix->numRows; // Size of matrix
     1044
     1045    // Decompose matrix: A = U S V^T
     1046    gsl_matrix *A = gsl_matrix_alloc(numRows, numCols); // Input matrix in GSL-speak; becomes matrix U
     1047    gsl_matrix *V = gsl_matrix_alloc(numCols, numCols); // Untransposed matrix V
     1048    gsl_vector *S = gsl_vector_alloc(numCols);          // Singular values
     1049    gsl_vector *work = gsl_vector_alloc(numCols);       // Work space for GSL
     1050
     1051    matrixPStoGSL(A, matrix);
     1052
     1053    int gslStatus = 0;                  // Status of GSL
     1054    if ((gslStatus = gsl_linalg_SV_decomp(A, V, S, work))) {
     1055        const char *err = gsl_strerror(gslStatus);
     1056        psError(PS_ERR_UNKNOWN, true, "Unable to decompose matrix: %s", err);
     1057        gsl_matrix_free(A);
     1058        gsl_matrix_free(V);
     1059        gsl_vector_free(S);
     1060        gsl_vector_free(work);
     1061        return NULL;
     1062    }
     1063    gsl_vector_free(work);
     1064
     1065    if (isfinite(thresh) && thresh > 0.0) {
     1066        // Trim the singular values
     1067        double total = 0.0;             // Total of singular values
     1068        for (int i = 0; i < numCols; i++) {
     1069            total += gsl_vector_get(S, i);
     1070        }
     1071        thresh *= total;
     1072        for (int i = 0; i < numCols; i++) {
     1073            double value = gsl_vector_get(S, i); // Singular value
     1074            if (value < thresh) {
     1075                psTrace("psLib.math", 5, "Trimming singular value %d: %lg", i, value);
     1076                gsl_vector_set(S, i, 0.0);
     1077#if 0
     1078                for (int j = 0; j < numCols; j++) {
     1079                    // Being thorough; probably unnecessary
     1080                    gsl_matrix_set(V, j, i, 0.0);
     1081                    gsl_matrix_set(A, j, i, 0.0);
     1082                }
     1083#endif
     1084            } else {
     1085                psTrace("psLib.math", 5, "Singular value %d: %lg", i, value);
     1086            }
     1087        }
     1088    }
     1089
     1090    // Solve system (or minimise least-squares if overconstrained): Ax = b
     1091    gsl_vector *b = gsl_vector_alloc(numCols); // Vector b
     1092    gsl_vector *x = gsl_vector_alloc(numCols); // Solution
     1093
     1094    vectorPStoGSL(b, vector);
     1095
     1096    if ((gslStatus = gsl_linalg_SV_solve(A, V, S, b, x))) {
     1097        const char *err = gsl_strerror(gslStatus);
     1098        psError(PS_ERR_UNKNOWN, true, "Unable to solve matrix equation: %s", err);
     1099        gsl_matrix_free(A);
     1100        gsl_matrix_free(V);
     1101        gsl_vector_free(S);
     1102        gsl_vector_free(b);
     1103        gsl_vector_free(x);
     1104        return NULL;
     1105    }
     1106
     1107    gsl_matrix_free(A);
     1108    gsl_matrix_free(V);
     1109    gsl_vector_free(S);
     1110    gsl_vector_free(b);
     1111
     1112    out = psVectorRecycle(out, numCols, PS_TYPE_F64);
     1113
     1114    vectorGSLtoPS(out, x);
     1115    gsl_vector_free(x);
     1116
     1117    return out;
     1118}
     1119
    10281120// This code supplied by Andy Becker (becker@astro.washington.edu)
    1029 psImage *psMatrixSVD(psImage* evec, psVector* eval, const psImage* in)
     1121psImage *psMatrixSVD_old(psImage* evec, psVector* eval, const psImage* in)
    10301122{
    10311123    #define psMatrixSVD_EXIT {psFree(evec); psFree(eval); return NULL;}
     
    10501142
    10511143    // Copy psImage data into GSL matrix data
    1052     psImageToGslMatrix(A, in);
     1144    matrixPStoGSL(A, in);
    10531145
    10541146    // Calculate SVD decomposition
     
    10561148
    10571149    // Copy GSL matrix data to psImage data
    1058     gslMatrixToPsImage(evec, V);
    1059     gslVectorToPsVector(eval, S);
     1150    matrixGSLtoPS(evec, V);
     1151    vectorGSLtoPS(eval, S);
    10601152
    10611153    // Take the square root of eval
     
    10761168    return evec;
    10771169}
     1170
     1171// this is basically a wrapper for the gsl function: gsl_linalg_SV_decomp() SVD decomposes
     1172// matrix A based on the following equation: A = U w V^T .  This function (as usual for SVD
     1173// implementations) returns V not V^T.  U and V are returned to images; w is returned to a
     1174// vector representing the diagonal of w.  The input image A is not modified.  U, V, and w may
     1175// be supplied as NULL or may be allocated; their lengths are set here to match the
     1176// dimensionality of A.  XXX there is no error handling for the gsl functions (anywhere in
     1177// psMatrix.c)
     1178bool psMatrixSVD(psImage **U, psVector **w, psImage **V, const psImage *A)
     1179{
     1180    // Error checks  Missing one for eval
     1181    PS_ASSERT_PTR_NON_NULL(U, false);
     1182    PS_ASSERT_PTR_NON_NULL(w, false);
     1183    PS_ASSERT_PTR_NON_NULL(V, false);
     1184    PS_ASSERT_PTR_NON_NULL(A, false);
     1185
     1186    // A is provided with size Nx,Ny = numCols,numRows
     1187    // U has size Nx,Ny
     1188    // V has size Nx,Nx
     1189    // w has size Nx
     1190
     1191    // Initialize data
     1192    int numRows = A->numRows;
     1193    int numCols = A->numCols;
     1194
     1195    *U = psImageRecycle(*U,  numCols, numRows, A->type.type);
     1196    *V = psImageRecycle(*V,  numCols, numCols, A->type.type);
     1197    *w = psVectorRecycle(*w, numCols, A->type.type);
     1198
     1199    gsl_matrix *Agsl = gsl_matrix_alloc(numRows, numCols);
     1200    gsl_matrix *Vgsl = gsl_matrix_alloc(numCols, numCols);
     1201    gsl_vector *Sgsl = gsl_vector_alloc(numCols);
     1202    gsl_vector *work = gsl_vector_alloc(numCols);
     1203
     1204    // Copy psImage data into GSL matrix data
     1205    matrixPStoGSL(Agsl, A);
     1206
     1207    // Calculate SVD decomposition
     1208    gsl_linalg_SV_decomp(Agsl, Vgsl, Sgsl, work);
     1209
     1210    // Copy GSL matrix data to psImage data
     1211    matrixGSLtoPS(*V, Vgsl);
     1212    matrixGSLtoPS(*U, Agsl);  // gsl_linalg_SV_decomp replaces A with U
     1213    vectorGSLtoPS(*w, Sgsl);
     1214
     1215    // Free GSL data
     1216    gsl_matrix_free(Agsl);
     1217    gsl_matrix_free(Vgsl);
     1218    gsl_vector_free(Sgsl);
     1219    gsl_vector_free(work);
     1220
     1221    return true;
     1222}
     1223
  • branches/tap_branches/psLib/src/math/psMatrix.h

    r24084 r27838  
    6666 */
    6767psImage *psMatrixLUInvert(
    68     psImage *out,                  ///< place result here if not NULL
    69     const psImage* LU,             ///< LU-decomposed matrix.
    70     const psVector* perm           ///< Permutation vector resulting from psMatrixLUD function.
     68    psImage *out,                  ///< place result here if not NULL
     69    const psImage* LU,             ///< LU-decomposed matrix.
     70    const psVector* perm           ///< Permutation vector resulting from psMatrixLUD function.
    7171);
    7272
     
    186186);
    187187
    188 /// Single value decomposition, provided by Andy Becker
    189 psImage *psMatrixSVD(psImage* evec, psVector* eval, const psImage* in);
     188/// Solve a matrix equation using Singular Value Decomposition
     189///
     190/// Solves Ax = b for x
     191psVector *psMatrixSolveSVD(
     192    psVector *solution,                 ///< Solution to output, or NULL
     193    const psImage *matrix,              ///< Matrix to be solved
     194    const psVector *vector,             ///< Vector of values
     195    float thresh                        ///< Threshold relative to maximum for trimming singular values
     196    );
     197
     198/// Single value decomposition (original by Andy Becker, updated by EAM)
     199bool psMatrixSVD(psImage **U, psVector **w, psImage **V, const psImage *A);
    190200
    191201/// @}
  • branches/tap_branches/psLib/src/math/psMinimizeLMM.c

    r24089 r27838  
    9999
    100100// XXX check that the GJ solver works:
    101 # if (TESTGJ) 
     101# if (TESTGJ)
    102102    psImage *out = psImageAlloc (alpha->numRows, alpha->numCols, PS_TYPE_F32);
    103103    for (int oy = 0; oy < out->numRows; oy++) {
    104         for (int ox = 0; ox < out->numCols; ox++) {
    105             float value = 0;
    106             for (int i = 0; i < alpha->numCols; i++) {
    107                 value += alpha->data.F32[i][ox]*Alpha->data.F32[oy][i];
    108             }
    109             out->data.F32[oy][ox] = value;
    110         }
     104        for (int ox = 0; ox < out->numCols; ox++) {
     105            float value = 0;
     106            for (int i = 0; i < alpha->numCols; i++) {
     107                value += alpha->data.F32[i][ox]*Alpha->data.F32[oy][i];
     108            }
     109            out->data.F32[oy][ox] = value;
     110        }
    111111    }
    112112
    113113    psVector *vect = psVectorAlloc (beta->n, PS_TYPE_F32);
    114114    for (int oy = 0; oy < vect->n; oy++) {
    115         float value = 0;
    116         for (int i = 0; i < alpha->numCols; i++) {
    117             value += alpha->data.F32[oy][i]*Beta->data.F32[i];
    118         }
    119         vect->data.F32[oy] = value;
    120     }
    121    
     115        float value = 0;
     116        for (int i = 0; i < alpha->numCols; i++) {
     117            value += alpha->data.F32[oy][i]*Beta->data.F32[i];
     118        }
     119        vect->data.F32[oy] = value;
     120    }
     121
    122122    psFree (out);
    123123    psFree (vect);
     
    223223    if (isnan(chisq)) {
    224224        psTrace ("psLib.math", 5, "psMinLM_SetABX() returned a NAN chisq.\n");
    225         psVectorInit (delta, NAN);
     225        psVectorInit (delta, NAN);
    226226        retValue = false;
    227227    }
     
    238238    if (!status) {
    239239        psTrace ("psLib.math", 5, "psMinLM_GuessABP() returned FALSE.\n");
    240         psVectorInit (delta, NAN);
     240        psVectorInit (delta, NAN);
    241241        retValue = false;
    242242    }
     
    301301    PS_ASSERT_VECTOR_NON_NULL(dy, NAN);
    302302
    303     PS_ASSERT_VECTOR_TYPE(params, PS_TYPE_F32, false);
     303    PS_ASSERT_VECTOR_TYPE(params, PS_TYPE_F32, NAN);
    304304    if (paramMask) {
    305         PS_ASSERT_VECTOR_TYPE(paramMask, PS_TYPE_VECTOR_MASK, false);
     305        PS_ASSERT_VECTOR_TYPE(paramMask, PS_TYPE_VECTOR_MASK, NAN);
    306306    }
    307307
     
    325325        chisq += PS_SQR(delta) * dy->data.F32[i];
    326326
    327         assert (!isnan(dy->data.F32[i]));
    328         assert (!isnan(delta));
    329         assert (!isnan(chisq));
     327        if (isnan(dy->data.F32[i])) return NAN;
     328        if (isnan(delta)) return NAN;
     329        if (isnan(chisq)) return NAN;
    330330
    331331        // we track alpha,beta and params,deriv separately
  • branches/tap_branches/psLib/src/math/psStats.c

    r25884 r27838  
    749749    // Iterate to get the best bin size; an iteration limit is enforced at the bottom of the loop.
    750750    for (int iterate = 1; iterate > 0; iterate++) {
    751         psTrace(TRACE, 6,
    752                 "-------------------- Iterating on Bin size.  Iteration number %d --------------------\n",
    753                 iterate);
     751        psTrace(TRACE, 6, "-------------------- Iterating on Bin size.  Iteration number %d --------------------\n", iterate);
     752
     753        if (iterate >= PS_ROBUST_MAX_ITERATIONS) {
     754          // This occurs when a large number of the values are identical --- a bin size cannot be found
     755          // that will spread out the distribution.  Therefore, set what we can, and fall over
     756          // gracefully.
     757          COUNT_WARNING(10, 100, "Maximum number of iterations (%d) exceeded.", PS_ROBUST_MAX_ITERATIONS);
     758          goto escape;
     759        }
    754760
    755761        // Get the minimum and maximum values
     
    791797        psTrace(TRACE, 6, "Initial robust bin size is %.2f\n", binSize);
    792798
    793         // ADD step 0: Construct the histogram with the specified bin size.  NOTE: we can not specify the bin
    794         // size precisely since the argument to psHistogramAlloc() is the number of bins, not the binSize.  If
    795         // we get here, we know that binSize != 0.0.
    796         long numBins = (max - min) / binSize; // Number of bins
     799        // ADD step 0: Construct the histogram with the specified bin size.  NOTE: we can
     800        // not specify the bin size precisely since the argument to psHistogramAlloc() is
     801        // the number of bins, not the binSize.  If we get here, we know that binSize !=
     802        // 0.0.  We can also have a floating-point round-off error such that the last bin
     803        // of the histogram does not correspond exactly with the value of 'max'.  Let's be
     804        // a bit generous and extend the histogram by two bins in either direction
     805        long numBins = 4 + (max - min) / binSize; // Number of bins
    797806        psTrace(TRACE, 6, "Numbins is %ld\n", numBins);
    798807        psTrace(TRACE, 6, "Creating a robust histogram from data range (%.2f - %.2f)\n", min, max);
    799808        // Generate the histogram
    800         histogram = psHistogramAlloc(min, max, numBins);
     809        histogram = psHistogramAlloc(min - 2.0*binSize, max + 2.0*binSize, numBins);
    801810        // XXXXX we need to consider this step if errors -> variance
    802811        if (!psVectorHistogram(histogram, myVector, errors, mask, maskVal)) {
     
    807816            psFree(statsMinMax);
    808817            psFree(mask);
    809 
    810818            return false;
    811819        }
     
    813821            PS_VECTOR_PRINT_F32(histogram->bounds);
    814822            PS_VECTOR_PRINT_F32(histogram->nums);
     823        }
     824
     825        // perversity check: if most of the values land in a single bin, then we probably
     826        // have a perverse case (eg, small number of points at extremely large / small
     827        // values; nearly bi-modal distribution).  if so, keep only points within 5? 10?
     828        // bins of that excess bin:
     829        int nMaxBin = 0;
     830        int iMaxBin = 0;
     831        for (long i = 1; i < histogram->nums->n; i++) {
     832            if (histogram->nums->data.F32[i] > nMaxBin) {
     833                nMaxBin = histogram->nums->data.F32[i];
     834                iMaxBin = i;
     835            }
     836        }
     837        if (nMaxBin > numValid / 2) {
     838            float minKeep = histogram->bounds->data.F32[iMaxBin] - 10*binSize;
     839            float maxKeep = histogram->bounds->data.F32[iMaxBin + 1] + 10*binSize;
     840            int nInvalid = 0;
     841            for (long i = 0; i < myVector->n; i++) {
     842                // skip the already-masked values
     843                if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskVal) continue;
     844                bool invalid = false;
     845                invalid |= (myVector->data.F32[i] <= minKeep);
     846                invalid |= (myVector->data.F32[i] >= maxKeep);
     847                invalid |= (!isfinite(myVector->data.F32[i]));
     848                if (!invalid) continue;
     849                mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = maskVal;
     850                nInvalid ++;
     851            }
     852
     853            if (nInvalid) {
     854              psTrace(TRACE, 6, "data is concentrated in a single bin, masking %d extreme outliers and retrying\n", nInvalid);
     855              psFree(histogram);
     856              psFree(cumulative);
     857              histogram = NULL;
     858              cumulative = NULL;
     859              continue;
     860            }
     861            // if we did not mask anything, give up.
    815862        }
    816863
     
    10071054    stats->robustN50 = N50;
    10081055    psTrace(TRACE, 6, "The robustN50 is %ld.\n", N50);
     1056    psTrace(TRACE, 6, "The robust median and stdev are %f, %f\n", stats->robustMedian, stats->robustStdev);
    10091057
    10101058    // Clean up
     
    18251873            COUNT_WARNING(10, 100, "Failed to calculate the min/max of the input vector.\n");
    18261874            psFree(statsMinMax);
     1875            psFree(histogram);
    18271876            goto escape;
    18281877        }
     
    18941943
    18951944            if (!status) {
    1896                 psErrorClear();
     1945                psErrorClear();
    18971946                COUNT_WARNING(10, 100, "Failed to fit a gaussian to the robust histogram.\n");
    18981947                psFree(poly);
     
    19842033
    19852034            if (!status) {
    1986                 psErrorClear();
     2035                psErrorClear();
    19872036                COUNT_WARNING(10, 100, "Failed to fit a gaussian to the robust histogram.\n");
    19882037                psFree(poly);
  • branches/tap_branches/psLib/src/math/psUnaryOp.c

    r17050 r27838  
    211211}
    212212
    213 psMathType* psUnaryOp(psPtr out, const psPtr in, const char *op)
     213psMathType* psUnaryOp(psPtr out, psPtr in, const char *op)
    214214{
    215215    #define psUnaryOp_EXIT { \
  • branches/tap_branches/psLib/src/math/psUnaryOp.h

    r11248 r27838  
    5959psMathType* psUnaryOp(
    6060    psPtr out,                         ///< Output type, either psImage or psVector.
    61     const psPtr in,                    ///< Input, either psImage or psVector.
     61    psPtr in,                          ///< Input, either psImage or psVector.
    6262    const char *op                     ///< Operator.
    6363);
  • branches/tap_branches/psLib/src/mathtypes/psImage.h

    r19056 r27838  
    6666#define P_PSIMAGE_SET_ROW0(img,r0) {*(int*)&img->row0 = r0;}
    6767#define P_PSIMAGE_SET_TYPE(img,t) {*(psMathType*)&img->type = t;}
     68#define P_PSIMAGE_GET_TYPE(img) ((img)->type->type)
    6869
    6970/** Create an image of the specified size and type.
  • branches/tap_branches/psLib/src/mathtypes/psVector.c

    r24886 r27838  
    729729    char line[1024];
    730730
    731     sprintf (line, "vector: %s\n", name);
     731    sprintf (line, "# vector: %s\n", name);
    732732    if (write(fd, line, strlen(line))) {;} //ignore return value
    733733
  • branches/tap_branches/psLib/src/pslib_strict.h

    r23149 r27838  
    102102#include "psType.h"
    103103#include "psArray.h"
    104 #include "psBitSet.h"
     104#include "psBits.h"
    105105#include "psHash.h"
    106106#include "psList.h"
  • branches/tap_branches/psLib/src/sys/psErrorCodes.c.in

    r11675 r27838  
    6767static void freeErrorDescription(psErrorDescription* err)
    6868{
    69     psFree((void *)err->description);
     69    psFree(err->description);
    7070}
    7171
  • branches/tap_branches/psLib/src/sys/psMemory.h

    r23305 r27838  
    326326
    327327/** Free memory.  This operates much like free().
    328  *
     328 * 
    329329 *  @see psAlloc, psRealloc
     330 *  note: we cast ptr to (void *) in case we are supplied a const pointer.
    330331 */
    331332#ifdef DOXYGEN
     
    336337#ifndef SWIG
    337338#define psFree(ptr) \
    338         psMemDecrRefCounter(ptr)
     339    ptr = psMemDecrRefCounter((void *)ptr);
    339340#endif // ifndef SWIG
    340341#endif // ifdef DOXYGEN
  • branches/tap_branches/psLib/src/sys/psTrace.c

    r20546 r27838  
    119119
    120120    psMemSetPersistent((psPtr)comp->name,false);
    121     psFree((void *)comp->name);
     121    psFree(comp->name);
    122122}
    123123
  • branches/tap_branches/psLib/src/sys/psType.c

    r11617 r27838  
    2020
    2121#include "psType.h"
    22 #include "psBitSet.h"
     22#include "psBits.h"
    2323#include "psFits.h"
    2424#include "psPixels.h"
     
    4545        }
    4646        break;
    47     case PS_DATA_BITSET:
    48         if (psMemCheckBitSet(ptr)) {
     47    case PS_DATA_BITS:
     48        if (psMemCheckBits(ptr)) {
    4949            return true;
    5050        }
  • branches/tap_branches/psLib/src/sys/psType.h

    r25256 r27838  
    107107    PS_DATA_STRING = 0x10000,          ///< psString (char *)
    108108    PS_DATA_ARRAY,                     ///< psArray
    109     PS_DATA_BITSET,                    ///< psBitSet
     109    PS_DATA_BITS,                      ///< psBits
    110110    PS_DATA_CUBE,                      ///< psCube
    111111    PS_DATA_FITS,                      ///< psFits
  • branches/tap_branches/psLib/src/types/Makefile.am

    r23148 r27838  
    66libpslibtypes_la_SOURCES = \
    77        psArray.c \
    8         psBitSet.c \
     8        psBits.c \
    99        psHash.c \
    1010        psList.c \
     
    2323pkginclude_HEADERS = \
    2424        psArray.h \
    25         psBitSet.h \
     25        psBits.h \
    2626        psHash.h \
    2727        psList.h \
  • branches/tap_branches/psLib/src/types/psArray.c

    r15714 r27838  
    166166// drop an item from the array and free it
    167167bool psArrayRemoveData(psArray* array,
    168                        const psPtr data)
     168                       psPtr data)
    169169{
    170170    PS_ASSERT_ARRAY_NON_NULL(array, false);
  • branches/tap_branches/psLib/src/types/psArray.h

    r19056 r27838  
    186186bool psArrayRemoveData(
    187187    psArray* array,                    ///< array to operate on
    188     const psPtr data                   ///< the data pointer to remove from psArray
     188    psPtr data                         ///< the data pointer to remove from psArray
    189189);
    190190
  • branches/tap_branches/psLib/src/types/psList.c

    r18955 r27838  
    210210    }
    211211
     212    // XXX remove this as an error
    212213    if (location < 0 || location >= (int)list->n) {
    213214        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     
    446447    psListIterator* iterator = list->iterators->data[0];
    447448
     449    // XXX remove this as an eror
    448450    if (! psListIteratorSet(iterator,location)) {
    449451        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
  • branches/tap_branches/psLib/src/types/psLookupTable.c

    r17447 r27838  
    3131#include "psString.h"
    3232#include "psError.h"
     33#include "psString.h"
     34#include "psSlurp.h"
    3335#include "psLookupTable.h"
    3436
     
    153155        char *end = NULL; \
    154156        ps##TYPE value = FUNC(strValue, &end, 0); \
    155         if (*end != '\0' && !isspace(*end)) { \
     157        if (*end != '\0' && *end != '\n' && !isspace(*end)) { \
     158            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Characters left over after parsing %s: %s", \
     159                strValue, end); \
    156160            *status = PS_PARSE_ERROR_VALUE; \
    157161        } \
     
    164168        char *end = NULL; \
    165169        ps##TYPE value = FUNC(strValue, &end); \
    166         if (*end != '\0' && !isspace(*end)) { \
     170        if (*end != '\0' && *end != '\n' && !isspace(*end)) { \
     171            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Characters left over after parsing %s: %s", \
     172                strValue, end); \
    167173            *status = PS_PARSE_ERROR_VALUE; \
    168174        } \
     
    244250}
    245251
    246 psArray *psVectorsReadFromFile(const char *filename,
    247                                const char *format)
     252psArray *psVectorsReadFromFile(const char *filename, const char *format)
    248253{
    249254    PS_ASSERT_STRING_NON_EMPTY(filename, NULL);
    250255    PS_ASSERT_STRING_NON_EMPTY(format, NULL);
    251256
    252     psArray*          outputArray = NULL;
    253     psVector*         colVector   = NULL;
    254     char*             strValue    = NULL;
    255     char*             strNum      = NULL;
    256     char*             line        = NULL;
    257     char*             linePtr     = NULL;
    258     int               numCols     = 0;
    259     int               numRows     = 0;
    260     FILE*             fp          = NULL;
    261     const char*       tempFormat  = NULL;
    262     psParseErrorType  parseStatus = PS_PARSE_SUCCESS;
    263 
    264     // Create temp pointer which can then be used several times
    265     tempFormat = format;
    266 
    267     // Create output array and set array elements to zero
    268     outputArray = psArrayAllocEmpty(INITIAL_NUM);
    269 
    270     // Parse the format string to determine how many vectors
    271     // and whether the format string is valid
    272     while ((strValue = getToken((char**)&tempFormat, " \t", &parseStatus))) {
    273 
    274         // Check for %d format sub string
     257    psArray *outputArray = psArrayAllocEmpty(INITIAL_NUM); // Array of vectors to return
     258    psParseErrorType parseStatus = PS_PARSE_SUCCESS; // Status of parsing
     259
     260    // Parse the format string to determine how many vectors and whether the format string is valid
     261    const char *tempFormat = format;    // Pointer into format
     262    psString strValue;                  // Format of interest
     263    int numCols = 0;                    // Number of columns found in format
     264    while ((strValue = getToken((char**)&tempFormat, " \t", &parseStatus)) &&
     265           parseStatus == PS_PARSE_SUCCESS) {
     266        if (strstr(strValue,"\%*") != 0) {
     267            // Don't increase number of columns
     268            continue;
     269        }
     270        psElemType type;                // Type specified
    275271        if (strcmp(strValue,"\%d") == 0 ) {
    276             numCols++;
    277             colVector = psVectorAlloc(1,PS_TYPE_S32);
    278             outputArray = psArrayAdd(outputArray, ARRAY_STRIDE, colVector);
    279             psFree(colVector);
     272            type = PS_TYPE_S32;
    280273        } else if (strcmp(strValue,"\%ld") == 0) {
    281             numCols++;
    282             colVector = psVectorAlloc(1,PS_TYPE_S64);
    283             outputArray = psArrayAdd(outputArray, ARRAY_STRIDE, colVector);
    284             psFree(colVector);
     274            type = PS_TYPE_S64;
    285275        } else if (strcmp(strValue,"\%f") == 0) {
    286             numCols++;
    287             colVector = psVectorAlloc(1,PS_TYPE_F32);
    288             outputArray = psArrayAdd(outputArray, ARRAY_STRIDE, colVector);
    289             psFree(colVector);
     276            type = PS_TYPE_F32;
    290277        } else if (strcmp(strValue,"\%lf") == 0) {
    291             numCols++;
    292             colVector = psVectorAlloc(1,PS_TYPE_F64);
    293             outputArray = psArrayAdd(outputArray, ARRAY_STRIDE, colVector);
    294             psFree(colVector);
    295         } else if (strstr(strValue,"\%*") != 0) {
    296             // Don't increase number of columns
     278            type = PS_TYPE_F64;
    297279        } else {
    298             psError(PS_ERR_BAD_PARAMETER_VALUE, true,
    299                     "Invalid format specifier");
     280            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Invalid format specifier: %s", strValue);
    300281            psFree(strValue);
    301             numCols = 0;
    302             break;
    303         }
     282            psFree(outputArray);
     283            return NULL;
     284        }
     285        psVector *colVector = psVectorAllocEmpty(1, type); // Vector for type
     286        outputArray = psArrayAdd(outputArray, ARRAY_STRIDE, colVector);
     287        psFree(colVector);
     288        numCols++;
    304289        psFree(strValue);
     290    }
     291    if (parseStatus != PS_PARSE_SUCCESS) {
     292        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Failed to parse format at column %d: %s",
     293                numCols, strValue);
     294        psFree(strValue);
     295        psFree(outputArray);
     296        return NULL;
     297    }
     298
     299    if (numCols == 0) {
     300        // Format string parse error detected
     301        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Format string was not parsed sucessfully");
     302        psFree(outputArray);
     303        return NULL;
    305304    }
    306305
    307306    // If the format string was parsed successfully and return numCols the
    308307    // prepare to open file and read values
    309     if (numCols > 0) {
    310 
    311         // Open specified file
    312         if ((fp=fopen(filename, "r")) == NULL) {
    313             psError(PS_ERR_BAD_PARAMETER_VALUE, true, _("Failed to open file %s."),
    314                     filename);
    315             psFree(outputArray);
    316             return NULL;
    317         } else {
    318             // Initialize array index
    319             int arrayIndex = 0;
    320 
    321             // Create reusable line for continuous read
    322             line = (char*)psAlloc(MAX_STRING_LENGTH*sizeof(char));
    323 
    324             // Loop through file to get numRows, numCols, and column data types
    325             while ((fgets(line, MAX_STRING_LENGTH, fp) != NULL) &&
    326                     (parseStatus == PS_PARSE_SUCCESS))   {
    327 
    328                 // Copy pointer to line for parsing
    329                 linePtr = line;
    330 
    331                 // If line is not a comment or blank, then extract data
    332                 if (!ignoreLine(linePtr)) {
    333                     numRows++;
    334 
    335                     // Copy format pointer for parsing
    336                     tempFormat = format;
    337                     arrayIndex = 0;
    338                     parseStatus = PS_PARSE_SUCCESS;
    339 
    340                     // Loop through format and line strings to get values in text table file
    341                     while ((strValue=getToken((char**)&tempFormat," \t",&parseStatus))
    342                             && (strNum=getToken((char**)&linePtr," \t",&parseStatus)) ) {
    343                         // Set column vector
    344                         colVector = outputArray->data[arrayIndex];
    345 
    346                         // Set column entries based on format string defining the type
    347                         if (strcmp(strValue,"\%d") == 0 ) {
    348                             colVector = psVectorRecycle(colVector, numRows,
    349                                                         colVector->type.type);
    350                             parseValue(colVector,numRows-1,strNum,&parseStatus);
    351                             arrayIndex++;
    352                         } else if (strcmp(strValue,"\%ld") == 0) {
    353                             colVector = psVectorRecycle(colVector, numRows,
    354                                                         colVector->type.type);
    355                             parseValue(colVector,numRows-1,strNum,&parseStatus);
    356                             arrayIndex++;
    357                         } else if (strcmp(strValue,"\%f") == 0) {
    358                             colVector = psVectorRecycle(colVector, numRows,
    359                                                         colVector->type.type);
    360                             parseValue(colVector,numRows-1,strNum,&parseStatus);
    361                             arrayIndex++;
    362                         } else if (strcmp(strValue,"\%lf") == 0) {
    363                             colVector = psVectorRecycle(colVector, numRows,
    364                                                         colVector->type.type);
    365                             parseValue(colVector,numRows-1,strNum,&parseStatus);
    366                             arrayIndex++;
    367                         } else if (strstr(strValue,"\%*") != 0) {
    368                             // Don't increase number of columns
    369                         }
    370                         psFree(strValue);
    371                         psFree(strNum);
    372 
    373                         // If the file line was not parsed successful report
    374                         // error and return NULL
    375                         if (parseStatus != PS_PARSE_SUCCESS) {
    376                             psError(PS_ERR_UNKNOWN, true,
    377                                     "Parsing text file failed.");
    378                             fclose(fp);
    379                             psFree(outputArray);
    380                             psFree(line);
    381                             return NULL;
    382                         }
    383                     }
    384                     if (strValue != NULL && strNum == NULL) {
    385                         psError(PS_ERR_UNKNOWN, true,
    386                                 "Parsing text file failed - missing table value(s).");
    387                         fclose(fp);
    388                         psFree(outputArray);
    389                         psFree(line);
    390                         psFree(strValue);
    391                         return NULL;
    392                     }
    393                 }  // ignore line
     308
     309    psString file = psSlurpFilename(filename); // Contents of file
     310    if (!file) {
     311        psError(psErrorCodeLast(), false, "Unable to read file of vectors");
     312        psFree(outputArray);
     313        return NULL;
     314    }
     315
     316    psArray *lines = psStringSplitArray(file, "\n", false); // Lines of file
     317    psFree(file);
     318    long numRows = 0;                                  // Number of rows
     319    for (long i = 0; i < lines->n; i++) {
     320        psString line = lines->data[i]; // Line of interest
     321        if (ignoreLine(line)) {
     322            continue;
     323        }
     324        numRows++;
     325
     326        char *linePtr = line;           // Pointer into line
     327
     328        // Copy format pointer for parsing
     329        const char *tempFormat = format; // Pointer into format
     330        long arrayIndex = 0;            // Index in array
     331        parseStatus = PS_PARSE_SUCCESS;
     332
     333        // Loop through format and line strings to get values in text table file
     334        char *strNum;                   // Number within line
     335        while ((strValue=getToken((char**)&tempFormat," \t",&parseStatus)) &&
     336               (strNum=getToken((char**)&linePtr," \t",&parseStatus)) &&
     337               parseStatus == PS_PARSE_SUCCESS) {
     338            if (strstr(strValue,"\%*") != 0) {
     339                continue;
    394340            }
    395341
    396             //Return NULL for an empty table
    397             if (numRows == 0) {
    398                 psError(PS_ERR_UNKNOWN, true,
    399                         "Parsing text file failed - input table is empty.");
    400                 fclose(fp);
     342            // Set column vector
     343            psVector *colVector = outputArray->data[arrayIndex]; // Column vector of interest
     344
     345            outputArray->data[arrayIndex] = colVector = psVectorRecycle(colVector, numRows,
     346                                                                        colVector->type.type);
     347            parseValue(colVector, numRows - 1, strNum, &parseStatus);
     348            arrayIndex++;
     349
     350            if (parseStatus != PS_PARSE_SUCCESS) {
     351                psError(PS_ERR_UNKNOWN, false, "Parsing text file failed: %s as %s", strNum, strValue);
    401352                psFree(outputArray);
    402                 psFree(line);
     353                psFree(lines);
     354                psFree(strNum);
     355                psFree(strValue);
    403356                return NULL;
    404357            }
    405 
    406             // Read on the lines in the file - close file pointer
    407             fclose(fp);
    408             psFree(line);
    409         }
    410     } else {
    411         // Format string parse error detected
    412         psError(PS_ERR_UNKNOWN, true,
    413                 "Format string was not parsed sucessfully");
     358            psFree(strValue);
     359            psFree(strNum);
     360
     361        }
     362        if (strValue != NULL && strNum == NULL) {
     363            psError(PS_ERR_UNKNOWN, true,
     364                    "Parsing text file failed - missing table value(s).");
     365            psFree(outputArray);
     366            psFree(lines);
     367            psFree(strValue);
     368            return NULL;
     369        }
     370    }
     371    if (parseStatus != PS_PARSE_SUCCESS) {
     372        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Failed to parse format at column %d: %s",
     373                numCols, strValue);
     374        psFree(strValue);
    414375        psFree(outputArray);
    415376        return NULL;
    416377    }
     378
     379    psFree(lines);
    417380
    418381    // Return populated array
  • branches/tap_branches/psLib/src/types/psMetadata.c

    r25383 r27838  
    280280    }
    281281    case     PS_DATA_ARRAY:                     // psArray
    282     case     PS_DATA_BITSET:                    // psBitSet
     282    case     PS_DATA_BITS:                      // psBits
    283283    case     PS_DATA_CUBE:                      // psCube
    284284    case     PS_DATA_FITS:                      // psFits
     
    622622
    623623// may need to extend this to change the keyname in the copy
    624 bool psMetadataItemSupplement(psMetadata *out,
     624bool psMetadataItemSupplement(bool *status,
     625                              psMetadata *out,
    625626                              const psMetadata *in,
    626627                              const char *key)
     
    632633    psMetadataItem *item = psMetadataLookup(in, key);
    633634    if (!item) {
    634         psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Could not find '%s' in metadata.\n", key);
     635        if (status) {
     636            *status = false;
     637        } else {
     638            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Could not find '%s' in metadata.\n", key);
     639        }
    635640        return false;
    636641    }
     
    968973}
    969974
    970 psMetadataItem* psMetadataLookup(const psMetadata *md,
     975// Get entry by index
     976psMetadataItem *psMetadataGetIndex(psMetadata *md, long location)
     977{
     978    PS_ASSERT_METADATA_NON_NULL(md, false);
     979    return psListGet(md->list, location);
     980}
     981
     982psMetadataItem *psMetadataLookup(const psMetadata *md,
    971983                                 const char *key)
    972984{
     
    11471159    PS_ASSERT_METADATA_NON_NULL(md,NULL);
    11481160
     1161    // XXX remove this as an error
    11491162    entry = (psMetadataItem*) psListGet(md->list, location);
    11501163    if (entry == NULL) {
  • branches/tap_branches/psLib/src/types/psMetadata.h

    r25383 r27838  
    545545 */
    546546bool psMetadataItemSupplement(
     547    bool *status,                       ///< if supplied, returns true/false if key is found (suppresses the error)
    547548    psMetadata *out,                   ///< output Metadata container for copying.
    548549    const psMetadata *in,              ///< Metadata collection from which to copy.
  • branches/tap_branches/psLib/src/types/psMetadataConfig.c

    r23859 r27838  
    16491649        return false;
    16501650    }
    1651     fprintf(file, "%s", fileString);
     1651    if (fprintf(file, "%s", fileString) != strlen(fileString)) {
     1652        psError(PS_ERR_IO, true, "Failed to write contents of configuration file %s", filename);
     1653        psFree(fileString);
     1654        fclose(file);
     1655        return false;
     1656    }
    16521657    psFree(fileString);
    16531658    if (fclose(file) == EOF) {
  • branches/tap_branches/psLib/test/types/Makefile.am

    r18145 r27838  
    2929        tap_psPixels_all \
    3030        tap_psHash_all \
    31         tap_psBitSet_all \
     31        tap_psBits_all \
    3232        tap_psList_all \
    3333        tap_psLookupTable_all \
Note: See TracChangeset for help on using the changeset viewer.