ECode AbstractSelectableChannel::Register(
    /* [in] */ ISelector* selector,
    /* [in] */ Int32 interestSet,
    /* [in] */ IObject* obj,
    /* [out] */ ISelectionKey** result)
{
    VALIDATE_NOT_NULL(result);
    *result = NULL;
    VALIDATE_NOT_NULL(selector);
    VALIDATE_NOT_NULL(obj);

    Boolean isOpen = FALSE;
    IsOpen(&isOpen);
    if (!isOpen) {
        return E_CLOSED_CHANNEL_EXCEPTION;
    }

    Int32 ops = 0;
    GetValidOps(&ops);
    if (!((interestSet & ~ops) == 0)) {
        return E_ILLEGAL_ARGUMENT_EXCEPTION;
    }

    AutoLock lock(mBlockingLock);
    if (mIsBlocking) {
        return E_ILLEGAL_BLOCKING_MODE_EXCEPTION;
    }

    selector->IsOpen(&isOpen);
    if (!isOpen) {
        if (0 == interestSet) {
            return E_ILLEGAL_SELECTOR_EXCEPTION;
        }
        return E_NULL_POINTER_EXCEPTION;
    }

    AutoPtr<ISelectionKey> key;
    GetKeyFor(selector, (ISelectionKey**)&key);
    if (NULL == key) {
        AbstractSelector* absSel = (AbstractSelector*)selector;
        absSel->Register(this, interestSet, obj, (ISelectionKey**)&key);
        mKeyList.PushBack(key);
    }
    else {
        Boolean isValid = FALSE;
        key->IsValid(&isValid);
        if (!isValid) {
            return E_CANCELLED_KEY_EXCEPTION;
        }
        key->GetInterestOps(interestSet, NULL);
        key->Attach(obj, NULL);
    }

    *result = key;
    REFCOUNT_ADD(*result);
    return NOERROR;
}
MaxPoint GridSearchCrossValidationDriver::doCrossValidationLoop(
			CyclicCoordinateDescent& ccd,
			AbstractSelector& selector,
			const CCDArguments& allArguments,
			int nThreads,
			std::vector<CyclicCoordinateDescent*>& ccdPool,
			std::vector<AbstractSelector*>& selectorPool) {

    const auto& arguments = allArguments.crossValidation;

// 	std::vector<double> weights;
	for (int step = 0; step < gridSize; step++) {

		std::vector<double> predLogLikelihood;
		double point = computeGridPoint(step);
		ccd.setHyperprior(point);
		selector.reseed();

		double pointEstimate = doCrossValidationStep(ccd, selector, allArguments, step,
			nThreads, ccdPool, selectorPool,
			predLogLikelihood);
		double value = pointEstimate / (double(arguments.foldToCompute) / double(arguments.fold));

		gridPoint.push_back(point);
		gridValue.push_back(value);
	}

	// Report results
	double maxPoint;
	double maxValue;
	findMax(&maxPoint, &maxValue);

//     std::ostringstream stream;
// 	stream << std::endl;
// 	stream << "Maximum predicted log likelihood (" << maxValue << ") found at:" << std::endl;
// 	stream << "\t" << maxPoint << " (variance)" << std::endl;
// 	if (!allArguments.useNormalPrior) {
// 		double lambda = convertVarianceToHyperparameter(maxPoint);
// 		stream << "\t" << lambda << " (lambda)" << std::endl;
// 	}
// 	logger->writeLine(stream);
    std::vector<double> point(1, maxPoint);
    return MaxPoint{point, maxValue};
    //return std::vector<double>(1, maxPoint);
}
// This is specific to auto-search
std::vector<double> AutoSearchCrossValidationDriver::doCrossValidationLoop(
			CyclicCoordinateDescent& ccd,
			AbstractSelector& selector,
			const CCDArguments& allArguments,
			int nThreads,
			std::vector<CyclicCoordinateDescent*>& ccdPool,
			std::vector<AbstractSelector*>& selectorPool) {

    const auto& arguments = allArguments.crossValidation;

	double tryvalue = (arguments.startingVariance > 0) ?
	    arguments.startingVariance :
		modelData.getNormalBasedDefaultVar();

	std::ostringstream stream;
	stream << "Starting var = " << tryvalue;
	if (arguments.startingVariance == -1) {
	    stream << " (default)";
	}
	logger->writeLine(stream);

	const double tolerance = 1E-2; // TODO Make Cyclops argument

	int nDim = ccd.getHyperprior().size();
	std::vector<double> currentOptimal(nDim, tryvalue);

	bool globalFinished = false;
	std::vector<double> savedOptimal;

	while (!globalFinished) {

	    if (nDim > 1) {
	        savedOptimal = currentOptimal; // make copy
	    }

	    for (int dim = 0; dim < nDim; ++dim) {

	        // Local search
	        UniModalSearch searcher(10, 0.01, log(1.5));

	        int step = 0;
	        bool dimFinished = false;

	        while (!dimFinished) {

	            ccd.setHyperprior(dim, currentOptimal[dim]);
	            selector.reseed();

	            std::vector<double> predLogLikelihood;

	            // Newly re-located code
	            double pointEstimate = doCrossValidationStep(ccd, selector, allArguments, step,
                                                          nThreads, ccdPool, selectorPool,
                                                          predLogLikelihood);

	            double stdDevEstimate = computeStDev(predLogLikelihood, pointEstimate);

	            std::ostringstream stream;
	            stream << "AvgPred = " << pointEstimate << " with stdev = " << stdDevEstimate << std::endl;
	            searcher.tried(currentOptimal[dim], pointEstimate, stdDevEstimate);
	            pair<bool,double> next = searcher.step();
	            stream << "Completed at " << currentOptimal[dim] << std::endl;
	            stream << "Next point at " << next.second << " and " << next.first;
	            logger->writeLine(stream);

	            currentOptimal[dim] = next.second;
	            if (!next.first) {
	                dimFinished = true;
	            }
	            std::ostringstream stream1;
	            stream1 << searcher;
	            logger->writeLine(stream1);
	            step++;
	            if (step >= maxSteps) {
	                std::ostringstream stream;
	                stream << "Max steps reached!";
	                logger->writeLine(stream);
	                dimFinished = true;
	            }
	        }
	    }

	    if (nDim == 1) {
	        globalFinished = true;
	    } else {

	        double diff = 0.0;
	        for (int i = 0; i < nDim; ++i) {
	            diff += std::abs((currentOptimal[i] - savedOptimal[i]) / savedOptimal[i]);
	        }
	        std::ostringstream stream;
	        stream << "Absolute percent difference in cycle: " << diff << std::endl;

	        globalFinished = (diff < tolerance);
	    }
	}
	return currentOptimal;
}