Matrix

JavaScript の数学ライブラリ Math.js を使って行列の計算をしてみました。


Matrix 0.1

Math.js の行列のサンプルコードをベースに主な機能を使ってみました。

実行結果

matrix01.html

ソース

Math.js のソースファイルはインターネット上のものを指定します。 Math.js と SyntaxHighlighter を併用するとブラウザのスタックが溢れてしまうので、 このページでは SyntaxHighlighter は使用しません。
<script src="https://unpkg.com/mathjs@9.5.0/lib/browser/math.js">

HTML の <body> タグに以下のコードを埋め込みました。

このコードは Math.js のサンプルコードをベースにしています。

/**
 * 結果表示用の関数です。HTMLとして展開します。
 * @since 0.1
 */
function writeln(str) {
	document.writeln(str + "<br>");
}
function write(str) {
	document.writeln(str);
}

/**
 * コメントを表示する関数です。
 * @sinse 0.1
 */
function comment(str) {
	writeln("<span style='color: lime'>// " + str + "</span>");
}

/**
 * テストの実行と表示を行う関数です。
 * @since 0.1
 */
function test(exp) {
	write(exp + " ");
	var ans = eval(exp);
	comment(ans);
}

comment("行列と配列を作成します。 行列は Array の単なるラッパーであり、")
comment("いくつかの便利なユーティリティを提供します。")
test("a = math.matrix([1, 4, 9, 16, 25])") // [1, 4, 9, 16, 25]
test("a.size()") // 5 
test("precision = 4") // 4
test("math.format(a.size(), precision)") // [5]
test("b = math.matrix(math.ones([2, 3]))") // [[1, 1, 1], [1, 1, 1]]
test("b.size()") // 2,3
test("math.format(b.size(), precision)") // [2, 3]
writeln("")

comment("行列の配列データは、valueOf() を使用して取得できます。")
test("a") // [1, 4, 9, 16, 25]
test("array = a.valueOf()") // 1,4,9,16,25
test("b") // [[1, 1, 1], [1, 1, 1]]
test("b.valueOf()") // 1,1,1,1,1,1
test("math.format(b.valueOf(), precision)") // [[1, 1, 1], [1, 1, 1]]
writeln("")

comment("行列はコピーできます。")
test("clone = a.clone()") // [1, 4, 9, 16, 25]
test("clone") // [1, 4, 9, 16, 25]
writeln("")

comment("行列の演算")
test("math.sqrt(a)") // [1, 2, 3, 4, 5]
test("c = [1, 2, 3, 4, 5]") // 1,2,3,4,5
test("math.factorial(c)") // [1, 2, 6, 24, 120]
writeln("")

comment("行列の作成および操作。 配列と行列は混合して使用できます。")
test("d = [[1, 2], [3, 4]]") // 1,2,3,4
test("math.format(d, precision)") // [[1, 2], [3, 4]]
test("e = math.matrix([[5, 6], [1, 1]])") // [[5, 6], [1, 1]]
writeln("")

comment("部分行列の設定")
comment("行列のインデックスはゼロベースです。")
test("e.subset(math.index(1, [0, 1]), [[7, 8]])") // [[5, 6], [7, 8]]
test("f = math.multiply(d, e)") // [[19, 22], [43, 50]]
test("math.add(d, e)") // [[6, 8], [10, 12]]
test("g = f.subset(math.index(1, 0))") // 43
writeln("")

comment("部分行列の取得")
comment("行列のインデックスはゼロベースです。")
test("h = math.diag(math.range(1, 4))") // [[1, 0, 0], [0, 2, 0], [0, 0, 3]]
test("h.subset(math.index([1, 2], [1, 2]))") // [[2, 0], [0, 3]]
test("i = math.range(1, 6)") // [1, 2, 3, 4, 5]
test("i.subset(math.index(math.range(1, 4)))") // [2, 3, 4]
writeln("")

