YAMAHA RTX1200を使ってJPNEに接続するプロバイダでIPv4 over IPv6を実現する検証[draft]

TL; DR

  • フレッツ契約情報を見つけ出す
  • ZOOT NATIVEの契約をする
  • DS-Liteの設定をする

はじめに

新型コロナウイルス感染症の流行で在宅勤務が一般的になったためかPPPoE接続の速度が終わってきて何のために回線契約しているのかわからなくなってきた今日このごろ、 家にちょっといいルーターがあればIPv4 over IPv6によってプロバイダの網終端装置をバイパスして多少速度を稼ぎたくなるところです。 ところで我が家で契約しているSo-net光は、ある日を境にIPv6のVNEをインターネットマルチフィード(mfeed)から日本ネットワークイネイブラー(JPNE)に変更してしまいました。 これによってIPv4 over IPv6を実現するために利用するトンネリング技術がDS-LiteからMAP-Eに変わったことを意味します。 一方、我が家に存在するYAMAHA RTX1200はMAP-Eに対応していません。 *1

ということで、設備投資をしなければMAP-EによるIPv4 over IPv6が使えないということになりますが、 mfeedを経由するIPv6 IPoEサービスを提供するプロバイダを別途契約することでDS-LiteによるIPv4 over IPv6を実現できないものでしょうか。 そこで今回はインターリンクが提供しているZOOT NATIVEとSo-net光を同時に契約できないか試してみます

予備調査

ZOOT NATIVEがコラボ光との併用をユースケースとして想定しているのか調べてみると、次のヘルプページがヒットします。 光コラボレーション(ドコモ光など)でZOOT NATIVEは利用できますか?

ということで大手を振ってプロバイダを切り替えられることがわかりました。正確に言えば切り替えるわけではなく複数プロバイダと契約する状態になっているわけですが。

事前準備

ZOOT NATIVE申込みのためにはフレッツのお客様IDとアクセスキーが必要です。 so-netの場合は[接続サービスご利用状況]->[ご契約情報の詳細]とたどったページで確認することができます。 この2つの値をメモしておきましょう。 f:id:akahana_1:20200606224745p:plain 次に、v6プラスオプションに加入していないか確認します。もし確認していた場合はその場で解約しておきます。 解約してから実際にVNEからの払い戻しが停止されるまでは1日程度必要なため、もしプロバイダでv6プラス契約をしていた場合はここで少し待つ必要があります。 私の場合は、解約申込みをしてから1日後になぜか再度v6プラスが有効になり、その後すぐにv6プラスが解約されるという謎の現象が発生しました。 v6プラスを有効化していた場合はある程度ゆとりを持ったスケジュールにするのが良いと思われます。

これでso-netとの契約情報から必要なものを抜き出し、事前準備が整いました。

ZOOT NATIVEへの申込みと開通

ZOOT NATIVEに申し込むフォームで先程メモしたフレッツのお客様IDとアクセスキーを利用します。 また、ZOOT NATIVEの申込ではフレッツ光の回線契約タイプの記入が求められます。

契約タイプの特定には回線の最大速度、貸与機器の種別などを見ながらフレッツ光の公式HPのプラント見比べるのが良いでしょう。 私はONUのみの貸与で、GE-PON-ONUが貸与されていたことと集合住宅に居住しているのでフレッツ光ネクストマンション・ギガラインタイプとしました。 あとはフォームに従って手続きを進めていけばZOOT NATIVEの申し込み作業は完了です。

次に、DS-Liteの設定をしますが、これについてはYAMAHAページの記載のとおりに行えば、良いでしょう。 http://www.rtpro.yamaha.co.jp/RT/docs/ipip/index.html#setting9

設定を終えたあとにhttp://ipv6-test.comにアクセスすれば、IPv4アドレスがMF-native6-eとなっているはずです。 これでDS-Lite開通が終了しました。おめでとうございます。

ハマりどころ

DS-Liteの設定をしたあとは一度WANにつながってるインターフェイスを再起動してあげましょう。 再起動しない状態だと、フレッツ網から外に抜けられないIPv6アドレスがルーターに割り当てられたままになっている可能性があります。 下の画像は、so-netのv6プラスオプションを解約して、その後にZOOT NATIVEの契約が通った状態ので私のRTX 1200に広告されていたrouter-prefixのリストです。

f:id:akahana_1:20200606234433p:plain

かなり分かりづらいですが2408:~から始まるアドレスと2409:~から始まるアドレスと240b:~から始まるアドレスの3種類のアドレスが広告されていることがわかります。 この内、2409:から始まるものがmfeedによって広告されているrouter-prefixです。残りのふたつのプレフィックスはなにか。 まず、2408:~から始まるrouter-prefixはフレッツ網内で有効なIPv6アドレスを示します。よって、このアドレスを使ってインターネットに出ていくことはできません。 もう一つの、240b:から始まるrouter-prefixはJPNEから広告されているrouter-prefixですのでJPNEの終端に対して接続することはできますが、mfeedの終端に対して接続することができません。 この状態でIPIPトンネルをmfeedが管理するAFTRに向けて張ろうとすると、張ることはできるものの通信が行えないといった状況が発生します。 おそらく、2409:~以外のアドレスを使ってAFTRと通信しようとしているからです。 これは、v6プラスの割当を受けた後、それを解約してv6契約がない状態からmfeedの割当を受けた時に、それまでにもらっていたrouter-prefixが削除できていないと起こる事象です。 こうなれば、ルーター再起動なりLANインターフェースの再起動を行うことが求められるでしょう。

*1:正確に言えばMAP-Eによるトンネル接続は可能ですが、あっという間にIPマスカレード(NAT)のポートを使い切ってしまうため使えたものではありません

LuaLaTeXで簡単日中混植

この記事はTUT Advent Calendar 2019 13日目の記事です。 Advent Calendarがスカスカだと適当な日付を指定して記事を投げ込めるというのはとてもいいことですね。 よくはないが。 ちなみに 2015年から投稿しているので5年連続です。控えろ控えろ

皆さんはLaTeXを使っていますか? もちろん、理工系の大学に通っているみなさんは、レポートに論文にとLaTeXが大活躍していることと思います。

そんなLaTeX処理系の一つであるLuaLaTeXでは、従来のLaTeX処理系と異なって、フォントファイルの実態を取り扱えるようになっています *1

