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

org.protempa.graph.Weight Maven / Gradle / Ivy

There is a newer version: 5.2-Alpha-2
Show newest version
/*
 * #%L
 * JavaUtil
 * %%
 * Copyright (C) 2012 - 2013 Emory University
 * %%
 * 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.
 * #L%
 */
package org.protempa.graph;

import java.io.Serializable;

/**
 * Like a Long except that there are special values representing
 * positive infinity, negative infinity, positive epsilon (smallest positive
 * value), and negative epsilon (smallest negative value).
 * 
 * @author Andrew Post
 */
public final class Weight implements Comparable, Serializable {

    private static final long serialVersionUID = -20812788110969523L;
    
    /**
     * Whether or not this weight has a value of infinity.
     */
    private boolean isInfinity = false;
    /**
     * true if this weight has a value of positive infinity,
     * false if this weight has a value of negative infinity.
     */
    private boolean posOrNeg = true;

    private long val;
    private transient volatile int hashCode;

    Weight() {
    }

    /**
     * Creates a weight with the given value.
     *
     * @param val
     *            a long value.
     */
    Weight(long val) {
        this.val = val;
    }

    /**
     * Creates a weight with the given value.
     *
     * @param val
     *            a Number value (if null, default value is
     *            0L). It is converted to a long
     *            using Number.longValue().
     */
    Weight(Number val) {
        if (val != null) {
            this.val = val.longValue();
        }
    }

    /**
     * Creates a weight with a value of positive or negative infinity.
     *
     * @param posOrNeg
     *            true to create a weight with a value of
     *            positive infinity, false to create a weight
     *            with a value of negative infinity.
     */
    Weight(boolean posOrNeg) {
        isInfinity = true;
        this.posOrNeg = posOrNeg;
    }

    /**
     * Copy constructor.
     *
     * @param w
     *            a Weight. If null, this
     *            creates a Weight with the default value (0).
     */
    Weight(Weight w) {
        if (w != null) {
            isInfinity = w.isInfinity;
            posOrNeg = w.posOrNeg;
            val = w.val;
        }
    }

    void set(Weight w) {
        if (w != null) {
            isInfinity = w.isInfinity;
            posOrNeg = w.posOrNeg;
            val = w.val;
        } else {
            isInfinity = false;
            posOrNeg = true;
            val = 0L;
        }

        hashCode = 0;
    }

    /**
     * Gets the value of this weight.
     *
     * @return a long representing the value of this weight. If this weight has
     *         a value of positive infinity, Long.MAX_VALUE is
     *         returned. If this weight has a value of negative infinity,
     *         Long.MIN_VALUE is returned.
     */
    public long value() {
        if (isInfinity && !posOrNeg) {
            return Long.MIN_VALUE;
        } else if (isInfinity && posOrNeg) {
            return Long.MAX_VALUE;
        } else {
            return val;
        }
    }

    /**
     * Checks to see if this weight is greater than the given long value.
     *
     * @param val
     *            a long value.
     * @return true if this weight is greater than the given long value, false
     *         otherwise.
     */
    public boolean greaterThan(long val) {
        if (isInfinity && posOrNeg) {
            return true;
        } else if (isInfinity && !posOrNeg) {
            return false;
        } else {
            return this.val > val;
        }
    }

    public int compareToLong(long val) {
        if (greaterThan(val)) {
            return 1;
        } else if (lessThan(val)) {
            return -1;
        } else {
            return 0;
        }
    }

    /**
     * Checks to see if this weight is less than the given long value.
     *
     * @param val
     *            a long value.
     * @return true if this weight is less than the given long value, false
     *         otherwise.
     */
    public boolean lessThan(long val) {
        if (isInfinity && !posOrNeg) {
            return true;
        } else if (isInfinity && posOrNeg) {
            return false;
        } else {
            return this.val < val;
        }
    }

    /**
     * Checks if this weight has the same value as the given long.
     *
     * @param val
     *            a long.
     * @return true if this weight has the same value, false otherwise. Always
     *         returns false if the value of this weight is infinity.
     */
    public boolean isEqual(long val) {
        if (isInfinity) {
            return false;
        } else {
            return this.val == val;
        }
    }

