Author: gsingers
Date: Sat Nov 29 20:04:54 2008
New Revision: 721756

URL: http://svn.apache.org/viewvc?rev=721756&view=rev
Log:
MAHOUT-79: fix fuzzy K Means combiner usage

Added:
    
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansUtil.java
   (with props)
Modified:
    
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansClusterMapper.java
    
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansCombiner.java
    
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansDriver.java
    
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansJob.java
    
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansMapper.java
    
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansReducer.java
    
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/SoftCluster.java
    
lucene/mahout/trunk/core/src/test/java/org/apache/mahout/clustering/fuzzykmeans/TestFuzzyKmeansClustering.java

Modified: 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansClusterMapper.java
URL: 
http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansClusterMapper.java?rev=721756&r1=721755&r2=721756&view=diff
==============================================================================
--- 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansClusterMapper.java
 (original)
+++ 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansClusterMapper.java
 Sat Nov 29 20:04:54 2008
@@ -28,10 +28,9 @@
 
 public class FuzzyKMeansClusterMapper extends FuzzyKMeansMapper {
   public void map(WritableComparable key, Text values,
-      OutputCollector<Text, Text> output, Reporter reporter) throws 
IOException {
+      OutputCollector<Text, Text> output, Reporter reporter) throws IOException
+  {
     Vector point = AbstractVector.decodeVector(values.toString());
-    SoftCluster.outputPointWithClusterProbabilities(point, clusters, values,
-        output);
-  }
-
+    SoftCluster.outputPointWithClusterProbabilities(key.toString(), point, 
clusters, values, output);
+  }  
 }

Modified: 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansCombiner.java
URL: 
http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansCombiner.java?rev=721756&r1=721755&r2=721756&view=diff
==============================================================================
--- 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansCombiner.java
 (original)
+++ 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansCombiner.java
 Sat Nov 29 20:04:54 2008
@@ -27,22 +27,41 @@
 import org.apache.hadoop.mapred.Reducer;
 import org.apache.hadoop.mapred.Reporter;
 import org.apache.mahout.matrix.AbstractVector;
