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; 018 019import java.io.Serializable; 020import java.util.Comparator; 021import java.util.logging.Level; 022import java.util.logging.Logger; 023 024/** 025 * A class for features. Features are an immutable tuple of name and a double value. 026 * <p> 027 * Features can be manufactured by the {@link Example} and are not expected 028 * to be long lived objects. They may be deconstructed when stored in an Example. 029 * One day they should become value/inline types. 030 */ 031public class Feature implements Serializable, Cloneable, Comparable<Feature> { 032 private static final long serialVersionUID = 1L; 033 034 private static final Logger logger = Logger.getLogger(Feature.class.getName()); 035 036 /** 037 * The feature name. 038 */ 039 protected final String name; 040 041 /** 042 * The feature value. 043 */ 044 protected final double value; 045 046 /** 047 * Creates an immutable feature. 048 * @param name The feature name. 049 * @param value The feature value. 050 */ 051 public Feature(String name, double value) { 052 this.name = name; 053 this.value = value; 054 } 055 056 /** 057 * Returns the feature name. 058 * @return The feature name 059 */ 060 public String getName() { 061 return name; 062 } 063 064 /** 065 * Returns the feature value. 066 * @return The feature value. 067 */ 068 public double getValue() { 069 return value; 070 } 071 072 @Override 073 public String toString() { 074 return String.format("(%s, %f)", name, value); 075 } 076 077 /** 078 * Returns the feature name formatted as a table cell. 079 * @return The feature name. 080 */ 081 public String toHTML() { 082 String cleanName = getName().replace("&", "&") 083 .replace("<", "<") 084 .replace(">", ">"); 085 086 return String.format("<td style=\"text-align:left\">%s</td>", cleanName); 087 } 088 089 @Override 090 public boolean equals(Object o) { 091 if (this == o) return true; 092 if (o == null || getClass() != o.getClass()) return false; 093 094 Feature feature = (Feature) o; 095 096 if (Double.compare(feature.value, value) != 0) return false; 097 return name != null ? name.equals(feature.name) : feature.name == null; 098 } 099 100 @Override 101 public int hashCode() { 102 int result; 103 long temp; 104 result = name != null ? name.hashCode() : 0; 105 temp = Double.doubleToLongBits(value); 106 result = 31 * result + (int) (temp ^ (temp >>> 32)); 107 return result; 108 } 109 110 @Override 111 public Feature clone() { 112 try { 113 return (Feature) super.clone(); 114 } catch (CloneNotSupportedException e) { 115 logger.log(Level.SEVERE, "Clone failed, returning copy"); 116 return new Feature(name,value); 117 } 118 } 119 120 /** 121 * A comparator using the lexicographic ordering of feature names. 122 * @return A lexicographic comparator. 123 */ 124 public static Comparator<Feature> featureNameComparator() { 125 return Comparator.comparing(a -> a.name); 126 } 127 128 @Override 129 public int compareTo(Feature o) { 130 return name.compareTo(o.name); 131 } 132}