double Parameters::calculate_fy(int area_number, double x, double y)
	{
		if(Testing_parameters::test == 1)
			switch(area_number)
			{
				case 0: return 1.0 / calculate_rho(area_number) * 0;
				case 1:	return 1.0 / calculate_rho(area_number) * 0;
				default: return 1.0;
			}
		if (Testing_parameters::test == 2)
			switch (area_number)
			{
			case 0: return 0.0;
			case 1:	return 0.0;
			default: return 0.0;
			}
		if(Testing_parameters::test == 3)
			switch(area_number)
			{
			case 0: return -calculate_lambda(area_number) * (60 * x * x - 60 * y * y) + 
							1.0 / calculate_rho(area_number) * (60 * x * x - 60 * y * y) + 
							400 * pow_i(4, x)  * pow_i(3, y) + 100 * (pow_i(7, y) 
							- pow_i(4, x)  * pow_i(3, y));
			case 1:	return -calculate_lambda(area_number) * (60 * x * x - 60 * y * y) + 
							1.0 / calculate_rho(area_number) * (60 * x * x - 60 * y * y) + 
							400 * pow_i(4, x)  * pow_i(3, y) + 100 * (pow_i(7, y)
							- pow_i(4, x)  * pow_i(3, y));
			default: return 1.0;
			}

		return 1.0;
	}
	double Parameters::calculate_fx(int area_number, double x, double y)
	{
		if(Testing_parameters::test == 1)
			switch(area_number)
			{
				case 0: return 1.0 / calculate_rho(area_number) * 0;
				case 1:	return 1.0 / calculate_rho(area_number) * 0;
				default: return 1.0;
			}
		if (Testing_parameters::test == 2)
			switch (area_number)
			{
			case 0: return 0.0;
			case 1:	return 0.0;
			default: return 0.0;
			}

		if(Testing_parameters::test == 3)
			switch(area_number)
			{
			case 0: return -calculate_lambda(area_number) * 120 * x * y + 
							1.0 / calculate_rho(area_number) * 120 * x * y + 
							400 * x * pow_i(6, y) + 300 * (pow_i(5, x) * y * y
							- x * pow_i(6, y));
			case 1:	return -calculate_lambda(area_number) * 120 * x * y + 
							1.0 / calculate_rho(area_number) * 120 * x * y + 
							400 * x * pow_i(6, y) + 300 * (pow_i(5, x) * y * y
							- x * pow_i(6, y));
			default: return 1.0;
			}

		return 1.0;
	}
