2D array (matrix)

Matrix: Mat[T] #

import org.saddle._
import org.saddle.order._

A Mat[T] represents a matrix of values. Internally it is stored as a single contiguous array in row-major order.

The row-major layout is compatible with EJML, a linear algebra library running on the JVM. If you want to use a BLAS, you can take a look in saddle-linalg.

Factories #

import org.saddle._
 Mat(2,2, Array(1,2,3,4))
// res0: Mat[Int] = [2 x 2]
// 1 2 
// 3 4 
// 

// all same:
 Mat(Array(Array(1,3), Array(2,4)))
// res1: Mat[Int] = [2 x 2]
// 1 2 
// 3 4 
// 
 Mat(Vec(1,3), Vec(2,4))
// res2: Mat[Int] = [2 x 2]
// 1 2 
// 3 4 
// 
 Mat(Array(Vec(1,3), Vec(2,4)))
// res3: Mat[Int] = [2 x 2]
// 1 2 
// 3 4 
// 

// identity matrix:
 mat.ident(2)
// res4: Mat[Double] = [2 x 2]
// 1.0000 0.0000 
// 0.0000 1.0000 
// 

// empty matrix:
 Mat.empty[Double]
// res5: Mat[Double] = [0 x 0]
// 

// zeros:
 Mat[Int](2, 2)
// res6: Mat[Int] = [2 x 2]
// 0 0 
// 0 0 
//

Again, sometimes we want to create instances filled with random observations. As to Vec, we can do the following:

mat.rand(2,2)       
// res7: Mat[Double] = [2 x 2]
// 0.1084 0.8074 
// 0.9548 0.1605 
//        
 mat.randp(2,2)      // random positive doubles
// res8: Mat[Double] = [2 x 2]
// 0.9223 0.0147 
// 0.7010 0.7001 
//       // random positive doubles
 mat.randn(2,2)      // random normally distributed doubles
// res9: Mat[Double] = [2 x 2]
// -0.9728  0.6626 
// -1.1631 -1.1542 
//       // random normally distributed doubles
 mat.randn2(2,2,3,12) // random normally distributed with mean=3, stdev=12
// res10: Mat[Double] = [2 x 2]
// -19.9126 -5.4039 
//   4.7075  5.8598 
//

There are a few other factory methods available:

mat.ones(2,2)
// res11: Mat[Double] = [2 x 2]
// 1.0000 1.0000 
// 1.0000 1.0000 
// 
 mat.zeros(2,2)
// res12: Mat[Double] = [2 x 2]
// 0.0000 0.0000 
// 0.0000 0.0000 
// 
 mat.diag(Vec(1,2))
// res13: Mat[Double] = [2 x 2]
// 1.0000 0.0000 
// 0.0000 2.0000 
//

Binary operations #

Let’s look at some basic operations with Mat. As with Vec, you may perform calculations on two Mat instances, or on a Mat and a scalar value.

import org.saddle.ops.BinOps._
// element-wise multiplication
 Mat(2,2,Array(1,2,3,4)) * Mat(2,2,Array(4,1,2,3))
// res14: Mat[Int] = [2 x 2]
// 4  2 
// 6 12 
//

Linear algebra #

Matrix multiplication, matrix-vector multiplication or other linear algebra operatoins need saddle-linalg, which depends on netlib-java. These work just on Mat[Double] and Vec[Double].

import org.saddle.linalg._
// matrix multiplication
 Mat(2,2,Array(1d,2d,3d,4d)) mm Mat(2,2,Array(4d,1d,2d,3d))
// res15: Mat[Double] = [2 x 2]
//  8.0000  7.0000 
// 20.0000 15.0000 
// 


// matrix-vector multiplication
 Mat(2,2,Array(1d,2d,3d,4d)) mv Vec(2d,1d)
// res16: Vec[Double] = [2 x 1]
//  4.0000
// 10.0000
// 

// as expected
 Mat(2,2,Array(1,2,3,4)) * 2
// res17: Mat[Int] = [2 x 2]
// 2 4 
// 6 8 
// 
 Mat(2,2,Array(1,2,3,4)) + 2
// res18: Mat[Int] = [2 x 2]
// 3 4 
// 5 6 
// 
 Mat(2,2,Array(1,2,3,4)) << 2
// res19: Mat[Int] = [2 x 2]
//  4  8 
// 12 16 
// 
// etc...

// transpose
 Mat(2,2,Array(1,2,3,4)).T
// res20: Mat[Int] = [2 x 2]
// 1 3 
// 2 4 
// 

// properties of Mat
val m = Mat(2,2,Array(1,2,3,4))
// m: Mat[Int] = [2 x 2]
// 1 2 
// 3 4 
// 
 m.numRows
// res21: Int = 2
 m.numCols
// res22: Int = 2
 m.isSquare
// res23: Boolean = true
 m.isEmpty
// res24: Boolean = false

Operations #

There are a few ways to extract values from a Mat.

m.at(0,1)
// res25: scalar.Scalar[Int] = Value(el = 2)

// be careful with this one!
 m.raw(0,1)
// res26: Int = 2

 m.takeRows(0)
// res27: Mat[Int] = [1 x 2]
// 1 2 
// 

 m.withoutRows(0)
// res28: Mat[Int] = [1 x 2]
// 3 4 
// 

 m.takeCols(0)
// res29: Mat[Int] = [2 x 1]
// 1 
// 3 
// 

 m.col(0)
// res30: Vec[Int] = [2 x 1]
// 1
// 3
// 
 m.row(0)
// res31: Vec[Int] = [2 x 1]
// 1
// 2
// 
 m.rows
// res32: IndexedSeq[Vec[Int]] = Vector(
//   [2 x 1]
// 1
// 2
// ,
//   [2 x 1]
// 3
// 4
// 
// )
 m.cols
// res33: IndexedSeq[Vec[Int]] = Vector(
//   [2 x 1]
// 1
// 3
// ,
//   [2 x 1]
// 2
// 4
// 
// )

Some other interesting methods on Mat:

val m2 = Mat(2,2,Array(1,2,na[Int],4))
// m2: Mat[Int] = [2 x 2]
// 1 2 
// NA 4 
// 

 m2.rowsWithNA
// res34: Set[Int] = Set(1)
 m2.dropRowsWithNA
// res35: Mat[Int] = [1 x 2]
// 1 2 
// 
 m2.reshape(1,4)
// res36: Mat[Int] = [1 x 4]
// 1 2 NA 4 
// 
 mat.rand(2,2).roundTo(2)
// res37: Mat[Double] = [2 x 2]
// 0.2300 0.8300 
// 0.5400 0.8300 
//