Vector UnconstrainedLocalSearch::find_gcp(const Vector& gk, const Matrix& Bk, const Vector& zk,  const IntervalVector& region) {

	// ====================== STEP 2.0 : initialization ======================

	////  cout << " [find_gcp] initial region=" << region << endl;
	// The Cauchy point
	Vector z_gcp = zk;
	//  cout << " [find_gcp] initial zk=" << zk << endl;

	// The opposite of the gradient of z->z^T*Bk*z - gk^T z
	Vector g = gk - Bk*zk;

	// Compute a descent direction d
	// that must "point" inside the box
	Vector d(n);

	// If the function decreases wrt the ith dimension
	// and the point zk is very close (less than sigma) to the
	// ith "upper face" of the bounding box then we project
	// the gradient on this face (we nullify the ith component).
	// We apply the symmetric case with the "lower face".
	// The constraint x=ui or x=li is activated.
	for (int i = 0 ; i < n ; i++) {
		if(  fabs(gk[i]) > sigma &&
				((gk[i] < 0 && zk[i] < box[i].ub() - sigma) ||
				 (gk[i] > 0 && zk[i] > box[i].lb() + sigma)) )
			d[i] = -gk[i];
		// else d[i] remains equal to 0.
	}
	//  cout << " [find_gcp] initial d=" << d << endl;
	// compute f'
	double fp = gk*d;
	//  cout << " [find_gcp] initial fp=" << fp << endl;

	// compute f''
	double fs = d*(Bk*d);
	//  cout << " [find_gcp] initial fs=" << fs << endl;


	bool gcp_found = (fp >= -eps);

	try {

		while (!gcp_found) {
			// ====================== STEP 2.1 : Find the next breakpoint ======================

			LineSearch ls(region,z_gcp,d,data,sigma); // if d~0, an exception is raised

			double deltat = ls.alpha_max();
			//  cout << " [find_gcp] deltat=" << deltat << endl;

			// check if we are in a corner
			// deltat can be very large even if the norm of the gradient is > eps
			// because once the "large" dimensions are treated, it may only
			// remains directions with d[i] very small (but not less than sigma).
			// In any case, we have deltat <= 1/sigma*diam(region) <= 2*Delta/sigma.

			//		assert(deltat<10*(2*Delta/sigma));

			// ====================== STEP 2.2 : Test whether the GCP has been found ======================

			// The minimum is in the segment [0,deltat]
			if ((fs > 0.0) && (0<-(fp/fs)) && (-(fp/fs)<deltat)) {
				z_gcp -= (fp/fs)*d;

				// Security check: z_gcp may be outside the region because of rounding
				ls.proj(z_gcp);

				gcp_found = true;
			}
			else {

				// ====================== STEP 2.3 : Update line derivatives ======================

				// b = Bk*(\sum_{I[i]==2} di*ei)
				Vector b(n);
				for (int i=0; i<n; i++) {
					if (ls.next_activated(i)) {
						for (int j=0; j<n; j++) b[j]+=d[i]*Bk[j][i];
					}
				}

				// set gcp to the the point on the face
				z_gcp = ls.endpoint();

				// update f'
				fp += deltat*fs - b*z_gcp;

				for (int i=0; i<n; i++) {
					if (ls.next_activated(i)) fp -= d[i]*g[i];
				}

				// update f''
				for (int i=0; i<n; i++) {
					fs -= (ls.next_activated(i) ? b[i]*d[i] : 2.0*b[i]*d[i]);
				}

				// update d and I
				for (int i=0; i<n; i++) {
					if (ls.next_activated(i)) {
						//  cout << " [find_gcp] activate ctr n°" << i << endl;
						d[i] = 0.0;
					}
				}

				//  cout << " [find_gcp] current d=" << d << endl;
				//  cout << " [find_gcp] current z_gcp=" << z_gcp << endl;
				//  cout << " [find_gcp] current fp=" << fp << endl;
				//  cout << " [find_gcp] current fs=" << fs << endl;
				// update the termination condition
				gcp_found = (fp >= -eps); // the minimum is at a breakpoint
			}
		}
	}
	catch(LineSearch::NullDirectionException&) {
		// we are in a corner of the region: we stop with current z_gcp
	}

	// ====================== STEP 2.4 : termination with GCP ======================
	//  cout << " [find_gcp] z_gcp =" << z_gcp << endl;
	assert(region.contains(z_gcp));

	return z_gcp;
}