void ToolsRhoEstimator::on_valueChanged(double newval) {
  newval++;  // hack to avoid the "unused parameter" g++ warning.

  // scrape the field values, convert to metric if needed.
  double temp = tempSpinBox->value();
  double press = pressSpinBox->value();
  double dewp = dewpSpinBox->value();
  if (impBut->isChecked()) {
    // yup, convert to metric.
    temp = fahrenheit_to_celsius(temp);
    press = inchesmercury_to_hectopascals(press);
    dewp = fahrenheit_to_celsius(dewp);
  }

  // calculate rho, in (kg/m^3)
  double rho_met = calculate_rho(temp, press, dewp);
  // calculate rho in imperial units.
  double rho_imp = rho_met_to_imp(rho_met);

  // display the calculated Rho's.
  std::stringstream ss_met, ss_imp;
  ss_met.precision(6);
  ss_met << rho_met;
  txtRhoMet->setText(tr(ss_met.str().c_str()));
  ss_imp.precision(6);
  ss_imp << rho_imp;
  txtRhoImp->setText(tr(ss_imp.str().c_str()));
}
Beispiel #4
0
void Solver::Solve(int l, const Kernel& Q, const double *b_, const schar *y_,
		   double *alpha_, double Cp, double Cn, double eps,
		   SolutionInfo* si, int shrinking)
{
	this->l = l;
	this->Q = &Q;
	clone(b, b_,l);
	clone(y, y_,l);
	clone(alpha,alpha_,l);
	this->Cp = Cp;
	this->Cn = Cn;
	this->eps = eps;
	unshrinked = false;

	// initialize alpha_status
	{
		alpha_status = new char[l];
		for(int i=0;i<l;i++)
			update_alpha_status(i);
	}

	// initialize active set (for shrinking)
	{
		active_set = new int[l];
		for(int i=0;i<l;i++)
			active_set[i] = i;
		active_size = l;
	}

	// initialize gradient
	{
		G = new double[l];
		G_bar = new double[l];
		int i;
		for(i=0;i<l;i++)
		{
			G[i] = b[i];
			G_bar[i] = 0;
		}
		for(i=0;i<l;i++)
			if(!is_lower_bound(i))
			{
				Qfloat *Q_i = Q.get_Q(i,l);
				double alpha_i = alpha[i];
				int j;
				for(j=0;j<l;j++)
					G[j] += alpha_i*Q_i[j];
				if(is_upper_bound(i))
					for(j=0;j<l;j++)
						G_bar[j] += get_C(i) * Q_i[j];
			}
	}

	// optimization step

	int iter = 0;
	int counter = min(l,1000)+1;

	while(1)
	{
		// show progress and do shrinking

		if(--counter == 0)
		{
			counter = min(l,1000);
			if(shrinking) do_shrinking();
			info("."); info_flush();
		}

		int i,j;
		if(select_working_set(i,j)!=0)
		{
			// reconstruct the whole gradient
			reconstruct_gradient();
			// reset active set size and check
			active_size = l;
			info("*"); info_flush();
			if(select_working_set(i,j)!=0)
				break;
			else
				counter = 1;	// do shrinking next iteration
		}
		
		++iter;

		// update alpha[i] and alpha[j], handle bounds carefully
		
		const Qfloat *Q_i = Q.get_Q(i,active_size);
		const Qfloat *Q_j = Q.get_Q(j,active_size);

		double C_i = get_C(i);
		double C_j = get_C(j);

		double old_alpha_i = alpha[i];
		double old_alpha_j = alpha[j];

		if(y[i]!=y[j])
		{
			double delta = (-G[i]-G[j])/(Q_i[i]+Q_j[j]+2*Q_i[j]);
			double diff = alpha[i] - alpha[j];
			alpha[i] += delta;
			alpha[j] += delta;
			
			if(diff > 0)
			{
				if(alpha[j] < 0)
				{
					alpha[j] = 0;
					alpha[i] = diff;
				}
			}
			else
			{
				if(alpha[i] < 0)
				{
					alpha[i] = 0;
					alpha[j] = -diff;
				}
			}
			if(diff > C_i - C_j)
			{
				if(alpha[i] > C_i)
				{
					alpha[i] = C_i;
					alpha[j] = C_i - diff;
				}
			}
			else
			{
				if(alpha[j] > C_j)
				{
					alpha[j] = C_j;
					alpha[i] = C_j + diff;
				}
			}
		}
		else
		{
			double delta = (G[i]-G[j])/(Q_i[i]+Q_j[j]-2*Q_i[j]);
			double sum = alpha[i] + alpha[j];
			alpha[i] -= delta;
			alpha[j] += delta;
			if(sum > C_i)
			{
				if(alpha[i] > C_i)
				{
					alpha[i] = C_i;
					alpha[j] = sum - C_i;
				}
			}
			else
			{
				if(alpha[j] < 0)
				{
					alpha[j] = 0;
					alpha[i] = sum;
				}
			}
			if(sum > C_j)
			{
				if(alpha[j] > C_j)
				{
					alpha[j] = C_j;
					alpha[i] = sum - C_j;
				}
			}
			else
			{
				if(alpha[i] < 0)
				{
					alpha[i] = 0;
					alpha[j] = sum;
				}
			}
		}

		// update G

		double delta_alpha_i = alpha[i] - old_alpha_i;
		double delta_alpha_j = alpha[j] - old_alpha_j;
		
		for(int k=0;k<active_size;k++)
		{
			G[k] += Q_i[k]*delta_alpha_i + Q_j[k]*delta_alpha_j;
		}

		// update alpha_status and G_bar

		{
			bool ui = is_upper_bound(i);
			bool uj = is_upper_bound(j);
			update_alpha_status(i);
			update_alpha_status(j);
			int k;
			if(ui != is_upper_bound(i))
			{
				Q_i = Q.get_Q(i,l);
				if(ui)
					for(k=0;k<l;k++)
						G_bar[k] -= C_i * Q_i[k];
				else
					for(k=0;k<l;k++)
						G_bar[k] += C_i * Q_i[k];
			}

			if(uj != is_upper_bound(j))
			{
				Q_j = Q.get_Q(j,l);
				if(uj)
					for(k=0;k<l;k++)
						G_bar[k] -= C_j * Q_j[k];
				else
					for(k=0;k<l;k++)
						G_bar[k] += C_j * Q_j[k];
			}
		}
	}

	// calculate rho

	si->rho = calculate_rho();

	// calculate objective value
	{
		double v = 0;
		int i;
		for(i=0;i<l;i++)
			v += alpha[i] * (G[i] + b[i]);

		si->obj = v/2;
	}

	// put back the solution
	{
		for(int i=0;i<l;i++)
			alpha_[active_set[i]] = alpha[i];
	}

	// juggle everything back
	/*{
		for(int i=0;i<l;i++)
			while(active_set[i] != i)
				swap_index(i,active_set[i]);
				// or Q.swap_index(i,active_set[i]);
	}*/

	si->upper_bound_p = Cp;
	si->upper_bound_n = Cn;

	info("\noptimization finished, #iter = %d\n",iter);

	delete[] b;
	delete[] y;
	delete[] alpha;
	delete[] alpha_status;
	delete[] active_set;
	delete[] G;
	delete[] G_bar;
}
int main(int np, char** p)
{
  double * current, *error;
  double * current_pre, *error_pre;//preliminary input
  int i,j,k,t;
  FILE* file_in_current;
  FILE* file_in_matrix;
  FILE* file_out;
  FILE* file_out_excl;
  FILE* file_const;
  int par_int;
  double par_double;
  double int_result, int_error;
  double center;
  double omega;
  
  
  gsl_vector * R;
  gsl_vector * omega_R; //for real center definition

  gsl_vector * Q;

  gsl_vector * Q_initial;

  gsl_matrix * S;//covariance matrix
  gsl_matrix * S_pre;//covariance matrix (preliminary input)

  file_in_current=fopen(p[2],"r");
  file_in_matrix=fopen(p[3],"r");
  sprintf(directory,"%s", p[4]);
  Nt_2=atoi(p[1]);
  dNt_2=(double) Nt_2;
//reading parameters file
  file_const=fopen(p[5],"r");
  
//double accuracy=1e-8;
parse_option(file_const,"%le",&accuracy);
//long int N_int_steps=1000000;
parse_option(file_const,"%ld",&N_int_steps);
//double omega_plot_delta=0.01;
parse_option(file_const,"%le",&omega_plot_delta);
//double omega_plot_limit=30.0;
parse_option(file_const,"%le",&omega_plot_limit);
//double lambda=1.0;
parse_option(file_const,"%le",&lambda);
//double center_start=3.0;
parse_option(file_const,"%le",&center_start);
//double center_stop=18.01;
parse_option(file_const,"%le",&center_stop);
//double center_delta=3.0;
parse_option(file_const,"%le",&center_delta);
//int flag_exclude
parse_option(file_const,"%d",&flag_exclude_delta);
//int count_start
parse_option(file_const,"%d",&count_start_exclude);
//int flag_model
parse_option(file_const,"%d",&flag_model);
if(flag_model==1)
{
  fscanf(file_const, "%d", &N_valid_points);
  points_numbers=(int*) calloc(N_valid_points, sizeof(int));
  for(i=0;i<N_valid_points; i++)
    fscanf(file_const, "%d", &(points_numbers[i]));
}
else
{
  N_valid_points=Nt_2;
  points_numbers=(int*) calloc(N_valid_points, sizeof(int));
  for(i=0;i<N_valid_points; i++)
    points_numbers[i]=i+1;
}


  fclose(file_const);

file_out=fopen_control("parameters.txt","w");
fprintf(file_out,"number of points (=half of physical number of timeslices)=%d\n", Nt_2);

fprintf(file_out,"file with current correlator:\n %s\n", p[2]);
fprintf(file_out,"file with covariance matrix:\n %s\n", p[3]);
fprintf(file_out,"path for output:\n %s\n", p[4]);
fprintf(file_out,"file with parameters:\n %s\n", p[5]);




//double accuracy=1e-8;
fprintf(file_out,"accuracy=%.15le\n",accuracy);
//long int N_int_steps=1000000;
fprintf(file_out,"Number os steps in numerical interation=%ld\n",N_int_steps);
//double omega_plot_delta=0.01;
fprintf(file_out,"Step in plots of resolution function(omega)=%.15le\n",omega_plot_delta);
//double omega_plot_limit=30.0;
fprintf(file_out,"Limit in plots of resolution function(omega)=%.15le\n",omega_plot_limit);
//double lambda=1.0;
fprintf(file_out,"Lambda(regularization)=%.15le\n(=1 - without regularization)\n",lambda);
//double center_start=3.0;
fprintf(file_out,"Center of resolution function starts from = %.15le\n",center_start);
//double center_stop=18.01;
fprintf(file_out,"Center of resolution function stops at %.15le\n",center_stop);
//double center_delta=3.0;
fprintf(file_out,"Step in center of resolution function = %.15le\n",center_delta);
//flag_exclude_delta;
fprintf(file_out,"TExclude or not (1 or 0) initial delta finction %d\n",flag_exclude_delta);
//count_start_exclude
fprintf(file_out,"Number of iteration for center to start exclusion of initial delta-function = %d\n",count_start_exclude);
//model_flag;
fprintf(file_out,"Take into account all (0)  or not all (1) timeslices = %d\n",flag_model);
if(flag_model==1)
{
  fprintf(file_out,"Number of timeslices taken into account = %d\n",N_valid_points);
  for(i=0;i<N_valid_points;i++)
  {
    fprintf(file_out,"%d\n",points_numbers[i]);
  }
}
fclose(file_out);


  current_pre=(double*) calloc(Nt_2, sizeof(double));
  error_pre=(double*) calloc(Nt_2, sizeof(double));

  S_pre=gsl_matrix_calloc(Nt_2, Nt_2);

  for(t=1;t<=Nt_2;t++)
  {
    fscanf(file_in_current, "%d", &par_int);
    fscanf(file_in_current, "%le", &par_double);
    current_pre[t-1]=par_double;
    
    fscanf(file_in_current, "%le", &par_double);
    error_pre[t-1]=par_double;
  }
  fclose(file_in_current);

  file_out=fopen_control("current_control_pre.txt","w");
  for(t=0;t<Nt_2;t++)
  {
    fprintf(file_out,"%d\t%.15le\t%.15le\n", t, current_pre[t], error_pre[t]);
  }
  fclose(file_out);

  for(i=1;i<=Nt_2;i++)
  for(t=1;t<=Nt_2;t++)
  {
    fscanf(file_in_matrix, "%le", &par_double);
    gsl_matrix_set(S_pre, i-1, t-1, par_double);

  }
  fclose(file_in_matrix);

  file_out=fopen_control("cov_matrix_control_pre.txt","w");
  for(i=0;i<Nt_2;i++){
  for(t=0;t<Nt_2;t++)
  {
    fprintf(file_out,"%.15le\t", gsl_matrix_get(S_pre, i,t));
  }
  fprintf(file_out,"\n");
  }
  fclose(file_out);
//conversion to real arrays taken into account only certain timeslices
///////////////////////////////////////////
///////////////////////////////////////////
///////////////////////////////////////////
{ 
  int count1, count2;
  Nt_2_pre=Nt_2;
  dNt_2_pre=(double) Nt_2_pre;
  if(flag_model==1)
  {
    Nt_2=N_valid_points;
    dNt_2=(double)Nt_2;
  } 
  current=(double*) calloc(Nt_2, sizeof(double));
  error=(double*) calloc(Nt_2, sizeof(double));

  S=gsl_matrix_calloc(Nt_2, Nt_2);

  for(count1=0;count1<Nt_2;count1++)
  {
    current[count1]=current_pre[points_numbers[count1]-1];
    error[count1]=error_pre[points_numbers[count1]-1];
  }
  fclose(file_in_current);

  file_out=fopen_control("current_control_fin.txt","w");
  for(t=0;t<Nt_2;t++)
  {
    fprintf(file_out,"%d\t%.15le\t%.15le\n", points_numbers[t], current[t], error[t]);
  }
  fclose(file_out);

  for(count1=0;count1<Nt_2;count1++)
  for(count2=0;count2<Nt_2;count2++)
  {
    par_double=gsl_matrix_get(S_pre,points_numbers[count1]-1, points_numbers[count2]-1);
    gsl_matrix_set(S, count1, count2, par_double);
  }
  fclose(file_in_matrix);

  file_out=fopen_control("cov_matrix_control.txt","w");
  for(i=0;i<Nt_2;i++){
  for(t=0;t<Nt_2;t++)
  {
    fprintf(file_out,"%.15le\t", gsl_matrix_get(S, i,t));
  }
  fprintf(file_out,"\n");
  }
  fclose(file_out);
}
//end of conversion
///////////////////////////////////////////
///////////////////////////////////////////
///////////////////////////////////////////



//integration to obtain R vector
  file_out=fopen_control("R_control.txt","w");
  
  R=gsl_vector_alloc(Nt_2);
{
  gsl_integration_workspace * w  = gsl_integration_workspace_alloc (N_int_steps);
  gsl_function F;
  F.function = &kernel_int;
  for(t=1;t<=Nt_2;t++)
  {
    F.params = &t;
    gsl_integration_qagiu (&F, 0.0, accuracy, accuracy, N_int_steps, w, &int_result, &int_error); 
    gsl_vector_set(R,t-1,int_result);
    fprintf(file_out,"%d\t%.15le\t%.15le\n", t, int_result, int_error); fflush(file_out);
  }
  gsl_integration_workspace_free (w);

}
  fclose(file_out);
///////
//integration to obtain omega_R vector
  file_out=fopen_control("omega_R_control.txt","w");
  
  omega_R=gsl_vector_alloc(Nt_2);
{
  gsl_integration_workspace * w  = gsl_integration_workspace_alloc (N_int_steps);
  gsl_function F;
  F.function = &omega_kernel_int;
  for(t=1;t<=Nt_2;t++)
  {
    F.params = &t;
    gsl_integration_qagiu (&F, 0.0, accuracy, accuracy, N_int_steps, w, &int_result, &int_error); 
    gsl_vector_set(omega_R,t-1,int_result);
    fprintf(file_out,"%d\t%.15le\t%.15le\n", t, int_result, int_error); fflush(file_out);
  }
  gsl_integration_workspace_free (w);

}
  fclose(file_out);
///////


  {
  int count_center=0;
  double C, C0;
  gsl_vector* Q_real;
  Q_initial=gsl_vector_calloc(Nt_2);
  for(center=center_start; center<=center_stop; center+=center_delta)
  {
    double center_real=center/(2.0*dNt_2_pre);
    double center_calculated=0.0;
    double center_calculated_real=0.0;
    char file_name[1000];
    sprintf(file_name,"delta_function_c=%3.3leT.txt", center);
    Q=gsl_vector_calloc(Nt_2);
    Q_real=gsl_vector_calloc(Nt_2);
    calculate_Q(Q, R, S, center_real);
    if(count_center==0)
    {
      for(i=0;i<Nt_2;i++)
        gsl_vector_set(Q_initial, i, gsl_vector_get(Q,i));
    }
    if(count_center==0)
    {
      for(i=0;i<Nt_2;i++)
        gsl_vector_set(Q_real, i, gsl_vector_get(Q,i));
    }
    else
    {
      if(flag_exclude_delta==1 && count_center>=count_start_exclude)
      {
        FILE* log_exclusion;
        log_exclusion=fopen_log("log_exclusion.txt","a", center_real);
        C=delta0(Q);
        C0=delta0(Q_initial);
        fprintf(log_exclusion,"C=%.15le\nC0=%.15le\n",C,C0);fflush(log_exclusion);
        
        for(i=0;i<Nt_2;i++)
          gsl_vector_set(Q_real, i, gsl_vector_get(Q,i)-(C/C0)*gsl_vector_get(Q_initial,i));
        
        //normalization
        double new_norma=0.0;
        for(i=0;i<Nt_2;i++)
        {
          new_norma += gsl_vector_get(Q_real, i) * gsl_vector_get(R,i);
        }
        fprintf(log_exclusion, "norma_old=%.15le\n", new_norma);fflush(log_exclusion);
        
        for(i=0;i<Nt_2;i++)
        {
          gsl_vector_set(Q_real,i,gsl_vector_get(Q_real, i)/new_norma );
        }
        new_norma=0.0; 
        for(i=0;i<Nt_2;i++)
        {
          new_norma += gsl_vector_get(Q_real, i) * gsl_vector_get(R,i);
        }
        fprintf(log_exclusion, "norma_new=%.15le\n", new_norma);fflush(log_exclusion);
        
        fclose(log_exclusion);     
      }
      else
      {
        for(i=0;i<Nt_2;i++)
        gsl_vector_set(Q_real, i, gsl_vector_get(Q,i));
      }
    }
    //delta function output
    file_out=fopen_control(file_name,"w");
    for(omega=0;omega<omega_plot_limit/(2.0*dNt_2_pre);omega+=omega_plot_delta/(2.0*dNt_2_pre))
    {
      fprintf(file_out,"%.15le\t%.15le\t%.15le\n", omega*2.0*dNt_2_pre, delta(omega,Q), delta(omega, Q_real));
      fflush(file_out);
    }
    fclose(file_out);
    
    //output of dimensionless spectral function
    double rho, rho_stat_err, width;
    double rho_real, rho_stat_err_real, width_real;
//values to really characterize delta functions 
double start, stop, center1, width1;
double real_start, real_stop, real_center1, real_width1;


    file_out=fopen_control("rho.txt", "a");
    file_out_excl=fopen_control("rho_excl.txt", "a");
    calculate_rho(Q, current, error, &rho, &rho_stat_err);
    width=delta_width_calculation(Q, center_real);

    delta_characteristics_calculation(&start, &stop, &center1, Q, center_real);
    width1=(stop-start)/2.0;

    calculate_rho(Q_real, current, error, &rho_real, &rho_stat_err_real);
    width_real=delta_width_calculation(Q_real, center_real);

    delta_characteristics_calculation(&real_start, &real_stop, &real_center1, Q_real, center_real);
    real_width1=(real_stop-real_start)/2.0;


    fprintf(file_out,"%.15le\t%.15le\t%.15le\t%.15le\t%.15le\t%.15le\n", center, width*2.0*dNt_2_pre, center1, width1, rho, rho_stat_err);
    fprintf(file_out_excl,"%.15le\t%.15le\t%.15le\t%.15le\t%.15le\t%.15le\n", center, width_real*2.0*dNt_2_pre, real_center1, real_width1,  rho_real, rho_stat_err_real);
    
    fclose(file_out);
    fclose(file_out_excl);
    gsl_vector_free(Q);
    gsl_vector_free(Q_real);
    count_center++;
  }
  gsl_vector_free(Q_initial);
  }
  gsl_vector_free(R);
  gsl_vector_free(omega_R);
  gsl_matrix_free(S);
  gsl_matrix_free(S_pre);
  
  free(current);
  free(error);

  free(current_pre);
  free(error_pre);

  if(flag_model==1)
    free(points_numbers);
  return 0;
}
Beispiel #6
0
float Solver<TQ>::solve(int l, TQ& Q, const signed char *y_,
			float *alpha_, float C, float eps, int shrinking)
{
  this->l = l;
  this->Q = &Q;
  this->QD = Q.get_QD();
  this->C = C;
  this->eps = eps;
  unshrinked = false;
  
  p = new float [l];
  std::fill(p, p + l, float(-1.0));

  y = new signed char [l];
  std::copy(y_, y_ + l, y);

  alpha = new float [l];
  std::copy(alpha_, alpha_ + l, alpha);

  // initialize alpha_status
  {
    alpha_status = new int[l];
    for(int i=0;i<l;i++)
      update_alpha_status(i);
  }

  // initialize active set (for shrinking)
  {
    active_set = new int[l];
    for(int i=0;i<l;i++)
      active_set[i] = i;
    active_size = l;
  }

  // initialize gradient
  {
    G = new float[l];
    G_bar = new float[l];
    for(int i=0;i<l;i++)
      {
	G[i] = p[i];
	G_bar[i] = 0;
      }
    for(int i=0;i<l;i++)
      if(!is_lower_bound(i))
	{
	  const float *Q_i = Q.get_Q(i,l);
	  float alpha_i = alpha[i];
	  for(int j=0;j<l;j++)
	    G[j] += alpha_i*Q_i[j];
	  if(is_upper_bound(i))
	    for(int j=0;j<l;j++)
	      G_bar[j] += get_C(i) * Q_i[j];
	}
  }

  // optimization step

  int iter = 0;
  int counter = std::min(l,1000)+1;

  while (1)
    {
      // show progress and do shrinking

      if(--counter == 0)
	{
	  counter = std::min(l,1000);
	  if(shrinking) 
	    do_shrinking();
	}

      int i,j;
      
      if (select_working_set(i, j) != 0)
	{
	  // reconstruct the whole gradient
	  reconstruct_gradient();
	  // reset active set size and check
	  active_size = l;
	  if (select_working_set(i, j) != 0)
	    break;
	  else
	    counter = 1;	// do shrinking next iteration
	}
		
      ++iter;

      // update alpha[i] and alpha[j], handle bounds carefully
      const float *Q_i = Q.get_Q(i, active_size);
      const float *Q_j = Q.get_Q(j, active_size);

      NTA_ASSERT(Q_i != nullptr);
      NTA_ASSERT(Q_j != nullptr);

      float C_i = get_C(i);
      float C_j = get_C(j);

      float old_alpha_i = alpha[i];
      float old_alpha_j = alpha[j];

      if (y[i]!=y[j])
	{
	  float quad_coef = Q_i[i]+Q_j[j]+2*Q_i[j];
	  if (quad_coef <= 0)
	    quad_coef = TAU;
	  NTA_ASSERT(quad_coef > 0);
	  float delta = (-G[i]-G[j])/quad_coef;
	  float diff = alpha[i] - alpha[j];
	  alpha[i] += delta;
	  alpha[j] += delta;
			
	  if(diff > 0)
	    {
	      if(alpha[j] < 0)
		{
		  alpha[j] = 0;
		  alpha[i] = diff;
		}
	    }
	  else
	    {
	      if(alpha[i] < 0)
		{
		  alpha[i] = 0;
		  alpha[j] = -diff;
		}
	    }
	  if(diff > C_i - C_j)
	    {
	      if(alpha[i] > C_i)
		{
		  alpha[i] = C_i;
		  alpha[j] = C_i - diff;
		}
	    }
	  else
	    {
	      if(alpha[j] > C_j)
		{
		  alpha[j] = C_j;
		  alpha[i] = C_j + diff;
		}
	    }
	}
      else
	{
	  float quad_coef = Q_i[i]+Q_j[j]-2*Q_i[j];
	  if (quad_coef <= 0)
	    quad_coef = TAU;
	  NTA_ASSERT(quad_coef > 0);
	  float delta = (G[i]-G[j])/quad_coef;
	  float sum = alpha[i] + alpha[j];
	  alpha[i] -= delta;
	  alpha[j] += delta;

	  if(sum > C_i)
	    {
	      if(alpha[i] > C_i)
		{
		  alpha[i] = C_i;
		  alpha[j] = sum - C_i;
		}
	    }
	  else
	    {
	      if(alpha[j] < 0)
		{
		  alpha[j] = 0;
		  alpha[i] = sum;
		}
	    }
	  if(sum > C_j)
	    {
	      if(alpha[j] > C_j)
		{
		  alpha[j] = C_j;
		  alpha[i] = sum - C_j;
		}
	    }
	  else
	    {
	      if(alpha[i] < 0)
		{
		  alpha[i] = 0;
		  alpha[j] = sum;
		}
	    }
	}

      // update G
      float delta_alpha_i = alpha[i] - old_alpha_i;
      float delta_alpha_j = alpha[j] - old_alpha_j;
		
      for(int k=0;k<active_size;k++) {
	G[k] += Q_i[k]*delta_alpha_i + Q_j[k]*delta_alpha_j;
	NTA_ASSERT(-HUGE_VAL <= G[k] && G[k] <= HUGE_VAL);
      }

      // update alpha_status and G_bar
      {
	bool ui = is_upper_bound(i);
	bool uj = is_upper_bound(j);
	update_alpha_status(i);
	update_alpha_status(j);

	if(ui != is_upper_bound(i))
	  {
	    Q_i = Q.get_Q(i,l);
	    if(ui)
	      for(int k=0;k<l;k++)
		G_bar[k] -= C_i * Q_i[k];
	    else
	      for(int k=0;k<l;k++)
		G_bar[k] += C_i * Q_i[k];
	  }

	if(uj != is_upper_bound(j))
	  {
	    Q_j = Q.get_Q(j,l);
	    if(uj)
	      for(int k=0;k<l;k++)
		G_bar[k] -= C_j * Q_j[k];
	    else
	      for(int k=0;k<l;k++)
		G_bar[k] += C_j * Q_j[k];
	  }
      }
    }
  
  float rho = calculate_rho();

  // put back the solution
  for(int i=0;i<l;i++)
    alpha_[active_set[i]] = alpha[i];

  delete[] p;
  delete[] y;
  delete[] alpha;
  delete[] alpha_status;
  delete[] active_set;
  delete[] G;
  delete[] G_bar;

  return rho;
}