隙間

こちらはいわゆる仕事用のもの.

Call C in your R

この記事は明治大学 Advent Calendar 2018 - Qiitaの13日目の記事です.

修論の合間を縫ってめちゃくちゃ急いで書きました.不備があったら,ぜひ教えてください.可能なかぎり修正します.


最近,僕のインターネットの知り合いの方の中で洋画を夜な夜な漁るのが流行っていて, その界隈の中で「君の名で僕を呼んで」 という映画がとにかく良い,という話を耳にするのです.その英題が ”call me by your name.”

なので,今回はそれにちなんで「Rスクリプトの中からCの実行ファイルを実行し,計算速度を上げるtips」としてpipeと呼ばれる技術を紹介します.

現在では後発でRcppという大変便利なライブラリが開発され,ここで紹介するより高速に処理をすることができる技術もありますが,呼び出すのがC++で,タイトルの語感を崩したくはないので,  pipe自体がR&Cという言語の組み合わせに限らず,多くの言語で実装可能な汎用性の高い技術なので,こちらを紹介します.

Call C in your R.



pipeとは

pipeとは,ある実行ファイルが処理(process)を進めている最中に,途中まで処理をした(or 自身が入力として受け取ったデータ)を別の実行ファイルに入力として渡し,その実行ファイル内で設計された演算処理をしてもらったあとにデータを出力として受け取る作業のことを言います.

CやPythonに代表される手続き型言語において,プログラミングの基本概念の1つである関数でも,関数はメインモジュール(Cでのmain関数に相当)から引数(argument)を入力として受け取り,演算処理を施した後,返却値(return value)として出力するというのが基本の流れです.また,C言語でのscanf()printf()関数に代表される標準入出力(standard input and output)もユーザー(人間)とコンピューター間の入力と出力を担っているものですよね.

このようにコンピューターにまつわる情報処理では様々な階層で「入力→演算→出力」が行われています.今回紹介するpipeもまた,「実行ファイルと実行ファイル間の入力→演算→出力」を実装する手段だと考えてもらうと,後述の内容が理解しやすいでしょう.

実行時間・処理速度・計算量

実行時間

また今回の記事はプログラムの速さ・処理能力といった項目を扱うので,簡単にですが,これらを議論・検証するための用語を整理しておきます.概念的には極めて重要なものですが,それと同時に直感的に理解しづらい部分もあるため,1度最後まで読んだ後に時間をおいて,ここに帰ってきてもらっても大丈夫です.

これ以降,ある処理を完了させるまでの時間を実行時間 (running time)と定義します.教科書や分野によって,用語の用法に差がありますが,今回はこのように定義をすることにします.後述する「処理速度」「計算量」についても同様です.*1

処理速度

処理速度とは,実行ファイルがプログラム内に記述された入力・演算・出力等の処理を完了させるまでの速さを指します.

一般論として,同一の環境で同一の処理を行うとき,同一のアルゴリズムを実装しても,実装に用いたプログラミング言語によってその処理の実行時間には差があります.これをプログラミングの世界では「処理速度が違う」と表現することが多いです.メモリへのアクセスの仕組みや,メモリでのデータ保持の方法の違いなど処理速度の違いの原因となるものは様々あります.よく「XXは速いよね」とか「XXXはfor文遅いんだよねぇ」と言われるのは往々にしてこの処理速度のことを指しています.

計算量

前述した処理速度の他に,実行時間を決める要因の一つに計算量と呼ばれる概念が存在します. 計算量(computational complexity)とは計算可能な問題において,その計算を解くためのを完了させるまでの計算資源の必要量を指します.

より厳密には,計算を完了させるための演算(四則演算・真偽判定などなど,プログラミングにおけるステップ)回数を評価する時間計算量とその計算を完了させるまでに必要な情報の記憶領域の規模を表す空間計算量に分けて考えます.*2

時間計算量は,ランダウの記号O(\cdot)と処理の対象となるデータの入力サイズnを用いて,n多項式時間として表現します.アルゴリズムの良し悪しを評価する際の重要な指標の一つです. 詳しくは以下のページを参照してください:


qiita.com


時間計算量の概念を知っていると,いくら,処理速度が早くても,処理にかかる時間計算量が大きければ,結果的に実行時間が遅くなるというのが容易に想像がつくでしょう.このように実行時間に関わるのは時間計算量です.以降,断りがない場合は計算量とは時間計算量のことを指すこととします.

ベンチマーク

プログラムにおいて,実際に実装した処理の実行時間を定量的に評価するために,今回は検証する2言語(RとC)を用いて,同一の処理を同一のアルゴリズムで実装し,処理速度を評価します.

今回検証で使うのはこの手のテストでおなじみのフィボナッチ数列の値を求める計算です:

F_{n+2} = F_{n+1} + F_{n}(n \geqq 0),

F_{1} = 1, F_{0} = 1.

また,検証に用いた環境は以下の通りです:

macOS 10.12.6
MacBook Pro (Retina, 13-inch, Early 2015)
2.7 GHz Intel Core i5
8 GB

また,C言語,Rの各スクリプト内で実行時間を測定するために,それぞれ以下のライブラリ・モジュールを使用しました. それぞれの記事を参考にしてください:


stackoverflow.com


hiratake55.hatenadiary.jp


さらに,今回の検証ではフィボナッチ数列の計算を実装する際にメモ化を用いた実装をしています. メモ化について知らない人は後述のメモ化の項目をあらかじめ読んでください.次以降の項目で,実際にベンチマークの結果を見ていきましょう.

(補足)メモ化

フィボナッチ数列は数学的な定義に基づけば,再帰的(recursively)に計算することができます.具体的にどのようにコンピューター内部で計算されているかはこのアニメーション などを参考にしてください.

しかし,プログラムで再帰計算をそのまま実装してしまうと,計算時間が指数関数的に増加することが一般的に知られています.*3 *4

おそらく,前述したアニメーションを見れば,この処理速度の低下(実行時間の増加)は項数が増えるほど,再起の深さが大きくなることに起因することが直感的に理解できるでしょう.

そこで,このような再帰処理を実装する際にプログラミングでは(とりわけ,競技プログラミングの分野)ではメモ化と呼ばれる技術を用いることで,再帰深度を抑え,計算量を抑えることがしばしば行われます.

詳しくは以下のページを参照してください:


www.slideshare.net


qiita.com


Fibonacci in C

まずはC言語単独でフィボナッチ数列の計算のベンチマークを行います.実際のコードは以下の通りです.

implementation in C
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

#define N /* input num of terms in the sequence here. */

int Fibonacci(int i);
int Fmemo[N];

int main(int argc, const char * argv[]) {
    int long a=0;
    struct timeval tval_before, tval_after, tval_result;
    
    int i;
    for (i = 0; i < N; i++) {
        Fmemo[i] = 0;
    }
    
    Fmemo[0] = 1;
    Fmemo[1] = 1;
   
    gettimeofday(&tval_before, NULL);
    a = Fibonacci(N);
    gettimeofday(&tval_after, NULL);
    timersub(&tval_after, &tval_before, &tval_result);
    printf("Time elapsed: %ld.%09ld\n", (long int)tval_result.tv_sec, (long int)tval_result.tv_usec);
       
    return 0;
}

int Fibonacci(int i){
    switch (i) {
        case 0:
            return 1;
            break;
            
        case 1:
            return 1;
            break;
            
        default:
            
            if (Fmemo[i]!=0) {
                return Fmemo[i];
            }else{
                Fmemo[i] = Fibonacci(i-1) + Fibonacci(i-2);
                return Fmemo[i];
            }
     
            break;
    }
}
result

結果は以下の通り*5

N time (sec)
20 1.0E-10
200 4.0E-9
2000 4.6E-8
20000 8.14E-7

Fibonacci in R

次にR単独でフィボナッチ数列の計算のベンチマークを行います.実際のコードは以下の通りです.

implementation in R
N <- ## input num of terms in the sequence here. ##
Fmemo <- rep(0,N)
Fmemo[1] <- 1
Fmemo[2] <- 1

