/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.mahout.fpm.pfpgrowth.fpgrowth; import com.google.common.primitives.Longs; import java.util.Arrays; /** * A in FPGrowth is a list of items (here int) and the * support(the number of times the pattern is seen in the dataset) * */ public class Pattern implements Comparable<Pattern> { private static final int DEFAULT_INITIAL_SIZE = 2; private static final float GROWTH_RATE = 1.5f; private boolean dirty = true; private int hashCode; private int length; private int[] pattern; private long support = Long.MAX_VALUE; private long[] supportValues; public Pattern() { this(DEFAULT_INITIAL_SIZE); } private Pattern(int size) { if (size < DEFAULT_INITIAL_SIZE) { size = DEFAULT_INITIAL_SIZE; } this.pattern = new int[size]; this.supportValues = new long[size]; dirty = true; } public final void add(int id, long supportCount) { dirty = true; if (length >= pattern.length) { resize(); } this.pattern[length] = id; this.supportValues[length++] = supportCount; this.support = supportCount > this.support ? this.support : supportCount; } public final int[] getPattern() { return this.pattern; } public final Object[] getPatternWithSupport() { return new Object[] {this.pattern, this.supportValues}; } public final boolean isSubPatternOf(Pattern frequentPattern) { int[] otherPattern = frequentPattern.getPattern(); int otherLength = frequentPattern.length(); if (this.length() > frequentPattern.length()) { return false; } int i = 0; int otherI = 0; while (i < length && otherI < otherLength) { if (otherPattern[otherI] == pattern[i]) { otherI++; i++; } else if (otherPattern[otherI] < pattern[i]) { otherI++; } else { return false; } } return otherI != otherLength || i == length; } public final int length() { return this.length; } public final long support() { return this.support; } private void resize() { int size = (int) (GROWTH_RATE * length); if (size < DEFAULT_INITIAL_SIZE) { size = DEFAULT_INITIAL_SIZE; } int[] oldpattern = pattern; long[] oldSupport = supportValues; this.pattern = new int[size]; this.supportValues = new long[size]; System.arraycopy(oldpattern, 0, this.pattern, 0, length); System.arraycopy(oldSupport, 0, this.supportValues, 0, length); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } Pattern other = (Pattern) obj; // expensive check done only if length and support matches return length == other.length && support == other.support && Arrays.equals(pattern, other.pattern); } @Override public int hashCode() { if (!dirty) { return hashCode; } int result = Arrays.hashCode(pattern); result = 31 * result + Longs.hashCode(support); result = 31 * result + length; hashCode = result; return result; } @Override public final String toString() { int[] arr = new int[length]; System.arraycopy(pattern, 0, arr, 0, length); return Arrays.toString(arr) + '-' + support; } @Override public int compareTo(Pattern cr2) { long support2 = cr2.support(); int length2 = cr2.length(); if (support == support2) { if (length < length2) { return -1; } else if (length > length2) { return 1; } else { return 0; } } else { return support > support2 ? 1 : -1; } } }