All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ocadotechnology.physics.utils.BinarySearch Maven / Gradle / Ivy

There is a newer version: 16.6.21
Show newest version
/*
 * Copyright © 2017-2023 Ocado (Ocava)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.ocadotechnology.physics.utils;

import java.util.function.DoubleFunction;
import java.util.function.ToDoubleFunction;

import com.google.common.base.Preconditions;

public class BinarySearch {
    private BinarySearch(){}

    /**
     * Searches over the double range between lowerBound and upperBound for an instance of T specified by the
     * comparator.
     *
     * Any precision constraints should be taken account of in comparator.
     *
     * @param pointAtValue should supply the T instance which corresponds with a given double value
     * @param comparator should take a T and return 0 if T is being searched for, less than 0 for if T maps to a lower
     *                   value than the object being searched for, and greater than 0 for if T maps to a higher value
     *                   than the object being searched for.
     * @param lowerBound the lower bound of the region to be searched over
     * @param upperBound the upper bound of the region to be searched over
     * @return the first encountered T instance provided by pointAtValue for which the comparator returns zero.
     *
     * @throws IllegalArgumentException if the lower bound is greater than the upper bound, or if the comparator returns
     *                                  greater than zero for the T instance at the lower bound, or less than zero for
     *                                  the T instance at the upper bound.
     */
    public static  T find(DoubleFunction pointAtValue, ToDoubleFunction comparator, double lowerBound, double upperBound) {
        Preconditions.checkArgument(lowerBound <= upperBound, "lower bound " + lowerBound + " must not be greater than upper bound " + upperBound);
        
        T lowerBoundPoint = pointAtValue.apply(lowerBound);
        double lowerBoundComp = comparator.applyAsDouble(lowerBoundPoint);
        if (lowerBoundComp == 0) {
            return lowerBoundPoint;
        }
        Preconditions.checkArgument(lowerBoundComp < 0, "Invalid search parameter");

        T upperBoundPoint = pointAtValue.apply(upperBound);
        double upperBoundComp = comparator.applyAsDouble(upperBoundPoint);
        if (upperBoundComp == 0) {
            return upperBoundPoint;
        }
        Preconditions.checkArgument(upperBoundComp > 0, "Invalid search parameter");

        while (true) {
            double mid = (lowerBound + upperBound) / 2.0;
            T newPoint = pointAtValue.apply(mid);
            double comp = comparator.applyAsDouble(newPoint);
            Preconditions.checkState(mid > lowerBound && mid < upperBound);

            if (comp == 0) {
                return newPoint;
            } else if (comp < 0) {
                lowerBound = mid;
            } else {
                upperBound = mid;
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy