package ca.pfv.spmf.algorithms.sequentialpatterns.clasp_AGP.dataStructures.creators;
import java.util.ArrayList;
import java.util.List;
import ca.pfv.spmf.algorithms.sequentialpatterns.clasp_AGP.dataStructures.Item;
import ca.pfv.spmf.algorithms.sequentialpatterns.clasp_AGP.dataStructures.abstracciones.Abstraction_Generic;
import ca.pfv.spmf.algorithms.sequentialpatterns.clasp_AGP.dataStructures.abstracciones.Abstraction_Qualitative;
import ca.pfv.spmf.algorithms.sequentialpatterns.clasp_AGP.dataStructures.abstracciones.ItemAbstractionPair;
import ca.pfv.spmf.algorithms.sequentialpatterns.clasp_AGP.dataStructures.patterns.Pattern;
import ca.pfv.spmf.algorithms.sequentialpatterns.clasp_AGP.dataStructures.patterns.PatternCreator;
/**
* Class that implements a qualitative abstraction. Two different values are
* possible: to be with an equal relation with respect to a previous pair (if
* occurs at the same time), or to be with an after relation with respect to
* that previous pair (the previous pair have a before relation with respect to
* this one)
*
* 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 extends AbstractionCreator {
private static AbstractionCreator_Qualitative instance = null;
public static void sclear() {
instance = null;
}
private AbstractionCreator_Qualitative() {
}
public static AbstractionCreator_Qualitative getInstance() {
if (instance == null) {
instance = new AbstractionCreator_Qualitative();
}
return instance;
}
/**
* It creates a default abstraction. The abstraction is established to false
* @return the abstraction
*/
@Override
public Abstraction_Generic createDefaultAbstraction() {
return Abstraction_Qualitative.create(false);
}
/**
* It creates a relation with the given parameter.
* @param hasEqualRelation The boolean indicatin if the item has an equal
* relation with the previous item in the pattern
* @return the created relation
*/
public Abstraction_Generic crearAbstraccion(boolean hasEqualRelation) {
return Abstraction_Qualitative.create(hasEqualRelation);
}
/**
* It obtains the subpattern that is derived from removing from the given
* pattern ,the item specified in the position pointed out by the given index
* @param extension the pattern
* @param index the index
* @return the 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 (int i = 0; i < extension.size(); i++) {
if (i != index) {
if (i == nextIndex) {
if (abstraction == null) {
abstraction = extension.getIthElement(i).getAbstraction();
}
subpatternElements.add(pairCreator.getItemAbstractionPair(extension.getIthElement(i).getItem(), abstraction));
} else {
subpatternElements.add(extension.getIthElement(i));
}
} else {
if (index == 0) {
abstraction = createDefaultAbstraction();
} else {
Abstraction_Qualitative abstraccionDelQuitado = (Abstraction_Qualitative) extension.getIthElement(i).getAbstraction();
if (!abstraccionDelQuitado.hasEqualRelation()) {
abstraction = crearAbstraccion(false);
}
}
}
}
return patternCreator.createPattern(subpatternElements);
}
@Override
public void clear() {
}
/**
* Method that check if for the two patterns given as parameters, the
* shortest one is a subpattern of the longest one
* @param shorter The pattern which we check if is a subpattern of another
* longer than it
* @param larger Pattern which we want to check if another pattern is
* subpattern of itself
* @param index index that indicates which position we have to take into account
* @param positions List of positions of the appearances of the elements of
* the shorter pattern in the longer one
* @return true if it is a subpattern, otherwise false
*/
@Override
public boolean isSubpattern(Pattern shorter, Pattern larger, int index, List<Integer> positions) {
//We get the pair indicated by index
ItemAbstractionPair pair = shorter.getIthElement(index);
Item itemPair = pair.getItem();
Abstraction_Generic absPair = pair.getAbstraction();
//And we also get the abstraction that was in the index-1 position
Abstraction_Generic previousAbs = index > 0 ? shorter.getIthElement(index - 1).getAbstraction() : null;
//Flag in order to cancel the search
boolean cancelled = false;
Integer pos;
/* While the item index pointed out by the position is less than the
* size of the largest pattern
*/
while (positions.get(index) < larger.size()) {
/*
* We search for the item of the shorter pattern pointed by index in
* the longer one
*/
if (index == 0) {
pos = searchForFirstAppearance(larger, positions.get(index), itemPair);
} else {
pos = findItemPositionInPattern(larger, itemPair, absPair, previousAbs, positions.get(index), positions.get(index - 1));
}
//If we found any position
if (pos != null) {
//We set it in the array of positions
positions.set(index, pos);
//if we are not in the last element of the shorter pattern
if (index + 1 < shorter.size()) {
//We create a new position that is just one position after
Integer newPos = increasePosition(positions.get(index));
//And we initialize the next index position to that new position
positions.set(index + 1, newPos);
/* And we make a recursive call to go on checking if shorter
* is a subpattern of longer
*/
boolean output = isSubpattern(shorter, larger, index + 1, positions);
//If we have found a matching between both patterns
if (output) {
positions.clear();
//we return a true answer
return true;
}
} else {//If, conversely, we are in the last element of the shorter pattern
/*
* We have already found a matching between shorter and
* longer and we conclude that one is a subpattern of the
* other one
*/
positions.clear();
return true;
}
} else {//If conversely, we did not find any position for the current index
//If we are not in the first element of the pattern
if (index > 0) {
/* We increase the itemset position of the previous index in
* order to find other matching elements
*/
int newPos = increaseItemset(larger, positions.get(index - 1));
//And we update that position
positions.set(index - 1, newPos);
}
//We set to to true the flag that indicates the end of the method
cancelled = true;
/*
* And break the loop in order to go back and try to find other
* matching elements that makes the subsequence possible
*/
break;
}
}
/* If we are finish the loop and not by breaking it, and we are not looking
* for the first element of the shorter pattern
*/
if (index > 0 && !cancelled) {
/* We increase the itemset position of the previous index in order
* to find other matching elements
*/
int newPos = increaseItemset(larger, positions.get(index - 1));
//And we update that position
positions.set(index - 1, newPos);
}
/*
* We return a false value, indicating that we cannot reach a matching
* with the current choices of elements in the longer pattern
*/
return false;
}
/**
* Method that search the first appearance of an item (given as parameter)
* in a pattern, starting from a beginning index
* @param p Pattern where we search for an item
* @param beginning Index from which we start to search from the item
* @param itemPair Item to search for
* @return The item position where we found the item, or null if this
* does not appear
*/
public Integer searchForFirstAppearance(Pattern p, Integer beginning, Item itemPair) {
for (int i = beginning; i < p.size(); i++) {
Item currentItem = p.getIthElement(i).getItem();
if (currentItem.equals(itemPair)) {
return i;
}
}
return null;
}
/**
* It searches for a position in the pattern given as parameter where
* an item, also given as a parameter, appears
* @param p Pattern where we are going to search for
* @param itemPair Item to search for
* @param currentAbs Abstraction of the current element of the pattern
* where the item appeared
* @param previousAbs Astraction of the previous element of the pattern
* where the item appeared
* @param currentPosition Position for the current element
* @param previousPosition Position of the previous element
* @return the position
*/
public Integer findItemPositionInPattern(Pattern p, Item itemPair, Abstraction_Generic currentAbs, Abstraction_Generic previousAbs, Integer currentPosition, Integer previousPosition) {
Abstraction_Qualitative abs = (Abstraction_Qualitative) currentAbs;
Integer pos;
//If the current Abstraction has an equal relation with the previous pair
if (abs.hasEqualRelation()) {
//We search for the item in the same itemset where the previous item appeared
pos = searchForInTheSameItemset(p, itemPair, currentPosition);
} else {//Otherwise
//We start keeping the currentPosition
int positionToSearchFor = currentPosition;
/*
* If the positions of both the current item and the previous one
* are not in different itemsets
*/
if (!areInDifferentItemsets(p, previousPosition, currentPosition)) {
/*
* We increase the position until we get the first element that
* appear in another itemset
*/
positionToSearchFor = increaseItemset(p, currentPosition);
}
pos = searchForFirstAppearance(p, positionToSearchFor, itemPair);
}
return pos;
}
/**
* It increase the position of a given position by 1.
* @param beginning the position
* @return the position +1
*/
public Integer increasePosition(Integer beginning) {
return beginning + 1;
}
/**
* Increase a position to the first element position where it starts
* another itemset
* @param p Pattern in which we search for the beginning of another itemset
* @param beginning Index from which we start to search for
* @return The item index where a new Itemset starts
*/
public int increaseItemset(Pattern p, Integer beginning) {
//For all the elements appearing after beginning index
for (int i = beginning + 1; i < p.size(); i++) {
ItemAbstractionPair currentPair = p.getIthElement(i);
Abstraction_Qualitative qualitativeAbs = (Abstraction_Qualitative) currentPair.getAbstraction();
//If the relation is not an equal relation, then we have changed of itemset
if (!qualitativeAbs.hasEqualRelation()) {
//And return the index
return i;
}
}
/*
* If we have got this point that means that we were in the last itemset
* of the pattern and, therefore, we return the size of the pattern,
* since there can not be any index bigger than this value
*/
return p.size();
}
/**
* Search for an item in the same itemset that the previous one appeared
* @param pattern Pattern where we are goin to search for the item
* @param itemPair Item to search for
* @param beginning Index from which we are going to start to search for
* @return the index where the item appears, or null if this index does not
* exist
*/
private Integer searchForInTheSameItemset(Pattern pattern, Item itemPair, Integer beginning) {
//From the beginning index and on
for (int i = beginning; i < pattern.size(); i++) {
ItemAbstractionPair currentPair = pattern.getIthElement(i);
Abstraction_Qualitative qualitativeAbstraction = (Abstraction_Qualitative) currentPair.getAbstraction();
//If the item has not an equal relation
if (!qualitativeAbstraction.hasEqualRelation()) {
/*
* We have finished without finding the item, since we have
* already change of itemset
*/
return null;
} else {
/*
* If, conversely, there is an equal relation, we check if this
* item is equal to which we are searching for
*/
if (currentPair.getItem().equals(itemPair)) {
//In that case we return the index position
return i;
}
}
}
return null;
}
/**
* Method that informs if for a pattern, two positions correspond
* to a same itemset or not
* @param pattern Pattern in which we check the two positions
* @param p1 First position
* @param p2 Second position
* @return True if they are in different itemsets, False otherwise
*/
private boolean areInDifferentItemsets(Pattern pattern, Integer p1, Integer p2) {
//For all the elements between positions p1 and p2
for (int i = p1+1; i <= p2 && i < pattern.size(); i++) {
ItemAbstractionPair currentPair = pattern.getIthElement(i);
Abstraction_Qualitative qualitativeAbs = (Abstraction_Qualitative) currentPair.getAbstraction();
/*
* If the ith element does not have an equal relation, we conclude
* that p1 and p2 are not in the same itemset and we can finish
*/
if(!qualitativeAbs.hasEqualRelation())
return true;
}
//If we get this point that means p1 and p2 are in the same itemset
return false;
}
}