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.hash; 018 019import com.oracle.labs.mlrg.olcut.config.Config; 020import com.oracle.labs.mlrg.olcut.provenance.ConfiguredObjectProvenance; 021import com.oracle.labs.mlrg.olcut.provenance.ObjectProvenance; 022import com.oracle.labs.mlrg.olcut.provenance.Provenance; 023import com.oracle.labs.mlrg.olcut.provenance.primitives.IntProvenance; 024import com.oracle.labs.mlrg.olcut.provenance.primitives.StringProvenance; 025 026import java.io.IOException; 027import java.io.ObjectInputStream; 028import java.util.HashMap; 029import java.util.Map; 030import java.util.Objects; 031 032/** 033 * Hashes names using String.hashCode(), then reduces the dimension. 034 */ 035public final class ModHashCodeHasher extends Hasher { 036 private static final long serialVersionUID = 2L; 037 038 static final String DIMENSION = "dimension"; 039 040 @Config(mandatory = true,description="Salt used in the hash.") 041 private transient String salt = null; 042 043 @Config(mandatory = true,description="Range of the hashing function.") 044 private int dimension = 100; 045 046 private ModHashCodeHasherProvenance provenance; 047 048 /** 049 * for olcut. 050 */ 051 private ModHashCodeHasher() { } 052 053 public ModHashCodeHasher(String salt) { 054 this(100,salt); 055 } 056 057 public ModHashCodeHasher(int dimension, String salt) { 058 this.dimension = dimension; 059 this.salt = salt; 060 postConfig(); 061 } 062 063 /** 064 * Used by the OLCUT configuration system, and should not be called by external code. 065 */ 066 @Override 067 public void postConfig() { 068 this.provenance = new ModHashCodeHasherProvenance(dimension); 069 } 070 071 @Override 072 public String hash(String name) { 073 if (salt == null) { 074 throw new IllegalStateException("Salt not set"); 075 } 076 String salted = salt + name; 077 return ""+(salted.hashCode() % dimension); 078 } 079 080 @Override 081 public void setSalt(String salt) { 082 if (Hasher.validateSalt(salt)) { 083 this.salt = salt; 084 } else { 085 throw new IllegalArgumentException("Salt: '" + salt + ", does not meet the requirements for a salt."); 086 } 087 } 088 089 @Override 090 public ConfiguredObjectProvenance getProvenance() { 091 return provenance; 092 } 093 094 @Override 095 public String toString() { 096 return "ModHashCodeHasher(dimension=" + dimension + ")"; 097 } 098 099 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 100 in.defaultReadObject(); 101 salt = null; 102 } 103 104 /** 105 * Provenance for the {@link ModHashCodeHasher}. 106 */ 107 public final static class ModHashCodeHasherProvenance implements ConfiguredObjectProvenance { 108 private static final long serialVersionUID = 1L; 109 110 private final IntProvenance dimension; 111 112 ModHashCodeHasherProvenance(int dimension) { 113 this.dimension = new IntProvenance(DIMENSION,dimension); 114 } 115 116 public ModHashCodeHasherProvenance(Map<String, Provenance> map) { 117 dimension = ObjectProvenance.checkAndExtractProvenance(map,DIMENSION,IntProvenance.class,ModHashCodeHasherProvenance.class.getSimpleName()); 118 } 119 120 @Override 121 public Map<String, Provenance> getConfiguredParameters() { 122 Map<String,Provenance> map = new HashMap<>(); 123 map.put("saltStr",new StringProvenance("saltStr","")); 124 map.put(DIMENSION,dimension); 125 return map; 126 } 127 128 @Override 129 public boolean equals(Object o) { 130 if (this == o) return true; 131 if (!(o instanceof ModHashCodeHasherProvenance)) return false; 132 ModHashCodeHasherProvenance pairs = (ModHashCodeHasherProvenance) o; 133 return dimension.equals(pairs.dimension); 134 } 135 136 @Override 137 public int hashCode() { 138 return Objects.hash(dimension); 139 } 140 141 @Override 142 public String getClassName() { 143 return ModHashCodeHasher.class.getName(); 144 } 145 146 @Override 147 public String toString() { 148 return generateString("Hasher"); 149 } 150 } 151}