[jblas] 06/24: Imported Upstream version 1.0.1

Tony Mancill tmancill at moszumanska.debian.org
Sun Jan 5 05:45:57 UTC 2014


This is an automated email from the git hooks/post-receive script.

tmancill pushed a commit to branch master
in repository jblas.

commit f3f32233fd1e488351723e495477040366e70971
Author: tony mancill <tmancill at debian.org>
Date:   Tue Dec 31 15:19:19 2013 -0800

    Imported Upstream version 1.0.1
---
 AUTHORS                                            |  10 +-
 BUGS                                               |   8 +
 BUILDING_ATLAS                                     | 198 ++++++++++
 INSTALL                                            | 226 ++++-------
 Makefile                                           |  84 +++-
 README                                             |  31 +-
 RELEASE_NOTES                                      |  38 ++
 ROADMAP                                            |   9 +
 build.xml                                          | 108 +++---
 config/arch_flavor.c                               |  54 +++
 config/config.rb                                   | 300 ++++++++++----
 config/{path.rb => config_cc.rb}                   | 111 ++++--
 config/{path.rb => config_fortran.rb}              |  76 ++--
 config/{path.rb => config_java.rb}                 |  73 ++--
 config/{path.rb => config_lapack_sources.rb}       |  78 ++--
 config/config_libs.rb                              | 154 ++++++++
 config/{path.rb => config_make.rb}                 |  59 ++-
 config/{path.rb => config_os_arch.rb}              |  95 +++--
 config/{path.rb => config_tools.rb}                |  62 ++-
 config/configure.rb                                | 430 ++-------------------
 config/lib_helpers.rb                              | 166 ++++++++
 config/path.rb                                     |  91 +++--
 config/{path.rb => string_ext.rb}                  |  54 +--
 docs/jblas-logo-64.png                             | Bin 0 -> 2477 bytes
 docs/jblas-logo-square.png                         | Bin 0 -> 1369 bytes
 native/jblas_arch_flavor.c                         |  54 +++
 nbproject/private/private.xml                      |   5 -
 nbproject/project.xml                              |   4 +-
 scripts/java-class.java                            |  28 +-
 scripts/static_class_to_float.rb                   |   2 +-
 src/org/jblas/Decompose.java                       |  17 +
 src/org/jblas/DoubleMatrix.java                    | 310 ++++++++++-----
 src/org/jblas/FloatMatrix.java                     | 310 ++++++++++-----
 src/org/jblas/MatrixFunctions.java                 | 118 ++++++
 src/org/jblas/NativeBlas.java                      |  28 +-
 .../ATLASDoubleMultiplicationBenchmark.java}       |  81 ++--
 .../ATLASFloatMultiplicationBenchmark.java}        |  81 ++--
 .../AllRange.java => benchmark/Benchmark.java}     |  65 +---
 .../BenchmarkResult.java}                          |  72 ++--
 .../JavaDoubleMultiplicationBenchmark.java}        |  87 ++---
 .../JavaFloatMultiplicationBenchmark.java}         |  87 ++---
 src/org/jblas/benchmark/Main.java                  | 141 +++++++
 .../{ranges/AllRange.java => benchmark/Timer.java} |  71 ++--
 .../AllRange.java => benchmark/package-info.java}  |  63 +--
 src/org/jblas/ranges/AllRange.java                 |   2 +-
 src/org/jblas/ranges/IntervalRange.java            |  15 +-
 .../IntervalRange.java => util/ArchFlavor.java}    |  79 ++--
 src/org/jblas/util/LibraryLoader.java              |  83 +++-
 .../IntervalRange.java => util/Logger.java}        |  85 ++--
 src/org/jblas/util/Permutations.java               |  37 +-
 src/org/jblas/util/SanityChecks.java               | 108 ++++--
 src/overview.textile                               |   4 +-
 test/org/jblas/ranges/IntervalRangeTest.java       |  40 ++
 53 files changed, 2850 insertions(+), 1742 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index a1a98c6..d8eb26c 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,2 +1,8 @@
-Mikio L. Braun - main developer
-Johannes Schaback - additional programming
\ No newline at end of file
+Main Developer:
+
+Mikio L. Braun
+
+Additional Programming and Contributions:
+
+Johannes Schaback
+Jan Saputra Müller
\ No newline at end of file
diff --git a/BUGS b/BUGS
new file mode 100644
index 0000000..896b512
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,8 @@
+Known Bugs:
+
+- XERBLA handling under Mac OS X
+
+  Under Mac OS X, xerbla isn't properly handled, leading to an error message
+and the exit of the program. The linker does not take our own version
+of xerbla, but instead uses the one supplied by the BLAS library. I
+still need to figure out what the right options are.
diff --git a/BUILDING_ATLAS b/BUILDING_ATLAS
new file mode 100644
index 0000000..44726d6
--- /dev/null
+++ b/BUILDING_ATLAS
@@ -0,0 +1,198 @@
+BUILDING_ATLAS
+--------------
+
+In this file, I summarize the different configuration options for the
+platforms.  I keep this information mainly for my own reference, but
+of course, you can try it out yourself ;)
+
+I strongly suggest that you build ATLAS with the --with-netlib-lapack
+option. This includes higher-level routines not covered in ATLAS from
+the lapack libraries.
+
+From my experience, I also found that the Core2 architectural defaults
+work pretty well for both Intel and AMD chips. On 64bit, AMD64K10h is
+a bit better, but not much. On the other hand, the AMD settings
+perform too well on the Intel platform.
+
+OBTAINING THE SOFTWARE
+----------------------
+
+Getting lapack:
+
+wget http://www.netlib.org/lapack/lapack-lite-3.1.1.tgz
+
+Getting ATLAS:
+
+wget http://sourceforge.net/projects/math-atlas/files/Stable/3.8.3/atlas3.8.3.tar.bz2/download
+
+Getting jblas:
+
+git clone git://github.com/mikiobraun/jblas.git
+
+ATLAS OPTIONS
+-------------
+
+This chart may come in handy when you want ATLAS to build with some
+predefined configurations.
+
+ATLAS Architecture Options: (-A)
+
+    0 = 'UNKNOWN'
+    1 = 'POWER3'
+    2 = 'POWER4'
+    3 = 'POWER5'
+    4 = 'PPCG4'
+    5 = 'PPCG5'
+    6 = 'P5'
+    7 = 'P5MMX'
+    8 = 'PPRO'
+    9 = 'PII'
+   10 = 'PIII'
+   11 = 'PM'
+   12 = 'CoreSolo'
+   13 = 'CoreDuo'
+   14 = 'Core2Solo'
+   15 = 'Core2' <-
+   16 = 'Corei7'
+   17 = 'P4'
+   18 = 'P4E'
+   19 = 'Efficeon'
+   20 = 'K7'
+   21 = 'HAMMER' <- for "normal AMD"
+   22 = 'AMD64K10h' <- for "64bit AMD"
+   23 = 'UNKNOWNx86'
+   24 = 'IA64Itan'
+   25 = 'IA64Itan2'
+   26 = 'USI'
+   27 = 'USII'
+   28 = 'USIII'
+   29 = 'USIV'
+   30 = 'UnknownUS'
+   31 = 'MIPSR1xK'
+   32 = 'MIPSICE9'
+
+ATLAS Operating System Options: (-O)
+
+    0 = 'UNKNOWN'
+    1 = 'Linux'
+    2 = 'SunOS'
+    3 = 'SunOS4'
+    4 = 'OSF1'
+    5 = 'IRIX'
+    6 = 'AIX'
+    7 = 'Win9x'
+    8 = 'WinNT'
+    9 = 'HPUX'
+   10 = 'FreeBSD'
+   11 = 'OSX'
+
+Linux
+=====
+
+LAPACK
+------
+
+Copy make.inc.LINUX from INSTALL, update options like this:
+
+FORTRAN  = gfortran 
+OPTS     = -O2 -fPIC
+DRVOPTS  = $(OPTS)
+NOOPT    = -fPIC
+LOADER   = gfortran
+LOADOPTS = -fPIC
+
+compile with "make -k blaslib lapacklib". "-k" (continue on error) is
+needed because some files won't build otherwise.
+
+
+ATLAS
+-----
+
+For 32 bit:
+
+mkdir build
+cd build
+> ../configure -C if gfortran \
+  --with-netlib-lapack=$HOME/build/lapack-lite-3.1.1/liblapack_fortran.a \
+  -A 15 -Si cputhrchk 0 -b 32 
+make
+make time
+
+This sets the fortran compiler to gfortran, architecture Core2, 32
+bit, and don't test for CPU throttling (not needed because we use
+predefined configuration)
+
+For 64 bit:
+
+as above, but configure with
+
+> ../configure \
+  --with-netlib-lapack=/home/mikio/build/lapack-lite-3.1.1/lapack_LINUX.a \
+  -A 21 -b 64 -Si cputhrchk 0 -Fa alg -fPIC  
+
+
+jblas
+-----
+
+> ./configure --static-libs --libpath=$HOME/build/ATLAS/build/lib/
+
+
+Mac OS X
+========
+
+If you install the gfortran with mac ports, you get gcc-mp-4.3 and
+gfortran-mp-4.3. This means you have to redefine all the
+compilers. Apart from that, it was pretty "smooth sailing ;)"
+
+LAPACK
+------
+
+cp INSTALL/make.inc.LINUX make.inc
+
+Update options to
+
+FORTRAN  = gfortran-mp-4.3 
+OPTS     = -funroll-all-loops -O3 -fPIC
+DRVOPTS  = $(OPTS)
+NOOPT    = -fPIC
+LOADER   = gfortran-mp-4.3
+LOADOPTS =
+
+Run with "make -k"
+
+
+ATLAS
+-----
+
+mkdir build_macosx
+cd build_macosx
+
+Execute the following script buil.sh:
+
+CC=gcc-mp-4.3
+F77=gfortran-mp-4.3
+LAPACK=$HOME/Documents/lapack-lite-3.1.1
+../configure -b 32 -C xc $CC -C gc $CC -C if $F77 -C ic $CC -C dm $CC -C sm $CC -C dk $CC -C sk $CC -Fa alg -fPIC --with-netlib-lapack=$LAPACK/liblapack_fortran.a
+
+It's important to set the 32bit flag. Otherwise, it seems to construct
+64 bit code.
+
+
+Windows XP (32bit)
+==================
+
+I'm describing here using cygwin. For some reason, the gcc4 version in cygwin
+does not support compiling to mingw, but using the cygwin version leads
+to some address spaces clashes with Java (at least, the last time I checked),
+leading to a crash as soon as the cygwin compiled code is loaded.
+
+What all of this means is that you should use the old gcc3 "legacy" compilers.
+
+Back in ATLAS 3.6, one needed to set architectures explicitly. With 3.8.3, there is no
+need to do so, but you have to set the fortran compiler explicitly to "g77" (and
+the bit numbers to 32):
+
+../configure --with-netlib-lapack=$HOME/mikio/build/lapack-lite-3.1.1/liblapack_fortran.a -A 15 -C if g77 -b 32
+
+
+
diff --git a/INSTALL b/INSTALL
index 0b957e6..26e6ce3 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,42 +1,63 @@
 INSTALL Guide 
 
+Version 1.0, December 22, 2009
+Version 0.3, September 17, 2009
 Version 0.2, May 8, 2009
 Version 0.1, March 28, 2009
 
-jblas depends on a BLAS and LAPACK library for most of its
-computational intensive parts. I recommend getting a high-quality
-implementation like ATLAS http://math-atlas.sourceforge.net/, but
-taking the default implementation should also suffice. 
+If you just want to get started, I recommend that you download the
+multiplatform" jar file which already includes the required native
+BLAS and LAPACK code based on lapack-lite
+(http://www.netlib.org/lapack/lapack-lite-3.1.1.tgz) and ATLAS
+(http://math-atlas.sourceforge.net/) for a number of operating
+systems. Currently supported are:
 
-Since the LAPACK libraries which come with ATLAS are incomplete (for
-example, no eigenvalue computations), you also need the Fortran LAPACK
-and BLAS libraries. These will be linked in a way such that the
-optimized ATLAS versions are used when available.
+- Windows
+- Linux
+- Mac OS X
 
+both in 32 bit and 64 bit versions.
 
-STANDARD PROCEDURE
-==================
+If you are only adding code on the Java side, then you can work with
+the supplied build.xml ant script. Simply type "ant jar" to compile
+the new jar file.
 
-COMPILING JBLAS
+If you want to access further functions from LAPACK, you need to
+recompile the native part. This procedure is a bit more involved, see
+below.
 
-Assuming that you already have LAPACK and ATLAS libraries
-somewhere. This has been tested on Linux (debian lenny) and Windows
-XP/Cygwin.
+
+COMPILING JBLAS (JAVA PART)
+===========================
 
 Prerequisites: 
   - java JDK
   - ant
   - ruby
-  - Windows XP: cygwin with gcc, nm, ruby, make, etc.
 
-1. Run "./configure".
+Running "ant clean jar" should do the job ;)
+
+"ant jar" collects all static JNI libraries. Other build targets are:
+
+- ant dynamic-lean-jar
+  
+  Build a jar file with the JNI libraries, but without the ATLAS libraries
+  built in for only the current platform.
+
+- ant static-lean-jar
 
-2. Running "ant clean jar" should do the job ;)
+  Build a jar file with the JNI and ATLAS libraries only for the current
+  platform.
+
+- ant minimal-jar
+
+  Build a jar file without the JNI and ATLAS libraries. Both must be
+  installed in the usual library locations.
 
 
 INSTALLING JBLAS
 
-1. Add "jblas-0.2.jar" to your CLASSPATH
+1. Add "jblas-1.0.jar" to your CLASSPATH
 
 2. By default, the dynamic libraries are extracted from the jar file
    to the default temporary directory and loaded from there. If you
@@ -46,7 +67,49 @@ INSTALLING JBLAS
    For Linux, use LD_LIBRARY_PATH, for Windows, PATH
    
 
-CONFIGURE FLAGS
+COMPILING THE NATIVE PART
+=========================
+
+I assume that you already have a built of lapack-lite or ATLAS based
+on the lapack-lite libraries. That build process is quite
+involved. You can find some information about it in
+BUILDING_ATLAS. You can also use the atlas libraries which come with
+your distribution.
+
+The build goes like this:
+
+- run ./configure with options (see below)
+- run "make" to build the JNI library
+- run "ant jar" to package the library into the jar file
+
+
+BUILD OPTIONS
+-------------
+
+Dynamic vs. Static
+
+Basically, you can build with "dynamic" binding or "static" binding,
+which means that either the JNI library is dynamically loading the
+lapack libraries, or they are already linked into it. The latter case
+("static") is better for standalone cases, but the resulting jar file
+is bigger.
+
+The default is dynamic binding, otherwise pass the option
+"--static-libs" to the configure script.
+
+This option also affects what libraries "ant jar" packs into the jar file.
+
+
+LAPACK build vs. ATLAS build
+
+You can either build against LAPACK only, or against the ATLAS
+libraries. LAPACK is somewhat slower, but probably easier to
+compile. To compile against LAPACK, pass the "--lapack-build"
+option. I also recommend to use the "--libpath" option to specify
+exactly where the libraries are.
+
+
+CONFIGURE FLAGS SUMMARY
 
 The configure script understands the following options:
 
@@ -68,131 +131,8 @@ The configure script understands the following options:
    shared LAPACK/BLAS/ATLAS libraries. Default for Windows XP.
 
 --help
-   print this help
-
-
-JAR BUILDING OPTIONS
-
-You can generate different kinds of jar-files. By default, you get a
-jar file which contains the JNI wrapper code for your platform which
-is named jblas-VERSION.jar
-
-"make all-jars" generates a number of other options, including
-
-jblas-VERSION-OS_NAME-OS_ARCH.jar 
-    - default build for your platform, links BLAS / LAPACK / ATLAS
-      libraries dynamically if available
-
-jblas-VERSION-OS_NAME-OS_ARCH-static.jar 
-    - with static libraries, for standalone deployment
-
-jblas-VERSION-multiplatform.jar
-    - with libraries for all available platforms, for OS independent
-      standalone deployment.
-      
-The available platforms are those which are found in the native-libs
-directory. In order to build these, merge the contents of the
-native-libs directory from different platforms.
-
-In other words, for each OS, you do
-
-  > ./configure --static-libs ... further options ...
-  > ant compile-native
-
-And then collect the files in native-libs. For example, your
-native-libs directory can then look like this:
-
-  > find native-libs
-  native-libs/
-  native-libs/Linux
-  native-libs/Linux/i386
-  native-libs/Linux/i386/libjblas.so
-  native-libs/Windows
-  native-libs/Windows/x86
-  native-libs/Windows/x86/jblas.dll
-
-If you now run "make all-jars", you get a jar file which can be used
-on the Linux and Windows platform.
-
-
-FURTHER BUILD OPTIONS
-=====================
-
-ADDING OTHER FUNCTIONS FROM LAPACK
-
-Currently, I've only added stubs for LAPACK routines I have needed so
-far.  If you want to add further stubs, you need the LAPACK
-sources. Currently, the build is set up to work with the directory
-structure of lapack-lite
-http://www.netlib.org/lapack/lapack-lite-3.1.1.tgz If you want to play
-around with other LAPACK routines, it is best to download the archive
-and unpack it in the jblas directory. You can also type in
-"./configure --download-lapack" to let the configure script handle
-this (requires "wget" and "tar" to be installed)
-
-Then, you have to do a "ant realclean jar" to delete the cached
-information about the Fortran routines and reparse the definitions.
-
-
-ANT TARGETS
-
-javadoc
-  generate javadoc pages
-
-compile-test
-  compiles tests (need junit3)
-
-test
-  run some tests (not that good coverage so far)
-
-compile
-  recompile classes
-
-
-COMPILING LAPACK/BLAS AND ATLAS
-===============================
-
-Here are some hints when you want to compile LAPACK/BLAS and LAPACK
-from scratch. Note that the installation processes for both these
-packages are quite non-standard... .
-
-
-COMPILING LAPACK/BLAS
-
-1. Copy a matching make.inc.* from the INSTALL directory to the base
-   directory, where * stands for your operating system (for example, *
-   = LINUX for Linux and Windows/Cygwin, * = gfortran if you have the
-   (newer) gfortran instead of g77)
-
-2. In make.inc, add the option "-fPIC" to OPTS and NOOPTS
-
-2. Run "make blaslib lapacklib"
-
-4. Rename "blas_*.a" to "libblas_fortran.a" and 
-   "lapack_*.a" to "liblapack_fortran.a"
-
-If you want to make a LAPACK build, make sure to specify --static-libs
-when configuring jblas as well.
-
-
-COMPILING ATLAS 
-
-A version more recent than 3.8.0 should work
-
-1. Create a build directory with "mkdir build" and cd into it with "cd
-   build".
+   print help
 
-2. For Linux, run "../configure -Fa alg -fPIC". (Note: for 3.8.3 on my
-   system, I had to add the "-b 32" flag to set the pointer
-   width. Also make sure to turn of any CPU throttling with
-   'cpufreq-set'.)
 
