You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mahout.apache.org by gs...@apache.org on 2009/12/18 00:22:41 UTC

svn commit: r891983 [29/47] - in /lucene/mahout/trunk: ./ core/ core/src/main/java/org/apache/mahout/cf/taste/hadoop/item/ core/src/main/java/org/apache/mahout/clustering/ core/src/main/java/org/apache/mahout/clustering/canopy/ core/src/main/java/org/a...

Added: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/PrimeFinder.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/PrimeFinder.java?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/PrimeFinder.java (added)
+++ lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/PrimeFinder.java Thu Dec 17 23:22:16 2009
@@ -0,0 +1,172 @@
+package org.apache.mahout.math.map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Arrays;
+
+/**
+ * Not of interest for users; only for implementors of hashtables.
+ * Used to keep hash table capacities prime numbers.
+ *
+ * <p>Choosing prime numbers as hash table capacities is a good idea to keep them working fast,
+ * particularly under hash table expansions.
+ *
+ * <p>However, JDK 1.2, JGL 3.1 and many other toolkits do nothing to keep capacities prime.
+ * This class provides efficient means to choose prime capacities.
+ *
+ * <p>Choosing a prime is <tt>O(log 300)</tt> (binary search in a list of 300 int's).
+ * Memory requirements: 1 KB static memory.
+ *
+ */
+public class PrimeFinder {
+
+  private static final Logger log = LoggerFactory.getLogger(PrimeFinder.class);
+
+  /** The largest prime this class can generate; currently equal to <tt>Integer.MAX_VALUE</tt>. */
+  public static final int largestPrime = Integer.MAX_VALUE; //yes, it is prime.
+
+  /**
+   * The prime number list consists of 11 chunks. Each chunk contains prime numbers. A chunk starts with a prime P1. The
+   * next element is a prime P2. P2 is the smallest prime for which holds: P2 >= 2*P1. The next element is P3, for which
+   * the same holds with respect to P2, and so on.
+   *
+   * Chunks are chosen such that for any desired capacity >= 1000 the list includes a prime number <= desired capacity *
+   * 1.11 (11%). For any desired capacity >= 200 the list includes a prime number <= desired capacity * 1.16 (16%). For
+   * any desired capacity >= 16 the list includes a prime number <= desired capacity * 1.21 (21%).
+   *
+   * Therefore, primes can be retrieved which are quite close to any desired capacity, which in turn avoids wasting
+   * memory. For example, the list includes 1039,1117,1201,1277,1361,1439,1523,1597,1759,1907,2081. So if you need a
+   * prime >= 1040, you will find a prime <= 1040*1.11=1154.
+   *
+   * Chunks are chosen such that they are optimized for a hashtable growthfactor of 2.0; If your hashtable has such a
+   * growthfactor then, after initially "rounding to a prime" upon hashtable construction, it will later expand to prime
+   * capacities such that there exist no better primes.
+   *
+   * In total these are about 32*10=320 numbers -> 1 KB of static memory needed. If you are stingy, then delete every
+   * second or fourth chunk.
+   */
+
+  private static final int[] primeCapacities = {
+      //chunk #0
+      largestPrime,
+
+      //chunk #1
+      5, 11, 23, 47, 97, 197, 397, 797, 1597, 3203, 6421, 12853, 25717, 51437, 102877, 205759,
+      411527, 823117, 1646237, 3292489, 6584983, 13169977, 26339969, 52679969, 105359939,
+      210719881, 421439783, 842879579, 1685759167,
+
+      //chunk #2
+      433, 877, 1759, 3527, 7057, 14143, 28289, 56591, 113189, 226379, 452759, 905551, 1811107,
+      3622219, 7244441, 14488931, 28977863, 57955739, 115911563, 231823147, 463646329, 927292699,
+      1854585413,
+
+      //chunk #3
+      953, 1907, 3821, 7643, 15287, 30577, 61169, 122347, 244703, 489407, 978821, 1957651, 3915341,
+      7830701, 15661423, 31322867, 62645741, 125291483, 250582987, 501165979, 1002331963,
+      2004663929,
+
+      //chunk #4
+      1039, 2081, 4177, 8363, 16729, 33461, 66923, 133853, 267713, 535481, 1070981, 2141977, 4283963,
+      8567929, 17135863, 34271747, 68543509, 137087021, 274174111, 548348231, 1096696463,
+
+      //chunk #5
+      31, 67, 137, 277, 557, 1117, 2237, 4481, 8963, 17929, 35863, 71741, 143483, 286973, 573953,
+      1147921, 2295859, 4591721, 9183457, 18366923, 36733847, 73467739, 146935499, 293871013,
+      587742049, 1175484103,
+
+      //chunk #6
+      599, 1201, 2411, 4831, 9677, 19373, 38747, 77509, 155027, 310081, 620171, 1240361, 2480729,
+      4961459, 9922933, 19845871, 39691759, 79383533, 158767069, 317534141, 635068283, 1270136683,
+
+      //chunk #7
+      311, 631, 1277, 2557, 5119, 10243, 20507, 41017, 82037, 164089, 328213, 656429, 1312867,
+      2625761, 5251529, 10503061, 21006137, 42012281, 84024581, 168049163, 336098327, 672196673,
+      1344393353,
+
+      //chunk #8
+      3, 7, 17, 37, 79, 163, 331, 673, 1361, 2729, 5471, 10949, 21911, 43853, 87719, 175447, 350899,
+      701819, 1403641, 2807303, 5614657, 11229331, 22458671, 44917381, 89834777, 179669557,
+      359339171, 718678369, 1437356741,
+
+      //chunk #9
+      43, 89, 179, 359, 719, 1439, 2879, 5779, 11579, 23159, 46327, 92657, 185323, 370661, 741337,
+      1482707, 2965421, 5930887, 11861791, 23723597, 47447201, 94894427, 189788857, 379577741,
+      759155483, 1518310967,
+
+      //chunk #10
+      379, 761, 1523, 3049, 6101, 12203, 24407, 48817, 97649, 195311, 390647, 781301, 1562611,
+      3125257, 6250537, 12501169, 25002389, 50004791, 100009607, 200019221, 400038451, 800076929,
+      1600153859
+  };
+
+
+  static { //initializer
+    // The above prime numbers are formatted for human readability.
+    // To find numbers fast, we sort them once and for all.
+
+    Arrays.sort(primeCapacities);
+  }
+
+  /** Makes this class non instantiable, but still let's others inherit from it. */
+  private PrimeFinder() {
+  }
+
+  /** Tests correctness. Try from=1000, to=10000 from=200,  to=1000 from=16,   to=1000 from=1000, to=Integer.MAX_VALUE */
+  protected static void main(String[] args) {
+    int from = Integer.parseInt(args[0]);
+    int to = Integer.parseInt(args[1]);
+
+    statistics(from, to);
+  }
+
+  /**
+   * Returns a prime number which is <code>&gt;= desiredCapacity</code> and very close to <code>desiredCapacity</code>
+   * (within 11% if <code>desiredCapacity &gt;= 1000</code>).
+   *
+   * @param desiredCapacity the capacity desired by the user.
+   * @return the capacity which should be used for a hashtable.
+   */
+  public static int nextPrime(int desiredCapacity) {
+    int i = java.util.Arrays.binarySearch(primeCapacities, desiredCapacity);
+    //int i = new IntArrayList(primeCapacities).binarySearch(desiredCapacity); // for debug only TODO
+    if (i < 0) {
+      // desired capacity not found, choose next prime greater than desired capacity
+      i = -i - 1; // remember the semantics of binarySearch...
+    }
+    return primeCapacities[i];
+  }
+
+  /** Tests correctness. */
+  private static void statistics(int from, int to) {
+    // check that primes contain no accidental errors
+    for (int i = 0; i < primeCapacities.length - 1; i++) {
+      if (primeCapacities[i] >= primeCapacities[i + 1]) {
+        throw new IllegalStateException(
+            "primes are unsorted or contain duplicates; detected at " + i + '@' + primeCapacities[i]);
+      }
+    }
+
+    double accDeviation = 0.0;
+    double maxDeviation = -1.0;
+
+    for (int i = from; i <= to; i++) {
+      int primeCapacity = nextPrime(i);
+      //log.info(primeCapacity);
+      double deviation = (primeCapacity - i) / (double) i;
+
+      if (deviation > maxDeviation) {
+        maxDeviation = deviation;
+        log.info("new maxdev @" + i + "@dev=" + maxDeviation);
+      }
+
+      accDeviation += deviation;
+    }
+    long width = 1 + (long) to - (long) from;
+
+    double meanDeviation = accDeviation / width;
+    log.info("Statistics for [" + from + ',' + to + "] are as follows");
+    log.info("meanDeviation = " + (float) meanDeviation * 100 + " %");
+    log.info("maxDeviation = " + (float) maxDeviation * 100 + " %");
+  }
+}

