ScalaNLPを使う

Scala用の科学計算ライブラリを引き続き探していたところ、ScalaNLPというのを見つけた。
名前通りNatural Language Processing、つまり自然言語処理用のライブラリなのだが、数学周りも結構充実しているし、何よりScala向けにチューニングされたライブラリなので、これを使うのがよいだろう。

sbtを使う

Scala Build Toolか〜」と思っていたら、実は「Simple Build Tool」だったという罠。
とまあひとまず置いておいて、sbtを使うとライブラリの依存関係解決や自動ビルドが非常に便利。
ScalaNLPもさっと使えてしまうので、これを使わない手はない。
詳しい日本語解説サイトはここにあるのでぜひ参照されたい。

【参考】始める sbt - ようこそ

sbtのインストールについては割愛する。
僕はMacで作業しているけれど、Macならbrewでサクッとインストールできるはずだ。
とりあえずこんな感じでbuild.sbt(sbtのconfigファイル)を書いて、プロジェクトのルートディレクトリにおいてみよう。

// プロジェクト名
name := "project"

// プロジェクトバージョン
version := "1.0"

// 使用するscalaのバージョン
scalaVersion := "2.10.4"

// 以下ScalaNLPのインストール手順よりコピペ
libraryDependencies  ++= Seq(
	// other dependencies here
	"org.scalanlp" % "breeze_2.10" % "0.7",
	// native libraries are not included by default. add this if you want them (as of 0.7)
	// native libraries greatly improve performance, but increase jar sizes.
	"org.scalanlp" % "breeze-natives_2.10" % "0.7"
	)

resolvers ++= Seq(
	// other resolvers here
	"Sonatype Releases" at "https://oss.sonatype.org/content/repositories/releases/"
)

ScalaNLPのインストール用記述は以下のWikiを参照した。
【参考】Installation · scalanlp/breeze Wiki · GitHub

ここでシェルからsbtコマンドを叩くと何やら依存関係を解決するためにいろいろダウンロードしてきて、最終的には止まってプロンプトが出る。
プロンプトが出たら一旦抜ける。sbtの準備は完了だ。

ScalaNLPを使って計算してみる

sbtはディレクトリ構造が一応あるみたいだが、プロジェクトのルート以下に.scalaファイルをおけばちゃんと反応してコンパイルしてくれるようだ。
普通は
.
├─ build.sbt
├── project
│   └── target
├── src
│   └── main
│   └── scala // .scalaファイル
│   └── resources // .jarファイル等
└── target
みたいな階層構造にするのが一般的のようだ。
projectとtargetはsbtによる自動生成物だ。

というわけでサンプル。

import breeze.linalg._
import breeze.math._
import breeze.numerics._
import scala.math._

object Test {
	def main(args: Array[String]) {
		println(s"e^{i*pi} = ${Complex(E,0).pow(Complex(0,Pi))}")
	}
}

実行結果

$ sbt run
......
[info] Running Test
e^{i*pi} = -1.0 + 1.2246467991473532E-16i
[success] Total time: 2 s, completed Jul 22, 2014 9:43:40 AM

虚数部に丸め誤差が出てしまったが、概ねよいといえるだろう。
今回はオイラーの公式を用いて
e^{i\pi}=\cos\pi+i\sin\pi=-1
を計算した。

breezeというのが、ScalaNLPに含まれるうち数学を主に扱うライブラリ群だ。
とりあえずbreeze.linalg、breeze.math、breeze.numericsをimportしておけばよいだろう。
あとは説明は不要だと思う。
ちなみに、いちいちComplexのインスタンスを生成するのが面倒であれば、

implicit def double2complex(x: Double) = Complex(x, 0)

のように暗黙の型変換を定義しておくとよい。

今回は相変わらず複素数計算に留まってしまったが、ScalaNLPは実際にはMatlabやNumPyをリスペクトしたライブラリなので、行列計算もお手の物だ。
(ただし例によってScalaは型にうるさいため、Stringを要素に含んだ行列を生成するにはどうすればよいか現在検討中であるが)