package ca.pfv.spmf.algorithms.sequentialpatterns.clospan_AGP.items.patterns;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import ca.pfv.spmf.algorithms.sequentialpatterns.clospan_AGP.items.abstractions.ItemAbstractionPair;
import ca.pfv.spmf.algorithms.sequentialpatterns.clospan_AGP.items.creators.AbstractionCreator;
/**
* Implementation of pattern structure. We define it as a list of pairs <abstraction, item>.
* Besides, a bitSet appearingIn denotes the sequences where the pattern appears.
*
* Copyright Antonio Gomariz PeƱalver 2013
*
* This file is part of the SPMF DATA MINING SOFTWARE
* (http://www.philippe-fournier-viger.com/spmf).
*
* SPMF is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SPMF is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SPMF. If not, see <http://www.gnu.org/licenses/>.
*
* @author agomariz
*/
public class Pattern implements Comparable<Pattern>{
/**
* List of pairs <abstraction, item> that define the pattern
*/
private List<ItemAbstractionPair> elements;
/**
* Set of sequence IDs indicating where the pattern appears
*/
//private List<Integer> appearingIn;
private BitSet appearingIn;
/**
* Appearance frequency of this concrete pattern
*/
private int support;
/**
* Addition of all the different sequence identifiers
*/
private int sumIdSequences=-1;
/**
* Standard constructor
*/
public Pattern() {
this.elements = new ArrayList<ItemAbstractionPair>();
//this.appearingIn = new ArrayList<Integer>();
this.appearingIn=new BitSet();
}
/**
* New pattern from a list of pairs <abstraction, item>
* @param elements
*/
public Pattern(List<ItemAbstractionPair> elements) {
this.elements = elements;
//this.appearingIn = new ArrayList<Integer>();
this.appearingIn=new BitSet();
}
/**
* New pattern from a single pair <abstraction, item>
* @param pair
*/
public Pattern(ItemAbstractionPair pair) {
this.elements = new ArrayList<ItemAbstractionPair>();
this.elements.add(pair);
//this.appearingIn = new ArrayList<Integer>();
this.appearingIn=new BitSet();
}
/**
* Get the string representation of this pattern
* @return the string representation
*/
@Override
public String toString() {
StringBuilder result = new StringBuilder();
for (int i = 0; i < elements.size(); i++) {
result.append(elements.get(i).toString());
}
result.append("\t(").append(appearingIn.size()).append(')');
result.append("\t[");
result.append(getSupport());
result.append("]");
return result.toString();
}
/**
* Get the string representation of this itemset in SPMF format.
* @param outputSequenceIdentifiers if true sequence id will be shown for this pattern
* @return the string representation
*/
public String toStringToFile(boolean outputSequenceIdentifiers) {
StringBuilder result = new StringBuilder();
for (int i = 0; i < elements.size(); i++) {
if(i==elements.size()-1){
if(i!=0)
result.append(elements.get(i).toStringToFile());
else
result.append(elements.get(i).getItem());
result.append(" -1");
}
else if(i==0){
result.append(elements.get(i).getItem());
}else{
result.append(elements.get(i).toStringToFile());
}
}
result.append(" #SUP: ");
result.append(getSupport());
// if the user wants the sequence IDs, we will show them
if(outputSequenceIdentifiers) {
result.append(" #SID: ");
for (int i = appearingIn.nextSetBit(0); i >= 0; i = appearingIn.nextSetBit(i+1)) {
result.append(i);
result.append(" ");
}
}
return result.toString();
}
/**
* It clones a pattern
* @return the clone
*/
public Pattern clonePatron() {
PatternCreator patternCreator = PatternCreator.getInstance();
List<ItemAbstractionPair> elementsCopy = new ArrayList<ItemAbstractionPair>(elements);
Pattern clone = patternCreator.createPattern(elementsCopy);
return clone;
}
/**
* It obtains the elements of the pattern
* @return the list of elements
*/
public List<ItemAbstractionPair> getElements() {
return elements;
}
/**
* It obtains the Ith element of the pattern
* @param i the position
* @return the ith element
*/
public ItemAbstractionPair getIthElement(int i) {
return elements.get(i);
}
/**
* It obtains the last element of the pattern
* @return the last element
*/
public ItemAbstractionPair getLastElement() {
if (size() > 0) {
return getIthElement(size() - 1);
}
return null;
}
/**
* Setter method to set the elements of the pattern
* @param elements
*/
public void setElements(List<ItemAbstractionPair> elements) {
this.elements = elements;
}
/**
* It adds an item with its abstraction in the pattern. The new pair is
* added in the last position of the pattern.
* @param pair the pair to be added
*/
public void add(ItemAbstractionPair pair) {
this.elements.add(pair);
}
/**
* It returns the number of items contained in the pattern
* @return the number of items
*/
public int size() {
return elements.size();
}
/**
* Check if this pattern is equal to another according to the lexicographic order.
* @param o the other pattern
* @return 0 if equal, -1 if smaller, 1 otherwise
*/
@Override
public int compareTo(Pattern o) {
List<ItemAbstractionPair> elementsOfGreaterPattern, elementOfSmallerPattern;
if (getElements().size() >= o.getElements().size()) {
elementsOfGreaterPattern = getElements();
elementOfSmallerPattern = o.getElements();
} else {
elementOfSmallerPattern = getElements();
elementsOfGreaterPattern = o.getElements();
}
for (int i = 0; i < elementOfSmallerPattern.size(); i++) {
int comparison = elementOfSmallerPattern.get(i).compareTo(elementsOfGreaterPattern.get(i));
if (comparison != 0) {
return comparison;
}
}
if (elementsOfGreaterPattern.size() == elementOfSmallerPattern.size()) {
return 0;
}
if (getElements().size() < o.getElements().size()) {
return -1;
}
return 1;
}
@Override
public boolean equals(Object o) {
if (o instanceof Pattern) {
Pattern p = (Pattern) o;
if (this.compareTo(p) == 0) {
return true;
}
return false;
}
return false;
}
@Override
public int hashCode() {
int hash = 5;
hash = 67 * hash + (this.elements != null ? this.elements.hashCode() : 0);
return hash;
}
/**
* It returns the list of sequence IDs where the pattern appears.
* @return the list of sequence ids as a bitset
*/
/*public List<Integer> getAppearingIn() {
return appearingIn;
}*/
public BitSet getAppearingIn() {
return appearingIn;
}
/**
* It sets the list of sequence IDs where the pattern appears.
* @param ids a list of sequence ids
*/
public void setAppearingIn(BitSet ids){
//this.appearingIn=new ArrayList<Integer>(ids);
this.appearingIn=ids;
setSupport(this.appearingIn.cardinality());
}
/**
* Check if the current Pattern is a subpattern of another one
* given as parameter.
* @param abstractionCreator an instance of an abstraction creator
* @param p the other pattern
* @return true if this pattern is a subpattern. Otherwise, false.
*/
public boolean isSubpattern(AbstractionCreator abstractionCreator, Pattern p){
//We initialize all the positions values to 0
List<Integer> positions=new ArrayList<Integer>(p.size());
for(int i=0;i<size();i++){
positions.add(0);
}
//And we call to the method of abstractionCreator
return abstractionCreator.isSubpattern(this,p,0,positions);
}
/**
* Method to obtain the support of a pattern
*
* @return the support
*/
public int getSupport() {
return support;
}
/**
* Method to set the support of this pattern
* @param support as an integer value
*/
public void setSupport(int support) {
this.support = support;
}
/**
* Get the sum of all the sequence
* identifiers that are present in the support of this pattern.
* @return the sum of the ids.
*/
public int getSumIdSequences() {
if(sumIdSequences<0)
sumIdSequences=calculateSumIdSequences();
return sumIdSequences;
}
/**
* Set the value for the addition of all the sequence
* identifiers that are present in the support of this pattern
*
* @param sumIdSequences the sum
*/
public void setSumIdSequences(int sumIdSequences) {
this.sumIdSequences = sumIdSequences;
}
/**
* Method to calculate the sum of sequence identifiers.
* @return the sum of the sequence identifiers.
*/
private int calculateSumIdSequences() {
int sum=0;
for(int i=appearingIn.nextSetBit(0);i>=0;i=appearingIn.nextSetBit(i+1))
sum+=i;
return sum;
}
/**
* It concatenates the given pair as a last element of the pattern
* @param pair the pair
* @return the resulting pattern
*/
public Pattern concatenate(ItemAbstractionPair pair) {
Pattern result = clonePatron();
result.add(pair);
return result;
}
/**
* It concatenates the given pattern to the current pattern
* @param pattern the pattern
* @return the resulting pattern
*/
public Pattern concatenate(Pattern pattern) {
Pattern result = clonePatron();
result.getElements().addAll(pattern.getElements());
return result;
}
}