void pingpong(CtrlType *ctrl, GraphType *graph, int nparts, int chain_length, float *tpwgts, float ubfactor, int toplevel)
     // do batch-local search; chain_length is the search length
{

  int nvtxs, nedges, moves, iter;
  idxtype *w;
  //float *m_adjwgt;

  nedges = graph->nedges;
  nvtxs = graph->nvtxs;

  w = idxsmalloc(nvtxs, 0, "pingpong: weight");
  Compute_Weights(ctrl, graph, w);
  //m_adjwgt = fmalloc(nedges, "pingpong: normalized matrix");
  //transform_matrix(ctrl, graph, w, m_adjwgt);

  //printf("Chain length is %d.\n", chain_length);
 
  moves =0;
  iter =0;
  
  //printf("Number of boundary points is %d\n", graph->nbnd);
  do{
    //Weighted_kernel_k_means(ctrl, graph, nparts, w, m_adjwgt, tpwgts, ubfactor);
    Weighted_kernel_k_means(ctrl, graph, nparts, w, tpwgts, ubfactor);
    if (chain_length>0){
      
      //moves = local_search(ctrl, graph, nparts, chain_length, w, m_adjwgt, tpwgts, ubfactor);
      moves = local_search(ctrl, graph, nparts, chain_length, w, tpwgts, ubfactor);
      //printf("Number of local search moves is %d\n", moves);
      //printf("Number of boundary points is %d\n", graph->nbnd);
    }
    iter ++;
    if (iter > MAXITERATIONS)
      break;
  }while(moves >0) ;
  if(memory_saving ==0){
    remove_empty_clusters_l1(ctrl, graph, nparts, w, tpwgts, ubfactor);
    if(toplevel>0)
      remove_empty_clusters_l2(ctrl, graph, nparts, w, tpwgts, ubfactor);
  }
  free(w); 
  //free(m_adjwgt); 
}
/*
 *  Do EM repeatedly to fit normalization functions for each genotype
 *
 * @param Contrast - contrast values for each snp
 * @param Strength - strength values for each snp
 * @param max_iterations - don't go to infinity
 * @param log_lik_convergence - stopped making progress
 * @param NP - output prediction functions for each genotype
 */
