A `LinearAlgebra` typeclass.

The `axle-jblas` spoke provides witnesses for JBLAS matrices.

The default jblas matrix `toString` isn’t very readable, so this tutorial wraps most results in the Axle `string` function, invoking the `cats.Show` witness for those matrices.

## Imports and implicits

Import JBLAS and Axle’s `LinearAlgebra` witness for it.

``````import axle._
import axle.jblas._
import axle.syntax.linearalgebra.matrixOps
import spire.implicits.DoubleAlgebra

import laJblasDouble._
``````

## Creating Matrices

``````string(ones(2, 3))
// res1: String =
// 1.000000 1.000000 1.000000
// 1.000000 1.000000 1.000000

string(ones(1, 4))
// res2: String = 1.000000 1.000000 1.000000 1.000000

string(ones(4, 1))
// res3: String =
// 1.000000
// 1.000000
// 1.000000
// 1.000000
``````

## Creating matrices from arrays

``````string(fromColumnMajorArray(2, 2, List(1.1, 2.2, 3.3, 4.4).toArray))
// res4: String =
// 1.100000 3.300000
// 2.200000 4.400000

string(fromColumnMajorArray(2, 2, List(1.1, 2.2, 3.3, 4.4).toArray).t)
// res5: String =
// 1.100000 2.200000
// 3.300000 4.400000

val m = fromColumnMajorArray(4, 5, (1 to 20).map(_.toDouble).toArray)
// m: org.jblas.DoubleMatrix = [1.000000, 5.000000, 9.000000, 13.000000, 17.000000; 2.000000, 6.000000, 10.000000, 14.000000, 18.000000; 3.000000, 7.000000, 11.000000, 15.000000, 19.000000; 4.000000, 8.000000, 12.000000, 16.000000, 20.000000]

string(m)
// res6: String =
// 1.000000 5.000000 9.000000 13.000000 17.000000
// 2.000000 6.000000 10.000000 14.000000 18.000000
// 3.000000 7.000000 11.000000 15.000000 19.000000
// 4.000000 8.000000 12.000000 16.000000 20.000000
``````

## Random matrices

``````val r = rand(3, 3)
// r: org.jblas.DoubleMatrix = [0.285241, 0.438920, 0.513144; 0.218250, 0.424770, 0.999493; 0.851683, 0.247471, 0.319942]

string(r)
// res7: String =
// 0.285241 0.438920 0.513144
// 0.218250 0.424770 0.999493
// 0.851683 0.247471 0.319942
``````

## Matrices defined by functions

``````string(matrix(4, 5, (r, c) => r / (c + 1d)))
// res8: String =
// 0.000000 0.000000 0.000000 0.000000 0.000000
// 1.000000 0.500000 0.333333 0.250000 0.200000
// 2.000000 1.000000 0.666667 0.500000 0.400000
// 3.000000 1.500000 1.000000 0.750000 0.600000

string(matrix(4, 5, 1d,
(r: Int) => r + 0.5,
(c: Int) => c + 0.6,
(r: Int, c: Int, diag: Double, left: Double, right: Double) => diag))
// res9: String =
// 1.000000 1.600000 2.600000 3.600000 4.600000
// 1.500000 1.000000 1.600000 2.600000 3.600000
// 2.500000 1.500000 1.000000 1.600000 2.600000
// 3.500000 2.500000 1.500000 1.000000 1.600000
``````

``````val x = fromColumnMajorArray(3, 1, Vector(4.0, 5.1, 6.2).toArray)
// x: org.jblas.DoubleMatrix = [4.000000; 5.100000; 6.200000]

string(x)
// res10: String =
// 4.000000
// 5.100000
// 6.200000

val y = fromColumnMajorArray(3, 1, Vector(7.3, 8.4, 9.5).toArray)
// y: org.jblas.DoubleMatrix = [7.300000; 8.400000; 9.500000]

string(y)
// res11: String =
// 7.300000
// 8.400000
// 9.500000

x.isEmpty
// res12: Boolean = false

x.isRowVector
// res13: Boolean = false

x.isColumnVector
// res14: Boolean = true

x.isSquare
// res15: Boolean = false

x.isScalar
// res16: Boolean = false

x.rows
// res17: Int = 3

x.columns
// res18: Int = 1

x.length
// res19: Int = 3
``````

## Accessing columns, rows, and elements

``````string(x.column(0))
// res20: String =
// 4.000000
// 5.100000
// 6.200000

string(x.row(1))
// res21: String = 5.100000

x.get(2, 0)
// res22: Double = 6.2

