/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package ca.pfv.spmf.algorithms.sequentialpatterns.gsp_AGP.items.creators;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import ca.pfv.spmf.algorithms.sequentialpatterns.gsp_AGP.items.CandidateInSequenceFinder;
import ca.pfv.spmf.algorithms.sequentialpatterns.gsp_AGP.items.Item;
import ca.pfv.spmf.algorithms.sequentialpatterns.gsp_AGP.items.Itemset;
import ca.pfv.spmf.algorithms.sequentialpatterns.gsp_AGP.items.Sequence;
import ca.pfv.spmf.algorithms.sequentialpatterns.gsp_AGP.items.abstractions.Abstraction_Generic;
import ca.pfv.spmf.algorithms.sequentialpatterns.gsp_AGP.items.abstractions.Abstraction_Qualitative;
import ca.pfv.spmf.algorithms.sequentialpatterns.gsp_AGP.items.abstractions.ItemAbstractionPair;
import ca.pfv.spmf.algorithms.sequentialpatterns.gsp_AGP.items.patterns.Pattern;
import ca.pfv.spmf.algorithms.sequentialpatterns.gsp_AGP.items.patterns.PatternCreator;
/**
* This class is the implementation of a creator of a qualitative abstraction.
*
* 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 AbstractionCreator_Qualitative implements AbstractionCreator {
/**
* Static reference to make this class singleton
*/
private static AbstractionCreator_Qualitative instance = null;
private AbstractionCreator_Qualitative() {
}
/**
* Get the static instance of this singleton class
*
* @return the instance
*/
public static AbstractionCreator_Qualitative getInstance() {
if (instance == null) {
instance = new AbstractionCreator_Qualitative();
}
return instance;
}
/**
* It creates the default abstraction. Defined to false, for this
* implementation.
*
* @return the abstraction
*/
@Override
public Abstraction_Generic CreateDefaultAbstraction() {
return Abstraction_Qualitative.create(false);
}
/**
* It creates the abstraction such as is given by the argument
*
* @param appearingInTheSameItemset the abstraction value
* @return the abstraction
*/
public Abstraction_Generic createAbstraction(boolean appearingInTheSameItemset) {
return Abstraction_Qualitative.create(appearingInTheSameItemset);
}
@Override
public List<Pattern> createSize2Sequences(List<Sequence> sequences) {
Map<Pattern, Pattern> totalMap = new HashMap<Pattern, Pattern>();
List<Pattern> output = new LinkedList<Pattern>();
for (Sequence s : sequences) {
List<Itemset> itemsets = s.getItemsets();
//For each sequence itemset
for (int i = 0; i < itemsets.size(); i++) {
Itemset currentItemset = itemsets.get(i);
//We get each one of the items appearing there
for (int j = 0; j < currentItemset.size(); j++) {
Item item = currentItemset.get(j);
ItemAbstractionPair pair1 = new ItemAbstractionPair(item, CreateDefaultAbstraction());
//With all of the rest of items in the itemset we make 2-itemsets extensions
for (int k = j + 1; k < currentItemset.size(); k++) {
Item item2 = currentItemset.get(k);
ItemAbstractionPair pair2 = new ItemAbstractionPair(item2, Abstraction_Qualitative.create(true));
updateAppeareanceSet(totalMap, pair1, pair2, s.getId());
}
//And with all the items that are in later itemsets we make 2-sequence extensions
for (int k = i + 1; k < itemsets.size(); k++) {
Itemset nextItemset = itemsets.get(k);
for (int n = 0; n < nextItemset.size(); n++) {
Item item2 = nextItemset.get(n);
ItemAbstractionPair pair2 = new ItemAbstractionPair(item2, Abstraction_Qualitative.create(false));
updateAppeareanceSet(totalMap, pair1, pair2, s.getId());
}
}
}
}
}
output.addAll(totalMap.values());
Collections.sort(output);
return output;
}
public void updateAppeareanceSet(Map<Pattern, Pattern> totalMap, ItemAbstractionPair pair1, ItemAbstractionPair pair2, int seqId) {
PatternCreator patternCreator = PatternCreator.getInstance();
List<ItemAbstractionPair> elementsPatternSize2 = new ArrayList<ItemAbstractionPair>(2);
elementsPatternSize2.add(pair1);
elementsPatternSize2.add(pair2);
Pattern newPattern = patternCreator.createPattern(elementsPatternSize2);
Pattern existingPattern = totalMap.get(newPattern);
if (existingPattern == null) {
existingPattern = newPattern;
totalMap.put(newPattern, newPattern);
}
existingPattern.addAppearance(seqId);
}
/**
* It returns the subpattern obtained by removing an item
* at a given index in a pattern.
*
* @param extension The pattern on which we will get a subpattern
* @param index the element to remove from the given pattern
* @return the resulting subpattern
*/
@Override
public Pattern getSubpattern(Pattern extension, int index) {
ItemAbstractionPairCreator pairCreator = ItemAbstractionPairCreator.getInstance();
PatternCreator patternCreator = PatternCreator.getInstance();
List<ItemAbstractionPair> subpatternElements = new ArrayList<ItemAbstractionPair>(extension.size() - 1);
Abstraction_Generic abstraction = null;
int nextIndex = index + 1;
//For each element in the pattern
for (int i = 0; i < extension.size(); i++) {
//we copy it if is not in the given index argument
if (i != index) {
//If is the element that appears after our index
if (i == nextIndex) {
//If we do no have any value in "abstraction" it means that it was not prepared before. In that case we take the abstraction appearing in the ith-element
if (abstraction == null) {
abstraction = extension.getIthElement(i).getAbstraction();
}
//Otherwise, we use the abstraction that we had previously prepared
subpatternElements.add(pairCreator.getItemAbstractionPair(extension.getIthElement(i).getItem(), abstraction));
} else {
subpatternElements.add(extension.getIthElement(i));
}
//If we remove it, we check how are the temporal relations when we do it
} else {
//If it is the first element in the pattern, we establish the default abstraction for the next element
if (index == 0) {
abstraction = CreateDefaultAbstraction();
} else {
//If it is not the first element, we check if it appears in a itemset later than its predecessor
Abstraction_Qualitative abstractionOfRemovedElement = (Abstraction_Qualitative) extension.getIthElement(i).getAbstraction();
//If that is the case, we prepare the abstraction for its sucessor
if (!abstractionOfRemovedElement.hasEqualRelation()) {
abstraction = createAbstraction(false);
}
}
}
}
return patternCreator.createPattern(subpatternElements);
}
@Override
public List<Pattern> createSize2Sequences(Map<Integer, Map<Item, List<Integer>>> bbdd, Map<Item, Pattern> frequentItems) {
Map<Pattern, Pattern> totalMap = new HashMap<Pattern, Pattern>();
List<Pattern> output = new LinkedList<Pattern>();
for (Entry<Integer, Map<Item, List<Integer>>> seq : bbdd.entrySet()) {
Integer sequenceId = seq.getKey();
List<Entry<Item, List<Integer>>> itemItemsetsAssociations = new ArrayList(seq.getValue().entrySet());
//For each sequence itemset
for (int i = 0; i < itemItemsetsAssociations.size(); i++) {
Entry<Item, List<Integer>> currentEntry1 = itemItemsetsAssociations.get(i);
Item item1 = currentEntry1.getKey();
List<Integer> appearances1 = currentEntry1.getValue();
if (!isFrequent(item1, frequentItems)) {
continue;
}
for (int m = 0; m < appearances1.size(); m++) {
int appearanceItem1 = appearances1.get(m);
ItemAbstractionPair pair1 = new ItemAbstractionPair(item1, CreateDefaultAbstraction());
for (int j = 0; j < itemItemsetsAssociations.size(); j++) {
Entry<Item, List<Integer>> currentEntry2 = itemItemsetsAssociations.get(j);
Item item2 = currentEntry2.getKey();
List<Integer> appearances2 = currentEntry2.getValue();
if (!isFrequent(item2, frequentItems)) {
continue;
}
for (int k = 0; k < appearances2.size(); k++) {
int appearanceItem2 = appearances2.get(k);
ItemAbstractionPair pair2 = null;
if (appearanceItem2 == appearanceItem1) {
if (-item2.compareTo(item1) == 1) {
pair2 = new ItemAbstractionPair(item2, Abstraction_Qualitative.create(true));
}
} else if (appearanceItem2 > appearanceItem1) {
pair2 = new ItemAbstractionPair(item2, Abstraction_Qualitative.create(false));
}
if (pair2 != null) {
updateAppeareanceSet(totalMap, pair1, pair2, sequenceId);
}
}
}
}
}
}
output.addAll(totalMap.values());
Collections.sort(output);
return output;
}
private boolean isFrequent(Item item1, Map<Item, Pattern> itemsfrecuentes) {
return (itemsfrecuentes.get(item1)) != null;
}
@Override
public void clear() {
instance = null;
}
public static void sclear() {
instance = null;
}
/**
* Method that creates an abstraction depending of two time values. The
* abstraction will be true if both times are the same, otherwise it will be
* false. The two time values usually comes from comparing the time of two
* items.
*
* @param currentTime the current time
* @param previousTime the previous time
* @return the abstraction
*/
public Abstraction_Generic createAbstraction(long currentTime, long previousTime) {
boolean inTheSameItemset = false;
if (currentTime == previousTime) {
inTheSameItemset = true;
}
Abstraction_Qualitative abstraction = Abstraction_Qualitative.create(inTheSameItemset);
return abstraction;
}
/**
* Method that finds the position that an item has within a concrete
* sequence. The position is returned in a duple <itemset index, item
* index>. The method used to find the item it depends on how the relations,
* between the current item and the previous one, are
*
* @param sequence The sequence where we want to find the item
* @param itemPair Item to find
* @param absPair abstraction of the item to find
* @param previousAbs Previous abstraction in the pattern of this item
* @param itemsetIndex Itemset index that the current item has
* @param itemIndex Item index that the current item has.
* @param previousItemsetIndex Itemset index of the previous item in the
* pattern
* @param previousItemIndex Item index of the previous item in the pattern
* @return The position where the item is
*/
public int[] findPositionOfItemInSequence(Sequence sequence, Item itemPair, Abstraction_Generic absPair, Abstraction_Generic previousAbs, int itemsetIndex, int itemIndex, int previousItemsetIndex, int previousItemIndex) {
Abstraction_Qualitative abs = (Abstraction_Qualitative) absPair;
int[] pos = null;
//If our item has an equal relation
if (abs.hasEqualRelation()) {
//If both itemset indices, for the current and the previous ones, are the same
if (itemsetIndex == previousItemsetIndex) {
//We search for the item in the same itemset
pos = sequence.SearchForItemAtTheSameItemset(itemPair, itemsetIndex, itemIndex);
}
} else {//If, conversely, our item has not an equal relation
int itemsetIndexToSearchFor = itemsetIndex;
int itemIndexToSearchFor = itemIndex;
//If the current itemset index and the previous one point out to the same position
if (itemsetIndex == previousItemsetIndex) {
//We make the current itemset index to point to the next itemset, starting from the first item index
itemsetIndexToSearchFor++;
itemIndexToSearchFor = 0;
}
//And, finally, we look for the item in all the itemsets that appear later than the original itemset index
//pos = sequence.searchForAnItemInLaterItemset(itemPair, itemsetIndexToSearchFor, itemIndexToSearchFor);
pos = sequence.searchForTheFirstAppearance(itemsetIndexToSearchFor, itemIndexToSearchFor, itemPair);
}
return pos;
}
/**
* Method that generates a candidate from two given patterns. if all the
* elements of pattern1, except the first one, are the same as all the
* elements of pattern2, except the last one. For example, if pattern1= a <
* (b c) < d, and pattern2=(b c) < d < e, we are interested in checking if
* the subpattern of pattern1, obtaining by suppressing the first item, is
* equal to the subpattern of pattern2 that is obtained by removing its last
* item. I.e.,
* p1 = a < (b c) < d
* p2 = (b c) < d < e
* and we want two know if the central part of both pattern is the same.
* If is not, we set different to true.
*
*
* @param creator
* @param pattern1 The pattern that plays the role of prefix
* @param pattern2 The pattern that plays the rol of suffix
* @param minSupport The minimum relative support
* @return The candidate generated from the two patterns
*/
public Pattern generateCandidates(AbstractionCreator creator, Pattern pattern1, Pattern pattern2, double minSupport) {
// Flag to know if the central part of the pattern is different
boolean different = false;
List<ItemAbstractionPair> elements1 = pattern1.getElements();
List<ItemAbstractionPair> elements2 = pattern2.getElements();
for (int i = 0; i < (elements1.size() - 1) && !different; i++) {
ItemAbstractionPair pair1 = elements1.get(i + 1);
ItemAbstractionPair pair2 = elements2.get(i);
if (i == 0) {
if (!pair1.getItem().equals(pair2.getItem())) {
different = true;
}
} else {
if (!pair1.equals(pair2)) {
different = true;
}
}
}
if (different) {//If we cannot compose any candidate we return null
return null;
} else {/*otherwise, we first check if the junction of their appearing
* sets still has more appearances than the minimum relative support is
*/
BitSet intersection = (BitSet) pattern1.getAppearingIn().clone();
intersection.and(pattern2.getAppearingIn());
//If we have more appearences than the minSupport is
if (intersection.cardinality() >= minSupport) {
//the candidate can be frequent, so we keep it
Pattern newPattern = pattern1.clonePattern();
newPattern.add(pattern2.getLastElement());
return newPattern;
} else {//Otherwise, it never could be frequent and we can remove it
return null;
}
}
}
/**
* Method to find a candidate in a sequence. It is an intermedium call in
* order to separate the implementation and to be able to define different
* ways of searching.
* @param finder finder of candidates
* @param candidate The candidate to find
* @param sequence The sequence where we want to try finding the candidate
* @param k The level in which we are, i.e. the candidate length
* @param i the candidate item in which we start
* @param position The position list for all the candiate elements
*/
public void isCandidateInSequence(CandidateInSequenceFinder finder, Pattern candidate, Sequence sequence, int k, int i, List<int[]> position) {
finder.isCandidatePresentInTheSequence_qualitative(candidate, sequence, k, 0, position);
}
public List<Pattern> generateSize2Candidates(AbstractionCreator creator, Pattern pat1, Pattern pat2) {
List<Pattern> output = new LinkedList<Pattern>();
PatternCreator patternCreator = PatternCreator.getInstance();
ItemAbstractionPairCreator pairCreator = ItemAbstractionPairCreator.getInstance();
ItemAbstractionPair elementFromPattern1 = pat1.getIthElement(0);
ItemAbstractionPair elementFromPattern2 = pat2.getIthElement(0);
List<ItemAbstractionPair> elementsOfNewPattern1 = new ArrayList<ItemAbstractionPair>(2);
elementsOfNewPattern1.add(elementFromPattern1);
elementsOfNewPattern1.add(pairCreator.getItemAbstractionPair(elementFromPattern2.getItem(), Abstraction_Qualitative.create(false)));
Pattern newPattern1 = patternCreator.createPattern(elementsOfNewPattern1);
output.add(newPattern1);
if (!elementFromPattern1.equals(elementFromPattern2)) {
List<ItemAbstractionPair> elementsOfNewPattern2 = new ArrayList<ItemAbstractionPair>(2);
elementsOfNewPattern2.add(elementFromPattern2);
elementsOfNewPattern2.add(pairCreator.getItemAbstractionPair(elementFromPattern1.getItem(), Abstraction_Qualitative.create(false)));
Pattern newPattern2 = patternCreator.createPattern(elementsOfNewPattern2);
output.add(newPattern2);
ItemAbstractionPair smallestPair, greaterPair;
if (elementFromPattern1.compareTo(elementFromPattern2) > 0) {
smallestPair = elementFromPattern1;
greaterPair = elementFromPattern2;
} else {
smallestPair = elementFromPattern2;
greaterPair = elementFromPattern1;
}
List<ItemAbstractionPair> elementsOfNewPattern3 = new ArrayList<ItemAbstractionPair>(2);
elementsOfNewPattern3.add(smallestPair);
elementsOfNewPattern3.add(pairCreator.getItemAbstractionPair(greaterPair.getItem(), Abstraction_Qualitative.create(true)));
Pattern newPattern3 = patternCreator.createPattern(elementsOfNewPattern3);
output.add(newPattern3);
}
return output;
}
}