作業中のメモ

よく「計算機」を使って作業をする.知らなかったことを中心にまとめるつもり.

【改訂版】 LaTeX に複数のソースコードを載せる

どうも,お久しぶりです.筆者です.

更新理由

以前,LaTeX の記事 を書いたが,プリアンブルの記述が汚かったので,もう少し綺麗にかけないものかと思い,色々調べた.

方法

方法という程しっかりしたものではないが,以前作成したものを少しいじればよい. 具体的には,言語を指定しないスタイルを定義(lstdefinestyle)し,後で,これを言語毎に呼び出せばよい.

比較的簡単ではあるが,以前ここまで出来なかったのは,単純に,複数の言語を LaTeX に取り込めるという段階で満足してしまっていたためである.お恥ずかしい.

コード

さて,いつも通り,コードを載せておく.今回は,アルファベット順に並び替え,色の定義等も行っておいたので,適宜変更すれば自分好みのものに変更出来る.

また,ソースコードの一番下に「includeCode」というコマンドも定義しておいた.これは,ファイルから呼び出すときに便利であると思う. 例えば,「./src/main.c」にある C コードを LaTeX に貼りたい場合は,

\includeCode[C]{./src/main.c}{main}

としてもらえればよい.最初の C は「CustomC」の C である.という事は,「./sample.sh」の shell script を LaTeX に貼りたい場合は,

\includeCode[Bash]{./sample.sh}{title}

とすれば良いのである.また,3 つ目の引数は,ソースコードの caption として表示される項目である.上記の場合,それぞれ「main」と「title」と表示されるはずである.

一言

今まで gist にコードを書いて,スクリプトを持ってきていたが,はてなブログでも,シンタックス・ハイライトに対応しているんだな.最近知ったことである.今後どうやってコードを書いていこうか,悩みどころだ. まぁ,今回みたいに,短いものはここに書いて,長いものは gist だろうなぁ.

Ubuntu 14.04 LTE の入力メソッド

どうも筆者です.

最近,仮想 OS に Ubuntu 14.04 LTE をインストールした. しかし,デフォルトの Unity では動作が重いため,Xubuntu を導入することにした.

Xubuntu の導入

Xubuntu 自体は,コマンド叩けば導入が出来た.

ところが,いつも通り日本語を入力しようとすると,直接入力と日本語入力が,高速に切り替わる状況となってしまった.すなわち,日本語を入力しようとしても,タイミングが悪いと直接入力になってしまい,直接入力に変更しようとしても,タイミングが悪いと日本語入力のままという状況になった.このままでは,使いづらいので,何とかする必要があった.

入力メソッドについて

まずは,入力メソッドについて調べた.すると,IBus や Fcitx,uim というものがあることが分かった.最近では,Fcitx が主に利用されているようである.

入力メソッドの確認

ここでは,自分の計算機が Fcitx になっているか調べるため,「設定」→「言語サポート」から,「キーボード入力に使う IM システム」の項目を調べ,fcitx となっていることを確認した. 次に,「設定」→「fcitx 設定」から,fcitx の設定を確認した.

入力メソッドの設定内容

入力メソッドには,「日本語キーボード」と「Mozc」が設定されており,全体の設定では,Zenkakuhankaku と Ctrl + Space で,入力メソッドのオンオフが出来るようになっていた. 試しに,Zenkakuhankaku のキーを ESC キーで無効にしたところ,問題はなくなったが,Ctrl + Space で入力切替を行わないといけない状況になってしまった.コレでは不便である. そこで,どこかに設定ファイルがあると思い,探してみると,以下の場所にあることが分かった.

入力メソッドの設定ファイルの変更

設定ファイルの場所が分かったので,これを編集して設定を行う.まずは,ESC キーで切り替えが行えるようにした.

これで,荒ぶることなく切り替えが行えるようになったが,Vim を使用する筆者にとって,これでは少し不便であった.設定ファイルをもう少し見ていくと,インプットメソッドをオンにする時と,オフにする時のキーが別々で設定できることが分かった.

そこで,インプットメソッドをオンにするときは,半角/全角キーを,オフにするときは ESC キーを使うように設定を行った.

これで,荒ぶることなく,Vim に支障なく日本語と直接入力の切り替えが行えるようになった.

レーベンバーグ・マーカート法と準ニュートン法(C 言語)