val fiveByFive = fromColumnMajorArray(5, 5, (1 to 25).map(_.toDouble).toArray)
// fiveByFive: org.jblas.DoubleMatrix = [1.000000, 6.000000, 11.000000, 16.000000, 21.000000; 2.000000, 7.000000, 12.000000, 17.000000, 22.000000; 3.000000, 8.000000, 13.000000, 18.000000, 23.000000; 4.000000, 9.000000, 14.000000, 19.000000, 24.000000; 5.000000, 10.000000, 15.000000, 20.000000, 25.000000]

string(fiveByFive)
// res23: String =
// 1.000000 6.000000 11.000000 16.000000 21.000000
// 2.000000 7.000000 12.000000 17.000000 22.000000
// 3.000000 8.000000 13.000000 18.000000 23.000000
// 4.000000 9.000000 14.000000 19.000000 24.000000
// 5.000000 10.000000 15.000000 20.000000 25.000000

string(fiveByFive.slice(1 to 3, 2 to 4))
// res24: String =
// 12.000000 17.000000 22.000000
// 13.000000 18.000000 23.000000
// 14.000000 19.000000 24.000000

string(fiveByFive.slice(0.until(5,2), 0.until(5,2)))
// res25: String =
// 1.000000 11.000000 21.000000
// 3.000000 13.000000 23.000000
// 5.000000 15.000000 25.000000
``````

## Negate, Transpose, Power

``````string(x.negate)
// res26: String =
// -4.000000
// -5.100000
// -6.200000

string(x.transpose)
// res27: String = 4.000000 5.100000 6.200000

// x.log
// x.log10

string(x.pow(2d))
// res31: String =
// 16.000000
// 26.010000
// 38.440000
``````

## Mins, Maxs, Ranges, and Sorts

``````r.max

r.min

// r.ceil
// r.floor

string(r.rowMaxs)

string(r.rowMins)

string(r.columnMaxs)

string(r.columnMins)

string(rowRange(r))

string(columnRange(r))

string(r.sortRows)

string(r.sortColumns)

string(r.sortRows.sortColumns)
``````

## Statistics

``````string(r.rowMeans)
// res32: String =
// 0.412435
// 0.547504
// 0.473032

string(r.columnMeans)
// res33: String = 0.451724 0.370387 0.610860

// median(r)

string(sumsq(r))
// res36: String = 0.854359 0.434322 1.364666

string(std(r))
// res37: String = 0.284132 0.087106 0.285900

string(cov(r))
// res38: String =
// 0.009239 -0.005334 -0.013027
// -0.005334 0.000986 -0.015923
// -0.013027 -0.015923 0.028211

string(centerRows(r))
// res39: String =
// -0.127194 0.026485 0.100709
// -0.329254 -0.122734 0.451989
// 0.378651 -0.225561 -0.153090

string(centerColumns(r))
// res40: String =
// -0.166484 0.068533 -0.097716
// -0.233475 0.054383 0.388633
// 0.399958 -0.122916 -0.290917

string(zscore(r))
// res41: String =
// -0.585937 0.786770 -0.341783
// -0.821710 0.624330 1.359331
// 1.407647 -1.411100 -1.017548
``````

## Principal Component Analysis

``````val (u, s) = pca(r, 0.95)
// u: org.jblas.DoubleMatrix = [-0.330396, -0.470912, 0.817973; -0.325446, -0.756653, -0.567064; 0.885959, -0.453562, 0.096739]
// s: org.jblas.DoubleMatrix = [0.038918; 0.011878; 0.011396]

string(u)
// res42: String =
// -0.330396 -0.470912 0.817973
// -0.325446 -0.756653 -0.567064
// 0.885959 -0.453562 0.096739

string(s)
// res43: String =
// 0.038918
// 0.011878
// 0.011396
``````

## Horizontal and vertical concatenation

``````string(x aside y)
// res44: String =
// 4.000000 7.300000
// 5.100000 8.400000
// 6.200000 9.500000

string(x atop y)
// res45: String =
// 4.000000
// 5.100000
// 6.200000
// 7.300000
// 8.400000
// 9.500000
``````

``````val x = ones(2, 3)
// x: org.jblas.DoubleMatrix = [1.000000, 1.000000, 1.000000; 1.000000, 1.000000, 1.000000]

string(x)
// res46: String =
// 1.000000 1.000000 1.000000
// 1.000000 1.000000 1.000000
``````

``````import spire.implicits.additiveSemigroupOps

string(x + x)
// res47: String =
// 2.000000 2.000000 2.000000
// 2.000000 2.000000 2.000000
``````

``````string(x.addScalar(1.1))
// res48: String =
// 2.100000 2.100000 2.100000
// 2.100000 2.100000 2.100000
``````

Matrix subtraction