void EMContrast(const std::vector<double> &Contrast,
                const std::vector<double> &Strength,
                const int max_iterations,
                const double log_lik_convergence,
                NormalizationPredictor &NP)
{
	// this is the only routine that needs newmat
	// so I can isolate it!
	vector<double> mu;
	vector<double> sigma;
	vector<double> probs;
	vector<double> wAA,wAB,wBB;
	vector<double> mAA,mAB,mBB;
	vector<double> zAA,zAB,zBB;
	vector<double> lik_per_snp;

	double last_log_lik,log_lik_diff,curr_log_lik;
	unsigned int n_iterations,nSNP;

	InitializeEMVars(mu,sigma,probs,Contrast);
	NP.TargetCenter.resize(3);
	NP.TargetCenter[0]=-.66;
	NP.TargetCenter[1]=0;
	NP.TargetCenter[2]= .66;
	NP.CenterCovariates.resize(3);
	NP.CenterCovariates[0] = 0;
	NP.CenterCovariates[1] = 0;
	NP.CenterCovariates[2] = 0;

	nSNP = Contrast.size();
	mAA.resize(nSNP);
	mAB.resize(nSNP);
	mBB.resize(nSNP);
	wAA.resize(nSNP);
	wAB.resize(nSNP);
	wBB.resize(nSNP);
	zAA.resize(nSNP);
	zAB.resize(nSNP);
	zBB.resize(nSNP);
	lik_per_snp.resize(nSNP);

	FillVector(mBB,mu[0]);
	FillVector(mAB,mu[1]);
	FillVector(mAA,mu[2]);
	Compute_Weights(wAA,mAA,sigma[2],Contrast);
	Compute_Weights(wAB,mAB,sigma[1],Contrast);
	Compute_Weights(wBB,mBB,sigma[0],Contrast);

	last_log_lik = -1000000;
	log_lik_diff = log_lik_convergence+1;
	n_iterations = 0;

	while (log_lik_diff > log_lik_convergence && n_iterations < max_iterations){
		n_iterations += 1;
		// E step
		// update probs for each group
		// relative genotype probability per SNP
		// relative likelihood steps
		LikelihoodPerSNP(lik_per_snp,wAA,wAB,wBB,probs);
		//cout<< "likpersnp\t";
		//td(lik_per_snp);
		GenotypePerSNP(zAA,wAA,lik_per_snp,probs[2]);
		GenotypePerSNP(zAB,wAB,lik_per_snp,probs[1]);
		GenotypePerSNP(zBB,wBB,lik_per_snp,probs[0]);
		/*td(zAA);
		td(zAB);
		td(zBB);*/
		probs[0] = compute_mean(zBB);
		probs[1] = compute_mean(zAB);
		probs[2] = compute_mean(zAA);
		//cout << "probs:\t";
		//td(probs);
		curr_log_lik = ComputeLL(lik_per_snp);
		//cout << "curr_lik:\t" << curr_log_lik << endl;
		log_lik_diff = curr_log_lik-last_log_lik;
		last_log_lik = curr_log_lik;
		// done with E step

		// now do the big M step
		// do magic: generate predictors for each group
		// how to do magic:  SVD of of design matrix outside of loop
		// do magic within loop
		// fitAA = predictor weighted by zAA
		// mAA = current predictions for this
		// fitAB = predictor weighted by zAB
		// mAB = current predictions for this
		// fitBB = predictor weighted by zBB
		// mBB = current predictions for this genotype by snp
		//Dummy_Fit(Contrast,mAA,zAA);
		Dummy_Fit(Contrast,Strength,zAB,NP.fitAB,mAB);
		//Dummy_Fit(Contrast,mBB,zBB);
		// try the real one
		FitWeightedCubic(Contrast,Strength,zAA,NP.fitAA,mAA);
		//FitWeightedCubic(Contrast,Strength,zAB,NP.fitAB,mAB);
		FitWeightedCubic(Contrast,Strength,zBB,NP.fitBB,mBB);

		/*td(zAA);
		td(mAA);
		td(zAB);
		td(mAB);
		td(zBB);
		td(mBB);*/

		sigma[0] = WeightedSigma(Contrast,mBB,zBB);
		sigma[1] = WeightedSigma(Contrast,mAB,zAB);
		sigma[2] = WeightedSigma(Contrast,mAA,zAA);
		MinSigma(sigma, .001);
		Compute_Weights(wAA,mAA,sigma[2],Contrast);
		Compute_Weights(wAB,mAB,sigma[1],Contrast);
		Compute_Weights(wBB,mBB,sigma[0],Contrast);
		HardShell(Contrast,wAA,wBB);
		/*td(wAA);
		td(wAB);
		td(wBB);
		cout << "sigma\t";
		td(sigma);*/

	}
	/*cout << "Fitted values" << endl;
	unsigned int dummy;
	for (dummy=0; dummy<Contrast.size(); dummy++)
	{
		cout << dummy << "\t";
		cout << Contrast[dummy] << "\t";
		cout << Strength[dummy] << "\t";
		cout << mAA[dummy] << "\t";
		cout << mAB[dummy] << "\t";
		cout << mBB[dummy] << "\t";
		cout << zAA[dummy] << "\t";
		cout << zAB[dummy] << "\t";
		cout << zBB[dummy] << "\t";
		cout << endl;
	}*/
	//td(Contrast);
	//td(mAA);
	//td(mAB);
	//td(mBB);
	// transfer useful data out of program
	// need: predictor vectors fAA, fAB, fBB
	// need: sigma
	NP.sigma.resize(3);
	NP.sigma[0]=sigma[0];
	NP.sigma[1]=sigma[1];
	NP.sigma[2]=sigma[2];
}