coffee break

某の情報系大学院生

Kotlin ~gradleでHello World~

kotlinてGUI開発ライブラリないのかよと憤慨していたがサードパーティー製でハイクオリティなtornadoFXというライブラリを見つけた。これはJavaFXを拡張してKotlinのコードで書けるようにしたものだ。開発が活発に進められていて、ガイドもしっかりしている(ただし全編英語)。いつか公式がこれをライブラリに組み込んでくれないかなーと期待。
github.com

だがこのライブラリを使うにはIDEAを使うか、mavenやgradleなどのビルドツールを使わなくてはならない。使わなくてもコンパイルまでは通せるが、実行すると謎の文言とともに大量のエラーを吐かれる。

そこで今回はまずgradleでkotlinのコードを実行できることを目標にする。gradleの導入は以下のサイトが非常にわかりやすく説明してくださっている。
qiita.com

フォルダ構成

今回はkotlinフォルダ直下のdemoフォルダにファイルを保存する。

├ src
│ ├ main
│ │ ├ kotlin
| | | ├ bin
| | | └ demo
│ │ └ java
│ └ test
│   ├ kotlin
│  └ java
├ build
| ├…
| …

└ build.gradle

HelloWorld.kt

クラスを持たない単純なhello world

package demo

fun main(args : Array<String>){
  println("Hello gradle!")
}

build.gradle

kotlin公式にこう書かれているのをちょっと編集する。
kotlinlang.org
tornadofxを使うことを見越して、今回はkotlin_version = '1.1.2'、kotlinOptions.jvmTarget = "1.8"を指定する。
これは先ほど挙げたtornadofxのサイトのReadMeに書いてある。

buildscript {
  ext.kotlin_version = '1.1.2'
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
  }
}

apply plugin: 'kotlin'
apply plugin: 'application'

compileKotlin{
  kotlinOptions.jvmTarget = "1.8"
}

mainClassName = 'demo.HelloWorldKt'

defaultTasks 'run'

repositories {
  mavenCentral()
}

dependencies {
  compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
  testCompile 'junit:junit:4.11'
  testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
}

task hello(type: JavaExec){
  main="demo"
  classpath = sourceSets.main.runtimeClasspath
}

javaでは一つのファイルに最低一つのクラスがあるので、taskの中にあるmain=でパッケージ名.mainメソッドを含むクラスネームを指定するが、kotlinはクラスを持たない場合もあるのでその時はパッケージ名のみを指定するのみでよいらしい。勘でやったらビルドできてしまったので詳しい仕様は知らない。またtaskのtype指定はJavaExecである。KotlinExecと書いたらそんなものはないと言われ失敗した。

上記のファイルを作成して>gradle buildを実行すると以下のように延々とダウンロードしながらビルドしてくれる。僕の環境では初回で20秒ほどかかっていた。オプションでDaemonを指定すれば次回以降は実行時間も短くなるかも?
f:id:mildtech:20170826213507p:plain
その後>gradle runを実行するとプログラムが走る。
結果は:runのすぐ下の行に出力される。ちゃんと正しくHello gradle!と表示されている。
f:id:mildtech:20170826213855p:plain

今後は実際にtornadofxを使って最低限のアプリ(ウィンドウ表示、ボタン、テキストボックスなどを備えたもの)を作っていこうと思う。

Kotlinの標準入力でつっかかった

最近Kotlinの勉強を始めた。Kotlinを知ったきっかけは、今年の5月にGoogleがKotlinをAndroid開発言語として正式にサポートするとの発表をしたことだ。当時大学の講義でJavaを勉強中だった僕にとって、たかが標準出力のだけに毎回System.out.printlnと打たなきゃいけないのがストレスでしょうがなかった。しかしKotlinではprintlnだけで済む。さらにhello worldのサンプルコードを見た時に、main関数がクラスに属する必要がないことも知って衝撃を受けた。調べるほどにKotlinの魅力にはまっていき、夏休み期間に入ったこともあってようやく本格的にKotlinの勉強を始めることができた。