    /**
     * Creates a new weight with value equal to the sum of both weights. Note
     * that +inf and -inf cannot be added. If you try, an
     * IllegalArgumentException will be thrown.
     *
     * @param w
     *            a weight.
     * @return a new weight.
     */
    public Weight add(Weight w) {
        if (w == null) {
            return new Weight(this);
        } else {
            boolean wIsInfinity = w.isInfinity;
            boolean wPosOrNeg = w.posOrNeg;
            if ((isInfinity && posOrNeg && wIsInfinity && !wPosOrNeg)
                    || (isInfinity && !posOrNeg && wIsInfinity && wPosOrNeg)) {
                throw new IllegalArgumentException("+inf - inf!");
            } else if ((isInfinity && posOrNeg) || (w.isInfinity && wPosOrNeg)) {
                return WeightFactory.POS_INFINITY;
            } else if ((isInfinity && !posOrNeg) || (wIsInfinity && !wPosOrNeg)) {
                return WeightFactory.NEG_INFINITY;
            } else {
                return new Weight(val + w.val);
            }
        }
    }

    void addToSelf(Weight w) {
        if (w != null) {
            boolean wIsInfinity = w.isInfinity;
            boolean wPosOrNeg = w.posOrNeg;
            if ((isInfinity && posOrNeg && wIsInfinity && !wPosOrNeg)
                    || (isInfinity && !posOrNeg && wIsInfinity && wPosOrNeg)) {
                throw new IllegalArgumentException("+inf - inf!");
            } else if ((isInfinity && posOrNeg) || (wIsInfinity && wPosOrNeg)) {
                set(WeightFactory.POS_INFINITY);
            } else if ((isInfinity && !posOrNeg) || (wIsInfinity && !wPosOrNeg)) {
                set(WeightFactory.NEG_INFINITY);
            } else {
                val += w.val;
                hashCode = 0;
            }
        }
    }

    /**
     * Creates a new weight the value equal to the difference between the two
     * weights. Note that infinity cannot be subtracted from infinity. If you
     * try, an IllegalArgumentException will be thrown.
     *
     * @param w
     *            a weight.
     * @return a new weight.
     */
    public Weight subtract(Weight w) {
        if (w == null) {
            return new Weight(this);
        } else {
            boolean wIsInfinity = w.isInfinity;
            boolean wPosOrNeg = w.posOrNeg;
            if ((isInfinity && posOrNeg && wIsInfinity && wPosOrNeg)
                    || (isInfinity && !posOrNeg && wIsInfinity && !wPosOrNeg)) {
                throw new IllegalArgumentException("+inf - inf!");
            } else if ((isInfinity && posOrNeg) || (wIsInfinity && !wPosOrNeg)) {
                return WeightFactory.POS_INFINITY;
            } else if ((isInfinity && !posOrNeg) || (wIsInfinity && wPosOrNeg)) {
                return WeightFactory.NEG_INFINITY;
            } else {
                return new Weight(val - w.val);
            }
        }
    }

    /**
     * Gets the larger of the two given weights.
     *
     * @param w1
     *            a weight. Cannot be null.
     * @param w2
     *            a weight. Cannot be null.
     * @return a weight.
     */
    public static Weight max(Weight w1, Weight w2) {
        if (w1 == null) {
            throw new IllegalArgumentException("Argument w1 cannot be null");
        }
        if (w2 == null) {
            throw new IllegalArgumentException("Argument w2 cannot be null");
        }
        if ((w1.isInfinity && w1.posOrNeg) || (w2.isInfinity && !w2.posOrNeg)) {
            return w1;
        } else if ((w2.isInfinity && w2.posOrNeg)
                || (w1.isInfinity && !w1.posOrNeg)) {
            return w2;
        } else if (w1.val >= w2.val) {
            return w1;
        } else {
            return w2;
        }
    }