この事によって、従来のLaTeX文書では考えられなかった、複数のフォントファイルを用いた文章を極めて簡単に作成することができるようになっているので、 今回はその紹介として日本語フォントと中国語(簡体字)フォントの混植を実現する方法を取り上げます。 とても簡単ですよ!

(2019.12.17 追記) 具体的には、日本語文書内で簡体字が必要となった時に、適切な簡体字を出すための方法についてです。 書いているときは、この意味で十分伝わると思いこんでいましたが、あらゆるフォントが簡体字字形になったり、 あるいは簡体字であることが文中で明記されていない場合にも簡体字になるかのような曖昧性を抱えていたので、注記しておきます。

ちなみにこの記事は私も参加しているサークル『おるみん党』の冬のコミックマーケット宣伝のために執筆されています。 ここで言及したテクニックも登場する、おるみん党の機関誌『測点』Vol.2は冬のコミックマーケット(C97)4日目に南リー31bで頒布されます。 読書好きの皆さんに向けた叢書管理ツールEnju Leafを使った書誌情報管理や、Web Assemblyの紹介、中国メーカーから販売されているRISC-Vプロセッサ採用ボードの調査記録などの記事を取り揃えてお待ちしています。 頒布価格は500円。お誕生日席に配置されたので、かなりわかりやすいと思います。皆さん、冬の有明南展示場で会いましょう。

用意するもの

まずTeX Liveなどを使って、LuaTeXをインストールしてください。 今回のテストではTeX Live 2019にバンドルされているLuaTeX v1.11.2を使っています。

LuaTeX上でCJKフォントを扱う手法として、luatexjaチームが開発しているパッケージ群が利用できます。

とりあえず次のようなファイルを用意して、LuaTeXで正しくコンパイルできることを確認しましょう

\documentclass{ltjsarticle}
\usepackage{luatex85, lautexja}
\usepackage{bxjalipsum}

\begin{document}
\jalipsum{kusamakura}
\end{document}

正しくコンパイルできれば草枕の冒頭が書かれたPDFが生成されるはずです。 LuaTeXのコンパイルを初めて行うときは、フォントデータベース生成のためにコンパイルに時間がかかる点に気をつけてください。

フォントを取り扱う

次にシステムにインストールされているフォントを明示的に取り扱ってみます。 TeX Liveをインストールすると日本語標準フォントとしてIPAexフォントがバンドルされているので、 これを指定してPDFファイルを生成してみます。

\documentclass{ltjsarticle}
\usepackage{luatex85, lautexja}
\usepackage[ipaex]{luatexja-preset} % この行を追加
\usepackage{bxjalipsum}

\begin{document}
\jalipsum{kusamakura}
\end{document}

luatexja-presetパッケージによって、一般的なフォントであれば簡単にPDFに埋め込むことができます。

再度文書をコンパイルすれば、IPAexフォントが埋め込まれたPDFが生成されることでしょう。

簡単日中混植

それでは本題の日本語+中国語(簡体字)混植を試してみましょう。 luatexjaパッケージはluatexja-fontspecというパッケージを提供しています。 これはfontspecパッケージ(())をCJK向けに拡張したパッケージで、CJK向けに便利な機能がいくつか追加されています。 中でも便利なのがAltFontと呼ばれるフォント機能で、これを利用することで簡単に複数のフォントを切り替えて使うことができます。 例えば、公式ドキュメントからサンプルを引っ張ってくると

\jfontspec[
    AltFont={
       {Range="4E00-"67EF, Font=KozGoPr6N-Medium} ,
       {Range="6800-"9EFF, FakeBold=4},
       {Range="3040-"306F, Font=KozGoPr6N-Regular}
    }
][KozMinPr6N-Regular]

などとすれば、簡単に混植が実現できます。 この例だと、基本的には小塚明朝 Pr6Nを使いますが、Unicodeの文字範囲U+3040~U+306fでは小塚ゴシック Pr6N Regularを U+4E00からU+67EFの文字範囲では小塚ゴシック Pr6N MediumをU+6800からU+9EFFの文字範囲では小塚明朝を擬似ボールド体にして利用しています。

というわけで、これを真似すれば簡単に日本語と簡体字の混植ができそうです。 詳細について話すまでもなかったですね。というわけにはいかないのが現実です。

CJK統合漢字の罠

では次のようなTeXソースを用意してコンパイルしてみましょう。 ここでは、Windows環境を想定して、簡体字フォントにSimSunを使う例です。 お手持ちの環境に合わせて簡体字フォント部分を入れ替えてください。

\documentclass{ltjsarticle}
\usepackage{luatex85, luatexja}
\usepackage[ipaex]{luatexja-preset}

