Exemple #1
0
	void update_alpha_status(int i)
	{
		if(alpha[i] >= get_C(i))
			alpha_status[i] = UPPER_BOUND;
		else if(alpha[i] <= 0)
			alpha_status[i] = LOWER_BOUND;
		else alpha_status[i] = FREE;
	}
Exemple #2
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;
}
Exemple #3
0
/* dD_nac = a * D_nac * (A'/A + B'/B - C'/C) */
static void get_derivative_nac(double *ddnac,
                               double *dnac,
                               const int num_patom,
                               const double *lattice,
                               const double *mass,
                               const double *q,
                               const double *born,
                               const double *dielectric,
                               const double *q_direction,
                               const double factor)
{
  int i, j, k, l, m;
  double a, b, c, da, db, dc, volume, mass_sqrt;
  double q_cart[3], rec_lat[9];

  volume =
    lattice[0] * (lattice[4] * lattice[8] - lattice[5] * lattice[7]) +
    lattice[1] * (lattice[5] * lattice[6] - lattice[3] * lattice[8]) +
    lattice[2] * (lattice[3] * lattice[7] - lattice[4] * lattice[6]);

  rec_lat[0] = (lattice[4] * lattice[8] - lattice[5] * lattice[7]) / volume;
  rec_lat[1] = (lattice[5] * lattice[6] - lattice[3] * lattice[8]) / volume;
  rec_lat[2] = (lattice[3] * lattice[7] - lattice[4] * lattice[6]) / volume;
  rec_lat[3] = (lattice[7] * lattice[2] - lattice[8] * lattice[1]) / volume;
  rec_lat[4] = (lattice[8] * lattice[0] - lattice[6] * lattice[2]) / volume;
  rec_lat[5] = (lattice[6] * lattice[1] - lattice[7] * lattice[0]) / volume;
  rec_lat[6] = (lattice[1] * lattice[5] - lattice[2] * lattice[4]) / volume;
  rec_lat[7] = (lattice[2] * lattice[3] - lattice[0] * lattice[5]) / volume;
  rec_lat[8] = (lattice[0] * lattice[4] - lattice[1] * lattice[3]) / volume;

  for (i = 0; i < 3; i++) {
    q_cart[i] = 0;
    for (j = 0; j < 3; j++) {
      if (q_direction) {
        q_cart[i] += rec_lat[i * 3 + j] * q_direction[j];
      } else {
        q_cart[i] += rec_lat[i * 3 + j] * q[j];
      }
    }
  }

  c = get_C(q_cart, dielectric);

  for (i = 0; i < num_patom; i++) { /* atom_i */
    for (j = 0; j < num_patom; j++) { /* atom_j */
      mass_sqrt = sqrt(mass[i] * mass[j]);
      for (k = 0; k < 3; k++) { /* derivative direction */
        for (l = 0; l < 3; l++) { /* alpha */
          a = get_A(i, l, q_cart, born);
          da = get_dA(i, l, k, born);
          for (m = 0; m < 3; m++) { /* beta */
            b = get_A(j, m, q_cart, born);
            db = get_dA(j, m, k, born);
            dc = get_dC(l, m, k, q_cart, dielectric);
            ddnac[k * num_patom * num_patom * 9 +
                  i * 9 * num_patom + j * 9 + l * 3 + m] =
              (da * b + db * a - a * b * dc / c) / (c * mass_sqrt) * factor;
            if (k == 0) {
              dnac[i * 9 * num_patom + j * 9 + l * 3 + m] =
                a * b / (c * mass_sqrt) * factor;
            }
          }
        }
      }
    }
  }
}
Exemple #4
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;
}