Propchange: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/PrimeFinder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/QuickOpenIntIntHashMap.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/QuickOpenIntIntHashMap.java?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/QuickOpenIntIntHashMap.java (added)
+++ lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/QuickOpenIntIntHashMap.java Thu Dec 17 23:22:16 2009
@@ -0,0 +1,223 @@
+/*
+Copyright � 1999 CERN - European Organization for Nuclear Research.
+Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose 
+is hereby granted without fee, provided that the above copyright notice appear in all copies and 
+that both that copyright notice and this permission notice appear in supporting documentation. 
+CERN makes no representations about the suitability of this software for any purpose. 
+It is provided "as is" without expressed or implied warranty.
+*/
+package org.apache.mahout.math.map;
+
+/**
+ * Status: Experimental; Do not use for production yet. Hash map holding (key,value) associations of type
+ * <tt>(int-->int)</tt>; Automatically grows and shrinks as needed; Implemented using open addressing with double
+ * hashing. First see the <a href="package-summary.html">package summary</a> and javadoc <a
+ * href="package-tree.html">tree view</a> to get the broad picture.
+ *
+ * Implements open addressing with double hashing, using "Brent's variation". Brent's variation slows insertions a bit
+ * down (not much) but reduces probes (collisions) for successful searches, in particular for large load factors. (It
+ * does not improve unsuccessful searches.) See D. Knuth, Searching and Sorting, 3rd ed., p.533-545
+ *
+ * @author wolfgang.hoschek@cern.ch
+ * @version 1.0, 09/24/99
+ * @see java.util.HashMap
+ */
+class QuickOpenIntIntHashMap extends OpenIntIntHashMap {
+  //public int totalProbesSaved = 0; // benchmark only
+
+  /** Constructs an empty map with default capacity and default load factors. */
+  QuickOpenIntIntHashMap() {
+    this(defaultCapacity);
+  }
+
+  /**
+   * Constructs an empty map with the specified initial capacity and default load factors.
+   *
+   * @param initialCapacity the initial capacity of the map.
+   * @throws IllegalArgumentException if the initial capacity is less than zero.
+   */
+  QuickOpenIntIntHashMap(int initialCapacity) {
+    this(initialCapacity, defaultMinLoadFactor, defaultMaxLoadFactor);
+  }
+
+  /**
+   * Constructs an empty map with the specified initial capacity and the specified minimum and maximum load factor.
+   *
+   * @param initialCapacity the initial capacity.
+   * @param minLoadFactor   the minimum load factor.
+   * @param maxLoadFactor   the maximum load factor.
+   * @throws IllegalArgumentException if <tt>initialCapacity < 0 || (minLoadFactor < 0.0 || minLoadFactor >= 1.0) ||
+   *                                  (maxLoadFactor <= 0.0 || maxLoadFactor >= 1.0) || (minLoadFactor >=
+   *                                  maxLoadFactor)</tt>.
+   */
+  QuickOpenIntIntHashMap(int initialCapacity, double minLoadFactor, double maxLoadFactor) {
+    setUp(initialCapacity, minLoadFactor, maxLoadFactor);
+  }
+
+  /**
+   * Associates the given key with the given value. Replaces any old <tt>(key,someOtherValue)</tt> association, if
+   * existing.
+   *
+   * @param key   the key the value shall be associated with.
+   * @param value the value to be associated.
+   * @return <tt>true</tt> if the receiver did not already contain such a key; <tt>false</tt> if the receiver did
+   *         already contain such a key - the new value has now replaced the formerly associated value.
+   */
+  @Override
+  public boolean put(int key, int value) {
+    /*
+       This is open addressing with double hashing, using "Brent's variation".
+       Brent's variation slows insertions a bit down (not much) but reduces probes (collisions) for successful searches, in particular for large load factors.
+       (It does not improve unsuccessful searches.)
+       See D. Knuth, Searching and Sorting, 3rd ed., p.533-545
+
+       h1(key) = hash % M
+       h2(key) = decrement = Max(1, hash/M % M)
+       M is prime = capacity = table.length
+       probing positions are table[(h1-j*h2) % M] for j=0,1,...
+       (M and h2 could also be chosen differently, but h2 is required to be relative prime to M.)
+    */
+
+    int[] tab = table;
+    byte[] stat = state;
+    int length = tab.length;
+
+    int hash = HashFunctions.hash(key) & 0x7FFFFFFF;
+    int i = hash % length;
+    int decrement = (hash / length) % length;
+    if (decrement == 0) {
+      decrement = 1;
+    }
+    //log.info("insert search for (key,value)=("+key+","+value+") at i="+i+", dec="+decrement);
+
+    // stop if we find a removed or free slot, or if we find the key itself
+    // do NOT skip over removed slots (yes, open addressing is like that...)
+    //int comp = comparisons;
+    int t = 0;  // the number of probes
+    int p0 = i; // the first position to probe
+    while (stat[i] == FULL && tab[i] != key) {
+      t++;
+      i -= decrement;
+      //hashCollisions++;
+      if (i < 0) {
+        i += length;
+      }
+    }
+    //if (comparisons-comp>0) log.info("probed "+(comparisons-comp)+" slots.");
+    if (stat[i] == FULL) {
+      // key already contained at slot i.
+      this.values[i] = value;
+      return false;
+    }
+    // not already contained, should be inserted at slot i.
+
+    if (this.distinct > this.highWaterMark) {
+      int newCapacity = chooseGrowCapacity(this.distinct + 1, this.minLoadFactor, this.maxLoadFactor);
+
+      //log.info("grow rehashing ");
+      //log.info("at distinct="+distinct+", capacity="+table.length+" to newCapacity="+newCapacity+" ...");
+
+      rehash(newCapacity);
+      return put(key, value);
+    }
+
+    /*
+    Brent's variation does a local reorganization to reduce probes. It essentially means:
+    We test whether it is possible to move the association we probed first (table[p0]) out of the way.
+    If this is possible, it will reduce probes for the key to be inserted, since it takes its place; it gets hit earlier.
+    However, future probes for the key that we move out of the way will increase.
+    Thus we only move it out of the way, if we have a net gain, that is, if we save more probes than we loose.
+    For the first probe we safe more than we loose if the number of probes we needed was >=2 (t>=2).
+    If the first probe cannot be moved out of the way, we try the next probe (p1).
+    Now we safe more than we loose if t>=3.
+    We repeat this until we find that we cannot gain or that we can indeed move p(x) out of the way.
+
+    Note: Under the great majority of insertions t<=1, so the loop is entered very infrequently.
+    */
+    while (t > 1) {
+      //log.info("t="+t);
+      int key0 = tab[p0];
+      hash = HashFunctions.hash(key0) & 0x7FFFFFFF;
+      decrement = (hash / length) % length;
+      if (decrement == 0) {
+        decrement = 1;
+      }
+      int pc = p0 - decrement; // pc = (p0-j*decrement) % M, j=1,2,..
+      if (pc < 0) {
+        pc += length;
+      }
+
+      if (stat[pc] != FREE) { // not a free slot, continue searching for free slot to move to, or break.
+        p0 = pc;
+        t--;
+      } else { // free or removed slot found, now move...
+        //log.info("copying p0="+p0+" to pc="+pc+", (key,val)=("+tab[p0]+","+values[p0]+"), saving "+(t-1)+" probes.");
+        //this.totalProbesSaved += (t - 1);
+        tab[pc] = key0;
+        stat[pc] = FULL;
+        values[pc] = values[p0];
+        i = p0; // prepare to insert: table[p0]=key
+        t = 0; // break loop
+      }
+    }
+
+    //log.info("inserting at i="+i);
+    this.table[i] = key;
+    this.values[i] = value;
+    if (this.state[i] == FREE) {
+      this.freeEntries--;
+    }
+    this.state[i] = FULL;
+    this.distinct++;
+
+    if (this.freeEntries < 1) { //delta
+      int newCapacity = chooseGrowCapacity(this.distinct + 1, this.minLoadFactor, this.maxLoadFactor);
+      rehash(newCapacity);
+    }
+
+    return true;
+  }
+
+  /**
+   * Rehashes the contents of the receiver into a new table with a smaller or larger capacity. This method is called
+   * automatically when the number of keys in the receiver exceeds the high water mark or falls below the low water
+   * mark.
+   */
+  @Override
+  protected void rehash(int newCapacity) {
+    int oldCapacity = table.length;
+    //if (oldCapacity == newCapacity) return;
+
+    int[] oldTable = table;
+    int[] oldValues = values;
+    byte[] oldState = state;
+
+    int[] newTable = new int[newCapacity];
+    int[] newValues = new int[newCapacity];
+    byte[] newState = new byte[newCapacity];
+
+    this.lowWaterMark = chooseLowWaterMark(newCapacity, this.minLoadFactor);
+    this.highWaterMark = chooseHighWaterMark(newCapacity, this.maxLoadFactor);
+
+    this.table = newTable;
+    this.values = newValues;
+    this.state = newState;
+    this.freeEntries = newCapacity - this.distinct; // delta
+
+    int tmp = this.distinct;
+    this.distinct = Integer.MIN_VALUE; // switch of watermarks
+    for (int i = oldCapacity; i-- > 0;) {
+      if (oldState[i] == FULL) {
+        put(oldTable[i], oldValues[i]);
+        /*
+        int element = oldTable[i];
+        int index = indexOfInsertion(element);
+        newTable[index]=element;
+        newValues[index]=oldValues[i];
+        newState[index]=FULL;
+        */
+      }
+    }
+    this.distinct = tmp;
+  }
+}