\begin{document}
{
\jfontspec[
    AltFont={
       {Range="4E00-"9FEF, Font=SimSun}, % Unicode CJK 統合漢字面をすべて簡体字に置き換える
    }
]{IPAexMincho}
简体字とは、中国およびシンガポールにおいて现在正字として采用している。从来よりも简略化した汉字。简化字とも呼ばれる。\footnote{\url{https://dic.nicovideo.jp/a/簡体字}
}
\end{document}

ここでは「简」「现」「采」「从」「汉」の5字が、簡体字字形として表示されることが期待される文字です。 他の文字は、和文字形として表示されていて、この部分だけ簡体字になってくれていれば、目的を達したと言えます。

コンパイルに成功するとブラウザ表示で簡体字になっている部分が、豆腐にならずに正しく簡体字字体で表示されていることがわかるでしょう。 例えばこんな感じです。

f:id:akahana_1:20191215185553j:plain

ところで問題は、簡体字で書かれていない箇所においても、字形が簡体字相当になっている問題です。 これはCJK統合漢字面全体を簡体字字形を利用したフォントに置き換えているからです。 では、簡体字部分だけに置き換え範囲を限定してすればよいというのが直感的ですが、ここに一つ問題があります。 というのも、簡体字が割り当てられているコードポイントは、UnicodeのCJK統合漢字面の上に広くまたがっており、特定の範囲を指定することで解決する問題ではないからです。 このあたりは明らかにUnicodeの不具合では?という気持ちになるのですが、規格として制定されているのであれば仕方がないので、なんとかしてこれを解決しなければなりません。

文字種を限定した解決策

CJK統合漢字面全体にまたがって、簡体字字形のものと和文字形のものが存在しているということは、文字範囲の指定という統一的な枠組みで二つの字形を混植することは難しく、都度都度アノテーションを行っていくしかないという結論になります。 というわけで解決策として取りうる方法の一つは AltFontのRangeキーに対応する値として字形を変更したい対象を列挙する となります。

先ほどの文書であれば

\documentclass{ltjsarticle}
\usepackage{luatex85, luatexja}
\usepackage[ipaex]{luatexja-preset}

\begin{document}
{
\jfontspec[
    AltFont={
       {Range={`简, `现, `从, `汉}, Font=SimSun}, % 簡体字で表示したい字形を列挙する
    }
]{IPAexMincho}
简体字とは、中国およびシンガポールにおいて现在正字として采用している。从来よりも简略化した汉字。简化字とも呼ばれる。\footnote{\url{https://dic.nicovideo.jp/a/簡体字}
}
\end{document}

f:id:akahana_1:20191215185728j:plain

これで簡体字で表示したい漢字のみが簡体字字形で、その他の漢字は和文字形で表示されるようになりました。 このように、和文字形と簡体字あるいは繁体字字形をLuaTeX上で混植させるには、多少気にしなればならないことがあるという紹介でした。

おまけ

ところでSource Han Sans CJKみたいにCJK多言語対応しているフォントを使えばいいのでは?と思われた人はいないでしょうか。 おそらく一番正しい解決法はそれです。 確認するためにluatexja-presetsourcehanオプションを指定して、コンパイルしてみましょう。

\documentclass{ltjsarticle}
\usepackage{luatex85, luatexja}
\usepackage[sourcehan]{luatexja-preset}

\begin{document}
简体字とは、中国およびシンガポールにおいて现在正字として采用している。从来よりも简略化した汉字。简化字とも呼ばれる。\footnote{\url{https://dic.nicovideo.jp/a/簡体字}
\end{document}

思った通りの出力になりましたね。というわけで、和文簡体字で異なるフォントを使いたいという希望がなければ、これが最も簡単な解決法です。

f:id:akahana_1:20191215185808j:plain

というわけで、このように和文中において特定の文字において簡体字を指定せざるを得ない状況が発生したときは

  1. Source Han CJKのような基本字形として和文字形を採用し、その他に簡体字のみの文字コードに対して正しく字形が存在してるフォントを使う
  2. luatexja-fontspecが提供するAltFontオプションを利用して、簡体字文字コード部分を対応する適切なフォントに置き換える

の選択肢を取ることが出来ます。

*1:今までのLaTeXはフォントファイルをそのまま取り扱っていませんでした

卒研を倒すための装備の整え方

タイトルはoverclaimなので話半分に読みましょう。

TL;DR

TeXを使って論文を書いているときに gitを使って管理したり、自動校正を導入したりする方法についてなんとなく話します。 具体的には

  • latexmkを使った自動ビルド
  • 自動校正ツールの使い方
  • gitにとりあえずファイルを放り込む

みたいな話です。

だいたい、このリポジトリの説明。

github.com

まえがき

皆さん!楽しい研究ライフを送っていますか? まあ、楽しいことも楽しくないこともあると思います。 私は死んでます。

さて、研究をしていてもそれで終わりでなくて最終的には何かしらの記録を残す必要があります。 そう、論文です。 論文を書くのは大変ですね。 ところでWordで論文を書いていて体裁がひどいことになったりしていませんか? あるいは、突然論文がすっ飛んでしまったり?

どうせなら、論文を書く環境をあらかじめ整えておきたいですよね。 ここではTeXにターゲットを絞って論文を倒すために考えられることを列挙します。 君も論文をやっていけ。

論文を書き始める前に

論文を書き始める前の設定が論文がうまく書けるかを決めると言っても過言ではないので、先にその話をします。 論文を書くときに予めフォーマットが定まっているのならそのフォーマットを使いましょう。 私が卒論を書いたときはTeXフォーマットが用意されていなかった記憶があり、キレながら適当なフォーマットをでっち上げた記憶があります。 フォーマットをでっち上げる必要がある人はフォントサイズとフォント指定、余白に気をつけましょう。 フォントサイズについては私が過去に書いた記事を読むといろいろわかります

装備を整える

論文を倒すために装備を整えましょう。戦いに出るために武器を持たぬ人間はいない。 同じように我々もこれから論文と戦うのだから、装備をと整えずして他に何をするのかという話になります。

環境設定

倒すも何も、その前にまずは環境設定をする必要があります。 私はLinuxWindowsが動くマシンしか持っておらず、Macではどのように設定するのかよくわかりません。 もしもTeXの環境をインストールしていない人がいる場合はTeX Liveをインストールしておくといいと思います。具体的にはTeX Live - TeX Wikiを参照してください。

ついでに使うエディタも決めてしまいましょう。 いっとき前ならばTeXWorksなりTeXShopなりの統合環境を使うのがデフォルトという感じでしたが、今はElectronベースのエディタを使ってプラグインで環境を整えるのがイケてるんじゃないでしょうか。 この記事ではElectronベースイケイケエディタとしてVisual Studio Codeを前提にします。 他のElectronベースイケイケエディタを使っている人は適宜読み替えてください。 具体的な設定はVisual Studio Code - TeX Wikiを参考にしてください。 LaTeX Workshopはイケてる拡張機能だと思います。普段Visual Studio Codeをあんまり使わないのでイケてる具合があんまり説明できないので、そこは他の人の記事を見てください。

あと、この記事では環境の前提条件をupLaTeXとします。LuaLaTeXとかだといくつか楽になるのかもしれませんが、あんまり詳しくないのでここでは説明しません。

ビルドを自動化する

ちまちまとファイルを書いてからコマンドを叩いて結果を確認したいか? そんなわけはないですね。

Visual Studio Code + LaTeX Workshopを使っていればファイル保存時に自動でビルドが走って嬉しい!!ですね。 LaTeX Workshopだと標準でlatexmkというlatexビルドのための便利ツールキットが使えるので、これを実際に動作するようにすれば、保存時にいい感じにビルドしてくれるはずです。 武器は装備しないと意味がないぜ!

upLaTeX用の一番簡単な設定はこれです。

あとは論文用ディレクトリ直下にlatexmkrcとして突っ込んでおけば、LaTeX Workshopがlatexmkを使ってコンパイルするときに自動参照してくれます。

gitを使って版を管理する

論文を書いているときにどこを書いているかわからなくなったり、あるいはいきなりファイルが失われたりする可能性があるので、事前にバックアップを十分取っておきたいですよね。 セーブスロットを用意して保存できると良い。 とりあえずDropboxみたいなオンラインストレージを使っているなら、Dropboxが管理するディレクトリの中に論文を用意して管理しましょう。

それとミスったときに後戻りできると嬉しいのでgitを使って管理しましょう。 Visual Studio Codeだとgitを直接叩く拡張機能がすでに同梱されているので、あとはgitの実行ファイルが存在していれば楽に使えます。 Visual Studio CodeでGitを利用する (1/3):特集:Visual Studio Code早分かりガイド - @ITなどを読むと具体的にどうすればいいかがわかります。

とりあえず手が一旦止まったらgitメニューを開いて、こんな感じで表示されている[+]マークをクリックしてファイルを登録して適当にメッセージを入力し[✔]をクリックしてセーブするといいです。

あとは適当なオンラインリポジトリサービスにPrivateでリポジトリを用意しておくと、もしものときにネットの向こうにファイルがあって便利です。

gitを使う時はこんな感じのファイルを作って.gitignoreという名前で論文と同じディレクトリに置いておくと、余計なファイルが表示されなくて心が落ち着きます。

怪しげな場所を潰す

文章をガリガリ書いているとなんだか文章がぐんにゃりしてくることがあります。 例えば今のこの文章もだいぶぐんにゃりしています。 こういうことになるのは防ぎたいところですが、それなりに難しいのである程度機械になんとかしてもらいましょう。

世の中には自動校正ツールと呼ばれるものがいくつかあってこれらを使うといい感じに文章の確認ができます。 代表的な自動校正ツールは

  • textlint
  • RedPen

のふたつがあります。 textlintはnodejs製でVisual Studio Code向けにプラグインも用意されていて便利でいいですね。 RedPenはJava製のアプリで別途サーバーを用意して実行するケースで強い気がします。

普段はRedPenを使うようにしています。多人数で原稿を書いてgitリポジトリと連携するときなんかはCIを使ってRedPenを回すほうが楽ちんな気がします。 nodejsと向き合っていける人は、textlintを使うのもいいでしょう。

RedPenだとXMLで設定を書くことができて次のような形でいくつか簡単なルールを設定できます。

<redpen-conf lang="ja" variant="zenkaku2">
  <validators>
    <validator name="SentenceLength">
      <property name="max_len" value="100" />
    </validator>
    <validator name="HankakuKana" />
    <validator name="JapaneseStyle" />
    <validator name="DoubleNegative" />
    <validator name="SectionLevel">
      <property name="max_num" value="3" />
    </validator>
    <validator name="KatakanaEndHyphen" />
    <validator name="GappedSection" />
    <validator name="ListLevel" />
  </validators>
</redpen-conf>

この設定だと

  • 句読点を,.にする
  • 文長を100文字に制限する
  • 半角カナを使わない
  • 文末のスタイルを統一する
  • 二重否定を禁止する
  • 節の最大深さを3までにする(chapter->section->subsectionまで)
  • カタカナ終わりの長音を抑止する
  • 空のセクションを作らない
  • 入れ子の箇条書きの深さ制限をする

といったことが実現できます。

具体的に何が設定できるかはRedPen 1.10 ドキュメントなどを見ると良いでしょう。 実際のエラーメッセージはこんな感じで表示されます。

autobuild-latex.tex:11: ValidationError[JapaneseStyle], 不正な日本語のスタイルを発見しました "あった" at line: それに加えて,各執筆者による原稿をいざ結合してひとつの冊子として組版しようとした時に,誤字・脱字があったり内容にいくらかの誤りが含まれているということになると大変です.
autobuild-latex.tex:15: ValidationError[JapaneseStyle], 不正な日本語のスタイルを発見しました "である" at line: そこで今回は,継続的インテグレーション(CI)サービスであるwerckerを用いてRedPenによる自動校正とupによる自動タイプセットに挑戦しました.
autobuild-latex.tex:77: ValidationError[JapaneseStyle], 不正な日本語のスタイルを発見しました "である" at line: 今回のタイプセットではディストリビューションのひとつであるTeXLiveに同梱されている,upを用います.
autobuild-latex.tex:81: ValidationError[JapaneseStyle], 不正な日本語のスタイルを発見しました "である" at line: ところで,DockerイメージのリポジトリであるDocker Hubを見るとどうやらTexLive2017に対応したDockerイメージは無いようです.
autobuild-latex.tex:138: ValidationError[JapaneseStyle], 不正な日本語のスタイルを発見しました "である" at line: ただし,バージョンによってはSource Han SerifおよびSource Han Sansが使えない可能性があるため,下記のコマンドによってバージョンが1.0以降であることを確認しておきます.

こうやって見るといくつかのエラーは本当にそうなってるのかわからないところがありますが、 最低限ヤバそうな部分を潰すのにこういうのは使えます。 真面目に怪しげな箇所を潰すときは指導教官に相談してください。

終わりに

本当はこれをAdCalの記事にする予定だったんですが、なんとなく記録がてら別の日に投稿することにしました。 実際このワークフローでうまくいったんですか?と聞かれるとなんとも言えないところですが、備えあれば憂いなしということで一つお願いします。 ちなみにDockerHubには私の作ったredpen-cliのDockerイメージとTeXLive + SourceHanFontsのDockerイメージが転がっているので大抵のことをやるときには便利だと思います。

逐次的に読めるシリアライズファイルを作る/読む

TUT Advent Calendar 2018 7日目の記事です。

雉も鳴かずば打たれまいとはよく言ったもので、煽りをしたばっかりに書かざるを得なくなったので書いています。 もう少し真面目なネタを書くべきですが、あいにくと年末の一大イベントに向けてスケジュールがカッツカツになっているので簡単なネタでお茶を濁します。 使える人には使えるし、知ってる人走っているちょっとした豆知識です。

TL;DR

  • データのリストからひとつずつデータを取り出して、ひとつごとにシリアライズすると、読み込みが先頭から逐次的に行える
  • その代わり、ランダムアクセスを実現するのは難しい(そのためにはすべてをオンメモリにするか,データベースを持ち込む必要がある)
  • 必要とするメモリ量が少なくなるのでメインメモリが多くないラップトップでもデータを眺めるだけなら出来る

あらまし

皆さんは100万件や1000万件、あるいはそれ以上の数のファイルを日常的に扱うことがあると思います。*1 しかし、あなたの手元のラップトップにはメモリが8GBしかありません! これではデータをすべてメモリに載せるのは厳しそうです……。 という状況で使える軽いテクニックの話です。

たとえばTwitterJSONが1000万件程度収められているケースを考えると、これは明らかに8GBのような貧弱なメモリに載りそうにはありません。 いま、単純におのおののデータを1回だけ眺めて必要な値を抜き出すというタスクを考えると

  1. データリストの先頭からひとつデータを取り出す
  2. 必要な処理を行う
  3. データリスト末端でなければ1.に戻る

を繰り返すだけでよく、すべてのデータをオンメモリとする必要はなくなります。

そこで、すべてのデータを一回ずつ取り出せる構造を考えたくなってきました。 最も単純な方法としては、JSONをstringfyした行データを用意して1行ずつ読み込んでいく方法があります。 たしかにこれは便利ですが、そのかわり生データがそのまま保存されるため、今度はストレージが爆発する可能性があって嬉しくないです。 なんらかの圧縮法(たとえばgzipやbzip)を使って、うまくデータを圧縮しながらかつ行単位で読み込みが出来るようにならないでしょうか……。

実はこれは簡単に実現できます。具体的には次のコードを実行すれば十分です。

import gzip
data = [ ... ] # JSONオブジェクトのリスト
with gzip.open("data.dump", "wb") as f:
     f.write(str(data).encode("UTF-8"))
     f.write("\n".encode("UTF-8"))

これで実現できました。 ほんとに?となるので試してみましょう。

適当なデータを用意して、いい感じにダンプしてみます。 今回はテストデータを適当な件数生成してくれるdatabasetestdata.comを使ってJSONデータを10000件程度生成してみます。

Database test data generator - Fill your database with random test data!

サンプルコードはこんな感じです。

import json
import bz2
import gzip
import string

with open("sample.json") as f:
    d = json.load(f)


# gzipで試す
with gzip.open("sample.gz", "wb") as f:
    for _ in d:
        f.write(json.dumps(_).encode("UTF-8"))
        f.write("\n".encode("UTF-8"))

with gzip.open("sample.gz") as f:
    result = []
    for i, _ in enumerate(f):
        s = "".join(filter(lambda x: x in string.printable, _.decode("UTF-8")))
        a = json.loads(s)
        result.append(a == d[i])

print("gzip result :", all(result))

# bzip2で試す
with bz2.BZ2File("sample.bz2", "wb") as f:
    for _ in d:
        f.write(json.dumps(_).encode("UTF-8"))
        f.write("\n".encode("UTF-8"))

with bz2.BZ2File("sample.bz2") as f:
    result = []
    for i, _ in enumerate(f):
        s = "".join(filter(lambda x: x in string.printable, _.decode("UTF-8")))
        a = json.loads(s)
        result.append(a == d[i])

print("bzip2 result :", all(result))

実行結果はこうなりました

akahana@stokuno $ python3 sample.py
gzip result : True
bzip2 result : True

うまくいきましたね。

ついでにファイルサイズを確認してみましょう。

akahana@stokuno $ du -h sample.*
216K    sample.bz2
396K    sample.gz
1.7M    sample.json

どうやらいい感じに削減できているようです。

この方法のメリットは - プログラム実行時のメモリ使用量が全展開に比べて抑えられる - 逐次読み出しのみが必要なタスクでは十分に動作する という点です。

一方でデメリットとして - データを読み出す際のコストが重たい。特に時間は通常の読み込みよりも大幅に要する - すべてのデータを一度に圧縮するケースに比べて効率が低い

の2点です。 データを読み出す際に毎回gzipなどのアルゴリズムを用いてデータの展開を行う必要があるため、必然的に生データに比べてデータ読み出しに必要な時間が増えます。 また、データ圧縮時に利用する辞書が各データごとに用意されるため、全体を1度で圧縮するケースに比べれば効率が低いと言えるでしょう。

一方で限られたユースケースでは強力に動作します。 特に、メモリの制約を持つ中であるデータをシーケンシャルに読んで特定のタスクを実行したい(たとえばデータフィルタリング)ということを大規模なデータに行う際には有効な手法だと思います。

使える機会がどれくらいあるか、わかりませんが。知っておくと便利な手法でしょう。

まとめ

今回のAdCalでは大規模なデータの逐次処理に関してメモリやストレージにある程度制約が設けられている環境で動作させる方法を紹介しました。これらの方法は、データに対する単純な処理をメモリ使用量を少なくした状態で行いたいというケースにおいて役立ちます。 そういうケースがいかほど存在するかは別にして、頭の片隅に置いておくといいでしょう。

*1:要出典

Twitterが死んだあとに

Twitterがコミュニケーションツール足り得た要因になったUserStreamが廃止された。 開発者としてTwitterアプリを作ったりしたわけではないため、特にTwitter社の開発方針に文句をつけたいところがないというわけではないものの それほどTwitter社と提供するサービスに対して真摯に向き合った記憶もないが、なんとなく自分の中で一つの時代が終わりゆくので記録としていくつか文章を残しておきたい。

開発者たちが何を思っているのかはmikutterの薄い本製作委員会刊『mikutterの薄い本Vol.14 レズと青い鳥』を読むのがよい。

mikutter-book.booth.pm

Twitterとの出会い

Twitterと出会ったのは2009年のことだった。 当時NHK BS2で放映されていた『ザ☆ネットスター!』という番組に取り上げられたことがきっかけで、なんとなく登録してみた記憶がある。 この番組もやたらと不思議な番組で、なぜサブカル批評で有名な人が出ていたりといろいろとあった番組だった。 よくこの時期にあの番組に出会って、以来思想の側に傾倒しなかったものだなあという気持ちがある。 それはさておいて、インターネット上に知り合いがいたわけでもなく、ただなんとなくこれから先にやってくるイケてるアプリらしいみたいなあやふやな動機で登録したんじゃないだろうか。

当時のことといえば、広瀬香美Twitterに登録したカドなんかで有名になっており、ヒウィッヒヒーとかいう謎のあだ名が付けられ、勝間和代などがつぶやいていたりしたような気がする。 もちろんインターネット上で知り合いを作ろうというような明確な目的があるわけでもなく、インターネット有名人みたいなのの発言を見たいわけでもなかったので、登録したままでそのまま数年間放置されることになった。 一時期、『なるほど4時じゃねーの』というbotだけを動かしていた記憶がある。

Twitterにハマりだす

Twitterに本格的にハマりだしたのは、2011年になってからのことだった。 この年には東日本大震災が発生し、その中でTwitterがもたらすリアルタイム性の高い情報というものが注目を集めた年だったと思う。 今でも活動しているTwitter速報アカウントの草分けといえる『特務機関NERV』が開設されたのも、この年だった気がする。

自分はといえば、ちょうと高等専門学校に入学した年であり、高専という学校の性格なのか同じ学科の同期もあるいはサークル活動における先輩もTwitterをやっていたことでTwitterにのめりこみだしたような記憶がある。 この頃、ようやくはじめての携帯電話としてSC-02Bを手に入れたこともあって、通学の間などにTwitterに貼り付くような人生が始まったわけである。 今考えるとこのときに引き返しておけば、こんなにこじれた人間が生まれることもなかったような気がする。 当時Android向けのTwitterクライアントといえばtwiccaが最もメジャーなクライアントだったこともあり、twiccaをインストールして使っていた。 のちに、複数アカウントを管理したいと思うまではtwiccaがメインクライアントだった。 そんなこんなで、ゆったりとTwitterをやっていたわけだが、そんな人間を本格的にTwitterに叩き落とすツールが現れる。

Windows向けTwitterクライアントアプリTweenである。

Windows向けTwitterクライアントの代表といっても過言ではないこのクライアントの特徴は、異常に詰め込まれた情報とUserStreamにあった。 1ツイートが1行に対応し、それらがUserStreamの力を借りて時にはとてつもない勢いでUIの上を滑っていく。 Tweenは自分にとってTwitterを物理身体によるリアルタイムコミュニケーションを代替するにたるサービスであると思わせるのに十分な機能を持っていた。 このツールとの出会いが完全にその後ずるずるとTwitterを続ける理由を生み出したと言える。 リアルタイムでTLが更新されていくこと、もっというと自分のツイートやリプライに対してリアルタイムで反応が返ってくることが認識できるというのは革命的だった。 そう、リアルタイムである。

この頃のTwitterを眺めてみると、「コミュニケーションはすなわちリズムゲームのようなものだ」とする説を唱えるツイートが流れていた。 自分はその見解に全く同意せざるを得ない。 コミュニケーションにはリズム感が大事で、テキストベースでそれを体現するには常時サーバーなりあるいは相手方とつながっている必要がある。 その点で見ればUserStreamは、コミュニケーションのリズム感を担保することのできる極めて強力なツールだった。 結果として、ツイートを投げたほんの数秒後にふぁぼが返ってくる、あるいは10秒もしないうちに空リプが返ってくるなどの多種多様なコミュニケーションがそこに生まれたわけである。

そしてTwitterにハマりいくつかのクライアントを乗り換えていった。 WindowsはTweenからTweenがオープンソース化をやめたタイミングでOpenTweenに行き、複数アカウントの管理をし始めたタイミングでTweetDeckに流れ着いた。 Linuxは最初の頃ツイタマなどを使っていた記憶がある。いつの間にやらこれもTweetDeckに流れ着いた。WebUIは一つの正義であるという気がする。 Androidはtwiccaからtwitcleやjanetterなど様々なクライアントを試したあとにYukari for Androidにたどり着き今もそれを使っている。 これらのクライアントはいずれもUserStreamに対応している(あるいはしていた)し、UserStreamなしのTwitterというのは考えがたいものだった。 情報を発信すると同時にリアルタイムチャットツールに瞬時に切り替わるTwitterが好きだった。

そして、UserStreamの死

リアルタイム性を持ったテキストベースのコミュニケーションに魅せられたが結果、テキストベースの会話をリアルタイムで行うbotについて研究したいなどと願うようになった。 結果として、高専の卒業研究はそのような形で行うことになった。このときもUserStreamに非常に助けられた記憶がある。 UserStreamに繋ぎっぱなしで放置しておけば、人々の会話を大量に収集することができる。これらは、研究の助けになった。

2011年以降、Twitterは急速にそのユーザー数を拡大していったはずである。記憶はそうなっているが現実の事態であるか定かでない。 その結果として、Twitterは徐々に公益性を帯びるようになってきた。最近だとSNSから発信されたフェイクニュースが世間を賑わせるようになっている。 冷静な議論には十分な情報と時間が必要だ。ところが、Twitterが備えた高いリアルタイム性と、140文字に制限された情報はそのような冷静さをいともたやすく失わせる。 また、Twitterの経営上の問題もある。彼らはもはやユーザーに対してリアルタイム性のあるコミュニケーションを提供するという選択肢は取れなくなった。 あるいは、元より求めていたものはリアルタイム性の高いコミュニケーションではないのかもしれないが、その点はあまり詳しく知らない。

そして、この夏にUserStreamというリアルタイム性はTwitterから失われた。

これによって、人々が発信した内容について吟味する猶予を持つことが今までよりも少しはできるようになるのかもしれない。 それはTwitterを人々がその日のことをつぶやくツールから言論プラットフォームとしての責任ある形に移行することを促すのだろう。 ただ、それでも、多くの人は未だに与えられた情報の一部しか見ることがないし、CJKにおける140文字という制限は情報を伝えきるには難しすぎる。 十分な情報を提供するために用意されたスレッド機能も多く使いこなされているとは言い難いように感じている。 マイクロブロギングサービスを謳うにしては、発信される情報があまりにも少なすぎるのだ。

Twitterはさえずるツールであったはずなのに、利用者が増え公共性を求められる機会が増えたことで言論プラットフォームへと移行しなければならない時期が来た。 あるいはUserStreamという体力が必要なツールを維持するだけの力を失い、制約されたアクセス環境と広告という藁にすがりつくしかなくなったのかもしれない。 いわば幼年期の終わりなのかもしれない。 しかし、Twitterがこれから迎える成年期が必ずしも実りをもたらすものであるとは、個人的にはあまり考えられない。 Twitterで発信可能な極めて制約された情報が深い議論を生み出すようなプラットフォームへの移行を生み出すとは思えないし、 短文広告プラットフォームとしてその生涯を閉じるのではないかと思っている。 それでも、Twitterに魅せられ、もっと言えばUserStreamというリアルタイム性を持ったコミュニケーションに魅せられた人間としては、Twitterが少しでも長くその力を持って生き続けることを願わずにはいられない。

リアルタイムコミュニケーション中毒の行く先

Twitterからリアルタイムにコミュニケーションを行う機能はもはや永遠に失われた。 TweetDeckが残っている?REST APIを異常な回数叩くことであたかも疑似リアルタイムを作り出しているが、通知欄の挙動などを見れば到底リアルタイムとは言い難いことがわかる。 幸いにしてか、Twitter然としたSNSプラットフォームを作成しようという試みは様々に行われていた。 個人的な記憶の最も最初にあるのはGNU SocialなどのOStatusを採用した一連のマイクロブログサービス群であり、いくつかに登録した記憶がある。 これらはUIがイケておらず、また日本人ユーザーの数もそれほど多くなかったためになんだかなあと感じたことを覚えている。

そして、2017年にはmastodonが脚光を浴びた。 mastodonのような後発のサービスはTwitterの悪いところを見てとり、それらを改良して出来上がっていることから利用感もいい。 また、WebSocketを使ってサーバーに繋ぐことができるのでリアルタイム性もある程度担保されていると言える。 これから、UserStreamのようなものを使いたいと願うのであればmastodonに移住するよりほかないのだろう。

Windowsラップトップでイヤホン接続/非接続で音量を切り替える

TL;DR

  • ラップトップの場合、初期設定ではイヤホン接続/非接続で音量設定が切り替わらないことがある
  • Realtek HD オーディオマネージャで設定するとイヤホン接続/非接続で音量設定が切り替えられるようになる
  • 具体的には、デバイス詳細設定からマルチストリームモードを選択すれば良い
続きを読む

そのフォントサイズほんとに9pt?―jsclassesのフォントサイズ指定について

いよいよもって冬らしくなってきたこの頃ですがTUTの皆さんはいかがお過ごしでしょうか。 TUT Advent Calendar 2017 6日目を担当する@akahana_1です。 普段はコンピュータクラブでコンテキストに多分に依存した雑談をしたり、年に非負整数回発行される部誌『とよぎぃ通信』の編集をしたりしています。

さて、学部4年生の方々はそろそろ卒論の提出(あるいはもうすでに終わっている?)や卒研発表等に追われる忙しい時期ですね。 中にはTeXを使って原稿を制作する人もいるでしょう。そういう原稿にはなぜだかフォントサイズの指定がなされていたります。 というわけで、そんな人達のために使える小話を一つ

結論

  • LaTeX + js~~で指定できるフォントサイズは基本的に欧文のもの、和文はそれに合わせてやや小さくなる
  • ただしいくつかの和文フォントサイズは指定可能
  • TeXのフォントサイズは他のソフトウェアのものよりやや小さくなるので、他のソフトウェアと完全に同じ出力を実現することはそのままでは難しい。

前フリ

LaTeXで日本語文章を作成する時に皆さんが使われるクラスファイルといえばjsの接頭辞で始まるクラスファイル群(以下jsclassesと呼ぶ)だと思います。 jsclassesではドキュメントクラスの読み込み時にクラスオプションを指定することで本文のフォントサイズを変更することが出来ます。 例えば、本文を9ptにしたいときは

\documentclass[a4paper, 9pt]{jsarticle}

と指定しますね。

ところでこの時指定される9ptって日本語の9ptですか?

というわけでちょっと確かめてみましょう。

次に示す二つの例は、それぞれpLaTeX(w/jsclasses)でフォントサイズに10ptを指定した時の出力結果と、Adobe Indesign CCでフォントサイズに10ptを指定した時の出力結果です。

f:id:akahana_1:20171206232458p:plain f:id:akahana_1:20171206232512p:plain

おや?よく見るとpLaTeXを用いた出力結果のほうがややフォントサイズが小さくなっていますね。 なんでこうなってるんでしょうか?

答えは単純です。なぜならば 『jsclassesで指定できるフォントサイズは欧文フォントのサイズで和文フォントのサイズではない』 からです。 どういうことなのか具体的に見ていきましょう。

jsclassesにおけるフォントサイズ決定について

さて、jsclassesにおけるフォントサイズ指定では欧文フォントのサイズが指定されるということを明らかにしましたが、だとしても疑問が残ります。

1 : 欧文フォントサイズの指定だったとして和文フォントのサイズはどうやって決定されるの?

2 : 和文フォントサイズを思い通りにする方法はないの?

あたりが定番じゃないでしょうか。 順を追って解説していきます。

まずはじめに、jsclassesでは指定された欧文フォントのサイズに対して和文フォントのサイズをやや小さくすると言う処理を行っています。 なぜ、そのようなことになっているのでしょうか?

皆さんご存知のことと思いますが、pLaTeXエンジンではフォントファイルをそのまま取り扱うことはしません。 代わりにtfm(TeX font metric)ファイルを参照して文字の幅を取得して、文字を配置していきます。 配置された文字が実際のフォントに置き換わるのはdviファイルをdviドライバによって変換したタイミングです。 このことから、TeXで日本語を取り扱うためにはまず日本語文字に対応するtfmファイルが必要なことがわかります。

そのようなtfmファイルとして作成されたものの一つがmin10.tfmです。これはpTeXのさらに前身である「アスキー日本語TeX」向けに作られたtfmファイルです。 そして、このtfmファイルに定義される10pt指定で出力されるフォントのサイズが9.62216ptとなっています。*1 TeXが取り扱う1ptの大きさは1/72.27inchですから*2 、9.62216 / 72.27 * 25.4 = 3.3818mmが実際に出力されるサイズとなっていました。 現在ではmin10.tfmファイルによるメトリックは用いられていませんが、jsclassesで用いられているjisフォントメトリックでも同様に10ptでは9.62216ptで出力されるようになっています。

さて、話がここで終われば単純ですが、まだ続きます。 和文組版では一般的にptの代わりに級(Q)という単位を使います。1Q=0.25mmとして定義されています。 jisフォントメトリックでは10ptの欧文に対して9.62216ptの和文となっていましたが、jsclassesではさらにこれを13Q相当に縮小して用いています。 ということは3.3818mm / 0.25mm = 13.527Qとなるので、13 / 13.527 = 0.961倍すればよいことになります。 よって、jsclassesでは標準設定となる10pt指定の和文フォントサイズは13Q、おおよそ9.24ptとなります。 これはTeXにおけるptの定義を用いているので、他のソフトウェアで用いられる定義の1/72inchを用いてptに換算すれば9.21ptということになります。

1.の解答は 「jsclassesでは欧文10ptに対して和文が0.962216 * 0.961 = 0.9247倍されたフォントサイズになる」

ということになります。 そして解説の中で明らかにしましたが、TeXのptは他のソフトウェアで扱うptよりもやや小さい」ということもわかります。 というわけで、フォント指定がなされているタイプの原稿を執筆する時に厳密に他のソフトウェアでの出力にTeXを追従させようとする試みはかなり難しいといえます。 ちなみに、タイトルで取り上げている9ptも同じように換算してみると10pt * 0.913 * 0.9247 = 8.4425ptとなります。 クラスオプションで9ptを指定したつもりが本文の和文は8ptのほうが近い値で組まれることになってしまいますね。

おや?今9ptの換算をしたつもりなのに、なぜか10ptを元にして計算を行い謎の係数を乗じてますね。この謎については後で答えることにして、次の疑問を解決します。

jsclassesでクラスオプションに指定したフォントサイズは欧文のフォントサイズを指すことがわかり、それに比べて和文のフォントサイズはやや小さくなるということがわかりました。 では、和文のフォントサイズを指定してしまう方法はないのでしょうか。

これについてもjsclassesのクラスオプションに用意されています。 具体的には次のフォントサイズで和文を出力するように設定することが可能です。

  • pt指定のもの
    • 10ptj
    • 10.5ptj
    • 11ptj
    • 12ptj
  • 級数指定のもの
    • 12Q
    • 14Q

これらのフォントサイズについては和文のフォントサイズを指定することになります。この時、和文のフォントサイズに合わせて先ほどとは反対に欧文のフォントサイズがやや大きくなります。 というわけで2.の解答は

「一部のフォントサイズであれば和文のフォントサイズを指定することができる」

となります。 あっさりしたものですね。

ただし、まだ一つだけ疑問が残っています。 先程、和文フォントサイズが欧文フォントサイズに対してやや小さくなると言う説明をして、9ptでも換算してみた時に登場した謎の係数0.913は一体何なのでしょうか。 そして、tfmファイルには文字の幅が記録されていると言いましたが、そのままだと複数のフォントサイズ向けに複数のtfmファイルを用意する必要があるように見えます。 ところがjisフォントメトリックを用いる時に利用するtfmファイルは二つだけ(jis.tfmおよびjisg.tfm)です。 どうやって様々なフォントサイズを実現しているのでしょうか。

というわけで3つ目の疑問はこれです。

3 : pLaTeX + jsclassesにおいて複数のフォントサイズの切り替えをどうやって実現しているのか

先に結論だけを言うと組版時に用紙サイズを任意に拡大(縮小)してから10ptで組版を行い、それを元の用紙サイズになるように縮小(拡大)して指定のフォントサイズを実現します」

どういうことなのか、詳しく説明します。 jis.tfmおよびjisg.tfmに記載されているフォントメトリックは10pt指定時のものです。このままでは他のフォントサイズを取り扱うことが出来ません。 しかし、現実にはそのような複数のフォントサイズを取り扱う需要があるわけです。 この解決方法はふたつ考えられます。

  • フォントサイズごとに異なるフォントメトリックを用意する
  • フォントメトリックを固定して何らかの方法でフォントサイズを実現する

前者の方法はjisメトリックの前身であるmin10を始めとするフォントメトリックで用いられていた方法です。 しかしjisメトリックを利用するjsclassesでは後者の何とかする方法を採用します。

これを実現するのがTeXプリミティブとして用意されている\mag命令です。この命令は引数に取る数値の1000分率の割合で組版を行う版面を拡大します。 つまり\mag 1414と書かれていれば、版面が1.414倍拡大された状態になります。そしてjsclassesではこれを利用して10pt設定のフォントメトリックを用いて所望のフォントサイズを得ています。 このような組版を行っているのは世界広しといえどもjsclassesくらいのものなようです。

というわけで先程の換算で出現した0.913と言う謎の係数はこの\magにおける拡大率になります。 そしてこの\magにおける拡大縮小はすべてのフォントサイズ指定に関わってきます。

次の画像を見てください。 どちらもソースファイルのプリアンブルを除くと同じ

\begin{document}
\section{これがLargeサイズ}
Windowsでコンピューターの世界が広がります
\end{document}

です。

f:id:akahana_1:20171206233447p:plain f:id:akahana_1:20171206233459p:plain

見比べると下の画像のほうが上の画像よりも全体的にフォントサイズが大きくなっていることがわかりますね。 というのも上の画像ではプリアンブルが

\documentclass[a4paper, 9pt]{jsarticle}

なのに対して、下の画像ではプリアンブルが

\documentclass[a4paper, 10pt]{jsarticle}

となっているためです。

つまり\magによる版面拡大縮小の影響は本文フォント以外のフォントも影響を受けます。 TeXとフォントサイズの変更で検索すると本文フォントに対して\Largeなどが何ptであるか記載されている例がありますが、あくまでも欧文10ptの時に他のフォントサイズ指定が欧文でどのptに相当するかを書いているだけであって、jsclassesのクラスオプションでフォントサイズを変更した場合は連動して変わりうるということです。

まとめ

卒論や修論、あるいは発表予稿などを書く時に役に立つかもしれないTeXの豆知識について書いてみました。 \magの解説についてはかなり怪しい部分があると思うので、詳細な動作を知っている方がいらっしゃいましたら教えていただけると幸いです。 それでは皆様よきTeXライフを。

また、僕も編集に関わっている豊橋技術科学大学コンピュータクラブ部誌『とよぎぃ通信』が冬のコミックマーケット93で頒布される予定です。 C93初日東ク-34aで皆様をお待ちしています。

さて、明日は@_Nnwww氏の音楽についての記事です。氏は現代音楽が好みであることを存じているので、どんな飛び道具がやってくるのか期待しています。

参考文献

*1:10ptは欧文における標準のフォントサイズです

*2:ちなみにPostScriptの1ポイントは1/72inchです。このことからもTeXのptのほうがそれ以外のソフトでの出力よりやや小さくなることがわかります。