どうも筆者です.

最近,観測データを既知の関数で近似する必要が生じた.そのための近似方法を以前示したが,あれは,そのままプログラムを組むと,次元が大きくなると解きにくくなってしまうという問題がある. そのため,何か良い方法がないかと調べていたところ,「レーベンバーグ・マーカート法」というものがあることが分かった.

レーベンバーグ・マーカート法は,非線形関数の 2 乗和が最小になるものを求める方法として使われるらしい.これを使えば,誤差の 2 乗和が最小となるという点で,関数フィッティングが行える.

これを使うには,「LAPACK」と「BLAS」が必要になる.なので,参考サイトにあるように,インストールを試みたが,「levmar」が上手くインストール出来なかった.しかし,筆者の PC には,Intel コンパイラがインストールされている.このときに,MKL も一緒にインストールされるので,これを用いれば実行出来るのではないかと考えた.Makefile があったので,Intel 用の「Makefile.icc」を書き換えることにした.現段階では,バージョンが 2.6 であり,Makefile.icc の中身は,1 段目のようになっている.このまま使えば動くはずだったが,上手く動かなかった(f2c をインストールし忘れていたのが原因だと思う)ので,Makefile.icc を 2 段目のように書き換えた.

これで,実行することが出来た.ここで,[IntelVersion] は,各々がインストールした Intel Compiler のバージョンが記述されたディレクトリ名が入る.ここは,各自調べて欲しい.

また,関数の最小値も求めたかったので,色々調べた.すると,「liblbfgs」というパッケージが存在することが分かった.これは,Fortran で実装されていた「準ニュートン法」を C 言語に直したものらしい.よくやったなぁ...作者に感謝しつつ,手順に従ってインストールすることにした.しかし,これも何故かインストールが上手くいかなかったので,仕方なく,毎回コンパイルすることにした.

修正した Makefile とソースコートは以下のようになった.

また,ファイルの階層は,

  • Makefile [libsrc] [src]
    • [libsrc] 「levmar-2.6」に含まれているファイルを全てコピーし,Makefile を書き換えたもの.
    • [src] MT.h arithmetic_ansi.h lbfgs.c lbfgs.h main.c

という風になっている.分かりづらくて申し訳ない.

今回は,

 { \displaystyle 
  y = -2x^{2} + 6x + \dfrac{1}{2}
}

の最大値を求めることにした.真の関数値に ボックス・ミューラー法により,標準正規分布に従う乱数を加えたものを測定値とした.そして,

  1. レーベンバーグ・マーカート法により,測定データを 2 次関数で近似する.そのときのパラメータを p[0],p[1],p[2] とした.
  2. 近似したパラメータを用いて,準ニュートン法により,最大値をとる  x を求めた.

という流れで処理を行った.最初は,levmar で実装されている「dlevmar_dif」の引数「adata」の使い方が分からなかったが,調べたところ,キャストして渡せばよいらしいので,プログラムにあるように渡した.また,これと似た関数に「dlevmar_def」というものがある.これは,ヤコビ行列を計算する関数を自分で与える場合に利用する.今回は,面倒だったので,近似したものを用いた(すなわち,dlevmar_dif を利用した).

また,lbfgs では,float と double の使い分けが出来るようにしてあるため,double ではなく,「lbfgsfloatval_t」というものが利用されている.個人的には,double でしか計算しないので,ここは,double と書いてもかまわない(ヘッダーで typedef により宣言されているだけなので).

dlevmar_dif には,ユーザー側が与えるデータとして,測定データを与えているのに対し,lbfgs では,推定した係数データを与えていることに注意.また,最小値を求める関数であるため,最大値を求める場合は,マイナスをかけておく必要がある.そのため,evaluate 関数では,最後に,g[0] と fx の符号を反転させている.

これを実行すると,p[0] = -2.002300,p[1] = 5.944318,p[2] = 0.611619 と係数を推定でき,最大値を取る  x は, \hat{x} = 1.484373 と求められる.真の関数では, x^{*} = \dfrac{3}{2} のとき最大となるので,正しく推定できていることが確認できた.

参考文献

Levenberg-Marquardt in C/C++

http://kivantium.hateblo.jp/entry/20140408/p1

http://www.sat.t.u-tokyo.ac.jp/~omi/random_variables_generation.html#Prepare_MT