-   For Windows/Cygwin, run "../configure -O 1", maybe also add "-b 32"
-   for 32bit systems. This basically configures ATLAS as if you
-   compiled on a Linux system, because the Windows/Cygwin option
-   seems to be broken (at least when you're using Cygwin).
 
-3. Run "make" (takes a lot of time, your machine should also not be
-   under load) 
 
-4. Only for Linux: Change directory to "build/lib" and run "make shared"
diff --git a/Makefile b/Makefile
index 4779311..accaae1 100644
--- a/Makefile
+++ b/Makefile
@@ -32,7 +32,12 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ## --- END LICENSE BLOCK ---
 
+VERSION=1.0.1
+
+######################################################################
+#
 # Load the output of the configuration files
+#
 ifneq ($(wildcard configure.out),)
 include configure.out
 else
@@ -49,9 +54,10 @@ PACKAGE=org.jblas
 # generate path from package name
 PACKAGE_PATH=$(subst .,/,$(PACKAGE))
 
-LIB_PATH=native-libs/$(LINKAGE)/$(OS_NAME)/$(OS_ARCH)
+LIB_PATH=native-libs/$(LINKAGE_TYPE)/$(OS_NAME)/$(OS_ARCH)
+FULL_LIB_PATH=native-libs/$(LINKAGE_TYPE)/$(OS_NAME)/$(OS_ARCH_WITH_FLAVOR)
 
-#
+#######################################################################
 # Pattern rules
 #
 # The crazy thing is, with these rules, you ONLY need to specify which
@@ -67,16 +73,32 @@ LIB_PATH=native-libs/$(LINKAGE)/$(OS_NAME)/$(OS_ARCH)
 %.$(SO) : %.o
 	$(LD) $(LDFLAGS) -o $@ $^ $(LOADLIBES)
 
-# the default target
-all	: compile-native
+######################################################################
+#
+# Main section
+#
+
+# The default target
+all	: prepare generate-wrapper compile-native
+
+# create native directory if it doesn't exist
+prepare :
+	test -d native || mkdir native
 
-compile-native : $(LIB_PATH)/$(LIB)jblas.$(SO)
+# Generate the JNI dynamic link library
+compile-native : $(FULL_LIB_PATH)/$(LIB)jblas.$(SO) $(LIB_PATH)/$(LIB)jblas_arch_flavor.$(SO)
 
-generate-wrapper: src/$(PACKAGE_PATH)/NativeBlas.java native/NativeBlas.c
+# Generate the code for the wrapper (both Java and C)
+generate-wrapper: src/$(PACKAGE_PATH)/NativeBlas.java native/NativeBlas.c src/org/jblas/util/ArchFlavor.java
+	ant javah
 
+# Clean all object files
 clean:
-	rm -f native/*.o native/*.$(SO) $(LIB_PATH)/*.$(SO) src/$(PACKAGE_PATH)/NativeBlas.java
+	rm -f native/*.o native/*.$(SO) $(LIB_PATH)/*.$(SO) $(FULL_LIB_PATH)/*.$(SO) src/$(PACKAGE_PATH)/NativeBlas.java
 
+# Full clean, including information extracted from the fortranwrappers.
+# You will need the original fortran sources in order to rebuild
+# the wrappers.
 ifeq ($(LAPACK_HOME),)
 realclean:
 	@echo "Since you don't have LAPACK sources, I cannot rebuild stubs and deleting the cached information is not a good idea."
@@ -86,8 +108,11 @@ realclean:
 	rm -f fortranwrapper.dump
 endif
 
-# Generating the stubs. This target requires that the blas sources can be found in ~/src/blas/*.f
-src/$(PACKAGE_PATH)/NativeBlas.java native/NativeBlas.c: scripts/fortranwrapper.rb scripts/fortran/types.rb scripts/fortran/java.rb scripts/java-class.java scripts/java-impl.c
+# Generating the stubs. This target requires that the blas sources can
+# be found in the $(BLAS) and $(LAPACK) directories.
+src/$(PACKAGE_PATH)/NativeBlas.java native/NativeBlas.c: \
+  scripts/fortranwrapper.rb scripts/fortran/types.rb \
+  scripts/fortran/java.rb scripts/java-class.java scripts/java-impl.c
 	$(RUBY) scripts/fortranwrapper.rb $(PACKAGE) NativeBlas \
 	$(BLAS)/*.f \
 	$(LAPACK)/[sd]gesv.f \
@@ -97,18 +122,28 @@ src/$(PACKAGE_PATH)/NativeBlas.java native/NativeBlas.c: scripts/fortranwrapper.
 	$(LAPACK)/[sd]posv.f \
 	$(LAPACK)/[sdcz]geev.f \
 	$(LAPACK)/[sd]getrf.f \
-    $(LAPACK)/[sd]potrf.f 
+	$(LAPACK)/[sd]potrf.f 
 
-$(LIB_PATH)/$(LIB)jblas.$(SO) : native/NativeBlas.$(SO)
+# Move the compile library to the machine specific directory.
+$(FULL_LIB_PATH)/$(LIB)jblas.$(SO) : native/NativeBlas.$(SO)
+	mkdir -p $(FULL_LIB_PATH)
+	mv "$<" "$@"
+
+$(LIB_PATH)/$(LIB)jblas_arch_flavor.$(SO): native/jblas_arch_flavor.$(SO)
 	mkdir -p $(LIB_PATH)
-	mv $< $@
+	mv "$<" "$@"
 
+######################################################################
 #
-# For testing
+# Testing etc.
 #
-VERSION=0.3
 
-make test-dist:
+# run org.jblas.util.SanityChecks
+sanity-checks:
+	java -cp jblas-$(VERSION).jar org.jblas.util.SanityChecks
+
+# Create a tar, extract in a directory, and rebuild from scratch.
+test-dist:
 	ant clean tar
 	rm -rf jblas-$(VERSION)
 	tar xzvf jblas-$(VERSION).tgz
@@ -118,20 +153,33 @@ make test-dist:
 	java -cp jblas-$(VERSION).jar org.jblas.util.SanityChecks
 	cd ..
 
+######################################################################
+#
+# Packaging
+#
+
+
+# Build different kind of jars:
 #
-# Building different kinds of jar files
+# * with dynamic libraries
+# * with static libraries
+# * a "fat" jar with everything
 #
+# FIXME: I think this build target assumes that the current configuration
+# is "dynamic"
 all-jars:
 	ant clean-jars
 	./configure --keep-options $$(cat configure.options)
 	ant jar 
 	ant lean-jar
 	./configure --keep-options --static-libs $$(cat configure.options)
-	ant compile-native static-jar fat-jar
+	make
+	ant static-jar fat-jar
 
+# Build static jars
 all-static-jars:
 	./configure --keep-options --static-libs $$(cat configure.options)
-	ant compile-native
+	make
 	for os_name in native-libs/*; do \
 	  for os_arch in $$os_name/* ; do \
 	    ant static-jar -Dos_name=$$(basename $$os_name) \
diff --git a/README b/README
index 8243033..5a2bd64 100644
--- a/README
+++ b/README
@@ -1,16 +1,20 @@
 jblas is a matrix library for Java which uses existing high
 performance BLAS and LAPACK libraries like ATLAS.
 
+Version 1.0.1, January 14, 2010
+Version 1.0, December 22, 2009
 Version 0.3, September 17, 2009
 Version 0.2, May 8, 2009
 Version 0.1, March 28, 2009
 
 see also the file RELEASE_NOTES
 
+Homepage: http://jblas.org
+
 INSTALL
 
-In principle, all you need is the jblas-0.2.jar in your
-classpath. jblas-0.2.jar will then automagically extract your platform
+In principle, all you need is the jblas-1.0.1,jar in your
+classpath. jblas-1.0.1.jar will then automagically extract your platform
 dependent native library to a tempfile and load it from there. You can
 also put that file somewhere in your load path ($LD_LIBRARY_PATH for
 Linux, %PATH for Windows).
@@ -18,16 +22,19 @@ Linux, %PATH for Windows).
 
 BUILDING
 
-If you want to build jBLAS from the sources, you need to set up quite
-a few things:
+If you only work on the java part, an ant build.xml is provided to
+recompile the sources. In addition to that you need an installation of
+ruby for some scripts which automaticall generate code. Then, you just
+type "ant" on the command line.
 
-You will need some implementation of blas and lapack, for example, as
-provided by ATLAS (http://math-atlas.sourceforge.net/). You also need
-the Fortran sources for BLAS and LAPACK, available, for example from
-http://www.netlib.org/lapack/lapack-lite-3.1.1.tgz.
+If you want to build jblas from the sources including the native part,
+you need to set up quite a few things:
 
-Besides that, you need an installation of ruby, for some code
-generation scripts.
+You will need some implementation of blas and lapack. jblas is tested
+with either plain lapack, or ATLAS
+(http://math-atlas.sourceforge.net/). You also need the Fortran
+sources for BLAS and LAPACK, available, for example from
+http://www.netlib.org/lapack/lapack-lite-3.1.1.tgz.
 
 If you still want to build the source your own, see INSTALL for further
 details.
@@ -37,6 +44,10 @@ HOW TO GET STARTED
 
 Have a look at javadoc/index.html and javadoc/org/jblas/DoubleMatrix.html
 
+If you want to validate your installation and get some performance
+numbers, try "java -server -jar jblas-1.0.1.jar", or drop the server
+in case, you only have the "client" JVM installed.
+
 
 LICENSE
 
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index da2f0c7..9f29cd8 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -1,3 +1,41 @@
+Release 1.0.1 - January 14, 2010
+
+Minor fixes, mostly to do with handling spaces in the configure
+scripts under windows, and running also on older processor which do
+not support SSE2 (older Athlon64 processors, for example).
+
+Changes from 1.0:
+
+- jar contains prebuilt ATLAS libraries for SSE2 and SSE3 and selects
+  based on what is supported.
+
+Still no support for 64bit for Windows, mostly because cygwin/mingw
+support for 64bit is quite experimental, and ATLAS doesn't support
+64bit builds under Windows. If you have managed to compile the thing,
+let me know ;)
+
+You can still use the 32bit version on a 64bit Windows, of course.
+
+----------------------------------------------------------------------
+
+Release 1.0 - December 22, 2009
+
+Leo (@thinkberg) conviced me to bump my version number to 1.0 because
+the software itself is stable, and I now cover all platforms I
+originally targeted.
+
+Changes from 0.3:
+
+- expm moved from DoubleMatrix to MatrixFunctions
+
+- Build for Mac OS X
+
+- configure script has been overhauled.
+
+- Matrix classes are now serializable.
+
+----------------------------------------------------------------------
+
 Release v0.3 - September 17, 2009
 
 Release v0.3 adds some features, in particular LU and Cholesky decomposition,
diff --git a/ROADMAP b/ROADMAP
new file mode 100644
index 0000000..a07f024
--- /dev/null
+++ b/ROADMAP
@@ -0,0 +1,9 @@
+Roadmap to jblas-0.3.1
+
+- collect static builds for Windows(32), Linux(32/64), MacOSX(32/64).
+
+- create multiplatform jar (for all).
+
+- little benchmarking and testing tool.
+
+- update README, INSTALL, RELEASE_NOTES
\ No newline at end of file
diff --git a/build.xml b/build.xml
index aebae77..c861ab2 100644
--- a/build.xml
+++ b/build.xml
@@ -33,16 +33,15 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 -->
-<project name="java-blas" basedir="." default="jar">
+<project name="java-blas" basedir="." default="multiplatform-jar">
     <description>
 		This is the build script to compile and deploy the java-blas project.
 		It also generates JavaDoc from source in ../doc.
     </description>
 
-    <import file="configure.xml" />
-
     <!-- Define directories -->
 
+    <property name="version" value="1.0.1" />
     <property name="src" value="${basedir}/src" />
     <property name="test" value="${basedir}/test" />
     <property name="bin" value="${basedir}/bin" />
@@ -54,7 +53,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     <property name="external" value="${basedir}/external" />
     <property name="scripts" value="${basedir}/scripts" />
     <property name="pkgbase" value="org.jblas" />
-    <property name="version" value="0.3" />
 
     <!-- Macros -->
 
@@ -88,16 +86,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     <macrodef name="create-jar" description="create jar file">
         <attribute name="filename" />
         <sequential>
-        <jar destfile="@{filename}">
-            <fileset dir="${bin}">
-                <include name="org/**" />
-                <include name="lib/**/lib*.so"/>
-                <include name="lib/**/*.dll"/>
-            </fileset>
-            <manifest>
-                <attribute name="Built-By" value="IDA Group, TU Berlin" />
-            </manifest>
-        </jar>
+            <jar destfile="@{filename}">
+                <fileset dir="${bin}">
+                    <include name="org/**" />
+                    <include name="lib/**/lib*.so"/>
+                    <include name="lib/**/*.dll"/>
+		    <include name="lib/**/*.jnilib"/>
+                </fileset>
+                <manifest>
+                    <attribute name="Built-By" value="IDA Group, TU Berlin" />
+                    <attribute name="Main-Class" value="org.jblas.benchmark.Main" />
+                </manifest>
+            </jar>
         </sequential>
     </macrodef>
 
@@ -107,55 +107,47 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
         <delete dir="${doc}" />
         <delete dir="${bin}" />
         <delete dir="${include}" />
-        <exec executable="${make}">
-            <arg line="clean" />
-        </exec>
     </target>
     <target name="clean-jars" description="delete all jar files">
         <delete>
             <fileset dir="." includes="*.jar" />
         </delete>
     </target>
-    <target name="realclean" depends="clean" description="delete also dumped information on fortran functions">
-        <exec executable="${make}">
-            <arg line="realclean" />
-        </exec>
-    </target>
     <target name="prepare" description="create directories needed for compilation">
         <mkdir dir="${bin}" />
-        <mkdir dir="${native}" />
         <mkdir dir="${include}" />
     </target>
-    <target name="compile" depends="prepare,wrapper,generate-float" description="compile java code">
-        <javac destdir="${bin}" encoding="utf-8" source="1.6" debug="on" compiler="javac1.6" fork="yes" nowarn="yes">
+    <target name="compile" depends="prepare,generate-float" description="compile java code">
+        <javac destdir="${bin}" encoding="utf-8" source="1.5" debug="on" compiler="javac1.5" target="1.5" fork="yes" nowarn="yes">
             <src path="${src}" />
         </javac>
     </target>
     <target name="compile-test" depends="compile" description="compile java test code">
-        <javac destdir="${bin}" encoding="utf-8" source="1.6" debug="on" compiler="javac1.6" fork="yes" nowarn="yes">
+        <javac destdir="${bin}" encoding="utf-8" source="1.5" debug="on" compiler="javac1.5" target="1.5" fork="yes" nowarn="yes">
             <src path="${test}" />
             <classpath>
                 <pathelement location="${external}/junit.jar" />
             </classpath>
         </javac>
     </target>
-    <target name="javah" depends="prepare,wrapper,compile" description="run javah">
+    <target name="javah" depends="prepare" description="run javah">
+        <javac destdir="${bin}" encoding="utf-8" source="1.5" debug="on" compiler="javac1.5" target="1.5" fork="yes" nowarn="yes">
+            <src path="${src}" />
+            <include name="**/NativeBlas.java" />
+            <include name="**/ArchFlavor.java" />
+        </javac>
         <javah destdir="${include}" force="yes">
             <class name="${pkgbase}.NativeBlas" />
             <classpath>
                 <pathelement path="${bin}" />
             </classpath>
         </javah>
-    </target>
-    <target name="compile-native" depends="prepare,javah" description="compile native JNI stubs">
-        <exec executable="${make}">
-            <arg line="compile-native" />
-        </exec>
-    </target>
-    <target name="wrapper" depends="prepare" description="generate the JNI stub code">
-        <exec executable="${make}">
-            <arg line="generate-wrapper" />
-        </exec>
+        <javah destdir="${include}" force="yes">
+            <class name="org.jblas.util.ArchFlavor" />
+            <classpath>
+                <pathelement path="${bin}" />
+            </classpath>
+        </javah>
     </target>
     <target name="generate-float" depends="preprocess" description="generate float versions of classes">
         <class-to-float class="${pkgbase}.DoubleMatrix"/>
@@ -180,51 +172,44 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
     <!-- jar files -->
 
-    <target name="jar" depends="compile,compile-native" description="create jblas.jar (local system, as configured)">
+    <target name="dynamic-lean-jar" depends="compile" description="create jblas.jar (local system, dynamic)">
         <delete dir="${bin}/lib" />
         <copy todir="${bin}/lib">
             <fileset dir="${native-libs}">
-                <include name="${linkage}/${os_name}/${os_arch}/*" />
+                <include name="dynamic/${os.name}/${os.arch}/*" />
             </fileset>
         </copy>
-        <create-jar filename="jblas-${version}.jar" />
+        <create-jar filename="jblas-lean-${os.name}-${os.arch}-${version}.jar" />
     </target>
 
-    <target name="dynamic-jar" depends="compile,compile-native" description="create jblas.jar (local system, dynamic)">
+    <target name="static-lean-jar" depends="compile" description="create jblas.jar (local system, dynamic)">
         <delete dir="${bin}/lib" />
         <copy todir="${bin}/lib">
             <fileset dir="${native-libs}">
-                <include name="dynamic/${os_name}/${os_arch}/*" />
+                <include name="static/${os.name}/${os.arch}/*" />
             </fileset>
         </copy>
-        <create-jar filename="jblas-${version}-${os_name}-${os_arch}.jar" />
+        <create-jar filename="jblas-lean-${os.name}-${os.arch}-${version}.jar" />
     </target>
-    <target name="static-jar" description="create jblas-static.jar (local system, static)">
-        <delete dir="${bin}/lib" />
-        <copy todir="${bin}/lib">
-            <fileset dir="${native-libs}">
-                <include name="static/${os_name}/${os_arch}/*" />
-            </fileset>
-        </copy>
-        <create-jar filename="jblas-${version}-${os_name}-${os_arch}-static.jar" />
-    </target>
-    <target name="fat-jar" description="create jblas-multiplatform.jar (local system, static, plus everything else in native-libs)">
+
+    <target name="jar" depends="compile" description="create multiplatform.jar (everything in native-libs/static)">
         <delete dir="${bin}/lib" />
         <copy todir="${bin}/lib">
             <fileset dir="${native-libs}">
                 <include name="static/**" />
             </fileset>
         </copy>
-        <create-jar filename="jblas-${version}-multiplatform.jar" />
+        <create-jar filename="jblas-${version}.jar" />
     </target>
-    <target name="lean-jar" description="create jblas-lean.jar (local system, dynamic, without shared libs)" >
+    
+    <target name="minimal-jar" depends="compile" description="create jblas-lean.jar (local system, dynamic, without shared libs)" >
         <delete dir="${bin}/lib" />
-        <create-jar filename="jblas-${version}-lean.jar" />
+        <create-jar filename="jblas-minimal-${version}.jar" />
     </target>
 
     <!-- javadoc -->
 
-    <target name="javadoc" depends="generate-float,wrapper">
+    <target name="javadoc" depends="generate-float">
         <mkdir dir="${doc}" />
         <javadoc packagenames="org.jblas.*"
 		sourcepath="${src}" defaultexcludes="yes"
@@ -246,16 +231,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     <target name="test" depends="compile-test,jar">
         <junit printsummary="yes" haltonfailure="yes" showoutput="yes">
             <classpath>
-                <pathelement location="${external}/junit.jar" />
+                <!-- <pathelement location="${external}/junit.jar" /> -->
                 <pathelement path="${bin}" />
             </classpath>
             <formatter type="plain" usefile="false" />
-            <test name="${pkgbase}.TestDoubleMatrix" />
+            <!-- <test name="${pkgbase}.TestDoubleMatrix" />
             <test name="${pkgbase}.TestEigen" />
+            <test name="${pkgbase}.ranges.IntervalRangeTest" /> -->
+            <test name="${pkgbase}.DecomposeTest" />
         </junit>
     </target>
     <target name="all" depends="jar, javadoc">
     </target>
+
+    <!-- taring everything up for distribution -->
+    
     <target name="tar" depends="javadoc">
         <tar destfile="jblas-${version}.tgz" compression="gzip">
             <tarfileset dir="${basedir}" prefix="jblas-${version}">
diff --git a/config/arch_flavor.c b/config/arch_flavor.c
new file mode 100644
index 0000000..f65a165
--- /dev/null
+++ b/config/arch_flavor.c
@@ -0,0 +1,54 @@
+#include <stdio.h>
+
+/* Thanks to the following pages for helping me out on this.
+ *
+ * http://softpixel.com/~cwright/programming/simd/cpuid.php
+ * http://www.gentoo.org/proj/en/hardened/pic-fix-guide.xml
+ */
+#define cpuid(func,ax,bx,cx,dx)	\
+  __asm__ __volatile__ (" \
+        movl %%ebx, %%edi; \
+        cpuid;		  \
+        movl %%ebx, %1;	  \
+        movl %%edi, %%ebx" \
+	: "=a" (ax), "=r" (bx), "=c" (cx), "=d" (dx) \
+        : "a" (func) \
+        : "edi");
+
+/* in edx */
+#define SSE (1L << 25)
+#define SSE2 (1L << 26)
+
+/* in ecx */
+#define SSE3 (1L << 0)
+
+int sse_level() {
+  int level = -1;
+  int a, b, c, d;
+
+  cpuid(1, a, b, c, d);
+
+  if (d & SSE) {
+    level = 1;
+  }
+
+  if (d & SSE2) {
+    level = 2;
+  }
+
+  if (c & SSE3) {
+    level = 3;
+  }
+  return level;
+}
+
+int main(int argc, char **argv) {
+  switch (sse_level()) {
+  case 1:
+    printf("sse\n");
+  case 2:
+    printf("sse2\n");
+  case 3:
+    printf("sse3\n");
+  }
+}
diff --git a/config/config.rb b/config/config.rb
index 1f20f1c..f8048fe 100644
--- a/config/config.rb
+++ b/config/config.rb
@@ -34,80 +34,225 @@
 
 require 'config/path'
 
-class ConfigError < Exception
-  attr_reader :message
+module Config
+  class ConfigError < Exception
+    attr_reader :message
 
-  def initialize(msg)
-    @message = msg
+    def initialize(msg)
+      @message = msg
+    end
   end
-end
 
-class Config
-  def initialize
-    @config = Hash.new {|h,k| Array.new }
-    @log = open('configure.log', 'w')
-    @xmlstuff = Array.new
-  end
+  # A class for collecting configuration information.
+  #
+  # Basically, this class is like a hash function and is able to output
+  # it's results in a format which cCan be read by Makefile.
+  #
+  # It basically looks like this
+  #
+  #   KEY=VALUE
+  #
+  # However, you can also use "<<" on keys, or "+=" in the bulk update
+  # sections to add, for example, compile options.
+  class ConfigStore
+    # Create a new empty config object
+    def initialize
+      @config = Hash.new {|h,k| Array.new }
+      @xmlstuff = Array.new
+    end
 
-  def [](k)
-    @config[k]
-  end
+    # Lookup an existing key.
+    def [](k)
+      @config[k]
+    end
 
-  def []=(k, v)
-    @config[k] = v
-    log "Setting #{k} to #{v}"
-  end
+    def add(k, v)
+      @config[k] = v
+    end
 
-  def add_xml(str)
-    @xmlstuff << str
-    return
-  end
+    # Define a key.
+    def []=(k, v)
+      @config[k] = v
+      log "Setting #{k} to #{v}"
+    end
 
-  def dump_xml(io)
-    io.puts "<project name=\"imported-configuration-settings\">"
-    io.puts(@xmlstuff.join "\n")
-    io.puts "</project>"
-  end
+    # Add stuff to the xml file.
+    def add_xml(str)
+      @xmlstuff << str
+      return
+    end
 
-  def log(msg)
-    @log.puts(msg)
-  end
+    # Dump the xml configuration options to a file.
+    def dump_xml(io)
+      io.puts "<project name=\"imported-configuration-settings\">"
+      io.puts(@xmlstuff.join("\n"))
+      io.puts "</project>"
+    end
 
-  def <<(str)
-    str.each_line do |line|
-      next if line.chomp.empty?
-      i = line.index /\A\s*([a-zA-Z_]+)\s*(\+?=)(.*)/
-      if i.nil?
-        puts "Warning: Cannot parse config definition '#{line}'"
-        next
+    # Bulk add some keys.
+    #
+    # The format is lines of "KEY=VALUE".
+    def <<(str)
+      str.each_line do |line|
+        next if line.chomp.empty?
+        i = line.index /\A\s*([a-zA-Z_]+)\s*(\+?=)(.*)/
+        if i.nil?
+          puts "Warning: Cannot parse config definition '#{line}'"
+          next
+        end
+        var = $1
+        op = $2
+        val = $3.strip
+        if op == '='
+          self[var] = val
+        elsif op == '+='
+          if @config.has_key? var
+            self[var] = [self[var], val]
+          else
+            self[var] = [val]
+          end
+        end
       end
-      var = $1
-      op = $2
-      val = $3.strip
-      if op == '='
-        self[var] = val
-      elsif op == '+='
-        if @config.has_key? var
-          self[var] = [self[var], val]
+      return
+    end
+
+    # Dump the config to a file.
+    def dump(io)
+      @config.keys.select {|s| String === s}.sort.each do |k|
+        v = @config[k]
+        case v
+        when Array
+          io.puts "#{k}=#{v.join ' '}"
         else
-          self[var] <<= val
+          io.puts "#{k}=#{v}"
         end
       end
     end
-    return
   end
 
-  def dump(io)
-    @config.each_pair do |k, v|
-      case v
-      when Array
-        io.puts "#{k}=#{v.join ' '}"
+  class AutomaticConfigStore < ConfigStore
+    def [](key)
+      ConfigureTask.run(key) unless @config.include? key
+      return super(key)
+    end
+
+    def []=(key, value)
+      super(key, value)
+    end
+  end
+
+  CONFIG = ConfigStore.new
+
+  class ConfigureTask
+    attr_reader :symbols
+    attr_reader :dependencies
+
+    def initialize(symbols, dependencies, &block)
+      @symbols = symbols
+      @dependencies = dependencies
+      @block = block
+      @has_run = false
+      @description = ConfigureTask.get_description
+    end
+
+    def run(*args)
+      unless @has_run
+        @dependencies.each {|d| ConfigureTask.run(d, *args) }
+        unless @description.nil?
+          print @description + '... '
+          $stdout.flush
+        end
+        @block.call(*args) unless @block.nil?
+        @has_run = true
+      end
+    end
+
+    def self.add(task)
+      @tasks ||= {}
+      task.symbols.each {|s| @tasks[s] = task}
+    end
+
+    def self.run(name, *args)
+      task = @tasks[name]
+      if task.nil?
+        puts "Error: Cannot find task '#{name}'"
       else
-        io.puts "#{k}=#{v}"
+        task.run(*args)
       end
     end
+
+    def self.run_all(*args)
+      @tasks.values.each {|c| c.run(*args)}
+    end
+
+    def self.dump
+      p @tasks
+    end
+
+    def self.add_description(desc)
+      @desc = desc
+    end
+
+    def self.get_description
+      result = @desc
+      @desc = nil
+      return result
+    end
+
+    def self.log(msg)
+      @log ||= open('configure.log', 'w')
+      @log.puts(msg)
+    end
+  end
+
+  module_function
+
+  # Define a new configuration task.
+  #
+  # Syntax is similar to rake tasks:
+  #
+  #   * configure :foobar do ... end - task without prerequisites
+  #   * configure :foobar => :quux do ... end - task depend on quux
+  #
+  # The block is optional
+  def configure(*args, &block)
+    if Hash === args[-1]
+      syms = args[0...-1] + [args[-1].keys[0]]
+      deps = args[-1].values[0]
+      deps = [deps] unless Array === deps
+    else
+      syms = args
+      deps = []
+    end
+    task = ConfigureTask.new(syms, deps, &block)
+    ConfigureTask.add(task)
+  end
+
+  # Define the description for a task.
+  #
+  # This affects the next task defined. If a a description is given,
+  # it will be printed before the task is run. The task must then
+  # call +ok+ to finish the line.
+  def desc(description)
+    ConfigureTask.add_description(description)
+  end
+
+  # Print 'ok', potentially followed by a comment.
+  def ok(msg='')
+    if msg.empty?
+      puts "ok"
+    else
+      puts "ok (#{msg})"
+    end
   end
 
+  # Print error message and raise a ConfigError.
+  def fail(msg='')
+    puts "*failed*"
+    raise ConfigError, msg
+  end
+
+  # Print a message on the screen.
   def msg(m)
     print m + "... "
     $stdout.flush
@@ -121,31 +266,38 @@ class Config
     end
   end
 
-  def ok
-    puts "ok"
+  # Print a log message.
+  def log(msg)
+    ConfigureTask.log(msg)
   end
 
-  def fail(msg=false)
-    puts "*failed*"
-    raise ConfigError, msg
+  def run(target)
+    begin
+      ConfigureTask.run target
+    rescue ConfigError => e
+      puts
+      puts "Configuration failed!"
+      puts
+      puts "Reason: #{e.message}"
+      exit
+    end
   end
+end
 
-  def check_cmd(*cmds)
-    cmds.each do |cmd|
-      log "Searching for command #{cmd}"
-      self.fail("coulnd't find command #{cmd}") unless where cmd
-    end
-    yield self if block_given?
-    return 
+if __FILE__ == $0
+  include Config
+
+  configure :say_hello do
+    puts "Hello"
+    CONFIG[:say_hello] = 42
   end
 
-  def check_files(path, *files)
-    files.each do |file|
-      file = File.join(path, *file)
-      log "Searching for file #{file}"
-      self.fail("couldn't find #{file}") unless File.exist? file
-    end
-    yield self if block_given?
-    return
+  configure :say_goodbye do
+    p CONFIG[:say_hello]
+    puts "Goodbye!"
   end
-end
+
+  configure :default => :say_goodbye
+
+  ConfigureTask.run :default
+end
\ No newline at end of file
diff --git a/config/path.rb b/config/config_cc.rb
similarity index 50%
copy from config/path.rb
copy to config/config_cc.rb
index febeab3..eb232e2 100644
--- a/config/path.rb
+++ b/config/config_cc.rb
@@ -1,24 +1,24 @@
 ## --- BEGIN LICENSE BLOCK ---
 # Copyright (c) 2009, Mikio L. Braun
 # All rights reserved.
-# 
+#
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are
 # met:
-# 
+#
 #     * Redistributions of source code must retain the above copyright
 #       notice, this list of conditions and the following disclaimer.
-# 
+#
 #     * Redistributions in binary form must reproduce the above
 #       copyright notice, this list of conditions and the following
 #       disclaimer in the documentation and/or other materials provided
 #       with the distribution.
-# 
+#
 #     * Neither the name of the Technische Universität Berlin nor the
 #       names of its contributors may be used to endorse or promote
 #       products derived from this software without specific prior
 #       written permission.
-# 
+#
 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -32,39 +32,78 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ## --- END LICENSE BLOCK ---
 
-require 'set'
+require 'config/path'
+require 'config/config'
+require 'config/config_java'
 
-PATH = ENV['PATH'].split(':')
+include Config
+include Path
 
-def where(file, path=PATH)
-  path.each do |p|
-    fn = File.join(p, file)
-    #print "  Checking #{fn}"
-    if File.exist? fn
-      #puts "  found"
-      if block_given? 
-        return p if yield fn
-      else
-        return p
-      end
-    else
-      #puts
-    end
+# Set up flags for different environments.
+configure :cc => 'CC'
+
+desc 'Setting up gcc and flags'
+configure 'CC', 'CFLAGS' => ['OS_NAME', 'OS_ARCH', 'JAVA_HOME'] do
+  os_name = Config::CONFIG['OS_NAME']
+  java_home = Config::CONFIG['JAVA_HOME'].escape
+  case os_name
+  when 'Linux'
+    Path.check_cmd('gcc', 'make', 'ld')
+    Config::CONFIG << <<EOS
+CC = gcc
+CFLAGS = -fPIC
+INCDIRS += -Iinclude -I#{java_home}/include -I#{java_home}/include/linux
+SO = so
+LIB = lib
+RUBY=ruby
+LDFLAGS += -shared
+EOS
+  when 'SunOS'
+    Path.check_cmd('gcc', 'make', 'ld')
+    Config::CONFIG << <<EOS
+CC = gcc
+CFLAGS = -fPIC
+INCDIRS += -Iinclude -I#{java_home}/include -I#{java_home}/include/solaris
+SO = so
+LIB = lib
+RUBY=ruby
+LDFLAGS += -G
+EOS
+  when 'Windows'
+    Path.check_cmd('gcc', 'make', 'ld')
+    Path.check_cmd('cygpath')
+    Config::CONFIG << <<EOS
+CC = gcc
+CFLAGS = -ggdb -D__int64='long long'
+INCDIRS += -I"#{dir java_home}/include" -I"#{dir java_home}/include/win32" -Iinclude
+LDFLAGS += -mno-cygwin -shared -Wl,--add-stdcall-alias
+SO = dll
+LIB =
+RUBY = ruby
+EOS
+  when 'Mac\ OS\ X'
+    Path.check_cmd('gcc-mp-4.3', 'make')
+    Config::CONFIG << <<EOS
+CC = gcc-mp-4.3
+LD = gcc-mp-4.3
+CFLAGS = -fPIC
+INCDIRS += -Iinclude -I#{java_home}/include
+SO = jnilib
+LIB = lib
+RUBY = ruby
+LDFLAGS += -shared
+EOS
+  else
+    Config.fail "Sorry, the OS #{os_name} is currently not supported"
   end
-  return
-end
 
-# returns the path to the command as specified by
-# line or nil if the command does not exist, or
-# it did not produce the right result
-def where_with_output(line, output)
-   cmd = line.split[0]
-   p = where(cmd)
-   return unless p
-   out = %x(#{File.join(p,line)})
-   if out =~ output
-     return p
-   else
-     return
-   end
+  if %w(i386 x86 x86_64 amd64).include? Config::CONFIG['OS_ARCH']
+    Config::CONFIG['CFLAGS'] << ' -DHAS_CPUID'
+  end
+
+  ok(CONFIG['CC'])
 end
+
+if __FILE__ == $0
+  ConfigureTask.run :cc
+end
\ No newline at end of file
diff --git a/config/path.rb b/config/config_fortran.rb
similarity index 63%
copy from config/path.rb
copy to config/config_fortran.rb
index febeab3..a2f324a 100644
--- a/config/path.rb
+++ b/config/config_fortran.rb
@@ -1,24 +1,24 @@
 ## --- BEGIN LICENSE BLOCK ---
 # Copyright (c) 2009, Mikio L. Braun
 # All rights reserved.
-# 
+#
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are
 # met:
-# 
+#
 #     * Redistributions of source code must retain the above copyright
 #       notice, this list of conditions and the following disclaimer.
-# 
+#
 #     * Redistributions in binary form must reproduce the above
 #       copyright notice, this list of conditions and the following
 #       disclaimer in the documentation and/or other materials provided
 #       with the distribution.
-# 
+#
 #     * Neither the name of the Technische Universität Berlin nor the
 #       names of its contributors may be used to endorse or promote
 #       products derived from this software without specific prior
 #       written permission.
-# 
+#
 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -32,39 +32,49 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ## --- END LICENSE BLOCK ---
 
-require 'set'
+require 'config/path'
+require 'config/config'
+require 'config/config_cc'
+require 'config/config_os_arch'
 
-PATH = ENV['PATH'].split(':')
+include Config
+include Path
 
-def where(file, path=PATH)
-  path.each do |p|
-    fn = File.join(p, file)
-    #print "  Checking #{fn}"
-    if File.exist? fn
-      #puts "  found"
-      if block_given? 
-        return p if yield fn
-      else
-        return p
-      end
+configure :fortran => ['F77', 'LD']
+
+desc 'deciding whether to use g77 or gfortran'
+configure 'F77', 'LD' => [:os_arch, :cc] do
+  #unless ENV['CC'].nil?
+  #  CONFIG['CC'] = ENV['CC']
+  #  return
+  #end
+
+  if CONFIG['OS_NAME'] == 'Mac\ OS\ X'
+    CONFIG['LD'] = CONFIG['CC']
+    CONFIG['F77'] = 'gfortran-mp-4.3'
+  else
+    g77 = Path.where('g77')
+    gfortran = Path.where('gfortran')
+    f77 = Path.where('f77')
+    if g77
+      CONFIG['LD'] = 'g77'
+      CONFIG['F77'] = 'g77'
+    elsif gfortran
+      CONFIG['F77'] = 'gfortran'
+      CONFIG['LD'] = CONFIG['CC']
+    elsif f77
+      CONFIG['F77'] = 'f77'
+      CONFIG['LD'] = 'f77'
     else
-      #puts
+      CONFIG.fail <<EOS.indent(2)
+Either g77 or gfortran have to be installed to compile against the
+fortran libraries.
+EOS
     end
   end
-  return
+  ok(CONFIG['F77'])
 end
 
-# returns the path to the command as specified by
-# line or nil if the command does not exist, or
-# it did not produce the right result
-def where_with_output(line, output)
-   cmd = line.split[0]
-   p = where(cmd)
-   return unless p
-   out = %x(#{File.join(p,line)})
-   if out =~ output
-     return p
-   else
-     return
-   end
+if __FILE__ == $0
+  ConfigureTask.run :fortran
 end
diff --git a/config/path.rb b/config/config_java.rb
similarity index 66%
copy from config/path.rb
copy to config/config_java.rb
index febeab3..c834f1b 100644
--- a/config/path.rb
+++ b/config/config_java.rb
@@ -1,24 +1,24 @@
 ## --- BEGIN LICENSE BLOCK ---
 # Copyright (c) 2009, Mikio L. Braun
 # All rights reserved.
-# 
+#
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are
 # met:
-# 
+#
 #     * Redistributions of source code must retain the above copyright
 #       notice, this list of conditions and the following disclaimer.
-# 
+#
 #     * Redistributions in binary form must reproduce the above
 #       copyright notice, this list of conditions and the following
 #       disclaimer in the documentation and/or other materials provided
 #       with the distribution.
-# 
+#
 #     * Neither the name of the Technische Universität Berlin nor the
 #       names of its contributors may be used to endorse or promote
 #       products derived from this software without specific prior
 #       written permission.
-# 
+#
 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -32,39 +32,40 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ## --- END LICENSE BLOCK ---
 
-require 'set'
+# Configure Java Environment
+require 'config/config'
+require 'config/path'
+require 'config/config_os_arch'
 
-PATH = ENV['PATH'].split(':')
+include Config
+include Path
 
-def where(file, path=PATH)
-  path.each do |p|
-    fn = File.join(p, file)
-    #print "  Checking #{fn}"
-    if File.exist? fn
-      #puts "  found"
-      if block_given? 
-        return p if yield fn
-      else
-        return p
-      end
-    else
-      #puts
-    end
-  end
-  return
+configure :java => ['FOUND_JAVA', 'JAVA_HOME']
+
+desc 'checking for java, javac'
+configure 'FOUND_JAVA' do
+  check_cmd('java', 'javac')
+  %x(javac config/PrintProperty.java)
+  CONFIG['FOUND_JAVA'] = true
+  ok
 end
 
-# returns the path to the command as specified by
-# line or nil if the command does not exist, or
-# it did not produce the right result
-def where_with_output(line, output)
-   cmd = line.split[0]
-   p = where(cmd)
-   return unless p
-   out = %x(#{File.join(p,line)})
-   if out =~ output
-     return p
-   else
-     return
-   end
+desc 'locating the Java Development Kit'
+configure 'JAVA_HOME' => ['FOUND_JAVA', 'OS_NAME'] do
+  if ENV.include? 'JAVA_HOME'
+    java_home = ENV['JAVA_HOME']
+  else
+    java_home = dir(File.dirname(%x(java -cp config PrintProperty java.home)))
+  end
+  if CONFIG['OS_NAME'] == 'Mac\ OS\ X'
+    java_home = File.join(java_home, 'Home')
+  end
+  check_files java_home, ['include', 'jni.h'] do
+    CONFIG['JAVA_HOME'] = java_home #.escape
+  end
+  ok(java_home)
 end
+
+if __FILE__ == $0
+  ConfigureTask.run :java
+end
\ No newline at end of file
diff --git a/config/path.rb b/config/config_lapack_sources.rb
similarity index 54%
copy from config/path.rb
copy to config/config_lapack_sources.rb
index febeab3..1bb67d9 100644
--- a/config/path.rb
+++ b/config/config_lapack_sources.rb
@@ -1,24 +1,24 @@
 ## --- BEGIN LICENSE BLOCK ---
 # Copyright (c) 2009, Mikio L. Braun
 # All rights reserved.
-# 
+#
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are
 # met:
-# 
+#
 #     * Redistributions of source code must retain the above copyright
 #       notice, this list of conditions and the following disclaimer.
-# 
+#
 #     * Redistributions in binary form must reproduce the above
 #       copyright notice, this list of conditions and the following
 #       disclaimer in the documentation and/or other materials provided
 #       with the distribution.
-# 
+#
 #     * Neither the name of the Technische Universität Berlin nor the
 #       names of its contributors may be used to endorse or promote
 #       products derived from this software without specific prior
 #       written permission.
-# 
+#
 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -32,39 +32,49 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ## --- END LICENSE BLOCK ---
 
-require 'set'
+require 'config/config'
+require 'config/path'
+require 'config/opts'
+require 'config/string_ext'
 
-PATH = ENV['PATH'].split(':')
+include Config
 
-def where(file, path=PATH)
-  path.each do |p|
-    fn = File.join(p, file)
-    #print "  Checking #{fn}"
-    if File.exist? fn
-      #puts "  found"
-      if block_given? 
-        return p if yield fn
-      else
-        return p
-      end
+configure :lapack_sources => 'LAPACK_HOME'
+
+desc 'search for lapack sources (configure by --lapack=dir)'
+configure 'LAPACK_HOME' do
+  lapack_home = $opts.get :lapack, './lapack-lite-3.1.1'
+  begin
+    Path.check_files(lapack_home,
+      ['BLAS', 'SRC', 'dgemm.f'],
+      ['SRC', 'dsyev.f'])
+  rescue ConfigError => e
+    if $opts.defined? :download_lapack
+      puts "trying to download lapack (about 5M)"
+      print "Looking for wget..."; check_cmd 'wget'; Config.ok
+      lapack_tgz = File.join('.', 'lapack-lite-3.1.1.tgz')
+      File.delete(lapack_tgz) if File.exist?(lapack_tgz)
+      system("wget http://www.netlib.org/lapack/lapack-lite-3.1.1.tgz")
+      system("tar xzvf lapack-lite-3.1.1.tgz")
+      check_lapack_home(lapack_home)
     else
-      #puts
+      CONFIG['LAPACK_HOME'] = ''
+      puts <<EOS.indent(2)
+Couldn\'t locate sources for LAPACK and BLAS. Supply the location
+of the lapack sources with the --lapack=... switch. Sources for lapack can be
+found at http://www.netlib.org/lapack/lapack-lite-3.1.1.tgz or try
+running configure with the --download-lapack option.
+
+Compling jblas should work, but unless you have the LAPACK and BLAS sources
+you cannot add further stubs.
+EOS
     end
   end
-  return
+  CONFIG['LAPACK_HOME'] = lapack_home
+  ok(lapack_home)
 end
 
-# returns the path to the command as specified by
-# line or nil if the command does not exist, or
-# it did not produce the right result
-def where_with_output(line, output)
-   cmd = line.split[0]
-   p = where(cmd)
-   return unless p
-   out = %x(#{File.join(p,line)})
-   if out =~ output
-     return p
-   else
-     return
-   end
-end
+if __FILE__ == $0
+  $opts = Opts.new(ARGV)
+  Config.run :lapack_sources
+end
\ No newline at end of file
diff --git a/config/config_libs.rb b/config/config_libs.rb
new file mode 100644
index 0000000..e9948a1
--- /dev/null
+++ b/config/config_libs.rb
@@ -0,0 +1,154 @@
+## --- BEGIN LICENSE BLOCK ---
+# Copyright (c) 2009, Mikio L. Braun
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+#     * Neither the name of the Technische Universität Berlin nor the
+#       names of its contributors may be used to endorse or promote
+#       products derived from this software without specific prior
+#       written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+## --- END LICENSE BLOCK ---
+
+######################################################################
+#
+# Locating the libraries
+#
+# This is a bit involved since the standard ATLAS compilation produces
+# a liblapack.so which only implements a subset of the lapack functions.
+# So the basic strategy is to
+#
+# (a) find the path to the atlas specific library
+# (b) find the path to a full lapack library
+#
+# Pass the lapack libraries and theirs paths first.
+#
+# Of course, if you want to build a lapack-only path, we only search
+# for the full lapack libraries.
+
+require 'config/config'
+require 'config/lib_helpers'
+require 'config/opts'
+require 'config/config_os_arch'
+require 'config/config_fortran'
+
+include Config
+
+ATLAS_REQUIRED_SYMBOLS = [
+  'dsyev_', # eigenvalue function not yet included in ATLAS/LAPACK
+  'ATL_dgemm',
+  'dgemm_', # matrix-matrix multiplication
+  'daxpy_', # blas-related function
+  'cblas_daxpy', # atlas itself often uses cblas
+  'ATL_caxpy'
+]
+
+LAPACK_REQUIRED_SYMBOLS = [ 'dsyev_', 'daxpy_' ]
+
+ATLAS_LIBS = %w(lapack lapack_fortran lapack_atlas f77blas atlas cblas)
+LAPACK_LIBS = %w(lapack_fortran lapack blas_fortran blas)
+
+configure :libs => 'LOADLIBES'
+
+desc 'determining build type'
+configure 'LINKAGE_TYPE' do
+  if $opts.defined? :static_libs
+    CONFIG['LINKAGE_TYPE'] = 'static'
+    CONFIG.add_xml '<property name="linkage" value="static" />'
+  else
+    CONFIG['LINKAGE_TYPE'] = 'dynamic'
+    CONFIG.add_xml '<property name="linkage" value="dynamic" />'
+  end
+  ok(CONFIG['LINKAGE_TYPE'])
+end
+
+desc 'getting library path...'
+configure :libpath => 'OS_NAME' do
+  if $opts.defined? :libpath
+    CONFIG[:libpath] = $opts[:libpath].split(':')
+  else
+    if CONFIG['OS_NAME'] == 'Mac\ OS\ X'
+      CONFIG[:libpath] = ['/opt/local/lib']
+    else
+      CONFIG[:libpath] = %w(/usr/lib /lib /usr/lib/sse2)
+    end
+  end
+  ok(CONFIG[:libpath].inspect)
+end
+
+desc 'determining whether to build for lapack or atlas'
+configure 'BUILD_TYPE' do
+  if $opts.defined? :lapack_build
+    CONFIG['BUILD_TYPE'] = 'lapack'
+    ok('lapack')
+  else
+    CONFIG['BUILD_TYPE'] = 'atlas'
+    ok('atlas')
+  end
+end
+
+desc 'looking for libraries...'
+configure 'LOADLIBES' => ['LINKAGE_TYPE', :libpath, 'F77', 'BUILD_TYPE'] do
+
+  case CONFIG['BUILD_TYPE']
+  when 'atlas'
+    libs = ATLAS_LIBS
+    syms = ATLAS_REQUIRED_SYMBOLS
+  when 'lapack'
+    libs = LAPACK_LIBS
+    syms = LAPACK_REQUIRED_SYMBOLS
+  end
+
+  result = LibHelpers.find_libs(CONFIG[:libpath], libs, syms)
+  p result
+
+  case CONFIG['LINKAGE_TYPE']
+  when 'dynamic'
+    CONFIG['LDFLAGS'] += result.values.uniq.map {|s| '-L' + s.escape}
+    CONFIG['LOADLIBES'] += result.keys.map {|s| '-l' + s.escape}
+  when 'static'
+    #CONFIG['LOADLIBES'] += ['-Wl,--allow-multiple-definition'] unless CONFIG['OS_NAME'] == 'Mac\ OS\ X'
+
+    # Add the libraries with their full path to the command line.
+    # We have to sort them in the order as they appear in +libs+, otherwise
+    # we'll have unresolved symbols, at least under Linux.
+    CONFIG['LOADLIBES'] += result.keys.
+      sort {|x, y| libs.index(x) <=> libs.index(y)}.
+      map {|s| File.join(result[s], LibHelpers.libname(s)).escape }
+    if CONFIG['F77'] == 'gfortran'
+      CONFIG['LOADLIBES'] += ['-l:libgfortran.a']
+    end
+    if CONFIG['OS_NAME'] == 'Mac\ OS\ X'
+      CONFIG['LOADLIBES'] += ['/opt/local/lib/gcc43/libgfortran.a']
+    end 
+  end
+  ok
+end
+
+if __FILE__ == $0
+  $opts = Opts.new(ARGV)
+  Config.run :libs
+  Config::CONFIG.dump($stdout)
+end
\ No newline at end of file
diff --git a/config/path.rb b/config/config_make.rb
similarity index 71%
copy from config/path.rb
copy to config/config_make.rb
index febeab3..b0b1c25 100644
--- a/config/path.rb
+++ b/config/config_make.rb
@@ -1,24 +1,24 @@
 ## --- BEGIN LICENSE BLOCK ---
 # Copyright (c) 2009, Mikio L. Braun
 # All rights reserved.
-# 
+#
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are
 # met:
-# 
+#
 #     * Redistributions of source code must retain the above copyright
 #       notice, this list of conditions and the following disclaimer.
-# 
+#
 #     * Redistributions in binary form must reproduce the above
 #       copyright notice, this list of conditions and the following
 #       disclaimer in the documentation and/or other materials provided
 #       with the distribution.
-# 
+#
 #     * Neither the name of the Technische Universität Berlin nor the
 #       names of its contributors may be used to endorse or promote
 #       products derived from this software without specific prior
 #       written permission.
-# 
+#
 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -32,39 +32,28 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ## --- END LICENSE BLOCK ---
 
-require 'set'
+require 'config/config'
+require 'config/path'
 
-PATH = ENV['PATH'].split(':')
+include Config
+include Path
 
-def where(file, path=PATH)
-  path.each do |p|
-    fn = File.join(p, file)
-    #print "  Checking #{fn}"
-    if File.exist? fn
-      #puts "  found"
-      if block_given? 
-        return p if yield fn
-      else
-        return p
-      end
-    else
-      #puts
+configure :make => ['MAKE']
+
+desc 'looking for version of make'
+configure 'MAKE' do
+  if Path.where('gmake')
+    puts 'gmake'
+    CONFIG['MAKE'] = 'gmake'
+  else
+    if Path.where_with_output('make -v', /GNU Make/).nil?
+      Config.fail('I need GNU make to run...')
     end
+    CONFIG['MAKE'] = 'make'
   end
-  return
+  ok(CONFIG['MAKE'])
 end
 
-# returns the path to the command as specified by
-# line or nil if the command does not exist, or
-# it did not produce the right result
-def where_with_output(line, output)
-   cmd = line.split[0]
-   p = where(cmd)
-   return unless p
-   out = %x(#{File.join(p,line)})
-   if out =~ output
-     return p
-   else
-     return
-   end
-end
+if __FILE__ == $0
+  ConfigureTask.run :make
+end
\ No newline at end of file
diff --git a/config/path.rb b/config/config_os_arch.rb
similarity index 52%
copy from config/path.rb
copy to config/config_os_arch.rb
index febeab3..975084d 100644
--- a/config/path.rb
+++ b/config/config_os_arch.rb
@@ -1,24 +1,24 @@
 ## --- BEGIN LICENSE BLOCK ---
 # Copyright (c) 2009, Mikio L. Braun
 # All rights reserved.
-# 
+#
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are
 # met:
-# 
+#
 #     * Redistributions of source code must retain the above copyright
 #       notice, this list of conditions and the following disclaimer.
-# 
+#
 #     * Redistributions in binary form must reproduce the above
 #       copyright notice, this list of conditions and the following
 #       disclaimer in the documentation and/or other materials provided
 #       with the distribution.
-# 
+#
 #     * Neither the name of the Technische Universität Berlin nor the
 #       names of its contributors may be used to endorse or promote
 #       products derived from this software without specific prior
 #       written permission.
-# 
+#
 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -32,39 +32,64 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ## --- END LICENSE BLOCK ---
 
-require 'set'
+#
+# Check the Operating System
+#
 
-PATH = ENV['PATH'].split(':')
+require 'config/config'
+require 'config/string_ext'
+require 'config/config_java'
 
-def where(file, path=PATH)
-  path.each do |p|
-    fn = File.join(p, file)
-    #print "  Checking #{fn}"
-    if File.exist? fn
-      #puts "  found"
-      if block_given? 
-        return p if yield fn
-      else
-        return p
-      end
-    else
-      #puts
-    end
+include Config
+
+def detect_os
+  os_name = %x(java -cp config PrintProperty os.name).chomp
+  if os_name.start_with? 'Windows'
+    os_name = 'Windows'
+  end
+  return os_name
+end
+
+configure :os_arch => ['OS_NAME', 'OS_ARCH', 'ARCH_FLAVOR']
+
+desc 'determining operating system'
+configure 'OS_NAME' => 'FOUND_JAVA' do
+  os_name = detect_os
+  CONFIG['OS_NAME'] = os_name.gsub(' ', '\ ')
+  CONFIG.add_xml "<property name=\"os_name\" value=\"#{os_name}\" />"
+  ok(os_name)
+end
+
+desc 'determining architecture'
+configure 'OS_ARCH' => 'FOUND_JAVA' do
+  os_arch = %x(java -cp config PrintProperty os.arch).chomp
+  CONFIG['OS_ARCH'] = os_arch
+  CONFIG.add_xml "<property name=\"os_arch\" value=\"#{os_arch}\" />"
+  ok(os_arch)
+end
+
+desc 'determining architecture flavor'
+configure 'ARCH_FLAVOR' => 'OS_ARCH' do
+  if $opts.defined? :arch_flavor
+    arch_flavor = $opts[:arch_flavor]
+  elsif %w(i386 amd64 x86 x86_64).include? CONFIG['OS_ARCH']
+    Path.check_cmd('gcc')
+    out = %x(gcc -o config/arch_flavor config/arch_flavor.c)
+    fail('couldn\'t compile the config script') unless out.empty?
+    arch_flavor = %x(config/arch_flavor).chomp
+  else
+    arch_flavor = ''
   end
-  return
+
+  if arch_flavor.empty?
+    CONFIG['OS_ARCH_WITH_FLAVOR'] = CONFIG['OS_ARCH']
+  else
+    CONFIG['OS_ARCH_WITH_FLAVOR'] = CONFIG['OS_ARCH'] + File::SEPARATOR + arch_flavor
+  end
+
+  ok(arch_flavor)
 end
 
-# returns the path to the command as specified by
-# line or nil if the command does not exist, or
-# it did not produce the right result
-def where_with_output(line, output)
-   cmd = line.split[0]
-   p = where(cmd)
-   return unless p
-   out = %x(#{File.join(p,line)})
-   if out =~ output
-     return p
-   else
-     return
-   end
+if __FILE__ == $0
+  ConfigureTask.run :os_arch
 end
diff --git a/config/path.rb b/config/config_tools.rb
similarity index 72%
copy from config/path.rb
copy to config/config_tools.rb
index febeab3..24a71ae 100644
--- a/config/path.rb
+++ b/config/config_tools.rb
@@ -1,24 +1,24 @@
 ## --- BEGIN LICENSE BLOCK ---
 # Copyright (c) 2009, Mikio L. Braun
 # All rights reserved.
-# 
+#
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are
 # met:
-# 
+#
 #     * Redistributions of source code must retain the above copyright
 #       notice, this list of conditions and the following disclaimer.
-# 
+#
 #     * Redistributions in binary form must reproduce the above
 #       copyright notice, this list of conditions and the following
 #       disclaimer in the documentation and/or other materials provided
 #       with the distribution.
-# 
+#
 #     * Neither the name of the Technische Universität Berlin nor the
 #       names of its contributors may be used to endorse or promote
 #       products derived from this software without specific prior
 #       written permission.
-# 
+#
 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -32,39 +32,31 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ## --- END LICENSE BLOCK ---
 
-require 'set'
+require 'config/config'
+require 'config/path'
+require 'config/config_os_arch'
 
-PATH = ENV['PATH'].split(':')
+include Config
+include Path
 
-def where(file, path=PATH)
-  path.each do |p|
-    fn = File.join(p, file)
-    #print "  Checking #{fn}"
-    if File.exist? fn
-      #puts "  found"
-      if block_given? 
-        return p if yield fn
-      else
-        return p
-      end
-    else
-      #puts
+configure :tools => ['FOUND_NM', 'FOUND_CYGPATH']
+
+desc 'looking for nm'
+configure 'FOUND_NM' do
+  check_cmd 'nm'
+  CONFIG['FOUND_NM'] = true
+  ok
+end
+
+configure 'FOUND_CYGPATH' => 'OS_NAME' do
+  if CONFIG['OS_NAME'] == 'Windows'
+    msg 'checking for cygpath' do
+      check_cmd 'cygpath'
+      CONFIG['FOUND_CGYPATH'] = true
     end
   end
-  return
 end
 
-# returns the path to the command as specified by
-# line or nil if the command does not exist, or
-# it did not produce the right result
-def where_with_output(line, output)
-   cmd = line.split[0]
-   p = where(cmd)
-   return unless p
-   out = %x(#{File.join(p,line)})
-   if out =~ output
-     return p
-   else
-     return
-   end
-end
+if __FILE__ == $0
+  ConfigureTask.run :tools
+end
\ No newline at end of file
diff --git a/config/configure.rb b/config/configure.rb
index 1fe4b3c..06977bb 100644
--- a/config/configure.rb
+++ b/config/configure.rb
@@ -36,20 +36,37 @@ require 'config/path'
 require 'config/config'
 require 'config/opts'
 
-# I shouldn't assume that things have certain layout but instead just try
-# to find the resources:
-#
-# - LAPACK and BLAS sources if I want to recompile (otherwise, not)
-# - lapack_build: complete lapack and blas libraries
-# - atlas_build: complete lapack libraries, atlas libraries
+require 'config/config_tools'
+require 'config/config_os_arch'
+require 'config/config_cc'
+require 'config/config_fortran'
+require 'config/config_make'
+require 'config/config_lapack_sources'
+require 'config/config_libs'
+
+include Config
+include Path
+
+args = []
+paste = false
+ARGV.each do |arg|
+  if arg[-1] == ?\\
+    paste_next = true
+    arg = arg[0...-1] + ' '
+  else
+    paste_next = false
+  end
+
+  if paste
+    args[-1] += arg
+  else
+    args << arg
+  end
 
-#Todo:
-#  - find/download/compile LAPACK
-#  - find ATLAS
-#  - write out stuff to .config
-# EOS
+  paste = paste_next
+end
 
-$opts = Opts.new(ARGV, {}, <<EOS)
+$opts = Opts.new(args, {}, <<EOS)
 Usage: ./configure [options]
 
 options summary:
@@ -63,389 +80,14 @@ options summary:
                            dynamically loaded jblas library which does
                            not depend on lapack or atlas libraries. 
                            (default for Windows!)
+  --arch-flavor=...        Set architectural flavor (e.g. --arch-flavor=sse2)
 EOS
 
-config = Config.new
-
-# translate dir (mainly necessary for cygwin)
-def dir(s)
-  case $os_name
-  when 'Windows'
-    s = s.gsub(/\\/, '\\\\\\\\')
-    %x(cygpath -u #{s}).chomp
-  else
-    s # safe default... 
-  end
-end
-
-def libname(name)
-  if $opts.defined? :static_libs
-    'lib' + name + '.a'
-  else
-    case $os_name
-    when 'Linux'
-      'lib' + name + '.so'
-    when 'SunOS'
-      'lib' + name + '.so'
-    when 'Windows'
-      'lib' + name + '.a'
-    end
-  end
-end
-
-# returns an array of the symbols defined in the library +fn+.
-def libsyms(fn)
-  nmopt = File.extname(fn) == '.so' ? '-D' : ''
-  %x(nm -p #{nmopt} #{fn}).grep(/ T _?([a-zA-Z0-9_]+)/) {|m| $1}
-end
-
-# indent a multiline text
-class String
-  def indent(cnt)
-    split("\n").map {|l| ' ' * cnt + l}.join("\n")
-  end
-
-  def start_with?(head)
-    self.length > head.length && self[0...head.length] == head
-  end
-end
-
-begin
-  ######################################################################
-  config.msg('checking for java, javac') do 
-    config.check_cmd('java', 'javac')
-    %x(javac config/PrintProperty.java)
-    nil
-  end
-
-  ######################################################################
-  config.msg('checking for nm') do
-    config.check_cmd 'nm'
-  end
-
-  ######################################################################
-  config.msg('determining operating system') do
-    $os_name = %x(java -cp config PrintProperty os.name).chomp
-    if $os_name.start_with? 'Windows'
-      $os_name = 'Windows'
-    end
-    if $os_name == 'Windows'
-      config.msg 'checking for cygpath' do
-        config.check_cmd 'cygpath'
-      end
-    end
-    config['OS_NAME'] = $os_name
-    config.add_xml "<property name=\"os_name\" value=\"#{$os_name}\" />"
-    $os_name
-  end
-
-  config.msg('determining architecture') do
-    $os_arch = %x(java -cp config PrintProperty os.arch).chomp
-    config['OS_ARCH'] = $os_arch
-    config.add_xml "<property name=\"os_arch\" value=\"#{$os_arch}\" />"
-    $os_arch
-  end
-
-  ######################################################################
-  config.msg('locating the Java Development Kit') do
-    $java_home = dir(File.dirname(%x(java -cp config PrintProperty java.home)))
-    p $java_home
-    config.check_files $java_home, ['include', 'jni.h'] do
-      config['JAVA_HOME'] = $java_home
-    end
-  end
-  
-  ######################################################################
-  config.msg('deciding whether to use g77 or gfortran') do
-    g77 = where('g77')
-    gfortran = where('gfortran')
-    f77 = where('f77')
-    if g77
-      config['LD'] = 'g77'
-      config['F77'] = 'g77'
-    elsif gfortran
-      #config['LD'] = 'gfortran'
-      config['F77'] = 'gfortran'
-      config['LD'] = 'gcc'
-    elsif f77
-      config['F77'] = 'f77'
-      config['LD'] = 'f77'
-    else
-      config.fail <<EOS.indent 2
-Either g77 or gfortran have to be installed to compile against the
-fortran libraries.
-EOS
-    end
-  end
-  
-  ######################################################################
-  config.msg('Setting up gcc and flags') do
-    config.check_cmd('gcc', 'make', 'ld')
-    case $os_name
-    when 'Linux'
-      config << <<EOS
-CC = gcc
-CFLAGS = -fPIC
-INCDIRS += -Iinclude -I#{$java_home}/include -I#{$java_home}/include/linux
-SO = so
-LIB = lib
-RUBY=ruby
-LDFLAGS += -shared
-EOS
-    when 'SunOS'
-      config << <<EOS
-CC = gcc
-CFLAGS = -fPIC
-INCDIRS += -Iinclude -I#{$java_home}/include -I#{$java_home}/include/solaris
-SO = so
-LIB = lib
-RUBY=ruby
-LDFLAGS += -G
-EOS
-    when 'Windows'
-      config.check_cmd('cygpath')
-      config << <<EOS
-CC = gcc
-CFLAGS = -ggdb -D__int64='long long'
-INCDIRS += -I"#{dir $java_home}/include" -I"#{dir $java_home}/include/win32" -Iinclude
-LDFLAGS += -mno-cygwin -shared -Wl,--add-stdcall-alias
-SO = dll
-LIB = 
-RUBY = ruby
-EOS
-    else
-      config.fail "Sorry, the OS #{$os_name} is currently not supported"
-    end
-  end
-
-  ######################################################################
-  config.msg('looking for version of make') do
-     if where('gmake')
-	puts 'gmake'
-        config['MAKE'] = 'gmake'
-	config.add_xml '<property name="make" value="gmake" />'
-     else
-        if where_with_output('make -v', /GNU Make/).nil?
-      	  config.fail('I need GNU make to run...')
-	end
-        config['MAKE'] = 'make'
-	config.add_xml '<property name="make" value="make" />'
-     end
-  end
-
-  ######################################################################
-  def check_lapack_home(config)
-    config.check_files($lapack_home, 
-                       ['BLAS', 'SRC', 'dgemm.f'], 
-                       ['SRC', 'dsyev.f']) do
-      config['LAPACK_HOME'] = $lapack_home
-    end
-  end
-  
-  config.msg('locating lapack sources') do
-    $lapack_home = $opts.get :lapack, './lapack-lite-3.1.1'
-    begin
-      check_lapack_home(config)
-    rescue ConfigError => e
-      if $opts.defined? :download_lapack
-        puts "trying to download lapack (about 5M)"
-        lapack_tgz = File.join('.', 'lapack-lite-3.1.1.tgz')
-        File.delete(lapack_tgz) if File.exist?(lapack_tgz)
-        system("wget http://www.netlib.org/lapack/lapack-lite-3.1.1.tgz")
-        system("tar xzvf lapack-lite-3.1.1.tgz")
-        check_lapack_home(config)
-      else
-        puts <<EOS.indent 2
-Couldn\'t locate sources for LAPACK and BLAS. Supply the location
-of the lapack sources with the --lapack=... switch. Sources for lapack can be
-found at http://www.netlib.org/lapack/lapack-lite-3.1.1.tgz or try
-running configure with the --download-lapack option.
-
-Compling jblas should work, but unless you have the LAPACK and BLAS sources
-you cannot add further stubs.
-EOS
-        config['LAPACK_HOME'] = ''
-        $lapack_home = ''
-      end
-    end
-    $lapack_home
-  end
-
-  ######################################################################
-  #
-  # Locating the libraries
-  #
-  # This is a bit involved since the standard ATLAS compilation produces
-  # a liblapack.so which only implements a subset of the lapack functions.
-  # So the basic strategy is to
-  # 
-  # (a) find the path to the atlas specific library
-  # (b) find the path to a full lapack library
-  #
-  # Pass the lapack libraries and theirs paths first.
-  #
-  # Of course, if you want to build a lapack-only path, we only search
-  # for the full lapack libraries.
-
-  if $opts.defined? :libpath
-    LIBPATH = $opts[:libpath].split(':')
-  else
-    LIBPATH = %w(/usr/lib /lib /usr/lib/sse2)
-  end
-
-  $libpaths = []
-  
-  # Like Set, but retains order in which elements were added
-  def addpath(path)
-    $libpaths << path unless $libpaths.include?
-  end
-  
-  def locate_lib(config, name, symbol=nil)
-    p = where(libname(name), LIBPATH) do |fn| 
-      symbol.nil? or libsyms(fn).include? symbol
-    end
-
-    if not p
-      config.fail("couldn't find library '#{name}' in\npath #{LIBPATH.join ':'}")
-    end
-    
-    config.log "found library #{name} in #{p}"
-    return p
-  end
-
-  # Tries to find one of the libraries +names+ in LIBPATH,
-  # potentially containing the +symbol+.
-  # Returns the path and the actual name of the library
-  def locate_one_of_libs(config, names, symbol=nil)
-    p = nil
-    l = nil
-    config.log "Searching for one of #{names.join ', '} in #{LIBPATH.join ':'}#{if symbol then ' having symbol ' + symbol.to_s end}"
-    for name in names
-      config.log "  Searching for #{libname(name)}"
-      p = where(libname(name), LIBPATH) do |fn| 
-        symbol.nil? or libsyms(fn).include? symbol
-      end
-
-      if p
-        l = name
-        config.log "Found at #{l} at #{p}"
-        break
-      end
-    end
-
-    if not p
-      config.log "Haven't found any of #{names.join ', '}!"
-      config.fail("couldn't find library '#{name}' in\npath #{LIBPATH.join ':'}")
-    end
-
-    config.log "found library #{l} in #{p}"
-    return p, l
-  end
-
-  ######################################################################
-  config.msg('locating lapack and blas libraries') do 
-    begin      
-      $lapack_path, $lapack_name = 
-        locate_one_of_libs(config, ['lapack_fortran', 'lapack'], 'dsyev_')
-      $blas_path, $blas_name = 
-        locate_one_of_libs(config, ['blas_fortran', 'blas', 'f77blas'], 'daxpy_')
-    rescue ConfigError => e
-      config.fail <<EOS.indent 2
-Couldn\'t locate LAPACK and BLAS libraries.
-
-Reason: #{e.message}
-
-You can try to pass the location via --libpath=...
-or build your own LAPACK and BLAS libraries (see INSTALL)
-EOS
-    end
-    $libpaths << $lapack_path
-    $libpaths << $blas_path
-    nil
-  end
-  
-  unless $opts.defined? :lapack_build
-    config.msg('locating atlas libraries') do
-      begin
-        $atlas_path = locate_lib(config, 'atlas')
-        $lapack_atlas_path, $lapack_atlas_name = 
-          locate_one_of_libs(config, ['lapack_atlas', 'lapack'], 'ATL_dgetri')
-        $cblas_path = locate_lib(config, 'cblas', 'cblas_daxpy')
-      rescue ConfigError => e
-        config.fail <<EOS.indent 2
-Couldn\'t locate ATLAS libraries.
-
-Reason: #{e.message}
-
-You can try to pass the location via --libpath=...
-or build your own ATLAS libraries (see INSTALL)
-EOS
-      end
-      $libpaths << $atlas_path
-      $libpaths << $lapack_atlas_path
-      $libpaths << $cblas_path
-      nil
-    end
-  end
-
-  ######################################################################
-  #
-  # Set output directory depending on static or dynamic libraries
-  #
-  if $opts.defined? :static_libs
-    config.add_xml '<property name="linkage" value="static" />'
-    config['LINKAGE'] = 'static'
-  else
-    config.add_xml '<property name="linkage" value="dynamic" />'
-    config['LINKAGE'] = 'dynamic'
-  end
-
-
-  ######################################################################
-  # Some sanity checks, in particular that ATLAS's and LAPACK's lapack
-  # library doesn't have the same name... . 
-  if $lapack_name == $lapack_atlas_name
-    config.fail <<EOS.indent 2
-The full lapack library and the one from ATLAS have the same name which
-makes it impossible to link in both. Either fiddle with --libpath=... or
-try renaming some of the libraries:
-
-lapack's #{libname $lapack_name} to #{libname 'lapack_fortran'}
-ATLAS' #{libname $lapack_name} to #{libname 'lapack_atlas'}
-EOS
-  end
+configure :all => [:os_arch, :tools, :java, :cc, :fortran, :make, :lapack_sources, :libs]
 
-  # Okay, then we're done!
-  config << "LDFLAGS += #{$libpaths.map {|s| '-L' + s}.join ' '}"
+run :all
 
-  if $opts.defined? :lapack_build
-    loadlibes = [$lapack_name, $blas_name]
-  else
-    loadlibes = [$lapack_atlas_name, $lapack_name, $blas_name, 'cblas', 'atlas']
-  end
-
-  if $opts.defined? :static_libs
-    loadlibes = "LOADLIBES = -Wl,--allow-multiple-definition #{loadlibes.map {|l| ' -l:lib' + l + '.a'}}"
-  else
-    loadlibes = "LOADLIBES =#{loadlibes.map {|l| ' -l' + l}}"
-  end
-
-  # add fortran static library if we're using gfortran
-  if $opts.defined? :static_libs and config['F77'] == 'gfortran'
-    loadlibes += " -l:libgfortran.a"
-  end
-  config << loadlibes
-
-  ######################################################################
-  # dumping results
-  puts
-  puts 'Configuration succesfull, writing out results to configure.out'
-  open('configure.out', 'w') {|f| config.dump f}
-  open('configure.xml', 'w') {|f| config.dump_xml f}
-
-rescue ConfigError => e
-  puts 
-  puts "Configuration failed!"
-  puts
-  puts "Reason: #{e.message}"
-end
+puts
+puts 'Configuration succesfull, writing out results to configure.out'
+open('configure.out', 'w') {|f| CONFIG.dump f}
+open('configure.xml', 'w') {|f| CONFIG.dump_xml f}
diff --git a/config/lib_helpers.rb b/config/lib_helpers.rb
new file mode 100644
index 0000000..6a3812e
--- /dev/null
+++ b/config/lib_helpers.rb
@@ -0,0 +1,166 @@
+## --- BEGIN LICENSE BLOCK ---
+# Copyright (c) 2009, Mikio L. Braun
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#
+#     * Neither the name of the Technische Universität Berlin nor the
+#       names of its contributors may be used to endorse or promote
+#       products derived from this software without specific prior
+#       written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+## --- END LICENSE BLOCK ---
+
+require 'config/config'
+require 'config/path'
+require 'config/config_os_arch'
+
+module LibHelpers
+  module_function
+
+  def libname(name)
+    case Config::CONFIG['LINKAGE_TYPE']
+    when 'static'
+      'lib' + name + '.a'
+    when 'dynamic'
+      case Config::CONFIG['OS_NAME']
+      when 'Linux'
+        'lib' + name + '.so'
+      when 'SunOS'
+        'lib' + name + '.so'
+      when 'Windows'
+        'lib' + name + '.a'
+      when 'Mac\ OS\ X'
+        'lib' + name + '.dylib'
+      else
+        Config.fail "Sorry, OS '#{Config::CONFIG['OS_NAME']}' is not supported yet..."
+      end
+    else
+      raise "LINKAGE_TYPE should be either dynamic or static, but is #{Config::CONFIG['LINKAGE_TYPE']}"
+    end
+  end
+
+  # returns an array of the symbols defined in the library +fn+.
+  def libsyms(fn)
+    nmopt = File.extname(fn) == '.so' ? '-D' : ''
+    %x(nm -p #{nmopt} #{fn.escape}).grep(/ T _?([a-zA-Z0-9_]+)/) {|m| $1}
+  end
+
+  def locate_lib(libpath, name, symbol=nil)
+    p = Path.where(libname(name), libpath) do |fn|
+      symbol.nil? or libsyms(fn).include? symbol
+    end
+
+    if not p
+      Config.fail("couldn't find library '#{name}' in\npath #{libpath.join ':'}")
+    end
+
+    Config.log "found library #{name} in #{p}"
+    return p
+  end
+
+  # Tries to find one of the libraries +names+ in LIBPATH,
+  # potentially containing the +symbol+.
+  # Returns the path and the actual name of the library
+  def locate_one_of_libs(libpath, names, symbol=nil)
+    p = nil
+    l = nil
+    Config.log "Searching for one of #{names.join ', '} in #{libpath.join ':'}#{if symbol then ' having symbol ' + symbol.to_s end}"
+    for name in names
+      Config.log "  Searching for #{libname(name)}"
+      p = Path.where(libname(name), libpath) do |fn|
+        symbol.nil? or libsyms(fn).include? symbol
+      end
+
+      if p
+        l = name
+        Config.log "Found at #{l} at #{p}"
+        break
+      end
+    end
+
+    if not p
+      Config.log "Haven't found any of #{names.join ', '}!"
+      Config.fail("couldn't find library '#{name}' in\npath #{LIBPATH.join ':'}")
+    end
+
+    Config.log "found library #{l} in #{p}"
+    return p, l
+  end
+
+  # locate +libs+ in given +paths+ and look for the +symbols+
+  #
+  # What you get is a hash mapping libraries to their paths. If a symbol could
+  # not be found, a Config::ConfigError is raised.
+  def find_libs(paths, libs, symbols)
+    found_symbols = {}
+    paths.each do |path|
+      libs.each do |lib|
+        libfile = File.join(path, libname(lib))
+        next unless test ?f, libfile
+        syms = libsyms(libfile)
+        symbols.each do |s|
+          if syms.include? s
+            found_symbols[s] ||= []
+            found_symbols[s] << [path, lib]
+          end
+        end
+      end
+    end
+
+    #p found_symbols
+
+    not_found_symbols = symbols.reject {|s| found_symbols.include? s }
+    unless not_found_symbols.empty?
+      Config.fail "Could not locate libraries for the following symbols: #{not_found_symbols.join ', '}."
+    end
+
+    #found_symbols.each_pair {|k,v| printf "%20s: %s\n", k, v.inspect}
+    result = {}
+    found_symbols.each_pair do |k, v|
+      result[v[0][1]] = v[0][0]
+    end
+    return result
+  end
+end
+
+if __FILE__ == $0
+  include LibHelpers
+  symbols_needed = [
+    'dsyev_', # eigenvalue function not yet included in ATLAS/LAPACK
+    'ATL_dgetri', # an atlas-specific function
+    'ATL_dgemm', 
+    'dgemm_', # matrix-matrix multiplication
+    'daxpy_', # blas-related function
+    'xerbla_', # xerbla?
+  ]
+
+  paths = %w(/usr/lib/sse2 /usr/lib)
+
+  libs = %w(atlas lapack blas f77blas cblas lapack_atlas)
+
+  Config::CONFIG['BUILD_TYPE'] = 'static'
+  Config::CONFIG['OS_NAME'] = 'Linux'
+  p find_libs(paths, libs, symbols_needed)
+end
\ No newline at end of file
diff --git a/config/path.rb b/config/path.rb
index febeab3..62695fd 100644
--- a/config/path.rb
+++ b/config/path.rb
@@ -33,38 +33,75 @@
 ## --- END LICENSE BLOCK ---
 
 require 'set'
+require 'config/config'
 
-PATH = ENV['PATH'].split(':')
+module Path
+  PATH = ENV['PATH'].split(':')
 
-def where(file, path=PATH)
-  path.each do |p|
-    fn = File.join(p, file)
-    #print "  Checking #{fn}"
-    if File.exist? fn
-      #puts "  found"
-      if block_given? 
-        return p if yield fn
+  module_function
+
+  def where(file, path=PATH)
+    path.each do |p|
+      fn = File.join(p, file)
+      #print "  Checking #{fn}"
+      if File.exist? fn
+        #puts "  found"
+        if block_given?
+          return p if yield fn
+        else
+          return p
+        end
       else
-        return p
+        #puts
       end
+    end
+    return
+  end
+
+  # returns the path to the command as specified by
+  # line or nil if the command does not exist, or
+  # it did not produce the right result
+  def where_with_output(line, output)
+    cmd = line.split[0]
+    p = where(cmd)
+    return unless p
+    out = %x(#{File.join(p,line)})
+    if out =~ output
+      return p
     else
-      #puts
+      return
+    end
+  end
+
+  # Check whether a cmd could be found.
+  def check_cmd(*cmds)
+    cmds.each do |cmd|
+      Config.log "Searching for command #{cmd}"
+      Config.fail("coulnd't find command #{cmd}") unless Path.where cmd
     end
+    yield self if block_given?
+    return
   end
-  return
-end
 
-# returns the path to the command as specified by
-# line or nil if the command does not exist, or
-# it did not produce the right result
-def where_with_output(line, output)
-   cmd = line.split[0]
-   p = where(cmd)
-   return unless p
-   out = %x(#{File.join(p,line)})
-   if out =~ output
-     return p
-   else
-     return
-   end
-end
+  # Check whether files could be found in the given path.
+  def check_files(path, *files)
+    files.each do |file|
+      file = File.join(path, *file)
+      Config.log "Searching for file #{file}"
+      Config.fail("couldn't find #{file}") unless File.exist? file
+    end
+    yield if block_given?
+    return
+  end
+
+  # translate dir (mainly necessary for cygwin)
+  def dir(s)
+    case Config::CONFIG['OS_NAME']
+    when 'Windows'
+      s = s.gsub(/\\/, '\\\\\\\\')
+      %x(cygpath -u '#{s}').chomp
+    else
+      s # safe default...
+    end
+  end
+end
\ No newline at end of file
diff --git a/config/path.rb b/config/string_ext.rb
similarity index 71%
copy from config/path.rb
copy to config/string_ext.rb
index febeab3..b4edfc9 100644
--- a/config/path.rb
+++ b/config/string_ext.rb
@@ -1,24 +1,24 @@
 ## --- BEGIN LICENSE BLOCK ---
 # Copyright (c) 2009, Mikio L. Braun
 # All rights reserved.
-# 
+#
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions are
 # met:
-# 
+#
 #     * Redistributions of source code must retain the above copyright
 #       notice, this list of conditions and the following disclaimer.
-# 
+#
 #     * Redistributions in binary form must reproduce the above
 #       copyright notice, this list of conditions and the following
 #       disclaimer in the documentation and/or other materials provided
 #       with the distribution.
-# 
+#
 #     * Neither the name of the Technische Universität Berlin nor the
 #       names of its contributors may be used to endorse or promote
 #       products derived from this software without specific prior
 #       written permission.
-# 
+#
 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -32,39 +32,17 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ## --- END LICENSE BLOCK ---
 
-require 'set'
-
-PATH = ENV['PATH'].split(':')
+# indent a multiline text
+class String # :nodoc:
+  def indent(cnt)
+    split("\n").map {|l| ' ' * cnt + l}.join("\n")
+  end
 
-def where(file, path=PATH)
-  path.each do |p|
-    fn = File.join(p, file)
-    #print "  Checking #{fn}"
-    if File.exist? fn
-      #puts "  found"
-      if block_given? 
-        return p if yield fn
-      else
-        return p
-      end
-    else
-      #puts
-    end
+  def start_with?(head)
+    self.length > head.length && self[0...head.length] == head
   end
-  return
-end
 
-# returns the path to the command as specified by
-# line or nil if the command does not exist, or
-# it did not produce the right result
-def where_with_output(line, output)
-   cmd = line.split[0]
-   p = where(cmd)
-   return unless p
-   out = %x(#{File.join(p,line)})
-   if out =~ output
-     return p
-   else
-     return
-   end
-end
+  def escape
+    gsub /\s/, '\ '
+  end
+end
\ No newline at end of file
diff --git a/docs/jblas-logo-64.png b/docs/jblas-logo-64.png
new file mode 100644
index 0000000..c747bc9
Binary files /dev/null and b/docs/jblas-logo-64.png differ
diff --git a/docs/jblas-logo-square.png b/docs/jblas-logo-square.png
new file mode 100644
index 0000000..b563197
Binary files /dev/null and b/docs/jblas-logo-square.png differ
diff --git a/native/jblas_arch_flavor.c b/native/jblas_arch_flavor.c
new file mode 100644
index 0000000..3a51839
--- /dev/null
+++ b/native/jblas_arch_flavor.c
@@ -0,0 +1,54 @@
+/**********************************************************************/
+/*                detecting sse level                                 */
+/**********************************************************************/
+
+#include "org_jblas_util_ArchFlavor.h"
+
+/*
+ * Thanks to the following pages for helping me out on this.
+ *
+ * http://softpixel.com/~cwright/programming/simd/cpuid.php
+ * http://www.gentoo.org/proj/en/hardened/pic-fix-guide.xml
+ */
+#define cpuid(func,ax,bx,cx,dx)	\
+  __asm__ __volatile__ (" \
+        movl %%ebx, %%edi; \
+        cpuid;		  \
+        movl %%ebx, %1;	  \
+        movl %%edi, %%ebx" \
+	: "=a" (ax), "=r" (bx), "=c" (cx), "=d" (dx) \
+        : "a" (func) \
+        : "edi");
+
+/* in edx */
+#define SSE (1L << 25)
+#define SSE2 (1L << 26)
+
+/* in ecx */
+#define SSE3 (1L << 0)
+
+int sse_level() {
+  int level = -1;
+#ifdef HAS_CPUID
+  int a, b, c, d;
+
+  cpuid(1, a, b, c, d);
+
+  if (d & SSE) {
+    level = 1;
+  }
+
+  if (d & SSE2) {
+    level = 2;
+  }
+
+  if (c & SSE3) {
+    level = 3;
+  }
+#endif
+  return level;
+}
+
+JNIEXPORT jint JNICALL Java_org_jblas_util_ArchFlavor_SSELevel(JNIEnv *env, jclass this) {
+    return sse_level();
+}
diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml
deleted file mode 100644
index 2dd4812..0000000
--- a/nbproject/private/private.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
-    <data xmlns="http://www.netbeans.org/ns/profiler/1" profile-file-target="" profile-target="debugDirectBufferGC" version="0.4"/>
-    <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/1"/>
-</project-private>
diff --git a/nbproject/project.xml b/nbproject/project.xml
index 2768776..9e71fd8 100644
--- a/nbproject/project.xml
+++ b/nbproject/project.xml
@@ -117,7 +117,7 @@
             </ide-actions>
             <export>
                 <type>jar</type>
-                <location>jblas.jar</location>
+                <location>jblas-0.3.jar</location>
                 <build-target>jar</build-target>
             </export>
             <view>
@@ -169,7 +169,7 @@
         <java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/2">
             <compilation-unit>
                 <package-root>src</package-root>
-                <built-to>jblas.jar</built-to>
+                <built-to>jblas-0.3.jar</built-to>
                 <source-level>1.5</source-level>
             </compilation-unit>
             <compilation-unit>
diff --git a/scripts/java-class.java b/scripts/java-class.java
index 003adf8..dd3950d 100644
--- a/scripts/java-class.java
+++ b/scripts/java-class.java
@@ -33,9 +33,10 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 // --- END LICENSE BLOCK ---
-
 package <%= package %>;
 
+import org.jblas.util.Logger;
+
 /**
  * Native BLAS and LAPACK functions.
  *
@@ -75,20 +76,19 @@ public class <%= classname %> {
   static {
 	  try {
 		  System.loadLibrary("jblas");
-	  }
-	  catch(UnsatisfiedLinkError e) {
-		  System.err.println(
-				  "BLAS native library not found in path. Copying native library\n" +
-				  "from the archive. Consider installing the library somewhere\n" +
-				  "in the path (for Windows: PATH, for Linux: LD_LIBRARY_PATH).");
-		  new org.jblas.util.LibraryLoader().loadLibrary("jblas");
-	  }
-  } 
-
-  private static int[] intDummy = new int[1];
-  private static double[] doubleDummy = new double[1];
-  private static float[] floatDummy = new float[1];
+        } catch (UnsatisfiedLinkError e) {
+            Logger.getLogger().config(
+                    "BLAS native library not found in path. Copying native library "
+                    + "from the archive. Consider installing the library somewhere "
+                    + "in the path (for Windows: PATH, for Linux: LD_LIBRARY_PATH).");
+            new org.jblas.util.LibraryLoader().loadLibrary("jblas", true);
+        }
+    }
+    private static int[] intDummy = new int[1];
+    private static double[] doubleDummy = new double[1];
+    private static float[] floatDummy = new float[1];
 
+     
 <% for r in routines -%>
 <%= generate_native_declaration r %>
 <% end %>
diff --git a/scripts/static_class_to_float.rb b/scripts/static_class_to_float.rb
index d5eebd0..dd15790 100644
--- a/scripts/static_class_to_float.rb
+++ b/scripts/static_class_to_float.rb
@@ -69,7 +69,7 @@ def translate(cl, s)
   copybody.gsub! /DoubleBuffer/, 'FloatBuffer'
   copybody.gsub! /DoubleVector/, 'FloatVector'
   copybody.gsub! /ComplexDouble/, 'ComplexFloat'
-  copybody.gsub! /([0-9]+\.[0-9]+)/, '\1f'
+  copybody.gsub! /([0-9]+\.[0-9]+(?:[eE]-?[0-9]+)?)/, '\1f'
   copybody.gsub! /double/, 'float'
   copybody.gsub! /NativeBlas\.dz/, 'NativeBlas.sc'
   copybody.gsub! /NativeBlas\.d/, 'NativeBlas.s'
diff --git a/src/org/jblas/Decompose.java b/src/org/jblas/Decompose.java
index 655fcaf..27375e6 100644
--- a/src/org/jblas/Decompose.java
+++ b/src/org/jblas/Decompose.java
@@ -14,6 +14,13 @@ import static org.jblas.util.Functions.min;
  */
 public class Decompose {
 
+    /**
+     * Class to hold an LU decomposition result.
+     *
+     * Contains a lower matrix L, and upper matrix U, and a permutation matrix
+     * P such that P*L*U is the original matrix.
+     * @param <T>
+     */
     public static class LUDecomposition<T> {
 
         public T l;
@@ -27,6 +34,16 @@ public class Decompose {
         }
     }
 
+    /**
+     * Compute LU Decomposition of a general matrix.
+     *
+     * Computes the LU decomposition using GETRF. Returns three matrices L, U, P,
+     * where L is lower diagonal, U is upper diagonal, and P is a permutation
+     * matrix such that A = P * L * U.
+     *
+     * @param A general matrix
+     * @return An LUDecomposition object.
+     */
     public static LUDecomposition<DoubleMatrix> lu(DoubleMatrix A) {
         int[] ipiv = new int[min(A.rows, A.columns)];
         DoubleMatrix result = A.dup();
diff --git a/src/org/jblas/DoubleMatrix.java b/src/org/jblas/DoubleMatrix.java
index 4c229e5..3065836 100644
--- a/src/org/jblas/DoubleMatrix.java
+++ b/src/org/jblas/DoubleMatrix.java
@@ -35,7 +35,6 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 // --- END LICENSE BLOCK ---
-
 package org.jblas;
 
 import org.jblas.exceptions.SizeException;
@@ -48,7 +47,10 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
 
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.io.PrintWriter;
+import java.io.Serializable;
 import java.io.StringWriter;
 import java.util.AbstractList;
 import java.util.Arrays;
@@ -275,7 +277,7 @@ import java.util.List;
  * 
  * @author Mikio Braun, Johannes Schaback
  */
-public class DoubleMatrix {
+public class DoubleMatrix implements Serializable {
 
     /** Number of rows. */
     public int rows;
@@ -287,6 +289,8 @@ public class DoubleMatrix {
     public double[] data = null; // rows are contiguous
     public static final DoubleMatrix EMPTY = new DoubleMatrix();
 
+     static final long serialVersionUID = -1249281332731183060L;
+
     /**************************************************************************
      *
      * Constructors and factory functions
@@ -306,7 +310,7 @@ public class DoubleMatrix {
         }
 
         data = newData;
-    //System.err.printf("%d * %d matrix created\n", rows, columns);
+        //System.err.printf("%d * %d matrix created\n", rows, columns);
     }
 
     /**
@@ -375,6 +379,51 @@ public class DoubleMatrix {
         }
     }
 
+    /**
+     * Construct DoubleMatrix from ASCII representation.
+     *
+     * This is not very fast, but can be quiet useful when
+     * you want to "just" construct a matrix, for example
+     * when testing.
+     *
+     * The format is semicolon separated rows of space separated values,
+     * for example "1 2 3; 4 5 6; 7 8 9".
+     */
+    public static DoubleMatrix valueOf(String text) {
+        String[] rowValues = text.split(";");
+
+        // process first line
+        String[] columnValues = rowValues[0].trim().split("\\s+");
+
+        DoubleMatrix result = null;
+
+        // process rest
+        for (int r = 0; r < rowValues.length; r++) {
+            columnValues = rowValues[r].trim().split("\\s+");
+
+            if (r == 0) {
+                result = new DoubleMatrix(rowValues.length, columnValues.length);
+            }
+
+            for (int c = 0; c < columnValues.length; c++) {
+                result.put(r, c, Double.valueOf(columnValues[c]));
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Serialization
+     */
+    private void writeObject(ObjectOutputStream s) throws IOException {
+        s.defaultWriteObject();
+    }
+
+    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
+        s.defaultReadObject();
+    }
+
     /** Create matrix with random values uniformly in 0..1. */
     public static DoubleMatrix rand(int rows, int columns) {
         DoubleMatrix m = new DoubleMatrix(rows, columns);
@@ -480,6 +529,25 @@ public class DoubleMatrix {
         return get(0);
     }
 
+    public static DoubleMatrix logspace(double lower, double upper, int size) {
+        DoubleMatrix result = new DoubleMatrix(size);
+        for (int i = 0; i < size; i++) {
+            double t = (double) i / (size - 1);
+            double e = lower * (1 - t) + t * upper;
+            result.put(i, (double) Math.pow(10.0, e));
+        }
+        return result;
+    }
+
+    public static DoubleMatrix linspace(int lower, int upper, int size) {
+        DoubleMatrix result = new DoubleMatrix(size);
+        for (int i = 0; i < size; i++) {
+            double t = (double) i / (size - 1);
+            result.put(i, lower * (1 - t) + t * upper);
+        }
+        return result;
+    }
+
     /**
      * Concatenates two matrices horizontally. Matrices must have identical
      * numbers of rows.
@@ -565,8 +633,8 @@ public class DoubleMatrix {
 
     /** Get elements from specified rows and columns. */
     public DoubleMatrix get(Range rs, Range cs) {
-        rs.init(0, rows - 1);
-        cs.init(0, columns - 1);
+        rs.init(0, rows);
+        cs.init(0, columns);
         DoubleMatrix result = new DoubleMatrix(rs.length(), cs.length());
 
         for (; !rs.hasMore(); rs.next()) {
@@ -670,6 +738,28 @@ public class DoubleMatrix {
         return getRows(rindices.findIndices());
     }
 
+    public DoubleMatrix getRows(Range indices, DoubleMatrix result) {
+        indices.init(0, rows);
+        if (result.rows < indices.length()) {
+            throw new SizeException("Result matrix does not have enough rows (" + result.rows + " < " + indices.length() + ")");
+        }
+        result.checkColumns(columns);
+
+        for (int c = 0; c < columns; c++) {
+            indices.init(0, rows);
+            for (int r = 0; indices.hasMore(); indices.next(), r++) {
+                result.put(r, c, get(indices.index(), c));
+            }
+        }
+        return result;
+    }
+
+    public DoubleMatrix getRows(Range indices) {
+        indices.init(0, rows);
+        DoubleMatrix result = new DoubleMatrix(indices.length(), columns);
+        return getRows(indices, result);
+    }
+
     /** Get whole columns from the passed indices. */
     public DoubleMatrix getColumns(int[] cindices) {
         DoubleMatrix result = new DoubleMatrix(rows, cindices.length);
@@ -775,8 +865,8 @@ public class DoubleMatrix {
 
     /** Put a matrix into specified indices. */
     public DoubleMatrix put(Range rs, Range cs, DoubleMatrix x) {
-        rs.init(0, rows - 1);
-        cs.init(0, columns - 1);
+        rs.init(0, rows);
+        cs.init(0, columns);
 
         x.checkRows(rs.length());
         x.checkColumns(cs.length());
@@ -969,11 +1059,15 @@ public class DoubleMatrix {
     public DoubleMatrix repmat(int rowMult, int columnMult) {
         DoubleMatrix result = new DoubleMatrix(rows * rowMult, columns * columnMult);
 
-        for (int c = 0; c < columnMult; c++)
-            for (int r = 0; r < rowMult; r++)
-                for (int i = 0; i < rows; i++)
-                    for (int j = 0; j < columns; j++)
+        for (int c = 0; c < columnMult; c++) {
+            for (int r = 0; r < rowMult; r++) {
+                for (int i = 0; i < rows; i++) {
+                    for (int j = 0; j < columns; j++) {
                         result.put(r * rows + i, c * columns + j, get(i, j));
+                    }
+                }
+            }
+        }
         return result;
     }
 
@@ -1294,6 +1388,7 @@ public class DoubleMatrix {
      * Also implements the {@link ConvertsToDoubleMatrix} interface.
      */
     public class ElementsAsListView extends AbstractList<Double> implements ConvertsToDoubleMatrix {
+
         private DoubleMatrix me;
 
         public ElementsAsListView(DoubleMatrix me) {
@@ -1316,6 +1411,7 @@ public class DoubleMatrix {
     }
 
     public class RowsAsListView extends AbstractList<DoubleMatrix> implements ConvertsToDoubleMatrix {
+
         private DoubleMatrix me;
 
         public RowsAsListView(DoubleMatrix me) {
@@ -1338,6 +1434,7 @@ public class DoubleMatrix {
     }
 
     public class ColumnsAsListView extends AbstractList<DoubleMatrix> implements ConvertsToDoubleMatrix {
+
         private DoubleMatrix me;
 
         public ColumnsAsListView(DoubleMatrix me) {
@@ -1633,67 +1730,43 @@ public class DoubleMatrix {
     public DoubleMatrix truth() {
         return dup().truthi();
     }
- 
-    /**
-    * Calculate matrix exponential of a square matrix.
-    * 
-    * A scaled Pade approximation algorithm is used.
-    * The algorithm has been directly translated from Golub & Van Loan "Matrix Computations",
-    * algorithm 11.3.1. Special Horner techniques from 11.2 are also used to minimize the number
-    * of matrix multiplications. 
-    * 
-    * @param A square matrix
-    * @return matrix exponential of A
-    */
-    public static DoubleMatrix expm(DoubleMatrix A)
-    {
-		// constants for pade approximation
-		final double c0 = 1.0;
-		final double c1 = 0.5;
-		final double c2 = 0.12;
-		final double c3 = 0.01833333333333333;
-		final double c4 = 0.0019927536231884053;
-		final double c5 = 1.630434782608695E-4;
-		final double c6 = 1.0351966873706E-5;
-		final double c7 = 5.175983436853E-7;
-		final double c8 = 2.0431513566525E-8;
-		final double c9 = 6.306022705717593E-10;
-		final double c10 = 1.4837700484041396E-11;
-		final double c11 = 2.5291534915979653E-13;
-		final double c12 = 2.8101705462199615E-15;
-		final double c13 = 1.5440497506703084E-17;
-		
-		int j = Math.max(0, 1 + (int)Math.floor(Math.log(A.normmax())/Math.log(2)));
-		DoubleMatrix As = A.div((double)Math.pow(2, j)); // scaled version of A
-		int n = A.getRows();
-		
-		// calculate D and N using special Horner techniques
-		DoubleMatrix As_2 = As.mmul(As);
-		DoubleMatrix As_4 = As_2.mmul(As_2);
-		DoubleMatrix As_6 = As_4.mmul(As_2);
-		// U = c0*I + c2*A^2 + c4*A^4 + (c6*I + c8*A^2 + c10*A^4 + c12*A^6)*A^6
-		DoubleMatrix U = DoubleMatrix.eye(n).muli(c0).addi(As_2.mul(c2)).addi(As_4.mul(c4)).addi(
-				DoubleMatrix.eye(n).muli(c6).addi(As_2.mul(c8)).addi(As_4.mul(c10)).addi(As_6.mul(c12)).mmuli(As_6));
-		// V = c1*I + c3*A^2 + c5*A^4 + (c7*I + c9*A^2 + c11*A^4 + c13*A^6)*A^6
-		DoubleMatrix V = DoubleMatrix.eye(n).muli(c1).addi(As_2.mul(c3)).addi(As_4.mul(c5)).addi(
-				DoubleMatrix.eye(n).muli(c7).addi(As_2.mul(c9)).addi(As_4.mul(c11)).addi(As_6.mul(c13)).mmuli(As_6));
-		
-		DoubleMatrix AV = As.mmuli(V);
-		DoubleMatrix N = U.add(AV);
-		DoubleMatrix D = U.subi(AV);
-		
-		// solve DF = N for F
-		DoubleMatrix F = Solve.solve(D, N);
-		
-		// now square j times
-		for(int k = 0; k < j; k++)
-		{
-			F.mmuli(F);
-		}
-		
-		return F;
-    }
-    
+
+    public DoubleMatrix isNaNi() {
+        for (int i = 0; i < length; i++) {
+            put(i, Double.isNaN(get(i)) ? 1.0 : 0.0);
+        }
+        return this;
+    }
+
+    public DoubleMatrix isNaN() {
+        return dup().isNaNi();
+    }
+
+    public DoubleMatrix isInfinitei() {
+        for (int i = 0; i < length; i++) {
+            put(i, Double.isInfinite(get(i)) ? 1.0 : 0.0);
+        }
+        return this;
+    }
+
+    public DoubleMatrix isInfinite() {
+        return dup().isInfinitei();
+    }
+
+    public DoubleMatrix selecti(DoubleMatrix where) {
+        checkLength(where.length);
+        for (int i = 0; i < length; i++) {
+            if (where.get(i) == 0.0) {
+                put(i, 0.0);
+            }
+        }
+        return this;
+    }
+
+    public DoubleMatrix select(DoubleMatrix where) {
+        return dup().selecti(where);
+    }
+
     /****************************************************************
      * Rank one-updates
      */
@@ -1940,7 +2013,7 @@ public class DoubleMatrix {
         }
         return s;
     }
-    
+
     /** Computes the product of all elements of the matrix */
     public double prod() {
         double p = 1.0;
@@ -1995,10 +2068,10 @@ public class DoubleMatrix {
         double norm = 0, dot = 0;
         for (int i = 0; i < this.length; i++) {
             double x = get(i);
-            norm += x*x;
-            dot += x*other.get(i);
+            norm += x * x;
+            dot += x * other.get(i);
         }
-        return dot/norm;
+        return dot / norm;
     }
 
     /**
@@ -2010,7 +2083,7 @@ public class DoubleMatrix {
         for (int i = 0; i < length; i++) {
             norm += get(i) * get(i);
         }
-        return (double)Math.sqrt(norm);
+        return (double) Math.sqrt(norm);
     }
 
     /**
@@ -2020,8 +2093,9 @@ public class DoubleMatrix {
         double max = 0.0;
         for (int i = 0; i < length; i++) {
             double a = Math.abs(get(i));
-            if (a > max)
+            if (a > max) {
                 max = a;
+            }
         }
         return max;
     }
@@ -2038,6 +2112,38 @@ public class DoubleMatrix {
     }
 
     /**
+     * Returns the squared (Euclidean) distance.
+     */
+    public double squaredDistance(DoubleMatrix other) {
+        other.checkLength(length);
+        double sd = 0.0;
+        for (int i = 0; i < length; i++) {
+            double d = get(i) - other.get(i);
+            sd += d * d;
+        }
+        return sd;
+    }
+
+    /**
+     * Returns the (euclidean) distance.
+     */
+    public double distance2(DoubleMatrix other) {
+        return (double) Math.sqrt(squaredDistance(other));
+    }
+
+    /**
+     * Returns the (1-norm) distance.
+     */
+    public double distance1(DoubleMatrix other) {
+        other.checkLength(length);
+        double d = 0.0;
+        for (int i = 0; i < length; i++) {
+            d += Math.abs(get(i) - other.get(i));
+        }
+        return d;
+    }
+
+    /**
      * Return a new matrix with all elements sorted.
      */
     public DoubleMatrix sort() {
@@ -2304,9 +2410,11 @@ public class DoubleMatrix {
     /** Add a row vector to all rows of the matrix (in place). */
     public DoubleMatrix addiRowVector(DoubleMatrix x) {
         x.checkLength(columns);
-        for (int c = 0; c < columns; c++)
-            for (int r = 0; r < rows; r++)
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) + x.get(c));
+            }
+        }
         return this;
     }
 
@@ -2318,9 +2426,11 @@ public class DoubleMatrix {
     /** Add a vector to all columns of the matrix (in-place). */
     public DoubleMatrix addiColumnVector(DoubleMatrix x) {
         x.checkLength(rows);
-        for (int c = 0; c < columns; c++)
-            for (int r = 0; r < rows; r++)
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) + x.get(r));
+            }
+        }
         return this;
     }
 
@@ -2333,9 +2443,11 @@ public class DoubleMatrix {
     public DoubleMatrix subiRowVector(DoubleMatrix x) {
         // This is a bit crazy, but a row vector must have as length as the columns of the matrix.
         x.checkLength(columns);
-        for (int c = 0; c < columns; c++)
-            for (int r = 0; r < rows; r++)
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) - x.get(c));
+            }
+        }
         return this;
     }
 
@@ -2347,9 +2459,11 @@ public class DoubleMatrix {
     /** Subtract a column vector from all columns of the matrix (in-place). */
     public DoubleMatrix subiColumnVector(DoubleMatrix x) {
         x.checkLength(rows);
-        for (int c = 0; c < columns; c++)
-            for (int r = 0; r < rows; r++)
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) - x.get(r));
+            }
+        }
         return this;
     }
 
@@ -2374,8 +2488,9 @@ public class DoubleMatrix {
     public DoubleMatrix muliColumnVector(DoubleMatrix x) {
         x.checkLength(rows);
         for (int c = 0; c < columns; c++) {
-            for (int r = 0; r < rows; r++)
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) * x.get(r));
+            }
         }
         return this;
     }
@@ -2388,9 +2503,11 @@ public class DoubleMatrix {
     /** Multiply all rows with a row vector (in-place). */
     public DoubleMatrix muliRowVector(DoubleMatrix x) {
         x.checkLength(columns);
-        for (int c = 0; c < columns; c++)
-            for (int r = 0; r < rows; r++)
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) * x.get(c));
+            }
+        }
         return this;
     }
 
@@ -2401,9 +2518,11 @@ public class DoubleMatrix {
 
     public DoubleMatrix diviRowVector(DoubleMatrix x) {
         x.checkLength(columns);
-        for (int c = 0; c < columns; c++)
-            for (int r = 0; r < rows; r++)
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) / x.get(c));
+            }
+        }
         return this;
     }
 
@@ -2413,9 +2532,11 @@ public class DoubleMatrix {
 
     public DoubleMatrix diviColumnVector(DoubleMatrix x) {
         x.checkLength(rows);
-        for (int c = 0; c < columns; c++)
-            for (int r = 0; r < rows; r++)
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) / x.get(r));
+            }
+        }
         return this;
     }
 
@@ -2552,8 +2673,9 @@ public class DoubleMatrix {
             }
 
             DoubleMatrix row = new DoubleMatrix(columns);
-            for (int c = 0; c < columns; c++)
+            for (int c = 0; c < columns; c++) {
                 row.put(c, Double.valueOf(elements[c]));
+            }
             rows.add(row);
         }
         is.close();
diff --git a/src/org/jblas/FloatMatrix.java b/src/org/jblas/FloatMatrix.java
index 44af945..58850a1 100644
--- a/src/org/jblas/FloatMatrix.java
+++ b/src/org/jblas/FloatMatrix.java
@@ -35,7 +35,6 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 // --- END LICENSE BLOCK ---
-
 package org.jblas;
 
 import org.jblas.exceptions.SizeException;
@@ -48,7 +47,10 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
 
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.io.PrintWriter;
+import java.io.Serializable;
 import java.io.StringWriter;
 import java.util.AbstractList;
 import java.util.Arrays;
@@ -275,7 +277,7 @@ import java.util.List;
  * 
  * @author Mikio Braun, Johannes Schaback
  */
-public class FloatMatrix {
+public class FloatMatrix implements Serializable {
 
     /** Number of rows. */
     public int rows;
@@ -287,6 +289,8 @@ public class FloatMatrix {
     public float[] data = null; // rows are contiguous
     public static final FloatMatrix EMPTY = new FloatMatrix();
 
+     static final long serialVersionUID = -1249281332731183060L;
+
     /**************************************************************************
      *
      * Constructors and factory functions
@@ -306,7 +310,7 @@ public class FloatMatrix {
         }
 
         data = newData;
-    //System.err.printf("%d * %d matrix created\n", rows, columns);
+        //System.err.printf("%d * %d matrix created\n", rows, columns);
     }
 
     /**
@@ -375,6 +379,51 @@ public class FloatMatrix {
         }
     }
 
+    /**
+     * Construct FloatMatrix from ASCII representation.
+     *
+     * This is not very fast, but can be quiet useful when
+     * you want to "just" construct a matrix, for example
+     * when testing.
+     *
+     * The format is semicolon separated rows of space separated values,
+     * for example "1 2 3; 4 5 6; 7 8 9".
+     */
+    public static FloatMatrix valueOf(String text) {
+        String[] rowValues = text.split(";");
+
+        // process first line
+        String[] columnValues = rowValues[0].trim().split("\\s+");
+
+        FloatMatrix result = null;
+
+        // process rest
+        for (int r = 0; r < rowValues.length; r++) {
+            columnValues = rowValues[r].trim().split("\\s+");
+
+            if (r == 0) {
+                result = new FloatMatrix(rowValues.length, columnValues.length);
+            }
+
+            for (int c = 0; c < columnValues.length; c++) {
+                result.put(r, c, Float.valueOf(columnValues[c]));
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Serialization
+     */
+    private void writeObject(ObjectOutputStream s) throws IOException {
+        s.defaultWriteObject();
+    }
+
+    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
+        s.defaultReadObject();
+    }
+
     /** Create matrix with random values uniformly in 0..1. */
     public static FloatMatrix rand(int rows, int columns) {
         FloatMatrix m = new FloatMatrix(rows, columns);
@@ -480,6 +529,25 @@ public class FloatMatrix {
         return get(0);
     }
 
+    public static FloatMatrix logspace(float lower, float upper, int size) {
+        FloatMatrix result = new FloatMatrix(size);
+        for (int i = 0; i < size; i++) {
+            float t = (float) i / (size - 1);
+            float e = lower * (1 - t) + t * upper;
+            result.put(i, (float) Math.pow(10.0f, e));
+        }
+        return result;
+    }
+
+    public static FloatMatrix linspace(int lower, int upper, int size) {
+        FloatMatrix result = new FloatMatrix(size);
+        for (int i = 0; i < size; i++) {
+            float t = (float) i / (size - 1);
+            result.put(i, lower * (1 - t) + t * upper);
+        }
+        return result;
+    }
+
     /**
      * Concatenates two matrices horizontally. Matrices must have identical
      * numbers of rows.
@@ -565,8 +633,8 @@ public class FloatMatrix {
 
     /** Get elements from specified rows and columns. */
     public FloatMatrix get(Range rs, Range cs) {
-        rs.init(0, rows - 1);
-        cs.init(0, columns - 1);
+        rs.init(0, rows);
+        cs.init(0, columns);
         FloatMatrix result = new FloatMatrix(rs.length(), cs.length());
 
         for (; !rs.hasMore(); rs.next()) {
@@ -670,6 +738,28 @@ public class FloatMatrix {
         return getRows(rindices.findIndices());
     }
 
+    public FloatMatrix getRows(Range indices, FloatMatrix result) {
+        indices.init(0, rows);
+        if (result.rows < indices.length()) {
+            throw new SizeException("Result matrix does not have enough rows (" + result.rows + " < " + indices.length() + ")");
+        }
+        result.checkColumns(columns);
+
+        for (int c = 0; c < columns; c++) {
+            indices.init(0, rows);
+            for (int r = 0; indices.hasMore(); indices.next(), r++) {
+                result.put(r, c, get(indices.index(), c));
+            }
+        }
+        return result;
+    }
+
+    public FloatMatrix getRows(Range indices) {
+        indices.init(0, rows);
+        FloatMatrix result = new FloatMatrix(indices.length(), columns);
+        return getRows(indices, result);
+    }
+
     /** Get whole columns from the passed indices. */
     public FloatMatrix getColumns(int[] cindices) {
         FloatMatrix result = new FloatMatrix(rows, cindices.length);
@@ -775,8 +865,8 @@ public class FloatMatrix {
 
     /** Put a matrix into specified indices. */
     public FloatMatrix put(Range rs, Range cs, FloatMatrix x) {
-        rs.init(0, rows - 1);
-        cs.init(0, columns - 1);
+        rs.init(0, rows);
+        cs.init(0, columns);
 
         x.checkRows(rs.length());
         x.checkColumns(cs.length());
@@ -969,11 +1059,15 @@ public class FloatMatrix {
     public FloatMatrix repmat(int rowMult, int columnMult) {
         FloatMatrix result = new FloatMatrix(rows * rowMult, columns * columnMult);
 
-        for (int c = 0; c < columnMult; c++)
-            for (int r = 0; r < rowMult; r++)
-                for (int i = 0; i < rows; i++)
-                    for (int j = 0; j < columns; j++)
+        for (int c = 0; c < columnMult; c++) {
+            for (int r = 0; r < rowMult; r++) {
+                for (int i = 0; i < rows; i++) {
+                    for (int j = 0; j < columns; j++) {
                         result.put(r * rows + i, c * columns + j, get(i, j));
+                    }
+                }
+            }
+        }
         return result;
     }
 
@@ -1294,6 +1388,7 @@ public class FloatMatrix {
      * Also implements the {@link ConvertsToFloatMatrix} interface.
      */
     public class ElementsAsListView extends AbstractList<Float> implements ConvertsToFloatMatrix {
+
         private FloatMatrix me;
 
         public ElementsAsListView(FloatMatrix me) {
@@ -1316,6 +1411,7 @@ public class FloatMatrix {
     }
 
     public class RowsAsListView extends AbstractList<FloatMatrix> implements ConvertsToFloatMatrix {
+
         private FloatMatrix me;
 
         public RowsAsListView(FloatMatrix me) {
@@ -1338,6 +1434,7 @@ public class FloatMatrix {
     }
 
     public class ColumnsAsListView extends AbstractList<FloatMatrix> implements ConvertsToFloatMatrix {
+
         private FloatMatrix me;
 
         public ColumnsAsListView(FloatMatrix me) {
@@ -1633,67 +1730,43 @@ public class FloatMatrix {
     public FloatMatrix truth() {
         return dup().truthi();
     }
- 
-    /**
-    * Calculate matrix exponential of a square matrix.
-    * 
-    * A scaled Pade approximation algorithm is used.
-    * The algorithm has been directly translated from Golub & Van Loan "Matrix Computations",
-    * algorithm 11.3f.1. Special Horner techniques from 11.2f are also used to minimize the number
-    * of matrix multiplications. 
-    * 
-    * @param A square matrix
-    * @return matrix exponential of A
-    */
-    public static FloatMatrix expm(FloatMatrix A)
-    {
-		// constants for pade approximation
-		final float c0 = 1.0f;
-		final float c1 = 0.5f;
-		final float c2 = 0.12f;
-		final float c3 = 0.01833333333333333f;
-		final float c4 = 0.0019927536231884053f;
-		final float c5 = 1.630434782608695E-4f;
-		final float c6 = 1.0351966873706E-5f;
-		final float c7 = 5.175983436853E-7f;
-		final float c8 = 2.0431513566525E-8f;
-		final float c9 = 6.306022705717593E-10f;
-		final float c10 = 1.4837700484041396E-11f;
-		final float c11 = 2.5291534915979653E-13f;
-		final float c12 = 2.8101705462199615E-15f;
-		final float c13 = 1.5440497506703084E-17f;
-		
-		int j = Math.max(0, 1 + (int)Math.floor(Math.log(A.normmax())/Math.log(2)));
-		FloatMatrix As = A.div((float)Math.pow(2, j)); // scaled version of A
-		int n = A.getRows();
-		
-		// calculate D and N using special Horner techniques
-		FloatMatrix As_2 = As.mmul(As);
-		FloatMatrix As_4 = As_2.mmul(As_2);
-		FloatMatrix As_6 = As_4.mmul(As_2);
-		// U = c0*I + c2*A^2 + c4*A^4 + (c6*I + c8*A^2 + c10*A^4 + c12*A^6)*A^6
-		FloatMatrix U = FloatMatrix.eye(n).muli(c0).addi(As_2.mul(c2)).addi(As_4.mul(c4)).addi(
-				FloatMatrix.eye(n).muli(c6).addi(As_2.mul(c8)).addi(As_4.mul(c10)).addi(As_6.mul(c12)).mmuli(As_6));
-		// V = c1*I + c3*A^2 + c5*A^4 + (c7*I + c9*A^2 + c11*A^4 + c13*A^6)*A^6
-		FloatMatrix V = FloatMatrix.eye(n).muli(c1).addi(As_2.mul(c3)).addi(As_4.mul(c5)).addi(
-				FloatMatrix.eye(n).muli(c7).addi(As_2.mul(c9)).addi(As_4.mul(c11)).addi(As_6.mul(c13)).mmuli(As_6));
-		
-		FloatMatrix AV = As.mmuli(V);
-		FloatMatrix N = U.add(AV);
-		FloatMatrix D = U.subi(AV);
-		
-		// solve DF = N for F
-		FloatMatrix F = Solve.solve(D, N);
-		
-		// now square j times
-		for(int k = 0; k < j; k++)
-		{
-			F.mmuli(F);
-		}
-		
-		return F;
-    }
-    
+
+    public FloatMatrix isNaNi() {
+        for (int i = 0; i < length; i++) {
+            put(i, Float.isNaN(get(i)) ? 1.0f : 0.0f);
+        }
+        return this;
+    }
+
+    public FloatMatrix isNaN() {
+        return dup().isNaNi();
+    }
+
+    public FloatMatrix isInfinitei() {
+        for (int i = 0; i < length; i++) {
+            put(i, Float.isInfinite(get(i)) ? 1.0f : 0.0f);
+        }
+        return this;
+    }
+
+    public FloatMatrix isInfinite() {
+        return dup().isInfinitei();
+    }
+
+    public FloatMatrix selecti(FloatMatrix where) {
+        checkLength(where.length);
+        for (int i = 0; i < length; i++) {
+            if (where.get(i) == 0.0f) {
+                put(i, 0.0f);
+            }
+        }
+        return this;
+    }
+
+    public FloatMatrix select(FloatMatrix where) {
+        return dup().selecti(where);
+    }
+
     /****************************************************************
      * Rank one-updates
      */
@@ -1940,7 +2013,7 @@ public class FloatMatrix {
         }
         return s;
     }
-    
+
     /** Computes the product of all elements of the matrix */
     public float prod() {
         float p = 1.0f;
@@ -1995,10 +2068,10 @@ public class FloatMatrix {
         float norm = 0, dot = 0;
         for (int i = 0; i < this.length; i++) {
             float x = get(i);
-            norm += x*x;
-            dot += x*other.get(i);
+            norm += x * x;
+            dot += x * other.get(i);
         }
-        return dot/norm;
+        return dot / norm;
     }
 
     /**
@@ -2010,7 +2083,7 @@ public class FloatMatrix {
         for (int i = 0; i < length; i++) {
             norm += get(i) * get(i);
         }
-        return (float)Math.sqrt(norm);
+        return (float) Math.sqrt(norm);
     }
 
     /**
@@ -2020,8 +2093,9 @@ public class FloatMatrix {
         float max = 0.0f;
         for (int i = 0; i < length; i++) {
             float a = Math.abs(get(i));
-            if (a > max)
+            if (a > max) {
                 max = a;
+            }
         }
         return max;
     }
@@ -2038,6 +2112,38 @@ public class FloatMatrix {
     }
 
     /**
+     * Returns the squared (Euclidean) distance.
+     */
+    public float squaredDistance(FloatMatrix other) {
+        other.checkLength(length);
+        float sd = 0.0f;
+        for (int i = 0; i < length; i++) {
+            float d = get(i) - other.get(i);
+            sd += d * d;
+        }
+        return sd;
+    }
+
+    /**
+     * Returns the (euclidean) distance.
+     */
+    public float distance2(FloatMatrix other) {
+        return (float) Math.sqrt(squaredDistance(other));
+    }
+
+    /**
+     * Returns the (1-norm) distance.
+     */
+    public float distance1(FloatMatrix other) {
+        other.checkLength(length);
+        float d = 0.0f;
+        for (int i = 0; i < length; i++) {
+            d += Math.abs(get(i) - other.get(i));
+        }
+        return d;
+    }
+
+    /**
      * Return a new matrix with all elements sorted.
      */
     public FloatMatrix sort() {
@@ -2304,9 +2410,11 @@ public class FloatMatrix {
     /** Add a row vector to all rows of the matrix (in place). */
     public FloatMatrix addiRowVector(FloatMatrix x) {
         x.checkLength(columns);
-        for (int c = 0; c < columns; c++)
-            for (int r = 0; r < rows; r++)
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) + x.get(c));
+            }
+        }
         return this;
     }
 
@@ -2318,9 +2426,11 @@ public class FloatMatrix {
     /** Add a vector to all columns of the matrix (in-place). */
     public FloatMatrix addiColumnVector(FloatMatrix x) {
         x.checkLength(rows);
-        for (int c = 0; c < columns; c++)
-            for (int r = 0; r < rows; r++)
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) + x.get(r));
+            }
+        }
         return this;
     }
 
@@ -2333,9 +2443,11 @@ public class FloatMatrix {
     public FloatMatrix subiRowVector(FloatMatrix x) {
         // This is a bit crazy, but a row vector must have as length as the columns of the matrix.
         x.checkLength(columns);
-        for (int c = 0; c < columns; c++)
-            for (int r = 0; r < rows; r++)
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) - x.get(c));
+            }
+        }
         return this;
     }
 
@@ -2347,9 +2459,11 @@ public class FloatMatrix {
     /** Subtract a column vector from all columns of the matrix (in-place). */
     public FloatMatrix subiColumnVector(FloatMatrix x) {
         x.checkLength(rows);
-        for (int c = 0; c < columns; c++)
-            for (int r = 0; r < rows; r++)
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) - x.get(r));
+            }
+        }
         return this;
     }
 
@@ -2374,8 +2488,9 @@ public class FloatMatrix {
     public FloatMatrix muliColumnVector(FloatMatrix x) {
         x.checkLength(rows);
         for (int c = 0; c < columns; c++) {
-            for (int r = 0; r < rows; r++)
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) * x.get(r));
+            }
         }
         return this;
     }
@@ -2388,9 +2503,11 @@ public class FloatMatrix {
     /** Multiply all rows with a row vector (in-place). */
     public FloatMatrix muliRowVector(FloatMatrix x) {
         x.checkLength(columns);
-        for (int c = 0; c < columns; c++)
-            for (int r = 0; r < rows; r++)
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) * x.get(c));
+            }
+        }
         return this;
     }
 
@@ -2401,9 +2518,11 @@ public class FloatMatrix {
 
     public FloatMatrix diviRowVector(FloatMatrix x) {
         x.checkLength(columns);
-        for (int c = 0; c < columns; c++)
-            for (int r = 0; r < rows; r++)
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) / x.get(c));
+            }
+        }
         return this;
     }
 
@@ -2413,9 +2532,11 @@ public class FloatMatrix {
 
     public FloatMatrix diviColumnVector(FloatMatrix x) {
         x.checkLength(rows);
-        for (int c = 0; c < columns; c++)
-            for (int r = 0; r < rows; r++)
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
                 put(r, c, get(r, c) / x.get(r));
+            }
+        }
         return this;
     }
 
@@ -2552,8 +2673,9 @@ public class FloatMatrix {
             }
 
             FloatMatrix row = new FloatMatrix(columns);
-            for (int c = 0; c < columns; c++)
+            for (int c = 0; c < columns; c++) {
                 row.put(c, Float.valueOf(elements[c]));
+            }
             rows.add(row);
         }
         is.close();
diff --git a/src/org/jblas/MatrixFunctions.java b/src/org/jblas/MatrixFunctions.java
index 5235c52..3307940 100644
--- a/src/org/jblas/MatrixFunctions.java
+++ b/src/org/jblas/MatrixFunctions.java
@@ -394,6 +394,65 @@ public class MatrixFunctions {
     public static double tanh(double x) { return (double)Math.tanh(x); }
 //RJPP-END--------------------------------------------------------------
 
+    /**
+     * Calculate matrix exponential of a square matrix.
+     *
+     * A scaled Pade approximation algorithm is used.
+     * The algorithm has been directly translated from Golub & Van Loan "Matrix Computations",
+     * algorithm 11.3.1. Special Horner techniques from 11.2 are also used to minimize the number
+     * of matrix multiplications.
+     *
+     * @param A square matrix
+     * @return matrix exponential of A
+     */
+    public static DoubleMatrix expm(DoubleMatrix A) {
+        // constants for pade approximation
+        final double c0 = 1.0;
+        final double c1 = 0.5;
+        final double c2 = 0.12;
+        final double c3 = 0.01833333333333333;
+        final double c4 = 0.0019927536231884053;
+        final double c5 = 1.630434782608695E-4;
+        final double c6 = 1.0351966873706E-5;
+        final double c7 = 5.175983436853E-7;
+        final double c8 = 2.0431513566525E-8;
+        final double c9 = 6.306022705717593E-10;
+        final double c10 = 1.4837700484041396E-11;
+        final double c11 = 2.5291534915979653E-13;
+        final double c12 = 2.8101705462199615E-15;
+        final double c13 = 1.5440497506703084E-17;
+
+        int j = Math.max(0, 1 + (int) Math.floor(Math.log(A.normmax()) / Math.log(2)));
+        DoubleMatrix As = A.div((double) Math.pow(2, j)); // scaled version of A
+        int n = A.getRows();
+
+        // calculate D and N using special Horner techniques
+        DoubleMatrix As_2 = As.mmul(As);
+        DoubleMatrix As_4 = As_2.mmul(As_2);
+        DoubleMatrix As_6 = As_4.mmul(As_2);
+        // U = c0*I + c2*A^2 + c4*A^4 + (c6*I + c8*A^2 + c10*A^4 + c12*A^6)*A^6
+        DoubleMatrix U = DoubleMatrix.eye(n).muli(c0).addi(As_2.mul(c2)).addi(As_4.mul(c4)).addi(
+                DoubleMatrix.eye(n).muli(c6).addi(As_2.mul(c8)).addi(As_4.mul(c10)).addi(As_6.mul(c12)).mmuli(As_6));
+        // V = c1*I + c3*A^2 + c5*A^4 + (c7*I + c9*A^2 + c11*A^4 + c13*A^6)*A^6
+        DoubleMatrix V = DoubleMatrix.eye(n).muli(c1).addi(As_2.mul(c3)).addi(As_4.mul(c5)).addi(
+                DoubleMatrix.eye(n).muli(c7).addi(As_2.mul(c9)).addi(As_4.mul(c11)).addi(As_6.mul(c13)).mmuli(As_6));
+
+        DoubleMatrix AV = As.mmuli(V);
+        DoubleMatrix N = U.add(AV);
+        DoubleMatrix D = U.subi(AV);
+
+        // solve DF = N for F
+        DoubleMatrix F = Solve.solve(D, N);
+
+        // now square j times
+        for (int k = 0; k < j; k++) {
+            F.mmuli(F);
+        }
+
+        return F;
+    }
+
+
 //STOP
     public static DoubleMatrix floatToDouble(FloatMatrix fm) {
     	DoubleMatrix dm = new DoubleMatrix(fm.rows, fm.columns);
@@ -766,6 +825,65 @@ public class MatrixFunctions {
     public static float tanh(float x) { return (float)Math.tanh(x); }
 //RJPP-END--------------------------------------------------------------
 
+    /**
+     * Calculate matrix exponential of a square matrix.
+     *
+     * A scaled Pade approximation algorithm is used.
+     * The algorithm has been directly translated from Golub & Van Loan "Matrix Computations",
+     * algorithm 11.3f.1. Special Horner techniques from 11.2f are also used to minimize the number
+     * of matrix multiplications.
+     *
+     * @param A square matrix
+     * @return matrix exponential of A
+     */
+    public static FloatMatrix expm(FloatMatrix A) {
+        // constants for pade approximation
+        final float c0 = 1.0f;
+        final float c1 = 0.5f;
+        final float c2 = 0.12f;
+        final float c3 = 0.01833333333333333f;
+        final float c4 = 0.0019927536231884053f;
+        final float c5 = 1.630434782608695E-4f;
+        final float c6 = 1.0351966873706E-5f;
+        final float c7 = 5.175983436853E-7f;
+        final float c8 = 2.0431513566525E-8f;
+        final float c9 = 6.306022705717593E-10f;
+        final float c10 = 1.4837700484041396E-11f;
+        final float c11 = 2.5291534915979653E-13f;
+        final float c12 = 2.8101705462199615E-15f;
+        final float c13 = 1.5440497506703084E-17f;
+
+        int j = Math.max(0, 1 + (int) Math.floor(Math.log(A.normmax()) / Math.log(2)));
+        FloatMatrix As = A.div((float) Math.pow(2, j)); // scaled version of A
+        int n = A.getRows();
+
+        // calculate D and N using special Horner techniques
+        FloatMatrix As_2 = As.mmul(As);
+        FloatMatrix As_4 = As_2.mmul(As_2);
+        FloatMatrix As_6 = As_4.mmul(As_2);
+        // U = c0*I + c2*A^2 + c4*A^4 + (c6*I + c8*A^2 + c10*A^4 + c12*A^6)*A^6
+        FloatMatrix U = FloatMatrix.eye(n).muli(c0).addi(As_2.mul(c2)).addi(As_4.mul(c4)).addi(
+                FloatMatrix.eye(n).muli(c6).addi(As_2.mul(c8)).addi(As_4.mul(c10)).addi(As_6.mul(c12)).mmuli(As_6));
+        // V = c1*I + c3*A^2 + c5*A^4 + (c7*I + c9*A^2 + c11*A^4 + c13*A^6)*A^6
+        FloatMatrix V = FloatMatrix.eye(n).muli(c1).addi(As_2.mul(c3)).addi(As_4.mul(c5)).addi(
+                FloatMatrix.eye(n).muli(c7).addi(As_2.mul(c9)).addi(As_4.mul(c11)).addi(As_6.mul(c13)).mmuli(As_6));
+
+        FloatMatrix AV = As.mmuli(V);
+        FloatMatrix N = U.add(AV);
+        FloatMatrix D = U.subi(AV);
+
+        // solve DF = N for F
+        FloatMatrix F = Solve.solve(D, N);
+
+        // now square j times
+        for (int k = 0; k < j; k++) {
+            F.mmuli(F);
+        }
+
+        return F;
+    }
+
+
     
 //END
 }
diff --git a/src/org/jblas/NativeBlas.java b/src/org/jblas/NativeBlas.java
index 1fb064c..f577055 100644
--- a/src/org/jblas/NativeBlas.java
+++ b/src/org/jblas/NativeBlas.java
@@ -33,9 +33,10 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 // --- END LICENSE BLOCK ---
-
 package org.jblas;
 
+import org.jblas.util.Logger;
+
 /**
  * Native BLAS and LAPACK functions.
  *
@@ -75,20 +76,19 @@ public class NativeBlas {
   static {
 	  try {
 		  System.loadLibrary("jblas");
-	  }
-	  catch(UnsatisfiedLinkError e) {
-		  System.err.println(
-				  "BLAS native library not found in path. Copying native library\n" +
-				  "from the archive. Consider installing the library somewhere\n" +
-				  "in the path (for Windows: PATH, for Linux: LD_LIBRARY_PATH).");
-		  new org.jblas.util.LibraryLoader().loadLibrary("jblas");
-	  }
-  } 
-
-  private static int[] intDummy = new int[1];
-  private static double[] doubleDummy = new double[1];
-  private static float[] floatDummy = new float[1];
+        } catch (UnsatisfiedLinkError e) {
+            Logger.getLogger().config(
+                    "BLAS native library not found in path. Copying native library "
+                    + "from the archive. Consider installing the library somewhere "
+                    + "in the path (for Windows: PATH, for Linux: LD_LIBRARY_PATH).");
+            new org.jblas.util.LibraryLoader().loadLibrary("jblas", true);
+        }
+    }
+    private static int[] intDummy = new int[1];
+    private static double[] doubleDummy = new double[1];
+    private static float[] floatDummy = new float[1];
 
+     
   public static native void caxpy(int n, ComplexFloat ca, float[] cx, int cxIdx, int incx, float[] cy, int cyIdx, int incy);
   public static native void ccopy(int n, float[] cx, int cxIdx, int incx, float[] cy, int cyIdx, int incy);
   public static native ComplexFloat cdotc(int n, float[] cx, int cxIdx, int incx, float[] cy, int cyIdx, int incy);
diff --git a/src/org/jblas/ranges/AllRange.java b/src/org/jblas/benchmark/ATLASDoubleMultiplicationBenchmark.java
similarity index 64%
copy from src/org/jblas/ranges/AllRange.java
copy to src/org/jblas/benchmark/ATLASDoubleMultiplicationBenchmark.java
index 9fe1d78..2a7a81d 100644
--- a/src/org/jblas/ranges/AllRange.java
+++ b/src/org/jblas/benchmark/ATLASDoubleMultiplicationBenchmark.java
@@ -1,25 +1,25 @@
 // --- BEGIN LICENSE BLOCK ---
-/* 
+/*
  * Copyright (c) 2009, Mikio L. Braun
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
- * 
+ *
  *     * Redistributions of source code must retain the above copyright
  *       notice, this list of conditions and the following disclaimer.
- * 
+ *
  *     * Redistributions in binary form must reproduce the above
  *       copyright notice, this list of conditions and the following
  *       disclaimer in the documentation and/or other materials provided
  *       with the distribution.
- * 
+ *
  *     * Neither the name of the Technische Universität Berlin nor the
  *       names of its contributors may be used to endorse or promote
  *       products derived from this software without specific prior
  *       written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -34,52 +34,37 @@
  */
 // --- END LICENSE BLOCK ---
 
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-
-package org.jblas.ranges;
+package org.jblas.benchmark;
 
-import org.jblas.*;
+import org.jblas.DoubleMatrix;
+import static org.jblas.DoubleMatrix.*;
 
 /**
- * A range over all available indices. Can be used to address whole columns or rows. Like
- * the ":" index in matlab. Don't forget to call init() before using this range.
+ *
  */
-public class AllRange implements Range {
-    private int lower;
-    private int upper;
-    private int value;
-    private int counter;
-    
-    public AllRange() {}
-    
-    public void init(int l, int u) {
-        lower = l;
-        upper = u;
-        value = l;
-        counter = 0;
-    }
-    
-    public int length() {
-        return upper - lower + 1;
-    }
-    
-    public int value() {
-        return value;
-    }
-    
-    public int index() {
-        return counter;
-    }
-    
-    public void next() {
-        counter++;
-        value++;
+class ATLASDoubleMultiplicationBenchmark implements Benchmark {
+
+    public String getName() {
+        return "ATLAS matrix multiplication, double precision";
     }
-    
-    public boolean hasMore() {
-        return value < upper;
+
+    public BenchmarkResult run(int size, double seconds) {
+        int counter = 0;
+        long ops = 0;
+
+        DoubleMatrix A = randn(size, size);
+        DoubleMatrix B = randn(size, size);
+        DoubleMatrix C = randn(size, size);
+
+        Timer t = new Timer();
+        t.start();
+        while (!t.ranFor(seconds)) {
+            A.mmuli(B, C);
+            counter++;
+            ops += 2L * size * size * size;
+        }
+        t.stop();
+
+        return new BenchmarkResult(ops, t.elapsedSeconds(), counter);
     }
 }
diff --git a/src/org/jblas/ranges/AllRange.java b/src/org/jblas/benchmark/ATLASFloatMultiplicationBenchmark.java
similarity index 64%
copy from src/org/jblas/ranges/AllRange.java
copy to src/org/jblas/benchmark/ATLASFloatMultiplicationBenchmark.java
index 9fe1d78..a4cdfc4 100644
--- a/src/org/jblas/ranges/AllRange.java
+++ b/src/org/jblas/benchmark/ATLASFloatMultiplicationBenchmark.java
@@ -1,25 +1,25 @@
 // --- BEGIN LICENSE BLOCK ---
-/* 
+/*
  * Copyright (c) 2009, Mikio L. Braun
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
- * 
+ *
  *     * Redistributions of source code must retain the above copyright
  *       notice, this list of conditions and the following disclaimer.
- * 
+ *
  *     * Redistributions in binary form must reproduce the above
  *       copyright notice, this list of conditions and the following
  *       disclaimer in the documentation and/or other materials provided
  *       with the distribution.
- * 
+ *
  *     * Neither the name of the Technische Universität Berlin nor the
  *       names of its contributors may be used to endorse or promote
  *       products derived from this software without specific prior
  *       written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -34,52 +34,37 @@
  */
 // --- END LICENSE BLOCK ---
 
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-
-package org.jblas.ranges;
+package org.jblas.benchmark;
 
-import org.jblas.*;
+import org.jblas.FloatMatrix;
+import static org.jblas.FloatMatrix.*;
 
 /**
- * A range over all available indices. Can be used to address whole columns or rows. Like
- * the ":" index in matlab. Don't forget to call init() before using this range.
+ *
  */
-public class AllRange implements Range {
-    private int lower;
-    private int upper;
-    private int value;
-    private int counter;
-    
-    public AllRange() {}
-    
-    public void init(int l, int u) {
-        lower = l;
-        upper = u;
-        value = l;
-        counter = 0;
-    }
-    
-    public int length() {
-        return upper - lower + 1;
-    }
-    
-    public int value() {
-        return value;
-    }
-    
-    public int index() {
-        return counter;
-    }
-    
-    public void next() {
-        counter++;
-        value++;
+class ATLASFloatMultiplicationBenchmark implements Benchmark {
+
+    public String getName() {
+        return "ATLAS matrix multiplication, single precision";
     }
-    
-    public boolean hasMore() {
-        return value < upper;
+
+    public BenchmarkResult run(int size, double seconds) {
+        int counter = 0;
+        long ops = 0;
+
+        FloatMatrix A = randn(size, size);
+        FloatMatrix B = randn(size, size);
+        FloatMatrix C = randn(size, size);
+
+        Timer t = new Timer();
+        t.start();
+        while (!t.ranFor(seconds)) {
+            A.mmuli(B, C);
+            counter++;
+            ops += 2L * size * size * size;
+        }
+        t.stop();
+
+        return new BenchmarkResult(ops, t.elapsedSeconds(), counter);
     }
 }
diff --git a/src/org/jblas/ranges/AllRange.java b/src/org/jblas/benchmark/Benchmark.java
similarity index 63%
copy from src/org/jblas/ranges/AllRange.java
copy to src/org/jblas/benchmark/Benchmark.java
index 9fe1d78..31b3589 100644
--- a/src/org/jblas/ranges/AllRange.java
+++ b/src/org/jblas/benchmark/Benchmark.java
@@ -1,25 +1,25 @@
 // --- BEGIN LICENSE BLOCK ---
-/* 
+/*
  * Copyright (c) 2009, Mikio L. Braun
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
- * 
+ *
  *     * Redistributions of source code must retain the above copyright
  *       notice, this list of conditions and the following disclaimer.
- * 
+ *
  *     * Redistributions in binary form must reproduce the above
  *       copyright notice, this list of conditions and the following
  *       disclaimer in the documentation and/or other materials provided
  *       with the distribution.
- * 
+ *
  *     * Neither the name of the Technische Universität Berlin nor the
  *       names of its contributors may be used to endorse or promote
  *       products derived from this software without specific prior
  *       written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -34,52 +34,15 @@
  */
 // --- END LICENSE BLOCK ---
 
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-
-package org.jblas.ranges;
-
-import org.jblas.*;
+package org.jblas.benchmark;
 
 /**
- * A range over all available indices. Can be used to address whole columns or rows. Like
- * the ":" index in matlab. Don't forget to call init() before using this range.
+ *
+ * @author mikio
  */
-public class AllRange implements Range {
-    private int lower;
-    private int upper;
-    private int value;
-    private int counter;
-    
-    public AllRange() {}
-    
-    public void init(int l, int u) {
-        lower = l;
-        upper = u;
-        value = l;
-        counter = 0;
-    }
-    
-    public int length() {
-        return upper - lower + 1;
-    }
-    
-    public int value() {
-        return value;
-    }
-    
-    public int index() {
-        return counter;
-    }
-    
-    public void next() {
-        counter++;
-        value++;
-    }
-    
-    public boolean hasMore() {
-        return value < upper;
-    }
+interface Benchmark {
+
+    public String getName();
+
+    public BenchmarkResult run(int size, double seconds);
 }
diff --git a/src/org/jblas/ranges/AllRange.java b/src/org/jblas/benchmark/BenchmarkResult.java
similarity index 64%
copy from src/org/jblas/ranges/AllRange.java
copy to src/org/jblas/benchmark/BenchmarkResult.java
index 9fe1d78..e15585a 100644
--- a/src/org/jblas/ranges/AllRange.java
+++ b/src/org/jblas/benchmark/BenchmarkResult.java
@@ -1,25 +1,25 @@
 // --- BEGIN LICENSE BLOCK ---
-/* 
+/*
  * Copyright (c) 2009, Mikio L. Braun
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
- * 
+ *
  *     * Redistributions of source code must retain the above copyright
  *       notice, this list of conditions and the following disclaimer.
- * 
+ *
  *     * Redistributions in binary form must reproduce the above
  *       copyright notice, this list of conditions and the following
  *       disclaimer in the documentation and/or other materials provided
  *       with the distribution.
- * 
+ *
  *     * Neither the name of the Technische Universität Berlin nor the
  *       names of its contributors may be used to endorse or promote
  *       products derived from this software without specific prior
  *       written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -34,52 +34,26 @@
  */
 // --- END LICENSE BLOCK ---
 
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-
-package org.jblas.ranges;
-
-import org.jblas.*;
+package org.jblas.benchmark;
 
 /**
- * A range over all available indices. Can be used to address whole columns or rows. Like
- * the ":" index in matlab. Don't forget to call init() before using this range.
+ *
  */
-public class AllRange implements Range {
-    private int lower;
-    private int upper;
-    private int value;
-    private int counter;
-    
-    public AllRange() {}
-    
-    public void init(int l, int u) {
-        lower = l;
-        upper = u;
-        value = l;
-        counter = 0;
-    }
-    
-    public int length() {
-        return upper - lower + 1;
-    }
-    
-    public int value() {
-        return value;
-    }
-    
-    public int index() {
-        return counter;
-    }
-    
-    public void next() {
-        counter++;
-        value++;
+class BenchmarkResult {
+    long numOps;
+    double duration;
+    int iterations;
+
+    BenchmarkResult(long numOps, double duration, int iterations) {
+        this.numOps = numOps;
+        this.duration = duration;
+        this.iterations = iterations;
     }
-    
-    public boolean hasMore() {
-        return value < upper;
+
+    void printResult() {
+        System.out.printf("%6.1f MFLOPS (%d iterations in %.1f seconds)%n",
+                numOps / duration / 1e6,
+                iterations,
+                duration);
     }
 }
diff --git a/src/org/jblas/ranges/IntervalRange.java b/src/org/jblas/benchmark/JavaDoubleMultiplicationBenchmark.java
similarity index 58%
copy from src/org/jblas/ranges/IntervalRange.java
copy to src/org/jblas/benchmark/JavaDoubleMultiplicationBenchmark.java
index beaf0e4..e970939 100644
--- a/src/org/jblas/ranges/IntervalRange.java
+++ b/src/org/jblas/benchmark/JavaDoubleMultiplicationBenchmark.java
@@ -1,25 +1,25 @@
 // --- BEGIN LICENSE BLOCK ---
-/* 
+/*
  * Copyright (c) 2009, Mikio L. Braun
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
- * 
+ *
  *     * Redistributions of source code must retain the above copyright
  *       notice, this list of conditions and the following disclaimer.
- * 
+ *
  *     * Redistributions in binary form must reproduce the above
  *       copyright notice, this list of conditions and the following
  *       disclaimer in the documentation and/or other materials provided
  *       with the distribution.
- * 
+ *
  *     * Neither the name of the Technische Universität Berlin nor the
  *       names of its contributors may be used to endorse or promote
  *       products derived from this software without specific prior
  *       written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -34,53 +34,54 @@
  */
 // --- END LICENSE BLOCK ---
 
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package org.jblas.ranges;
+package org.jblas.benchmark;
+
+import static org.jblas.DoubleMatrix.*;
 
 /**
- * Range which varies from a given interval. Endpoints are both inclusive!
+ *
  */
-public class IntervalRange implements Range {
-    private int start;
-    private int end;
-    private int value;
-    private int counter;
+class JavaDoubleMultiplicationBenchmark implements Benchmark {
 
-    /** Construct new interval range. Endpoints are inclusive. */
-    public IntervalRange(int a, int b) {
-        start = a;
-        end = b;
+    public String getName() {
+        return "Java matrix multiplication, double precision";
     }
 
-    public void init(int lower, int upper) {
-        value = start;
-        counter = 0;
-        if (start < lower || end > upper) {
-            throw new IllegalArgumentException("Bounds " + lower + " to " + upper + " are beyond range interval " + start + " to " + end + ".");
+    /** Compute C = A * B */
+    private void mmuli(int n, double[] A, double[] B, double[] C) {
+        for (int i = 0; i < n * n; i++) {
+            C[i] = 0;
         }
-    }
 
-    public int length() {
-        return end - start + 1;
+        for (int j = 0; j < n; j++) {
+            int jn = j * n;
+            for (int k = 0; k < n; k++) {
+                int kn = k * n;
+                double bkjn = B[k + jn];
+                for (int i = 0; i < n; i++) {
+                    C[i + jn] += A[i + kn] + bkjn;
+                }
+            }
+        }
     }
 
-    public void next() {
-        counter++;
-        value++;
-    }
-    
-    public int index() {
-        return counter;
-    }
-    
-    public int value() {
-        return value;
-    }
+    public BenchmarkResult run(int size, double seconds) {
+        int counter = 0;
+        long ops = 0;
+
+        double[] A = randn(size, size).data;
+        double[] B = randn(size, size).data;
+        double[] C = randn(size, size).data;
+
+        Timer t = new Timer();
+        t.start();
+        while (!t.ranFor(seconds)) {
+            mmuli(size, A, B, C);
+            counter++;
+            ops += 2L * size * size * size;
+        }
+        t.stop();
 
-    public boolean hasMore() {
-        return counter < end;
+        return new BenchmarkResult(ops, t.elapsedSeconds(), counter);
     }
 }
diff --git a/src/org/jblas/ranges/IntervalRange.java b/src/org/jblas/benchmark/JavaFloatMultiplicationBenchmark.java
similarity index 58%
copy from src/org/jblas/ranges/IntervalRange.java
copy to src/org/jblas/benchmark/JavaFloatMultiplicationBenchmark.java
index beaf0e4..2821b1f 100644
--- a/src/org/jblas/ranges/IntervalRange.java
+++ b/src/org/jblas/benchmark/JavaFloatMultiplicationBenchmark.java
@@ -1,25 +1,25 @@
 // --- BEGIN LICENSE BLOCK ---
-/* 
+/*
  * Copyright (c) 2009, Mikio L. Braun
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
- * 
+ *
  *     * Redistributions of source code must retain the above copyright
  *       notice, this list of conditions and the following disclaimer.
- * 
+ *
  *     * Redistributions in binary form must reproduce the above
  *       copyright notice, this list of conditions and the following
  *       disclaimer in the documentation and/or other materials provided
  *       with the distribution.
- * 
+ *
  *     * Neither the name of the Technische Universität Berlin nor the
  *       names of its contributors may be used to endorse or promote
  *       products derived from this software without specific prior
  *       written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -34,53 +34,54 @@
  */
 // --- END LICENSE BLOCK ---
 
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package org.jblas.ranges;
+package org.jblas.benchmark;
+
+import static org.jblas.FloatMatrix.randn;
 
 /**
- * Range which varies from a given interval. Endpoints are both inclusive!
+ *
  */
-public class IntervalRange implements Range {
-    private int start;
-    private int end;
-    private int value;
-    private int counter;
+class JavaFloatMultiplicationBenchmark implements Benchmark {
 
-    /** Construct new interval range. Endpoints are inclusive. */
-    public IntervalRange(int a, int b) {
-        start = a;
-        end = b;
+    public String getName() {
+        return "Java matrix multiplication, single precision";
     }
 
-    public void init(int lower, int upper) {
-        value = start;
-        counter = 0;
-        if (start < lower || end > upper) {
-            throw new IllegalArgumentException("Bounds " + lower + " to " + upper + " are beyond range interval " + start + " to " + end + ".");
+    /** Compute C = A * B */
+    private void mmuli(int n, float[] A, float[] B, float[] C) {
+        for (int i = 0; i < n * n; i++) {
+            C[i] = 0;
         }
-    }
 
-    public int length() {
-        return end - start + 1;
+        for (int j = 0; j < n; j++) {
+            int jn = j * n;
+            for (int k = 0; k < n; k++) {
+                int kn = k * n;
+                float bkjn = B[k + jn];
+                for (int i = 0; i < n; i++) {
+                    C[i + jn] += A[i + kn] + bkjn;
+                }
+            }
+        }
     }
 
-    public void next() {
-        counter++;
-        value++;
-    }
-    
-    public int index() {
-        return counter;
-    }
-    
-    public int value() {
-        return value;
-    }
+    public BenchmarkResult run(int size, double seconds) {
+        int counter = 0;
+        long ops = 0;
+
+        float[] A = randn(size, size).data;
+        float[] B = randn(size, size).data;
+        float[] C = randn(size, size).data;
+
+        Timer t = new Timer();
+        t.start();
+        while (!t.ranFor(seconds)) {
+            mmuli(size, A, B, C);
+            counter++;
+            ops += 2L * size * size * size;
+        }
+        t.stop();
 
-    public boolean hasMore() {
-        return counter < end;
+        return new BenchmarkResult(ops, t.elapsedSeconds(), counter);
     }
 }
diff --git a/src/org/jblas/benchmark/Main.java b/src/org/jblas/benchmark/Main.java
new file mode 100644
index 0000000..46ca5b9
--- /dev/null
+++ b/src/org/jblas/benchmark/Main.java
@@ -0,0 +1,141 @@
+// --- BEGIN LICENSE BLOCK ---
+/*
+ * Copyright (c) 2009, Mikio L. Braun
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     * Neither the name of the Technische Universität Berlin nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+// --- END LICENSE BLOCK ---
+package org.jblas.benchmark;
+
+import java.io.PrintStream;
+import org.jblas.util.Logger;
+
+/**
+ * A simple command-line style benchmarking program.
+ * 
+ * <p>Benchmarks matrix-matrix multiplication, and compares to a 
+ * pure Java implementation</p>
+ *
+ * @author Mikio L. Braun
+ */
+public class Main {
+
+    static Benchmark[] multiplicationBenchmarks = {
+        new JavaDoubleMultiplicationBenchmark(),
+        new JavaFloatMultiplicationBenchmark(),
+        new ATLASDoubleMultiplicationBenchmark(),
+        new ATLASFloatMultiplicationBenchmark(),};
+
+    public static void printHelp() {
+        System.out.printf("Usage: benchmark [opts]%n"
+                + "%n"
+                + "with options:%n"
+                + "%n"
+                + "  --arch-flavor=value     overriding arch flavor (e.g. --arch-flavor=sse2)%n"
+                + "  --skip-java             don't run java benchmarks%n"
+                + "  --help                  show this help%n");
+    }
+
+    public static void main(String[] args) {
+        int[] multiplicationSizes = {10, 100, 1000};
+        PrintStream out = System.out;
+
+        boolean skipJava = false;
+        boolean unrecognizedOptions = false;
+
+        for (String arg : args) {
+            if (arg.startsWith("--")) {
+                int i = arg.indexOf('=');
+                String value = null;
+                if (i != -1) {
+                    value = arg.substring(i + 1);
+                    arg = arg.substring(0, i);
+                }
+
+                if (arg.equals("--arch-flavor")) {
+                    Logger.getLogger().info("Setting arch flavor to " + value);
+                    org.jblas.util.ArchFlavor.overrideArchFlavor(value);
+                } else if (arg.equals("--skip-java")) {
+                    skipJava = true;
+                } else if (arg.equals("--help")) {
+                    printHelp();
+                    return;
+                } else if (arg.equals("--debug")) {
+                    Logger.getLogger().setLevel(Logger.DEBUG);
+                } else {
+                    Logger.getLogger().warning("Unrecognized option \"" + arg + "\"");
+                    unrecognizedOptions = true;
+                }
+            }
+        }
+        if (unrecognizedOptions) {
+            return;
+        }
+
+        out.println(
+                "Simple benchmark for jblas");
+        out.println();
+
+        out.println(
+                "Running sanity benchmarks.");
+        out.println();
+        org.jblas.util.SanityChecks.main(args);
+        out.println();
+
+        out.println(
+                "Each benchmark will take about 5 seconds...");
+
+
+
+
+
+
+
+        for (Benchmark b : multiplicationBenchmarks) {
+            if (skipJava) {
+                if (b.getName().contains("Java")) {
+                    continue;
+                }
+            }
+
+            out.println();
+            out.println("Running benchmark \"" + b.getName() + "\".");
+            for (int n : multiplicationSizes) {
+                out.printf("n = %-5d: ", n);
+                out.flush();
+
+                BenchmarkResult result = b.run(n, 5.0);
+
+                result.printResult();
+            }
+        }
+    }
+}
diff --git a/src/org/jblas/ranges/AllRange.java b/src/org/jblas/benchmark/Timer.java
similarity index 65%
copy from src/org/jblas/ranges/AllRange.java
copy to src/org/jblas/benchmark/Timer.java
index 9fe1d78..0fae1a3 100644
--- a/src/org/jblas/ranges/AllRange.java
+++ b/src/org/jblas/benchmark/Timer.java
@@ -1,25 +1,25 @@
 // --- BEGIN LICENSE BLOCK ---
-/* 
+/*
  * Copyright (c) 2009, Mikio L. Braun
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
- * 
+ *
  *     * Redistributions of source code must retain the above copyright
  *       notice, this list of conditions and the following disclaimer.
- * 
+ *
  *     * Redistributions in binary form must reproduce the above
  *       copyright notice, this list of conditions and the following
  *       disclaimer in the documentation and/or other materials provided
  *       with the distribution.
- * 
+ *
  *     * Neither the name of the Technische Universität Berlin nor the
  *       names of its contributors may be used to endorse or promote
  *       products derived from this software without specific prior
  *       written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -34,52 +34,35 @@
  */
 // --- END LICENSE BLOCK ---
 
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-
-package org.jblas.ranges;
-
-import org.jblas.*;
+package org.jblas.benchmark;
 
 /**
- * A range over all available indices. Can be used to address whole columns or rows. Like
- * the ":" index in matlab. Don't forget to call init() before using this range.
+ *
+ * @author mikio
  */
-public class AllRange implements Range {
-    private int lower;
-    private int upper;
-    private int value;
-    private int counter;
-    
-    public AllRange() {}
-    
-    public void init(int l, int u) {
-        lower = l;
-        upper = u;
-        value = l;
-        counter = 0;
-    }
-    
-    public int length() {
-        return upper - lower + 1;
+class Timer {
+    long startTime;
+    long stopTime;
+
+    Timer() {
+        startTime = -1;
+        stopTime = -1;
     }
     
-    public int value() {
-        return value;
+    void start() {
+        startTime = System.nanoTime();
     }
     
-    public int index() {
-        return counter;
+    long stop() {
+        stopTime = System.nanoTime();
+        return stopTime - startTime;
     }
-    
-    public void next() {
-        counter++;
-        value++;
+
+    boolean ranFor(double seconds) {
+        return (System.nanoTime() - startTime) / 1e9 >= seconds;
     }
-    
-    public boolean hasMore() {
-        return value < upper;
+
+    double elapsedSeconds() {
+        return (stopTime - startTime) / 1e9;
     }
 }
diff --git a/src/org/jblas/ranges/AllRange.java b/src/org/jblas/benchmark/package-info.java
similarity index 63%
copy from src/org/jblas/ranges/AllRange.java
copy to src/org/jblas/benchmark/package-info.java
index 9fe1d78..d5081f3 100644
--- a/src/org/jblas/ranges/AllRange.java
+++ b/src/org/jblas/benchmark/package-info.java
@@ -1,25 +1,25 @@
 // --- BEGIN LICENSE BLOCK ---
-/* 
+/*
  * Copyright (c) 2009, Mikio L. Braun
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
- * 
+ *
  *     * Redistributions of source code must retain the above copyright
  *       notice, this list of conditions and the following disclaimer.
- * 
+ *
  *     * Redistributions in binary form must reproduce the above
  *       copyright notice, this list of conditions and the following
  *       disclaimer in the documentation and/or other materials provided
  *       with the distribution.
- * 
+ *
  *     * Neither the name of the Technische Universität Berlin nor the
  *       names of its contributors may be used to endorse or promote
  *       products derived from this software without specific prior
  *       written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -34,52 +34,9 @@
  */
 // --- END LICENSE BLOCK ---
 
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-
-package org.jblas.ranges;
-
-import org.jblas.*;
-
 /**
- * A range over all available indices. Can be used to address whole columns or rows. Like
- * the ":" index in matlab. Don't forget to call init() before using this range.
+ * Simple benchmarking tool.
+ *
+ * <p>Run org.jblas.benchmark.Main</p>.
  */
-public class AllRange implements Range {
-    private int lower;
-    private int upper;
-    private int value;
-    private int counter;
-    
-    public AllRange() {}
-    
-    public void init(int l, int u) {
-        lower = l;
-        upper = u;
-        value = l;
-        counter = 0;
-    }
-    
-    public int length() {
-        return upper - lower + 1;
-    }
-    
-    public int value() {
-        return value;
-    }
-    
-    public int index() {
-        return counter;
-    }
-    
-    public void next() {
-        counter++;
-        value++;
-    }
-    
-    public boolean hasMore() {
-        return value < upper;
-    }
-}
+package org.jblas.benchmark;
diff --git a/src/org/jblas/ranges/AllRange.java b/src/org/jblas/ranges/AllRange.java
index 9fe1d78..cc1b804 100644
--- a/src/org/jblas/ranges/AllRange.java
+++ b/src/org/jblas/ranges/AllRange.java
@@ -63,7 +63,7 @@ public class AllRange implements Range {
     }
     
     public int length() {
-        return upper - lower + 1;
+        return upper - lower;
     }
     
     public int value() {
diff --git a/src/org/jblas/ranges/IntervalRange.java b/src/org/jblas/ranges/IntervalRange.java
index beaf0e4..65e5f06 100644
--- a/src/org/jblas/ranges/IntervalRange.java
+++ b/src/org/jblas/ranges/IntervalRange.java
@@ -41,13 +41,14 @@
 package org.jblas.ranges;
 
 /**
- * Range which varies from a given interval. Endpoints are both inclusive!
+ * Range which varies from a given interval. Endpoint is exclusive!
+ *
+ * "new IntervalRange(0, 3)" enumerates 0, 1, 2.
  */
 public class IntervalRange implements Range {
     private int start;
     private int end;
     private int value;
-    private int counter;
 
     /** Construct new interval range. Endpoints are inclusive. */
     public IntervalRange(int a, int b) {
@@ -57,23 +58,21 @@ public class IntervalRange implements Range {
 
     public void init(int lower, int upper) {
         value = start;
-        counter = 0;
-        if (start < lower || end > upper) {
+        if (start < lower || end > upper + 1) {
             throw new IllegalArgumentException("Bounds " + lower + " to " + upper + " are beyond range interval " + start + " to " + end + ".");
         }
     }
 
     public int length() {
-        return end - start + 1;
+        return end - start;
     }
 
     public void next() {
-        counter++;
         value++;
     }
     
     public int index() {
-        return counter;
+        return value;
     }
     
     public int value() {
@@ -81,6 +80,6 @@ public class IntervalRange implements Range {
     }
 
     public boolean hasMore() {
-        return counter < end;
+        return value < end;
     }
 }
diff --git a/src/org/jblas/ranges/IntervalRange.java b/src/org/jblas/util/ArchFlavor.java
similarity index 53%
copy from src/org/jblas/ranges/IntervalRange.java
copy to src/org/jblas/util/ArchFlavor.java
index beaf0e4..f115482 100644
--- a/src/org/jblas/ranges/IntervalRange.java
+++ b/src/org/jblas/util/ArchFlavor.java
@@ -33,54 +33,55 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 // --- END LICENSE BLOCK ---
-
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package org.jblas.ranges;
+package org.jblas.util;
 
 /**
- * Range which varies from a given interval. Endpoints are both inclusive!
+ *
  */
-public class IntervalRange implements Range {
-    private int start;
-    private int end;
-    private int value;
-    private int counter;
-
-    /** Construct new interval range. Endpoints are inclusive. */
-    public IntervalRange(int a, int b) {
-        start = a;
-        end = b;
-    }
+public class ArchFlavor {
 
-    public void init(int lower, int upper) {
-        value = start;
-        counter = 0;
-        if (start < lower || end > upper) {
-            throw new IllegalArgumentException("Bounds " + lower + " to " + upper + " are beyond range interval " + start + " to " + end + ".");
+    static {
+        try {
+            System.loadLibrary("jblas_arch_flavor");
+        } catch (UnsatisfiedLinkError e) {
+            Logger.getLogger().config("ArchFlavor native library not found in path. Copying native library "
+                    + "libjblas_arch_flavor from the archive. Consider installing the library somewhere "
+                    + "in the path (for Windows: PATH, for Linux: LD_LIBRARY_PATH).");
+            new org.jblas.util.LibraryLoader().loadLibrary("jblas_arch_flavor", false);
         }
     }
+    private static String fixedFlavor = null;
 
-    public int length() {
-        return end - start + 1;
-    }
+    public static final int SSE = 1;
+    public static final int SSE2 = 2;
+    public static final int SSE3 = 3;
+    public static final int NO_SSE = -1; // for platforms where it isn't applicable.
 
-    public void next() {
-        counter++;
-        value++;
-    }
-    
-    public int index() {
-        return counter;
-    }
-    
-    public int value() {
-        return value;
+    public static native int SSELevel();
+
+    public static String archFlavor() {
+        if (fixedFlavor != null)
+            return fixedFlavor;
+
+        String arch = System.getProperty("os.arch");
+
+        if (arch.equals("i386") || arch.equals("x86") || arch.equals("x86_64") || arch.equals("amd64")) {
+            switch (SSELevel()) {
+                case SSE:
+                    return "sse";
+                case SSE2:
+                    return "sse2";
+                case SSE3:
+                    return "sse3";
+                default:
+                    return null;
+            }
+        } else {
+            return null;
+        }
     }
 
-    public boolean hasMore() {
-        return counter < end;
+    public static void overrideArchFlavor(String flavor) {
+        fixedFlavor = flavor;
     }
 }
diff --git a/src/org/jblas/util/LibraryLoader.java b/src/org/jblas/util/LibraryLoader.java
index f54a188..768f3c6 100644
--- a/src/org/jblas/util/LibraryLoader.java
+++ b/src/org/jblas/util/LibraryLoader.java
@@ -43,45 +43,75 @@ import java.io.*;
  */
 public class LibraryLoader {
 
-    /** Find the library <tt>libname</tt> as a resource, copy it to a tempfile
+    /**
+     * <p>Find the library <tt>libname</tt> as a resource, copy it to a tempfile
      * and load it using System.load(). The name of the library has to be the
      * base name, it is mapped to the corresponding system name using
      * System.mapLibraryName(). For example, the library "foo" is called "libfoo.so"
      * under Linux and "foo.dll" under Windows, but you just have to pass "foo"
-     * the loadLibrary().
+     * the loadLibrary().</p>
      *
-     * I'm not quite sure if this doesn't open all kinds of security holes. Any ideas?
+     * <p>I'm not quite sure if this doesn't open all kinds of security holes. Any ideas?</p>
+     *
+     * <p>This function reports some more information to the "org.jblas" logger at
+     * the FINE level.</p>
      *
      * @param libname basename of the library
      * @throws UnsatisfiedLinkError if library cannot be founds
      */
-    public void loadLibrary(String libname) {
+    public void loadLibrary(String libname, boolean withFlavor) {
+        String libpath;
+        Logger logger = Logger.getLogger();
+
         libname = System.mapLibraryName(libname);
 
         // We're in a static initializer and need a class. What shall we do?
         Class cl = getClass();
 
         // Trying to copy from here.
-        System.err.println("Trying to copy from /" + libname + ".");
+        logger.debug("Trying to copy from /" + libname + ".");
+        libpath = "/" + libname;
         InputStream is = cl.getResourceAsStream("/" + libname);
 
         // Trying to copy from "bin"
         if (is == null) {
-            System.err.println("Trying to copy from /bin/" + libname + ".");
-            is = cl.getResourceAsStream("/bin/" + libname);
+            logger.debug("Trying to copy from /bin/" + libname + ".");
+            libpath = "/bin/" + libname;
+            is = cl.getResourceAsStream(libpath);
         }
 
         // Trying to extract static version from the jar file. Why the static version?
         // Because it is more likely to run.
         if (is == null) {
-            System.err.println("Trying to copy from " + fatJarLibraryPath(libname, "static") + ".");
-            is = cl.getResourceAsStream(fatJarLibraryPath(libname, "static"));
+            libpath = fatJarLibraryPath("static");
+            logger.debug("Trying to copy from " + libpath + ".");
+            is = cl.getResourceAsStream(libpath + libname);
         }
 
         // Finally, let's see if we can get the dynamic version.
         if (is == null) {
-            is = cl.getResourceAsStream(fatJarLibraryPath(libname, "dynamic"));
-            System.err.println("Trying to copy from " + fatJarLibraryPath(libname, "dynamic") + ".");
+            libpath = fatJarLibraryPath("dynamic");
+            logger.debug("Trying to copy from " + libpath + ".");
+            is = cl.getResourceAsStream(libpath + libname);
+        }
+
+        // And then we do it again for the "Non-Unified" path name.
+        // The reason is that changes in the build process might lead to actually
+        // having "Windows Vista" or something in the path... .
+        if (is == null) {
+            libpath = fatJarLibraryPathNonUnified("static");
+            if (withFlavor) libpath = addFlavor(libpath);
+            logger.debug("Trying to copy from " + libpath + ".");
+            is = cl.getResourceAsStream(libpath + libname);
+        }
+
+        // Finally, let's see if we can the static version with the unified
+        // path name.
+        if (is == null) {
+            libpath = fatJarLibraryPath("static");
+            if (withFlavor) libpath = addFlavor(libpath);
+            logger.debug("Trying to copy from " + libpath + ".");
+            is = cl.getResourceAsStream(libpath + libname);
         }
 
         // Oh man, have to get out of here!
@@ -89,12 +119,14 @@ public class LibraryLoader {
             throw new UnsatisfiedLinkError("Couldn't find the resource " + libname + ".");
         }
 
+        logger.config("Loading " + libname + " from " + libpath + ".");
+
         try {
             File tempfile = File.createTempFile("jblas", libname);
             tempfile.deleteOnExit();
             OutputStream os = new FileOutputStream(tempfile);
 
-            System.out.println("tempfile.getPath() = " + tempfile.getPath());
+            logger.debug("tempfile.getPath() = " + tempfile.getPath());
 
             long savedTime = System.currentTimeMillis();
 
@@ -105,15 +137,15 @@ public class LibraryLoader {
             }
 
             double seconds = (double) (System.currentTimeMillis() - savedTime) / 1e3;
-            System.err.println("Copying took " + seconds + " seconds.");
+            logger.debug("Copying took " + seconds + " seconds.");
 
             os.close();
 
             System.load(tempfile.getPath());
         } catch (IOException io) {
-            System.err.println("Could not create the temp file: " + io.toString() + ".\n");
+            logger.error("Could not create the temp file: " + io.toString() + ".\n");
         } catch (UnsatisfiedLinkError ule) {
-            System.err.println("Couldn't load copied link file: " + ule.toString() + ".\n");
+            logger.error("Couldn't load copied link file: " + ule.toString() + ".\n");
         }
     }
 
@@ -126,10 +158,27 @@ public class LibraryLoader {
 
     /** Compute the path to the library. The path is basically
     "/" + os.name + "/" + os.arch + "/" + libname. */
-    static public String fatJarLibraryPath(String libname, String linkage) {
+    static public String fatJarLibraryPath(String linkage) {
         String sep = "/"; //System.getProperty("file.separator");
         String os_name = unifyOSName(System.getProperty("os.name"));
         String os_arch = System.getProperty("os.arch");
-        return sep + "lib" + sep + linkage + sep + os_name + sep + os_arch + sep + libname;
+        String path = sep + "lib" + sep + linkage + sep + os_name + sep + os_arch + sep;
+        return path;
+    }
+
+    static public String fatJarLibraryPathNonUnified(String linkage) {
+        String sep = "/"; //System.getProperty("file.separator");
+        String os_name = System.getProperty("os.name");
+        String os_arch = System.getProperty("os.arch");
+        String path = sep + "lib" + sep + linkage + sep + os_name + sep + os_arch + sep;
+        return path;
+    }
+
+    static private String addFlavor(String path) {
+        String sep = "/";
+        String arch_flavor = ArchFlavor.archFlavor();
+        if (arch_flavor != null)
+            path += arch_flavor + sep;
+        return path;
     }
 }
diff --git a/src/org/jblas/ranges/IntervalRange.java b/src/org/jblas/util/Logger.java
similarity index 60%
copy from src/org/jblas/ranges/IntervalRange.java
copy to src/org/jblas/util/Logger.java
index beaf0e4..e94d493 100644
--- a/src/org/jblas/ranges/IntervalRange.java
+++ b/src/org/jblas/util/Logger.java
@@ -1,25 +1,25 @@
 // --- BEGIN LICENSE BLOCK ---
-/* 
+/*
  * Copyright (c) 2009, Mikio L. Braun
  * All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * met:
- * 
+ *
  *     * Redistributions of source code must retain the above copyright
  *       notice, this list of conditions and the following disclaimer.
- * 
+ *
  *     * Redistributions in binary form must reproduce the above
  *       copyright notice, this list of conditions and the following
  *       disclaimer in the documentation and/or other materials provided
  *       with the distribution.
- * 
+ *
  *     * Neither the name of the Technische Universität Berlin nor the
  *       names of its contributors may be used to endorse or promote
  *       products derived from this software without specific prior
  *       written permission.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -34,53 +34,60 @@
  */
 // --- END LICENSE BLOCK ---
 
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package org.jblas.ranges;
+package org.jblas.util;
 
 /**
- * Range which varies from a given interval. Endpoints are both inclusive!
+ *
  */
-public class IntervalRange implements Range {
-    private int start;
-    private int end;
-    private int value;
-    private int counter;
+public class Logger {
+    public static final int ERROR = 5;
+    public static final int WARNING = 4;
+    public static final int INFO = 3;
+    public static final int CONFIG = 2;
+    public static final int DEBUG = 1;
 
-    /** Construct new interval range. Endpoints are inclusive. */
-    public IntervalRange(int a, int b) {
-        start = a;
-        end = b;
+    public static final String levelNames[] = {
+        "DEBUG", "CONFIG", "INFO", "WARNING", "ERROR"
+    };
+
+    private static Logger theLogger = new Logger();
+    private int level;
+
+    private Logger() {
+        level = INFO;
     }
 
-    public void init(int lower, int upper) {
-        value = start;
-        counter = 0;
-        if (start < lower || end > upper) {
-            throw new IllegalArgumentException("Bounds " + lower + " to " + upper + " are beyond range interval " + start + " to " + end + ".");
+    public static Logger getLogger() {
+        return theLogger;
+    }
+
+    public void log(int messageLevel, String msg) {
+        if (level <= messageLevel) {
+            System.err.println("-- org.jblas " + levelNames[messageLevel - 1] + " "+ msg);
         }
     }
 
-    public int length() {
-        return end - start + 1;
+    public void debug(String msg) {
+        log(DEBUG, msg);
     }
 
-    public void next() {
-        counter++;
-        value++;
+    public void config(String msg) {
+        log(CONFIG, msg);
     }
-    
-    public int index() {
-        return counter;
+
+    public void info(String msg) {
+        log(INFO, msg);
     }
-    
-    public int value() {
-        return value;
+
+    public void warning(String msg) {
+        log(WARNING, msg);
+    }
+
+    public void error(String msg) {
+        log(ERROR, msg);
     }
 
-    public boolean hasMore() {
-        return counter < end;
+    public void setLevel(int level) {
+        this.level = level;
     }
 }
diff --git a/src/org/jblas/util/Permutations.java b/src/org/jblas/util/Permutations.java
index 40d9ebf..78373e2 100644
--- a/src/org/jblas/util/Permutations.java
+++ b/src/org/jblas/util/Permutations.java
@@ -1,7 +1,38 @@
+// --- BEGIN LICENSE BLOCK ---
 /*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright (c) 2009, Mikio L. Braun
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     * Neither the name of the Technische Universität Berlin nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+// --- END LICENSE BLOCK ---
 
 package org.jblas.util;
 
@@ -9,7 +40,9 @@ import java.util.Random;
 import org.jblas.DoubleMatrix;
 
 /**
+ * Functions which generate random permutations.
  *
+ * @author Mikio L. Braun
  */
 public class Permutations {
     /**
diff --git a/src/org/jblas/util/SanityChecks.java b/src/org/jblas/util/SanityChecks.java
index 95c192a..72f7da5 100644
--- a/src/org/jblas/util/SanityChecks.java
+++ b/src/org/jblas/util/SanityChecks.java
@@ -1,14 +1,49 @@
+// --- BEGIN LICENSE BLOCK ---
 /*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
+ * Copyright (c) 2009, Mikio L. Braun
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *
+ *     * Neither the name of the Technische Universität Berlin nor the
+ *       names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior
+ *       written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+// --- END LICENSE BLOCK ---
+
 package org.jblas.util;
 
 import org.jblas.NativeBlas;
 import org.jblas.DoubleMatrix;
 
 /**
+ * Run a few sanity checks on the installation to see whether
+ * everything runs as expected.
  *
+ * @author Mikio L. Braun
  */
 public class SanityChecks {
 
@@ -24,6 +59,7 @@ public class SanityChecks {
         }
     }
 
+    /** Check whether vector addition works. This is pure Java code and should work. */
     public static void checkVectorAddition() {
         DoubleMatrix x = new DoubleMatrix(3, 1, 1.0, 2.0, 3.0);
         DoubleMatrix y = new DoubleMatrix(3, 1, 4.0, 5.0, 6.0);
@@ -32,42 +68,71 @@ public class SanityChecks {
         check("checking vector addition", x.add(y).equals(z));
     }
 
+    /** Check matrix multiplication. This is already ATLAS/BLAS code. */
     public static void checkMatrixMultiplication() {
 
-        DoubleMatrix A = new DoubleMatrix(new double[][] {
-            { 1.0, 2.0, 3.0 },
-            { 4.0, 5.0, 6.0 },
-            { 7.0, 8.0, 9.0 }
-        });
-        DoubleMatrix E = new DoubleMatrix(new double[][] {
-            { 0.0, 0.0, 1.0 },
-            { 0.0, 1.0, 0.0 },
-            { 1.0, 0.0, 0.0 }
-        });
-        DoubleMatrix B = new DoubleMatrix(new double[][] {
-            { 3.0, 2.0, 1.0 },
-            { 6.0, 5.0, 4.0 },
-            { 9.0, 8.0, 7.0 }
-        });
+        DoubleMatrix A = new DoubleMatrix(new double[][]{
+                    {1.0, 2.0, 3.0},
+                    {4.0, 5.0, 6.0},
+                    {7.0, 8.0, 9.0}
+                });
+        DoubleMatrix E = new DoubleMatrix(new double[][]{
+                    {0.0, 0.0, 1.0},
+                    {0.0, 1.0, 0.0},
+                    {1.0, 0.0, 0.0}
+                });
+        DoubleMatrix B = new DoubleMatrix(new double[][]{
+                    {3.0, 2.0, 1.0},
+                    {6.0, 5.0, 4.0},
+                    {9.0, 8.0, 7.0}
+                });
 
         check("checking matrix multiplication", A.mmul(E).equals(B));
     }
 
+    /**
+     * Check whether error handling works. If it works, you should see an
+     * ok, otherwise, you might see the actual error message and then
+     * the program exits.
+     */
     public static void checkXerbla() {
         double[] x = new double[9];
         try {
             NativeBlas.dgemm('N', 'N', 3, -1, 3, 1.0, x, 0, 3, x, 0, 3, 0.0, x, 0, 3);
-        }
-        catch(IllegalArgumentException e) {
+        } catch (IllegalArgumentException e) {
             check("checking XERBLA", e.getMessage().contains("XERBLA"));
             return;
         }
-        assert(false); // shouldn't happen
+        assert (false); // shouldn't happen
+    }
+
+    /**
+     * Compute eigenvalues. This is a routine not in ATLAS, but in the original
+     * LAPACK.
+     */
+    public static void checkEigenvalues() {
+        DoubleMatrix A = new DoubleMatrix(new double[][]{
+                    {3.0, 2.0, 0.0},
+                    {2.0, 3.0, 2.0},
+                    {0.0, 2.0, 3.0}
+                });
+
+        DoubleMatrix E = new DoubleMatrix(3, 1);
+
+        NativeBlas.dsyev('N', 'U', 3, A.data, 0, 3, E.data, 0);
+        check("checking existence of dsyev...", true);
     }
 
     public static void main(String[] args) {
+        Logger.getLogger().setLevel(Logger.CONFIG);
+        for (String arg: args) {
+            if (arg.equals("--debug")) {
+                Logger.getLogger().setLevel(Logger.DEBUG);
+            }
+        }
         checkVectorAddition();
         checkMatrixMultiplication();
+        checkEigenvalues();
         checkXerbla();
         printSummary();
     }
@@ -75,8 +140,7 @@ public class SanityChecks {
     private static void printSummary() {
         if (checksFailed == 0) {
             System.out.println("Sanity checks passed.");
-        }
-        else {
+        } else {
             System.out.println("Sainty checks FAILED!");
         }
     }
diff --git a/src/overview.textile b/src/overview.textile
index cfd0db3..7af53df 100644
--- a/src/overview.textile
+++ b/src/overview.textile
@@ -33,8 +33,8 @@ In all brevity, here is what you need to know to get started:
   reading or writing a whole column, row, or submatrix.
 
 * There exist only two-dimensional matrices. Vectors are matrices
-  whose columns or rows are 0. This has turned out to be much more
-  convenient thatn having separated classes.
+  whose number of columns or rows are 1. This has turned out to be
+  much more convenient thatn having separated classes.
 
 * Every math operator maps to a short mnemonic name. For example, +
   becomes @add@, - becomes @sub@, * becomes @mul@, / becomes @div@,
diff --git a/test/org/jblas/ranges/IntervalRangeTest.java b/test/org/jblas/ranges/IntervalRangeTest.java
new file mode 100644
index 0000000..cd3aa53
--- /dev/null
+++ b/test/org/jblas/ranges/IntervalRangeTest.java
@@ -0,0 +1,40 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.jblas.ranges;
+
+
+import junit.framework.TestCase;
+import org.jblas.DoubleMatrix;
+
+/**
+ *
+ * @author mikio
+ */
+public class IntervalRangeTest extends TestCase {
+
+    DoubleMatrix A;
+
+    public IntervalRangeTest(String testName) {
+        super(testName);
+    }
+    
+    @Override
+    public void setUp() {
+            A = new DoubleMatrix(4, 3,
+                    1.0, 2.0, 3.0, 4.0,
+                    5.0, 6.0, 7.0, 8.0,
+                    9.0, 10.0, 11.0, 12.0).transpose();
+    }
+
+    public void testGetRows() {
+        DoubleMatrix ARows1to2 = new DoubleMatrix(2, 4,
+                5.0, 9.0,
+                6.0, 10.0,
+                7.0, 11.0,
+                8.0, 12.0);
+        assertEquals(ARows1to2, A.getRows(new IntervalRange(1, 3)));
+    }
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/jblas.git



More information about the pkg-java-commits mailing list