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.anomaly;
018
019import org.tribuo.Output;
020
021import java.util.Objects;
022
023/**
024 * An {@link Output} representing either an {@link EventType#ANOMALOUS} or an
025 * {@link EventType#EXPECTED} event.
026 * <p>
027 * Event trainers are allowed to throw IllegalArgumentException if they are supplied
028 * an {@link EventType#ANOMALOUS} at training time. It's noted in the documentation if they
029 * do support training from anomalous and expected data.
030 */
031public final class Event implements Output<Event> {
032    private static final long serialVersionUID = 1L;
033
034    /**
035     * The default score of events.
036     */
037    public static final double DEFAULT_SCORE = Double.NaN;
038
039    /**
040     * The type of event.
041     */
042    public enum EventType {
043        /**
044         * An anomalous event, with id 1.
045         */
046        ANOMALOUS(1),
047        /**
048         * An expected event, with id 0.
049         */
050        EXPECTED(0),
051        /**
052         * An unknown (i.e., unlabelled) event, with id -1.
053         */
054        UNKNOWN(-1);
055        private final int value;
056
057        EventType(int value) {
058            this.value = value;
059        }
060
061        /**
062         * Returns the id of the event.
063         * @return The event id.
064         */
065        protected int getID() {
066            return value;
067        }
068    }
069
070    private final EventType type;
071
072    private final double score;
073
074    /**
075     * Constructs a new event of the specified type and score.
076     * @param type The event type.
077     * @param score The event score.
078     */
079    public Event(EventType type, double score) {
080        this.type = type;
081        this.score = score;
082    }
083
084    /**
085     * Constructs a new event of the specified type with the default score of {@link Event#DEFAULT_SCORE}.
086     * @param type The event type.
087     */
088    public Event(EventType type) {
089        this(type,DEFAULT_SCORE);
090    }
091
092    /**
093     * Get a real valued score for this label.
094     * <p>
095     * If the score is not set then it returns {@link Event#DEFAULT_SCORE}.
096     * @return The predicted score for this label.
097     */
098    public double getScore() {
099        return score;
100    }
101
102    /**
103     * Gets the event type.
104     * @return An event type.
105     */
106    public EventType getType() {
107        return type;
108    }
109
110    @Override
111    public boolean equals(Object o) {
112        if (this == o) return true;
113        if (!(o instanceof Event)) return false;
114        Event event = (Event) o;
115        return type == event.type;
116    }
117
118    @Override
119    public int hashCode() {
120        return Objects.hash(type);
121    }
122
123    @Override
124    public boolean fullEquals(Event o) {
125        if (this == o) return true;
126        if (o == null) return false;
127
128        if ((!(Double.isNaN(o.score) && Double.isNaN(score))) && (Double.compare(o.score, score) != 0)) return false;
129        return type != null ? type.equals(o.type) : o.type == null;
130    }
131
132    @Override
133    public String toString() {
134        if (Double.isNaN(score)) {
135            return type.toString();
136        } else {
137            return "("+type.toString()+","+score+")";
138        }
139    }
140
141    @Override
142    public Event copy() {
143        return new Event(type,score);
144    }
145
146    /**
147     * Returns "EventType" or "EventType,score=eventScore".
148     * @param includeConfidence Include whatever confidence score the label contains, if known.
149     * @return A String form suitable for serialization.
150     */
151    @Override
152    public String getSerializableForm(boolean includeConfidence) {
153        if (includeConfidence && !Double.isNaN(score)) {
154            return type.toString() + ",score=" + score;
155        } else {
156            return type.toString();
157        }
158    }
159
160}