001/*
002 * Copyright (c) 2015-2020, Oracle and/or its affiliates. All rights reserved.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.tribuo.classification;
018
019/**
020 * An immutable multi-class classification label.
021 * <p>
022 * The labels themselves are Strings. A Label also contains an
023 * optional score which measures the confidence in that label,
024 * though it is not required to be a probability.
025 * <p>
026 * Label equality and hashCode is defined solely on the String
027 * label, it does not take into account the score.
028 */
029public final class Label implements Classifiable<Label> {
030    private static final long serialVersionUID = 1L;
031
032    /**
033     * The name of the unknown label (i.e., an unlabelled output).
034     */
035    public static final String UNKNOWN = "LABEL##UNKNOWN";
036
037    /**
038     * The name of the label.
039     */
040    protected final String label;
041
042    /**
043     * The score of the label.
044     */
045    protected final double score;
046
047    /**
048     * Builds a label with the supplied string and score.
049     * @param label The label name.
050     * @param score The label instance score.
051     */
052    public Label(String label, double score) {
053        this.label = label;
054        this.score = score;
055    }
056
057    /**
058     * Builds a label with the sentinel score of Double.NaN.
059     * @param label The name of this label.
060     */
061    public Label(String label) {
062        this(label,Double.NaN);
063    }
064
065    /**
066     * Get a real valued score for this label.
067     * <p>
068     * If the score is not set then it returns Double.NaN.
069     * @return The predicted score for this label.
070     */
071    public double getScore() {
072        return score;
073    }
074
075    /**
076     * Gets the name of this label.
077     * @return A String.
078     */
079    public String getLabel() {
080        return label;
081    }
082
083    @Override
084    public boolean equals(Object o) {
085        if (this == o) return true;
086        if (!(o instanceof Label)) return false;
087
088        Label that = (Label) o;
089
090        return label != null ? label.equals(that.label) : that.label == null;
091    }
092
093    @Override
094    public boolean fullEquals(Label o) {
095        if (this == o) return true;
096        if (o == null) return false;
097
098        if ((!(Double.isNaN(o.score) && Double.isNaN(score))) && (Double.compare(o.score, score) != 0)) return false;
099        return label != null ? label.equals(o.label) : o.label == null;
100    }
101
102    @Override
103    public int hashCode() {
104        int result;
105        result = label.hashCode();
106        return result;
107    }
108
109    @Override
110    public String toString() {
111        if (Double.isNaN(score)) {
112            return label;
113        } else {
114            return "("+label+","+score+")";
115        }
116    }
117
118    @Override
119    public Label copy() {
120        return new Label(label,score);
121    }
122
123    /**
124     * Returns "labelName" or "labelName,score=labelScore".
125     * @param includeConfidence Include whatever confidence score the label contains, if known.
126     * @return A String form suitable for serialization.
127     */
128    @Override
129    public String getSerializableForm(boolean includeConfidence) {
130        if (includeConfidence && !Double.isNaN(score)) {
131            return label + ",score=" + score;
132        } else {
133            return label;
134        }
135    }
136}