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>>= desiredCapacity</code> and very close to <code>desiredCapacity</code>
+ * (within 11% if <code>desiredCapacity >= 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><Implementation><KeyType><ValueType>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<KeyType><ValueType></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 < 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 <= loadFactor <= 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 > 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 < 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> </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> </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 =
+ * {
+ * { null, make(2,2,1), null },
+ * { make(4,4,2), null, make(4,3,3) },
+ * { null, make(2,2,4), null }
+ * };
+ * log.info(compose(parts1));
+ * </pre>
+ * </td> <td><tt>8 x 9 matrix<br> 0 0 0 0 1 1 0 0 0<br>
+ * 0 0 0 0 1 1 0 0 0<br> 2 2 2 2 0 0 3 3 3<br>
+ * 2 2 2 2 0 0 3 3 3<br> 2 2 2 2 0 0 3 3 3<br>
+ * 2 2 2 2 0 0 3 3 3<br> 0 0 0 0 4 4 0 0 0<br>
+ * 0 0 0 0 4 4 0 0 0</tt></td> </tr> <tr align="left" valign="top"> <td>
+ * <pre>
+ * DoubleMatrix2D[][] parts3 =
+ * {
+ * { identity(3), null, },
+ * { null, identity(3).viewColumnFlip() },
+ * { identity(3).viewRowFlip(), null }
+ * };
+ * log.info("\n"+make(parts3));
+ * </pre>
+ * </td> <td><tt>9 x 6 matrix<br> 1 0 0 0 0 0<br>
+ * 0 1 0 0 0 0<br> 0 0 1 0 0 0<br>
+ * 0 0 0 0 0 1<br> 0 0 0 0 1 0<br>
+ * 0 0 0 1 0 0<br> 0 0 1 0 0 0<br>
+ * 0 1 0 0 0 0<br> 1 0 0 0 0 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 =
+ * {
+ * { A, _, A, _ },
+ * { _, A, _, B }
+ * };
+ * log.info("\n"+make(parts4));
+ * </pre>
+ * </td> <td><tt>4 x 8 matrix<br> 1 2 0 0 1 2 0 0<br>
+ * 3 4 0 0 3 4 0 0<br> 0 0 1 2 0 0 3 2<br>
+ * 0 0 3 4 0 0 1 0 </tt></td> </tr> <tr align="left" valign="top"> <td>
+ * <pre>
+ * DoubleMatrix2D[][] parts2 =
+ * {
+ * { null, make(2,2,1), null },
+ * { make(4,4,2), null, make(4,3,3) },
+ * { 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>--> 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 =
+ * {
+ * { _, A, _ },
+ * { B, _, C },
+ * { _, D, _ }
+ * };
+ * decompose(parts,matrix);
+ * log.info("\nA = "+A);
+ * log.info("\nB = "+B);
+ * log.info("\nC = "+C);
+ * log.info("\nD = "+D);
+ * </pre>
+ * </td> <td><tt>8 x 9 matrix<br> 9 9 9 9 1 1 9 9 9<br>
+ * 9 9 9 9 1 1 9 9 9<br> 2 2 2 2 9 9 3 3 3<br>
+ * 2 2 2 2 9 9 3 3 3<br> 2 2 2 2 9 9 3 3 3<br>
+ * 2 2 2 2 9 9 3 3 3<br> 9 9 9 9 4 4 9 9 9<br>
+ * 9 9 9 9 4 4 9 9 9</tt></td> <td> <p><tt>A = 2 x 2 matrix<br>
+ * 1 1<br> 1 1</tt></p> <p><tt>B = 4 x 4 matrix<br> 2 2 2 2<br>
+ * 2 2 2 2<br> 2 2 2 2<br> 2 2 2 2</tt></p> <p><tt>C =
+ * 4 x 3 matrix<br> 3 3 3<br> 3 3 3<br> </tt><tt>3 3 3<br>
+ * </tt><tt>3 3 3</tt></p> <p><tt>D = 2 x 2 matrix<br> 4 4<br> 4 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 <= row < 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 <= slice < slices():
+ * values[slice].length != rows()</tt>.
+ * @throws IllegalArgumentException if <tt>for any 0 <= column < 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