package com.kellegous.mas864.clusterss;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;

import Jama.Matrix;

/**
 * @author knorton
 * Copyright (C) 2005 MIT Media Lab, All Right Reserved.
 */
public class BOWKernelGenerator implements KernelGenerator {
    private double      gamma = -.001;
    private double      tolerance = 150;
    private double      variance = 0.0;
    private ArrayList   data =  null;
    private HashSet     dict = null;
    private double      mean = 0.0;
    private Matrix      dataMatrix = null;
    
    public BOWKernelGenerator() {
        this.reset();
    }
    
    public void setTolerance(double tolerance) {
        this.tolerance = tolerance;
        this.invalidate();
    }
    
    public void reset() {
        this.data = new ArrayList();
        this.dict = new HashSet();
        this.invalidate();
    }
    
    public void addDataVector(HashSet x) {
        this.invalidate();
        this.appendToDict(x);
        this.data.add(x);
    }
    
    private void appendToDict(HashSet x) {
        for (Iterator i=x.iterator();i.hasNext();) {
            Object w = i.next();
            if (!this.dict.contains(w))
                this.dict.add(w);
        }
    }
    
    public int getSize() {
        return this.data.size();
    }  
    
    public double getWeight(int a, int b) {
        if (this.dataMatrix==null)
            generate();
        
        double d = this.dataMatrix.get(a,b);
        if (d<tolerance)
            return Math.exp(gamma*d/variance);
        else
            return 0.0;
    }
        
    private void generate() {            
        int n = this.data.size();
        Matrix k = new Matrix(n,n);
        
        for (int i=0;i<n;i++) {
            HashSet si = (HashSet)this.data.get(i);
            for (int j=0;j<i;j++) {
                k.set(i,j,k.get(j,i));
                this.mean += k.get(i,j);
            }
            
            for (int j=i;j<n;j++) {
                int s = 0;

                HashSet sj = (HashSet)this.data.get(j);	                
                for (Iterator it=this.dict.iterator();it.hasNext();) {
                    String wd = (String)it.next();
                    if (si.contains(wd) && sj.contains(wd))
                        s++;
                }
                k.set(i,j,Math.min(si.size(),sj.size())-s);
                mean += k.get(i,j);
                //k.set(i,j,1.0-1.0/Math.max(s,Double.MIN_VALUE));
            }            
        }
        this.dataMatrix = k;
        this.mean /= n*n;
        
        for (int i=0;i<n;i++) {
            for (int j=0;j<n;j++) {
                double v = k.get(i,j)-this.mean;
                this.variance += (v*v);
            }
        }
        this.variance /= (n*n-1);
    }
    
    private void invalidate() {
        this.dataMatrix = null;
    }
}
