Beispiel #1
0
int main(int argc, char **argv) {
	float Score;
	float BestScore = HugeScore;
	int p, i;
	SetupParams(argc, argv);
	clock_t Clock0;
	KK K1; // main KK class, for all data
	K1.penaltyMix = PenaltyMix;

	Clock0 = clock(); // start timer

	K1.LoadData(); // load .fet file
	
	// Seed random number generator
	srand(RandomSeed);
	
	// open distance dump file if required
	if (DistDump) Distfp = fopen("DISTDUMP", "w");	

    // start with provided file, if required
    if (*StartCluFile) {
        Output("Starting from cluster file %s\n", StartCluFile);
        BestScore = K1.CEM(StartCluFile, 1, 1);
		Output("%d->%d Clusters: Score %f\n\n", K1.nStartingClusters, K1.nClustersAlive, BestScore);
		for(p=0; p<K1.nPoints; p++) K1.BestClass[p] = K1.Class[p];
		SaveOutput(K1.BestClass);
    }


	// loop through numbers of clusters ...
	for(K1.nStartingClusters=MinClusters; K1.nStartingClusters<=MaxClusters; K1.nStartingClusters++) for(i=0; i<nStarts; i++) {
		// do CEM iteration
        Output("Starting from %d clusters...\n", K1.nStartingClusters);
		Score = K1.Cluster();
		
		Output("%d->%d Clusters: Score %f, best is %f\n", K1.nStartingClusters, K1.nClustersAlive, Score, BestScore);
		
		if (Score < BestScore) {
			Output("THE BEST YET!\n");
			// New best classification found
			BestScore = Score;
			for(p=0; p<K1.nPoints; p++) K1.BestClass[p] = K1.Class[p];
			SaveOutput(K1.BestClass);
		}
		Output("\n");
	}
	
	SaveOutput(K1.BestClass);
	
	Output("That took %f seconds.\n", (clock()-Clock0)/(float) CLOCKS_PER_SEC);
	
	if (DistDump) fclose(Distfp);
	
	return 0;
}
bool ImageSegmenter::Process()
{
	// Read input image
	m_docImage = imread(m_document_image_path.c_str(), CV_LOAD_IMAGE_GRAYSCALE); // converts to grayscale if required

	PreprocessImage(m_docImage);

	SplitIntoLines(m_docImage);	

	if (m_output_level == "LINES") {
		SaveOutput(m_output_level);
		return true;
	}
	else {
		SplitLinesIntoWords(m_docImage);
		SaveOutput(m_output_level);
	}
			
	return true;
}
Beispiel #3
0
/*---------------------------------------------------------------*/
int main(int argc, char *argv[]) {
  int nargs, n, err;
  char tmpstr[2000], *signstr=NULL,*SUBJECTS_DIR, fname[2000];
  //char *OutDir = NULL;
  RFS *rfs;
  int nSmoothsPrev, nSmoothsDelta;
  MRI *z, *zabs=NULL, *sig=NULL, *p=NULL;
  int FreeMask = 0;
  int nthSign, nthFWHM, nthThresh;
  double sigmax, zmax, threshadj, csize, csizeavg, searchspace,avgvtxarea;
  int csizen;
  int nClusters, cmax,rmax,smax;
  SURFCLUSTERSUM *SurfClustList;
  struct timeb  mytimer;
  LABEL *clabel;
  FILE *fp, *fpLog=NULL;

  nargs = handle_version_option (argc, argv, vcid, "$Name: stable5 $");
  if (nargs && argc - nargs == 1) exit (0);
  argc -= nargs;
  cmdline = argv2cmdline(argc,argv);
  uname(&uts);
  getcwd(cwd,2000);

  Progname = argv[0] ;
  argc --;
  argv++;
  ErrorInit(NULL, NULL, NULL) ;
  DiagInit(NULL, NULL, NULL) ;
  if (argc == 0) usage_exit();
  parse_commandline(argc, argv);
  check_options();
  if (checkoptsonly) return(0);
  dump_options(stdout);

  if(LogFile){
    fpLog = fopen(LogFile,"w");
    if(fpLog == NULL){
      printf("ERROR: opening %s\n",LogFile);
      exit(1);
    }
    dump_options(fpLog);
  } 

  if(SynthSeed < 0) SynthSeed = PDFtodSeed();
  srand48(SynthSeed);

  SUBJECTS_DIR = getenv("SUBJECTS_DIR");

  // Create output directory
  printf("Creating %s\n",OutTop);
  err = fio_mkdirp(OutTop,0777);
  if(err) exit(1);
  for(nthFWHM=0; nthFWHM < nFWHMList; nthFWHM++){
    for(nthThresh = 0; nthThresh < nThreshList; nthThresh++){
      for(nthSign = 0; nthSign < nSignList; nthSign++){
	if(SignList[nthSign] ==  0) signstr = "abs"; 
	if(SignList[nthSign] == +1) signstr = "pos"; 
	if(SignList[nthSign] == -1) signstr = "neg"; 
	sprintf(tmpstr,"%s/fwhm%02d/%s/th%02d",
		OutTop,(int)round(FWHMList[nthFWHM]),
		signstr,(int)round(10*ThreshList[nthThresh]));
	sprintf(fname,"%s/%s.csd",tmpstr,csdbase);
	if(fio_FileExistsReadable(fname)){
	  printf("ERROR: output file %s exists\n",fname);
	  if(fpLog) fprintf(fpLog,"ERROR: output file %s exists\n",fname);
          exit(1);
	}
	err = fio_mkdirp(tmpstr,0777);
	if(err) exit(1);
      }
    }
  }

  // Load the target surface
  sprintf(tmpstr,"%s/%s/surf/%s.%s",SUBJECTS_DIR,subject,hemi,surfname);
  printf("Loading %s\n",tmpstr);
  surf = MRISread(tmpstr);
  if(!surf) return(1);

  // Handle masking
  if(LabelFile){
    printf("Loading label file %s\n",LabelFile);
    sprintf(tmpstr,"%s/%s/label/%s.%s.label",
	    SUBJECTS_DIR,subject,hemi,LabelFile);
    if(!fio_FileExistsReadable(tmpstr)){
      printf(" Cannot find label file %s\n",tmpstr);
      sprintf(tmpstr,"%s",LabelFile);
      printf(" Trying label file %s\n",tmpstr);
      if(!fio_FileExistsReadable(tmpstr)){
	printf("  ERROR: cannot read or find label file %s\n",LabelFile);
	exit(1);
      }
    }
    printf("Loading %s\n",tmpstr);
    clabel = LabelRead(NULL, tmpstr);
    mask = MRISlabel2Mask(surf, clabel, NULL);
    FreeMask = 1;
  }
  if(MaskFile){
    printf("Loading %s\n",MaskFile);
    mask = MRIread(MaskFile);
    if(mask == NULL) exit(1);
  }
  if(mask && SaveMask){
    sprintf(tmpstr,"%s/mask.mgh",OutTop);
    printf("Saving mask to %s\n",tmpstr);
    err = MRIwrite(mask,tmpstr);
    if(err) exit(1);
  }

  // Compute search space
  searchspace = 0;
  nmask = 0;
  for(n=0; n < surf->nvertices; n++){
    if(mask && MRIgetVoxVal(mask,n,0,0,0) < 0.5) continue;
    searchspace += surf->vertices[n].area;
    nmask++;
  }
  printf("Found %d voxels in mask\n",nmask);
  if(surf->group_avg_surface_area > 0)
    searchspace *= (surf->group_avg_surface_area/surf->total_area);
  printf("search space %g mm2\n",searchspace);
  avgvtxarea = searchspace/nmask;
  printf("average vertex area %g mm2\n",avgvtxarea);

  // Determine how many iterations are needed for each FWHM
  nSmoothsList = (int *) calloc(sizeof(int),nFWHMList);
  for(nthFWHM=0; nthFWHM < nFWHMList; nthFWHM++){
    nSmoothsList[nthFWHM] = MRISfwhm2niters(FWHMList[nthFWHM], surf);
    printf("%2d %5.1f  %4d\n",nthFWHM,FWHMList[nthFWHM],nSmoothsList[nthFWHM]);
    if(fpLog) fprintf(fpLog,"%2d %5.1f  %4d\n",nthFWHM,FWHMList[nthFWHM],nSmoothsList[nthFWHM]);
  }
  printf("\n");

  // Allocate the CSDs
  for(nthFWHM=0; nthFWHM < nFWHMList; nthFWHM++){
    for(nthThresh = 0; nthThresh < nThreshList; nthThresh++){
      for(nthSign = 0; nthSign < nSignList; nthSign++){
	csd = CSDalloc();
	sprintf(csd->simtype,"%s","null-z");
	sprintf(csd->anattype,"%s","surface");
	sprintf(csd->subject,"%s",subject);
	sprintf(csd->hemi,"%s",hemi);
	sprintf(csd->contrast,"%s","NA");
	csd->seed = SynthSeed;
	csd->nreps = nRepetitions;
	csd->thresh = ThreshList[nthThresh];
	csd->threshsign = SignList[nthSign];
	csd->nullfwhm = FWHMList[nthFWHM];
	csd->varfwhm = -1;
	csd->searchspace = searchspace;
	CSDallocData(csd);
	csdList[nthFWHM][nthThresh][nthSign] = csd;
      }
    }
  }

  // Alloc the z map
  z = MRIallocSequence(surf->nvertices, 1,1, MRI_FLOAT, 1);

  // Set up the random field specification
  rfs = RFspecInit(SynthSeed,NULL);
  rfs->name = strcpyalloc("gaussian");
  rfs->params[0] = 0;
  rfs->params[1] = 1;

  printf("Thresholds (%d): ",nThreshList);
  for(n=0; n < nThreshList; n++) printf("%5.2f ",ThreshList[n]);
  printf("\n");
  printf("Signs (%d): ",nSignList);
  for(n=0; n < nSignList; n++)  printf("%2d ",SignList[n]);
  printf("\n");
  printf("FWHM (%d): ",nFWHMList);
  for(n=0; n < nFWHMList; n++) printf("%5.2f ",FWHMList[n]);
  printf("\n");

  // Start the simulation loop
  printf("\n\nStarting Simulation over %d Repetitions\n",nRepetitions);
  if(fpLog) fprintf(fpLog,"\n\nStarting Simulation over %d Repetitions\n",nRepetitions);
  TimerStart(&mytimer) ;
  for(nthRep = 0; nthRep < nRepetitions; nthRep++){
    msecTime = TimerStop(&mytimer) ;
    printf("%5d %7.1f ",nthRep,(msecTime/1000.0)/60);
    if(fpLog) {
      fprintf(fpLog,"%5d %7.1f ",nthRep,(msecTime/1000.0)/60);
      fflush(fpLog);
    }
    // Synthesize an unsmoothed z map
    RFsynth(z,rfs,mask); 
    nSmoothsPrev = 0;
    
    // Loop through FWHMs
    for(nthFWHM=0; nthFWHM < nFWHMList; nthFWHM++){
      printf("%d ",nthFWHM);
      if(fpLog) {
	fprintf(fpLog,"%d ",nthFWHM);
	fflush(fpLog);
      }
      nSmoothsDelta = nSmoothsList[nthFWHM] - nSmoothsPrev;
      nSmoothsPrev = nSmoothsList[nthFWHM];
      // Incrementally smooth z
      MRISsmoothMRI(surf, z, nSmoothsDelta, mask, z); // smooth z
      // Rescale
      RFrescale(z,rfs,mask,z);
      // Slightly tortured way to get the right p-values because
      //   RFstat2P() computes one-sided, but I handle sidedness
      //   during thresholding.
      // First, use zabs to get a two-sided pval bet 0 and 0.5
      zabs = MRIabs(z,zabs);
      p = RFstat2P(zabs,rfs,mask,0,p);
      // Next, mult pvals by 2 to get two-sided bet 0 and 1
      MRIscalarMul(p,p,2.0);
      sig = MRIlog10(p,NULL,sig,1); // sig = -log10(p)
      for(nthThresh = 0; nthThresh < nThreshList; nthThresh++){
	for(nthSign = 0; nthSign < nSignList; nthSign++){
	  csd = csdList[nthFWHM][nthThresh][nthSign];

	  // If test is not ABS then apply the sign
	  if(csd->threshsign != 0) MRIsetSign(sig,z,0);
	  // Get the max stats
	  sigmax = MRIframeMax(sig,0,mask,csd->threshsign,
			       &cmax,&rmax,&smax);
	  zmax = MRIgetVoxVal(z,cmax,rmax,smax,0);
	  if(csd->threshsign == 0){
	    zmax = fabs(zmax);
	    sigmax = fabs(sigmax);
	  }
	  // Mask
	  if(mask) MRImask(sig,mask,sig,0.0,0.0);

	  // Surface clustering
	  MRIScopyMRI(surf, sig, 0, "val");
	  if(csd->threshsign == 0) threshadj = csd->thresh;
	  else threshadj = csd->thresh - log10(2.0); // one-sided test
	  SurfClustList = sclustMapSurfClusters(surf,threshadj,-1,csd->threshsign,
						0,&nClusters,NULL);
	  // Actual area of cluster with max area
	  csize  = sclustMaxClusterArea(SurfClustList, nClusters);
	  // Number of vertices of cluster with max number of vertices. 
	  // Note: this may be a different cluster from above!
	  csizen = sclustMaxClusterCount(SurfClustList, nClusters);
	  // Area of this cluster based on average vertex area. This just scales
	  // the number of vertices.
	  csizeavg = csizen * avgvtxarea;
	  if(UseAvgVtxArea) csize = csizeavg;
	  // Store results
	  csd->nClusters[nthRep] = nClusters;
	  csd->MaxClusterSize[nthRep] = csize;
	  csd->MaxSig[nthRep] = sigmax;
	  csd->MaxStat[nthRep] = zmax;
	} // Sign
      } // Thresh
    } // FWHM
    printf("\n");
    if(fpLog) fprintf(fpLog,"\n");
    if(SaveEachIter || fio_FileExistsReadable(SaveFile)) SaveOutput();
    if(fio_FileExistsReadable(StopFile)) {
      printf("Found stop file %s\n",StopFile);
      goto finish;
    }
  } // Simulation Repetition

 finish:

  SaveOutput();

  msecTime = TimerStop(&mytimer) ;
  printf("Total Sim Time %g min (%g per rep)\n",
	 msecTime/(1000*60.0),(msecTime/(1000*60.0))/nthRep);
  if(fpLog) fprintf(fpLog,"Total Sim Time %g min (%g per rep)\n",
		    msecTime/(1000*60.0),(msecTime/(1000*60.0))/nthRep);

  if(DoneFile){
    fp = fopen(DoneFile,"w");
    fprintf(fp,"%g\n",msecTime/(1000*60.0));
    fclose(fp);
  }
  printf("mri_mcsim done\n");
  if(fpLog){
    fprintf(fpLog,"mri_mcsim done\n");
    fclose(fpLog);
  }
  exit(0);
}
Beispiel #4
0
void
avtZoneDumpFilter::PostExecute()
{
    // skip dump if not enabled
    if(!atts.GetEnabled())
        return;

#ifdef PARALLEL
    // loop index
    int i;

    // get the number of processors and the current processor id
    int nprocs = PAR_Size();
    int procid = PAR_Rank();

    // get the number of zone infos to send
    int  n_snd_zones = zones.size();
    // size of each zone info
    int  zinfo_size = ZoneInfo::PackedSize();
    // calculate the total send message size
    int  snd_msg_size = n_snd_zones * zinfo_size;
    // send buffer
    unsigned char *snd_msg = NULL;

    // vars for the root processor
    // size of the gather message
    int  rcv_msg_size = 0;
    // holds size of the msg from each other processor
    int *rcv_count = NULL;
    // holds the displacement of the msg from each other processor
    int *rcv_disp  = NULL;
    // receive buffer
    unsigned char *rcv_msg = NULL;

    if(procid == 0)
    {
        // allocate space for these for root proc only
        rcv_count = new int[nprocs];
        rcv_disp  = new int[nprocs];
    }

    // gather message sizes from all procs to root proc
    MPI_Gather(&snd_msg_size,1, MPI_INT,
               rcv_count, 1, MPI_INT,
               0, VISIT_MPI_COMM);

    // find message offsets and total rcv size
    if(procid == 0)
    {
        rcv_disp[0]  = 0;
        rcv_msg_size = rcv_count[0];

        for( i=1; i<nprocs;i++)
        {
            rcv_disp[i]   = rcv_count[i-1]  +  rcv_disp[i-1];
            rcv_msg_size += rcv_count[i];
        }
    }

    // get total # of zone infos
    int nrcv_zones = rcv_msg_size / zinfo_size;

    // create msg to send to the root proc
    if(snd_msg_size > 0)
    {
        snd_msg= new unsigned char[snd_msg_size];
        unsigned char *snd_msg_ptr = snd_msg;

        // pack zone infos
        for(i=0; i < n_snd_zones; i++)
        {
            zones[i].Pack(snd_msg_ptr);
            snd_msg_ptr+= zinfo_size;
        }
    }

    if(procid == 0 && rcv_msg_size > 0)
    {
        // create the rcv buffer for the root proc
        rcv_msg = new unsigned char[rcv_msg_size];
    }

    // gather all zone infos
    MPI_Gatherv(snd_msg, snd_msg_size, MPI_UNSIGNED_CHAR,
                rcv_msg, rcv_count, rcv_disp, MPI_UNSIGNED_CHAR,
                0,VISIT_MPI_COMM);

    if(procid == 0 )
    {
        // unpack all rcvd zones
        std::vector<ZoneInfo> rcv_zones(nrcv_zones);

        unsigned char *rcv_msg_ptr = rcv_msg;

        for( i = 0; i < nrcv_zones; i++)
        {
            rcv_zones[i].Unpack(rcv_msg_ptr);
            rcv_msg_ptr += zinfo_size;
        }

        // save all zones
        SaveOutput(atts.GetOutputFile(),rcv_zones);
    }

    // cleanup

    if(snd_msg)
        delete[] snd_msg;

    if(rcv_msg)
        delete[] rcv_msg;

    if(rcv_count)
        delete[] rcv_count;

    if(rcv_disp)
        delete[] rcv_disp;
#else

    // for serial case, simply dump out zones found during the exe pass.
    SaveOutput(atts.GetOutputFile(),zones);

#endif
}
void mexFunction( int nlhs, mxArray *plhs[], 
				 int nrhs, const mxArray *prhs[] ) 
{
	float Score;
	float BestScore = HugeScore;
	int p, i;
	SetupParams(nrhs,prhs);

	clock_t Clock0;
	KK K1; // main KK class, for all data
	K1.penaltyMix = PenaltyMix;

	Clock0 = clock(); // start timer

	K1.LoadData(prhs[0]); // load .fet file

	mwSize     dim1[2] = {1,K1.nPoints};
	plhs[0] = mxCreateNumericArray(2, dim1, mxDOUBLE_CLASS, mxREAL);
	double *OutputArray = mxGetPr(plhs[0]);

	// Seed random number generator
	srand(RandomSeed);

	// open distance dump file if required
	//if (DistDump) Distfp = fopen("DISTDUMP", "w");

    // start with provided file, if required

	if (!mxIsEmpty(prhs[1])) {
        Output("Starting from existing clusters \n");
        BestScore = K1.CEM(prhs[1], 1, 1);
		Output("%d->%d Clusters: Score %f\n\n", K1.nStartingClusters, K1.nClustersAlive, BestScore);
		for(p=0; p<K1.nPoints; p++) K1.BestClass[p] = K1.Class[p];
		SaveOutput(K1.BestClass, OutputArray);
    }


	// loop through numbers of clusters ...
	for(K1.nStartingClusters=MinClusters; K1.nStartingClusters<=MaxClusters; K1.nStartingClusters++) for(i=0; i<nStarts; i++) {
		// do CEM iteration
        Output("Starting from %d clusters...\n", K1.nStartingClusters);
		Score = K1.Cluster();

		Output("%d->%d Clusters: Score %f, best is %f\n", K1.nStartingClusters, K1.nClustersAlive, Score, BestScore);

		if (Score < BestScore) {
			Output("THE BEST YET!\n");
			// New best classification found
			BestScore = Score;
			for(p=0; p<K1.nPoints; p++) K1.BestClass[p] = K1.Class[p];
			SaveOutput(K1.BestClass, OutputArray);
		}
		Output("\n");
	}

	SaveOutput(K1.BestClass, OutputArray);

	Output("That took %f seconds.\n", (clock()-Clock0)/(float) CLOCKS_PER_SEC);

	//if (DistDump) fclose(Distfp);

}
Beispiel #6
0
void merge(TString outfile, TString firstfile, TString pat=defaultPattern)
{
        TList   decayModes;
	bool    save=false;
        TString dir=".";
	TString first="";
	long    flags=0,id=0,size=0,modtime=0;
	if(firstfile.Contains("~"))
	{
		cout<<"ERROR: input path cannot contain '~' character."<<endl;
		return;
	}
	// Check pattern
	TRegexp pattern(pat,true);
	if(pattern.Status()!=0)
	{
		cout<<"ERROR: Wrong regular expression."<<endl;
		return;
	}
	// Load libraries
        loadLibs();
	gSystem->GetPathInfo(firstfile, &id, &size, &flags, &modtime);
	bool isDirectory = flags&2;
	if(isDirectory)
	{
		dir=firstfile;
		first="";
	}
	else
	{
		//Separate directory from filename
		int separator=firstfile.Last('/');
		if(separator!=-1) dir=firstfile(0,separator+1);
		first=firstfile(separator+1,firstfile.Length());
	}
	cout<<"Output file: "<<outfile<<endl;
	cout<<"Input  dir:  "<<dir<<endl;
	if(!isDirectory) cout<<"First  file: "<<first<<endl;
	cout<<endl;
	// Get file list and add first file if present
        TList *files = getFileList(first,dir,pattern);
	if(!isDirectory)
	{
		TFile *ff = new TFile(firstfile,"READ");
		files->AddBefore(files->First(),ff);
	}
	// Merge files
	TIter next(files);
	TFile *file;
        while(file = (TFile*)next())
        {
		if(!file->IsOpen()) continue;
                ReadFile(file,decayModes);
                cout<<"=============================="<<endl;
                save=true;
        }
	// Save output
        if(save)
	{
		cout<<"Saving..."<<endl;
		SaveOutput(outfile,decayModes);
		cout<<"Output saved to "<<outfile<<endl<<endl;
	}
	else    cout<<"Nothing to save."<<endl<<endl;
	// Closing files
	cout<<"Closing files..."<<endl;
	TIter cl(files);
        while(file = (TFile*)cl()) { file->Close(); delete file; }
	delete files;
	gSystem->Exit(0);
}
Beispiel #7
0
// CEM(StartFile) - Does a whole CEM algorithm from a random start
// optional start file loads this cluster file to start iteration
// if Recurse is 0, it will not try and split.
// if InitRand is 0, use cluster assignments already in structure
float KK::CEM(char *CluFile /*= NULL*/, int Recurse /*=1*/, int InitRand /*=1*/)  {
	int p, c, i;
	int nChanged;
	int Iter;
	Array<int> OldClass(nPoints);
	float Score, OldScore;
	int LastStepFull; // stores whether the last step was a full one
    int DidSplit;

    if (CluFile && *CluFile) LoadClu(CluFile);
	else if (InitRand) {
        // initialize data to random
        if (nStartingClusters>1)
    	    for(p=0; p<nPoints; p++) Class[p] = irand(1, nStartingClusters-1);
        else
            for(p=0; p<nPoints; p++) Class[p] = 0;
			
		for(c=0; c<MaxPossibleClusters; c++) ClassAlive[c] = (c<nStartingClusters);	
    }
	
	// set all clases to alive
    Reindex();

	// main loop
	Iter = 0;
	FullStep = 1;
	do {
		// Store old classifications
		for(p=0; p<nPoints; p++) OldClass[p] = Class[p];
		
		// M-step - calculate class weights, means, and covariance matrices for each class
		MStep();
		
		// E-step - calculate scores for each point to belong to each class
		EStep();

		// dump distances if required
		
		if (DistDump) MatPrint(Distfp, LogP.m_Data, DistDump, MaxPossibleClusters);
		
		// C-step - choose best class for each 
		CStep(); 
		
		// Would deleting any classes improve things?
		if(Recurse) ConsiderDeletion();
		
		// Calculate number changed
		nChanged = 0;
		for(p=0; p<nPoints; p++) nChanged += (OldClass[p] != Class[p]);
		
		// Calculate score
		OldScore = Score;
		Score = ComputeScore();
	
		if(Verbose>=1) {
            if(Recurse==0) Output("\t");
            Output("Iteration %d%c: %d clusters Score %.7g nChanged %d\n",
			    Iter, FullStep ? 'F' : 'Q', nClustersAlive, Score, nChanged);
        }
		
		Iter++;

		if (Debug) {
			for(p=0;p<nPoints;p++) BestClass[p] = Class[p];
			SaveOutput(BestClass);
			Output("Press return");
			getchar();
		}
		
		// Next step a full step?
		LastStepFull = FullStep;
		FullStep = (
						nChanged>ChangedThresh*nPoints 
						|| nChanged == 0 
						|| Iter%FullStepEvery==0 
					//	|| Score > OldScore Doesn't help!  
					//	Score decreases are not because of quick steps!
					) ;
		if (Iter>MaxIter) {
			Output("Maximum iterations exceeded\n");
			break;
		}		

        // try splitting
        if ((Recurse && SplitEvery>0) && (Iter%SplitEvery==SplitEvery-1 || (nChanged==0 && LastStepFull))) {
            DidSplit = TrySplits();
        } else DidSplit = 0;

	} while (nChanged > 0 || !LastStepFull || DidSplit);

	if (DistDump) fprintf(Distfp, "\n");

	return Score;
}