1 /* 2 * This file is part of ELKI: 3 * Environment for Developing KDD-Applications Supported by Index-Structures 4 * 5 * Copyright (C) 2018 6 * ELKI Development Team 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Affero General Public License for more details. 17 * 18 * You should have received a copy of the GNU Affero General Public License 19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 package de.lmu.ifi.dbs.elki.algorithm.itemsetmining; 22 23 import de.lmu.ifi.dbs.elki.data.BitVector; 24 import de.lmu.ifi.dbs.elki.data.SparseNumberVector; 25 import de.lmu.ifi.dbs.elki.data.type.VectorFieldTypeInformation; 26 import de.lmu.ifi.dbs.elki.utilities.datastructures.BitsUtil; 27 import de.lmu.ifi.dbs.elki.utilities.exceptions.APIViolationException; 28 29 /** 30 * Frequent itemset. 31 * 32 * @author Erich Schubert 33 * @since 0.7.0 34 */ 35 public abstract class Itemset implements Comparable<Itemset> { 36 /** 37 * Support for this itemset. 38 */ 39 int support; 40 41 /** 42 * Increase the support of the itemset. 43 * 44 * @return New support. 45 */ increaseSupport()46 public int increaseSupport() { 47 return ++support; 48 } 49 50 /** 51 * Get item support. 52 * 53 * @return Support 54 */ getSupport()55 public int getSupport() { 56 return support; 57 } 58 59 /** 60 * Test whether the itemset is contained in a bit vector. 61 * 62 * @param bv Bit vector 63 * @return {@code true} when the itemset is contained in this vector. 64 */ containedIn(SparseNumberVector bv)65 public boolean containedIn(SparseNumberVector bv) { 66 int i1 = this.iter(), i2 = bv.iter(); 67 while(this.iterValid(i1)) { 68 if(!bv.iterValid(i2)) { 69 return false; 70 } 71 int d1 = this.iterDim(i1), d2 = bv.iterDim(i2); 72 if(d1 < d2) { 73 return false; // Missing 74 } 75 if(d1 == d2) { 76 if(bv.iterDoubleValue(i2) == 0.) { 77 return false; 78 } 79 i1 = this.iterAdvance(i1); 80 } 81 i2 = bv.iterAdvance(i2); 82 } 83 return true; 84 } 85 86 /** 87 * Itemset length. 88 * 89 * @return Itemset length 90 */ length()91 abstract public int length(); 92 93 /** 94 * Get the items. 95 * 96 * @param i Itemset 97 * @param bits Output bitset (must be zeros) 98 * @return Output bitset 99 */ toBitset(Itemset i, long[] bits)100 public static long[] toBitset(Itemset i, long[] bits) { 101 for(int it = i.iter(); i.iterValid(it); it = i.iterAdvance(it)) { 102 BitsUtil.setI(bits, i.iterDim(it)); 103 } 104 return bits; 105 } 106 107 /** 108 * Get an iterator over items, usually the position within an array. 109 * 110 * Intended usage: 111 * 112 * <pre> 113 * {@code 114 * for (int iter = v.iter(); v.iterValid(iter); iter = v.iterAdvance(iter)) { 115 * final int item = v.iterItem(iter); 116 * // Do something. 117 * } 118 * } 119 * </pre> 120 * 121 * @return Iterator 122 */ iter()123 public abstract int iter(); 124 125 /** 126 * Advance the iterator to the next position. 127 * 128 * @param iter Iterator 129 * @return New iterator position 130 */ iterAdvance(int iter)131 public abstract int iterAdvance(int iter); 132 133 /** 134 * Check if the iterator position is valid. 135 * 136 * @param iter Iterator 137 * @return {@code true} if the position is valid. 138 */ iterValid(int iter)139 public abstract boolean iterValid(int iter); 140 141 /** 142 * Item at the iterator position. 143 * 144 * @param iter Iterator 145 * @return Current item 146 */ iterDim(int iter)147 public abstract int iterDim(int iter); 148 149 @Override compareTo(Itemset o)150 public int compareTo(Itemset o) { 151 // Compare by length, then lexicographical. 152 final int l1 = length(), l2 = o.length(); 153 return (l1 < l2) ? -1 : (l1 > l2) ? +1 : // 154 compareLexicographical(this, o); 155 } 156 157 @Override equals(Object obj)158 public boolean equals(Object obj) { 159 if(obj == this) { 160 return true; 161 } 162 if(obj == null || !(obj instanceof Itemset)) { 163 return false; 164 } 165 Itemset o = (Itemset) obj; 166 int i1 = this.iter(), i2 = o.iter(); 167 while(this.iterValid(i1) && o.iterValid(i2)) { 168 int v1 = this.iterDim(i1), v2 = o.iterDim(i2); 169 if(v1 != v2) { 170 return false; 171 } 172 i1 = this.iterAdvance(i1); 173 i2 = o.iterAdvance(i2); 174 } 175 return this.iterValid(i1) == o.iterValid(i2); 176 } 177 178 /** 179 * @deprecated Itemsets MUST NOT BE USED IN HASH MAPS. 180 */ 181 @Deprecated 182 @Override hashCode()183 public int hashCode() { 184 throw new APIViolationException("Itemsets may not be used in hash maps."); 185 } 186 187 /** 188 * Robust compare using the iterators, lexicographical only! 189 * 190 * Note: This does NOT take length into account. 191 * 192 * @param o Other itemset. 193 * @return Comparison result. 194 */ compareLexicographical(Itemset a, Itemset o)195 protected static int compareLexicographical(Itemset a, Itemset o) { 196 int i1 = a.iter(), i2 = o.iter(); 197 while(a.iterValid(i1) && o.iterValid(i2)) { 198 int v1 = a.iterDim(i1), v2 = o.iterDim(i2); 199 if(v1 < v2) { 200 return -1; 201 } 202 if(v2 < v1) { 203 return +1; 204 } 205 i1 = a.iterAdvance(i1); 206 i2 = o.iterAdvance(i2); 207 } 208 return a.iterValid(i1) ? 1 : o.iterValid(i2) ? -1 : 0; 209 } 210 211 @Override toString()212 public String toString() { 213 return appendTo(new StringBuilder(), null).toString(); 214 } 215 216 /** 217 * Append items and support to a string buffer. 218 * 219 * @param buf Buffer 220 * @param meta Relation metadata (for labels) 221 * @return String buffer for chaining. 222 */ appendTo(StringBuilder buf, VectorFieldTypeInformation<BitVector> meta)223 public final StringBuilder appendTo(StringBuilder buf, VectorFieldTypeInformation<BitVector> meta) { 224 appendItemsTo(buf, meta); 225 return buf.append(": ").append(support); 226 } 227 228 /** 229 * Only append the items to a string buffer. 230 * 231 * @param buf Buffer 232 * @param meta Relation metadata (for labels) 233 * @return String buffer for chaining. 234 */ appendItemsTo(StringBuilder buf, VectorFieldTypeInformation<BitVector> meta)235 public StringBuilder appendItemsTo(StringBuilder buf, VectorFieldTypeInformation<BitVector> meta) { 236 int it = this.iter(); 237 if(this.iterValid(it)) { 238 while(true) { 239 int v = this.iterDim(it); 240 String lbl = (meta != null) ? meta.getLabel(v) : null; 241 if(lbl == null) { 242 buf.append(v); 243 } 244 else { 245 buf.append(lbl); 246 } 247 it = this.iterAdvance(it); 248 if(!this.iterValid(it)) { 249 break; 250 } 251 buf.append(", "); 252 } 253 } 254 return buf; 255 } 256 } 257