Matrices & Linear Algebra

While it is always possible to use the underlying container classes directly (see Modules for more information on backends), Koma provides a set of top-level convenience functions to make the experience more similar to other scientific environments. All these functions reside in the koma namespace and use the underlying object-oriented hierarchy internally.

When working with matrices in Koma you'll almost always want to

import koma.extensions.*

This namespace defines some extension functions which would ordinarily be defined on Matrix itself but can't be for performance reasons. Since there are only Matrix extension functions defined in koma.extensions, it should be safe to star import it without polluting your workspace. If you don't import koma.extensions you'll be missing a lot of functionality including basic things like getters and setters.

Creating Matrices

Koma provides several functions for creating new matrices:

// x is a 3x3 identity matrix
var x = eye(3)

// x is a 3x3 matrix of zeros
x = zeros(3,3)

// x is a 3x3 with Gaussian random noise, distribution 0,1
x = randn(3,3)

// x is a 3x3 with uniform random noise
x = rand(3,3)

// x is a 4x5 matrix where the ith row and jth column has the value i+j*2
x = fill(4,5) { row, col -> row+col*2.0 }

val someData = arrayOf(doubleArrayOf(1.0,2.0,3.0), doubleArrayOf(4.0,5.0,6.0))
// x is a 2x3 matrix constructed from the data in a java array of arrays
x = create(someData)

See here for a complete list of available creators. There is also a DSL for matrix literals:

// a is a 2x3 matrix filled with the numbers passed in
val a = mat[1,2,3.3 end

Math Functions

Matrices have useful map functions that return matrices for chaining operations (see here for a complete list).

// Create a 3x3 identity and then add 0.1 to all elements
val x = eye(3) + 0.1

// Map each element through a function that adds .01
val y = { it + .01 }

// Map each element through a function that adds or subtracts depending on the element index
val z = x.mapIndexed { row, col, ele -> if (row > col) ele + 1 else ele - 1 }

// Are there any elements greater than 1?
val hasGreater = x.any { it > 1 }

// Are all elements greater than 1?
val allGreater = x.all { it > 1 }

// Print all the elements in row-order
x.forEach { println(it) }

// Print all the elements including their column number
x.forEachIndexed { row, col, ele -> println("$col $it") }

// Apply a function to a row at a time and store the outputs in a contiguous matrix
val sins = x.mapRows { row -> sin(row) }

// Print all elements greater than 1
x.each { if (it>1) println(it) }

We can also do some linear algebra:

// Matrix literal syntax, see creators.kt for 
// convenience functions like zeros(5,5)
var A = mat[1,0,0 end
            0,3,0 end

// Calculate the matrix inverse
var Ainv = A.inv()

var b = mat[2,2,4].T

// Use overloaded operators:

// * is matrix multiplication 
var c = A*b + 1

// emul is element-wise multiplication
var d = (A emul A) + 1

// Number of decimals to show


Which produces:


mat[ 3.00  end
     7.00  end
     17.00 ]

Many special functions are supported (see the matrix interface for a complete list):

val a = 2*eye(3)+.01 // eye is identity matrix

a.chol()  // Cholesky decomposition
a.det()   // Determinant
a.diag()  // Diagonal vector
a.inv()   // Matrix inverse
a.norm()  // Matrix norm

Scalar functions can be applied elementwise to matrices (see here for a complete list):

val x = create(0..100)/5.0  // Matrix of 0, 1/5, 2/5, ...
val y = sin(x)              // Sin applied elementwise
plot(y)                     // Plot of sin function

Matrix indexing and slicing is supported (see here for a list of operators as well as the Matrix type):

val x = randn(5,5)
val y = x[0,0..4] // Grab the first row

x[0..2,0..3] = zeros(3,4) // Set the upper-left 3x4 sub-matrix of x to zero

A Matrix is convertible to an Iterable:

val x = randn(5,5).toIterable()

// Adds all elements and returns sum
x.reduce { x, y -> x+y }

// Returns list of all elements greater than 4
x.find { it > 4 }