int StochasticReleaseTestProbe::computePValues(long int step, int f) {
   int status = PV_SUCCESS;
   assert(step >=0 && step < INT_MAX);
   int nf = getTargetLayer()->getLayerLoc()->nf;
   assert(f >= 0 && f < nf);
   int idx = (step-1)*nf + f;
   pvwdata_t wgt = conn->get_wDataStart(0)[f*(nf+1)]; // weights should be one-to-one weights

   HyPerLayer * pre = conn->preSynapticLayer();
   const pvdata_t * preactPtr = pre->getLayerData();
   const PVLayerLoc * preLoc = pre->getLayerLoc();
   const int numPreNeurons = pre->getNumNeurons();
   bool found=false;
   pvdata_t preact = 0.0f;
   for (int n=f; n<numPreNeurons; n+=nf) {
      int nExt = kIndexExtended(n, preLoc->nx, preLoc->ny, preLoc->nf, preLoc->halo.lt, preLoc->halo.rt, preLoc->halo.dn, preLoc->halo.up);
      pvdata_t a = preactPtr[nExt];
      if (a!=0.0f) {
         if (found) {
            assert(preact==a);
         }
         else {
            found = true;
            preact = a;
         }
      }
   }
   preact *= getParent()->getDeltaTime();
   if (preact < 0.0f) preact = 0.0f;
   if (preact > 1.0f) preact = 1.0f;

   const PVLayerLoc * loc = getTargetLayer()->getLayerLoc();
   const pvdata_t * activity = getTargetLayer()->getLayerData();
   int nnzf = 0;
   const int numNeurons = getTargetLayer()->getNumNeurons();
   for (int n=f; n<numNeurons; n+=nf) {
      int nExt = kIndexExtended(n, loc->nx, loc->ny, loc->nf, loc->halo.lt, loc->halo.rt, loc->halo.dn, loc->halo.up);
      assert(activity[nExt]==0 || activity[nExt]==wgt);
      if (activity[nExt]!=0) nnzf++;
   }
   HyPerLayer * l = getTargetLayer();
   HyPerCol * hc = l->getParent();
   MPI_Allreduce(MPI_IN_PLACE, &nnzf, 1, MPI_INT, MPI_SUM, hc->icCommunicator()->communicator());
   if (hc->columnId()==0) {
      const int neuronsPerFeature = l->getNumGlobalNeurons()/nf;
      double mean = preact * neuronsPerFeature;
      double stddev = sqrt(neuronsPerFeature*preact*(1-preact));
      double numdevs = (nnzf-mean)/stddev;
      pvalues[idx] = erfc(fabs(numdevs)/sqrt(2));
      fprintf(outputstream->fp, "    Feature %d, nnz=%5d, expectation=%7.1f, std.dev.=%5.1f, discrepancy of %f deviations, p-value %f\n",
              f, nnzf, mean, stddev, numdevs, pvalues[idx]);
   }
   assert(status==PV_SUCCESS);
   return status;
}
int main(int argc, char* argv[])
{
   int status = 0;

   PV_Init* initObj = new PV_Init(&argc, &argv);
   initObj->initialize(argc, argv);

   // create the managing hypercolumn
   //
   HyPerCol* hc = new HyPerCol("test_constant_input column", argc, argv, initObj);

   // create the image
   //
   TestImage * image = new TestImage("test_constant_input image", hc);

   // create the layers
   //
   HyPerLayer * retina = new Retina("test_constant_input retina", hc);

   // create the connections
   //
   HyPerConn * conn = new HyPerConn("test_constant_input connection", hc);
   const int nxp = conn->xPatchSize();
   const int nyp = conn->yPatchSize();
   const PVLayerLoc * imageLoc = image->getLayerLoc();
   const PVLayerLoc * retinaLoc = image->getLayerLoc();
   const int nfPre = imageLoc->nf;
    
   float sumOfWeights = (float) (nxp*nyp*nfPre);
   if (imageLoc->nx > retinaLoc->nx) { sumOfWeights *= imageLoc->nx/retinaLoc->nx;}
   if (imageLoc->ny > retinaLoc->ny) { sumOfWeights *= imageLoc->ny/retinaLoc->ny;}
   
   hc->run();

   const int rank = hc->columnId();
#ifdef DEBUG_OUTPUT
   printf("[%d]: column: ", rank);
   printLoc(hc->getImageLoc());
   printf("[%d]: image : ", rank);
   printLoc(image->getImageLoc());
   printf("[%d]: retina: ", rank);
   printLoc(*retina->getLayerLoc());
   printf("[%d]: l1    : ", rank);
   printLoc(*l1->getLayerLoc());
#endif

   status = checkLoc(hc, image->getLayerLoc());
   if (status != PV_SUCCESS) {
      fprintf(stderr, "[%d]: test_constant_input: ERROR in image loc\n", rank);
      exit(status);
   }

   status = checkLoc(hc, retina->getLayerLoc());
   if (status != PV_SUCCESS) {
      fprintf(stderr, "[%d]: test_constant_input: ERROR in retina loc\n", rank);
      exit(status);
   }

   status = checkInput(image->getLayerLoc(), image->getActivity(), image->getConstantVal(), true);
   if (status != PV_SUCCESS) {
      fprintf(stderr, "[%d]: test_constant_input: ERROR in image data\n", rank);
      exit(status);
   }

   float retinaVal = sumOfWeights * image->getConstantVal();

   status = checkInput(retina->getLayerLoc(), retina->getActivity(), retinaVal, false);
   if (status != 0) {
      fprintf(stderr, "[%d]: test_constant_input: ERROR in retina data\n", rank);
      exit(status);
   }

   status = checkInput(retina->getLayerLoc(), retina->getLayerData(), retinaVal, true);
   if (status != 0) {
      fprintf(stderr, "[%d]: test_constant_input: ERROR in retina data\n", rank);
      exit(status);
   }

   delete hc;
   delete initObj;

   return status;
}
int RescaleLayerTestProbe::outputState(double timed)
{
   int status = StatsProbe::outputState(timed);
   if (timed==getParent()->getStartTime()) { return PV_SUCCESS; }
   float tolerance = 2.0e-5f;
   InterColComm * icComm = getTargetLayer()->getParent()->icCommunicator();
   bool isRoot = icComm->commRank() == 0;

   RescaleLayer * targetRescaleLayer = dynamic_cast<RescaleLayer *>(getTargetLayer());
   assert(targetRescaleLayer);

   if (targetRescaleLayer->getRescaleMethod()==NULL) {
      fprintf(stderr, "RescaleLayerTestProbe \"%s\": RescaleLayer \"%s\" does not have rescaleMethod set.  Exiting.\n", name, targetRescaleLayer->getName());
      status = PV_FAILURE;
   }
   else if (!strcmp(targetRescaleLayer->getRescaleMethod(), "maxmin")) {
      if (!isRoot) { return PV_SUCCESS; }
      for(int b = 0; b < parent->getNBatch(); b++){
         float targetMax = targetRescaleLayer->getTargetMax();
         if (fabs(fMax[b]-targetMax)>tolerance) {
            fprintf(stderr, "RescaleLayerTestProbe \"%s\": RescaleLayer \"%s\" has max %f instead of target max %f\n", getName(), targetRescaleLayer->getName(), fMax[b], targetMax);
            status = PV_FAILURE;
         }
         float targetMin = targetRescaleLayer->getTargetMin();
         if (fabs(fMin[b]-targetMin)>tolerance) {
            fprintf(stderr, "RescaleLayerTestProbe \"%s\": RescaleLayer \"%s\" has min %f instead of target min %f\n", getName(), targetRescaleLayer->getName(), fMin[b], targetMin);
            status = PV_FAILURE;
         }

         // Now, check whether rescaled activity and original V are colinear.
         PVLayerLoc const * rescaleLoc = targetRescaleLayer->getLayerLoc();
         PVHalo const * rescaleHalo = &rescaleLoc->halo;
         int nk = rescaleLoc->nx * rescaleLoc->nf;
         int ny = rescaleLoc->ny;
         int rescaleStrideYExtended = (rescaleLoc->nx + rescaleHalo->lt + rescaleHalo->rt) * rescaleLoc->nf;
         int rescaleExtendedOffset = kIndexExtended(0, rescaleLoc->nx, rescaleLoc->ny, rescaleLoc->nf, rescaleHalo->lt, rescaleHalo->rt, rescaleHalo->dn, rescaleHalo->up);
         pvadata_t const * rescaledData = targetRescaleLayer->getLayerData() + b * targetRescaleLayer->getNumExtended() + rescaleExtendedOffset;
         PVLayerLoc const * origLoc = targetRescaleLayer->getOriginalLayer()->getLayerLoc();
         PVHalo const * origHalo = &origLoc->halo;
         assert(nk == origLoc->nx * origLoc->nf);
         assert(ny == origLoc->ny);
         int origStrideYExtended = (origLoc->nx + origHalo->lt + origHalo->rt) * origLoc->nf;
         int origExtendedOffset = kIndexExtended(0, rescaleLoc->nx, rescaleLoc->ny, rescaleLoc->nf, rescaleHalo->lt, rescaleHalo->rt, rescaleHalo->dn, rescaleHalo->up);
         pvadata_t const * origData = targetRescaleLayer->getOriginalLayer()->getLayerData() + b * targetRescaleLayer->getOriginalLayer()->getNumExtended() + origExtendedOffset;

         bool iscolinear = colinear(nk, ny, origStrideYExtended, rescaleStrideYExtended, origData, rescaledData, tolerance, NULL, NULL, NULL);
         if (!iscolinear) {
            fprintf(stderr, "RescaleLayerTestProbe \"%s\": Rescale layer \"%s\" data is not a linear rescaling of original membrane potential.\n", getName(), targetRescaleLayer->getName());
            status = PV_FAILURE;
         }
      }
   }
   //l2 norm with a patch size of 1 (default) should be the same as rescaling with meanstd with target mean 0 and std of 1/sqrt(patchsize)
   else if (!strcmp(targetRescaleLayer->getRescaleMethod(), "meanstd") || !strcmp(targetRescaleLayer->getRescaleMethod(), "l2")) {
      if (!isRoot) { return PV_SUCCESS; }
      for(int b = 0; b < parent->getNBatch(); b++){
         float targetMean, targetStd;
         if(!strcmp(targetRescaleLayer->getRescaleMethod(), "meanstd")){
            targetMean = targetRescaleLayer->getTargetMean();
            targetStd = targetRescaleLayer->getTargetStd();
         }
         else{
            targetMean = 0;
            targetStd = 1/sqrt((float)targetRescaleLayer->getL2PatchSize());
         }

         if (fabs(avg[b]-targetMean)>tolerance) {
            fprintf(stderr, "RescaleLayerTestProbe \"%s\": RescaleLayer \"%s\" has mean %f instead of target mean %f\n", getName(), targetRescaleLayer->getName(), (double)avg[b], targetMean);
            status = PV_FAILURE;
         }
         if (sigma[b]>tolerance && fabs(sigma[b]-targetStd)>tolerance) {
            fprintf(stderr, "RescaleLayerTestProbe \"%s\": RescaleLayer \"%s\" has std.dev. %f instead of target std.dev. %f\n", getName(), targetRescaleLayer->getName(), (double)sigma[b], targetStd);
            status = PV_FAILURE;
         }

         // Now, check whether rescaled activity and original V are colinear.
         PVLayerLoc const * rescaleLoc = targetRescaleLayer->getLayerLoc();
         PVHalo const * rescaleHalo = &rescaleLoc->halo;
         int nk = rescaleLoc->nx * rescaleLoc->nf;
         int ny = rescaleLoc->ny;
         int rescaleStrideYExtended = (rescaleLoc->nx + rescaleHalo->lt + rescaleHalo->rt) * rescaleLoc->nf;
         int rescaleExtendedOffset = kIndexExtended(0, rescaleLoc->nx, rescaleLoc->ny, rescaleLoc->nf, rescaleHalo->lt, rescaleHalo->rt, rescaleHalo->dn, rescaleHalo->up);
         pvadata_t const * rescaledData = targetRescaleLayer->getLayerData() + b*targetRescaleLayer->getNumExtended() + rescaleExtendedOffset;
         PVLayerLoc const * origLoc = targetRescaleLayer->getOriginalLayer()->getLayerLoc();
         PVHalo const * origHalo = &origLoc->halo;
         assert(nk == origLoc->nx * origLoc->nf);
         assert(ny == origLoc->ny);
         int origStrideYExtended = (origLoc->nx + origHalo->lt + origHalo->rt) * origLoc->nf;
         int origExtendedOffset = kIndexExtended(0, rescaleLoc->nx, rescaleLoc->ny, rescaleLoc->nf, rescaleHalo->lt, rescaleHalo->rt, rescaleHalo->dn, rescaleHalo->up);
         pvadata_t const * origData = targetRescaleLayer->getOriginalLayer()->getLayerData() + b*targetRescaleLayer->getOriginalLayer()->getNumExtended() + origExtendedOffset;

         bool iscolinear = colinear(nk, ny, origStrideYExtended, rescaleStrideYExtended, origData, rescaledData, tolerance, NULL, NULL, NULL);
         if (!iscolinear) {
            fprintf(stderr, "RescaleLayerTestProbe \"%s\": Rescale layer \"%s\" data is not a linear rescaling of original membrane potential.\n", getName(), targetRescaleLayer->getName());
            status = PV_FAILURE;
         }
      }
   }
   else if (!strcmp(targetRescaleLayer->getRescaleMethod(), "pointmeanstd")) {
      PVLayerLoc const * loc = targetRescaleLayer->getLayerLoc();
      int nf = loc->nf;
      if (nf<2) { return PV_SUCCESS; }
      PVHalo const * halo = &loc->halo;
      float targetMean = targetRescaleLayer->getTargetMean();
      float targetStd = targetRescaleLayer->getTargetStd();
      int numNeurons = targetRescaleLayer->getNumNeurons();
      for(int b = 0; b < parent->getNBatch(); b++){
         pvpotentialdata_t const * originalData = targetRescaleLayer->getV() + b*targetRescaleLayer->getNumNeurons();
         pvadata_t const * rescaledData = targetRescaleLayer->getLayerData() + b*targetRescaleLayer->getNumExtended();
         for (int k=0; k<numNeurons; k+=nf) {
            int kExtended = kIndexExtended(k, loc->nx, loc->ny, loc->nf, halo->lt, halo->rt, halo->dn, halo->up);
            double pointmean = 0.0;
            for (int f=0; f<nf; f++) {
               pointmean += rescaledData[kExtended+f];
            }
            pointmean /= nf;
            double pointstd = 0.0;
            for (int f=0; f<nf; f++) {
               double d = rescaledData[kExtended+f]-pointmean;
               pointstd += d*d;
            }
            pointstd /= nf;
            pointstd = sqrt(pointstd);
            if (fabs(pointmean-targetMean)>tolerance) {
               fprintf(stderr, "RescaleLayerTestProbe \"%s\": RescaleLayer \"%s\", location in rank %d, starting at restricted neuron %d, has mean %f instead of target mean %f\n",
                     getName(), targetRescaleLayer->getName(), getParent()->columnId(), k, pointmean, targetMean);
               status = PV_FAILURE;
            }
            if (pointstd>tolerance && fabs(pointstd-targetStd)>tolerance) {
               fprintf(stderr, "RescaleLayerTestProbe \"%s\": RescaleLayer \"%s\", location in rank %d, starting at restricted neuron %d, has std.dev. %f instead of target std.dev. %f\n",
                     getName(), targetRescaleLayer->getName(), getParent()->columnId(), k, pointstd, targetStd);
               status = PV_FAILURE;
            }
            bool iscolinear = colinear(nf, 1, 0, 0, &originalData[k], &rescaledData[kExtended], tolerance, NULL, NULL, NULL);
            if (!iscolinear) {
               fprintf(stderr, "RescaleLayerTestProbe \"%s\": RescaleLayer \"%s\", location in rank %d, starting at restricted neuron %d, is not a linear rescaling.\n",
                     getName(), targetRescaleLayer->getName(), parent->columnId(), k);
               status = PV_FAILURE;
            }
         }
      }
   }
   else if (!strcmp(targetRescaleLayer->getRescaleMethod(), "zerotonegative")) {
      int numNeurons = targetRescaleLayer->getNumNeurons();
      assert(numNeurons == targetRescaleLayer->getOriginalLayer()->getNumNeurons());
      PVLayerLoc const * rescaleLoc = targetRescaleLayer->getLayerLoc();
      PVHalo const * rescaleHalo = &rescaleLoc->halo;
      int nf = rescaleLoc->nf;
      HyPerLayer * originalLayer = targetRescaleLayer->getOriginalLayer();
      PVLayerLoc const * origLoc = originalLayer->getLayerLoc();
      PVHalo const * origHalo = &origLoc->halo;
      assert(origLoc->nf == nf);

      for(int b = 0; b < parent->getNBatch(); b++){
         pvadata_t const * rescaledData = targetRescaleLayer->getLayerData() + b * targetRescaleLayer->getNumExtended();
         pvadata_t const * originalData = originalLayer->getLayerData() + b * originalLayer->getNumExtended();
         for (int k=0; k<numNeurons; k++) {
            int rescale_kExtended = kIndexExtended(k, rescaleLoc->nx, rescaleLoc->ny, rescaleLoc->nf, rescaleHalo->lt, rescaleHalo->rt, rescaleHalo->dn, rescaleHalo->up);
            int orig_kExtended = kIndexExtended(k, origLoc->nx, origLoc->ny, origLoc->nf, origHalo->lt, origHalo->rt, origHalo->dn, origHalo->up);
            pvadata_t observedval = rescaledData[rescale_kExtended];
            pvpotentialdata_t correctval = originalData[orig_kExtended] ? observedval : -1.0;
            if (observedval != correctval) {
               fprintf(stderr, "RescaleLayerTestProbe \"%s\": RescaleLayer \"%s\", rank %d, restricted neuron %d has value %f instead of expected %f\n.",
                     this->getName(), targetRescaleLayer->getName(), parent->columnId(), k, observedval, correctval);
               status = PV_FAILURE;
            }
         }
      }
   }
   else {
      assert(0);  // All allowable rescaleMethod values are handled above.
   }
   if (status == PV_FAILURE) {
      exit(EXIT_FAILURE);
   }
   return status;
}