``````import spire.implicits.additiveGroupOps

string(x - x)
// res49: String =
// 0.000000 0.000000 0.000000
// 0.000000 0.000000 0.000000
``````

Scalar subtraction (JBLAS method)

``````string(x.subtractScalar(0.2))
// res50: String =
// 0.800000 0.800000 0.800000
// 0.800000 0.800000 0.800000
``````

## Multiplication and Division

Scalar multiplication

``````string(x.multiplyScalar(3d))
// res51: String =
// 3.000000 3.000000 3.000000
// 3.000000 3.000000 3.000000
``````

Matrix multiplication

``````import spire.implicits.multiplicativeSemigroupOps
// import spire.implicits.multiplicativeSemigroupOps

string(x * x.transpose)
// res52: String =
// 3.000000 3.000000
// 3.000000 3.000000
``````

Scalar division (JBLAS method)

``````string(x.divideScalar(100d))
// res53: String =
// 0.010000 0.010000 0.010000
// 0.010000 0.010000 0.010000
``````

## Map element values

``````implicit val endo = axle.jblas.endoFunctorDoubleMatrix[Double]
// endo: axle.algebra.Endofunctor[org.jblas.DoubleMatrix,Double] = axle.jblas.package\$\$anon\$6@6473ee76

import axle.syntax.endofunctor.endofunctorOps
// import axle.syntax.endofunctor.endofunctorOps

val half = ones(3, 3).map(_ / 2d)
// half: org.jblas.DoubleMatrix = [0.500000, 0.500000, 0.500000; 0.500000, 0.500000, 0.500000; 0.500000, 0.500000, 0.500000]

string(half)
// res54: String =
// 0.500000 0.500000 0.500000
// 0.500000 0.500000 0.500000
// 0.500000 0.500000 0.500000
``````

## Boolean operators

``````string(r lt half)
// res55: String =
// 1.000000 1.000000 0.000000
// 1.000000 1.000000 0.000000
// 0.000000 1.000000 1.000000

string(r le half)
// res56: String =
// 1.000000 1.000000 0.000000
// 1.000000 1.000000 0.000000
// 0.000000 1.000000 1.000000

string(r gt half)
// res57: String =
// 0.000000 0.000000 1.000000
// 0.000000 0.000000 1.000000
// 1.000000 0.000000 0.000000

string(r ge half)
// res58: String =
// 0.000000 0.000000 1.000000
// 0.000000 0.000000 1.000000
// 1.000000 0.000000 0.000000

string(r eq half)
// res59: String =
// 0.000000 0.000000 0.000000
// 0.000000 0.000000 0.000000
// 0.000000 0.000000 0.000000

string(r ne half)
// res60: String =
// 1.000000 1.000000 1.000000
// 1.000000 1.000000 1.000000
// 1.000000 1.000000 1.000000

string((r lt half) or (r gt half))
// res61: String =
// 1.000000 1.000000 1.000000
// 1.000000 1.000000 1.000000
// 1.000000 1.000000 1.000000

string((r lt half) and (r gt half))
// res62: String =
// 0.000000 0.000000 0.000000
// 0.000000 0.000000 0.000000
// 0.000000 0.000000 0.000000

string((r lt half) xor (r gt half))
// res63: String =
// 1.000000 1.000000 1.000000
// 1.000000 1.000000 1.000000
// 1.000000 1.000000 1.000000

string((r lt half) not)
// res64: String =
// 0.000000 0.000000 1.000000
// 0.000000 0.000000 1.000000
// 1.000000 0.000000 0.000000
``````

## Higher order methods

``````string(m.map(_ + 1))
// res65: String =
// 2.000000 6.000000 10.000000 14.000000 18.000000
// 3.000000 7.000000 11.000000 15.000000 19.000000
// 4.000000 8.000000 12.000000 16.000000 20.000000
// 5.000000 9.000000 13.000000 17.000000 21.000000

string(m.map(_ * 10))
// res66: String =
// 10.000000 50.000000 90.000000 130.000000 170.000000
// 20.000000 60.000000 100.000000 140.000000 180.000000
// 30.000000 70.000000 110.000000 150.000000 190.000000
// 40.000000 80.000000 120.000000 160.000000 200.000000

// m.foldLeft(zeros(4, 1))(_ + _)

string(m.foldLeft(ones(4, 1))(_ mulPointwise _))
// res69: String =
// 9945.000000
// 30240.000000
// 65835.000000
// 122880.000000

// m.foldTop(zeros(1, 5))(_ + _)

string(m.foldTop(ones(1, 5))(_ mulPointwise _))
// res72: String = 24.000000 1680.000000 11880.000000 43680.000000 116280.000000
``````