Author: rdonkin
Date: Mon May  9 11:41:20 2011
New Revision: 1100967

URL: http://svn.apache.org/viewvc?rev=1100967&view=rev
Log:
Consolidated duplication by factoring out tokenizers.

Added:
    
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/TokenCollector.java
   (with props)
    
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/TokenCounter.java
   (with props)
Modified:
    
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/BayesianAnalyzer.java
    
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/Tokenizer.java

Modified: 
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/BayesianAnalyzer.java
URL: 
http://svn.apache.org/viewvc/james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/BayesianAnalyzer.java?rev=1100967&r1=1100966&r2=1100967&view=diff
==============================================================================
--- 
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/BayesianAnalyzer.java
 (original)
+++ 
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/BayesianAnalyzer.java
 Mon May  9 11:41:20 2011
@@ -309,42 +309,7 @@ public class BayesianAnalyzer {
      * @param target
      */
     private void addTokenOccurrences(Reader stream, Map<String, Integer> 
target) throws java.io.IOException {
-        String token;
-        String header = "";
-
-        // Update target with the tokens/count encountered.
-        while ((token = nextToken(stream)) != null) {
-            boolean endingLine = false;
-            if (token.length() > 0 && token.charAt(token.length() - 1) == 
'\n') {
-                endingLine = true;
-                token = token.substring(0, token.length() - 1);
-            }
-
-            if (token.length() > 0 && header.length() + token.length() < 90 && 
!allDigits(token)) {
-                if (token.equals("From:") || token.equals("Return-Path:") || 
token.equals("Subject:") || token.equals("To:")) {
-                    header = token;
-                    if (!endingLine) {
-                        continue;
-                    }
-                }
-
-                token = header + token;
-
-                Integer value = null;
-
-                if (target.containsKey(token)) {
-                    value = Integer.valueOf(((Integer) 
target.get(token)).intValue() + 1);
-                } else {
-                    value = Integer.valueOf(1);
-                }
-
-                target.put(token, value);
-            }
-
-            if (endingLine) {
-                header = "";
-            }
-        }
+        new TokenCounter(target).count(stream);
     }
 
     /**
@@ -356,110 +321,11 @@ public class BayesianAnalyzer {
      */
     private Set<String> parse(Reader stream) throws java.io.IOException {
         Set<String> tokens = new HashSet<String>();
-        String token;
-        String header = "";
-
-        // Build a Map of tokens encountered.
-        while ((token = nextToken(stream)) != null) {
-            boolean endingLine = false;
-            if (token.length() > 0 && token.charAt(token.length() - 1) == 
'\n') {
-                endingLine = true;
-                token = token.substring(0, token.length() - 1);
-            }
-
-            if (token.length() > 0 && header.length() + token.length() < 90 && 
!allDigits(token)) {
-                if (token.equals("From:") || token.equals("Return-Path:") || 
token.equals("Subject:") || token.equals("To:")) {
-                    header = token;
-                    if (!endingLine) {
-                        continue;
-                    }
-                }
-
-                token = header + token;
-
-                tokens.add(token);
-            }
-
-            if (endingLine) {
-                header = "";
-            }
-        }
-
+        new TokenCollector(tokens).collect(stream);
         // Return the unique set of tokens encountered.
         return tokens;
     }
 
-    private String nextToken(Reader reader) throws java.io.IOException {
-        StringBuffer token = new StringBuffer();
-        int i;
-        char ch, ch2;
-        boolean previousWasDigit = false;
-        boolean tokenCharFound = false;
-
-        if (!reader.ready()) {
-            return null;
-        }
-
-        while ((i = reader.read()) != -1) {
-
-            ch = (char) i;
-
-            if (ch == ':') {
-                String tokenString = token.toString() + ':';
-                if (tokenString.equals("From:") || 
tokenString.equals("Return-Path:") || tokenString.equals("Subject:") || 
tokenString.equals("To:")) {
-                    return tokenString;
-                }
-            }
-
-            if (Character.isLetter(ch) || ch == '-' || ch == '$' || ch == 
'\u20AC' // the
-                                                                               
    // EURO
-                                                                               
    // symbol
-                    || ch == '!' || ch == '\'') {
-                tokenCharFound = true;
-                previousWasDigit = false;
-                token.append(ch);
-            } else if (Character.isDigit(ch)) {
-                tokenCharFound = true;
-                previousWasDigit = true;
-                token.append(ch);
-            } else if (previousWasDigit && (ch == '.' || ch == ',')) {
-                reader.mark(1);
-                previousWasDigit = false;
-                i = reader.read();
-                if (i == -1) {
-                    break;
-                }
-                ch2 = (char) i;
-                if (Character.isDigit(ch2)) {
-                    tokenCharFound = true;
-                    previousWasDigit = true;
-                    token.append(ch);
-                    token.append(ch2);
-                } else {
-                    reader.reset();
-                    break;
-                }
-            } else if (ch == '\r') { //NOPMD
-                // cr found, ignore
-            } else if (ch == '\n') {
-                // eol found
-                tokenCharFound = true;
-                previousWasDigit = false;
-                token.append(ch);
-                break;
-            } else if (tokenCharFound) {
-                break;
-            }
-        }
-
-        if (tokenCharFound) {
-            // System.out.println("Token read: " + token);
-            return token.toString();
-        } else {
-            return null;
-        }
-    }
-
     /**
      * Compute the probability that "token" is SPAM.
      * 
@@ -654,13 +520,4 @@ public class BayesianAnalyzer {
 
         return (p / (p + np));
     }
-
-    private boolean allDigits(String s) {
-        for (int i = 0; i < s.length(); i++) {
-            if (!Character.isDigit(s.charAt(i))) {
-                return false;
-            }
-        }
-        return true;
-    }
 }

Added: 
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/TokenCollector.java
URL: 
http://svn.apache.org/viewvc/james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/TokenCollector.java?rev=1100967&view=auto
==============================================================================
--- 
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/TokenCollector.java
 (added)
+++ 
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/TokenCollector.java
 Mon May  9 11:41:20 2011
@@ -0,0 +1,63 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.ai.classic;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Collection;
+
+/**
+ * Collects tokens.
+ */
+public class TokenCollector extends Tokenizer {
+
+    /** Stores collected tokens */
+    private final Collection<String> tokens;
+ 
+    
+    /**
+     * Constructs a collector which collects tokens
+     * into the given collection.
+     * @param tokens not null
+     */
+    public TokenCollector(Collection<String> tokens) {
+        super();
+        this.tokens = tokens;
+    }
+    
+    /**
+     * Collects tokens from stream.
+     * @param stream not null
+     * @return this, not null
+     * @throws IOException
+     */
+    public TokenCollector collect(final Reader stream) throws IOException {
+        doTokenize(stream);
+        return this;
+    }
+ 
+    /**
+     * Adds the token to the collection.
+     */
+    @Override
+    protected void next(String token) {
+        tokens.add(token);
+    }
+}

Propchange: 
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/TokenCollector.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/TokenCounter.java
URL: 
http://svn.apache.org/viewvc/james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/TokenCounter.java?rev=1100967&view=auto
==============================================================================
--- 
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/TokenCounter.java
 (added)
+++ 
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/TokenCounter.java
 Mon May  9 11:41:20 2011
@@ -0,0 +1,71 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.ai.classic;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Map;
+
+/**
+ * Counts tokens occuring in stream.
+ * Totals are added to map.
+ */
+public class TokenCounter extends Tokenizer {
+
+    /** Counts for token indexed by token */
+    private final Map<String, Integer> countsByToken;
+    
+    /**
+     * Constructs a token counter to update values in given map.
+     * @param countsByToken counts for token indexed by token, not null 
+     */
+    public TokenCounter(Map<String, Integer> countsByToken) {
+        super();
+        this.countsByToken = countsByToken;
+    }
+
+    /**
+     * Tokenizes and adds token counts to map.
+     * @param stream not null
+     * @return this, not null
+     * @throws IOException
+     */
+    public TokenCounter count(Reader stream) throws IOException {
+        doTokenize(stream);
+        return this;
+    }
+    
+    /**
+     * Updates count for token in map.
+     */
+    @Override
+    protected void next(String token) {
+        Integer value = null;
+
+        if (countsByToken.containsKey(token)) {
+            value = Integer.valueOf(((Integer) 
countsByToken.get(token)).intValue() + 1);
+        } else {
+            value = Integer.valueOf(1);
+        }
+
+        countsByToken.put(token, value);        
+    }
+
+}

Propchange: 
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/TokenCounter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/Tokenizer.java
URL: 
http://svn.apache.org/viewvc/james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/Tokenizer.java?rev=1100967&r1=1100966&r2=1100967&view=diff
==============================================================================
--- 
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/Tokenizer.java
 (original)
+++ 
james/mailet/ai/trunk/classic/src/main/java/org/apache/james/ai/classic/Tokenizer.java
 Mon May  9 11:41:20 2011
@@ -19,300 +19,24 @@
 
 package org.apache.james.ai.classic;
 
+import java.io.IOException;
 import java.io.Reader;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
 
 /**
- * <p>
- * Determines probability that text contains Spam.
- * </p>
- * 
- * <p>
- * Based upon Paul Grahams' <a href="http://www.paulgraham.com/spam.html";>A 
Plan
- * for Spam</a>. Extended to Paul Grahams' <a
- * href="http://paulgraham.com/better.html";>Better Bayesian Filtering</a>.
- * </p>
- * 
- * <p>
- * Sample method usage:
- * </p>
- * 
- * <p>
- * Use: void addHam(Reader) and void addSpam(Reader)
- * 
- * methods to build up the Maps of ham & spam tokens/occurrences. Both addHam
- * and addSpam assume they're reading one message at a time, if you feed more
- * than one message per call, be sure to adjust the appropriate message 
counter:
- * hamMessageCount or spamMessageCount.
- * 
- * Then...
- * </p>
- * 
- * <p>
- * Use: void buildCorpus()
- * 
- * to build the final token/probabilities Map.
- * 
- * Use your own methods for persistent storage of either the individual 
ham/spam
- * corpus & message counts, and/or the final corpus.
- * 
- * Then you can...
- * </p>
- * 
- * <p>
- * Use: double computeSpamProbability(Reader)
- * 
- * to determine the probability that a particular text contains spam. A 
returned
- * result of 0.9 or above is an indicator that the text was spam.
- * </p>
- * 
- * <p>
- * If you use persistent storage, use: void setCorpus(Map)
- * 
- * before calling computeSpamProbability.
- * </p>
- * 
- * @since 2.3.0
+ * Tokenizes streaming mail input.
  */
+public abstract class Tokenizer {
 
-public class Tokenizer {
-
-    /**
-     * Number of "interesting" tokens to use to compute overall spamminess
-     * probability.
-     */
-    private final static int MAX_INTERESTING_TOKENS = 15;
-
-    /**
-     * Minimum probability distance from 0.5 to consider a token "interesting"
-     * to use to compute overall spamminess probability.
-     */
-    private final static double INTERESTINGNESS_THRESHOLD = 0.46;
-
-    /**
-     * Default token probability to use when a token has not been encountered
-     * before.
-     */
-    final static double DEFAULT_TOKEN_PROBABILITY = 0.4;
-
-    /** Map of ham tokens and their occurrences. */
-    private Map<String, Integer> hamTokenCounts = new HashMap<String, 
Integer>();
-
-    /** Map of spam tokens and their occurrences. */
-    private Map<String, Integer> spamTokenCounts = new HashMap<String, 
Integer>();
-
-    /** Number of ham messages analyzed. */
-    private int hamMessageCount = 0;
-
-    /** Number of spam messages analyzed. */
-    private int spamMessageCount = 0;
-
-    /** Final token/probability corpus. */
-    private Map<String, Double> corpus = new HashMap<String, Double>();
-
-    /**
-     * Basic class constructor.
-     */
-    public Tokenizer() {
-    }
-
-    /**
-     * Public setter for the hamTokenCounts Map.
-     * 
-     * @param hamTokenCounts
-     *            The new ham Token counts Map.
-     */
-    public void setHamTokenCounts(Map<String, Integer> hamTokenCounts) {
-        this.hamTokenCounts = hamTokenCounts;
-    }
-
-    /**
-     * Public getter for the hamTokenCounts Map.
-     */
-    public Map<String, Integer> getHamTokenCounts() {
-        return this.hamTokenCounts;
-    }
-
-    /**
-     * Public setter for the spamTokenCounts Map.
-     * 
-     * @param spamTokenCounts
-     *            The new spam Token counts Map.
-     */
-    public void setSpamTokenCounts(Map<String, Integer> spamTokenCounts) {
-        this.spamTokenCounts = spamTokenCounts;
-    }
-
-    /**
-     * Public getter for the spamTokenCounts Map.
-     */
-    public Map<String, Integer> getSpamTokenCounts() {
-        return this.spamTokenCounts;
-    }
-
-    /**
-     * Public setter for spamMessageCount.
-     * 
-     * @param spamMessageCount
-     *            The new spam message count.
-     */
-    public void setSpamMessageCount(int spamMessageCount) {
-        this.spamMessageCount = spamMessageCount;
-    }
-
-    /**
-     * Public getter for spamMessageCount.
-     */
-    public int getSpamMessageCount() {
-        return this.spamMessageCount;
-    }
-
-    /**
-     * Public setter for hamMessageCount.
-     * 
-     * @param hamMessageCount
-     *            The new ham message count.
-     */
-    public void setHamMessageCount(int hamMessageCount) {
-        this.hamMessageCount = hamMessageCount;
-    }
-
+    private String token;
+    private String header = "";
+   
     /**
-     * Public getter for hamMessageCount.
-     */
-    public int getHamMessageCount() {
-        return this.hamMessageCount;
-    }
-
-    /**
-     * Clears all analysis repositories and counters.
-     */
-    public void clear() {
-        corpus.clear();
-
-        tokenCountsClear();
-
-        hamMessageCount = 0;
-        spamMessageCount = 0;
-    }
-
-    /**
-     * Clears token counters.
-     */
-    public void tokenCountsClear() {
-        hamTokenCounts.clear();
-        spamTokenCounts.clear();
-    }
-
-    /**
-     * Public setter for corpus.
+     * Tokenizes a stream.
      * 
-     * @param corpus
-     *            The new corpus.
-     */
-    public void setCorpus(Map<String, Double> corpus) {
-        this.corpus = corpus;
-    }
-
-    /**
-     * Public getter for corpus.
+     * @param stream not null
      */
-    public Map<String, Double> getCorpus() {
-        return this.corpus;
-    }
+    protected void doTokenize(Reader stream) throws IOException {
 
-    /**
-     * Builds the corpus from the existing ham & spam counts.
-     */
-    public void buildCorpus() {
-        // Combine the known ham & spam tokens.
-        Set<String> set = new HashSet<String>(hamTokenCounts.size() + 
spamTokenCounts.size());
-        set.addAll(hamTokenCounts.keySet());
-        set.addAll(spamTokenCounts.keySet());
-        Map<String, Double> tempCorpus = new HashMap<String, 
Double>(set.size());
-
-        // Iterate through all the tokens and compute their new
-        // individual probabilities.
-        Iterator<String> i = set.iterator();
-        while (i.hasNext()) {
-            String token = i.next();
-            tempCorpus.put(token, new Double(computeProbability(token)));
-        }
-        setCorpus(tempCorpus);
-    }
-
-    /**
-     * Adds a message to the ham list.
-     * 
-     * @param stream
-     *            A reader stream on the ham message to analyze
-     * @throws IOException
-     *             If any error occurs
-     */
-    public void addHam(Reader stream) throws java.io.IOException {
-        addTokenOccurrences(stream, hamTokenCounts);
-        hamMessageCount++;
-    }
-
-    /**
-     * Adds a message to the spam list.
-     * 
-     * @param stream
-     *            A reader stream on the spam message to analyze
-     * @throws IOException
-     *             If any error occurs
-     */
-    public void addSpam(Reader stream) throws java.io.IOException {
-        addTokenOccurrences(stream, spamTokenCounts);
-        spamMessageCount++;
-    }
-
-    /**
-     * Computes the probability that the stream contains SPAM.
-     * 
-     * @param stream
-     *            The text to be analyzed for Spamminess.
-     * @return A 0.0 - 1.0 probability
-     * @throws IOException
-     *             If any error occurs
-     */
-    public double computeSpamProbability(Reader stream) throws 
java.io.IOException {
-        // Build a set of the tokens in the Stream.
-        Set<String> tokens = parse(stream);
-
-        // Get the corpus to use in this run
-        // A new corpus may be being built in the meantime
-        Map<String, Double> workCorpus = getCorpus();
-
-        // Assign their probabilities from the Corpus (using an additional
-        // calculation to determine spamminess).
-        SortedSet<TokenProbabilityStrength> tokenProbabilityStrengths = 
getTokenProbabilityStrengths(tokens, workCorpus);
-
-        // Compute and return the overall probability that the
-        // stream is SPAM.
-        return computeOverallProbability(tokenProbabilityStrengths, 
workCorpus);
-    }
-
-    /**
-     * Parses a stream into tokens, and updates the target Map with the
-     * token/counts.
-     * 
-     * @param stream
-     * @param target
-     */
-    private void addTokenOccurrences(Reader stream, Map<String, Integer> 
target) throws java.io.IOException {
-        String token;
-        String header = "";
-
-        // Update target with the tokens/count encountered.
         while ((token = nextToken(stream)) != null) {
             boolean endingLine = false;
             if (token.length() > 0 && token.charAt(token.length() - 1) == 
'\n') {
@@ -330,15 +54,7 @@ public class Tokenizer {
 
                 token = header + token;
 
-                Integer value = null;
-
-                if (target.containsKey(token)) {
-                    value = Integer.valueOf(((Integer) 
target.get(token)).intValue() + 1);
-                } else {
-                    value = Integer.valueOf(1);
-                }
-
-                target.put(token, value);
+                next(token);
             }
 
             if (endingLine) {
@@ -346,49 +62,22 @@ public class Tokenizer {
             }
         }
     }
-
+    
     /**
-     * Parses a stream into tokens, and returns a Set of the unique tokens
-     * encountered.
-     * 
-     * @param stream
-     * @return Set
+     * Process next token.
+     * @param token not null
      */
-    private Set<String> parse(Reader stream) throws java.io.IOException {
-        Set<String> tokens = new HashSet<String>();
-        String token;
-        String header = "";
+    protected abstract void next(String token);
 
-        // Build a Map of tokens encountered.
-        while ((token = nextToken(stream)) != null) {
-            boolean endingLine = false;
-            if (token.length() > 0 && token.charAt(token.length() - 1) == 
'\n') {
-                endingLine = true;
-                token = token.substring(0, token.length() - 1);
-            }
-
-            if (token.length() > 0 && header.length() + token.length() < 90 && 
!allDigits(token)) {
-                if (token.equals("From:") || token.equals("Return-Path:") || 
token.equals("Subject:") || token.equals("To:")) {
-                    header = token;
-                    if (!endingLine) {
-                        continue;
-                    }
-                }
-
-                token = header + token;
-
-                tokens.add(token);
-            }
-
-            if (endingLine) {
-                header = "";
+    private boolean allDigits(String s) {
+        for (int i = 0; i < s.length(); i++) {
+            if (!Character.isDigit(s.charAt(i))) {
+                return false;
             }
         }
-
-        // Return the unique set of tokens encountered.
-        return tokens;
+        return true;
     }
-
+    
     private String nextToken(Reader reader) throws java.io.IOException {
         StringBuffer token = new StringBuffer();
         int i;
@@ -459,208 +148,4 @@ public class Tokenizer {
             return null;
         }
     }
-
-    /**
-     * Compute the probability that "token" is SPAM.
-     * 
-     * @param token
-     * @return The probability that the token occurs within spam.
-     */
-    private double computeProbability(String token) {
-        double hamFactor = 0;
-        double spamFactor = 0;
-
-        boolean foundInHam = false;
-        boolean foundInSpam = false;
-
-        double minThreshold = 0.01;
-        double maxThreshold = 0.99;
-
-        if (hamTokenCounts.containsKey(token)) {
-            foundInHam = true;
-        }
-
-        if (spamTokenCounts.containsKey(token)) {
-            foundInSpam = true;
-        }
-
-        if (foundInHam) {
-            hamFactor = 2 * ((Integer) 
hamTokenCounts.get(token)).doubleValue();
-            if (!foundInSpam) {
-                minThreshold = (hamFactor > 20) ? 0.0001 : 0.0002;
-            }
-        }
-
-        if (foundInSpam) {
-            spamFactor = ((Integer) spamTokenCounts.get(token)).doubleValue();
-            if (!foundInHam) {
-                maxThreshold = (spamFactor > 10) ? 0.9999 : 0.9998;
-            }
-        }
-
-        if ((hamFactor + spamFactor) < 5) {
-            // This token hasn't been seen enough.
-            return 0.4;
-        }
-
-        double spamFreq = Math.min(1.0, spamFactor / spamMessageCount);
-        double hamFreq = Math.min(1.0, hamFactor / hamMessageCount);
-
-        return Math.max(minThreshold, Math.min(maxThreshold, (spamFreq / 
(hamFreq + spamFreq))));
-    }
-
-    /**
-     * Returns a SortedSet of TokenProbabilityStrength built from the Corpus 
and
-     * the tokens passed in the "tokens" Set. The ordering is from the highest
-     * strength to the lowest strength.
-     * 
-     * @param tokens
-     * @param workCorpus
-     * @return SortedSet of TokenProbabilityStrength objects.
-     */
-    private SortedSet<TokenProbabilityStrength> 
getTokenProbabilityStrengths(Set<String> tokens, Map<String, Double> 
workCorpus) {
-        // Convert to a SortedSet of token probability strengths.
-        SortedSet<TokenProbabilityStrength> tokenProbabilityStrengths = new 
TreeSet<TokenProbabilityStrength>();
-
-        Iterator<String> i = tokens.iterator();
-        while (i.hasNext()) {
-            TokenProbabilityStrength tps = new TokenProbabilityStrength();
-
-            tps.token = (String) i.next();
-
-            if (workCorpus.containsKey(tps.token)) {
-                tps.strength = Math.abs(0.5 - ((Double) 
workCorpus.get(tps.token)).doubleValue());
-            } else {
-                // This token has never been seen before,
-                // we'll give it initially the default probability.
-                Double corpusProbability = new 
Double(DEFAULT_TOKEN_PROBABILITY);
-                tps.strength = Math.abs(0.5 - DEFAULT_TOKEN_PROBABILITY);
-                boolean isTokenDegeneratedFound = false;
-
-                Collection<String> degeneratedTokens = 
buildDegenerated(tps.token);
-                Iterator<String> iDegenerated = degeneratedTokens.iterator();
-                String tokenDegenerated = null;
-                double strengthDegenerated;
-                while (iDegenerated.hasNext()) {
-                    tokenDegenerated = (String) iDegenerated.next();
-                    if (workCorpus.containsKey(tokenDegenerated)) {
-                        Double probabilityTemp = (Double) 
workCorpus.get(tokenDegenerated);
-                        strengthDegenerated = Math.abs(0.5 - 
probabilityTemp.doubleValue());
-                        if (strengthDegenerated > tps.strength) {
-                            isTokenDegeneratedFound = true;
-                            tps.strength = strengthDegenerated;
-                            corpusProbability = probabilityTemp;
-                        }
-                    }
-                }
-                // to reduce memory usage, put in the corpus only if the
-                // probability is different from (stronger than) the default
-                if (isTokenDegeneratedFound) {
-                    synchronized (workCorpus) {
-                        workCorpus.put(tps.token, corpusProbability);
-                    }
-                }
-            }
-
-            tokenProbabilityStrengths.add(tps);
-        }
-
-        return tokenProbabilityStrengths;
-    }
-
-    private Collection<String> buildDegenerated(String fullToken) {
-        ArrayList<String> tokens = new ArrayList<String>();
-        String header;
-        String token;
-        String tokenLower;
-
-        // look for a header string termination
-        int headerEnd = fullToken.indexOf(':');
-        if (headerEnd >= 0) {
-            header = fullToken.substring(0, headerEnd);
-            token = fullToken.substring(headerEnd);
-        } else {
-            header = "";
-            token = fullToken;
-        }
-
-        // prepare a version of the token containing all lower case (for
-        // performance reasons)
-        tokenLower = token.toLowerCase();
-
-        int end = token.length();
-        do {
-            if (!token.substring(0, end).equals(tokenLower.substring(0, end))) 
{
-                tokens.add(header + tokenLower.substring(0, end));
-                if (header.length() > 0) {
-                    tokens.add(tokenLower.substring(0, end));
-                }
-            }
-            if (end > 1 && token.charAt(0) >= 'A' && token.charAt(0) <= 'Z') {
-                tokens.add(header + token.charAt(0) + tokenLower.substring(1, 
end));
-                if (header.length() > 0) {
-                    tokens.add(token.charAt(0) + tokenLower.substring(1, end));
-                }
-            }
-
-            if (token.charAt(end - 1) != '!') {
-                break;
-            }
-
-            end--;
-
-            tokens.add(header + token.substring(0, end));
-            if (header.length() > 0) {
-                tokens.add(token.substring(0, end));
-            }
-        } while (end > 0);
-
-        return tokens;
-    }
-
-    /**
-     * Compute the spamminess probability of the interesting tokens in the
-     * tokenProbabilities SortedSet.
-     * 
-     * @param tokenProbabilityStrengths
-     * @param workCorpus
-     * @return Computed spamminess.
-     */
-    private double 
computeOverallProbability(SortedSet<TokenProbabilityStrength> 
tokenProbabilityStrengths, Map<String, Double> workCorpus) {
-        double p = 1.0;
-        double np = 1.0;
-        double tempStrength = 0.5;
-        int count = MAX_INTERESTING_TOKENS;
-        Iterator<TokenProbabilityStrength> iterator = 
tokenProbabilityStrengths.iterator();
-        while ((iterator.hasNext()) && (count-- > 0 || tempStrength >= 
INTERESTINGNESS_THRESHOLD)) {
-            TokenProbabilityStrength tps = iterator.next();
-            tempStrength = tps.strength;
-
-            // System.out.println(tps);
-
-            double theDoubleValue = DEFAULT_TOKEN_PROBABILITY; // initialize it
-                                                               // to the 
default
-            Double theDoubleObject = (Double) workCorpus.get(tps.token);
-            // if either the original token or a degeneration was found use the
-            // double value, otherwise use the default
-            if (theDoubleObject != null) {
-                theDoubleValue = theDoubleObject.doubleValue();
-            }
-            p *= theDoubleValue;
-            np *= (1.0 - theDoubleValue);
-            // System.out.println("Token " + tps + ", p=" + theDoubleValue +
-            // ", overall p=" + p / (p + np));
-        }
-
-        return (p / (p + np));
-    }
-
-    private boolean allDigits(String s) {
-        for (int i = 0; i < s.length(); i++) {
-            if (!Character.isDigit(s.charAt(i))) {
-                return false;
-            }
-        }
-        return true;
-    }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to