Fibonacci <- function(i){
  if(i == 1 || i == 2){
    return(1)
  }else{
    if(Fmemo[i]!=0){
      return(Fmemo[i])
    }else{
      Fmemo[i] <- Fibonacci(i-1) + Fibonacci(i-2)
      return(Fmemo[i])
    }
  }
}

system.time(
  print(Fibonacci(N))
  )
result

結果は以下の通り:

N time (sec)
20 3.0E-2
200 356+
2000 ---
20000 ---

Rの場合に関しては,200\leqq Nの場合は計算が終了する予感もしないため検証を断念しました... (760secくらいまでは待った.)

Call C in your R

ここまでで検証したように,Rでそのまま数列の計算を実装すると,実行時間をとても多く要します.そもそも,このような用途にRが適していないため,言語の設計構造上不向きであることや,ルーチン(関数)の呼び出しに時間がかかることが原因のようです.

それではこの問題を解決するために,Nの値を入力し,フィボナッチ数列の値を出力する関数を.cファイルで記述し,その関数をRのネイティブ関数である.Cインターフェースを介して,サブルーチンとして受け取る方法を実装します.

anythingbutrbitrary.blogspot.com

具体的な手順は以下の通りです:

  1. C言語で関数を実装

  2. .cファイルを$ R CMD SHLIBコンパイル

  3. Rスクリプトを実行

順を追って確認します.


C言語で関数を実装

Rの .Cインターフェースを介して入力を受け取るとき,.cファイル内で実装された関数は引数を ポインタ変数として受け取ります.したがって,関数を実装する際はポインタ型変数を受け取る関数として実装します.また,R側で呼び出す関数は返却値を持たないvoid 型でなければいけません.

この仕様の関係上,今回は項数(N)の値を持つ変数の上にF_Nの値を上書きするような方法で実装されていることに注意してください.

さらに今回の場合,メモ化に使う配列を用いる関係で以下のように実装します.(staticC とか使えばもうちょい賢くできそう...)

fibo_routine.c

long int Fmemo[30000];
long int Fib(int i);

void Fibonacci(int *N){
    int i;
    for(i = 0; i < 30000; i++){
        Fmemo[i] = 0;
    }
    
    Fmemo[0] = 1;
    Fmemo[1] = 1;
    
    *N = Fib(*N);
}

long int Fib(int i){
    switch (i-1) {
        case 0:
            return 1;
            break;
            
        case 1:
            return 1;
            break;
            
        default:
            
            if (Fmemo[i]!=0) {
                return Fmemo[i];
            }else{
                Fmemo[i] = Fib(i-1) + Fib(i-2);
                return Fmemo[i];
            }
            
            break;
    }
}
.cファイルを$ R CMD SHLIBコンパイル

次に fibo_routine.cコンパイルしてバイナリ(実行ファイル)の形にします.ここで通常であれば,cc コマンド等でコンパイルしますが,今回は以下のように:

$ R CMD SHLIB fibo_routine.c

コンパイルします.

正常にコンパイルできれば,fibo_routine.o fibo_routine.so というバイナリファイルが生成されるはずです.

Rスクリプトを実行

前段階で生成されたバイナリファイルのうち fibo_routine.so 側を使用し,R側で呼び込みます.

dyn.load("fibo_routine.so") の1行でバイナリファイルを読み込み,次の.C()の部分で.cファイル内で実装したFibonacci 関数を呼び出しています.