Windows 7 での画面出力の設定

お久しぶりです.筆者です.

最近,PC を買い換えた.最近のマザーボードには,DVI や HDMI のグラフィック出力機能が搭載されているんだな.進歩したものだ.

以前使用していた PC には,マザーボードにそういった機能がなかったため,グラフィックボードを購入して取り付けていた.今回は,以前購入したオンボードに加え,オンボードの出力も利用できることとなる. 筆者は今,デュアルモニタで PC を使用している.しかし,冬場の寒い時期や友達が来たときには,テレビ等に出力して作業をしたくなるときがある. そこで,必要なときにテレビに出力する方法を以前から考えていたが,たまにしか使わない機能のためにグラボを買い足すのに意味があるのか,と考えていた. 今回は,以前から考えていたことが実現できるのではないかと思い至った.

前置きが長くなったが,今回もたいしたことではない.ただ単に,Windows の知らなかった機能が知れたという報告だけである.

さて,実際にテレビにつなぐため,AmazonHDMI ケーブルを購入し,配線を行った.BIOS 等の設定をして,グラボとオンボードの両方が使えるようにした(細かいことは,以下の URL を参考にした).その後,ドライバー等の設定を行って,テレビに出力することに成功した.

成功はしたが,まだこの時期(設定したのは 10 月初め)は,そこまで寒くないので,テレビに出力することはほとんどない.しかし,比較的友達が遊びに来るので,平均して 2 週間に 1 回程度はテレビに出力していた.また,普段テレビも見るので,

  1. 友達が来て,必要になったら HDMI ケーブルをオンボード側につなぐ.
  2. パソコンを使いつつ,テレビもつけたくなったら,HDMI ケーブルを抜く.

ということを行っていた.ただ,これはかなり面倒な作業であって,個人的に,あまりプラグを抜き差ししたくなかった.また,最近は接続をする頻度が高くなっていたので,その度にいじらなければならなかった.

そこで,何か良い方法がないかと,今日調べた(遅い).すると,流石は Windows,ソフトウェアを入れなくても欲しい機能がすでに備わっていた.「画面の解像度」の設定から,認識しているモニタの数を確認する.現段階では,PC 用のモニタ 2 台とテレビの合計 3 台であった.ここから,テレビの出力をしている(設定画面上の)モニタを選択肢し,「複数のディスプレイ」の部分に注目する.多くの場合は,「表示画面を拡張する」という風になっている.ここからプルダウンメニューの項目を見ると,「このディスプレイを切断する」という項目があることに気づいた.テレビに対してこの設定を行うと,テレビを見ていても HDMI の出力はされなくなりかつ,ケーブルを取り外さなくて良くなる.この機能を知ったときに筆者は感動した.

この機能のおかげで,ケーブルを抜き差しすることなく,システム上で出力の設定が「手軽に」行えるのである.PC をつけたたま,テレビを消すと,設定画面上からは消えてしまうが,再びテレビをつけたときに「検出」をしてやることで再び認識される.

普段,デュアルモニタで一方を表示させないような設定をしようとは思わないため,この機能に気付かなかった.このおかげで,得した気分になれた.

テレビに出力している人で,同じことを考えている人がいたら,ぜひ参考にして欲しい.ではでは.

参考文献

Z87-PRO:オンボード出力とグラフィックカード出力の同時利用(マルチディスプレイ)について

LU 分解による連立一次方程式の解法

前回は,ガウスの消去法について,簡単に説明した.今回は,LU 分解について説明する.

LU 分解

行列  {A}正則行列逆行列を持つもの)であるとする.このとき,行列  {A} を部分ピボット選択をする(この行列を  {P} とする)ことにより,

 { \displaystyle
  PA = LU
}

