Skip to content

Commit

Permalink
chore: add eigen to the matrix_operations.js benchmark. Switch to `…
Browse files Browse the repository at this point in the history
…tinybench` to make that work
  • Loading branch information
josdejong committed Dec 11, 2024
1 parent 35d38fe commit 7f02ba2
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 70 deletions.
40 changes: 40 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"core-js": "3.39.0",
"del": "8.0.0",
"dtslint": "4.2.1",
"eigen": "0.2.2",
"eslint": "8.57.0",
"eslint-config-prettier": "9.1.0",
"eslint-config-standard": "17.1.0",
Expand Down Expand Up @@ -90,6 +91,7 @@
"process": "0.11.10",
"sinon": "19.0.2",
"sylvester": "0.0.21",
"tinybench": "3.0.7",
"ts-node": "10.9.2",
"typescript": "5.5.4",
"webpack": "5.96.1",
Expand Down
145 changes: 75 additions & 70 deletions test/benchmark/matrix_operations.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,20 @@
* has room for improvements, it's not a fully fletched benchmark suite.
*/

import Benchmark from 'benchmark'
import { Bench } from 'tinybench'
import det from 'ndarray-determinant'
import gemm from 'ndarray-gemm'
import ops from 'ndarray-ops'
import pack from 'ndarray-pack'
import numeric from 'numericjs'
import padRight from 'pad-right'
import sylvester from 'sylvester'
import eig from 'eigen'
import zeros from 'zeros'
import { all, create } from '../../lib/esm/index.js'

const suite = new Benchmark.Suite()
const bench = new Bench({ time: 100 })
const math = create(all)

function pad (text) {
return padRight(text, 40, ' ')
}

// fiedler matrix 25 x 25
const fiedler = [
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24],
Expand Down Expand Up @@ -56,66 +52,75 @@ const fiedler = [
[24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
];

// mathjs
(function () {
const A = math.matrix(fiedler, 'dense', 'number')

suite.add(pad('matrix operations mathjs (number) A+A'), function () { return math.add(A, A) })
suite.add(pad('matrix operations mathjs (number) A*A'), function () { return math.multiply(A, A) })
suite.add(pad('matrix operations mathjs (number) A\''), function () { return math.transpose(A) })
suite.add(pad('matrix operations mathjs (number) det(A)'), function () { return math.det(A) })
})();

// mathjs
(function () {
const A = math.matrix(fiedler)

suite.add(pad('matrix operations mathjs (generic) A+A'), function () { return math.add(A, A) })
suite.add(pad('matrix operations mathjs (generic) A*A'), function () { return math.multiply(A, A) })
suite.add(pad('matrix operations mathjs (generic) A\''), function () { return math.transpose(A) })
suite.add(pad('matrix operations mathjs (generic) det(A)'), function () { return math.det(A) })
})();

// sylvester
(function () {
const A = sylvester.Matrix.create(fiedler)

suite.add(pad('matrix operations sylvester A+A'), function () { return A.add(A) })
suite.add(pad('matrix operations sylvester A*A'), function () { return A.multiply(A) })
suite.add(pad('matrix operations sylvester A\''), function () { return A.transpose() })
suite.add(pad('matrix operations sylvester det(A)'), function () { return A.det() })
})();

// numericjs
(function () {
const A = fiedler

suite.add(pad('matrix operations numericjs A+A'), function () { return numeric.add(A, A) })
suite.add(pad('matrix operations numericjs A*A'), function () { return numeric.dot(A, A) })
suite.add(pad('matrix operations numericjs A\''), function () { return numeric.transpose(A) })
suite.add(pad('matrix operations numericjs det(A)'), function () { return numeric.det(A) })
})();

// ndarray
(function () {
const A = pack(fiedler)
const B = zeros([25, 25])

suite.add(pad('matrix operations ndarray A+A'), function () { return ops.add(B, A, A) })
suite.add(pad('matrix operations ndarray A*A'), function () { return gemm(B, A, A) })
suite.add(pad('matrix operations ndarray A\''), function () { ops.assign(B, A); return B.transpose(1, 0) })
suite.add(pad('matrix operations ndarray det(A)'), function () { return det(A) })
})()

const durations = []

suite
.on('cycle', function (event) {
const benchmark = event.target
console.log(String(event.target))
durations.push(benchmark.name + ' avg duration per operation: ' + Math.round(benchmark.stats.mean * 1e6) + ' microseconds')
})
.run()

console.log()
console.log(durations.join('\n'))
(async function () {
// mathjs
(function () {
const A = math.matrix(fiedler, 'dense', 'number')

bench.add('matrix operations mathjs (number) A+A', function () { return math.add(A, A) })
bench.add('matrix operations mathjs (number) A*A', function () { return math.multiply(A, A) })
bench.add('matrix operations mathjs (number) A\'', function () { return math.transpose(A) })
bench.add('matrix operations mathjs (number) det(A)', function () { return math.det(A) })
})();

// mathjs
(function () {
const A = math.matrix(fiedler)

bench.add('matrix operations mathjs (generic) A+A', function () { return math.add(A, A) })
bench.add('matrix operations mathjs (generic) A*A', function () { return math.multiply(A, A) })
bench.add('matrix operations mathjs (generic) A\'', function () { return math.transpose(A) })
bench.add('matrix operations mathjs (generic) det(A)', function () { return math.det(A) })
})();

// sylvester
(function () {
const A = sylvester.Matrix.create(fiedler)

bench.add('matrix operations sylvester A+A', function () { return A.add(A) })
bench.add('matrix operations sylvester A*A', function () { return A.multiply(A) })
bench.add('matrix operations sylvester A\'', function () { return A.transpose() })
bench.add('matrix operations sylvester det(A)', function () { return A.det() })
})();

// numericjs
(function () {
const A = fiedler

bench.add('matrix operations numericjs A+A', function () { return numeric.add(A, A) })
bench.add('matrix operations numericjs A*A', function () { return numeric.dot(A, A) })
bench.add('matrix operations numericjs A\'', function () { return numeric.transpose(A) })
bench.add('matrix operations numericjs det(A)', function () { return numeric.det(A) })
})();

// ndarray
(function () {
const A = pack(fiedler)
const B = zeros([25, 25])

bench.add('matrix operations ndarray A+A', function () { return ops.add(B, A, A) })
bench.add('matrix operations ndarray A*A', function () { return gemm(B, A, A) })
bench.add('matrix operations ndarray A\'', function () { ops.assign(B, A); return B.transpose(1, 0) })
bench.add('matrix operations ndarray det(A)', function () { return det(A) })
})()

// eigen-js
await eig.ready
await (function () {
const A = new eig.Matrix(fiedler)

bench.add('matrix operations eigen-js A+A', function () { return A.matAdd(A) })
bench.add('matrix operations eigen-js A*A', function () { return A.matMul(A) })
bench.add('matrix operations eigen-js A\'', function () { return A.transpose() })
bench.add('matrix operations eigen-js det(A)', function () { return A.det() })
})()

await bench.run()

console.table(bench.tasks.map(({ name, result }) => ({
Name: name,
'Ops/sec': Math.round(result?.hz),
'Average Time (\u00b5s)': result?.mean * 1000,
'Variance (\u00b5s)': result?.variance * 1000
})))
})().catch(console.error)

0 comments on commit 7f02ba2

Please sign in to comment.