comment("多次元行列のリサイズ")
test("j = math.matrix()")
test("defaultValue = 0")
test("j.resize([2, 2, 2], defaultValue)") // [[[0, 0], [0, 0]], [[0, 0], [0, 0]]]
test("j.size()") // 2, 2, 2
test("j.resize([2, 2])") // [[0, 0], [0, 0]]
test("j.size()") // 2,2
writeln("")

comment("行列の範囲外の値を設定すると、行列のサイズが変更されます。")
comment("新しい要素はゼロで初期化されます。")
test("k = math.matrix()")
test("k.subset(math.index(2), 6)") // [0, 0, 6]
writeln("")

comment("新しい要素を null に設定しながら、行列の範囲外の値を設定")
test("m = math.matrix()")
test("defaultValue = null")
test("m.subset(math.index(2), 6, defaultValue)") // [null, null, 6]
writeln("")

comment("範囲の作成")
test("math.range(1, 6)") // [1, 2, 3, 4, 5]
test("math.range(0, 18, 3)") // [0, 3, 6, 9, 12, 15]
test("math.range('2:-1:-3')") // [2, 1, 0, -1, -2]
test("math.factorial(math.range('1:6'))") // [1, 2, 6, 24, 120]
writeln("")

Matrix 0.2

Math.js でベクトルの定義と計算を行ってみました。

実行結果

matrix02.html

ソース

Math.js のソースファイルはインターネット上のものを指定しています。 Math.js と SyntaxHighlighter を併用するとブラウザのスタックが溢れてしまうので、 このページでは SyntaxHighlighter は使用しません。
<script src="https://unpkg.com/mathjs@9.5.0/lib/browser/math.js">

HTML の <body> タグに以下のコードを埋め込みました。

/**
 * 結果表示用の関数です。HTMLとして展開します。
 * @since 0.1
 */
function writeln(str) {
	document.writeln(str + "<br>");
}
function write(str) {
	document.writeln(str);
}

/**
 * コメントを表示する関数です。
 * @sinse 0.1
 */
function comment(str) {
	writeln("<span style='color: lime'>// " + str + "</span>");
}

/**
 * テストの実行と表示を行う関数です。
 * @since 0.1
 */
function test(exp) {
	write(exp + " ");
	var ans = eval(exp);
	comment(ans);
}

comment("配列による行ベクトルの定義")
test("r1 = math.matrix([[1, 0, 0]])") // [[1, 0, 0]]
test("r1.size()") // 1,3
test("precision = 4") // 4
test("math.format(r1.size(), precision)") // [1, 3]
writeln("")

comment("転置 transpose による列ベクトルの定義")
test("c1 = math.transpose(r1)") // [[1], [0], [0]]
test("c1.size()") // 3,1
test("math.format(c1.size(), precision)") // [3, 1]
writeln("")

comment("zeros による行ベクトルの定義")
test("r0 = math.matrix(math.zeros(1, 3))") // [[0, 0, 0]]
comment("subset による行ベクトルの定義")
test("r2 = r0.subset(math.index(0, 1), 1)") // [[0, 1, 0]]
comment("行ベクトルの和")
test("r12 = math.add(r1, r2)") // [[1, 1, 0]]
writeln("")

comment("zeros による列ベクトルの定義")
test("c0 = math.matrix(math.zeros(3, 1))") // [[0], [0], [0]]
comment("subset による列ベクトルの定義")
test("c2 = c0.subset(math.index(1, 0), 1)") // [[0], [1], [0]]
writeln("")

comment("行ベクトルを配列として取り出す")
test("array = r1.valueOf()") // 1,0,0
comment("format による表示")
test("math.format(array, precision)") // [[1, 0, 0]]
comment("行ベクトルの要素")
test("array[0][0]") // 1
test("array[0][1]") // 0
test("array[0][2]") // 0
writeln("")

comment("列ベクトルを配列として取り出す")
test("array = c2.valueOf()") // 0,1,0
comment("format による表示")
test("math.format(array, precision)") // [[0], [1], [0]]
comment("列ベクトルの要素")
test("array[0][0]") // 0
test("array[1][0]") // 1
test("array[2][0]") // 0
writeln("")