のように LU 分解できる.ここで,L,U はそれぞれ,

 { \displaystyle
  \begin{equation}
    L = \left(
      \begin{array}{ccccc}
        1 & 0 & 0 & \cdots & 0\\
        l_{2}^{(1)} & 1 & 0 & \cdots & 0\\
        l_{3}^{(1)} & l_{3}^{(2)} & 1 & \cdots & 0\\
        \vdots & \vdots & \vdots & \ddots & \vdots\\
        l_{n}^{(1)} & l_{n}^{(2)} & l_{n}^{(3)} & \cdots & 1\\
      \end{array}
    \right),\quad U = \left(
      \begin{array}{ccccc}
        a_{11}^{(0)} & a_{12}^{(0)} & a_{13}^{(0)} & \cdots & a_{1n}^{(0)}\\
        0 & a_{22}^{(1)} & a_{23}^{(1)} & \cdots & \cdots a_{2n}^{(1)}\\
        0 & 0 & a_{33}^{(2)} & \cdots & a_{3n}^{(2)}\\
        \vdots & \vdots & \vdots & \ddots & \vdots\\
        0 & 0 & 0 & \cdots & a_{nn}^{(n - 1)}\\
      \end{array}
    \right)
  \end{equation}
}

である.ここから,  {A\boldsymbol{x} = \boldsymbol{b}} を解くことを考える.まず, {L \boldsymbol{y} = P\boldsymbol{b}} を解く.すなわち,

 { \displaystyle
  \begin{equation}
    \left(
      \begin{array}{ccccc}
        1 & 0 & 0 & \cdots & 0\\
        l_{2}^{(1)} & 1 & 0 & \cdots & 0\\
        l_{3}^{(1)} & l_{3}^{(2)} & 1 & \cdots & 0\\
        \vdots & \vdots & \vdots & \ddots & \vdots\\
        l_{n}^{(1)} & l_{n}^{(2)} & l_{n}^{(3)} & \cdots & 1\\
      \end{array}
    \right)\left(
      \begin{array}{c}
        y_{1}\\
        y_{2}\\
        y_{3}\\
        \vdots\\
        y_{n}\\
      \end{array}
    \right) = \left(
      \begin{array}{c}
        b_{p_{1}}\\
        b_{p_{2}}\\
        b_{p_{3}}\\
        \vdots\\
        b_{p_{n}}\\
      \end{array}
    \right)
  \end{equation}
}

を解くことになる.ここで, {b_{p_{k}}} は,部分ピボット選択により,入れ替えたものを表す.入れ替えが行われなかった場合は, {b_{p_{k}} = b_{k}} である. この方程式は,前進代入で解くことが出来る.つまり,

 { \displaystyle
  \begin{equation}
    y_{k} = b_{p_{k}} - \sum_{j = 1}^{k - 1} l_{k}^{(j)} y_{j},\quad (k = 1, \cdots, n)
  \end{equation}
}

で求められる.次に, {U \boldsymbol{x} = \boldsymbol{y}} を解く.すなわち,

 { \displaystyle
  \begin{equation}
    \left(
      \begin{array}{ccccc}
        a_{11}^{(0)} & a_{12}^{(0)} & a_{13}^{(0)} & \cdots & a_{1n}^{(0)}\\
        0 & a_{22}^{(1)} & a_{23}^{(1)} & \cdots & \cdots a_{2n}^{(1)}\\
        0 & 0 & a_{33}^{(2)} & \cdots & a_{3n}^{(2)}\\
        \vdots & \vdots & \vdots & \ddots & \vdots\\
        0 & 0 & 0 & \cdots & a_{nn}^{(n - 1)}\\
      \end{array}
    \right)\left(
      \begin{array}{c}
        x_{1}\\
        x_{2}\\
        x_{3}\\
        \vdots\\
        x_{n}\\
      \end{array}
    \right) = \left(
      \begin{array}{c}
        y_{1}\\
        y_{2}\\
        y_{3}\\
        \vdots\\
        y_{n}\\
      \end{array}
    \right)
  \end{equation}
}

を解く.これは,ガウスの消去法のときと同様に,後退代入で解くことが出来る.つまり,

 { \displaystyle
  \begin{equation}
    x_{k} = \dfrac{1}{a_{kk}^{(k - 1)}} \left( y_{k} - \sum_{j = k + 1}^{n} a_{kj}^{(k - 1)}x_{j} \right),\quad (k = n - 1, \cdots, 1)
  \end{equation}
}

で求められる.

アルゴリズム

これを,C 言語で書き下すと以下のようになる.

参考文献

ガウスの消去法,LU 分解 http://www.ms.u-tokyo.ac.jp/~narutaka/lec/lud.pdf

LU 分解法 http://www.kata-lab.itc.u-tokyo.ac.jp/OpenLecture/SP20121218.pdf