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 com.oracle.labs.mlrg.olcut.util.Pair;
020import org.tribuo.ImmutableOutputInfo;
021import org.tribuo.MutableOutputInfo;
022import org.tribuo.OutputInfo;
023import org.tribuo.anomaly.Event.EventType;
024
025import java.util.ArrayList;
026import java.util.Collections;
027import java.util.HashSet;
028import java.util.List;
029import java.util.Set;
030
031/**
032 * The base class for tracking anomalous events.
033 */
034public abstract class AnomalyInfo implements OutputInfo<Event>  {
035    private static final long serialVersionUID = 1L;
036
037    private static final Set<Event> DOMAIN = makeDomain();
038
039    /**
040     * The number of expected events observed.
041     */
042    protected long expectedCount = 0;
043
044    /**
045     * The number of anomalous events observed.
046     */
047    protected long anomalyCount = 0;
048
049    /**
050     * The number of unknown events observed (i.e., those without labels).
051     */
052    protected int unknownCount = 0;
053
054    /**
055     * Constructs a new empty anomaly info.
056     */
057    protected AnomalyInfo() { }
058
059    /**
060     * Copies the supplied anomaly info.
061     * @param other The info to copy.
062     */
063    protected AnomalyInfo(AnomalyInfo other) {
064        this.expectedCount = other.expectedCount;
065        this.anomalyCount = other.anomalyCount;
066        this.unknownCount = other.unknownCount;
067    }
068
069    @Override
070    public int getUnknownCount() {
071        return unknownCount;
072    }
073
074    /**
075     * The number of anomalous events observed.
076     * @return The number of anomalies.
077     */
078    public long getAnomalyCount() {
079        return anomalyCount;
080    }
081
082    /**
083     * The number of expected events observed.
084     * @return The number of normal events.
085     */
086    public long getExpectedCount() {
087        return expectedCount;
088    }
089
090    /**
091     * Returns the set of possible {@link Event}s.
092     * <p>
093     * Each event has the default score of Double.NaN.
094     * @return The set of possible events.
095     */
096    @Override
097    public Set<Event> getDomain() {
098        return DOMAIN;
099    }
100
101    /**
102     * Gets the count of the supplied EventType.
103     * @param type An EventType.
104     * @return A non-negative long.
105     */
106    public long getEventCount(EventType type) {
107        switch (type) {
108            case ANOMALOUS:
109                return anomalyCount;
110            case EXPECTED:
111                return expectedCount;
112            case UNKNOWN:
113                return unknownCount;
114            default:
115                return 0;
116        }
117    }
118
119    @Override
120    public Iterable<Pair<String,Long>> outputCountsIterable() {
121        List<Pair<String,Long>> list = new ArrayList<>();
122
123        list.add(new Pair<>(EventType.ANOMALOUS.toString(),anomalyCount));
124        list.add(new Pair<>(EventType.EXPECTED.toString(),expectedCount));
125
126        return list;
127    }
128
129    /**
130     * The number of possible event types (i.e., 2).
131     * @return The number of possible event types.
132     */
133    @Override
134    public int size() {
135        return DOMAIN.size();
136    }
137
138    @Override
139    public ImmutableOutputInfo<Event> generateImmutableOutputInfo() {
140        return new ImmutableAnomalyInfo(this);
141    }
142
143    @Override
144    public MutableOutputInfo<Event> generateMutableOutputInfo() {
145        return new MutableAnomalyInfo(this);
146    }
147
148    @Override
149    public String toReadableString() {
150        return "{Anomalies:"+anomalyCount+",expected:"+expectedCount+"}";
151    }
152
153    @Override
154    public abstract AnomalyInfo copy();
155
156    private static Set<Event> makeDomain() {
157        HashSet<Event> set = new HashSet<>();
158
159        set.add(AnomalyFactory.EXPECTED_EVENT);
160        set.add(AnomalyFactory.ANOMALOUS_EVENT);
161
162        return Collections.unmodifiableSet(set);
163    }
164}