+import org.apache.mahout.matrix.Vector;
 
 public class FuzzyKMeansCombiner extends MapReduceBase implements
     Reducer<Text, Text, Text, Text> {
 
   public void reduce(Text key, Iterator<Text> values,
       OutputCollector<Text, Text> output, Reporter reporter) throws 
IOException {
-    SoftCluster cluster = SoftCluster.decodeCluster(key.toString());
+    SoftCluster cluster = new SoftCluster(key.toString().trim());
     while (values.hasNext()) {
       String pointInfo = values.next().toString();
-      double pointProb = Double.parseDouble(pointInfo.substring(0, 
pointInfo.indexOf(':')));
+      // check whether this is already processed
+      int mapperSepIndex = pointInfo
+          .indexOf(FuzzyKMeansDriver.MAPPER_VALUE_SEPARATOR); // ~ separator is
+      // used in mapper
+      int combinerSepIndex = pointInfo
+          .indexOf(FuzzyKMeansDriver.COMBINER_VALUE_SEPARATOR); // tab 
separator
+      // is used in
+      // combiner
+      int index = mapperSepIndex == -1 ? combinerSepIndex : mapperSepIndex;// 
needed
+      // to
+      // split
+      // prob and vector
+      double pointProb = Double.parseDouble(pointInfo.substring(0, index));
 
-      String encodedVector = pointInfo.substring(pointInfo.indexOf(':') + 1);
-      cluster.addPoint(AbstractVector.decodeVector(encodedVector), pointProb
-          * SoftCluster.getM());
+      String encodedVector = pointInfo.substring(index + 1);
+      Vector v = AbstractVector.decodeVector(encodedVector);
+      if (mapperSepIndex != -1) // first time thru combiner
+      {
+        cluster.addPoint(v, Math.pow(pointProb, SoftCluster.getM()));
+      } else {
+        cluster.addPoints(v, pointProb);
+      }
     }
-    output.collect(key, new Text(cluster.getPointProbSum() + ", "
+    output.collect(key, new Text(cluster.getPointProbSum()
+        + FuzzyKMeansDriver.COMBINER_VALUE_SEPARATOR
         + cluster.getWeightedPointTotal().asFormatString()));
   }
 

Modified: 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansDriver.java
URL: 
http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansDriver.java?rev=721756&r1=721755&r2=721756&view=diff
==============================================================================
--- 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansDriver.java
 (original)
+++ 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansDriver.java
 Sat Nov 29 20:04:54 2008
@@ -27,33 +27,60 @@
 import org.apache.hadoop.fs.FileUtil;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.fs.PathFilter;
-import org.apache.hadoop.io.SequenceFile;
 import org.apache.hadoop.io.Text;
 import org.apache.hadoop.mapred.FileInputFormat;
 import org.apache.hadoop.mapred.FileOutputFormat;
+import org.apache.hadoop.mapred.FileSplit;
 import org.apache.hadoop.mapred.JobClient;
 import org.apache.hadoop.mapred.JobConf;
+import org.apache.hadoop.mapred.KeyValueLineRecordReader;
 import org.apache.hadoop.mapred.SequenceFileOutputFormat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class FuzzyKMeansDriver {
 
-  private static final Logger log = 
LoggerFactory.getLogger(FuzzyKMeansDriver.class);
+  private static final Logger log = LoggerFactory
+      .getLogger(FuzzyKMeansDriver.class);
+
+  public static final String MAPPER_VALUE_SEPARATOR = "~";
+
+  public static final String COMBINER_VALUE_SEPARATOR = "\t";
 
   private FuzzyKMeansDriver() {
   }
 
+  private static void printMessage() {
+    System.out
+        .println("Usage: input clusterIn output measureClass convergenceDelta 
maxIterations m [doClusteringOnly]");
+  }
+
   public static void main(String[] args) {
-    String input = args[0];
-    String clusters = args[1];
-    String output = args[2];
-    String measureClass = args[3];
-    double convergenceDelta = Double.parseDouble(args[4]);
-    int maxIterations = Integer.parseInt(args[5]);
-    int m = Integer.parseInt(args[6]);
-    runJob(input, clusters, output, measureClass, convergenceDelta,
-        maxIterations, 10,m);
+    if (args.length < 7) {
+      System.out.println("Expected number of arguments: 7 or 8 : received:"
+          + args.length);
+      printMessage();
+    }
+    int index = 0;
+    String input = args[index++];
+    String clusters = args[index++];
+    String output = args[index++];
+    String measureClass = args[index++];
+    double convergenceDelta = Double.parseDouble(args[index++]);
+    int maxIterations = new Integer(args[index++]);
+    float m = Float.parseFloat(args[index++]);
+    boolean doClustering = false;
+    if (args.length > 7)
+      doClustering = Boolean.parseBoolean(args[index++]);
+    if (doClustering) {
+      runClustering(input, clusters, output, measureClass, Double
+          .toString(convergenceDelta), 500, m);
+    } else {
+      runJob(input, clusters, output, measureClass, convergenceDelta,
+          maxIterations, 10, 10, m);
+
+    }
+
   }
 
   /**
@@ -69,7 +96,7 @@
    */
   public static void runJob(String input, String clustersIn, String output,
       String measureClass, double convergenceDelta, int maxIterations,
-      int numMapTasks, int m) {
+      int numMapTasks, int numReduceTasks, float m) {
 
     boolean converged = false;
     int iteration = 0;
@@ -82,7 +109,7 @@
       // point the output to a new directory per iteration
       String clustersOut = output + File.separator + "clusters-" + iteration;
       converged = runIteration(input, clustersIn, clustersOut, measureClass,
-          delta, numMapTasks, iteration, m);
+          delta, numMapTasks, numReduceTasks, iteration, m);
 
       // now point the input to the old output directory
       clustersIn = output + File.separator + "clusters-" + iteration;
@@ -110,8 +137,8 @@
    * @return true if the iteration successfully runs
    */
   private static boolean runIteration(String input, String clustersIn,
-                                      String clustersOut, String measureClass, 
String convergenceDelta,
-                                      int numMapTasks, int iterationNumber, 
int m) {
+      String clustersOut, String measureClass, String convergenceDelta,
+      int numMapTasks, int numReduceTasks, int iterationNumber, float m) {
 
     JobConf conf = new JobConf(FuzzyKMeansJob.class);
     conf.setJobName("Fuzzy K Means{" + iterationNumber + "}");
@@ -127,14 +154,16 @@
     conf.setCombinerClass(FuzzyKMeansCombiner.class);
     conf.setReducerClass(FuzzyKMeansReducer.class);
     conf.setNumMapTasks(numMapTasks);
-    conf.setNumReduceTasks(numMapTasks);
-
-    conf.setOutputFormat(SequenceFileOutputFormat.class);
+    conf.setNumReduceTasks(numReduceTasks);
+    
     conf.set(SoftCluster.CLUSTER_PATH_KEY, clustersIn);
     conf.set(SoftCluster.DISTANCE_MEASURE_KEY, measureClass);
     conf.set(SoftCluster.CLUSTER_CONVERGENCE_KEY, convergenceDelta);
     conf.set(SoftCluster.M_KEY, String.valueOf(m));
 
+    // uncomment it to run locally
+    // conf.set("mapred.job.tracker", "local");
+
     try {
       JobClient.runJob(conf);
       FileSystem fs = FileSystem.get(conf);
@@ -157,7 +186,7 @@
    */
   private static void runClustering(String input, String clustersIn,
       String output, String measureClass, String convergenceDelta,
-      int numMapTasks, double m) {
+      int numMapTasks, float m) {
 
     JobConf conf = new JobConf(FuzzyKMeansDriver.class);
     conf.setJobName("Fuzzy K Means Clustering");
@@ -216,12 +245,21 @@
     boolean converged = true;
 
     for (Path p : result) {
-      SequenceFile.Reader reader = new SequenceFile.Reader(fs, p, conf);
-      Text key = new Text();
-      Text value = new Text();
 
-      while (converged && reader.next(key, value)) {
-        converged = value.toString().startsWith("V");
+      KeyValueLineRecordReader reader = null;
+
+      try {
+        reader = new KeyValueLineRecordReader(conf, new FileSplit(p, 0, fs
+            .getFileStatus(p).getLen(), (String[]) null));
+        Text key = new Text();
+        Text value = new Text();
+        while (converged && reader.next(key, value)) {
+          converged = value.toString().startsWith("V");
+        }
+      } finally {
+        if (reader != null) {
+          reader.close();
+        }
       }
     }
 

Modified: 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansJob.java
URL: 
http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansJob.java?rev=721756&r1=721755&r2=721756&view=diff
==============================================================================
--- 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansJob.java
 (original)
+++ 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansJob.java
 Sat Nov 29 20:04:54 2008
@@ -26,12 +26,13 @@
 
 public class FuzzyKMeansJob {
 
-  private static final Logger log = 
LoggerFactory.getLogger(FuzzyKMeansJob.class);
+  private static final Logger log = LoggerFactory
+      .getLogger(FuzzyKMeansJob.class);
 
   public static void main(String[] args) throws IOException {
 
-    if (args.length != 9) {
-      log.warn("Expected num Arguments: 9  received: {}", args.length);
+    if (args.length != 10) {
+      log.warn("Expected num Arguments: 10  received: {}", args.length);
       printMessage();
       return;
     }
@@ -39,23 +40,24 @@
     String input = args[index++];
     String clusters = args[index++];
     String output = args[index++];
-     String measureClass = args[index++];
+    String measureClass = args[index++];
     double convergenceDelta = Double.parseDouble(args[index++]);
     int maxIterations = Integer.parseInt(args[index++]);
     int numMapTasks = Integer.parseInt(args[index++]);
+    int numReduceTasks = Integer.parseInt(args[index++]);
     boolean doCanopy = Boolean.parseBoolean(args[index++]);
-    int m = Integer.parseInt(args[index++]);
+    float m = Float.parseFloat(args[index++]);
 
-    runJob(input, clusters, output,
-        measureClass, convergenceDelta,
-        maxIterations, numMapTasks, doCanopy,m);
+    runJob(input, clusters, output, measureClass, convergenceDelta,
+        maxIterations, numMapTasks, numReduceTasks, doCanopy, m);
   }
 
   /**
    * Prints Error Message
    */
   private static void printMessage() {
-    log.warn("Usage: inputDir clusterDir OutputDir ConvergenceDelata  
maxIterations numMapTasks doCanopy");
+    log
+        .warn("Usage: inputDir clusterDir OutputDir measureClass 
ConvergenceDelata  maxIterations numMapTasks numReduceTasks doCanopy m");
   }
 
   /**
@@ -73,7 +75,8 @@
    */
   public static void runJob(String input, String clustersIn, String output,
       String measureClass, double convergenceDelta, int maxIterations,
-      int numMapTasks, boolean doCanopy, int m) throws IOException {
+      int numMapTasks, int numReduceTasks, boolean doCanopy, float m)
+      throws IOException {
 
     // run canopy to find initial clusters
     if (doCanopy) {
@@ -83,7 +86,7 @@
     }
     // run fuzzy k -means
     FuzzyKMeansDriver.runJob(input, clustersIn, output, measureClass,
-        convergenceDelta, maxIterations, numMapTasks,m);
+        convergenceDelta, maxIterations, numMapTasks, numReduceTasks, m);
 
   }
 }

Modified: 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansMapper.java
URL: 
http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansMapper.java?rev=721756&r1=721755&r2=721756&view=diff
==============================================================================
--- 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansMapper.java
 (original)
+++ 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansMapper.java
 Sat Nov 29 20:04:54 2008
@@ -21,12 +21,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.hadoop.fs.FileStatus;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.FileUtil;
-import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.fs.PathFilter;
-import org.apache.hadoop.io.SequenceFile;
 import org.apache.hadoop.io.Text;
 import org.apache.hadoop.io.WritableComparable;
 import org.apache.hadoop.mapred.JobConf;
@@ -62,6 +56,11 @@
     this.clusters = clusters;
   }
 
+  /*
+   * (non-Javadoc)
+   * 
+   * @see 
org.apache.hadoop.mapred.MapReduceBase#configure(org.apache.hadoop.mapred.JobConf)
+   */
   @Override
   public void configure(JobConf job) {
 
@@ -71,62 +70,11 @@
     log.info("In Mapper Configure:");
     clusters = new ArrayList<SoftCluster>();
 
-    configureWithClusterInfo(job);
+    FuzzyKMeansUtil.configureWithClusterInfo(job
+        .get(SoftCluster.CLUSTER_PATH_KEY), clusters);
 
     if (clusters.size() == 0)
       throw new NullPointerException("Cluster is empty!!!");
   }
 
-  /**
-   * Configure the mapper with the cluster info
-   * 
-   * @param job
-   */
-  protected void configureWithClusterInfo(JobConf job) {
-    // Get the path location where the cluster Info is stored
-    String clusterPathStr = job.get(SoftCluster.CLUSTER_PATH_KEY);
-    Path clusterPath = new Path(clusterPathStr);
-    List<Path> result = new ArrayList<Path>();
-
-    // filter out the files
-    PathFilter clusterFileFilter = new PathFilter() {
-      public boolean accept(Path path) {
-        return path.getName().startsWith("part");
-      }
-    };
-
-    try {
-      // get all filtered file names in result list
-      FileSystem fs = clusterPath.getFileSystem(job);
-      FileStatus[] matches = fs.listStatus(FileUtil.stat2Paths(fs.globStatus(
-          clusterPath, clusterFileFilter)), clusterFileFilter);
-
-      for (FileStatus match : matches) {
-        result.add(fs.makeQualified(match.getPath()));
-      }
-
-      // iterate thru the result path list
-      for (Path path : result) {
-        SequenceFile.Reader reader = new SequenceFile.Reader(fs, path, job);
-        try {
-          Text key = new Text();
-          Text value = new Text();
-          //int counter = 1;
-          while (reader.next(key, value)) {
-            // get the cluster info
-            SoftCluster cluster = SoftCluster.decodeCluster(value.toString());
-            // add the center so the centroid will be correct on output
-            // formatting
-            cluster.addPoint(cluster.getCenter(), 1);
-            clusters.add(cluster);
-          }
-        } finally {
-          reader.close();
-        }
-      }
-
-    } catch (IOException e) {
-      throw new RuntimeException(e);
-    }
-  }
 }

Modified: 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansReducer.java
URL: 
http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansReducer.java?rev=721756&r1=721755&r2=721756&view=diff
==============================================================================
--- 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansReducer.java
 (original)
+++ 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansReducer.java
 Sat Nov 29 20:04:54 2008
@@ -18,7 +18,11 @@
 package org.apache.mahout.clustering.fuzzykmeans;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.hadoop.io.Text;
 import org.apache.hadoop.mapred.JobConf;
@@ -34,39 +38,79 @@
 public class FuzzyKMeansReducer extends MapReduceBase implements
     Reducer<Text, Text, Text, Text> {
 
-  private static final Logger log = 
LoggerFactory.getLogger(FuzzyKMeansReducer.class);
+  private static final Logger log = LoggerFactory
+      .getLogger(FuzzyKMeansReducer.class);
+
+  protected Map<String, SoftCluster> clusterMap;
 
   public void reduce(Text key, Iterator<Text> values,
       OutputCollector<Text, Text> output, Reporter reporter) throws 
IOException {
-    SoftCluster cluster = SoftCluster.decodeCluster(key.toString());
-    while (values.hasNext()) {
-      String value = values.next().toString();
 
-      int ix = value.indexOf(',');
-      try {
-        double partialSumPtProb = Double.parseDouble(value.substring(0, ix));
-        Vector total = AbstractVector.decodeVector(value.substring(ix + 2));
-        cluster.addPoints(partialSumPtProb, total);
-      } catch (RuntimeException e) {
-        // TODO srowen thinks this should be replaced with a more specific 
catch, or not use exceptions to control flow
-        // Escaped from Combiner. So, let's do that processing too:
-        log.info("Escaped from combiner: Key: {} Value: {}", key, value);
-        double pointProb = Double.parseDouble(value.substring(0, 
value.indexOf(':')));
+    SoftCluster cluster = clusterMap.get(key.toString());
 
-        String encodedVector = value.substring(value.indexOf(':') + 1);
-        cluster.addPoint(AbstractVector.decodeVector(encodedVector), pointProb 
* SoftCluster.getM());
+    while (values.hasNext()) {
+      String value = values.next().toString();
+      int mapperSepIndex = value
+          .indexOf(FuzzyKMeansDriver.MAPPER_VALUE_SEPARATOR); // tild separator
+      // is used in
+      // mapper
+      int combinerSepIndex = value
+          .indexOf(FuzzyKMeansDriver.COMBINER_VALUE_SEPARATOR); // tab 
separator
+      // is used in
+      // combiner
+      int index = mapperSepIndex == -1 ? combinerSepIndex : mapperSepIndex;// 
needed
+      // to
+      // split
+      // prob and vector
+      double partialSumPtProb = new Double(value.substring(0, index));
+      Vector total = AbstractVector.decodeVector(value.substring(index + 1));
+      if (mapperSepIndex != -1) // escaped from combiner
+      {
+        cluster.addPoint(total, Math.pow(partialSumPtProb, 
SoftCluster.getM()));
+      } else {
+        cluster.addPoints(total, partialSumPtProb);
       }
-    }
 
+    }
     // force convergence calculation
     cluster.computeConvergence();
-    output.collect(new Text(cluster.getIdentifier()), new 
Text(SoftCluster.formatCluster(cluster)));
+    output.collect(new Text(cluster.getIdentifier()), new Text(SoftCluster
+        .formatCluster(cluster)));
   }
 
+  /*
+   * (non-Javadoc)
+   * 
+   * @see 
org.apache.hadoop.mapred.MapReduceBase#configure(org.apache.hadoop.mapred.JobConf)
+   */
   @Override
   public void configure(JobConf job) {
+
     super.configure(job);
     SoftCluster.configure(job);
+    clusterMap = new HashMap<String, SoftCluster>();
+
+    List<SoftCluster> clusters = new ArrayList<SoftCluster>();
+    FuzzyKMeansUtil.configureWithClusterInfo(job
+        .get(SoftCluster.CLUSTER_PATH_KEY), clusters);
+    setClusterMap(clusters);
+
+    if (clusterMap.size() == 0)
+      throw new NullPointerException("Cluster is empty!!!");
+  }
+
+  private void setClusterMap(List<SoftCluster> clusters) {
+    clusterMap = new HashMap<String, SoftCluster>();
+    for (SoftCluster cluster : clusters) {
+      clusterMap.put(cluster.getIdentifier(), cluster);
+    }
+    clusters.clear();
+    clusters = null;
+  }
+
+  public void config(List<SoftCluster> clusters) {
+    setClusterMap(clusters);
+
   }
 
 }

Added: 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansUtil.java
URL: 
http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansUtil.java?rev=721756&view=auto
==============================================================================
--- 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansUtil.java
 (added)
+++ 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansUtil.java
 Sat Nov 29 20:04:54 2008
@@ -0,0 +1,102 @@
+package org.apache.mahout.clustering.fuzzykmeans;
+/**
+ * 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.
+ */
+
+
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.FileUtil;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.PathFilter;
+import org.apache.hadoop.io.Text;
+import org.apache.hadoop.mapred.FileSplit;
+import org.apache.hadoop.mapred.JobConf;
+import org.apache.hadoop.mapred.KeyValueLineRecordReader;
+import org.apache.hadoop.mapred.RecordReader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FuzzyKMeansUtil {
+  private static final Logger log = 
LoggerFactory.getLogger(FuzzyKMeansUtil.class);
+
+  /**
+   * Configure the mapper with the cluster info
+   *
+   * @param clusterPathStr
+   * @param clusters
+   */
+  public static void configureWithClusterInfo(String clusterPathStr, 
List<SoftCluster> clusters) {
+    //Get the path location where the cluster Info is stored
+    JobConf job = new JobConf(FuzzyKMeansUtil.class);
+    Path clusterPath = new Path(clusterPathStr);
+    List<Path> result = new ArrayList<Path>();
+//    log.info("I am here");
+    //filter out the files
+    PathFilter clusterFileFilter = new PathFilter() {
+      public boolean accept(Path path) {
+        return path.getName().startsWith("part");
+      }
+    };
+
+    try {
+      //get all filtered file names in result list
+      FileSystem fs = clusterPath.getFileSystem(job);
+      FileStatus[] matches = fs.listStatus(FileUtil.stat2Paths(fs.globStatus(
+              clusterPath, clusterFileFilter)), clusterFileFilter);
+
+      for (FileStatus match : matches) {
+        result.add(fs.makeQualified(match.getPath()));
+      }
+
+      //iterate thru the result path list
+      for (Path path : result) {
+        RecordReader<Text, Text> recordReader = null;
+//        SequenceFile.Reader reader = new SequenceFile.Reader(fs, path, job);
+        try {
+          recordReader = new KeyValueLineRecordReader(job, new FileSplit(path, 
0, fs.getFileStatus(path).getLen(), (String[]) null));
+          Text key = new Text();
+          Text value = new Text();
+          int counter = 1;
+          while (recordReader.next(key, value)) {
+            //get the cluster info
+            SoftCluster cluster = SoftCluster.decodeCluster(value.toString());
+            // add the center so the centroid will be correct on output
+            // formatting
+//            cluster.addPoint(cluster.getCenter(), 1);
+            clusters.add(cluster);
+          }
+        } finally {
+          if (recordReader != null) {
+            recordReader.close();
+          }
+
+        }
+      }
+
+    } catch (IOException e) {
+      log.info("Exception occurred in loading clusters:", e);
+      e.printStackTrace();
+      throw new RuntimeException(e);
+    }
+  }
+
+
+}
\ No newline at end of file

Propchange: 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/FuzzyKMeansUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/SoftCluster.java
URL: 
http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/SoftCluster.java?rev=721756&r1=721755&r2=721756&view=diff
==============================================================================
--- 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/SoftCluster.java
 (original)
+++ 
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/clustering/fuzzykmeans/SoftCluster.java
 Sat Nov 29 20:04:54 2008
@@ -39,8 +39,10 @@
 
   public static final String M_KEY = 
"org.apache.mahout.clustering.fuzzykmeans.m";
 
-  private static double m = 2.0; //default value
-  public static final double MINIMAL_VALUE = 0.0000000001; // using it for 
adding
+  private static double m = 2.0; // default value
+
+  public static final double MINIMAL_VALUE = 0.0000000001; // using it for
+                                                            // adding
 
   // exception
   // this value to any
@@ -69,6 +71,7 @@
   private boolean converged = false;
 
   private static DistanceMeasure measure;
+
   private static double convergenceDelta = 0;
 
   /**
@@ -93,8 +96,9 @@
     String id = formattedString.substring(0, beginIndex);
     String center = formattedString.substring(beginIndex);
     if (id.startsWith("C") || id.startsWith("V")) {
-      int clusterId = Integer.parseInt(formattedString.substring(1, beginIndex 
- 2));
-      Vector clusterCenter = AbstractVector.decodeVector(center);
+      int clusterId = new Integer(formattedString.substring(1, beginIndex - 
2));
+      Vector clusterCenter = null;
+      clusterCenter = AbstractVector.decodeVector(center);
 
       SoftCluster cluster = new SoftCluster(clusterCenter, clusterId);
       cluster.converged = id.startsWith("V");
@@ -153,15 +157,18 @@
       OutputCollector<Text, Text> output) throws IOException {
     List<Double> clusterDistanceList = new ArrayList<Double>();
     for (SoftCluster cluster : clusters) {
-      clusterDistanceList.add(measure.distance(point, cluster.getCenter()));
+      clusterDistanceList.add(measure.distance(cluster.getCenter(), point));
     }
 
     for (int i = 0; i < clusters.size(); i++) {
       double probWeight = computeProbWeight(clusterDistanceList.get(i),
           clusterDistanceList);
-
-      Text key = new Text(formatCluster(clusters.get(i)));
-      Text value = new Text(probWeight + ":" + values);
+      Text key = new Text(clusters.get(i).getIdentifier()); // just output the
+                                                            // 
identifier,avoids
+                                                            // too much data
+                                                            // traffic
+      Text value = new Text(Double.toString(probWeight)
+          + FuzzyKMeansDriver.MAPPER_VALUE_SEPARATOR + values.toString());
       output.collect(key, value);
     }
   }
@@ -176,8 +183,8 @@
    * @param output the OutputCollector to emit into
    * @throws IOException
    */
-  public static void outputPointWithClusterProbabilities(Vector point,
-      List<SoftCluster> clusters, Text values,
+  public static void outputPointWithClusterProbabilities(String key,
+      Vector point, List<SoftCluster> clusters, Text values,
       OutputCollector<Text, Text> output) throws IOException {
 
     String outputKey = values.toString();
@@ -189,10 +196,12 @@
     }
 
     for (int i = 0; i < clusters.size(); i++) {
+      // System.out.print("cluster:" + i + "\t" + clusterDistanceList.get(i));
+
       double probWeight = computeProbWeight(clusterDistanceList.get(i),
           clusterDistanceList);
-      outputValue.append(clusters.get(i).clusterId).append(':').append(
-          probWeight).append(' ');
+      outputValue.append(clusters.get(i).clusterId).append(":").append(
+          probWeight).append(" ");
     }
     output.collect(new Text(outputKey.trim()), new Text(outputValue.toString()
         .trim()
@@ -209,17 +218,18 @@
   public static double computeProbWeight(double clusterDistance,
       List<Double> clusterDistanceList) {
     double denom = 0.0;
-    if (clusterDistance == 0.0) {
+    if (clusterDistance == 0) {
       clusterDistance = MINIMAL_VALUE;
     }
-    for (double eachCDist : clusterDistanceList) {
+    for (Double eachCDist : clusterDistanceList) {
       if (eachCDist == 0)
         eachCDist = MINIMAL_VALUE;
 
       denom += Math.pow(clusterDistance / eachCDist, (double) 2 / (m - 1));
 
     }
-    return 1.0 / denom;
+    double val = (double) (1) / denom;
+    return val;
   }
 
   /**
@@ -264,6 +274,19 @@
     this.weightedPointTotal = center.like();
   }
 
+  /**
+   * Construct a new softcluster with the given clusterID
+   * 
+   * @param clusterId
+   */
+  public SoftCluster(String clusterId) {
+
+    this.clusterId = Integer.parseInt((clusterId.substring(1)));
+    this.pointProbSum = 0;
+    // this.weightedPointTotal = center.like();
+    this.converged = clusterId.startsWith("V");
+  }
+
   @Override
   public String toString() {
     return getIdentifier() + " - " + center.asFormatString();
@@ -288,22 +311,22 @@
     if (weightedPointTotal == null)
       weightedPointTotal = point.copy().times(ptProb);
     else
-      weightedPointTotal = point.times(ptProb).plus(weightedPointTotal);
+      weightedPointTotal = weightedPointTotal.plus(point.times(ptProb));
   }
 
   /**
-   * Add the point to the SoftCluster
-   *
-   * @param partialSumPtProb
+   * Add the point to the cluster
+   * 
+   * @param count the number of points in the delta
    * @param delta a point to add
    */
-  public void addPoints(double partialSumPtProb, Vector delta) {
+  public void addPoints(Vector delta, double partialSumPtProb) {
     centroid = null;
     pointProbSum += partialSumPtProb;
     if (weightedPointTotal == null)
       weightedPointTotal = delta.copy();
     else
-      weightedPointTotal = delta.plus(weightedPointTotal);
+      weightedPointTotal = weightedPointTotal.plus(delta);
   }
 
   public Vector getCenter() {
@@ -330,7 +353,7 @@
    */
   public boolean computeConvergence() {
     Vector centroid = computeCentroid();
-    converged = measure.distance(centroid, center) <= convergenceDelta;
+    converged = measure.distance(center, centroid) <= convergenceDelta;
     return converged;
   }
 
@@ -338,10 +361,18 @@
     return weightedPointTotal;
   }
 
+  public void setWeightedPointTotal(Vector v) {
+    this.weightedPointTotal = v;
+  }
+
   public boolean isConverged() {
     return converged;
   }
 
+  public static void main(String[] args) {
+
+  }
+
   public int getClusterId() {
     return clusterId;
   }

Modified: 
lucene/mahout/trunk/core/src/test/java/org/apache/mahout/clustering/fuzzykmeans/TestFuzzyKmeansClustering.java
URL: 
http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/clustering/fuzzykmeans/TestFuzzyKmeansClustering.java?rev=721756&r1=721755&r2=721756&view=diff
==============================================================================
--- 
lucene/mahout/trunk/core/src/test/java/org/apache/mahout/clustering/fuzzykmeans/TestFuzzyKmeansClustering.java
 (original)
+++ 
lucene/mahout/trunk/core/src/test/java/org/apache/mahout/clustering/fuzzykmeans/TestFuzzyKmeansClustering.java
 Sat Nov 29 20:04:54 2008
@@ -18,20 +18,22 @@
 package org.apache.mahout.clustering.fuzzykmeans;
 
 import java.io.BufferedReader;
+import java.io.BufferedWriter;
 import java.io.File;
-import java.io.InputStreamReader;
 import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.nio.charset.Charset;
 
 import junit.framework.TestCase;
 
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.io.SequenceFile;
 import org.apache.hadoop.io.Text;
 import org.apache.hadoop.mapred.JobConf;
 import org.apache.mahout.clustering.kmeans.TestKmeansClustering;
@@ -89,16 +91,16 @@
 
     DistanceMeasure measure = (DistanceMeasure) cl.newInstance();
     SoftCluster.config(measure, threshold);
-    //boolean converged = false;
-    //for (int iter = 0; !converged && iter < numIter; iter++) {
-    for (int iter = 0; iter < numIter; iter++) {
-      iterateReference(points, clusterList, measure);
+    boolean converged = false;
+    for (int iter = 0; !converged && iter < numIter; iter++) {
+      converged = iterateReference(points, clusterList, measure);
     }
     computeCluster(points, clusterList, measure, pointClusterInfo);
   }
 
-  public void iterateReference(List<Vector> points,
+  public boolean iterateReference(List<Vector> points,
       List<SoftCluster> clusterList, DistanceMeasure measure) {
+    boolean converged = true;
     // for each
     for (Vector point : points) {
       List<Double> clusterDistanceList = new ArrayList<Double>();
@@ -109,13 +111,20 @@
       for (int i = 0; i < clusterList.size(); i++) {
         double probWeight = SoftCluster.computeProbWeight(clusterDistanceList
             .get(i), clusterDistanceList);
-        clusterList.get(i).addPoint(point, probWeight * SoftCluster.getM());
+        clusterList.get(i).addPoint(point,
+            Math.pow(probWeight, SoftCluster.getM()));
       }
     }
     for (SoftCluster cluster : clusterList) {
-      cluster.computeConvergence();
-      cluster.recomputeCenter();
+      if (!cluster.computeConvergence())
+        converged = false;
     }
+    // update the cluster centers
+    if (!converged)
+      for (SoftCluster cluster : clusterList)
+        cluster.recomputeCenter();
+    return converged;
+
   }
 
   public void computeCluster(List<Vector> points,
@@ -200,18 +209,30 @@
       // pick k initial cluster centers at random
       JobConf job = new JobConf(FuzzyKMeansDriver.class);
       FileSystem fs = FileSystem.get(job);
-      Path path = new Path("testdata/clusters/part-00000");
-      SequenceFile.Writer writer = new SequenceFile.Writer(fs, job, path,
-          Text.class, Text.class);
+      Path path = new Path("testdata/clusters");
+      if (fs.exists(path)) {
+        fs.delete(path, true);
+      }
+
+      testData = new File("testdata/clusters");
+      if (!testData.exists())
+        testData.mkdir();
+
+      BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
+          new FileOutputStream("testdata/clusters/part-00000"), Charset
+              .forName("UTF-8")));
+
       for (int i = 0; i < k + 1; i++) {
         Vector vec = tweakValue(points.get(i));
 
         SoftCluster cluster = new SoftCluster(vec);
         // add the center so the centroid will be correct upon output
         cluster.addPoint(cluster.getCenter(), 1);
-        writer.append(new Text(cluster.getIdentifier()), new Text(SoftCluster
-            .formatCluster(cluster)));
+        writer.write(cluster.getIdentifier() + "\t"
+            + SoftCluster.formatCluster(cluster) + "\n");
+
       }
+      writer.flush();
       writer.close();
 
       JobConf conf = new JobConf(FuzzyKMeansDriver.class);
@@ -221,24 +242,26 @@
         fs.delete(outPath, true);
       }
       fs.mkdirs(outPath);
-      // now run the Job
+      // now run the Job      
       FuzzyKMeansDriver.runJob("testdata/points", "testdata/clusters",
-          "output", EuclideanDistanceMeasure.class.getName(), 0.001, 2, 1,2);
+          "output", EuclideanDistanceMeasure.class.getName(), 0.001, 2, 1,
+          k + 1, 2);      
 
       // now compare the expected clusters with actual
       File outDir = new File("output/points");
       assertTrue("output dir exists?", outDir.exists());
       String[] outFiles = outDir.list();
-      assertEquals("output dir files?", 4, outFiles.length);
-      BufferedReader reader = new BufferedReader(new InputStreamReader(new 
FileInputStream(
-          "output/points/part-00000"), Charset.forName("UTF-8")));
+//      assertEquals("output dir files?", 4, outFiles.length);
+      BufferedReader reader = new BufferedReader(new InputStreamReader(
+          new FileInputStream("output/points/part-00000"), Charset
+              .forName("UTF-8")));
 
       while (reader.ready()) {
         String line = reader.readLine();
         String[] lineParts = line.split("\t");
         assertEquals("line parts", 2, lineParts.length);
-        String clusterInfoStr = lineParts[1].substring(1,
-            lineParts[1].length() - 1);
+        String clusterInfoStr = lineParts[1].replace("[", "").replace("]", "");
+
         String[] clusterInfoList = clusterInfoStr.split(" ");
         assertEquals("Number of clusters", k + 1, clusterInfoList.length);
         double prob = 0.0;
@@ -296,16 +319,16 @@
       Map<String, Double> pointTotalProbMap = new HashMap<String, Double>();
 
       for (String key : mapCollector.getKeys()) {
-        //SoftCluster cluster = SoftCluster.decodeCluster(key);
+        // SoftCluster cluster = SoftCluster.decodeCluster(key);
         List<Text> values = mapCollector.getValue(key);
 
         for (Text value : values) {
           String pointInfo = value.toString();
           double pointProb = Double.parseDouble(pointInfo.substring(0,
-              pointInfo.indexOf(':')));
+              pointInfo.indexOf(FuzzyKMeansDriver.MAPPER_VALUE_SEPARATOR)));
 
-          String encodedVector = pointInfo
-              .substring(pointInfo.indexOf(':') + 1);
+          String encodedVector = pointInfo.substring(pointInfo
+              .indexOf(FuzzyKMeansDriver.MAPPER_VALUE_SEPARATOR) + 1);
 
           Double val = pointTotalProbMap.get(encodedVector);
           double probVal = 0.0;
@@ -393,7 +416,7 @@
         Vector vec = tweakValue(points.get(i));
 
         SoftCluster cluster = new SoftCluster(vec, i);
-        cluster.addPoint(cluster.getCenter(), 1);
+        // cluster.addPoint(cluster.getCenter(), 1);
         clusterList.add(cluster);
       }
 
@@ -421,6 +444,8 @@
       // run reducer
       DummyOutputCollector<Text, Text> reducerCollector = new 
DummyOutputCollector<Text, Text>();
       FuzzyKMeansReducer reducer = new FuzzyKMeansReducer();
+      reducer.config(clusterList);
+
       for (String key : combinerCollector.getKeys()) {
         List<Text> values = combinerCollector.getValue(key);
         reducer
@@ -496,6 +521,8 @@
       // run reducer
       DummyOutputCollector<Text, Text> reducerCollector = new 
DummyOutputCollector<Text, Text>();
       FuzzyKMeansReducer reducer = new FuzzyKMeansReducer();
+      reducer.config(clusterList);
+
       for (String key : combinerCollector.getKeys()) {
         List<Text> values = combinerCollector.getValue(key);
         reducer
@@ -545,8 +572,8 @@
           refClusterInfoMap.put(clusterProb[0], clusterProbVal);
         }
 
-        String[] clusterInfoList = value.get(0).toString().substring(1,
-            refValue.length() - 1).split(" ");
+        String[] clusterInfoList = value.get(0).toString().replace("[", "")
+            .replace("]", "").split(" ");
         assertEquals("Number of clusters", k + 1, clusterInfoList.length);
         for (String clusterInfo : refClusterInfoList) {
           String[] clusterProb = clusterInfo.split(":");


Reply via email to