dyn.load("fibo_routine.so")
.C("Fibonacci", N = as.integer(##input the val of N here##))

実際にスクリプトを実行した結果は以下の通りです:

> dyn.load("fibo_routine.so")
> .C("Fibonacci", N = as.integer(20))
$N
[1] 6765

 F_{20} = 6765が出力されていることを確認してください.

比較結果

それでは以上の結果を踏まえて,R単独での実装と.C込みでのベンチマークを比較します.

小数点以下を正確に測定するためにベンチマークの方法を若干変更しています.*6

dyn.load("fibo_routine.so")

options(digits.secs = 6) # This is set so that milliseconds are displayed
start.time <- Sys.time()
system.time(.C("Fibonacci", N = as.integer(20000)))
end.time <- Sys.time()
time.taken <- end.time - start.time
time.taken

結果は以下の通り:

N R standalone (sec) R w/ .C interface (sec)
20 3.0E-2 1.04E-1
200 356+ 1.12E-1
2000 --- 1.14E-1
20000 --- 1.25E-1

最初の N=20の時こそ,効果は見られませんが,それ以降を比較すると差は歴然です.

早いね.

こうすることで,シミュレーション本体はCで実行し,結果の解析をRでやるというフローがワンフローでできるなど恩恵は様々です.

興味があれば,冒頭で紹介したRcppも活用して見てください.そして,残り2枠のアドベントカレンダーをぜひ埋めましょう.

(完)

*1:ここらへんの計算複雑性の理論は普通に怪しいので,もし,間違ってたらコメントください.

*2:チューリングマシンでは時間計算量が「動作ステップ数」空間計算量が「テープ長」に相当.詳しくは現象数理学科「情報処理」「数学の方法」「アルゴリズム論」他

*3:http://www.cs.tsukuba.ac.jp/~kam/lecture/gairon1/SS1-2013-algorithm.pdf

*4:厳密には,  O\left( \frac{1+\sqrt{5}}{2}\right)^n

*5:https://www.google.co.jp/search?q=1.0e-10%E3%81%A8%E3%81%AF&rlz=1C5CHFA_enJP709JP709&oq=1.0E-10&aqs=chrome.1.69i57j0l5.5343j0j4&sourceid=chrome&ie=UTF-8

*6:https://stackoverflow.com/questions/7546946/get-execution-time-in-milliseconds-in-r/36646392

はじめての正規表現2018 ~トリコとともに~

この記事は明治大学 Advent Calendar 2018 - Qiitaの5日目の記事です.

半ばノリと勢いで巻き込まれましたが,頑張っていきます.

まぁしゃあないか,「はじまりか、」 は平成アイドル界屈指のmasterpieceやし.

気持ちが乙女なので,西野カナの「トリセツ」を歌いながら書きます.

これからもどうぞよろしくね.



きっかけ

我らが拠点,明治大学中野キャンパスの近くには「トリコカレー」というカレー屋さんがあります.

他店に類を見ない濃厚なルーと充実のトッピングが人々を魅了し,弊学にも多くのファンがいます.

その熱狂ぶりはとどまるところを知らず,ある信者ファンに至っては「トリコ」に関するツイートを目視で逐一いいね!をしているほどです.

ある日,その彼がいつものように「トリコ」に関するツイートを検索しようとしたところ, 他ユーザーとこのようなやりとりに発展しました.

確かに,これを一般的な検索窓だけで見つけたりすることは難しいよねと思ったと同時に,ちょっと頑張ればこのくらいならできそうじゃんとも思った次第です.

なので今回はそんな彼の投げキッス運動*1を文字列処理の技術で応援しようと思います.

目的

人力で発見しなくても「トリコ」に関係しそうなワードを任意のテキストから検出する.

より一般的には

「任意の文字列パターン(法則性)を一般的・定量的に表現し,文字列検索・照合等で活用する」

になります.

このような問題を解決するために,文字列処理の世界では,正規表現(Regular Expression, regex)と呼ばれる技術が存在します.

今回はその正規表現を活用しながら「トリコ」にまつわる,あんな文字列やこんな文字列を検出していきましょう.

エゴサばかりしてた今日までの自分から生まれ変わるために.

正規表現のあれこれ

メタ文字

正規表現の構文では文字列の法則性(以下パターン)を記号的に表現するために,メタ文字と呼ばれる特殊文字を使ってパターンを表現します.

. ^ $ [ ] * + ? | ( )

これらのメタ文字を組み合わせ,「(ここに)何かの1文字」とか「何かのひらがな3文字」とか「0から9の数字」といったような任意のパターンを表現することができます.順を追って解説します.

メタ文字を含まない表記

通常,完全一致を仮定した場合,文字列「トリコ」を検出する場合には文字列「トリコ」と等価評価を行います.したがって,文字列「トリコ」との比較で検出されるパターンは「トリコ」のみとなります.

トリコ 

f:id:mblogit:20181204024442p:plain

この構文では以下のような文字列が該当します.

(例) トリコ
任意の1文字 「.」(ピリオド)

検出したいパターンの中に任意の1文字を含む場合は「.」(ピリオド)でその1文字を表現することができます.

ト.リコ 

f:id:mblogit:20181204021918p:plain

この構文では以下のような文字列が該当します.

(例) トあリコ  ト1リコ トーリコ  ト&リコ  
同一文字の繰り返し 「* + ? 」

同一文字が複数繰り返されているパターンを検出したい場合は「* + ? 」を使います.しかし,それぞれの文字で表現できる繰り返しのパターンに違いがあるので,注意して使い分ける必要があります.

直前の文字が0個もしくは1個以上繰り返されている「*」(アスタリスク)

ある箇所に任意の文字が0個もしくは1個以上繰り返されている場合には「*」(アスタリスク)を使います.

ト〜*リコ 

f:id:mblogit:20181204030248p:plain
この構文では以下のような文字列が該当します.

(例) トリコ  ト〜リコ ト〜〜リコ  ト〜〜〜〜〜〜〜〜リコ  
直前の文字が最低1個以上繰り返されている「+」(プラス)

ある箇所に任意の文字が最低1個以上繰り返されている場合には「+」(プラス)を使います.「*」(アスタリスク)の場合と異なり,直前の文字が最低1回繰り返されている場合のみを表現するため,「トリコ」自体はこのパターンに該当しないことに注意してください.

ト〜+リコ 

f:id:mblogit:20181204123436p:plain
この構文では以下のような文字列が該当します.

(例) ト〜リコ ト〜〜リコ  ト〜〜〜〜〜〜〜〜リコ  
直前の文字が1個だけ存在する場合かしない場合.「?」(クエスチョンマーク)

ある箇所に任意の文字が1個だけ存在する場合,もしくは存在しない場合を表現するときは「?」(クエスチョンマーク)を使います.前述の記号と異なり繰り返し要素はあまりありませんが,直前文字が0個の場合にセンシティブという点では,類似した性質を持ちます.

ト〜?リコ 

f:id:mblogit:20181204123438p:plain

この構文では以下のような文字列が該当します.

(例) トリコ ト〜リコ
任意の文字の繰り返し 「.*」

メタ文字は組み合わせて使うことでより,複雑なパターンを表現することができます.

前述したピリオドとアスタリスクを組み合わせて「任意の文字の繰り返し」を表現することができます.

ト.*リコ 

f:id:mblogit:20181204123421p:plain
この構文では以下のような文字列が該当します.

(例) トリコ  ト〜リコ ト1〜リコ トあぺぱぺリコ  トkfジェイrfklさdfクォイエfんqリコ  
行頭と行末 「^ $」 (ハット・ドル)

正規表現では任意の文字列が行頭/行末にくるパターンも検出することが可能です.

つまり,与えられたテキストが任意の単語(文字列)で始まる場合.もしくは任意の単語で終わる場合かといったパターンも検出することができます.

(a) ^トリコ  
(b) トリコ$ 

f:id:mblogit:20181204124210p:plain
(a)

f:id:mblogit:20181204123447p:plain
(b)

この構文では以下のような文字列が該当します.

(例) (a) トリコはカレー屋さんです トリコのエコランチは日替わりのトッピングがつきます  
(例) (b) プエルトリコ
複数候補のある文字・文字列のいずれかに該当する 「|」(バー)

表現したいパターンのうち同一箇所に複数候補があり,かつ,その候補のいずれかが該当した場合を検出したい場合は「|」(バー)を用いて表記することが可能です.数学における「または」「or」「∨」をイメージするとわかりやすいです.

トリコ|野方ホープ 

f:id:mblogit:20181204123444p:plain

この構文では以下のような文字列が該当します.

(例) トリコ 野方ホープ
指定された文字のいずれか "[ ]"

ある箇所において,いくつかある文字の候補のうち,いずれかが該当する場合を表記するのには「[ ]」を活用します.

ト[リ○△]コ 

f:id:mblogit:20181204123441p:plain

この構文では以下のような文字列が該当します.

(例) トリコ ト○コ ト△コ

また,「[ ]」の中でアルファベットいずれか1文字や数字いずれか1文字を表記する場合には,以下のように「-」を用いて包括的に表記をすることが可能です.

[ABCDEFGHIJKLMNOPQRSTUVWXYZ] → [A-Z]
[0123456789] → [0-9]

さらに同じように「-」を用いて,ひらがなや漢字も包括的に表記することが可能ですが,JIS漢字コードの水準等の知識が必要になるため,ここでは扱いません.

グループ化 「( )」

ここまでで説明したメタ文字は直前の1文字というような文字単位でのパターン生成を担ってきましたが,「( )」を用いてグループ化することで,対象の範囲を複数個の文字に拡大・限定して,各々のメタ文字を生成することができます.

以下例をみてください.野方ホープには中野店と吉祥寺店の2つ*2があります.このとき「野方ホープ中野店」「野方ホープ吉祥寺店」の両方を網羅するパターンを正規表現するときにどのように書き下すことができますか?

正規表現に慣れてない読者の中にはおそらくこのように書き下した人がいると思います.

野方ホープ中野|吉祥寺店 

f:id:mblogit:20181204123428p:plain

しかし,これでは目的としてる2店舗を検出することはできません.

この構文では以下の2パターンを検出してしまいます.

(例) 野方ホープ中野 吉祥寺店

このような場合,「( )」を用いてグループ化することで「|」(バー)の作用範囲を限定し,以下のように書き下すことが可能です.

野方ホープ(中野|吉祥寺)店 

f:id:mblogit:20181204124712p:plain

この構文では以下のような文字列が該当します.

(例) 野方ホープ中野店 野方ホープ吉祥寺店

検証結果

それでは,これらの正規表現を使ってトリコに関する文字列がパターンにマッチするかどうかを確認します.

使用言語はpython で re モジュールを使用しました. またメタ文字として割り当てられている「.」(ピリオド)をピリオドとして認識させる場合には,「\.」と表記します. 他のメタ文字に関しても同様です.

# -*- coding: utf-8 -*-

import re

targetList = ["トリコ","トルコ","ト.リコ","トリ._..~..コ","トリ_コ","ト,リコ","トリ~コ","プエルトリコ","野方ホープ"]

for index,trg in enumerate(targetList):
    isMatch = re.match('^ト[\._~,]*リ[\._~,]*コ[\._~,]*$' , trg)
    if isMatch:
        print index, trg, "matched"
    else:
        print index, trg, "not matched"

f:id:mblogit:20181204123714p:plain

出力結果

0 トリコ matched
1 トルコ not matched
2 ト.リコ matched
3 トリ._..~..コ matched
4 トリ_コ matched
5 ト,リコ matched
6 トリ~コ matched
7 プエルトリコ not matched
8 野方ホープ not matched

やったね!

引用

Regexper

サルにもわかる正規表現入門

pythonの正規表現メモ - Qiita

*1:ここではむやみやたらに他人にいいね(ハート)を送りつける行為を指します

*2: (他にもあるけど)

卒業論文をこれから書くLaTeX初心者が最低限守るべきLaTeXのルール(数式編)

LaTeXの云々と言うよりもレポート・論文の書き方の問題かもしれない.

卒業論文中の数式は基本的に文の中に存在するように書くことが基本です.

英文の場合であれば,

This equation is formulated as follows:

{ \displaystyle
e^{i\pi} = -1.
}

のように,地の文の最後はコロン(:), 数式の最後にピリオド(.)を打ちます.

複数の数式を列挙する場合は

These equations are formulated as follows:

{ \displaystyle
e^{i\pi} = -1,
}

{\displaystyle f(a)+{\frac {f'(a)}{1!}}(x-a)+{\frac {f''(a)}{2!}}(x-a)^{2}+{\frac {f'''(a)}{3!}}(x-a)^{3}+\cdots .
}

のように,カンマ(,)でつなぎ,最後はピリオド(.)でしめるようにします.

数式を提示した後に,式中の文字を説明したい場合は

{ \displaystyle
e^{i\pi} = -1,
}

where { \displaystyle e} is the base of natural logarithm.

のように,説明文(where節)までで一つの文という扱いをします.

卒業論文をこれから書くLaTeX初心者が最低限守るべきLaTeXのルール(改行・改ページ編)

いよいよ,卒論の追い込みの時期が近づいてきて, LaTeXに関わる質問を受けることが多くなりました.

普段からLaTeXを使ってる人にとっては何事もないような事柄ですが, 幾つかのコマンドを初心者が誤用している例がたくさん見られる項目があります.なので,これを機にまとめておこうと思います.

思いついた順につらつら書き足す感じでやっていきます.

内輪以外の人も少しでも参考になればいいと言った具合です.

強制改行は基本使わない.

LaTeXで文章を書くときに初心者にめちゃくちゃ多いのが,「改行のやり方が間違っている」というものです.

「すべての改行を強制改行 "\\"で行う. 」はコマンド誤用の定番中の定番です.

その例がこちら.

この文で第1段落を始めます. この文で第1段落を閉じます.
\\この文で第2段落を始めます. この文で第2段落を閉じます.

f:id:mblogit:20161207114046p:plain

この場合,一見うまく改行ができているように思いますが,第2段落の初めの部分でインテンド(字下げ)が効いていません.

このように,段落を変えるための改行は以下のように,空行を1行挟むことによって改行します.

この文で第1段落を始めます. この文で第1段落を閉じます.

この文で第2段落を始めます. この文で第2段落を閉じます.

f:id:mblogit:20161207114047p:plain

このようにすれば,改行と同時に字下げも行われるので,こちらの方法で改行は行います.

図表の中での改行では強制改行を行うことは,ままありますが,地の文で強制改行を使うことは基本的にありません.

段落の先頭に "\quad" とかやらない.

上の強制改行を使いかつ,段落の初めに字下げのために段落初めに"\quad"とか"\qquad"を挿してくるのが定番の間違ってるパターンです.

この文で第1段落を始めます. この文で第1段落を閉じます.
\\\quad この文で第2段落を始めます. この文で第2段落を閉じます.

この方法でコンパイルすると以下のような出力を得ます.

f:id:mblogit:20161207120944p:plain

この方法ですべて解決できているかのようにも見えますが,よく見ると第1段落と第2段落のインテンドの幅が異なっていて,第2段落が必要以上に下げられてしまっています.

このような体裁は文の量が増えれば増えるほど,悪目立ちします. 正しい方法で書いている人にとってはとても違和感を感じるものです.

これに関しても前の部分で説明した,「1行挟む」方法を用いればすべて解決します.

改ページをコマンド1つで行う

改行についで,誤用が多いと思われるのは「改ページ」に関するものです.

よくある例は,

この文で1ページ目を終えます.
\hspace{**cm}
この文で2ページ目を始めます.

という具合に,\hspace{} で改ページされるまで,長さを手動でひたすら調整し続けるというもの. (horizontal space の略,**cm鉛直方向にスペースを取る.)

個人的な経験では,学参書で問題文の後ろにスペースを空けるときに使ったりするようなものなので,少なくとも改ページには使うべきではないです.

(枚数制限がある原稿とかで,少しでもスペースを詰める場合に**に負の値を入れて,詰めるみたいなこともやるけど,まぁこれは今回はいいや.)

これならまだしも,本当に最悪なのは強制改行連打でごり押しをキメてくるものです.

この文で1ページ目を終えます.
\\
\\
\\
\\
\\
\\
\\
\\
この文で2ページ目を始めます.

さすがに,これが正しいと思って,書いてる人はいないとは思いますが,方法がわからず仕方無くこれに走る... という人をたまに見かけます.

これらの方法で一見解決できてる(特に\hspace{} の場合は) ように見えますが,いずれの場合も,地の文に続いて,文中に余白や空行を書き足してる扱いなので,正式な改ページではありません.

この方法の場合,途中で前ページに新しい内容を加筆するとその分,余白や空行が押し出しを受ける形になり,2ページ目に謎の余白ができる→その余白を消すために,**cmや行数を地味に調節する.と言ったスパイラルに確実に陥ります.

レポート程度ならこれでも対応出来るかもしれませんが,複数ページに及ぶ卒業論文のようなもので,加筆するたびにこの作業に追われると思うと,もはや地獄です.

ここでも,LaTeXにはあらかじめ有用なコマンドが用意されています.

この文で1ページ目を終えます.
\newpage
この文で2ページ目を始めます.
この文で1ページ目を終えます.
\clearpage
この文で2ページ目を始めます.

の2つです.

\newpage の方はシンプルにソースに書いてある部分で改ページを行ってくれます.

\clearpageの方はそれまでに挿入された図表(正確には浮動体)をすべて出力してから改ページを行うというものです.

したがって,\clearpage を使うと,図表が本文からものすごくずれる,といった症状が比較的起こりにくくなります.

初めまして.

卒業研究がひと段落したので,これを機に立ち上げてみました*1. 暖かい目で見守っていただけるとありがたいです.

自己紹介

  • 都内在住の理系大学生(B4).
  • 現在,所属している学部の接続大学院に内部進学する予定です.

専門分野

  • 数理科学(応用数理系)を専攻しています.数学系と情報系のハーフ&ハーフと言ったところです.
  • 現在は交通流(Traffic Flow)に関する研究をやっています.
  • 確率的セルオートマトンモデルを用いた交通流シミュレーションにおける最適パラメータ分布みたいなことを卒業研究ではやりました.
  • 機械学習とかにも興味があるので進学したら突然テーマを変えるかもしれません.

使用言語

  • プログラミング自体は大学入学時から始めました.現時点で4年目.
  • processing から入門しました.
  • そのあとは大学のカリキュラムや必要に応じて言語を転々としています.
  • これに準じてLaTeXとBitBucket も使えるようになりました.
  • 現在のタスクを回すルーティーン主に:
    • Cで数値計算だけ行う
    • 出力ファイルを受け取り, processing or R でデータを可視化
    • LaTeXで文章書く
    • これらのファイルをBitBucketでバージョン管理する

というようなものです.

可視化ツールは,微分方程式で記述できるダイナミクスを可視化するような場合はprocessing, データ分析系は迷わずRといったところです.なぜ,この道筋でPythonに出会わなかったのか.

最近だと,数値計算のルーチンだけの実行ファイルを生成して,可視化ツール側でpipeを使って呼び出して一括処理とかするようになり始めました.

編集方針

  • コンセプト的には「数理科学系学生のためのプログラミング」を中心に記事をポストします.
  • 基本的には備忘録としてメモ代わりに使っていきます.あと単純に作文の練習もしたかった.
  • 基本的にはオープンな状態でブログを書いていきますが,同じ研究室のメンバーや初学者に向けて少しでも役に立つような記事が書ければいいかなくらいに思っています.
  • 情報系の学科というわけではないので,ガチガチでコードを組んでるわけではないです.この機内にプログラマーな方がいらっしゃいましたら,お近くの客室コメント欄でアドバイスをいただけると幸いです.
  • 当面はこの時期に需要が見込まれるであろう,LaTeXに関するポストが集中するだろうと思います.

*1:もともと,別のサービスでこの記事を投げたのですが, 「ここにはふさわしくない記事です.内輪の紹介であれば内輪でやってください.」と,ユーザーからとコメントをいただいたので, はてなの方にお引越ししました.(全然,内輪の紹介ではなかったんだけど.)

さすがに1発目のコメントがこれなのは心折れる.

これからtipsを書いていく上でバックグラウンドの共有とか結構大事かなと思っていたのですが,指摘された点も一理あると思ったので. 相性が良いこちらのサービスに乗り換えました.