Propchange: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/QuickOpenIntIntHashMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/package.html
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/package.html?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/package.html (added)
+++ lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/package.html Thu Dec 17 23:22:16 2009
@@ -0,0 +1,290 @@
+<HTML>
+<BODY>
+Automatically growing and shrinking maps holding objects or primitive
+data types such as <tt>int</tt>, <tt>double</tt>, etc. Currently all maps are
+based upon hashing.
+<h2><a name="Overview"></a>1. Overview</h2>
+
+<p>The map package offers flexible object oriented abstractions modelling automatically
+  resizing maps. It is designed to be scalable in terms of performance and memory
+  requirements.</p>
+
+<p>Features include: </p>
+
+<p></p>
+<ul>
+  <li>Maps operating on objects as well as all primitive data types such as <code>int</code>,
+    <code>double</code>, etc.
+  </li>
+  <li>Compact representations</li>
+  <li>Support for quick access to associations</li>
+  <li>A number of general purpose map operations</li>
+</ul>
+<p>File-based I/O can be achieved through the standard Java built-in serialization
+  mechanism. All classes implement the {@link java.io.Serializable} interface.
+  However, the toolkit is entirely decoupled from advanced I/O. It provides data
+  structures and algorithms only.
+
+<p> This toolkit borrows some terminology from the Javasoft <a
+    href="http://www.javasoft.com/products/jdk/1.2/docs/guide/collections/index.html">
+  Collections framework</a> written by Josh Bloch and introduced in JDK 1.2.
+
+<h2>2. Introduction</h2>
+
+<p>A map is an associative container that manages a set of (key,value) pairs.
+  It is useful for implementing a collection of one-to-one mappings. A (key,value)
+  pair is called an <i>association</i>. A value can be looked up up via its key.
+  Associations can quickly be set, removed and retrieved. They are stored in a
+  hashing structure based on the hash code of their keys, which is obtained by
+  using a hash function. </p>
+
+<p> A map can, for example, contain <tt>Name-->Location</tt> associations like
+  <tt>{("Pete", "Geneva"), ("Steve", "Paris"), ("Robert", "New York")}</tt> used
+  in address books or <tt>Index-->Value</tt> mappings like <tt>{(0, 100), (3,
+    1000), (100000, 70)}</tt> representing sparse lists or matrices. For example
+  this could mean at index 0 we have a value of 100, at index 3 we have a value
+  of 1000, at index 1000000 we have a value of 70, and at all other indexes we
+  have a value of, say, zero. Another example is a map of IP addresses to domain
+  names (DNS). Maps can also be useful to represent<i> multi sets</i>, that is,
+  sets where elements can occur more than once. For multi sets one would have
+  <tt>Value-->Frequency</tt> mappings like <tt>{(100, 1), (50, 1000), (101, 3))}</tt>
+  meaning element 100 occurs 1 time, element 50 occurs 1000 times, element 101
+  occurs 3 times. Further, maps can also manage <tt>ObjectIdentifier-->Object</tt>
+  mappings like <tt>{(12, obj1), (7, obj2), (10000, obj3), (9, obj4)}</tt> used
+  in Object Databases.
+
+<p> A map cannot contain two or more <i>equal</i> keys; a key can map to at most
+  one value. However, more than one key can map to identical values. For primitive
+  data types "equality" of keys is defined as identity (operator <tt>==</tt>).
+  For maps using <tt>Object</tt> keys, the meaning of "equality" can be specified
+  by the user upon instance construction. It can either be defined to be identity
+  (operator <tt>==</tt>) or to be given by the method {@link java.lang.Object#equals(Object)}.
+  Associations of kind <tt>(AnyType,Object)</tt> can be of the form <tt>(AnyKey,null)
+  </tt>, i.e. values can be <tt>null</tt>.
+
+<p> The classes of this package make no guarantees as to the order of the elements
+  returned by iterators; in particular, they do not guarantee that the order will
+  remain constant over time.
+
+<h2></h2>
+<h4>Copying</h4>
+
+<p>
+
+<p>Any map can be copied. A copy is <i>equal</i> to the original but entirely
+  independent of the original. So changes in the copy are not reflected in the
+  original, and vice-versa.
+
+<h2>3. Package organization</h2>
+
+<p>For most primitive data types and for objects there exists a separate map version.
+  All versions are just the same, except that they operate on different data types.
+  Colt includes two kinds of implementations for maps: The two different implementations
+  are tagged <b>Chained</b> and <b>Open</b>.
+  Note: Chained is no more included. Wherever it is mentioned it is of historic interest only.</p>
+<ul>
+  <li><b>Chained</b> uses extendible separate chaining with chains holding unsorted
+    dynamically linked collision lists.
+  <li><b>Open</b> uses extendible open addressing with double hashing.
+</ul>
+<p>Class naming follows the schema <tt>&lt;Implementation&gt;&lt;KeyType&gt;&lt;ValueType&gt;HashMap</tt>.
+  For example, a {@link org.apache.mahout.math.map.OpenIntDoubleHashMap} holds <tt>(int-->double)</tt>
+  associations and is implemented with open addressing. A {@link org.apache.mahout.math.map.OpenIntObjectHashMap}
+  holds <tt>(int-->Object)</tt> associations and is implemented with open addressing.
+</p>
+
+<p>The classes for maps of a given (key,value) type are derived from a common
+  abstract base class tagged <tt>Abstract&lt;KeyType&gt;&lt;ValueType&gt;</tt><tt>Map</tt>.
+  For example, all maps operating on <tt>(int-->double)</tt> associations are
+  derived from {@link org.apache.mahout.math.map.AbstractIntDoubleMap}, which in turn is derived
+  from an abstract base class tying together all maps regardless of assocation
+  type, {@link org.apache.mahout.math.map.AbstractMap}. The abstract base classes provide skeleton
+  implementations for all but few methods. Experimental layouts (such as chaining,
+  open addressing, extensible hashing, red-black-trees, etc.) can easily be implemented
+  and inherit a rich set of functionality. Have a look at the javadoc <a href="package-tree.html">tree
+    view</a> to get the broad picture.</p>
+
+<h2>4. Example usage</h2>
+<TABLE>
+  <TD CLASS="PRE">
+      <PRE>
+int[]    keys   = {0    , 3     , 100000, 9   };
+double[] values = {100.0, 1000.0, 70.0  , 71.0};
+
+AbstractIntDoubleMap map = new OpenIntDoubleHashMap();
+
+// add several associations
+for (int i=0; i &lt; keys.length; i++) map.put(keys[i], values[i]);
+
+log.info("map="+map);
+log.info("size="+map.size());
+log.info(map.containsKey(3));
+log.info("get(3)="+map.get(3));
+log.info(map.containsKey(4));
+log.info("get(4)="+map.get(4));
+log.info(map.containsValue(71.0));
+log.info("keyOf(71.0)="+map.keyOf(71.0));
+
+// remove one association
+map.removeKey(3);
+log.info("\nmap="+map);
+log.info(map.containsKey(3));
+log.info("get(3)="+map.get(3));
+log.info(map.containsValue(1000.0));
+log.info("keyOf(1000.0)="+map.keyOf(1000.0));
+
+// clear
+map.clear();
+log.info("\nmap="+map);
+log.info("size="+map.size());
+</PRE>
+  </TD>
+</TABLE>
+
+yields the following output
+
+<TABLE>
+  <TD CLASS="PRE">
+<PRE>
+map=[0->100.0, 3->1000.0, 9->71.0, 100000->70.0]
+size=4
+true
+get(3)=1000.0
+false
+get(4)=0.0
+true
+keyOf(71.0)=9
+
+map=[0->100.0, 9->71.0, 100000->70.0]
+false
+get(3)=0.0
+false
+keyOf(1000.0)=-2147483648
+
+map=[]
+size=0
+</PRE>
+  </TD>
+</TABLE>
+<h2> 5. Notes </h2>
+
+<p>
+  Note that implementations are not synchronized.
+
+<p>
+  Choosing efficient parameters for hash maps is not always easy.
+  However, since parameters determine efficiency and memory requirements, here is a quick guide how to choose them.
+  If your use case does not heavily operate on hash maps but uses them just because they provide
+  convenient functionality, you can safely skip this section.
+  For those of you who care, read on.
+
+<p>
+
+  There are three parameters that can be customized upon map construction: <tt>initialCapacity</tt>,
+  <tt>minLoadFactor</tt> and <tt>maxLoadFactor</tt>.
+  The more memory one can afford, the faster a hash map.
+  The hash map's capacity is the maximum number of associations that can be added without needing to allocate new
+  internal memory.
+  A larger capacity means faster adding, searching and removing.
+  The <tt>initialCapacity</tt> corresponds to the capacity used upon instance construction.
+
+<p>
+  The <tt>loadFactor</tt> of a hash map measures the degree of "fullness".
+  It is given by the number of assocations (<tt>size()</tt>)
+  divided by the hash map capacity <tt>(0.0 &lt;= loadFactor &lt;= 1.0)</tt>.
+  The more associations are added, the larger the loadFactor and the more hash map performance degrades.
+  Therefore, when the loadFactor exceeds a customizable threshold (<tt>maxLoadFactor</tt>), the hash map is
+  automatically grown.
+  In such a way performance degradation can be avoided.
+  Similarly, when the loadFactor falls below a customizable threshold (<tt>minLoadFactor</tt>), the hash map is
+  automatically shrinked.
+  In such a way excessive memory consumption can be avoided.
+  Automatic resizing (both growing and shrinking) obeys the following invariant:
+
+<p>
+  <tt>capacity * minLoadFactor <= size() <= capacity * maxLoadFactor</tt>
+
+<p> The term <tt>capacity * minLoadFactor</tt> is called the <i>low water mark</i>,
+  <tt>capacity * maxLoadFactor</tt> is called the <i>high water mark</i>. In other
+  words, the number of associations may vary within the water mark constraints.
+  When it goes out of range, the map is automatically resized and memory consumption
+  changes proportionally.
+<ul>
+  <li>To tune for memory at the expense of performance, both increase <tt>minLoadFactor</tt> and <tt>maxLoadFactor</tt>.
+  <li>To tune for performance at the expense of memory, both decrease <tt>minLoadFactor</tt> and <tt>maxLoadFactor</tt>.
+    As as special case set <tt>minLoadFactor=0</tt> to avoid any automatic shrinking.
+</ul>
+Resizing large hash maps can be time consuming, <tt>O(size())</tt>, and should be avoided if possible (maintaining
+primes is not the reason).
+Unnecessary growing operations can be avoided if the number of associations is known before they are added, or can be
+estimated.<p>
+  In such a case good parameters are as follows:
+
+<p>
+  <i>For chaining:</i>
+  <br>Set the <tt>initialCapacity = 1.4*expectedSize</tt> or greater.
+  <br>Set the <tt>maxLoadFactor = 0.8</tt> or greater.
+
+<p>
+  <i>For open addressing:</i>
+  <br>Set the <tt>initialCapacity = 2*expectedSize</tt> or greater. Alternatively call <tt>ensureCapacity(...)</tt>.
+  <br>Set the <tt>maxLoadFactor = 0.5</tt>.
+  <br>Never set <tt>maxLoadFactor &gt; 0.55</tt>; open addressing exponentially slows down beyond that point.
+
+<p>
+  In this way the hash map will never need to grow and still stay fast.
+  It is never a good idea to set <tt>maxLoadFactor &lt; 0.1</tt>,
+  because the hash map would grow too often.
+  If it is entirelly unknown how many associations the application will use,
+  the default constructor should be used. The map will grow and shrink as needed.
+
+<p>
+
+  <b>Comparision of chaining and open addressing</b>
+
+<p> Chaining is faster than open addressing, when assuming unconstrained memory
+  consumption. Open addressing is more space efficient than chaining, because
+  it does not create entry objects but uses primitive arrays which are considerably
+  smaller. Entry objects consume significant amounts of memory compared to the
+  information they actually hold. Open addressing also poses no problems to the
+  garbage collector. In contrast, chaining can create millions of entry objects
+  which are linked; a nightmare for any garbage collector. In addition, entry
+  object creation is a bit slow. <br>
+  Therefore, with the same amount of memory, or even less memory, hash maps with
+  larger capacity can be maintained under open addressing, which yields smaller
+  loadFactors, which in turn keeps performance competitive with chaining. In our
+  benchmarks, using significantly less memory, open addressing usually is not
+  more than 1.2-1.5 times slower than chaining.
+
+<p><b>Further readings</b>:
+  <br>Knuth D., The Art of Computer Programming: Searching and Sorting, 3rd ed.
+  <br>Griswold W., Townsend G., The Design and Implementation of Dynamic Hashing for Sets and Tables in Icon, Software -
+  Practice and Experience, Vol. 23(4), 351-367 (April 1993).
+  <br>Larson P., Dynamic hash tables, Comm. of the ACM, 31, (4), 1988.
+
+<p>
+  <b>Performance:</b>
+
+<p>
+  Time complexity:
+  <br>The classes offer <i>expected</i> time complexity <tt>O(1)</tt> (i.e. constant time) for the basic operations
+  <tt>put</tt>, <tt>get</tt>, <tt>removeKey</tt>, <tt>containsKey</tt> and <tt>size</tt>,
+  assuming the hash function disperses the elements properly among the buckets.
+  Otherwise, pathological cases, although highly improbable, can occur, degrading performance to <tt>O(N)</tt> in the
+  worst case.
+  Operations <tt>containsValue</tt> and <tt>keyOf</tt> are <tt>O(N)</tt>.
+
+<p>
+  Memory requirements for <i>open addressing</i>:
+  <br>worst case: <tt>memory [bytes] = (1/minLoadFactor) * size() * (1 + sizeOf(key) + sizeOf(value))</tt>.
+  <br>best case: <tt>memory [bytes] = (1/maxLoadFactor) * size() * (1 + sizeOf(key) + sizeOf(value))</tt>.
+  Where <tt>sizeOf(int) = 4</tt>, <tt>sizeOf(double) = 8</tt>, <tt>sizeOf(Object) = 4</tt>, etc.
+  Thus, an <tt>OpenIntIntHashMap</tt> with minLoadFactor=0.25 and maxLoadFactor=0.5 and 1000000 associations uses
+  between 17 MB and 34 MB.
+  The same map with 1000 associations uses between 17 and 34 KB.
+
+<p>
+
+</BODY>
+</HTML>
+

Propchange: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/map/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory1D.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory1D.java?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory1D.java (added)
+++ lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory1D.java Thu Dec 17 23:22:16 2009
@@ -0,0 +1,203 @@
+/*
+Copyright � 1999 CERN - European Organization for Nuclear Research.
+Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose 
+is hereby granted without fee, provided that the above copyright notice appear in all copies and 
+that both that copyright notice and this permission notice appear in supporting documentation. 
+CERN makes no representations about the suitability of this software for any purpose. 
+It is provided "as is" without expressed or implied warranty.
+*/
+package org.apache.mahout.math.matrix;
+
+import org.apache.mahout.math.PersistentObject;
+import org.apache.mahout.math.jet.math.Functions;
+import org.apache.mahout.math.jet.random.engine.MersenneTwister;
+import org.apache.mahout.math.jet.random.sampling.RandomSamplingAssistant;
+import org.apache.mahout.math.list.AbstractDoubleList;
+import org.apache.mahout.math.list.DoubleArrayList;
+import org.apache.mahout.math.matrix.impl.DenseDoubleMatrix1D;
+import org.apache.mahout.math.matrix.impl.SparseDoubleMatrix1D;
+
+/** @deprecated until unit tests are in place.  Until this time, this class/interface is unsupported. */
+@Deprecated
+public class DoubleFactory1D extends PersistentObject {
+
+  /** A factory producing dense matrices. */
+  public static final DoubleFactory1D dense = new DoubleFactory1D();
+
+  /** A factory producing sparse matrices. */
+  private static final DoubleFactory1D sparse = new DoubleFactory1D();
+
+  /** Makes this class non instantiable, but still let's others inherit from it. */
+  protected DoubleFactory1D() {
+  }
+
+  /**
+   * C = A||B; Constructs a new matrix which is the concatenation of two other matrices. Example: <tt>0 1</tt> append
+   * <tt>3 4</tt> --> <tt>0 1 3 4</tt>.
+   */
+  public DoubleMatrix1D append(DoubleMatrix1D A, DoubleMatrix1D B) {
+    // concatenate
+    DoubleMatrix1D matrix = make(A.size() + B.size());
+    matrix.viewPart(0, A.size()).assign(A);
+    matrix.viewPart(A.size(), B.size()).assign(B);
+    return matrix;
+  }
+
+  /** Constructs a matrix with cells having ascending values. For debugging purposes. Example: <tt>0 1 2</tt> */
+  public DoubleMatrix1D ascending(int size) {
+    return descending(size).assign(Functions.chain(Functions.neg, Functions.minus(size)));
+  }
+
+  /** Constructs a matrix with cells having descending values. For debugging purposes. Example: <tt>2 1 0</tt> */
+  public DoubleMatrix1D descending(int size) {
+    DoubleMatrix1D matrix = make(size);
+    int v = 0;
+    for (int i = size; --i >= 0;) {
+      matrix.setQuick(i, v++);
+    }
+    return matrix;
+  }
+
+  /**
+   * Constructs a matrix with the given cell values. The values are copied. So subsequent changes in <tt>values</tt> are
+   * not reflected in the matrix, and vice-versa.
+   *
+   * @param values The values to be filled into the new matrix.
+   */
+  public DoubleMatrix1D make(double[] values) {
+    if (this == sparse) {
+      return new SparseDoubleMatrix1D(values);
+    } else {
+      return new DenseDoubleMatrix1D(values);
+    }
+  }
+
+  /** Constructs a matrix which is the concatenation of all given parts. Cells are copied. */
+  public DoubleMatrix1D make(DoubleMatrix1D[] parts) {
+    if (parts.length == 0) {
+      return make(0);
+    }
+
+    int size = 0;
+    for (DoubleMatrix1D part1 : parts) {
+      size += part1.size();
+    }
+
+    DoubleMatrix1D vector = make(size);
+    size = 0;
+    for (DoubleMatrix1D part : parts) {
+      vector.viewPart(size, part.size()).assign(part);
+      size += part.size();
+    }
+
+    return vector;
+  }
+
+  /** Constructs a matrix with the given shape, each cell initialized with zero. */
+  public DoubleMatrix1D make(int size) {
+    if (this == sparse) {
+      return new SparseDoubleMatrix1D(size);
+    }
+    return new DenseDoubleMatrix1D(size);
+  }
+
+  /** Constructs a matrix with the given shape, each cell initialized with the given value. */
+  public DoubleMatrix1D make(int size, double initialValue) {
+    return make(size).assign(initialValue);
+  }
+
+  /**
+   * Constructs a matrix from the values of the given list. The values are copied. So subsequent changes in
+   * <tt>values</tt> are not reflected in the matrix, and vice-versa.
+   *
+   * @param values The values to be filled into the new matrix.
+   * @return a new matrix.
+   */
+  public DoubleMatrix1D make(AbstractDoubleList values) {
+    int size = values.size();
+    DoubleMatrix1D vector = make(size);
+    for (int i = size; --i >= 0;) {
+      vector.set(i, values.get(i));
+    }
+    return vector;
+  }
+
+  /** Constructs a matrix with uniformly distributed values in <tt>(0,1)</tt> (exclusive). */
+  public DoubleMatrix1D random(int size) {
+    return make(size).assign(Functions.random());
+  }
+
+  /**
+   * C = A||A||..||A; Constructs a new matrix which is concatenated <tt>repeat</tt> times. Example:
+   * <pre>
+   * 0 1
+   * repeat(3) -->
+   * 0 1 0 1 0 1
+   * </pre>
+   */
+  public DoubleMatrix1D repeat(DoubleMatrix1D A, int repeat) {
+    int size = A.size();
+    DoubleMatrix1D matrix = make(repeat * size);
+    for (int i = repeat; --i >= 0;) {
+      matrix.viewPart(size * i, size).assign(A);
+    }
+    return matrix;
+  }
+
+  /**
+   * Constructs a randomly sampled matrix with the given shape. Randomly picks exactly
+   * <tt>Math.round(size*nonZeroFraction)</tt> cells and initializes them to <tt>value</tt>, all the rest will be
+   * initialized to zero. Note that this is not the same as setting each cell with probability <tt>nonZeroFraction</tt>
+   * to <tt>value</tt>.
+   *
+   * @throws IllegalArgumentException if <tt>nonZeroFraction < 0 || nonZeroFraction > 1</tt>.
+   * @see org.apache.mahout.math.jet.random.sampling.RandomSampler
+   */
+  public DoubleMatrix1D sample(int size, double value, double nonZeroFraction) {
+    double epsilon = 1e-09;
+    if (nonZeroFraction < 0 - epsilon || nonZeroFraction > 1 + epsilon) {
+      throw new IllegalArgumentException();
+    }
+    if (nonZeroFraction < 0) {
+      nonZeroFraction = 0;
+    }
+    if (nonZeroFraction > 1) {
+      nonZeroFraction = 1;
+    }
+
+    DoubleMatrix1D matrix = make(size);
+
+    int n = (int) Math.round(size * nonZeroFraction);
+    if (n == 0) {
+      return matrix;
+    }
+
+    RandomSamplingAssistant sampler =
+        new RandomSamplingAssistant(n, size,
+            new MersenneTwister());
+    for (int i = size; --i >= 0;) {
+      if (sampler.sampleNextElement()) {
+        matrix.set(i, value);
+      }
+    }
+
+    return matrix;
+  }
+
+  /**
+   * Constructs a list from the given matrix. The values are copied. So subsequent changes in <tt>values</tt> are not
+   * reflected in the list, and vice-versa.
+   *
+   * @param values The values to be filled into the new list.
+   * @return a new list.
+   */
+  public org.apache.mahout.math.list.DoubleArrayList toList(DoubleMatrix1D values) {
+    int size = values.size();
+    DoubleArrayList list = new DoubleArrayList(size);
+    list.setSize(size);
+    for (int i = size; --i >= 0;) {
+      list.set(i, values.get(i));
+    }
+    return list;
+  }
+}

Propchange: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory1D.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory2D.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory2D.java?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory2D.java (added)
+++ lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory2D.java Thu Dec 17 23:22:16 2009
@@ -0,0 +1,745 @@
+/*
+Copyright � 1999 CERN - European Organization for Nuclear Research.
+Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose 
+is hereby granted without fee, provided that the above copyright notice appear in all copies and 
+that both that copyright notice and this permission notice appear in supporting documentation. 
+CERN makes no representations about the suitability of this software for any purpose. 
+It is provided "as is" without expressed or implied warranty.
+*/
+package org.apache.mahout.math.matrix;
+
+import org.apache.mahout.math.PersistentObject;
+import org.apache.mahout.math.jet.math.Functions;
+import org.apache.mahout.math.jet.random.engine.MersenneTwister;
+import org.apache.mahout.math.jet.random.sampling.RandomSamplingAssistant;
+import org.apache.mahout.math.matrix.impl.DenseDoubleMatrix2D;
+import org.apache.mahout.math.matrix.impl.RCDoubleMatrix2D;
+import org.apache.mahout.math.matrix.impl.SparseDoubleMatrix2D;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+/**
+ Factory for convenient construction of 2-d matrices holding <tt>double</tt>
+ cells. Also provides convenient methods to compose (concatenate) and decompose
+ (split) matrices from/to constituent blocks. </p>
+ <p>&nbsp; </p>
+ <table border="0" cellspacing="0">
+ <tr align="left" valign="top">
+ <td><i>Construction</i></td>
+ <td>Use idioms like <tt>DoubleFactory2D.dense.make(4,4)</tt> to construct
+ dense matrices, <tt>DoubleFactory2D.sparse.make(4,4)</tt> to construct sparse
+ matrices.</td>
+ </tr>
+ <tr align="left" valign="top">
+ <td><i> Construction with initial values </i></td>
+ <td>Use other <tt>make</tt> methods to construct matrices with given initial
+ values. </td>
+ </tr>
+ <tr align="left" valign="top">
+ <td><i> Appending rows and columns </i></td>
+ <td>Use methods {@link #appendColumns(DoubleMatrix2D,DoubleMatrix2D) appendColumns},
+ {@link #appendColumns(DoubleMatrix2D,DoubleMatrix2D) appendRows} and {@link
+#repeat(DoubleMatrix2D,int,int) repeat} to append rows and columns. </td>
+ </tr>
+ <tr align="left" valign="top">
+ <td><i> General block matrices </i></td>
+ <td>Use methods {@link #compose(DoubleMatrix2D[][]) compose} and {@link #decompose(DoubleMatrix2D[][],DoubleMatrix2D)
+decompose} to work with general block matrices. </td>
+ </tr>
+ <tr align="left" valign="top">
+ <td><i> Diagonal matrices </i></td>
+ <td>Use methods {@link #diagonal(DoubleMatrix1D) diagonal(vector)}, {@link
+#diagonal(DoubleMatrix2D) diagonal(matrix)} and {@link #identity(int) identity}
+ to work with diagonal matrices. </td>
+ </tr>
+ <tr align="left" valign="top">
+ <td><i> Diagonal block matrices </i></td>
+ <td>Use method {@link #composeDiagonal(DoubleMatrix2D,DoubleMatrix2D,DoubleMatrix2D)
+composeDiagonal} to work with diagonal block matrices. </td>
+ </tr>
+ <tr align="left" valign="top">
+ <td><i>Random</i></td>
+ <td>Use methods {@link #random(int,int) random} and {@link #sample(int,int,double,double)
+sample} to construct random matrices. </td>
+ </tr>
+ </table>
+ <p>&nbsp;</p>
+ <p>If the factory is used frequently it might be useful to streamline the notation.
+ For example by aliasing: </p>
+ <table>
+ <td class="PRE">
+ <pre>
+ DoubleFactory2D F = DoubleFactory2D.dense;
+ F.make(4,4);
+ F.descending(10,20);
+ F.random(4,4);
+ ...
+ </pre>
+ </td>
+ </table>
+
+ @author wolfgang.hoschek@cern.ch
+ @version 1.0, 09/24/99
+ */
+
+/** @deprecated until unit tests are in place.  Until this time, this class/interface is unsupported. */
+@Deprecated
+public class DoubleFactory2D extends PersistentObject {
+
+  private static final Logger log = LoggerFactory.getLogger(DoubleFactory2D.class);
+
+  /** A factory producing dense matrices. */
+  public static final DoubleFactory2D dense = new DoubleFactory2D();
+
+  /** A factory producing sparse hash matrices. */
+  private static final DoubleFactory2D sparse = new DoubleFactory2D();
+
+  /** A factory producing sparse row compressed matrices. */
+  private static final DoubleFactory2D rowCompressed = new DoubleFactory2D();
+
+  /*
+  * A factory producing sparse row compressed modified matrices.
+  */
+  //public static final DoubleFactory2D rowCompressedModified = new DoubleFactory2D();
+
+  /** Makes this class non instantiable, but still let's others inherit from it. */
+  protected DoubleFactory2D() {
+  }
+
+  /**
+   * C = A||B; Constructs a new matrix which is the column-wise concatenation of two other matrices.
+   * <pre>
+   * 0 1 2
+   * 3 4 5
+   * appendColumns
+   * 6 7
+   * 8 9
+   * -->
+   * 0 1 2 6 7
+   * 3 4 5 8 9
+   * </pre>
+   */
+  public DoubleMatrix2D appendColumns(DoubleMatrix2D A, DoubleMatrix2D B) {
+    // force both to have maximal shared number of rows.
+    if (B.rows() > A.rows()) {
+      B = B.viewPart(0, 0, A.rows(), B.columns());
+    } else if (B.rows() < A.rows()) {
+      A = A.viewPart(0, 0, B.rows(), A.columns());
+    }
+
+    // concatenate
+    int ac = A.columns();
+    int bc = B.columns();
+    int r = A.rows();
+    DoubleMatrix2D matrix = make(r, ac + bc);
+    matrix.viewPart(0, 0, r, ac).assign(A);
+    matrix.viewPart(0, ac, r, bc).assign(B);
+    return matrix;
+  }
+
+  /**
+   * C = A||B; Constructs a new matrix which is the row-wise concatenation of two other matrices.
+   * <pre>
+   * 0 1
+   * 2 3
+   * 4 5
+   * appendRows
+   * 6 7
+   * 8 9
+   * -->
+   * 0 1
+   * 2 3
+   * 4 5
+   * 6 7
+   * 8 9
+   * </pre>
+   */
+  public DoubleMatrix2D appendRows(DoubleMatrix2D A, DoubleMatrix2D B) {
+    // force both to have maximal shared number of columns.
+    if (B.columns() > A.columns()) {
+      B = B.viewPart(0, 0, B.rows(), A.columns());
+    } else if (B.columns() < A.columns()) {
+      A = A.viewPart(0, 0, A.rows(), B.columns());
+    }
+
+    // concatenate
+    int ar = A.rows();
+    int br = B.rows();
+    int c = A.columns();
+    DoubleMatrix2D matrix = make(ar + br, c);
+    matrix.viewPart(0, 0, ar, c).assign(A);
+    matrix.viewPart(ar, 0, br, c).assign(B);
+    return matrix;
+  }
+
+  /**
+   * Constructs a matrix with cells having ascending values. For debugging purposes. Example:
+   * <pre>
+   * 0 1 2
+   * 3 4 5
+   * </pre>
+   */
+  public DoubleMatrix2D ascending(int rows, int columns) {
+    return descending(rows, columns).assign(Functions.chain(Functions.neg, Functions.minus(columns * rows)));
+  }
+
+  /**
+   * Checks whether the given array is rectangular, that is, whether all rows have the same number of columns.
+   *
+   * @throws IllegalArgumentException if the array is not rectangular.
+   */
+  protected static void checkRectangularShape(double[][] array) {
+    int columns = -1;
+    for (int row = array.length; --row >= 0;) {
+      if (array[row] != null) {
+        if (columns == -1) {
+          columns = array[row].length;
+        }
+        if (array[row].length != columns) {
+          throw new IllegalArgumentException("All rows of array must have same number of columns.");
+        }
+      }
+    }
+  }
+
+  /**
+   * Checks whether the given array is rectangular, that is, whether all rows have the same number of columns.
+   *
+   * @throws IllegalArgumentException if the array is not rectangular.
+   */
+  private static void checkRectangularShape(DoubleMatrix2D[][] array) {
+    int columns = -1;
+    for (int row = array.length; --row >= 0;) {
+      if (array[row] != null) {
+        if (columns == -1) {
+          columns = array[row].length;
+        }
+        if (array[row].length != columns) {
+          throw new IllegalArgumentException("All rows of array must have same number of columns.");
+        }
+      }
+    }
+  }
+
+  /**
+   * Constructs a block matrix made from the given parts. The inverse to method {@link #decompose(DoubleMatrix2D[][],
+   * DoubleMatrix2D)}. <p> All matrices of a given column within <tt>parts</tt> must have the same number of columns.
+   * All matrices of a given row within <tt>parts</tt> must have the same number of rows. Otherwise an
+   * <tt>IllegalArgumentException</tt> is thrown. Note that <tt>null</tt>s within <tt>parts[row,col]</tt> are an
+   * exception to this rule: they are ignored. Cells are copied. Example: <table border="1" cellspacing="0"> <tr
+   * align="left" valign="top"> <td><tt>Code</tt></td> <td><tt>Result</tt></td> </tr> <tr align="left" valign="top">
+   * <td>
+   * <pre>
+   * DoubleMatrix2D[][] parts1 =
+   * {
+   * &nbsp;&nbsp;&nbsp;{ null,        make(2,2,1), null        },
+   * &nbsp;&nbsp;&nbsp;{ make(4,4,2), null,        make(4,3,3) },
+   * &nbsp;&nbsp;&nbsp;{ null,        make(2,2,4), null        }
+   * };
+   * log.info(compose(parts1));
+   * </pre>
+   * </td> <td><tt>8&nbsp;x&nbsp;9&nbsp;matrix<br> 0&nbsp;0&nbsp;0&nbsp;0&nbsp;1&nbsp;1&nbsp;0&nbsp;0&nbsp;0<br>
+   * 0&nbsp;0&nbsp;0&nbsp;0&nbsp;1&nbsp;1&nbsp;0&nbsp;0&nbsp;0<br> 2&nbsp;2&nbsp;2&nbsp;2&nbsp;0&nbsp;0&nbsp;3&nbsp;3&nbsp;3<br>
+   * 2&nbsp;2&nbsp;2&nbsp;2&nbsp;0&nbsp;0&nbsp;3&nbsp;3&nbsp;3<br> 2&nbsp;2&nbsp;2&nbsp;2&nbsp;0&nbsp;0&nbsp;3&nbsp;3&nbsp;3<br>
+   * 2&nbsp;2&nbsp;2&nbsp;2&nbsp;0&nbsp;0&nbsp;3&nbsp;3&nbsp;3<br> 0&nbsp;0&nbsp;0&nbsp;0&nbsp;4&nbsp;4&nbsp;0&nbsp;0&nbsp;0<br>
+   * 0&nbsp;0&nbsp;0&nbsp;0&nbsp;4&nbsp;4&nbsp;0&nbsp;0&nbsp;0</tt></td> </tr> <tr align="left" valign="top"> <td>
+   * <pre>
+   * DoubleMatrix2D[][] parts3 =
+   * {
+   * &nbsp;&nbsp;&nbsp;{ identity(3),               null,                        },
+   * &nbsp;&nbsp;&nbsp;{ null,                      identity(3).viewColumnFlip() },
+   * &nbsp;&nbsp;&nbsp;{ identity(3).viewRowFlip(), null                         }
+   * };
+   * log.info("\n"+make(parts3));
+   * </pre>
+   * </td> <td><tt>9&nbsp;x&nbsp;6&nbsp;matrix<br> 1&nbsp;0&nbsp;0&nbsp;0&nbsp;0&nbsp;0<br>
+   * 0&nbsp;1&nbsp;0&nbsp;0&nbsp;0&nbsp;0<br> 0&nbsp;0&nbsp;1&nbsp;0&nbsp;0&nbsp;0<br>
+   * 0&nbsp;0&nbsp;0&nbsp;0&nbsp;0&nbsp;1<br> 0&nbsp;0&nbsp;0&nbsp;0&nbsp;1&nbsp;0<br>
+   * 0&nbsp;0&nbsp;0&nbsp;1&nbsp;0&nbsp;0<br> 0&nbsp;0&nbsp;1&nbsp;0&nbsp;0&nbsp;0<br>
+   * 0&nbsp;1&nbsp;0&nbsp;0&nbsp;0&nbsp;0<br> 1&nbsp;0&nbsp;0&nbsp;0&nbsp;0&nbsp;0 </tt></td> </tr> <tr align="left"
+   * valign="top"> <td>
+   * <pre>
+   * DoubleMatrix2D A = ascending(2,2);
+   * DoubleMatrix2D B = descending(2,2);
+   * DoubleMatrix2D _ = null;
+   *
+   * DoubleMatrix2D[][] parts4 =
+   * {
+   * &nbsp;&nbsp;&nbsp;{ A, _, A, _ },
+   * &nbsp;&nbsp;&nbsp;{ _, A, _, B }
+   * };
+   * log.info("\n"+make(parts4));
+   * </pre>
+   * </td> <td><tt>4&nbsp;x&nbsp;8&nbsp;matrix<br> 1&nbsp;2&nbsp;0&nbsp;0&nbsp;1&nbsp;2&nbsp;0&nbsp;0<br>
+   * 3&nbsp;4&nbsp;0&nbsp;0&nbsp;3&nbsp;4&nbsp;0&nbsp;0<br> 0&nbsp;0&nbsp;1&nbsp;2&nbsp;0&nbsp;0&nbsp;3&nbsp;2<br>
+   * 0&nbsp;0&nbsp;3&nbsp;4&nbsp;0&nbsp;0&nbsp;1&nbsp;0 </tt></td> </tr> <tr align="left" valign="top"> <td>
+   * <pre>
+   * DoubleMatrix2D[][] parts2 =
+   * {
+   * &nbsp;&nbsp;&nbsp;{ null,        make(2,2,1), null        },
+   * &nbsp;&nbsp;&nbsp;{ make(4,4,2), null,        make(4,3,3) },
+   * &nbsp;&nbsp;&nbsp;{ null,        make(2,3,4), null        }
+   * };
+   * log.info("\n"+Factory2D.make(parts2));
+   * </pre>
+   * </td> <td><tt>IllegalArgumentException<br> A[0,1].cols != A[2,1].cols<br> (2 != 3)</tt></td> </tr> </table>
+   *
+   * @throws IllegalArgumentException subject to the conditions outlined above.
+   */
+  public DoubleMatrix2D compose(DoubleMatrix2D[][] parts) {
+    checkRectangularShape(parts);
+    int rows = parts.length;
+    int columns = 0;
+    if (parts.length > 0) {
+      columns = parts[0].length;
+    }
+    DoubleMatrix2D empty = make(0, 0);
+
+    if (rows == 0 || columns == 0) {
+      return empty;
+    }
+
+    // determine maximum column width of each column
+    int[] maxWidths = new int[columns];
+    for (int column = columns; --column >= 0;) {
+      int maxWidth = 0;
+      for (int row = rows; --row >= 0;) {
+        DoubleMatrix2D part = parts[row][column];
+        if (part != null) {
+          int width = part.columns();
+          if (maxWidth > 0 && width > 0 && width != maxWidth) {
+            throw new IllegalArgumentException("Different number of columns.");
+          }
+          maxWidth = Math.max(maxWidth, width);
+        }
+      }
+      maxWidths[column] = maxWidth;
+    }
+
+    // determine row height of each row
+    int[] maxHeights = new int[rows];
+    for (int row = rows; --row >= 0;) {
+      int maxHeight = 0;
+      for (int column = columns; --column >= 0;) {
+        DoubleMatrix2D part = parts[row][column];
+        if (part != null) {
+          int height = part.rows();
+          if (maxHeight > 0 && height > 0 && height != maxHeight) {
+            throw new IllegalArgumentException("Different number of rows.");
+          }
+          maxHeight = Math.max(maxHeight, height);
+        }
+      }
+      maxHeights[row] = maxHeight;
+    }
+
+
+    // shape of result
+    int resultRows = 0;
+    for (int row = rows; --row >= 0;) {
+      resultRows += maxHeights[row];
+    }
+    int resultCols = 0;
+    for (int column = columns; --column >= 0;) {
+      resultCols += maxWidths[column];
+    }
+
+    DoubleMatrix2D matrix = make(resultRows, resultCols);
+
+    // copy
+    int r = 0;
+    for (int row = 0; row < rows; row++) {
+      int c = 0;
+      for (int column = 0; column < columns; column++) {
+        DoubleMatrix2D part = parts[row][column];
+        if (part != null) {
+          matrix.viewPart(r, c, part.rows(), part.columns()).assign(part);
+        }
+        c += maxWidths[column];
+      }
+      r += maxHeights[row];
+    }
+
+    return matrix;
+  }
+
+  /**
+   * Constructs a diagonal block matrix from the given parts (the <i>direct sum</i> of two matrices). That is the
+   * concatenation
+   * <pre>
+   * A 0
+   * 0 B
+   * </pre>
+   * (The direct sum has <tt>A.rows()+B.rows()</tt> rows and <tt>A.columns()+B.columns()</tt> columns). Cells are
+   * copied.
+   *
+   * @return a new matrix which is the direct sum.
+   */
+  public DoubleMatrix2D composeDiagonal(DoubleMatrix2D A, DoubleMatrix2D B) {
+    int ar = A.rows();
+    int ac = A.columns();
+    int br = B.rows();
+    int bc = B.columns();
+    DoubleMatrix2D sum = make(ar + br, ac + bc);
+    sum.viewPart(0, 0, ar, ac).assign(A);
+    sum.viewPart(ar, ac, br, bc).assign(B);
+    return sum;
+  }
+
+  /**
+   * Constructs a diagonal block matrix from the given parts. The concatenation has the form
+   * <pre>
+   * A 0 0
+   * 0 B 0
+   * 0 0 C
+   * </pre>
+   * from the given parts. Cells are copied.
+   */
+  public DoubleMatrix2D composeDiagonal(DoubleMatrix2D A, DoubleMatrix2D B, DoubleMatrix2D C) {
+    DoubleMatrix2D diag = make(A.rows() + B.rows() + C.rows(), A.columns() + B.columns() + C.columns());
+    diag.viewPart(0, 0, A.rows(), A.columns()).assign(A);
+    diag.viewPart(A.rows(), A.columns(), B.rows(), B.columns()).assign(B);
+    diag.viewPart(A.rows() + B.rows(), A.columns() + B.columns(), C.rows(), C.columns()).assign(C);
+    return diag;
+  }
+
+  /**
+   * Splits a block matrix into its constituent blocks; Copies blocks of a matrix into the given parts. The inverse to
+   * method {@link #compose(DoubleMatrix2D[][])}. <p> All matrices of a given column within <tt>parts</tt> must have the
+   * same number of columns. All matrices of a given row within <tt>parts</tt> must have the same number of rows.
+   * Otherwise an <tt>IllegalArgumentException</tt> is thrown. Note that <tt>null</tt>s within <tt>parts[row,col]</tt>
+   * are an exception to this rule: they are ignored. Cells are copied. Example: <table border="1" cellspacing="0"> <tr
+   * align="left" valign="top"> <td><tt>Code</tt></td> <td><tt>matrix</tt></td> <td><tt>--&gt; parts </tt></td> </tr>
+   * <tr align="left" valign="top"> <td>
+   * <pre>
+   * DoubleMatrix2D matrix = ... ;
+   * DoubleMatrix2D _ = null;
+   * DoubleMatrix2D A,B,C,D;
+   * A = make(2,2); B = make (4,4);
+   * C = make(4,3); D = make (2,2);
+   * DoubleMatrix2D[][] parts =
+   * {
+   * &nbsp;&nbsp;&nbsp;{ _, A, _ },
+   * &nbsp;&nbsp;&nbsp;{ B, _, C },
+   * &nbsp;&nbsp;&nbsp;{ _, D, _ }
+   * };
+   * decompose(parts,matrix);
+   * log.info(&quot;\nA = &quot;+A);
+   * log.info(&quot;\nB = &quot;+B);
+   * log.info(&quot;\nC = &quot;+C);
+   * log.info(&quot;\nD = &quot;+D);
+   * </pre>
+   * </td> <td><tt>8&nbsp;x&nbsp;9&nbsp;matrix<br> 9&nbsp;9&nbsp;9&nbsp;9&nbsp;1&nbsp;1&nbsp;9&nbsp;9&nbsp;9<br>
+   * 9&nbsp;9&nbsp;9&nbsp;9&nbsp;1&nbsp;1&nbsp;9&nbsp;9&nbsp;9<br> 2&nbsp;2&nbsp;2&nbsp;2&nbsp;9&nbsp;9&nbsp;3&nbsp;3&nbsp;3<br>
+   * 2&nbsp;2&nbsp;2&nbsp;2&nbsp;9&nbsp;9&nbsp;3&nbsp;3&nbsp;3<br> 2&nbsp;2&nbsp;2&nbsp;2&nbsp;9&nbsp;9&nbsp;3&nbsp;3&nbsp;3<br>
+   * 2&nbsp;2&nbsp;2&nbsp;2&nbsp;9&nbsp;9&nbsp;3&nbsp;3&nbsp;3<br> 9&nbsp;9&nbsp;9&nbsp;9&nbsp;4&nbsp;4&nbsp;9&nbsp;9&nbsp;9<br>
+   * 9&nbsp;9&nbsp;9&nbsp;9&nbsp;4&nbsp;4&nbsp;9&nbsp;9&nbsp;9</tt></td> <td> <p><tt>A = 2&nbsp;x&nbsp;2&nbsp;matrix<br>
+   * 1&nbsp;1<br> 1&nbsp;1</tt></p> <p><tt>B = 4&nbsp;x&nbsp;4&nbsp;matrix<br> 2&nbsp;2&nbsp;2&nbsp;2<br>
+   * 2&nbsp;2&nbsp;2&nbsp;2<br> 2&nbsp;2&nbsp;2&nbsp;2<br> 2&nbsp;2&nbsp;2&nbsp;2</tt></p> <p><tt>C =
+   * 4&nbsp;x&nbsp;3&nbsp;matrix<br> 3&nbsp;3&nbsp;3<br> 3&nbsp;3&nbsp;3<br> </tt><tt>3&nbsp;3&nbsp;3<br>
+   * </tt><tt>3&nbsp;3&nbsp;3</tt></p> <p><tt>D = 2&nbsp;x&nbsp;2&nbsp;matrix<br> 4&nbsp;4<br> 4&nbsp;4</tt></p> </td>
+   * </tr> </table>
+   *
+   * @throws IllegalArgumentException subject to the conditions outlined above.
+   */
+  public void decompose(DoubleMatrix2D[][] parts, DoubleMatrix2D matrix) {
+    checkRectangularShape(parts);
+    int rows = parts.length;
+    int columns = 0;
+    if (parts.length > 0) {
+      columns = parts[0].length;
+    }
+    if (rows == 0 || columns == 0) {
+      return;
+    }
+
+    // determine maximum column width of each column
+    int[] maxWidths = new int[columns];
+    for (int column = columns; --column >= 0;) {
+      int maxWidth = 0;
+      for (int row = rows; --row >= 0;) {
+        DoubleMatrix2D part = parts[row][column];
+        if (part != null) {
+          int width = part.columns();
+          if (maxWidth > 0 && width > 0 && width != maxWidth) {
+            throw new IllegalArgumentException("Different number of columns.");
+          }
+          maxWidth = Math.max(maxWidth, width);
+        }
+      }
+      maxWidths[column] = maxWidth;
+    }
+
+    // determine row height of each row
+    int[] maxHeights = new int[rows];
+    for (int row = rows; --row >= 0;) {
+      int maxHeight = 0;
+      for (int column = columns; --column >= 0;) {
+        DoubleMatrix2D part = parts[row][column];
+        if (part != null) {
+          int height = part.rows();
+          if (maxHeight > 0 && height > 0 && height != maxHeight) {
+            throw new IllegalArgumentException("Different number of rows.");
+          }
+          maxHeight = Math.max(maxHeight, height);
+        }
+      }
+      maxHeights[row] = maxHeight;
+    }
+
+
+    // shape of result parts
+    int resultRows = 0;
+    for (int row = rows; --row >= 0;) {
+      resultRows += maxHeights[row];
+    }
+    int resultCols = 0;
+    for (int column = columns; --column >= 0;) {
+      resultCols += maxWidths[column];
+    }
+
+    if (matrix.rows() < resultRows || matrix.columns() < resultCols) {
+      throw new IllegalArgumentException("Parts larger than matrix.");
+    }
+
+    // copy
+    int r = 0;
+    for (int row = 0; row < rows; row++) {
+      int c = 0;
+      for (int column = 0; column < columns; column++) {
+        DoubleMatrix2D part = parts[row][column];
+        if (part != null) {
+          part.assign(matrix.viewPart(r, c, part.rows(), part.columns()));
+        }
+        c += maxWidths[column];
+      }
+      r += maxHeights[row];
+    }
+
+  }
+
+  /**
+   * Constructs a matrix with cells having descending values. For debugging purposes. Example:
+   * <pre>
+   * 5 4 3
+   * 2 1 0
+   * </pre>
+   */
+  public DoubleMatrix2D descending(int rows, int columns) {
+    DoubleMatrix2D matrix = make(rows, columns);
+    int v = 0;
+    for (int row = rows; --row >= 0;) {
+      for (int column = columns; --column >= 0;) {
+        matrix.setQuick(row, column, v++);
+      }
+    }
+    return matrix;
+  }
+
+  /**
+   * Constructs a new diagonal matrix whose diagonal elements are the elements of <tt>vector</tt>. Cells values are
+   * copied. The new matrix is not a view. Example:
+   * <pre>
+   * 5 4 3 -->
+   * 5 0 0
+   * 0 4 0
+   * 0 0 3
+   * </pre>
+   *
+   * @return a new matrix.
+   */
+  public DoubleMatrix2D diagonal(DoubleMatrix1D vector) {
+    int size = vector.size();
+    DoubleMatrix2D diag = make(size, size);
+    for (int i = size; --i >= 0;) {
+      diag.setQuick(i, i, vector.getQuick(i));
+    }
+    return diag;
+  }
+
+  /**
+   * Constructs a new vector consisting of the diagonal elements of <tt>A</tt>. Cells values are copied. The new vector
+   * is not a view. Example:
+   * <pre>
+   * 5 0 0 9
+   * 0 4 0 9
+   * 0 0 3 9
+   * --> 5 4 3
+   * </pre>
+   *
+   * @param A the matrix, need not be square.
+   * @return a new vector.
+   */
+  public DoubleMatrix1D diagonal(DoubleMatrix2D A) {
+    int min = Math.min(A.rows(), A.columns());
+    DoubleMatrix1D diag = make1D(min);
+    for (int i = min; --i >= 0;) {
+      diag.setQuick(i, A.getQuick(i, i));
+    }
+    return diag;
+  }
+
+  /** Constructs an identity matrix (having ones on the diagonal and zeros elsewhere). */
+  public DoubleMatrix2D identity(int rowsAndColumns) {
+    DoubleMatrix2D matrix = make(rowsAndColumns, rowsAndColumns);
+    for (int i = rowsAndColumns; --i >= 0;) {
+      matrix.setQuick(i, i, 1);
+    }
+    return matrix;
+  }
+
+  /**
+   * Constructs a matrix with the given cell values. <tt>values</tt> is required to have the form
+   * <tt>values[row][column]</tt> and have exactly the same number of columns in every row. <p> The values are copied.
+   * So subsequent changes in <tt>values</tt> are not reflected in the matrix, and vice-versa.
+   *
+   * @param values The values to be filled into the new matrix.
+   * @throws IllegalArgumentException if <tt>for any 1 &lt;= row &lt; values.length: values[row].length !=
+   *                                  values[row-1].length</tt>.
+   */
+  public DoubleMatrix2D make(double[][] values) {
+    if (this == sparse) {
+      return new SparseDoubleMatrix2D(values);
+    } else {
+      return new DenseDoubleMatrix2D(values);
+    }
+  }
+
+  /**
+   * Construct a matrix from a one-dimensional column-major packed array, ala Fortran. Has the form
+   * <tt>matrix.get(row,column) == values[row + column*rows]</tt>. The values are copied.
+   *
+   * @param values One-dimensional array of doubles, packed by columns (ala Fortran).
+   * @param rows   the number of rows.
+   * @throws IllegalArgumentException <tt>values.length</tt> must be a multiple of <tt>rows</tt>.
+   */
+  public DoubleMatrix2D make(double[] values, int rows) {
+    int columns = (rows != 0 ? values.length / rows : 0);
+    if (rows * columns != values.length) {
+      throw new IllegalArgumentException("Array length must be a multiple of m.");
+    }
+
+    DoubleMatrix2D matrix = make(rows, columns);
+    for (int row = 0; row < rows; row++) {
+      for (int column = 0; column < columns; column++) {
+        matrix.setQuick(row, column, values[row + column * rows]);
+      }
+    }
+    return matrix;
+  }
+
+  /** Constructs a matrix with the given shape, each cell initialized with zero. */
+  public DoubleMatrix2D make(int rows, int columns) {
+    if (this == sparse) {
+      return new SparseDoubleMatrix2D(rows, columns);
+    }
+    if (this == rowCompressed) {
+      return new RCDoubleMatrix2D(rows, columns);
+    }
+    //if (this==rowCompressedModified) return new RCMDoubleMatrix2D(rows,columns);
+    else {
+      return new DenseDoubleMatrix2D(rows, columns);
+    }
+  }
+
+  /** Constructs a matrix with the given shape, each cell initialized with the given value. */
+  public DoubleMatrix2D make(int rows, int columns, double initialValue) {
+    if (initialValue == 0) {
+      return make(rows, columns);
+    }
+    return make(rows, columns).assign(initialValue);
+  }
+
+  /** Constructs a 1d matrix of the right dynamic type. */
+  protected DoubleMatrix1D make1D(int size) {
+    return make(0, 0).like1D(size);
+  }
+
+  /** Constructs a matrix with uniformly distributed values in <tt>(0,1)</tt> (exclusive). */
+  public DoubleMatrix2D random(int rows, int columns) {
+    return make(rows, columns).assign(Functions.random());
+  }
+
+  /**
+   * C = A||A||..||A; Constructs a new matrix which is duplicated both along the row and column dimension. Example:
+   * <pre>
+   * 0 1
+   * 2 3
+   * repeat(2,3) -->
+   * 0 1 0 1 0 1
+   * 2 3 2 3 2 3
+   * 0 1 0 1 0 1
+   * 2 3 2 3 2 3
+   * </pre>
+   */
+  public DoubleMatrix2D repeat(DoubleMatrix2D A, int rowRepeat, int columnRepeat) {
+    int r = A.rows();
+    int c = A.columns();
+    DoubleMatrix2D matrix = make(r * rowRepeat, c * columnRepeat);
+    for (int i = rowRepeat; --i >= 0;) {
+      for (int j = columnRepeat; --j >= 0;) {
+        matrix.viewPart(r * i, c * j, r, c).assign(A);
+      }
+    }
+    return matrix;
+  }
+
+  /**
+   * Constructs a randomly sampled matrix with the given shape. Randomly picks exactly
+   * <tt>Math.round(rows*columns*nonZeroFraction)</tt> cells and initializes them to <tt>value</tt>, all the rest will
+   * be initialized to zero. Note that this is not the same as setting each cell with probability
+   * <tt>nonZeroFraction</tt> to <tt>value</tt>. Note: The random seed is a constant.
+   *
+   * @throws IllegalArgumentException if <tt>nonZeroFraction < 0 || nonZeroFraction > 1</tt>.
+   * @see org.apache.mahout.math.jet.random.sampling.RandomSampler
+   */
+  public DoubleMatrix2D sample(int rows, int columns, double value, double nonZeroFraction) {
+    DoubleMatrix2D matrix = make(rows, columns);
+    sample(matrix, value, nonZeroFraction);
+    return matrix;
+  }
+
+  /**
+   * Modifies the given matrix to be a randomly sampled matrix. Randomly picks exactly
+   * <tt>Math.round(rows*columns*nonZeroFraction)</tt> cells and initializes them to <tt>value</tt>, all the rest will
+   * be initialized to zero. Note that this is not the same as setting each cell with probability
+   * <tt>nonZeroFraction</tt> to <tt>value</tt>. Note: The random seed is a constant.
+   *
+   * @throws IllegalArgumentException if <tt>nonZeroFraction < 0 || nonZeroFraction > 1</tt>.
+   * @see org.apache.mahout.math.jet.random.sampling.RandomSampler
+   */
+  public DoubleMatrix2D sample(DoubleMatrix2D matrix, double value, double nonZeroFraction) {
+    int rows = matrix.rows();
+    int columns = matrix.columns();
+    double epsilon = 1e-09;
+    if (nonZeroFraction < 0 - epsilon || nonZeroFraction > 1 + epsilon) {
+      throw new IllegalArgumentException();
+    }
+    if (nonZeroFraction < 0) {
+      nonZeroFraction = 0;
+    }
+    if (nonZeroFraction > 1) {
+      nonZeroFraction = 1;
+    }
+
+    matrix.assign(0);
+
+    int size = rows * columns;
+    int n = (int) Math.round(size * nonZeroFraction);
+    if (n == 0) {
+      return matrix;
+    }
+
+    RandomSamplingAssistant sampler =
+        new RandomSamplingAssistant(n, size,
+            new MersenneTwister());
+    for (int i = 0; i < size; i++) {
+      if (sampler.sampleNextElement()) {
+        int row = i / columns;
+        int column = i % columns;
+        matrix.set(row, column, value);
+      }
+    }
+
+    return matrix;
+  }
+}

Propchange: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory2D.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory3D.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory3D.java?rev=891983&view=auto
==============================================================================
--- lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory3D.java (added)
+++ lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory3D.java Thu Dec 17 23:22:16 2009
@@ -0,0 +1,87 @@
+/*
+Copyright � 1999 CERN - European Organization for Nuclear Research.
+Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose 
+is hereby granted without fee, provided that the above copyright notice appear in all copies and 
+that both that copyright notice and this permission notice appear in supporting documentation. 
+CERN makes no representations about the suitability of this software for any purpose. 
+It is provided "as is" without expressed or implied warranty.
+*/
+package org.apache.mahout.math.matrix;
+
+import org.apache.mahout.math.PersistentObject;
+import org.apache.mahout.math.jet.math.Functions;
+import org.apache.mahout.math.matrix.impl.DenseDoubleMatrix3D;
+import org.apache.mahout.math.matrix.impl.SparseDoubleMatrix3D;
+
+/** @deprecated until unit tests are in place.  Until this time, this class/interface is unsupported. */
+@Deprecated
+public class DoubleFactory3D extends PersistentObject {
+
+  /** A factory producing dense matrices. */
+  public static final DoubleFactory3D dense = new DoubleFactory3D();
+
+  /** A factory producing sparse matrices. */
+  private static final DoubleFactory3D sparse = new DoubleFactory3D();
+
+  /** Makes this class non instantiable, but still let's others inherit from it. */
+  protected DoubleFactory3D() {
+  }
+
+  /** Constructs a matrix with cells having ascending values. For debugging purposes. */
+  public DoubleMatrix3D ascending(int slices, int rows, int columns) {
+    return descending(slices, rows, columns)
+        .assign(Functions.chain(Functions.neg, Functions.minus(slices * rows * columns)));
+  }
+
+  /** Constructs a matrix with cells having descending values. For debugging purposes. */
+  public DoubleMatrix3D descending(int slices, int rows, int columns) {
+    DoubleMatrix3D matrix = make(slices, rows, columns);
+    int v = 0;
+    for (int slice = slices; --slice >= 0;) {
+      for (int row = rows; --row >= 0;) {
+        for (int column = columns; --column >= 0;) {
+          matrix.setQuick(slice, row, column, v++);
+        }
+      }
+    }
+    return matrix;
+  }
+
+  /**
+   * Constructs a matrix with the given cell values. <tt>values</tt> is required to have the form
+   * <tt>values[slice][row][column]</tt> and have exactly the same number of slices, rows and columns as the receiver.
+   * <p> The values are copied. So subsequent changes in <tt>values</tt> are not reflected in the matrix, and
+   * vice-versa.
+   *
+   * @param values the values to be filled into the cells.
+   * @return <tt>this</tt> (for convenience only).
+   * @throws IllegalArgumentException if <tt>values.length != slices() || for any 0 &lt;= slice &lt; slices():
+   *                                  values[slice].length != rows()</tt>.
+   * @throws IllegalArgumentException if <tt>for any 0 &lt;= column &lt; columns(): values[slice][row].length !=
+   *                                  columns()</tt>.
+   */
+  public DoubleMatrix3D make(double[][][] values) {
+    if (this == sparse) {
+      return new SparseDoubleMatrix3D(values);
+    }
+    return new DenseDoubleMatrix3D(values);
+  }
+
+  /** Constructs a matrix with the given shape, each cell initialized with zero. */
+  public DoubleMatrix3D make(int slices, int rows, int columns) {
+    if (this == sparse) {
+      return new SparseDoubleMatrix3D(slices, rows, columns);
+    }
+    return new DenseDoubleMatrix3D(slices, rows, columns);
+  }
+
+  /** Constructs a matrix with the given shape, each cell initialized with the given value. */
+  public DoubleMatrix3D make(int slices, int rows, int columns, double initialValue) {
+    return make(slices, rows, columns).assign(initialValue);
+  }
+
+  /** Constructs a matrix with uniformly distributed values in <tt>(0,1)</tt> (exclusive). */
+  public DoubleMatrix3D random(int slices, int rows, int columns) {
+    return make(slices, rows, columns).assign(Functions.random());
+  }
+}

Propchange: lucene/mahout/trunk/math/src/main/java/org/apache/mahout/math/matrix/DoubleFactory3D.java
------------------------------------------------------------------------------
    svn:eol-style = native