Skip to content
Commits on Source (7)
.idea
.gradle
**/*.iml
**/*.ipr
EjmlVersion.java
\ No newline at end of file
<component name="CopyrightManager">
<copyright>
<option name="notice" value="Copyright (c) 2009-2015, Peter Abeles. All Rights Reserved.&#10;&#10;This file is part of Efficient Java Matrix Library (EJML).&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10; http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
<option name="keyword" value="Copyright" />
<option name="allowReplaceKeyword" value="" />
<option name="myName" value="ejml" />
<option name="myLocal" value="true" />
<option name="notice" value="Copyright (c) 2009-2018, Peter Abeles. All Rights Reserved.&#10;&#10;This file is part of Efficient Java Matrix Library (EJML).&#10;&#10;Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);&#10;you may not use this file except in compliance with the License.&#10;You may obtain a copy of the License at&#10;&#10; http://www.apache.org/licenses/LICENSE-2.0&#10;&#10;Unless required by applicable law or agreed to in writing, software&#10;distributed under the License is distributed on an &quot;AS IS&quot; BASIS,&#10;WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.&#10;See the License for the specific language governing permissions and&#10;limitations under the License." />
</copyright>
</component>
\ No newline at end of file
<component name="CopyrightManager">
<settings default="">
<settings default="ejml">
<module2copyright>
<element module="ejml" copyright="ejml" />
</module2copyright>
<LanguageOptions name="Groovy">
<option name="fileTypeOverride" value="1" />
</LanguageOptions>
<LanguageOptions name="HTML">
<option name="fileTypeOverride" value="1" />
<option name="prefixLines" value="false" />
</LanguageOptions>
<LanguageOptions name="Properties">
<option name="fileTypeOverride" value="1" />
</LanguageOptions>
</settings>
</component>
\ No newline at end of file
*.iws
\ No newline at end of file
language: java
jdk:
- openjdk6
- oraclejdk7
- oraclejdk8
- openjdk8
# - oraclejdk9
install:
- gradle autogenerate
- gradle assemble
script:
......@@ -9,9 +9,9 @@
## Introduction
Efficient Java Matrix Library (EJML) is a linear algebra library for manipulating dense matrices. Its design goals are; 1) to be as computationally and memory efficient as possible for both small and large matrices, and 2) to be accessible to both novices and experts. These goals are accomplished by dynamically selecting the best algorithms to use at runtime, clean API, and multiple interfaces. EJML is free, written in 100% Java and has been released under an Apache v2.0 license.
Efficient Java Matrix Library (EJML) is a linear algebra library for manipulating real/complex/dense/sparse matrices. Its design goals are; 1) to be as computationally and memory efficient as possible for both small and large matrices, and 2) to be accessible to both novices and experts. These goals are accomplished by dynamically selecting the best algorithms to use at runtime, clean API, and multiple interfaces. EJML is free, written in 100% Java and has been released under an Apache v2.0 license.
EJML has three distinct ways to interact with it: 1) procedural, 2) SimpleMatrix, and 3) Equations. Procedure provides all capabilities of EJML and almost complete control over memory creation, speed, and specific algorithms. SimpleMatrix provides a simplified subset of the core capabilities in an easy to use flow styled object-oriented API, inspired by Jama. Equations is a symbolic interface, similar in spirit to Matlab and other CAS, that provides a compact way of writing equations.
EJML has three distinct ways to interact with it: 1) Operations, 2) SimpleMatrix, and 3) Equations. Operations provides all capabilities of EJML and almost complete control over memory creation, speed, and specific algorithms with a procedural API. SimpleMatrix provides a simplified subset of the core capabilities in an easy to use flow styled object-oriented API, inspired by Jama. Equations is a symbolic interface, similar in spirit to Matlab and other CAS, that provides a compact way of writing equations.
The following functionality is provided:
* Basic operators (addition, multiplication, ...)
......@@ -20,12 +20,12 @@ The following functionality is provided:
* Decompositions (LU, QR, Cholesky, SVD, Eigenvalue, ...)
* Matrix Features (rank, symmetric, definitiveness, ...)
* Random Matrices (covariance, orthogonal, symmetric, ...)
* Different Internal Formats (row-major, block)
* Different Internal Formats (row-major, block, sparse, ...)
* Unit Testing
Unit tests are extensively used to ensure correctness of each algorithm's implementation. Internal benchmarks and Java Matrix Benchmark are both used to ensure the speed of this library.
==========================================================================
---------------------------------------------------------------------------
## Documentation
For a more detailed explanation of how to use the library see:
......@@ -36,65 +36,130 @@ The JavaDoc has also been posted online at:
http://ejml.org/javadoc/
==========================================================================
## Including in Gradle and Maven Projects
---------------------------------------------------------------------------
## Maven Central
EJML is on the Maven central repository and can easily be included in projects by adding the following code to the dependency section of your Maven or Gradle project. This will include all the modules in EJML.
EJML is in Maven central repository and can easily be added to Gradle, Maven, and similar project managers.
Gradle:
```
compile group: 'org.ejml', name: 'all', version: '0.27'
```
Maven:
```
<groupId>org.ejml</groupId>
<artifactId>all</artifactId>
<version>0.27</version>
<artifactId>ejml-all</artifactId>
<version>0.34</version>
```
Or you can include the required modules individually
Name | Description
-----------------|-------------------------------------------------------
core | Contains core data structures
dense64 | Algorithms for dense real 64-bit floats
denseC64 | Algorithms for dense complex 64-bit floats
equation | Equations interface
simple | Object oriented SimpleMatrix interface
This will add the entire library. Alternatively, you can include the required modules individually:
| Name | Description
|------------------|-------------------------------------------------------
| ejml-core | Contains core data structures and common code
| ejml-fdense | Algorithms for dense real 32-bit floats
| ejml-ddense | Algorithms for dense real 64-bit floats
| ejml-cdense | Algorithms for dense complex 32-bit floats
| ejml-zdense | Algorithms for dense complex 64-bit floats
| ejml-dsparse | Algorithms for sparse real 64-bit floats
| ejml-simple | Object oriented SimpleMatrix and Equations interfaces
---------------------------------------------------------------------------
==========================================================================
## Building
Gradle is the official build environment for EJML. In addition to all the standard commands the following are also available.
Gradle is the official build environment for EJML. Before the project can build you must run autogenerate
to create the 32-bit code.
```bash
cd ejml
./gradlew autogenerate
./gradlew install
```
After invoking those commands EJML will build and be in your local maven repo and can be included by other applications. Below is a list of custom Gradle commands that might be of use to you.
* createLibraryDirectory : To build all the modules as jars and save them in ejml/libraries
* oneJar : To compile all the modules into a single jar at ejml/EJML.jar
==========================================================================
---
## File System
* **docs/** :
Documentation for this library. This documentation is often out of date and online is the best place to get the latest.
* **examples/** :
Contains several examples of how EJML can be used to solve different problems or how EJML can be modified for different applications.
* **main/core** :
Contains all essential data structures
* **main/dense64** :
Algorithms for real dense 64-bit floating point matrices
* **main/denseC64** :
Algorithms for complex dense 64-bit floating point matrices
* **main/equation** :
Contains source code for Equations API
* **main/simple** :
Contains source code for SimpleMatrix
* **main/experimental/** :
Where experimental or alternative approaches and possibly buggy code goes that is not ready to be used by most users.
* **main/** :
Library source code
* **change.txt** :
History of what changed between each version.
* **TODO_Algorithms.txt** :
Contains a list of what needs to be added to this library.
==========================================================================
---------------------------------------------------------------------------
# Procedural, SimpleMatrix, and Equations API
EJML provides three different ways to access the library. This lets the user trade off ease of use for control/complexity. An example of each is shown below. All of which implement Kalman gain function:
[Procedural](http://ejml.org/wiki/index.php?title=Procedural)
```
mult(H,P,c);
multTransB(c,H,S);
addEquals(S,R);
if( !invert(S,S_inv) ) throw new RuntimeException("Invert failed");
multTransA(H,S_inv,d);
mult(P,d,K);
```
[SimpleMatrix](http://ejml.org/wiki/index.php?title=SimpleMatrix)
```
SimpleMatrix S = H.mult(P).mult(H.transpose()).plus(R);
SimpleMatrix K = P.mult(H.transpose().mult(S.invert()));
```
[Equations](http://ejml.org/wiki/index.php?title=Equations)
```
eq.process("K = P*H'*inv( H*P*H' + R )");
```
---------------------------------------------------------------------------
## Procedural API: Matrix and Class Names
EJML supports a variety of different matrix types and uses the following pattern for matrix class names:
```
Patterns:
<data type>Matrix<structure>
<data type>MatrixSparse<structure>
Description:
<data type> is a single character
'D' for real double
'F' for real float
'Z' for complex double
'C' for complex float
'B' for binary
<structure> is the name the internal data structure.
Matrix Suffix Abreviation Description
=========================================================================
RMaj RM dense row-major
RBlock RB dense block row-major
NxN FN dense fixed sized matrix of size N
N FN dense fixed sized vector of length N
CSC CC compressed sparse column
Triplet TR sparse triplet
=========================================================================
Examples:
DMatrixRMaj double real dense row-major matrix
CMatrixRMaj float complex dense row-major matrix
ZMatrixSparseCSC double complex sparse CSC matrix
CommonOps_DDRM Operations on DMatrixRMaj
CommonOps_DSCC Operations on DMatrixSparseCSC
```
Algorithms which operate on a specific matrix type have a suffix that's 5 characters, e.g. _DDRM. The first letter 'D' is the data type, the second letter 'D' is for dense (sparse is 'S'), and the last two letters are an abbreviation for the structure.
---------------------------------------------------------------------------
## Questions and Comments
A public message board has been created for asking questions and making comments:
......@@ -105,14 +170,15 @@ Bugs can either be posted on that message board or at:
https://github.com/lessthanoptimal/ejml/issues
==========================================================================
---------------------------------------------------------------------------
## Acknowledgements
I would like to thank all the people have made various comments, suggestions, and reported bugs. Also David Watkins
for writing "Fundamentals of Matrix Computations", which clearly explains algorithms and yet addresses important
implementation issues.
implementation issues. Timothy A. Davis for his book "Direct Methods for Sparse Linear Systems" and for CSparse
which provided the initial seed for the sparse algorithms.
==========================================================================
---------------------------------------------------------------------------
## License
EJML is released under the Apache v2.0 open source license
plugins {
id "com.peterabeles.gversion" version "1.1"
}
gversion {
srcDir = "main/ejml-core/src"
classPackage = "org.ejml"
className = "EjmlVersion"
}
allprojects {
apply plugin: 'idea'
apply plugin: 'eclipse'
group = 'org.ejml'
version = '0.28'
version = '0.34'
}
subprojects {
......@@ -12,10 +22,18 @@ subprojects {
apply plugin: 'maven'
apply plugin: 'signing'
sourceCompatibility = 1.6
targetCompatibility = 1.6
sourceCompatibility = 1.8
targetCompatibility = 1.8
javadoc.failOnError = false
// Enable incremental compile. Should make single file changes faster
tasks.withType(JavaCompile) {
options.incremental = true
}
test {
ignoreFailures true
reports.html.enabled = false
}
repositories {
mavenCentral()
......@@ -36,21 +54,37 @@ subprojects {
}
}
test {
generate {
java {
srcDir 'test'
srcDir 'generate'
}
compileClasspath += sourceSets.main.runtimeClasspath
}
benchmark {
java {
srcDir 'benchmarks/src'
}
resources {
srcDir 'benchmark/resources'
}
compileClasspath += sourceSets.main.runtimeClasspath
}
test {
java {
srcDir 'test'
srcDir 'benchmarks/test'
}
resources {
srcDir 'resources/test'
}
compileClasspath += sourceSets.benchmark.runtimeClasspath
}
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.11'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
jar {
......@@ -61,6 +95,7 @@ subprojects {
}
}
javadoc.failOnError = false
task javadocJar(type: Jar) {
classifier = 'javadoc'
from javadoc
......@@ -72,7 +107,8 @@ subprojects {
}
artifacts {
archives javadocJar, sourcesJar
archives sourcesJar
// archives javadocJar // uncomment for release
}
// if Maven central isn't setup in gradle.properties skip all of this
......@@ -98,7 +134,7 @@ subprojects {
name 'EJML'
packaging 'pom'
// optionally artifactId can be defined here
description 'A fast and easy to use dense matrix linear algebra library written in Java.'
description 'A fast and easy to use dense and sparse matrix linear algebra library written in Java.'
url 'http://ejml.org/'
scm {
......@@ -129,47 +165,43 @@ subprojects {
}
def allModules = [
':main:core',
':main:dense64',
':main:denseC64',
':main:equation',
':main:simple'
':main:ejml-core',
':main:ejml-ddense',
':main:ejml-dsparse',
':main:ejml-fdense',
':main:ejml-zdense',
':main:ejml-cdense',
':main:ejml-simple',
':main:ejml-experimental',
]
// Creates a directory with all the comiled jars
task createLibraryDirectory( dependsOn: allModules.collect{ it+":jar"}+allModules.collect{ it+":sourcesJar"}) << {
// Create lists of .class jars and source jars
ext.listJars = files(allModules.collect{ project(it).tasks.jar.archivePath })
ext.listSource = files(allModules.collect{ project(it).tasks.sourcesJar.archivePath })
task createLibraryDirectory( dependsOn: allModules.collect{ it+":jar"}+allModules.collect{ it+":sourcesJar"}) {
file('libraries').deleteDir()
file('libraries').mkdir()
doLast {
// Create lists of .class jars and source jars
ext.listJars = files(allModules.collect{ project(it).tasks.jar.archivePath })
ext.listSource = files(allModules.collect{ project(it).tasks.sourcesJar.archivePath })
copy {
from ext.listJars
from ext.listSource
into 'libraries'
file('libraries').deleteDir()
file('libraries').mkdir()
// append on BoofCV so it's clear which jars are part of BoofCV and which are not
rename { String fileName ->
"EJML-" + fileName
copy {
from ext.listJars
from ext.listSource
into 'libraries'
}
}
}
idea {
project {
jdkName = '1.6 (64bit)'
languageLevel = '1.6'
}
}
def javadocProjects = [
':main:denseC64',
':main:dense64',
':main:core',
':main:equation'
':main:ejml-core',
':main:ejml-ddense',
':main:ejml-dsparse',
':main:ejml-fdense',
':main:ejml-zdense',
':main:ejml-cdense',
':main:ejml-simple'
]
task alljavadoc(type: Javadoc) {
// only include source code in src directory to avoid including 3rd party code which some projects do as a hack
......@@ -178,11 +210,14 @@ task alljavadoc(type: Javadoc) {
classpath = files(javadocProjects.collect { project(it).sourceSets.main.compileClasspath })
destinationDir = file("${buildDir}/docs/javadoc")
// Hack for Java 8u121 and beyond. Comment out if running an earlier version of Java
options.addBooleanOption("-allow-script-in-comments", true)
configure(options) {
failOnError = false
docTitle = "Efficient Java Matrix Library (EJML) v$project.version"
links = [ 'http://docs.oracle.com/javase/7/docs/api/' ]
header = file('docs/header.txt').text
bottom = file('docs/bottom.txt').text // the quotes messes up javadoc still create bug report
links = [ 'http://docs.oracle.com/javase/8/docs/api/' ]
bottom = file('docs/bottom.txt').text
}
}
......@@ -192,8 +227,14 @@ task oneJarBin(type: Jar, dependsOn: javadocProjects.collect { it + ":compileJav
from files(javadocProjects.collect { project(it).sourceSets.main.output })
}
task wrapper(type: Wrapper) {
gradleVersion = '4.3'
}
project(':main:ejml-core').compileJava.dependsOn(createVersionFile)
// Disable the creation of jars for distribution. If you don't do this it will crash
[':main',':examples'].each {String a ->
[':main',':examples',':main:autocode'].each {String a ->
project(a) {
if( project.hasProperty('ossrhUsername') ) {
signArchives.enabled = false
......
<!--
~ Copyright (c) 2009-2017, Peter Abeles. All Rights Reserved.
~
~ This file is part of Efficient Java Matrix Library (EJML).
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project name="EJML" basedir="." default="main">
......@@ -132,7 +150,7 @@
</packageset>
<doctitle><![CDATA[<h1>Efficient Java Matrix Library API Specification</h1>]]></doctitle>
<bottom><![CDATA[<i>Copyright &#169; 2009-2015 Peter Abeles All Rights Reserved.</i>]]></bottom>
<bottom><![CDATA[<i>Copyright &#169; 2009-2017 Peter Abeles All Rights Reserved.</i>]]></bottom>
<!--<group title="Group 1 Packages" packages="com.dummy.test.a*"/>-->
<!--<group title="Group 2 Packages" packages="com.dummy.test.b*:com.dummy.test.c*"/>-->
<!--<link offline="true" href="http://java.sun.com/j2se/1.5.0/docs/api/" packagelistLoc="C:\tmp"/>-->
......@@ -147,41 +165,33 @@
author="true"
version="true"
use="true"
windowtitle="Efficient Java Matrix Library"
overview="src/overview.html">
windowtitle="Efficient Java Matrix Library">
<link offline="false" href="http://docs.oracle.com/javase/7/docs/api/" packagelistloc="package-list" />
<packageset dir="main/core/src" defaultexcludes="yes">
<packageset dir="main/ejml-cdense/src" defaultexcludes="yes">
<include name="org/ejml/**"/>
</packageset>
<packageset dir="main/dense64/src" defaultexcludes="yes">
<packageset dir="main/ejml-core/src" defaultexcludes="yes">
<include name="org/ejml/**"/>
</packageset>
<packageset dir="main/denseC64/src" defaultexcludes="yes">
<packageset dir="main/ejml-ddense/src" defaultexcludes="yes">
<include name="org/ejml/**"/>
</packageset>
<packageset dir="main/equation/src" defaultexcludes="yes">
<packageset dir="main/ejml-dsparse/src" defaultexcludes="yes">
<include name="org/ejml/**"/>
</packageset>
<packageset dir="main/simple/src" defaultexcludes="yes">
<packageset dir="main/ejml-fdense/src" defaultexcludes="yes">
<include name="org/ejml/**"/>
</packageset>
<packageset dir="main/ejml-simple/src" defaultexcludes="yes">
<include name="org/ejml/**"/>
</packageset>
<packageset dir="main/ejml-zdense/src" defaultexcludes="yes">
<include name="org/ejml/**"/>
</packageset>
<doctitle><![CDATA[<h1>Efficient Java Matrix Library API Specification:</h1>]]></doctitle>
<header><![CDATA[<script type="text/javascript"><!--
google_ad_client = "ca-pub-0419821832107208";
/* boofcv javadoc banner */
google_ad_slot = "3257872658";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
]]>
</header>
<bottom><![CDATA[<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
......@@ -193,7 +203,7 @@ src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<br>
<b>Copyright &copy; 2009-2015 Peter Abeles</b>
<b>Copyright &copy; 2009-2017 Peter Abeles</b>
]]>
</bottom>
</javadoc>
......
......@@ -2,6 +2,207 @@ Change log for EJML
Date format: year/month/day
----- Version 0.34
2018/04/13
- SimpleMatrix
* Added createLike()
* Removed most hard coded matrix types internally
* Change simple matrix's constructor to take in an array to remove confusion over float and double
* Fixed bug in concatRows and concatColumns
* Renamed set(double) to fill(double)
* Made set(row,col, value) generic
* Added automatic conversion of matrix types during an operation.
- Very simple heuristic. Only ensures that everything is the same matrix type
- Fixed Sized Matrices
* Added multiplication and scale operations
- QRP
* Dense real version was incorrectly scaling the threshold for singularity detection
- Created SolveNullSpace
* Make it easier and faster to find the null space
* QR, QRP, and SVD
- Equation
* Added print() This will print to stdout the results of what's inside
* Fixed bug. Can handle comma inside a brucket block that's in a function call.
"b=normF([[1 2],1])"
* Added random matrices and ability to specify the seed
rand,randn,rng
* Added ability to print expression's output
* Added automatic conversion from FMatrixRMaj to DMatrixRMaj
- EjmlVersion
* Contains version information
----- Version 0.33
2018/01/17
- BMatrixRMaj
* Added fill()
* Added sum()
- Relaxed length requirements on permutation vector
* Thanks Florian Enner for the pull request
- Added MatrixFeatures_D which work on all double real matrices
* isEquals()
* isIdentical()
- CommonOps_*DRM
* More functions throw MatrixDimensionException
* Some functions will resize input when there's a miss match now
- Operations
* Prints a useful error message when you try to add,subtract,multiply a 1x1 matrix against a NxM matrix
- Added CommonOps_BDRM
* transposeSquare()
- CSV Parsing support
* Supports all dense types now
* Refactored to reflect new matrix names
* Added support for writing and reading sparse matrix in CSV
----- Version 0.32
2017/09/18
- Thanks to HEBI Robotics for sponsoring the addition of sparse solvers!
* http://hebirobotics.com/
- Examples
* Added new example showing how to use results from an LU decomposition to solve
- CommonOps - RMaj
* Added concatColumns(A,B) concatRows(A,B)
- Simple Matrix
* Added concatColumns(A,B) concatRows(A,B)
* Added rows(begin,end) <-- extracts the specified rows
* Added cols(begin,end) <-- extracts the specified columns
* Fixed issue with bits() and derived classes. Thanks Florian Enner
* Redesigned internals to make it more module and easier to add support for different types of matrices
- DMatrixSparseCSC
* Fixed bug in set(row,col,val) where the first time a non-zero element was added it would assign the wrong value
Thanks GeoffreyGuettier
* Added growMaxColumns()
- MatrixFeatures_DSCC
* Added isSymmetric()
* Added isOrthogonal()
- ConvertDMatrixStruct
* Moved functions from ConvertDMatrixSparse into this class
* Added tolerance for zero when converting from dense to sparse
- RandomMatrices_DSCC
* Added symmetric()
* Added symmetricPosDef()
- CommonOps_DSCC
* Added permuteSymmetric()
* Added checkDuplicates()
* Added isPositiveDefinite()
* Added concatColumns()
* Added concatRows()
* Added extractColumn()
* Added dotInnerColumns()
* Added solve() dense
* Added invert() dense
* Added det()
* Added removeZeros()
* Added changeSign()
* Added elementSum()
* Added elementMult()
* Added trace()
* Fixed various bugs
- CommonOps_DDRM
* Added permuteRowInv()
- Sparse Decompositions and Solvers
* Cholesky - Up Looking
* LU
* QR
- Sparse Triangular Solver
* Added solveTranL()
* Added column pivots to one of the solvers
- Data Types
* Added DScalar and IScalar
* Added *GrowArray to act as workspace in sparse algorithms
- SolvePseudoInverseSvd_DDRM
* Recycles memory for U and V internally
* Thanks Florian Enner for pointing this out
----- Version 0.31
2017/05/18
- Changed minimum Java version from 6 to 7
- Added SimpleEVD.getEigenvalues()
- Added SimpleSVD.getSingularValues()
- Fixed issue with generics and SimpleEVD and SimpleSVD
- Auto generated float 32-bit support of all 64-bit code
- SimpleMatrix
* Added support for float 32-bit matrices
* Replaced extractDiag() with diag() and changed behavior.
- Fixed Sized Matrix
* Added MatrixFeatures
* Added NormOps
* FixedOps
- Discovered a bug in a unit test
- Fixed bugs in elementAbsMax() elementAbsMin() trace()
- Improved the speed of element-wise max and min operations
- New naming for matrices (see readme)
- New naming for operation classes (see readme)
- Operations API
* added minCol(), maxCol(), minRow(), maxRow()
- Sparse matrix support for real values
* Compressed Sparse Column (CSC) a.k.a. Compressed Column
* Triplet
* Basic operation up to triangular solve
- A script has been provided that will perform most of the refactorings:
convert_to_ejml31.py
- Fixed a minor printing glitch for dense matrices. There was an extra space
- Equations
* Assignment to a submatrix now works with variables
A((2+i):10,1:20) = 5 <--- this works now
* Added sum(), sum(A,0), sum(A,1)
* min(A,0), max(A,0), min(A,1), max(A,1),
- Modules now have "ejml-" as a suffice to avoid collisions with other libraries
- equations module has been moved into ejml-simple for dependency reasons
----- Version 0.30
2016/11/09
- Thanks Peter Fodar for fixing misleading javadoc
- Fixed bug in computation of eigenvectors where the first eigenvalue was complex it would get messed up
* Thanks user343 for reporting the bug!
- Complex matrix multiplication
* added multTransA variants
* added multTransB variants
* added multTransAB variants
- Added the following complex decompositions
* Hessenberg Similar Decomposition
* Tridiagonal Similar Decomposition
- Added MatrixFeatures.isLowerTriangle()
- Added createLike() to all matrices
* Creates a new matrix that is the same size and shape. filled with zeros initially
- Fixed CRandomMatrices.createHermitian()
- Fixed CMatrixFeatures.isHermitian()
----- Version 0.29
2016/01/23
- CommonOps
* Added extract with int[] for rows and columns or just indexes
* Added support for matrix element-wise inequality functions and boolean matrix
- This does go a little bit beyond the strict "linear algebra" only scope
- Primarily driven by adding features to Equations
- Equations
* Can now create vectors using integer sequences
a = [5:10]
a = [ 2 3 4 0,-2, 4 ]
Commas are needed when using negative numbers or else it will think you're doing a-b instead of a and -b.
* Now now reference submatrices using integer sequences. Works in 1D and 2D.
b = A(1 2 3 2 0 , 4: ) <-- 2D sub-matrix
c = A(4:3:20 3 4 5) <-- reference elements by index in the sequence. c will be a row matrix
* Sub-matrix also works for assignment
d(3,5:) = f
* Added macros
Example: "macro m2m(a) = a*2*a"
- Added DenseMatrixBool
* boolean matrix
----- Version 0.28
2015/07/09
......
#!/usr/bin/python
import fnmatch
import os
import sys
def findReplace(directory, find, replace, filePattern):
changed = 0
examined = 0
for path, dirs, files in os.walk(os.path.abspath(directory)):
for filename in fnmatch.filter(files, filePattern):
examined += 1
filepath = os.path.join(path, filename)
with open(filepath) as f:
s = f.read()
c = s.replace(find, replace)
if s != c:
changed += 1
with open(filepath, "w") as f:
f.write(c)
if changed > 0:
print "changed {:4d} examined {:4d} {:s} -> {:s}".format(changed,examined,find,replace)
if len(sys.argv) < 2:
print "Need to specify where to apply the script to"
exit(0)
location = sys.argv[1]
print "Recursively apply search and replace to "+location
def F(find,replace):
findReplace(location,find,replace,"*.java")
def G(patA,patB):
F(patA+"64F",patB+"_F64")
def H(patA,patB):
F(patA+"64F",patB+"_C64")
F("org.ejml.factory.DecompositionFactory","org.ejml.dense.row.factory.DecompositionFactory_DDRM")
F("org.ejml.alg.dense.mult.VectorVectorMult","org.ejml.dense.row.mult.VectorVectorMult_DDRM")
F("org.ejml.factory.LinearSolverFactory","org.ejml.dense.row.factory.LinearSolverFactory_DDRM")
F("org.ejml.ops.CommonOps","org.ejml.dense.row.CommonOps_DDRM")
F("org.ejml.ops.NormOps","org.ejml.dense.row.NormOps_DDRM")
F("org.ejml.ops.SingularOps","org.ejml.dense.row.SingularOps_DDRM")
F("org.ejml.ops.SpecializedOps","org.ejml.dense.row.SpecializedOps_DDRM")
F("org.ejml.ops.MatrixFeatures","org.ejml.dense.row.MatrixFeatures_DDRM")
F("org.ejml.ops.RandomMatrices","org.ejml.dense.row.RandomMatrices_DDRM")
F("org.ejml.alg.dense.linsol.LinearSolverSafe","org.ejml.LinearSolverSafe")
F("org.ejml.alg.dense.mult.MatrixMultProduct","org.ejml.dense.row.mult.MatrixMultProduct_DDRM")
F("org.ejml.interfaces.decomposition.EigenDecomposition","org.ejml.interfaces.decomposition.EigenDecomposition_F64")
F("org.ejml.alg.fixed.FixedOps","org.ejml.dense.fixed.CommonOps_DDF")
F("org.ejml.ops.ConvertMatrixType","org.ejml.ops.ConvertDMatrixStruct")
# F("","")
for n in ["CholeskyDecomposition","EigenDecomposition",
"CholeskyLDLDecomposition","BidiagonalDecomposition",
"LUDecomposition","QRPDecomposition",
"SingularValueDecomposition","TridiagonalSimilarDecomposition"]:
package_path = "org.ejml.interfaces.decomposition."
F(package_path+n+";",package_path+n+"_F64;")
F(n+"<DenseMatrix64F>",n+"_F64<DMatrixRMaj>")
F("CommonOps.","CommonOps_DDRM.")
F("CovarianceOps.","CovarianceOps_DDRM.")
F("EigenOps.","EigenOps_R64.")
F("MatrixFeatures.","MatrixFeatures_DDRM.")
F("NormOps.","NormOps_DDRM.")
F("RandomMatrices.","RandomMatrices_DDRM.")
F("SingularOps.","SingularOps_DDRM.")
F("SpecializedOps.","SpecializedOps_DDRM.")
F("DecompositionFactory.","DecompositionFactory_DDRM.")
F("VectorVectorMult.","VectorVectorMult_DDRM.")
F("LinearSolverFactory.","LinearSolverFactory_DDRM.")
F("MatrixMultProduct.","MatrixMultProduct_DDRM.")
F("MatrixFeatures.","MatrixFeatures_DDRM.")
F("ConvertMatrixType.","ConvertDMatrixStruct.")
F("UtilEjml.parseMatrix","UtilEjml.parse_DDRM")
G("Complex","Complex")
G("ComplexMath","ComplexMath")
F("DenseMatrix64F","DMatrixRMaj")
F("BlockMatrix64F","DMatrixRBlock")
# Random matrix functions that got refactored
F("DDRM.createSymmetric","DDRM.symmetric")
F("DDRM.createRandom","DDRM.rectangle")
F("DDRM.createOrthogonal","DDRM.orthogonal")
F("DDRM.setRandom","DDRM.fillUniform")
for n in range(2,7):
F("FixedFeatures{:d}".format(n),"MatrixFeatures_DDF{:d}".format(n))
F("FixedNormOps{:d}".format(n),"NormOps_DDF{:d}".format(n))
F("FixedOps{:d}".format(n),"CommonOps_DDF{:d}".format(n))
F("FixedMatrix{:d}x{:d}_64F".format(n,n),"DMatrix{:d}x{:d}".format(n,n))
F("FixedMatrix{:d}_64F".format(n,n),"DMatrix{:d}".format(n,n))
print "Finished!"
libejml-java (0.28-1) UNRELEASED; urgency=low
libejml-java (0.34-1) UNRELEASED; urgency=medium
* Initial release (Closes: #???)
* New upstream version
* Standards-Version: 4.1.4
* Point Vcs-fields to Salsa
* debhelper 11
-- Andreas Tille <tille@debian.org> Wed, 05 Jun 2013 14:51:51 +0200
-- Andreas Tille <tille@debian.org> Wed, 02 May 2018 07:52:24 +0200
libejml-java (0.28-1) unstable; urgency=low
* Initial release (Closes: #805381)
-- Andreas Tille <tille@debian.org> Tue, 17 Nov 2015 16:32:53 +0100
......@@ -3,14 +3,14 @@ Maintainer: Debian Java Maintainers <pkg-java-maintainers@lists.alioth.debian.or
Uploaders: Andreas Tille <tille@debian.org>
Section: java
Priority: optional
Build-Depends: debhelper (>= 9),
Build-Depends: debhelper (>= 11~),
javahelper,
default-jdk,
ant,
gradle
Standards-Version: 3.9.6
Vcs-Browser: https://anonscm.debian.org/cgit/pkg-java/libejml-java.git
Vcs-Git: git://anonscm.debian.org/pkg-java/libejml-java.git
Standards-Version: 4.1.4
Vcs-Browser: https://salsa.debian.org/java-team/libejml-java
Vcs-Git: https://salsa.debian.org/java-team/libejml-java.git
Homepage: http://ejml.org/wiki
Package: libejml-java
......@@ -37,4 +37,3 @@ Description: Efficient Java Matrix Library
flow styled object-oriented API, inspired by Jama. Equations is a
symbolic interface, similar in spirit to Matlab and other CAS, that
provides a compact way of writing equations.
Feature TODO
- a = [5:10]
- first: b = [1 2 50 69]
then: c(b) = 1
Maybe do this by parsing "5:10" and "1 2 3 4 5" into IntegerSequence with specific types range and list?
Have an interator in IntegerSequence for generic processing, but allow for specialized for each sequence type?
- Block bidiagonal
- Explore having the various implementations of MatrixMult_* internally invoke an interface that can be swapped
* Performance hit for small matrices?
*
-------------------
- Add to CommonOps invertSPD()
- Unroll symmetric inverse by minor
......@@ -42,6 +41,7 @@ For some future Release
- Save up rotators, multiply against each other, then multiply against U and V
- Divide and conquer algorithm
- An implementation that just finds zero singular values
- Bidiagonal decompositions have a lot of inefficient code
- Incremental SVD
......
......@@ -9,4 +9,4 @@
</script>
<br>
<b>Copyright &copy; 2009-2015 Peter Abeles</b>
<b>Copyright &copy; 2009-2018 Peter Abeles</b>
......@@ -18,11 +18,11 @@ the number of permutations.
Block Cholesky Decomposition
---------------------------
The DenseMatrix64F based CholeskyDecompositionBlock class is easier to tune and offers equivalent
The DMatrixRMaj based CholeskyDecompositionBlock class is easier to tune and offers equivalent
performance to BlockMatrix64F based BlockCholeskyOuter class. CholeskyDecompositionBlock achieves
optimal performance with munch smaller block sizes, but its performance actually degrades when
larger blocks that are optimal for BlockMatrix64F algorithms are used. CholeskyDecompositionBlock
also works directly with DenseMatrix64F and avoids the need to convert matrix types.
also works directly with DMatrixRMaj and avoids the need to convert matrix types.
Block matrix solver is much faster than the row-major solver.
......
Sparse Matrix
- TODO Add fill reduce algorithms
* Update CommonOps.solve() to specify a reasonable general purpose algorithm
- TODO After fill reducing algorithms have been implemented revisit all unit tests which touch them and update
- TODO autogenerate float sparse code
TODO functions? func name( Matrix a, int b, double c ) = a(b:(2*b),:).*c
TODO equations support for boolean matrices and inequalities
TODO Neural network back propagation example?
TODO MatrixMatrixMult
- Strip all inner accessors to matrix values
- Functions for checking inputs
TODO look at sparse matrix contribution
TODO equations support for boolean matrices and inequalities
\ No newline at end of file
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- boofcv javadoc banner -->
<ins class="adsbygoogle"
style="display:inline-block;width:468px;height:60px"
data-ad-client="ca-pub-0419821832107208"
data-ad-slot="3257872658"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
\ No newline at end of file
\documentclass[12pt]{article}%book report
\usepackage{bm}
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage[pdftex]{graphicx}
\title{Efficient Java Matrix Library}
\author{Peter Abeles}
\date{\today}
\begin{document}
\maketitle
\tableofcontents
\begin{abstract}
Efficient Java Matrix Library (EJML) is a linear algebra library for manipulating dense matrices. Its design goals are; 1) to be as computationally efficient as possible for both small and large matrices, and 2) to be accessible to both novices and experts. These goals are accomplished by dynamically selecting the best algorithms to use at runtime and by designing a clean API. EJML is free, written in 100\% Java and has been released under an LGPL license.
http://code.google.com/p/efficient-java-matrix-library/
\end{abstract}
\section{IMPORANT}
This document is horribly out of date but for some reason its a top result on google. To get the latest documentation go to:
http://code.google.com/p/efficient-java-matrix-library/
\section{Introduction}
Efficient Java Matrix Library (EJML) is a linear algebra library for manipulating dense matrices. Its design goals are; 1) to be as computationally efficient as possible for both small and large matrices, and 2) to be accessible to both novices and experts. These goals are accomplished by dynamically selecting the best algorithms to use at runtime and by designing a clean API. EJML is free, written in 100\% Java and has been released under an LGPL license.
EJML has three distinct ways to interact with it. This allows a programmer to choose between simplicity and efficiency. 1) A simplified interface that allows a more object oriented way of programming. 2) Letting EJML select the best algorithm to use. 3) Directly calling specialized algorithms. In general EJML is one the fastest single threaded pure Java library. See Java Matrix Benchmark for a detailed comparison of different libraries.
The following is provided:
\begin{itemize}
\item Basic operators (addition, multiplication, ... ).
\item Linear Solvers (batch and incremental).
\item Decompositions (LU, QR, Cholesky, SVD, Eigenvalue).
\item Matrix Features (rank, symmetric, definitiveness, ... ).
\item Random Matrices (covariance, orthogonal, symmetric, ..
\end{itemize}
In addition there are many specialized algorithms for specific matrix sizes and types.
\section{Data Structures and Algorithms}
\label{sec:structures}
DenseMatrix64F is the most basic data structure in EJML. It is a dense matrix composed of doubles. Internally the matrix is stored as a single array using a row-major format, see Figure \ref{fig:rowmajor}. SimpleMatrix is a wrapper on top of DenseMatrix64F that provides a simplified interface.
\begin{figure}[h]
\begin{displaymath}
\begin{array}{|c|c|c|}
\hline
a_{11} & a_{12} & a_{13} \\
\hline
a_{21} & a_{22} & a_{23} \\
\hline
\end{array}
\rightarrow
\begin{array}{|c|c|c|c|c|c|}
\hline
a_{11} & a_{12} & a_{13} & a_{21} & a_{22} & a_{23} \\
\hline
\end{array}
\end{displaymath}
\caption{\label{fig:rowmajor}A matrix encoded in row-major format.}
\end{figure}
An operation, in this context, is just a mathematical function that takes at least one matrix in as an input. For example addition and subtraction are both operators. CommonOps and SpecializedOps are two classes which have several static functions that are operators for DenseMatrix64F. SimpleMatrix has all of its operators as part of its class for convenience. For a comparision of using operators with DenseMatrix64F and SimpleMatrix see Figure \ref{fig:ops_vs_simple}.
There are many operators in EJML. Figure \ref{fig:operators} contains a list of some of the operators in this libraries. Figure \ref{fig:simplefuncs} contains a list of operators that can be directly performed by SimpleMatrix. To make SimpleMatrix easier to program with, only a subset of the most essential operators are provided. However, by directly accessing the internal DenseMatrix64 in a SimpleMatrix, all the operators can be called on it.
\begin{figure}[h]
\begin{center}
\begin{tabular}{c}
Matrix multiplcation using operations. \\
\hline \\
\begin{minipage}[c]{10cm}
\begin{verbatim}
DenseMatrix64F c =
new DenseMatrix64F(a.numRows,b.numCols);
CommonOps.mult(a,b,c);
\end{verbatim}
\end{minipage}
\\
\vspace{1cm}\\
Matrix multiplcation using SimpleMatrix \\
\hline \\
\begin{minipage}[c]{10cm}
\begin{verbatim}
SimpleMatrix c = a.times(b);
\end{verbatim}
\end{minipage}
\end{tabular}
\end{center}
\caption{\label{fig:ops_vs_simple}Comparision operations and SimpleMatrix.}
\end{figure}
Some of the operators do not specify which specific algorithm is used and some do. For example, many of the operators in CommonOps can call different algorithms depending on the structure of the matrix passed in. This allows the most efficient algorithm to be called. However, many the functions in MatrixMatrixMult are designed to be optimal for matrices of different sizes. Unless there is a very good reason not to, all calls should be made to the more generic operators.
One good reason not to use the generic operators is if you, the programmer, knows something they do not. For example, if a matrix is positive definite, then the generic inverse function is suboptimal. In that situation you should use CholeskyDecomposition directly because it is much faster.
\begin{figure}[h]
\begin{tabular}{cll}
Class & function & description \\
\hline
CommonOps & mult & $C = AB$ and $C = \alpha AB$ and $C = A^TB$ \\
CommonOps & multTranA & $C = A^TB$ and $C = \alpha A^TB$\\
CommonOps & multTranAB & $C = A^TB^T$ and $C = \alpha A^TB^T$\\
CommonOps & multTranB & $C = AB^T$ and $C = \alpha AB^T$\\
CommonOps & multAdd & $C = C+AB$ and $C = C+\alpha AB$\\
CommonOps & multAddTranA & $C = C+A^TB$ and $C = C+\alpha A^TB$\\
CommonOps & multAddTranAB & $C = C+A^TB^T$ and $C = C+\alpha A^TB^T$\\
CommonOps & multAddTranB & $C = C+AB^T$ and $C = C+\alpha AB^T$\\
CommonOps & multElement & $c_{ij} = a_{ij} b_{ij}$ \\
CommonOps & add & $C = A+B$, $C = \alpha A+\beta B$\\
CommonOps & addEquals & $A = A+B$, $A = A + \beta B$\\
CommonOps & sub & $C = A-B$ \\
CommonOps & subEquals & $A = A-B$\\
CommonOps & invert & Matrix inverse $A^{-1}$\\
CommonOps & solve & Solves for $X = A^{-1} B$\\
CommonOps & normF & Matrix norm \\
CommonOps & scale & $a_{ij} = \alpha a_{ij}$ \\
CommonOps & transpose & $a_{ij} = a_{ji}$ \\
CommonOps & trace & $\sum_i a_{ii}$ \\
SpecializedOps & identity & Creates an identity matrix \\
SpecializedOps & diag & Creates a diagonal matrix \\
SpecializedOps & submatrix & Creates a submatrix of the original \\
SpecializedOps & diffNormF & $\sqrt{\sum_{ij}(a_{ij}-b_{ij})^2 }$ \\
SpecializedOps & diffNormP1 & $\sum_{ij}|a_{ij}-b_{ij}|$ \\
SpecializedOps & copyChangeRow & Swaps the rows of the original matrix \\
MatrixFeatures & hasNaN & Does the matrix contain a NaN \\
MatrixFeatures & hasUncountable & Does the matrix contain a NaN or Infinity\\
MatrixFeatures & isVector & Is the matrix a vector? \\
MatrixFeatures & isPositiveDefinite & Is the matrix positive definite? \\
MatrixFeatures & isPositiveSemidefinite & Is the matrix positive semidefinite? \\
MatrixFeatures & isSquare & Is the matrix square? \\
MatrixFeatures & isSymmetric & Is the matrix symmetric? \\
MatrixFeatures & isSimilar & $|a_{ij}-b_{ij}|\le \sigma \; \forall \; i,j$ \\
CovarianceOps & isValidFast & Quick covariance validity check. \\
CovarianceOps & isValid & Rigerous covariance validity check. \\
CovarianceOps & invert & Faster covariance matrix inversion. \\
CovarianceOps & randomVector & Draws a random vector from the covariance. \\
\end{tabular}
\caption{\label{fig:operators}Some of the matrix operators included in EJML}
\end{figure}
\begin{figure}[h]
\begin{tabular}{ll}
function & description \\
\hline
wrap & Allows a DenseMatrix64F to be manipulated as a SimpleMatrix. \\
identity & Creates an identity matrix.\\
random & Creates a matrix with random elements.\\
diag & Creates a diagonal matrix. \\
getMatrix & Returns the internal DenseMatrix64F.\\
transpose & Returns the transpose of this matrix.\\
mult(B) & Returns $AB$\\
plus(B) & Returns $A+B$\\
minus(B) & Returns $A-B$\\
plus($\beta$,B) & Returns $A+\beta B$\\
scale($\alpha$) & Returns $\alpha A$\\
invert() & Returns $A^{-1}$\\
solve(B) & Returns $X=A^{-1}B$\\
set(val) & $a_{ij} = val$\\
zero & $a_{ij} = 0$ \\
norm & Returns the matrix norm. \\
determinant & Returns the determinant. \\
trace & Returns the matrix's trace. \\
reshape & Changes the matrix's shape with out declaring new data. \\
computeSVD & Singular Value Decomposition \\
set(i,j,val) & $a_{ij} = val$ \\
get(i,j) & Returns $a_{ij}$ \\
numRows() & Returns number of rows.\\
numCols() & Returns number of columns.\\
\end{tabular}
\caption{\label{fig:simplefuncs}Functions provided by SimpleMatrix.}
\end{figure}
\section{Examples}
In the examples directory three different implementations of a Kalman filter are provided along with a Levenberg-Marquardt optimization algorithm. These two algorithms are popular in various engineering disciplines.
The three different implementations of the Kalman filter are provided. Each one demonstrates different ways that EJML can be used. to show off the interfaces that one can use in EJML. In the following subsections the update function is shown and discussed.
\subsection{KalmanFilterSimple.java}
Figure \ref{fig:update_simple} shows several concepts related to the simple interface. The wrap() function on the top demonstrates how a regular DenseMatrix64F can be changed into a SimpleMatrix with ease. Memory management is at a minimal since new matrices of the correct size are automatically created by each operation. The code is also noticeably easier to read.
\begin{figure}[h]
\begin{verbatim}
public void update(DenseMatrix64F _z, DenseMatrix64F _R) {
// a fast way to make the matrices usable by SimpleMatrix
SimpleMatrix z = SimpleMatrix.wrap(_z);
SimpleMatrix R = SimpleMatrix.wrap(_R);
// y = z - H x
SimpleMatrix y = z.minus(H.mult(x));
// S = H P H' + R
SimpleMatrix S = H.mult(P).mult(H.transpose()).plus(R);
// K = PH'S^(-1)
SimpleMatrix K = P.mult(H.transpose().mult(S.invert()));
// x = x + Ky
x = x.plus(K.mult(y));
// P = (I-kH)P = P - KHP
P = P.minus(K.mult(H).mult(P));
}
\end{verbatim}
\caption{\label{fig:update_simple}Code from KalmanFilterSimple.java}
\end{figure}
\subsection{KalmanFilterOps.java}
The operation interface, shown in Figure \ref{fig:update_ops}, is noticeably more complex. It requires matrices to be predeclared. For this to work the programmer needs to figure out the exact shape of these intermediate matrices. What was on one line now takes up multiple lines.
Memory management is more complicated in this example. In Figure \ref{fig:predeclare} matrices that store the intermediate results are declared in the constructor. This requires more though from the programmer, but greatly reduces the amount of memory created and destroyed each processing cycle.
\begin{figure}[h]
\begin{verbatim}
public void update(DenseMatrix64F z, DenseMatrix64F R) {
// y = z - H x
mult(H,x,y);
sub(z,y,y);
// S = H P H' + R
mult(H,P,c);
multTransB(c,H,S);
addEquals(S,R);
// K = PH'S^(-1)
if( !invert(S,S_inv) ) throw new RuntimeException("Invert failed");
multTransA(H,S_inv,d);
mult(P,d,K);
// x = x + Ky
mult(K,y,a);
addEquals(x,a);
// P = (I-kH)P = P - (KH)P = P-K(HP)
mult(H,P,c);
mult(K,c,b);
subEquals(P,b);
}
\end{verbatim}
\caption{\label{fig:update_ops}Code from KalmanFilterOps.java}
\end{figure}
\begin{figure}
\begin{verbatim}
a = new DenseMatrix64F(dimenX,1);
b = new DenseMatrix64F(dimenX,dimenX);
y = new DenseMatrix64F(dimenZ,1);
S = new DenseMatrix64F(dimenZ,dimenZ);
S_inv = new DenseMatrix64F(dimenZ,dimenZ);
c = new DenseMatrix64F(dimenZ,dimenX);
d = new DenseMatrix64F(dimenX,dimenZ);
K = new DenseMatrix64F(dimenX,dimenZ);
\end{verbatim}
\caption{\label{fig:predeclare}When directly working with the operation functions, matrices that contain the intermediate results need to be declared.}
\end{figure}
\subsection{KalmanFilterAlg.java}
Finally there is the algorithm interface, Figure \ref{fig:update_alg}. Here specific algorithms are called. The most important is the use of the Cholesky decomposition, which speeds up the matrix inverse. In other cases it takes advantage of it knowing before hand the size and shape of the matrix, which results in a slight performance gain.
\subsection{Notes}
What is the benefit of the added complexity of using the operator and algorithm interfaces over the simplistic interface? The operator interface runs about 23\% faster than the simplistic interface and the algorithm interface runs about 28\% faster than the simplistic interface. The exact performance differences will vary greatly depending on the application.
\begin{figure}[h]
\begin{verbatim}
public void update(DenseMatrix64F z, DenseMatrix64F R) {
// y = z - H x
MatrixVectorMult.mult(H,x,y);
sub(z,y,y);
// S = H P H' + R
MatrixMatrixMult.mult_small(H,P,c);
MatrixMatrixMult.multTransB(c,H,S);
addEquals(S,R);
// K = PH'S^(-1)
if( !chol.decompose(S) ) throw new RuntimeException("Invert failed");
chol.setToInverse(S_inv);
MatrixMatrixMult.multTransA_small(H,S_inv,d);
MatrixMatrixMult.mult_small(P,d,K);
// x = x + Ky
MatrixVectorMult.mult(K,y,a);
addEquals(x,a);
// P = (I-kH)P = P - (KH)P = P-K(HP)
MatrixMatrixMult.mult_small(H,P,c);
MatrixMatrixMult.mult_small(K,c,b);
subEquals(P,b);
}
\end{verbatim}
\caption{\label{fig:update_alg}Code from KalmanFilterAlg.java}
\end{figure}
\appendix
\section{Design Philosophy}
This library was written in response to perceived weaknesses in other Java matrix libraries. The three biggest are, 1) unnecessarily slow performance in small matrices, 2) lack of flexibility in memory management, and 3) needing to choose between ease of use and performance.
One of the areas EJML performs very well is when dealing with small matrices. This is accomplished by having very low overhead and by using specialized algorithms for small matrices. The overhead is reduce by not having abstraction that allow native code or java code to be run, or generic algorithms that can work on a wide variety of matrix types. Specialized algorithms vary from switching the order the matrix is traversed depending on its size to having hand coded algorithms for specific matrix sizes. EJML also performs well with large matrices, where it still most often performs significantly better than other related libraries.
One way to write efficient Java algorithms is to minimize the amount of memory that is created and destroyed. This smooths out the processing time by not having the garbage collector needing to run as often and reduces the number of cycles spent reinitializing the data. All of the algorithms in EJML have been coded such that they predeclared all the data they use. The reshape function is also provided. While extremely easy to implement, it is often neglected in other libraries forcing you to declare a new matrix when the data changes.
Jama\footnote{http://math.nist.gov/javanumerics/jama/} is still a popular library despite no longer being actively developed. The primary reason for this is that it is easy to use. Matrix Toolkit Java (MTJ)\footnote{http://code.google.com/p/matrix-toolkits-java/} gives the developer more control, but is harder to use. EJML uses ideas from both libraries to create a simple yet robust interface. A user can program in EJML using the following interfaces; simple, operator, and algorithm.
Simple is a wrapper on top of the operator interface. It hides much of the memory management from the user and allows more readable code. The operator interface simplifies the selection of which algorithm to use from the user by automatically selecting what it thinks is the best one. The algorithm interface gives complete control to the programmer, but requires more skill and knowledge to user effectively.
\subsection{Why multiple implementations?}
Optimizing an algorithm for processing small and large matrices requires different strategies. An optimal small matrix algorithm typically minimizes the number of operations. Large matrix algorithms need to minimize the number of operations and cache misses.
On a modern desktop computer missing a CPU cache entails a large performance hit. A cache miss is when a computer needs to access memory that is not available on one of its high speed memory caches. This forces it to access the much slower main memory.
Small matrices can often be stored entirely in the CPU's cache, making it much less likely to have a cache miss. Large matrix algorithms are designed to avoid cache misses, often by processing the data in a less straight forward way that takes more operations. Typically running a small matrix algorithm on a large matrix will result in a very large peformance hit, but the inverse only results in a relatively small performance hit.
\end{document}