0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Math.js で行列計算

Last updated at Posted at 2022-10-26

JavaScript で 6 元連立方程式を大量に解く必要があったので Math.js を試しました。Deno での利用についても触れます。

※ Python の numpy や sympy を使うなら情報も多くて簡単ですが、方程式が必要になったコードの他の部分は Deno で書いていたこともあって JavaScript でやってみました。

Node.js

ダウンロードページに書いてあるように配布物が 1 ファイルにまとめられているので、npm ではなくそちらを使います。

まずは感触をつかむため REPL で使ってみます。

math.js をダウンロードして置いたディレクトリで Node.js を起動して、行列の計算をします。

> math = require("./math.js")

> x=[[1,2],[3,4]]
[ [ 1, 2 ], [ 3, 4 ] ]
> y=[5,6]
[ 5, 6 ]
> math.multiply(x,y)
[ 17, 39 ]
x=\begin{pmatrix}1&2\\3&4\end{pmatrix},
\ y=\begin{pmatrix}5\\6\end{pmatrix},
\ xy=\begin{pmatrix}17\\39\end{pmatrix}

※ 演算子のオーバーロードができないため x * y のような書き方はできません。

メソッドチェーン

プロトタイプが拡張されたわけではないので、x.multiply(y) のようにメソッドを呼ぶことはできません。

その代わり chaindone で挟めばメソッドチェーンが使えます。

> math.chain(x).multiply(y).done()
[ 17, 39 ]

簡単な計算だと冗長なだけですが、ある程度長くなればメリットがありそうです。

比較のため両方の書き方で同じ計算をしてみます。

> math.multiply(math.transpose(math.multiply(x,y)),math.inv(x))
[ 24.5, -2.5 ]
> math.chain(x).multiply(y).transpose().multiply(math.inv(x)).done()
[ 24.5, -2.5 ]
(xy)^\top x^{-1}=\begin{pmatrix}24.5\\-2.5\end{pmatrix}

※ ベクトルは自動的に転置されるため、コードでは転置を省略できます。

> math.multiply(math.multiply(x, y), math.inv(x))
[ 24.5, -2.5 ]
> math.chain(x).multiply(y).multiply(math.inv(x)).done()
[ 24.5, -2.5 ]

REPL で math. まで書いて [Tab] で候補を出して、気になったメソッドをドキュメントで確認すれば良さそうです。

連立方程式

連立方程式を解くには行列で書き直します。

\left\{
\begin{array}{l}
3x+2y=2 \\
4x+3y=3
\end{array}
\right.
\quad\rightarrow\quad
\begin{pmatrix}3&2\\4&3\end{pmatrix}
\begin{pmatrix}x\\y\end{pmatrix}
=\begin{pmatrix}2\\3\end{pmatrix}

両辺に左側から係数の逆行列を掛けることで解が求まります。

\begin{pmatrix}x\\y\end{pmatrix}
=\begin{pmatrix}3&2\\4&3\end{pmatrix}^{-1}
 \begin{pmatrix}2\\3\end{pmatrix}
=\begin{pmatrix}0\\1\end{pmatrix}

これをコードで計算します。

> math.chain([[3,2],[4,3]]).inv().multiply([2,3]).done()
[ 0, 1 ]

なお、今回の調査の目的だった 6 元連立方程式は、行列のサイズを大きくするだけで計算できました。

Deno

Deno を認識して Node.js 互換周りの面倒を見てくれる CDN があり、そのうち 1 つの esm.sh 経由で読み込みます。

> import * as math from "https://esm.sh/mathjs@11.3.2/"
undefined
> math.chain([[3,2],[4,3]]).inv().multiply([2,3]).done()
[ 0, 1 ]

試行錯誤

参考までに、試行錯誤の過程を残しておきます。

ドキュメントには import する例が載っています。

import { sqrt } from 'mathjs'

console.log(sqrt(-4).toString()) // 2i

Deno の REPL で試すとエラーになりました。

> import { sqrt } from "./math.js"
Uncaught TypeError: Cannot set properties of undefined (setting 'math')
    at file:///mnt/c/Users/7shi/Desktop/%E4%BD%9C%E6%A5%AD%E4%B8%AD/tts/gismu/node/math.js:2:184
    at file:///mnt/c/Users/7shi/Desktop/%E4%BD%9C%E6%A5%AD%E4%B8%AD/tts/gismu/node/math.js:2:189

math.js は Babel で生成された読むのに適さないコードです。整形して最初の部分を見ると、環境ごとにエクスポート先を選んでいる部分でエラーになっています。

整形したコード
!function (e,t) {
  "object" == typeof exports && "object" == typeof module
  ? module.exports = t()
  : "function" == typeof define && define.amd
    ? define([], t)
    : "object" == typeof exports
      ? exports.math = t()
      : e.math = t() // ここでエラー
}(this, (() => (() => {

exports というオブジェクトを用意するだけでうまくいきました。

> const exports={}
undefined
> import "./math.js"
Module {}
> exports.math.sqrt(4)
2

モジュールとしてインポートしたわけではなく、exports.math = t() によってライブラリが詰め込まれた状態です。

かなり無理やりな方法で、しかも REPL でしか通用しません。コードをファイルに書くと名前空間が分離されるため、ダミーで用意した exports が見付けられなくなります。

互換モード

Deno には Node.js の互換モードがあったようです。

互換モードは既に削除されたとのことですが、Deno をサポートした CDN 経由で読み込む方法が紹介されています。

例えば、esm.shSkypackなどのCDNは、Node.jsの組み込みモジュールの読み込みを検出すると、自動的にdeno_std/nodeを読み込むように置換してくれます。

esm.sh 経由でモジュールを読み込むとすんなり動きました。これが最初に紹介した方法です。

Deno が npm をサポートしたのもつい最近だったと思いましたが、それとは別に CDN 側でも Deno 対応が進んでいるのは驚きました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?