[jblas] 01/24: Imported Upstream version 0.1

Tony Mancill tmancill at moszumanska.debian.org
Sun Jan 5 05:45:56 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 23e0f112752c1d0eb18b4f1f86ea15b7c4dec4c4
Author: tony mancill <tmancill at debian.org>
Date:   Tue Dec 31 15:19:18 2013 -0800

    Imported Upstream version 0.1
---
 AUTHORS                                            |    2 +
 COPYING                                            |   31 +
 INSTALL                                            |  151 +
 Makefile                                           |  113 +
 README                                             |   53 +
 build.xml                                          |  225 ++
 config/PrintProperty.java                          |    7 +
 config/config.rb                                   |  139 +
 config/configure.rb                                |  381 +++
 config/opts.rb                                     |   87 +
 config/path.rb                                     |   55 +
 configure                                          |    4 +
 fortranwrapper.dump                                |  Bin 0 -> 42859 bytes
 javadoc.css                                        |   55 +
 nbproject/ide-file-targets.xml                     |   43 +
 nbproject/private/private.xml                      |    5 +
 nbproject/project.xml                              |  183 ++
 scripts/add-license.rb                             |  137 +
 scripts/c-file.c                                   |   48 +
 scripts/c-header.h                                 |   51 +
 scripts/class_to_float.rb                          |   87 +
 scripts/fortran.rb                                 |  348 +++
 scripts/fortran/c.rb                               |  175 ++
 scripts/fortran/java.rb                            |  586 ++++
 scripts/fortranwrapper.rb                          |  134 +
 scripts/java-class.java                            |   60 +
 scripts/java-impl.c                                |  161 ++
 scripts/render-textile.rb                          |   45 +
 scripts/rjpp.rb                                    |   95 +
 scripts/static_class_to_float.rb                   |  109 +
 scripts/test_fortranwrapper                        |    4 +
 src/org/jblas/core/ComplexDouble.java              |  322 +++
 src/org/jblas/core/ComplexFloat.java               |  322 +++
 src/org/jblas/core/Functions.java                  |   46 +
 src/org/jblas/core/package-info.java               |   42 +
 src/org/jblas/la/Blas.java                         |  378 +++
 src/org/jblas/la/ComplexDoubleMatrix.java          | 2011 +++++++++++++
 src/org/jblas/la/ComplexFloatMatrix.java           | 2011 +++++++++++++
 src/org/jblas/la/DoubleFunction.java               |   45 +
 src/org/jblas/la/DoubleMatrix.java                 | 2965 ++++++++++++++++++++
 src/org/jblas/la/Eigen.java                        |  188 ++
 src/org/jblas/la/FloatFunction.java                |   45 +
 src/org/jblas/la/FloatMatrix.java                  | 2965 ++++++++++++++++++++
 src/org/jblas/la/Geometry.java                     |  181 ++
 src/org/jblas/la/JavaBlas.java                     |  286 ++
 src/org/jblas/la/MatrixFunctions.java              |  750 +++++
 src/org/jblas/la/SimpleBlas.java                   |  670 +++++
 src/org/jblas/la/Solve.java                        |  101 +
 src/org/jblas/la/Trigonometry.java                 |   67 +
 .../la/exceptions/LapackArgumentException.java     |   52 +
 .../la/exceptions/LapackConvergenceException.java  |   53 +
 src/org/jblas/la/exceptions/LapackException.java   |   53 +
 src/org/jblas/la/exceptions/SizeException.java     |   43 +
 src/org/jblas/la/exceptions/package-info.java      |    5 +
 src/org/jblas/la/package-info.java                 |   42 +
 src/org/jblas/la/ranges/AllRange.java              |   85 +
 src/org/jblas/la/ranges/IndicesRange.java          |   95 +
 src/org/jblas/la/ranges/IntervalRange.java         |   86 +
 src/org/jblas/la/ranges/PointRange.java            |   79 +
 src/org/jblas/la/ranges/Range.java                 |   77 +
 src/org/jblas/la/ranges/RangeUtils.java            |   86 +
 src/org/jblas/la/ranges/package-info.java          |    5 +
 src/org/jblas/util/LibraryLoader.java              |  111 +
 src/org/jblas/util/package-info.java               |   42 +
 src/overview.html                                  |   90 +
 src/overview.textile                               |   80 +
 test/org/jblas/core/Dynamic.java                   |   49 +
 test/org/jblas/core/TestComplexFloat.java          |   80 +
 test/org/jblas/la/BenchmarkAccess.java             |   89 +
 test/org/jblas/la/BenchmarkComplex.java            |   79 +
 test/org/jblas/la/BenchmarkElementwise.java        |   99 +
 test/org/jblas/la/BenchmarkMatrix.java             |  164 ++
 test/org/jblas/la/ComplexDoubleMatrixTest.java     |   88 +
 test/org/jblas/la/DemoImages.java                  |  319 +++
 test/org/jblas/la/EigenTest.java                   |   79 +
 test/org/jblas/la/SimpleBlasTest.java              |   77 +
 test/org/jblas/la/TestBlasDouble.java              |  183 ++
 test/org/jblas/la/TestBlasDoubleComplex.java       |   63 +
 test/org/jblas/la/TestBlasFloat.java               |  183 ++
 test/org/jblas/la/TestDoubleMatrix.java            |  641 +++++
 test/org/jblas/la/TestFloatMatrix.java             |  641 +++++
 test/org/jblas/la/TestGeometry.java                |   78 +
 test/org/jblas/la/TestMatrixFunctions.java         |   49 +
 test/org/jblas/la/TestSolve.java                   |   50 +
 test/org/jblas/la/TicToc.java                      |   70 +
 85 files changed, 21134 insertions(+)

diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..a1a98c6
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,2 @@
+Mikio L. Braun - main developer
+Johannes Schaback - additional programming
\ No newline at end of file
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..cab378d
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,31 @@
+Copyright (c) 2009, Mikio L. Braun and contributors
+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.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..06048d3
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,151 @@
+INSTALL Guide v0.1 - March 30, 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. 
+
+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.
+
+
+STANDARD PROCEDURE
+==================
+
+COMPILING JBLAS
+
+Assuming that you already have LAPACK and ATLAS libraries
+somewhere. This has been tested on Linux (debian lenny) and Windows
+XP/Cygwin.
+
+Prerequisites: 
+  - java JDK
+  - ant
+  - ruby
+  - Windows XP: cygwin with gcc, nm, ruby, make, etc.
+
+1. Run "./configure".
+
+2. Running "ant clean all" should do the job ;)
+
+
+INSTALLING JBLAS
+
+1. Add "jblas.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
+   don't want to do this, extract the dynamic library from jblas.jar
+   and copy it somewhere where it can be found.
+
+   For Linux, use LD_LIBRARY_PATH, for Windows, PATH
+   
+
+CONFIGURE FLAGS
+
+The configure script understands the following options:
+
+--lapack=DIR
+   Location where the LAPACK and BLAS sources can be found. Location of
+   the extracted lapack-lite files. Otherwise it is assumed that they
+   can be found in the jblas directory
+
+--lapack-build
+   Build only against LAPACK and BLAS, not ATLAS. Note that depending on
+   your configuration, you might still get an ATLAS version (for example, when
+   you compile under debian and ATLAS is installed). Use --static-libs then.
+
+--download-lapack
+   Download and unpack lapack-lite here if not found.
+
+--static-libs
+   Searches for static libraries only. Resulting jblas will not depend on
+   shared LAPACK/BLAS/ATLAS libraries. Default for Windows XP.
+
+--help
+   print this help
+
+
+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".
+
+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
new file mode 100644
index 0000000..b0ceaf8
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,113 @@
+## --- 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 ---
+
+# Load the output of the configuration files
+ifneq ($(wildcard configure.out),)
+include configure.out
+else
+$(error Please run "./configure" first...)
+endif
+
+ifneq ($(LAPACK_HOME),)
+LAPACK=$(LAPACK_HOME)/SRC
+BLAS=$(LAPACK_HOME)/BLAS/SRC
+endif
+
+PACKAGE=org.jblas.la
+
+# generate path from package name
+PACKAGE_PATH=$(subst .,/,$(PACKAGE))
+
+#
+# Pattern rules
+#
+# The crazy thing is, with these rules, you ONLY need to specify which
+# object files belong to a source file the rest is determined
+# automatically by make.
+#
+
+# rule to compile files
+%.o : %.c
+	$(CC) $(CFLAGS) $(INCDIRS) -c $< -o $@
+
+# rule to generate shared library from object file 
+%.$(SO) : %.o
+	$(LD) $(LDFLAGS) -o $@ $^ $(LOADLIBES)
+
+# the default target
+all	: compile-native
+
+compile-native : bin/$(LIB)jblas.$(SO)
+
+generate-wrapper: src/$(PACKAGE_PATH)/Blas.java native/Blas.c
+
+clean:
+	rm -f native/*.o native/*.$(SO) bin/*.$(SO) src/$(PACKAGE_PATH)/Blas.java
+
+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."
+	@echo "(nothing deleted)"
+else
+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)/Blas.java native/Blas.c: scripts/fortranwrapper.rb scripts/fortran.rb scripts/fortran/java.rb scripts/java-class.java scripts/java-impl.c
+	$(RUBY) scripts/fortranwrapper.rb $(PACKAGE) Blas \
+	$(BLAS)/*.f \
+	$(LAPACK)/[sd]gesv.f \
+	$(LAPACK)/[sd]sysv.f \
+	$(LAPACK)/[sd]syev.f \
+	$(LAPACK)/[sd]syev[rdx].f \
+	$(LAPACK)/[sd]posv.f \
+	$(LAPACK)/[sd]geev.f
+
+bin/$(LIB)jblas.$(SO) : native/Blas.$(SO)
+	mv $< $@
+
+#
+# For testing
+#
+VERSION=0.1
+
+make test-dist:
+	ant clean tar
+	rm -rf jblas-$(VERSION)
+	tar xzvf jblas-$(VERSION).tgz
+	cd jblas-$(VERSION)
+	./configure
+	ant clean jar
+	cd ..
diff --git a/README b/README
new file mode 100644
index 0000000..5f63eb4
--- /dev/null
+++ b/README
@@ -0,0 +1,53 @@
+jblas is a matrix library for Java which uses existing high
+performance BLAS and LAPACK libraries like ATLAS.
+
+Version 0.1, March 28, 2009
+
+INSTALL
+
+In principle, all you need is the jblas.jar in your
+classpath. jblas.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).
+
+
+BUILDING
+
+If you want to build jBLAS from the sources, you need to set up quite
+a few things:
+
+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.
+
+Besides that, you need an installation of ruby, for some code
+generation scripts.
+
+If you still want to build the source your own, see INSTALL for further
+details.
+
+
+HOW TO GET STARTED
+
+Have a look at javadoc/index.html and javadoc/org/jblas/la/DoubleMatrix.html
+
+
+LICENSE
+
+jblas is distributed under a BSD-style license. See the file LICENSE
+for more information.
+
+
+BUGS
+
+If you encounter any bugs, feel free to go to http://jblas.org and
+register a ticket for them. Make sure to include as much information
+as possible. For configuration problems it would also be helpful to
+include the file "configure.log".
+
+
+CONTRIBUTORS
+
+see file AUTHORS
\ No newline at end of file
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..98e5bba
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+Copyright (c) 2009, Mikio L. Braun
+Copyright (c) 2008, Johannes Schaback
+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.
+-->
+<project name="java-blas" basedir="." default="jar">
+    <description>
+		This is the build script to compile and deploy the java-blas project.
+		It also generates JavaDoc from source in ../doc.
+    </description>
+
+	<!-- Define directories -->
+    <property name="src" value="${basedir}/src" />
+    <property name="test" value="${basedir}/test" />
+    <property name="bin" value="${basedir}/bin" />
+    <property name="deploy" value="${basedir}/deploy" />
+    <property name="doc" value="${basedir}/javadoc" />
+    <property name="jar" value="${basedir}/jblas.jar" />
+    <property name="include" value="${basedir}/include" />
+    <property name="native" value="${basedir}/native" />
+    <property name="external" value="${basedir}/external" />
+    <property name="scripts" value="${basedir}/scripts" />
+    <property name="pkgbase" value="org.jblas" />
+    <property name="version" value="0.1" />
+    <macrodef name="class-to-float">
+        <attribute name="class"/>
+        <attribute name="path" default="src"/>
+        <sequential>
+            <echo message="Generating float version of @{class}"/>
+            <exec executable="ruby">
+                <arg line="scripts/class_to_float.rb @{path} @{class}"/>
+            </exec>
+        </sequential>
+    </macrodef>
+    <macrodef name="static-class-to-float">
+        <attribute name="class"/>
+        <sequential>
+            <echo message="Add float versions to class @{class}"/>
+            <exec executable="ruby">
+                <arg line="scripts/static_class_to_float.rb src @{class}"/>
+            </exec>
+        </sequential>
+    </macrodef>
+    <macrodef name="rjpp">
+        <attribute name="file"/>
+        <sequential>
+            <exec executable="ruby">
+                <arg line="scripts/rjpp.rb @{file}"/>
+            </exec>
+        </sequential>
+    </macrodef>
+    <target name="clean">
+        <delete dir="${doc}" />
+        <delete dir="${bin}" />
+        <delete dir="${native}" />
+        <delete dir="${include}" />
+        <delete file="${jar}" />
+        <exec executable="make">
+            <arg line="clean" />
+        </exec>
+    </target>
+    <target name="realclean" depends="clean">
+        <exec executable="make">
+            <arg line="realclean" />
+        </exec>
+    </target>
+    <target name="prepare">
+        <mkdir dir="${bin}" />
+        <mkdir dir="${native}" />
+        <mkdir dir="${include}" />
+    </target>
+    <target name="compile" depends="prepare,wrapper,generate-float">
+        <javac destdir="${bin}" source="1.6" debug="on" compiler="javac1.6" fork="yes" nowarn="yes">
+            <src path="${src}" />
+            <classpath>
+                <pathelement location="${external}/junit.jar" />
+            </classpath>
+        </javac>
+    </target>
+    <target name="compile-test" depends="prepare,wrapper,generate-float">
+        <javac destdir="${bin}" source="1.6" debug="on" compiler="javac1.6" fork="yes" nowarn="yes">
+            <src path="${test}" />
+            <classpath>
+                <pathelement location="${external}/junit.jar" />
+            </classpath>
+        </javac>
+    </target>
+    <target name="javah" depends="prepare,wrapper,compile">
+        <javah destdir="${include}" force="yes">
+            <class name="${pkgbase}.la.Blas" />
+            <classpath>
+                <pathelement path="${bin}" />
+            </classpath>
+        </javah>
+    </target>
+    <target name="compile-native" depends="prepare,javah">
+        <exec executable="make">
+            <arg line="compile-native" />
+        </exec>
+    </target>
+    <target name="wrapper">
+        <exec executable="make">
+            <arg line="generate-wrapper" />
+        </exec>
+    </target>
+    <target name="generate-float" depends="preprocess">
+        <class-to-float class="${pkgbase}.la.DoubleMatrix"/>
+        <class-to-float class="${pkgbase}.la.DoubleFunction"/>
+        <class-to-float class="${pkgbase}.core.ComplexDouble"/>
+        <class-to-float path="test" class="${pkgbase}.la.TestDoubleMatrix"/>
+        <class-to-float path="test" class="${pkgbase}.la.TestBlasDouble"/>
+        <class-to-float class="${pkgbase}.la.ComplexDoubleMatrix"/>
+        <static-class-to-float class="${pkgbase}.la.SimpleBlas"/>
+        <static-class-to-float class="${pkgbase}.la.Solve"/>
+        <static-class-to-float class="${pkgbase}.la.Eigen"/>
+        <static-class-to-float class="${pkgbase}.la.Geometry"/>
+        <static-class-to-float class="${pkgbase}.la.MatrixFunctions"/>
+        <static-class-to-float class="${pkgbase}.la.JavaBlas"/>
+    </target>
+    <target name="preprocess">
+        <rjpp file="src/org/jblas/la/DoubleMatrix.java"/>
+        <rjpp file="test/org/jblas/la/TestDoubleMatrix.java"/>
+        <rjpp file="src/org/jblas/la/MatrixFunctions.java"/>
+        <rjpp file="src/org/jblas/la/ComplexDoubleMatrix.java"/>
+    </target>
+    <target name="jar" depends="compile,compile-native">
+        <jar destfile="${jar}">
+            <fileset dir="${bin}">
+                <include name="org/**" />
+                <include name="lib*.so"/>
+                <include name="*.dll"/>
+            </fileset>
+            <manifest>
+                <attribute name="Built-By" value="IDA Group, TU Berlin" />
+            </manifest>
+        </jar>
+    </target>
+    <target name="javadoc" depends="generate-float">
+        <mkdir dir="${doc}" />
+        <javadoc packagenames="org.jblas.*"
+		sourcepath="${src}" defaultexcludes="yes"
+		destdir="${doc}" author="true" version="true"
+		use="true" windowtitle="jblas" linksource="yes"
+			stylesheetfile="javadoc.css" overview="${src}/overview.html">
+            <doctitle>
+	<![CDATA[ <h1>jblas - Linear Algebra for Java</h1> ]]>
+            </doctitle>
+            <bottom>
+	<![CDATA[ written by Mikio L. Braun and Johannes Schaback ]]>
+            </bottom>
+            <tag name="dedication" scope="all" description="Dedication:" />
+        </javadoc>
+    </target>
+    <target name="test" depends="compile-test,jar">
+        <junit printsummary="yes" haltonfailure="yes" showoutput="yes">
+            <classpath>
+                <pathelement location="${external}/junit.jar" />
+                <pathelement path="${bin}" />
+            </classpath>
+            <formatter type="plain" usefile="false" />
+            <test name="${pkgbase}.la.TestBlasDouble" />
+        </junit>
+    </target>
+    <target name="all" depends="jar, javadoc">
+    </target>
+    <target name="debugDirectBufferGC" depends="jar">
+        <java classname="${pkgbase}.la.DebugDirectBufferGC" classpath="${basedir}/jBLAS.jar" />
+    </target>
+    <target name="tar" depends="javadoc">
+        <tar destfile="jblas-${version}.tgz" compression="gzip">
+            <tarfileset dir="${basedir}" prefix="jblas-${version}">
+                <include name="src/**" />
+                <include name="test/**" />
+                <exclude name="**/*.rjpp" />
+                <exclude name="**/semantic.cache" />
+                <include name="scripts/**" />
+                <exclude name="**/*~" />
+                <include name="build.xml" />
+                <include name="Makefile" />
+                <include name="config/*.rb" />
+                <include name="config/*.java" />
+                <include name="fortranwrapper.dump" />
+                <include name="README" />
+                <include name="INSTALL" />
+                <include name="COPYING" />
+                <include name="AUTHORS" />
+                <include name="javadoc.css" />
+                <include name="javadoc/**" />
+                <include name="nbproject/**" />
+            </tarfileset>
+            <tarfileset dir="${basedir}" prefix="jblas-${version}" mode="755"
+		    includes="configure" />
+        </tar>
+    </target>
+</project>
diff --git a/config/PrintProperty.java b/config/PrintProperty.java
new file mode 100644
index 0000000..840eaf3
--- /dev/null
+++ b/config/PrintProperty.java
@@ -0,0 +1,7 @@
+public class PrintProperty {
+    public static void main(String[] args) {
+	for (String arg: args) {
+	    System.out.println(System.getProperty(arg));
+	}
+    }
+}
\ No newline at end of file
diff --git a/config/config.rb b/config/config.rb
new file mode 100644
index 0000000..618f2bb
--- /dev/null
+++ b/config/config.rb
@@ -0,0 +1,139 @@
+## --- 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/path'
+
+class ConfigError < Exception
+  attr_reader :message
+
+  def initialize(msg)
+    @message = msg
+  end
+end
+
+class Config
+  def initialize
+    @config = Hash.new {|h,k| Array.new }
+    @log = open('configure.log', 'w')
+  end
+
+  def [](k)
+    @config[k]
+  end
+
+  def []=(k, v)
+    @config[k] = v
+    log "Setting #{k} to #{v}"
+  end
+
+  def log(msg)
+    @log.puts(msg)
+  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
+      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
+    return
+  end
+
+  def dump(io)
+    @config.each_pair do |k, v|
+      case v
+      when Array
+        io.puts "#{k}=#{v.join ' '}"
+      else
+        io.puts "#{k}=#{v}"
+      end
+    end
+  end
+
+  def msg(m)
+    print m + "... "
+    $stdout.flush
+    if block_given?
+      msg = yield
+      if msg.nil?
+        ok
+      else
+        puts msg
+      end
+    end
+  end
+
+  def ok
+    puts "ok"
+  end
+
+  def fail(msg=false)
+    puts "*failed*"
+    raise ConfigError, msg
+  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 
+  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
+  end
+end
diff --git a/config/configure.rb b/config/configure.rb
new file mode 100644
index 0000000..2e9722d
--- /dev/null
+++ b/config/configure.rb
@@ -0,0 +1,381 @@
+## --- 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/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
+
+#Todo:
+#  - find/download/compile LAPACK
+#  - find ATLAS
+#  - write out stuff to .config
+# EOS
+
+$opts = Opts.new(ARGV, {}, <<EOS)
+Usage: ./configure [options]
+
+options summary:
+  --lapack=DIR             lapack-lite directory
+  --lapack-build           build against fortran lapack instead of ATLAS
+  --libpath=DIR1:DIR2:...  comma separated list of directories to contain
+                           the ATLAS libraries
+  --download-lapack        try to download and compile lapack if not
+                           found
+  --static-libs            look for static libraries only. Results in a
+                           dynamically loaded jblas library which does
+                           not depend on lapack or atlas libraries. 
+                           (default for Windows!)
+EOS
+
+config = Config.new
+
+# translate dir (mainly necessary for cygwin)
+def dir(s)
+  case $os_name
+  when 'Linux'
+    s
+  when 'Windows XP'
+    s = s.gsub /\\/, '\\\\\\\\'
+    %x(cygpath -u #{s}).chomp
+  else
+    raise ConfigError, "The OS #{$os_name} is currently unsupported!"
+  end
+end
+
+def libname(name)
+  if $opts.defined? :static_libs
+    'lib' + name + '.a'
+  else
+    case $os_name
+    when 'Linux'
+      'lib' + name + '.so'
+    when 'Windows XP'
+      '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 #{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
+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 == 'Windows XP'
+      config.msg 'checking for cygpath' do
+        config.check_cmd 'cygpath'
+      end
+    end
+    $os_name
+  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')
+    if g77
+      config['LD'] = 'g77'
+    elsif gfortran
+      config['LD'] = 'gfortran'
+    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 -ggdb
+INCDIRS += -Iinclude -I#{$java_home}/include -I#{$java_home}/include/linux
+SO = so
+LIB = lib
+RUBY=ruby
+LDFLAGS += -shared
+EOS
+    when 'Windows XP'
+      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
+
+  ######################################################################
+  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)"
+        File.delete(File.join('.', 'lapack-lite-3.1.1.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
+  
+
+  ######################################################################
+  # 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
+
+  # Okay, then we're done!
+  if $opts.defined? :lapack_build
+    config << <<EOS
+LDFLAGS += #{$libpaths.map {|s| '-L' + s}.join ' '}
+LOADLIBES = -l#{$lapack_name} -l#{$blas_name}
+EOS
+  else
+    config << <<EOS
+LDFLAGS += #{$libpaths.map {|s| '-L' + s}.join ' '}
+LOADLIBES = -l#{$lapack_atlas_name} -l#{$lapack_name} -l#{$blas_name} -lcblas -latlas
+EOS
+  end
+
+  ######################################################################
+  # dumping results
+  puts
+  puts 'Configuration succesfull, writing out results to configure.out'
+  open('configure.out', 'w') {|f| config.dump f}
+
+rescue ConfigError => e
+  puts 
+  puts "Configuration failed!"
+  puts
+  puts "Reason: #{e.message}"
+end
diff --git a/config/opts.rb b/config/opts.rb
new file mode 100644
index 0000000..b1f7b29
--- /dev/null
+++ b/config/opts.rb
@@ -0,0 +1,87 @@
+## --- 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 ---
+
+class Opts
+  attr_accessor :opts, :args
+
+  def initialize(args, shortcuts={}, usage=nil)
+    @opts = Hash.new
+    @args = Array.new
+    args.each do |a|
+      case a
+      when '-h'
+        puts usage
+        exit
+      when '--help'
+        puts usage
+        exit
+      when /\A--/
+        a = a[2..-1]
+        if a.index('=')
+          key, value = a.split('=')
+          opts[key.gsub(/-/, '_').to_sym] = value
+        else
+          opts[a.gsub(/-/, '_').to_sym] = true
+        end
+      when /\A-/
+        key = a[1..1].to_sym
+        key = shortcuts[key] if shortcuts.has_key? key
+        value = a[2..-1]
+        if not value.empty?
+          opts[key] = value
+        else
+          opts[key] = true
+        end
+      else
+        @args << a
+      end
+    end
+
+    def defined?(v)
+      @opts.has_key? v
+    end
+
+    def [](key)
+      @opts[key]
+    end
+
+    def get(key, default)
+      if @opts.include? key
+        @opts[key]
+      else
+        default
+      end
+    end
+  end
+end
diff --git a/config/path.rb b/config/path.rb
new file mode 100644
index 0000000..85b0b3f
--- /dev/null
+++ b/config/path.rb
@@ -0,0 +1,55 @@
+## --- 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 'set'
+
+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
+      else
+        return p
+      end
+    else
+      #puts
+    end
+  end
+  return
+end
diff --git a/configure b/configure
new file mode 100755
index 0000000..86c95a9
--- /dev/null
+++ b/configure
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+ruby config/configure.rb $*
+
diff --git a/fortranwrapper.dump b/fortranwrapper.dump
new file mode 100644
index 0000000..98e79c2
Binary files /dev/null and b/fortranwrapper.dump differ
diff --git a/javadoc.css b/javadoc.css
new file mode 100644
index 0000000..ec5066d
--- /dev/null
+++ b/javadoc.css
@@ -0,0 +1,55 @@
+/* Javadoc style sheet */
+
+/* Define colors, fonts and other style attributes here to override the defaults */
+
+/* Page background color */
+body { background-color: #FFFFFF; color:#000000 }
+
+/* Headings */
+h1 { font-size: 145% }
+
+/* Table colors */
+.TableHeadingColor     { background: #CCCCFF; color:#000000 } /* Dark mauve */
+.TableSubHeadingColor  { background: #EEEEFF; color:#000000 } /* Light mauve */
+.TableRowColor         { background: #FFFFFF; color:#000000 } /* White */
+
+/* Font used in left-hand frame lists */
+.FrameTitleFont   { font-size: 100%; font-family: Helvetica, Arial, sans-serif; color:#000000 }
+.FrameHeadingFont { font-size:  90%; font-family: Helvetica, Arial, sans-serif; color:#000000 }
+.FrameItemFont    { font-size:  90%; font-family: Helvetica, Arial, sans-serif; color:#000000 }
+
+/* Navigation bar fonts and colors */
+.NavBarCell1    { background-color:#EEEEFF; color:#000000} /* Light mauve */
+.NavBarCell1Rev { background-color:#00008B; color:#FFFFFF} /* Dark Blue */
+.NavBarFont1    { font-family: Arial, Helvetica, sans-serif; color:#000000;color:#000000;}
+.NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;color:#FFFFFF;}
+
+.NavBarCell2    { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF; color:#000000}
+.NavBarCell3    { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF; color:#000000}
+
+table.my {
+  border-collapse: collapse;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+table.my td, th {
+  border: solid 1px #888;
+  padding: 5px;
+}
+
+table.my th {
+  background-color: #eef;
+}
+
+span.code { 
+  display:block;
+  padding: 0;
+  padding: 1em;
+  margin-top: 1em;
+  margin-bottom: 1em;
+  margin-left: 0;
+  margin-right: 0;
+  font-family: monospace;
+  text-align: center;          
+}
\ No newline at end of file
diff --git a/nbproject/ide-file-targets.xml b/nbproject/ide-file-targets.xml
new file mode 100644
index 0000000..0dcdfda
--- /dev/null
+++ b/nbproject/ide-file-targets.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project basedir=".." name="jBLAS-IDE">
+    <import file="../build.xml"/>
+    <!-- TODO: edit the following target according to your needs -->
+    <!-- (more info: http://www.netbeans.org/kb/41/freeform-config.html#runsingle) -->
+    <target name="test-selected-file-in-test-old">
+        <fail unless="run.class">Must set property 'run.class'</fail>
+        <junit classname="${run.class}" failonerror="true" fork="true">
+            <classpath>
+                <pathelement path="external/junit.jar:bin"/>
+            </classpath>
+        </junit>
+    </target>
+    <target depends="compile,compileNative" name="test-selected-file-in-test">
+        <mkdir dir="test-results"/>
+        <junit errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
+            <test name="${run.class}" todir="test-results"/>
+            <classpath path="${bin}:external/junit.jar"/>
+            <formatter type="brief" usefile="false"/>
+            <formatter type="xml"/>
+        </junit>
+    </target>
+    <!-- TODO: edit the following target according to your needs -->
+    <!-- (more info: http://www.netbeans.org/kb/41/freeform-config.html#runsingle) -->
+    <target name="debug-test-selected-file-in-test">
+        <fail unless="debug.class">Must set property 'debug.class'</fail>
+        <path id="cp">
+            <pathelement path="${bin}:external/junit.jar"/>
+        </path>
+        <nbjpdastart addressproperty="jpda.address" name="jBLAS" transport="dt_socket">
+            <classpath refid="cp"/>
+        </nbjpdastart>
+        <junit errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
+            <classpath path="${classes.dir}:external/junit.jar:${test.classes.dir}"/>
+            <jvmarg value="-Xdebug"/>
+            <jvmarg value="-Xnoagent"/>
+            <jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
+            <test name="${debug.class}" todir="${test.results.dir}"/>
+            <formatter type="brief" usefile="false"/>
+            <formatter type="xml"/>
+        </junit>
+    </target>
+</project>
diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml
new file mode 100644
index 0000000..2dd4812
--- /dev/null
+++ b/nbproject/private/private.xml
@@ -0,0 +1,5 @@
+<?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
new file mode 100644
index 0000000..33deba3
--- /dev/null
+++ b/nbproject/project.xml
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.ant.freeform</type>
+    <configuration>
+        <general-data xmlns="http://www.netbeans.org/ns/freeform-project/1">
+            <name>jBLAS-Array</name>
+        </general-data>
+        <general-data xmlns="http://www.netbeans.org/ns/freeform-project/2">
+            <!-- Do not use Project Properties customizer when editing this file manually. -->
+            <name>jBLAS-Array</name>
+            <properties/>
+            <folders>
+                <source-folder>
+                    <label>jBLAS</label>
+                    <location>.</location>
+                    <encoding>UTF-8</encoding>
+                </source-folder>
+                <source-folder>
+                    <label>src</label>
+                    <type>java</type>
+                    <location>src</location>
+                    <excludes>**/doc/,**/*.rjpp,**/*.cache</excludes>
+                    <encoding>UTF-8</encoding>
+                </source-folder>
+                <source-folder>
+                    <label>test</label>
+                    <type>java</type>
+                    <location>test</location>
+                    <excludes>**/doc/,**/*.rjpp,**/*.cache</excludes>
+                    <encoding>UTF-8</encoding>
+                </source-folder>
+                <source-folder>
+                    <label>scripts</label>
+                    <type>java</type>
+                    <location>scripts</location>
+                    <excludes>**/doc/,**/*.rjpp,**/*.cache</excludes>
+                    <encoding>UTF-8</encoding>
+                </source-folder>
+                <source-folder>
+                    <label>native</label>
+                    <type>java</type>
+                    <location>native</location>
+                    <excludes>**/doc/,**/*.rjpp,**/*.cache</excludes>
+                    <encoding>UTF-8</encoding>
+                </source-folder>
+                <source-folder>
+                    <label>include</label>
+                    <type>java</type>
+                    <location>include</location>
+                    <excludes>**/doc/,**/*.rjpp,**/*.cache</excludes>
+                    <encoding>UTF-8</encoding>
+                </source-folder>
+            </folders>
+            <ide-actions>
+                <action name="build">
+                    <target>jar</target>
+                </action>
+                <action name="clean">
+                    <target>clean</target>
+                </action>
+                <action name="javadoc">
+                    <target>javadoc</target>
+                </action>
+                <action name="test">
+                    <target>test</target>
+                </action>
+                <action name="rebuild">
+                    <target>clean</target>
+                    <target>jar</target>
+                </action>
+                <action name="test.single">
+                    <script>nbproject/ide-file-targets.xml</script>
+                    <target>test-selected-file-in-test</target>
+                    <context>
+                        <property>run.class</property>
+                        <folder>test</folder>
+                        <pattern>\.java$</pattern>
+                        <format>java-name</format>
+                        <arity>
+                            <one-file-only/>
+                        </arity>
+                    </context>
+                </action>
+                <action name="debug.single">
+                    <script>nbproject/ide-file-targets.xml</script>
+                    <target>debug-selected-file-in-test</target>
+                    <context>
+                        <property>debug.class</property>
+                        <folder>test</folder>
+                        <pattern>\.java$</pattern>
+                        <format>java-name</format>
+                        <arity>
+                            <one-file-only/>
+                        </arity>
+                    </context>
+                </action>
+                <action name="debug.test.single">
+                    <script>nbproject/ide-file-targets.xml</script>
+                    <target>debug-test-selected-file-in-test</target>
+                    <context>
+                        <property>debug.class</property>
+                        <folder>test</folder>
+                        <pattern>\.java$</pattern>
+                        <format>java-name</format>
+                        <arity>
+                            <one-file-only/>
+                        </arity>
+                    </context>
+                </action>
+            </ide-actions>
+            <export>
+                <type>jar</type>
+                <location>jBLAS.jar</location>
+                <build-target>jar</build-target>
+            </export>
+            <view>
+                <items>
+                    <source-folder style="packages">
+                        <label>src</label>
+                        <location>src</location>
+                        <excludes>**/doc/,**/*.rjpp,**/*.cache</excludes>
+                    </source-folder>
+                    <source-folder style="packages">
+                        <label>test</label>
+                        <location>test</location>
+                        <excludes>**/doc/,**/*.rjpp,**/*.cache</excludes>
+                    </source-folder>
+                    <source-folder style="packages">
+                        <label>scripts</label>
+                        <location>scripts</location>
+                        <excludes>**/doc/,**/*.rjpp,**/*.cache</excludes>
+                    </source-folder>
+                    <source-folder style="packages">
+                        <label>native</label>
+                        <location>native</location>
+                        <excludes>**/doc/,**/*.rjpp,**/*.cache</excludes>
+                    </source-folder>
+                    <source-folder style="packages">
+                        <label>include</label>
+                        <location>include</location>
+                        <excludes>**/doc/,**/*.rjpp,**/*.cache</excludes>
+                    </source-folder>
+                    <source-file>
+                        <location>build.xml</location>
+                    </source-file>
+                </items>
+                <context-menu>
+                    <ide-action name="build"/>
+                    <ide-action name="rebuild"/>
+                    <ide-action name="clean"/>
+                    <ide-action name="javadoc"/>
+                    <ide-action name="test"/>
+                </context-menu>
+            </view>
+            <subprojects/>
+        </general-data>
+        <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>
+                <source-level>1.5</source-level>
+            </compilation-unit>
+            <compilation-unit>
+                <package-root>test</package-root>
+                <unit-tests/>
+                <classpath mode="compile">src:../../../../usr/share/java/junit.jar</classpath>
+                <source-level>1.5</source-level>
+            </compilation-unit>
+            <compilation-unit>
+                <package-root>scripts</package-root>
+                <source-level>1.5</source-level>
+            </compilation-unit>
+            <compilation-unit>
+                <package-root>native</package-root>
+                <source-level>1.5</source-level>
+            </compilation-unit>
+            <compilation-unit>
+                <package-root>include</package-root>
+                <source-level>1.5</source-level>
+            </compilation-unit>
+        </java-data>
+    </configuration>
+</project>
diff --git a/scripts/add-license.rb b/scripts/add-license.rb
new file mode 100644
index 0000000..ef176ee
--- /dev/null
+++ b/scripts/add-license.rb
@@ -0,0 +1,137 @@
+## --- 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 ---
+
+LICENSE = <<EOS.split("\n")
+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.
+EOS
+
+DEFAULT_COPYRIGHT = "2009, Mikio L. Braun"
+
+BLB = '--- BEGIN LICENSE BLOCK ---'
+ELB = "--- END LICENSE BLOCK ---"
+
+SUFFIXMAP = {
+  '.rb' => :hash,
+  '.c' => :doubleslash,
+  '.h' => :doubleslash,
+  '.java' => :java
+}
+SUFFIXMAP.default = :hash
+
+# Comment a piece of text (given as an array of lines) for
+# a given code type
+def comment_block(file, txt)
+  #puts File.extname(file)
+  code = SUFFIXMAP[File.extname(file)]
+  case code
+  when :hash
+    ['## ' + BLB] + txt.map {|l| '# ' + l} + ['## ' + ELB]
+  when :java
+    ['// ' + BLB, '/* '] + txt.map{|l| ' * ' + l} + [' */', '// ' + ELB, ]
+  when :doubleslash
+    ['/// ' + BLB] + txt.map {|l| '// ' + l} + ['/// ' + ELB]
+  else
+    LICENSE
+  end
+end
+
+# Remove the license block and return the found copyrights or
+# DEFAULT_COPYRIGHT
+def remove_license_block(code)
+  copyrights = []
+  if code[0] =~ Regexp.new(BLB)
+    code.shift
+    while not code.empty? and code[0] !~ Regexp.new(ELB)
+      if code[0] =~ /Copyright \(c\) (.+)/
+        copyrights << $1
+      end
+      code.shift
+    end
+    code.shift
+    code.shift
+  end
+  #return [DEFAULT_COPYRIGHT]
+  return copyrights.empty? ? [DEFAULT_COPYRIGHT] : copyrights
+end
+
+# Add a license to a file
+def add_license(file)
+  #puts "--- #{file}"
+  code = open(file).read
+  open(file + '~', 'w') {|f| f.print code}
+  code = code.split("\n")
+  copyrights = remove_license_block(code)
+  license_block = copyrights.map {|cr| 'Copyright (c) ' + cr} + LICENSE
+  license_block = comment_block(file,license_block)
+  code = license_block + [''] + code
+  open(file, 'w') {|f| f.puts code.join("\n")}
+end
+
+FILES = ['{src,test}/**/*.java',
+         'scripts/*.{c,h,java}', 
+         '{scripts,config}/**/*.rb',
+         'include/*.h', 'Makefile']
+#FILES = 'Makefile.lb'
+files = FILES.map {|p| Dir.glob(p)}.flatten
+
+files.each do |file| add_license file end
diff --git a/scripts/c-file.c b/scripts/c-file.c
new file mode 100644
index 0000000..de84b51
--- /dev/null
+++ b/scripts/c-file.c
@@ -0,0 +1,48 @@
+/// --- 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 ---
+
+/*
+ * Wrapper files for LAPACK
+ *
+ * 
+ * automatically generated by fortranwrapper
+ */
+
+#include "<%= filename %>.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+<% for r in routines %>
+<%= C.wrapper_for r -%>
+<% end%>
diff --git a/scripts/c-header.h b/scripts/c-header.h
new file mode 100644
index 0000000..9f7c3c7
--- /dev/null
+++ b/scripts/c-header.h
@@ -0,0 +1,51 @@
+/// --- 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 ---
+
+/*
+ * Wrapper files for FORTRAN
+ *
+ * automatically generated by fortranwrapper
+ */
+
+#ifndef <%= filename.upcase %>_H
+#define <%= filename.upcase %>_H
+
+typedef struct { float r; float i; } <%= C::COMPLEX_TYPE %>;
+typedef struct { double r; double i; } <%= C::DOUBLE_COMPLEX_TYPE %>;
+
+<% routines.each do |r| -%>
+extern <%= C.declaration_for r %>;
+<% end -%>
+
+#endif
diff --git a/scripts/class_to_float.rb b/scripts/class_to_float.rb
new file mode 100644
index 0000000..43ce5bd
--- /dev/null
+++ b/scripts/class_to_float.rb
@@ -0,0 +1,87 @@
+## --- 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 ---
+
+def readfile(fn)
+  f = open(fn)
+  s = f.read
+  f.close
+  s
+end
+
+def writefile(fn, s)
+  f = open(fn, 'w')
+  f.write s
+  f.close
+end
+
+def classfile(classname)
+  classname.tr('.', File::SEPARATOR) + '.java'
+end
+
+def translate(s)
+  s.gsub! /DoubleMatrix/, 'FloatMatrix'
+  s.gsub! /DoubleBuffer/, 'FloatBuffer'
+  s.gsub! /DoubleVector/, 'FloatVector'
+  s.gsub! /ComplexDouble/, 'ComplexFloat'
+  s.gsub! /([0-9]+\.[0-9]+)/, '\1f'
+  s.gsub! /double/, 'float'
+  s.gsub! /(\s)Blas\.dz/, '\1Blas.sc'
+  s.gsub! /(\s)Blas\.d/, '\1Blas.s'
+  s.gsub! /(\s)Blas\.z/, '\1Blas.c'
+  s.gsub! /nextDouble/, 'nextFloat'
+  s.gsub! /DoubleFunction/, 'FloatFunction'
+  s.gsub! /TestBlasDouble/, 'TestBlasFloat'
+  s.gsub! /Double\./, 'Float.'
+  s.gsub! /readDouble/, 'readFloat'
+  s
+end
+
+if ARGV.size < 2
+  puts "Usage: ruby class_to_float.rb srcprefix classname"
+  exit
+end
+
+prefix = ARGV[0]
+source = ARGV[1]
+target = source.gsub(/Double/, 'Float')
+
+sourcefn = File.join(prefix, classfile(source))
+targetfn = File.join(prefix, classfile(target))
+
+if File.exist? sourcefn
+  s = readfile(sourcefn)
+  writefile(targetfn, translate(s))
+else
+  puts "Could not read file #{sourcefn}"
+end
diff --git a/scripts/fortran.rb b/scripts/fortran.rb
new file mode 100644
index 0000000..eef9028
--- /dev/null
+++ b/scripts/fortran.rb
@@ -0,0 +1,348 @@
+## --- 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 ---
+
+# This module contains a minimum of parsing routines and data types to
+# be able to write automatic wrappers of blas and lapack routines
+module Fortran
+
+  # Fortran 70 types
+  # Source: http://www.nacs.uci.edu/dcslib/sun/compilers/fortran/f77rm/2_data.doc.html
+  Types = ['BYTE',
+           'CHARACTER',
+           'CHARACTER\*[0-9]+',
+           'CHARACTER\*\(\s*\*\s*\)',
+           'COMPLEX(?:\*(?:8|16))?',
+           'DOUBLE\ COMPLEX',
+           'DOUBLE\ PRECISION', 
+           'INTEGER(?:\*(?:2|4|8))?',
+           'LOGICAL(?:\*(?:1|2|4|8))?',
+           'REAL(?:\*(?:4|8))?']
+
+  # Mapping of some types to default names
+  DefaultTypes = { 
+    'BYTE' => 'LOGICAL*1',
+    'COMPLEX' => 'COMPLEX*8',
+    'DOUBLE COMPLEX' => 'COMPLEX*16',
+    'DOUBLE PRECISION' => 'REAL*8',
+    'INTEGER' => 'INTEGER*4',
+    'LOGICAL' => 'LOGICAL*4',
+    'REAL' => 'REAL*4' }
+            
+
+  # Return a regular expression which matches against all Fortran::Types.
+  def self.types_as_regexp
+    Fortran::Types.join('|')
+  end
+
+  # Return a Fortran subroutine object.
+  # +args+ is an array of the names of the arguments
+  def self.subroutine(name, args)
+    Routine.new FortranType.new('VOID'), name, args
+  end
+
+  # Return a Fortran function object.
+  def self.function(return_type, name, args)
+    Routine.new FortranType.new(return_type), name, args
+  end
+
+  # Concatenate all continuated lines. These are lines where there is a 
+  # mark ('$' or 'C') in the 5th column. For example:
+  #
+  #  1234567890
+  #       SUBROUTINE DGEEVX( BALANC, JOBVL, JOBVR, SENSE, N, A, LDA, WR, WI,
+  #      $                   VL, LDVL, VR, LDVR, ILO, IHI, SCALE, ABNRM,
+  #      $                   RCONDE, RCONDV, WORK, LWORK, IWORK, INFO )
+  #
+  # Returns an array of the resulting lines.
+  def self.parse_continuations(lines)
+    m = []
+    lines.each do |l|
+      l.chomp!
+      if l =~ /^     [$C]\ *( .+)/ then 
+        m[-1] << $1
+      else 
+        m << l
+      end
+    end
+    m
+  end
+
+  # Map fortran types to a unique name (via DefaultTypes).
+  def self.standardize_type(name)
+    name.strip!
+    DefaultTypes.fetch name, name
+  end
+
+
+  # Represents a FORTRAN data type
+  class FortranType
+    attr_accessor :basetype, :array, :comment
+
+    # Construct new FortranType. Set array and comment later if you want to.
+    def initialize(type, array=false, comment=nil)
+      @basetype = Fortran.standardize_type type
+      @array = array
+      @comment = comment
+    end
+
+    def to_s # :nodoc:
+      s = @basetype.clone
+      s << ' (array)' if @array
+      s << ' # ' + @comment if comment
+      s
+    end
+  end
+
+  # This class describes a fortran subroutine or function. It
+  # mainly collects all the information about the arguments and
+  # their types.
+  #
+  # You can use Fortran.subroutine and Fortran.function to 
+  # construct the respective type.
+  class Routine
+    # name of the routine
+    attr_reader :name
+    # argument names of the routines (as array)
+    attr_reader :args
+    # hash mapping argument names to FortranType objects
+    attr_reader :argtype
+    # return type as FortranType object or nil
+    attr_reader :return_type
+
+    # Construct a new Routine object. If return_type is nil, it is a subroutine.
+    def initialize(return_type, name, args)
+      @return_type = return_type
+      @name = name
+      @args = args
+      @argtype = Hash.new
+    end
+    
+    # Check whether all arguments have at least types.
+    def have_all_types?
+      @args.each do |a|
+        unless @argtype.has_key? a
+          return false
+        end
+      end
+      true
+    end
+
+    def each_arg
+      args.each do |name|
+        type = argtype[name]
+        yield name, type
+      end
+    end
+
+    def to_s # :nodoc:
+      s = [ (@return_type ? "#@return_type function " : "subroutine ") + @name + "\n"]
+      @args.each do |arg|
+        s << "   #{arg} of type #{@argtype[arg]}\n"
+      end
+      unless workspace_arguments.empty?
+        s << "Workspace Arguments: " + workspace_arguments.join(', ')
+      end
+      s.join
+    end
+
+    def number_of_scalar_output_arguments
+      count = 0
+      each_arg do |name, type|
+        if type.comment =~ /output/ and not type.array
+          count += 1
+        end
+      end
+      count
+    end
+
+    # Generate some code for each argument and collect the results
+    def gen_each_arg(joinwith="\n")
+      s = []
+      args.each do |name|
+        t = yield name, argtype[name]
+        s << t unless t.nil?
+      end
+      return s.join(joinwith)
+    end
+
+    def workspace_arguments
+      results = []
+      args.each_with_index do |a, i|
+        results << a if workspace_argument? a
+      end
+      return results
+    end
+
+    def workspace_argument?(name)
+      i = args.index(name)
+      name =~ /WORK\Z/ and i < @args.size - 1 and args[i+1] == 'L' + name
+    end
+
+    def workspace_size_argument?(name)
+      i = args.index(name)
+      name =~ /\AL[A-Z]*WORK\Z/ and i > 0 and args[i-1] == name[1..-1]
+    end
+  end
+
+  # In order to pass additional information to the template code,
+  # subclass Template Context and put the information into instance
+  # variables. These will then be accessible from the template.
+  class TemplateContext
+
+    # Generate output from a template file.
+    # This function also uses the new-line suppressing extension as
+    # in rails. Put a minus after or before the '%' to suppress the 
+    # previous or following newline.
+    #
+    #    <%= some expression %>\nblahblah  <- newline is output
+    #    <%= some expression -%>\nblahblah <- newline is removed
+    def generate(template_file)
+      f = open(template_file)
+      template = f.read
+      f.close
+
+      # Add the littel newline suppression hack as in rails.
+      # Minus in front of closing or after opening '%' suppresses newlines.
+      template.gsub! /-%>\n/, '%>'
+      template.gsub! /\n<%-/, '<%'
+      
+      ERB.new(template).result(binding)
+    end
+  end
+
+  #
+  # Regular expressions used below.
+  #
+  # Stored here for better performance
+  #
+  
+  # Matches e.g. SUBROUTINE DAXPY(N,DA,DX,INCX,DY, INCY)
+  SubroutineDecl = 
+    Regexp.compile /SUBROUTINE ([A-Z0-9]+)\(\ *([A-Z0-9, ]+)\ *\)/
+  
+  # Matches e.g. DOUBLE PRECISION FUNCTION DDOT(N,DX,INCX,DY,INCY)
+  FunctionDecl = 
+    Regexp.compile /\ +([A-Z ]+) FUNCTION ([A-Z0-9]+)\(\ *([A-Z0-9, ]+)\ *\)/ 
+  
+  # Matches e.g. INTEGER INCX,INCY,N
+  VariableDecl = 
+    Regexp.compile /\ +(#{Fortran.types_as_regexp})\ +([A-Z,()*0-9 ]+)/
+    
+  # Matches e.g. *  LDA     (input) INTEGER
+  MetaComment = 
+    Regexp.compile /\A\*\s*([A-Z0-9,]+)\s+\(([a-zA-Z\/]*)\)/
+  
+  # Matches e.g. A, but also DX(*)
+  ArgumentParens = 
+    Regexp.compile /[A-Z0-9]+(?: *\([A-Z, 0-9*]+\))?/
+  
+
+  # Parse a FORTRAN file, return a Routine object describing the
+  # defined object.
+  #
+  # This function is really tailored towards the blas and lapack
+  # files, although it can in principle parse all FORTRAN types. In
+  # addition, it parses comments to look for metadata, in particular
+  # whether a variable is used as input or output. Lines like
+  #
+  #
+  #    *  JOBVL   (input) CHARACTER*1
+  #
+  # are parsed and the information in parenthesis is extracted.
+  def self.parse_file(f)
+    routine = nil
+    lines = f.readlines
+    lines = Fortran.parse_continuations(lines)
+
+    lines.each do |l|
+      #puts l
+      case l
+        #
+        # parse headings, e.g.
+        #  
+        #     DOUBLE PRECISION FUNCTION DDOT(N,DX,INCX,DY,INCY)
+        #     SUBROUTINE DAXPY(N,DA,DX,INCX,DY,INCY)
+        #
+      when SubroutineDecl 
+        name = $1
+        args = $2.scan /[A-Z0-9]+/
+        routine = Fortran.subroutine name, args
+      when FunctionDecl
+        return_type = $1
+        name = $2
+        args = $3.scan /[A-Z0-9]+/
+        routine = Fortran.function return_type, name, args
+        #
+        # parse argument types, e.g.
+        #
+        #      DOUBLE PRECISION DX(*),DY(*)
+        #      COMPLEX*16       A( LDA, * ), VL( LDVL, * ), VR( L...
+        #
+      when VariableDecl
+          puts "#$1 -> #$2" if $debug
+        type = $1
+        args = $2.scan ArgumentParens 
+        args.each do |argname| 
+          puts "  #{argname} -> #{type}" if $debug
+          if argname =~ /([A-Z0-9]+)\ *\(.*\)/
+            argname = $1
+            array = true
+          else
+            array = false
+          end
+          if routine.args.member? argname
+            routine.argtype[argname] = Fortran::FortranType.new(type, array)
+          end
+        end
+        # 
+        # parse comments which with respect to input/output, e.g.
+        #
+        # *  JOBVL   (input) CHARACTER*1
+        #
+      when MetaComment
+        args = $1; comment = $2
+        #puts "#{args} -> #{comment}"
+        args.split(',').each do |argname|
+          at = routine.argtype[argname]
+          if at
+            at.comment = comment
+          else
+            puts "Warning: cannot add comment to variable #{argname} in file #{f.path} line \"#{l}\" (argument not defined)"
+          end
+        end
+      end
+    end
+    return routine
+  end
+end
diff --git a/scripts/fortran/c.rb b/scripts/fortran/c.rb
new file mode 100644
index 0000000..35a952b
--- /dev/null
+++ b/scripts/fortran/c.rb
@@ -0,0 +1,175 @@
+## --- 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 ---
+
+module Fortran
+  module C
+    COMPLEX_TYPE = 'fortran_complext_t'
+    DOUBLE_COMPLEX_TYPE = 'fortran_double_complex_t'
+
+    class Generator < TemplateContext
+      attr_reader :filename, :routines
+
+      def initialize(filename, routines)
+        @filename = filename
+        @routines = routines
+      end
+    end
+
+    def self.generate(template_file, filename, routines)
+      g = Generator.new(filename, routines)
+      g.generate(template_file)
+    end
+
+    def self.reference?(r, argname)
+      argtype = r.argtype[argname]
+      argtype and (argtype.array or argtype.comment =~ /output/)
+    end
+    
+    # Generate declaration for wrapper in C.
+    def self.declaration_for r
+      name = r.name.downcase
+      args = []
+
+      if not r.rettype
+        rettype = 'void'
+      elsif r.rettype.basetype == 'COMPLEX*8'
+        rettype = 'void'
+        args << COMPLEX_TYPE + '* retval'
+      elsif r.rettype.basetype == 'COMPLEX*16'
+        rettype = 'void'
+        args << DOUBLE_COMPLEX_TYPE + '* retval'
+      else
+        rettype = C.map_basetype(r.rettype)
+      end
+
+      r.args.each do |argname|
+        argtype = r.argtype[argname]
+        cargname = argname.downcase
+        ctype = C.map_basetype(argtype)
+        ctype << '*' if reference?(r, argname)
+        args << ctype + ' ' + cargname
+      end
+
+      "#{rettype} #{name}(#{args.join ', '})"
+    end
+     
+    def self.fortran_declaration_for r
+      name = r.name.downcase + '_'
+      args = []
+
+      if not r.rettype
+        rettype = 'void'
+      elsif r.rettype.basetype == 'COMPLEX*8'
+        rettype = 'void'
+        args << COMPLEX_TYPE + '* retval'
+      elsif r.rettype.basetype == 'COMPLEX*16'
+        rettype = 'void'
+        args << DOUBLE_COMPLEX_TYPE + '* retval';
+      else
+        rettype = C.map_basetype(r.rettype)
+      end
+      
+      r.args.each do |argname|
+        argtype = r.argtype[argname]
+        argname = argname.downcase
+        ctype = C.map_basetype(argtype) + '*';
+        args << ctype + ' ' + argname
+      end
+    
+      "#{rettype} #{name}(#{args.join ', '})"      
+    end
+
+    def self.call_fortran_routine r
+      name = r.name.downcase + '_'
+
+      args = []
+
+      if not r.rettype
+        retstmt = ''
+      elsif r.rettype.basetype == 'COMPLEX*8'
+        retstmt = ''
+        args << 'retval'
+      elsif r.rettype.basetype == 'COMPLEX*16'
+        retstmt = ''
+        args << 'retval'
+      else
+        retstmt = 'return '
+      end
+      
+      r.args.each do |argname|
+        if reference?(r, argname)
+          args << argname.downcase
+        else
+          args << '&' + argname.downcase
+        end
+      end
+    
+      "#{retstmt}#{name}(#{args.join ', '})"      
+    end
+
+    # Generate the actual wrapper.
+    def self.wrapper_for r
+      return <<EOS
+#{declaration_for r}
+{
+  extern #{fortran_declaration_for r};
+  #{call_fortran_routine r};
+}
+EOS
+    end
+
+    def self.map_basetype(type)
+      return 'void' unless type
+      t = ''
+      case type.basetype
+      when 'CHARACTER' then t << 'char'
+      when 'CHARACTER*1' then t << 'char'
+      when /CHARACTER\*[0-9]+/ then t << 'char*'
+      when 'REAL*4' then t << 'float'
+      when 'REAL*8' then t << 'double'
+      when 'INTEGER*2' then t << 'short'
+      when 'INTEGER*4' then t << 'int'
+      when 'INTEGER*8' then t << 'long'
+      when 'LOGICAL*1' then t << 'byte'
+      when 'LOGICAL*2' then t << 'short'
+      when 'LOGICAL*4' then t << 'int'
+      when 'LOGICAL*8' then t << 'long'
+      when 'COMPLEX*8' then t << COMPLEX_TYPE
+      when 'COMPLEX*16' then t << DOUBLE_COMPLEX_TYPE
+      else
+        raise ArgumentError, "Don't know how to convert '#{type}'"
+      end
+    end
+  end
+end
diff --git a/scripts/fortran/java.rb b/scripts/fortran/java.rb
new file mode 100644
index 0000000..184b2ea
--- /dev/null
+++ b/scripts/fortran/java.rb
@@ -0,0 +1,586 @@
+## --- 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 ---
+
+module Fortran
+
+  class FortranType
+    # extend FortranType by converters to java and C
+    ArrayTypeMap = { 'REAL*4' => 'float[]',
+      'REAL*8' => 'double[]',
+      'INTEGER*2' => 'short[]',
+      'INTEGER*4' => 'int[]',
+      'INTEGER*8' => 'long[]',
+      'LOGICAL*1' => 'byte[]',
+      'LOGICAL*2' => 'short[]',
+      'LOGICAL*4' => 'int[]',
+      'LOGICAL*8' => 'long[]',
+      'COMPLEX*8' => 'float[]',
+      'COMPLEX*16' => 'double[]',
+      'VOID' => 'void'
+    }
+    
+    StdTypeMap = { 'CHARACTER' => 'char',
+      'CHARACTER*1' => 'char',
+      'CHARACTER*N' => 'String',
+      'REAL*4' => 'float',
+      'REAL*8' => 'double',
+      'INTEGER*2' => 'short',
+      'INTEGER*4' => 'int',
+      'INTEGER*8' => 'long',
+      'LOGICAL*1' => 'byte',
+      'LOGICAL*2' => 'short',
+      'LOGICAL*4' => 'int',
+      'LOGICAL*8' => 'long',
+      'COMPLEX*8' => 'ComplexFloat',
+      'COMPLEX*16' => 'ComplexDouble',
+      'VOID' => 'void'
+    }
+    
+    # Map a Fortran type to Java type or throw an ArgumentError
+    def to_java
+      if basetype =~ /CHARACTER\*[0-9]+/
+        self.basetype = 'CHARACTER*N'
+      end
+      
+      result = if array or comment =~ /output/
+                 ArrayTypeMap[basetype]
+               else
+                 StdTypeMap[basetype]
+               end
+
+      if not result
+        raise ArgumentError, "Don't know how to convert '#{to_s}'"
+      end
+      
+      return result
+    end
+    
+    def to_c
+      javatype = to_java
+      if javatype =~ /\[\]$/
+        'j' + javatype[0...-2] + 'Array'
+      elsif javatype == 'void'
+        'void'
+      elsif javatype =~ /Complex/
+        'jobject'
+      else
+        'j' + javatype.downcase
+      end
+    end
+  end
+
+  # This module contains code for generating Java native declarations
+  # for Fortran routines.
+  module Java
+
+    # Generate
+    def self.generate(template_file, package, class_name, routines)
+      g = Generator.new(package, class_name, routines)
+      g.generate(template_file)
+    end
+
+    ######################################################################
+
+    # A special TemplateContext for Java. In addition, the package
+    # name and classname is stored.
+    #
+    # Usually, you would use the generate method instead of explicitly
+    # constructing an object
+    class Generator < TemplateContext
+      attr_reader :package, :classname, :routines
+
+      # Create a new Generator context. You can use generate
+      # to directly construct and write a template file
+      def initialize(package, classname, routines)
+        @package = package
+        @classname = classname
+        @routines = routines
+      end
+
+      def generate_native_declaration(r)
+        writer = WrapperCodeGenerator.new(header_file_name, r)
+        writer.native_declaration
+      end
+
+      def generate_wrapper(r)
+        writer = WrapperCodeGenerator.new(header_file_name, r)
+        writer.wrapper
+      end
+
+      def header_file_name
+        package.tr('.', '_') + '_' + classname
+      end
+    end
+    
+    ######################################################################
+
+    # Generator of wrapper code for one routine, both for Java
+    # (native_declaration) and C (wrapper)
+    class WrapperCodeGenerator
+      attr_reader   :prefix
+      attr_accessor :return_type, :fct_name, :decl_args
+      attr_accessor :fortran_args, :fortran_return_type
+      attr_accessor :conversions
+      attr_accessor :call_pre, :call_post, :fortran_fct_name, :call_args
+      attr_accessor :arrays
+      
+      def initialize(prefix, r)
+        @package = prefix
+        @routine = r
+        @return_type = ''
+        @fct_name = prefix + '_' + r.name.downcase
+        @decl_args = ''
+        @conversions = ''
+        @fortran_args = []
+        @fortran_return_type = ''
+        @call_pre = ''
+        @fortran_fct_name = ''
+        @call_args = []
+        @call_post = ''
+        @arrays = [] # already seen arrays
+      end
+      
+  public
+      # Generate the JNI-wrapper code for the fortran routine.
+      # This is a bit more complex and calls other routines for the different
+      # parts.
+      def wrapper
+        make_fortran_fct_name r.name
+
+        code_for_return_type(r.return_type)
+
+        r.each_arg do |name, type| 
+          code_for_argument(name, type)
+        end
+
+        return <<EOS
+JNIEXPORT #{return_type} JNICALL Java_#{fct_name}(JNIEnv *env, jclass this#{decl_args})
+{
+  extern #{fortran_return_type} #{fortran_fct_name}(#{fortran_args.join(', ')});
+  
+#{conversions}
+  savedEnv = env;
+  #{call_pre}#{fortran_fct_name}(#{call_args.join(', ')});
+#{call_post}
+}
+EOS
+      end
+      
+      # Generate the native function declaration within a Java class.
+      # Everything you need is HERE!
+      def native_declaration
+        begin
+          return_type = ''
+          fct_name = r.name.downcase
+          args = []
+
+          return_type = java_return_type
+          
+          r.args.each do |name|
+            type = r.argtype[name]
+            if name != 'INFO'
+              args << type.to_java + " " + name.downcase
+              if type.to_java =~ /\[\]/
+                args << "int #{name.downcase}Idx"
+              end
+            end
+          end
+          result = "  public static native #{return_type} #{fct_name}(#{args.join(", ")});"
+          unless r.workspace_arguments.empty?
+            result += "\n" + with_workspace_query
+          end
+          return result
+        rescue
+          puts
+          puts "---Error for routine #{@routine}"
+          puts
+          raise
+        end
+      end
+
+      # Generate Java function with an automatic workspace query.
+      def with_workspace_query
+        args = []
+        r.each_arg do |n, t|
+          unless r.workspace_argument? n or r.workspace_size_argument? n or n == 'INFO'
+            args << t.to_java + " " + n.downcase
+            if t.to_java =~ /\[\]/
+              args << "int #{n.downcase}Idx"
+            end
+          end
+        end
+        return <<EOS
+  public static #{java_return_type} #{r.name.downcase}(#{args.join(", ")}) {
+    int info;
+#{declare_workspace_arrays}
+    info = #{workspace_query};
+    if (info != 0)
+      return info;
+#{allocate_workspaces}
+    info = #{call_with_workspaces};
+    return info;
+  }
+EOS
+      end
+
+  private ############################################################
+
+      # convenience accessor
+      def r; @routine; end
+
+      def java_return_type
+          if r.return_type.basetype == 'VOID' and r.args.last == 'INFO'
+            'int'
+          else
+            r.return_type.to_java
+          end        
+      end
+
+      def make_fortran_fct_name name
+        fortran_fct_name << name.downcase + '_'
+      end
+
+      def code_for_return_type type
+        javatype = type.to_java
+        ctype = type.to_c
+
+        gen = generator(type)
+        gen.set_type(type, javatype, ctype)
+
+        gen.make_return_type
+        gen.make_fortran_return_type
+        gen.make_convert_return_type
+        gen.make_call_return
+      end
+
+      def code_for_argument(name, type)
+        javatype = type.to_java
+        ctype = type.to_c
+        name = name.downcase
+
+        gen = generator(type, name)
+        gen.set_type(type, javatype, ctype)
+        gen.set_name(name)
+
+        gen.make_decl_arg
+        gen.make_fortran_arg
+        gen.make_convert_arg
+        gen.make_call_arg
+      end
+
+      # find the correct code generator for the given type
+      def generator(type, name=nil)       
+        javatype = type.to_java
+        #puts javatype
+        #puts name
+        #puts @routine.return_type.basetype
+        g = if javatype == 'void'
+          Java::NilArgument.new(self)
+        elsif javatype == 'int[]' and name == 'info' and @routine.return_type.basetype == 'VOID'
+          Java::InfoArgument.new(self)
+        elsif javatype =~ /\[\]/
+          Java::BufferArgument.new(self)
+        elsif javatype =~ /Complex/
+          Java::ComplexArgument.new(self)
+        elsif javatype == 'char'
+          Java::CharArgument.new(self)
+        else
+          Java::GenericArgument.new(self)
+        end
+        #puts "seleced generator #{g.class}"
+        return g
+      end
+
+      #
+      # Stuff for workspaces below
+      #
+
+      # Declarations for workspace arrays
+      def declare_workspace_arrays
+        r.gen_each_arg do |n, t|
+          if r.workspace_argument? n
+            "    #{t.to_java} #{n.downcase} = new #{t.to_java[0..-3]}[1];"
+          elsif r.workspace_size_argument? n
+            "    #{t.to_java} #{n.downcase};"
+          end
+        end
+      end
+
+      # Generate a call with the workspace queries
+      def workspace_query
+        return "#{r.name.downcase}(" +
+          r.gen_each_arg(', ') do |n,t|
+            if r.workspace_size_argument? n
+              '-1'
+            elsif n != 'INFO'
+              if t.to_java =~ /\[\]\Z/
+                if r.workspace_argument? n
+                  "#{n.downcase}, 0"
+                else
+                  "#{n.downcase}, #{n.downcase}Idx"
+                end
+              else
+                n.downcase
+              end
+            end
+          end + ")"
+      end
+
+      # allocate the actual workspaces
+      def allocate_workspaces
+        r.gen_each_arg do |n, t|
+          if r.workspace_argument? n
+            n = n.downcase
+            "    l#{n} = (int) #{n}[0]; #{n} = new #{t.to_java[0..-3]}[l#{n}];"
+          end
+        end
+      end
+
+      # call with the allocated workspaces
+      def call_with_workspaces
+        return "#{r.name.downcase}(" +
+          r.gen_each_arg(', ') do |n,t|
+            if n != 'INFO'
+              if t.to_java =~ /\[\]\Z/
+                if r.workspace_argument? n
+                  "#{n.downcase}, 0"
+                else
+                  "#{n.downcase}, #{n.downcase}Idx"
+                end
+              else
+                n.downcase
+              end
+            end
+          end + ")"
+      end
+    end
+
+    ######################################################################
+    #
+    # Actual code generators
+    #
+    
+    # The default case: Just convert types to their java and C
+    # equivalents, pass the reference to the fortran routine and 
+    # return the result 
+    class GenericArgument
+      attr_reader :code, :type, :javatype, :ctype, :name
+
+      def initialize(code)
+        @code = code
+      end
+
+      def set_type(type, javatype, ctype)
+        @type = type
+        @javatype = javatype
+        @ctype = ctype
+      end
+
+      def set_name(name)
+        @name = name
+      end
+
+      def make_fortran_return_type
+        if ctype == 'jfloat'
+          code.fortran_return_type << 'jdouble'
+        else
+          code.fortran_return_type << ctype
+        end
+      end
+
+      def make_return_type
+        code.return_type << ctype
+      end
+
+      def make_convert_return_type
+      end
+
+      def make_call_return
+        code.call_pre << ctype + " retval = "
+        if ctype == 'jfloat'
+          code.call_post << "\n  return (jdouble) retval;"
+        else
+          code.call_post << "\n  return retval;"
+        end
+      end
+
+      def make_decl_arg
+        code.decl_args << ", " + ctype + " " + name
+      end
+
+      def make_fortran_arg
+        code.fortran_args << "j" + javatype + " *"
+      end
+      
+      def make_convert_arg
+      end
+      
+      def make_call_arg
+        code.call_args << "&#{name}"
+      end
+    end
+
+    # For arrays: Add an additional argument to the declaration,
+    # and get the array from the direct buffer
+    class BufferArgument < GenericArgument
+      def make_decl_arg
+        super
+        code.decl_args << ", jint " + name + "Idx"
+      end
+
+      def make_fortran_arg
+        code.fortran_args << "j" + ctype[1...-5] + " *"
+      end
+      
+      # Okay, my apologies for this method. What makes it so difficult
+      # is that it can happen that you pass in an array twice. If you
+      # then call Get<Type>ArrayElements twice you get two copies
+      # and any attempt to do something truly inplace won't work (for
+      # example dswap). So I have to check before each array if 
+      # I maybe already have it. And the same thing around in the end... .
+      def make_convert_arg
+        basectype = ctype[0...-5]
+        code.conversions << <<EOS + '    '
+  #{basectype} *#{name}PtrBase = 0, *#{name}Ptr = 0;
+  if (#{name}) {
+EOS
+        unless code.arrays.empty?
+          code.arrays.each do |a, t|
+            if t == basectype
+              code.conversions << "if((*env)->IsSameObject(env, #{name}, #{a}) == JNI_TRUE)\n      #{name}PtrBase = #{a}PtrBase;\n    else\n      "
+            end
+          end
+        end
+        code.conversions << <<EOS
+#{name}PtrBase = (*env)->Get#{basectype[1..-1].capitalize}ArrayElements(env, #{name}, NULL);
+    #{name}Ptr = #{name}PtrBase + #{'2*' if type.basetype =~ /COMPLEX/}#{name}Idx;
+  }
+EOS
+        
+        # and releasing the stuff again...
+        release = "  if(#{name}PtrBase"
+        code.arrays.each do |a, t| 
+          if t == basectype
+            release << " && #{name}PtrBase != #{a}PtrBase"
+          end
+        end
+        release << ") {" + <<EOS
+        
+    (*env)->Release#{basectype[1..-1].capitalize}ArrayElements(env, #{name}, #{name}PtrBase, 0);
+  }
+EOS
+        code.call_post = release + code.call_post
+        
+        # store information about the arrays we have already handled
+        code.arrays << [name, basectype]
+      end
+
+      def make_call_arg
+        code.call_args << "#{name}Ptr"
+      end
+    end
+
+    # For complex values (scalars only!): fortran returns the value in the
+    # first argument, therefore declare the return value, modify the 
+    # fortran argument list, and generate the *Complex object.
+    #
+    # for arguments, extract the values from the Java object
+    class ComplexArgument < GenericArgument
+      def make_fortran_return_type
+        code.fortran_args << javatype + " *"
+        code.fortran_return_type << "void"
+      end
+
+      def make_fortran_arg
+        code.fortran_args << javatype + " *"
+      end
+
+      def make_convert_return_type
+        code.conversions << "  #{javatype} retval;\n"
+      end
+
+      def make_call_return
+        code.call_post << "\n  return create#{javatype}(env, &retval);"
+        code.call_args << "&retval"
+      end
+
+      def make_convert_arg
+        code.conversions << "  #{javatype} #{name}Cplx;\n"
+        code.conversions << "  get#{javatype}(env, #{name}, &#{name}Cplx);\n"
+      end
+
+      def make_call_arg
+        code.call_args << "&#{name}Cplx"
+      end
+    end
+    
+    # For characters: This handles only the first byte. Now idea if it
+    # is really worth dealing with UTF-8 and all the rest...
+    class CharArgument < GenericArgument
+      def make_convert_arg
+        code.conversions << "  char #{name}Chr = (char) #{name};\n"
+      end
+
+      def make_call_arg
+        code.call_args << "&#{name}Chr"
+      end
+
+      def make_fortran_arg
+        code.fortran_args << javatype + " *"
+      end
+    end
+    
+    # For nil arguments (only return value): don't add a return value
+    class NilArgument < GenericArgument
+      def make_call_return
+      end
+    end
+
+    # For info arguments
+    class InfoArgument < GenericArgument
+      def make_decl_arg
+        code.return_type = 'jint'
+      end
+
+      def make_convert_arg
+        code.conversions << "  int info;\n"
+        code.call_post << "\n  return info;"
+      end
+
+      def make_fortran_arg
+        code.fortran_args << ctype[1...-5] + " *"
+      end
+    end
+  end # module Java
+end # module Fortran
diff --git a/scripts/fortranwrapper.rb b/scripts/fortranwrapper.rb
new file mode 100644
index 0000000..f616683
--- /dev/null
+++ b/scripts/fortranwrapper.rb
@@ -0,0 +1,134 @@
+## --- 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 ---
+
+#!/usr/bin/env ruby
+# -*- ruby -*-
+
+# get directory where script resides and add to load path
+Dir.chdir(File.dirname(__FILE__)) { $SCRIPT_DIR = Dir.pwd }
+$LOAD_PATH << $SCRIPT_DIR
+
+#throw "ARGH"
+
+require 'erb'
+require 'optparse'
+
+require 'fortran'
+require 'fortran/java'
+require 'fortran/c'
+
+Banner = <<EOS
+A wrapper of fortran functions for JNI
+written by Mikio L. Braun, mikiobraun at gmail.com
+
+Usage: #{__FILE__} [options] package class file1.f file2.f ...
+EOS
+
+FORTRANWRAPPER_DUMP = 'fortranwrapper.dump'
+
+$here = false
+$force = false
+OptionParser.new do |opts|
+  opts.banner = Banner
+  
+  opts.on("-h", "--here", "output files here") {|v| $here = true}
+  opts.on("-f", "--force", "force parsing of fortran file") {|v| $force = true}
+end.parse!
+
+if ARGV.size < 3
+  puts Banner
+  exit
+end
+
+package = ARGV[0]
+klass = ARGV[1]
+
+$debug = false
+
+number_of_routines = 0
+routines = []
+
+if !$force and File.exist?(FORTRANWRAPPER_DUMP)
+  routines = File.open(FORTRANWRAPPER_DUMP) {|f| Marshal.load(f)}
+  puts "Using dumped routines..."
+else
+  # The main loop.
+  # For all files, read the file and loop over all lines.
+  ARGV[2..-1].each do |fn|
+    next if fn =~ /xerbla/ or fn =~ /scabs1/ or fn =~ /dsdot/
+    open(fn) do |f|
+      begin
+        routine = Fortran.parse_file f
+      rescue
+        puts "Error while parsing file #{fn}:"
+        raise
+      end
+      # check whether all arguments have a type associated
+      if not routine.have_all_types?
+        puts routine
+        raise "couldn't parse all types!"
+      end
+      
+      number_of_routines += 1
+      routines << routine
+    end
+  end
+end
+
+File.open(FORTRANWRAPPER_DUMP, "w") {|f| Marshal.dump(routines, f)}
+
+#puts "Parsed #{number_of_routines} routines"
+def generate(template_file, package, klass, routines)
+  template_file = File.join($SCRIPT_DIR, template_file)
+  Fortran::Java.generate(template_file, package, klass, routines)
+end
+
+def full_file_path(prefix, package, klass)
+  p = [prefix] + package.split('.') + [ klass ]
+  File.join(p)
+end
+
+java_class = generate('java-class.java', package, klass, routines)
+java_impl = generate('java-impl.c', package, klass, routines)
+
+if $here
+  java_filename = klass + '.java'
+  wrapper_filename = klass + '.c'
+else
+  java_filename = full_file_path('src', package, klass) + '.java'
+  wrapper_filename = File.join('native', klass) + '.c'
+end
+
+File.open(java_filename, 'w') {|o| o.write java_class}
+File.open(wrapper_filename, 'w') {|o| o.write java_impl}
diff --git a/scripts/java-class.java b/scripts/java-class.java
new file mode 100644
index 0000000..7618390
--- /dev/null
+++ b/scripts/java-class.java
@@ -0,0 +1,60 @@
+// --- 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 <%= package %>;
+
+import org.jblas.core.ComplexFloat;
+import org.jblas.core.ComplexDouble;
+
+public class <%= classname %> {
+
+  static {
+	  try {
+		  System.loadLibrary("j<%= classname.downcase %>");
+	  }
+	  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("j<%= classname.downcase %>");
+	  }
+  } 
+
+<% for r in routines -%>
+<%= generate_native_declaration r %>
+<% end %>
+}
diff --git a/scripts/java-impl.c b/scripts/java-impl.c
new file mode 100644
index 0000000..071f21c
--- /dev/null
+++ b/scripts/java-impl.c
@@ -0,0 +1,161 @@
+/// --- 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 ---
+
+#include "<%= header_file_name %>.h"
+
+#define CORE_PACKAGE "org/jblas/core/"
+
+/*
+ * For convenience, we define some typedefs here which have the
+ * same name as certain Java types, but their implementation differs (of course)
+ */
+typedef struct { float real, imag; } ComplexFloat;
+typedef struct { double real, imag; } ComplexDouble;
+typedef char *String;
+
+typedef char ByteBuffer;
+typedef short ShortBuffer;
+typedef int IntBuffer;
+typedef long LongBuffer;
+typedef float FloatBuffer;
+typedef double DoubleBuffer;
+
+/* a function to create new objects */
+static jobject createObject(JNIEnv *env, const char *className, const char *signature, ...)
+{
+  va_list args;
+  jclass klass = (*env)->FindClass(env, className);
+  jmethodID init = (*env)->GetMethodID(env, klass, "<init>", signature);
+  jobject newObject;
+
+  va_start(args, signature);
+  newObject = (*env)->NewObjectV(env, klass, init, args);
+  va_end(args);
+}
+
+static jobject createComplexFloat(JNIEnv *env, ComplexFloat *fc)
+{
+  return createObject(env, CORE_PACKAGE "ComplexFloat", "(FF)V", fc->real, fc->imag);
+}
+
+static jobject createComplexDouble(JNIEnv *env, ComplexDouble *dc)
+{
+  return createObject(env, CORE_PACKAGE "ComplexDouble", "(DD)V", dc->real, dc->imag);
+}
+
+static void getComplexFloat(JNIEnv *env, jobject fc, ComplexFloat *result)
+{
+  jclass klass = (*env)->FindClass(env, CORE_PACKAGE "ComplexFloat");
+  jfieldID reField = (*env)->GetFieldID(env, klass, "r", "F");
+  jfieldID imField = (*env)->GetFieldID(env, klass, "i", "F");
+
+  result->real = (*env)->GetFloatField(env, fc, reField);
+  result->imag = (*env)->GetFloatField(env, fc, imField);
+}
+
+static void getComplexDouble(JNIEnv *env, jobject dc, ComplexDouble *result)
+{
+  jclass klass = (*env)->FindClass(env, CORE_PACKAGE "ComplexDouble");
+  jfieldID reField = (*env)->GetFieldID(env, klass, "r", "D");
+  jfieldID imField = (*env)->GetFieldID(env, klass, "i", "D");
+
+  result->real = (*env)->GetDoubleField(env, dc, reField);
+  result->imag = (*env)->GetDoubleField(env, dc, imField);
+}
+
+static void throwIllegalArgumentException(JNIEnv *env, const char *message)
+{
+  jclass klass = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
+
+  (*env)->ThrowNew(env, klass, message);
+}
+
+/**********************************************************************/
+/*                 XERBLA function arguments                          */
+/**********************************************************************/
+
+static char *routine_names[] = {
+<% for r in routines.sort {|r1, r2| r1.name <=> r2.name} %> "<%= r.name %>", <% end -%>
+	0
+};
+
+static char *routine_arguments[][<%= (routines.map do |r| r.args.length end).max %>] = {
+<% for r in routines.sort {|r1, r2| r1.name <=> r2.name} -%>
+   { <%= (r.args.map do |s| '"' + s + '"' end).join(', ') %> }, 
+<% end -%>
+};
+
+/**********************************************************************/
+/*                 Our implementation of XERBLA                       */
+/**********************************************************************/
+static JNIEnv *savedEnv = 0;
+
+
+void xerbla_(char *fct, int *info)
+{
+	static char name[7];
+	static char buffer[256];
+	int i;
+	char **p;
+	char **arguments = 0;
+	
+	for (i = 0; i < 6; i++) {
+		if (fct[i] == ' ')
+			break;	
+		name[i] = fct[i];
+	}
+	name[i] = '\0';
+	
+	//fprintf(stderr, "Searching for function \"%s\"\n", name);
+	
+	for (p = routine_names, i = 0; *p; p++, i++)
+		if (!strcmp(*p, name))
+			arguments = routine_arguments[i];
+			
+	if (!arguments) {
+		sprintf(buffer, "XERBLA: Error on argument %d for *unknown function* %s (how odd!)\n", *info, name);
+	}
+	else {
+		sprintf(buffer, "XERBLA: Error on argument %d (%s) in %s", *info, arguments[*info-1], name);
+	}
+	throwIllegalArgumentException(savedEnv, buffer);
+}
+
+/**********************************************************************/
+/*                 generated functions below                          */
+/**********************************************************************/
+
+<% for r in routines %>
+<%= generate_wrapper r -%>
+<% end %>
diff --git a/scripts/render-textile.rb b/scripts/render-textile.rb
new file mode 100644
index 0000000..128e766
--- /dev/null
+++ b/scripts/render-textile.rb
@@ -0,0 +1,45 @@
+require 'set'
+
+require 'rubygems'
+require 'redcloth'
+
+def link_to_package(txt, pkg)
+  txt.gsub!(pkg, 
+            "<a href=\"#{pkg.tr('.', '/')}/package-summary.html\">#{pkg}</a>")
+end
+
+def link_to_class(txt, cls)
+  fullname = SOURCES.
+    grep(Regexp.new(cls))[0].
+    tr('.', '/').
+    gsub('/java', '.html').
+    gsub('src/', '')
+  txt.gsub!(/(\W)#{cls}(\W)/) do |m| 
+    $1 + "<a href=\"#{fullname}\">#{cls}</a>" + $2
+  end
+end
+
+SOURCES = Dir.glob('src/**/*.java')
+CLASSES = SOURCES.map {|f| File.basename(f, '.java')}
+PACKAGES = Set.new(SOURCES.map {|f| File.dirname(f)})
+
+#puts "Classes:"
+#CLASSES.each {|c| puts c}
+#puts
+#puts "Packages:"
+#PACKAGES.each {|p| puts p}
+
+#exit
+
+ARGV.each do |f|
+  newf = f.gsub /.textile$/, '.html'
+  out = open(newf, 'w') do |o|
+    txt = open(f, 'r').read
+    html = RedCloth.new(txt).to_html
+    html.gsub!(/<br \/>/, '')
+    html.gsub!(/<table>/, '<table class="my">')
+    PACKAGES.each {|p| link_to_package(html, p)}
+    CLASSES.each {|c| link_to_class(html, c)}
+    o.write('<html><body>' + html + '</body></html>')
+  end
+end
diff --git a/scripts/rjpp.rb b/scripts/rjpp.rb
new file mode 100644
index 0000000..458aaf6
--- /dev/null
+++ b/scripts/rjpp.rb
@@ -0,0 +1,95 @@
+## --- 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 ---
+
+#!/usr/bin/ruby
+#
+# The Ruby Java PreProcessor
+#
+# Contrary to the "usual" cpp, commands will be expanded "in-place" in
+# an idempotent fashion (meaning that you can run rjpp on the same
+# file more than once.
+#
+# Directives are either given as
+#
+# /*# ... directive ... #*/
+#
+# After expansion, the code will look like this:
+#
+# /*# original directive #*/
+# //RJPP-BEGIN------------------------------------------------------------
+# expanded code
+# //RJPP-END--------------------------------------------------------------
+#
+# So you can run the rjpp twice on a file and get the same result as
+# running it once. This property is called idempotency in mathematics X-D
+
+
+# print usage
+if ARGV.length == 0
+  puts "Usage: jrpp file"
+end
+
+def collect(*args)
+  args.join "\n"
+end
+
+def doc(s)
+  "/** " + s + " */"
+end
+
+#open file
+file = open(ARGV[0], 'r').read
+saved_file = file
+
+# remove existing expansions
+file.gsub! /\/\/RJPP-BEGIN.*?\/\/RJPP-END[^\n]*\n/m, ''
+
+# expand code
+file.gsub! /\/\*\#(.*?)\#\*\//m do |s|
+  expansion = eval($1).to_s
+  result = s
+  unless expansion.empty?
+    result << "\n//RJPP-BEGIN------------------------------------------------------------\n" + expansion + "//RJPP-END--------------------------------------------------------------"
+  end
+  result
+end
+
+# write file
+if file.length == 0
+  puts "How odd... The whole file magically vanished..."
+else
+  open(ARGV[0] + '.rjpp', 'w').write(saved_file)
+  open(ARGV[0], 'w').write(file)
+  #print file
+end
diff --git a/scripts/static_class_to_float.rb b/scripts/static_class_to_float.rb
new file mode 100644
index 0000000..7aa9d9a
--- /dev/null
+++ b/scripts/static_class_to_float.rb
@@ -0,0 +1,109 @@
+## --- 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 ---
+
+def readfile(fn)
+  f = open(fn)
+  s = f.read
+  f.close
+  s
+end
+
+def writefile(fn, s)
+  f = open(fn, 'w')
+  f.write s
+  f.close
+end
+
+def classfile(classname)
+  classname.tr('.', File::SEPARATOR) + '.java'
+end
+
+def translate(cl, s)
+  mark = "public class #{cl.split('.').last} {\n"
+  i = s.index(mark) + mark.length
+  j = s.rindex('}')
+  head = s[0...i]
+  body = s[i...j]
+
+  # remove part copied in last time
+  body.gsub! /\/\/BEGIN.*?\/\/END\n/m, ''
+
+  copybody = body.dup
+
+  # remove part which should not be added as float
+  copybody.gsub! /\/\/STOP.*?\/\/START\n/m, ''
+
+  # do necessary substitutions
+  copybody.gsub! /DoubleMatrix/, 'FloatMatrix'
+  copybody.gsub! /DoubleBuffer/, 'FloatBuffer'
+  copybody.gsub! /DoubleVector/, 'FloatVector'
+  copybody.gsub! /ComplexDouble/, 'ComplexFloat'
+  copybody.gsub! /([0-9]+\.[0-9]+)/, '\1f'
+  copybody.gsub! /double/, 'float'
+  copybody.gsub! /Blas\.dz/, 'Blas.sc'
+  copybody.gsub! /Blas\.d/, 'Blas.s'
+  copybody.gsub! /Blas\.z/, 'Blas.c'
+  copybody.gsub! /Blas\.idamax/, 'Blas.isamax'
+  copybody.gsub! /Blas\.izamax/, 'Blas.icamax'
+  copybody.gsub!(/([a-z]+)Double/, '\1Float')
+
+  # construct output file
+  out = []
+  out << head
+  out << body
+  out << "//BEGIN\n"
+  out << "  // The code below has been automatically generated.\n"
+  out << "  // DO NOT EDIT!\n"
+  out << copybody
+  out << "//END\n"
+  out << "}\n"
+  return out.join
+end
+
+if ARGV.size < 2
+  puts "Usage: ruby static_class_to_float.rb srcprefix classname"
+  exit
+end
+
+prefix = ARGV[0]
+source = ARGV[1]
+
+fn = File.join(prefix, classfile(source))
+
+if File.exist? fn
+  s = readfile(fn)
+  writefile(fn, translate(source, s))
+else
+  puts "Could not read file #{fn}"
+end
diff --git a/scripts/test_fortranwrapper b/scripts/test_fortranwrapper
new file mode 100644
index 0000000..435c65d
--- /dev/null
+++ b/scripts/test_fortranwrapper
@@ -0,0 +1,4 @@
+#scripts/fortranwrapper com.fhg.la Blas ~/src/blas/ddot.f ~/src/blas/zdotc.f ~/src/blas/saxpy.f ~/src/blas/cdotc.f ~/src/blas/zgemm.f
+scripts/fortranwrapper com.fhg.la Blas ~/src/blas/*.f
+ant compile createHeaderFiles
+make bin/Blas.o
\ No newline at end of file
diff --git a/src/org/jblas/core/ComplexDouble.java b/src/org/jblas/core/ComplexDouble.java
new file mode 100644
index 0000000..b8e6e73
--- /dev/null
+++ b/src/org/jblas/core/ComplexDouble.java
@@ -0,0 +1,322 @@
+// --- 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.core;
+
+import static java.lang.Math.sqrt;
+
+import java.nio.DoubleBuffer;
+
+/**
+ * A complex value with double precision.
+ * 
+ * @author Mikio L. Braun
+ * 
+ */
+public class ComplexDouble {
+
+    private double r,  i;
+    public static final ComplexDouble UNIT = new ComplexDouble(1.0, 0.0);
+    public static final ComplexDouble I = new ComplexDouble(0.0, 1.0);
+    public static final ComplexDouble NEG_UNIT = new ComplexDouble(-1.0, 0.0);
+    public static final ComplexDouble NEG_I = new ComplexDouble(0.0, -1.0);
+    public static final ComplexDouble ZERO = new ComplexDouble(0.0);
+
+    public ComplexDouble(double real, double imag) {
+        r = real;
+        i = imag;
+    }
+
+    public ComplexDouble(double real) {
+        this(real, 0.0);
+    }
+
+    public String toString() {
+        if (i >= 0) {
+            return r + " + " + i + "i";
+        } else {
+            return r + " - " + (-i) + "i";
+        }
+    }
+
+    public ComplexDouble set(double real, double imag) {
+        r = real;
+        i = imag;
+        return this;
+    }
+
+    public double real() {
+        return r;
+    }
+
+    public double imag() {
+        return i;
+    }
+
+    public ComplexDouble dup() {
+        return new ComplexDouble(r, i);
+    }
+
+    public ComplexDouble copy(ComplexDouble other) {
+        r = other.r;
+        i = other.i;
+        return this;
+    }
+
+    /** Add two complex numbers in-place */
+    public ComplexDouble addi(ComplexDouble c, ComplexDouble result) {
+        if (this == result) {
+            r += c.r;
+            i += c.i;
+        } else {
+            result.r = r + c.r;
+            result.i = i + c.i;
+        }
+        return result;
+    }
+
+    /** Add two complex numbers in-place storing the result in this. */
+    public ComplexDouble addi(ComplexDouble c) {
+        return addi(c, this);
+    }
+
+    /** Add two complex numbers. */
+    public ComplexDouble add(ComplexDouble c) {
+        return dup().addi(c);
+    }
+
+    /** Add a real number to a complex number in-place. */
+    public ComplexDouble addi(double a, ComplexDouble result) {
+        if (this == result) {
+            r += a;
+        } else {
+            result.r = r + a;
+            result.i = i;
+        }
+        return result;
+    }
+
+    /** Add a real number to complex number in-place, storing the result in this. */
+    public ComplexDouble addi(double c) {
+        return addi(c, this);
+    }
+
+    /** Add a real number to a complex number. */
+    public ComplexDouble add(double c) {
+        return dup().addi(c);
+    }
+
+    /** Subtract two complex numbers, in-place */
+    public ComplexDouble subi(ComplexDouble c, ComplexDouble result) {
+        if (this == result) {
+            r -= c.r;
+            i -= c.i;
+        } else {
+            result.r = r - c.r;
+            result.i = i - c.i;
+        }
+        return this;
+    }
+    
+    public ComplexDouble subi(ComplexDouble c) {
+        return subi(c, this);
+    }
+
+    /** Subtract two complex numbers */
+    public ComplexDouble sub(ComplexDouble c) {
+        return dup().subi(c);
+    }
+
+    public ComplexDouble subi(double a, ComplexDouble result) {
+        if (this == result) {
+            r -= a;
+        } else {
+            result.r = r - a;
+            result.i = i;
+        }
+        return result;
+    }
+    
+    public ComplexDouble subi(double a) {
+        return subi(a, this);
+    }
+
+    public ComplexDouble sub(double r) {
+        return dup().subi(r);
+    }
+
+    /** Multiply two complex numbers, inplace */
+    public ComplexDouble muli(ComplexDouble c, ComplexDouble result) {
+        double newR = r * c.r - i * c.i;
+        double newI = r * c.i + i * c.r;
+        result.r = newR;
+        result.i = newI;
+        return result;
+    }
+    
+    public ComplexDouble muli(ComplexDouble c) {
+        return muli(c, this);
+    }
+
+    /** Multiply two complex numbers */
+    public ComplexDouble mul(ComplexDouble c) {
+        return dup().muli(c);
+    }
+
+    public ComplexDouble mul(double v) {
+        return dup().muli(v);
+    }
+
+    public ComplexDouble muli(double v, ComplexDouble result) {
+        if (this == result) {
+            r *= v;
+            i *= v;    
+        } else {
+            result.r = r * v;
+            result.i = i * v;
+        }
+        return this;
+    }
+    
+    public ComplexDouble muli(double v) {
+        return muli(v, this);
+    }
+
+    /** Divide two complex numbers */
+    public ComplexDouble div(ComplexDouble c) {
+        return dup().divi(c);
+    }
+
+    /** Divide two complex numbers, in-place */
+    public ComplexDouble divi(ComplexDouble c, ComplexDouble result) {
+        double d = c.r * c.r + c.i * c.i;
+        double newR = (r * c.r + i * c.i) / d;
+        double newI = (i * c.r - r * c.i) / d;
+        result.r = newR;
+        result.i = newI;
+        return result;
+    }
+
+    public ComplexDouble divi(ComplexDouble c) {
+        return divi(c, this);
+    }
+    
+    public ComplexDouble divi(double v, ComplexDouble result) {
+        if (this == result) {
+            r /= v;
+            i /= v;
+        } else {
+            result.r = r / v;
+            result.i = i / v;
+        }
+        return this;
+    }
+    
+    public ComplexDouble divi(double v) {
+        return divi(v, this);
+    }
+
+    public ComplexDouble div(double v) {
+        return dup().divi(v);
+    }
+
+    /** Return the absolute value */
+    public double abs() {
+        return (double) sqrt(r * r + i * i);
+    }
+
+    public ComplexDouble invi() {
+        double d = r * r + i * i;
+        r = r / d;
+        i = -i / d;
+        return this;
+    }
+    
+    public ComplexDouble inv() {
+        return dup().invi();
+    }
+
+    public ComplexDouble neg() {
+        return dup().negi();
+    }
+
+    public ComplexDouble negi() {
+        r = -r;
+        i = -i;
+        return this;
+    }
+
+    public ComplexDouble conji() {
+        i = -i;
+        return this;
+    }
+    
+    public ComplexDouble conj() {
+        return dup().conji();
+    }
+    
+    /**
+     * Comparing two DoubleComplex values.
+     */
+    public boolean equals(Object o) {
+        if (!(o instanceof ComplexDouble)) {
+            return false;
+        }
+        ComplexDouble c = (ComplexDouble) o;
+
+        return eq(c);
+    }
+
+    public boolean eq(ComplexDouble c) {
+        return Math.abs(r - c.r) + Math.abs(i - c.i) < (double) 1e-6;
+    }
+
+    public boolean ne(ComplexDouble c) {
+        return !eq(c);
+    }
+
+    public boolean isZero() {
+        return r == 0.0 && i == 0.0;
+    }
+    
+    public boolean isReal() {
+        return i == 0.0;
+    }
+    
+    public boolean isImag() {
+        return r == 0.0;
+    }
+}
diff --git a/src/org/jblas/core/ComplexFloat.java b/src/org/jblas/core/ComplexFloat.java
new file mode 100644
index 0000000..de1c885
--- /dev/null
+++ b/src/org/jblas/core/ComplexFloat.java
@@ -0,0 +1,322 @@
+// --- 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.core;
+
+import static java.lang.Math.sqrt;
+
+import java.nio.FloatBuffer;
+
+/**
+ * A complex value with float precision.
+ * 
+ * @author Mikio L. Braun
+ * 
+ */
+public class ComplexFloat {
+
+    private float r,  i;
+    public static final ComplexFloat UNIT = new ComplexFloat(1.0f, 0.0f);
+    public static final ComplexFloat I = new ComplexFloat(0.0f, 1.0f);
+    public static final ComplexFloat NEG_UNIT = new ComplexFloat(-1.0f, 0.0f);
+    public static final ComplexFloat NEG_I = new ComplexFloat(0.0f, -1.0f);
+    public static final ComplexFloat ZERO = new ComplexFloat(0.0f);
+
+    public ComplexFloat(float real, float imag) {
+        r = real;
+        i = imag;
+    }
+
+    public ComplexFloat(float real) {
+        this(real, 0.0f);
+    }
+
+    public String toString() {
+        if (i >= 0) {
+            return r + " + " + i + "i";
+        } else {
+            return r + " - " + (-i) + "i";
+        }
+    }
+
+    public ComplexFloat set(float real, float imag) {
+        r = real;
+        i = imag;
+        return this;
+    }
+
+    public float real() {
+        return r;
+    }
+
+    public float imag() {
+        return i;
+    }
+
+    public ComplexFloat dup() {
+        return new ComplexFloat(r, i);
+    }
+
+    public ComplexFloat copy(ComplexFloat other) {
+        r = other.r;
+        i = other.i;
+        return this;
+    }
+
+    /** Add two complex numbers in-place */
+    public ComplexFloat addi(ComplexFloat c, ComplexFloat result) {
+        if (this == result) {
+            r += c.r;
+            i += c.i;
+        } else {
+            result.r = r + c.r;
+            result.i = i + c.i;
+        }
+        return result;
+    }
+
+    /** Add two complex numbers in-place storing the result in this. */
+    public ComplexFloat addi(ComplexFloat c) {
+        return addi(c, this);
+    }
+
+    /** Add two complex numbers. */
+    public ComplexFloat add(ComplexFloat c) {
+        return dup().addi(c);
+    }
+
+    /** Add a real number to a complex number in-place. */
+    public ComplexFloat addi(float a, ComplexFloat result) {
+        if (this == result) {
+            r += a;
+        } else {
+            result.r = r + a;
+            result.i = i;
+        }
+        return result;
+    }
+
+    /** Add a real number to complex number in-place, storing the result in this. */
+    public ComplexFloat addi(float c) {
+        return addi(c, this);
+    }
+
+    /** Add a real number to a complex number. */
+    public ComplexFloat add(float c) {
+        return dup().addi(c);
+    }
+
+    /** Subtract two complex numbers, in-place */
+    public ComplexFloat subi(ComplexFloat c, ComplexFloat result) {
+        if (this == result) {
+            r -= c.r;
+            i -= c.i;
+        } else {
+            result.r = r - c.r;
+            result.i = i - c.i;
+        }
+        return this;
+    }
+    
+    public ComplexFloat subi(ComplexFloat c) {
+        return subi(c, this);
+    }
+
+    /** Subtract two complex numbers */
+    public ComplexFloat sub(ComplexFloat c) {
+        return dup().subi(c);
+    }
+
+    public ComplexFloat subi(float a, ComplexFloat result) {
+        if (this == result) {
+            r -= a;
+        } else {
+            result.r = r - a;
+            result.i = i;
+        }
+        return result;
+    }
+    
+    public ComplexFloat subi(float a) {
+        return subi(a, this);
+    }
+
+    public ComplexFloat sub(float r) {
+        return dup().subi(r);
+    }
+
+    /** Multiply two complex numbers, inplace */
+    public ComplexFloat muli(ComplexFloat c, ComplexFloat result) {
+        float newR = r * c.r - i * c.i;
+        float newI = r * c.i + i * c.r;
+        result.r = newR;
+        result.i = newI;
+        return result;
+    }
+    
+    public ComplexFloat muli(ComplexFloat c) {
+        return muli(c, this);
+    }
+
+    /** Multiply two complex numbers */
+    public ComplexFloat mul(ComplexFloat c) {
+        return dup().muli(c);
+    }
+
+    public ComplexFloat mul(float v) {
+        return dup().muli(v);
+    }
+
+    public ComplexFloat muli(float v, ComplexFloat result) {
+        if (this == result) {
+            r *= v;
+            i *= v;    
+        } else {
+            result.r = r * v;
+            result.i = i * v;
+        }
+        return this;
+    }
+    
+    public ComplexFloat muli(float v) {
+        return muli(v, this);
+    }
+
+    /** Divide two complex numbers */
+    public ComplexFloat div(ComplexFloat c) {
+        return dup().divi(c);
+    }
+
+    /** Divide two complex numbers, in-place */
+    public ComplexFloat divi(ComplexFloat c, ComplexFloat result) {
+        float d = c.r * c.r + c.i * c.i;
+        float newR = (r * c.r + i * c.i) / d;
+        float newI = (i * c.r - r * c.i) / d;
+        result.r = newR;
+        result.i = newI;
+        return result;
+    }
+
+    public ComplexFloat divi(ComplexFloat c) {
+        return divi(c, this);
+    }
+    
+    public ComplexFloat divi(float v, ComplexFloat result) {
+        if (this == result) {
+            r /= v;
+            i /= v;
+        } else {
+            result.r = r / v;
+            result.i = i / v;
+        }
+        return this;
+    }
+    
+    public ComplexFloat divi(float v) {
+        return divi(v, this);
+    }
+
+    public ComplexFloat div(float v) {
+        return dup().divi(v);
+    }
+
+    /** Return the absolute value */
+    public float abs() {
+        return (float) sqrt(r * r + i * i);
+    }
+
+    public ComplexFloat invi() {
+        float d = r * r + i * i;
+        r = r / d;
+        i = -i / d;
+        return this;
+    }
+    
+    public ComplexFloat inv() {
+        return dup().invi();
+    }
+
+    public ComplexFloat neg() {
+        return dup().negi();
+    }
+
+    public ComplexFloat negi() {
+        r = -r;
+        i = -i;
+        return this;
+    }
+
+    public ComplexFloat conji() {
+        i = -i;
+        return this;
+    }
+    
+    public ComplexFloat conj() {
+        return dup().conji();
+    }
+    
+    /**
+     * Comparing two DoubleComplex values.
+     */
+    public boolean equals(Object o) {
+        if (!(o instanceof ComplexFloat)) {
+            return false;
+        }
+        ComplexFloat c = (ComplexFloat) o;
+
+        return eq(c);
+    }
+
+    public boolean eq(ComplexFloat c) {
+        return Math.abs(r - c.r) + Math.abs(i - c.i) < (float) 1e-6;
+    }
+
+    public boolean ne(ComplexFloat c) {
+        return !eq(c);
+    }
+
+    public boolean isZero() {
+        return r == 0.0f && i == 0.0f;
+    }
+    
+    public boolean isReal() {
+        return i == 0.0f;
+    }
+    
+    public boolean isImag() {
+        return r == 0.0f;
+    }
+}
diff --git a/src/org/jblas/core/Functions.java b/src/org/jblas/core/Functions.java
new file mode 100644
index 0000000..8573ea8
--- /dev/null
+++ b/src/org/jblas/core/Functions.java
@@ -0,0 +1,46 @@
+// --- 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.core;
+
+public class Functions {
+	public static double sinc(double x) {
+		if (x == 0)
+			return 1.0;
+		else
+			return Math.sin(Math.PI * x) / (Math.PI * x);
+	}
+}
diff --git a/src/org/jblas/core/package-info.java b/src/org/jblas/core/package-info.java
new file mode 100644
index 0000000..0f9901a
--- /dev/null
+++ b/src/org/jblas/core/package-info.java
@@ -0,0 +1,42 @@
+// --- 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 ---
+
+/**
+ * Support classes for jBLAS.
+ * 
+ * This package contains several base classes, for example complex data types.
+ */
+package org.jblas.core;
diff --git a/src/org/jblas/la/Blas.java b/src/org/jblas/la/Blas.java
new file mode 100644
index 0000000..6d7c62d
--- /dev/null
+++ b/src/org/jblas/la/Blas.java
@@ -0,0 +1,378 @@
+// --- 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.la;
+
+import org.jblas.core.ComplexFloat;
+import org.jblas.core.ComplexDouble;
+
+public class Blas {
+
+  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");
+	  }
+  } 
+
+  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);
+  public static native ComplexFloat cdotu(int n, float[] cx, int cxIdx, int incx, float[] cy, int cyIdx, int incy);
+  public static native void cgbmv(char trans, int m, int n, int kl, int ku, ComplexFloat alpha, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx, ComplexFloat beta, float[] y, int yIdx, int incy);
+  public static native void cgemm(char transa, char transb, int m, int n, int k, ComplexFloat alpha, float[] a, int aIdx, int lda, float[] b, int bIdx, int ldb, ComplexFloat beta, float[] c, int cIdx, int ldc);
+  public static native void cgemv(char trans, int m, int n, ComplexFloat alpha, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx, ComplexFloat beta, float[] y, int yIdx, int incy);
+  public static native void cgerc(int m, int n, ComplexFloat alpha, float[] x, int xIdx, int incx, float[] y, int yIdx, int incy, float[] a, int aIdx, int lda);
+  public static native void cgeru(int m, int n, ComplexFloat alpha, float[] x, int xIdx, int incx, float[] y, int yIdx, int incy, float[] a, int aIdx, int lda);
+  public static native void chbmv(char uplo, int n, int k, ComplexFloat alpha, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx, ComplexFloat beta, float[] y, int yIdx, int incy);
+  public static native void chemm(char side, char uplo, int m, int n, ComplexFloat alpha, float[] a, int aIdx, int lda, float[] b, int bIdx, int ldb, ComplexFloat beta, float[] c, int cIdx, int ldc);
+  public static native void chemv(char uplo, int n, ComplexFloat alpha, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx, ComplexFloat beta, float[] y, int yIdx, int incy);
+  public static native void cher2(char uplo, int n, ComplexFloat alpha, float[] x, int xIdx, int incx, float[] y, int yIdx, int incy, float[] a, int aIdx, int lda);
+  public static native void cher2k(char uplo, char trans, int n, int k, ComplexFloat alpha, float[] a, int aIdx, int lda, float[] b, int bIdx, int ldb, float beta, float[] c, int cIdx, int ldc);
+  public static native void cher(char uplo, int n, float alpha, float[] x, int xIdx, int incx, float[] a, int aIdx, int lda);
+  public static native void cherk(char uplo, char trans, int n, int k, float alpha, float[] a, int aIdx, int lda, float beta, float[] c, int cIdx, int ldc);
+  public static native void chpmv(char uplo, int n, ComplexFloat alpha, float[] ap, int apIdx, float[] x, int xIdx, int incx, ComplexFloat beta, float[] y, int yIdx, int incy);
+  public static native void chpr2(char uplo, int n, ComplexFloat alpha, float[] x, int xIdx, int incx, float[] y, int yIdx, int incy, float[] ap, int apIdx);
+  public static native void chpr(char uplo, int n, float alpha, float[] x, int xIdx, int incx, float[] ap, int apIdx);
+  public static native void crotg(ComplexFloat ca, ComplexFloat cb, float c, ComplexFloat s);
+  public static native void cscal(int n, ComplexFloat ca, float[] cx, int cxIdx, int incx);
+  public static native void csrot(int n, float[] cx, int cxIdx, int incx, float[] cy, int cyIdx, int incy, float c, float s);
+  public static native void csscal(int n, float sa, float[] cx, int cxIdx, int incx);
+  public static native void cswap(int n, float[] cx, int cxIdx, int incx, float[] cy, int cyIdx, int incy);
+  public static native void csymm(char side, char uplo, int m, int n, ComplexFloat alpha, float[] a, int aIdx, int lda, float[] b, int bIdx, int ldb, ComplexFloat beta, float[] c, int cIdx, int ldc);
+  public static native void csyr2k(char uplo, char trans, int n, int k, ComplexFloat alpha, float[] a, int aIdx, int lda, float[] b, int bIdx, int ldb, ComplexFloat beta, float[] c, int cIdx, int ldc);
+  public static native void csyrk(char uplo, char trans, int n, int k, ComplexFloat alpha, float[] a, int aIdx, int lda, ComplexFloat beta, float[] c, int cIdx, int ldc);
+  public static native void ctbmv(char uplo, char trans, char diag, int n, int k, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx);
+  public static native void ctbsv(char uplo, char trans, char diag, int n, int k, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx);
+  public static native void ctpmv(char uplo, char trans, char diag, int n, float[] ap, int apIdx, float[] x, int xIdx, int incx);
+  public static native void ctpsv(char uplo, char trans, char diag, int n, float[] ap, int apIdx, float[] x, int xIdx, int incx);
+  public static native void ctrmm(char side, char uplo, char transa, char diag, int m, int n, ComplexFloat alpha, float[] a, int aIdx, int lda, float[] b, int bIdx, int ldb);
+  public static native void ctrmv(char uplo, char trans, char diag, int n, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx);
+  public static native void ctrsm(char side, char uplo, char transa, char diag, int m, int n, ComplexFloat alpha, float[] a, int aIdx, int lda, float[] b, int bIdx, int ldb);
+  public static native void ctrsv(char uplo, char trans, char diag, int n, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx);
+  public static native double dasum(int n, double[] dx, int dxIdx, int incx);
+  public static native void daxpy(int n, double da, double[] dx, int dxIdx, int incx, double[] dy, int dyIdx, int incy);
+  public static native double dcabs1(ComplexDouble z);
+  public static native void dcopy(int n, double[] dx, int dxIdx, int incx, double[] dy, int dyIdx, int incy);
+  public static native double ddot(int n, double[] dx, int dxIdx, int incx, double[] dy, int dyIdx, int incy);
+  public static native void dgbmv(char trans, int m, int n, int kl, int ku, double alpha, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx, double beta, double[] y, int yIdx, int incy);
+  public static native void dgemm(char transa, char transb, int m, int n, int k, double alpha, double[] a, int aIdx, int lda, double[] b, int bIdx, int ldb, double beta, double[] c, int cIdx, int ldc);
+  public static native void dgemv(char trans, int m, int n, double alpha, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx, double beta, double[] y, int yIdx, int incy);
+  public static native void dger(int m, int n, double alpha, double[] x, int xIdx, int incx, double[] y, int yIdx, int incy, double[] a, int aIdx, int lda);
+  public static native double dnrm2(int n, double[] x, int xIdx, int incx);
+  public static native void drot(int n, double[] dx, int dxIdx, int incx, double[] dy, int dyIdx, int incy, double c, double s);
+  public static native void drotg(double da, double db, double c, double s);
+  public static native void drotm(int n, double[] dx, int dxIdx, int incx, double[] dy, int dyIdx, int incy, double[] dparam, int dparamIdx);
+  public static native void drotmg(double[] dd1, int dd1Idx, double[] dd2, int dd2Idx, double[] dx1, int dx1Idx, double dy1, double[] dparam, int dparamIdx);
+  public static native void dsbmv(char uplo, int n, int k, double alpha, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx, double beta, double[] y, int yIdx, int incy);
+  public static native void dscal(int n, double da, double[] dx, int dxIdx, int incx);
+  public static native double dsdot(int n, float[] sx, int sxIdx, int incx, float[] sy, int syIdx, int incy);
+  public static native void dspmv(char uplo, int n, double alpha, double[] ap, int apIdx, double[] x, int xIdx, int incx, double beta, double[] y, int yIdx, int incy);
+  public static native void dspr2(char uplo, int n, double alpha, double[] x, int xIdx, int incx, double[] y, int yIdx, int incy, double[] ap, int apIdx);
+  public static native void dspr(char uplo, int n, double alpha, double[] x, int xIdx, int incx, double[] ap, int apIdx);
+  public static native void dswap(int n, double[] dx, int dxIdx, int incx, double[] dy, int dyIdx, int incy);
+  public static native void dsymm(char side, char uplo, int m, int n, double alpha, double[] a, int aIdx, int lda, double[] b, int bIdx, int ldb, double beta, double[] c, int cIdx, int ldc);
+  public static native void dsymv(char uplo, int n, double alpha, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx, double beta, double[] y, int yIdx, int incy);
+  public static native void dsyr2(char uplo, int n, double alpha, double[] x, int xIdx, int incx, double[] y, int yIdx, int incy, double[] a, int aIdx, int lda);
+  public static native void dsyr2k(char uplo, char trans, int n, int k, double alpha, double[] a, int aIdx, int lda, double[] b, int bIdx, int ldb, double beta, double[] c, int cIdx, int ldc);
+  public static native void dsyr(char uplo, int n, double alpha, double[] x, int xIdx, int incx, double[] a, int aIdx, int lda);
+  public static native void dsyrk(char uplo, char trans, int n, int k, double alpha, double[] a, int aIdx, int lda, double beta, double[] c, int cIdx, int ldc);
+  public static native void dtbmv(char uplo, char trans, char diag, int n, int k, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx);
+  public static native void dtbsv(char uplo, char trans, char diag, int n, int k, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx);
+  public static native void dtpmv(char uplo, char trans, char diag, int n, double[] ap, int apIdx, double[] x, int xIdx, int incx);
+  public static native void dtpsv(char uplo, char trans, char diag, int n, double[] ap, int apIdx, double[] x, int xIdx, int incx);
+  public static native void dtrmm(char side, char uplo, char transa, char diag, int m, int n, double alpha, double[] a, int aIdx, int lda, double[] b, int bIdx, int ldb);
+  public static native void dtrmv(char uplo, char trans, char diag, int n, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx);
+  public static native void dtrsm(char side, char uplo, char transa, char diag, int m, int n, double alpha, double[] a, int aIdx, int lda, double[] b, int bIdx, int ldb);
+  public static native void dtrsv(char uplo, char trans, char diag, int n, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx);
+  public static native double dzasum(int n, double[] zx, int zxIdx, int incx);
+  public static native double dznrm2(int n, double[] x, int xIdx, int incx);
+  public static native int icamax(int n, float[] cx, int cxIdx, int incx);
+  public static native int idamax(int n, double[] dx, int dxIdx, int incx);
+  public static native int isamax(int n, float[] sx, int sxIdx, int incx);
+  public static native int izamax(int n, double[] zx, int zxIdx, int incx);
+  public static native int lsame(char ca, char cb);
+  public static native float sasum(int n, float[] sx, int sxIdx, int incx);
+  public static native void saxpy(int n, float sa, float[] sx, int sxIdx, int incx, float[] sy, int syIdx, int incy);
+  public static native float scasum(int n, float[] cx, int cxIdx, int incx);
+  public static native float scnrm2(int n, float[] x, int xIdx, int incx);
+  public static native void scopy(int n, float[] sx, int sxIdx, int incx, float[] sy, int syIdx, int incy);
+  public static native float sdot(int n, float[] sx, int sxIdx, int incx, float[] sy, int syIdx, int incy);
+  public static native float sdsdot(int n, float sb, float[] sx, int sxIdx, int incx, float[] sy, int syIdx, int incy);
+  public static native void sgbmv(char trans, int m, int n, int kl, int ku, float alpha, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx, float beta, float[] y, int yIdx, int incy);
+  public static native void sgemm(char transa, char transb, int m, int n, int k, float alpha, float[] a, int aIdx, int lda, float[] b, int bIdx, int ldb, float beta, float[] c, int cIdx, int ldc);
+  public static native void sgemv(char trans, int m, int n, float alpha, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx, float beta, float[] y, int yIdx, int incy);
+  public static native void sger(int m, int n, float alpha, float[] x, int xIdx, int incx, float[] y, int yIdx, int incy, float[] a, int aIdx, int lda);
+  public static native float snrm2(int n, float[] x, int xIdx, int incx);
+  public static native void srot(int n, float[] sx, int sxIdx, int incx, float[] sy, int syIdx, int incy, float c, float s);
+  public static native void srotg(float sa, float sb, float c, float s);
+  public static native void srotm(int n, float[] sx, int sxIdx, int incx, float[] sy, int syIdx, int incy, float[] sparam, int sparamIdx);
+  public static native void srotmg(float[] sd1, int sd1Idx, float[] sd2, int sd2Idx, float[] sx1, int sx1Idx, float sy1, float[] sparam, int sparamIdx);
+  public static native void ssbmv(char uplo, int n, int k, float alpha, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx, float beta, float[] y, int yIdx, int incy);
+  public static native void sscal(int n, float sa, float[] sx, int sxIdx, int incx);
+  public static native void sspmv(char uplo, int n, float alpha, float[] ap, int apIdx, float[] x, int xIdx, int incx, float beta, float[] y, int yIdx, int incy);
+  public static native void sspr2(char uplo, int n, float alpha, float[] x, int xIdx, int incx, float[] y, int yIdx, int incy, float[] ap, int apIdx);
+  public static native void sspr(char uplo, int n, float alpha, float[] x, int xIdx, int incx, float[] ap, int apIdx);
+  public static native void sswap(int n, float[] sx, int sxIdx, int incx, float[] sy, int syIdx, int incy);
+  public static native void ssymm(char side, char uplo, int m, int n, float alpha, float[] a, int aIdx, int lda, float[] b, int bIdx, int ldb, float beta, float[] c, int cIdx, int ldc);
+  public static native void ssymv(char uplo, int n, float alpha, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx, float beta, float[] y, int yIdx, int incy);
+  public static native void ssyr2(char uplo, int n, float alpha, float[] x, int xIdx, int incx, float[] y, int yIdx, int incy, float[] a, int aIdx, int lda);
+  public static native void ssyr2k(char uplo, char trans, int n, int k, float alpha, float[] a, int aIdx, int lda, float[] b, int bIdx, int ldb, float beta, float[] c, int cIdx, int ldc);
+  public static native void ssyr(char uplo, int n, float alpha, float[] x, int xIdx, int incx, float[] a, int aIdx, int lda);
+  public static native void ssyrk(char uplo, char trans, int n, int k, float alpha, float[] a, int aIdx, int lda, float beta, float[] c, int cIdx, int ldc);
+  public static native void stbmv(char uplo, char trans, char diag, int n, int k, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx);
+  public static native void stbsv(char uplo, char trans, char diag, int n, int k, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx);
+  public static native void stpmv(char uplo, char trans, char diag, int n, float[] ap, int apIdx, float[] x, int xIdx, int incx);
+  public static native void stpsv(char uplo, char trans, char diag, int n, float[] ap, int apIdx, float[] x, int xIdx, int incx);
+  public static native void strmm(char side, char uplo, char transa, char diag, int m, int n, float alpha, float[] a, int aIdx, int lda, float[] b, int bIdx, int ldb);
+  public static native void strmv(char uplo, char trans, char diag, int n, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx);
+  public static native void strsm(char side, char uplo, char transa, char diag, int m, int n, float alpha, float[] a, int aIdx, int lda, float[] b, int bIdx, int ldb);
+  public static native void strsv(char uplo, char trans, char diag, int n, float[] a, int aIdx, int lda, float[] x, int xIdx, int incx);
+  public static native void zaxpy(int n, ComplexDouble za, double[] zx, int zxIdx, int incx, double[] zy, int zyIdx, int incy);
+  public static native void zcopy(int n, double[] zx, int zxIdx, int incx, double[] zy, int zyIdx, int incy);
+  public static native ComplexDouble zdotc(int n, double[] zx, int zxIdx, int incx, double[] zy, int zyIdx, int incy);
+  public static native ComplexDouble zdotu(int n, double[] zx, int zxIdx, int incx, double[] zy, int zyIdx, int incy);
+  public static native void zdrot(int n, double[] cx, int cxIdx, int incx, double[] cy, int cyIdx, int incy, double c, double s);
+  public static native void zdscal(int n, double da, double[] zx, int zxIdx, int incx);
+  public static native void zgbmv(char trans, int m, int n, int kl, int ku, ComplexDouble alpha, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx, ComplexDouble beta, double[] y, int yIdx, int incy);
+  public static native void zgemm(char transa, char transb, int m, int n, int k, ComplexDouble alpha, double[] a, int aIdx, int lda, double[] b, int bIdx, int ldb, ComplexDouble beta, double[] c, int cIdx, int ldc);
+  public static native void zgemv(char trans, int m, int n, ComplexDouble alpha, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx, ComplexDouble beta, double[] y, int yIdx, int incy);
+  public static native void zgerc(int m, int n, ComplexDouble alpha, double[] x, int xIdx, int incx, double[] y, int yIdx, int incy, double[] a, int aIdx, int lda);
+  public static native void zgeru(int m, int n, ComplexDouble alpha, double[] x, int xIdx, int incx, double[] y, int yIdx, int incy, double[] a, int aIdx, int lda);
+  public static native void zhbmv(char uplo, int n, int k, ComplexDouble alpha, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx, ComplexDouble beta, double[] y, int yIdx, int incy);
+  public static native void zhemm(char side, char uplo, int m, int n, ComplexDouble alpha, double[] a, int aIdx, int lda, double[] b, int bIdx, int ldb, ComplexDouble beta, double[] c, int cIdx, int ldc);
+  public static native void zhemv(char uplo, int n, ComplexDouble alpha, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx, ComplexDouble beta, double[] y, int yIdx, int incy);
+  public static native void zher2(char uplo, int n, ComplexDouble alpha, double[] x, int xIdx, int incx, double[] y, int yIdx, int incy, double[] a, int aIdx, int lda);
+  public static native void zher2k(char uplo, char trans, int n, int k, ComplexDouble alpha, double[] a, int aIdx, int lda, double[] b, int bIdx, int ldb, double beta, double[] c, int cIdx, int ldc);
+  public static native void zher(char uplo, int n, double alpha, double[] x, int xIdx, int incx, double[] a, int aIdx, int lda);
+  public static native void zherk(char uplo, char trans, int n, int k, double alpha, double[] a, int aIdx, int lda, double beta, double[] c, int cIdx, int ldc);
+  public static native void zhpmv(char uplo, int n, ComplexDouble alpha, double[] ap, int apIdx, double[] x, int xIdx, int incx, ComplexDouble beta, double[] y, int yIdx, int incy);
+  public static native void zhpr2(char uplo, int n, ComplexDouble alpha, double[] x, int xIdx, int incx, double[] y, int yIdx, int incy, double[] ap, int apIdx);
+  public static native void zhpr(char uplo, int n, double alpha, double[] x, int xIdx, int incx, double[] ap, int apIdx);
+  public static native void zrotg(ComplexDouble ca, ComplexDouble cb, double c, ComplexDouble s);
+  public static native void zscal(int n, ComplexDouble za, double[] zx, int zxIdx, int incx);
+  public static native void zswap(int n, double[] zx, int zxIdx, int incx, double[] zy, int zyIdx, int incy);
+  public static native void zsymm(char side, char uplo, int m, int n, ComplexDouble alpha, double[] a, int aIdx, int lda, double[] b, int bIdx, int ldb, ComplexDouble beta, double[] c, int cIdx, int ldc);
+  public static native void zsyr2k(char uplo, char trans, int n, int k, ComplexDouble alpha, double[] a, int aIdx, int lda, double[] b, int bIdx, int ldb, ComplexDouble beta, double[] c, int cIdx, int ldc);
+  public static native void zsyrk(char uplo, char trans, int n, int k, ComplexDouble alpha, double[] a, int aIdx, int lda, ComplexDouble beta, double[] c, int cIdx, int ldc);
+  public static native void ztbmv(char uplo, char trans, char diag, int n, int k, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx);
+  public static native void ztbsv(char uplo, char trans, char diag, int n, int k, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx);
+  public static native void ztpmv(char uplo, char trans, char diag, int n, double[] ap, int apIdx, double[] x, int xIdx, int incx);
+  public static native void ztpsv(char uplo, char trans, char diag, int n, double[] ap, int apIdx, double[] x, int xIdx, int incx);
+  public static native void ztrmm(char side, char uplo, char transa, char diag, int m, int n, ComplexDouble alpha, double[] a, int aIdx, int lda, double[] b, int bIdx, int ldb);
+  public static native void ztrmv(char uplo, char trans, char diag, int n, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx);
+  public static native void ztrsm(char side, char uplo, char transa, char diag, int m, int n, ComplexDouble alpha, double[] a, int aIdx, int lda, double[] b, int bIdx, int ldb);
+  public static native void ztrsv(char uplo, char trans, char diag, int n, double[] a, int aIdx, int lda, double[] x, int xIdx, int incx);
+  public static native int dgesv(int n, int nrhs, double[] a, int aIdx, int lda, int[] ipiv, int ipivIdx, double[] b, int bIdx, int ldb);
+  public static native int sgesv(int n, int nrhs, float[] a, int aIdx, int lda, int[] ipiv, int ipivIdx, float[] b, int bIdx, int ldb);
+  public static native int dsysv(char uplo, int n, int nrhs, double[] a, int aIdx, int lda, int[] ipiv, int ipivIdx, double[] b, int bIdx, int ldb, double[] work, int workIdx, int lwork);
+  public static int dsysv(char uplo, int n, int nrhs, double[] a, int aIdx, int lda, int[] ipiv, int ipivIdx, double[] b, int bIdx, int ldb) {
+    int info;
+    double[] work = new double[1];
+    int lwork;
+    info = dsysv(uplo, n, nrhs, a, aIdx, lda, ipiv, ipivIdx, b, bIdx, ldb, work, 0, -1);
+    if (info != 0)
+      return info;
+    lwork = (int) work[0]; work = new double[lwork];
+    info = dsysv(uplo, n, nrhs, a, aIdx, lda, ipiv, ipivIdx, b, bIdx, ldb, work, 0, lwork);
+    return info;
+  }
+
+  public static native int ssysv(char uplo, int n, int nrhs, float[] a, int aIdx, int lda, int[] ipiv, int ipivIdx, float[] b, int bIdx, int ldb, float[] work, int workIdx, int lwork);
+  public static int ssysv(char uplo, int n, int nrhs, float[] a, int aIdx, int lda, int[] ipiv, int ipivIdx, float[] b, int bIdx, int ldb) {
+    int info;
+    float[] work = new float[1];
+    int lwork;
+    info = ssysv(uplo, n, nrhs, a, aIdx, lda, ipiv, ipivIdx, b, bIdx, ldb, work, 0, -1);
+    if (info != 0)
+      return info;
+    lwork = (int) work[0]; work = new float[lwork];
+    info = ssysv(uplo, n, nrhs, a, aIdx, lda, ipiv, ipivIdx, b, bIdx, ldb, work, 0, lwork);
+    return info;
+  }
+
+  public static native int dsyev(char jobz, char uplo, int n, double[] a, int aIdx, int lda, double[] w, int wIdx, double[] work, int workIdx, int lwork);
+  public static int dsyev(char jobz, char uplo, int n, double[] a, int aIdx, int lda, double[] w, int wIdx) {
+    int info;
+    double[] work = new double[1];
+    int lwork;
+    info = dsyev(jobz, uplo, n, a, aIdx, lda, w, wIdx, work, 0, -1);
+    if (info != 0)
+      return info;
+    lwork = (int) work[0]; work = new double[lwork];
+    info = dsyev(jobz, uplo, n, a, aIdx, lda, w, wIdx, work, 0, lwork);
+    return info;
+  }
+
+  public static native int ssyev(char jobz, char uplo, int n, float[] a, int aIdx, int lda, float[] w, int wIdx, float[] work, int workIdx, int lwork);
+  public static int ssyev(char jobz, char uplo, int n, float[] a, int aIdx, int lda, float[] w, int wIdx) {
+    int info;
+    float[] work = new float[1];
+    int lwork;
+    info = ssyev(jobz, uplo, n, a, aIdx, lda, w, wIdx, work, 0, -1);
+    if (info != 0)
+      return info;
+    lwork = (int) work[0]; work = new float[lwork];
+    info = ssyev(jobz, uplo, n, a, aIdx, lda, w, wIdx, work, 0, lwork);
+    return info;
+  }
+
+  public static native int dsyevd(char jobz, char uplo, int n, double[] a, int aIdx, int lda, double[] w, int wIdx, double[] work, int workIdx, int lwork, int[] iwork, int iworkIdx, int liwork);
+  public static int dsyevd(char jobz, char uplo, int n, double[] a, int aIdx, int lda, double[] w, int wIdx) {
+    int info;
+    double[] work = new double[1];
+    int lwork;
+    int[] iwork = new int[1];
+    int liwork;
+    info = dsyevd(jobz, uplo, n, a, aIdx, lda, w, wIdx, work, 0, -1, iwork, 0, -1);
+    if (info != 0)
+      return info;
+    lwork = (int) work[0]; work = new double[lwork];
+    liwork = (int) iwork[0]; iwork = new int[liwork];
+    info = dsyevd(jobz, uplo, n, a, aIdx, lda, w, wIdx, work, 0, lwork, iwork, 0, liwork);
+    return info;
+  }
+
+  public static native int dsyevr(char jobz, char range, char uplo, int n, double[] a, int aIdx, int lda, double vl, double vu, int il, int iu, double abstol, int[] m, int mIdx, double[] w, int wIdx, double[] z, int zIdx, int ldz, int[] isuppz, int isuppzIdx, double[] work, int workIdx, int lwork, int[] iwork, int iworkIdx, int liwork);
+  public static int dsyevr(char jobz, char range, char uplo, int n, double[] a, int aIdx, int lda, double vl, double vu, int il, int iu, double abstol, int[] m, int mIdx, double[] w, int wIdx, double[] z, int zIdx, int ldz, int[] isuppz, int isuppzIdx) {
+    int info;
+    double[] work = new double[1];
+    int lwork;
+    int[] iwork = new int[1];
+    int liwork;
+    info = dsyevr(jobz, range, uplo, n, a, aIdx, lda, vl, vu, il, iu, abstol, m, mIdx, w, wIdx, z, zIdx, ldz, isuppz, isuppzIdx, work, 0, -1, iwork, 0, -1);
+    if (info != 0)
+      return info;
+    lwork = (int) work[0]; work = new double[lwork];
+    liwork = (int) iwork[0]; iwork = new int[liwork];
+    info = dsyevr(jobz, range, uplo, n, a, aIdx, lda, vl, vu, il, iu, abstol, m, mIdx, w, wIdx, z, zIdx, ldz, isuppz, isuppzIdx, work, 0, lwork, iwork, 0, liwork);
+    return info;
+  }
+
+  public static native int dsyevx(char jobz, char range, char uplo, int n, double[] a, int aIdx, int lda, double vl, double vu, int il, int iu, double abstol, int[] m, int mIdx, double[] w, int wIdx, double[] z, int zIdx, int ldz, double[] work, int workIdx, int lwork, int[] iwork, int iworkIdx, int[] ifail, int ifailIdx);
+  public static int dsyevx(char jobz, char range, char uplo, int n, double[] a, int aIdx, int lda, double vl, double vu, int il, int iu, double abstol, int[] m, int mIdx, double[] w, int wIdx, double[] z, int zIdx, int ldz, int[] iwork, int iworkIdx, int[] ifail, int ifailIdx) {
+    int info;
+    double[] work = new double[1];
+    int lwork;
+    info = dsyevx(jobz, range, uplo, n, a, aIdx, lda, vl, vu, il, iu, abstol, m, mIdx, w, wIdx, z, zIdx, ldz, work, 0, -1, iwork, iworkIdx, ifail, ifailIdx);
+    if (info != 0)
+      return info;
+    lwork = (int) work[0]; work = new double[lwork];
+    info = dsyevx(jobz, range, uplo, n, a, aIdx, lda, vl, vu, il, iu, abstol, m, mIdx, w, wIdx, z, zIdx, ldz, work, 0, lwork, iwork, iworkIdx, ifail, ifailIdx);
+    return info;
+  }
+
+  public static native int ssyevd(char jobz, char uplo, int n, float[] a, int aIdx, int lda, float[] w, int wIdx, float[] work, int workIdx, int lwork, int[] iwork, int iworkIdx, int liwork);
+  public static int ssyevd(char jobz, char uplo, int n, float[] a, int aIdx, int lda, float[] w, int wIdx) {
+    int info;
+    float[] work = new float[1];
+    int lwork;
+    int[] iwork = new int[1];
+    int liwork;
+    info = ssyevd(jobz, uplo, n, a, aIdx, lda, w, wIdx, work, 0, -1, iwork, 0, -1);
+    if (info != 0)
+      return info;
+    lwork = (int) work[0]; work = new float[lwork];
+    liwork = (int) iwork[0]; iwork = new int[liwork];
+    info = ssyevd(jobz, uplo, n, a, aIdx, lda, w, wIdx, work, 0, lwork, iwork, 0, liwork);
+    return info;
+  }
+
+  public static native int ssyevr(char jobz, char range, char uplo, int n, float[] a, int aIdx, int lda, float vl, float vu, int il, int iu, float abstol, int[] m, int mIdx, float[] w, int wIdx, float[] z, int zIdx, int ldz, int[] isuppz, int isuppzIdx, float[] work, int workIdx, int lwork, int[] iwork, int iworkIdx, int liwork);
+  public static int ssyevr(char jobz, char range, char uplo, int n, float[] a, int aIdx, int lda, float vl, float vu, int il, int iu, float abstol, int[] m, int mIdx, float[] w, int wIdx, float[] z, int zIdx, int ldz, int[] isuppz, int isuppzIdx) {
+    int info;
+    float[] work = new float[1];
+    int lwork;
+    int[] iwork = new int[1];
+    int liwork;
+    info = ssyevr(jobz, range, uplo, n, a, aIdx, lda, vl, vu, il, iu, abstol, m, mIdx, w, wIdx, z, zIdx, ldz, isuppz, isuppzIdx, work, 0, -1, iwork, 0, -1);
+    if (info != 0)
+      return info;
+    lwork = (int) work[0]; work = new float[lwork];
+    liwork = (int) iwork[0]; iwork = new int[liwork];
+    info = ssyevr(jobz, range, uplo, n, a, aIdx, lda, vl, vu, il, iu, abstol, m, mIdx, w, wIdx, z, zIdx, ldz, isuppz, isuppzIdx, work, 0, lwork, iwork, 0, liwork);
+    return info;
+  }
+
+  public static native int ssyevx(char jobz, char range, char uplo, int n, float[] a, int aIdx, int lda, float vl, float vu, int il, int iu, float abstol, int[] m, int mIdx, float[] w, int wIdx, float[] z, int zIdx, int ldz, float[] work, int workIdx, int lwork, int[] iwork, int iworkIdx, int[] ifail, int ifailIdx);
+  public static int ssyevx(char jobz, char range, char uplo, int n, float[] a, int aIdx, int lda, float vl, float vu, int il, int iu, float abstol, int[] m, int mIdx, float[] w, int wIdx, float[] z, int zIdx, int ldz, int[] iwork, int iworkIdx, int[] ifail, int ifailIdx) {
+    int info;
+    float[] work = new float[1];
+    int lwork;
+    info = ssyevx(jobz, range, uplo, n, a, aIdx, lda, vl, vu, il, iu, abstol, m, mIdx, w, wIdx, z, zIdx, ldz, work, 0, -1, iwork, iworkIdx, ifail, ifailIdx);
+    if (info != 0)
+      return info;
+    lwork = (int) work[0]; work = new float[lwork];
+    info = ssyevx(jobz, range, uplo, n, a, aIdx, lda, vl, vu, il, iu, abstol, m, mIdx, w, wIdx, z, zIdx, ldz, work, 0, lwork, iwork, iworkIdx, ifail, ifailIdx);
+    return info;
+  }
+
+  public static native int dposv(char uplo, int n, int nrhs, double[] a, int aIdx, int lda, double[] b, int bIdx, int ldb);
+  public static native int sposv(char uplo, int n, int nrhs, float[] a, int aIdx, int lda, float[] b, int bIdx, int ldb);
+  public static native int dgeev(char jobvl, char jobvr, int n, double[] a, int aIdx, int lda, double[] wr, int wrIdx, double[] wi, int wiIdx, double[] vl, int vlIdx, int ldvl, double[] vr, int vrIdx, int ldvr, double[] work, int workIdx, int lwork);
+  public static int dgeev(char jobvl, char jobvr, int n, double[] a, int aIdx, int lda, double[] wr, int wrIdx, double[] wi, int wiIdx, double[] vl, int vlIdx, int ldvl, double[] vr, int vrIdx, int ldvr) {
+    int info;
+    double[] work = new double[1];
+    int lwork;
+    info = dgeev(jobvl, jobvr, n, a, aIdx, lda, wr, wrIdx, wi, wiIdx, vl, vlIdx, ldvl, vr, vrIdx, ldvr, work, 0, -1);
+    if (info != 0)
+      return info;
+    lwork = (int) work[0]; work = new double[lwork];
+    info = dgeev(jobvl, jobvr, n, a, aIdx, lda, wr, wrIdx, wi, wiIdx, vl, vlIdx, ldvl, vr, vrIdx, ldvr, work, 0, lwork);
+    return info;
+  }
+
+  public static native int sgeev(char jobvl, char jobvr, int n, float[] a, int aIdx, int lda, float[] wr, int wrIdx, float[] wi, int wiIdx, float[] vl, int vlIdx, int ldvl, float[] vr, int vrIdx, int ldvr, float[] work, int workIdx, int lwork);
+  public static int sgeev(char jobvl, char jobvr, int n, float[] a, int aIdx, int lda, float[] wr, int wrIdx, float[] wi, int wiIdx, float[] vl, int vlIdx, int ldvl, float[] vr, int vrIdx, int ldvr) {
+    int info;
+    float[] work = new float[1];
+    int lwork;
+    info = sgeev(jobvl, jobvr, n, a, aIdx, lda, wr, wrIdx, wi, wiIdx, vl, vlIdx, ldvl, vr, vrIdx, ldvr, work, 0, -1);
+    if (info != 0)
+      return info;
+    lwork = (int) work[0]; work = new float[lwork];
+    info = sgeev(jobvl, jobvr, n, a, aIdx, lda, wr, wrIdx, wi, wiIdx, vl, vlIdx, ldvl, vr, vrIdx, ldvr, work, 0, lwork);
+    return info;
+  }
+
+
+}
diff --git a/src/org/jblas/la/ComplexDoubleMatrix.java b/src/org/jblas/la/ComplexDoubleMatrix.java
new file mode 100644
index 0000000..f44a292
--- /dev/null
+++ b/src/org/jblas/la/ComplexDoubleMatrix.java
@@ -0,0 +1,2011 @@
+// --- 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.la;
+
+import org.jblas.la.exceptions.SizeException;
+import org.jblas.core.ComplexDouble;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class ComplexDoubleMatrix {
+	
+	public int rows;
+	public int columns;
+	public int length;
+	public double[] data = null; // rows are contiguous
+
+	/**************************************************************************
+	 * 
+	 * Constructors and factory functions
+	 * 
+	 **************************************************************************/
+
+	/** Create a new matrix with <i>newRows</i> rows, <i>newColumns</i> columns
+	 * using <i>newData></i> as the data. The length of the data is not checked!
+	 */
+	public ComplexDoubleMatrix(int newRows, int newColumns, double... newData) {
+		rows = newRows;
+		columns = newColumns;
+		length = rows * columns;
+
+                if (newData.length != 2 * newRows * newColumns)
+			throw new IllegalArgumentException(
+					"Passed data must match matrix dimensions.");
+
+                data = newData;
+	}
+	
+	/**
+	 * Creates a new <i>n</i> times <i>m</i> <tt>ComplexDoubleMatrix</tt>.
+	 * @param newRows the number of rows (<i>n</i>) of the new matrix.
+	 * @param newColumns the number of columns (<i>m</i>) of the new matrix.
+	 */
+	public ComplexDoubleMatrix(int newRows, int newColumns) {
+		this(newRows, newColumns, new double[2 * newRows * newColumns]);
+	}
+	
+	/**
+	 * Creates a new <tt>ComplexDoubleMatrix</tt> of size 0 times 0.
+	 */
+	public ComplexDoubleMatrix() {
+		this(0, 0, null);
+	}
+
+	/**
+	 * Create a Matrix of length <tt>len</tt>. By default, this creates a row vector.
+	 * @param len
+	 */
+	public ComplexDoubleMatrix(int len) {
+		this(len, 1, new double[2 * len]);
+	}
+	
+	public ComplexDoubleMatrix(double[] newData) {
+		this(newData.length/2);
+				
+		data = newData;
+	}
+
+	public ComplexDoubleMatrix(ComplexDouble[] newData) {
+		this(newData.length);
+				
+		for (int i = 0; i < newData.length; i++)
+			put(i, newData[i]);
+	}
+		
+        
+        /** Construct a complex matrix from a real matrix. */
+        public ComplexDoubleMatrix(DoubleMatrix m) {
+            this(m.rows, m.columns);
+            
+            Blas.dcopy(m.length, m.data, 0, 1, data, 0, 2);
+        }
+
+        /** Construct a complex matrix from separate real and imaginary parts. Either 
+         * part can be set to null in which case it will be ignored.
+         */
+        public ComplexDoubleMatrix(DoubleMatrix real, DoubleMatrix imag) {
+            this(real.rows, real.columns);
+            real.assertSameSize(imag);
+            
+            if (real != null)
+                Blas.dcopy(length, real.data, 0, 1, data, 0, 2);
+            if (imag != null)
+                Blas.dcopy(length, imag.data, 0, 1, data, 1, 2);
+        }
+        
+        /**
+	 * Creates a new matrix by reading it from a file.
+	 * @param filename the path and name of the file to read the matrix from
+	 * @throws IOException 
+	 */
+	public ComplexDoubleMatrix(String filename) throws IOException {
+		load(filename);
+	}
+	
+	/**
+	 * Creates a new <i>n</i> times <i>m</i> <tt>ComplexDoubleMatrix</tt> from
+	 * the given <i>n</i> times <i>m</i> 2D data array. The first dimension of the array makes the
+	 * rows (<i>n</i>) and the second dimension the columns (<i>m</i>). For example, the
+	 * given code <br/><br/>
+	 * <code>new ComplexDoubleMatrix(new double[][]{{1d, 2d, 3d}, {4d, 5d, 6d}, {7d, 8d, 9d}}).print();</code><br/><br/>
+	 * will constructs the following matrix:
+	 * <pre>
+	 * 1.0	2.0	3.0
+	 * 4.0	5.0	6.0
+	 * 7.0	8.0	9.0
+	 * </pre>.
+	 * @param data <i>n</i> times <i>m</i> data array
+	 */ 
+	public ComplexDoubleMatrix(double[][] data) {
+		this(data.length, data[0].length);
+						
+		for (int r = 0; r < rows; r++)
+			assert(data[r].length == columns);
+		
+		for (int r = 0; r < rows; r++)
+			for (int c = 0; c < columns; c++)
+				put(r, c, data[r][c]);
+	}
+	
+	/**
+	 * Creates a new matrix in which all values are equal 0.
+	 * @param rows number of rows
+	 * @param columns number of columns
+	 * @return new matrix
+	 */
+	public static ComplexDoubleMatrix zeros(int rows, int columns) {
+		return new ComplexDoubleMatrix(rows, columns);
+	}
+	
+	public static ComplexDoubleMatrix zeros(int length) {
+		return zeros(length, 1);
+	}
+
+	/**
+	 * Creates a new matrix in which all values are equal 1.
+	 * @param rows number of rows
+	 * @param columns number of columns
+	 * @return new matrix
+	 */
+	public static ComplexDoubleMatrix ones(int rows, int columns) {
+		ComplexDoubleMatrix m = new ComplexDoubleMatrix(rows, columns);
+		
+		for (int i = 0; i < rows * columns; i++)
+			m.put(i, 1.0);
+		
+		return m;
+	}
+	
+	public static ComplexDoubleMatrix ones(int length) {
+		return ones(length, 1);
+	}
+	
+	/**
+	 * Creates a new matrix where the values of the given vector are the diagonal values of
+	 * the matrix.
+	 * @param x the diagonal values
+	 * @return new matrix
+	 */
+	public static ComplexDoubleMatrix diag(ComplexDoubleMatrix x) {
+		ComplexDoubleMatrix m = new ComplexDoubleMatrix(x.length, x.length);
+		
+		for (int i = 0; i < x.length; i++)
+			m.put(i, i, x.get(i));
+		
+		return m;
+	}
+	
+	/**
+	 * Create a 1 * 1 - matrix. For many operations, this matrix functions like a
+	 * normal double
+	 * @param s value of the matrix
+	 * @return the constructed ComplexDoubleMatrix 
+	 */
+	public static ComplexDoubleMatrix scalar(double s) {
+		ComplexDoubleMatrix m = new ComplexDoubleMatrix(1, 1);
+		m.put(0, 0, s);
+		return m;
+	}
+	
+	/** Test whether a matrix is scalar */
+	public boolean isScalar() {
+		return length == 1;
+	}
+	
+	/** Return the first element of the matrix */
+	public ComplexDouble scalar() {
+		return get(0);
+	}
+	
+	public static ComplexDoubleMatrix concatHorizontally(ComplexDoubleMatrix A, ComplexDoubleMatrix B) {
+		if (A.rows != B.rows)
+			throw new SizeException("Matrices don't have same number of rows.");
+		
+		ComplexDoubleMatrix result = new ComplexDoubleMatrix(A.rows, A.columns + B.columns);
+		SimpleBlas.copy(A, result);
+		Blas.zcopy(B.length, B.data, 0, 1, result.data, A.length, 1);
+		return result;
+	}
+
+	public static ComplexDoubleMatrix concatVertically(ComplexDoubleMatrix A, ComplexDoubleMatrix B) {
+		if (A.columns != B.columns)
+			throw new SizeException("Matrices don't have same number of columns.");
+		
+		ComplexDoubleMatrix result = new ComplexDoubleMatrix(A.rows + B.rows, A.columns);
+
+		for (int i = 0; i < A.columns; i++) {
+			Blas.zcopy(A.rows, A.data, A.index(0, i), 1, result.data, result.index(0, i), 1);
+			Blas.zcopy(B.rows, B.data, B.index(0, i), 1, result.data, result.index(A.rows, i), 1);
+		}
+		
+		return result;
+	}
+	
+	/**************************************************************************
+	 * Working with slices (Man! 30+ methods just to make this a bit flexible...) 
+	 */
+
+	public ComplexDoubleMatrix get(int[] indices) {
+		ComplexDoubleMatrix result = new ComplexDoubleMatrix(indices.length);
+		
+		for (int i = 0; i < indices.length; i++)
+			result.put(i, get(indices[i]));
+		
+		return result;
+	}
+	
+	public ComplexDoubleMatrix get(int r, int[] indices) {
+		ComplexDoubleMatrix result = new ComplexDoubleMatrix(1, indices.length);
+		
+		for (int i = 0; i < indices.length; i++)
+			result.put(i, get(r, indices[i]));
+		
+		return result;
+	}
+	
+	public ComplexDoubleMatrix get(int[] indices, int c) {
+		ComplexDoubleMatrix result = new ComplexDoubleMatrix(indices.length, c);
+		
+		for (int i = 0; i < indices.length; i++)
+			result.put(i, get(indices[i], c));
+		
+		return result;
+	}
+	
+	public ComplexDoubleMatrix get(int[] rindices, int[] cindices) {
+		ComplexDoubleMatrix result = new ComplexDoubleMatrix(rindices.length, cindices.length);
+		
+		for (int i = 0; i < rindices.length; i++)
+			for (int j = 0; j < cindices.length; j++)
+				result.put(i, j, get(rindices[i], cindices[j]));
+		
+		return result;
+	}
+	
+	public ComplexDoubleMatrix get(ComplexDoubleMatrix indices) {
+		return get(indices.findIndices());
+	}
+
+	public ComplexDoubleMatrix get(int r, ComplexDoubleMatrix indices) {
+		return get(r, indices.findIndices());
+	}
+	
+	public ComplexDoubleMatrix get(ComplexDoubleMatrix indices, int c) {
+		return get(indices.findIndices(), c);
+	}
+
+	public ComplexDoubleMatrix get(ComplexDoubleMatrix rindices, ComplexDoubleMatrix cindices) {
+		return get(rindices.findIndices(), cindices.findIndices());
+	}
+	
+	private void checkLength(int l) {
+		if (length != l)
+			throw new SizeException("Matrix does not have the necessary length (" + length + " != " + l + ").");
+	}
+
+	private void checkRows(int r) {
+		if (rows != r)
+			throw new SizeException("Matrix does not have the necessary length (" + length + " != " + r + ").");
+	}
+	
+	private void checkColumns(int c) {
+		if (columns != c)
+			throw new SizeException("Matrix does not have the necessary length (" + length + " != " + c + ").");
+	}
+
+	public ComplexDoubleMatrix put(int[] indices, ComplexDoubleMatrix x) {
+		if (x.isScalar())
+			return put(indices, x.scalar());
+		x.checkLength(indices.length);
+		
+		for (int i = 0; i < indices.length; i++)
+			put(indices[i], x.get(i));
+		
+		return this;
+	}
+	
+	public ComplexDoubleMatrix put(int r, int[] indices, ComplexDoubleMatrix x) {
+		if (x.isScalar())
+			return put(r, indices, x.scalar());
+		x.checkColumns(indices.length);
+		
+		for (int i = 0; i < indices.length; i++)
+			put(r, indices[i], x.get(i));
+		
+		return this;
+	}
+	
+	public ComplexDoubleMatrix put(int[] indices, int c, ComplexDoubleMatrix x) {
+		if (x.isScalar())
+			return put(indices, c, x.scalar());		
+		x.checkRows(indices.length);
+		
+		for (int i = 0; i < indices.length; i++)
+			put(indices[i], c, x.get(i));
+		
+		return this;
+	}
+	
+	public ComplexDoubleMatrix put(int[] rindices, int[] cindices, ComplexDoubleMatrix x) {
+		if (x.isScalar())
+			return put(rindices, cindices, x.scalar());		
+		x.checkRows(rindices.length);
+		x.checkColumns(cindices.length);
+		
+		for (int i = 0; i < rindices.length; i++)
+			for (int j = 0; j < cindices.length; j++)
+				put(rindices[i], cindices[j], x.get(i,j));
+		
+		return this;
+	}
+	
+	public ComplexDoubleMatrix put(int[] indices, double v) {
+		for (int i = 0; i < indices.length; i++)
+			put(indices[i], v);
+		
+		return this;
+	}
+
+	public ComplexDoubleMatrix putReal(int[] indices, double v) {
+		return put(indices, v);
+	}
+
+	public ComplexDoubleMatrix putImag(int[] indices, double v) {
+		for (int i = 0; i < indices.length; i++)
+			putImag(indices[i], v);
+		
+		return this;
+	}
+
+	public ComplexDoubleMatrix put(int[] indices, ComplexDouble v) {
+		for (int i = 0; i < indices.length; i++)
+			put(indices[i], v);
+		
+		return this;
+	}
+
+	public ComplexDoubleMatrix put(int r, int[] indices, double v) {
+		for (int i = 0; i < indices.length; i++)
+			put(r, indices[i], v);
+		
+		return this;
+	}
+
+	public ComplexDoubleMatrix putReal(int r, int[] indices, double v) {
+		return put(r, indices, v);
+	}
+
+	public ComplexDoubleMatrix putImag(int r, int[] indices, double v) {
+		for (int i = 0; i < indices.length; i++)
+			putImag(r, indices[i], v);
+		
+		return this;
+	}
+
+	public ComplexDoubleMatrix put(int r, int[] indices, ComplexDouble v) {
+		for (int i = 0; i < indices.length; i++)
+			put(r, indices[i], v);
+		
+		return this;
+	}
+
+	public ComplexDoubleMatrix put(int[] indices, int c, double v) {
+		for (int i = 0; i < indices.length; i++)
+			put(indices[i], c, v);
+		
+		return this;
+	}
+	
+	public ComplexDoubleMatrix putReal(int[] indices, int c, double v) {
+		return put(indices, c, v);
+	}
+	
+	public ComplexDoubleMatrix putImag(int[] indices, int c, double v) {
+		for (int i = 0; i < indices.length; i++)
+			putImag(indices[i], c, v);
+		
+		return this;
+	}
+	
+	public ComplexDoubleMatrix put(int[] indices, int c, ComplexDouble v) {
+		for (int i = 0; i < indices.length; i++)
+			put(indices[i], c, v);
+		
+		return this;
+ 	}
+	
+	public ComplexDoubleMatrix put(int[] rindices, int[] cindices, double v) {
+		for (int i = 0; i < rindices.length; i++)
+			for (int j = 0; j < cindices.length; j++)
+				put(rindices[i], cindices[j], v);
+		
+		return this;
+	}
+	
+	public ComplexDoubleMatrix putReal(int[] rindices, int[] cindices, double v) {
+		return put(rindices, cindices, v);
+	}
+	
+	public ComplexDoubleMatrix putImag(int[] rindices, int[] cindices, double v) {
+		for (int i = 0; i < rindices.length; i++)
+			for (int j = 0; j < cindices.length; j++)
+				put(rindices[i], cindices[j], v);
+		
+		return this;
+	}
+
+	public ComplexDoubleMatrix put(int[] rindices, int[] cindices, ComplexDouble v) {
+		for (int i = 0; i < rindices.length; i++)
+			for (int j = 0; j < cindices.length; j++)
+				put(rindices[i], cindices[j], v);
+		
+		return this;
+	}
+
+	public ComplexDoubleMatrix put(ComplexDoubleMatrix indices, ComplexDoubleMatrix v) {
+		return put(indices.findIndices(), v);
+	}
+
+	public ComplexDoubleMatrix put(int r, ComplexDoubleMatrix indices, ComplexDoubleMatrix v) {
+		return put(r, indices.findIndices(), v);
+	}
+	
+	public ComplexDoubleMatrix put(ComplexDoubleMatrix indices, int c, ComplexDoubleMatrix v) {
+		return put(indices.findIndices(), c, v);
+	}
+
+	public ComplexDoubleMatrix put(ComplexDoubleMatrix rindices, ComplexDoubleMatrix cindices, ComplexDoubleMatrix v) {
+		return put(rindices.findIndices(), cindices.findIndices(), v);
+	}
+
+	public ComplexDoubleMatrix put(ComplexDoubleMatrix indices, double v) {
+		return put(indices.findIndices(), v);
+	}
+
+	public ComplexDoubleMatrix putReal(ComplexDoubleMatrix indices, double v) {
+		return put(indices, v);
+	}
+
+	public ComplexDoubleMatrix putImag(ComplexDoubleMatrix indices, double v) {
+		return putImag(indices.findIndices(), v);
+	}
+
+	public ComplexDoubleMatrix put(ComplexDoubleMatrix indices, ComplexDouble v) {
+		return put(indices.findIndices(), v);
+	}
+	
+	public ComplexDoubleMatrix put(int r, ComplexDoubleMatrix indices, double v) {
+		return put(r, indices.findIndices(), v);
+	}
+	
+	public ComplexDoubleMatrix putReal(int r, ComplexDoubleMatrix indices, double v) {
+		return put(r, indices, v);
+	}
+
+	public ComplexDoubleMatrix putImag(int r, ComplexDoubleMatrix indices, double v) {
+		return putImag(r, indices.findIndices(), v);
+	}
+
+	public ComplexDoubleMatrix put(int r, ComplexDoubleMatrix indices, ComplexDouble v) {
+		return put(r, indices.findIndices(), v);
+	}
+
+	public ComplexDoubleMatrix put(ComplexDoubleMatrix indices, int c, double v) {
+		return put(indices.findIndices(), c, v);
+	}
+
+	public ComplexDoubleMatrix putReal(ComplexDoubleMatrix indices, int c, double v) {
+		return put(indices, c, v);
+	}
+
+	public ComplexDoubleMatrix putImag(ComplexDoubleMatrix indices, int c, double v) {
+		return putImag(indices.findIndices(), c, v);
+	}
+
+	public ComplexDoubleMatrix put(ComplexDoubleMatrix indices, int c, ComplexDouble v) {
+		return put(indices.findIndices(), c, v);
+	}
+
+	public ComplexDoubleMatrix put(ComplexDoubleMatrix rindices, ComplexDoubleMatrix cindices, double v) {
+		return put(rindices.findIndices(), cindices.findIndices(), v);
+	}
+
+	public ComplexDoubleMatrix putReal(ComplexDoubleMatrix rindices, ComplexDoubleMatrix cindices, double v) {
+		return putReal(rindices, cindices, v);
+	}
+
+	public ComplexDoubleMatrix putImag(ComplexDoubleMatrix rindices, ComplexDoubleMatrix cindices, double v) {
+		return putImag(rindices.findIndices(), cindices.findIndices(), v);
+	}
+
+	public ComplexDoubleMatrix put(ComplexDoubleMatrix rindices, ComplexDoubleMatrix cindices, ComplexDouble v) {
+		return put(rindices.findIndices(), cindices.findIndices(), v);
+	}
+
+	
+	public int[] findIndices() {
+		int len = 0;
+		for (int i = 0; i < length; i++)
+			if (!get(i).isZero())
+				len++;
+		
+		int[] indices = new int[len];
+		int c = 0;
+		
+		for (int i = 0; i < length; i++)
+			if (!get(i).isZero())
+				indices[c++] = i;
+		
+		return indices;
+	}
+	
+	/**************************************************************************
+	 * Basic operations (copying, resizing, element access)
+	 */
+	
+	/** Return transposed copy of this matrix */
+	public ComplexDoubleMatrix transpose() {
+		ComplexDoubleMatrix result = new ComplexDoubleMatrix(columns, rows);
+		
+		for (int i = 0; i < rows; i++)
+			for (int j = 0; j < columns; j++)
+				result.put(j, i, get(i, j));
+		
+		return result;
+	}
+	
+		
+	/** Compare two matrices.
+	 * @param o Object to compare to
+	 * @return true if and only if other is also a ComplexDoubleMatrix which has the same size and the
+	 * maximal absolute difference in matrix elements is smaller thatn 1e-6.  */
+	public boolean equals(Object o) {
+		if (!(o instanceof ComplexDoubleMatrix))
+			return false;
+
+		ComplexDoubleMatrix other = (ComplexDoubleMatrix) o;
+
+		if (!sameSize(other))
+			return false;
+		
+		DoubleMatrix diff = MatrixFunctions.absi(sub(other)).getReal();
+		
+		return diff.max() / (rows * columns) < 1e-6;
+	}
+
+	
+	/** Resize the matrix. All elements will be set to zero. */
+	public void resize(int newRows, int newColumns) {
+		rows = newRows;
+		columns = newColumns;
+		length = newRows * newColumns;
+		data = new double[2 * rows * columns];
+	}
+
+	
+	/** Reshape the matrix. Number of elements must not change. */
+	public ComplexDoubleMatrix reshape(int newRows, int newColumns) {
+		if (length != newRows * newColumns)
+			throw new IllegalArgumentException(
+					"Number of elements must not change.");
+
+		rows = newRows;
+		columns = newColumns;
+		
+		return this;
+	}
+
+	/** Checks whether two matrices have the same size. */
+	public boolean sameSize(ComplexDoubleMatrix a) {
+		return rows == a.rows && columns == a.columns;
+	}
+
+	/** 
+	 * Assert that two matrices have the same size.
+	 * 
+	 * @param a the other matrix
+	 * @throws SizeException if matrix sizes don't match. 
+	 * */
+	public void assertSameSize(ComplexDoubleMatrix a) {
+		if (!sameSize(a))
+			throw new SizeException("Matrices must have the same size.");
+	}
+	
+	/** 
+	 * Check whether this can be multiplied with a. 
+	 * 
+	 * @param a right-hand-side of the multiplication.
+	 * @return true iff <tt>this.columns == a.rows</tt>
+	 */
+	public boolean multipliesWith(ComplexDoubleMatrix a) {
+		return columns == a.rows;
+	}
+	
+	public void assertMultipliesWith(ComplexDoubleMatrix a) {
+		if (!multipliesWith(a))
+			throw new SizeException("Number of columns of left matrix must be equal to number of rows of right matrix.");
+	}
+	
+	public boolean sameLength(ComplexDoubleMatrix a) {
+		return length == a.length;
+	}
+	
+	public void assertSameLength(ComplexDoubleMatrix a) {
+		if (!sameLength(a))
+			throw new SizeException("Matrices must have same length (is: " + length + " and " + a.length + ")");
+	}
+	
+	/** Copy ComplexDoubleMatrix a to this. this a is resized if necessary. */
+	public ComplexDoubleMatrix copy(ComplexDoubleMatrix a) {
+		if (!sameSize(a))
+			resize(a.rows, a.columns);
+		
+		SimpleBlas.copy(a, this);
+		return a;
+	}
+	
+	/** Returns a duplicate of this matrix. Geometry is the same (including offsets, transpose, etc.),
+	 * but the buffer is not shared.
+	 */
+	public ComplexDoubleMatrix dup() {
+		ComplexDoubleMatrix out = new ComplexDoubleMatrix(rows, columns);
+
+                System.arraycopy(out.data, 0, data, 0, 2 * length);
+		
+		return out;
+	}
+	
+	public ComplexDoubleMatrix swapColumns(int i, int j) {
+		Blas.zswap(rows, data, index(0, i), 1, data, index(0, j), 1);
+		return this;
+	}
+	
+	public ComplexDoubleMatrix swapRows(int i, int j) {
+		Blas.zswap(columns, data, index(i, 0), rows, data, index(j, 0), rows);
+		return this;
+	}
+		
+	/** Set matrix element */
+	public ComplexDoubleMatrix put(int rowIndex, int columnIndex, double value) {
+		data[2*index(rowIndex, columnIndex)] =  value;
+		return this;
+	}
+
+	public ComplexDoubleMatrix put(int rowIndex, int columnIndex, ComplexDouble value) {
+		int i = 2*index(rowIndex, columnIndex);
+		data[i] = value.real(); data[i+1] = value.imag();
+		return this;
+	}
+
+	public ComplexDoubleMatrix putReal(int rowIndex, int columnIndex, double value) {
+		data[2*index(rowIndex, columnIndex)] = value;
+		return this;
+	}
+
+	public ComplexDoubleMatrix putImag(int rowIndex, int columnIndex, double value) {
+		data[2*index(rowIndex, columnIndex)+1] = value;
+		return this;
+	}
+	
+	/** Retrieve matrix element */
+	public ComplexDouble get(int rowIndex, int columnIndex) {
+            int i = 2*index(rowIndex, columnIndex);
+            return new ComplexDouble(data[i], data[i+1]);
+	}
+	
+	public DoubleMatrix getReal() {
+		DoubleMatrix result = new DoubleMatrix(rows, columns);
+		
+		Blas.dcopy(length, data, 0, 2, result.data, 0, 1);
+		
+		return result;
+	}
+
+	/** Get index of an element */
+	public int index(int rowIndex, int columnIndex) {
+		//System.out.printf("Index for (%d, %d) -> %d\n", rowIndex, columnIndex, (rows * columnIndex + rowIndex) * 2);
+		return rows * columnIndex + rowIndex;
+	}
+
+	public ComplexDouble get(int i) {
+		return new ComplexDouble(data[i * 2], data[i * 2 + 1]);
+	}
+	
+        public ComplexDouble get(int i, ComplexDouble result) {
+            return result.set(data[i * 2], data[i*2+1]);
+        }
+        
+	public double getReal(int i) {
+		return data[2*i];
+	}
+	
+	public double getImag(int i) {
+		return data[2*i + 1]; 
+	}
+
+	public ComplexDoubleMatrix put(int i, double v) {
+		data[2*i] = v;
+		return this;
+	}
+	
+	public ComplexDoubleMatrix put(int i, ComplexDouble v) {
+		data[2*i] = v.real();
+		data[2*i+1] = v.imag();
+		return this;
+	}
+	
+	public ComplexDoubleMatrix putReal(int i, double v) {
+		return put(i, v);
+	}
+	
+	public ComplexDoubleMatrix putImag(int i, double v) {
+		data[2*i+1] = v;
+		return this;
+	}
+
+	public int getRows() {
+		return rows;
+	}
+	
+	public int getColumns() {
+		return columns;
+	}
+	
+	public int getLength() {
+		return length;
+	}
+	
+	/** Checks whether the matrix is empty. */
+	public boolean isEmpty() {
+		return columns == 0 || rows == 0;
+	}
+	
+	/** Checks whether the matrix is square. */
+	public boolean isSquare() {
+		return columns == rows;
+	}
+	
+	public void assertSquare() {
+		if (!isSquare())
+			throw new SizeException("Matrix must be square!");
+	}
+	
+	/** Checks whether the matrix is a vector. */
+	public boolean isVector() {
+		return columns == 1 || rows == 1;
+	}
+	
+	public boolean isRowVector() {
+		return columns == 1;
+	}
+	
+	public boolean isColumnVector() {
+		return rows == 1;
+	}
+		
+        /** Get diagonal of the matrix. */
+	public ComplexDoubleMatrix diag() {
+		ComplexDoubleMatrix d = new ComplexDoubleMatrix(rows);
+		Blas.zcopy(rows, data, 0, rows + 1, d.data, 0, 1);
+		return d;
+	}
+        
+        /** Get real part of the matrix. */
+        public DoubleMatrix real() {
+            DoubleMatrix result = new DoubleMatrix(rows, columns);
+            Blas.dcopy(length, data, 0, 2, result.data, 0, 1);
+            return result;
+        }
+        
+        /** Get imaginary part of the matrix. */
+        public DoubleMatrix imag() {
+            DoubleMatrix result = new DoubleMatrix(rows, columns);
+            Blas.dcopy(length, data, 1, 2, result.data, 0, 1);
+            return result;            
+        }
+
+	
+	/** 
+	 * Pretty-print this matrix to <tt>System.out</tt>. 
+	 * */
+	public void print() {
+		System.out.println(toString());
+	}
+
+	/** 
+	 * Generate string representation of this matrix 
+	 * (multi-line).
+	 * */
+	public String toString() {
+		StringBuilder s = new StringBuilder();
+
+		s.append("[");
+		
+		for (int i = 0; i < rows; i++) {
+			for (int j = 0; j < columns; j++) {
+				s.append(get(i, j));
+				if (j < columns - 1)
+					s.append(", ");
+			}
+			if (i < rows - 1)
+				s.append("; ");
+		}
+
+		s.append("]");
+		
+		return s.toString();
+	}
+
+	public double[] toDoubleArray() {
+		double[] array = new double[2*length];
+		
+		for (int i = 0; i < 2*length; i++)
+			array[i] = data[i];
+		
+		return array;
+	}
+	
+	public ComplexDouble[] toArray() {
+		ComplexDouble[] array = new ComplexDouble[length];
+		
+		for (int i = 0; i < length; i++)
+			array[i] = get(i);
+		
+		return array;		
+	}
+	
+	public ComplexDouble[][] toArray2() {
+		ComplexDouble[][] array = new ComplexDouble[rows][columns];
+		
+		for (int r = 0; r < rows; r++)
+			for (int c = 0; c < columns; c++)
+				array[r][c] = get(r, c);
+				
+		return array;
+	}
+	
+	public boolean[] toBooleanArray() {
+		boolean[] array = new boolean[length];
+		
+		for (int i = 0; i < length; i++)
+			array[i] = get(i).isZero() ? false : true;
+		
+		return array;
+	}
+	
+	public boolean[][] toBooleanArray2() {
+		boolean[][] array = new boolean[rows][columns];
+		
+		for (int r = 0; r < rows; r++)
+			for (int c = 0; c < columns; c++)
+				array[r][c] = get(r, c).isZero() ? false : true;
+				
+		return array;
+	}
+
+	/**************************************************************************
+	 * Arithmetic Operations
+	 */
+
+	/** 
+	 * Ensures that the result vector has the same length as this. If not,
+	 * resizing result is tried, which fails if result == this or result == other.
+	 */
+	private void ensureResultLength(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+		if (!sameLength(result)) {
+			if (result == this || result == other)
+				throw new SizeException("Cannot resize result matrix because it is used in-place.");
+			result.resize(rows, columns);
+		}
+	}
+
+	/** Add two matrices. */
+	public ComplexDoubleMatrix addi(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+		if (other.isScalar())
+			return addi(other.scalar(), result);
+		
+		assertSameLength(other);
+		ensureResultLength(other, result);
+		
+		if (result == this)
+			SimpleBlas.axpy(ComplexDouble.UNIT, other, result);
+		else if (result == other)
+			SimpleBlas.axpy(ComplexDouble.UNIT, this, result);
+		else {
+			SimpleBlas.copy(this, result);
+			SimpleBlas.axpy(ComplexDouble.UNIT, other, result);
+		}
+
+		return result;
+	}
+	
+	/** Add a scalar to a matrix. */
+	public ComplexDoubleMatrix addi(ComplexDouble v, ComplexDoubleMatrix result) {
+		ensureResultLength(null, result);
+		
+		for (int i = 0; i < length; i++)
+			result.put(i, get(i).add(v));
+		return result;
+	}
+	
+	public ComplexDoubleMatrix addi(double v, ComplexDoubleMatrix result) {
+		return addi(new ComplexDouble(v), result);
+	}
+
+	/** Subtract two matrices. */
+	public ComplexDoubleMatrix subi(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+		if (other.isScalar())
+			return subi(other.scalar(), result);
+		
+		assertSameLength(other);
+		ensureResultLength(other, result);
+		
+		if (result == this)
+			SimpleBlas.axpy(ComplexDouble.NEG_UNIT, other, result);
+		else if (result == other) {
+			SimpleBlas.scal(ComplexDouble.NEG_UNIT, result);
+			SimpleBlas.axpy(ComplexDouble.UNIT, this, result);
+		}
+		else {
+			SimpleBlas.copy(this, result);
+			SimpleBlas.axpy(ComplexDouble.NEG_UNIT, other, result);
+		}
+		return result;
+	}
+	
+	/** Subtract a scalar from a matrix */
+	public ComplexDoubleMatrix subi(ComplexDouble v, ComplexDoubleMatrix result) {
+		ensureResultLength(null, result);
+		
+		for (int i = 0; i < length; i++)
+			result.put(i, get(i).sub(v));
+		return result;
+	}
+	
+	public ComplexDoubleMatrix subi(double v, ComplexDoubleMatrix result) {
+		return subi(new ComplexDouble(v), result);
+	}
+
+	/** 
+	 * Subtract two matrices, but subtract first from second matrix, that is, 
+	 * compute <em>result = other - this</em>. 
+	 * */
+	public ComplexDoubleMatrix rsubi(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+		return other.subi(this, result);
+	}
+	
+	/** Subtract a matrix from a scalar */
+	public ComplexDoubleMatrix rsubi(ComplexDouble a, ComplexDoubleMatrix result) {
+		ensureResultLength(null, result);
+		
+		for (int i = 0; i < length; i++)
+			result.put(i, a.sub(get(i)));
+		return result;
+	}
+
+	public ComplexDoubleMatrix rsubi(double a, ComplexDoubleMatrix result) {
+		return rsubi(new ComplexDouble(a), result);
+	}
+
+	/** (Elementwise) Multiplication */ 
+	public ComplexDoubleMatrix muli(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+		if (other.isScalar())
+			return muli(other.scalar(), result);
+		
+		assertSameLength(other);
+		ensureResultLength(other, result);
+		
+                ComplexDouble c = new ComplexDouble(0.0);
+                ComplexDouble d = new ComplexDouble(0.0);
+                
+		for (int i = 0; i < length; i++)
+			result.put(i, get(i, c).muli(other.get(i, d)));
+		return result;
+	}
+	
+	/** (Elementwise) Multiplication with a scalar */
+	public ComplexDoubleMatrix muli(ComplexDouble v, ComplexDoubleMatrix result) {
+		ensureResultLength(null, result);
+		
+                ComplexDouble c = new ComplexDouble(0.0);
+                
+		for (int i = 0; i < length; i++)
+			result.put(i, get(i, c).muli(v));
+		return result;
+	}
+
+	public ComplexDoubleMatrix muli(double v, ComplexDoubleMatrix result) {
+		return muli(new ComplexDouble(v), result);
+	}
+
+	/** Matrix-Matrix Multiplication */
+	public ComplexDoubleMatrix mmuli(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+		if (other.isScalar())
+			return muli(other.scalar(), result);
+
+		/* check sizes and resize if necessary */
+		assertMultipliesWith(other);
+		if (result.rows != rows || result.columns != other.columns) {
+			if (result != this && result != other)
+				result.resize(rows, other.columns);
+			else
+				throw new SizeException("Cannot resize result matrix because it is used in-place.");
+		}
+		
+		if (result == this || result == other) {
+			/* actually, blas cannot do multiplications in-place. Therefore, we will fake by
+			 * allocating a temporary object on the side and copy the result later.
+			 */
+			ComplexDoubleMatrix temp = new ComplexDoubleMatrix(result.rows, result.columns);
+			SimpleBlas.gemm(ComplexDouble.UNIT, this, other, ComplexDouble.ZERO, temp);
+			SimpleBlas.copy(temp, result);
+		}
+		else {
+			SimpleBlas.gemm(ComplexDouble.UNIT, this, other, ComplexDouble.ZERO, result);
+		}		
+		return result;
+	}
+	
+	/** Matrix-Matrix Multiplication with a scalar (for symmetry, does the
+	 * same as muli(scalar)
+	 */
+	public ComplexDoubleMatrix mmuli(ComplexDouble v, ComplexDoubleMatrix result) {
+		return muli(v, result);
+	}
+
+	public ComplexDoubleMatrix mmuli(double v, ComplexDoubleMatrix result) {
+		return muli(v, result);
+	}
+	
+	/** (Elementwise) division */
+	public ComplexDoubleMatrix divi(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+		if (other.isScalar())
+			return divi(other.scalar(), result);
+		
+		assertSameLength(other);
+		ensureResultLength(other, result);
+		
+                ComplexDouble c1 = new ComplexDouble(0.0);
+                ComplexDouble c2 = new ComplexDouble(0.0);
+                
+		for (int i = 0; i < length; i++)
+			result.put(i, get(i, c1).divi(other.get(i, c2)));
+		return result;
+	}
+		
+	/** (Elementwise) division with a scalar */
+	public ComplexDoubleMatrix divi(ComplexDouble a, ComplexDoubleMatrix result) {
+		ensureResultLength(null, result);
+		
+                ComplexDouble c = new ComplexDouble(0.0);
+                
+		for (int i = 0; i < length; i++)
+			result.put(i, get(i, c).divi(a));
+		return result;
+	}	
+
+	public ComplexDoubleMatrix divi(double a, ComplexDoubleMatrix result) {
+		return divi(new ComplexDouble(a), result);
+	}
+
+	/** 
+	 * (Elementwise) division, with operands switched. Computes
+	 * <em>result = other / this</em>. */
+	public ComplexDoubleMatrix rdivi(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+		if (other.isScalar())
+			return divi(other.scalar(), result);
+		
+		assertSameLength(other);
+		ensureResultLength(other, result);
+
+                ComplexDouble c1 = new ComplexDouble(0.0);
+                ComplexDouble c2 = new ComplexDouble(0.0);
+
+		for (int i = 0; i < length; i++)
+			result.put(i, other.get(i, c1).divi(get(i, c2)));
+		return result;
+	}
+		
+	/** (Elementwise) division with a scalar, with operands switched. Computes
+	 * <em>result = a / this</em>.*/
+	public ComplexDoubleMatrix rdivi(ComplexDouble a, ComplexDoubleMatrix result) {
+		ensureResultLength(null, result);
+
+                ComplexDouble c1 = new ComplexDouble(0.0);
+                ComplexDouble c2 = new ComplexDouble(0.0);
+
+		for (int i = 0; i < length; i++) {
+                    c1.copy(a);
+                    result.put(i, c1.divi(get(i, c2)));                    
+                }
+		return result;
+	}
+
+	public ComplexDoubleMatrix rdivi(double a, ComplexDoubleMatrix result) {
+		return rdivi(new ComplexDouble(a), result);
+	}
+	
+	public ComplexDoubleMatrix negi() {
+                ComplexDouble c = new ComplexDouble(0.0);
+		for (int i = 0; i < length; i++)
+			put(i, get(i, c).negi());
+		return this;
+	}
+	
+	public ComplexDoubleMatrix neg() {
+		return dup().negi();
+	}
+
+	public ComplexDoubleMatrix noti() {
+                ComplexDouble c = new ComplexDouble(0.0);
+		for (int i = 0; i < length; i++)
+			put(i, get(i, c).isZero() ? 1.0 : 0.0);
+		return this;
+	}
+	
+	public ComplexDoubleMatrix not() {
+		return dup().noti();
+	}
+	
+	public ComplexDoubleMatrix truthi() {
+                ComplexDouble c = new ComplexDouble(0.0);
+		for (int i = 0; i < length; i++)
+			put(i, get(i, c).isZero() ? 0.0 : 1.0);
+		return this;
+	}
+	
+	public ComplexDoubleMatrix truth() {
+		return dup().truthi();
+	}
+        
+        public ComplexDoubleMatrix conji() {
+            ComplexDouble c = new ComplexDouble(0.0);
+            for (int i = 0; i < length; i++)
+                put(i, get(i, c).conji());
+            return this;
+        }
+
+	/****************************************************************
+	 * Rank one-updates
+	 */
+	
+	/** Computes a rank-1-update A = A + alpha * x * y'. */ 
+	public ComplexDoubleMatrix rankOneUpdate(ComplexDouble alpha, ComplexDoubleMatrix x, ComplexDoubleMatrix y) {
+		if (rows != x.length)
+			throw new SizeException("Vector x has wrong length (" + x.length + " != " + rows + ").");
+		if (columns != y.length)
+			throw new SizeException("Vector y has wrong length (" + x.length + " != " + columns + ").");			
+		
+		SimpleBlas.gerc(alpha, x, y, this);
+		return this;
+	}
+
+	public ComplexDoubleMatrix rankOneUpdate(double alpha, ComplexDoubleMatrix x, ComplexDoubleMatrix y) {
+		return rankOneUpdate(new ComplexDouble(alpha), x, y);
+	}
+
+	/** Computes a rank-1-update A = A + alpha * x * x'. */ 
+	public ComplexDoubleMatrix rankOneUpdate(double alpha, ComplexDoubleMatrix x) {
+		return rankOneUpdate(new ComplexDouble(alpha), x, x);
+	}
+
+	/** Computes a rank-1-update A = A + alpha * x * x'. */ 
+	public ComplexDoubleMatrix rankOneUpdate(ComplexDouble alpha, ComplexDoubleMatrix x) {
+		return rankOneUpdate(alpha, x, x);
+	}
+
+	/** Computes a rank-1-update A = A + x * x'. */ 
+	public ComplexDoubleMatrix rankOneUpdate(ComplexDoubleMatrix x) {
+		return rankOneUpdate(1.0, x, x);
+	}
+
+	/** Computes a rank-1-update A = A + x * y'. */ 
+	public ComplexDoubleMatrix rankOneUpdate(ComplexDoubleMatrix x, ComplexDoubleMatrix y) {
+		return rankOneUpdate(1.0, x, y);
+	}
+
+	/****************************************************************
+	 * Logical operations
+	 */
+	
+	public ComplexDouble sum() {
+		ComplexDouble s = new ComplexDouble(0.0);
+                ComplexDouble c = new ComplexDouble(0.0);
+		for (int i = 0; i < length; i++)
+			s.addi(get(i, c));
+		return s;
+	}
+	
+	public ComplexDouble mean() {
+		return sum().div((double)length);
+	}
+	
+	/* computes this^T * other */
+	public ComplexDouble dotc(ComplexDoubleMatrix other) {
+		return SimpleBlas.dotc(this, other);
+	}
+	
+	/* computs this^H * other */
+	public ComplexDouble dotu(ComplexDoubleMatrix other) {
+		return SimpleBlas.dotu(this, other);
+	}
+
+	public double norm2() {
+		return SimpleBlas.nrm2(this);
+	}
+	
+	public double normmax() {
+		int i = SimpleBlas.iamax(this);
+		return get(i).abs();
+	}
+
+	public double norm1() {
+		return SimpleBlas.asum(this);
+	}
+		
+	/** Return a vector containing the sums of the columns (having number of columns many entries) */
+	public ComplexDoubleMatrix columnSums() {
+		ComplexDoubleMatrix v =
+                        new ComplexDoubleMatrix(1, columns);
+
+		for (int c = 0; c < columns; c++)
+			v.put(c, getColumn(c).sum());
+
+		return v;
+	}
+
+	public ComplexDoubleMatrix columnMeans() {
+		return columnSums().divi(rows);
+	}
+	
+	public ComplexDoubleMatrix rowSums() {
+		ComplexDoubleMatrix v = new ComplexDoubleMatrix(rows);
+
+		for (int r = 0; r < rows; r++)
+			v.put(r, getRow(r).sum());
+
+		return v;
+	}
+
+	public ComplexDoubleMatrix rowMeans() {
+		return rowSums().divi(columns);
+	}
+
+	public ComplexDoubleMatrix getColumn(int c) {
+		ComplexDoubleMatrix result = new ComplexDoubleMatrix(rows, 1);
+		Blas.zcopy(rows, data, index(0, c), 1, result.data, 0, 1);
+		return result;
+	}
+	
+	public void putColumn(int c, ComplexDoubleMatrix v) {
+		Blas.zcopy(rows, v.data, 0, 1, data, index(0, c), 1);
+	}
+
+	public ComplexDoubleMatrix getRow(int r) {
+		ComplexDoubleMatrix result = new ComplexDoubleMatrix(1, columns);
+		Blas.zcopy(columns, data, index(r, 0), rows, result.data, 0, 1);
+		return result;
+	}
+	
+	public void putRow(int r, ComplexDoubleMatrix v) {
+		Blas.zcopy(columns, v.data, 0, 1, data, index(r, 0), rows);
+	}
+
+	/**************************************************************************
+	 * Elementwise Functions
+	 */
+
+	/** Add a row vector to all rows of the matrix */
+	public void addRowVector(ComplexDoubleMatrix x) {
+		for (int r = 0; r < rows; r++) {
+			Blas.zaxpy(columns, ComplexDouble.UNIT, x.data, 0, 1, data, index(r, 0), rows);
+		}
+	}
+
+	/** Add a vector to all columns of the matrix */
+	public void addColumnVector(ComplexDoubleMatrix x) {
+		for (int c = 0; c < columns; c++) {
+			Blas.zaxpy(rows, ComplexDouble.UNIT, x.data, 0, 1, data, index(0, c), 1);
+		}
+	}
+
+       	/** Add a row vector to all rows of the matrix */
+	public void subRowVector(ComplexDoubleMatrix x) {
+		for (int r = 0; r < rows; r++) {
+			Blas.zaxpy(columns, ComplexDouble.NEG_UNIT, x.data, 0, 1, data, index(r, 0), rows);
+		}
+	}
+
+	/** Add a vector to all columns of the matrix */
+	public void subColumnVector(ComplexDoubleMatrix x) {
+		for (int c = 0; c < columns; c++) {
+			Blas.zaxpy(rows, ComplexDouble.NEG_UNIT, x.data, 0, 1, data, index(0, c), 1);
+		}
+	}
+
+	/**
+	 * Writes out this matrix to the given data stream.
+	 * @param dos the data output stream to write to.
+	 * @throws IOException 
+	 */
+	public void out(DataOutputStream dos) throws IOException {
+		dos.writeUTF("double");
+		dos.writeInt(columns);
+		dos.writeInt(rows);
+		
+		dos.writeInt(data.length);
+		for(int i=0; i < data.length;i++)
+			dos.writeDouble(data[i]);
+	}
+	
+	/**
+	 * Reads in a matrix from the given data stream. Note
+	 * that the old data of this matrix will be discarded.
+	 * @param dis the data input stream to read from.
+	 * @throws IOException 
+	 */
+	public void in(DataInputStream dis) throws IOException {
+		if(!dis.readUTF().equals("double")) 
+			throw new IllegalStateException("The matrix in the specified file is not of the correct type!");
+		
+		this.columns	= dis.readInt();
+		this.rows		= dis.readInt();
+
+		final int MAX = dis.readInt();
+		data = new double[MAX];
+		for(int i=0; i < MAX;i++)
+			data[i] = dis.readDouble();
+	}	
+	
+	/**
+	 * Saves this matrix to the specified file.
+	 * @param filename the file to write the matrix in.
+	 * @throws IOException thrown on errors while writing the matrix to the file
+	 */
+	public void save(String filename) throws IOException {
+		DataOutputStream dos = new DataOutputStream(new FileOutputStream(filename, false));
+		this.out(dos);
+	}
+	
+	/**
+	 * Loads a matrix from a file into this matrix. Note that the old data
+	 * of this matrix will be discarded.
+	 * @param filename the file to read the matrix from
+	 * @throws IOException thrown on errors while reading the matrix
+	 */
+	public void load(String filename) throws IOException {
+		DataInputStream dis = new DataInputStream(new FileInputStream(filename));
+		this.in(dis);
+	}
+
+	/****************************************************************
+	 * Autogenerated code
+	 */
+	
+	/***** Code for operators ***************************************/ 
+
+	/* Overloads for the usual arithmetic operations */
+	/*#
+	 def gen_overloads(base, result_rows, result_cols); <<-EOS
+	public ComplexDoubleMatrix #{base}i(ComplexDoubleMatrix other) {
+		return #{base}i(other, this);
+	}
+	 	
+	public ComplexDoubleMatrix #{base}(ComplexDoubleMatrix other) {
+	  	return #{base}i(other, new ComplexDoubleMatrix(#{result_rows}, #{result_cols}));
+	}
+
+	public ComplexDoubleMatrix #{base}i(ComplexDouble v) {
+		return #{base}i(v, this);
+	}
+	
+	public ComplexDoubleMatrix #{base}i(double v) {
+		return #{base}i(new ComplexDouble(v), this);
+	}
+
+	public ComplexDoubleMatrix #{base}(ComplexDouble v) {
+		return #{base}i(v, new ComplexDoubleMatrix(rows, columns));
+	} 	
+
+	public ComplexDoubleMatrix #{base}(double v) {
+		return #{base}i(new ComplexDouble(v), new ComplexDoubleMatrix(rows, columns));
+	} 	
+	 	
+	 	EOS
+	  end
+	#*/
+
+	/* Generating code for logical operators. This not only generates the stubs 
+	 * but really all of the code.
+	 */
+	
+	/*#
+	 def gen_compare(name, op); <<-EOS
+	 public ComplexDoubleMatrix #{name}i(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+	    if (other.isScalar())
+	       return #{name}i(other.scalar(), result);
+	       
+	 	assertSameLength(other);
+	 	ensureResultLength(other, result);
+	 	
+                ComplexDouble c1 = new ComplexDouble(0.0);
+                ComplexDouble c2 = new ComplexDouble(0.0);
+          
+                for (int i = 0; i < length; i++)
+                    result.put(i, get(i, c1).#{op}(other.get(i, c2)) ? 1.0 : 0.0);
+	   return result;
+	 }
+	 
+	 public ComplexDoubleMatrix #{name}i(ComplexDoubleMatrix other) {
+	   return #{name}i(other, this);
+	 }
+	 
+	 public ComplexDoubleMatrix #{name}(ComplexDoubleMatrix other) {
+	   return #{name}i(other, new ComplexDoubleMatrix(rows, columns));
+	 }
+	 
+	 public ComplexDoubleMatrix #{name}i(ComplexDouble value, ComplexDoubleMatrix result) {
+	   ensureResultLength(null, result);
+           ComplexDouble c = new ComplexDouble(0.0);
+	   for (int i = 0; i < length; i++)
+	     result.put(i, get(i, c).#{op}(value) ? 1.0 : 0.0);
+	   return result;
+	 }
+
+	 public ComplexDoubleMatrix #{name}i(double value, ComplexDoubleMatrix result) {
+	   return #{name}i(new ComplexDouble(value), result);
+	 }
+
+	 public ComplexDoubleMatrix #{name}i(ComplexDouble value) {
+	   return #{name}i(value, this);
+	 }
+	 
+	 public ComplexDoubleMatrix #{name}i(double value) {
+	   return #{name}i(new ComplexDouble(value));
+	 }
+	 
+	 public ComplexDoubleMatrix #{name}(ComplexDouble value) {
+	   return #{name}i(value, new ComplexDoubleMatrix(rows, columns));
+	 }
+	 
+	 public ComplexDoubleMatrix #{name}(double value) {
+	   return #{name}i(new ComplexDouble(value));
+	 }
+
+	 EOS
+	 end
+	 #*/
+	
+	/*#
+	 def gen_logical(name, op); <<-EOS
+	 public ComplexDoubleMatrix #{name}i(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+	 	assertSameLength(other);
+	 	ensureResultLength(other, result);
+	 	
+                ComplexDouble t1 = new ComplexDouble(0.0);
+                ComplexDouble t2 = new ComplexDouble(0.0);
+         
+               for (int i = 0; i < length; i++)
+                  result.put(i, (!get(i, t1).isZero()) #{op} (!other.get(i, t2).isZero()) ? 1.0 : 0.0);
+	   return result;
+	 }
+	 
+	 public ComplexDoubleMatrix #{name}i(ComplexDoubleMatrix other) {
+	   return #{name}i(other, this);
+	 }
+	 
+	 public ComplexDoubleMatrix #{name}(ComplexDoubleMatrix other) {
+	   return #{name}i(other, new ComplexDoubleMatrix(rows, columns));
+	 }
+	 
+	 public ComplexDoubleMatrix #{name}i(ComplexDouble value, ComplexDoubleMatrix result) {
+	 	ensureResultLength(null, result);
+	 	boolean val = !value.isZero();
+                ComplexDouble t = new ComplexDouble(0.0);
+                for (int i = 0; i < length; i++)
+                     result.put(i, !get(i, t).isZero() #{op} val ? 1.0 : 0.0);
+	   return result;
+	 }
+
+ 	 public ComplexDoubleMatrix #{name}i(double value, ComplexDoubleMatrix result) {
+ 	   return #{name}i(new ComplexDouble(value), result);
+ 	 }
+
+	 public ComplexDoubleMatrix #{name}i(ComplexDouble value) {
+	   return #{name}i(value, this);
+	 }
+
+ 	 public ComplexDoubleMatrix #{name}i(double value) {
+ 	   return #{name}i(new ComplexDouble(value), this);
+ 	 }
+
+	 public ComplexDoubleMatrix #{name}(ComplexDouble value) {
+	   return #{name}i(value, new ComplexDoubleMatrix(rows, columns));
+	 }
+	 
+	 public ComplexDoubleMatrix #{name}(double value) {
+	   return #{name}i(new ComplexDouble(value));
+	 }
+	 EOS
+	 end
+	 #*/
+
+	/*# collect(gen_overloads('add', 'rows', 'columns'),
+	  gen_overloads('sub', 'rows', 'columns'),
+	  gen_overloads('rsub', 'rows', 'columns'),
+	  gen_overloads('div', 'rows', 'columns'),
+	  gen_overloads('rdiv', 'rows', 'columns'),
+	  gen_overloads('mul', 'rows', 'columns'),
+	  gen_overloads('mmul', 'rows', 'other.columns'),
+	  gen_compare('eq', 'eq'),
+	  gen_compare('ne', 'eq'),
+	  gen_logical('and', '&'),
+	  gen_logical('or', '|'),
+	  gen_logical('xor', '^'))
+	 #*/
+//RJPP-BEGIN------------------------------------------------------------
+	public ComplexDoubleMatrix addi(ComplexDoubleMatrix other) {
+		return addi(other, this);
+	}
+	 	
+	public ComplexDoubleMatrix add(ComplexDoubleMatrix other) {
+	  	return addi(other, new ComplexDoubleMatrix(rows, columns));
+	}
+
+	public ComplexDoubleMatrix addi(ComplexDouble v) {
+		return addi(v, this);
+	}
+	
+	public ComplexDoubleMatrix addi(double v) {
+		return addi(new ComplexDouble(v), this);
+	}
+
+	public ComplexDoubleMatrix add(ComplexDouble v) {
+		return addi(v, new ComplexDoubleMatrix(rows, columns));
+	} 	
+
+	public ComplexDoubleMatrix add(double v) {
+		return addi(new ComplexDouble(v), new ComplexDoubleMatrix(rows, columns));
+	} 	
+	 	
+
+	public ComplexDoubleMatrix subi(ComplexDoubleMatrix other) {
+		return subi(other, this);
+	}
+	 	
+	public ComplexDoubleMatrix sub(ComplexDoubleMatrix other) {
+	  	return subi(other, new ComplexDoubleMatrix(rows, columns));
+	}
+
+	public ComplexDoubleMatrix subi(ComplexDouble v) {
+		return subi(v, this);
+	}
+	
+	public ComplexDoubleMatrix subi(double v) {
+		return subi(new ComplexDouble(v), this);
+	}
+
+	public ComplexDoubleMatrix sub(ComplexDouble v) {
+		return subi(v, new ComplexDoubleMatrix(rows, columns));
+	} 	
+
+	public ComplexDoubleMatrix sub(double v) {
+		return subi(new ComplexDouble(v), new ComplexDoubleMatrix(rows, columns));
+	} 	
+	 	
+
+	public ComplexDoubleMatrix rsubi(ComplexDoubleMatrix other) {
+		return rsubi(other, this);
+	}
+	 	
+	public ComplexDoubleMatrix rsub(ComplexDoubleMatrix other) {
+	  	return rsubi(other, new ComplexDoubleMatrix(rows, columns));
+	}
+
+	public ComplexDoubleMatrix rsubi(ComplexDouble v) {
+		return rsubi(v, this);
+	}
+	
+	public ComplexDoubleMatrix rsubi(double v) {
+		return rsubi(new ComplexDouble(v), this);
+	}
+
+	public ComplexDoubleMatrix rsub(ComplexDouble v) {
+		return rsubi(v, new ComplexDoubleMatrix(rows, columns));
+	} 	
+
+	public ComplexDoubleMatrix rsub(double v) {
+		return rsubi(new ComplexDouble(v), new ComplexDoubleMatrix(rows, columns));
+	} 	
+	 	
+
+	public ComplexDoubleMatrix divi(ComplexDoubleMatrix other) {
+		return divi(other, this);
+	}
+	 	
+	public ComplexDoubleMatrix div(ComplexDoubleMatrix other) {
+	  	return divi(other, new ComplexDoubleMatrix(rows, columns));
+	}
+
+	public ComplexDoubleMatrix divi(ComplexDouble v) {
+		return divi(v, this);
+	}
+	
+	public ComplexDoubleMatrix divi(double v) {
+		return divi(new ComplexDouble(v), this);
+	}
+
+	public ComplexDoubleMatrix div(ComplexDouble v) {
+		return divi(v, new ComplexDoubleMatrix(rows, columns));
+	} 	
+
+	public ComplexDoubleMatrix div(double v) {
+		return divi(new ComplexDouble(v), new ComplexDoubleMatrix(rows, columns));
+	} 	
+	 	
+
+	public ComplexDoubleMatrix rdivi(ComplexDoubleMatrix other) {
+		return rdivi(other, this);
+	}
+	 	
+	public ComplexDoubleMatrix rdiv(ComplexDoubleMatrix other) {
+	  	return rdivi(other, new ComplexDoubleMatrix(rows, columns));
+	}
+
+	public ComplexDoubleMatrix rdivi(ComplexDouble v) {
+		return rdivi(v, this);
+	}
+	
+	public ComplexDoubleMatrix rdivi(double v) {
+		return rdivi(new ComplexDouble(v), this);
+	}
+
+	public ComplexDoubleMatrix rdiv(ComplexDouble v) {
+		return rdivi(v, new ComplexDoubleMatrix(rows, columns));
+	} 	
+
+	public ComplexDoubleMatrix rdiv(double v) {
+		return rdivi(new ComplexDouble(v), new ComplexDoubleMatrix(rows, columns));
+	} 	
+	 	
+
+	public ComplexDoubleMatrix muli(ComplexDoubleMatrix other) {
+		return muli(other, this);
+	}
+	 	
+	public ComplexDoubleMatrix mul(ComplexDoubleMatrix other) {
+	  	return muli(other, new ComplexDoubleMatrix(rows, columns));
+	}
+
+	public ComplexDoubleMatrix muli(ComplexDouble v) {
+		return muli(v, this);
+	}
+	
+	public ComplexDoubleMatrix muli(double v) {
+		return muli(new ComplexDouble(v), this);
+	}
+
+	public ComplexDoubleMatrix mul(ComplexDouble v) {
+		return muli(v, new ComplexDoubleMatrix(rows, columns));
+	} 	
+
+	public ComplexDoubleMatrix mul(double v) {
+		return muli(new ComplexDouble(v), new ComplexDoubleMatrix(rows, columns));
+	} 	
+	 	
+
+	public ComplexDoubleMatrix mmuli(ComplexDoubleMatrix other) {
+		return mmuli(other, this);
+	}
+	 	
+	public ComplexDoubleMatrix mmul(ComplexDoubleMatrix other) {
+	  	return mmuli(other, new ComplexDoubleMatrix(rows, other.columns));
+	}
+
+	public ComplexDoubleMatrix mmuli(ComplexDouble v) {
+		return mmuli(v, this);
+	}
+	
+	public ComplexDoubleMatrix mmuli(double v) {
+		return mmuli(new ComplexDouble(v), this);
+	}
+
+	public ComplexDoubleMatrix mmul(ComplexDouble v) {
+		return mmuli(v, new ComplexDoubleMatrix(rows, columns));
+	} 	
+
+	public ComplexDoubleMatrix mmul(double v) {
+		return mmuli(new ComplexDouble(v), new ComplexDoubleMatrix(rows, columns));
+	} 	
+	 	
+
+	 public ComplexDoubleMatrix eqi(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+	    if (other.isScalar())
+	       return eqi(other.scalar(), result);
+	       
+	 	assertSameLength(other);
+	 	ensureResultLength(other, result);
+	 	
+                ComplexDouble c1 = new ComplexDouble(0.0);
+                ComplexDouble c2 = new ComplexDouble(0.0);
+          
+                for (int i = 0; i < length; i++)
+                    result.put(i, get(i, c1).eq(other.get(i, c2)) ? 1.0 : 0.0);
+	   return result;
+	 }
+	 
+	 public ComplexDoubleMatrix eqi(ComplexDoubleMatrix other) {
+	   return eqi(other, this);
+	 }
+	 
+	 public ComplexDoubleMatrix eq(ComplexDoubleMatrix other) {
+	   return eqi(other, new ComplexDoubleMatrix(rows, columns));
+	 }
+	 
+	 public ComplexDoubleMatrix eqi(ComplexDouble value, ComplexDoubleMatrix result) {
+	   ensureResultLength(null, result);
+           ComplexDouble c = new ComplexDouble(0.0);
+	   for (int i = 0; i < length; i++)
+	     result.put(i, get(i, c).eq(value) ? 1.0 : 0.0);
+	   return result;
+	 }
+
+	 public ComplexDoubleMatrix eqi(double value, ComplexDoubleMatrix result) {
+	   return eqi(new ComplexDouble(value), result);
+	 }
+
+	 public ComplexDoubleMatrix eqi(ComplexDouble value) {
+	   return eqi(value, this);
+	 }
+	 
+	 public ComplexDoubleMatrix eqi(double value) {
+	   return eqi(new ComplexDouble(value));
+	 }
+	 
+	 public ComplexDoubleMatrix eq(ComplexDouble value) {
+	   return eqi(value, new ComplexDoubleMatrix(rows, columns));
+	 }
+	 
+	 public ComplexDoubleMatrix eq(double value) {
+	   return eqi(new ComplexDouble(value));
+	 }
+
+
+	 public ComplexDoubleMatrix nei(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+	    if (other.isScalar())
+	       return nei(other.scalar(), result);
+	       
+	 	assertSameLength(other);
+	 	ensureResultLength(other, result);
+	 	
+                ComplexDouble c1 = new ComplexDouble(0.0);
+                ComplexDouble c2 = new ComplexDouble(0.0);
+          
+                for (int i = 0; i < length; i++)
+                    result.put(i, get(i, c1).eq(other.get(i, c2)) ? 1.0 : 0.0);
+	   return result;
+	 }
+	 
+	 public ComplexDoubleMatrix nei(ComplexDoubleMatrix other) {
+	   return nei(other, this);
+	 }
+	 
+	 public ComplexDoubleMatrix ne(ComplexDoubleMatrix other) {
+	   return nei(other, new ComplexDoubleMatrix(rows, columns));
+	 }
+	 
+	 public ComplexDoubleMatrix nei(ComplexDouble value, ComplexDoubleMatrix result) {
+	   ensureResultLength(null, result);
+           ComplexDouble c = new ComplexDouble(0.0);
+	   for (int i = 0; i < length; i++)
+	     result.put(i, get(i, c).eq(value) ? 1.0 : 0.0);
+	   return result;
+	 }
+
+	 public ComplexDoubleMatrix nei(double value, ComplexDoubleMatrix result) {
+	   return nei(new ComplexDouble(value), result);
+	 }
+
+	 public ComplexDoubleMatrix nei(ComplexDouble value) {
+	   return nei(value, this);
+	 }
+	 
+	 public ComplexDoubleMatrix nei(double value) {
+	   return nei(new ComplexDouble(value));
+	 }
+	 
+	 public ComplexDoubleMatrix ne(ComplexDouble value) {
+	   return nei(value, new ComplexDoubleMatrix(rows, columns));
+	 }
+	 
+	 public ComplexDoubleMatrix ne(double value) {
+	   return nei(new ComplexDouble(value));
+	 }
+
+
+	 public ComplexDoubleMatrix andi(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+	 	assertSameLength(other);
+	 	ensureResultLength(other, result);
+	 	
+                ComplexDouble t1 = new ComplexDouble(0.0);
+                ComplexDouble t2 = new ComplexDouble(0.0);
+         
+               for (int i = 0; i < length; i++)
+                  result.put(i, (!get(i, t1).isZero()) & (!other.get(i, t2).isZero()) ? 1.0 : 0.0);
+	   return result;
+	 }
+	 
+	 public ComplexDoubleMatrix andi(ComplexDoubleMatrix other) {
+	   return andi(other, this);
+	 }
+	 
+	 public ComplexDoubleMatrix and(ComplexDoubleMatrix other) {
+	   return andi(other, new ComplexDoubleMatrix(rows, columns));
+	 }
+	 
+	 public ComplexDoubleMatrix andi(ComplexDouble value, ComplexDoubleMatrix result) {
+	 	ensureResultLength(null, result);
+	 	boolean val = !value.isZero();
+                ComplexDouble t = new ComplexDouble(0.0);
+                for (int i = 0; i < length; i++)
+                     result.put(i, !get(i, t).isZero() & val ? 1.0 : 0.0);
+	   return result;
+	 }
+
+ 	 public ComplexDoubleMatrix andi(double value, ComplexDoubleMatrix result) {
+ 	   return andi(new ComplexDouble(value), result);
+ 	 }
+
+	 public ComplexDoubleMatrix andi(ComplexDouble value) {
+	   return andi(value, this);
+	 }
+
+ 	 public ComplexDoubleMatrix andi(double value) {
+ 	   return andi(new ComplexDouble(value), this);
+ 	 }
+
+	 public ComplexDoubleMatrix and(ComplexDouble value) {
+	   return andi(value, new ComplexDoubleMatrix(rows, columns));
+	 }
+	 
+	 public ComplexDoubleMatrix and(double value) {
+	   return andi(new ComplexDouble(value));
+	 }
+
+	 public ComplexDoubleMatrix ori(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+	 	assertSameLength(other);
+	 	ensureResultLength(other, result);
+	 	
+                ComplexDouble t1 = new ComplexDouble(0.0);
+                ComplexDouble t2 = new ComplexDouble(0.0);
+         
+               for (int i = 0; i < length; i++)
+                  result.put(i, (!get(i, t1).isZero()) | (!other.get(i, t2).isZero()) ? 1.0 : 0.0);
+	   return result;
+	 }
+	 
+	 public ComplexDoubleMatrix ori(ComplexDoubleMatrix other) {
+	   return ori(other, this);
+	 }
+	 
+	 public ComplexDoubleMatrix or(ComplexDoubleMatrix other) {
+	   return ori(other, new ComplexDoubleMatrix(rows, columns));
+	 }
+	 
+	 public ComplexDoubleMatrix ori(ComplexDouble value, ComplexDoubleMatrix result) {
+	 	ensureResultLength(null, result);
+	 	boolean val = !value.isZero();
+                ComplexDouble t = new ComplexDouble(0.0);
+                for (int i = 0; i < length; i++)
+                     result.put(i, !get(i, t).isZero() | val ? 1.0 : 0.0);
+	   return result;
+	 }
+
+ 	 public ComplexDoubleMatrix ori(double value, ComplexDoubleMatrix result) {
+ 	   return ori(new ComplexDouble(value), result);
+ 	 }
+
+	 public ComplexDoubleMatrix ori(ComplexDouble value) {
+	   return ori(value, this);
+	 }
+
+ 	 public ComplexDoubleMatrix ori(double value) {
+ 	   return ori(new ComplexDouble(value), this);
+ 	 }
+
+	 public ComplexDoubleMatrix or(ComplexDouble value) {
+	   return ori(value, new ComplexDoubleMatrix(rows, columns));
+	 }
+	 
+	 public ComplexDoubleMatrix or(double value) {
+	   return ori(new ComplexDouble(value));
+	 }
+
+	 public ComplexDoubleMatrix xori(ComplexDoubleMatrix other, ComplexDoubleMatrix result) {
+	 	assertSameLength(other);
+	 	ensureResultLength(other, result);
+	 	
+                ComplexDouble t1 = new ComplexDouble(0.0);
+                ComplexDouble t2 = new ComplexDouble(0.0);
+         
+               for (int i = 0; i < length; i++)
+                  result.put(i, (!get(i, t1).isZero()) ^ (!other.get(i, t2).isZero()) ? 1.0 : 0.0);
+	   return result;
+	 }
+	 
+	 public ComplexDoubleMatrix xori(ComplexDoubleMatrix other) {
+	   return xori(other, this);
+	 }
+	 
+	 public ComplexDoubleMatrix xor(ComplexDoubleMatrix other) {
+	   return xori(other, new ComplexDoubleMatrix(rows, columns));
+	 }
+	 
+	 public ComplexDoubleMatrix xori(ComplexDouble value, ComplexDoubleMatrix result) {
+	 	ensureResultLength(null, result);
+	 	boolean val = !value.isZero();
+                ComplexDouble t = new ComplexDouble(0.0);
+                for (int i = 0; i < length; i++)
+                     result.put(i, !get(i, t).isZero() ^ val ? 1.0 : 0.0);
+	   return result;
+	 }
+
+ 	 public ComplexDoubleMatrix xori(double value, ComplexDoubleMatrix result) {
+ 	   return xori(new ComplexDouble(value), result);
+ 	 }
+
+	 public ComplexDoubleMatrix xori(ComplexDouble value) {
+	   return xori(value, this);
+	 }
+
+ 	 public ComplexDoubleMatrix xori(double value) {
+ 	   return xori(new ComplexDouble(value), this);
+ 	 }
+
+	 public ComplexDoubleMatrix xor(ComplexDouble value) {
+	   return xori(value, new ComplexDoubleMatrix(rows, columns));
+	 }
+	 
+	 public ComplexDoubleMatrix xor(double value) {
+	   return xori(new ComplexDouble(value));
+	 }
+//RJPP-END--------------------------------------------------------------
+}
diff --git a/src/org/jblas/la/ComplexFloatMatrix.java b/src/org/jblas/la/ComplexFloatMatrix.java
new file mode 100644
index 0000000..1750df0
--- /dev/null
+++ b/src/org/jblas/la/ComplexFloatMatrix.java
@@ -0,0 +1,2011 @@
+// --- 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.la;
+
+import org.jblas.la.exceptions.SizeException;
+import org.jblas.core.ComplexFloat;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class ComplexFloatMatrix {
+	
+	public int rows;
+	public int columns;
+	public int length;
+	public float[] data = null; // rows are contiguous
+
+	/**************************************************************************
+	 * 
+	 * Constructors and factory functions
+	 * 
+	 **************************************************************************/
+
+	/** Create a new matrix with <i>newRows</i> rows, <i>newColumns</i> columns
+	 * using <i>newData></i> as the data. The length of the data is not checked!
+	 */
+	public ComplexFloatMatrix(int newRows, int newColumns, float... newData) {
+		rows = newRows;
+		columns = newColumns;
+		length = rows * columns;
+
+                if (newData.length != 2 * newRows * newColumns)
+			throw new IllegalArgumentException(
+					"Passed data must match matrix dimensions.");
+
+                data = newData;
+	}
+	
+	/**
+	 * Creates a new <i>n</i> times <i>m</i> <tt>ComplexFloatMatrix</tt>.
+	 * @param newRows the number of rows (<i>n</i>) of the new matrix.
+	 * @param newColumns the number of columns (<i>m</i>) of the new matrix.
+	 */
+	public ComplexFloatMatrix(int newRows, int newColumns) {
+		this(newRows, newColumns, new float[2 * newRows * newColumns]);
+	}
+	
+	/**
+	 * Creates a new <tt>ComplexFloatMatrix</tt> of size 0 times 0.
+	 */
+	public ComplexFloatMatrix() {
+		this(0, 0, null);
+	}
+
+	/**
+	 * Create a Matrix of length <tt>len</tt>. By default, this creates a row vector.
+	 * @param len
+	 */
+	public ComplexFloatMatrix(int len) {
+		this(len, 1, new float[2 * len]);
+	}
+	
+	public ComplexFloatMatrix(float[] newData) {
+		this(newData.length/2);
+				
+		data = newData;
+	}
+
+	public ComplexFloatMatrix(ComplexFloat[] newData) {
+		this(newData.length);
+				
+		for (int i = 0; i < newData.length; i++)
+			put(i, newData[i]);
+	}
+		
+        
+        /** Construct a complex matrix from a real matrix. */
+        public ComplexFloatMatrix(FloatMatrix m) {
+            this(m.rows, m.columns);
+            
+            Blas.scopy(m.length, m.data, 0, 1, data, 0, 2);
+        }
+
+        /** Construct a complex matrix from separate real and imaginary parts. Either 
+         * part can be set to null in which case it will be ignored.
+         */
+        public ComplexFloatMatrix(FloatMatrix real, FloatMatrix imag) {
+            this(real.rows, real.columns);
+            real.assertSameSize(imag);
+            
+            if (real != null)
+                Blas.scopy(length, real.data, 0, 1, data, 0, 2);
+            if (imag != null)
+                Blas.scopy(length, imag.data, 0, 1, data, 1, 2);
+        }
+        
+        /**
+	 * Creates a new matrix by reading it from a file.
+	 * @param filename the path and name of the file to read the matrix from
+	 * @throws IOException 
+	 */
+	public ComplexFloatMatrix(String filename) throws IOException {
+		load(filename);
+	}
+	
+	/**
+	 * Creates a new <i>n</i> times <i>m</i> <tt>ComplexFloatMatrix</tt> from
+	 * the given <i>n</i> times <i>m</i> 2D data array. The first dimension of the array makes the
+	 * rows (<i>n</i>) and the second dimension the columns (<i>m</i>). For example, the
+	 * given code <br/><br/>
+	 * <code>new ComplexFloatMatrix(new float[][]{{1d, 2d, 3d}, {4d, 5d, 6d}, {7d, 8d, 9d}}).print();</code><br/><br/>
+	 * will constructs the following matrix:
+	 * <pre>
+	 * 1.0f	2.0f	3.0f
+	 * 4.0f	5.0f	6.0f
+	 * 7.0f	8.0f	9.0f
+	 * </pre>.
+	 * @param data <i>n</i> times <i>m</i> data array
+	 */ 
+	public ComplexFloatMatrix(float[][] data) {
+		this(data.length, data[0].length);
+						
+		for (int r = 0; r < rows; r++)
+			assert(data[r].length == columns);
+		
+		for (int r = 0; r < rows; r++)
+			for (int c = 0; c < columns; c++)
+				put(r, c, data[r][c]);
+	}
+	
+	/**
+	 * Creates a new matrix in which all values are equal 0.
+	 * @param rows number of rows
+	 * @param columns number of columns
+	 * @return new matrix
+	 */
+	public static ComplexFloatMatrix zeros(int rows, int columns) {
+		return new ComplexFloatMatrix(rows, columns);
+	}
+	
+	public static ComplexFloatMatrix zeros(int length) {
+		return zeros(length, 1);
+	}
+
+	/**
+	 * Creates a new matrix in which all values are equal 1.
+	 * @param rows number of rows
+	 * @param columns number of columns
+	 * @return new matrix
+	 */
+	public static ComplexFloatMatrix ones(int rows, int columns) {
+		ComplexFloatMatrix m = new ComplexFloatMatrix(rows, columns);
+		
+		for (int i = 0; i < rows * columns; i++)
+			m.put(i, 1.0f);
+		
+		return m;
+	}
+	
+	public static ComplexFloatMatrix ones(int length) {
+		return ones(length, 1);
+	}
+	
+	/**
+	 * Creates a new matrix where the values of the given vector are the diagonal values of
+	 * the matrix.
+	 * @param x the diagonal values
+	 * @return new matrix
+	 */
+	public static ComplexFloatMatrix diag(ComplexFloatMatrix x) {
+		ComplexFloatMatrix m = new ComplexFloatMatrix(x.length, x.length);
+		
+		for (int i = 0; i < x.length; i++)
+			m.put(i, i, x.get(i));
+		
+		return m;
+	}
+	
+	/**
+	 * Create a 1 * 1 - matrix. For many operations, this matrix functions like a
+	 * normal float
+	 * @param s value of the matrix
+	 * @return the constructed ComplexFloatMatrix 
+	 */
+	public static ComplexFloatMatrix scalar(float s) {
+		ComplexFloatMatrix m = new ComplexFloatMatrix(1, 1);
+		m.put(0, 0, s);
+		return m;
+	}
+	
+	/** Test whether a matrix is scalar */
+	public boolean isScalar() {
+		return length == 1;
+	}
+	
+	/** Return the first element of the matrix */
+	public ComplexFloat scalar() {
+		return get(0);
+	}
+	
+	public static ComplexFloatMatrix concatHorizontally(ComplexFloatMatrix A, ComplexFloatMatrix B) {
+		if (A.rows != B.rows)
+			throw new SizeException("Matrices don't have same number of rows.");
+		
+		ComplexFloatMatrix result = new ComplexFloatMatrix(A.rows, A.columns + B.columns);
+		SimpleBlas.copy(A, result);
+		Blas.ccopy(B.length, B.data, 0, 1, result.data, A.length, 1);
+		return result;
+	}
+
+	public static ComplexFloatMatrix concatVertically(ComplexFloatMatrix A, ComplexFloatMatrix B) {
+		if (A.columns != B.columns)
+			throw new SizeException("Matrices don't have same number of columns.");
+		
+		ComplexFloatMatrix result = new ComplexFloatMatrix(A.rows + B.rows, A.columns);
+
+		for (int i = 0; i < A.columns; i++) {
+			Blas.ccopy(A.rows, A.data, A.index(0, i), 1, result.data, result.index(0, i), 1);
+			Blas.ccopy(B.rows, B.data, B.index(0, i), 1, result.data, result.index(A.rows, i), 1);
+		}
+		
+		return result;
+	}
+	
+	/**************************************************************************
+	 * Working with slices (Man! 30+ methods just to make this a bit flexible...) 
+	 */
+
+	public ComplexFloatMatrix get(int[] indices) {
+		ComplexFloatMatrix result = new ComplexFloatMatrix(indices.length);
+		
+		for (int i = 0; i < indices.length; i++)
+			result.put(i, get(indices[i]));
+		
+		return result;
+	}
+	
+	public ComplexFloatMatrix get(int r, int[] indices) {
+		ComplexFloatMatrix result = new ComplexFloatMatrix(1, indices.length);
+		
+		for (int i = 0; i < indices.length; i++)
+			result.put(i, get(r, indices[i]));
+		
+		return result;
+	}
+	
+	public ComplexFloatMatrix get(int[] indices, int c) {
+		ComplexFloatMatrix result = new ComplexFloatMatrix(indices.length, c);
+		
+		for (int i = 0; i < indices.length; i++)
+			result.put(i, get(indices[i], c));
+		
+		return result;
+	}
+	
+	public ComplexFloatMatrix get(int[] rindices, int[] cindices) {
+		ComplexFloatMatrix result = new ComplexFloatMatrix(rindices.length, cindices.length);
+		
+		for (int i = 0; i < rindices.length; i++)
+			for (int j = 0; j < cindices.length; j++)
+				result.put(i, j, get(rindices[i], cindices[j]));
+		
+		return result;
+	}
+	
+	public ComplexFloatMatrix get(ComplexFloatMatrix indices) {
+		return get(indices.findIndices());
+	}
+
+	public ComplexFloatMatrix get(int r, ComplexFloatMatrix indices) {
+		return get(r, indices.findIndices());
+	}
+	
+	public ComplexFloatMatrix get(ComplexFloatMatrix indices, int c) {
+		return get(indices.findIndices(), c);
+	}
+
+	public ComplexFloatMatrix get(ComplexFloatMatrix rindices, ComplexFloatMatrix cindices) {
+		return get(rindices.findIndices(), cindices.findIndices());
+	}
+	
+	private void checkLength(int l) {
+		if (length != l)
+			throw new SizeException("Matrix does not have the necessary length (" + length + " != " + l + ").");
+	}
+
+	private void checkRows(int r) {
+		if (rows != r)
+			throw new SizeException("Matrix does not have the necessary length (" + length + " != " + r + ").");
+	}
+	
+	private void checkColumns(int c) {
+		if (columns != c)
+			throw new SizeException("Matrix does not have the necessary length (" + length + " != " + c + ").");
+	}
+
+	public ComplexFloatMatrix put(int[] indices, ComplexFloatMatrix x) {
+		if (x.isScalar())
+			return put(indices, x.scalar());
+		x.checkLength(indices.length);
+		
+		for (int i = 0; i < indices.length; i++)
+			put(indices[i], x.get(i));
+		
+		return this;
+	}
+	
+	public ComplexFloatMatrix put(int r, int[] indices, ComplexFloatMatrix x) {
+		if (x.isScalar())
+			return put(r, indices, x.scalar());
+		x.checkColumns(indices.length);
+		
+		for (int i = 0; i < indices.length; i++)
+			put(r, indices[i], x.get(i));
+		
+		return this;
+	}
+	
+	public ComplexFloatMatrix put(int[] indices, int c, ComplexFloatMatrix x) {
+		if (x.isScalar())
+			return put(indices, c, x.scalar());		
+		x.checkRows(indices.length);
+		
+		for (int i = 0; i < indices.length; i++)
+			put(indices[i], c, x.get(i));
+		
+		return this;
+	}
+	
+	public ComplexFloatMatrix put(int[] rindices, int[] cindices, ComplexFloatMatrix x) {
+		if (x.isScalar())
+			return put(rindices, cindices, x.scalar());		
+		x.checkRows(rindices.length);
+		x.checkColumns(cindices.length);
+		
+		for (int i = 0; i < rindices.length; i++)
+			for (int j = 0; j < cindices.length; j++)
+				put(rindices[i], cindices[j], x.get(i,j));
+		
+		return this;
+	}
+	
+	public ComplexFloatMatrix put(int[] indices, float v) {
+		for (int i = 0; i < indices.length; i++)
+			put(indices[i], v);
+		
+		return this;
+	}
+
+	public ComplexFloatMatrix putReal(int[] indices, float v) {
+		return put(indices, v);
+	}
+
+	public ComplexFloatMatrix putImag(int[] indices, float v) {
+		for (int i = 0; i < indices.length; i++)
+			putImag(indices[i], v);
+		
+		return this;
+	}
+
+	public ComplexFloatMatrix put(int[] indices, ComplexFloat v) {
+		for (int i = 0; i < indices.length; i++)
+			put(indices[i], v);
+		
+		return this;
+	}
+
+	public ComplexFloatMatrix put(int r, int[] indices, float v) {
+		for (int i = 0; i < indices.length; i++)
+			put(r, indices[i], v);
+		
+		return this;
+	}
+
+	public ComplexFloatMatrix putReal(int r, int[] indices, float v) {
+		return put(r, indices, v);
+	}
+
+	public ComplexFloatMatrix putImag(int r, int[] indices, float v) {
+		for (int i = 0; i < indices.length; i++)
+			putImag(r, indices[i], v);
+		
+		return this;
+	}
+
+	public ComplexFloatMatrix put(int r, int[] indices, ComplexFloat v) {
+		for (int i = 0; i < indices.length; i++)
+			put(r, indices[i], v);
+		
+		return this;
+	}
+
+	public ComplexFloatMatrix put(int[] indices, int c, float v) {
+		for (int i = 0; i < indices.length; i++)
+			put(indices[i], c, v);
+		
+		return this;
+	}
+	
+	public ComplexFloatMatrix putReal(int[] indices, int c, float v) {
+		return put(indices, c, v);
+	}
+	
+	public ComplexFloatMatrix putImag(int[] indices, int c, float v) {
+		for (int i = 0; i < indices.length; i++)
+			putImag(indices[i], c, v);
+		
+		return this;
+	}
+	
+	public ComplexFloatMatrix put(int[] indices, int c, ComplexFloat v) {
+		for (int i = 0; i < indices.length; i++)
+			put(indices[i], c, v);
+		
+		return this;
+ 	}
+	
+	public ComplexFloatMatrix put(int[] rindices, int[] cindices, float v) {
+		for (int i = 0; i < rindices.length; i++)
+			for (int j = 0; j < cindices.length; j++)
+				put(rindices[i], cindices[j], v);
+		
+		return this;
+	}
+	
+	public ComplexFloatMatrix putReal(int[] rindices, int[] cindices, float v) {
+		return put(rindices, cindices, v);
+	}
+	
+	public ComplexFloatMatrix putImag(int[] rindices, int[] cindices, float v) {
+		for (int i = 0; i < rindices.length; i++)
+			for (int j = 0; j < cindices.length; j++)
+				put(rindices[i], cindices[j], v);
+		
+		return this;
+	}
+
+	public ComplexFloatMatrix put(int[] rindices, int[] cindices, ComplexFloat v) {
+		for (int i = 0; i < rindices.length; i++)
+			for (int j = 0; j < cindices.length; j++)
+				put(rindices[i], cindices[j], v);
+		
+		return this;
+	}
+
+	public ComplexFloatMatrix put(ComplexFloatMatrix indices, ComplexFloatMatrix v) {
+		return put(indices.findIndices(), v);
+	}
+
+	public ComplexFloatMatrix put(int r, ComplexFloatMatrix indices, ComplexFloatMatrix v) {
+		return put(r, indices.findIndices(), v);
+	}
+	
+	public ComplexFloatMatrix put(ComplexFloatMatrix indices, int c, ComplexFloatMatrix v) {
+		return put(indices.findIndices(), c, v);
+	}
+
+	public ComplexFloatMatrix put(ComplexFloatMatrix rindices, ComplexFloatMatrix cindices, ComplexFloatMatrix v) {
+		return put(rindices.findIndices(), cindices.findIndices(), v);
+	}
+
+	public ComplexFloatMatrix put(ComplexFloatMatrix indices, float v) {
+		return put(indices.findIndices(), v);
+	}
+
+	public ComplexFloatMatrix putReal(ComplexFloatMatrix indices, float v) {
+		return put(indices, v);
+	}
+
+	public ComplexFloatMatrix putImag(ComplexFloatMatrix indices, float v) {
+		return putImag(indices.findIndices(), v);
+	}
+
+	public ComplexFloatMatrix put(ComplexFloatMatrix indices, ComplexFloat v) {
+		return put(indices.findIndices(), v);
+	}
+	
+	public ComplexFloatMatrix put(int r, ComplexFloatMatrix indices, float v) {
+		return put(r, indices.findIndices(), v);
+	}
+	
+	public ComplexFloatMatrix putReal(int r, ComplexFloatMatrix indices, float v) {
+		return put(r, indices, v);
+	}
+
+	public ComplexFloatMatrix putImag(int r, ComplexFloatMatrix indices, float v) {
+		return putImag(r, indices.findIndices(), v);
+	}
+
+	public ComplexFloatMatrix put(int r, ComplexFloatMatrix indices, ComplexFloat v) {
+		return put(r, indices.findIndices(), v);
+	}
+
+	public ComplexFloatMatrix put(ComplexFloatMatrix indices, int c, float v) {
+		return put(indices.findIndices(), c, v);
+	}
+
+	public ComplexFloatMatrix putReal(ComplexFloatMatrix indices, int c, float v) {
+		return put(indices, c, v);
+	}
+
+	public ComplexFloatMatrix putImag(ComplexFloatMatrix indices, int c, float v) {
+		return putImag(indices.findIndices(), c, v);
+	}
+
+	public ComplexFloatMatrix put(ComplexFloatMatrix indices, int c, ComplexFloat v) {
+		return put(indices.findIndices(), c, v);
+	}
+
+	public ComplexFloatMatrix put(ComplexFloatMatrix rindices, ComplexFloatMatrix cindices, float v) {
+		return put(rindices.findIndices(), cindices.findIndices(), v);
+	}
+
+	public ComplexFloatMatrix putReal(ComplexFloatMatrix rindices, ComplexFloatMatrix cindices, float v) {
+		return putReal(rindices, cindices, v);
+	}
+
+	public ComplexFloatMatrix putImag(ComplexFloatMatrix rindices, ComplexFloatMatrix cindices, float v) {
+		return putImag(rindices.findIndices(), cindices.findIndices(), v);
+	}
+
+	public ComplexFloatMatrix put(ComplexFloatMatrix rindices, ComplexFloatMatrix cindices, ComplexFloat v) {
+		return put(rindices.findIndices(), cindices.findIndices(), v);
+	}
+
+	
+	public int[] findIndices() {
+		int len = 0;
+		for (int i = 0; i < length; i++)
+			if (!get(i).isZero())
+				len++;
+		
+		int[] indices = new int[len];
+		int c = 0;
+		
+		for (int i = 0; i < length; i++)
+			if (!get(i).isZero())
+				indices[c++] = i;
+		
+		return indices;
+	}
+	
+	/**************************************************************************
+	 * Basic operations (copying, resizing, element access)
+	 */
+	
+	/** Return transposed copy of this matrix */
+	public ComplexFloatMatrix transpose() {
+		ComplexFloatMatrix result = new ComplexFloatMatrix(columns, rows);
+		
+		for (int i = 0; i < rows; i++)
+			for (int j = 0; j < columns; j++)
+				result.put(j, i, get(i, j));
+		
+		return result;
+	}
+	
+		
+	/** Compare two matrices.
+	 * @param o Object to compare to
+	 * @return true if and only if other is also a ComplexFloatMatrix which has the same size and the
+	 * maximal absolute difference in matrix elements is smaller thatn 1e-6.  */
+	public boolean equals(Object o) {
+		if (!(o instanceof ComplexFloatMatrix))
+			return false;
+
+		ComplexFloatMatrix other = (ComplexFloatMatrix) o;
+
+		if (!sameSize(other))
+			return false;
+		
+		FloatMatrix diff = MatrixFunctions.absi(sub(other)).getReal();
+		
+		return diff.max() / (rows * columns) < 1e-6;
+	}
+
+	
+	/** Resize the matrix. All elements will be set to zero. */
+	public void resize(int newRows, int newColumns) {
+		rows = newRows;
+		columns = newColumns;
+		length = newRows * newColumns;
+		data = new float[2 * rows * columns];
+	}
+
+	
+	/** Reshape the matrix. Number of elements must not change. */
+	public ComplexFloatMatrix reshape(int newRows, int newColumns) {
+		if (length != newRows * newColumns)
+			throw new IllegalArgumentException(
+					"Number of elements must not change.");
+
+		rows = newRows;
+		columns = newColumns;
+		
+		return this;
+	}
+
+	/** Checks whether two matrices have the same size. */
+	public boolean sameSize(ComplexFloatMatrix a) {
+		return rows == a.rows && columns == a.columns;
+	}
+
+	/** 
+	 * Assert that two matrices have the same size.
+	 * 
+	 * @param a the other matrix
+	 * @throws SizeException if matrix sizes don't match. 
+	 * */
+	public void assertSameSize(ComplexFloatMatrix a) {
+		if (!sameSize(a))
+			throw new SizeException("Matrices must have the same size.");
+	}
+	
+	/** 
+	 * Check whether this can be multiplied with a. 
+	 * 
+	 * @param a right-hand-side of the multiplication.
+	 * @return true iff <tt>this.columns == a.rows</tt>
+	 */
+	public boolean multipliesWith(ComplexFloatMatrix a) {
+		return columns == a.rows;
+	}
+	
+	public void assertMultipliesWith(ComplexFloatMatrix a) {
+		if (!multipliesWith(a))
+			throw new SizeException("Number of columns of left matrix must be equal to number of rows of right matrix.");
+	}
+	
+	public boolean sameLength(ComplexFloatMatrix a) {
+		return length == a.length;
+	}
+	
+	public void assertSameLength(ComplexFloatMatrix a) {
+		if (!sameLength(a))
+			throw new SizeException("Matrices must have same length (is: " + length + " and " + a.length + ")");
+	}
+	
+	/** Copy ComplexFloatMatrix a to this. this a is resized if necessary. */
+	public ComplexFloatMatrix copy(ComplexFloatMatrix a) {
+		if (!sameSize(a))
+			resize(a.rows, a.columns);
+		
+		SimpleBlas.copy(a, this);
+		return a;
+	}
+	
+	/** Returns a duplicate of this matrix. Geometry is the same (including offsets, transpose, etc.),
+	 * but the buffer is not shared.
+	 */
+	public ComplexFloatMatrix dup() {
+		ComplexFloatMatrix out = new ComplexFloatMatrix(rows, columns);
+
+                System.arraycopy(out.data, 0, data, 0, 2 * length);
+		
+		return out;
+	}
+	
+	public ComplexFloatMatrix swapColumns(int i, int j) {
+		Blas.cswap(rows, data, index(0, i), 1, data, index(0, j), 1);
+		return this;
+	}
+	
+	public ComplexFloatMatrix swapRows(int i, int j) {
+		Blas.cswap(columns, data, index(i, 0), rows, data, index(j, 0), rows);
+		return this;
+	}
+		
+	/** Set matrix element */
+	public ComplexFloatMatrix put(int rowIndex, int columnIndex, float value) {
+		data[2*index(rowIndex, columnIndex)] =  value;
+		return this;
+	}
+
+	public ComplexFloatMatrix put(int rowIndex, int columnIndex, ComplexFloat value) {
+		int i = 2*index(rowIndex, columnIndex);
+		data[i] = value.real(); data[i+1] = value.imag();
+		return this;
+	}
+
+	public ComplexFloatMatrix putReal(int rowIndex, int columnIndex, float value) {
+		data[2*index(rowIndex, columnIndex)] = value;
+		return this;
+	}
+
+	public ComplexFloatMatrix putImag(int rowIndex, int columnIndex, float value) {
+		data[2*index(rowIndex, columnIndex)+1] = value;
+		return this;
+	}
+	
+	/** Retrieve matrix element */
+	public ComplexFloat get(int rowIndex, int columnIndex) {
+            int i = 2*index(rowIndex, columnIndex);
+            return new ComplexFloat(data[i], data[i+1]);
+	}
+	
+	public FloatMatrix getReal() {
+		FloatMatrix result = new FloatMatrix(rows, columns);
+		
+		Blas.scopy(length, data, 0, 2, result.data, 0, 1);
+		
+		return result;
+	}
+
+	/** Get index of an element */
+	public int index(int rowIndex, int columnIndex) {
+		//System.out.printf("Index for (%d, %d) -> %d\n", rowIndex, columnIndex, (rows * columnIndex + rowIndex) * 2);
+		return rows * columnIndex + rowIndex;
+	}
+
+	public ComplexFloat get(int i) {
+		return new ComplexFloat(data[i * 2], data[i * 2 + 1]);
+	}
+	
+        public ComplexFloat get(int i, ComplexFloat result) {
+            return result.set(data[i * 2], data[i*2+1]);
+        }
+        
+	public float getReal(int i) {
+		return data[2*i];
+	}
+	
+	public float getImag(int i) {
+		return data[2*i + 1]; 
+	}
+
+	public ComplexFloatMatrix put(int i, float v) {
+		data[2*i] = v;
+		return this;
+	}
+	
+	public ComplexFloatMatrix put(int i, ComplexFloat v) {
+		data[2*i] = v.real();
+		data[2*i+1] = v.imag();
+		return this;
+	}
+	
+	public ComplexFloatMatrix putReal(int i, float v) {
+		return put(i, v);
+	}
+	
+	public ComplexFloatMatrix putImag(int i, float v) {
+		data[2*i+1] = v;
+		return this;
+	}
+
+	public int getRows() {
+		return rows;
+	}
+	
+	public int getColumns() {
+		return columns;
+	}
+	
+	public int getLength() {
+		return length;
+	}
+	
+	/** Checks whether the matrix is empty. */
+	public boolean isEmpty() {
+		return columns == 0 || rows == 0;
+	}
+	
+	/** Checks whether the matrix is square. */
+	public boolean isSquare() {
+		return columns == rows;
+	}
+	
+	public void assertSquare() {
+		if (!isSquare())
+			throw new SizeException("Matrix must be square!");
+	}
+	
+	/** Checks whether the matrix is a vector. */
+	public boolean isVector() {
+		return columns == 1 || rows == 1;
+	}
+	
+	public boolean isRowVector() {
+		return columns == 1;
+	}
+	
+	public boolean isColumnVector() {
+		return rows == 1;
+	}
+		
+        /** Get diagonal of the matrix. */
+	public ComplexFloatMatrix diag() {
+		ComplexFloatMatrix d = new ComplexFloatMatrix(rows);
+		Blas.ccopy(rows, data, 0, rows + 1, d.data, 0, 1);
+		return d;
+	}
+        
+        /** Get real part of the matrix. */
+        public FloatMatrix real() {
+            FloatMatrix result = new FloatMatrix(rows, columns);
+            Blas.scopy(length, data, 0, 2, result.data, 0, 1);
+            return result;
+        }
+        
+        /** Get imaginary part of the matrix. */
+        public FloatMatrix imag() {
+            FloatMatrix result = new FloatMatrix(rows, columns);
+            Blas.scopy(length, data, 1, 2, result.data, 0, 1);
+            return result;            
+        }
+
+	
+	/** 
+	 * Pretty-print this matrix to <tt>System.out</tt>. 
+	 * */
+	public void print() {
+		System.out.println(toString());
+	}
+
+	/** 
+	 * Generate string representation of this matrix 
+	 * (multi-line).
+	 * */
+	public String toString() {
+		StringBuilder s = new StringBuilder();
+
+		s.append("[");
+		
+		for (int i = 0; i < rows; i++) {
+			for (int j = 0; j < columns; j++) {
+				s.append(get(i, j));
+				if (j < columns - 1)
+					s.append(", ");
+			}
+			if (i < rows - 1)
+				s.append("; ");
+		}
+
+		s.append("]");
+		
+		return s.toString();
+	}
+
+	public float[] toDoubleArray() {
+		float[] array = new float[2*length];
+		
+		for (int i = 0; i < 2*length; i++)
+			array[i] = data[i];
+		
+		return array;
+	}
+	
+	public ComplexFloat[] toArray() {
+		ComplexFloat[] array = new ComplexFloat[length];
+		
+		for (int i = 0; i < length; i++)
+			array[i] = get(i);
+		
+		return array;		
+	}
+	
+	public ComplexFloat[][] toArray2() {
+		ComplexFloat[][] array = new ComplexFloat[rows][columns];
+		
+		for (int r = 0; r < rows; r++)
+			for (int c = 0; c < columns; c++)
+				array[r][c] = get(r, c);
+				
+		return array;
+	}
+	
+	public boolean[] toBooleanArray() {
+		boolean[] array = new boolean[length];
+		
+		for (int i = 0; i < length; i++)
+			array[i] = get(i).isZero() ? false : true;
+		
+		return array;
+	}
+	
+	public boolean[][] toBooleanArray2() {
+		boolean[][] array = new boolean[rows][columns];
+		
+		for (int r = 0; r < rows; r++)
+			for (int c = 0; c < columns; c++)
+				array[r][c] = get(r, c).isZero() ? false : true;
+				
+		return array;
+	}
+
+	/**************************************************************************
+	 * Arithmetic Operations
+	 */
+
+	/** 
+	 * Ensures that the result vector has the same length as this. If not,
+	 * resizing result is tried, which fails if result == this or result == other.
+	 */
+	private void ensureResultLength(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+		if (!sameLength(result)) {
+			if (result == this || result == other)
+				throw new SizeException("Cannot resize result matrix because it is used in-place.");
+			result.resize(rows, columns);
+		}
+	}
+
+	/** Add two matrices. */
+	public ComplexFloatMatrix addi(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+		if (other.isScalar())
+			return addi(other.scalar(), result);
+		
+		assertSameLength(other);
+		ensureResultLength(other, result);
+		
+		if (result == this)
+			SimpleBlas.axpy(ComplexFloat.UNIT, other, result);
+		else if (result == other)
+			SimpleBlas.axpy(ComplexFloat.UNIT, this, result);
+		else {
+			SimpleBlas.copy(this, result);
+			SimpleBlas.axpy(ComplexFloat.UNIT, other, result);
+		}
+
+		return result;
+	}
+	
+	/** Add a scalar to a matrix. */
+	public ComplexFloatMatrix addi(ComplexFloat v, ComplexFloatMatrix result) {
+		ensureResultLength(null, result);
+		
+		for (int i = 0; i < length; i++)
+			result.put(i, get(i).add(v));
+		return result;
+	}
+	
+	public ComplexFloatMatrix addi(float v, ComplexFloatMatrix result) {
+		return addi(new ComplexFloat(v), result);
+	}
+
+	/** Subtract two matrices. */
+	public ComplexFloatMatrix subi(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+		if (other.isScalar())
+			return subi(other.scalar(), result);
+		
+		assertSameLength(other);
+		ensureResultLength(other, result);
+		
+		if (result == this)
+			SimpleBlas.axpy(ComplexFloat.NEG_UNIT, other, result);
+		else if (result == other) {
+			SimpleBlas.scal(ComplexFloat.NEG_UNIT, result);
+			SimpleBlas.axpy(ComplexFloat.UNIT, this, result);
+		}
+		else {
+			SimpleBlas.copy(this, result);
+			SimpleBlas.axpy(ComplexFloat.NEG_UNIT, other, result);
+		}
+		return result;
+	}
+	
+	/** Subtract a scalar from a matrix */
+	public ComplexFloatMatrix subi(ComplexFloat v, ComplexFloatMatrix result) {
+		ensureResultLength(null, result);
+		
+		for (int i = 0; i < length; i++)
+			result.put(i, get(i).sub(v));
+		return result;
+	}
+	
+	public ComplexFloatMatrix subi(float v, ComplexFloatMatrix result) {
+		return subi(new ComplexFloat(v), result);
+	}
+
+	/** 
+	 * Subtract two matrices, but subtract first from second matrix, that is, 
+	 * compute <em>result = other - this</em>. 
+	 * */
+	public ComplexFloatMatrix rsubi(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+		return other.subi(this, result);
+	}
+	
+	/** Subtract a matrix from a scalar */
+	public ComplexFloatMatrix rsubi(ComplexFloat a, ComplexFloatMatrix result) {
+		ensureResultLength(null, result);
+		
+		for (int i = 0; i < length; i++)
+			result.put(i, a.sub(get(i)));
+		return result;
+	}
+
+	public ComplexFloatMatrix rsubi(float a, ComplexFloatMatrix result) {
+		return rsubi(new ComplexFloat(a), result);
+	}
+
+	/** (Elementwise) Multiplication */ 
+	public ComplexFloatMatrix muli(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+		if (other.isScalar())
+			return muli(other.scalar(), result);
+		
+		assertSameLength(other);
+		ensureResultLength(other, result);
+		
+                ComplexFloat c = new ComplexFloat(0.0f);
+                ComplexFloat d = new ComplexFloat(0.0f);
+                
+		for (int i = 0; i < length; i++)
+			result.put(i, get(i, c).muli(other.get(i, d)));
+		return result;
+	}
+	
+	/** (Elementwise) Multiplication with a scalar */
+	public ComplexFloatMatrix muli(ComplexFloat v, ComplexFloatMatrix result) {
+		ensureResultLength(null, result);
+		
+                ComplexFloat c = new ComplexFloat(0.0f);
+                
+		for (int i = 0; i < length; i++)
+			result.put(i, get(i, c).muli(v));
+		return result;
+	}
+
+	public ComplexFloatMatrix muli(float v, ComplexFloatMatrix result) {
+		return muli(new ComplexFloat(v), result);
+	}
+
+	/** Matrix-Matrix Multiplication */
+	public ComplexFloatMatrix mmuli(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+		if (other.isScalar())
+			return muli(other.scalar(), result);
+
+		/* check sizes and resize if necessary */
+		assertMultipliesWith(other);
+		if (result.rows != rows || result.columns != other.columns) {
+			if (result != this && result != other)
+				result.resize(rows, other.columns);
+			else
+				throw new SizeException("Cannot resize result matrix because it is used in-place.");
+		}
+		
+		if (result == this || result == other) {
+			/* actually, blas cannot do multiplications in-place. Therefore, we will fake by
+			 * allocating a temporary object on the side and copy the result later.
+			 */
+			ComplexFloatMatrix temp = new ComplexFloatMatrix(result.rows, result.columns);
+			SimpleBlas.gemm(ComplexFloat.UNIT, this, other, ComplexFloat.ZERO, temp);
+			SimpleBlas.copy(temp, result);
+		}
+		else {
+			SimpleBlas.gemm(ComplexFloat.UNIT, this, other, ComplexFloat.ZERO, result);
+		}		
+		return result;
+	}
+	
+	/** Matrix-Matrix Multiplication with a scalar (for symmetry, does the
+	 * same as muli(scalar)
+	 */
+	public ComplexFloatMatrix mmuli(ComplexFloat v, ComplexFloatMatrix result) {
+		return muli(v, result);
+	}
+
+	public ComplexFloatMatrix mmuli(float v, ComplexFloatMatrix result) {
+		return muli(v, result);
+	}
+	
+	/** (Elementwise) division */
+	public ComplexFloatMatrix divi(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+		if (other.isScalar())
+			return divi(other.scalar(), result);
+		
+		assertSameLength(other);
+		ensureResultLength(other, result);
+		
+                ComplexFloat c1 = new ComplexFloat(0.0f);
+                ComplexFloat c2 = new ComplexFloat(0.0f);
+                
+		for (int i = 0; i < length; i++)
+			result.put(i, get(i, c1).divi(other.get(i, c2)));
+		return result;
+	}
+		
+	/** (Elementwise) division with a scalar */
+	public ComplexFloatMatrix divi(ComplexFloat a, ComplexFloatMatrix result) {
+		ensureResultLength(null, result);
+		
+                ComplexFloat c = new ComplexFloat(0.0f);
+                
+		for (int i = 0; i < length; i++)
+			result.put(i, get(i, c).divi(a));
+		return result;
+	}	
+
+	public ComplexFloatMatrix divi(float a, ComplexFloatMatrix result) {
+		return divi(new ComplexFloat(a), result);
+	}
+
+	/** 
+	 * (Elementwise) division, with operands switched. Computes
+	 * <em>result = other / this</em>. */
+	public ComplexFloatMatrix rdivi(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+		if (other.isScalar())
+			return divi(other.scalar(), result);
+		
+		assertSameLength(other);
+		ensureResultLength(other, result);
+
+                ComplexFloat c1 = new ComplexFloat(0.0f);
+                ComplexFloat c2 = new ComplexFloat(0.0f);
+
+		for (int i = 0; i < length; i++)
+			result.put(i, other.get(i, c1).divi(get(i, c2)));
+		return result;
+	}
+		
+	/** (Elementwise) division with a scalar, with operands switched. Computes
+	 * <em>result = a / this</em>.*/
+	public ComplexFloatMatrix rdivi(ComplexFloat a, ComplexFloatMatrix result) {
+		ensureResultLength(null, result);
+
+                ComplexFloat c1 = new ComplexFloat(0.0f);
+                ComplexFloat c2 = new ComplexFloat(0.0f);
+
+		for (int i = 0; i < length; i++) {
+                    c1.copy(a);
+                    result.put(i, c1.divi(get(i, c2)));                    
+                }
+		return result;
+	}
+
+	public ComplexFloatMatrix rdivi(float a, ComplexFloatMatrix result) {
+		return rdivi(new ComplexFloat(a), result);
+	}
+	
+	public ComplexFloatMatrix negi() {
+                ComplexFloat c = new ComplexFloat(0.0f);
+		for (int i = 0; i < length; i++)
+			put(i, get(i, c).negi());
+		return this;
+	}
+	
+	public ComplexFloatMatrix neg() {
+		return dup().negi();
+	}
+
+	public ComplexFloatMatrix noti() {
+                ComplexFloat c = new ComplexFloat(0.0f);
+		for (int i = 0; i < length; i++)
+			put(i, get(i, c).isZero() ? 1.0f : 0.0f);
+		return this;
+	}
+	
+	public ComplexFloatMatrix not() {
+		return dup().noti();
+	}
+	
+	public ComplexFloatMatrix truthi() {
+                ComplexFloat c = new ComplexFloat(0.0f);
+		for (int i = 0; i < length; i++)
+			put(i, get(i, c).isZero() ? 0.0f : 1.0f);
+		return this;
+	}
+	
+	public ComplexFloatMatrix truth() {
+		return dup().truthi();
+	}
+        
+        public ComplexFloatMatrix conji() {
+            ComplexFloat c = new ComplexFloat(0.0f);
+            for (int i = 0; i < length; i++)
+                put(i, get(i, c).conji());
+            return this;
+        }
+
+	/****************************************************************
+	 * Rank one-updates
+	 */
+	
+	/** Computes a rank-1-update A = A + alpha * x * y'. */ 
+	public ComplexFloatMatrix rankOneUpdate(ComplexFloat alpha, ComplexFloatMatrix x, ComplexFloatMatrix y) {
+		if (rows != x.length)
+			throw new SizeException("Vector x has wrong length (" + x.length + " != " + rows + ").");
+		if (columns != y.length)
+			throw new SizeException("Vector y has wrong length (" + x.length + " != " + columns + ").");			
+		
+		SimpleBlas.gerc(alpha, x, y, this);
+		return this;
+	}
+
+	public ComplexFloatMatrix rankOneUpdate(float alpha, ComplexFloatMatrix x, ComplexFloatMatrix y) {
+		return rankOneUpdate(new ComplexFloat(alpha), x, y);
+	}
+
+	/** Computes a rank-1-update A = A + alpha * x * x'. */ 
+	public ComplexFloatMatrix rankOneUpdate(float alpha, ComplexFloatMatrix x) {
+		return rankOneUpdate(new ComplexFloat(alpha), x, x);
+	}
+
+	/** Computes a rank-1-update A = A + alpha * x * x'. */ 
+	public ComplexFloatMatrix rankOneUpdate(ComplexFloat alpha, ComplexFloatMatrix x) {
+		return rankOneUpdate(alpha, x, x);
+	}
+
+	/** Computes a rank-1-update A = A + x * x'. */ 
+	public ComplexFloatMatrix rankOneUpdate(ComplexFloatMatrix x) {
+		return rankOneUpdate(1.0f, x, x);
+	}
+
+	/** Computes a rank-1-update A = A + x * y'. */ 
+	public ComplexFloatMatrix rankOneUpdate(ComplexFloatMatrix x, ComplexFloatMatrix y) {
+		return rankOneUpdate(1.0f, x, y);
+	}
+
+	/****************************************************************
+	 * Logical operations
+	 */
+	
+	public ComplexFloat sum() {
+		ComplexFloat s = new ComplexFloat(0.0f);
+                ComplexFloat c = new ComplexFloat(0.0f);
+		for (int i = 0; i < length; i++)
+			s.addi(get(i, c));
+		return s;
+	}
+	
+	public ComplexFloat mean() {
+		return sum().div((float)length);
+	}
+	
+	/* computes this^T * other */
+	public ComplexFloat dotc(ComplexFloatMatrix other) {
+		return SimpleBlas.dotc(this, other);
+	}
+	
+	/* computs this^H * other */
+	public ComplexFloat dotu(ComplexFloatMatrix other) {
+		return SimpleBlas.dotu(this, other);
+	}
+
+	public float norm2() {
+		return SimpleBlas.nrm2(this);
+	}
+	
+	public float normmax() {
+		int i = SimpleBlas.iamax(this);
+		return get(i).abs();
+	}
+
+	public float norm1() {
+		return SimpleBlas.asum(this);
+	}
+		
+	/** Return a vector containing the sums of the columns (having number of columns many entries) */
+	public ComplexFloatMatrix columnSums() {
+		ComplexFloatMatrix v =
+                        new ComplexFloatMatrix(1, columns);
+
+		for (int c = 0; c < columns; c++)
+			v.put(c, getColumn(c).sum());
+
+		return v;
+	}
+
+	public ComplexFloatMatrix columnMeans() {
+		return columnSums().divi(rows);
+	}
+	
+	public ComplexFloatMatrix rowSums() {
+		ComplexFloatMatrix v = new ComplexFloatMatrix(rows);
+
+		for (int r = 0; r < rows; r++)
+			v.put(r, getRow(r).sum());
+
+		return v;
+	}
+
+	public ComplexFloatMatrix rowMeans() {
+		return rowSums().divi(columns);
+	}
+
+	public ComplexFloatMatrix getColumn(int c) {
+		ComplexFloatMatrix result = new ComplexFloatMatrix(rows, 1);
+		Blas.ccopy(rows, data, index(0, c), 1, result.data, 0, 1);
+		return result;
+	}
+	
+	public void putColumn(int c, ComplexFloatMatrix v) {
+		Blas.ccopy(rows, v.data, 0, 1, data, index(0, c), 1);
+	}
+
+	public ComplexFloatMatrix getRow(int r) {
+		ComplexFloatMatrix result = new ComplexFloatMatrix(1, columns);
+		Blas.ccopy(columns, data, index(r, 0), rows, result.data, 0, 1);
+		return result;
+	}
+	
+	public void putRow(int r, ComplexFloatMatrix v) {
+		Blas.ccopy(columns, v.data, 0, 1, data, index(r, 0), rows);
+	}
+
+	/**************************************************************************
+	 * Elementwise Functions
+	 */
+
+	/** Add a row vector to all rows of the matrix */
+	public void addRowVector(ComplexFloatMatrix x) {
+		for (int r = 0; r < rows; r++) {
+			Blas.caxpy(columns, ComplexFloat.UNIT, x.data, 0, 1, data, index(r, 0), rows);
+		}
+	}
+
+	/** Add a vector to all columns of the matrix */
+	public void addColumnVector(ComplexFloatMatrix x) {
+		for (int c = 0; c < columns; c++) {
+			Blas.caxpy(rows, ComplexFloat.UNIT, x.data, 0, 1, data, index(0, c), 1);
+		}
+	}
+
+       	/** Add a row vector to all rows of the matrix */
+	public void subRowVector(ComplexFloatMatrix x) {
+		for (int r = 0; r < rows; r++) {
+			Blas.caxpy(columns, ComplexFloat.NEG_UNIT, x.data, 0, 1, data, index(r, 0), rows);
+		}
+	}
+
+	/** Add a vector to all columns of the matrix */
+	public void subColumnVector(ComplexFloatMatrix x) {
+		for (int c = 0; c < columns; c++) {
+			Blas.caxpy(rows, ComplexFloat.NEG_UNIT, x.data, 0, 1, data, index(0, c), 1);
+		}
+	}
+
+	/**
+	 * Writes out this matrix to the given data stream.
+	 * @param dos the data output stream to write to.
+	 * @throws IOException 
+	 */
+	public void out(DataOutputStream dos) throws IOException {
+		dos.writeUTF("float");
+		dos.writeInt(columns);
+		dos.writeInt(rows);
+		
+		dos.writeInt(data.length);
+		for(int i=0; i < data.length;i++)
+			dos.writeDouble(data[i]);
+	}
+	
+	/**
+	 * Reads in a matrix from the given data stream. Note
+	 * that the old data of this matrix will be discarded.
+	 * @param dis the data input stream to read from.
+	 * @throws IOException 
+	 */
+	public void in(DataInputStream dis) throws IOException {
+		if(!dis.readUTF().equals("float")) 
+			throw new IllegalStateException("The matrix in the specified file is not of the correct type!");
+		
+		this.columns	= dis.readInt();
+		this.rows		= dis.readInt();
+
+		final int MAX = dis.readInt();
+		data = new float[MAX];
+		for(int i=0; i < MAX;i++)
+			data[i] = dis.readFloat();
+	}	
+	
+	/**
+	 * Saves this matrix to the specified file.
+	 * @param filename the file to write the matrix in.
+	 * @throws IOException thrown on errors while writing the matrix to the file
+	 */
+	public void save(String filename) throws IOException {
+		DataOutputStream dos = new DataOutputStream(new FileOutputStream(filename, false));
+		this.out(dos);
+	}
+	
+	/**
+	 * Loads a matrix from a file into this matrix. Note that the old data
+	 * of this matrix will be discarded.
+	 * @param filename the file to read the matrix from
+	 * @throws IOException thrown on errors while reading the matrix
+	 */
+	public void load(String filename) throws IOException {
+		DataInputStream dis = new DataInputStream(new FileInputStream(filename));
+		this.in(dis);
+	}
+
+	/****************************************************************
+	 * Autogenerated code
+	 */
+	
+	/***** Code for operators ***************************************/ 
+
+	/* Overloads for the usual arithmetic operations */
+	/*#
+	 def gen_overloads(base, result_rows, result_cols); <<-EOS
+	public ComplexFloatMatrix #{base}i(ComplexFloatMatrix other) {
+		return #{base}i(other, this);
+	}
+	 	
+	public ComplexFloatMatrix #{base}(ComplexFloatMatrix other) {
+	  	return #{base}i(other, new ComplexFloatMatrix(#{result_rows}, #{result_cols}));
+	}
+
+	public ComplexFloatMatrix #{base}i(ComplexFloat v) {
+		return #{base}i(v, this);
+	}
+	
+	public ComplexFloatMatrix #{base}i(float v) {
+		return #{base}i(new ComplexFloat(v), this);
+	}
+
+	public ComplexFloatMatrix #{base}(ComplexFloat v) {
+		return #{base}i(v, new ComplexFloatMatrix(rows, columns));
+	} 	
+
+	public ComplexFloatMatrix #{base}(float v) {
+		return #{base}i(new ComplexFloat(v), new ComplexFloatMatrix(rows, columns));
+	} 	
+	 	
+	 	EOS
+	  end
+	#*/
+
+	/* Generating code for logical operators. This not only generates the stubs 
+	 * but really all of the code.
+	 */
+	
+	/*#
+	 def gen_compare(name, op); <<-EOS
+	 public ComplexFloatMatrix #{name}i(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+	    if (other.isScalar())
+	       return #{name}i(other.scalar(), result);
+	       
+	 	assertSameLength(other);
+	 	ensureResultLength(other, result);
+	 	
+                ComplexFloat c1 = new ComplexFloat(0.0f);
+                ComplexFloat c2 = new ComplexFloat(0.0f);
+          
+                for (int i = 0; i < length; i++)
+                    result.put(i, get(i, c1).#{op}(other.get(i, c2)) ? 1.0f : 0.0f);
+	   return result;
+	 }
+	 
+	 public ComplexFloatMatrix #{name}i(ComplexFloatMatrix other) {
+	   return #{name}i(other, this);
+	 }
+	 
+	 public ComplexFloatMatrix #{name}(ComplexFloatMatrix other) {
+	   return #{name}i(other, new ComplexFloatMatrix(rows, columns));
+	 }
+	 
+	 public ComplexFloatMatrix #{name}i(ComplexFloat value, ComplexFloatMatrix result) {
+	   ensureResultLength(null, result);
+           ComplexFloat c = new ComplexFloat(0.0f);
+	   for (int i = 0; i < length; i++)
+	     result.put(i, get(i, c).#{op}(value) ? 1.0f : 0.0f);
+	   return result;
+	 }
+
+	 public ComplexFloatMatrix #{name}i(float value, ComplexFloatMatrix result) {
+	   return #{name}i(new ComplexFloat(value), result);
+	 }
+
+	 public ComplexFloatMatrix #{name}i(ComplexFloat value) {
+	   return #{name}i(value, this);
+	 }
+	 
+	 public ComplexFloatMatrix #{name}i(float value) {
+	   return #{name}i(new ComplexFloat(value));
+	 }
+	 
+	 public ComplexFloatMatrix #{name}(ComplexFloat value) {
+	   return #{name}i(value, new ComplexFloatMatrix(rows, columns));
+	 }
+	 
+	 public ComplexFloatMatrix #{name}(float value) {
+	   return #{name}i(new ComplexFloat(value));
+	 }
+
+	 EOS
+	 end
+	 #*/
+	
+	/*#
+	 def gen_logical(name, op); <<-EOS
+	 public ComplexFloatMatrix #{name}i(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+	 	assertSameLength(other);
+	 	ensureResultLength(other, result);
+	 	
+                ComplexFloat t1 = new ComplexFloat(0.0f);
+                ComplexFloat t2 = new ComplexFloat(0.0f);
+         
+               for (int i = 0; i < length; i++)
+                  result.put(i, (!get(i, t1).isZero()) #{op} (!other.get(i, t2).isZero()) ? 1.0f : 0.0f);
+	   return result;
+	 }
+	 
+	 public ComplexFloatMatrix #{name}i(ComplexFloatMatrix other) {
+	   return #{name}i(other, this);
+	 }
+	 
+	 public ComplexFloatMatrix #{name}(ComplexFloatMatrix other) {
+	   return #{name}i(other, new ComplexFloatMatrix(rows, columns));
+	 }
+	 
+	 public ComplexFloatMatrix #{name}i(ComplexFloat value, ComplexFloatMatrix result) {
+	 	ensureResultLength(null, result);
+	 	boolean val = !value.isZero();
+                ComplexFloat t = new ComplexFloat(0.0f);
+                for (int i = 0; i < length; i++)
+                     result.put(i, !get(i, t).isZero() #{op} val ? 1.0f : 0.0f);
+	   return result;
+	 }
+
+ 	 public ComplexFloatMatrix #{name}i(float value, ComplexFloatMatrix result) {
+ 	   return #{name}i(new ComplexFloat(value), result);
+ 	 }
+
+	 public ComplexFloatMatrix #{name}i(ComplexFloat value) {
+	   return #{name}i(value, this);
+	 }
+
+ 	 public ComplexFloatMatrix #{name}i(float value) {
+ 	   return #{name}i(new ComplexFloat(value), this);
+ 	 }
+
+	 public ComplexFloatMatrix #{name}(ComplexFloat value) {
+	   return #{name}i(value, new ComplexFloatMatrix(rows, columns));
+	 }
+	 
+	 public ComplexFloatMatrix #{name}(float value) {
+	   return #{name}i(new ComplexFloat(value));
+	 }
+	 EOS
+	 end
+	 #*/
+
+	/*# collect(gen_overloads('add', 'rows', 'columns'),
+	  gen_overloads('sub', 'rows', 'columns'),
+	  gen_overloads('rsub', 'rows', 'columns'),
+	  gen_overloads('div', 'rows', 'columns'),
+	  gen_overloads('rdiv', 'rows', 'columns'),
+	  gen_overloads('mul', 'rows', 'columns'),
+	  gen_overloads('mmul', 'rows', 'other.columns'),
+	  gen_compare('eq', 'eq'),
+	  gen_compare('ne', 'eq'),
+	  gen_logical('and', '&'),
+	  gen_logical('or', '|'),
+	  gen_logical('xor', '^'))
+	 #*/
+//RJPP-BEGIN------------------------------------------------------------
+	public ComplexFloatMatrix addi(ComplexFloatMatrix other) {
+		return addi(other, this);
+	}
+	 	
+	public ComplexFloatMatrix add(ComplexFloatMatrix other) {
+	  	return addi(other, new ComplexFloatMatrix(rows, columns));
+	}
+
+	public ComplexFloatMatrix addi(ComplexFloat v) {
+		return addi(v, this);
+	}
+	
+	public ComplexFloatMatrix addi(float v) {
+		return addi(new ComplexFloat(v), this);
+	}
+
+	public ComplexFloatMatrix add(ComplexFloat v) {
+		return addi(v, new ComplexFloatMatrix(rows, columns));
+	} 	
+
+	public ComplexFloatMatrix add(float v) {
+		return addi(new ComplexFloat(v), new ComplexFloatMatrix(rows, columns));
+	} 	
+	 	
+
+	public ComplexFloatMatrix subi(ComplexFloatMatrix other) {
+		return subi(other, this);
+	}
+	 	
+	public ComplexFloatMatrix sub(ComplexFloatMatrix other) {
+	  	return subi(other, new ComplexFloatMatrix(rows, columns));
+	}
+
+	public ComplexFloatMatrix subi(ComplexFloat v) {
+		return subi(v, this);
+	}
+	
+	public ComplexFloatMatrix subi(float v) {
+		return subi(new ComplexFloat(v), this);
+	}
+
+	public ComplexFloatMatrix sub(ComplexFloat v) {
+		return subi(v, new ComplexFloatMatrix(rows, columns));
+	} 	
+
+	public ComplexFloatMatrix sub(float v) {
+		return subi(new ComplexFloat(v), new ComplexFloatMatrix(rows, columns));
+	} 	
+	 	
+
+	public ComplexFloatMatrix rsubi(ComplexFloatMatrix other) {
+		return rsubi(other, this);
+	}
+	 	
+	public ComplexFloatMatrix rsub(ComplexFloatMatrix other) {
+	  	return rsubi(other, new ComplexFloatMatrix(rows, columns));
+	}
+
+	public ComplexFloatMatrix rsubi(ComplexFloat v) {
+		return rsubi(v, this);
+	}
+	
+	public ComplexFloatMatrix rsubi(float v) {
+		return rsubi(new ComplexFloat(v), this);
+	}
+
+	public ComplexFloatMatrix rsub(ComplexFloat v) {
+		return rsubi(v, new ComplexFloatMatrix(rows, columns));
+	} 	
+
+	public ComplexFloatMatrix rsub(float v) {
+		return rsubi(new ComplexFloat(v), new ComplexFloatMatrix(rows, columns));
+	} 	
+	 	
+
+	public ComplexFloatMatrix divi(ComplexFloatMatrix other) {
+		return divi(other, this);
+	}
+	 	
+	public ComplexFloatMatrix div(ComplexFloatMatrix other) {
+	  	return divi(other, new ComplexFloatMatrix(rows, columns));
+	}
+
+	public ComplexFloatMatrix divi(ComplexFloat v) {
+		return divi(v, this);
+	}
+	
+	public ComplexFloatMatrix divi(float v) {
+		return divi(new ComplexFloat(v), this);
+	}
+
+	public ComplexFloatMatrix div(ComplexFloat v) {
+		return divi(v, new ComplexFloatMatrix(rows, columns));
+	} 	
+
+	public ComplexFloatMatrix div(float v) {
+		return divi(new ComplexFloat(v), new ComplexFloatMatrix(rows, columns));
+	} 	
+	 	
+
+	public ComplexFloatMatrix rdivi(ComplexFloatMatrix other) {
+		return rdivi(other, this);
+	}
+	 	
+	public ComplexFloatMatrix rdiv(ComplexFloatMatrix other) {
+	  	return rdivi(other, new ComplexFloatMatrix(rows, columns));
+	}
+
+	public ComplexFloatMatrix rdivi(ComplexFloat v) {
+		return rdivi(v, this);
+	}
+	
+	public ComplexFloatMatrix rdivi(float v) {
+		return rdivi(new ComplexFloat(v), this);
+	}
+
+	public ComplexFloatMatrix rdiv(ComplexFloat v) {
+		return rdivi(v, new ComplexFloatMatrix(rows, columns));
+	} 	
+
+	public ComplexFloatMatrix rdiv(float v) {
+		return rdivi(new ComplexFloat(v), new ComplexFloatMatrix(rows, columns));
+	} 	
+	 	
+
+	public ComplexFloatMatrix muli(ComplexFloatMatrix other) {
+		return muli(other, this);
+	}
+	 	
+	public ComplexFloatMatrix mul(ComplexFloatMatrix other) {
+	  	return muli(other, new ComplexFloatMatrix(rows, columns));
+	}
+
+	public ComplexFloatMatrix muli(ComplexFloat v) {
+		return muli(v, this);
+	}
+	
+	public ComplexFloatMatrix muli(float v) {
+		return muli(new ComplexFloat(v), this);
+	}
+
+	public ComplexFloatMatrix mul(ComplexFloat v) {
+		return muli(v, new ComplexFloatMatrix(rows, columns));
+	} 	
+
+	public ComplexFloatMatrix mul(float v) {
+		return muli(new ComplexFloat(v), new ComplexFloatMatrix(rows, columns));
+	} 	
+	 	
+
+	public ComplexFloatMatrix mmuli(ComplexFloatMatrix other) {
+		return mmuli(other, this);
+	}
+	 	
+	public ComplexFloatMatrix mmul(ComplexFloatMatrix other) {
+	  	return mmuli(other, new ComplexFloatMatrix(rows, other.columns));
+	}
+
+	public ComplexFloatMatrix mmuli(ComplexFloat v) {
+		return mmuli(v, this);
+	}
+	
+	public ComplexFloatMatrix mmuli(float v) {
+		return mmuli(new ComplexFloat(v), this);
+	}
+
+	public ComplexFloatMatrix mmul(ComplexFloat v) {
+		return mmuli(v, new ComplexFloatMatrix(rows, columns));
+	} 	
+
+	public ComplexFloatMatrix mmul(float v) {
+		return mmuli(new ComplexFloat(v), new ComplexFloatMatrix(rows, columns));
+	} 	
+	 	
+
+	 public ComplexFloatMatrix eqi(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+	    if (other.isScalar())
+	       return eqi(other.scalar(), result);
+	       
+	 	assertSameLength(other);
+	 	ensureResultLength(other, result);
+	 	
+                ComplexFloat c1 = new ComplexFloat(0.0f);
+                ComplexFloat c2 = new ComplexFloat(0.0f);
+          
+                for (int i = 0; i < length; i++)
+                    result.put(i, get(i, c1).eq(other.get(i, c2)) ? 1.0f : 0.0f);
+	   return result;
+	 }
+	 
+	 public ComplexFloatMatrix eqi(ComplexFloatMatrix other) {
+	   return eqi(other, this);
+	 }
+	 
+	 public ComplexFloatMatrix eq(ComplexFloatMatrix other) {
+	   return eqi(other, new ComplexFloatMatrix(rows, columns));
+	 }
+	 
+	 public ComplexFloatMatrix eqi(ComplexFloat value, ComplexFloatMatrix result) {
+	   ensureResultLength(null, result);
+           ComplexFloat c = new ComplexFloat(0.0f);
+	   for (int i = 0; i < length; i++)
+	     result.put(i, get(i, c).eq(value) ? 1.0f : 0.0f);
+	   return result;
+	 }
+
+	 public ComplexFloatMatrix eqi(float value, ComplexFloatMatrix result) {
+	   return eqi(new ComplexFloat(value), result);
+	 }
+
+	 public ComplexFloatMatrix eqi(ComplexFloat value) {
+	   return eqi(value, this);
+	 }
+	 
+	 public ComplexFloatMatrix eqi(float value) {
+	   return eqi(new ComplexFloat(value));
+	 }
+	 
+	 public ComplexFloatMatrix eq(ComplexFloat value) {
+	   return eqi(value, new ComplexFloatMatrix(rows, columns));
+	 }
+	 
+	 public ComplexFloatMatrix eq(float value) {
+	   return eqi(new ComplexFloat(value));
+	 }
+
+
+	 public ComplexFloatMatrix nei(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+	    if (other.isScalar())
+	       return nei(other.scalar(), result);
+	       
+	 	assertSameLength(other);
+	 	ensureResultLength(other, result);
+	 	
+                ComplexFloat c1 = new ComplexFloat(0.0f);
+                ComplexFloat c2 = new ComplexFloat(0.0f);
+          
+                for (int i = 0; i < length; i++)
+                    result.put(i, get(i, c1).eq(other.get(i, c2)) ? 1.0f : 0.0f);
+	   return result;
+	 }
+	 
+	 public ComplexFloatMatrix nei(ComplexFloatMatrix other) {
+	   return nei(other, this);
+	 }
+	 
+	 public ComplexFloatMatrix ne(ComplexFloatMatrix other) {
+	   return nei(other, new ComplexFloatMatrix(rows, columns));
+	 }
+	 
+	 public ComplexFloatMatrix nei(ComplexFloat value, ComplexFloatMatrix result) {
+	   ensureResultLength(null, result);
+           ComplexFloat c = new ComplexFloat(0.0f);
+	   for (int i = 0; i < length; i++)
+	     result.put(i, get(i, c).eq(value) ? 1.0f : 0.0f);
+	   return result;
+	 }
+
+	 public ComplexFloatMatrix nei(float value, ComplexFloatMatrix result) {
+	   return nei(new ComplexFloat(value), result);
+	 }
+
+	 public ComplexFloatMatrix nei(ComplexFloat value) {
+	   return nei(value, this);
+	 }
+	 
+	 public ComplexFloatMatrix nei(float value) {
+	   return nei(new ComplexFloat(value));
+	 }
+	 
+	 public ComplexFloatMatrix ne(ComplexFloat value) {
+	   return nei(value, new ComplexFloatMatrix(rows, columns));
+	 }
+	 
+	 public ComplexFloatMatrix ne(float value) {
+	   return nei(new ComplexFloat(value));
+	 }
+
+
+	 public ComplexFloatMatrix andi(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+	 	assertSameLength(other);
+	 	ensureResultLength(other, result);
+	 	
+                ComplexFloat t1 = new ComplexFloat(0.0f);
+                ComplexFloat t2 = new ComplexFloat(0.0f);
+         
+               for (int i = 0; i < length; i++)
+                  result.put(i, (!get(i, t1).isZero()) & (!other.get(i, t2).isZero()) ? 1.0f : 0.0f);
+	   return result;
+	 }
+	 
+	 public ComplexFloatMatrix andi(ComplexFloatMatrix other) {
+	   return andi(other, this);
+	 }
+	 
+	 public ComplexFloatMatrix and(ComplexFloatMatrix other) {
+	   return andi(other, new ComplexFloatMatrix(rows, columns));
+	 }
+	 
+	 public ComplexFloatMatrix andi(ComplexFloat value, ComplexFloatMatrix result) {
+	 	ensureResultLength(null, result);
+	 	boolean val = !value.isZero();
+                ComplexFloat t = new ComplexFloat(0.0f);
+                for (int i = 0; i < length; i++)
+                     result.put(i, !get(i, t).isZero() & val ? 1.0f : 0.0f);
+	   return result;
+	 }
+
+ 	 public ComplexFloatMatrix andi(float value, ComplexFloatMatrix result) {
+ 	   return andi(new ComplexFloat(value), result);
+ 	 }
+
+	 public ComplexFloatMatrix andi(ComplexFloat value) {
+	   return andi(value, this);
+	 }
+
+ 	 public ComplexFloatMatrix andi(float value) {
+ 	   return andi(new ComplexFloat(value), this);
+ 	 }
+
+	 public ComplexFloatMatrix and(ComplexFloat value) {
+	   return andi(value, new ComplexFloatMatrix(rows, columns));
+	 }
+	 
+	 public ComplexFloatMatrix and(float value) {
+	   return andi(new ComplexFloat(value));
+	 }
+
+	 public ComplexFloatMatrix ori(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+	 	assertSameLength(other);
+	 	ensureResultLength(other, result);
+	 	
+                ComplexFloat t1 = new ComplexFloat(0.0f);
+                ComplexFloat t2 = new ComplexFloat(0.0f);
+         
+               for (int i = 0; i < length; i++)
+                  result.put(i, (!get(i, t1).isZero()) | (!other.get(i, t2).isZero()) ? 1.0f : 0.0f);
+	   return result;
+	 }
+	 
+	 public ComplexFloatMatrix ori(ComplexFloatMatrix other) {
+	   return ori(other, this);
+	 }
+	 
+	 public ComplexFloatMatrix or(ComplexFloatMatrix other) {
+	   return ori(other, new ComplexFloatMatrix(rows, columns));
+	 }
+	 
+	 public ComplexFloatMatrix ori(ComplexFloat value, ComplexFloatMatrix result) {
+	 	ensureResultLength(null, result);
+	 	boolean val = !value.isZero();
+                ComplexFloat t = new ComplexFloat(0.0f);
+                for (int i = 0; i < length; i++)
+                     result.put(i, !get(i, t).isZero() | val ? 1.0f : 0.0f);
+	   return result;
+	 }
+
+ 	 public ComplexFloatMatrix ori(float value, ComplexFloatMatrix result) {
+ 	   return ori(new ComplexFloat(value), result);
+ 	 }
+
+	 public ComplexFloatMatrix ori(ComplexFloat value) {
+	   return ori(value, this);
+	 }
+
+ 	 public ComplexFloatMatrix ori(float value) {
+ 	   return ori(new ComplexFloat(value), this);
+ 	 }
+
+	 public ComplexFloatMatrix or(ComplexFloat value) {
+	   return ori(value, new ComplexFloatMatrix(rows, columns));
+	 }
+	 
+	 public ComplexFloatMatrix or(float value) {
+	   return ori(new ComplexFloat(value));
+	 }
+
+	 public ComplexFloatMatrix xori(ComplexFloatMatrix other, ComplexFloatMatrix result) {
+	 	assertSameLength(other);
+	 	ensureResultLength(other, result);
+	 	
+                ComplexFloat t1 = new ComplexFloat(0.0f);
+                ComplexFloat t2 = new ComplexFloat(0.0f);
+         
+               for (int i = 0; i < length; i++)
+                  result.put(i, (!get(i, t1).isZero()) ^ (!other.get(i, t2).isZero()) ? 1.0f : 0.0f);
+	   return result;
+	 }
+	 
+	 public ComplexFloatMatrix xori(ComplexFloatMatrix other) {
+	   return xori(other, this);
+	 }
+	 
+	 public ComplexFloatMatrix xor(ComplexFloatMatrix other) {
+	   return xori(other, new ComplexFloatMatrix(rows, columns));
+	 }
+	 
+	 public ComplexFloatMatrix xori(ComplexFloat value, ComplexFloatMatrix result) {
+	 	ensureResultLength(null, result);
+	 	boolean val = !value.isZero();
+                ComplexFloat t = new ComplexFloat(0.0f);
+                for (int i = 0; i < length; i++)
+                     result.put(i, !get(i, t).isZero() ^ val ? 1.0f : 0.0f);
+	   return result;
+	 }
+
+ 	 public ComplexFloatMatrix xori(float value, ComplexFloatMatrix result) {
+ 	   return xori(new ComplexFloat(value), result);
+ 	 }
+
+	 public ComplexFloatMatrix xori(ComplexFloat value) {
+	   return xori(value, this);
+	 }
+
+ 	 public ComplexFloatMatrix xori(float value) {
+ 	   return xori(new ComplexFloat(value), this);
+ 	 }
+
+	 public ComplexFloatMatrix xor(ComplexFloat value) {
+	   return xori(value, new ComplexFloatMatrix(rows, columns));
+	 }
+	 
+	 public ComplexFloatMatrix xor(float value) {
+	   return xori(new ComplexFloat(value));
+	 }
+//RJPP-END--------------------------------------------------------------
+}
diff --git a/src/org/jblas/la/DoubleFunction.java b/src/org/jblas/la/DoubleFunction.java
new file mode 100644
index 0000000..fc6d54e
--- /dev/null
+++ b/src/org/jblas/la/DoubleFunction.java
@@ -0,0 +1,45 @@
+// --- 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.la;
+
+/**
+ * Represents a function on doubles.
+ */
+public interface DoubleFunction {
+        /** Compute the function. */
+	public double compute(double x);
+}
diff --git a/src/org/jblas/la/DoubleMatrix.java b/src/org/jblas/la/DoubleMatrix.java
new file mode 100644
index 0000000..33b1b48
--- /dev/null
+++ b/src/org/jblas/la/DoubleMatrix.java
@@ -0,0 +1,2965 @@
+// --- BEGIN LICENSE BLOCK ---
+/* 
+ * Copyright (c) 2009, Mikio L. Braun
+ * Copyright (c) 2008, Johannes Schaback
+ * 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.la;
+
+import org.jblas.la.exceptions.SizeException;
+import org.jblas.la.ranges.Range;
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * A general matrix class for <tt>double</tt> typed values.
+ * 
+ * Don't be intimidated by the large number of methods this function defines. Most
+ * are overloads provided for ease of use. For example, for each arithmetic operation,
+ * up to six overloaded versions exist to handle in-place computations, and
+ * scalar arguments.
+ * 
+ * <h3>Construction</h3>
+ * 
+ * <p>To construct a two-dimensional matrices, you can use the following constructors
+ * and static methods.</p>
+ * 
+ * <table class="my">
+ * <tr><th>Method<th>Description
+ * <tr><td>DoubleMatrix(m,n, [value1, value2, value3...])<td>Values are filled in row by row.
+ * <tr><td>DoubleMatrix(new double[][] {{value1, value2, ...}, ...}<td>Inner arrays are columns.
+ * <tr><td>DoubleMatrix.zeros(m,n) <td>Initial values set to 0.0.
+ * <tr><td>DoubleMatrix.ones(m,n) <td>Initial values set to 1.0.
+ * <tr><td>DoubleMatrix.rand(m,n) <td>Values drawn at random between 0.0 and 1.0.
+ * <tr><td>DoubleMatrix.randn(m,n) <td>Values drawn from normal distribution.
+ * <tr><td>DoubleMatrix.eye(n) <td>Unit matrix (values 0.0 except for 1.0 on the diagonal).
+ * <tr><td>DoubleMatrix.diag(array) <td>Diagonal matrix with given diagonal elements.
+ * </table>
+ * 
+ * <p>Alternatively, you can construct (column) vectors, if you just supply the length
+ * using the following constructors and static methods.</p>
+ * 
+ * <table class="my">
+ * <tr><th>Method<th>Description
+ * <tr><td>DoubleMatrix(m)<td>Constructs a column vector.
+ * <tr><td>DoubleMatrix(new double[] {value1, value2, ...})<td>Constructs a column vector.
+ * <tr><td>DoubleMatrix.zeros(m) <td>Initial values set to 1.0.
+ * <tr><td>DoubleMatrix.ones(m) <td>Initial values set to 0.0.
+ * <tr><td>DoubleMatrix.rand(m) <td>Values drawn at random between 0.0 and 1.0.
+ * <tr><td>DoubleMatrix.randn(m) <td>Values drawn from normal distribution.
+ * </table>
+ * 
+ * <p>You can also construct new matrices by concatenating matrices either horziontally
+ * or vertically:</p>
+ * 
+ * <table class="my">
+ * <tr><th>Method<th>Description
+ * <tr><td>x.concatHorizontally(y)<td>New matrix will be x next to y.
+ * <tr><td>x.concatVertically(y)<td>New matrix will be x atop y.
+ * </table>
+ * 
+ * <h3>Element Access, Copying and Duplication</h3>
+ * 
+ * <p>To access individual elements, or whole rows and columns, use the following
+ * methods:<p>
+ * 
+ * <table class="my">
+ * <tr><th>x.Method<th>Description
+ * <tr><td>x.get(i,j)<td>Get element in row i and column j.
+ * <tr><td>x.put(i, j, v)<td>Set element in row i and column j to value v
+ * <tr><td>x.get(i)<td>Get the ith element of the matrix (traversing rows first).
+ * <tr><td>x.put(i, v)<td>Set the ith element of the matrix (traversing rows first).
+ * <tr><td>x.getColumn(i)<td>Get a copy of column i.
+ * <tr><td>x.putColumn(i, c)<td>Put matrix c into column i.
+ * <tr><td>x.getRow(i)<td>Get a copy of row i.
+ * <tr><td>x.putRow(i, c)<td>Put matrix c into row i.
+ * <tr><td>x.swapColumns(i, j)<td>Swap the contents of columns i and j.
+ * <tr><td>x.swapRows(i, j)<td>Swap the contents of columns i and j.
+ * </table>
+ * 
+ * <p>For <tt>get</tt> and <tt>put</tt>, you can also pass integer arrays,
+ * DoubleMatrix objects, or Range objects, which then specify the indices used 
+ * as follows:
+ * 
+ * <ul>
+ * <li><em>integer array:</em> the elements will be used as indices.
+ * <li><em>DoubleMatrix object:</em> non-zero entries specify the indices.
+ * <li><em>Range object:</em> see below.
+ * </ul>
+ * 
+ * <p>When using <tt>put</tt> with multiple indices, the assigned object must
+ * have the correct size or be a scalar.</p>
+ *
+ * <p>There exist the following Range objects. The Class <tt>RangeUtils</tt> also
+ * contains the a number of handy helper methods for constructing these ranges.</p>
+ * <table class="my">
+ * <tr><th>Class <th>RangeUtils method <th>Indices
+ * <tr><td>AllRange <td>all() <td>All legal indices.
+ * <tr><td>PointRange <td>point(i) <td> A single point.
+ * <tr><td>IntervalRange <td>interval(a, b)<td> All indices from a to b (inclusive)
+ * <tr><td rowspan=3>IndicesRange <td>indices(int[])<td> The specified indices.
+ * <tr><td>indices(DoubleMatrix)<td>The specified indices.
+ * <tr><td>find(DoubleMatrix)<td>The non-zero entries of the matrix.
+ * </table>
+ * 
+ * <p>The following methods can be used for duplicating and copying matrices.</p>
+ * 
+ * <table class="my">
+ * <tr><th>Method<th>Description
+ * <tr><td>x.dup()<td>Get a copy of x.
+ * <tr><td>x.copy(y)<td>Copy the contents of y to x (possible resizing x).
+ * </table>
+ *    
+ * <h3>Size and Shape</h3>
+ * 
+ * <p>The following methods permit to acces the size of a matrix and change its size or shape.</p>
+ * 
+ * <table class="my">
+ * <tr><th>x.Method<th>Description
+ * <tr><td>x.rows<td>Number of rows.
+ * <tr><td>x.columns<td>Number of columns.
+ * <tr><td>x.length<td>Total number of elements.
+ * <tr><td>x.isEmpty()<td>Checks whether rows == 0 and columns == 0.
+ * <tr><td>x.isRowVector()<td>Checks whether rows == 1.
+ * <tr><td>x.isColumnVector()<td>Checks whether columns == 1.
+ * <tr><td>x.isVector()<td>Checks whether rows == 1 or columns == 1.
+ * <tr><td>x.isSquare()<td>Checks whether rows == columns.
+ * <tr><td>x.isScalar()<td>Checks whether length == 1.
+ * <tr><td>x.resize(r, c)<td>Resize the matrix to r rows and c columns, discarding the content.
+ * <tr><td>x.reshape(r, c)<td>Resize the matrix to r rows and c columns.<br> Number of elements must not change.
+ * </table>
+ * 
+ * <p>The size is stored in the <tt>rows</tt> and <tt>columns</tt> member variables.
+ * The total number of elements is stored in <tt>length</tt>. Do not change these
+ * values unless you know what you're doing!</p>
+ * 
+ * <h3>Arithmetics</h3>
+ * 
+ * <p>The usual arithmetic operations are implemented. Each operation exists in a
+ * in-place version, recognizable by the suffix <tt>"i"</tt>, to which you can supply
+ * the result matrix (or <tt>this</tt> is used, if missing). Using in-place operations
+ * can also lead to a smaller memory footprint, as the number of temporary objects
+ * which are directly garbage collected again is reduced.</p>
+ * 
+ * <p>Whenever you specify a result vector, the result vector must already have the
+ * correct dimensions.</p>
+ * 
+ * <p>For example, you can add two matrices using the <tt>add</tt> method. If you want
+ * to store the result in of <tt>x + y</tt> in <tt>z</tt>, type
+ * <span class=code>
+ * x.addi(y, z)   // computes x = y + z.
+ * </span>
+ * Even in-place methods return the result, such that you can easily chain in-place methods,
+ * for example:
+ * <span class=code>
+ * x.addi(y).addi(z) // computes x += y; x += z
+ * </span></p> 
+ *
+ * <p>Methods which operate element-wise only make sure that the length of the matrices
+ * is correct. Therefore, you can add a 3 * 3 matrix to a 1 * 9 matrix, for example.</p>
+ * 
+ * <p>Finally, there exist versions which take doubles instead of DoubleMatrix Objects
+ * as arguments. These then compute the operation with the same value as the
+ * right-hand-side. The same effect can be achieved by passing a DoubleMatrix with
+ * exactly one element.</p>
+ * 
+ * <table class="my">
+ * <tr><th>Operation <th>Method <th>Comment
+ * <tr><td>x + y <td>x.add(y)			<td>
+ * <tr><td>x - y <td>x.sub(y), y.rsub(x) <td>rsub subtracts left from right hand side
+ * <tr><td rowspan=3>x * y 	<td>x.mul(y) <td>element-wise multiplication 
+ * <tr>						<td>x.mmul(y)<td>matrix-matrix multiplication
+ * <tr>						<td>x.dot(y) <td>scalar-product
+ * <tr><td>x / y <td>x.div(y), y.rdiv(x) <td>rdiv divides right hand side by left hand side.
+ * <tr><td>- x	<td>x.neg()				<td>
+ * </table>
+ * 
+ * <p>There also exist operations which work on whole columns or rows.</p>
+ * 
+ * <table class="my">
+ * <tr><th>Method <th>Description
+ * <tr><td>x.addRowVector<td>adds a vector to each row (addiRowVector works in-place)
+ * <tr><td>x.addColumnVector<td>adds a vector to each column
+ * <tr><td>x.subRowVector<td>subtracts a vector from each row
+ * <tr><td>x.subColumnVector<td>subtracts a vector from each column
+ * <tr><td>x.mulRow<td>Multiplies a row by a scalar
+ * <tr><td>x.mulColumn<td>multiplies a row by a column
+ * </table>
+ * 
+ * <p>In principle, you could achieve the same result by first calling getColumn(), 
+ * adding, and then calling putColumn, but these methods are much faster.</p>
+ * 
+ * <p>The following comparison operations are available</p>
+ *  
+ * <table class="my">
+ * <tr><th>Operation <th>Method
+ * <tr><td>x < y		<td>x.lt(y)
+ * <tr><td>x <= y	<td>x.le(y)
+ * <tr><td>x > y		<td>x.gt(y)
+ * <tr><td>x >= y	<td>x.ge(y)
+ * <tr><td>x == y		<td>x.eq(y)
+ * <tr><td>x != y		<td>x.ne(y)
+ * </table>
+ *
+ * <p> Logical operations are also supported. For these operations, a value different from
+ * zero is treated as "true" and zero is treated as "false". All operations are carried
+ * out elementwise.</p>
+ * 
+ * <table class="my">
+ * <tr><th>Operation <th>Method
+ * <tr><td>x & y 	<td>x.and(y)
+ * <tr><td>x | y 	<td>x.or(y)
+ * <tr><td>x ^ y	<td>x.xor(y)
+ * <tr><td>! x		<td>x.not()
+ * </table>
+ * 
+ * <p>Finally, there are a few more methods to compute various things:</p>
+ * 
+ * <table class="my">
+ * <tr><th>Method <th>Description
+ * <tr><td>x.max() <td>Return maximal element
+ * <tr><td>x.argmax() <td>Return index of largest element
+ * <tr><td>x.min() <td>Return minimal element
+ * <tr><td>x.argmin() <td>Return index of largest element
+ * <tr><td>x.columnMins() <td>Return column-wise minima
+ * <tr><td>x.columnArgmins() <td>Return column-wise index of minima
+ * <tr><td>x.columnMaxs() <td>Return column-wise maxima
+ * <tr><td>x.columnArgmaxs() <td>Return column-wise index of maxima
+ * </table>
+ * 
+ * @author Mikio Braun, Johannes Schaback
+ */
+public class DoubleMatrix {
+
+    /** Number of rows. */
+    public int rows;
+    /** Number of columns. */
+    public int columns;
+    /** Total number of elements (for convenience). */
+    public int length;
+    /** The actual data stored by rows (that is, row 0, row 1...). */
+    public double[] data = null; // rows are contiguous
+    public static final DoubleMatrix EMPTY = new DoubleMatrix();
+
+    /**************************************************************************
+     *
+     * Constructors and factory functions
+     *
+     **************************************************************************/
+    /** Create a new matrix with <i>newRows</i> rows, <i>newColumns</i> columns
+     * using <i>newData></i> as the data. The length of the data is not checked!
+     */
+    public DoubleMatrix(int newRows, int newColumns, double... newData) {
+        rows = newRows;
+        columns = newColumns;
+        length = rows * columns;
+
+        if (newData != null && newData.length != newRows * newColumns) {
+            throw new IllegalArgumentException(
+                    "Passed data must match matrix dimensions.");
+        }
+
+        data = newData;
+    //System.err.printf("%d * %d matrix created\n", rows, columns);
+    }
+
+    /**
+     * Creates a new <i>n</i> times <i>m</i> <tt>DoubleMatrix</tt>.
+     * @param newRows the number of rows (<i>n</i>) of the new matrix.
+     * @param newColumns the number of columns (<i>m</i>) of the new matrix.
+     */
+    public DoubleMatrix(int newRows, int newColumns) {
+        this(newRows, newColumns, new double[newRows * newColumns]);
+    }
+
+    /**
+     * Creates a new <tt>DoubleMatrix</tt> of size 0 times 0.
+     */
+    public DoubleMatrix() {
+        this(0, 0, (double[]) null);
+    }
+
+    /**
+     * Create a Matrix of length <tt>len</tt>. By default, this creates a row vector.
+     * @param len
+     */
+    public DoubleMatrix(int len) {
+        this(len, 1, new double[len]);
+    }
+
+    public DoubleMatrix(double[] newData) {
+        this(newData.length);
+        data = newData;
+    }
+
+    /**
+     * Creates a new matrix by reading it from a file.
+     * @param filename the path and name of the file to read the matrix from
+     * @throws IOException
+     */
+    public DoubleMatrix(String filename) throws IOException {
+        load(filename);
+    }
+
+    /**
+     * Creates a new <i>n</i> times <i>m</i> <tt>DoubleMatrix</tt> from
+     * the given <i>n</i> times <i>m</i> 2D data array. The first dimension of the array makes the
+     * rows (<i>n</i>) and the second dimension the columns (<i>m</i>). For example, the
+     * given code <br/><br/>
+     * <code>new DoubleMatrix(new double[][]{{1d, 2d, 3d}, {4d, 5d, 6d}, {7d, 8d, 9d}}).print();</code><br/><br/>
+     * will constructs the following matrix:
+     * <pre>
+     * 1.0	2.0	3.0
+     * 4.0	5.0	6.0
+     * 7.0	8.0	9.0
+     * </pre>.
+     * @param data <i>n</i> times <i>m</i> data array
+     */
+    public DoubleMatrix(double[][] data) {
+        this(data.length, data[0].length);
+
+        for (int r = 0; r < rows; r++) {
+            assert (data[r].length == columns);
+        }
+
+        for (int r = 0; r < rows; r++) {
+            for (int c = 0; c < columns; c++) {
+                put(r, c, data[r][c]);
+            }
+        }
+    }
+
+    /** Create matrix with random values uniformly in 0..1. */
+    public static DoubleMatrix rand(int rows, int columns) {
+        DoubleMatrix m = new DoubleMatrix(rows, columns);
+
+        java.util.Random r = new java.util.Random();
+        for (int i = 0; i < rows * columns; i++) {
+            m.data[i] = r.nextDouble();
+        }
+
+        return m;
+    }
+
+    /** Creates a row vector with random values uniformly in 0..1. */
+    public static DoubleMatrix rand(int len) {
+        return rand(len, 1);
+    }
+
+    /** Create matrix with normally distributed random values. */
+    public static DoubleMatrix randn(int rows, int columns) {
+        DoubleMatrix m = new DoubleMatrix(rows, columns);
+
+        java.util.Random r = new java.util.Random();
+        for (int i = 0; i < rows * columns; i++) {
+            m.data[i] = (double) r.nextGaussian();
+        }
+
+        return m;
+    }
+
+    /** Create row vector with normally distributed random values. */
+    public static DoubleMatrix randn(int len) {
+        return randn(len, 1);
+    }
+
+    /** Creates a new matrix in which all values are equal 0. */
+    public static DoubleMatrix zeros(int rows, int columns) {
+        return new DoubleMatrix(rows, columns);
+    }
+
+    /** Creates a row vector of given length. */
+    public static DoubleMatrix zeros(int length) {
+        return zeros(length, 1);
+    }
+
+    /** Creates a new matrix in which all values are equal 1. */
+    public static DoubleMatrix ones(int rows, int columns) {
+        DoubleMatrix m = new DoubleMatrix(rows, columns);
+
+        for (int i = 0; i < rows * columns; i++) {
+            m.put(i, 1.0);
+        }
+
+        return m;
+    }
+
+    /** Creates a row vector with all elements equal to 1. */
+    public static DoubleMatrix ones(int length) {
+        return ones(length, 1);
+    }
+
+    /** Construct a new n-by-n identity matrix. */
+    public static DoubleMatrix eye(int n) {
+        DoubleMatrix m = new DoubleMatrix(n, n);
+
+        for (int i = 0; i < n; i++) {
+            m.put(i, i, 1.0);
+        }
+
+        return m;
+    }
+
+    /**
+     * Creates a new matrix where the values of the given vector are the diagonal values of
+     * the matrix.
+     */
+    public static DoubleMatrix diag(DoubleMatrix x) {
+        DoubleMatrix m = new DoubleMatrix(x.length, x.length);
+
+        for (int i = 0; i < x.length; i++) {
+            m.put(i, i, x.get(i));
+        }
+
+        return m;
+    }
+
+    /**
+     * Create a 1-by-1 matrix. For many operations, this matrix functions like a
+     * normal double.
+     */
+    public static DoubleMatrix scalar(double s) {
+        DoubleMatrix m = new DoubleMatrix(1, 1);
+        m.put(0, 0, s);
+        return m;
+    }
+
+    /** Test whether a matrix is scalar. */
+    public boolean isScalar() {
+        return length == 1;
+    }
+
+    /** Return the first element of the matrix. */
+    public double scalar() {
+        return get(0);
+    }
+
+    /**
+     * Concatenates two matrices horizontally. Matrices must have identical
+     * numbers of rows.
+     */
+    public static DoubleMatrix concatHorizontally(DoubleMatrix A, DoubleMatrix B) {
+        if (A.rows != B.rows) {
+            throw new SizeException("Matrices don't have same number of rows.");
+        }
+
+        DoubleMatrix result = new DoubleMatrix(A.rows, A.columns + B.columns);
+        SimpleBlas.copy(A, result);
+        JavaBlas.rcopy(B.length, B.data, 0, 1, result.data, A.length, 1);
+        return result;
+    }
+
+    /**
+     * Concatenates two matrices vertically. Matrices must have identical
+     * numbers of columns.
+     */
+    public static DoubleMatrix concatVertically(DoubleMatrix A, DoubleMatrix B) {
+        if (A.columns != B.columns) {
+            throw new SizeException("Matrices don't have same number of columns (" + A.columns + " != " + B.columns + ".");
+        }
+
+        DoubleMatrix result = new DoubleMatrix(A.rows + B.rows, A.columns);
+
+        for (int i = 0; i < A.columns; i++) {
+            JavaBlas.rcopy(A.rows, A.data, A.index(0, i), 1, result.data, result.index(0, i), 1);
+            JavaBlas.rcopy(B.rows, B.data, B.index(0, i), 1, result.data, result.index(A.rows, i), 1);
+        }
+
+        return result;
+    }
+
+    /**************************************************************************
+     * Working with slices (Man! 30+ methods just to make this a bit flexible...)
+     */
+    /** Get all elements specified by the linear indices. */
+    public DoubleMatrix get(int[] indices) {
+        DoubleMatrix result = new DoubleMatrix(indices.length);
+
+        for (int i = 0; i < indices.length; i++) {
+            result.put(i, get(indices[i]));
+        }
+
+        return result;
+    }
+
+    /** Get all elements for a given row and the specified columns. */
+    public DoubleMatrix get(int r, int[] indices) {
+        DoubleMatrix result = new DoubleMatrix(1, indices.length);
+
+        for (int i = 0; i < indices.length; i++) {
+            result.put(i, get(r, indices[i]));
+        }
+
+        return result;
+    }
+
+    /** Get all elements for a given column and the specified rows. */
+    public DoubleMatrix get(int[] indices, int c) {
+        DoubleMatrix result = new DoubleMatrix(indices.length, c);
+
+        for (int i = 0; i < indices.length; i++) {
+            result.put(i, get(indices[i], c));
+        }
+
+        return result;
+    }
+
+    /** Get all elements from the specified rows and columns. */
+    public DoubleMatrix get(int[] rindices, int[] cindices) {
+        DoubleMatrix result = new DoubleMatrix(rindices.length, cindices.length);
+
+        for (int i = 0; i < rindices.length; i++) {
+            for (int j = 0; j < cindices.length; j++) {
+                result.put(i, j, get(rindices[i], cindices[j]));
+            }
+        }
+
+        return result;
+    }
+
+    /** Get elements from specified rows and columns. */
+    public DoubleMatrix get(Range rs, Range cs) {
+        rs.init(0, rows - 1);
+        cs.init(0, columns - 1);
+        DoubleMatrix result = new DoubleMatrix(rs.length(), cs.length());
+
+        for (; !rs.hasMore(); rs.next()) {
+            for (; !cs.hasMore(); cs.next()) {
+                result.put(rs.index(), cs.index(), get(rs.value(), cs.value()));
+            }
+        }
+
+        return result;
+    }
+
+    /** Get elements specified by the non-zero entries of the passed matrix. */
+    public DoubleMatrix get(DoubleMatrix indices) {
+        return get(indices.findIndices());
+    }
+
+    /**
+     * Get elements from a row and columns as specified by the non-zero entries of
+     * a matrix.
+     */
+    public DoubleMatrix get(int r, DoubleMatrix indices) {
+        return get(r, indices.findIndices());
+    }
+
+    /**
+     * Get elements from a column and rows as specified by the non-zero entries of
+     * a matrix.
+     */
+    public DoubleMatrix get(DoubleMatrix indices, int c) {
+        return get(indices.findIndices(), c);
+    }
+
+    /**
+     * Get elements from columns and rows as specified by the non-zero entries of
+     * the passed matrices.
+     */
+    public DoubleMatrix get(DoubleMatrix rindices, DoubleMatrix cindices) {
+        return get(rindices.findIndices(), cindices.findIndices());
+    }
+
+    /** Return all elements with linear index a, a + 1, ..., b - 1.*/
+    public DoubleMatrix getRange(int a, int b) {
+        DoubleMatrix result = new DoubleMatrix(b - a);
+
+        for (int k = 0; k < b - a; k++) {
+            result.put(k, get(a + k));
+        }
+
+        return result;
+    }
+
+    /** Get elements from a row and columns <tt>a</tt> to <tt>b</tt>. */
+    public DoubleMatrix getColumnRange(int r, int a, int b) {
+        DoubleMatrix result = new DoubleMatrix(1, b - a);
+
+        for (int k = 0; k < b - a; k++) {
+            result.put(k, get(r, a + k));
+        }
+
+        return result;
+    }
+
+    /** Get elements from a column and rows <tt>a/tt> to <tt>b</tt>. */
+    public DoubleMatrix getRowRange(int a, int b, int c) {
+        DoubleMatrix result = new DoubleMatrix(b - a);
+
+        for (int k = 0; k < b - a; k++) {
+            result.put(k, get(a + k, c));
+        }
+
+        return result;
+    }
+
+    /**
+     * Get elements from rows <tt>ra</tt> to <tt>rb</tt> and
+     * columns <tt>ca</tt> to <tt>cb</tt>.
+     */
+    public DoubleMatrix getRange(int ra, int rb, int ca, int cb) {
+        DoubleMatrix result = new DoubleMatrix(rb - ra, cb - ca);
+
+        for (int i = 0; i < rb - ra; i++) {
+            for (int j = 0; j < cb - ca; j++) {
+                result.put(i, j, get(ra + i, ca + j));
+            }
+        }
+
+        return result;
+    }
+
+    /** Get whole rows from the passed indices. */
+    public DoubleMatrix getRows(int[] rindices) {
+        DoubleMatrix result = new DoubleMatrix(rindices.length, columns);
+        for (int i = 0; i < rindices.length; i++) {
+            JavaBlas.rcopy(columns, data, index(rindices[i], 0), rows, result.data, result.index(i, 0), result.rows);
+        }
+        return result;
+    }
+
+    /** Get whole rows as specified by the non-zero entries of a matrix. */
+    public DoubleMatrix getRows(DoubleMatrix rindices) {
+        return getRows(rindices.findIndices());
+    }
+
+    /** Get whole columns from the passed indices. */
+    public DoubleMatrix getColumns(int[] cindices) {
+        DoubleMatrix result = new DoubleMatrix(rows, cindices.length);
+        for (int i = 0; i < cindices.length; i++) {
+            JavaBlas.rcopy(rows, data, index(0, cindices[i]), 1, result.data, result.index(0, i), 1);
+        }
+        return result;
+    }
+
+    /** Get whole columns as specified by the non-zero entries of a matrix. */
+    public DoubleMatrix getColumns(DoubleMatrix cindices) {
+        return getColumns(cindices.findIndices());
+    }
+
+    /**
+     * Assert that the matrix has a certain length.
+     * @throws SizeException
+     */
+    public void checkLength(int l) {
+        if (length != l) {
+            throw new SizeException("Matrix does not have the necessary length (" + length + " != " + l + ").");
+        }
+    }
+
+    /**
+     * Asserts that the matrix has a certain number of rows.
+     * @throws SizeException
+     */
+    public void checkRows(int r) {
+        if (rows != r) {
+            throw new SizeException("Matrix does not have the necessary number of rows (" + rows + " != " + r + ").");
+        }
+    }
+
+    /**
+     * Asserts that the amtrix has a certain number of columns.
+     * @throws SizeException
+     */
+    public void checkColumns(int c) {
+        if (columns != c) {
+            throw new SizeException("Matrix does not have the necessary number of columns (" + columns + " != " + c + ").");
+        }
+    }
+
+    /** Set elements in linear ordering in the specified indices. */
+    public DoubleMatrix put(int[] indices, DoubleMatrix x) {
+        if (x.isScalar()) {
+            return put(indices, x.scalar());
+        }
+        x.checkLength(indices.length);
+
+        for (int i = 0; i < indices.length; i++) {
+            put(indices[i], x.get(i));
+        }
+
+        return this;
+    }
+
+    /** Set multiple elements in a row. */
+    public DoubleMatrix put(int r, int[] indices, DoubleMatrix x) {
+        if (x.isScalar()) {
+            return put(r, indices, x.scalar());
+        }
+        x.checkColumns(indices.length);
+
+        for (int i = 0; i < indices.length; i++) {
+            put(r, indices[i], x.get(i));
+        }
+
+        return this;
+    }
+
+    /** Set multiple elements in a row. */
+    public DoubleMatrix put(int[] indices, int c, DoubleMatrix x) {
+        if (x.isScalar()) {
+            return put(indices, c, x.scalar());
+        }
+        x.checkRows(indices.length);
+
+        for (int i = 0; i < indices.length; i++) {
+            put(indices[i], c, x.get(i));
+        }
+
+        return this;
+    }
+
+    /** Put a sub-matrix as specified by the indices. */
+    public DoubleMatrix put(int[] rindices, int[] cindices, DoubleMatrix x) {
+        if (x.isScalar()) {
+            return put(rindices, cindices, x.scalar());
+        }
+        x.checkRows(rindices.length);
+        x.checkColumns(cindices.length);
+
+        for (int i = 0; i < rindices.length; i++) {
+            for (int j = 0; j < cindices.length; j++) {
+                put(rindices[i], cindices[j], x.get(i, j));
+            }
+        }
+
+        return this;
+    }
+
+    /** 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);
+
+        x.checkRows(rs.length());
+        x.checkColumns(cs.length());
+
+        for (; rs.hasMore(); rs.next()) {
+            for (; cs.hasMore(); cs.next()) {
+                put(rs.value(), cs.value(), x.get(rs.index(), cs.index()));
+            }
+        }
+
+        return this;
+    }
+
+    /** Put a single value into the specified indices (linear adressing). */
+    public DoubleMatrix put(int[] indices, double v) {
+        for (int i = 0; i < indices.length; i++) {
+            put(indices[i], v);
+        }
+
+        return this;
+    }
+
+    /** Put a single value into a row and the specified columns. */
+    public DoubleMatrix put(int r, int[] indices, double v) {
+        for (int i = 0; i < indices.length; i++) {
+            put(r, indices[i], v);
+        }
+
+        return this;
+    }
+
+    /** Put a single value into the specified rows of a column. */
+    public DoubleMatrix put(int[] indices, int c, double v) {
+        for (int i = 0; i < indices.length; i++) {
+            put(indices[i], c, v);
+        }
+
+        return this;
+    }
+
+    /** Put a single value into the specified rows and columns. */
+    public DoubleMatrix put(int[] rindices, int[] cindices, double v) {
+        for (int i = 0; i < rindices.length; i++) {
+            for (int j = 0; j < cindices.length; j++) {
+                put(rindices[i], cindices[j], v);
+            }
+        }
+
+        return this;
+    }
+
+    /**
+     * Put a sub-matrix into the indices specified by the non-zero entries
+     * of <tt>indices</tt> (linear adressing).
+     */
+    public DoubleMatrix put(DoubleMatrix indices, DoubleMatrix v) {
+        return put(indices.findIndices(), v);
+    }
+
+    /** Put a sub-vector into the specified columns (non-zero entries of <tt>indices</tt>) of a row. */
+    public DoubleMatrix put(int r, DoubleMatrix indices, DoubleMatrix v) {
+        return put(r, indices.findIndices(), v);
+    }
+
+    /** Put a sub-vector into the specified rows (non-zero entries of <tt>indices</tt>) of a column. */
+    public DoubleMatrix put(DoubleMatrix indices, int c, DoubleMatrix v) {
+        return put(indices.findIndices(), c, v);
+    }
+
+    /**
+     * Put a sub-matrix into the specified rows and columns (non-zero entries of
+     * <tt>rindices</tt> and <tt>cindices</tt>.
+     */
+    public DoubleMatrix put(DoubleMatrix rindices, DoubleMatrix cindices, DoubleMatrix v) {
+        return put(rindices.findIndices(), cindices.findIndices(), v);
+    }
+
+    /**
+     * Put a single value into the elements specified by the non-zero
+     * entries of <tt>indices</tt> (linear adressing).
+     */
+    public DoubleMatrix put(DoubleMatrix indices, double v) {
+        return put(indices.findIndices(), v);
+    }
+
+    /**
+     * Put a single value into the specified columns (non-zero entries of
+     * <tt>indices</tt>) of a row.
+     */
+    public DoubleMatrix put(int r, DoubleMatrix indices, double v) {
+        return put(r, indices.findIndices(), v);
+    }
+
+    /**
+     * Put a single value into the specified rows (non-zero entries of
+     * <tt>indices</tt>) of a column.
+     */
+    public DoubleMatrix put(DoubleMatrix indices, int c, double v) {
+        return put(indices.findIndices(), c, v);
+    }
+
+    /**
+     * Put a single value in the specified rows and columns (non-zero entries
+     * of <tt>rindices</tt> and <tt>cindices</tt>.
+     */
+    public DoubleMatrix put(DoubleMatrix rindices, DoubleMatrix cindices, double v) {
+        return put(rindices.findIndices(), cindices.findIndices(), v);
+    }
+
+    /** Find the linear indices of all non-zero elements. */
+    public int[] findIndices() {
+        int len = 0;
+        for (int i = 0; i < length; i++) {
+            if (get(i) != 0.0) {
+                len++;
+            }
+        }
+
+        int[] indices = new int[len];
+        int c = 0;
+
+        for (int i = 0; i < length; i++) {
+            if (get(i) != 0.0) {
+                indices[c++] = i;
+            }
+        }
+
+        return indices;
+    }
+
+    /**************************************************************************
+     * Basic operations (copying, resizing, element access)
+     */
+    /** Return transposed copy of this matrix. */
+    public DoubleMatrix transpose() {
+        DoubleMatrix result = new DoubleMatrix(columns, rows);
+
+        for (int i = 0; i < rows; i++) {
+            for (int j = 0; j < columns; j++) {
+                result.put(j, i, get(i, j));
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Compare two matrices. Returns true if and only if other is also a
+     * DoubleMatrix which has the same size and the maximal absolute
+     * difference in matrix elements is smaller thatn 1e-6.
+     */
+    public boolean equals(Object o) {
+        if (!(o instanceof DoubleMatrix)) {
+            return false;
+        }
+
+        DoubleMatrix other = (DoubleMatrix) o;
+
+        if (!sameSize(other)) {
+            return false;
+        }
+
+        DoubleMatrix diff = MatrixFunctions.absi(sub(other));
+
+        return diff.max() / (rows * columns) < 1e-6;
+    }
+
+    /** Resize the matrix. All elements will be set to zero. */
+    public void resize(int newRows, int newColumns) {
+        rows = newRows;
+        columns = newColumns;
+        length = newRows * newColumns;
+        data = new double[rows * columns];
+    }
+
+    /** Reshape the matrix. Number of elements must not change. */
+    public DoubleMatrix reshape(int newRows, int newColumns) {
+        if (length != newRows * newColumns) {
+            throw new IllegalArgumentException(
+                    "Number of elements must not change.");
+        }
+
+        rows = newRows;
+        columns = newColumns;
+
+        return this;
+    }
+
+    /** Generate a new matrix which has the given number of replications of this. */
+    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++)
+                        result.put(r * rows + i, c * columns + j, get(i, j));
+        return result;
+    }
+
+    /** Checks whether two matrices have the same size. */
+    public boolean sameSize(DoubleMatrix a) {
+        return rows == a.rows && columns == a.columns;
+    }
+
+    /** Throws SizeException unless two matrices have the same size. */
+    public void assertSameSize(DoubleMatrix a) {
+        if (!sameSize(a)) {
+            throw new SizeException("Matrices must have the same size.");
+        }
+    }
+
+    /** Checks whether two matrices can be multiplied (that is, number of columns of
+     * this must equal number of rows of a. */
+    public boolean multipliesWith(DoubleMatrix a) {
+        return columns == a.rows;
+    }
+
+    /** Throws SizeException unless matrices can be multiplied with one another. */
+    public void assertMultipliesWith(DoubleMatrix a) {
+        if (!multipliesWith(a)) {
+            throw new SizeException("Number of columns of left matrix must be equal to number of rows of right matrix.");
+        }
+    }
+
+    /** Checks whether two matrices have the same length. */
+    public boolean sameLength(DoubleMatrix a) {
+        return length == a.length;
+    }
+
+    /** Throws SizeException unless matrices have the same length. */
+    public void assertSameLength(DoubleMatrix a) {
+        if (!sameLength(a)) {
+            throw new SizeException("Matrices must have same length (is: " + length + " and " + a.length + ")");
+        }
+    }
+
+    /** Copy DoubleMatrix a to this. this a is resized if necessary. */
+    public DoubleMatrix copy(DoubleMatrix a) {
+        if (!sameSize(a)) {
+            resize(a.rows, a.columns);
+        }
+
+        System.arraycopy(data, 0, a.data, 0, length);
+        return a;
+    }
+
+    /**
+     * Returns a duplicate of this matrix. Geometry is the same (including offsets, transpose, etc.),
+     * but the buffer is not shared.
+     */
+    public DoubleMatrix dup() {
+        DoubleMatrix out = new DoubleMatrix(rows, columns);
+
+        JavaBlas.rcopy(length, data, 0, 1, out.data, 0, 1);
+
+        return out;
+    }
+
+    /** Swap two columns of a matrix. */
+    public DoubleMatrix swapColumns(int i, int j) {
+        Blas.dswap(rows, data, index(0, i), 1, data, index(0, j), 1);
+        return this;
+    }
+
+    /** Swap two rows of a matrix. */
+    public DoubleMatrix swapRows(int i, int j) {
+        Blas.dswap(columns, data, index(i, 0), rows, data, index(j, 0), rows);
+        return this;
+    }
+
+    /** Set matrix element */
+    public DoubleMatrix put(int rowIndex, int columnIndex, double value) {
+        data[index(rowIndex, columnIndex)] = value;
+        return this;
+    }
+
+    /** Retrieve matrix element */
+    public double get(int rowIndex, int columnIndex) {
+        return data[index(rowIndex, columnIndex)];
+    }
+
+    /** Get index of an element */
+    public int index(int rowIndex, int columnIndex) {
+        return rowIndex + rows * columnIndex;
+    }
+
+    /** Compute the row index of a linear index. */
+    public int indexRows(int i) {
+        return i / rows;
+    }
+
+    /** Compute the column index of a linear index. */
+    public int indexColumns(int i) {
+        return i - indexRows(i) * rows;
+    }
+
+    /** Get a matrix element (linear indexing). */
+    public double get(int i) {
+        return data[i];
+    }
+
+    /** Set a matrix element (linear indexing). */
+    public DoubleMatrix put(int i, double v) {
+        data[i] = v;
+        return this;
+    }
+
+    /** Set all elements to a value. */
+    public DoubleMatrix fill(double value) {
+        for (int i = 0; i < length; i++) {
+            put(i, value);
+        }
+        return this;
+    }
+
+    /** Get number of rows. */
+    public int getRows() {
+        return rows;
+    }
+
+    /** Get number of columns. */
+    public int getColumns() {
+        return columns;
+    }
+
+    /** Get total number of elements. */
+    public int getLength() {
+        return length;
+    }
+
+    /** Checks whether the matrix is empty. */
+    public boolean isEmpty() {
+        return columns == 0 || rows == 0;
+    }
+
+    /** Checks whether the matrix is square. */
+    public boolean isSquare() {
+        return columns == rows;
+    }
+
+    /** Throw SizeException unless matrix is square. */
+    public void assertSquare() {
+        if (!isSquare()) {
+            throw new SizeException("Matrix must be square!");
+        }
+    }
+
+    /** Checks whether the matrix is a vector. */
+    public boolean isVector() {
+        return columns == 1 || rows == 1;
+    }
+
+    /** Checks whether the matrix is a row vector. */
+    public boolean isRowVector() {
+        return rows == 1;
+    }
+
+    /** Checks whether the matrix is a column vector. */
+    public boolean isColumnVector() {
+        return columns == 1;
+    }
+
+    /** Returns the diagonal of the matrix. */
+    public DoubleMatrix diag() {
+        assertSquare();
+        DoubleMatrix d = new DoubleMatrix(rows);
+        JavaBlas.rcopy(rows, data, 0, rows + 1, d.data, 0, 1);
+        return d;
+    }
+
+    /** Pretty-print this matrix to <tt>System.out</tt>. */
+    public void print() {
+        System.out.println(toString());
+    }
+
+    /** Generate string representation of the matrix. */
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder();
+
+        s.append("[");
+
+        for (int i = 0; i < rows; i++) {
+            for (int j = 0; j < columns; j++) {
+                s.append(get(i, j));
+                if (j < columns - 1) {
+                    s.append(", ");
+                }
+            }
+            if (i < rows - 1) {
+                s.append("; ");
+            }
+        }
+
+        s.append("]");
+
+        return s.toString();
+    }
+
+    /**
+     * Generate string representation of the matrix, with specified
+     * format for the entries. For example, <code>x.toString("%.1f")</code>
+     * generates a string representations having only one position after the
+     * decimal point.
+     */
+    public String toString(String fmt) {
+        StringWriter s = new StringWriter();
+        PrintWriter p = new PrintWriter(s);
+
+        p.print("[");
+
+        for (int r = 0; r < rows; r++) {
+            for (int c = 0; c < columns; c++) {
+                p.printf(fmt, get(r, c));
+                if (c < columns - 1) {
+                    p.print(", ");
+                }
+            }
+            if (r < rows - 1) {
+                p.print("; ");
+            }
+        }
+
+        p.print("]");
+
+        return s.toString();
+    }
+
+    /** Converts the matrix to a one-dimensional array of doubles. */
+    public double[] toArray() {
+        double[] array = new double[length];
+
+        System.arraycopy(data, 0, array, 0, length);
+
+        return array;
+    }
+
+    /** Converts the matrix to a two-dimensional array of doubles. */
+    public double[][] toArray2() {
+        double[][] array = new double[rows][columns];
+
+        for (int r = 0; r < rows; r++) {
+            for (int c = 0; c < columns; c++) {
+                array[r][c] = get(r, c);
+            }
+        }
+
+        return array;
+    }
+
+    /** Converts the matrix to a one-dimensional array of integers. */
+    public int[] toIntArray() {
+        int[] array = new int[length];
+
+        for (int i = 0; i < length; i++) {
+            array[i] = (int) Math.rint(get(i));
+        }
+
+        return array;
+    }
+
+    /** Convert the matrix to a two-dimensional array of integers. */
+    public int[][] toIntArray2() {
+        int[][] array = new int[rows][columns];
+
+        for (int r = 0; r < rows; r++) {
+            for (int c = 0; c < columns; c++) {
+                array[r][c] = (int) Math.rint(get(r, c));
+            }
+        }
+
+        return array;
+    }
+
+    /** Convert the matrix to a one-dimensional array of boolean values. */
+    public boolean[] toBooleanArray() {
+        boolean[] array = new boolean[length];
+
+        for (int i = 0; i < length; i++) {
+            array[i] = get(i) != 0.0 ? true : false;
+        }
+
+        return array;
+    }
+
+    /** Convert the matrix to a two-dimensional array of boolean values. */
+    public boolean[][] toBooleanArray2() {
+        boolean[][] array = new boolean[rows][columns];
+
+        for (int r = 0; r < rows; r++) {
+            for (int c = 0; c < columns; c++) {
+                array[r][c] = get(r, c) != 0.0 ? true : false;
+            }
+        }
+
+        return array;
+    }
+
+    /** Convert matrix to FloatMatrix. */
+    public FloatMatrix toFloatMatrix() {
+        FloatMatrix result = new FloatMatrix(rows, columns);
+
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
+                result.put(r, c, (float) get(r, c));
+            }
+        }
+
+        return result;
+    }
+
+    /**************************************************************************
+     * Arithmetic Operations
+     */
+    /**
+     * Ensures that the result vector has the same length as this. If not,
+     * resizing result is tried, which fails if result == this or result == other.
+     */
+    private void ensureResultLength(DoubleMatrix other, DoubleMatrix result) {
+        if (!sameLength(result)) {
+            if (result == this || result == other) {
+                throw new SizeException("Cannot resize result matrix because it is used in-place.");
+            }
+            result.resize(rows, columns);
+        }
+    }
+
+    /** Add two matrices (in-place). */
+    public DoubleMatrix addi(DoubleMatrix other, DoubleMatrix result) {
+        if (other.isScalar()) {
+            return addi(other.scalar(), result);
+        }
+        if (isScalar()) {
+            return other.addi(scalar(), result);
+        }
+
+        assertSameLength(other);
+        ensureResultLength(other, result);
+
+        if (result == this) {
+            SimpleBlas.axpy(1.0, other, result);
+        } else if (result == other) {
+            SimpleBlas.axpy(1.0, this, result);
+        } else {
+            /*SimpleBlas.copy(this, result);
+            SimpleBlas.axpy(1.0, other, result);*/
+            JavaBlas.rzgxpy(length, result.data, data, other.data);
+        }
+
+        return result;
+    }
+
+    /** Add a scalar to a matrix (in-place). */
+    public DoubleMatrix addi(double v, DoubleMatrix result) {
+        ensureResultLength(null, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, get(i) + v);
+        }
+        return result;
+    }
+
+    /** Subtract two matrices (in-place). */
+    public DoubleMatrix subi(DoubleMatrix other, DoubleMatrix result) {
+        if (other.isScalar()) {
+            return subi(other.scalar(), result);
+        }
+        if (isScalar()) {
+            return other.rsubi(scalar(), result);
+        }
+
+        assertSameLength(other);
+        ensureResultLength(other, result);
+
+        if (result == this) {
+            SimpleBlas.axpy(-1.0, other, result);
+        } else if (result == other) {
+            SimpleBlas.scal(-1.0, result);
+            SimpleBlas.axpy(1.0, this, result);
+        } else {
+            SimpleBlas.copy(this, result);
+            SimpleBlas.axpy(-1.0, other, result);
+        }
+        return result;
+    }
+
+    /** Subtract a scalar from a matrix (in-place). */
+    public DoubleMatrix subi(double v, DoubleMatrix result) {
+        ensureResultLength(null, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, get(i) - v);
+        }
+        return result;
+    }
+
+    /**
+     * Subtract two matrices, but subtract first from second matrix, that is,
+     * compute <em>result = other - this</em> (in-place).
+     * */
+    public DoubleMatrix rsubi(DoubleMatrix other, DoubleMatrix result) {
+        return other.subi(this, result);
+    }
+
+    /** Subtract a matrix from a scalar (in-place). */
+    public DoubleMatrix rsubi(double a, DoubleMatrix result) {
+        ensureResultLength(null, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, a - get(i));
+        }
+        return result;
+    }
+
+    /** Elementwise multiplication (in-place). */
+    public DoubleMatrix muli(DoubleMatrix other, DoubleMatrix result) {
+        if (other.isScalar()) {
+            return muli(other.scalar(), result);
+        }
+        if (isScalar()) {
+            return other.muli(scalar(), result);
+        }
+
+        assertSameLength(other);
+        ensureResultLength(other, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, get(i) * other.get(i));
+        }
+        return result;
+    }
+
+    /** Elementwise multiplication with a scalar (in-place). */
+    public DoubleMatrix muli(double v, DoubleMatrix result) {
+        ensureResultLength(null, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, get(i) * v);
+        }
+        return result;
+    }
+
+    /** Matrix-matrix multiplication (in-place). */
+    public DoubleMatrix mmuli(DoubleMatrix other, DoubleMatrix result) {
+        if (other.isScalar()) {
+            return muli(other.scalar(), result);
+        }
+        if (isScalar()) {
+            return other.muli(scalar(), result);
+        }
+
+        /* check sizes and resize if necessary */
+        assertMultipliesWith(other);
+        if (result.rows != rows || result.columns != other.columns) {
+            if (result != this && result != other) {
+                result.resize(rows, other.columns);
+            } else {
+                throw new SizeException("Cannot resize result matrix because it is used in-place.");
+            }
+        }
+
+        if (result == this || result == other) {
+            /* actually, blas cannot do multiplications in-place. Therefore, we will fake by
+             * allocating a temporary object on the side and copy the result later.
+             */
+            DoubleMatrix temp = new DoubleMatrix(result.rows, result.columns);
+            if (other.columns == 1) {
+                SimpleBlas.gemv(1.0, this, other, 0.0, temp);
+            } else {
+                SimpleBlas.gemm(1.0, this, other, 0.0, temp);
+            }
+            SimpleBlas.copy(temp, result);
+        } else {
+            if (other.columns == 1) {
+                SimpleBlas.gemv(1.0, this, other, 0.0, result);
+            } else {
+                SimpleBlas.gemm(1.0, this, other, 0.0, result);
+            }
+        }
+        return result;
+    }
+
+    /** Matrix-matrix multiplication with a scalar (for symmetry, does the
+     * same as <code>muli(scalar)</code> (in-place).
+     */
+    public DoubleMatrix mmuli(double v, DoubleMatrix result) {
+        return muli(v, result);
+    }
+
+    /** Elementwise division (in-place). */
+    public DoubleMatrix divi(DoubleMatrix other, DoubleMatrix result) {
+        if (other.isScalar()) {
+            return divi(other.scalar(), result);
+        }
+        if (isScalar()) {
+            return other.rdivi(scalar(), result);
+        }
+
+        assertSameLength(other);
+        ensureResultLength(other, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, get(i) / other.get(i));
+        }
+        return result;
+    }
+
+    /** Elementwise division with a scalar (in-place). */
+    public DoubleMatrix divi(double a, DoubleMatrix result) {
+        ensureResultLength(null, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, get(i) / a);
+        }
+        return result;
+    }
+
+    /**
+     * Elementwise division, with operands switched. Computes
+     * <code>result = other / this</code> (in-place). */
+    public DoubleMatrix rdivi(DoubleMatrix other, DoubleMatrix result) {
+        return other.divi(this, result);
+    }
+
+    /** (Elementwise) division with a scalar, with operands switched. Computes
+     * <code>result = a / this</code> (in-place). */
+    public DoubleMatrix rdivi(double a, DoubleMatrix result) {
+        ensureResultLength(null, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, a / get(i));
+        }
+        return result;
+    }
+
+    /** Negate each element (in-place). */
+    public DoubleMatrix negi() {
+        for (int i = 0; i < length; i++) {
+            put(i, -get(i));
+        }
+        return this;
+    }
+
+    /** Negate each element. */
+    public DoubleMatrix neg() {
+        return dup().negi();
+    }
+
+    /** Maps zero to 1.0 and all non-zero values to 0.0 (in-place). */
+    public DoubleMatrix noti() {
+        for (int i = 0; i < length; i++) {
+            put(i, get(i) == 0.0 ? 1.0 : 0.0);
+        }
+        return this;
+    }
+
+    /** Maps zero to 1.0 and all non-zero values to 0.0. */
+    public DoubleMatrix not() {
+        return dup().noti();
+    }
+
+    /** Maps zero to 0.0 and all non-zero values to 1.0 (in-place). */
+    public DoubleMatrix truthi() {
+        for (int i = 0; i < length; i++) {
+            put(i, get(i) == 0.0 ? 0.0 : 1.0);
+        }
+        return this;
+    }
+
+    /** Maps zero to 0.0 and all non-zero values to 1.0. */
+    public DoubleMatrix truth() {
+        return dup().truthi();
+    }
+
+    /****************************************************************
+     * Rank one-updates
+     */
+    /** Computes a rank-1-update A = A + alpha * x * y'. */
+    public DoubleMatrix rankOneUpdate(double alpha, DoubleMatrix x, DoubleMatrix y) {
+        if (rows != x.length) {
+            throw new SizeException("Vector x has wrong length (" + x.length + " != " + rows + ").");
+        }
+        if (columns != y.length) {
+            throw new SizeException("Vector y has wrong length (" + x.length + " != " + columns + ").");
+        }
+
+        SimpleBlas.ger(alpha, x, y, this);
+        return this;
+    }
+
+    /** Computes a rank-1-update A = A + alpha * x * x'. */
+    public DoubleMatrix rankOneUpdate(double alpha, DoubleMatrix x) {
+        return rankOneUpdate(alpha, x, x);
+    }
+
+    /** Computes a rank-1-update A = A + x * x'. */
+    public DoubleMatrix rankOneUpdate(DoubleMatrix x) {
+        return rankOneUpdate(1.0, x, x);
+    }
+
+    /** Computes a rank-1-update A = A + x * y'. */
+    public DoubleMatrix rankOneUpdate(DoubleMatrix x, DoubleMatrix y) {
+        return rankOneUpdate(1.0, x, y);
+    }
+
+    /****************************************************************
+     * Logical operations
+     */
+    /** Returns the minimal element of the matrix. */
+    public double min() {
+        if (isEmpty()) {
+            return Double.POSITIVE_INFINITY;
+        }
+        double v = Double.POSITIVE_INFINITY;
+        for (int i = 0; i < length; i++) {
+            if (!Double.isNaN(get(i)) && get(i) < v) {
+                v = get(i);
+            }
+        }
+
+        return v;
+    }
+
+    /**
+     * Returns the linear index of the minimal element. If there are
+     * more than one elements with this value, the first one is returned.
+     */
+    public int argmin() {
+        if (isEmpty()) {
+            return -1;
+        }
+        double v = Double.POSITIVE_INFINITY;
+        int a = -1;
+        for (int i = 0; i < length; i++) {
+            if (!Double.isNaN(get(i)) && get(i) < v) {
+                v = get(i);
+                a = i;
+            }
+        }
+
+        return a;
+    }
+
+    /**
+     * Computes the minimum between two matrices. Returns the smaller of the
+     * corresponding elements in the matrix (in-place).
+     */
+    public DoubleMatrix mini(DoubleMatrix other, DoubleMatrix result) {
+        if (result == this) {
+            for (int i = 0; i < length; i++) {
+                if (get(i) > other.get(i)) {
+                    put(i, other.get(i));
+                }
+            }
+        } else {
+            for (int i = 0; i < length; i++) {
+                if (get(i) > other.get(i)) {
+                    result.put(i, other.get(i));
+                } else {
+                    result.put(i, get(i));
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Computes the minimum between two matrices. Returns the smaller of the
+     * corresponding elements in the matrix (in-place on this).
+     */
+    public DoubleMatrix mini(DoubleMatrix other) {
+        return mini(other, this);
+    }
+
+    /**
+     * Computes the minimum between two matrices. Returns the smaller of the
+     * corresponding elements in the matrix (in-place on this).
+     */
+    public DoubleMatrix min(DoubleMatrix other) {
+        return mini(other, new DoubleMatrix(rows, columns));
+    }
+
+    public DoubleMatrix mini(double v, DoubleMatrix result) {
+        if (result == this) {
+            for (int i = 0; i < length; i++) {
+                if (get(i) > v) {
+                    result.put(i, v);
+                }
+            }
+        } else {
+            for (int i = 0; i < length; i++) {
+                if (get(i) > v) {
+                    result.put(i, v);
+                } else {
+                    result.put(i, get(i));
+                }
+            }
+
+        }
+        return this;
+    }
+
+    public DoubleMatrix mini(double v) {
+        return mini(v, this);
+    }
+
+    public DoubleMatrix min(double v) {
+        return mini(v, new DoubleMatrix(rows, columns));
+    }
+
+    /** Returns the maximal element of the matrix. */
+    public double max() {
+        if (isEmpty()) {
+            return Double.NEGATIVE_INFINITY;
+        }
+        double v = Double.NEGATIVE_INFINITY;
+        for (int i = 0; i < length; i++) {
+            if (!Double.isNaN(get(i)) && get(i) > v) {
+                v = get(i);
+            }
+        }
+        return v;
+    }
+
+    /**
+     * Returns the linear index of the maximal element of the matrix. If
+     * there are more than one elements with this value, the first one
+     * is returned.
+     */
+    public int argmax() {
+        if (isEmpty()) {
+            return -1;
+        }
+        double v = Double.NEGATIVE_INFINITY;
+        int a = -1;
+        for (int i = 0; i < length; i++) {
+            if (!Double.isNaN(get(i)) && get(i) > v) {
+                v = get(i);
+                a = i;
+            }
+        }
+
+        return a;
+    }
+
+    /**
+     * Computes the maximum between two matrices. Returns the larger of the
+     * corresponding elements in the matrix (in-place).
+     */
+    public DoubleMatrix maxi(DoubleMatrix other, DoubleMatrix result) {
+        if (result == this) {
+            for (int i = 0; i < length; i++) {
+                if (get(i) < other.get(i)) {
+                    put(i, other.get(i));
+                }
+            }
+        } else {
+            for (int i = 0; i < length; i++) {
+                if (get(i) < other.get(i)) {
+                    result.put(i, other.get(i));
+                } else {
+                    result.put(i, get(i));
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Computes the maximum between two matrices. Returns the smaller of the
+     * corresponding elements in the matrix (in-place on this).
+     */
+    public DoubleMatrix maxi(DoubleMatrix other) {
+        return maxi(other, this);
+    }
+
+    /**
+     * Computes the maximum between two matrices. Returns the larger of the
+     * corresponding elements in the matrix (in-place on this).
+     */
+    public DoubleMatrix max(DoubleMatrix other) {
+        return maxi(other, new DoubleMatrix(rows, columns));
+    }
+
+    public DoubleMatrix maxi(double v, DoubleMatrix result) {
+        if (result == this) {
+            for (int i = 0; i < length; i++) {
+                if (get(i) < v) {
+                    result.put(i, v);
+                }
+            }
+        } else {
+            for (int i = 0; i < length; i++) {
+                if (get(i) < v) {
+                    result.put(i, v);
+                } else {
+                    result.put(i, get(i));
+                }
+            }
+
+        }
+        return this;
+    }
+
+    public DoubleMatrix maxi(double v) {
+        return maxi(v, this);
+    }
+
+    public DoubleMatrix max(double v) {
+        return maxi(v, new DoubleMatrix(rows, columns));
+    }
+
+    /** Computes the sum of all elements of the matrix. */
+    public double sum() {
+        double s = 0.0;
+        for (int i = 0; i < length; i++) {
+            s += get(i);
+        }
+        return s;
+    }
+
+    /**
+     * Computes the mean value of all elements in the matrix,
+     * that is, <code>x.sum() / x.length</code>.
+     */
+    public double mean() {
+        return sum() / length;
+    }
+
+    /**
+     * Computes the cumulative sum, that is, the sum of all elements
+     * of the matrix up to a given index in linear addressing (in-place).
+     */
+    public DoubleMatrix cumulativeSumi() {
+        double s = 0.0;
+        for (int i = 0; i < length; i++) {
+            s += get(i);
+            put(i, s);
+        }
+        return this;
+    }
+
+    /**
+     * Computes the cumulative sum, that is, the sum of all elements
+     * of the matrix up to a given index in linear addressing.
+     */
+    public DoubleMatrix cumulativeSum() {
+        return dup().cumulativeSumi();
+    }
+
+    /** The scalar product of this with other. */
+    public double dot(DoubleMatrix other) {
+        return SimpleBlas.dot(this, other);
+    }
+
+    /**
+     * The Euclidean norm of the matrix as vector, also the Frobenius
+     * norm of the matrix.
+     */
+    public double norm2() {
+        return SimpleBlas.nrm2(this);
+    }
+
+    /**
+     * The maximum norm of the matrix (maximal absolute value of the elements).
+     */
+    public double normmax() {
+        int i = SimpleBlas.iamax(this);
+        return Math.abs(get(i));
+    }
+
+    /**
+     * The 1-norm of the matrix as vector (sum of absolute values of elements).
+     */
+    public double norm1() {
+        return SimpleBlas.asum(this);
+    }
+
+    /**
+     * Return a new matrix with all elements sorted.
+     */
+    public DoubleMatrix sort() {
+        double array[] = toArray();
+        java.util.Arrays.sort(array);
+        return new DoubleMatrix(rows, columns, array);
+    }
+
+    /**
+     * Sort elements in-place.
+     */
+    public DoubleMatrix sorti() {
+        Arrays.sort(data);
+        return this;
+    }
+
+    /**
+     * Get the sorting permutation.
+     *
+     * @return an int[] array such that which indexes the elements in sorted
+     * order.
+     */
+    public int[] sortingPermutation() {
+        Integer[] indices = new Integer[length];
+
+        for (int i = 0; i < length; i++) {
+            indices[i] = i;
+        }
+
+        final double[] array = data;
+
+        Arrays.sort(indices, new Comparator() {
+
+            public int compare(Object o1, Object o2) {
+                int i = (Integer) o1;
+                int j = (Integer) o2;
+                if (array[i] < array[j]) {
+                    return -1;
+                } else if (array[i] == array[j]) {
+                    return 0;
+                } else {
+                    return 1;
+                }
+            }
+        });
+
+        int[] result = new int[length];
+
+        for (int i = 0; i < length; i++) {
+            result[i] = indices[i];
+        }
+
+        return result;
+    }
+
+    /**
+     * Sort columns (in-place).
+     */
+    public DoubleMatrix sortColumnsi() {
+        for (int i = 0; i < length; i += rows) {
+            Arrays.sort(data, i, i + rows);
+        }
+        return this;
+    }
+
+    /** Sort columns. */
+    public DoubleMatrix sortColumns() {
+        return dup().sortColumnsi();
+    }
+
+    /** Return matrix of indices which sort all columns. */
+    public int[][] columnSortingPermutations() {
+        int[][] result = new int[columns][];
+
+        DoubleMatrix temp = new DoubleMatrix(rows);
+        for (int c = 0; c < columns; c++) {
+            result[c] = getColumn(c, temp).sortingPermutation();
+        }
+
+        return result;
+    }
+
+    /** Sort rows (in-place). */
+    public DoubleMatrix sortRowsi() {
+        // actually, this is much harder because the data is not consecutive
+        // in memory...
+        DoubleMatrix temp = new DoubleMatrix(columns);
+        for (int r = 0; r < rows; r++) {
+            putRow(r, getRow(r, temp).sorti());
+        }
+        return this;
+    }
+
+    /** Sort rows. */
+    public DoubleMatrix sortRows() {
+        return dup().sortRowsi();
+    }
+
+    /** Return matrix of indices which sort all columns. */
+    public int[][] rowSortingPermutations() {
+        int[][] result = new int[rows][];
+
+        DoubleMatrix temp = new DoubleMatrix(columns);
+        for (int r = 0; r < rows; r++) {
+            result[r] = getRow(r, temp).sortingPermutation();
+        }
+
+        return result;
+    }
+
+    /** Return a vector containing the sums of the columns (having number of columns many entries) */
+    public DoubleMatrix columnSums() {
+        if (rows == 1) {
+            return dup();
+        } else {
+            DoubleMatrix v = new DoubleMatrix(1, columns);
+
+            for (int c = 0; c < columns; c++) {
+                for (int r = 0; r < rows; r++) {
+                    v.put(c, v.get(c) + get(r, c));
+                }
+            }
+
+            return v;
+        }
+    }
+
+    /** Return a vector containing the means of all columns. */
+    public DoubleMatrix columnMeans() {
+        return columnSums().divi(rows);
+    }
+
+    /** Return a vector containing the sum of the rows. */
+    public DoubleMatrix rowSums() {
+        if (columns == 1) {
+            return dup();
+        } else {
+            DoubleMatrix v = new DoubleMatrix(rows);
+
+            for (int c = 0; c < columns; c++) {
+                for (int r = 0; r < rows; r++) {
+                    v.put(r, v.get(r) + get(r, c));
+                }
+            }
+
+            return v;
+        }
+    }
+
+    /** Return a vector containing the means of the rows. */
+    public DoubleMatrix rowMeans() {
+        return rowSums().divi(columns);
+    }
+
+    /** Get a copy of a column. */
+    public DoubleMatrix getColumn(int c) {
+        return getColumn(c, new DoubleMatrix(rows, 1));
+    }
+
+    /** Copy a column to the given vector. */
+    public DoubleMatrix getColumn(int c, DoubleMatrix result) {
+        result.checkLength(rows);
+        JavaBlas.rcopy(rows, data, index(0, c), 1, result.data, 0, 1);
+        return result;
+    }
+
+    /** Copy a column back into the matrix. */
+    public void putColumn(int c, DoubleMatrix v) {
+        JavaBlas.rcopy(rows, v.data, 0, 1, data, index(0, c), 1);
+    }
+
+    /** Get a copy of a row. */
+    public DoubleMatrix getRow(int r) {
+        return getRow(r, new DoubleMatrix(1, columns));
+    }
+
+    /** Copy a row to a given vector. */
+    public DoubleMatrix getRow(int r, DoubleMatrix result) {
+        result.checkLength(columns);
+        JavaBlas.rcopy(columns, data, index(r, 0), rows, result.data, 0, 1);
+        return result;
+    }
+
+    /** Copy a row back into the matrix. */
+    public void putRow(int r, DoubleMatrix v) {
+        JavaBlas.rcopy(columns, v.data, 0, 1, data, index(r, 0), rows);
+    }
+
+    /** Return column-wise minimums. */
+    public DoubleMatrix columnMins() {
+        DoubleMatrix mins = new DoubleMatrix(1, columns);
+        for (int c = 0; c < columns; c++) {
+            mins.put(c, getColumn(c).min());
+        }
+        return mins;
+    }
+
+    /** Return index of minimal element per column. */
+    public int[] columnArgmins() {
+        int[] argmins = new int[columns];
+        for (int c = 0; c < columns; c++) {
+            argmins[c] = getColumn(c).argmin();
+        }
+        return argmins;
+    }
+
+    /** Return column-wise maximums. */
+    public DoubleMatrix columnMaxs() {
+        DoubleMatrix maxs = new DoubleMatrix(1, columns);
+        for (int c = 0; c < columns; c++) {
+            maxs.put(c, getColumn(c).max());
+        }
+        return maxs;
+    }
+
+    /** Return index of minimal element per column. */
+    public int[] columnArgmaxs() {
+        int[] argmaxs = new int[columns];
+        for (int c = 0; c < columns; c++) {
+            argmaxs[c] = getColumn(c).argmax();
+        }
+        return argmaxs;
+    }
+
+    /** Return row-wise minimums. */
+    public DoubleMatrix rowMins() {
+        DoubleMatrix mins = new DoubleMatrix(rows);
+        for (int c = 0; c < rows; c++) {
+            mins.put(c, getRow(c).min());
+        }
+        return mins;
+    }
+
+    /** Return index of minimal element per row. */
+    public int[] rowArgmins() {
+        int[] argmins = new int[rows];
+        for (int c = 0; c < rows; c++) {
+            argmins[c] = getRow(c).argmin();
+        }
+        return argmins;
+    }
+
+    /** Return row-wise maximums. */
+    public DoubleMatrix rowMaxs() {
+        DoubleMatrix maxs = new DoubleMatrix(rows);
+        for (int c = 0; c < rows; c++) {
+            maxs.put(c, getRow(c).max());
+        }
+        return maxs;
+    }
+
+    /** Return index of minimal element per row. */
+    public int[] rowArgmaxs() {
+        int[] argmaxs = new int[rows];
+        for (int c = 0; c < rows; c++) {
+            argmaxs[c] = getRow(c).argmax();
+        }
+        return argmaxs;
+    }
+
+    /**************************************************************************
+     * Elementwise Functions
+     */
+    /** Add a row vector to all rows of the matrix (in place). */
+    public DoubleMatrix addiRowVector(DoubleMatrix x) {
+        x.checkLength(columns);
+        for (int r = 0; r < rows; r++) {
+            JavaBlas.raxpy(columns, 1.0, x.data, 0, 1, data, index(r, 0), rows);
+        }
+        return this;
+    }
+
+    /** Add a row to all rows of the matrix. */
+    public DoubleMatrix addRowVector(DoubleMatrix x) {
+        return dup().addiRowVector(x);
+    }
+
+    /** 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++) {
+            JavaBlas.raxpy(rows, 1.0, x.data, 0, 1, data, index(0, c), 1);
+        }
+        return this;
+    }
+
+    /** Add a vector to all columns of the matrix. */
+    public DoubleMatrix addColumnVector(DoubleMatrix x) {
+        return dup().addiColumnVector(x);
+    }
+
+    /** Subtract a row vector from all rows of the matrix (in-place). */
+    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 r = 0; r < rows; r++) {
+            JavaBlas.raxpy(columns, -1.0, x.data, 0, 1, data, index(r, 0), rows);
+        }
+        return this;
+    }
+
+    /** Subtract a row vector from all rows of the matrix. */
+    public DoubleMatrix subRowVector(DoubleMatrix x) {
+        return dup().subiRowVector(x);
+    }
+
+    /** 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++) {
+            JavaBlas.raxpy(rows, -1.0, x.data, 0, 1, data, index(0, c), 1);
+        }
+        return this;
+    }
+
+    /** Subtract a vector from all columns of the matrix. */
+    public DoubleMatrix subColumnVector(DoubleMatrix x) {
+        return dup().subiColumnVector(x);
+    }
+
+    /** Multiply a row by a scalar. */
+    public DoubleMatrix mulRow(int r, double scale) {
+        Blas.dscal(columns, scale, data, index(r, 0), rows);
+        return this;
+    }
+
+    /** Multiply a column by a scalar. */
+    public DoubleMatrix mulColumn(int c, double scale) {
+        Blas.dscal(rows, scale, data, index(0, c), 1);
+        return this;
+    }
+
+    /** Multiply all columns with a column vector (in-place). */
+    public DoubleMatrix muliColumnVector(DoubleMatrix x) {
+        x.checkLength(rows);
+        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;
+    }
+
+    /** Multiply all columns with a column vector. */
+    public DoubleMatrix mulColumnVector(DoubleMatrix x) {
+        return dup().muliColumnVector(x);
+    }
+
+    /** 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++)
+                put(r, c, get(r, c) * x.get(c));
+        return this;
+    }
+
+    /** Multiply all rows with a row vector. */
+    public DoubleMatrix mulRowVector(DoubleMatrix x) {
+        return dup().muliRowVector(x);
+    }
+
+    /**
+     * Writes out this matrix to the given data stream.
+     * @param dos the data output stream to write to.
+     * @throws IOException
+     */
+    public void out(DataOutputStream dos) throws IOException {
+        dos.writeUTF("double");
+        dos.writeInt(columns);
+        dos.writeInt(rows);
+
+        dos.writeInt(data.length);
+        for (int i = 0; i < data.length; i++) {
+            dos.writeDouble(data[i]);
+        }
+    }
+
+    /**
+     * Reads in a matrix from the given data stream. Note
+     * that the old data of this matrix will be discarded.
+     * @param dis the data input stream to read from.
+     * @throws IOException
+     */
+    public void in(DataInputStream dis) throws IOException {
+        if (!dis.readUTF().equals("double")) {
+            throw new IllegalStateException("The matrix in the specified file is not of the correct type!");
+        }
+
+        this.columns = dis.readInt();
+        this.rows = dis.readInt();
+
+        final int MAX = dis.readInt();
+        data = new double[MAX];
+        for (int i = 0; i < MAX; i++) {
+            data[i] = dis.readDouble();
+        }
+    }
+
+    /**
+     * Saves this matrix to the specified file.
+     * @param filename the file to write the matrix in.
+     * @throws IOException thrown on errors while writing the matrix to the file
+     */
+    public void save(String filename) throws IOException {
+        DataOutputStream dos = new DataOutputStream(new FileOutputStream(filename, false));
+        this.out(dos);
+    }
+
+    /**
+     * Loads a matrix from a file into this matrix. Note that the old data
+     * of this matrix will be discarded.
+     * @param filename the file to read the matrix from
+     * @throws IOException thrown on errors while reading the matrix
+     */
+    public void load(String filename) throws IOException {
+        DataInputStream dis = new DataInputStream(new FileInputStream(filename));
+        this.in(dis);
+    }
+
+    public static DoubleMatrix loadAsciiFile(String filename) throws IOException {
+        BufferedReader is = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
+
+        // Go through file and count columns and rows. What makes this endeavour a bit difficult is
+        // that files can have leading or trailing spaces leading to spurious fields
+        // after String.split().
+        String line;
+        int rows = 0;
+        int columns = -1;
+        while ((line = is.readLine()) != null) {
+            String[] elements = line.split("\\s+");
+            int numElements = elements.length;
+            if (elements[0].length() == 0) {
+                numElements--;
+            }
+            if (elements[elements.length - 1].length() == 0) {
+                numElements--;
+            }
+
+            if (columns == -1) {
+                columns = numElements;
+            } else {
+                if (columns != numElements) {
+                    throw new IOException("Number of elements changes in line " + line + ".");
+                }
+            }
+
+            rows++;
+        }
+        is.close();
+
+        // Go through file a second time process the actual data.
+        is = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
+        DoubleMatrix result = new DoubleMatrix(rows, columns);
+        int r = 0;
+        while ((line = is.readLine()) != null) {
+            String[] elements = line.split("\\s+");
+            int firstElement = (elements[0].length() == 0) ? 1 : 0;
+            for (int c = 0, cc = firstElement; c < columns; c++, cc++) {
+                result.put(r, c, Double.valueOf(elements[cc]));
+            }
+            r++;
+        }
+        return result;
+    }
+
+    /****************************************************************
+     * Autogenerated code
+     */
+    /***** Code for operators ***************************************/
+
+    /* Overloads for the usual arithmetic operations */
+    /*#
+    def gen_overloads(base, result_rows, result_cols, verb=''); <<-EOS
+    #{doc verb.capitalize + " a matrix (in place)."}
+    public DoubleMatrix #{base}i(DoubleMatrix other) {
+    return #{base}i(other, this);
+    }
+
+    #{doc verb.capitalize + " a matrix (in place)."}
+    public DoubleMatrix #{base}(DoubleMatrix other) {
+    return #{base}i(other, new DoubleMatrix(#{result_rows}, #{result_cols}));
+    }
+
+    #{doc verb.capitalize + " a scalar (in place)."}
+    public DoubleMatrix #{base}i(double v) {
+    return #{base}i(v, this);
+    }
+
+    #{doc verb.capitalize + " a scalar."}
+    public DoubleMatrix #{base}(double v) {
+    return #{base}i(v, new DoubleMatrix(rows, columns));
+    }
+    EOS
+    end
+    #*/
+
+    /* Generating code for logical operators. This not only generates the stubs
+     * but really all of the code.
+     */
+    /*#
+    def gen_compare(name, op, cmp); <<-EOS
+    #{doc 'Test for ' + cmp + ' (in-place).'}
+    public DoubleMatrix #{name}i(DoubleMatrix other, DoubleMatrix result) {
+    if (other.isScalar())
+    return #{name}i(other.scalar(), result);
+
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) #{op} other.get(i) ? 1.0 : 0.0);
+    return result;
+    }
+
+    #{doc 'Test for ' + cmp + ' (in-place).'}
+    public DoubleMatrix #{name}i(DoubleMatrix other) {
+    return #{name}i(other, this);
+    }
+
+    #{doc 'Test for ' + cmp + '.'}
+    public DoubleMatrix #{name}(DoubleMatrix other) {
+    return #{name}i(other, new DoubleMatrix(rows, columns));
+    }
+
+    #{doc 'Test for ' + cmp + ' against a scalar (in-place).'}
+    public DoubleMatrix #{name}i(double value, DoubleMatrix result) {
+    ensureResultLength(null, result);
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) #{op} value ? 1.0 : 0.0);
+    return result;
+    }
+
+    #{doc 'Test for ' + cmp + ' against a scalar (in-place).'}
+    public DoubleMatrix #{name}i(double value) {
+    return #{name}i(value, this);
+    }
+
+    #{doc 'test for ' + cmp + ' against a scalar.'}
+    public DoubleMatrix #{name}(double value) {
+    return #{name}i(value, new DoubleMatrix(rows, columns));
+    }
+    EOS
+    end
+    #*/
+    /*#
+    def gen_logical(name, op, cmp); <<-EOS
+    #{doc 'Compute elementwise ' + cmp + ' (in-place).'}
+    public DoubleMatrix #{name}i(DoubleMatrix other, DoubleMatrix result) {
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0) #{op} (other.get(i) != 0.0) ? 1.0 : 0.0);
+    return result;
+    }
+
+    #{doc 'Compute elementwise ' + cmp + ' (in-place).'}
+    public DoubleMatrix #{name}i(DoubleMatrix other) {
+    return #{name}i(other, this);
+    }
+
+    #{doc 'Compute elementwise ' + cmp + '.'}
+    public DoubleMatrix #{name}(DoubleMatrix other) {
+    return #{name}i(other, new DoubleMatrix(rows, columns));
+    }
+
+    #{doc 'Compute elementwise ' + cmp + ' against a scalar (in-place).'}
+    public DoubleMatrix #{name}i(double value, DoubleMatrix result) {
+    ensureResultLength(null, result);
+    boolean val = (value != 0.0);
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0) #{op} val ? 1.0 : 0.0);
+    return result;
+    }
+
+    #{doc 'Compute elementwise ' + cmp + ' against a scalar (in-place).'}
+    public DoubleMatrix #{name}i(double value) {
+    return #{name}i(value, this);
+    }
+
+    #{doc 'Compute elementwise ' + cmp + ' against a scalar.'}
+    public DoubleMatrix #{name}(double value) {
+    return #{name}i(value, new DoubleMatrix(rows, columns));
+    }
+    EOS
+    end
+    #*/
+
+    /*# collect(gen_overloads('add', 'rows', 'columns', 'add'),
+    gen_overloads('sub', 'rows', 'columns', 'subtract'),
+    gen_overloads('rsub', 'rows', 'columns', '(right-)subtract'),
+    gen_overloads('div', 'rows', 'columns', 'elementwise divide by'),
+    gen_overloads('rdiv', 'rows', 'columns', '(right-)elementwise divide by'),
+    gen_overloads('mul', 'rows', 'columns', 'elementwise multiply by'),
+    gen_overloads('mmul', 'rows', 'other.columns', 'matrix-multiply by'),
+    gen_compare('lt', '<', '"less than"'),
+    gen_compare('gt', '>', '"greater than"'),
+    gen_compare('le', '<=', '"less than or equal"'),
+    gen_compare('ge', '>=', '"greater than or equal"'),
+    gen_compare('eq', '==', 'equality'),
+    gen_compare('ne', '!=', 'inequality'),
+    gen_logical('and', '&', 'logical and'),
+    gen_logical('or', '|', 'logical or'),
+    gen_logical('xor', '^', 'logical xor'))
+    #*/
+//RJPP-BEGIN------------------------------------------------------------
+    /** Add a matrix (in place). */
+    public DoubleMatrix addi(DoubleMatrix other) {
+    return addi(other, this);
+    }
+
+    /** Add a matrix (in place). */
+    public DoubleMatrix add(DoubleMatrix other) {
+    return addi(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** Add a scalar (in place). */
+    public DoubleMatrix addi(double v) {
+    return addi(v, this);
+    }
+
+    /** Add a scalar. */
+    public DoubleMatrix add(double v) {
+    return addi(v, new DoubleMatrix(rows, columns));
+    }
+
+    /** Subtract a matrix (in place). */
+    public DoubleMatrix subi(DoubleMatrix other) {
+    return subi(other, this);
+    }
+
+    /** Subtract a matrix (in place). */
+    public DoubleMatrix sub(DoubleMatrix other) {
+    return subi(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** Subtract a scalar (in place). */
+    public DoubleMatrix subi(double v) {
+    return subi(v, this);
+    }
+
+    /** Subtract a scalar. */
+    public DoubleMatrix sub(double v) {
+    return subi(v, new DoubleMatrix(rows, columns));
+    }
+
+    /** (right-)subtract a matrix (in place). */
+    public DoubleMatrix rsubi(DoubleMatrix other) {
+    return rsubi(other, this);
+    }
+
+    /** (right-)subtract a matrix (in place). */
+    public DoubleMatrix rsub(DoubleMatrix other) {
+    return rsubi(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** (right-)subtract a scalar (in place). */
+    public DoubleMatrix rsubi(double v) {
+    return rsubi(v, this);
+    }
+
+    /** (right-)subtract a scalar. */
+    public DoubleMatrix rsub(double v) {
+    return rsubi(v, new DoubleMatrix(rows, columns));
+    }
+
+    /** Elementwise divide by a matrix (in place). */
+    public DoubleMatrix divi(DoubleMatrix other) {
+    return divi(other, this);
+    }
+
+    /** Elementwise divide by a matrix (in place). */
+    public DoubleMatrix div(DoubleMatrix other) {
+    return divi(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** Elementwise divide by a scalar (in place). */
+    public DoubleMatrix divi(double v) {
+    return divi(v, this);
+    }
+
+    /** Elementwise divide by a scalar. */
+    public DoubleMatrix div(double v) {
+    return divi(v, new DoubleMatrix(rows, columns));
+    }
+
+    /** (right-)elementwise divide by a matrix (in place). */
+    public DoubleMatrix rdivi(DoubleMatrix other) {
+    return rdivi(other, this);
+    }
+
+    /** (right-)elementwise divide by a matrix (in place). */
+    public DoubleMatrix rdiv(DoubleMatrix other) {
+    return rdivi(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** (right-)elementwise divide by a scalar (in place). */
+    public DoubleMatrix rdivi(double v) {
+    return rdivi(v, this);
+    }
+
+    /** (right-)elementwise divide by a scalar. */
+    public DoubleMatrix rdiv(double v) {
+    return rdivi(v, new DoubleMatrix(rows, columns));
+    }
+
+    /** Elementwise multiply by a matrix (in place). */
+    public DoubleMatrix muli(DoubleMatrix other) {
+    return muli(other, this);
+    }
+
+    /** Elementwise multiply by a matrix (in place). */
+    public DoubleMatrix mul(DoubleMatrix other) {
+    return muli(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** Elementwise multiply by a scalar (in place). */
+    public DoubleMatrix muli(double v) {
+    return muli(v, this);
+    }
+
+    /** Elementwise multiply by a scalar. */
+    public DoubleMatrix mul(double v) {
+    return muli(v, new DoubleMatrix(rows, columns));
+    }
+
+    /** Matrix-multiply by a matrix (in place). */
+    public DoubleMatrix mmuli(DoubleMatrix other) {
+    return mmuli(other, this);
+    }
+
+    /** Matrix-multiply by a matrix (in place). */
+    public DoubleMatrix mmul(DoubleMatrix other) {
+    return mmuli(other, new DoubleMatrix(rows, other.columns));
+    }
+
+    /** Matrix-multiply by a scalar (in place). */
+    public DoubleMatrix mmuli(double v) {
+    return mmuli(v, this);
+    }
+
+    /** Matrix-multiply by a scalar. */
+    public DoubleMatrix mmul(double v) {
+    return mmuli(v, new DoubleMatrix(rows, columns));
+    }
+
+    /** Test for "less than" (in-place). */
+    public DoubleMatrix lti(DoubleMatrix other, DoubleMatrix result) {
+    if (other.isScalar())
+    return lti(other.scalar(), result);
+
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) < other.get(i) ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Test for "less than" (in-place). */
+    public DoubleMatrix lti(DoubleMatrix other) {
+    return lti(other, this);
+    }
+
+    /** Test for "less than". */
+    public DoubleMatrix lt(DoubleMatrix other) {
+    return lti(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** Test for "less than" against a scalar (in-place). */
+    public DoubleMatrix lti(double value, DoubleMatrix result) {
+    ensureResultLength(null, result);
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) < value ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Test for "less than" against a scalar (in-place). */
+    public DoubleMatrix lti(double value) {
+    return lti(value, this);
+    }
+
+    /** test for "less than" against a scalar. */
+    public DoubleMatrix lt(double value) {
+    return lti(value, new DoubleMatrix(rows, columns));
+    }
+
+    /** Test for "greater than" (in-place). */
+    public DoubleMatrix gti(DoubleMatrix other, DoubleMatrix result) {
+    if (other.isScalar())
+    return gti(other.scalar(), result);
+
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) > other.get(i) ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Test for "greater than" (in-place). */
+    public DoubleMatrix gti(DoubleMatrix other) {
+    return gti(other, this);
+    }
+
+    /** Test for "greater than". */
+    public DoubleMatrix gt(DoubleMatrix other) {
+    return gti(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** Test for "greater than" against a scalar (in-place). */
+    public DoubleMatrix gti(double value, DoubleMatrix result) {
+    ensureResultLength(null, result);
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) > value ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Test for "greater than" against a scalar (in-place). */
+    public DoubleMatrix gti(double value) {
+    return gti(value, this);
+    }
+
+    /** test for "greater than" against a scalar. */
+    public DoubleMatrix gt(double value) {
+    return gti(value, new DoubleMatrix(rows, columns));
+    }
+
+    /** Test for "less than or equal" (in-place). */
+    public DoubleMatrix lei(DoubleMatrix other, DoubleMatrix result) {
+    if (other.isScalar())
+    return lei(other.scalar(), result);
+
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) <= other.get(i) ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Test for "less than or equal" (in-place). */
+    public DoubleMatrix lei(DoubleMatrix other) {
+    return lei(other, this);
+    }
+
+    /** Test for "less than or equal". */
+    public DoubleMatrix le(DoubleMatrix other) {
+    return lei(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** Test for "less than or equal" against a scalar (in-place). */
+    public DoubleMatrix lei(double value, DoubleMatrix result) {
+    ensureResultLength(null, result);
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) <= value ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Test for "less than or equal" against a scalar (in-place). */
+    public DoubleMatrix lei(double value) {
+    return lei(value, this);
+    }
+
+    /** test for "less than or equal" against a scalar. */
+    public DoubleMatrix le(double value) {
+    return lei(value, new DoubleMatrix(rows, columns));
+    }
+
+    /** Test for "greater than or equal" (in-place). */
+    public DoubleMatrix gei(DoubleMatrix other, DoubleMatrix result) {
+    if (other.isScalar())
+    return gei(other.scalar(), result);
+
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) >= other.get(i) ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Test for "greater than or equal" (in-place). */
+    public DoubleMatrix gei(DoubleMatrix other) {
+    return gei(other, this);
+    }
+
+    /** Test for "greater than or equal". */
+    public DoubleMatrix ge(DoubleMatrix other) {
+    return gei(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** Test for "greater than or equal" against a scalar (in-place). */
+    public DoubleMatrix gei(double value, DoubleMatrix result) {
+    ensureResultLength(null, result);
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) >= value ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Test for "greater than or equal" against a scalar (in-place). */
+    public DoubleMatrix gei(double value) {
+    return gei(value, this);
+    }
+
+    /** test for "greater than or equal" against a scalar. */
+    public DoubleMatrix ge(double value) {
+    return gei(value, new DoubleMatrix(rows, columns));
+    }
+
+    /** Test for equality (in-place). */
+    public DoubleMatrix eqi(DoubleMatrix other, DoubleMatrix result) {
+    if (other.isScalar())
+    return eqi(other.scalar(), result);
+
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) == other.get(i) ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Test for equality (in-place). */
+    public DoubleMatrix eqi(DoubleMatrix other) {
+    return eqi(other, this);
+    }
+
+    /** Test for equality. */
+    public DoubleMatrix eq(DoubleMatrix other) {
+    return eqi(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** Test for equality against a scalar (in-place). */
+    public DoubleMatrix eqi(double value, DoubleMatrix result) {
+    ensureResultLength(null, result);
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) == value ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Test for equality against a scalar (in-place). */
+    public DoubleMatrix eqi(double value) {
+    return eqi(value, this);
+    }
+
+    /** test for equality against a scalar. */
+    public DoubleMatrix eq(double value) {
+    return eqi(value, new DoubleMatrix(rows, columns));
+    }
+
+    /** Test for inequality (in-place). */
+    public DoubleMatrix nei(DoubleMatrix other, DoubleMatrix result) {
+    if (other.isScalar())
+    return nei(other.scalar(), result);
+
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) != other.get(i) ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Test for inequality (in-place). */
+    public DoubleMatrix nei(DoubleMatrix other) {
+    return nei(other, this);
+    }
+
+    /** Test for inequality. */
+    public DoubleMatrix ne(DoubleMatrix other) {
+    return nei(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** Test for inequality against a scalar (in-place). */
+    public DoubleMatrix nei(double value, DoubleMatrix result) {
+    ensureResultLength(null, result);
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) != value ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Test for inequality against a scalar (in-place). */
+    public DoubleMatrix nei(double value) {
+    return nei(value, this);
+    }
+
+    /** test for inequality against a scalar. */
+    public DoubleMatrix ne(double value) {
+    return nei(value, new DoubleMatrix(rows, columns));
+    }
+
+    /** Compute elementwise logical and (in-place). */
+    public DoubleMatrix andi(DoubleMatrix other, DoubleMatrix result) {
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0) & (other.get(i) != 0.0) ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Compute elementwise logical and (in-place). */
+    public DoubleMatrix andi(DoubleMatrix other) {
+    return andi(other, this);
+    }
+
+    /** Compute elementwise logical and. */
+    public DoubleMatrix and(DoubleMatrix other) {
+    return andi(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** Compute elementwise logical and against a scalar (in-place). */
+    public DoubleMatrix andi(double value, DoubleMatrix result) {
+    ensureResultLength(null, result);
+    boolean val = (value != 0.0);
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0) & val ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Compute elementwise logical and against a scalar (in-place). */
+    public DoubleMatrix andi(double value) {
+    return andi(value, this);
+    }
+
+    /** Compute elementwise logical and against a scalar. */
+    public DoubleMatrix and(double value) {
+    return andi(value, new DoubleMatrix(rows, columns));
+    }
+
+    /** Compute elementwise logical or (in-place). */
+    public DoubleMatrix ori(DoubleMatrix other, DoubleMatrix result) {
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0) | (other.get(i) != 0.0) ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Compute elementwise logical or (in-place). */
+    public DoubleMatrix ori(DoubleMatrix other) {
+    return ori(other, this);
+    }
+
+    /** Compute elementwise logical or. */
+    public DoubleMatrix or(DoubleMatrix other) {
+    return ori(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** Compute elementwise logical or against a scalar (in-place). */
+    public DoubleMatrix ori(double value, DoubleMatrix result) {
+    ensureResultLength(null, result);
+    boolean val = (value != 0.0);
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0) | val ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Compute elementwise logical or against a scalar (in-place). */
+    public DoubleMatrix ori(double value) {
+    return ori(value, this);
+    }
+
+    /** Compute elementwise logical or against a scalar. */
+    public DoubleMatrix or(double value) {
+    return ori(value, new DoubleMatrix(rows, columns));
+    }
+
+    /** Compute elementwise logical xor (in-place). */
+    public DoubleMatrix xori(DoubleMatrix other, DoubleMatrix result) {
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0) ^ (other.get(i) != 0.0) ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Compute elementwise logical xor (in-place). */
+    public DoubleMatrix xori(DoubleMatrix other) {
+    return xori(other, this);
+    }
+
+    /** Compute elementwise logical xor. */
+    public DoubleMatrix xor(DoubleMatrix other) {
+    return xori(other, new DoubleMatrix(rows, columns));
+    }
+
+    /** Compute elementwise logical xor against a scalar (in-place). */
+    public DoubleMatrix xori(double value, DoubleMatrix result) {
+    ensureResultLength(null, result);
+    boolean val = (value != 0.0);
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0) ^ val ? 1.0 : 0.0);
+    return result;
+    }
+
+    /** Compute elementwise logical xor against a scalar (in-place). */
+    public DoubleMatrix xori(double value) {
+    return xori(value, this);
+    }
+
+    /** Compute elementwise logical xor against a scalar. */
+    public DoubleMatrix xor(double value) {
+    return xori(value, new DoubleMatrix(rows, columns));
+    }
+//RJPP-END--------------------------------------------------------------
+}
diff --git a/src/org/jblas/la/Eigen.java b/src/org/jblas/la/Eigen.java
new file mode 100644
index 0000000..fe3b6df
--- /dev/null
+++ b/src/org/jblas/la/Eigen.java
@@ -0,0 +1,188 @@
+// --- 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.la;
+
+/**
+ * <p>Eigenvalue and Eigenvector related functions.</p>
+ * 
+ * <p>Methods exist for working with symmetric matrices or general eigenvalues.
+ * The symmetric versions are usually much faster on symmetric matrices.</p>
+ */
+public class Eigen {
+        private static final DoubleMatrix dummyDouble = new DoubleMatrix(1);
+    
+        /** Compute the eigenvalues for a symmetric matrix. */
+	public static DoubleMatrix symmetricEigenvalues(DoubleMatrix A) {
+		A.assertSquare();
+		DoubleMatrix eigenvalues = new DoubleMatrix(A.rows);
+        int isuppz[] = new int[2*A.rows];
+		SimpleBlas.syevr('N', 'A', 'U', A.dup(), 0, 0, 0, 0, 0, eigenvalues, dummyDouble, isuppz);
+		return eigenvalues;
+	}
+
+        /** 
+         * Computes the eigenvalues and eigenvectors for a symmetric matrix. 
+         *
+         * @return an array of DoubleMatrix objects containing the eigenvectors 
+         * stored as the columns of the first matrix, and the eigenvalues as
+         * diagonal elements of the second matrix.
+         */
+	public static DoubleMatrix[] symmetricEigenvectors(DoubleMatrix A) {
+		A.assertSquare();
+		DoubleMatrix eigenvalues = new DoubleMatrix(A.rows);
+		DoubleMatrix eigenvectors = A.dup();
+        int isuppz[] = new int[2*A.rows];
+        SimpleBlas.syevr('V', 'A', 'U', A.dup(), 0, 0, 0, 0, 0, eigenvalues, eigenvectors, isuppz);
+		return new DoubleMatrix[] { eigenvectors, DoubleMatrix.diag(eigenvalues) };
+	}
+        
+        /** Computes the eigenvalues of a general matrix. */
+        public static ComplexDoubleMatrix eigenvalues(DoubleMatrix A) {
+            A.assertSquare();
+            DoubleMatrix WR = new DoubleMatrix(A.rows);
+            DoubleMatrix WI = WR.dup();
+            SimpleBlas.geev('N', 'N', A.dup(), WR, WI, dummyDouble, dummyDouble);
+                    
+            return new ComplexDoubleMatrix(WR, WI);
+        }
+        
+        /** 
+         * Computes the eigenvalues and eigenvectors of a general matrix.
+         * 
+         * @return an array of ComplexDoubleMatrix objects containing the eigenvectors
+         * stored as the columns of the first matrix, and the eigenvalues as the
+         * diagonal elements of the second matrix.
+         */
+        public static ComplexDoubleMatrix[] eigenvectors(DoubleMatrix A) {
+            A.assertSquare();
+            // setting up result arrays
+            DoubleMatrix WR = new DoubleMatrix(A.rows);
+            DoubleMatrix WI = WR.dup();
+            DoubleMatrix VR = new DoubleMatrix(A.rows, A.rows);
+
+            SimpleBlas.geev('N', 'V', A.dup(), WR, WI, dummyDouble, VR);
+            
+            // transferring the result
+            ComplexDoubleMatrix E = new ComplexDoubleMatrix(WR, WI);
+            ComplexDoubleMatrix V = new ComplexDoubleMatrix(A.rows, A.rows);
+            System.err.printf("VR = %s\n", VR.toString());
+            for (int i = 0; i < A.rows; i++) {
+                if (E.get(i).isReal()) {
+                    V.putColumn(i, new ComplexDoubleMatrix(VR.getColumn(i)));
+                } else {
+                    ComplexDoubleMatrix v = new ComplexDoubleMatrix(VR.getColumn(i), VR.getColumn(i+1));
+                    V.putColumn(i, v);
+                    V.putColumn(i+1, v.conji());
+                    i += 1;
+                }
+            }
+            return new ComplexDoubleMatrix[] { V, ComplexDoubleMatrix.diag(E) };
+        }
+//BEGIN
+  // The code below has been automatically generated.
+  // DO NOT EDIT!
+        private static final FloatMatrix dummyFloat = new FloatMatrix(1);
+    
+        /** Compute the eigenvalues for a symmetric matrix. */
+	public static FloatMatrix symmetricEigenvalues(FloatMatrix A) {
+		A.assertSquare();
+		FloatMatrix eigenvalues = new FloatMatrix(A.rows);
+        int isuppz[] = new int[2*A.rows];
+		SimpleBlas.syevr('N', 'A', 'U', A.dup(), 0, 0, 0, 0, 0, eigenvalues, dummyFloat, isuppz);
+		return eigenvalues;
+	}
+
+        /** 
+         * Computes the eigenvalues and eigenvectors for a symmetric matrix. 
+         *
+         * @return an array of FloatMatrix objects containing the eigenvectors 
+         * stored as the columns of the first matrix, and the eigenvalues as
+         * diagonal elements of the second matrix.
+         */
+	public static FloatMatrix[] symmetricEigenvectors(FloatMatrix A) {
+		A.assertSquare();
+		FloatMatrix eigenvalues = new FloatMatrix(A.rows);
+		FloatMatrix eigenvectors = A.dup();
+        int isuppz[] = new int[2*A.rows];
+        SimpleBlas.syevr('V', 'A', 'U', A.dup(), 0, 0, 0, 0, 0, eigenvalues, eigenvectors, isuppz);
+		return new FloatMatrix[] { eigenvectors, FloatMatrix.diag(eigenvalues) };
+	}
+        
+        /** Computes the eigenvalues of a general matrix. */
+        public static ComplexFloatMatrix eigenvalues(FloatMatrix A) {
+            A.assertSquare();
+            FloatMatrix WR = new FloatMatrix(A.rows);
+            FloatMatrix WI = WR.dup();
+            SimpleBlas.geev('N', 'N', A.dup(), WR, WI, dummyFloat, dummyFloat);
+                    
+            return new ComplexFloatMatrix(WR, WI);
+        }
+        
+        /** 
+         * Computes the eigenvalues and eigenvectors of a general matrix.
+         * 
+         * @return an array of ComplexFloatMatrix objects containing the eigenvectors
+         * stored as the columns of the first matrix, and the eigenvalues as the
+         * diagonal elements of the second matrix.
+         */
+        public static ComplexFloatMatrix[] eigenvectors(FloatMatrix A) {
+            A.assertSquare();
+            // setting up result arrays
+            FloatMatrix WR = new FloatMatrix(A.rows);
+            FloatMatrix WI = WR.dup();
+            FloatMatrix VR = new FloatMatrix(A.rows, A.rows);
+
+            SimpleBlas.geev('N', 'V', A.dup(), WR, WI, dummyFloat, VR);
+            
+            // transferring the result
+            ComplexFloatMatrix E = new ComplexFloatMatrix(WR, WI);
+            ComplexFloatMatrix V = new ComplexFloatMatrix(A.rows, A.rows);
+            System.err.printf("VR = %s\n", VR.toString());
+            for (int i = 0; i < A.rows; i++) {
+                if (E.get(i).isReal()) {
+                    V.putColumn(i, new ComplexFloatMatrix(VR.getColumn(i)));
+                } else {
+                    ComplexFloatMatrix v = new ComplexFloatMatrix(VR.getColumn(i), VR.getColumn(i+1));
+                    V.putColumn(i, v);
+                    V.putColumn(i+1, v.conji());
+                    i += 1;
+                }
+            }
+            return new ComplexFloatMatrix[] { V, ComplexFloatMatrix.diag(E) };
+        }
+//END
+}
diff --git a/src/org/jblas/la/FloatFunction.java b/src/org/jblas/la/FloatFunction.java
new file mode 100644
index 0000000..150e58c
--- /dev/null
+++ b/src/org/jblas/la/FloatFunction.java
@@ -0,0 +1,45 @@
+// --- 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.la;
+
+/**
+ * Represents a function on floats.
+ */
+public interface FloatFunction {
+        /** Compute the function. */
+	public float compute(float x);
+}
diff --git a/src/org/jblas/la/FloatMatrix.java b/src/org/jblas/la/FloatMatrix.java
new file mode 100644
index 0000000..2bda548
--- /dev/null
+++ b/src/org/jblas/la/FloatMatrix.java
@@ -0,0 +1,2965 @@
+// --- BEGIN LICENSE BLOCK ---
+/* 
+ * Copyright (c) 2009, Mikio L. Braun
+ * Copyright (c) 2008, Johannes Schaback
+ * 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.la;
+
+import org.jblas.la.exceptions.SizeException;
+import org.jblas.la.ranges.Range;
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * A general matrix class for <tt>float</tt> typed values.
+ * 
+ * Don't be intimidated by the large number of methods this function defines. Most
+ * are overloads provided for ease of use. For example, for each arithmetic operation,
+ * up to six overloaded versions exist to handle in-place computations, and
+ * scalar arguments.
+ * 
+ * <h3>Construction</h3>
+ * 
+ * <p>To construct a two-dimensional matrices, you can use the following constructors
+ * and static methods.</p>
+ * 
+ * <table class="my">
+ * <tr><th>Method<th>Description
+ * <tr><td>FloatMatrix(m,n, [value1, value2, value3...])<td>Values are filled in row by row.
+ * <tr><td>FloatMatrix(new float[][] {{value1, value2, ...}, ...}<td>Inner arrays are columns.
+ * <tr><td>FloatMatrix.zeros(m,n) <td>Initial values set to 0.0f.
+ * <tr><td>FloatMatrix.ones(m,n) <td>Initial values set to 1.0f.
+ * <tr><td>FloatMatrix.rand(m,n) <td>Values drawn at random between 0.0f and 1.0f.
+ * <tr><td>FloatMatrix.randn(m,n) <td>Values drawn from normal distribution.
+ * <tr><td>FloatMatrix.eye(n) <td>Unit matrix (values 0.0f except for 1.0f on the diagonal).
+ * <tr><td>FloatMatrix.diag(array) <td>Diagonal matrix with given diagonal elements.
+ * </table>
+ * 
+ * <p>Alternatively, you can construct (column) vectors, if you just supply the length
+ * using the following constructors and static methods.</p>
+ * 
+ * <table class="my">
+ * <tr><th>Method<th>Description
+ * <tr><td>FloatMatrix(m)<td>Constructs a column vector.
+ * <tr><td>FloatMatrix(new float[] {value1, value2, ...})<td>Constructs a column vector.
+ * <tr><td>FloatMatrix.zeros(m) <td>Initial values set to 1.0f.
+ * <tr><td>FloatMatrix.ones(m) <td>Initial values set to 0.0f.
+ * <tr><td>FloatMatrix.rand(m) <td>Values drawn at random between 0.0f and 1.0f.
+ * <tr><td>FloatMatrix.randn(m) <td>Values drawn from normal distribution.
+ * </table>
+ * 
+ * <p>You can also construct new matrices by concatenating matrices either horziontally
+ * or vertically:</p>
+ * 
+ * <table class="my">
+ * <tr><th>Method<th>Description
+ * <tr><td>x.concatHorizontally(y)<td>New matrix will be x next to y.
+ * <tr><td>x.concatVertically(y)<td>New matrix will be x atop y.
+ * </table>
+ * 
+ * <h3>Element Access, Copying and Duplication</h3>
+ * 
+ * <p>To access individual elements, or whole rows and columns, use the following
+ * methods:<p>
+ * 
+ * <table class="my">
+ * <tr><th>x.Method<th>Description
+ * <tr><td>x.get(i,j)<td>Get element in row i and column j.
+ * <tr><td>x.put(i, j, v)<td>Set element in row i and column j to value v
+ * <tr><td>x.get(i)<td>Get the ith element of the matrix (traversing rows first).
+ * <tr><td>x.put(i, v)<td>Set the ith element of the matrix (traversing rows first).
+ * <tr><td>x.getColumn(i)<td>Get a copy of column i.
+ * <tr><td>x.putColumn(i, c)<td>Put matrix c into column i.
+ * <tr><td>x.getRow(i)<td>Get a copy of row i.
+ * <tr><td>x.putRow(i, c)<td>Put matrix c into row i.
+ * <tr><td>x.swapColumns(i, j)<td>Swap the contents of columns i and j.
+ * <tr><td>x.swapRows(i, j)<td>Swap the contents of columns i and j.
+ * </table>
+ * 
+ * <p>For <tt>get</tt> and <tt>put</tt>, you can also pass integer arrays,
+ * FloatMatrix objects, or Range objects, which then specify the indices used 
+ * as follows:
+ * 
+ * <ul>
+ * <li><em>integer array:</em> the elements will be used as indices.
+ * <li><em>FloatMatrix object:</em> non-zero entries specify the indices.
+ * <li><em>Range object:</em> see below.
+ * </ul>
+ * 
+ * <p>When using <tt>put</tt> with multiple indices, the assigned object must
+ * have the correct size or be a scalar.</p>
+ *
+ * <p>There exist the following Range objects. The Class <tt>RangeUtils</tt> also
+ * contains the a number of handy helper methods for constructing these ranges.</p>
+ * <table class="my">
+ * <tr><th>Class <th>RangeUtils method <th>Indices
+ * <tr><td>AllRange <td>all() <td>All legal indices.
+ * <tr><td>PointRange <td>point(i) <td> A single point.
+ * <tr><td>IntervalRange <td>interval(a, b)<td> All indices from a to b (inclusive)
+ * <tr><td rowspan=3>IndicesRange <td>indices(int[])<td> The specified indices.
+ * <tr><td>indices(FloatMatrix)<td>The specified indices.
+ * <tr><td>find(FloatMatrix)<td>The non-zero entries of the matrix.
+ * </table>
+ * 
+ * <p>The following methods can be used for duplicating and copying matrices.</p>
+ * 
+ * <table class="my">
+ * <tr><th>Method<th>Description
+ * <tr><td>x.dup()<td>Get a copy of x.
+ * <tr><td>x.copy(y)<td>Copy the contents of y to x (possible resizing x).
+ * </table>
+ *    
+ * <h3>Size and Shape</h3>
+ * 
+ * <p>The following methods permit to acces the size of a matrix and change its size or shape.</p>
+ * 
+ * <table class="my">
+ * <tr><th>x.Method<th>Description
+ * <tr><td>x.rows<td>Number of rows.
+ * <tr><td>x.columns<td>Number of columns.
+ * <tr><td>x.length<td>Total number of elements.
+ * <tr><td>x.isEmpty()<td>Checks whether rows == 0 and columns == 0.
+ * <tr><td>x.isRowVector()<td>Checks whether rows == 1.
+ * <tr><td>x.isColumnVector()<td>Checks whether columns == 1.
+ * <tr><td>x.isVector()<td>Checks whether rows == 1 or columns == 1.
+ * <tr><td>x.isSquare()<td>Checks whether rows == columns.
+ * <tr><td>x.isScalar()<td>Checks whether length == 1.
+ * <tr><td>x.resize(r, c)<td>Resize the matrix to r rows and c columns, discarding the content.
+ * <tr><td>x.reshape(r, c)<td>Resize the matrix to r rows and c columns.<br> Number of elements must not change.
+ * </table>
+ * 
+ * <p>The size is stored in the <tt>rows</tt> and <tt>columns</tt> member variables.
+ * The total number of elements is stored in <tt>length</tt>. Do not change these
+ * values unless you know what you're doing!</p>
+ * 
+ * <h3>Arithmetics</h3>
+ * 
+ * <p>The usual arithmetic operations are implemented. Each operation exists in a
+ * in-place version, recognizable by the suffix <tt>"i"</tt>, to which you can supply
+ * the result matrix (or <tt>this</tt> is used, if missing). Using in-place operations
+ * can also lead to a smaller memory footprint, as the number of temporary objects
+ * which are directly garbage collected again is reduced.</p>
+ * 
+ * <p>Whenever you specify a result vector, the result vector must already have the
+ * correct dimensions.</p>
+ * 
+ * <p>For example, you can add two matrices using the <tt>add</tt> method. If you want
+ * to store the result in of <tt>x + y</tt> in <tt>z</tt>, type
+ * <span class=code>
+ * x.addi(y, z)   // computes x = y + z.
+ * </span>
+ * Even in-place methods return the result, such that you can easily chain in-place methods,
+ * for example:
+ * <span class=code>
+ * x.addi(y).addi(z) // computes x += y; x += z
+ * </span></p> 
+ *
+ * <p>Methods which operate element-wise only make sure that the length of the matrices
+ * is correct. Therefore, you can add a 3 * 3 matrix to a 1 * 9 matrix, for example.</p>
+ * 
+ * <p>Finally, there exist versions which take floats instead of FloatMatrix Objects
+ * as arguments. These then compute the operation with the same value as the
+ * right-hand-side. The same effect can be achieved by passing a FloatMatrix with
+ * exactly one element.</p>
+ * 
+ * <table class="my">
+ * <tr><th>Operation <th>Method <th>Comment
+ * <tr><td>x + y <td>x.add(y)			<td>
+ * <tr><td>x - y <td>x.sub(y), y.rsub(x) <td>rsub subtracts left from right hand side
+ * <tr><td rowspan=3>x * y 	<td>x.mul(y) <td>element-wise multiplication 
+ * <tr>						<td>x.mmul(y)<td>matrix-matrix multiplication
+ * <tr>						<td>x.dot(y) <td>scalar-product
+ * <tr><td>x / y <td>x.div(y), y.rdiv(x) <td>rdiv divides right hand side by left hand side.
+ * <tr><td>- x	<td>x.neg()				<td>
+ * </table>
+ * 
+ * <p>There also exist operations which work on whole columns or rows.</p>
+ * 
+ * <table class="my">
+ * <tr><th>Method <th>Description
+ * <tr><td>x.addRowVector<td>adds a vector to each row (addiRowVector works in-place)
+ * <tr><td>x.addColumnVector<td>adds a vector to each column
+ * <tr><td>x.subRowVector<td>subtracts a vector from each row
+ * <tr><td>x.subColumnVector<td>subtracts a vector from each column
+ * <tr><td>x.mulRow<td>Multiplies a row by a scalar
+ * <tr><td>x.mulColumn<td>multiplies a row by a column
+ * </table>
+ * 
+ * <p>In principle, you could achieve the same result by first calling getColumn(), 
+ * adding, and then calling putColumn, but these methods are much faster.</p>
+ * 
+ * <p>The following comparison operations are available</p>
+ *  
+ * <table class="my">
+ * <tr><th>Operation <th>Method
+ * <tr><td>x < y		<td>x.lt(y)
+ * <tr><td>x <= y	<td>x.le(y)
+ * <tr><td>x > y		<td>x.gt(y)
+ * <tr><td>x >= y	<td>x.ge(y)
+ * <tr><td>x == y		<td>x.eq(y)
+ * <tr><td>x != y		<td>x.ne(y)
+ * </table>
+ *
+ * <p> Logical operations are also supported. For these operations, a value different from
+ * zero is treated as "true" and zero is treated as "false". All operations are carried
+ * out elementwise.</p>
+ * 
+ * <table class="my">
+ * <tr><th>Operation <th>Method
+ * <tr><td>x & y 	<td>x.and(y)
+ * <tr><td>x | y 	<td>x.or(y)
+ * <tr><td>x ^ y	<td>x.xor(y)
+ * <tr><td>! x		<td>x.not()
+ * </table>
+ * 
+ * <p>Finally, there are a few more methods to compute various things:</p>
+ * 
+ * <table class="my">
+ * <tr><th>Method <th>Description
+ * <tr><td>x.max() <td>Return maximal element
+ * <tr><td>x.argmax() <td>Return index of largest element
+ * <tr><td>x.min() <td>Return minimal element
+ * <tr><td>x.argmin() <td>Return index of largest element
+ * <tr><td>x.columnMins() <td>Return column-wise minima
+ * <tr><td>x.columnArgmins() <td>Return column-wise index of minima
+ * <tr><td>x.columnMaxs() <td>Return column-wise maxima
+ * <tr><td>x.columnArgmaxs() <td>Return column-wise index of maxima
+ * </table>
+ * 
+ * @author Mikio Braun, Johannes Schaback
+ */
+public class FloatMatrix {
+
+    /** Number of rows. */
+    public int rows;
+    /** Number of columns. */
+    public int columns;
+    /** Total number of elements (for convenience). */
+    public int length;
+    /** The actual data stored by rows (that is, row 0, row 1...). */
+    public float[] data = null; // rows are contiguous
+    public static final FloatMatrix EMPTY = new FloatMatrix();
+
+    /**************************************************************************
+     *
+     * Constructors and factory functions
+     *
+     **************************************************************************/
+    /** Create a new matrix with <i>newRows</i> rows, <i>newColumns</i> columns
+     * using <i>newData></i> as the data. The length of the data is not checked!
+     */
+    public FloatMatrix(int newRows, int newColumns, float... newData) {
+        rows = newRows;
+        columns = newColumns;
+        length = rows * columns;
+
+        if (newData != null && newData.length != newRows * newColumns) {
+            throw new IllegalArgumentException(
+                    "Passed data must match matrix dimensions.");
+        }
+
+        data = newData;
+    //System.err.printf("%d * %d matrix created\n", rows, columns);
+    }
+
+    /**
+     * Creates a new <i>n</i> times <i>m</i> <tt>FloatMatrix</tt>.
+     * @param newRows the number of rows (<i>n</i>) of the new matrix.
+     * @param newColumns the number of columns (<i>m</i>) of the new matrix.
+     */
+    public FloatMatrix(int newRows, int newColumns) {
+        this(newRows, newColumns, new float[newRows * newColumns]);
+    }
+
+    /**
+     * Creates a new <tt>FloatMatrix</tt> of size 0 times 0.
+     */
+    public FloatMatrix() {
+        this(0, 0, (float[]) null);
+    }
+
+    /**
+     * Create a Matrix of length <tt>len</tt>. By default, this creates a row vector.
+     * @param len
+     */
+    public FloatMatrix(int len) {
+        this(len, 1, new float[len]);
+    }
+
+    public FloatMatrix(float[] newData) {
+        this(newData.length);
+        data = newData;
+    }
+
+    /**
+     * Creates a new matrix by reading it from a file.
+     * @param filename the path and name of the file to read the matrix from
+     * @throws IOException
+     */
+    public FloatMatrix(String filename) throws IOException {
+        load(filename);
+    }
+
+    /**
+     * Creates a new <i>n</i> times <i>m</i> <tt>FloatMatrix</tt> from
+     * the given <i>n</i> times <i>m</i> 2D data array. The first dimension of the array makes the
+     * rows (<i>n</i>) and the second dimension the columns (<i>m</i>). For example, the
+     * given code <br/><br/>
+     * <code>new FloatMatrix(new float[][]{{1d, 2d, 3d}, {4d, 5d, 6d}, {7d, 8d, 9d}}).print();</code><br/><br/>
+     * will constructs the following matrix:
+     * <pre>
+     * 1.0f	2.0f	3.0f
+     * 4.0f	5.0f	6.0f
+     * 7.0f	8.0f	9.0f
+     * </pre>.
+     * @param data <i>n</i> times <i>m</i> data array
+     */
+    public FloatMatrix(float[][] data) {
+        this(data.length, data[0].length);
+
+        for (int r = 0; r < rows; r++) {
+            assert (data[r].length == columns);
+        }
+
+        for (int r = 0; r < rows; r++) {
+            for (int c = 0; c < columns; c++) {
+                put(r, c, data[r][c]);
+            }
+        }
+    }
+
+    /** Create matrix with random values uniformly in 0..1. */
+    public static FloatMatrix rand(int rows, int columns) {
+        FloatMatrix m = new FloatMatrix(rows, columns);
+
+        java.util.Random r = new java.util.Random();
+        for (int i = 0; i < rows * columns; i++) {
+            m.data[i] = r.nextFloat();
+        }
+
+        return m;
+    }
+
+    /** Creates a row vector with random values uniformly in 0..1. */
+    public static FloatMatrix rand(int len) {
+        return rand(len, 1);
+    }
+
+    /** Create matrix with normally distributed random values. */
+    public static FloatMatrix randn(int rows, int columns) {
+        FloatMatrix m = new FloatMatrix(rows, columns);
+
+        java.util.Random r = new java.util.Random();
+        for (int i = 0; i < rows * columns; i++) {
+            m.data[i] = (float) r.nextGaussian();
+        }
+
+        return m;
+    }
+
+    /** Create row vector with normally distributed random values. */
+    public static FloatMatrix randn(int len) {
+        return randn(len, 1);
+    }
+
+    /** Creates a new matrix in which all values are equal 0. */
+    public static FloatMatrix zeros(int rows, int columns) {
+        return new FloatMatrix(rows, columns);
+    }
+
+    /** Creates a row vector of given length. */
+    public static FloatMatrix zeros(int length) {
+        return zeros(length, 1);
+    }
+
+    /** Creates a new matrix in which all values are equal 1. */
+    public static FloatMatrix ones(int rows, int columns) {
+        FloatMatrix m = new FloatMatrix(rows, columns);
+
+        for (int i = 0; i < rows * columns; i++) {
+            m.put(i, 1.0f);
+        }
+
+        return m;
+    }
+
+    /** Creates a row vector with all elements equal to 1. */
+    public static FloatMatrix ones(int length) {
+        return ones(length, 1);
+    }
+
+    /** Construct a new n-by-n identity matrix. */
+    public static FloatMatrix eye(int n) {
+        FloatMatrix m = new FloatMatrix(n, n);
+
+        for (int i = 0; i < n; i++) {
+            m.put(i, i, 1.0f);
+        }
+
+        return m;
+    }
+
+    /**
+     * Creates a new matrix where the values of the given vector are the diagonal values of
+     * the matrix.
+     */
+    public static FloatMatrix diag(FloatMatrix x) {
+        FloatMatrix m = new FloatMatrix(x.length, x.length);
+
+        for (int i = 0; i < x.length; i++) {
+            m.put(i, i, x.get(i));
+        }
+
+        return m;
+    }
+
+    /**
+     * Create a 1-by-1 matrix. For many operations, this matrix functions like a
+     * normal float.
+     */
+    public static FloatMatrix scalar(float s) {
+        FloatMatrix m = new FloatMatrix(1, 1);
+        m.put(0, 0, s);
+        return m;
+    }
+
+    /** Test whether a matrix is scalar. */
+    public boolean isScalar() {
+        return length == 1;
+    }
+
+    /** Return the first element of the matrix. */
+    public float scalar() {
+        return get(0);
+    }
+
+    /**
+     * Concatenates two matrices horizontally. Matrices must have identical
+     * numbers of rows.
+     */
+    public static FloatMatrix concatHorizontally(FloatMatrix A, FloatMatrix B) {
+        if (A.rows != B.rows) {
+            throw new SizeException("Matrices don't have same number of rows.");
+        }
+
+        FloatMatrix result = new FloatMatrix(A.rows, A.columns + B.columns);
+        SimpleBlas.copy(A, result);
+        JavaBlas.rcopy(B.length, B.data, 0, 1, result.data, A.length, 1);
+        return result;
+    }
+
+    /**
+     * Concatenates two matrices vertically. Matrices must have identical
+     * numbers of columns.
+     */
+    public static FloatMatrix concatVertically(FloatMatrix A, FloatMatrix B) {
+        if (A.columns != B.columns) {
+            throw new SizeException("Matrices don't have same number of columns (" + A.columns + " != " + B.columns + ".");
+        }
+
+        FloatMatrix result = new FloatMatrix(A.rows + B.rows, A.columns);
+
+        for (int i = 0; i < A.columns; i++) {
+            JavaBlas.rcopy(A.rows, A.data, A.index(0, i), 1, result.data, result.index(0, i), 1);
+            JavaBlas.rcopy(B.rows, B.data, B.index(0, i), 1, result.data, result.index(A.rows, i), 1);
+        }
+
+        return result;
+    }
+
+    /**************************************************************************
+     * Working with slices (Man! 30+ methods just to make this a bit flexible...)
+     */
+    /** Get all elements specified by the linear indices. */
+    public FloatMatrix get(int[] indices) {
+        FloatMatrix result = new FloatMatrix(indices.length);
+
+        for (int i = 0; i < indices.length; i++) {
+            result.put(i, get(indices[i]));
+        }
+
+        return result;
+    }
+
+    /** Get all elements for a given row and the specified columns. */
+    public FloatMatrix get(int r, int[] indices) {
+        FloatMatrix result = new FloatMatrix(1, indices.length);
+
+        for (int i = 0; i < indices.length; i++) {
+            result.put(i, get(r, indices[i]));
+        }
+
+        return result;
+    }
+
+    /** Get all elements for a given column and the specified rows. */
+    public FloatMatrix get(int[] indices, int c) {
+        FloatMatrix result = new FloatMatrix(indices.length, c);
+
+        for (int i = 0; i < indices.length; i++) {
+            result.put(i, get(indices[i], c));
+        }
+
+        return result;
+    }
+
+    /** Get all elements from the specified rows and columns. */
+    public FloatMatrix get(int[] rindices, int[] cindices) {
+        FloatMatrix result = new FloatMatrix(rindices.length, cindices.length);
+
+        for (int i = 0; i < rindices.length; i++) {
+            for (int j = 0; j < cindices.length; j++) {
+                result.put(i, j, get(rindices[i], cindices[j]));
+            }
+        }
+
+        return result;
+    }
+
+    /** Get elements from specified rows and columns. */
+    public FloatMatrix get(Range rs, Range cs) {
+        rs.init(0, rows - 1);
+        cs.init(0, columns - 1);
+        FloatMatrix result = new FloatMatrix(rs.length(), cs.length());
+
+        for (; !rs.hasMore(); rs.next()) {
+            for (; !cs.hasMore(); cs.next()) {
+                result.put(rs.index(), cs.index(), get(rs.value(), cs.value()));
+            }
+        }
+
+        return result;
+    }
+
+    /** Get elements specified by the non-zero entries of the passed matrix. */
+    public FloatMatrix get(FloatMatrix indices) {
+        return get(indices.findIndices());
+    }
+
+    /**
+     * Get elements from a row and columns as specified by the non-zero entries of
+     * a matrix.
+     */
+    public FloatMatrix get(int r, FloatMatrix indices) {
+        return get(r, indices.findIndices());
+    }
+
+    /**
+     * Get elements from a column and rows as specified by the non-zero entries of
+     * a matrix.
+     */
+    public FloatMatrix get(FloatMatrix indices, int c) {
+        return get(indices.findIndices(), c);
+    }
+
+    /**
+     * Get elements from columns and rows as specified by the non-zero entries of
+     * the passed matrices.
+     */
+    public FloatMatrix get(FloatMatrix rindices, FloatMatrix cindices) {
+        return get(rindices.findIndices(), cindices.findIndices());
+    }
+
+    /** Return all elements with linear index a, a + 1, ..., b - 1.*/
+    public FloatMatrix getRange(int a, int b) {
+        FloatMatrix result = new FloatMatrix(b - a);
+
+        for (int k = 0; k < b - a; k++) {
+            result.put(k, get(a + k));
+        }
+
+        return result;
+    }
+
+    /** Get elements from a row and columns <tt>a</tt> to <tt>b</tt>. */
+    public FloatMatrix getColumnRange(int r, int a, int b) {
+        FloatMatrix result = new FloatMatrix(1, b - a);
+
+        for (int k = 0; k < b - a; k++) {
+            result.put(k, get(r, a + k));
+        }
+
+        return result;
+    }
+
+    /** Get elements from a column and rows <tt>a/tt> to <tt>b</tt>. */
+    public FloatMatrix getRowRange(int a, int b, int c) {
+        FloatMatrix result = new FloatMatrix(b - a);
+
+        for (int k = 0; k < b - a; k++) {
+            result.put(k, get(a + k, c));
+        }
+
+        return result;
+    }
+
+    /**
+     * Get elements from rows <tt>ra</tt> to <tt>rb</tt> and
+     * columns <tt>ca</tt> to <tt>cb</tt>.
+     */
+    public FloatMatrix getRange(int ra, int rb, int ca, int cb) {
+        FloatMatrix result = new FloatMatrix(rb - ra, cb - ca);
+
+        for (int i = 0; i < rb - ra; i++) {
+            for (int j = 0; j < cb - ca; j++) {
+                result.put(i, j, get(ra + i, ca + j));
+            }
+        }
+
+        return result;
+    }
+
+    /** Get whole rows from the passed indices. */
+    public FloatMatrix getRows(int[] rindices) {
+        FloatMatrix result = new FloatMatrix(rindices.length, columns);
+        for (int i = 0; i < rindices.length; i++) {
+            JavaBlas.rcopy(columns, data, index(rindices[i], 0), rows, result.data, result.index(i, 0), result.rows);
+        }
+        return result;
+    }
+
+    /** Get whole rows as specified by the non-zero entries of a matrix. */
+    public FloatMatrix getRows(FloatMatrix rindices) {
+        return getRows(rindices.findIndices());
+    }
+
+    /** Get whole columns from the passed indices. */
+    public FloatMatrix getColumns(int[] cindices) {
+        FloatMatrix result = new FloatMatrix(rows, cindices.length);
+        for (int i = 0; i < cindices.length; i++) {
+            JavaBlas.rcopy(rows, data, index(0, cindices[i]), 1, result.data, result.index(0, i), 1);
+        }
+        return result;
+    }
+
+    /** Get whole columns as specified by the non-zero entries of a matrix. */
+    public FloatMatrix getColumns(FloatMatrix cindices) {
+        return getColumns(cindices.findIndices());
+    }
+
+    /**
+     * Assert that the matrix has a certain length.
+     * @throws SizeException
+     */
+    public void checkLength(int l) {
+        if (length != l) {
+            throw new SizeException("Matrix does not have the necessary length (" + length + " != " + l + ").");
+        }
+    }
+
+    /**
+     * Asserts that the matrix has a certain number of rows.
+     * @throws SizeException
+     */
+    public void checkRows(int r) {
+        if (rows != r) {
+            throw new SizeException("Matrix does not have the necessary number of rows (" + rows + " != " + r + ").");
+        }
+    }
+
+    /**
+     * Asserts that the amtrix has a certain number of columns.
+     * @throws SizeException
+     */
+    public void checkColumns(int c) {
+        if (columns != c) {
+            throw new SizeException("Matrix does not have the necessary number of columns (" + columns + " != " + c + ").");
+        }
+    }
+
+    /** Set elements in linear ordering in the specified indices. */
+    public FloatMatrix put(int[] indices, FloatMatrix x) {
+        if (x.isScalar()) {
+            return put(indices, x.scalar());
+        }
+        x.checkLength(indices.length);
+
+        for (int i = 0; i < indices.length; i++) {
+            put(indices[i], x.get(i));
+        }
+
+        return this;
+    }
+
+    /** Set multiple elements in a row. */
+    public FloatMatrix put(int r, int[] indices, FloatMatrix x) {
+        if (x.isScalar()) {
+            return put(r, indices, x.scalar());
+        }
+        x.checkColumns(indices.length);
+
+        for (int i = 0; i < indices.length; i++) {
+            put(r, indices[i], x.get(i));
+        }
+
+        return this;
+    }
+
+    /** Set multiple elements in a row. */
+    public FloatMatrix put(int[] indices, int c, FloatMatrix x) {
+        if (x.isScalar()) {
+            return put(indices, c, x.scalar());
+        }
+        x.checkRows(indices.length);
+
+        for (int i = 0; i < indices.length; i++) {
+            put(indices[i], c, x.get(i));
+        }
+
+        return this;
+    }
+
+    /** Put a sub-matrix as specified by the indices. */
+    public FloatMatrix put(int[] rindices, int[] cindices, FloatMatrix x) {
+        if (x.isScalar()) {
+            return put(rindices, cindices, x.scalar());
+        }
+        x.checkRows(rindices.length);
+        x.checkColumns(cindices.length);
+
+        for (int i = 0; i < rindices.length; i++) {
+            for (int j = 0; j < cindices.length; j++) {
+                put(rindices[i], cindices[j], x.get(i, j));
+            }
+        }
+
+        return this;
+    }
+
+    /** 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);
+
+        x.checkRows(rs.length());
+        x.checkColumns(cs.length());
+
+        for (; rs.hasMore(); rs.next()) {
+            for (; cs.hasMore(); cs.next()) {
+                put(rs.value(), cs.value(), x.get(rs.index(), cs.index()));
+            }
+        }
+
+        return this;
+    }
+
+    /** Put a single value into the specified indices (linear adressing). */
+    public FloatMatrix put(int[] indices, float v) {
+        for (int i = 0; i < indices.length; i++) {
+            put(indices[i], v);
+        }
+
+        return this;
+    }
+
+    /** Put a single value into a row and the specified columns. */
+    public FloatMatrix put(int r, int[] indices, float v) {
+        for (int i = 0; i < indices.length; i++) {
+            put(r, indices[i], v);
+        }
+
+        return this;
+    }
+
+    /** Put a single value into the specified rows of a column. */
+    public FloatMatrix put(int[] indices, int c, float v) {
+        for (int i = 0; i < indices.length; i++) {
+            put(indices[i], c, v);
+        }
+
+        return this;
+    }
+
+    /** Put a single value into the specified rows and columns. */
+    public FloatMatrix put(int[] rindices, int[] cindices, float v) {
+        for (int i = 0; i < rindices.length; i++) {
+            for (int j = 0; j < cindices.length; j++) {
+                put(rindices[i], cindices[j], v);
+            }
+        }
+
+        return this;
+    }
+
+    /**
+     * Put a sub-matrix into the indices specified by the non-zero entries
+     * of <tt>indices</tt> (linear adressing).
+     */
+    public FloatMatrix put(FloatMatrix indices, FloatMatrix v) {
+        return put(indices.findIndices(), v);
+    }
+
+    /** Put a sub-vector into the specified columns (non-zero entries of <tt>indices</tt>) of a row. */
+    public FloatMatrix put(int r, FloatMatrix indices, FloatMatrix v) {
+        return put(r, indices.findIndices(), v);
+    }
+
+    /** Put a sub-vector into the specified rows (non-zero entries of <tt>indices</tt>) of a column. */
+    public FloatMatrix put(FloatMatrix indices, int c, FloatMatrix v) {
+        return put(indices.findIndices(), c, v);
+    }
+
+    /**
+     * Put a sub-matrix into the specified rows and columns (non-zero entries of
+     * <tt>rindices</tt> and <tt>cindices</tt>.
+     */
+    public FloatMatrix put(FloatMatrix rindices, FloatMatrix cindices, FloatMatrix v) {
+        return put(rindices.findIndices(), cindices.findIndices(), v);
+    }
+
+    /**
+     * Put a single value into the elements specified by the non-zero
+     * entries of <tt>indices</tt> (linear adressing).
+     */
+    public FloatMatrix put(FloatMatrix indices, float v) {
+        return put(indices.findIndices(), v);
+    }
+
+    /**
+     * Put a single value into the specified columns (non-zero entries of
+     * <tt>indices</tt>) of a row.
+     */
+    public FloatMatrix put(int r, FloatMatrix indices, float v) {
+        return put(r, indices.findIndices(), v);
+    }
+
+    /**
+     * Put a single value into the specified rows (non-zero entries of
+     * <tt>indices</tt>) of a column.
+     */
+    public FloatMatrix put(FloatMatrix indices, int c, float v) {
+        return put(indices.findIndices(), c, v);
+    }
+
+    /**
+     * Put a single value in the specified rows and columns (non-zero entries
+     * of <tt>rindices</tt> and <tt>cindices</tt>.
+     */
+    public FloatMatrix put(FloatMatrix rindices, FloatMatrix cindices, float v) {
+        return put(rindices.findIndices(), cindices.findIndices(), v);
+    }
+
+    /** Find the linear indices of all non-zero elements. */
+    public int[] findIndices() {
+        int len = 0;
+        for (int i = 0; i < length; i++) {
+            if (get(i) != 0.0f) {
+                len++;
+            }
+        }
+
+        int[] indices = new int[len];
+        int c = 0;
+
+        for (int i = 0; i < length; i++) {
+            if (get(i) != 0.0f) {
+                indices[c++] = i;
+            }
+        }
+
+        return indices;
+    }
+
+    /**************************************************************************
+     * Basic operations (copying, resizing, element access)
+     */
+    /** Return transposed copy of this matrix. */
+    public FloatMatrix transpose() {
+        FloatMatrix result = new FloatMatrix(columns, rows);
+
+        for (int i = 0; i < rows; i++) {
+            for (int j = 0; j < columns; j++) {
+                result.put(j, i, get(i, j));
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Compare two matrices. Returns true if and only if other is also a
+     * FloatMatrix which has the same size and the maximal absolute
+     * difference in matrix elements is smaller thatn 1e-6.
+     */
+    public boolean equals(Object o) {
+        if (!(o instanceof FloatMatrix)) {
+            return false;
+        }
+
+        FloatMatrix other = (FloatMatrix) o;
+
+        if (!sameSize(other)) {
+            return false;
+        }
+
+        FloatMatrix diff = MatrixFunctions.absi(sub(other));
+
+        return diff.max() / (rows * columns) < 1e-6;
+    }
+
+    /** Resize the matrix. All elements will be set to zero. */
+    public void resize(int newRows, int newColumns) {
+        rows = newRows;
+        columns = newColumns;
+        length = newRows * newColumns;
+        data = new float[rows * columns];
+    }
+
+    /** Reshape the matrix. Number of elements must not change. */
+    public FloatMatrix reshape(int newRows, int newColumns) {
+        if (length != newRows * newColumns) {
+            throw new IllegalArgumentException(
+                    "Number of elements must not change.");
+        }
+
+        rows = newRows;
+        columns = newColumns;
+
+        return this;
+    }
+
+    /** Generate a new matrix which has the given number of replications of this. */
+    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++)
+                        result.put(r * rows + i, c * columns + j, get(i, j));
+        return result;
+    }
+
+    /** Checks whether two matrices have the same size. */
+    public boolean sameSize(FloatMatrix a) {
+        return rows == a.rows && columns == a.columns;
+    }
+
+    /** Throws SizeException unless two matrices have the same size. */
+    public void assertSameSize(FloatMatrix a) {
+        if (!sameSize(a)) {
+            throw new SizeException("Matrices must have the same size.");
+        }
+    }
+
+    /** Checks whether two matrices can be multiplied (that is, number of columns of
+     * this must equal number of rows of a. */
+    public boolean multipliesWith(FloatMatrix a) {
+        return columns == a.rows;
+    }
+
+    /** Throws SizeException unless matrices can be multiplied with one another. */
+    public void assertMultipliesWith(FloatMatrix a) {
+        if (!multipliesWith(a)) {
+            throw new SizeException("Number of columns of left matrix must be equal to number of rows of right matrix.");
+        }
+    }
+
+    /** Checks whether two matrices have the same length. */
+    public boolean sameLength(FloatMatrix a) {
+        return length == a.length;
+    }
+
+    /** Throws SizeException unless matrices have the same length. */
+    public void assertSameLength(FloatMatrix a) {
+        if (!sameLength(a)) {
+            throw new SizeException("Matrices must have same length (is: " + length + " and " + a.length + ")");
+        }
+    }
+
+    /** Copy FloatMatrix a to this. this a is resized if necessary. */
+    public FloatMatrix copy(FloatMatrix a) {
+        if (!sameSize(a)) {
+            resize(a.rows, a.columns);
+        }
+
+        System.arraycopy(data, 0, a.data, 0, length);
+        return a;
+    }
+
+    /**
+     * Returns a duplicate of this matrix. Geometry is the same (including offsets, transpose, etc.),
+     * but the buffer is not shared.
+     */
+    public FloatMatrix dup() {
+        FloatMatrix out = new FloatMatrix(rows, columns);
+
+        JavaBlas.rcopy(length, data, 0, 1, out.data, 0, 1);
+
+        return out;
+    }
+
+    /** Swap two columns of a matrix. */
+    public FloatMatrix swapColumns(int i, int j) {
+        Blas.sswap(rows, data, index(0, i), 1, data, index(0, j), 1);
+        return this;
+    }
+
+    /** Swap two rows of a matrix. */
+    public FloatMatrix swapRows(int i, int j) {
+        Blas.sswap(columns, data, index(i, 0), rows, data, index(j, 0), rows);
+        return this;
+    }
+
+    /** Set matrix element */
+    public FloatMatrix put(int rowIndex, int columnIndex, float value) {
+        data[index(rowIndex, columnIndex)] = value;
+        return this;
+    }
+
+    /** Retrieve matrix element */
+    public float get(int rowIndex, int columnIndex) {
+        return data[index(rowIndex, columnIndex)];
+    }
+
+    /** Get index of an element */
+    public int index(int rowIndex, int columnIndex) {
+        return rowIndex + rows * columnIndex;
+    }
+
+    /** Compute the row index of a linear index. */
+    public int indexRows(int i) {
+        return i / rows;
+    }
+
+    /** Compute the column index of a linear index. */
+    public int indexColumns(int i) {
+        return i - indexRows(i) * rows;
+    }
+
+    /** Get a matrix element (linear indexing). */
+    public float get(int i) {
+        return data[i];
+    }
+
+    /** Set a matrix element (linear indexing). */
+    public FloatMatrix put(int i, float v) {
+        data[i] = v;
+        return this;
+    }
+
+    /** Set all elements to a value. */
+    public FloatMatrix fill(float value) {
+        for (int i = 0; i < length; i++) {
+            put(i, value);
+        }
+        return this;
+    }
+
+    /** Get number of rows. */
+    public int getRows() {
+        return rows;
+    }
+
+    /** Get number of columns. */
+    public int getColumns() {
+        return columns;
+    }
+
+    /** Get total number of elements. */
+    public int getLength() {
+        return length;
+    }
+
+    /** Checks whether the matrix is empty. */
+    public boolean isEmpty() {
+        return columns == 0 || rows == 0;
+    }
+
+    /** Checks whether the matrix is square. */
+    public boolean isSquare() {
+        return columns == rows;
+    }
+
+    /** Throw SizeException unless matrix is square. */
+    public void assertSquare() {
+        if (!isSquare()) {
+            throw new SizeException("Matrix must be square!");
+        }
+    }
+
+    /** Checks whether the matrix is a vector. */
+    public boolean isVector() {
+        return columns == 1 || rows == 1;
+    }
+
+    /** Checks whether the matrix is a row vector. */
+    public boolean isRowVector() {
+        return rows == 1;
+    }
+
+    /** Checks whether the matrix is a column vector. */
+    public boolean isColumnVector() {
+        return columns == 1;
+    }
+
+    /** Returns the diagonal of the matrix. */
+    public FloatMatrix diag() {
+        assertSquare();
+        FloatMatrix d = new FloatMatrix(rows);
+        JavaBlas.rcopy(rows, data, 0, rows + 1, d.data, 0, 1);
+        return d;
+    }
+
+    /** Pretty-print this matrix to <tt>System.out</tt>. */
+    public void print() {
+        System.out.println(toString());
+    }
+
+    /** Generate string representation of the matrix. */
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder();
+
+        s.append("[");
+
+        for (int i = 0; i < rows; i++) {
+            for (int j = 0; j < columns; j++) {
+                s.append(get(i, j));
+                if (j < columns - 1) {
+                    s.append(", ");
+                }
+            }
+            if (i < rows - 1) {
+                s.append("; ");
+            }
+        }
+
+        s.append("]");
+
+        return s.toString();
+    }
+
+    /**
+     * Generate string representation of the matrix, with specified
+     * format for the entries. For example, <code>x.toString("%.1f")</code>
+     * generates a string representations having only one position after the
+     * decimal point.
+     */
+    public String toString(String fmt) {
+        StringWriter s = new StringWriter();
+        PrintWriter p = new PrintWriter(s);
+
+        p.print("[");
+
+        for (int r = 0; r < rows; r++) {
+            for (int c = 0; c < columns; c++) {
+                p.printf(fmt, get(r, c));
+                if (c < columns - 1) {
+                    p.print(", ");
+                }
+            }
+            if (r < rows - 1) {
+                p.print("; ");
+            }
+        }
+
+        p.print("]");
+
+        return s.toString();
+    }
+
+    /** Converts the matrix to a one-dimensional array of floats. */
+    public float[] toArray() {
+        float[] array = new float[length];
+
+        System.arraycopy(data, 0, array, 0, length);
+
+        return array;
+    }
+
+    /** Converts the matrix to a two-dimensional array of floats. */
+    public float[][] toArray2() {
+        float[][] array = new float[rows][columns];
+
+        for (int r = 0; r < rows; r++) {
+            for (int c = 0; c < columns; c++) {
+                array[r][c] = get(r, c);
+            }
+        }
+
+        return array;
+    }
+
+    /** Converts the matrix to a one-dimensional array of integers. */
+    public int[] toIntArray() {
+        int[] array = new int[length];
+
+        for (int i = 0; i < length; i++) {
+            array[i] = (int) Math.rint(get(i));
+        }
+
+        return array;
+    }
+
+    /** Convert the matrix to a two-dimensional array of integers. */
+    public int[][] toIntArray2() {
+        int[][] array = new int[rows][columns];
+
+        for (int r = 0; r < rows; r++) {
+            for (int c = 0; c < columns; c++) {
+                array[r][c] = (int) Math.rint(get(r, c));
+            }
+        }
+
+        return array;
+    }
+
+    /** Convert the matrix to a one-dimensional array of boolean values. */
+    public boolean[] toBooleanArray() {
+        boolean[] array = new boolean[length];
+
+        for (int i = 0; i < length; i++) {
+            array[i] = get(i) != 0.0f ? true : false;
+        }
+
+        return array;
+    }
+
+    /** Convert the matrix to a two-dimensional array of boolean values. */
+    public boolean[][] toBooleanArray2() {
+        boolean[][] array = new boolean[rows][columns];
+
+        for (int r = 0; r < rows; r++) {
+            for (int c = 0; c < columns; c++) {
+                array[r][c] = get(r, c) != 0.0f ? true : false;
+            }
+        }
+
+        return array;
+    }
+
+    /** Convert matrix to FloatMatrix. */
+    public FloatMatrix toFloatMatrix() {
+        FloatMatrix result = new FloatMatrix(rows, columns);
+
+        for (int c = 0; c < columns; c++) {
+            for (int r = 0; r < rows; r++) {
+                result.put(r, c, (float) get(r, c));
+            }
+        }
+
+        return result;
+    }
+
+    /**************************************************************************
+     * Arithmetic Operations
+     */
+    /**
+     * Ensures that the result vector has the same length as this. If not,
+     * resizing result is tried, which fails if result == this or result == other.
+     */
+    private void ensureResultLength(FloatMatrix other, FloatMatrix result) {
+        if (!sameLength(result)) {
+            if (result == this || result == other) {
+                throw new SizeException("Cannot resize result matrix because it is used in-place.");
+            }
+            result.resize(rows, columns);
+        }
+    }
+
+    /** Add two matrices (in-place). */
+    public FloatMatrix addi(FloatMatrix other, FloatMatrix result) {
+        if (other.isScalar()) {
+            return addi(other.scalar(), result);
+        }
+        if (isScalar()) {
+            return other.addi(scalar(), result);
+        }
+
+        assertSameLength(other);
+        ensureResultLength(other, result);
+
+        if (result == this) {
+            SimpleBlas.axpy(1.0f, other, result);
+        } else if (result == other) {
+            SimpleBlas.axpy(1.0f, this, result);
+        } else {
+            /*SimpleBlas.copy(this, result);
+            SimpleBlas.axpy(1.0f, other, result);*/
+            JavaBlas.rzgxpy(length, result.data, data, other.data);
+        }
+
+        return result;
+    }
+
+    /** Add a scalar to a matrix (in-place). */
+    public FloatMatrix addi(float v, FloatMatrix result) {
+        ensureResultLength(null, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, get(i) + v);
+        }
+        return result;
+    }
+
+    /** Subtract two matrices (in-place). */
+    public FloatMatrix subi(FloatMatrix other, FloatMatrix result) {
+        if (other.isScalar()) {
+            return subi(other.scalar(), result);
+        }
+        if (isScalar()) {
+            return other.rsubi(scalar(), result);
+        }
+
+        assertSameLength(other);
+        ensureResultLength(other, result);
+
+        if (result == this) {
+            SimpleBlas.axpy(-1.0f, other, result);
+        } else if (result == other) {
+            SimpleBlas.scal(-1.0f, result);
+            SimpleBlas.axpy(1.0f, this, result);
+        } else {
+            SimpleBlas.copy(this, result);
+            SimpleBlas.axpy(-1.0f, other, result);
+        }
+        return result;
+    }
+
+    /** Subtract a scalar from a matrix (in-place). */
+    public FloatMatrix subi(float v, FloatMatrix result) {
+        ensureResultLength(null, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, get(i) - v);
+        }
+        return result;
+    }
+
+    /**
+     * Subtract two matrices, but subtract first from second matrix, that is,
+     * compute <em>result = other - this</em> (in-place).
+     * */
+    public FloatMatrix rsubi(FloatMatrix other, FloatMatrix result) {
+        return other.subi(this, result);
+    }
+
+    /** Subtract a matrix from a scalar (in-place). */
+    public FloatMatrix rsubi(float a, FloatMatrix result) {
+        ensureResultLength(null, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, a - get(i));
+        }
+        return result;
+    }
+
+    /** Elementwise multiplication (in-place). */
+    public FloatMatrix muli(FloatMatrix other, FloatMatrix result) {
+        if (other.isScalar()) {
+            return muli(other.scalar(), result);
+        }
+        if (isScalar()) {
+            return other.muli(scalar(), result);
+        }
+
+        assertSameLength(other);
+        ensureResultLength(other, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, get(i) * other.get(i));
+        }
+        return result;
+    }
+
+    /** Elementwise multiplication with a scalar (in-place). */
+    public FloatMatrix muli(float v, FloatMatrix result) {
+        ensureResultLength(null, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, get(i) * v);
+        }
+        return result;
+    }
+
+    /** Matrix-matrix multiplication (in-place). */
+    public FloatMatrix mmuli(FloatMatrix other, FloatMatrix result) {
+        if (other.isScalar()) {
+            return muli(other.scalar(), result);
+        }
+        if (isScalar()) {
+            return other.muli(scalar(), result);
+        }
+
+        /* check sizes and resize if necessary */
+        assertMultipliesWith(other);
+        if (result.rows != rows || result.columns != other.columns) {
+            if (result != this && result != other) {
+                result.resize(rows, other.columns);
+            } else {
+                throw new SizeException("Cannot resize result matrix because it is used in-place.");
+            }
+        }
+
+        if (result == this || result == other) {
+            /* actually, blas cannot do multiplications in-place. Therefore, we will fake by
+             * allocating a temporary object on the side and copy the result later.
+             */
+            FloatMatrix temp = new FloatMatrix(result.rows, result.columns);
+            if (other.columns == 1) {
+                SimpleBlas.gemv(1.0f, this, other, 0.0f, temp);
+            } else {
+                SimpleBlas.gemm(1.0f, this, other, 0.0f, temp);
+            }
+            SimpleBlas.copy(temp, result);
+        } else {
+            if (other.columns == 1) {
+                SimpleBlas.gemv(1.0f, this, other, 0.0f, result);
+            } else {
+                SimpleBlas.gemm(1.0f, this, other, 0.0f, result);
+            }
+        }
+        return result;
+    }
+
+    /** Matrix-matrix multiplication with a scalar (for symmetry, does the
+     * same as <code>muli(scalar)</code> (in-place).
+     */
+    public FloatMatrix mmuli(float v, FloatMatrix result) {
+        return muli(v, result);
+    }
+
+    /** Elementwise division (in-place). */
+    public FloatMatrix divi(FloatMatrix other, FloatMatrix result) {
+        if (other.isScalar()) {
+            return divi(other.scalar(), result);
+        }
+        if (isScalar()) {
+            return other.rdivi(scalar(), result);
+        }
+
+        assertSameLength(other);
+        ensureResultLength(other, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, get(i) / other.get(i));
+        }
+        return result;
+    }
+
+    /** Elementwise division with a scalar (in-place). */
+    public FloatMatrix divi(float a, FloatMatrix result) {
+        ensureResultLength(null, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, get(i) / a);
+        }
+        return result;
+    }
+
+    /**
+     * Elementwise division, with operands switched. Computes
+     * <code>result = other / this</code> (in-place). */
+    public FloatMatrix rdivi(FloatMatrix other, FloatMatrix result) {
+        return other.divi(this, result);
+    }
+
+    /** (Elementwise) division with a scalar, with operands switched. Computes
+     * <code>result = a / this</code> (in-place). */
+    public FloatMatrix rdivi(float a, FloatMatrix result) {
+        ensureResultLength(null, result);
+
+        for (int i = 0; i < length; i++) {
+            result.put(i, a / get(i));
+        }
+        return result;
+    }
+
+    /** Negate each element (in-place). */
+    public FloatMatrix negi() {
+        for (int i = 0; i < length; i++) {
+            put(i, -get(i));
+        }
+        return this;
+    }
+
+    /** Negate each element. */
+    public FloatMatrix neg() {
+        return dup().negi();
+    }
+
+    /** Maps zero to 1.0f and all non-zero values to 0.0f (in-place). */
+    public FloatMatrix noti() {
+        for (int i = 0; i < length; i++) {
+            put(i, get(i) == 0.0f ? 1.0f : 0.0f);
+        }
+        return this;
+    }
+
+    /** Maps zero to 1.0f and all non-zero values to 0.0f. */
+    public FloatMatrix not() {
+        return dup().noti();
+    }
+
+    /** Maps zero to 0.0f and all non-zero values to 1.0f (in-place). */
+    public FloatMatrix truthi() {
+        for (int i = 0; i < length; i++) {
+            put(i, get(i) == 0.0f ? 0.0f : 1.0f);
+        }
+        return this;
+    }
+
+    /** Maps zero to 0.0f and all non-zero values to 1.0f. */
+    public FloatMatrix truth() {
+        return dup().truthi();
+    }
+
+    /****************************************************************
+     * Rank one-updates
+     */
+    /** Computes a rank-1-update A = A + alpha * x * y'. */
+    public FloatMatrix rankOneUpdate(float alpha, FloatMatrix x, FloatMatrix y) {
+        if (rows != x.length) {
+            throw new SizeException("Vector x has wrong length (" + x.length + " != " + rows + ").");
+        }
+        if (columns != y.length) {
+            throw new SizeException("Vector y has wrong length (" + x.length + " != " + columns + ").");
+        }
+
+        SimpleBlas.ger(alpha, x, y, this);
+        return this;
+    }
+
+    /** Computes a rank-1-update A = A + alpha * x * x'. */
+    public FloatMatrix rankOneUpdate(float alpha, FloatMatrix x) {
+        return rankOneUpdate(alpha, x, x);
+    }
+
+    /** Computes a rank-1-update A = A + x * x'. */
+    public FloatMatrix rankOneUpdate(FloatMatrix x) {
+        return rankOneUpdate(1.0f, x, x);
+    }
+
+    /** Computes a rank-1-update A = A + x * y'. */
+    public FloatMatrix rankOneUpdate(FloatMatrix x, FloatMatrix y) {
+        return rankOneUpdate(1.0f, x, y);
+    }
+
+    /****************************************************************
+     * Logical operations
+     */
+    /** Returns the minimal element of the matrix. */
+    public float min() {
+        if (isEmpty()) {
+            return Float.POSITIVE_INFINITY;
+        }
+        float v = Float.POSITIVE_INFINITY;
+        for (int i = 0; i < length; i++) {
+            if (!Float.isNaN(get(i)) && get(i) < v) {
+                v = get(i);
+            }
+        }
+
+        return v;
+    }
+
+    /**
+     * Returns the linear index of the minimal element. If there are
+     * more than one elements with this value, the first one is returned.
+     */
+    public int argmin() {
+        if (isEmpty()) {
+            return -1;
+        }
+        float v = Float.POSITIVE_INFINITY;
+        int a = -1;
+        for (int i = 0; i < length; i++) {
+            if (!Float.isNaN(get(i)) && get(i) < v) {
+                v = get(i);
+                a = i;
+            }
+        }
+
+        return a;
+    }
+
+    /**
+     * Computes the minimum between two matrices. Returns the smaller of the
+     * corresponding elements in the matrix (in-place).
+     */
+    public FloatMatrix mini(FloatMatrix other, FloatMatrix result) {
+        if (result == this) {
+            for (int i = 0; i < length; i++) {
+                if (get(i) > other.get(i)) {
+                    put(i, other.get(i));
+                }
+            }
+        } else {
+            for (int i = 0; i < length; i++) {
+                if (get(i) > other.get(i)) {
+                    result.put(i, other.get(i));
+                } else {
+                    result.put(i, get(i));
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Computes the minimum between two matrices. Returns the smaller of the
+     * corresponding elements in the matrix (in-place on this).
+     */
+    public FloatMatrix mini(FloatMatrix other) {
+        return mini(other, this);
+    }
+
+    /**
+     * Computes the minimum between two matrices. Returns the smaller of the
+     * corresponding elements in the matrix (in-place on this).
+     */
+    public FloatMatrix min(FloatMatrix other) {
+        return mini(other, new FloatMatrix(rows, columns));
+    }
+
+    public FloatMatrix mini(float v, FloatMatrix result) {
+        if (result == this) {
+            for (int i = 0; i < length; i++) {
+                if (get(i) > v) {
+                    result.put(i, v);
+                }
+            }
+        } else {
+            for (int i = 0; i < length; i++) {
+                if (get(i) > v) {
+                    result.put(i, v);
+                } else {
+                    result.put(i, get(i));
+                }
+            }
+
+        }
+        return this;
+    }
+
+    public FloatMatrix mini(float v) {
+        return mini(v, this);
+    }
+
+    public FloatMatrix min(float v) {
+        return mini(v, new FloatMatrix(rows, columns));
+    }
+
+    /** Returns the maximal element of the matrix. */
+    public float max() {
+        if (isEmpty()) {
+            return Float.NEGATIVE_INFINITY;
+        }
+        float v = Float.NEGATIVE_INFINITY;
+        for (int i = 0; i < length; i++) {
+            if (!Float.isNaN(get(i)) && get(i) > v) {
+                v = get(i);
+            }
+        }
+        return v;
+    }
+
+    /**
+     * Returns the linear index of the maximal element of the matrix. If
+     * there are more than one elements with this value, the first one
+     * is returned.
+     */
+    public int argmax() {
+        if (isEmpty()) {
+            return -1;
+        }
+        float v = Float.NEGATIVE_INFINITY;
+        int a = -1;
+        for (int i = 0; i < length; i++) {
+            if (!Float.isNaN(get(i)) && get(i) > v) {
+                v = get(i);
+                a = i;
+            }
+        }
+
+        return a;
+    }
+
+    /**
+     * Computes the maximum between two matrices. Returns the larger of the
+     * corresponding elements in the matrix (in-place).
+     */
+    public FloatMatrix maxi(FloatMatrix other, FloatMatrix result) {
+        if (result == this) {
+            for (int i = 0; i < length; i++) {
+                if (get(i) < other.get(i)) {
+                    put(i, other.get(i));
+                }
+            }
+        } else {
+            for (int i = 0; i < length; i++) {
+                if (get(i) < other.get(i)) {
+                    result.put(i, other.get(i));
+                } else {
+                    result.put(i, get(i));
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Computes the maximum between two matrices. Returns the smaller of the
+     * corresponding elements in the matrix (in-place on this).
+     */
+    public FloatMatrix maxi(FloatMatrix other) {
+        return maxi(other, this);
+    }
+
+    /**
+     * Computes the maximum between two matrices. Returns the larger of the
+     * corresponding elements in the matrix (in-place on this).
+     */
+    public FloatMatrix max(FloatMatrix other) {
+        return maxi(other, new FloatMatrix(rows, columns));
+    }
+
+    public FloatMatrix maxi(float v, FloatMatrix result) {
+        if (result == this) {
+            for (int i = 0; i < length; i++) {
+                if (get(i) < v) {
+                    result.put(i, v);
+                }
+            }
+        } else {
+            for (int i = 0; i < length; i++) {
+                if (get(i) < v) {
+                    result.put(i, v);
+                } else {
+                    result.put(i, get(i));
+                }
+            }
+
+        }
+        return this;
+    }
+
+    public FloatMatrix maxi(float v) {
+        return maxi(v, this);
+    }
+
+    public FloatMatrix max(float v) {
+        return maxi(v, new FloatMatrix(rows, columns));
+    }
+
+    /** Computes the sum of all elements of the matrix. */
+    public float sum() {
+        float s = 0.0f;
+        for (int i = 0; i < length; i++) {
+            s += get(i);
+        }
+        return s;
+    }
+
+    /**
+     * Computes the mean value of all elements in the matrix,
+     * that is, <code>x.sum() / x.length</code>.
+     */
+    public float mean() {
+        return sum() / length;
+    }
+
+    /**
+     * Computes the cumulative sum, that is, the sum of all elements
+     * of the matrix up to a given index in linear addressing (in-place).
+     */
+    public FloatMatrix cumulativeSumi() {
+        float s = 0.0f;
+        for (int i = 0; i < length; i++) {
+            s += get(i);
+            put(i, s);
+        }
+        return this;
+    }
+
+    /**
+     * Computes the cumulative sum, that is, the sum of all elements
+     * of the matrix up to a given index in linear addressing.
+     */
+    public FloatMatrix cumulativeSum() {
+        return dup().cumulativeSumi();
+    }
+
+    /** The scalar product of this with other. */
+    public float dot(FloatMatrix other) {
+        return SimpleBlas.dot(this, other);
+    }
+
+    /**
+     * The Euclidean norm of the matrix as vector, also the Frobenius
+     * norm of the matrix.
+     */
+    public float norm2() {
+        return SimpleBlas.nrm2(this);
+    }
+
+    /**
+     * The maximum norm of the matrix (maximal absolute value of the elements).
+     */
+    public float normmax() {
+        int i = SimpleBlas.iamax(this);
+        return Math.abs(get(i));
+    }
+
+    /**
+     * The 1-norm of the matrix as vector (sum of absolute values of elements).
+     */
+    public float norm1() {
+        return SimpleBlas.asum(this);
+    }
+
+    /**
+     * Return a new matrix with all elements sorted.
+     */
+    public FloatMatrix sort() {
+        float array[] = toArray();
+        java.util.Arrays.sort(array);
+        return new FloatMatrix(rows, columns, array);
+    }
+
+    /**
+     * Sort elements in-place.
+     */
+    public FloatMatrix sorti() {
+        Arrays.sort(data);
+        return this;
+    }
+
+    /**
+     * Get the sorting permutation.
+     *
+     * @return an int[] array such that which indexes the elements in sorted
+     * order.
+     */
+    public int[] sortingPermutation() {
+        Integer[] indices = new Integer[length];
+
+        for (int i = 0; i < length; i++) {
+            indices[i] = i;
+        }
+
+        final float[] array = data;
+
+        Arrays.sort(indices, new Comparator() {
+
+            public int compare(Object o1, Object o2) {
+                int i = (Integer) o1;
+                int j = (Integer) o2;
+                if (array[i] < array[j]) {
+                    return -1;
+                } else if (array[i] == array[j]) {
+                    return 0;
+                } else {
+                    return 1;
+                }
+            }
+        });
+
+        int[] result = new int[length];
+
+        for (int i = 0; i < length; i++) {
+            result[i] = indices[i];
+        }
+
+        return result;
+    }
+
+    /**
+     * Sort columns (in-place).
+     */
+    public FloatMatrix sortColumnsi() {
+        for (int i = 0; i < length; i += rows) {
+            Arrays.sort(data, i, i + rows);
+        }
+        return this;
+    }
+
+    /** Sort columns. */
+    public FloatMatrix sortColumns() {
+        return dup().sortColumnsi();
+    }
+
+    /** Return matrix of indices which sort all columns. */
+    public int[][] columnSortingPermutations() {
+        int[][] result = new int[columns][];
+
+        FloatMatrix temp = new FloatMatrix(rows);
+        for (int c = 0; c < columns; c++) {
+            result[c] = getColumn(c, temp).sortingPermutation();
+        }
+
+        return result;
+    }
+
+    /** Sort rows (in-place). */
+    public FloatMatrix sortRowsi() {
+        // actually, this is much harder because the data is not consecutive
+        // in memory...
+        FloatMatrix temp = new FloatMatrix(columns);
+        for (int r = 0; r < rows; r++) {
+            putRow(r, getRow(r, temp).sorti());
+        }
+        return this;
+    }
+
+    /** Sort rows. */
+    public FloatMatrix sortRows() {
+        return dup().sortRowsi();
+    }
+
+    /** Return matrix of indices which sort all columns. */
+    public int[][] rowSortingPermutations() {
+        int[][] result = new int[rows][];
+
+        FloatMatrix temp = new FloatMatrix(columns);
+        for (int r = 0; r < rows; r++) {
+            result[r] = getRow(r, temp).sortingPermutation();
+        }
+
+        return result;
+    }
+
+    /** Return a vector containing the sums of the columns (having number of columns many entries) */
+    public FloatMatrix columnSums() {
+        if (rows == 1) {
+            return dup();
+        } else {
+            FloatMatrix v = new FloatMatrix(1, columns);
+
+            for (int c = 0; c < columns; c++) {
+                for (int r = 0; r < rows; r++) {
+                    v.put(c, v.get(c) + get(r, c));
+                }
+            }
+
+            return v;
+        }
+    }
+
+    /** Return a vector containing the means of all columns. */
+    public FloatMatrix columnMeans() {
+        return columnSums().divi(rows);
+    }
+
+    /** Return a vector containing the sum of the rows. */
+    public FloatMatrix rowSums() {
+        if (columns == 1) {
+            return dup();
+        } else {
+            FloatMatrix v = new FloatMatrix(rows);
+
+            for (int c = 0; c < columns; c++) {
+                for (int r = 0; r < rows; r++) {
+                    v.put(r, v.get(r) + get(r, c));
+                }
+            }
+
+            return v;
+        }
+    }
+
+    /** Return a vector containing the means of the rows. */
+    public FloatMatrix rowMeans() {
+        return rowSums().divi(columns);
+    }
+
+    /** Get a copy of a column. */
+    public FloatMatrix getColumn(int c) {
+        return getColumn(c, new FloatMatrix(rows, 1));
+    }
+
+    /** Copy a column to the given vector. */
+    public FloatMatrix getColumn(int c, FloatMatrix result) {
+        result.checkLength(rows);
+        JavaBlas.rcopy(rows, data, index(0, c), 1, result.data, 0, 1);
+        return result;
+    }
+
+    /** Copy a column back into the matrix. */
+    public void putColumn(int c, FloatMatrix v) {
+        JavaBlas.rcopy(rows, v.data, 0, 1, data, index(0, c), 1);
+    }
+
+    /** Get a copy of a row. */
+    public FloatMatrix getRow(int r) {
+        return getRow(r, new FloatMatrix(1, columns));
+    }
+
+    /** Copy a row to a given vector. */
+    public FloatMatrix getRow(int r, FloatMatrix result) {
+        result.checkLength(columns);
+        JavaBlas.rcopy(columns, data, index(r, 0), rows, result.data, 0, 1);
+        return result;
+    }
+
+    /** Copy a row back into the matrix. */
+    public void putRow(int r, FloatMatrix v) {
+        JavaBlas.rcopy(columns, v.data, 0, 1, data, index(r, 0), rows);
+    }
+
+    /** Return column-wise minimums. */
+    public FloatMatrix columnMins() {
+        FloatMatrix mins = new FloatMatrix(1, columns);
+        for (int c = 0; c < columns; c++) {
+            mins.put(c, getColumn(c).min());
+        }
+        return mins;
+    }
+
+    /** Return index of minimal element per column. */
+    public int[] columnArgmins() {
+        int[] argmins = new int[columns];
+        for (int c = 0; c < columns; c++) {
+            argmins[c] = getColumn(c).argmin();
+        }
+        return argmins;
+    }
+
+    /** Return column-wise maximums. */
+    public FloatMatrix columnMaxs() {
+        FloatMatrix maxs = new FloatMatrix(1, columns);
+        for (int c = 0; c < columns; c++) {
+            maxs.put(c, getColumn(c).max());
+        }
+        return maxs;
+    }
+
+    /** Return index of minimal element per column. */
+    public int[] columnArgmaxs() {
+        int[] argmaxs = new int[columns];
+        for (int c = 0; c < columns; c++) {
+            argmaxs[c] = getColumn(c).argmax();
+        }
+        return argmaxs;
+    }
+
+    /** Return row-wise minimums. */
+    public FloatMatrix rowMins() {
+        FloatMatrix mins = new FloatMatrix(rows);
+        for (int c = 0; c < rows; c++) {
+            mins.put(c, getRow(c).min());
+        }
+        return mins;
+    }
+
+    /** Return index of minimal element per row. */
+    public int[] rowArgmins() {
+        int[] argmins = new int[rows];
+        for (int c = 0; c < rows; c++) {
+            argmins[c] = getRow(c).argmin();
+        }
+        return argmins;
+    }
+
+    /** Return row-wise maximums. */
+    public FloatMatrix rowMaxs() {
+        FloatMatrix maxs = new FloatMatrix(rows);
+        for (int c = 0; c < rows; c++) {
+            maxs.put(c, getRow(c).max());
+        }
+        return maxs;
+    }
+
+    /** Return index of minimal element per row. */
+    public int[] rowArgmaxs() {
+        int[] argmaxs = new int[rows];
+        for (int c = 0; c < rows; c++) {
+            argmaxs[c] = getRow(c).argmax();
+        }
+        return argmaxs;
+    }
+
+    /**************************************************************************
+     * Elementwise Functions
+     */
+    /** Add a row vector to all rows of the matrix (in place). */
+    public FloatMatrix addiRowVector(FloatMatrix x) {
+        x.checkLength(columns);
+        for (int r = 0; r < rows; r++) {
+            JavaBlas.raxpy(columns, 1.0f, x.data, 0, 1, data, index(r, 0), rows);
+        }
+        return this;
+    }
+
+    /** Add a row to all rows of the matrix. */
+    public FloatMatrix addRowVector(FloatMatrix x) {
+        return dup().addiRowVector(x);
+    }
+
+    /** 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++) {
+            JavaBlas.raxpy(rows, 1.0f, x.data, 0, 1, data, index(0, c), 1);
+        }
+        return this;
+    }
+
+    /** Add a vector to all columns of the matrix. */
+    public FloatMatrix addColumnVector(FloatMatrix x) {
+        return dup().addiColumnVector(x);
+    }
+
+    /** Subtract a row vector from all rows of the matrix (in-place). */
+    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 r = 0; r < rows; r++) {
+            JavaBlas.raxpy(columns, -1.0f, x.data, 0, 1, data, index(r, 0), rows);
+        }
+        return this;
+    }
+
+    /** Subtract a row vector from all rows of the matrix. */
+    public FloatMatrix subRowVector(FloatMatrix x) {
+        return dup().subiRowVector(x);
+    }
+
+    /** 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++) {
+            JavaBlas.raxpy(rows, -1.0f, x.data, 0, 1, data, index(0, c), 1);
+        }
+        return this;
+    }
+
+    /** Subtract a vector from all columns of the matrix. */
+    public FloatMatrix subColumnVector(FloatMatrix x) {
+        return dup().subiColumnVector(x);
+    }
+
+    /** Multiply a row by a scalar. */
+    public FloatMatrix mulRow(int r, float scale) {
+        Blas.sscal(columns, scale, data, index(r, 0), rows);
+        return this;
+    }
+
+    /** Multiply a column by a scalar. */
+    public FloatMatrix mulColumn(int c, float scale) {
+        Blas.sscal(rows, scale, data, index(0, c), 1);
+        return this;
+    }
+
+    /** Multiply all columns with a column vector (in-place). */
+    public FloatMatrix muliColumnVector(FloatMatrix x) {
+        x.checkLength(rows);
+        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;
+    }
+
+    /** Multiply all columns with a column vector. */
+    public FloatMatrix mulColumnVector(FloatMatrix x) {
+        return dup().muliColumnVector(x);
+    }
+
+    /** 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++)
+                put(r, c, get(r, c) * x.get(c));
+        return this;
+    }
+
+    /** Multiply all rows with a row vector. */
+    public FloatMatrix mulRowVector(FloatMatrix x) {
+        return dup().muliRowVector(x);
+    }
+
+    /**
+     * Writes out this matrix to the given data stream.
+     * @param dos the data output stream to write to.
+     * @throws IOException
+     */
+    public void out(DataOutputStream dos) throws IOException {
+        dos.writeUTF("float");
+        dos.writeInt(columns);
+        dos.writeInt(rows);
+
+        dos.writeInt(data.length);
+        for (int i = 0; i < data.length; i++) {
+            dos.writeDouble(data[i]);
+        }
+    }
+
+    /**
+     * Reads in a matrix from the given data stream. Note
+     * that the old data of this matrix will be discarded.
+     * @param dis the data input stream to read from.
+     * @throws IOException
+     */
+    public void in(DataInputStream dis) throws IOException {
+        if (!dis.readUTF().equals("float")) {
+            throw new IllegalStateException("The matrix in the specified file is not of the correct type!");
+        }
+
+        this.columns = dis.readInt();
+        this.rows = dis.readInt();
+
+        final int MAX = dis.readInt();
+        data = new float[MAX];
+        for (int i = 0; i < MAX; i++) {
+            data[i] = dis.readFloat();
+        }
+    }
+
+    /**
+     * Saves this matrix to the specified file.
+     * @param filename the file to write the matrix in.
+     * @throws IOException thrown on errors while writing the matrix to the file
+     */
+    public void save(String filename) throws IOException {
+        DataOutputStream dos = new DataOutputStream(new FileOutputStream(filename, false));
+        this.out(dos);
+    }
+
+    /**
+     * Loads a matrix from a file into this matrix. Note that the old data
+     * of this matrix will be discarded.
+     * @param filename the file to read the matrix from
+     * @throws IOException thrown on errors while reading the matrix
+     */
+    public void load(String filename) throws IOException {
+        DataInputStream dis = new DataInputStream(new FileInputStream(filename));
+        this.in(dis);
+    }
+
+    public static FloatMatrix loadAsciiFile(String filename) throws IOException {
+        BufferedReader is = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
+
+        // Go through file and count columns and rows. What makes this endeavour a bit difficult is
+        // that files can have leading or trailing spaces leading to spurious fields
+        // after String.split().
+        String line;
+        int rows = 0;
+        int columns = -1;
+        while ((line = is.readLine()) != null) {
+            String[] elements = line.split("\\s+");
+            int numElements = elements.length;
+            if (elements[0].length() == 0) {
+                numElements--;
+            }
+            if (elements[elements.length - 1].length() == 0) {
+                numElements--;
+            }
+
+            if (columns == -1) {
+                columns = numElements;
+            } else {
+                if (columns != numElements) {
+                    throw new IOException("Number of elements changes in line " + line + ".");
+                }
+            }
+
+            rows++;
+        }
+        is.close();
+
+        // Go through file a second time process the actual data.
+        is = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
+        FloatMatrix result = new FloatMatrix(rows, columns);
+        int r = 0;
+        while ((line = is.readLine()) != null) {
+            String[] elements = line.split("\\s+");
+            int firstElement = (elements[0].length() == 0) ? 1 : 0;
+            for (int c = 0, cc = firstElement; c < columns; c++, cc++) {
+                result.put(r, c, Float.valueOf(elements[cc]));
+            }
+            r++;
+        }
+        return result;
+    }
+
+    /****************************************************************
+     * Autogenerated code
+     */
+    /***** Code for operators ***************************************/
+
+    /* Overloads for the usual arithmetic operations */
+    /*#
+    def gen_overloads(base, result_rows, result_cols, verb=''); <<-EOS
+    #{doc verb.capitalize + " a matrix (in place)."}
+    public FloatMatrix #{base}i(FloatMatrix other) {
+    return #{base}i(other, this);
+    }
+
+    #{doc verb.capitalize + " a matrix (in place)."}
+    public FloatMatrix #{base}(FloatMatrix other) {
+    return #{base}i(other, new FloatMatrix(#{result_rows}, #{result_cols}));
+    }
+
+    #{doc verb.capitalize + " a scalar (in place)."}
+    public FloatMatrix #{base}i(float v) {
+    return #{base}i(v, this);
+    }
+
+    #{doc verb.capitalize + " a scalar."}
+    public FloatMatrix #{base}(float v) {
+    return #{base}i(v, new FloatMatrix(rows, columns));
+    }
+    EOS
+    end
+    #*/
+
+    /* Generating code for logical operators. This not only generates the stubs
+     * but really all of the code.
+     */
+    /*#
+    def gen_compare(name, op, cmp); <<-EOS
+    #{doc 'Test for ' + cmp + ' (in-place).'}
+    public FloatMatrix #{name}i(FloatMatrix other, FloatMatrix result) {
+    if (other.isScalar())
+    return #{name}i(other.scalar(), result);
+
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) #{op} other.get(i) ? 1.0f : 0.0f);
+    return result;
+    }
+
+    #{doc 'Test for ' + cmp + ' (in-place).'}
+    public FloatMatrix #{name}i(FloatMatrix other) {
+    return #{name}i(other, this);
+    }
+
+    #{doc 'Test for ' + cmp + '.'}
+    public FloatMatrix #{name}(FloatMatrix other) {
+    return #{name}i(other, new FloatMatrix(rows, columns));
+    }
+
+    #{doc 'Test for ' + cmp + ' against a scalar (in-place).'}
+    public FloatMatrix #{name}i(float value, FloatMatrix result) {
+    ensureResultLength(null, result);
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) #{op} value ? 1.0f : 0.0f);
+    return result;
+    }
+
+    #{doc 'Test for ' + cmp + ' against a scalar (in-place).'}
+    public FloatMatrix #{name}i(float value) {
+    return #{name}i(value, this);
+    }
+
+    #{doc 'test for ' + cmp + ' against a scalar.'}
+    public FloatMatrix #{name}(float value) {
+    return #{name}i(value, new FloatMatrix(rows, columns));
+    }
+    EOS
+    end
+    #*/
+    /*#
+    def gen_logical(name, op, cmp); <<-EOS
+    #{doc 'Compute elementwise ' + cmp + ' (in-place).'}
+    public FloatMatrix #{name}i(FloatMatrix other, FloatMatrix result) {
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0f) #{op} (other.get(i) != 0.0f) ? 1.0f : 0.0f);
+    return result;
+    }
+
+    #{doc 'Compute elementwise ' + cmp + ' (in-place).'}
+    public FloatMatrix #{name}i(FloatMatrix other) {
+    return #{name}i(other, this);
+    }
+
+    #{doc 'Compute elementwise ' + cmp + '.'}
+    public FloatMatrix #{name}(FloatMatrix other) {
+    return #{name}i(other, new FloatMatrix(rows, columns));
+    }
+
+    #{doc 'Compute elementwise ' + cmp + ' against a scalar (in-place).'}
+    public FloatMatrix #{name}i(float value, FloatMatrix result) {
+    ensureResultLength(null, result);
+    boolean val = (value != 0.0f);
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0f) #{op} val ? 1.0f : 0.0f);
+    return result;
+    }
+
+    #{doc 'Compute elementwise ' + cmp + ' against a scalar (in-place).'}
+    public FloatMatrix #{name}i(float value) {
+    return #{name}i(value, this);
+    }
+
+    #{doc 'Compute elementwise ' + cmp + ' against a scalar.'}
+    public FloatMatrix #{name}(float value) {
+    return #{name}i(value, new FloatMatrix(rows, columns));
+    }
+    EOS
+    end
+    #*/
+
+    /*# collect(gen_overloads('add', 'rows', 'columns', 'add'),
+    gen_overloads('sub', 'rows', 'columns', 'subtract'),
+    gen_overloads('rsub', 'rows', 'columns', '(right-)subtract'),
+    gen_overloads('div', 'rows', 'columns', 'elementwise divide by'),
+    gen_overloads('rdiv', 'rows', 'columns', '(right-)elementwise divide by'),
+    gen_overloads('mul', 'rows', 'columns', 'elementwise multiply by'),
+    gen_overloads('mmul', 'rows', 'other.columns', 'matrix-multiply by'),
+    gen_compare('lt', '<', '"less than"'),
+    gen_compare('gt', '>', '"greater than"'),
+    gen_compare('le', '<=', '"less than or equal"'),
+    gen_compare('ge', '>=', '"greater than or equal"'),
+    gen_compare('eq', '==', 'equality'),
+    gen_compare('ne', '!=', 'inequality'),
+    gen_logical('and', '&', 'logical and'),
+    gen_logical('or', '|', 'logical or'),
+    gen_logical('xor', '^', 'logical xor'))
+    #*/
+//RJPP-BEGIN------------------------------------------------------------
+    /** Add a matrix (in place). */
+    public FloatMatrix addi(FloatMatrix other) {
+    return addi(other, this);
+    }
+
+    /** Add a matrix (in place). */
+    public FloatMatrix add(FloatMatrix other) {
+    return addi(other, new FloatMatrix(rows, columns));
+    }
+
+    /** Add a scalar (in place). */
+    public FloatMatrix addi(float v) {
+    return addi(v, this);
+    }
+
+    /** Add a scalar. */
+    public FloatMatrix add(float v) {
+    return addi(v, new FloatMatrix(rows, columns));
+    }
+
+    /** Subtract a matrix (in place). */
+    public FloatMatrix subi(FloatMatrix other) {
+    return subi(other, this);
+    }
+
+    /** Subtract a matrix (in place). */
+    public FloatMatrix sub(FloatMatrix other) {
+    return subi(other, new FloatMatrix(rows, columns));
+    }
+
+    /** Subtract a scalar (in place). */
+    public FloatMatrix subi(float v) {
+    return subi(v, this);
+    }
+
+    /** Subtract a scalar. */
+    public FloatMatrix sub(float v) {
+    return subi(v, new FloatMatrix(rows, columns));
+    }
+
+    /** (right-)subtract a matrix (in place). */
+    public FloatMatrix rsubi(FloatMatrix other) {
+    return rsubi(other, this);
+    }
+
+    /** (right-)subtract a matrix (in place). */
+    public FloatMatrix rsub(FloatMatrix other) {
+    return rsubi(other, new FloatMatrix(rows, columns));
+    }
+
+    /** (right-)subtract a scalar (in place). */
+    public FloatMatrix rsubi(float v) {
+    return rsubi(v, this);
+    }
+
+    /** (right-)subtract a scalar. */
+    public FloatMatrix rsub(float v) {
+    return rsubi(v, new FloatMatrix(rows, columns));
+    }
+
+    /** Elementwise divide by a matrix (in place). */
+    public FloatMatrix divi(FloatMatrix other) {
+    return divi(other, this);
+    }
+
+    /** Elementwise divide by a matrix (in place). */
+    public FloatMatrix div(FloatMatrix other) {
+    return divi(other, new FloatMatrix(rows, columns));
+    }
+
+    /** Elementwise divide by a scalar (in place). */
+    public FloatMatrix divi(float v) {
+    return divi(v, this);
+    }
+
+    /** Elementwise divide by a scalar. */
+    public FloatMatrix div(float v) {
+    return divi(v, new FloatMatrix(rows, columns));
+    }
+
+    /** (right-)elementwise divide by a matrix (in place). */
+    public FloatMatrix rdivi(FloatMatrix other) {
+    return rdivi(other, this);
+    }
+
+    /** (right-)elementwise divide by a matrix (in place). */
+    public FloatMatrix rdiv(FloatMatrix other) {
+    return rdivi(other, new FloatMatrix(rows, columns));
+    }
+
+    /** (right-)elementwise divide by a scalar (in place). */
+    public FloatMatrix rdivi(float v) {
+    return rdivi(v, this);
+    }
+
+    /** (right-)elementwise divide by a scalar. */
+    public FloatMatrix rdiv(float v) {
+    return rdivi(v, new FloatMatrix(rows, columns));
+    }
+
+    /** Elementwise multiply by a matrix (in place). */
+    public FloatMatrix muli(FloatMatrix other) {
+    return muli(other, this);
+    }
+
+    /** Elementwise multiply by a matrix (in place). */
+    public FloatMatrix mul(FloatMatrix other) {
+    return muli(other, new FloatMatrix(rows, columns));
+    }
+
+    /** Elementwise multiply by a scalar (in place). */
+    public FloatMatrix muli(float v) {
+    return muli(v, this);
+    }
+
+    /** Elementwise multiply by a scalar. */
+    public FloatMatrix mul(float v) {
+    return muli(v, new FloatMatrix(rows, columns));
+    }
+
+    /** Matrix-multiply by a matrix (in place). */
+    public FloatMatrix mmuli(FloatMatrix other) {
+    return mmuli(other, this);
+    }
+
+    /** Matrix-multiply by a matrix (in place). */
+    public FloatMatrix mmul(FloatMatrix other) {
+    return mmuli(other, new FloatMatrix(rows, other.columns));
+    }
+
+    /** Matrix-multiply by a scalar (in place). */
+    public FloatMatrix mmuli(float v) {
+    return mmuli(v, this);
+    }
+
+    /** Matrix-multiply by a scalar. */
+    public FloatMatrix mmul(float v) {
+    return mmuli(v, new FloatMatrix(rows, columns));
+    }
+
+    /** Test for "less than" (in-place). */
+    public FloatMatrix lti(FloatMatrix other, FloatMatrix result) {
+    if (other.isScalar())
+    return lti(other.scalar(), result);
+
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) < other.get(i) ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Test for "less than" (in-place). */
+    public FloatMatrix lti(FloatMatrix other) {
+    return lti(other, this);
+    }
+
+    /** Test for "less than". */
+    public FloatMatrix lt(FloatMatrix other) {
+    return lti(other, new FloatMatrix(rows, columns));
+    }
+
+    /** Test for "less than" against a scalar (in-place). */
+    public FloatMatrix lti(float value, FloatMatrix result) {
+    ensureResultLength(null, result);
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) < value ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Test for "less than" against a scalar (in-place). */
+    public FloatMatrix lti(float value) {
+    return lti(value, this);
+    }
+
+    /** test for "less than" against a scalar. */
+    public FloatMatrix lt(float value) {
+    return lti(value, new FloatMatrix(rows, columns));
+    }
+
+    /** Test for "greater than" (in-place). */
+    public FloatMatrix gti(FloatMatrix other, FloatMatrix result) {
+    if (other.isScalar())
+    return gti(other.scalar(), result);
+
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) > other.get(i) ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Test for "greater than" (in-place). */
+    public FloatMatrix gti(FloatMatrix other) {
+    return gti(other, this);
+    }
+
+    /** Test for "greater than". */
+    public FloatMatrix gt(FloatMatrix other) {
+    return gti(other, new FloatMatrix(rows, columns));
+    }
+
+    /** Test for "greater than" against a scalar (in-place). */
+    public FloatMatrix gti(float value, FloatMatrix result) {
+    ensureResultLength(null, result);
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) > value ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Test for "greater than" against a scalar (in-place). */
+    public FloatMatrix gti(float value) {
+    return gti(value, this);
+    }
+
+    /** test for "greater than" against a scalar. */
+    public FloatMatrix gt(float value) {
+    return gti(value, new FloatMatrix(rows, columns));
+    }
+
+    /** Test for "less than or equal" (in-place). */
+    public FloatMatrix lei(FloatMatrix other, FloatMatrix result) {
+    if (other.isScalar())
+    return lei(other.scalar(), result);
+
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) <= other.get(i) ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Test for "less than or equal" (in-place). */
+    public FloatMatrix lei(FloatMatrix other) {
+    return lei(other, this);
+    }
+
+    /** Test for "less than or equal". */
+    public FloatMatrix le(FloatMatrix other) {
+    return lei(other, new FloatMatrix(rows, columns));
+    }
+
+    /** Test for "less than or equal" against a scalar (in-place). */
+    public FloatMatrix lei(float value, FloatMatrix result) {
+    ensureResultLength(null, result);
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) <= value ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Test for "less than or equal" against a scalar (in-place). */
+    public FloatMatrix lei(float value) {
+    return lei(value, this);
+    }
+
+    /** test for "less than or equal" against a scalar. */
+    public FloatMatrix le(float value) {
+    return lei(value, new FloatMatrix(rows, columns));
+    }
+
+    /** Test for "greater than or equal" (in-place). */
+    public FloatMatrix gei(FloatMatrix other, FloatMatrix result) {
+    if (other.isScalar())
+    return gei(other.scalar(), result);
+
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) >= other.get(i) ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Test for "greater than or equal" (in-place). */
+    public FloatMatrix gei(FloatMatrix other) {
+    return gei(other, this);
+    }
+
+    /** Test for "greater than or equal". */
+    public FloatMatrix ge(FloatMatrix other) {
+    return gei(other, new FloatMatrix(rows, columns));
+    }
+
+    /** Test for "greater than or equal" against a scalar (in-place). */
+    public FloatMatrix gei(float value, FloatMatrix result) {
+    ensureResultLength(null, result);
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) >= value ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Test for "greater than or equal" against a scalar (in-place). */
+    public FloatMatrix gei(float value) {
+    return gei(value, this);
+    }
+
+    /** test for "greater than or equal" against a scalar. */
+    public FloatMatrix ge(float value) {
+    return gei(value, new FloatMatrix(rows, columns));
+    }
+
+    /** Test for equality (in-place). */
+    public FloatMatrix eqi(FloatMatrix other, FloatMatrix result) {
+    if (other.isScalar())
+    return eqi(other.scalar(), result);
+
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) == other.get(i) ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Test for equality (in-place). */
+    public FloatMatrix eqi(FloatMatrix other) {
+    return eqi(other, this);
+    }
+
+    /** Test for equality. */
+    public FloatMatrix eq(FloatMatrix other) {
+    return eqi(other, new FloatMatrix(rows, columns));
+    }
+
+    /** Test for equality against a scalar (in-place). */
+    public FloatMatrix eqi(float value, FloatMatrix result) {
+    ensureResultLength(null, result);
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) == value ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Test for equality against a scalar (in-place). */
+    public FloatMatrix eqi(float value) {
+    return eqi(value, this);
+    }
+
+    /** test for equality against a scalar. */
+    public FloatMatrix eq(float value) {
+    return eqi(value, new FloatMatrix(rows, columns));
+    }
+
+    /** Test for inequality (in-place). */
+    public FloatMatrix nei(FloatMatrix other, FloatMatrix result) {
+    if (other.isScalar())
+    return nei(other.scalar(), result);
+
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) != other.get(i) ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Test for inequality (in-place). */
+    public FloatMatrix nei(FloatMatrix other) {
+    return nei(other, this);
+    }
+
+    /** Test for inequality. */
+    public FloatMatrix ne(FloatMatrix other) {
+    return nei(other, new FloatMatrix(rows, columns));
+    }
+
+    /** Test for inequality against a scalar (in-place). */
+    public FloatMatrix nei(float value, FloatMatrix result) {
+    ensureResultLength(null, result);
+    for (int i = 0; i < length; i++)
+    result.put(i, get(i) != value ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Test for inequality against a scalar (in-place). */
+    public FloatMatrix nei(float value) {
+    return nei(value, this);
+    }
+
+    /** test for inequality against a scalar. */
+    public FloatMatrix ne(float value) {
+    return nei(value, new FloatMatrix(rows, columns));
+    }
+
+    /** Compute elementwise logical and (in-place). */
+    public FloatMatrix andi(FloatMatrix other, FloatMatrix result) {
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0f) & (other.get(i) != 0.0f) ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Compute elementwise logical and (in-place). */
+    public FloatMatrix andi(FloatMatrix other) {
+    return andi(other, this);
+    }
+
+    /** Compute elementwise logical and. */
+    public FloatMatrix and(FloatMatrix other) {
+    return andi(other, new FloatMatrix(rows, columns));
+    }
+
+    /** Compute elementwise logical and against a scalar (in-place). */
+    public FloatMatrix andi(float value, FloatMatrix result) {
+    ensureResultLength(null, result);
+    boolean val = (value != 0.0f);
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0f) & val ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Compute elementwise logical and against a scalar (in-place). */
+    public FloatMatrix andi(float value) {
+    return andi(value, this);
+    }
+
+    /** Compute elementwise logical and against a scalar. */
+    public FloatMatrix and(float value) {
+    return andi(value, new FloatMatrix(rows, columns));
+    }
+
+    /** Compute elementwise logical or (in-place). */
+    public FloatMatrix ori(FloatMatrix other, FloatMatrix result) {
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0f) | (other.get(i) != 0.0f) ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Compute elementwise logical or (in-place). */
+    public FloatMatrix ori(FloatMatrix other) {
+    return ori(other, this);
+    }
+
+    /** Compute elementwise logical or. */
+    public FloatMatrix or(FloatMatrix other) {
+    return ori(other, new FloatMatrix(rows, columns));
+    }
+
+    /** Compute elementwise logical or against a scalar (in-place). */
+    public FloatMatrix ori(float value, FloatMatrix result) {
+    ensureResultLength(null, result);
+    boolean val = (value != 0.0f);
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0f) | val ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Compute elementwise logical or against a scalar (in-place). */
+    public FloatMatrix ori(float value) {
+    return ori(value, this);
+    }
+
+    /** Compute elementwise logical or against a scalar. */
+    public FloatMatrix or(float value) {
+    return ori(value, new FloatMatrix(rows, columns));
+    }
+
+    /** Compute elementwise logical xor (in-place). */
+    public FloatMatrix xori(FloatMatrix other, FloatMatrix result) {
+    assertSameLength(other);
+    ensureResultLength(other, result);
+
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0f) ^ (other.get(i) != 0.0f) ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Compute elementwise logical xor (in-place). */
+    public FloatMatrix xori(FloatMatrix other) {
+    return xori(other, this);
+    }
+
+    /** Compute elementwise logical xor. */
+    public FloatMatrix xor(FloatMatrix other) {
+    return xori(other, new FloatMatrix(rows, columns));
+    }
+
+    /** Compute elementwise logical xor against a scalar (in-place). */
+    public FloatMatrix xori(float value, FloatMatrix result) {
+    ensureResultLength(null, result);
+    boolean val = (value != 0.0f);
+    for (int i = 0; i < length; i++)
+    result.put(i, (get(i) != 0.0f) ^ val ? 1.0f : 0.0f);
+    return result;
+    }
+
+    /** Compute elementwise logical xor against a scalar (in-place). */
+    public FloatMatrix xori(float value) {
+    return xori(value, this);
+    }
+
+    /** Compute elementwise logical xor against a scalar. */
+    public FloatMatrix xor(float value) {
+    return xori(value, new FloatMatrix(rows, columns));
+    }
+//RJPP-END--------------------------------------------------------------
+}
diff --git a/src/org/jblas/la/Geometry.java b/src/org/jblas/la/Geometry.java
new file mode 100644
index 0000000..89186df
--- /dev/null
+++ b/src/org/jblas/la/Geometry.java
@@ -0,0 +1,181 @@
+// --- 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.la;
+
+/**
+ * <p>General functions which are geometric in nature.</p>
+ * 
+ * <p>For example, computing all pairwise squared distances between all columns of a matrix.</p>
+ */
+public class Geometry {
+	
+	/**
+	 * <p>Compute the pairwise squared distances between all columns of the two
+	 * matrices.</p>
+	 * 
+	 * <p>An efficient way to do this is to observe that <i>(x-y)^2 = x^2 - 2xy - y^2</i>
+	 * and to then properly carry out the computation with matrices.</p>
+	 */
+	public static DoubleMatrix pairwiseSquaredDistances(DoubleMatrix X, DoubleMatrix Y) {
+		if (X.rows != Y.rows)
+			throw new IllegalArgumentException(
+					"Matrices must have same number of rows");
+	
+		DoubleMatrix XX = X.mul(X).columnSums();
+		DoubleMatrix YY = Y.mul(Y).columnSums();
+	
+		DoubleMatrix Z = X.transpose().mmul(Y);
+		Z.muli(-2.0); //Z.print();
+		Z.addiColumnVector(XX);
+		Z.addiRowVector(YY);
+	
+		return Z;
+	}
+
+        /** Center a vector (subtract mean from all elements (in-place). */
+	public static DoubleMatrix center(DoubleMatrix x) {
+		return x.subi(x.mean());
+	}
+	
+        /** Center the rows of a matrix (in-place). */
+	public static DoubleMatrix centerRows(DoubleMatrix x) {
+                DoubleMatrix temp = new DoubleMatrix(x.columns);
+		for (int r = 0; r < x.rows; r++)
+			x.putRow(r, center(x.getRow(r, temp)));
+		return x;
+	}
+	
+        /** Center the columns of a matrix (in-place). */
+	public static DoubleMatrix centerColumns(DoubleMatrix x) {
+                DoubleMatrix temp = new DoubleMatrix(x.rows);
+		for (int c = 0; c < x.columns; c++)
+			x.putColumn(c, center(x.getColumn(c, temp)));
+		return x;
+	}
+	
+        /** Normalize a vector (scale such that its Euclidean norm is 1) (in-place). */
+	public static DoubleMatrix normalize(DoubleMatrix x) {
+		return x.divi(x.norm2());
+	}
+
+        /** Normalize the rows of a matrix (in-place). */
+	public static DoubleMatrix normalizeRows(DoubleMatrix x) {
+                DoubleMatrix temp = new DoubleMatrix(x.columns);
+		for (int r = 0; r < x.rows; r++)
+			x.putRow(r, normalize(x.getRow(r, temp)));
+		return x;
+	}
+	
+        /** Normalize the columns of a matrix (in-place). */
+	public static DoubleMatrix normalizeColumns(DoubleMatrix x) {
+                DoubleMatrix temp = new DoubleMatrix(x.rows);
+		for (int c = 0; c < x.columns; c++)
+			x.putColumn(c, normalize(x.getColumn(c, temp)));
+		return x;
+	}
+
+//BEGIN
+  // The code below has been automatically generated.
+  // DO NOT EDIT!
+	
+	/**
+	 * <p>Compute the pairwise squared distances between all columns of the two
+	 * matrices.</p>
+	 * 
+	 * <p>An efficient way to do this is to observe that <i>(x-y)^2 = x^2 - 2xy - y^2</i>
+	 * and to then properly carry out the computation with matrices.</p>
+	 */
+	public static FloatMatrix pairwiseSquaredDistances(FloatMatrix X, FloatMatrix Y) {
+		if (X.rows != Y.rows)
+			throw new IllegalArgumentException(
+					"Matrices must have same number of rows");
+	
+		FloatMatrix XX = X.mul(X).columnSums();
+		FloatMatrix YY = Y.mul(Y).columnSums();
+	
+		FloatMatrix Z = X.transpose().mmul(Y);
+		Z.muli(-2.0f); //Z.print();
+		Z.addiColumnVector(XX);
+		Z.addiRowVector(YY);
+	
+		return Z;
+	}
+
+        /** Center a vector (subtract mean from all elements (in-place). */
+	public static FloatMatrix center(FloatMatrix x) {
+		return x.subi(x.mean());
+	}
+	
+        /** Center the rows of a matrix (in-place). */
+	public static FloatMatrix centerRows(FloatMatrix x) {
+                FloatMatrix temp = new FloatMatrix(x.columns);
+		for (int r = 0; r < x.rows; r++)
+			x.putRow(r, center(x.getRow(r, temp)));
+		return x;
+	}
+	
+        /** Center the columns of a matrix (in-place). */
+	public static FloatMatrix centerColumns(FloatMatrix x) {
+                FloatMatrix temp = new FloatMatrix(x.rows);
+		for (int c = 0; c < x.columns; c++)
+			x.putColumn(c, center(x.getColumn(c, temp)));
+		return x;
+	}
+	
+        /** Normalize a vector (scale such that its Euclidean norm is 1) (in-place). */
+	public static FloatMatrix normalize(FloatMatrix x) {
+		return x.divi(x.norm2());
+	}
+
+        /** Normalize the rows of a matrix (in-place). */
+	public static FloatMatrix normalizeRows(FloatMatrix x) {
+                FloatMatrix temp = new FloatMatrix(x.columns);
+		for (int r = 0; r < x.rows; r++)
+			x.putRow(r, normalize(x.getRow(r, temp)));
+		return x;
+	}
+	
+        /** Normalize the columns of a matrix (in-place). */
+	public static FloatMatrix normalizeColumns(FloatMatrix x) {
+                FloatMatrix temp = new FloatMatrix(x.rows);
+		for (int c = 0; c < x.columns; c++)
+			x.putColumn(c, normalize(x.getColumn(c, temp)));
+		return x;
+	}
+
+//END
+}
diff --git a/src/org/jblas/la/JavaBlas.java b/src/org/jblas/la/JavaBlas.java
new file mode 100644
index 0000000..f6184d8
--- /dev/null
+++ b/src/org/jblas/la/JavaBlas.java
@@ -0,0 +1,286 @@
+// --- 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 ---
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.jblas.la;
+
+import org.jblas.la.exceptions.LapackException;
+
+/**
+ * <p>Implementation of some Blas functions, mostly those which require linear runtime
+ * in the number of matrix elements. Because of the copying overhead when passing
+ * primitive arrays to native code, it doesn't make sense for these functions
+ * to be implemented in native code. The Java code is about as fast.</p>
+ * 
+ * <p>The same conventions were used as in the native code, that is, for each array
+ * you also pass an index pointing to the starting index.</p>
+ * 
+ * <p>These methods are mostly optimized for the case where the starting index is 0
+ * and the increment is 1.</p>
+ */
+public class JavaBlas {
+
+    /** Exchange two vectors. */
+    public static void rswap(int n, double[] dx, int dxIdx, int incx, double[] dy, int dyIdx, int incy) {
+        if (incx == 1 && incy == 1 && dxIdx == 0 && dyIdx == 0) {
+            double z;
+            for (int i = 0; i < n; i++) {
+                z = dx[i];
+                dx[i] = dy[i];
+                dy[i] = z;
+            }
+        } else {
+            double z;
+            for (int c = 0, xi = dxIdx, yi = dyIdx; c < n; xi += incx, yi += incy, c++) {
+                z = dx[xi];
+                dx[xi] = dy[yi];
+                dy[yi] = z;
+            }
+        }
+    }
+
+    /** Copy dx to dy. */
+    public static void rcopy(int n, double[] dx, int dxIdx, int incx, double[] dy, int dyIdx, int incy) {
+        if (dxIdx < 0 || dxIdx + (n - 1) * incx >= dx.length) {
+            throw new LapackException("Java.raxpy", "Parameters for x aren't valid! (n = " + n + ", dx.length = " + dx.length + ", dxIdx = " + dxIdx + ", incx = " + incx + ")");
+        }
+        if (dyIdx < 0 || dyIdx + (n - 1) * incy >= dy.length) {
+            throw new LapackException("Java.raxpy", "Parameters for y aren't valid! (n = " + n + ", dy.length = " + dy.length + ", dyIdx = " + dyIdx + ", incy = " + incy + ")");
+        }
+        if (incx == 1 && incy == 1) {
+            System.arraycopy(dx, dxIdx, dy, dyIdx, n);
+        } else {
+            for (int c = 0, xi = dxIdx, yi = dyIdx; c < n; xi += incx, yi += incy, c++) {
+                dy[yi] = dx[xi];
+            }
+        }
+    }
+
+    /** Compute dy <- da * dx + dy. */
+    public static void raxpy(int n, double da, double[] dx, int dxIdx, int incx, double[] dy, int dyIdx, int incy) {
+        if (dxIdx < 0 || dxIdx + (n - 1) * incx >= dx.length) {
+            throw new LapackException("Java.raxpy", "Parameters for x aren't valid! (n = " + n + ", dx.length = " + dx.length + ", dxIdx = " + dxIdx + ", incx = " + incx + ")");
+        }
+        if (dyIdx < 0 || dyIdx + (n - 1) * incy >= dy.length) {
+            throw new LapackException("Java.raxpy", "Parameters for y aren't valid! (n = " + n + ", dy.length = " + dy.length + ", dyIdx = " + dyIdx + ", incy = " + incy + ")");
+        }
+        
+        if (incx == 1 && incy == 1 && dxIdx == 0 && dyIdx == 0) {
+            if (da == 1.0) {
+                for (int i = 0; i < n; i++) {
+                    dy[i] += dx[i];
+                }
+            } else {
+                for (int i = 0; i < n; i++) {
+                    dy[i] += da * dx[i];
+                }
+            }
+        } else {
+            if (da == 1.0) {
+                for (int c = 0, xi = dxIdx, yi = dyIdx; c < n; c++, xi += incx, yi += incy) {
+                    dy[yi] += dx[xi];
+                }
+
+            } else {
+                for (int c = 0, xi = dxIdx, yi = dyIdx; c < n; c++, xi += incx, yi += incy) {
+                    dy[yi] += da * dx[xi];
+                }
+            }
+        }
+    }
+
+    /** Computes dz <- dx + dy */
+    public static void rzaxpy(int n, double[] dz, int dzIdx, int incz, double da, double[] dx, int dxIdx, int incx, double[] dy, int dyIdx, int incy) {
+        if (dxIdx == 0 && incx == 1 && dyIdx == 0 && incy == 1 && dzIdx == 0 && incz == 1) {
+            if (da == 1.0) {
+                for (int c = 0; c < n; c++)
+                    dz[c] = dx[c] + dy[c];
+            } else {
+                for (int c = 0; c < n; c++)
+                    dz[c] = da*dx[c] + dy[c];
+            }
+        } else {
+            if (da == 1.0) {
+                for (int c = 0, xi = dxIdx, yi = dyIdx, zi = dzIdx; c < n; c++, xi += incx, yi += incy, zi += incz) {
+                    dz[zi] = dx[xi] + dy[yi];
+                }
+            } else {
+                for (int c = 0, xi = dxIdx, yi = dyIdx, zi = dzIdx; c < n; c++, xi += incx, yi += incy, zi += incz) {
+                    dz[zi] = da*dx[xi] + dy[yi];
+                }
+            }
+        }
+    }
+
+    public static void rzgxpy(int n, double[] dz, double[] dx, double[] dy) {
+        for (int c = 0; c < n; c++)
+            dz[c] = dx[c] + dy[c];       
+    }
+
+    /** Compute scalar product between dx and dy. */
+    public static double rdot(int n, double[] dx, int dxIdx, int incx, double[] dy, int dyIdx, int incy) {
+        double s = 0.0;
+        if (incx == 1 && incy == 1 && dxIdx == 0 && dyIdx == 0) {
+            for (int i = 0; i < n; i++)
+                s += dx[i] * dy[i];
+        }
+        else {
+            for (int c = 0, xi = dxIdx, yi = dyIdx; c < n; c++, xi += incx, yi += incy) {
+                s += dx[xi] * dy[yi];
+            }
+        }
+        return s;
+    }
+//BEGIN
+  // The code below has been automatically generated.
+  // DO NOT EDIT!
+
+    /** Exchange two vectors. */
+    public static void rswap(int n, float[] dx, int dxIdx, int incx, float[] dy, int dyIdx, int incy) {
+        if (incx == 1 && incy == 1 && dxIdx == 0 && dyIdx == 0) {
+            float z;
+            for (int i = 0; i < n; i++) {
+                z = dx[i];
+                dx[i] = dy[i];
+                dy[i] = z;
+            }
+        } else {
+            float z;
+            for (int c = 0, xi = dxIdx, yi = dyIdx; c < n; xi += incx, yi += incy, c++) {
+                z = dx[xi];
+                dx[xi] = dy[yi];
+                dy[yi] = z;
+            }
+        }
+    }
+
+    /** Copy dx to dy. */
+    public static void rcopy(int n, float[] dx, int dxIdx, int incx, float[] dy, int dyIdx, int incy) {
+        if (dxIdx < 0 || dxIdx + (n - 1) * incx >= dx.length) {
+            throw new LapackException("Java.raxpy", "Parameters for x aren't valid! (n = " + n + ", dx.length = " + dx.length + ", dxIdx = " + dxIdx + ", incx = " + incx + ")");
+        }
+        if (dyIdx < 0 || dyIdx + (n - 1) * incy >= dy.length) {
+            throw new LapackException("Java.raxpy", "Parameters for y aren't valid! (n = " + n + ", dy.length = " + dy.length + ", dyIdx = " + dyIdx + ", incy = " + incy + ")");
+        }
+        if (incx == 1 && incy == 1) {
+            System.arraycopy(dx, dxIdx, dy, dyIdx, n);
+        } else {
+            for (int c = 0, xi = dxIdx, yi = dyIdx; c < n; xi += incx, yi += incy, c++) {
+                dy[yi] = dx[xi];
+            }
+        }
+    }
+
+    /** Compute dy <- da * dx + dy. */
+    public static void raxpy(int n, float da, float[] dx, int dxIdx, int incx, float[] dy, int dyIdx, int incy) {
+        if (dxIdx < 0 || dxIdx + (n - 1) * incx >= dx.length) {
+            throw new LapackException("Java.raxpy", "Parameters for x aren't valid! (n = " + n + ", dx.length = " + dx.length + ", dxIdx = " + dxIdx + ", incx = " + incx + ")");
+        }
+        if (dyIdx < 0 || dyIdx + (n - 1) * incy >= dy.length) {
+            throw new LapackException("Java.raxpy", "Parameters for y aren't valid! (n = " + n + ", dy.length = " + dy.length + ", dyIdx = " + dyIdx + ", incy = " + incy + ")");
+        }
+        
+        if (incx == 1 && incy == 1 && dxIdx == 0 && dyIdx == 0) {
+            if (da == 1.0f) {
+                for (int i = 0; i < n; i++) {
+                    dy[i] += dx[i];
+                }
+            } else {
+                for (int i = 0; i < n; i++) {
+                    dy[i] += da * dx[i];
+                }
+            }
+        } else {
+            if (da == 1.0f) {
+                for (int c = 0, xi = dxIdx, yi = dyIdx; c < n; c++, xi += incx, yi += incy) {
+                    dy[yi] += dx[xi];
+                }
+
+            } else {
+                for (int c = 0, xi = dxIdx, yi = dyIdx; c < n; c++, xi += incx, yi += incy) {
+                    dy[yi] += da * dx[xi];
+                }
+            }
+        }
+    }
+
+    /** Computes dz <- dx + dy */
+    public static void rzaxpy(int n, float[] dz, int dzIdx, int incz, float da, float[] dx, int dxIdx, int incx, float[] dy, int dyIdx, int incy) {
+        if (dxIdx == 0 && incx == 1 && dyIdx == 0 && incy == 1 && dzIdx == 0 && incz == 1) {
+            if (da == 1.0f) {
+                for (int c = 0; c < n; c++)
+                    dz[c] = dx[c] + dy[c];
+            } else {
+                for (int c = 0; c < n; c++)
+                    dz[c] = da*dx[c] + dy[c];
+            }
+        } else {
+            if (da == 1.0f) {
+                for (int c = 0, xi = dxIdx, yi = dyIdx, zi = dzIdx; c < n; c++, xi += incx, yi += incy, zi += incz) {
+                    dz[zi] = dx[xi] + dy[yi];
+                }
+            } else {
+                for (int c = 0, xi = dxIdx, yi = dyIdx, zi = dzIdx; c < n; c++, xi += incx, yi += incy, zi += incz) {
+                    dz[zi] = da*dx[xi] + dy[yi];
+                }
+            }
+        }
+    }
+
+    public static void rzgxpy(int n, float[] dz, float[] dx, float[] dy) {
+        for (int c = 0; c < n; c++)
+            dz[c] = dx[c] + dy[c];       
+    }
+
+    /** Compute scalar product between dx and dy. */
+    public static float rdot(int n, float[] dx, int dxIdx, int incx, float[] dy, int dyIdx, int incy) {
+        float s = 0.0f;
+        if (incx == 1 && incy == 1 && dxIdx == 0 && dyIdx == 0) {
+            for (int i = 0; i < n; i++)
+                s += dx[i] * dy[i];
+        }
+        else {
+            for (int c = 0, xi = dxIdx, yi = dyIdx; c < n; c++, xi += incx, yi += incy) {
+                s += dx[xi] * dy[yi];
+            }
+        }
+        return s;
+    }
+//END
+}
diff --git a/src/org/jblas/la/MatrixFunctions.java b/src/org/jblas/la/MatrixFunctions.java
new file mode 100644
index 0000000..a82b59b
--- /dev/null
+++ b/src/org/jblas/la/MatrixFunctions.java
@@ -0,0 +1,750 @@
+// --- 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.la;
+ 
+import java.lang.Math;
+
+/**
+ * This class provides the functions from java.lang.Math for matrices. The
+ * functions are applied to each element of the matrix.
+ * 
+ * @author Mikio Braun
+ */
+public class MatrixFunctions {
+
+	/*#
+	def mapfct(f); <<-EOS
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) #{f}(x.get(i)));
+	   return x;
+	   EOS
+  	end
+  	
+  	def cmapfct(f); <<-EOS
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, x.get(i).#{f}());
+	   return x;
+	   EOS
+  	end
+	#*/
+
+	/**
+	 * Sets all elements in this matrix to their absolute values. Note
+	 * that this operation is in-place.
+	 * @see MatrixFunctions#abs(DoubleMatrix)
+	 * @return this matrix
+	 */
+	public static DoubleMatrix absi(DoubleMatrix x) { 
+		/*# mapfct('Math.abs') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.abs(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	public static ComplexDoubleMatrix absi(ComplexDoubleMatrix x) {
+		/*# cmapfct('abs') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, x.get(i).abs());
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the trigonometric <i>arccosine</i> function element wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#acos(DoubleMatrix)
+	 * @return this matrix
+	 */
+	public static DoubleMatrix acosi(DoubleMatrix x) { 
+		/*# mapfct('Math.acos') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.acos(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the trigonometric <i>arcsine</i> function element wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#asin(DoubleMatrix)
+	 * @return this matrix
+	 */	
+	public static DoubleMatrix asini(DoubleMatrix x) { 
+		/*# mapfct('Math.asin') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.asin(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the trigonometric <i>arctangend</i> function element wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#atan(DoubleMatrix)
+	 * @return this matrix
+	 */		
+	public static DoubleMatrix atani(DoubleMatrix x) { 
+		/*# mapfct('Math.atan') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.atan(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the <i>cube root</i> function element wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#cbrt(DoubleMatrix)
+	 * @return this matrix
+	 */		
+	public static DoubleMatrix cbrti(DoubleMatrix x) { 
+		/*# mapfct('Math.cbrt') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.cbrt(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Element-wise round up by applying the <i>ceil</i> function on each 
+	 * element. Note that this is an in-place operation.
+	 * @see MatrixFunctions#ceil(DoubleMatrix)
+	 * @return this matrix
+	 */		
+	public static DoubleMatrix ceili(DoubleMatrix x) { 
+		/*# mapfct('Math.ceil') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.ceil(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the <i>cosine</i> function element-wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#cos(DoubleMatrix)
+	 * @return this matrix
+	 */
+	public static DoubleMatrix cosi(DoubleMatrix x) { 
+		/*# mapfct('Math.cos') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.cos(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the <i>hyperbolic cosine</i> function element-wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#cosh(DoubleMatrix)
+	 * @return this matrix
+	 */	
+	public static DoubleMatrix coshi(DoubleMatrix x) { 
+		/*# mapfct('Math.cosh') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.cosh(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the <i>exponential</i> function element-wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#exp(DoubleMatrix)
+	 * @return this matrix
+	 */		
+	public static DoubleMatrix expi(DoubleMatrix x) { 
+		/*# mapfct('Math.exp') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.exp(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Element-wise round down by applying the <i>floor</i> function on each 
+	 * element. Note that this is an in-place operation.
+	 * @see MatrixFunctions#floor(DoubleMatrix)
+	 * @return this matrix
+	 */		
+	public static DoubleMatrix floori(DoubleMatrix x) { 
+		/*# mapfct('Math.floor') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.floor(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the <i>natural logarithm</i> function element-wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#log(DoubleMatrix)
+	 * @return this matrix
+	 */		
+	public static DoubleMatrix logi(DoubleMatrix x) {
+		/*# mapfct('Math.log') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.log(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the <i>logarithm with basis to 10</i> element-wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#log10(DoubleMatrix)
+	 * @return this matrix
+	 */
+	public static DoubleMatrix log10i(DoubleMatrix x) {
+		/*# mapfct('Math.log10') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.log10(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Element-wise power function. Replaces each element with its
+	 * power of <tt>d</tt>.Note that this is an in-place operation.
+	 * @param d the exponent
+	 * @see MatrixFunctions#pow(DoubleMatrix,double)
+	 * @return this matrix
+	 */	
+	public static DoubleMatrix powi(DoubleMatrix x, double d) {
+		if (d == 2.0)
+			return x.muli(x);
+		else {
+			for (int i = 0; i < x.length; i++)
+				x.put(i, (double) Math.pow(x.get(i), d));
+			return x;
+		}
+	}
+
+    public static DoubleMatrix powi(double base, DoubleMatrix x) {
+        for (int i = 0; i < x.length; i++)
+            x.put(i, (double) Math.pow(base, x.get(i)));
+        return x;
+    }
+
+    public static DoubleMatrix powi(DoubleMatrix x, DoubleMatrix e) {
+        x.checkLength(e.length);
+        for (int i = 0; i < x.length; i++)
+            x.put(i, (double) Math.pow(x.get(i), e.get(i)));
+        return x;
+    }
+
+    public static DoubleMatrix signumi(DoubleMatrix x) {
+		/*# mapfct('Math.signum') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.signum(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	public static DoubleMatrix sini(DoubleMatrix x) { 
+		/*# mapfct('Math.sin') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.sin(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+
+	public static DoubleMatrix sinhi(DoubleMatrix x) { 
+		/*# mapfct('Math.sinh') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.sinh(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	public static DoubleMatrix sqrti(DoubleMatrix x) { 
+		/*# mapfct('Math.sqrt') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.sqrt(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	public static DoubleMatrix tani(DoubleMatrix x) {
+		/*# mapfct('Math.tan') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.tan(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	public static DoubleMatrix tanhi(DoubleMatrix x) {
+		/*# mapfct('Math.tanh') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (double) Math.tanh(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+
+	/**
+	 * Returns a copy of this matrix where all elements are set to their
+	 * absolute values. 
+	 * @see MatrixFunctions#absi(DoubleMatrix)
+	 * @return copy of this matrix
+	 */
+	public static DoubleMatrix abs(DoubleMatrix x) { return absi(x.dup()); }
+	
+	/**
+	 * Returns a copy of this matrix where the trigonometric <i>acos</i> function is applied
+	 * element wise.
+	 * @see MatrixFunctions#acosi(DoubleMatrix)
+	 * @return copy of this matrix
+	 */
+	public static DoubleMatrix acos(DoubleMatrix x)   { return acosi(x.dup()); }
+	public static DoubleMatrix asin(DoubleMatrix x)   { return asini(x.dup()); }
+	public static DoubleMatrix atan(DoubleMatrix x)   { return atani(x.dup()); }
+	public static DoubleMatrix cbrt(DoubleMatrix x)   { return cbrti(x.dup()); }
+    public static DoubleMatrix ceil(DoubleMatrix x)   { return ceili(x.dup()); }
+    public static DoubleMatrix cos(DoubleMatrix x)    { return cosi(x.dup()); }
+    public static DoubleMatrix cosh(DoubleMatrix x)   { return coshi(x.dup()); }
+    public static DoubleMatrix exp(DoubleMatrix x)    { return expi(x.dup()); }
+    public static DoubleMatrix floor(DoubleMatrix x)  { return floori(x.dup()); }
+    public static DoubleMatrix log(DoubleMatrix x)    { return logi(x.dup()); }
+    public static DoubleMatrix log10(DoubleMatrix x)  { return log10i(x.dup()); }
+    public static double pow(double x, double y) { return (double)Math.pow(x, y); }
+    public static DoubleMatrix pow(DoubleMatrix x, double e) { return powi(x.dup(), e); }
+    public static DoubleMatrix pow(double b, DoubleMatrix x) { return powi(b, x.dup()); }
+    public static DoubleMatrix pow(DoubleMatrix x, DoubleMatrix e) { return powi(x.dup(), e); }
+    public static DoubleMatrix signum(DoubleMatrix x) { return signumi(x.dup()); }
+    public static DoubleMatrix sin(DoubleMatrix x)    { return sini(x.dup()); }
+    public static DoubleMatrix sinh(DoubleMatrix x)   { return sinhi(x.dup()); }
+    public static DoubleMatrix sqrt(DoubleMatrix x)   { return sqrti(x.dup()); }
+    public static DoubleMatrix tan(DoubleMatrix x)    { return tani(x.dup()); }
+    public static DoubleMatrix tanh(DoubleMatrix x)   { return tanhi(x.dup()); }
+
+    /*# %w{abs acos asin atan cbrt ceil cos cosh exp floor log log10 signum sin sinh sqrt tan tanh}.map do |fct| <<-EOS
+    public static double #{fct}(double x) { return (double)Math.#{fct}(x); }
+    EOS
+        end   
+     #*/
+//RJPP-BEGIN------------------------------------------------------------
+    public static double abs(double x) { return (double)Math.abs(x); }
+    public static double acos(double x) { return (double)Math.acos(x); }
+    public static double asin(double x) { return (double)Math.asin(x); }
+    public static double atan(double x) { return (double)Math.atan(x); }
+    public static double cbrt(double x) { return (double)Math.cbrt(x); }
+    public static double ceil(double x) { return (double)Math.ceil(x); }
+    public static double cos(double x) { return (double)Math.cos(x); }
+    public static double cosh(double x) { return (double)Math.cosh(x); }
+    public static double exp(double x) { return (double)Math.exp(x); }
+    public static double floor(double x) { return (double)Math.floor(x); }
+    public static double log(double x) { return (double)Math.log(x); }
+    public static double log10(double x) { return (double)Math.log10(x); }
+    public static double signum(double x) { return (double)Math.signum(x); }
+    public static double sin(double x) { return (double)Math.sin(x); }
+    public static double sinh(double x) { return (double)Math.sinh(x); }
+    public static double sqrt(double x) { return (double)Math.sqrt(x); }
+    public static double tan(double x) { return (double)Math.tan(x); }
+    public static double tanh(double x) { return (double)Math.tanh(x); }
+//RJPP-END--------------------------------------------------------------
+    
+//BEGIN
+  // The code below has been automatically generated.
+  // DO NOT EDIT!
+
+	/*#
+	def mapfct(f); <<-EOS
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) #{f}(x.get(i)));
+	   return x;
+	   EOS
+  	end
+  	
+  	def cmapfct(f); <<-EOS
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, x.get(i).#{f}());
+	   return x;
+	   EOS
+  	end
+	#*/
+
+	/**
+	 * Sets all elements in this matrix to their absolute values. Note
+	 * that this operation is in-place.
+	 * @see MatrixFunctions#abs(FloatMatrix)
+	 * @return this matrix
+	 */
+	public static FloatMatrix absi(FloatMatrix x) { 
+		/*# mapfct('Math.abs') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.abs(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	public static ComplexFloatMatrix absi(ComplexFloatMatrix x) {
+		/*# cmapfct('abs') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, x.get(i).abs());
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the trigonometric <i>arccosine</i> function element wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#acos(FloatMatrix)
+	 * @return this matrix
+	 */
+	public static FloatMatrix acosi(FloatMatrix x) { 
+		/*# mapfct('Math.acos') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.acos(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the trigonometric <i>arcsine</i> function element wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#asin(FloatMatrix)
+	 * @return this matrix
+	 */	
+	public static FloatMatrix asini(FloatMatrix x) { 
+		/*# mapfct('Math.asin') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.asin(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the trigonometric <i>arctangend</i> function element wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#atan(FloatMatrix)
+	 * @return this matrix
+	 */		
+	public static FloatMatrix atani(FloatMatrix x) { 
+		/*# mapfct('Math.atan') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.atan(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the <i>cube root</i> function element wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#cbrt(FloatMatrix)
+	 * @return this matrix
+	 */		
+	public static FloatMatrix cbrti(FloatMatrix x) { 
+		/*# mapfct('Math.cbrt') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.cbrt(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Element-wise round up by applying the <i>ceil</i> function on each 
+	 * element. Note that this is an in-place operation.
+	 * @see MatrixFunctions#ceil(FloatMatrix)
+	 * @return this matrix
+	 */		
+	public static FloatMatrix ceili(FloatMatrix x) { 
+		/*# mapfct('Math.ceil') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.ceil(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the <i>cosine</i> function element-wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#cos(FloatMatrix)
+	 * @return this matrix
+	 */
+	public static FloatMatrix cosi(FloatMatrix x) { 
+		/*# mapfct('Math.cos') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.cos(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the <i>hyperbolic cosine</i> function element-wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#cosh(FloatMatrix)
+	 * @return this matrix
+	 */	
+	public static FloatMatrix coshi(FloatMatrix x) { 
+		/*# mapfct('Math.cosh') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.cosh(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the <i>exponential</i> function element-wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#exp(FloatMatrix)
+	 * @return this matrix
+	 */		
+	public static FloatMatrix expi(FloatMatrix x) { 
+		/*# mapfct('Math.exp') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.exp(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Element-wise round down by applying the <i>floor</i> function on each 
+	 * element. Note that this is an in-place operation.
+	 * @see MatrixFunctions#floor(FloatMatrix)
+	 * @return this matrix
+	 */		
+	public static FloatMatrix floori(FloatMatrix x) { 
+		/*# mapfct('Math.floor') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.floor(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the <i>natural logarithm</i> function element-wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#log(FloatMatrix)
+	 * @return this matrix
+	 */		
+	public static FloatMatrix logi(FloatMatrix x) {
+		/*# mapfct('Math.log') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.log(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Applies the <i>logarithm with basis to 10</i> element-wise on this
+	 * matrix. Note that this is an in-place operation.
+	 * @see MatrixFunctions#log10(FloatMatrix)
+	 * @return this matrix
+	 */
+	public static FloatMatrix log10i(FloatMatrix x) {
+		/*# mapfct('Math.log10') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.log10(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	/**
+	 * Element-wise power function. Replaces each element with its
+	 * power of <tt>d</tt>.Note that this is an in-place operation.
+	 * @param d the exponent
+	 * @see MatrixFunctions#pow(FloatMatrix,float)
+	 * @return this matrix
+	 */	
+	public static FloatMatrix powi(FloatMatrix x, float d) {
+		if (d == 2.0f)
+			return x.muli(x);
+		else {
+			for (int i = 0; i < x.length; i++)
+				x.put(i, (float) Math.pow(x.get(i), d));
+			return x;
+		}
+	}
+
+    public static FloatMatrix powi(float base, FloatMatrix x) {
+        for (int i = 0; i < x.length; i++)
+            x.put(i, (float) Math.pow(base, x.get(i)));
+        return x;
+    }
+
+    public static FloatMatrix powi(FloatMatrix x, FloatMatrix e) {
+        x.checkLength(e.length);
+        for (int i = 0; i < x.length; i++)
+            x.put(i, (float) Math.pow(x.get(i), e.get(i)));
+        return x;
+    }
+
+    public static FloatMatrix signumi(FloatMatrix x) {
+		/*# mapfct('Math.signum') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.signum(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	
+	public static FloatMatrix sini(FloatMatrix x) { 
+		/*# mapfct('Math.sin') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.sin(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+
+	public static FloatMatrix sinhi(FloatMatrix x) { 
+		/*# mapfct('Math.sinh') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.sinh(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	public static FloatMatrix sqrti(FloatMatrix x) { 
+		/*# mapfct('Math.sqrt') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.sqrt(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	public static FloatMatrix tani(FloatMatrix x) {
+		/*# mapfct('Math.tan') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.tan(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+	public static FloatMatrix tanhi(FloatMatrix x) {
+		/*# mapfct('Math.tanh') #*/
+//RJPP-BEGIN------------------------------------------------------------
+	   for (int i = 0; i < x.length; i++)
+	      x.put(i, (float) Math.tanh(x.get(i)));
+	   return x;
+//RJPP-END--------------------------------------------------------------
+	}
+
+	/**
+	 * Returns a copy of this matrix where all elements are set to their
+	 * absolute values. 
+	 * @see MatrixFunctions#absi(FloatMatrix)
+	 * @return copy of this matrix
+	 */
+	public static FloatMatrix abs(FloatMatrix x) { return absi(x.dup()); }
+	
+	/**
+	 * Returns a copy of this matrix where the trigonometric <i>acos</i> function is applied
+	 * element wise.
+	 * @see MatrixFunctions#acosi(FloatMatrix)
+	 * @return copy of this matrix
+	 */
+	public static FloatMatrix acos(FloatMatrix x)   { return acosi(x.dup()); }
+	public static FloatMatrix asin(FloatMatrix x)   { return asini(x.dup()); }
+	public static FloatMatrix atan(FloatMatrix x)   { return atani(x.dup()); }
+	public static FloatMatrix cbrt(FloatMatrix x)   { return cbrti(x.dup()); }
+    public static FloatMatrix ceil(FloatMatrix x)   { return ceili(x.dup()); }
+    public static FloatMatrix cos(FloatMatrix x)    { return cosi(x.dup()); }
+    public static FloatMatrix cosh(FloatMatrix x)   { return coshi(x.dup()); }
+    public static FloatMatrix exp(FloatMatrix x)    { return expi(x.dup()); }
+    public static FloatMatrix floor(FloatMatrix x)  { return floori(x.dup()); }
+    public static FloatMatrix log(FloatMatrix x)    { return logi(x.dup()); }
+    public static FloatMatrix log10(FloatMatrix x)  { return log10i(x.dup()); }
+    public static float pow(float x, float y) { return (float)Math.pow(x, y); }
+    public static FloatMatrix pow(FloatMatrix x, float e) { return powi(x.dup(), e); }
+    public static FloatMatrix pow(float b, FloatMatrix x) { return powi(b, x.dup()); }
+    public static FloatMatrix pow(FloatMatrix x, FloatMatrix e) { return powi(x.dup(), e); }
+    public static FloatMatrix signum(FloatMatrix x) { return signumi(x.dup()); }
+    public static FloatMatrix sin(FloatMatrix x)    { return sini(x.dup()); }
+    public static FloatMatrix sinh(FloatMatrix x)   { return sinhi(x.dup()); }
+    public static FloatMatrix sqrt(FloatMatrix x)   { return sqrti(x.dup()); }
+    public static FloatMatrix tan(FloatMatrix x)    { return tani(x.dup()); }
+    public static FloatMatrix tanh(FloatMatrix x)   { return tanhi(x.dup()); }
+
+    /*# %w{abs acos asin atan cbrt ceil cos cosh exp floor log log10 signum sin sinh sqrt tan tanh}.map do |fct| <<-EOS
+    public static float #{fct}(float x) { return (float)Math.#{fct}(x); }
+    EOS
+        end   
+     #*/
+//RJPP-BEGIN------------------------------------------------------------
+    public static float abs(float x) { return (float)Math.abs(x); }
+    public static float acos(float x) { return (float)Math.acos(x); }
+    public static float asin(float x) { return (float)Math.asin(x); }
+    public static float atan(float x) { return (float)Math.atan(x); }
+    public static float cbrt(float x) { return (float)Math.cbrt(x); }
+    public static float ceil(float x) { return (float)Math.ceil(x); }
+    public static float cos(float x) { return (float)Math.cos(x); }
+    public static float cosh(float x) { return (float)Math.cosh(x); }
+    public static float exp(float x) { return (float)Math.exp(x); }
+    public static float floor(float x) { return (float)Math.floor(x); }
+    public static float log(float x) { return (float)Math.log(x); }
+    public static float log10(float x) { return (float)Math.log10(x); }
+    public static float signum(float x) { return (float)Math.signum(x); }
+    public static float sin(float x) { return (float)Math.sin(x); }
+    public static float sinh(float x) { return (float)Math.sinh(x); }
+    public static float sqrt(float x) { return (float)Math.sqrt(x); }
+    public static float tan(float x) { return (float)Math.tan(x); }
+    public static float tanh(float x) { return (float)Math.tanh(x); }
+//RJPP-END--------------------------------------------------------------
+    
+//END
+}
diff --git a/src/org/jblas/la/SimpleBlas.java b/src/org/jblas/la/SimpleBlas.java
new file mode 100644
index 0000000..ff140fb
--- /dev/null
+++ b/src/org/jblas/la/SimpleBlas.java
@@ -0,0 +1,670 @@
+// --- 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.la;
+
+import org.jblas.la.exceptions.LapackException;
+import org.jblas.la.exceptions.LapackArgumentException;
+import org.jblas.core.ComplexDouble;
+import org.jblas.core.ComplexFloat;
+import org.jblas.la.exceptions.LapackConvergenceException;
+
+//import edu.ida.core.OutputValue;
+
+/**
+ * This class provides a cleaner direct interface to the BLAS routines by
+ * extracting the parameters of the matrices from the matrices itself.
+ * 
+ * For example, you can just pass the vector and do not have to pass the length,
+ * corresponding DoubleBuffer, offset and step size explicitly.
+ * 
+ * Currently, all the general matrix routines are implemented.
+ * 
+ */
+public class SimpleBlas {
+	/***************************************************************************
+	 * BLAS Level 1
+	 */
+
+	/** Compute x <-> y (swap two matrices) */
+	public static DoubleMatrix swap(DoubleMatrix x, DoubleMatrix y) {
+		//Blas.dswap(x.length, x.data, 0, 1, y.data, 0, 1);
+		JavaBlas.rswap(x.length, x.data, 0, 1, y.data, 0, 1);
+                return y;
+	}
+
+	/** Compute x <- alpha * x (scale a matrix) */
+	public static DoubleMatrix scal(double alpha, DoubleMatrix x) {
+		Blas.dscal(x.length, alpha, x.data, 0, 1);
+		return x;
+	}
+
+	public static ComplexDoubleMatrix scal(ComplexDouble alpha, ComplexDoubleMatrix x) {
+		Blas.zscal(x.length, alpha, x.data, 0, 1);
+		return x;
+	}
+		
+	/** Compute y <- x (copy a matrix) */
+	public static DoubleMatrix copy(DoubleMatrix x, DoubleMatrix y) {
+		//Blas.dcopy(x.length, x.data, 0, 1, y.data, 0, 1);
+                JavaBlas.rcopy(x.length, x.data, 0, 1, y.data, 0, 1);
+		return y;
+	}
+	
+	public static ComplexDoubleMatrix copy(ComplexDoubleMatrix x, ComplexDoubleMatrix y) {
+		Blas.zcopy(x.length, x.data, 0, 1, y.data, 0, 1);
+		return y;		
+	}
+	
+	/** Compute y <- alpha * x + y (elementwise addition) */
+	public static DoubleMatrix axpy(double da, DoubleMatrix dx, DoubleMatrix dy) {
+		//Blas.daxpy(dx.length, da, dx.data, 0, 1, dy.data, 0, 1);
+		JavaBlas.raxpy(dx.length, da, dx.data, 0, 1, dy.data, 0, 1);
+             
+		return dy;
+	}
+
+	public static ComplexDoubleMatrix axpy(ComplexDouble da, ComplexDoubleMatrix dx, ComplexDoubleMatrix dy) {
+		Blas.zaxpy(dx.length, da, dx.data, 0, 1, dy.data, 0, 1);
+		return dy;
+	}
+
+	/** Compute x^T * y (dot product) */
+	public static double dot(DoubleMatrix x, DoubleMatrix y) {
+		//return Blas.ddot(x.length, x.data, 0, 1, y.data, 0, 1);
+                return JavaBlas.rdot(x.length, x.data, 0, 1, y.data, 0, 1);
+	}
+
+	/** Compute x^T * y (dot product) */
+	public static ComplexDouble dotc(ComplexDoubleMatrix x, ComplexDoubleMatrix y) {
+		return Blas.zdotc(x.length, x.data, 0, 1, y.data, 0, 1);
+	}
+	
+	/** Compute x^T * y (dot product) */
+	public static ComplexDouble dotu(ComplexDoubleMatrix x, ComplexDoubleMatrix y) {
+		return Blas.zdotu(x.length, x.data, 0, 1, y.data, 0, 1);
+	}
+
+	/** Compute || x ||_2 (2-norm) */
+	public static double nrm2(DoubleMatrix x) {
+		return Blas.dnrm2(x.length, x.data, 0, 1);
+	}
+	
+	public static double nrm2(ComplexDoubleMatrix x) {
+		return Blas.dznrm2(x.length, x.data, 0, 1);
+	}
+
+	/** Compute || x ||_1 (1-norm, sum of absolute values) */
+	public static double asum(DoubleMatrix x) {
+		return Blas.dasum(x.length, x.data, 0, 1);
+	}
+
+	public static double asum(ComplexDoubleMatrix x) {
+		return Blas.dzasum(x.length, x.data, 0, 1);
+	}
+
+	/**
+	 * Compute index of element with largest absolute value (index of absolute
+	 * value maximum)
+	 */
+	public static int iamax(DoubleMatrix x) {
+		return Blas.idamax(x.length, x.data, 0, 1) - 1;
+	}
+
+	public static int iamax(ComplexDoubleMatrix x) {
+		return Blas.izamax(x.length, x.data, 0, 1);
+	}
+
+	/***************************************************************************
+	 * BLAS Level 2
+	 */
+
+	/**
+	 * Compute y <- alpha*op(a)*x + beta * y (general matrix vector
+	 * multiplication)
+	 */
+	public static DoubleMatrix gemv(double alpha, DoubleMatrix a,
+			DoubleMatrix x, double beta, DoubleMatrix y) {
+            if (false) {
+		Blas.dgemv('N', a.rows, a.columns, alpha, a.data, 0, a.rows, x.data, 0,
+				1, beta, y.data, 0, 1);
+            }
+            else {
+                if (beta == 0.0) {
+                    for (int i = 0; i < y.length; i++)
+                        y.data[i] = 0.0;
+                    
+                        for (int j = 0; j < a.columns; j++)
+                            for (int i = 0; i < a.rows; i++)
+                                y.data[i] += a.get(i, j) * x.get(j);
+                }
+                else {
+                     for (int j = 0; j < a.columns; j++)
+                         for (int i = 0; i < a.rows; i++)
+                              y.data[j] = a.get(i, j) * x.get(i) + y.data[j];                    
+                }
+            }
+	    return y;
+	}
+
+	/** Compute A <- alpha * x * y^T + A (general rank-1 update) */
+	public static DoubleMatrix ger(double alpha, DoubleMatrix x,
+			DoubleMatrix y, DoubleMatrix a) {
+		Blas.dger(a.rows, a.columns, alpha, x.data, 0, 1, y.data, 0, 1, a.data,
+				0, a.rows);
+		return a;
+	}
+
+	/** Compute A <- alpha * x * y^T + A (general rank-1 update) */
+	public static ComplexDoubleMatrix geru(ComplexDouble alpha, ComplexDoubleMatrix x,
+			ComplexDoubleMatrix y, ComplexDoubleMatrix a) {
+		Blas.zgeru(a.rows, a.columns, alpha, x.data, 0, 1, y.data, 0, 1, a.data,
+				0, a.rows);
+		return a;
+	}
+
+	/** Compute A <- alpha * x * y^H + A (general rank-1 update) */
+	public static ComplexDoubleMatrix gerc(ComplexDouble alpha, ComplexDoubleMatrix x,
+			ComplexDoubleMatrix y, ComplexDoubleMatrix a) {
+		Blas.zgerc(a.rows, a.columns, alpha, x.data, 0, 1, y.data, 0, 1, a.data,
+				0, a.rows);
+		return a;
+	}
+
+	/***************************************************************************
+	 * BLAS Level 3
+	 */
+
+	/**
+	 * Compute c <- a*b + beta * c (general matrix matrix
+	 * multiplication)
+	 */
+	public static DoubleMatrix gemm(double alpha, DoubleMatrix a,
+			DoubleMatrix b, double beta, DoubleMatrix c) {
+		Blas.dgemm('N', 'N', c.rows, c.columns, a.columns, alpha, a.data, 0,
+				a.rows, b.data, 0, b.rows, beta, c.data, 0, c.rows);
+		return c;
+	}
+
+	public static ComplexDoubleMatrix gemm(ComplexDouble alpha, ComplexDoubleMatrix a,
+			ComplexDoubleMatrix b, ComplexDouble beta, ComplexDoubleMatrix c) {
+		Blas.zgemm('N', 'N', c.rows, c.columns, a.columns, alpha, a.data, 0,
+				a.rows, b.data, 0, b.rows, beta, c.data, 0, c.rows);
+		return c;
+	}
+
+	/***************************************************************************
+	 * LAPACK
+	 */
+	public static DoubleMatrix gesv(DoubleMatrix a, int[] ipiv,
+			DoubleMatrix b) {
+		int info = Blas.dgesv(a.rows, b.columns, a.data, 0, a.rows, ipiv, 0,
+				b.data, 0, b.rows);
+		checkInfo("DGESV", info);
+
+		if (info > 0)
+			throw new LapackException("DGESV",
+					"Linear equation cannot be solved because the matrix was singular.");
+
+		return b;
+	}
+
+//STOP
+	private static void checkInfo(String name, int info) {
+		if (info < -1)
+			throw new LapackArgumentException(name, info);
+	}
+//START
+
+	public static DoubleMatrix sysv(char uplo, DoubleMatrix a, int[] ipiv,
+			DoubleMatrix b) {
+		int info = Blas.dsysv(uplo, a.rows, b.columns, a.data, 0, a.rows, ipiv, 0,
+				b.data, 0, b.rows);
+		checkInfo("DSYSV", info);
+
+		if (info > 0)
+			throw new IllegalArgumentException(
+					"Linear equation cannot be solved because the matrix was singular.");
+
+		return b;
+	}
+
+	public static int syev(char jobz, char uplo, DoubleMatrix a, DoubleMatrix w) {
+		double[] work = new double[1];
+		int info = Blas.dsyev(jobz, uplo, a.rows, a.data, 0, a.rows, w.data, 0,
+				work, 0, -1);
+		checkInfo("DSYEV", info);
+
+		int lwork = (int) work[0];
+		work = new double[lwork];
+
+		// System.out.println("Optimal LWORK = " + lwork);
+
+		info = Blas.dsyev(jobz, uplo, a.rows, a.data, 0, a.rows, w.data, 0,
+				work, 0, lwork);
+
+		if (info > 0)
+			throw new IllegalArgumentException(
+					"Eigenvalues could not be computed " + info
+							+ " off-diagonal elements did not converge");
+
+		return info;
+	}
+
+	public static int syevx(char jobz, char range, char uplo, DoubleMatrix a,
+			double vl, double vu, int il, int iu, double abstol,
+			DoubleMatrix w, DoubleMatrix z) {
+		int n = a.rows;
+		int[] iwork = new int[5 * n];
+		int[] ifail = new int[n];
+        int[] m = new int[1];
+        int info;
+
+		info = Blas.dsyevx(jobz, range, uplo, n, a.data, 0, a.rows, vl, vu, il,
+				iu, abstol, m, 0, w.data, 0, z.data, 0, z.rows, iwork, 0, ifail, 0);
+
+        //System.out.printf("found eigenvalues = %d\n", m[0]);
+
+		if (info > 0) {
+			StringBuilder msg = new StringBuilder();
+			msg
+					.append("Not all eigenvalues converged. Non-converging eigenvalues were: ");
+			for (int i = 0; i < info; i++) {
+				if (i > 0)
+					msg.append(", ");
+				msg.append(ifail[i]);
+			}
+			msg.append(".");
+			throw new IllegalArgumentException(msg.toString());
+		}
+
+		return info;
+	}
+
+	public static int syevd(char jobz, char uplo, DoubleMatrix A,
+			DoubleMatrix w) {
+		int n = A.rows;
+
+		int info = Blas.dsyevd(jobz, uplo, n, A.data, 0, A.rows, w.data, 0);
+
+		if (info > 0)
+			throw new LapackConvergenceException("SYEVD", "Not all eigenvalues converged.");
+
+		return info;
+	}
+
+    public static int syevr(char jobz, char range, char uplo, DoubleMatrix a,
+			double vl, double vu, int il, int iu, double abstol,
+			DoubleMatrix w, DoubleMatrix z, int[] isuppz) {
+		int n = a.rows;
+        int[] m = new int[1];
+
+		int info = Blas.dsyevr(jobz, range, uplo, n, a.data, 0, a.rows, vl, vu,
+                il, iu, abstol, m, 0, w.data, 0, z.data, 0, z.rows, isuppz, 0);
+
+        //System.out.printf("found eigenvalues = %d\n", m[0]);
+
+		checkInfo("SYEVR", info);
+
+		return info;
+	}
+
+	public static void posv(char uplo, DoubleMatrix A, DoubleMatrix B) {
+		int n = A.rows;
+		int nrhs = B.columns;
+		int info = Blas.dposv(uplo, n, nrhs, A.data, 0, A.rows, B.data, 0,
+				B.rows);
+		checkInfo("DPOSV", info);
+		if (info > 0)
+			throw new LapackException("DPOSV",
+					"Leading minor of order i of A is not positive definite.");
+	}
+        
+        public static int geev(char jobvl, char jobvr, DoubleMatrix A, 
+                DoubleMatrix WR, DoubleMatrix WI, DoubleMatrix VL, DoubleMatrix VR) {
+            int info = Blas.dgeev(jobvl, jobvr, A.rows, A.data, 0, A.rows, WR.data, 0, 
+                    WI.data, 0, VL.data, 0, VL.rows, VR.data, 0, VR.rows);
+            if (info > 0)
+                throw new LapackException("DGEEV", "First " + info + " eigenvalues have not converged.");
+            return info;
+        }
+
+//BEGIN
+  // The code below has been automatically generated.
+  // DO NOT EDIT!
+	/***************************************************************************
+	 * BLAS Level 1
+	 */
+
+	/** Compute x <-> y (swap two matrices) */
+	public static FloatMatrix swap(FloatMatrix x, FloatMatrix y) {
+		//Blas.sswap(x.length, x.data, 0, 1, y.data, 0, 1);
+		JavaBlas.rswap(x.length, x.data, 0, 1, y.data, 0, 1);
+                return y;
+	}
+
+	/** Compute x <- alpha * x (scale a matrix) */
+	public static FloatMatrix scal(float alpha, FloatMatrix x) {
+		Blas.sscal(x.length, alpha, x.data, 0, 1);
+		return x;
+	}
+
+	public static ComplexFloatMatrix scal(ComplexFloat alpha, ComplexFloatMatrix x) {
+		Blas.cscal(x.length, alpha, x.data, 0, 1);
+		return x;
+	}
+		
+	/** Compute y <- x (copy a matrix) */
+	public static FloatMatrix copy(FloatMatrix x, FloatMatrix y) {
+		//Blas.scopy(x.length, x.data, 0, 1, y.data, 0, 1);
+                JavaBlas.rcopy(x.length, x.data, 0, 1, y.data, 0, 1);
+		return y;
+	}
+	
+	public static ComplexFloatMatrix copy(ComplexFloatMatrix x, ComplexFloatMatrix y) {
+		Blas.ccopy(x.length, x.data, 0, 1, y.data, 0, 1);
+		return y;		
+	}
+	
+	/** Compute y <- alpha * x + y (elementwise addition) */
+	public static FloatMatrix axpy(float da, FloatMatrix dx, FloatMatrix dy) {
+		//Blas.saxpy(dx.length, da, dx.data, 0, 1, dy.data, 0, 1);
+		JavaBlas.raxpy(dx.length, da, dx.data, 0, 1, dy.data, 0, 1);
+             
+		return dy;
+	}
+
+	public static ComplexFloatMatrix axpy(ComplexFloat da, ComplexFloatMatrix dx, ComplexFloatMatrix dy) {
+		Blas.caxpy(dx.length, da, dx.data, 0, 1, dy.data, 0, 1);
+		return dy;
+	}
+
+	/** Compute x^T * y (dot product) */
+	public static float dot(FloatMatrix x, FloatMatrix y) {
+		//return Blas.sdot(x.length, x.data, 0, 1, y.data, 0, 1);
+                return JavaBlas.rdot(x.length, x.data, 0, 1, y.data, 0, 1);
+	}
+
+	/** Compute x^T * y (dot product) */
+	public static ComplexFloat dotc(ComplexFloatMatrix x, ComplexFloatMatrix y) {
+		return Blas.cdotc(x.length, x.data, 0, 1, y.data, 0, 1);
+	}
+	
+	/** Compute x^T * y (dot product) */
+	public static ComplexFloat dotu(ComplexFloatMatrix x, ComplexFloatMatrix y) {
+		return Blas.cdotu(x.length, x.data, 0, 1, y.data, 0, 1);
+	}
+
+	/** Compute || x ||_2 (2-norm) */
+	public static float nrm2(FloatMatrix x) {
+		return Blas.snrm2(x.length, x.data, 0, 1);
+	}
+	
+	public static float nrm2(ComplexFloatMatrix x) {
+		return Blas.scnrm2(x.length, x.data, 0, 1);
+	}
+
+	/** Compute || x ||_1 (1-norm, sum of absolute values) */
+	public static float asum(FloatMatrix x) {
+		return Blas.sasum(x.length, x.data, 0, 1);
+	}
+
+	public static float asum(ComplexFloatMatrix x) {
+		return Blas.scasum(x.length, x.data, 0, 1);
+	}
+
+	/**
+	 * Compute index of element with largest absolute value (index of absolute
+	 * value maximum)
+	 */
+	public static int iamax(FloatMatrix x) {
+		return Blas.isamax(x.length, x.data, 0, 1) - 1;
+	}
+
+	public static int iamax(ComplexFloatMatrix x) {
+		return Blas.icamax(x.length, x.data, 0, 1);
+	}
+
+	/***************************************************************************
+	 * BLAS Level 2
+	 */
+
+	/**
+	 * Compute y <- alpha*op(a)*x + beta * y (general matrix vector
+	 * multiplication)
+	 */
+	public static FloatMatrix gemv(float alpha, FloatMatrix a,
+			FloatMatrix x, float beta, FloatMatrix y) {
+            if (false) {
+		Blas.sgemv('N', a.rows, a.columns, alpha, a.data, 0, a.rows, x.data, 0,
+				1, beta, y.data, 0, 1);
+            }
+            else {
+                if (beta == 0.0f) {
+                    for (int i = 0; i < y.length; i++)
+                        y.data[i] = 0.0f;
+                    
+                        for (int j = 0; j < a.columns; j++)
+                            for (int i = 0; i < a.rows; i++)
+                                y.data[i] += a.get(i, j) * x.get(j);
+                }
+                else {
+                     for (int j = 0; j < a.columns; j++)
+                         for (int i = 0; i < a.rows; i++)
+                              y.data[j] = a.get(i, j) * x.get(i) + y.data[j];                    
+                }
+            }
+	    return y;
+	}
+
+	/** Compute A <- alpha * x * y^T + A (general rank-1 update) */
+	public static FloatMatrix ger(float alpha, FloatMatrix x,
+			FloatMatrix y, FloatMatrix a) {
+		Blas.sger(a.rows, a.columns, alpha, x.data, 0, 1, y.data, 0, 1, a.data,
+				0, a.rows);
+		return a;
+	}
+
+	/** Compute A <- alpha * x * y^T + A (general rank-1 update) */
+	public static ComplexFloatMatrix geru(ComplexFloat alpha, ComplexFloatMatrix x,
+			ComplexFloatMatrix y, ComplexFloatMatrix a) {
+		Blas.cgeru(a.rows, a.columns, alpha, x.data, 0, 1, y.data, 0, 1, a.data,
+				0, a.rows);
+		return a;
+	}
+
+	/** Compute A <- alpha * x * y^H + A (general rank-1 update) */
+	public static ComplexFloatMatrix gerc(ComplexFloat alpha, ComplexFloatMatrix x,
+			ComplexFloatMatrix y, ComplexFloatMatrix a) {
+		Blas.cgerc(a.rows, a.columns, alpha, x.data, 0, 1, y.data, 0, 1, a.data,
+				0, a.rows);
+		return a;
+	}
+
+	/***************************************************************************
+	 * BLAS Level 3
+	 */
+
+	/**
+	 * Compute c <- a*b + beta * c (general matrix matrix
+	 * multiplication)
+	 */
+	public static FloatMatrix gemm(float alpha, FloatMatrix a,
+			FloatMatrix b, float beta, FloatMatrix c) {
+		Blas.sgemm('N', 'N', c.rows, c.columns, a.columns, alpha, a.data, 0,
+				a.rows, b.data, 0, b.rows, beta, c.data, 0, c.rows);
+		return c;
+	}
+
+	public static ComplexFloatMatrix gemm(ComplexFloat alpha, ComplexFloatMatrix a,
+			ComplexFloatMatrix b, ComplexFloat beta, ComplexFloatMatrix c) {
+		Blas.cgemm('N', 'N', c.rows, c.columns, a.columns, alpha, a.data, 0,
+				a.rows, b.data, 0, b.rows, beta, c.data, 0, c.rows);
+		return c;
+	}
+
+	/***************************************************************************
+	 * LAPACK
+	 */
+	public static FloatMatrix gesv(FloatMatrix a, int[] ipiv,
+			FloatMatrix b) {
+		int info = Blas.sgesv(a.rows, b.columns, a.data, 0, a.rows, ipiv, 0,
+				b.data, 0, b.rows);
+		checkInfo("DGESV", info);
+
+		if (info > 0)
+			throw new LapackException("DGESV",
+					"Linear equation cannot be solved because the matrix was singular.");
+
+		return b;
+	}
+
+
+	public static FloatMatrix sysv(char uplo, FloatMatrix a, int[] ipiv,
+			FloatMatrix b) {
+		int info = Blas.ssysv(uplo, a.rows, b.columns, a.data, 0, a.rows, ipiv, 0,
+				b.data, 0, b.rows);
+		checkInfo("DSYSV", info);
+
+		if (info > 0)
+			throw new IllegalArgumentException(
+					"Linear equation cannot be solved because the matrix was singular.");
+
+		return b;
+	}
+
+	public static int syev(char jobz, char uplo, FloatMatrix a, FloatMatrix w) {
+		float[] work = new float[1];
+		int info = Blas.ssyev(jobz, uplo, a.rows, a.data, 0, a.rows, w.data, 0,
+				work, 0, -1);
+		checkInfo("DSYEV", info);
+
+		int lwork = (int) work[0];
+		work = new float[lwork];
+
+		// System.out.println("Optimal LWORK = " + lwork);
+
+		info = Blas.ssyev(jobz, uplo, a.rows, a.data, 0, a.rows, w.data, 0,
+				work, 0, lwork);
+
+		if (info > 0)
+			throw new IllegalArgumentException(
+					"Eigenvalues could not be computed " + info
+							+ " off-diagonal elements did not converge");
+
+		return info;
+	}
+
+	public static int syevx(char jobz, char range, char uplo, FloatMatrix a,
+			float vl, float vu, int il, int iu, float abstol,
+			FloatMatrix w, FloatMatrix z) {
+		int n = a.rows;
+		int[] iwork = new int[5 * n];
+		int[] ifail = new int[n];
+        int[] m = new int[1];
+        int info;
+
+		info = Blas.ssyevx(jobz, range, uplo, n, a.data, 0, a.rows, vl, vu, il,
+				iu, abstol, m, 0, w.data, 0, z.data, 0, z.rows, iwork, 0, ifail, 0);
+
+        //System.out.printf("found eigenvalues = %d\n", m[0]);
+
+		if (info > 0) {
+			StringBuilder msg = new StringBuilder();
+			msg
+					.append("Not all eigenvalues converged. Non-converging eigenvalues were: ");
+			for (int i = 0; i < info; i++) {
+				if (i > 0)
+					msg.append(", ");
+				msg.append(ifail[i]);
+			}
+			msg.append(".");
+			throw new IllegalArgumentException(msg.toString());
+		}
+
+		return info;
+	}
+
+	public static int syevd(char jobz, char uplo, FloatMatrix A,
+			FloatMatrix w) {
+		int n = A.rows;
+
+		int info = Blas.ssyevd(jobz, uplo, n, A.data, 0, A.rows, w.data, 0);
+
+		if (info > 0)
+			throw new LapackConvergenceException("SYEVD", "Not all eigenvalues converged.");
+
+		return info;
+	}
+
+    public static int syevr(char jobz, char range, char uplo, FloatMatrix a,
+			float vl, float vu, int il, int iu, float abstol,
+			FloatMatrix w, FloatMatrix z, int[] isuppz) {
+		int n = a.rows;
+        int[] m = new int[1];
+
+		int info = Blas.ssyevr(jobz, range, uplo, n, a.data, 0, a.rows, vl, vu,
+                il, iu, abstol, m, 0, w.data, 0, z.data, 0, z.rows, isuppz, 0);
+
+        //System.out.printf("found eigenvalues = %d\n", m[0]);
+
+		checkInfo("SYEVR", info);
+
+		return info;
+	}
+
+	public static void posv(char uplo, FloatMatrix A, FloatMatrix B) {
+		int n = A.rows;
+		int nrhs = B.columns;
+		int info = Blas.sposv(uplo, n, nrhs, A.data, 0, A.rows, B.data, 0,
+				B.rows);
+		checkInfo("DPOSV", info);
+		if (info > 0)
+			throw new LapackException("DPOSV",
+					"Leading minor of order i of A is not positive definite.");
+	}
+        
+        public static int geev(char jobvl, char jobvr, FloatMatrix A, 
+                FloatMatrix WR, FloatMatrix WI, FloatMatrix VL, FloatMatrix VR) {
+            int info = Blas.sgeev(jobvl, jobvr, A.rows, A.data, 0, A.rows, WR.data, 0, 
+                    WI.data, 0, VL.data, 0, VL.rows, VR.data, 0, VR.rows);
+            if (info > 0)
+                throw new LapackException("DGEEV", "First " + info + " eigenvalues have not converged.");
+            return info;
+        }
+
+//END
+}
diff --git a/src/org/jblas/la/Solve.java b/src/org/jblas/la/Solve.java
new file mode 100644
index 0000000..cf6830e
--- /dev/null
+++ b/src/org/jblas/la/Solve.java
@@ -0,0 +1,101 @@
+// --- 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.la;
+
+/**
+ * Solving linear equations.
+ */
+public class Solve {
+	/* Solves the linear equation A*X = B. */
+	public static DoubleMatrix solve(DoubleMatrix A, DoubleMatrix B) {
+		A.assertSquare();
+		DoubleMatrix X = B.dup();
+		int[] ipiv = new int[B.rows];
+		SimpleBlas.gesv(A.dup(), ipiv, X);
+		return X;
+	}
+
+	/* Solves the linear equation A*X = B for symmetric A. */
+	public static DoubleMatrix solveSymmetric(DoubleMatrix A, DoubleMatrix B) {
+		A.assertSquare();
+		DoubleMatrix X = B.dup();
+		int[] ipiv = new int[B.rows];
+		SimpleBlas.sysv('U', A.dup(), ipiv, X);
+		return X;
+	}
+
+	
+	/* Solves the linear equation A*X = B for symmetric and positive definite A. */
+	public static DoubleMatrix solvePositive(DoubleMatrix A, DoubleMatrix B) {
+		A.assertSquare();
+		DoubleMatrix X = B.dup();
+		SimpleBlas.posv('U', A.dup(), X);
+		return X;
+	}
+
+//BEGIN
+  // The code below has been automatically generated.
+  // DO NOT EDIT!
+	/* Solves the linear equation A*X = B. */
+	public static FloatMatrix solve(FloatMatrix A, FloatMatrix B) {
+		A.assertSquare();
+		FloatMatrix X = B.dup();
+		int[] ipiv = new int[B.rows];
+		SimpleBlas.gesv(A.dup(), ipiv, X);
+		return X;
+	}
+
+	/* Solves the linear equation A*X = B for symmetric A. */
+	public static FloatMatrix solveSymmetric(FloatMatrix A, FloatMatrix B) {
+		A.assertSquare();
+		FloatMatrix X = B.dup();
+		int[] ipiv = new int[B.rows];
+		SimpleBlas.sysv('U', A.dup(), ipiv, X);
+		return X;
+	}
+
+	
+	/* Solves the linear equation A*X = B for symmetric and positive definite A. */
+	public static FloatMatrix solvePositive(FloatMatrix A, FloatMatrix B) {
+		A.assertSquare();
+		FloatMatrix X = B.dup();
+		SimpleBlas.posv('U', A.dup(), X);
+		return X;
+	}
+
+//END
+}
diff --git a/src/org/jblas/la/Trigonometry.java b/src/org/jblas/la/Trigonometry.java
new file mode 100644
index 0000000..1ec4768
--- /dev/null
+++ b/src/org/jblas/la/Trigonometry.java
@@ -0,0 +1,67 @@
+// --- 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 ---
+
+/*
+ * jBLAS - Light-weight wrapper for ATLAS and LAPACK (http://www.jBLAS.org)
+ * 
+ * Copyright (C) 2008 jBLAS Project
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details:
+ * http://www.gnu.org/copyleft/lesser.html#TOC3
+ * 
+ * Created on May 25, 2008
+ * $Id$
+ */
+package org.jblas.la;
+
+/**
+ * Container for trigonometric functions on vectors and matrices.
+ * 
+ * @author Johannes Schaback, last edited by $Author$, $Date$
+ * @version $Revision$
+ */
+public class Trigonometry
+{
+ // yet to be filled
+}
diff --git a/src/org/jblas/la/exceptions/LapackArgumentException.java b/src/org/jblas/la/exceptions/LapackArgumentException.java
new file mode 100644
index 0000000..376bc68
--- /dev/null
+++ b/src/org/jblas/la/exceptions/LapackArgumentException.java
@@ -0,0 +1,52 @@
+// --- 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.la.exceptions;
+
+/**
+ * LapackException for a specific argument. LAPACK routines routinely check
+ * whether some arguments contain illegal arguments. This exception class
+ * automatically constructs a message for a given argument index.
+ */
+public class LapackArgumentException extends LapackException {
+    /** 
+     * Construct exception for given function and info. Message
+     * will read "Argument <info> had an illegal value.");
+     */
+	public LapackArgumentException(String function, int info) {
+		super(function, "Argument " + info + " had an illegal value.");
+	}
+}
diff --git a/src/org/jblas/la/exceptions/LapackConvergenceException.java b/src/org/jblas/la/exceptions/LapackConvergenceException.java
new file mode 100644
index 0000000..23b1703
--- /dev/null
+++ b/src/org/jblas/la/exceptions/LapackConvergenceException.java
@@ -0,0 +1,53 @@
+// --- 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 ---
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.jblas.la.exceptions;
+
+/**
+ *
+ * @author mikio
+ */
+public class LapackConvergenceException extends LapackException {
+  	public LapackConvergenceException(String function, String msg) {
+		super(function, msg);
+	}
+
+}
diff --git a/src/org/jblas/la/exceptions/LapackException.java b/src/org/jblas/la/exceptions/LapackException.java
new file mode 100644
index 0000000..5ebd04a
--- /dev/null
+++ b/src/org/jblas/la/exceptions/LapackException.java
@@ -0,0 +1,53 @@
+// --- 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.la.exceptions;
+
+/**
+ * Base class for all exceptions within LAPACK. Also reports the function where the
+ * error is.
+ */
+public class LapackException extends RuntimeException {
+        /** Construct new LapackException for the given function. */
+	public LapackException(String function) {
+		super("LAPACK " + function);
+	}
+	
+        /** Construct new Lapack Exception for the given function, with message. */
+	public LapackException(String function, String message) {
+		super("LAPACK " + function + ": " + message);
+	}
+}
diff --git a/src/org/jblas/la/exceptions/SizeException.java b/src/org/jblas/la/exceptions/SizeException.java
new file mode 100644
index 0000000..2287fa6
--- /dev/null
+++ b/src/org/jblas/la/exceptions/SizeException.java
@@ -0,0 +1,43 @@
+// --- 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.la.exceptions;
+
+public class SizeException extends RuntimeException {
+	public SizeException(String message) {
+		super(message);
+	}
+}
diff --git a/src/org/jblas/la/exceptions/package-info.java b/src/org/jblas/la/exceptions/package-info.java
new file mode 100644
index 0000000..13d918c
--- /dev/null
+++ b/src/org/jblas/la/exceptions/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * jblas related exceptions.
+ */
+
+package org.jblas.la.exceptions;
\ No newline at end of file
diff --git a/src/org/jblas/la/package-info.java b/src/org/jblas/la/package-info.java
new file mode 100644
index 0000000..34c96f9
--- /dev/null
+++ b/src/org/jblas/la/package-info.java
@@ -0,0 +1,42 @@
+// --- 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 ---
+
+/**
+ * Main linear algebra package.
+ * 
+ * This package contains the linear algebra packages from jBLAS.
+ */
+package org.jblas.la;
diff --git a/src/org/jblas/la/ranges/AllRange.java b/src/org/jblas/la/ranges/AllRange.java
new file mode 100644
index 0000000..101f5af
--- /dev/null
+++ b/src/org/jblas/la/ranges/AllRange.java
@@ -0,0 +1,85 @@
+// --- 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 ---
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.jblas.la.ranges;
+
+import org.jblas.la.*;
+
+/**
+ * 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++;
+    }
+    
+    public boolean hasMore() {
+        return value < upper;
+    }
+}
diff --git a/src/org/jblas/la/ranges/IndicesRange.java b/src/org/jblas/la/ranges/IndicesRange.java
new file mode 100644
index 0000000..fffa712
--- /dev/null
+++ b/src/org/jblas/la/ranges/IndicesRange.java
@@ -0,0 +1,95 @@
+// --- 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 ---
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.jblas.la.ranges;
+
+import org.jblas.la.*;
+
+/**
+ * Range which varies over pre-specified indices.
+ * 
+ * For example,
+ * <pre>
+ *     int[] indices = new int[] { 1, 1, 2, 3, 5, 8, 13 };
+ *     Range r = new IndicesRange(indices);</pre>
+ * ranges over the first few Fibonacci numbers.
+ */
+public class IndicesRange implements Range {
+    private int[] indices;
+    private int counter;
+        
+    /** Initialize from integer array. */
+    public IndicesRange(int[] is) {
+        indices = is;
+    }
+    
+    public void init(int l, int u) {
+        counter = 0;
+    }
+    
+    /** 
+     * Initialize from DoubleMatrix. Entries are converted to integers
+     * by truncation.
+     */
+    public IndicesRange(DoubleMatrix is) {
+        this(is.toIntArray());
+    }
+    
+    public int length() {
+        return indices.length;
+    }
+    
+    public void next() {
+        counter++;
+    }
+    
+    public int index() {
+        return counter;
+    }
+
+    public int value() {
+        return indices[counter];
+    }
+    
+    public boolean hasMore() {
+        return counter < indices.length;
+    }
+}
diff --git a/src/org/jblas/la/ranges/IntervalRange.java b/src/org/jblas/la/ranges/IntervalRange.java
new file mode 100644
index 0000000..909c639
--- /dev/null
+++ b/src/org/jblas/la/ranges/IntervalRange.java
@@ -0,0 +1,86 @@
+// --- 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 ---
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.jblas.la.ranges;
+
+/**
+ * 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 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 int length() {
+        return end - start + 1;
+    }
+
+    public void next() {
+        counter++;
+        value++;
+    }
+    
+    public int index() {
+        return counter;
+    }
+    
+    public int value() {
+        return value;
+    }
+
+    public boolean hasMore() {
+        return counter < end;
+    }
+}
diff --git a/src/org/jblas/la/ranges/PointRange.java b/src/org/jblas/la/ranges/PointRange.java
new file mode 100644
index 0000000..a14ec86
--- /dev/null
+++ b/src/org/jblas/la/ranges/PointRange.java
@@ -0,0 +1,79 @@
+// --- 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 ---
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.jblas.la.ranges;
+
+/**
+ * A PointRange is a range which only has a single point.
+ */
+public class PointRange implements Range {
+    private int value;
+    private boolean consumed; 
+
+    /** Construct a new PointRange with the one given index. */
+    public PointRange(int v) {
+        value = v;
+    }
+    
+    public void init(int l, int u) {
+        consumed = false;
+    }
+
+    public int length() {
+        return 1;
+    }
+    
+    public int value() {
+        return value;
+    }
+    
+    public int index() {
+        return 0;
+    }
+    
+    public void next() {
+        consumed = true;
+    }
+    
+    public boolean hasMore() {
+        return !consumed;
+    }
+}
diff --git a/src/org/jblas/la/ranges/Range.java b/src/org/jblas/la/ranges/Range.java
new file mode 100644
index 0000000..ef784b1
--- /dev/null
+++ b/src/org/jblas/la/ranges/Range.java
@@ -0,0 +1,77 @@
+// --- 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 ---
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.jblas.la.ranges;
+
+/**
+ * <p>The Range interface represents basically a set of indices. Before using a range
+ * you have to call init() with the actually available lower and upper bounds, such 
+ * that you can also have an "AllRange" which contains all possible indices.</p>
+ * 
+ * <p>Further operations include:</p>
+ * 
+ * <ul>
+ * <li> length() - returns total number of elements.
+ * <li> next() - increase counter (use value()) to retrieve the value.
+ * <li> index() - get the index of the current value.
+ * <li> value() - get the current value.
+ * <li> hasMore() - more indices available.
+ * </ul>
+ * 
+ * <p>Typical uses look like this:</p>
+ * <pre>    for (r.init(lower, upper); r.hasMore(); r.next()) {
+ *       System.out.printf("Value number %d is %d%n", index(), value());
+ *    }</pre>
+ */
+public interface Range {
+    /** Initialize Range to available indices */
+    public void init(int lower, int upper);
+    /** Total number of indices. */
+    public int length();
+    /** Increase counter. */
+    public void next();
+    /** Consecutive numbering of current index. */
+    public int index();
+    /** Get current index. */
+    public int value();
+    /** More indices available? */
+    public boolean hasMore();
+}
diff --git a/src/org/jblas/la/ranges/RangeUtils.java b/src/org/jblas/la/ranges/RangeUtils.java
new file mode 100644
index 0000000..7a5ece9
--- /dev/null
+++ b/src/org/jblas/la/ranges/RangeUtils.java
@@ -0,0 +1,86 @@
+// --- 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 ---
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.jblas.la.ranges;
+
+import org.jblas.la.*;
+import org.jblas.la.ranges.IndicesRange;
+import org.jblas.la.ranges.AllRange;
+
+/**
+ * A bunch of static functions for making construction of ranges more
+ * uniform. Basically, we have
+ * <ul>
+ * <li>point(3) - a PointRange.
+ * <li>indices(new int[] {1,2,3,...}) - a Indices Range.
+ * <li>interval(1, 2) - an interval range.
+ * <li>all() - an AllRange.
+ * <li>indices(x) - with a DoubleMatrix.
+ * <li>find(x) - an index constructed from the non-zero elements of x.
+ * </ul>
+ * 
+ */
+public class RangeUtils {
+    /** Construct point range (constant range) with given index. */
+    public static Range point(int i) {
+        return new PointRange(i);
+    }
+    
+    public static Range indices(int[] is) {
+        return new IndicesRange(is);
+    }
+    
+    public static Range interval(int a, int b) {
+        return new IntervalRange(a, b);
+    }
+    
+    public static Range all() {
+        return new AllRange();
+    }
+    
+    public static Range indices(DoubleMatrix is) {
+        return new IndicesRange(is);
+    }
+    
+    public static Range find(DoubleMatrix is) {
+        return new IndicesRange(is.findIndices());
+    }
+}
diff --git a/src/org/jblas/la/ranges/package-info.java b/src/org/jblas/la/ranges/package-info.java
new file mode 100644
index 0000000..2a9747b
--- /dev/null
+++ b/src/org/jblas/la/ranges/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * Provide ways to specify indices ranges.
+ */
+
+package org.jblas.la.ranges;
\ No newline at end of file
diff --git a/src/org/jblas/util/LibraryLoader.java b/src/org/jblas/util/LibraryLoader.java
new file mode 100644
index 0000000..91d73f3
--- /dev/null
+++ b/src/org/jblas/util/LibraryLoader.java
@@ -0,0 +1,111 @@
+// --- 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.util;
+
+import java.io.*;
+
+/**
+ * Class which allows to load a dynamic file as resource (for example, from a 
+ * jar-file)
+ */
+public class LibraryLoader {
+	/** 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().
+	 * 
+	 * I'm not quite sure if this doesn't open all kinds of security holes. Any ideas?
+	 * 
+	 * @param libname basename of the library
+	 */ 
+	public void loadLibrary(String libname) {
+		libname = System.mapLibraryName(libname);
+
+		// We're in a static initializer and need a class. What shall we do?
+		Class cl = getClass();
+
+		InputStream is = cl.getResourceAsStream("/" + libname);
+
+        // Hm, let's see if we can find it in the build directory 
+		if (is == null)
+			is = cl.getResourceAsStream("/bin/" + libname);
+
+		if (is == null) {
+			System.err.println("Couldn't find the resource " + libname + ".");
+			System.exit(0);
+		}
+
+		try {
+			File tempfile = File.createTempFile("jblas", libname);
+			tempfile.deleteOnExit();
+			OutputStream os = new FileOutputStream(tempfile);
+
+			System.out.println("tempfile.getPath() = " + tempfile.getPath());
+
+			long savedTime = System.currentTimeMillis();
+
+			byte buf[] = new byte[1024];
+			int len;
+			while ((len = is.read(buf)) > 0) {
+				os.write(buf, 0, len);
+			}
+
+			double seconds = (double) (System.currentTimeMillis() - savedTime) / 1e3;
+			System.out.println("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");
+		} catch (UnsatisfiedLinkError ule) {
+			System.err.println("Couldn't load copied link file: " + ule.toString() + ".\n");
+		}
+	}
+
+    /** Compute the path to the library. The path is basically
+        "/" + os.name + "/" + os.arch + "/" + libname. */
+    static public String libraryPath(String libname) {
+        return "/" + System.getProperty("os.name") + "/" + System.getProperty("os.arch") + "/" + libname;
+    }
+
+    static public void main(String[] args) {
+        System.out.println(libraryPath(""));
+    }
+}
diff --git a/src/org/jblas/util/package-info.java b/src/org/jblas/util/package-info.java
new file mode 100644
index 0000000..78d8641
--- /dev/null
+++ b/src/org/jblas/util/package-info.java
@@ -0,0 +1,42 @@
+// --- 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 ---
+
+/**
+ * Support classes for jBLAS.
+ *
+ * This package contains several support classes.
+ */
+package org.jblas.util;
diff --git a/src/overview.html b/src/overview.html
new file mode 100644
index 0000000..8ade4de
--- /dev/null
+++ b/src/overview.html
@@ -0,0 +1,90 @@
+<html><body><h1>jblas – Linear Algebra for Java</h1>
+<p><em>If you are really impatient, I’d suggest you read the Classes
+Overview below and otherwise stick to the <span class="caps">API</span> Documentation for the
+classes like <a href="org/jblas/la/DoubleMatrix.html">DoubleMatrix</a>.</em></p>
+<p>The main goals of jblas were to provide very high performance, close
+to what you get from state-of-the-art <span class="caps">BLAS</span> and <span class="caps">LAPACK</span> libraries, and
+easy of use, which means that in the ideal case, you can just
+mechanically translate a matrix expression from formulas to Java
+code.</p>
+<p>In all brevity, here is what you need to know to get started:</p>
+<ul>
+	<li>There exist four classes: <a href="org/jblas/la/ComplexFloatMatrix.html">FloatMatrix</a>, <a href="org/jblas/la/DoubleMatrix.html">DoubleMatrix</a>,
+  <a href="org/jblas/la/ComplexFloatMatrix.html">ComplexFloatMatrix</a> and <a href="org/jblas/la/ComplexDoubleMatrix.html">ComplexDoubleMatrix</a> in the package
+  org.jblas.la which represent real and complex matrices in single and
+  double precision.</li>
+</ul>
+<ul>
+	<li>Higher-level routines for solving equations, or computing
+  eigenvalues are grouped in classes like <a href="org/jblas/la/Eigen.html">Eigen</a>, <a href="org/jblas/la/Solve.html">Solve</a>, or <a href="org/jblas/la/Geometry.html">Geometry</a>.</li>
+</ul>
+<ul>
+	<li>To construct a new matrix, you can either use the constructor, or
+  one of the factory methods <code>ones</code> (constructs a matrix of all ones),
+  <code>zeros</code>, <code>rand</code> (entries uniformly distributed between 0 and 1),
+  <code>randn</code> (entries normally distributed), <code>eye</code> (unit matrix), <code>diag</code>
+  (matrix with given diagonal). Dimensions are specified in the order
+  “row”, “column”. The number of columns defaults to 1 if omitted
+  (meaning that you construct a row vector, if you supply just one
+  dimension).</li>
+</ul>
+<ul>
+	<li>To access elements, you use <code>put</code> and <code>get</code>. Methods also exist for
+  reading or writing a whole column, row, or submatrix.</li>
+</ul>
+<ul>
+	<li>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.</li>
+</ul>
+<ul>
+	<li>Every math operator maps to a short mnemonic name. For example, +
+  becomes <code>add</code>, – becomes <code>sub</code>, * becomes <code>mul</code>, / becomes <code>div</code>,
+  and so on.</li>
+</ul>
+<ul>
+	<li>Often, you can pass a double or float value, or a matric with only
+  one element as the argument to a method, for example, to add the
+  same value to all elements of the matrix.</li>
+</ul>
+<ul>
+	<li><code>mul</code> is element-wise multiplication. Matrix-matrix multiplication
+  is called <code>mmul</code>.</li>
+</ul>
+<ul>
+	<li>Often, you can add an “i” to a method to have it work “in-place”. For
+  example, <code>addi</code> is like <code>+=</code>.</li>
+</ul>
+<p>What is missing right now:</p>
+<ul>
+	<li>Right now, the four classes more or less exist next to each other,
+  with no abstract superclass. This makes the classes pretty
+  straightforward, but the downside is that you cannot have a function
+  which works with any kind of matrices.</li>
+</ul>
+<ul>
+	<li>No support for sparse matrices.</li>
+</ul>
+<ul>
+	<li>Not all of <span class="caps">LAPACK</span> is covered, only things I’m using myself. In
+  principle, there is little overhead in adding further functions as
+  the generation of wrappers is automatic, but I’d rather include a
+  function from <span class="caps">LAPACK</span> only after I’m sure it does what it’s supposed
+  to do. In other words, I’ll happily add anything somebody needs as
+  long as he can check whether the method works as it should.</li>
+</ul>
+<ul>
+	<li>Build only works for Windows (XP) with Cygwin and Linux. Mac OS X
+  would be most welcome, but I don’t have access to such a machine.</li>
+</ul>
+<ul>
+	<li>jblas uses double and float arrays to store the matrix. Whenever you
+  call a native function, the array is first copied. This means that
+  it doesn’t make much sense to call a native routine if its
+  computation is linear in the size of the data, but this includes
+  most of <span class="caps">BLAS</span> Level 1 and Level 2. jblas therefore uses Java
+  implementation for things like vector addition, or even
+  matrix-vector multiplication and is therefore not as fast as native
+  <span class="caps">BLAS</span>. Currently, I’m contemplating some caching schemes to improve
+  performance here.</li>
+</ul></body></html>
\ No newline at end of file
diff --git a/src/overview.textile b/src/overview.textile
new file mode 100644
index 0000000..500191b
--- /dev/null
+++ b/src/overview.textile
@@ -0,0 +1,80 @@
+h1. jblas - Linear Algebra for Java
+
+<em>If you are really impatient, I'd suggest you read the Classes
+Overview below and otherwise stick to the API Documentation for the
+classes like DoubleMatrix.</em>
+
+The main goals of jblas were to provide very high performance, close
+to what you get from state-of-the-art BLAS and LAPACK libraries, and
+easy of use, which means that in the ideal case, you can just
+mechanically translate a matrix expression from formulas to Java
+code. 
+
+In all brevity, here is what you need to know to get started:
+
+* There exist four classes: FloatMatrix, DoubleMatrix,
+  ComplexFloatMatrix and ComplexDoubleMatrix in the package
+  org.jblas.la which represent real and complex matrices in single and
+  double precision.
+
+* Higher-level routines for solving equations, or computing
+  eigenvalues are grouped in classes like Eigen, Solve, or Geometry.
+
+* To construct a new matrix, you can either use the constructor, or
+  one of the factory methods @ones@ (constructs a matrix of all ones),
+  @zeros@, @rand@ (entries uniformly distributed between 0 and 1),
+  @randn@ (entries normally distributed), @eye@ (unit matrix), @diag@
+  (matrix with given diagonal). Dimensions are specified in the order
+  "row", "column". The number of columns defaults to 1 if omitted
+  (meaning that you construct a row vector, if you supply just one
+  dimension).
+
+* To access elements, you use @put@ and @get at . Methods also exist for
+  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.
+
+* Every math operator maps to a short mnemonic name. For example, +
+  becomes @add@, - becomes @sub@, * becomes @mul@, / becomes @div@,
+  and so on.
+
+* Often, you can pass a double or float value, or a matric with only
+  one element as the argument to a method, for example, to add the
+  same value to all elements of the matrix.
+
+* @mul@ is element-wise multiplication. Matrix-matrix multiplication
+  is called @mmul at .
+
+* Often, you can add an "i" to a method to have it work "in-place". For
+  example, @addi@ is like @+=@.
+
+What is missing right now:
+
+* Right now, the four classes more or less exist next to each other,
+  with no abstract superclass. This makes the classes pretty
+  straightforward, but the downside is that you cannot have a function
+  which works with any kind of matrices.
+
+* No support for sparse matrices.
+
+* Not all of LAPACK is covered, only things I'm using myself. In
+  principle, there is little overhead in adding further functions as
+  the generation of wrappers is automatic, but I'd rather include a
+  function from LAPACK only after I'm sure it does what it's supposed
+  to do. In other words, I'll happily add anything somebody needs as
+  long as he can check whether the method works as it should.
+
+* Build only works for Windows (XP) with Cygwin and Linux. Mac OS X
+  would be most welcome, but I don't have access to such a machine.
+
+* jblas uses double and float arrays to store the matrix. Whenever you
+  call a native function, the array is first copied. This means that
+  it doesn't make much sense to call a native routine if its
+  computation is linear in the size of the data, but this includes
+  most of BLAS Level 1 and Level 2. jblas therefore uses Java
+  implementation for things like vector addition, or even
+  matrix-vector multiplication and is therefore not as fast as native
+  BLAS. Currently, I'm contemplating some caching schemes to improve
+  performance here.
\ No newline at end of file
diff --git a/test/org/jblas/core/Dynamic.java b/test/org/jblas/core/Dynamic.java
new file mode 100644
index 0000000..76feaf6
--- /dev/null
+++ b/test/org/jblas/core/Dynamic.java
@@ -0,0 +1,49 @@
+// --- 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.core;
+
+public class Dynamic {
+	public static native void hello();
+	
+	public static void main(String[] args) {
+		System.out.println("trying to load library");
+		System.loadLibrary("Dynamic");
+		System.out.println("done");
+		hello();
+		System.out.println("done calling hello");
+	}
+}
diff --git a/test/org/jblas/core/TestComplexFloat.java b/test/org/jblas/core/TestComplexFloat.java
new file mode 100644
index 0000000..cc19d09
--- /dev/null
+++ b/test/org/jblas/core/TestComplexFloat.java
@@ -0,0 +1,80 @@
+// --- 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.core;
+
+import org.jblas.core.ComplexFloat;
+import junit.framework.TestCase;
+
+public class TestComplexFloat extends TestCase {
+    public TestComplexFloat() {
+    }
+
+	private ComplexFloat a, b;
+	
+	public void setUp() {
+		a = new ComplexFloat(1, 2);
+		b = new ComplexFloat(3, 4);
+	}
+	
+	public void testAdd() {
+		ComplexFloat c = a.add(b);
+		
+		assertEquals(4.0f, c.real());
+		assertEquals(6.0f, c.imag());
+	}
+
+	public void testMul() {
+		ComplexFloat c = a.mul(b);
+		
+		assertEquals(-5.0f, c.real());
+		assertEquals(10.0f, c.imag());
+	}
+	
+	public void testMulAndDiv() {
+		ComplexFloat d = a.mul(b).div(b);
+		
+		assertEquals(new ComplexFloat(1.0f, 2.0f), d);
+		
+		d = a.mul(b).mul(b.inv());
+
+		assertEquals(new ComplexFloat(1.0f, 2.0f), d);
+	}
+	
+	public void testDivByZero() {
+		a.div(new ComplexFloat(0.0f, 0.0f));
+	}
+}
diff --git a/test/org/jblas/la/BenchmarkAccess.java b/test/org/jblas/la/BenchmarkAccess.java
new file mode 100644
index 0000000..df2b985
--- /dev/null
+++ b/test/org/jblas/la/BenchmarkAccess.java
@@ -0,0 +1,89 @@
+// --- 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.la;
+
+import junit.framework.TestCase;
+
+import static org.jblas.la.TicToc.*;
+
+public class BenchmarkAccess extends TestCase {
+	public void testArrayVsDirectBuffer() {
+		System.out.println("Testing array access versus direct buffer access");
+		
+		int SIZE = 100;
+		int ITERS = 10000000;
+		DoubleMatrix ma = new DoubleMatrix(1, SIZE);
+		double[] aa = new double[SIZE];
+		DoubleMatrix mb = new DoubleMatrix(1, SIZE);
+		double[] ab = new double[SIZE];
+		
+		tic("double[]:");
+		for (int j = 0; j < ITERS; j++)
+			for (int i = 0; i < SIZE; i++) {
+				aa[i] = ab[i];
+			}
+		toc();
+		
+		/*tic("DoubleBuffer.put()");
+		for (int j = 0; j < ITERS; j++)
+			for (int i = 0; i < SIZE; i++) {
+				mb.data.put(i, ma.data.get(i));
+			}
+		toc();*/
+
+		tic("DoubleMatrix.put()");
+		for (int j = 0; j < ITERS; j++)
+			for (int i = 0; i < SIZE; i++) {
+				mb.put(i, ma.get(i));
+			}
+		toc();
+		
+		tic("DoubleMatrix.put() (two-dim)");
+		for (int j = 0; j < ITERS; j++)
+			for (int i = 0; i < SIZE; i++) {
+				mb.put(0, i, ma.get(0, i));
+			}
+		toc();
+		
+		tic("Blas.dcopy");
+		for (int j = 0; j < ITERS; j++)
+			Blas.dcopy(SIZE, mb.data, 0, 1, ma.data, 0, 1);
+		toc();
+		
+		System.out.println("Done");
+	}
+}
diff --git a/test/org/jblas/la/BenchmarkComplex.java b/test/org/jblas/la/BenchmarkComplex.java
new file mode 100644
index 0000000..5958452
--- /dev/null
+++ b/test/org/jblas/la/BenchmarkComplex.java
@@ -0,0 +1,79 @@
+// --- 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.la;
+
+import org.jblas.la.ComplexDoubleMatrix;
+import junit.framework.TestCase;
+import static org.jblas.la.TicToc.*;
+
+public class BenchmarkComplex extends TestCase {
+    public void testMul() {
+        int ITERS = 50000;
+        int SIZE = 100;
+        ComplexDoubleMatrix A = new ComplexDoubleMatrix(SIZE, SIZE);
+        ComplexDoubleMatrix B = new ComplexDoubleMatrix(SIZE, SIZE);
+        ComplexDoubleMatrix C = new ComplexDoubleMatrix(SIZE, SIZE);
+        
+        tic("Multiplying two matrices %d times", ITERS);
+        for (int i = 0; i < ITERS; i++)
+            A.muli(B, C);
+        printMflops(6L*SIZE*SIZE*ITERS, toc());
+        
+        tic("Doing it with temp variables");
+        for (int i = 0; i < ITERS; i++)
+            for (int j = 0; j < A.length; j++)
+                C.put(j, A.get(j).mul(B.get(j)));
+        printMflops(6L*SIZE*SIZE*ITERS, toc());
+        
+        tic("Doing it by hand");
+        for (int i = 0; i < ITERS; i++)
+            for (int j = 0; j < 2*A.length; j+=2) {
+                double ar = A.data[j], ai = A.data[j+1];
+                double br = B.data[j], bi = B.data[j+1];
+                double cr = ar * br - ai * bi;
+                double ci = ar * bi + ai * br;
+                C.data[j] = cr;
+                C.data[j+1] = ci;
+            }
+        printMflops(6L*SIZE*SIZE*ITERS, toc());
+    }
+    
+    private void printMflops(long ops, double time) {
+        System.out.printf("  [INFO] %.3f MFLOPS (%.1f million operations)\n", ops / time / 1e6d, ops / 1e6d);        
+    }
+
+}
diff --git a/test/org/jblas/la/BenchmarkElementwise.java b/test/org/jblas/la/BenchmarkElementwise.java
new file mode 100644
index 0000000..283056d
--- /dev/null
+++ b/test/org/jblas/la/BenchmarkElementwise.java
@@ -0,0 +1,99 @@
+// --- 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.la;
+
+import junit.framework.TestCase;
+import static org.jblas.la.TicToc.*;
+import static org.jblas.la.DoubleMatrix.*;
+
+public class BenchmarkElementwise extends TestCase {
+	public void testMuli() {
+		int SIZE = 1000;
+		int ITERS = 1000000;
+		DoubleMatrix x = rand(SIZE);
+		DoubleMatrix y = rand(SIZE);
+		DoubleMatrix z = zeros(SIZE);
+		
+		tic("muli():");
+		for (int i = 0; i < ITERS; i++)
+			x.muli(y, z);
+		toc();
+
+		double xa[]= new double[SIZE];
+		double ya[]= new double[SIZE];
+		double za[]= new double[SIZE];
+		
+		tic("muli (array):");
+		for (int i = 0; i < ITERS; i++)
+			for (int j = 0; j < SIZE; j++)
+				za[j] = xa[j] * ya[j];
+		toc();
+
+		/*tic("muli (double buffer:");
+		for (int i = 0; i < ITERS; i++)
+			for (int j = 0; j < SIZE; j++)
+				z.data.put(j, x.data.get(j) * y.data.get(j));
+		toc();*/
+		
+		tic("divi():");
+		for (int i = 0; i < ITERS/10; i++)
+			x.divi(y, z);
+		toc();
+
+		tic("addi():");
+		for (int i = 0; i < ITERS; i++)
+			x.addi(y, z);
+		toc();
+
+		tic("addi() array:");
+		for (int i = 0; i < ITERS; i++)
+			for (int j = 0; j < SIZE; j++)
+				za[j] = xa[j] + ya[j];
+		toc();
+
+		/*tic("addi() doublebuffer:");
+		for (int i = 0; i < ITERS; i++)
+			for (int j = 0; j < SIZE; j++)
+				z.data.put(j, x.data.get(j) + y.data.get(j));
+		toc();*/
+		
+		tic("subi():");
+		for (int i = 0; i < ITERS; i++)
+			x.subi(y, z);
+		toc();
+	}
+}
diff --git a/test/org/jblas/la/BenchmarkMatrix.java b/test/org/jblas/la/BenchmarkMatrix.java
new file mode 100644
index 0000000..0676f49
--- /dev/null
+++ b/test/org/jblas/la/BenchmarkMatrix.java
@@ -0,0 +1,164 @@
+// --- 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 ---
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.jblas.la;
+
+import org.jblas.la.SimpleBlas;
+import org.jblas.la.DoubleMatrix;
+import org.jblas.la.FloatMatrix;
+import junit.framework.TestCase;
+
+import static org.jblas.la.TicToc.*;
+
+/**
+ *
+ * @author mikio
+ */
+public class BenchmarkMatrix extends TestCase {
+    
+    private void printMflops(long ops, double time) {
+        System.out.printf("  [INFO] %.3f MFLOPS (%.1f million operations)\n", ops / time / 1e6d, ops / 1e6d);        
+    }
+    
+    public void setUp() {
+    }
+    
+    public void testBenchmarkMMulDouble() {
+        final int n = 1000;
+        DoubleMatrix x, y, z;
+        x = DoubleMatrix.randn(n, n);
+        y = DoubleMatrix.randn(n, n);
+        z = DoubleMatrix.randn(n, n);        
+
+        double time;
+        
+        tic("Multiplying DOUBLE matrices of size %d", n);
+        SimpleBlas.gemm(1.0, x, y, 0.0, z);
+        time = toc();
+        
+        long ops = 2L*n*n*n;
+        printMflops(ops, time);
+    }
+
+    public void testBenchmarkMMulFloat()  {
+        final int n = 1000;
+        FloatMatrix x = FloatMatrix.randn(n, n);
+        FloatMatrix y = FloatMatrix.randn(n, n);
+        FloatMatrix z = FloatMatrix.randn(n, n);
+        double time;
+        
+        tic("Multiplying FLOAT matrices of size %d", n);
+        SimpleBlas.gemm(1.0f, x, y, 0.0f, z);
+        printMflops(2L*n*n*n, toc());
+    }
+    
+    public void testBenchmarkAxpyAndDot() {
+        final int n = 10000;
+        final int ITERS = 10000;
+        DoubleMatrix x = DoubleMatrix.randn(n);
+        DoubleMatrix y = DoubleMatrix.randn(n);
+        
+        tic("Doing axpy with %d elements %d times", n, ITERS);
+        for (int i = 0; i < ITERS; i++)
+            SimpleBlas.axpy(1.0, x, y);
+        printMflops(n * ITERS, toc());
+
+        tic("Doing dot with %d elements %d times", n, ITERS);
+        for (int i = 0; i < ITERS; i++)
+            SimpleBlas.dot(x, y);
+        printMflops(n * ITERS, toc());
+    }    
+
+    public void testBenchmarkAxpyAndDotFloat() {
+        final int n = 10000;
+        final int ITERS = 10000;
+        FloatMatrix x = FloatMatrix.randn(n);
+        FloatMatrix y = FloatMatrix.randn(n);
+        
+        tic("Doing FLOAT axpy with %d elements %d times", n, ITERS);
+        for (int i = 0; i < ITERS; i++)
+            SimpleBlas.axpy(1.0f, x, y);
+        printMflops(n * ITERS, toc());
+
+        tic("Doing FLOAT dot with %d elements %d times", n, ITERS);
+        for (int i = 0; i < ITERS; i++)
+            SimpleBlas.dot(x, y);
+        printMflops(n * ITERS, toc());
+    }
+    
+    public void testBenchmarkGemvDouble() {
+        final int m = 1000;
+        final int n = 2000;
+        final int ITERS = 100;
+        DoubleMatrix x = DoubleMatrix.randn(m, n);
+        DoubleMatrix y = DoubleMatrix.randn(n, 1);
+        DoubleMatrix z = DoubleMatrix.randn(m, 1);
+        
+        tic("Doing DOUBLE Gemv with matrices of size %d * %d for %d times", m, n, ITERS);
+        for (int i = 0; i < ITERS; i++)
+            SimpleBlas.gemv(1.0, x, y, 0.0, z);
+        printMflops(2l*m*n*ITERS, toc());
+
+        tic("Doing DOUBLE Gemm with matrices of size %d * %d for %d times", m, n, ITERS);
+        for (int i = 0; i < ITERS; i++)
+            SimpleBlas.gemm(1.0, x, y, 0.0, z);
+        printMflops(2l*m*n*ITERS, toc());
+    }
+    
+    public void testBenchmarkGemvFloat() {
+        final int m = 1000;
+        final int n = 2000;
+        final int ITERS = 100;
+        FloatMatrix x = FloatMatrix.randn(m, n);
+        FloatMatrix y = FloatMatrix.randn(n, 1);
+        FloatMatrix z = FloatMatrix.randn(m, 1);
+        
+        tic("Doing Float Gemv with matrices of size %d * %d for %d times", m, n, ITERS);
+        for (int i = 0; i < ITERS; i++)
+            SimpleBlas.gemv(1.0f, x, y, 0.0f, z);
+        printMflops(2l*m*n*ITERS, toc());
+
+        tic("Doing Float Gemm with matrices of size %d * %d for %d times", m, n, ITERS);
+        for (int i = 0; i < ITERS; i++)
+            SimpleBlas.gemm(1.0f, x, y, 0.0f, z);
+        printMflops(2l*m*n*ITERS, toc());
+    }
+}
diff --git a/test/org/jblas/la/ComplexDoubleMatrixTest.java b/test/org/jblas/la/ComplexDoubleMatrixTest.java
new file mode 100644
index 0000000..cd3a566
--- /dev/null
+++ b/test/org/jblas/la/ComplexDoubleMatrixTest.java
@@ -0,0 +1,88 @@
+// --- 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 ---
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.jblas.la;
+
+import org.jblas.la.DoubleMatrix;
+import org.jblas.la.ComplexDoubleMatrix;
+import org.jblas.core.ComplexDouble;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import junit.framework.TestCase;
+
+/**
+ *
+ * @author mikio
+ */
+public class ComplexDoubleMatrixTest extends TestCase {
+    
+    public ComplexDoubleMatrixTest(String testName) {
+        super(testName);
+    }            
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testConstruction() {
+        ComplexDoubleMatrix A = new ComplexDoubleMatrix(3, 3);
+        
+        for (int i = 0; i < A.rows; i++)
+            for (int j = 0; j < A.columns; j++)
+                A.put(i, j, new ComplexDouble(i, j));
+        System.out.printf("A = %s\n", A.toString());
+        
+        System.out.println(A.mmul(A));
+        
+        DoubleMatrix R = new DoubleMatrix(3, 3, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
+        A = new ComplexDoubleMatrix(R, R.transpose());
+        System.out.println(A);
+        
+        assertEquals(A.real(), R);
+        assertEquals(A.imag(), R.transpose());
+    }
+}
diff --git a/test/org/jblas/la/DemoImages.java b/test/org/jblas/la/DemoImages.java
new file mode 100644
index 0000000..53f6380
--- /dev/null
+++ b/test/org/jblas/la/DemoImages.java
@@ -0,0 +1,319 @@
+// --- 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.la;
+
+import org.jblas.la.DoubleMatrix;
+import org.jblas.la.Blas;
+import junit.framework.TestCase;
+import static org.jblas.la.TicToc.*;
+import java.awt.image.BufferedImage;
+import javax.imageio.ImageIO;
+import java.io.File;
+import java.io.IOException;
+import static org.jblas.la.MatrixFunctions.*;
+import java.util.Arrays;
+
+public class DemoImages extends TestCase {
+	private DoubleMatrix tile(DoubleMatrix x, int ix, int iy, int wx, int wy) {
+		int width = (x.rows - ix) / wx;
+		int height = (x.columns - iy) / wy;
+		DoubleMatrix result = new DoubleMatrix(width*height, wx*wy);
+		int counter = 0;
+		for (int i = 0; i < x.rows - width; i += wx)
+			for (int j = 0; j < x.columns - height; j += wy) {
+				copyRect2(result, counter++, x, wx, wy, i, j);
+			}
+		return result;
+	}
+
+	private void copyRect2(DoubleMatrix result, int counter, DoubleMatrix x, int wx, int wy, int i, int j) {
+		for (int jj = 0; jj < wx; jj++)
+			Blas.dcopy(wy, x.data, x.index(i, j + jj), 1, result.data, result.index(counter, jj * wy), result.rows);
+	}
+	
+	private void copyRect(DoubleMatrix result, int counter, DoubleMatrix x, int wx, int wy, int i, int j) {
+		int[] I = range(i, i + wx - 1);
+		int[] J = range(j, j + wy - 1);
+		result.putRow(counter, x.get(I, J));
+	}
+	
+	private int[] range(int a, int b) {
+		int[] result = new int[b - a + 1];
+		for (int i = 0; i <= b - a; i++)
+			result[i] = a + i;
+		return result;
+	}
+
+	private int[] range(int a, int s, int b) {
+		int[] result = new int[(b - a + (s-1)) / s];
+		for (int c = 0, i = a; c < result.length; i += s, c++)
+			result[c] = i;
+		return result;
+	}
+	
+	private void print(int[] a) {
+		if (a.length == 0)
+			System.out.println("[]");
+		else {
+			System.out.print("[");
+			for (int i = 0; i < a.length - 1; i++)
+				System.out.printf("%d; ", a[i]);
+			System.out.printf("%d]\n", a[a.length - 1]);
+		}
+	}
+	
+	public void testRange() {
+		System.out.println("testRange-------");
+		print(range(1,3));
+		for (int i = 1; i < 10; i++) {
+			System.out.printf("i = %d ", i);
+			print(range(1,2,i));
+		}
+	}
+	
+	private DoubleMatrix[] loadImage(String name)
+		throws IOException {
+		BufferedImage image = ImageIO.read(new File(name));
+		
+		DoubleMatrix[] result = new DoubleMatrix[3];
+		for (int i = 0; i < 3; i++) {
+			result[i] = new DoubleMatrix(image.getWidth(), image.getHeight());
+		}
+		
+		for (int x = 0; x < image.getWidth(); x++) {
+			for (int y = 0; y < image.getHeight(); y++) {
+				int pixel = image.getRGB(x, y);
+				result[0].put(x, y, ((pixel & 0xff0000) >> 16) / 255.0 );
+				result[1].put(x, y, ((pixel & 0x00ff00) >> 8) / 255.0 );
+				result[2].put(x, y, ((pixel & 0x0000ff)) / 255.0 );
+			}
+		}
+		return result;
+	}
+	
+	private int doubleToByte(double v) {
+		if (v > 1.0) v = 1.0;
+		else if(v < 0.0) v = 0.0;
+		return (int) (v * 255);
+	}
+
+	private void saveImage(String name, String formatName, DoubleMatrix image)
+		throws IOException {
+		int width = image.rows;
+		int height = image.columns;
+		BufferedImage out = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+		
+		for (int x = 0; x < width; x++)
+			for (int y = 0; y < height; y++) {
+				int pixel = doubleToByte(image.get(x,y));
+				pixel |= (pixel << 16) | (pixel << 8);
+				out.setRGB(x, y, pixel);
+			}
+		
+		ImageIO.write(out, formatName, new File(name));		
+	}
+
+	private void saveImage(String name, String formatName, DoubleMatrix[] image)
+		throws IOException {
+		int width = image[0].rows;
+		int height = image[0].columns;
+		BufferedImage out = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+		
+		for (int x = 0; x < width; x++)
+			for (int y = 0; y < height; y++) {
+				int pixel = (doubleToByte(image[0].get(x,y)) << 16) |
+							(doubleToByte(image[1].get(x,y)) << 8) |
+							(doubleToByte(image[2].get(x,y)));
+				out.setRGB(x, y, pixel);
+			}
+		
+		ImageIO.write(out, formatName, new File(name));
+	}
+	
+	public void testTile() {
+		//DoubleMatrix x = DoubleMatrix.randn(1000,1000);
+		DoubleMatrix x = new DoubleMatrix(2000,2000);
+		for (int i = 1; i < x.length; i++)
+			x.put(i, i);
+		//x.print();
+		
+		tic("Tiling matrix");
+		DoubleMatrix t = tile(x, 0, 0, 100, 100);
+		toc();
+
+		System.out.printf("And the result has %d times %d entries\n", t.rows, t.columns);
+		//t.print();
+		
+		tic("Folding");
+		DoubleMatrix out = t.mmul(DoubleMatrix.ones(t.columns));
+		toc();
+		
+		//out.reshape(5, 5);
+		
+		//out.print();
+		
+		System.out.println("Done!");
+	}
+	
+	public void testLoadWrite() {
+		try {
+			tic("Loading");
+			DoubleMatrix[] img = loadImage("/home/mikio/pics/me.jpg");
+			toc();
+			tic("Saving");
+			saveImage("/home/mikio/pics/saved_me.png", "png", img);
+			toc();
+		} catch(IOException e) {
+			System.err.println("Error reading or writing file");
+		}
+	}
+
+	public long ops;
+	public long mult_ops;
+	public long add_ops;
+	public long copy_ops;
+	
+	private DoubleMatrix convolute(DoubleMatrix img, DoubleMatrix weights) {
+		DoubleMatrix result = new DoubleMatrix(img.rows - weights.columns, img.columns - weights.rows);
+		DoubleMatrix w = new DoubleMatrix(img.rows, weights.columns);
+		
+		ops = 0;
+		
+		for (int i = 0; i < img.columns - weights.rows; i++) {
+			// compute all filter for all columns
+			Blas.dgemm('N', 'N', img.rows, weights.rows, weights.columns, 
+						1.0, img.data, img.index(0, i), img.rows,
+						weights.data, 0, weights.rows,
+						0.0, w.data, 0, w.rows);
+			ops += 2*(long)img.rows * weights.rows * weights.columns;
+			
+			// collect results
+			// add rows of length w.rows - w.columns from j, j to first row.
+			for (int j = 1; j < w.columns; j++) {
+				Blas.daxpy(w.rows - w.columns, 1.0, w.data, img.index(j, j), 1, w.data, 0, 1);
+				ops += w.rows - w.columns;
+			}
+			// copy the result back to the output vector.
+			Blas.dcopy(w.rows - w.columns, w.data, 0, 1, result.data, result.index(0, i), 1);
+		}
+		return result;
+	}
+	
+	private DoubleMatrix convoluteNaive(DoubleMatrix img, DoubleMatrix weights) {
+		int width = weights.rows;
+		int height = weights.columns;
+		DoubleMatrix result = new DoubleMatrix(img.rows - width, img.columns - height);
+		for (int i = 0; i < img.rows - width; i++)
+			for (int j = 0; j < img.columns - height; j++) {
+				double sum = 0.0;
+				for (int l = 0; l < height; l++) {
+					for (int k = 0; k < width; k++) {
+						sum += img.get(i + k, j + l) * weights.get(k, l);
+					}
+				}
+				result.put(i, j, sum);
+			}
+		ops += 2 * (long)(img.rows - width) * (img.columns - height) * height * width;
+		return result;
+	}
+	
+	private double ringMask(double x, double y) {
+		double d = sqrt(x*x + y*y);
+		if (d < 0.0 || d >= 10.0)
+			return 0.0;
+		else
+			return 1.0;
+	}
+	
+	private double mexicanHatMask(double x, double y) {
+		double d = x*x + y*y;
+		double sigma = 2;
+		return 1/(sqrt(2*Math.PI)*sigma*sigma*sigma) * (1 - d/(sigma*sigma)) *
+			exp(- d / (2 * sigma*sigma));
+	}
+	
+	private DoubleMatrix makeMask(int[] x, int[] y) {
+		DoubleMatrix result = new DoubleMatrix(x.length, y.length);
+		
+		for (int i = 0; i < x.length; i++)
+			for (int j = 0; j < y.length; j++)
+				result.put(i, j, mexicanHatMask(x[i], y[j]));
+		return result;
+	}
+	
+	public void testConvolute() {
+		try {
+			DoubleMatrix[] img = loadImage("/home/mikio/pics/img.jpg");
+			
+			tic("Converting to grayscale");
+			DoubleMatrix scaledRed = img[0].mul(0.4);
+			DoubleMatrix scaledGreen = img[1].mul(0.4);
+			DoubleMatrix scaledBlue = img[2].mul(0.2);
+			DoubleMatrix gray = scaledRed.addi(scaledGreen).addi(scaledBlue);
+			toc();
+			
+			DoubleMatrix weights = makeMask(range(-20, 20), range(-20, 20));
+			//DoubleMatrix weights = DoubleMatrix.randn(51,51);
+			tic("Convoluting");
+			DoubleMatrix cgray = convolute(gray, weights);
+			double time = toc();
+			cgray.addi(0.5);
+			cgray.divi(abs(cgray).max());
+			
+			System.out.printf("[INFO] weight size = %d\n", weights.length);
+			System.out.printf("[INFO] total ops = %.3fM (%.3f MFLOPS)\n", ops / 1000000d, ops / 1000000d / time);
+			
+			saveImage("/home/mikio/pics/saved_img.jpg", "jpg", cgray);
+		} catch(IOException e) {
+			System.err.println("Error reading or writing file");
+		}		
+	}
+	
+	int countHowMany(int s, int I) {
+		int counter = 0;
+		for (int i = 0; i < I; i += s)
+			counter++;
+		return counter;
+	}
+	
+	public void testHowMany() {
+		/*for (int s = 1; s < 5; s++)
+			for (int i = 0; i < 20; i++)
+				System.out.printf("0..%d..%d => %d (vs. %d)\n", s, i, countHowMany(s, i), (i - 0 + (s-1)) / s);
+		*/	
+	}
+}
diff --git a/test/org/jblas/la/EigenTest.java b/test/org/jblas/la/EigenTest.java
new file mode 100644
index 0000000..446af1a
--- /dev/null
+++ b/test/org/jblas/la/EigenTest.java
@@ -0,0 +1,79 @@
+// --- 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 ---
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package org.jblas.la;
+
+import org.jblas.la.Eigen;
+import org.jblas.la.DoubleMatrix;
+import org.jblas.la.ComplexDoubleMatrix;
+import junit.framework.TestCase;
+import static org.jblas.la.TicToc.*;
+
+/**
+ *
+ * @author mikio
+ */
+public class EigenTest extends TestCase {
+
+    public EigenTest(String testName) {
+        super(testName);
+    }
+
+    public void testEigenvalues() {
+        DoubleMatrix A = new DoubleMatrix(2, 2, 3.0, -3.0, 1.0, 1.0);
+
+        ComplexDoubleMatrix E = Eigen.eigenvalues(A);
+        
+        System.out.printf("E = %s\n", E.toString());
+        
+        ComplexDoubleMatrix[] EV = Eigen.eigenvectors(A);
+        
+        System.out.printf("values = %s\n", EV[1].toString());
+        System.out.printf("vectors = %s\n", EV[0].toString());
+    }
+    
+    public void testBenchmarkEigenvalues() {
+        tic("Computing eigenvalues of random 1000*1000 matrix");
+        ComplexDoubleMatrix EV = Eigen.eigenvalues(DoubleMatrix.randn(500,500));
+        toc();
+        
+        System.out.printf("EV = %s\n", EV.toString());
+    }
+}
diff --git a/test/org/jblas/la/SimpleBlasTest.java b/test/org/jblas/la/SimpleBlasTest.java
new file mode 100644
index 0000000..d366d66
--- /dev/null
+++ b/test/org/jblas/la/SimpleBlasTest.java
@@ -0,0 +1,77 @@
+// --- 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 ---
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.jblas.la;
+
+import org.jblas.la.SimpleBlas;
+import org.jblas.la.DoubleMatrix;
+import junit.framework.TestCase;
+
+/**
+ *
+ * @author mikio
+ */
+public class SimpleBlasTest extends TestCase {
+    
+    public SimpleBlasTest(String testName) {
+        super(testName);
+    }
+
+    public void testGeev() {
+        DoubleMatrix A = new DoubleMatrix(2, 2, 3.0, -3.0, 1.0, 1.0);
+        DoubleMatrix WR = new DoubleMatrix(2);
+        DoubleMatrix WI = new DoubleMatrix(2);
+        DoubleMatrix VR = new DoubleMatrix(2,2);
+        DoubleMatrix VL = new DoubleMatrix(2,2);
+        
+        SimpleBlas.geev('V', 'N', A, WR, WI, VR, VL);
+        
+        assertEquals(new DoubleMatrix(2, 1, 2.0, 2.0), WR);
+        assertEquals(new DoubleMatrix(2, 1, Math.sqrt(2.0), -Math.sqrt(2.0)), WI);
+        
+        System.out.printf("WR = %s\n", WR.toString());
+        System.out.printf("WI = %s\n", WI.toString());
+        System.out.printf("VR = %s\n", VR.toString());
+        System.out.printf("VL = %s\n", VL.toString());
+        System.out.printf("A = %s\n", A.toString());
+        
+    }
+}
diff --git a/test/org/jblas/la/TestBlasDouble.java b/test/org/jblas/la/TestBlasDouble.java
new file mode 100644
index 0000000..690eba2
--- /dev/null
+++ b/test/org/jblas/la/TestBlasDouble.java
@@ -0,0 +1,183 @@
+// --- 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.la;
+
+import junit.framework.TestCase;
+
+import static org.jblas.la.MatrixFunctions.*;
+
+public class TestBlasDouble extends TestCase {
+
+	/** test sum of absolute values */
+	public void testAsum() {
+		double[] a = new double[]{1.0, 2.0, 3.0, 4.0};
+		
+		assertEquals(10.0, Blas.dasum(4, a, 0, 1));
+		assertEquals(4.0, Blas.dasum(2, a, 0, 2));
+		assertEquals(5.0, Blas.dasum(2, a, 1, 1));
+	}
+	
+	/** test scalar product */
+	public void testDot() {
+		double[] a = new double[] { 1.0, 2.0, 3.0, 4.0 };
+		double[] b = new double[] { 4.0, 5.0, 6.0, 7.0 };
+
+		assertEquals(32.0, Blas.ddot(3, a, 0, 1, b, 0, 1));
+		assertEquals(22.0, Blas.ddot(2, a, 0, 2, b, 0, 2));
+		assertEquals(5.0 + 12.0 + 21.0, Blas.ddot(3, a, 0, 1, b, 1, 1));
+	}
+	
+        public void testSwap() {
+            double[] a = new double[] { 1.0, 2.0, 3.0, 4.0 };
+            double[] b = new double[] { 4.0, 5.0, 6.0, 7.0 };
+            double[] c = new double[] { 1.0, 2.0, 3.0, 4.0 };
+            double[] d = new double[] { 4.0, 5.0, 6.0, 7.0 };
+            
+            System.out.println("dswap");
+            Blas.dswap(4, a, 0, 1, b, 0, 1);
+            assertTrue(arraysEqual(a, d));
+            assertTrue(arraysEqual(b, c));
+
+            System.out.println("dswap same");
+            Blas.dswap(2, a, 0, 2, a, 1, 2);
+            assertTrue(arraysEqual(a, 5.0, 4.0, 7.0, 6.0));
+        }
+        
+	/* test vector addition */
+	public void testAxpy() {
+		double[] x = new double[] { 1.0, 2.0, 3.0, 4.0 };
+		double[] y = new double[] { 0.0, 0.0, 0.0, 0.0 };
+		
+		Blas.daxpy(4, 2.0, x, 0, 1, y, 0, 1);
+		
+		for(int i = 0; i < 4; i++)
+			assertEquals(2*x[i], y[i]);
+	}
+	
+	/* test matric-vector multiplication */
+	public void testGemv() {
+		double[] A = new double[] { 1.0, 2.0, 3.0,
+										  4.0, 5.0, 6.0,
+										  7.0, 8.0, 9.0 };
+		
+		double[] x = new double[] {1.0, 3.0, 7.0 };
+		double[] y = new double[] { 0.0, 0.0, 0.0 };
+		
+		Blas.dgemv('N', 3, 3, 1.0, A, 0, 3, x, 0, 1, 0.0, y, 0, 1);
+		
+		//printMatrix(3, 3, A);
+		//printMatrix(3, 1, x);
+		//printMatrix(3, 1, y);
+		
+		assertTrue(arraysEqual(y, 62.0, 73.0, 84.0));
+		
+		Blas.dgemv('T', 3, 3, 1.0, A, 0, 3, x, 0, 1, 0.5, y, 0, 1);
+
+		//printMatrix(3, 1, y);
+		assertTrue(arraysEqual(y, 59.0, 97.5, 136.0));
+	}
+		
+	/** Compare double buffer against an array of doubles */
+	private boolean arraysEqual(double[] a, double... b) {
+		if (a.length != b.length)
+			return false;
+		else { 
+			double diff = 0.0;
+			for (int i = 0; i < b.length; i++)
+				diff += abs(a[i] - b[i]);
+			return diff < 1e-6;
+		}
+	}
+	
+	public static void main(String[] args) {
+		TestBlasDouble t = new TestBlasDouble();
+		
+		t.testAsum();
+	}
+	
+	public static void testSolve() {
+		DoubleMatrix A = new DoubleMatrix(3, 3, 3.0, 5.0, 6.0, 1.0, 0.0, 0.0, 2.0, 4.0, 0.0);
+		DoubleMatrix X = new DoubleMatrix(3, 1, 1.0, 2.0, 3.0);
+		int[] p = new int[3];
+		SimpleBlas.gesv(A, p, X);
+		A.print();
+		X.print();
+		// De-shuffle X
+		for (int i = 2; i >= 0; i--) {
+			int perm = p[i] - 1;
+			double t = X.get(i); X.put(i, X.get(perm)); X.put(perm, t);
+		}
+		System.out.println();
+		X.print();
+	}
+	
+	public static void testSymmetricSolve() {
+		System.out.println("--- Symmetric solve");
+		DoubleMatrix A = new DoubleMatrix(3, 3, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
+		DoubleMatrix x = new DoubleMatrix(3, 1, 1.0, 2.0, 3.0);
+		int[] p = new int[3];
+		SimpleBlas.sysv('U', A, p, x);
+		A.print();
+		x.print();
+	}
+	
+	public static void testSYEV() {
+		System.out.println("--- Symmetric eigenvalues");
+		int n = 10;
+		DoubleMatrix x = DoubleMatrix.randn(n).sort();
+		
+		//DoubleMatrix A = new DoubleMatrix(new double[][] {{1.0, 0.5, 0.1}, {0.5, 1.0, 0.5}, {0.1, 0.5, 1.0}});
+		DoubleMatrix A = expi(Geometry.pairwiseSquaredDistances(x, x).muli(-2.0));
+		DoubleMatrix w = new DoubleMatrix(n);
+		
+		DoubleMatrix B = A.dup();
+		System.out.println("Computing eigenvalues with SYEV");
+		SimpleBlas.syev('V', 'U', B, w);
+		System.out.println("Eigenvalues: ");
+		w.print();
+		System.out.println("Eigenvectors: ");
+		B.print();
+
+		B = A.dup();
+		System.out.println("Computing eigenvalues with SYEVD");
+		SimpleBlas.syevd('V', 'U', B, w);
+		System.out.println("Eigenvalues: ");
+		w.print();
+		System.out.println("Eigenvectors: ");
+		B.print();
+	}
+}
diff --git a/test/org/jblas/la/TestBlasDoubleComplex.java b/test/org/jblas/la/TestBlasDoubleComplex.java
new file mode 100644
index 0000000..d3371ed
--- /dev/null
+++ b/test/org/jblas/la/TestBlasDoubleComplex.java
@@ -0,0 +1,63 @@
+// --- 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.la;
+
+import junit.framework.TestCase;
+
+import org.jblas.core.ComplexDouble;
+
+public class TestBlasDoubleComplex extends TestCase {
+
+	public void testDotc() {
+		double[] a = new double[] { 1.0, 1.0, 2.0, 0.0, 3.0, 0.0 };
+		
+		ComplexDouble c = Blas.zdotu(3, a, 0, 1, a, 0, 1);
+		System.out.println(c);
+	}
+
+	public void testAxpy() {
+		double[] x = new double[] { 0.0, -1.0 };
+		double[] y = new double[] { 0.0, 1.0 };
+		ComplexDouble a = new ComplexDouble(0.0, 1.0);
+		
+		Blas.zdscal(1, 2.0, x, 0, 1);
+		assertEquals(new ComplexDouble(0.0, -2.0), new ComplexDouble(x[0], x[1]));
+		
+		Blas.zaxpy(1, a, x, 0, 1, y, 0, 1);
+		assertEquals(new ComplexDouble(2.0, 1.0), new ComplexDouble(y[0], y[1]));
+	}
+}
diff --git a/test/org/jblas/la/TestBlasFloat.java b/test/org/jblas/la/TestBlasFloat.java
new file mode 100644
index 0000000..5a60944
--- /dev/null
+++ b/test/org/jblas/la/TestBlasFloat.java
@@ -0,0 +1,183 @@
+// --- 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.la;
+
+import junit.framework.TestCase;
+
+import static org.jblas.la.MatrixFunctions.*;
+
+public class TestBlasFloat extends TestCase {
+
+	/** test sum of absolute values */
+	public void testAsum() {
+		float[] a = new float[]{1.0f, 2.0f, 3.0f, 4.0f};
+		
+		assertEquals(10.0f, Blas.sasum(4, a, 0, 1));
+		assertEquals(4.0f, Blas.sasum(2, a, 0, 2));
+		assertEquals(5.0f, Blas.sasum(2, a, 1, 1));
+	}
+	
+	/** test scalar product */
+	public void testDot() {
+		float[] a = new float[] { 1.0f, 2.0f, 3.0f, 4.0f };
+		float[] b = new float[] { 4.0f, 5.0f, 6.0f, 7.0f };
+
+		assertEquals(32.0f, Blas.sdot(3, a, 0, 1, b, 0, 1));
+		assertEquals(22.0f, Blas.sdot(2, a, 0, 2, b, 0, 2));
+		assertEquals(5.0f + 12.0f + 21.0f, Blas.sdot(3, a, 0, 1, b, 1, 1));
+	}
+	
+        public void testSwap() {
+            float[] a = new float[] { 1.0f, 2.0f, 3.0f, 4.0f };
+            float[] b = new float[] { 4.0f, 5.0f, 6.0f, 7.0f };
+            float[] c = new float[] { 1.0f, 2.0f, 3.0f, 4.0f };
+            float[] d = new float[] { 4.0f, 5.0f, 6.0f, 7.0f };
+            
+            System.out.println("dswap");
+            Blas.sswap(4, a, 0, 1, b, 0, 1);
+            assertTrue(arraysEqual(a, d));
+            assertTrue(arraysEqual(b, c));
+
+            System.out.println("dswap same");
+            Blas.sswap(2, a, 0, 2, a, 1, 2);
+            assertTrue(arraysEqual(a, 5.0f, 4.0f, 7.0f, 6.0f));
+        }
+        
+	/* test vector addition */
+	public void testAxpy() {
+		float[] x = new float[] { 1.0f, 2.0f, 3.0f, 4.0f };
+		float[] y = new float[] { 0.0f, 0.0f, 0.0f, 0.0f };
+		
+		Blas.saxpy(4, 2.0f, x, 0, 1, y, 0, 1);
+		
+		for(int i = 0; i < 4; i++)
+			assertEquals(2*x[i], y[i]);
+	}
+	
+	/* test matric-vector multiplication */
+	public void testGemv() {
+		float[] A = new float[] { 1.0f, 2.0f, 3.0f,
+										  4.0f, 5.0f, 6.0f,
+										  7.0f, 8.0f, 9.0f };
+		
+		float[] x = new float[] {1.0f, 3.0f, 7.0f };
+		float[] y = new float[] { 0.0f, 0.0f, 0.0f };
+		
+		Blas.sgemv('N', 3, 3, 1.0f, A, 0, 3, x, 0, 1, 0.0f, y, 0, 1);
+		
+		//printMatrix(3, 3, A);
+		//printMatrix(3, 1, x);
+		//printMatrix(3, 1, y);
+		
+		assertTrue(arraysEqual(y, 62.0f, 73.0f, 84.0f));
+		
+		Blas.sgemv('T', 3, 3, 1.0f, A, 0, 3, x, 0, 1, 0.5f, y, 0, 1);
+
+		//printMatrix(3, 1, y);
+		assertTrue(arraysEqual(y, 59.0f, 97.5f, 136.0f));
+	}
+		
+	/** Compare float buffer against an array of floats */
+	private boolean arraysEqual(float[] a, float... b) {
+		if (a.length != b.length)
+			return false;
+		else { 
+			float diff = 0.0f;
+			for (int i = 0; i < b.length; i++)
+				diff += abs(a[i] - b[i]);
+			return diff < 1e-6;
+		}
+	}
+	
+	public static void main(String[] args) {
+		TestBlasFloat t = new TestBlasFloat();
+		
+		t.testAsum();
+	}
+	
+	public static void testSolve() {
+		FloatMatrix A = new FloatMatrix(3, 3, 3.0f, 5.0f, 6.0f, 1.0f, 0.0f, 0.0f, 2.0f, 4.0f, 0.0f);
+		FloatMatrix X = new FloatMatrix(3, 1, 1.0f, 2.0f, 3.0f);
+		int[] p = new int[3];
+		SimpleBlas.gesv(A, p, X);
+		A.print();
+		X.print();
+		// De-shuffle X
+		for (int i = 2; i >= 0; i--) {
+			int perm = p[i] - 1;
+			float t = X.get(i); X.put(i, X.get(perm)); X.put(perm, t);
+		}
+		System.out.println();
+		X.print();
+	}
+	
+	public static void testSymmetricSolve() {
+		System.out.println("--- Symmetric solve");
+		FloatMatrix A = new FloatMatrix(3, 3, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f);
+		FloatMatrix x = new FloatMatrix(3, 1, 1.0f, 2.0f, 3.0f);
+		int[] p = new int[3];
+		SimpleBlas.sysv('U', A, p, x);
+		A.print();
+		x.print();
+	}
+	
+	public static void testSYEV() {
+		System.out.println("--- Symmetric eigenvalues");
+		int n = 10;
+		FloatMatrix x = FloatMatrix.randn(n).sort();
+		
+		//FloatMatrix A = new FloatMatrix(new float[][] {{1.0f, 0.5f, 0.1f}, {0.5f, 1.0f, 0.5f}, {0.1f, 0.5f, 1.0f}});
+		FloatMatrix A = expi(Geometry.pairwiseSquaredDistances(x, x).muli(-2.0f));
+		FloatMatrix w = new FloatMatrix(n);
+		
+		FloatMatrix B = A.dup();
+		System.out.println("Computing eigenvalues with SYEV");
+		SimpleBlas.syev('V', 'U', B, w);
+		System.out.println("Eigenvalues: ");
+		w.print();
+		System.out.println("Eigenvectors: ");
+		B.print();
+
+		B = A.dup();
+		System.out.println("Computing eigenvalues with SYEVD");
+		SimpleBlas.syevd('V', 'U', B, w);
+		System.out.println("Eigenvalues: ");
+		w.print();
+		System.out.println("Eigenvectors: ");
+		B.print();
+	}
+}
diff --git a/test/org/jblas/la/TestDoubleMatrix.java b/test/org/jblas/la/TestDoubleMatrix.java
new file mode 100644
index 0000000..66397d3
--- /dev/null
+++ b/test/org/jblas/la/TestDoubleMatrix.java
@@ -0,0 +1,641 @@
+// --- 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.la;
+
+import org.jblas.la.DoubleMatrix;
+import org.jblas.la.Geometry;
+import org.jblas.la.Solve;
+import junit.framework.TestCase;
+import java.util.Arrays;
+import static org.jblas.la.ranges.RangeUtils.*;
+
+public class TestDoubleMatrix extends TestCase {
+
+    DoubleMatrix A, B, C, D, E, F;
+
+    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);
+        B = new DoubleMatrix(3, 1, 2.0, 4.0, 8.0);
+        C = new DoubleMatrix(3, 1, -1.0, 2.0, -3.0);
+        D = new DoubleMatrix(3, 3, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
+        E = new DoubleMatrix(3, 3, 1.0, -2.0, 3.0, -4.0, 5.0, -6.0, 7.0, -8.0, 9.0);
+        F = new DoubleMatrix(3, 1, 3.0, 4.0, 7.0);
+    }
+
+    public void testConstructionAndSetGet() {
+        double[][] dataA = {{1.0, 5.0, 9.0}, {2.0, 6.0, 10.0}, {3.0, 7.0, 11.0}, {4.0, 8.0, 12.0}};
+
+        assertEquals(A.rows, 4);
+        assertEquals(A.columns, 3);
+
+        for (int r = 0; r < 4; r++) {
+            for (int c = 0; c < 3; c++) {
+                assertEquals(dataA[r][c], A.get(r, c));
+            }
+        }
+    }
+
+    public void testSetAndGet() {
+        DoubleMatrix M = new DoubleMatrix(3, 3);
+
+        for (int i = 0; i < 3; i++) {
+            for (int j = 0; j < 3; j++) {
+                M.put(i, j, i + j);
+            }
+        }
+        for (int i = 0; i < 3; i++) {
+            for (int j = 0; j < 3; j++) {
+                assertEquals((double) i + j, M.get(i, j));
+            }
+        }
+    }
+
+    public void testCopy() {
+        DoubleMatrix M = new DoubleMatrix();
+
+        assertFalse(M.equals(A));
+
+        M.copy(A);
+        assertEquals(M, A);
+    }
+
+    public void testDup() {
+        DoubleMatrix M = A.dup();
+        assertEquals(M, A);
+
+        M.put(0, 0, 2.0);
+        assertFalse(M.equals(A));
+    }
+
+    public void testResize() {
+        DoubleMatrix M = A.dup();
+
+        assertEquals(4, M.rows);
+        assertEquals(3, M.columns);
+
+        M.resize(4, 5);
+        assertEquals(4, M.rows);
+        assertEquals(5, M.columns);
+
+        assertEquals(0.0, M.get(3, 4));
+    }
+
+    public void testReshape() {
+        DoubleMatrix M = new DoubleMatrix(2, 2, 1.0, 2.0, 3.0, 4.0);
+
+        M.reshape(1, 4);
+        assertEquals(1.0, M.get(0, 0));
+        assertEquals(4.0, M.get(0, 3));
+
+        M.reshape(4, 1);
+        assertEquals(1.0, M.get(0, 0));
+        assertEquals(4.0, M.get(3, 0));
+    }
+
+    public void testMmul() {
+        DoubleMatrix R = A.dup();
+        DoubleMatrix result = new DoubleMatrix(4, 1, 94.0, 108.0, 122.0, 136.0);
+
+        A.mmuli(B, R);
+        assertEquals(result, R);
+
+        assertEquals(result, A.mmul(B));
+
+        DoubleMatrix resultDE = new DoubleMatrix(3, 3, 14.0, 16.0, 18.0, -26.0, -31.0, -36.0, 38.0, 46.0, 54.0);
+
+        // In-place with independent operands
+        assertEquals(resultDE, D.mmuli(E, R));
+
+        // In-place on this
+        R = D.dup();
+        assertEquals(resultDE, R.mmuli(E, R));
+
+        // In-place on this
+        R = E.dup();
+        assertEquals(resultDE, D.mmuli(R, R));
+
+        // Fully dynamic
+        assertEquals(resultDE, D.mmul(E));
+    }
+
+    public void testAdd() {
+        DoubleMatrix result = new DoubleMatrix(3, 1, 1.0, 6.0, 5.0);
+
+        DoubleMatrix R = new DoubleMatrix();
+
+        // In-place, but independent operands
+        B.addi(C, R);
+        assertEquals(result, R);
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.addi(C, R));
+
+        // In-place on other
+        R = C.dup();
+        assertEquals(result, B.addi(R, R));
+
+        // fully dynamic
+        assertEquals(result, B.add(C));
+
+        result = new DoubleMatrix(3, 1, 3.0, 5.0, 9.0);
+
+        // In-place, but independent operands
+        assertEquals(result, B.addi(1.0, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.addi(1.0, R));
+
+        // fully dynamic
+        assertEquals(result, B.add(1.0));
+    }
+
+    public void testSub() {
+        DoubleMatrix result = new DoubleMatrix(3, 1, 3.0, 2.0, 11.0);
+
+        DoubleMatrix R = new DoubleMatrix();
+
+        // In-place, but independent operands
+        assertEquals(result, B.subi(C, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.subi(C, R));
+
+        // In-place on other
+        R = C.dup();
+        assertEquals(result, B.subi(R, R));
+
+        // fully dynamic
+        assertEquals(result, B.sub(C));
+
+        result = new DoubleMatrix(3, 1, 1.0, 3.0, 7.0);
+
+        // In-place, but independent operands
+        assertEquals(result, B.subi(1.0, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.subi(1.0, R));
+
+        // fully dynamic
+        assertEquals(result, B.sub(1.0));
+    }
+
+    public void testRsub() {
+        DoubleMatrix result = new DoubleMatrix(3, 1, 3.0, 2.0, 11.0);
+
+        DoubleMatrix R = new DoubleMatrix();
+
+        // In-place, but independent operands
+        assertEquals(result, C.rsubi(B, R));
+
+        // In-place on this
+        R = C.dup();
+        assertEquals(result, R.rsubi(B, R));
+
+        // In-place on other
+        R = B.dup();
+        assertEquals(result, C.rsubi(R, R));
+
+        // fully dynamic
+        assertEquals(result, C.rsub(B));
+
+        result = new DoubleMatrix(3, 1, -1.0, -3.0, -7.0);
+
+        // In-place, but independent operands
+        assertEquals(result, B.rsubi(1.0, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.rsubi(1.0, R));
+
+        // fully dynamic
+        assertEquals(result, B.rsub(1.0));
+    }
+
+    public void testMul() {
+        DoubleMatrix result = new DoubleMatrix(3, 1, -2.0, 8.0, -24.0);
+
+        DoubleMatrix R = new DoubleMatrix();
+
+        // In-place, but independent operands
+        assertEquals(result, B.muli(C, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.muli(C, R));
+
+        // In-place on other
+        R = C.dup();
+        assertEquals(result, B.muli(R, R));
+
+        // fully dynamic
+        assertEquals(result, B.mul(C));
+
+        result = new DoubleMatrix(3, 1, 1.0, 2.0, 4.0);
+
+        // In-place, but independent operands
+        assertEquals(result, B.muli(0.5, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.muli(0.5, R));
+
+        // fully dynamic
+        assertEquals(result, B.mul(0.5));
+    }
+
+    public void testDiv() {
+        DoubleMatrix result = new DoubleMatrix(3, 1, -2.0, 2.0, -2.666666666);
+
+        DoubleMatrix R = new DoubleMatrix();
+
+        // In-place, but independent operands
+        assertEquals(result, B.divi(C, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.divi(C, R));
+
+        // In-place on other
+        R = C.dup();
+        assertEquals(result, B.divi(R, R));
+
+        // fully dynamic
+        assertEquals(result, B.div(C));
+
+        result = new DoubleMatrix(3, 1, 1.0, 2.0, 4.0);
+
+        // In-place, but independent operands
+        assertEquals(result, B.divi(2.0, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.divi(2.0, R));
+
+        // fully dynamic
+        assertEquals(result, B.div(2.0));
+    }
+
+    public void testRdiv() {
+        DoubleMatrix result = new DoubleMatrix(3, 1, -2.0, 2.0, -2.666666666);
+
+        DoubleMatrix R = new DoubleMatrix();
+
+        // In-place, but independent operands
+        assertEquals(result, C.rdivi(B, R));
+
+        // In-place on this
+        R = C.dup();
+        assertEquals(result, R.rdivi(B, R));
+
+        // In-place on other
+        R = B.dup();
+        assertEquals(result, C.rdivi(R, R));
+
+        // fully dynamic
+        assertEquals(result, C.rdiv(B));
+
+        result = new DoubleMatrix(3, 1, 0.5, 0.25, 0.125);
+
+        // In-place, but independent operands
+        assertEquals(result, B.rdivi(1.0, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.rdivi(1.0, R));
+
+        // fully dynamic
+        assertEquals(result, B.rdiv(1.0));
+    }
+
+    /*# def test_logical(op, result, scalar, result2); <<-EOS
+    public void test#{op.upcase}() {
+    DoubleMatrix result = new DoubleMatrix(3, 1, #{result});
+    DoubleMatrix result2 = new DoubleMatrix(3, 1, #{result2});
+    DoubleMatrix R = new DoubleMatrix();
+    
+    // in-place but independent operands
+    assertEquals(result, B.#{op}i(F, R));
+    
+    // in-place but in other
+    R = F.dup();
+    assertEquals(result, B.#{op}i(R, R));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result, R.#{op}i(F, R));
+    
+    // fully dynamic
+    assertEquals(result, B.#{op}(F));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result2, R.#{op}i(#{scalar}, R));
+    
+    // fully dynamic
+    assertEquals(result2, B.#{op}(#{scalar}));	
+    }
+    EOS
+    end	
+    #*/
+    /*# test_logical('lt', '1.0, 0.0, 0.0', 4.0, '1.0, 0.0, 0.0') #*/
+//RJPP-BEGIN------------------------------------------------------------
+    public void testLT() {
+    DoubleMatrix result = new DoubleMatrix(3, 1, 1.0, 0.0, 0.0);
+    DoubleMatrix result2 = new DoubleMatrix(3, 1, 1.0, 0.0, 0.0);
+    DoubleMatrix R = new DoubleMatrix();
+    
+    // in-place but independent operands
+    assertEquals(result, B.lti(F, R));
+    
+    // in-place but in other
+    R = F.dup();
+    assertEquals(result, B.lti(R, R));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result, R.lti(F, R));
+    
+    // fully dynamic
+    assertEquals(result, B.lt(F));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result2, R.lti(4.0, R));
+    
+    // fully dynamic
+    assertEquals(result2, B.lt(4.0));	
+    }
+//RJPP-END--------------------------------------------------------------
+	/*# test_logical('le', '1.0, 1.0, 0.0', 4.0, '1.0, 1.0, 0.0') #*/
+//RJPP-BEGIN------------------------------------------------------------
+    public void testLE() {
+    DoubleMatrix result = new DoubleMatrix(3, 1, 1.0, 1.0, 0.0);
+    DoubleMatrix result2 = new DoubleMatrix(3, 1, 1.0, 1.0, 0.0);
+    DoubleMatrix R = new DoubleMatrix();
+    
+    // in-place but independent operands
+    assertEquals(result, B.lei(F, R));
+    
+    // in-place but in other
+    R = F.dup();
+    assertEquals(result, B.lei(R, R));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result, R.lei(F, R));
+    
+    // fully dynamic
+    assertEquals(result, B.le(F));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result2, R.lei(4.0, R));
+    
+    // fully dynamic
+    assertEquals(result2, B.le(4.0));	
+    }
+//RJPP-END--------------------------------------------------------------
+	/*# test_logical('gt', '0.0, 0.0, 1.0', 4.0, '0.0, 0.0, 1.0') #*/
+//RJPP-BEGIN------------------------------------------------------------
+    public void testGT() {
+    DoubleMatrix result = new DoubleMatrix(3, 1, 0.0, 0.0, 1.0);
+    DoubleMatrix result2 = new DoubleMatrix(3, 1, 0.0, 0.0, 1.0);
+    DoubleMatrix R = new DoubleMatrix();
+    
+    // in-place but independent operands
+    assertEquals(result, B.gti(F, R));
+    
+    // in-place but in other
+    R = F.dup();
+    assertEquals(result, B.gti(R, R));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result, R.gti(F, R));
+    
+    // fully dynamic
+    assertEquals(result, B.gt(F));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result2, R.gti(4.0, R));
+    
+    // fully dynamic
+    assertEquals(result2, B.gt(4.0));	
+    }
+//RJPP-END--------------------------------------------------------------
+	/*# test_logical('ge', '0.0, 1.0, 1.0', 4.0, '0.0, 1.0, 1.0') #*/
+//RJPP-BEGIN------------------------------------------------------------
+    public void testGE() {
+    DoubleMatrix result = new DoubleMatrix(3, 1, 0.0, 1.0, 1.0);
+    DoubleMatrix result2 = new DoubleMatrix(3, 1, 0.0, 1.0, 1.0);
+    DoubleMatrix R = new DoubleMatrix();
+    
+    // in-place but independent operands
+    assertEquals(result, B.gei(F, R));
+    
+    // in-place but in other
+    R = F.dup();
+    assertEquals(result, B.gei(R, R));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result, R.gei(F, R));
+    
+    // fully dynamic
+    assertEquals(result, B.ge(F));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result2, R.gei(4.0, R));
+    
+    // fully dynamic
+    assertEquals(result2, B.ge(4.0));	
+    }
+//RJPP-END--------------------------------------------------------------
+    public void testMinMax() {
+        assertEquals(1.0, A.min());
+        assertEquals(12.0, A.max());
+    }
+
+    public void testArgMinMax() {
+        assertEquals(0, A.argmin());
+        assertEquals(11, A.argmax());
+    }
+
+    public void testTranspose() {
+        DoubleMatrix At = A.transpose();
+        assertEquals(1.0, At.get(0, 0));
+        assertEquals(2.0, At.get(0, 1));
+        assertEquals(5.0, At.get(1, 0));
+    }
+
+    public void testGetRowVector() {
+        for (int r = 0; r < A.rows; r++) {
+            A.getRow(r);
+        }
+
+        for (int c = 0; c < A.columns; c++) {
+            A.getColumn(c);
+        }
+
+        A.addiRowVector(new DoubleMatrix(3, 1, 10.0, 100.0, 1000.0));
+        A.addiColumnVector(new DoubleMatrix(1, 4, 10.0, 100.0, 1000.0, 10000.0));
+    }
+
+    public void testPairwiseDistance() {
+        DoubleMatrix D = Geometry.pairwiseSquaredDistances(A, A);
+
+        DoubleMatrix X = new DoubleMatrix(1, 3, 1.0, 0.0, -1.0);
+
+        Geometry.pairwiseSquaredDistances(X, X);
+
+        DoubleMatrix A1 = new DoubleMatrix(1, 2, 1.0, 2.0);
+        DoubleMatrix A2 = new DoubleMatrix(1, 3, 1.0, 2.0, 3.0);
+
+        Geometry.pairwiseSquaredDistances(A1, A2);
+    }
+
+    public void testSwapColumns() {
+        DoubleMatrix AA = A.dup();
+
+        System.out.println("testSwapColumns");
+        AA.swapColumns(1, 2);
+        assertEquals(new DoubleMatrix(4, 3, 1.0, 2.0, 3.0, 4.0, 9.0, 10.0, 11.0, 12.0, 5.0, 6.0, 7.0, 8.0), AA);
+    }
+
+    public void testSwapRows() {
+        DoubleMatrix AA = A.dup();
+
+        AA.swapRows(1, 2);
+        assertEquals(new DoubleMatrix(4, 3, 1.0, 3.0, 2.0, 4.0, 5.0, 7.0, 6.0, 8.0, 9.0, 11.0, 10.0, 12.0), AA);
+    }
+
+    public void testSolve() {
+        DoubleMatrix A = new DoubleMatrix(3, 3, 3.0, 5.0, 6.0, 1.0, 0.0, 0.0, 2.0, 4.0, 0.0);
+        DoubleMatrix B = new DoubleMatrix(3, 1, 1.0, 2.0, 3.0);
+
+        DoubleMatrix Adup = A.dup();
+        DoubleMatrix Bdup = B.dup();
+
+        DoubleMatrix X = Solve.solve(A, B);
+
+        assertEquals(Adup, A);
+        assertEquals(Bdup, B);
+    }
+
+    public void testConstructFromArray() {
+        double[][] data = {
+            {1.0, 2.0, 3.0},
+            {4.0, 5.0, 6.0},
+            {7.0, 8.0, 9.0}
+        };
+
+        DoubleMatrix A = new DoubleMatrix(data);
+
+        for (int r = 0; r < 3; r++) {
+            for (int c = 0; c < 3; c++) {
+                assertEquals(data[r][c], A.get(r, c));
+            }
+        }
+    }
+
+    public void testDiag() {
+        DoubleMatrix A = new DoubleMatrix(new double[][]{
+                    {1.0, 2.0, 3.0},
+                    {4.0, 5.0, 6.0},
+                    {7.0, 8.0, 9.0}
+                });
+
+        assertEquals(new DoubleMatrix(3, 1, 1.0, 5.0, 9.0), A.diag());
+
+        assertEquals(new DoubleMatrix(new double[][]{
+                    {1.0, 0.0, 0.0},
+                    {0.0, 2.0, 0.0},
+                    {0.0, 0.0, 3.0}
+                }), DoubleMatrix.diag(new DoubleMatrix(3, 1, 1.0, 2.0, 3.0)));
+    }
+
+    public void testColumnAndRowMinMax() {
+        assertEquals(new DoubleMatrix(1, 3, 1.0, 5.0, 9.0), A.columnMins());
+        assertEquals(new DoubleMatrix(4, 1, 1.0, 2.0, 3.0, 4.0), A.rowMins());
+        assertEquals(new DoubleMatrix(1, 3, 4.0, 8.0, 12.0), A.columnMaxs());
+        assertEquals(new DoubleMatrix(4, 1, 9.0, 10.0, 11.0, 12.0), A.rowMaxs());
+        int[] i = A.columnArgmins();
+        assertEquals(0, i[0]);
+        assertEquals(0, i[1]);
+        assertEquals(0, i[2]);
+        i = A.columnArgmaxs();
+        assertEquals(3, i[0]);
+        assertEquals(3, i[1]);
+        assertEquals(3, i[2]);
+        i = A.rowArgmins();
+        assertEquals(0, i[0]);
+        assertEquals(0, i[1]);
+        assertEquals(0, i[2]);
+        assertEquals(0, i[3]);
+        i = A.rowArgmaxs();
+        assertEquals(2, i[0]);
+        assertEquals(2, i[1]);
+        assertEquals(2, i[2]);
+        assertEquals(2, i[3]);
+    }
+
+    public void testToArray() {
+        assertTrue(Arrays.equals(new double[]{2.0, 4.0, 8.0}, B.toArray()));
+        assertTrue(Arrays.equals(new int[]{2, 4, 8}, B.toIntArray()));
+        assertTrue(Arrays.equals(new boolean[]{true, true, true}, B.toBooleanArray()));
+    }
+
+    public void testLoadAsciiFile() {
+        try {
+            DoubleMatrix result = DoubleMatrix.loadAsciiFile("/home/mikio/datasets/banana/banana_train_data_1.asc");
+            result.print();
+        } catch (Exception e) {
+            fail("Caught exception " + e);
+        }
+    }
+    
+    public void testRanges() {
+        A.print();
+        A.get(interval(0, 2), interval(0, 1)).print();
+    }
+}
diff --git a/test/org/jblas/la/TestFloatMatrix.java b/test/org/jblas/la/TestFloatMatrix.java
new file mode 100644
index 0000000..9b3b737
--- /dev/null
+++ b/test/org/jblas/la/TestFloatMatrix.java
@@ -0,0 +1,641 @@
+// --- 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.la;
+
+import org.jblas.la.FloatMatrix;
+import org.jblas.la.Geometry;
+import org.jblas.la.Solve;
+import junit.framework.TestCase;
+import java.util.Arrays;
+import static org.jblas.la.ranges.RangeUtils.*;
+
+public class TestFloatMatrix extends TestCase {
+
+    FloatMatrix A, B, C, D, E, F;
+
+    public void setUp() {
+        A = new FloatMatrix(4, 3, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f);
+        B = new FloatMatrix(3, 1, 2.0f, 4.0f, 8.0f);
+        C = new FloatMatrix(3, 1, -1.0f, 2.0f, -3.0f);
+        D = new FloatMatrix(3, 3, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f);
+        E = new FloatMatrix(3, 3, 1.0f, -2.0f, 3.0f, -4.0f, 5.0f, -6.0f, 7.0f, -8.0f, 9.0f);
+        F = new FloatMatrix(3, 1, 3.0f, 4.0f, 7.0f);
+    }
+
+    public void testConstructionAndSetGet() {
+        float[][] dataA = {{1.0f, 5.0f, 9.0f}, {2.0f, 6.0f, 10.0f}, {3.0f, 7.0f, 11.0f}, {4.0f, 8.0f, 12.0f}};
+
+        assertEquals(A.rows, 4);
+        assertEquals(A.columns, 3);
+
+        for (int r = 0; r < 4; r++) {
+            for (int c = 0; c < 3; c++) {
+                assertEquals(dataA[r][c], A.get(r, c));
+            }
+        }
+    }
+
+    public void testSetAndGet() {
+        FloatMatrix M = new FloatMatrix(3, 3);
+
+        for (int i = 0; i < 3; i++) {
+            for (int j = 0; j < 3; j++) {
+                M.put(i, j, i + j);
+            }
+        }
+        for (int i = 0; i < 3; i++) {
+            for (int j = 0; j < 3; j++) {
+                assertEquals((float) i + j, M.get(i, j));
+            }
+        }
+    }
+
+    public void testCopy() {
+        FloatMatrix M = new FloatMatrix();
+
+        assertFalse(M.equals(A));
+
+        M.copy(A);
+        assertEquals(M, A);
+    }
+
+    public void testDup() {
+        FloatMatrix M = A.dup();
+        assertEquals(M, A);
+
+        M.put(0, 0, 2.0f);
+        assertFalse(M.equals(A));
+    }
+
+    public void testResize() {
+        FloatMatrix M = A.dup();
+
+        assertEquals(4, M.rows);
+        assertEquals(3, M.columns);
+
+        M.resize(4, 5);
+        assertEquals(4, M.rows);
+        assertEquals(5, M.columns);
+
+        assertEquals(0.0f, M.get(3, 4));
+    }
+
+    public void testReshape() {
+        FloatMatrix M = new FloatMatrix(2, 2, 1.0f, 2.0f, 3.0f, 4.0f);
+
+        M.reshape(1, 4);
+        assertEquals(1.0f, M.get(0, 0));
+        assertEquals(4.0f, M.get(0, 3));
+
+        M.reshape(4, 1);
+        assertEquals(1.0f, M.get(0, 0));
+        assertEquals(4.0f, M.get(3, 0));
+    }
+
+    public void testMmul() {
+        FloatMatrix R = A.dup();
+        FloatMatrix result = new FloatMatrix(4, 1, 94.0f, 108.0f, 122.0f, 136.0f);
+
+        A.mmuli(B, R);
+        assertEquals(result, R);
+
+        assertEquals(result, A.mmul(B));
+
+        FloatMatrix resultDE = new FloatMatrix(3, 3, 14.0f, 16.0f, 18.0f, -26.0f, -31.0f, -36.0f, 38.0f, 46.0f, 54.0f);
+
+        // In-place with independent operands
+        assertEquals(resultDE, D.mmuli(E, R));
+
+        // In-place on this
+        R = D.dup();
+        assertEquals(resultDE, R.mmuli(E, R));
+
+        // In-place on this
+        R = E.dup();
+        assertEquals(resultDE, D.mmuli(R, R));
+
+        // Fully dynamic
+        assertEquals(resultDE, D.mmul(E));
+    }
+
+    public void testAdd() {
+        FloatMatrix result = new FloatMatrix(3, 1, 1.0f, 6.0f, 5.0f);
+
+        FloatMatrix R = new FloatMatrix();
+
+        // In-place, but independent operands
+        B.addi(C, R);
+        assertEquals(result, R);
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.addi(C, R));
+
+        // In-place on other
+        R = C.dup();
+        assertEquals(result, B.addi(R, R));
+
+        // fully dynamic
+        assertEquals(result, B.add(C));
+
+        result = new FloatMatrix(3, 1, 3.0f, 5.0f, 9.0f);
+
+        // In-place, but independent operands
+        assertEquals(result, B.addi(1.0f, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.addi(1.0f, R));
+
+        // fully dynamic
+        assertEquals(result, B.add(1.0f));
+    }
+
+    public void testSub() {
+        FloatMatrix result = new FloatMatrix(3, 1, 3.0f, 2.0f, 11.0f);
+
+        FloatMatrix R = new FloatMatrix();
+
+        // In-place, but independent operands
+        assertEquals(result, B.subi(C, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.subi(C, R));
+
+        // In-place on other
+        R = C.dup();
+        assertEquals(result, B.subi(R, R));
+
+        // fully dynamic
+        assertEquals(result, B.sub(C));
+
+        result = new FloatMatrix(3, 1, 1.0f, 3.0f, 7.0f);
+
+        // In-place, but independent operands
+        assertEquals(result, B.subi(1.0f, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.subi(1.0f, R));
+
+        // fully dynamic
+        assertEquals(result, B.sub(1.0f));
+    }
+
+    public void testRsub() {
+        FloatMatrix result = new FloatMatrix(3, 1, 3.0f, 2.0f, 11.0f);
+
+        FloatMatrix R = new FloatMatrix();
+
+        // In-place, but independent operands
+        assertEquals(result, C.rsubi(B, R));
+
+        // In-place on this
+        R = C.dup();
+        assertEquals(result, R.rsubi(B, R));
+
+        // In-place on other
+        R = B.dup();
+        assertEquals(result, C.rsubi(R, R));
+
+        // fully dynamic
+        assertEquals(result, C.rsub(B));
+
+        result = new FloatMatrix(3, 1, -1.0f, -3.0f, -7.0f);
+
+        // In-place, but independent operands
+        assertEquals(result, B.rsubi(1.0f, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.rsubi(1.0f, R));
+
+        // fully dynamic
+        assertEquals(result, B.rsub(1.0f));
+    }
+
+    public void testMul() {
+        FloatMatrix result = new FloatMatrix(3, 1, -2.0f, 8.0f, -24.0f);
+
+        FloatMatrix R = new FloatMatrix();
+
+        // In-place, but independent operands
+        assertEquals(result, B.muli(C, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.muli(C, R));
+
+        // In-place on other
+        R = C.dup();
+        assertEquals(result, B.muli(R, R));
+
+        // fully dynamic
+        assertEquals(result, B.mul(C));
+
+        result = new FloatMatrix(3, 1, 1.0f, 2.0f, 4.0f);
+
+        // In-place, but independent operands
+        assertEquals(result, B.muli(0.5f, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.muli(0.5f, R));
+
+        // fully dynamic
+        assertEquals(result, B.mul(0.5f));
+    }
+
+    public void testDiv() {
+        FloatMatrix result = new FloatMatrix(3, 1, -2.0f, 2.0f, -2.666666666f);
+
+        FloatMatrix R = new FloatMatrix();
+
+        // In-place, but independent operands
+        assertEquals(result, B.divi(C, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.divi(C, R));
+
+        // In-place on other
+        R = C.dup();
+        assertEquals(result, B.divi(R, R));
+
+        // fully dynamic
+        assertEquals(result, B.div(C));
+
+        result = new FloatMatrix(3, 1, 1.0f, 2.0f, 4.0f);
+
+        // In-place, but independent operands
+        assertEquals(result, B.divi(2.0f, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.divi(2.0f, R));
+
+        // fully dynamic
+        assertEquals(result, B.div(2.0f));
+    }
+
+    public void testRdiv() {
+        FloatMatrix result = new FloatMatrix(3, 1, -2.0f, 2.0f, -2.666666666f);
+
+        FloatMatrix R = new FloatMatrix();
+
+        // In-place, but independent operands
+        assertEquals(result, C.rdivi(B, R));
+
+        // In-place on this
+        R = C.dup();
+        assertEquals(result, R.rdivi(B, R));
+
+        // In-place on other
+        R = B.dup();
+        assertEquals(result, C.rdivi(R, R));
+
+        // fully dynamic
+        assertEquals(result, C.rdiv(B));
+
+        result = new FloatMatrix(3, 1, 0.5f, 0.25f, 0.125f);
+
+        // In-place, but independent operands
+        assertEquals(result, B.rdivi(1.0f, R));
+
+        // In-place on this
+        R = B.dup();
+        assertEquals(result, R.rdivi(1.0f, R));
+
+        // fully dynamic
+        assertEquals(result, B.rdiv(1.0f));
+    }
+
+    /*# def test_logical(op, result, scalar, result2); <<-EOS
+    public void test#{op.upcase}() {
+    FloatMatrix result = new FloatMatrix(3, 1, #{result});
+    FloatMatrix result2 = new FloatMatrix(3, 1, #{result2});
+    FloatMatrix R = new FloatMatrix();
+    
+    // in-place but independent operands
+    assertEquals(result, B.#{op}i(F, R));
+    
+    // in-place but in other
+    R = F.dup();
+    assertEquals(result, B.#{op}i(R, R));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result, R.#{op}i(F, R));
+    
+    // fully dynamic
+    assertEquals(result, B.#{op}(F));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result2, R.#{op}i(#{scalar}, R));
+    
+    // fully dynamic
+    assertEquals(result2, B.#{op}(#{scalar}));	
+    }
+    EOS
+    end	
+    #*/
+    /*# test_logical('lt', '1.0f, 0.0f, 0.0f', 4.0f, '1.0f, 0.0f, 0.0f') #*/
+//RJPP-BEGIN------------------------------------------------------------
+    public void testLT() {
+    FloatMatrix result = new FloatMatrix(3, 1, 1.0f, 0.0f, 0.0f);
+    FloatMatrix result2 = new FloatMatrix(3, 1, 1.0f, 0.0f, 0.0f);
+    FloatMatrix R = new FloatMatrix();
+    
+    // in-place but independent operands
+    assertEquals(result, B.lti(F, R));
+    
+    // in-place but in other
+    R = F.dup();
+    assertEquals(result, B.lti(R, R));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result, R.lti(F, R));
+    
+    // fully dynamic
+    assertEquals(result, B.lt(F));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result2, R.lti(4.0f, R));
+    
+    // fully dynamic
+    assertEquals(result2, B.lt(4.0f));	
+    }
+//RJPP-END--------------------------------------------------------------
+	/*# test_logical('le', '1.0f, 1.0f, 0.0f', 4.0f, '1.0f, 1.0f, 0.0f') #*/
+//RJPP-BEGIN------------------------------------------------------------
+    public void testLE() {
+    FloatMatrix result = new FloatMatrix(3, 1, 1.0f, 1.0f, 0.0f);
+    FloatMatrix result2 = new FloatMatrix(3, 1, 1.0f, 1.0f, 0.0f);
+    FloatMatrix R = new FloatMatrix();
+    
+    // in-place but independent operands
+    assertEquals(result, B.lei(F, R));
+    
+    // in-place but in other
+    R = F.dup();
+    assertEquals(result, B.lei(R, R));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result, R.lei(F, R));
+    
+    // fully dynamic
+    assertEquals(result, B.le(F));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result2, R.lei(4.0f, R));
+    
+    // fully dynamic
+    assertEquals(result2, B.le(4.0f));	
+    }
+//RJPP-END--------------------------------------------------------------
+	/*# test_logical('gt', '0.0f, 0.0f, 1.0f', 4.0f, '0.0f, 0.0f, 1.0f') #*/
+//RJPP-BEGIN------------------------------------------------------------
+    public void testGT() {
+    FloatMatrix result = new FloatMatrix(3, 1, 0.0f, 0.0f, 1.0f);
+    FloatMatrix result2 = new FloatMatrix(3, 1, 0.0f, 0.0f, 1.0f);
+    FloatMatrix R = new FloatMatrix();
+    
+    // in-place but independent operands
+    assertEquals(result, B.gti(F, R));
+    
+    // in-place but in other
+    R = F.dup();
+    assertEquals(result, B.gti(R, R));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result, R.gti(F, R));
+    
+    // fully dynamic
+    assertEquals(result, B.gt(F));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result2, R.gti(4.0f, R));
+    
+    // fully dynamic
+    assertEquals(result2, B.gt(4.0f));	
+    }
+//RJPP-END--------------------------------------------------------------
+	/*# test_logical('ge', '0.0f, 1.0f, 1.0f', 4.0f, '0.0f, 1.0f, 1.0f') #*/
+//RJPP-BEGIN------------------------------------------------------------
+    public void testGE() {
+    FloatMatrix result = new FloatMatrix(3, 1, 0.0f, 1.0f, 1.0f);
+    FloatMatrix result2 = new FloatMatrix(3, 1, 0.0f, 1.0f, 1.0f);
+    FloatMatrix R = new FloatMatrix();
+    
+    // in-place but independent operands
+    assertEquals(result, B.gei(F, R));
+    
+    // in-place but in other
+    R = F.dup();
+    assertEquals(result, B.gei(R, R));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result, R.gei(F, R));
+    
+    // fully dynamic
+    assertEquals(result, B.ge(F));
+    
+    // in-place in this
+    R = B.dup();
+    assertEquals(result2, R.gei(4.0f, R));
+    
+    // fully dynamic
+    assertEquals(result2, B.ge(4.0f));	
+    }
+//RJPP-END--------------------------------------------------------------
+    public void testMinMax() {
+        assertEquals(1.0f, A.min());
+        assertEquals(12.0f, A.max());
+    }
+
+    public void testArgMinMax() {
+        assertEquals(0, A.argmin());
+        assertEquals(11, A.argmax());
+    }
+
+    public void testTranspose() {
+        FloatMatrix At = A.transpose();
+        assertEquals(1.0f, At.get(0, 0));
+        assertEquals(2.0f, At.get(0, 1));
+        assertEquals(5.0f, At.get(1, 0));
+    }
+
+    public void testGetRowVector() {
+        for (int r = 0; r < A.rows; r++) {
+            A.getRow(r);
+        }
+
+        for (int c = 0; c < A.columns; c++) {
+            A.getColumn(c);
+        }
+
+        A.addiRowVector(new FloatMatrix(3, 1, 10.0f, 100.0f, 1000.0f));
+        A.addiColumnVector(new FloatMatrix(1, 4, 10.0f, 100.0f, 1000.0f, 10000.0f));
+    }
+
+    public void testPairwiseDistance() {
+        FloatMatrix D = Geometry.pairwiseSquaredDistances(A, A);
+
+        FloatMatrix X = new FloatMatrix(1, 3, 1.0f, 0.0f, -1.0f);
+
+        Geometry.pairwiseSquaredDistances(X, X);
+
+        FloatMatrix A1 = new FloatMatrix(1, 2, 1.0f, 2.0f);
+        FloatMatrix A2 = new FloatMatrix(1, 3, 1.0f, 2.0f, 3.0f);
+
+        Geometry.pairwiseSquaredDistances(A1, A2);
+    }
+
+    public void testSwapColumns() {
+        FloatMatrix AA = A.dup();
+
+        System.out.println("testSwapColumns");
+        AA.swapColumns(1, 2);
+        assertEquals(new FloatMatrix(4, 3, 1.0f, 2.0f, 3.0f, 4.0f, 9.0f, 10.0f, 11.0f, 12.0f, 5.0f, 6.0f, 7.0f, 8.0f), AA);
+    }
+
+    public void testSwapRows() {
+        FloatMatrix AA = A.dup();
+
+        AA.swapRows(1, 2);
+        assertEquals(new FloatMatrix(4, 3, 1.0f, 3.0f, 2.0f, 4.0f, 5.0f, 7.0f, 6.0f, 8.0f, 9.0f, 11.0f, 10.0f, 12.0f), AA);
+    }
+
+    public void testSolve() {
+        FloatMatrix A = new FloatMatrix(3, 3, 3.0f, 5.0f, 6.0f, 1.0f, 0.0f, 0.0f, 2.0f, 4.0f, 0.0f);
+        FloatMatrix B = new FloatMatrix(3, 1, 1.0f, 2.0f, 3.0f);
+
+        FloatMatrix Adup = A.dup();
+        FloatMatrix Bdup = B.dup();
+
+        FloatMatrix X = Solve.solve(A, B);
+
+        assertEquals(Adup, A);
+        assertEquals(Bdup, B);
+    }
+
+    public void testConstructFromArray() {
+        float[][] data = {
+            {1.0f, 2.0f, 3.0f},
+            {4.0f, 5.0f, 6.0f},
+            {7.0f, 8.0f, 9.0f}
+        };
+
+        FloatMatrix A = new FloatMatrix(data);
+
+        for (int r = 0; r < 3; r++) {
+            for (int c = 0; c < 3; c++) {
+                assertEquals(data[r][c], A.get(r, c));
+            }
+        }
+    }
+
+    public void testDiag() {
+        FloatMatrix A = new FloatMatrix(new float[][]{
+                    {1.0f, 2.0f, 3.0f},
+                    {4.0f, 5.0f, 6.0f},
+                    {7.0f, 8.0f, 9.0f}
+                });
+
+        assertEquals(new FloatMatrix(3, 1, 1.0f, 5.0f, 9.0f), A.diag());
+
+        assertEquals(new FloatMatrix(new float[][]{
+                    {1.0f, 0.0f, 0.0f},
+                    {0.0f, 2.0f, 0.0f},
+                    {0.0f, 0.0f, 3.0f}
+                }), FloatMatrix.diag(new FloatMatrix(3, 1, 1.0f, 2.0f, 3.0f)));
+    }
+
+    public void testColumnAndRowMinMax() {
+        assertEquals(new FloatMatrix(1, 3, 1.0f, 5.0f, 9.0f), A.columnMins());
+        assertEquals(new FloatMatrix(4, 1, 1.0f, 2.0f, 3.0f, 4.0f), A.rowMins());
+        assertEquals(new FloatMatrix(1, 3, 4.0f, 8.0f, 12.0f), A.columnMaxs());
+        assertEquals(new FloatMatrix(4, 1, 9.0f, 10.0f, 11.0f, 12.0f), A.rowMaxs());
+        int[] i = A.columnArgmins();
+        assertEquals(0, i[0]);
+        assertEquals(0, i[1]);
+        assertEquals(0, i[2]);
+        i = A.columnArgmaxs();
+        assertEquals(3, i[0]);
+        assertEquals(3, i[1]);
+        assertEquals(3, i[2]);
+        i = A.rowArgmins();
+        assertEquals(0, i[0]);
+        assertEquals(0, i[1]);
+        assertEquals(0, i[2]);
+        assertEquals(0, i[3]);
+        i = A.rowArgmaxs();
+        assertEquals(2, i[0]);
+        assertEquals(2, i[1]);
+        assertEquals(2, i[2]);
+        assertEquals(2, i[3]);
+    }
+
+    public void testToArray() {
+        assertTrue(Arrays.equals(new float[]{2.0f, 4.0f, 8.0f}, B.toArray()));
+        assertTrue(Arrays.equals(new int[]{2, 4, 8}, B.toIntArray()));
+        assertTrue(Arrays.equals(new boolean[]{true, true, true}, B.toBooleanArray()));
+    }
+
+    public void testLoadAsciiFile() {
+        try {
+            FloatMatrix result = FloatMatrix.loadAsciiFile("/home/mikio/datasets/banana/banana_train_data_1.asc");
+            result.print();
+        } catch (Exception e) {
+            fail("Caught exception " + e);
+        }
+    }
+    
+    public void testRanges() {
+        A.print();
+        A.get(interval(0, 2), interval(0, 1)).print();
+    }
+}
diff --git a/test/org/jblas/la/TestGeometry.java b/test/org/jblas/la/TestGeometry.java
new file mode 100644
index 0000000..70efc93
--- /dev/null
+++ b/test/org/jblas/la/TestGeometry.java
@@ -0,0 +1,78 @@
+// --- 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.la;
+
+import org.jblas.la.DoubleMatrix;
+import org.jblas.la.Geometry;
+import junit.framework.TestCase;
+
+public class TestGeometry extends TestCase {
+	public void testCenter() {
+		DoubleMatrix x = new DoubleMatrix(3, 1, 1.0, 2.0, 3.0);
+		
+		Geometry.center(x);
+		
+		assertEquals(new DoubleMatrix(3, 1, -1.0, 0.0, 1.0), x);
+		
+		DoubleMatrix M = new DoubleMatrix(new double[][] {{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}, {7.0, 8.0, 9.0}});
+		
+		//M.print();
+		
+		DoubleMatrix MR = Geometry.centerRows(M.dup());
+		DoubleMatrix MC = Geometry.centerColumns(M.dup());
+		
+		//MR.print();
+		//MC.print();
+		
+		assertEquals(new DoubleMatrix(new double[][] {{-1.0, 0.0, 1.0}, {-1.0, 0.0, 1.0}, {-1.0, 0.0, 1.0}}), MR);
+		assertEquals(new DoubleMatrix(new double[][] {{-3.0, -3.0, -3.0}, {0.0, 0.0, 0.0}, {3.0, 3.0, 3.0}}), MC);
+	}				
+	
+	public void testPwDist() {
+		DoubleMatrix M = new DoubleMatrix(3, 5, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
+		
+		DoubleMatrix D = Geometry.pairwiseSquaredDistances(M, M);
+		
+		D.print();
+		
+		M = M.transpose();
+				
+		D = Geometry.pairwiseSquaredDistances(M, M);
+		
+		D.print();
+	}
+}
diff --git a/test/org/jblas/la/TestMatrixFunctions.java b/test/org/jblas/la/TestMatrixFunctions.java
new file mode 100644
index 0000000..1ab992a
--- /dev/null
+++ b/test/org/jblas/la/TestMatrixFunctions.java
@@ -0,0 +1,49 @@
+// --- 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.la;
+
+import org.jblas.la.DoubleMatrix;
+import junit.framework.TestCase;
+import static org.jblas.la.MatrixFunctions.*;
+
+public class TestMatrixFunctions extends TestCase {
+	public void testAbs() {
+		DoubleMatrix m = new DoubleMatrix(1, 2, 1.0, -1.0);
+		
+		assertEquals(new DoubleMatrix(1, 2, 1.0, 1.0), abs(m));
+	}
+}
diff --git a/test/org/jblas/la/TestSolve.java b/test/org/jblas/la/TestSolve.java
new file mode 100644
index 0000000..8c535e8
--- /dev/null
+++ b/test/org/jblas/la/TestSolve.java
@@ -0,0 +1,50 @@
+// --- 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.la;
+
+import junit.framework.TestCase;
+
+import org.jblas.la.*;
+
+public class TestSolve extends TestCase {
+	public void testFaultySolveSymmetric() {
+		DoubleMatrix A = new DoubleMatrix(3, 3, 2d, 1d, 0d, 2d, 1d, 2d, 0d, 1d, 2d);
+		DoubleMatrix x = new DoubleMatrix(1, 3, 1d, 2d, 3d);
+		
+		Solve.solveSymmetric(A, x);
+	}
+}
diff --git a/test/org/jblas/la/TicToc.java b/test/org/jblas/la/TicToc.java
new file mode 100644
index 0000000..4de4789
--- /dev/null
+++ b/test/org/jblas/la/TicToc.java
@@ -0,0 +1,70 @@
+// --- 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.la;
+
+public class TicToc {
+    private static long savedTime;
+
+    public static void tic(String message) {
+        System.out.print(message);
+        System.out.print("...");
+        System.out.flush();
+        savedTime = System.currentTimeMillis();
+    }
+
+    public static void tic(String message, Object... args) {
+        System.out.printf(message, args);
+        System.out.print("...");
+        System.out.flush();
+        savedTime = System.currentTimeMillis();
+    }
+
+    public static double toc() {
+        long elapsedTime = System.currentTimeMillis() - savedTime;
+        System.out.printf(" (%.2fs)", (double)elapsedTime / 1000d);
+        System.out.println();
+        return (double)elapsedTime / 1000d;
+    }
+
+    public static void main(String args[]) {
+        tic("counting to 10000000");
+        int counter = 0;
+        for (int i = 0; i < 10000000; i++)
+                counter++;
+        toc();
+    }
+}

-- 
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