comment("ベクトルの演算")
test("v1 = math.matrix([[1, 2, 3]])") // [[1, 2, 3]]
test("v2 = math.matrix([[4, 5, 6]])") // [[4, 5, 6]]
comment("和")
test("math.add(v1, v2)") // [[5, 7, 9]]
comment("差")
test("math.subtract(v1, v2)") // [[-3, -3, -3]]
comment("内積")
test("math.multiply(v1, math.transpose(v2))") // [[32]]
comment("外積")
test("math.multiply(math.transpose(v1), v2)") // [[4, 5, 6], [8, 10, 12], [12, 15, 18]]
writeln("")

Matrix 0.3

Math.js で計算した行列を TEX に変換してみました。

実行結果

matrix03.html

ソース

Math.js のソースファイルはインターネット上のものを指定しています。 Math.js と SyntaxHighlighter を併用するとブラウザのスタックが溢れてしまうので、 このページでは SyntaxHighlighter は使用しません。
<script src="https://unpkg.com/mathjs@9.5.0/lib/browser/math.js">

HTML の <body> タグに以下のコードを埋め込みました。

/**
 * 結果表示用の関数です。HTMLとして展開します。
 * @since 0.1
 */
function writeln(str) {
	document.writeln(str + "<br>");
}
function write(str) {
	document.writeln(str);
}

/**
 * コメントを表示する関数です。
 * @sinse 0.1
 */
function comment(str) {
	writeln("<span style='color: lime'>// " + str + "</span>");
}

/**
 * 複数行のコメントを表示する関数です。
 * @sinse 0.3
 */
function comment1(str) {
	writeln("<div style='color: lime'>/* " + str)
}
function comment2(str) {
	writeln(str)
}
function comment3(str) {
	writeln(str + " */</div>")
}

/**
 * 行列をTeXに変換する関数です。
 * @sinse 0.3
 */
function matrix2tex(mtx) {
	typ = math.typeOf(mtx)
	if (typ == "Matrix" || typ == "Array") {
		dim = mtx.size()
		rows = dim[0]
		cols = dim[1]
		tex = "\\begin{bmatrix}<br>"
		for (i = 0; i < rows; i++) {
			for (j = 0; j < cols; j++) {
				tex += mtx.subset(math.index(i, j))
				if (j < cols - 1) {
					tex += " \& "
				}
			}
			if (i < rows - 1) {
				tex += " \\\\"
			}
			tex += "<br>"
		}
		tex += "\\end{bmatrix}" 
	} else {
		tex = mtx
	}
	return tex
}

/**
 * テストの実行と表示を行う関数です。
 * @since 0.1
 */
function test(exp) {
	write(exp + " ");
	var ans = eval(exp);
	comment(ans);
}

/**
 * 行列の結果をテキストとTeXで行う関数です。
 * @since 0.3
 */
 function testM(exp) {
	write(exp + " ")
	var ans = eval(exp)
	comment(ans)
	var tex = matrix2tex(ans)
	comment1("TeX")
	comment2(tex)
	comment3("")
}

comment("交点ベクトル v[i] の定義")
v = []
v[0] = math.matrix(math.zeros(1, 9))
for (i = 1; i <= 9; i++) {
	v[i] = v[0].clone()
	v[i].subset(math.index(0, i - 1), 1)
}
testM("v[0]") // [[0, 0, 0, 0, 0, 0, 0, 0, 0]]
testM("v[1]") // [[1, 0, 0, 0, 0, 0, 0, 0, 0]]
testM("v[9]") // [[0, 0, 0, 0, 0, 0, 0, 0, 1]]
writeln("")

comment("隣接行列 A[1] の定義")
A = []
A[1] = math.matrix()
testM("math.add(v[2],v[4])")
A[1].subset(math.index(0, math.range(0, 9)), math.add(v[2], v[4]))
A[1].subset(math.index(1, math.range(0, 9)), math.add(math.add(v[1], v[3]), v[5]))
A[1].subset(math.index(2, math.range(0, 9)), math.add(v[2], v[6]))
A[1].subset(math.index(3, math.range(0, 9)), math.add(math.add(v[1], v[5]), v[7]))
A[1].subset(math.index(4, math.range(0, 9)), math.add(math.add(math.add(v[2], v[4]), v[6]), v[8]))
A[1].subset(math.index(5, math.range(0, 9)), math.add(math.add(v[3], v[5]), v[9]))
A[1].subset(math.index(6, math.range(0, 9)), math.add(v[4], v[8]))
A[1].subset(math.index(7, math.range(0, 9)), math.add(math.add(v[5], v[7]), v[9]))
A[1].subset(math.index(8, math.range(0, 9)), math.add(v[6], v[8]))
testM("A[1]") // [[0, 1, 0, 1, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 1, 0, 0, 0], [1, 0, 0, 0, 1, 0, 1, 0, 0], [0, 1, 0, 1, 0, 1, 0, 1, 0], [0, 0, 1, 0, 1, 0, 0, 0, 1], [0, 0, 0, 1, 0, 0, 0, 1, 0], [0, 0, 0, 0, 1, 0, 1, 0, 1], [0, 0, 0, 0, 0, 1, 0, 1, 0]]
writeln("")

comment("隣接行列 A[1] の2乗 A[1]^2")
testM("A[2] = math.multiply(A[1], A[1])") // [[2, 0, 1, 0, 2, 0, 1, 0, 0], [0, 3, 0, 2, 0, 2, 0, 1, 0], [1, 0, 2, 0, 2, 0, 0, 0, 1], [0, 2, 0, 3, 0, 1, 0, 2, 0], [2, 0, 2, 0, 4, 0, 2, 0, 2], [0, 2, 0, 1, 0, 3, 0, 2, 0], [1, 0, 0, 0, 2, 0, 2, 0, 1], [0, 1, 0, 2, 0, 2, 0, 3, 0], [0, 0, 1, 0, 2, 0, 1, 0, 2]]
comment("隣接行列 A[1] の3乗 A[1]^3")
testM("A[3] = math.multiply(A[2], A[1])") // [[0, 5, 0, 5, 0, 3, 0, 3, 0], [5, 0, 5, 0, 8, 0, 3, 0, 3], [0, 5, 0, 3, 0, 5, 0, 3, 0], [5, 0, 3, 0, 8, 0, 5, 0, 3], [0, 8, 0, 8, 0, 8, 0, 8, 0], [3, 0, 5, 0, 8, 0, 3, 0, 5], [0, 3, 0, 5, 0, 3, 0, 5, 0], [3, 0, 3, 0, 8, 0, 5, 0, 5], [0, 3, 0, 3, 0, 5, 0, 5, 0]]
comment("隣接行列 A[1] の4乗 A[1]^4")
testM("A[4] = math.multiply(A[3], A[1])") // [[10, 0, 8, 0, 16, 0, 8, 0, 6], [0, 18, 0, 16, 0, 16, 0, 14, 0], [8, 0, 10, 0, 16, 0, 6, 0, 8], [0, 16, 0, 18, 0, 14, 0, 16, 0], [16, 0, 16, 0, 32, 0, 16, 0, 16], [0, 16, 0, 14, 0, 18, 0, 16, 0], [8, 0, 6, 0, 16, 0, 10, 0, 8], [0, 14, 0, 16, 0, 16, 0, 18, 0], [6, 0, 8, 0, 16, 0, 8, 0, 10]]
writeln("")

comment("交点ベクトル v[i] と 隣接行列 A[1] の積")
testM("math.multiply(v[1], A[1])")
writeln("")

comment("隣あう交点ベクトルと 隣接行列 A[1] の積")
testM("math.multiply(math.add(v[4], v[5]), A[1])")
writeln("")

comment("連をなす3交点ベクトルと 隣接行列 A[1] の積")
testM("math.multiply(math.add(math.add(v[4], v[5]), v[6]), A[1])")
writeln("")