    /**
     * Gets the smaller of the two given weights.
     *
     * @param w1
     *            a weight. Cannot be null.
     * @param w2
     *            a weight. Cannot be null.
     * @return a weight.
     */
    public static Weight min(Weight w1, Weight w2) {
        if (w1 == null) {
            throw new IllegalArgumentException("Argument w1 cannot be null");
        }
        if (w2 == null) {
            throw new IllegalArgumentException("Argument w2 cannot be null");
        }

        if ((w1.isInfinity && !w1.posOrNeg) || (w2.isInfinity && w2.posOrNeg)) {
            return w1;
        } else if ((w2.isInfinity && !w2.posOrNeg)
                || (w1.isInfinity && w1.posOrNeg)) {
            return w2;
        } else if (w1.val <= w2.val) {
            return w1;
        } else {
            return w2;
        }
    }

    /**
     * Checks if this weight has value of positive infinity.
     *
     * @return true if it does, false if it
     *         doesn't.
     */
    public boolean isPositiveInfinity() {
        return isInfinity && posOrNeg;
    }

    /**
     * Checks if this weight has value of negative infinity.
     *
     * @return true if it does, false if it
     *         doesn't.
     */
    public boolean isNegativeInfinity() {
        return isInfinity && !posOrNeg;
    }

    /**
     * Checks if this weight has value of positive or negative infinity.
     *
     * @return true if it does, false if it
     *         doesn't.
     */
    public boolean isInfinity() {
        return isInfinity;
    }

    /**
     * Creates a new weight with the opposite sign.
     *
     * @return a new Weight.
     */
    public Weight invertSign() {
        if (isInfinity) {
            if (posOrNeg) {
                return WeightFactory.NEG_INFINITY;
            } else {
                return WeightFactory.POS_INFINITY;
            }
        }
        return new Weight(-val);
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        if (isInfinity) {
            if (posOrNeg) {
                return "+inf";
            } else if (!posOrNeg) {
                return "-inf";
            }
        }
        return String.valueOf(val);
    }

    /**
     * Compares two Weight objects numerically.
     *
     * @param anotherWeight
     *            the Weight to be compared.
     * @return the value 0 if this Weight is equal
     *         to the argument Weight; a value less than
     *         0 if this Weight is numerically
     *         less than the argument Weight; and a value
     *         greater than 0 if this Weight is
     *         numerically greater than the argument Weight
     *         (signed comparison).
     */
    public int compareTo(Weight anotherWeight) {
        boolean wIsInfinity = anotherWeight.isInfinity;
        boolean wPosOrNeg = anotherWeight.posOrNeg;

        if (isInfinity && wIsInfinity
                && ((posOrNeg && wPosOrNeg) || (!posOrNeg && !wPosOrNeg))) {
            return 0;
        } else if ((isInfinity && posOrNeg) || (wIsInfinity && !wPosOrNeg)) {
            return 1;
        } else if ((isInfinity && !posOrNeg) || (wIsInfinity && wPosOrNeg)) {
            return -1;
        } else if (val < anotherWeight.val) {
            return -1;
        } else if (val > anotherWeight.val) {
            return 1;
        } else {
            return 0;
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null) {
            return false;
        }
        if (getClass() != o.getClass()) {
            return false;
        }

        Weight w = (Weight) o;

        return isInfinity == w.isInfinity && posOrNeg == w.posOrNeg
                && val == w.val;
    }

    @Override
    public int hashCode() {
        if (hashCode == 0) {
            int result = 17;
            result = 37 * result + (isInfinity ? 0 : 1);
            result = 37 * result + (posOrNeg ? 0 : 1);
            result = 37 * result + (int) (val ^ (val >>> 32));
            hashCode = result;
        }
        return hashCode;

    }

    /**
     * Checks if this weight has a value within the specified range.
     *
     * @param min
     *            the minimum Weight of the range.
     * @param max
     *            the maximum Weight of the range.
     * @return true if this weight is within the specified range,
     *         false if not.
     */
    boolean isWithinRange(Weight min, Weight max) {
        return compareTo(min) >= 0 && compareTo(max) <= 0;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy