com.analog.lyric.dimple.model.domains.DoubleRangeDomain.java Source code

Java tutorial

Introduction

Here is the source code for com.analog.lyric.dimple.model.domains.DoubleRangeDomain.java

Source

/*******************************************************************************
*   Copyright 2014 Analog Devices, Inc.
*
*   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.analog.lyric.dimple.model.domains;

import java.util.Arrays;

import org.eclipse.jdt.annotation.Nullable;
import com.google.common.math.DoubleMath;
import com.google.common.primitives.Doubles;

/**
 * A discrete domain defined by a range of doubles separated by a constant positive interval.
 * <p>
 * @see DiscreteDomain#range(double, double)
 * @see DiscreteDomain#range(double, double, double)
 */
public class DoubleRangeDomain extends DoubleDiscreteDomain {
    private static final long serialVersionUID = 1L;

    private final double _lowerBound;
    private final double _upperBound;
    private final double _interval;
    private final int _size;
    private final double _tolerance;
    private final boolean _hasIntCompatibleValues;

    /*--------------
     * Construction
     */

    private DoubleRangeDomain(double lowerBound, double upperBound, double interval, double tolerance, int size) {
        super(computeHashCode(lowerBound, upperBound, interval, tolerance));

        if (interval <= 0.0) {
            throw new IllegalArgumentException(
                    String.format("Non-positive interval '%g' for double range domain", interval));
        }

        if (tolerance < 0.0) {
            throw new IllegalArgumentException(
                    String.format("Negative tolerance '%g' for double range domain", tolerance));
        }

        if (tolerance >= interval / 2) {
            throw new IllegalArgumentException(String.format(
                    "Tolerance '%g' is too large for interval '%g' in double range domain", tolerance, interval));
        }

        if (upperBound < lowerBound) {
            throw new IllegalArgumentException(String.format(
                    "Bad double range [%g,%g]: upper bound lower than lower bound", lowerBound, upperBound));
        }

        _lowerBound = lowerBound;
        _upperBound = upperBound;
        _size = size;
        _interval = interval;
        _tolerance = tolerance;
        _hasIntCompatibleValues = isIntCompatibleValue(lowerBound) && isIntCompatibleValue(interval)
                && isIntCompatibleValue(upperBound);
    }

    static DoubleRangeDomain create(double lowerBound, double upperBound, double interval, double tolerance) {
        if (!Doubles.isFinite(tolerance)) {
            tolerance = defaultToleranceForInterval(interval);
        }

        int size = 1 + (int) ((tolerance + upperBound - lowerBound) / interval);

        return intern(new DoubleRangeDomain(lowerBound, upperBound, interval, tolerance, size));
    }

    private static int computeHashCode(double... values) {
        return Arrays.hashCode(values);
    }

    /*----------------
     * Object methods
     */

    @Override
    public boolean equals(@Nullable Object that) {
        if (this == that) {
            return true;
        }

        if (that instanceof DoubleRangeDomain) {
            DoubleRangeDomain thatRange = (DoubleRangeDomain) that;
            return _lowerBound == thatRange._lowerBound && _upperBound == thatRange._upperBound
                    && _interval == thatRange._interval && _tolerance == thatRange._tolerance;
        }

        return false;
    }

    /*----------------
     * Domain methods
     */

    @Override
    public final boolean hasIntCompatibleValues() {
        return _hasIntCompatibleValues;
    }

    /*------------------------
     * DiscreteDomain methods
     */

    @Override
    public final int size() {
        return _size;
    }

    /**
     * Same as {@link #getIndex(Object)} but taking a double.
     */
    @Override
    public int getIndex(double value) {
        int index = (int) Math.rint((value - _lowerBound) / _interval);
        return index < _size && DoubleMath.fuzzyEquals(_lowerBound + index * _interval, value, _tolerance) ? index
                : -1;
    }

    /*---------------------------
     * DoubleRangeDomain methods
     */

    /**
     * Same as {@link #getElement(int)} but returning an unboxed double.
     */
    @Override
    public double getDoubleElement(int i) {
        assertIndexInBounds(i, _size);
        return _lowerBound + i * _interval;
    }

    /**
     * The interval separating consecutive elements of the domain.
     * <p>
     * Guaranteed to be positive.
     */
    public double getInterval() {
        return _interval;
    }

    /**
     * Returns the lower bound for the domain which is also the same as the first element.
     * <p>
     * @see #getUpperBound()
     */
    public double getLowerBound() {
        return _lowerBound;
    }

    public double getUpperBound() {
        return _upperBound;
    }

    /**
     * The tolerance is the maximum difference allowed between a value and a domain element
     * for it to be consider to be the same element.
     * <p>
     * The tolerance must be positive and less than half the value of {@link #getInterval()} and is typically
     * much smaller than that.
     */
    public double getTolerance() {
        return _tolerance;
    }

    static public double defaultToleranceForInterval(double interval) {
        return Math.abs(interval * 1e-6);
    }
}