今回は標準入力の際にはまったことを記録しておく。KotlinはJava100%相互互換を謳っているので当然JavaのScannerも使える。JavaでScannerを使うには以下のように書けばいい。便宜上いろんなところを省いている。

import java.util.Scanner;

Scanner scan = new Scanner(System.in);

これに倣ってKotlinでも以下のように書くとコンパイルエラーとなる。

import java.util.Scanner

val scan = Scanner(System.in)

これはKotlinではinが予約語であるからではないかと思っている。(詳しく調べてないのであくまで推測)
なので色々調べるとScanner.`in`と書けばいいということはわかった。しかし`の打ち方で時間を食われた。何せ今まで使ったことなかった記号なので…
記号の名前はバッククォート、キーボード入力するときはShift+@だ。キーボードを見ればわかるのに見つけられなかった自分が恥ずかしい…
以上を踏まえてKotlinでの正しいScannerの使い方は以下のよう

import java.util.Scanner

val scan = Scanner(System.`in`)

あとはjavaと同じようにscan.nextInt()などを使って操作する。

LaTeXでハフマン符号の木を作る

大分前にレポートでハフマン符号を作る問題をやるときに、せっかくだからTeX上で作れないかなと方法を探していたら無事見つかったので残しておく。
考えはなんてことない、木構造を作るパッケージを使って木を横に伸びるようにさせるだけだ。

必要なパッケージ

tikz

これ1つだけでかなりの描画ツールが使用できる。今回はtreesを用いる。

サンプルコード

今回は4つの要素を持つハフマン符号を作成する。

実行結果

f:id:mildtech:20170728223610p:plain
木にしては結構歪な仕上がりになっているが枝に割り当てる符号語を表示させたかったためこれでいいとする。

解説

  • \documentclass[dvipdfmx]{artcle}

出力時のドライバにdvipdfmxを必ず指定することを忘れないこと。これを忘れるとせっかく作った木が全部表示されなくなる。

  • \usepackage{tikz}
  • \usetikzlibrary{trees}

tikzのライブラリtreesを使いますの宣言

  • \tikzset{スタイル名/.style = {スタイル内容}}

ノードの表示方法など、いちいち設定するのが面倒なので冒頭でエイリアスとして宣言する。今回はスタイル名をhollow nodeとして、各ノードが大きさ1ptの○になるように設定した。circleが〇,drawで○を表示せよ、inner sep = 1.0で直径1を指定している。
ノードを表示させずに枝を交差させる方法はないのか色々試したのだが、今のところ解決策は見つかっていないので妥協策。0pt指定もできるが下限値が設定されているらしく、それを下回ると下限値の大きさの○が表示され逆に見栄えが悪くなる。

  • \tikzset{level x/.style = {level distance = y cm,sibling distance = z cm}}
  • \tikzset{end/.style = {hollow node}}

xは何段目のノードであるかを表す。根が1段目だ。この段以降はすべてこの設定にしたいというときはx+と書くことで実現できる。yは次の段のノードとの高さを表す。zは親から分岐する子がどれくらい離れているかを表す。今回はこれに加え先ほど定義したhollow nodeもスタイルに加えることでノードの様式指定も同時に行っている。
今回は最終的にどのノード間も1cmになるよう調節した。残念ながら手動で計算して適切に設定しないと枝が重なったり木がぐちゃぐちゃになってしまう。自動でそろえてくれるパッケージもあるのだが、僕の理想の形の木を作ることができなかったので断念した(今回でも大分妥協してる部分が大きいのだが…)
endは葉を表す。これ以上分岐もすることないのでノードの様式だけ指定して終了。

  • \begin{tikzpicture}[オプション]
  • \end{tikzpicture}

これで挟まれた間に木構造の記述をする。今回は木を左方向に伸ばしたいのでオプションにgrow = leftを指定した。右に伸ばすときはrightにすればいい

  • \node[オプション]{ノード内容}

ここからが本番。このコードは根の宣言だ。ここから木を伸ばしていくのだが、木の記述を終えたらセミコロン";"で閉じなければならない
疑似コード風に書くと以下のようにする。

\node[option]{concept}
  child{
    ....
  }
  child{
    ....
  }
  ...;    %木全体の記述が終わったことを";"によって宣言

根は一段目なのでオプションに先ほど設定したlevel 1を付け加える。ノードには何も表示させないのでノード内容は空にしている。
これから子供たちの宣言をするのだが、pythonを書いている時並みのインデントを意識した方がいい。その方が親子の対応関係が分かりやすくなるからだ。

child{
node[オプション]{ノード内容}
edge from parent node[オプション]{オプション}
}

\node{}またはnode{}の下に直接childを書き込むことで木を伸ばすことができる。childの中で宣言されるnodeにバックスラッシュをつける必要はない。
サンプルコードのように入れ子状に書いていくことで木は形成される。level 1の直下に宣言されたchildは当然レベル2なのでnodeのオプションにはlevel 2を宣言する。1回のchild宣言につき一個の子ノードが作られるため、親から複数の子を伸ばすときはその回数分宣言する。
node
child{....}
child{....}
 ....
といった感じだ。

  • node[label=位置指定子:{ラベル内容}]{ノード内容}

ノードの周りに説明を書きたい場合はオプションにラベルを指定する。場所指定子はノードの左の場合はleft、右ならright、上ならabove、下ならbelowを指定する。このとき木の成長方向は関係なく、ノードに対する絶対位置で指定されることに注意されたい。位置を指定したらコロン":"を挟んで{}の中にラベルの内容を記述する。今回の例では数式コマンドを使っているので当然$$で囲む必要がある。また葉に対してラベルを付けているのでオプションにendも追加している。

  • edge from parent node[オプション]{ノード内容}

これは枝の途中に説明を加えるための記述だ。今回の例では割り振られた符号語を枝に表示させるために書いた。
edge from parentの字面そのままで、親から伸びてきた枝に対して何かしますよと言っている。nodeのオプションにはauto,swapが使える。これは枝に対してどちらの側にノード内容を表示させるかを指定するものだ。基本的にはautoを指定すると、親から子へ伸びる方向に対して左側に出力される。右側に出力させたい場合はswapも追加で指定する。サンプルコードと実行結果を見比べながら理解してほしい。


以上を駆使して頑張って書くとハフマン符号の木が作れる。ここまで説明しておいてなんだが、inkscapeillustratorなどを使って描画して画像を埋め込んだ方が自分の理想の木を簡単に作れる。TeX上ですべて完結させようとするとそれなりの労力を強いられることになるのでよく考えよう。

Windowsにjlistingパッケージを導入する

TeXソースコードを記載するとき、listings環境を使うと日本語を含むコメントが少々バグって表記されることがある。
これを解決するのにjlistingというパッケージを導入すればいいというのは調べてわかったのだが、Linux環境での説明であることが多くWindows10環境の僕ではどうやればいいのかわからなかった。長い時間をかけてようやく導入することに成功したので記録しておく。

jlistingパッケージのインストール

以下のページからjlisting.sty.bz2をダウンロードする。
osdn.net
ダウンロードしたファイルを以下のフォルダに移動させる。
C:w32tex\share\texmf-dist\tex\latex\listings
TexLiveを使ってる人は適宜読み替えてほしい。

Linuxに詳しくないので初めて知ったのだがbz2拡張子はLinuxではよく使われる圧縮方法らしい。Linuxで使われるということはWindowsではそのままだと解凍できないということだ。

Gowのインストール

そこで、WindowsのコマンドプロントでもLinuxのコマンドを使用できるようにするフリーソフトがあるのでダウンロードする。(今回は使わないがLinuxでよく見かけるsudoコマンドはこのソフトを入れても使うことができないので注意、あくまで.bz2形式ファイルを解凍するために入れる。)

github.com
このページの上方にあるDownload Installerをクリックしてダウンロード

ダウンロードしたらインストーラを実行するだけ、特に設定をいじらずにNextをおしまくればいい。
インストールが終わったらPCを再起動する。これで以下のLinuxコマンドが使えるようになる。
f:id:mildtech:20170724153716p:plain

今回使うLinuxコマンドはbzip2だ。

コマンドプロンプトを起動し、先ほどjlisting.sty.bz2を置いたC:w32tex\share\texmf-dist\tex\latex\listingsに移動する。
次に以下のコマンドを実行しファイルを解凍する。

bzip2 -d jlisting.sty.bz2

listingsフォルダの中を見て、jlisting.styファイルが7KBで存在してたら成功だ
ソースコードには¥usepackage{jlisting}と記述する。listingsと違って最後にsをつけないことに注意。あとは通常どおり書いていけば良い

jlistingなし
f:id:mildtech:20170724155530p:plain

jlistingあり
f:id:mildtech:20170724155534p:plain

確かに日本語付きコメントに対しても正しくlistingが適用されるようになった。

追記

Macの人もshare\texmf-dist\latex\listingを見つけてそこに入れて同様の操作を行えば行けるはず

LaTeX ページ番号

LaTeXのデフォルトの機能だとページ番号はフッターの中央に置かれるか表示させないかしかできない(?)ので,ページ番号の位置を指定される様式に対応できなかったが,先日ページ番号の位置をいじれるうえに表示形式も変えられる素晴らしいパッケージを見つけたので残しておく.

必要なパッケージ

  • fancyhdr

どうやらTeX Liveもしくはw32texを使ってる場合デフォルトでインストールされているらしい。特にダウンロードとかする必要はない。(2017/8/1追記)

以下のURLからダウンロード
http://www.ctan.org/tex-archive/macros/latex/contrib/fancyhdr
ダウンロードしたら解凍して画像みたいにTeXのフォルダの中に置いておくだけでOK.
f:id:mildtech:20170529130703p:plain

使い方

\usepackage{fancyhdr}した後,プリアンブルに詳しいページ番号の表示設定を書く.
そのあとこの設定を使いたい章のところで\pagestyle{foot}と書く.(どう書くかはサンプルコード参照).

\fancypagestyle{foot}
{
\fancyhead{}
\fancyfoot{}
\fancyfoot[L]{chapter 1}
\fancyfoot[C]{///sample page///}
\fancyfoot[R]{p.\thepage }
\renewcommand\headrulewidth{0pt}
}
  • \fancypagestyle{スタイル名}{内容}

内容にヘッダーやフッターの設定を書く。これで決めた設定を使いたい場合は\pagestyle{使いたい設定のスタイル名}とする。

  • \fancyhead[表示位置]{表示内容}
  • \fancyfoot[表示位置]{表示内容}

headはヘッダー、footはフッターの設定をする。表示位置のところには,左に表示させるならL,中央ならC,右ならRのどれかを入れる.表示内容のところは自由に書ける.カギ括弧で囲わてれることに注意.ページ番号を参照したいしたい場合はコマンド\thepageを使う.
上の例では[L],[C],[R]全部設定しているが,どれか一つだけでもOK.

  • \renewcommand\headrulewidth{xpt}

これはヘッダーに引かれる線の設定をする.表示させたくなければx=0にすればいい.どうやらヘッダーの設定を書かなかったら勝手に線が引かれる設定らしいから,もし表示させたくなければこの行は必須.

サンプルコード

f:id:mildtech:20170606025450p:plain

\documentclass{article}

\usepackage{fancyhdr}

\fancypagestyle{foot}
{
\fancyhead{}
\fancyfoot{}
\fancyfoot[L]{chapter 1}
\fancyfoot[C]{///sample page///}
\fancyfoot[R]{p.\thepage }
\renewcommand\headrulewidth{0pt}
}

\begin{document}
\pagestyle{foot}

\end{document}

追加で,lastpageというパッケージを使うと下の画像のようにもできる.上の画像ではp.1となっていたところがp.1/1となって全体のページ数を参照できるようになっている.

サンプルコード

f:id:mildtech:20170606030515p:plain

\documentclass{article}
\usepackage{fancyhdr}
\usepackage{lastpage}

\fancypagestyle{foot}
{
\fancyhead{}
\fancyfoot{}
\fancyfoot[L]{chapter 1}
\fancyfoot[C]{///sample page///}
\fancyfoot[R]{p.\thepage / \pageref{LastPage}}
\renewcommand\headrulewidth{0pt}
}

\begin{document}
\pagestyle{foot}
\end{document}
  • \pageref{LastPage}

こうするとpdfに変換する際に自動で総ページ数を参照して表示してくれるようになる.ちゃんとLastPageと大文字を含めて書くこと.

LaTeX 表作成

実験レポートで必要な表がTeXで描くにはちょっと複雑だった(初心者感想)
必要な情報がいろんなサイトに散らばってたのでまとめておく

必要なパッケージ

  • multirow

easyTeXをインストールして使ってる人ならデフォルトで入ってるはずなので特に気にすることはない

サンプルコード

まずはシンプルな表から
この表ならmultirowパッケージを使う必要はない
f:id:mildtech:20170529094309p:plain

\begin{table}[htbp]
\centering
\caption{サンプル表1}
\begin{tabular}{|c|c|c|c|} \hline
セル1 & セル2 & セル3 & セル4 \\ \hline
セル5 & セル6 & セル7 & セル8 \\ \hline
\end{tabular}
\end{table}

特に解説することもないだろう
下のリンクを見れば上の表で何をしてるかはわかる
一言付け加えるなら,表一列打ち込みが終わったら改行コマンド"\\"を打たないとコンパイルエラーを食らう
http://www.latex-cmd.com/fig_tab/table01.html

本題,上のリンクに載っていない複雑な表の描き方
f:id:mildtech:20170529115907p:plain


解説
  • 横のセルを結合したいとき

\multicolumn{結合したいセル数}{セルの書式設定}{セルの内容}
上のサンプル表でいうセル2.セルの書式設定は基本的にはc|がいいと思う.詳しくはさっき挙げたURLを参考に.
2つのセルを1つのセルとみなしているので&は一つ減る


  • 縦のセルを結合したいとき

\multirow{結合したいセル数}{*}{セルの内容}
上のサンプル表でいうセル3とセル6がこれ.
二番目の項の*てなんだよと思うかもしれないが,こう書くことでTeX側が勝手に最適な位置にセル内容を表示してくれる.一応説明すると列幅を指定するための項らしい.下手にいじらないのが吉.
結合先のセルは空白にしなきゃいけない.別に何か書いててもエラーにはならないしちゃんとその内容も表示されるけど文字が重なる.


  • 長方形型にセルを結合したいとき

\multicolumn{結合したいセル数}{セルの書式設定}{\multirow{結合したいセル数}{*}{セルの内容}}
上のサンプルでいうセル4がこれ.要するにmulticolumnのセル内容のところにmultirowをそのままぶち込むだけ.
ちなみにmultirowのセル内容にmulticolumnをぶち込んでみたらTeXに怒られた.上記の方法じゃないとだめらしい.
この形に結合するとコードが読みづらくなってコンパイルエラー食らったときに原因が分かりづらくなるので要注意.


  • 特定のセルにだけ下線を引く方法

\cline{x - y}
x,yはそれぞれ下線を引きたいセルの列番号を入れる.サンプルだとセル7からセル3,セル4に下線を引きたいと思ったら,セル7の列番号は3,セル4は結合されてるが結合前の状態を考えて列番号は6.だから\cline{3-6}と書く.もし\cline{3-5}とかいたらセル4の右半分には下線が引かれない.

複数指定したいときは以下のように書く
\cline{任意の列番号 - 飛ばすセルの一つ前の列番号} \cline{飛ばすセルの1つ後の列番号 - 任意の列番号}
ただ横に並べただけ.セル一個だけに下線を引きたいときはサンプルみたいに\cline{1-1}と,同じ列番号を指定してやればいける.
残念ながら\cline{1-1}{3-6}のように書くことはできない.


ちなみに\labelコマンドを使う場合は\captionより下の行に書くと正しく作動するらしい.別にどこに書いてもエラーにはならないけど,参照したときに番号が狂うバグが起きることが多々ある.


これだけ知っていれば基本的にどんな表でも描けるようになるはず