package ca.pfv.spmf.algorithms.sequential_rules.topseqrules_and_tns;
/* This file is copyright (c) 2008-2013 Philippe Fournier-Viger
*
* 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/>.
*/
import java.util.Map;
import java.util.Set;
/**
* This class represent a sequential rule as output by the TNS and TopSeqRules algorithm.
* <br/><br/>
* It is optimized for these algorithms by storing several additional fields that are necessary
* for such top-k algorithms. For example, a rule includes the
* transactions IDs of the antecedent, the transaction IDs of the consequent, the transaction IDs
* of the sequences where the antecedent appears before the consequent, maps of occurences for the
* antecedent and consequent, etc.
*
* @see AlgoTopSeqRules
* @see AlgoTNS
* @author Philippe Fournier-Viger
*/
public class Rule implements Comparable<Rule>{
/** antecedent */
private int[] itemset1;
/** consequent */
private int[] itemset2;
/** absolute support */
int transactioncount;
/** the transaction IDs of the antecedent */
Set<Integer> tidsI;
/** the transaction IDs of the consequent */
Set<Integer> tidsJ;
/** transaction IDs of the sequences where the antecedent appears before the consequent */
Set<Integer> tidsIJ;
/** maps of first occurences of the antecedent */
Map<Integer, Short> occurencesIfirst;
/** maps of last occurences of the antecedent */
Map<Integer, Short> occurencesJlast;
/** flag indicating if both left and right expansion should be explored from this rule */
boolean expandLR = false;
/** confidence of the rule */
private double confidence;
/**
* Constructor
* @param itemset1 antecedent
* @param itemset2 consequent
* @param confidence confidence of the rule
* @param transactioncount absolute support
* @param tidsI the transaction IDs of the antecedent
* @param tidsJ the transaction IDs of the consequent
* @param tidsIJ transaction IDs of the sequences where the antecedent appears before the consequent
* @param occurencesIfirst maps of first occurences of the antecedent
* @param occurencesJlast maps of last occurences of the antecedent
*/
public Rule(int[] itemset1, int[] itemset2, double confidence, int transactioncount,
Set<Integer> tidsI, Set<Integer> tidsJ, Set<Integer> tidsIJ,
Map<Integer, Short> occurencesIfirst,
Map<Integer, Short> occurencesJlast){
this.itemset1 = itemset1;
this.itemset2 = itemset2;
this.confidence = confidence;
this.transactioncount = transactioncount;
this.tidsI = tidsI;
this.tidsJ = tidsJ;
this.tidsIJ = tidsIJ;
this.occurencesJlast = occurencesJlast;
this.occurencesIfirst = occurencesIfirst;
}
/**
* Get the antecedent itemset.
* @return the antecedent.
*/
public int[] getItemset1() {
return itemset1;
}
/**
* Get the consequent itemset.
* @return the consequent.
*/
public int[] getItemset2() {
return itemset2;
}
/**
* Get the absolute support (a number of sequences)
* @return the absolute support
*/
public int getAbsoluteSupport(){
return transactioncount;
}
/**
* Get the relative support (a percentage)
* @param sequencecount the number of sequence in the original sequence database
* @return the relative support
*/
public double getRelativeSupport(int sequencecount) {
return ((double)transactioncount) / ((double) sequencecount);
}
/**
* Print this rule to the console
*/
public void print(){
System.out.println(toString());
}
/**
* Get a string representation of this rule.
* @return the string representation
*/
public String toString(){
StringBuilder buffer = new StringBuilder();
for(int i=0; i< itemset1.length; i++){
buffer.append(itemset1[i]);
if(i != itemset1.length-1){
buffer.append(",");
}
}
buffer.append(" ==> ");
for(int i=0; i< itemset2.length; i++){
buffer.append(itemset2[i]);
if(i != itemset2.length-1){
buffer.append(",");
}
}
return buffer.toString();
}
/**
* Get the confidence of this rule
* @return the confidence
*/
public double getConfidence() {
return confidence;
}
/**
* Compare this rule to another rule
* @return 0 if equal, 0< if smaller or >0 if larger
*/
public int compareTo(Rule o) {
if(o == this){
return 0;
}
int compare = this.getAbsoluteSupport() - o.getAbsoluteSupport();
if(compare !=0){
return compare;
}
int itemset1sizeA = this.itemset1 == null ? 0 : this.itemset1.length;
int itemset1sizeB = o.itemset1 == null ? 0 : o.itemset1.length;
int compare2 = itemset1sizeA - itemset1sizeB;
if(compare2 !=0){
return compare2;
}
int itemset2sizeA = this.itemset2 == null ? 0 : this.itemset2.length;
int itemset2sizeB = o.itemset2 == null ? 0 : o.itemset2.length;
int compare3 = itemset2sizeA - itemset2sizeB;
if(compare3 !=0){
return compare3;
}
int compare4 = Double.compare(this.confidence, o.confidence);
if(compare4 !=0){
return compare4;
}
return this.hashCode() - o.hashCode();
}
/**
* Check if this rule is equal to another (if they have the same items in their antecedent and consequent).
* @parameter o another rule
* @return true if equal
*/
public boolean equals(Object o){
Rule ruleX = (Rule)o;
if(ruleX.itemset1.length != this.itemset1.length){
return false;
}
if(ruleX.itemset2.length != this.itemset2.length){
return false;
}
for(int i=0; i< itemset1.length; i++){
if(this.itemset1[i] != ruleX.itemset1[i]){
return false;
}
}
for(int i=0; i< itemset2.length; i++){
if(this.itemset2[i] != ruleX.itemset2[i]){
return false;
}
}
return true;
}
}