犬のいる生活

この記事は圧倒的令和ッ!!ぴょこりんクラスタ Advent Calendar 2019のために書いたものです。 このAdvent Calendarが何なのかについては、主催者による紹介記事を見てください。

サマリ

犬を再度飼い始めた。世話は大変だけど、それを補って余りあるくらいかわいい。

はじめに

預かっていたトイプードルが帰ってしまって、1年ほど経った。 静かな部屋を埋めるために、魚を飼ったりしてみたが、 魚はトイプードルの代わりにならなかった。魚はぼーっと眺める楽しみがあるが、なでたり遊んだりができない。 犬はぼーっと眺めて楽しむというよりは、なでたり遊んだりできる。つまり、犬と魚は相補的な存在であった。 そうすると、静かな部屋を埋めるには犬を飼うしかない。 そこで、かわいい、賢い、毛が抜けない、かわいい、 においが少ない、かわいいという最強犬種であるトイプードルを飼うことにした。

今回は、トイプードルを飼ったときの話。

簡易成長記録

かわいさを言葉で伝えるのは愚かであるので、写真を貼る。

f:id:nbisco:20191105125404j:plain
生後3か月 その1

f:id:nbisco:20191109085304j:plain
生後3か月 その2

f:id:nbisco:20191216150851p:plain
生後3か月と1週間

f:id:nbisco:20191119074534j:plain
生後3か月と2週間

f:id:nbisco:20191113084239j:plain
生後3か月と2週間 その2

f:id:nbisco:20191122104658j:plain
生後3か月と3週間

f:id:nbisco:20191203121737j:plain
生後4か月(カット後)

f:id:nbisco:20191206194828j:plain
生後4か月と1週間

ある1日の抜粋

犬はかわいいだけではなく、飼うのが大変な生き物である。 来て1週間以内のある日の犬記録は以下の通り。

時間 出来事 ひとこと
6:20 騒ぎ声で飼い主が起きた。 元気がいいのはOKだが寝てほしい。外に聞こえてないのか不安になる。
6:30 栄養剤を人差し指第一関節の1/3程度舐めさせる。 栄養剤が好きなのか飛びついてくる。
6:40 トイレ掃除(大小) トイレシート上でやってくれたので、一安心。
6:50 朝ごはん作成。固形ドッグフード20gに粉ミルクを軽くふり、お湯で粒が浸るくらいに入れる。
7:40 ふやかし終了。朝ごはんを与える。
9:25 トイレ掃除(大)。トイレ内で飛び跳ねたので、糞の一部がケージ外床に付いていた。ウェットティッシュで拭き取り実施。
9:30 糞の一部が体毛についていたが、洗うほどでもないくらいの範囲だったので、ウェットティッシュで拭き取った。 暴れないでくれ頼む。
10:30 栄養剤を人差し指第一関節の1/3程度舐めさせる。
11:50 新しいぬいぐるみを入れる。入れたのはこれ。https://www.nitori-net.jp/ec/product/7970546s/?ptr=item 早速噛み付いて遊んでいたので、気に入ってくれた様子。
11:55 ドッグフード25g+とりささみを茹でたものを手親指の爪くらいを混ぜたものに、粉ミルクをふりかけ、お湯で粒が浸るくらいに入れる。
12:55 昼食。完食。最初にとりささみだけ食べて、あとでドッグフードを食べていた。
13:00 トイレ掃除(大小)。
15:45 トイレ掃除(小)。
16:00 ニュートリカルを人差し指第一関節の1/3程度舐めさせた。
16:05 ときどき静かになるので、寝てるのかもしれない。覗き込むと起きてしまうので覗けない。
17:10 トイレ掃除(小)。
17:20 寝た様子。覗き込むと起きてしまうので覗けない。
18:30 ドッグフード25g+とりささみを茹でたものを手親指の爪くらいを混ぜたものに、粉ミルクをふりかけ、お湯で粒が浸るくらいに入れる。
18:40 起きたが、おとなしい。静かである。
19:20 夕食完食。やっぱりささみはおいしいのか、一番先に食べているようだった。
21:05 トイレ掃除(大小)。
22:00 栄養剤を人差し指第一関節の1/3程度舐めさせる。
22:05 就寝

トイレ掃除が大変で、1日に何度もする上に、飼い主の姿が見えるとケージ内で飛び跳ねるので、 事故が起こりやすい。かと言って、放し飼いにすると家がトイレにされてしまうので、放し飼いにはできない。 発見速度だけが事故を防止するのである。 ちなみに、事故った場合はシャワーを浴びさせる必要があるが、犬は頻繁にシャワーを浴びるような皮膚になっていないので、 最低限で済むようにする必要がある。つまり、事故らせないことが大事。

最も辛いのは最初の3日間。とってもかわいそうな声で鳴くが、 外に出してはいけないからだ。子犬を外に出して遊ばせると、低血糖になってしまい、 最悪死に至る。ともかく、心を鬼にして外に出さないことが大事。1か月もすれば、 外で遊んでも低血糖にならないくらいには大きくなる。

いたずら集

子犬は何でも興味を示して、とりあえずかじる傾向があり、これがいたずらにつながりやすい。 これまでやってきたいたずらは以下の通り。ショックだったのは壁かじりで、猫飼ってないのに 壁が傷ついたのには泣いた。

  • ガムテープに興味を示した結果、段ボール製の小屋のつなぎ目を集中狙いし、破壊
  • 段ボールに興味を示した結果、段ボール製の小屋の噛みつきやすいところを集中狙いし、破壊。
  • コンセントに興味を示した結果、大外の被覆を剥がす。バレて叱られて以降噛みつかず。
  • 部屋の凸角に興味を示した結果、ちょっとかじる。かじっているところでバレて叱られるが、時折すきを見てかじろうとしている。
  • スリッパに興味を示した結果、こちらが目を離したすきに持ち去る。何度も叱られているが、懲りずに持ち去っている。

興味を強く示すもの

犬には個性があり、ある犬は興味を示すものが、別のある犬は興味を示さないことがよくある。 うちの犬が特に興味を示しているのは以下の通り。

  • スリッパ:ソファに座って、スリッパが足から脱げると、さっそうと段ボール小屋に持ち帰る
  • 靴下:目の前で靴下を履こうとすると、奪い取ろうとしてくる。奪い取られると小屋に持ち去られる。
  • かさかさ音がするもの:ビニール袋をこすり合わせる音に異様に興味を示し、すきあらば持っていこうとする
  • 段ボール:破壊した切れっ端をかじって遊んでいる。下手な人形よりも段ボールのほうが好き。

最近ではすこし賢くなったのか、スリッパ泥棒すると、カーテン裏に隠す術を体得してしまった。

f:id:nbisco:20191216175918j:plain
スリッパ泥棒が隠し場所を求めてさまよっている

飼い主の失敗

ケージを拡張しようと、以下の赤ちゃん用の柵を設置したところ、隙間が大きすぎて普通にスルーされた。 適当に測って買うのはいけない(戒め)。

www.amazon.co.jp

おわりに

犬がかわいい。飼うのは大変だけど、それを補ってあまりある癒やしがある。

SMVの目的外利用

この記事は圧倒的令和ッ!!ぴょこりんクラスタ Advent Calendar 2019のために書いたものです。 このAdvent Calendarが何なのかについては、主催者による紹介記事を見てください。

サマリ

NuSMVに数独を解かせようとしたが、ちょっと難しくなるとOOM Killerに殺されて解けなかったのでSATソルバに解かせた。道具は目的に合ったものを使おう。

はじめに

世の中にはモデル検査という技術がある。平たく言えば、プログラムをモデル化したもの*1に対し、どのような性質(例えば、デッドロックしないかどうかとか)を持つかを網羅的に調べる技術で、 航空機や自動車、鉄道など、特に安全性が求められるソフトウェアで使われることが多い。 事例はここに多少まとまっており、 国内ではスバルやJAXA、国外では、ボンバルディア、Airbus、Microsoftが使っている。

モデル検査ツールは、切り出す側面に応じて様々な種類がある。 以下に例を示す。

  • SPIN: 複数のプロセスの通信を、オートマトンでモデル化したものを検証するツール。
  • NuSMV: プログラムの状態遷移をモデル化したものを検証するツール。
  • UPAAL: プログラムの時間遷移をモデル化したものを検証するツール。

いろいろ種類はあるが、モデル検査ツールが共通して持つ特徴は以下の通り。

  • 検証対象の性質は何らかの論理式で記述される
  • 性質を持つかどうかは、論理式を満たすかどうかで表される
  • 論理式を満たすかどうかを、網羅的に検査する
  • 論理式を満たさない場合は、反例を1つ出力する

面白いのが4番目の反例を出力する性質で、これをうまく使えばちょっとしたクイズを解くことができる。 要は、満たしてほしい性質(=クイズの回答)の否定を論理式として与えて、 反例として回答を出させる、ということである。 というわけで、おなじみの数独をモデル検査ツールに解かせてみることにする。 使うのは文法がシンプルで、モデルも(たぶん)わかりやすいNuSMVとする。

NuSMVについて

入手

NuSMVは、SMVのなかで、唯一商用化・無料で使えるものである。 ダウンロードの際にフォームが出るが、CAPTCHAだけ入力すればダウンロードできる。 ビルドは大変なので、バイナリを使うのが楽。 Minisat版でもZchaff版でもどっちでもいいと思うが、自分はMinisatのほうを使った。

モデル化

素直に、数独の各マスの値が変化する、というモデル化を行う。 NuSMVでモデル化するにあたり、とりあえずやるだけであれば、きちんと文法や機能を使いこなす必要はないので、 今回使っているものだけ、例を用いて説明する。

例として、数独の1行、2つ空欄の場合のソースコードを示す。

-- a0 a1 a2 a3 a4 a5 a6 a7 a8
-- 7  8  3  1  4  2  9  x  x  のa7とa8を埋める
-- (a7, a8) = (5, 6)もしくは(6, 5)が答え。

MODULE main --  Cで言うところのmain関数的表現。とりあえず一番上に書いておけば良い。

DEFINE -- Cでいうところの`#define`マクロ。定数を使いたいときに使う。
  a0 := 7; -- 文末にセミコロンを置く
  a1 := 8;
  a2 := 3;
  a3 := 1;
  a4 := 4;
  a5 := 2;
  a6 := 9;

VAR -- 変数宣言。取りうる範囲まで指定する必要がある。SMVは網羅検査するので、なるべく取りうる範囲を絞る。
  a7 : {0, 5, 6}; -- 整数値が連続している場合は、x: a..b(pythonと違ってa <= x <= b)と書いてもよいが、
  a8 : {0, 5, 6}; -- 今回は歯抜けになっているので、{}でくくって書く

ASSIGN --  状態遷移ルール(=変数の初期値と変化ルール)を記述する。
   init(a7) := 0;    -- 初期値
   next(a7) := case  -- 次に何の値を取るか
     -- a0 + a1 + a2 + a3 + a4 + a5 + a6 + a8 = 44 : 1; -- <条件> : <次の値>というフォーマットで書く。
     -- 数独では、値が変化するのに必要なルールは特にないので、上の条件文はコメントアウトしておく。
     TRUE : {5, 6};  -- 最後に必ずTRUEの分岐を書く必要がある。TRUEだけだと、ランダムにどちらか選ばれる。
   esac;
   init(a8) := 0;    -- 初期値
   next(a8) := case  -- 次に何の値を取るか
     TRUE : {5, 6};  -- ランダムにどちらか選ばれる。
   esac;

SPEC
  !EF( -- EFは、将来一度でも成立する、という意味。!付きなので、将来一度も成立しない、と読む。
    !(a7 = a8) -- a7とa8が等しくならない。つまり、a7とa8が等しくならないことはない、という性質を検証する。
  )

これを実行するとこういう出力が出る。 a7 = 5, a8 = 6なので、期待通り解けている。

$ ./NuSMV-2.6.0-Linux/bin/NuSMV test.smv
*** This is NuSMV 2.6.0 (compiled on Wed Oct 14 15:36:56 2015)
*** Enabled addons are: compass
*** For more information on NuSMV see <http://nusmv.fbk.eu>
*** or email to <nusmv-users@list.fbk.eu>.
*** Please report bugs to <Please report bugs to <nusmv-users@fbk.eu>>

*** Copyright (c) 2010-2014, Fondazione Bruno Kessler

*** This version of NuSMV is linked to the CUDD library version 2.4.1
*** Copyright (c) 1995-2004, Regents of the University of Colorado

*** This version of NuSMV is linked to the MiniSat SAT solver.
*** See http://minisat.se/MiniSat.html
*** Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
*** Copyright (c) 2007-2010, Niklas Sorensson

-- specification !(EF !(a7 = a8))  is false
-- as demonstrated by the following execution sequence
Trace Description: CTL Counterexample
Trace Type: Counterexample
  -> State: 1.1 <-
    a7 = 0
    a8 = 0
    a6 = 9
    a5 = 2
    a4 = 4
    a3 = 1
    a2 = 3
    a1 = 8
    a0 = 7
  -> State: 1.2 <-
    a7 = 5
    a8 = 6

NuSMVで数独を解いてみる

その1: 簡単なやつ

先程の例をそのまま拡張してやればよいが、いかんせんマス目が多くて大変なので、 SMVスクリプトを生成させて、それを実行することにする。 ジェネレータのソースコードは以下の通り。 数独を解くNuSMVソースコードのジェネレータ · GitHub

では、まずは肩慣らしに簡単なやつを解いてみよう。 https://kachikachi.net/numberplace/ で、予め50個/81個の 数字が埋まっている問題を生成して、NuSMVに解かせてみる。

ソースコードはこれ。 簡単な数独を解くNuSMVソースコード · GitHub

問題はこれで、

# 0 1 2 3 4 5 6 7 8
A 0 8 6 1 0 0 0 2 0
B 3 2 4 0 0 0 1 0 5
C 7 5 1 3 2 0 9 8 6
D 2 4 3 9 8 6 0 0 1
E 0 0 0 7 0 1 0 0 0
F 5 0 0 2 4 3 8 6 9
G 6 9 8 0 1 7 4 3 2
H 1 0 5 0 0 0 6 9 8
I 0 3 0 0 0 9 5 1 0

NuSMVが出した回答は以下で、

 -> State: 1.2 <-
   A0 = 9
   A4 = 7
   A5 = 5
   A6 = 3
   A8 = 4
   B3 = 6
   B4 = 9
   B5 = 8
   B7 = 7
   C5 = 4
   D6 = 7
   D7 = 5
   E0 = 8
   E1 = 6
   E2 = 9
   E4 = 5
   E6 = 2
   E7 = 4
   E8 = 3
   F1 = 1
   F2 = 7
   G3 = 5
   H1 = 7
   H3 = 4
   H4 = 3
   H5 = 2
   I0 = 4
   I2 = 2
   I3 = 8
   I4 = 6
   I8 = 7

これをあてはめるとこうなる。合ってるっぽい。

# 0 1 2 3 4 5 6 7 8
A 9 8 6 1 7 5 3 2 4
B 3 2 4 6 9 8 1 7 5
C 7 5 1 3 2 4 9 8 6
D 2 4 3 9 8 6 7 5 1
E 8 6 9 7 5 1 2 4 3
F 5 1 7 2 4 3 8 6 9
G 6 9 8 5 1 7 4 3 2
H 1 7 5 4 3 2 6 9 8
I 4 3 2 8 6 9 5 1 7

状態数は

cat sudoku_sp_easy.smv | grep TRUE | perl -lane 's/\{//g; s/\};//g; s/,//g; s/TRUE ://g; s/ //g; print' | perl -lane 'BEGIN{$count=1;} $count *= (length $F[0]); END{print $count}'

166kほど。

その2: ちょっと難しいやつ

次に、https://kachikachi.net/numberplace/ で、予め35個/81個の 数字が埋まっている問題を生成して、NuSMVに解かせてみる。 この問題自体は、そのマスに入り得る数が1個しかないものから順に埋めていくだけで 解けるようなので、そんなに難しくはなさそう。

# 0 1 2 3 4 5 6 7 8
A 3 0 2 0 0 5 7 4 9
B 0 0 6 0 0 9 0 1 2
C 0 0 4 3 0 2 0 0 0
D 0 0 0 9 0 0 0 3 0
E 4 0 7 0 3 0 6 0 8
F 0 3 0 0 0 6 0 0 0
G 0 0 0 1 0 3 8 0 0
H 8 6 0 4 0 0 1 0 0
I 1 2 3 6 0 0 4 0 7

生成したソースコードはこれ。 ちょっと難しい数独を解くNuSMVソースコード · GitHub

メモリ8GB積んだVMで動かしているが、OOM killerに殺されたようでダメだった・・・ 状態数は

cat sudoku_sp_mid.smv | grep TRUE | perl -lane 's/\{//g; s/\};//g; s/,//g; s/TRUE ://g; s/ //g; print' | perl -lane 'BEGIN{$count=1;} $count *= (length $F[0]); END{print $count}'
2.49593749508299e+19

2.5 * 10^19くらいあるようで、網羅検査すればメモリ使い果たすよなという感がある。 金槌を持つと何でも釘に見えてしまうような使い方はよろしくないね。

SATソルバに解かせてみる

目的外利用の限界を感じたが、ちょっと悔しいのでSATソルバに解かせてみることにする。 SATソルバはSMVと違って網羅検査が目的ではなく、条件を満たす例を1つ出してくれるものだ。 条件を満たす例を1つ出すという目的内利用なので、SMVよりは当然速いはずだ。

使ったソルバはMicrosoft Researchが出しているZ3である。 解き方はSMVのときとほとんど変わらなくて、初期状態と満たすべき条件を書き下すだけである。 ソースコードは以下の通り。

z3を使って数独を解くソースコード · GitHub

で、早速ちょっと難しいやつを解かせてみる。今度は解けた。

# 0 1 2 3 4 5 6 7 8
A 3 1 2 8 6 5 7 4 9
B 5 8 6 7 4 9 3 1 2
C 9 7 4 3 1 2 5 8 6
D 6 5 8 9 7 4 2 3 1
E 4 9 7 2 3 1 6 5 8
F 2 3 1 5 8 6 9 7 4
G 7 4 9 1 2 3 8 6 5
H 8 6 5 4 9 7 1 2 3
I 1 2 3 6 5 8 4 9 7

今度は30個/81個埋まってる問題を解かせてみるが、これも難なく解けた。

ちなみに、問題がこれで、

# 0 1 2 3 4 5 6 7 8
A 0 5 0 0 0 1 0 7 0
B 1 0 0 0 0 2 0 0 0
C 2 0 7 0 0 4 1 0 0
D 0 2 0 0 0 0 9 1 6
E 0 0 5 0 0 0 2 0 0
F 9 1 6 0 0 0 0 3 0
G 0 0 1 7 0 0 5 0 3
H 0 0 0 5 0 0 0 0 1
I 0 4 0 9 0 0 0 2 0

回答がこれである。

# 0 1 2 3 4 5 6 7 8
A 3 5 4 6 9 1 8 7 2
B 1 6 9 8 7 2 3 5 4
C 2 8 7 3 5 4 1 6 9
D 7 2 8 4 3 5 9 1 6
E 4 3 5 1 6 9 2 8 7
F 9 1 6 2 8 7 4 3 5
G 6 9 1 7 2 8 5 4 3
H 8 7 2 5 4 3 6 9 1
I 5 4 3 9 1 6 7 2 8

もっと難しい問題も解けるようなので、当然と言えば当然か。でもいざ目の当たりにすると感動するね。

おわりに

SMVは状態遷移が手軽に書けてよいが、目的に合わせて使おう。 SMVは網羅的に調べてくれるのがよいところであって、こういうクイズを解く道具ではない。

*1:プログラムの特徴の一部を 切り出したもの

ベタのいる生活 その2: 水槽丸洗い

この記事は圧倒的令和ッ!!ぴょこりんクラスタ Advent Calendar 2019のために書いたものです。 このAdvent Calendarが何なのかについては、主催者による紹介記事を見てください。

記事のサマリ

たまには水槽を丸洗いしましょう。

はじめに

前回の記事の最後に、 現在の水槽が苔にまみれていて見苦しい写真を載せた。多少であればヘラで苔を削ぎ落とすのだけど、 ここまで生えてしまうと、景観回復のためには丸洗い以外に道はない。 そこで、今日は水槽丸洗いする。

忙しい人向け

詳細は後述だけど、こんな感じ。

  1. 魚の避難
  2. 水槽の中身(水草、置物、ヒーター、フィルタ)を全部出して水洗いする
  3. 水槽を水洗いする
  4. 水槽を空のまま設置
  5. 水槽の中身を戻す
  6. 水槽に水を入れる
  7. 魚を戻す。このとき、避難場所の水をなるべく入れないようにする。

ステップ1: 魚の避難

水槽を洗うためにまずやらなければならないのは、魚の避難である。 こんな感じでバケツに水を入れて、カルキ抜き薬剤を入れれば避難場所の出来上がり。

f:id:nbisco:20191207091424j:plain
避難場所

あとは、網ですくって移動させればよい。このとき、こういうがあると移動が楽になる。

移動後はこんな感じ。無造作に入っているが、エビのような繊細な生き物を入れるときは もっと丁寧に入れたほうがよいと聞いている。点滴法とかググってくれれば大変そうだと感じてもらえるかもしれない。 我が家のベタとアフリカンランプアイ*1はタフなので、思い切って移動させればOK。

f:id:nbisco:20191207092529j:plain
避難後

ステップ2: 水槽の中身を全部出して水洗い

うちの水槽には、賑やかし要員としての水草(アヌビアス・ナナアナカリス、マツモ、カボンバ(3つとも通称金魚草)、あと名前忘れた何か)とトンネル、生存に必須なフィルタとヒーターが入っている。 これらを全部出して、水洗いする。

f:id:nbisco:20191207093441j:plain
水草
f:id:nbisco:20191207093949j:plain
水槽の中のヒーターとフィルタ
f:id:nbisco:20191207094612j:plain
水槽の中身

アヌビアス・ナナは、土台の流木がだいぶヘタっていて木くず生成器と成り果ててしまったため、 この期に廃棄。また、名前忘れた何かは、土台は火山岩か何かで丈夫だが、藻と水替え時の強水流で参ってしまったため、これも廃棄する。 マツモとカボンバも参ってしまったけど、アナカリスは本当に丈夫で、 藻にも水替え時の強水流にも負けずに新芽を次々と生やしてくるので、 枯れ気味の枝を取る程度とした。

トンネル、ヒーターはメラミンスポンジでよく磨く。 フィルターは歯ブラシやらパイプ磨き用ブラシで苔を落とす。

洗い終わったあとはこんな感じ。わかりにくい写真だけど、苔が取れているのがわかるかもしれない。

f:id:nbisco:20191207100424j:plain
洗ったあと

ステップ3: 水槽を水洗い

中身が空になった水槽を洗っていく。これがbeforeで、めちゃめちゃ気分悪い図である。

f:id:nbisco:20191207100855j:plain
水槽: before

水槽も同じくメラミンスポンジでこする。 案外隅っこが洗いにくいので、適宜ヘラを使って削ぎ落としたり、 歯ブラシで擦り落とす必要がある。

がんばるとここまできれいになる。もとに戻ったとも言う。

f:id:nbisco:20191207101859j:plain
水槽: after

ステップ4~6: 水槽の中身を戻す&水槽に水を入れる

きれいになったと思いきや、案外苔がこびりついていてショックを受けた。 洗面台の照明が暗めでわからなかったんだと思うけど、 今更洗い直すのも大変なので諦め。 多少ゴミが浮いているが、フィルターが回ればこの辺はきれいになる。

f:id:nbisco:20191207105009j:plain
多少苔が残っているがきれいになった

ステップ7: 魚を戻す

最終的にこんな感じになった。

f:id:nbisco:20191207105429j:plain f:id:nbisco:20191207105434j:plain f:id:nbisco:20191207111251j:plain

おわりに

透明度の高い水槽は眺めていていい気分である。

余談:そもそも苔を生やさないようにするにはどうすればよいか?

苔が生える原因は、水中の栄養素と光量の多さである。 この辺の原因に対策を打つか、苔が生えることに関しては諦めて、 苔自体をきれいにする何かをいれることになる。

前者の対策では、単純には栄養素の量や光の量を絞ってやればよい。 が、実際は難しい*2ので丸洗いが楽。

  • 水中の栄養素を減らす
    • 水替えを毎日やる
    • 水草を生やしまくって、光合成で栄養素を食い尽くさせる。なお、光合成を全力稼働させるには、 二酸化炭素を添加する必要がある。
  • 光を減らす
    • 照明ONにしている時間を減らす
  • その他
    • 苔防止薬剤を入れる

苔自体をきれいにするには、苔自体を食べる生き物をいれればよい。 つまり、エビや巻き貝、オトシンクルス等の生き物をいれればよいのだけど、 欠点もあるので一概に入れればOKとは言えない。特にベタについては、 ヒレかじられリスクがあるので、混泳がそもそも難しいのもあり、 うちの水槽には入れてない。ちなみに、アフリカンランプアイはおとなしいので なんとかうまくやってくれている。

  • エビ:水草についた苔を食べる。ガラスの壁面のについた苔は食べない。 ベタの餌になってしまうこともあるし、ベタのヒレをかじってしまうこともある。 餌を食べると苔を食べてくれない。
  • 巻き貝:ガラスの壁面についた苔を食べる。見た目が悪いのと、 きれいに食べてくれるわけではない。
  • オトシンクルス:ガラスの壁面についた苔を食べる。おとなしくて混泳に向くが、 餌を食べてくれないので、苔がなくなったときは大変。あと、ベタのヒレをかじってしまうこともある。

*1:要は海外産のめだか

*2:特に二酸化炭素添加

ベタのいる生活 その1

この記事は圧倒的令和ッ!!ぴょこりんクラスタ Advent Calendar 2019のために書いたものです。 このAdvent Calendarが何なのかについては、主催者による紹介記事を見てください。

記事のサマリ

ベタを飼うときに揃えた道具と、運用について。

はじめに

ペットを飼うのは結構大変だと思う。 大変なのは世話にかける時間の確保である。

時間の確保が少なくて済むペットはいるか? いる。魚だ。魚は猫のように家を引っ掻き回したり、 犬のように吠えて暴れまわったりしない。 水槽の中なので、うさぎのようにトイレを覚えずとも、問題はない。匂いも音も少ない。 インタラクションは少ないが、泳いでる魚を眺めるだけで結構楽しい。

最終的に魚を飼う決断をしたのは以下の会話である。

nbisco: やはり日中部屋にいないけどペットを飼うならうさぎかなという気がしてきた
******: https://unagi-best.com/%E3%82%A6%E3%83%8A%E3%82%AE%E9%A3%BC%E8%82%B2.html
nbisco: 絶滅促進はやめろ
******: 食用じゃないのも色々いるみたいだぞ https://item.rakuten.co.jp/fish-neos/a13-240626-13/
nbisco: 予想外。これなら確かに飼えるかもしれない。

今回は、何を買ったか、運用をどうしているかについてまとめる。

何を飼うことにしたか

さて、そんなマンション向きのペットの魚であるが、うなぎではなくベタを飼うことにした。 ベタ(和名:闘魚)はタイのメコン川流域原産の淡水に住む熱帯魚である。 詳しくはここ

ベタにした理由は、シンプルに丈夫で飼いやすく、色鮮やかなヒレがひらひらして美しいから。 何分魚を飼うのは初めてなので、 多少世話をミスっても魚が耐えられるように、丈夫で飼いやすいのを最重要視した。 また、同一種類なのに、同じ色、同じ形のヒレの魚はほぼいなくて、 個体識別が可能なところもポイントである。愛着は個体識別できるところから始まるのだと思う。

ちなみに、まず思いつく金魚は飼うのが難しい魚であるらしい。 ベタ屋の店長曰く、「もともと病気持ちなせいで、体調が悪くなると なすすべなく全滅することがよくある」とのことであった。

何を買えばよいか

必須

自分が揃えたものは以下の通り。多少水槽が寂しいかもしれないが、これらがあればベタが飼える。

種類 品名 URL ひとこと
水槽 ジェックス グラステリア250 https://www.amazon.co.jp/gp/product/B0043AYLOO/ ガラスは見やすくてよい
フィルター ジェックス スリムフィルターS https://www.amazon.co.jp/gp/product/B0043AYLOO/ 水をきれいにして、かつ酸素を混ぜこむため
ライト 寿工芸 フラットLED 2032 シルバー https://www.amazon.co.jp/gp/product/B00UYIIGYU/ これがないと水槽の中が見えない
水温計 スドー スリム水温計 mini55 https://www.amazon.co.jp/gp/product/B0051RIXBA/ 熱帯魚は水温管理をきちんとする必要がある
ヒーター ジェックス NEW セーフカバー ヒートナビ SH80 https://www.amazon.co.jp/gp/product/B01FI29IPW/ 熱帯魚は水温管理をきちんとする必要がある
ヒカリ (Hikari) ベタ アドバンス 5g https://www.amazon.co.jp/gp/product/B00XVP39CM/
水のカルキ抜き薬剤 テトラ (Tetra) アクアセイフ プラス 100ml https://www.amazon.co.jp/gp/product/B00LFIDCQ0/
掃除用スポイト ジェックス おそうじラクラク クリーナースポイト ロング https://www.amazon.co.jp/gp/product/B01BXVIMXG/ ごみをちょっと吸い取る用
掃除用ホース 水作 プロホース エクストラ S https://www.amazon.co.jp/gp/product/B01DQA7DLY/ 水換えのメイン選手
掃除用バケツ バケツ 水槽の容量が10リットル弱くらいなので、5リットルくらいのものを100円ショップで買えばよい。 水槽全洗のときのために2個あるとよく、注ぎ口がついているものだとなおよい

これらを揃えるとこんな感じ。

f:id:nbisco:20190814163425j:plain f:id:nbisco:20190819075517j:plain

以下、多少の補足。

ベタはコップでも飼えると言われるが、水槽は広いほうが掃除の回数が減らせるし、 何より魚へのストレスも少ない(はず)。プラスチック製よりもガラス製のほうが 透明度が高くて魚がきれいに見える。ベタはジャンプして飛び出すことがあるので、必ず蓋を付けること。

フィルターも同様の理由で、ベタは多少汚れた水でも耐えられるし、 しかも魚なのに空気中から酸素を取り入れることもできるので、 なくても大丈夫ではある。ただ、水がきれいなこと、酸素が十分あることに越したことはない。 水換えの頻度も減らせる。何より、水換え途中に濁ったりした場合も、 フィルタを装備しておけば勝手に水がクリアになってくれる。

ベタは熱帯魚なので、水温計とヒーターが必要。室温を常に一定以上に保つ場合は別だけど、 あまり現実的ではないことが多いかもしれない。

あるとよい

あると水槽がにぎやかになったり、掃除が楽になるので買うとよいと思うものは以下。

種類 品名 URL ひとこと
水草 (水草)アヌビアスナナ プチ付流木 SSサイズ(1本)(約10cm) 本州・四国限定[生体] https://www.amazon.co.jp/gp/product/B00UF458D0/ 流木付きがよかった
隠れ家 スドー かくれ流木S朽木 https://www.amazon.co.jp/gp/product/B01LZXK95Q/ ベタがくぐったりして遊んでくれる
ベタの家 水作 ベタのおやすみリーフ https://www.amazon.co.jp/水作-ベタのおやすみリーフ/dp/B00R494IGC/ ベタが挟まって寝てたりする
ヘラ 井上工具 ジラコヘラ 90mm https://www.yodobashi.com/product/100000001002989364/ 水槽の壁に苔剥がし用
パイプ掃除ブラシ マルカン ニッソー らくミニメンテ パイプブラシセット https://www.yodobashi.com/product/100000001003205662/ フィルタについてるパイプを掃除する用

水草とベタの家をいれるとこんな感じになる。

f:id:nbisco:20190815194119j:plain f:id:nbisco:20190818222356j:plain

ちなみに、ベタは他の魚との混泳が苦手なので、できれば1匹だけ飼うのがよいとのこと。 ただ、混泳可否はベタの性格によるので、入れてみないとわからないですね~ みたいなことを店員さんに言われた。

意外だったのは、日本のメダカが混泳に全く向かないこと。 日本のメダカは弱いけど強気でヒレに噛み付いてきたりするようなのでダメだけど、 海外産のメダカはビビリでおとなしいのでまあ大丈夫でしょうとのことだった。 弱いけど強気なのか・・・

調子悪いときのために

調子悪いときにいれておくとよいもの。なお、病気かどうかは素人判断が難しいので、 適宜詳しい人、例えばお店の人に聞いてみるのがよいと思う。

種類 品名 URL
水を酸性にするやつ マジックリーフ https://www.amazon.co.jp/gp/product/B00UF458D0/
塩水を作るための塩 伯方の塩 1kg https://www.amazon.co.jp/gp/product/B000FQOJ7O/

以下、多少の補足。 淡水魚なのに塩とは、ということを考えるかもしれない。ここで塩を入れる理由は、魚の浸透圧と水を揃えることで、 体内の水分調節機能に使う体力を保つことができる、ということらしい。 詳しくはこのあたりを読もう。

運用

サマリは以下の通り。やることはほとんどない。

頻度 やること ひとこと
毎日 餌やり、ライトのON/OFF 魚が1日を感じられるよう、ライトはきちんとON/OFFする
3~4日に1回 水替え ベタ1匹でフィルタつけてるなら1週間くらいは引っ張ってもよい
2~3週間に1回くらい フィルタ交換 適当でよいと思う
気が向いたら 水槽全洗い 藻にまみれてどうしようもなくなったとき

毎日やること

1日の流れはこんな感じで、やることはほとんどない。可愛く泳いでいるところを眺めよう。 ベタは賢い魚なので、餌をあげようとする寄ってきてくれる。 夜、明るい水槽をぼーっと眺めてると時間が過ぎるのを忘れられる。

    • ライトを付ける
    • 朝ごはんをあげる
    • 晩ごはんをあげる
  • 寝る前
    • ライトを消す

3~4日に1回やること

ベタは多少水がきれいでなくても耐えられる強い魚だけど、 病気にならないように適度に変えておくのがよい。

手順は以下。

  1. 水槽の水を半分くらいホースで抜く
  2. 新しい水を作る
  3. ある程度水温を合わせた後、水槽に入れる

水替えの際は、水槽の水を全部入れ替えるのではなく、 水槽の半分の量の水を入れ替える。水の量を絞るのは、 水質を大きく変えないようにすることが理由である。 水質が大きく変わると魚のストレスになるそうだが、 ベタは強い魚なのであまり気にしなくてもよいらしい。

現在

こんな感じで苔にまみれているので、 次回は水槽の水を全部抜いてきれいにする回です。 f:id:nbisco:20191205103046j:plain f:id:nbisco:20191206161001j:plain

How do you like *** ?

この記事は圧倒的令和ッ!!ぴょこりんクラスタ Advent Calendar 2019のために書いたものです。 このAdvent Calendarが何なのかについては、主催者による紹介記事を見てください。

はじめに

録画データを整理していたら、水曜どうでしょうを録画していたことを思い出した。 録画するだけして満足してしまうパターンで、これまで触れてもいなかったが、 久しぶりに見てみると案外展開を覚えていて、同窓会で思い出話をしているような気分になった。 そんな気分のなか、ふと思い立って死蔵していた日記を手直しして放流することにした。

これは、当時大学生だった自分が、水曜どうでしょうが好きなお友達と集まって、サイコロの旅をやった話である。

第0投

サイコロの旅とは、低予算・低姿勢・低カロリーをモットーにしていた*1水曜どうでしょう」というバラエティ番組の企画である。 この番組の起源は今から約14年前*2に遡る。 この企画は東京をスタートして北海道を目指すもので、行き先及び交通手段はサイコロをふって決める。 あさっての方向に深夜バスで向かってしまい、いろいろ大変なことになる大泉洋鈴井貴之の リアクションを見ることが面白い企画である。

今回の旅はこの企画を下敷きに、大学生が手の届く範囲に改変している。 以下にルールを簡単にまとめる。

  • 移動は明治のサイコロキャラメルの出目に従う
  • 移動手段は青春18切符であるが、時と場合により色をつけてもよい。
  • 目的地は東京、スタート地点はサイコロを振って決める(スタート地点までは深夜バスで移動)
  • 2010/09/01スタートで、2010/09/03の終電までに家につくこと

旅のメンバーを紹介しよう。

名前 ひとこと
T 行き先候補を決めるディレクター担当。京都と旧国鉄が好き。
P 行き先候補を決めるディレクター担当。食べ放題に行くと、こちらが心配になるくらい食べる。
N 今回は家を守るために旅自体は不参加だが、サイコロの初投だけ参加。
S 運良く途中で合流した後輩。バスに乗ろうとして肘をぶつけてしまい、2針縫った。
ビスコ 作者。

第1投

もうそろそろ19時になろうかとしているというのに、外はまだまだ蒸し暑かった。

僕らはサイコロをふるべく、大学構内通路の照明が明るい場所へ移動した。 第1投は、家を守るため無念にも欠席することになった Nが担当する。スタート地点を決める重要なサイコロであるため、 N以外は若干緊張の表情をしていた。

行き先候補は以下の通り。サイコロを降る際はかっこ内は伏せていたので、 5以外はどこに連れて行かれるのかわからなかった。 出目5のブルーメッツ号は本家で出ていたこともあり、行き先がわかっていた。

  1. どこ?:シリウス号(東京駅→青森県八戸市)
  2. 平和そうなちょうちょ:パピヨン号(新宿駅名鉄岐阜)
  3. 何となくわかる:マスカット号(新宿駅→岡山)
  4. 砂漠の気配がする:キャメル号(浜松町駅米子駅(鳥取県))
  5. これだけは出してはダメ:ブルーメッツ号(新宿駅高知駅)
  6. バス名だけでは皆目わからない:夕陽号(東京駅→酒田(山形県))

Nの出した目は5であった。Nは出目については特にコメントなしで、 にこにこしながら扉視点で書かれた詩(プロペルティウス第1巻16番)について唐突に語り始めた。 20:30新宿発のバスに乗るには、もう殆ど時間の余裕はない。プロペルティウスはさておき、 新宿に向かった。

新宿駅に到着後、Nは嬉々として迷うことなくバスターミナルへと僕らを導いていった。 結果、無事に20:15に切符売り場に到着し、20:21に切符購入完了した。 席が連番で、しかも3つだけ空いてたときには出来すぎていてショックを受けた。 バスを待っている隣で、Nはものすごくにこにこしていた。

バスは4列シートで狭く、しかもフットレストはTと共用。 しかも隣のおばさんがいびきをするわ、寝ぼけてヒジ打ちをかましてくるわで、 眠れない夜を過ごす羽目になった。Tもなかなか眠れないようだったが、Pは憎たらしいことにぐっすり寝ていた。

第2投

9月2日午前7時、ブルーメッツ号は高知駅へのそのそと入ってきた。 涼しくてさわやかな朝である。

第2投の目は以下の通り。徳島以外は当たり目であるが、高知はあまり交通の便がよくないのか、 こうでもしないと家に帰れないというのがTの言であった。

  1. チャンスタイム 少しだけ特急:神戸
  2. 起死回生 少しだけ特急:岡山
  3. まだまだいける 少しだけ特急:高松
  4. 広島県突入 少しだけ特急:福山
  5. のんびり高知 各駅停車で:岡山
  6. 四国満喫:徳島

第2投は僕が担当した。無難に1の神戸を出して四国脱出である。 電車は7:30発のため、高知滞在は30分となった。 朝ごはん代わりに、駅の売店かつおめし(150円)を購入した。

高知駅から土佐山田駅まで各停で向かい、 土佐山田駅から大歩危駅まで特急南風に乗った。 特急だけあって乗り心地がよく、その上眺めもよかった。 旅のなかで一番まともな椅子だったと思う。 お金を稼ぐようになったらこういう列車で旅ができるといいなあ、とか、 深夜バスには2度と乗らないとかいう会話をしていたように記憶している。

最高の贅沢は時間をゆったり使うことだと思う。 特急の後は1両だけのほぼ貸しきり電車でのんびりと山の中を進んでいった。 緑鮮やかな大歩危の渓谷はとても美しい。 川の近くまで行けるとよかったのだけど、もちろん時間はないので眺めるだけである。

第3投

神戸の乗り換え時間が少ないため、第3投は前倒して阿波池田駅で行うことにした。 阿波池田駅は特急の止まる比較的大きな駅ではあるが、駅前の商店街はシャッター街で人影はない。 駅横の旅行代理店「ワープ池田支店」がやたら存在感があった。

第3投の目は以下の通りで、Tが出した目は1。

  1. 映画村:太秦(京都)
  2. 何があるかわからない:播磨新宮(兵庫)
  3. さあ帰ろう:米原(滋賀)
  4. マスカット:倉敷(岡山)
  5. もっとがんばろう:浜松(静岡)
  6. 四国が僕を呼んでいる:高松(香川)

無難に東へ進めていて、みんなのテンションも高いままで維持できていた。 偶然にも後輩Sが坂出駅で合流することになった。 Sは小豆島観光の帰りのようで、デジカメのメモリは石垣の写真でいっぱいになっていた。

昼食は岡山駅で食べた。デザートにジェラートを食べ、観光気分を味わいながら、 僕らは一路太秦へ向かった。なお、乗り換えの都合で神戸の滞在時間は約20秒であった。

第4投

日も傾いてきた18時ごろ、太秦に着いた。駅前の公園でPがふったサイコロの出目は4であり、 無事に京都泊が決まった。疲れのためか、Tのテンションがものすごく下がっており、 「もう電車乗りたくないよ・・・」と口走ってしまうほどであったため、一安心である。 ちなみに他の目は以下の通り。

  1. 少し戻る:大阪
  2. 飛行機見よう:泉佐野
  3. 千年の都:京都
  4. 千年の都:京都
  5. 滋賀の温泉:雄琴
  6. まだまだ進む:岐阜

晩ご飯のお店を探しつつ、料亭街を通り抜けた。 右を見ても左をみても高級料亭で、適当な格好のぼくらはとても浮いていた*3。 そんな僕らにも律儀にいらっしゃいませと言ってくれる料亭の人は人間ができているのか、 おなじみの京都ムーブなのかはわからなかった。 晩ご飯はT御用達の鍋・・・はちょっと予算的に厳しかったので、階下の飲み屋で食べた。 京都だからか、はもの天ぷらと冷奴が特においしかった。 はもの天ぷらは塩で食べるのがおいしく、冷奴は何もかけなくても楽しめた。

食事中に、Sが自慢の石垣写真を披露してくれた。 陰影のコントラストがきりっと効いている写真だった。そして石垣自体もなかなか見ごたえがあった。 石垣って馬鹿にできない。

宿ではディアゴスティーニについての会話が盛り上がった。 スターウォーズ博士のT曰く、ディアゴスティーニスターウォーズ大全集*4は、 最初に貰えるバインダーだけでは足りず、追加でバインダーを2冊くらい買わないと入りきらないらしい。 全集にはモブキャラに関する細かい設定まで書かれており、例えば、 エピソード4のモスアイズリーの酒場で一瞬だけ出てくる宇宙人が、後に反乱軍にパイロットとして入り戦死した、という設定も書かれているとのことである。

第5投

特に寝坊をすることもなく、無事に起きて京都駅でサイコロを振った。 サイコロの目は1で、奈良県王寺行きである。他の目は以下の通りで、 伊賀上野と、西行きの相生が地雷であった。

  1. 和(やわらぎ)の鐘が鳴るまち:王寺
  2. 北陸へGO:敦賀
  3. ダッシュはしない:大垣
  4. 忍者:伊賀上野
  5. 東へ、東へ。:浜松
  6. 新快速って速いですね。:相生

Sに見送られ、ぼくらは通勤ラッシュの電車へと乗り込んだ。 電車内では3人とも体力回復に努めた。 昨日のブルーメッツ号の毒牙は、僕らから想像以上に体力を奪い取っていた。 途中で意識を取り戻した僕は、ぼけーっと外を眺めていたが、お寺は全く見えなかった。 のどかで単調な風景が続いていた。

第6投

王寺でのんびりとサイコロを振った。3を出して鶴橋行きである。 近畿ばかりが出てしまい、T、Pの二人は若干の焦りを感じていた。近畿に囚われているのかもしれない。 他の目は以下の通り。松坂、近江塩津は危険な目であった。

  1. 和歌山一歩手前:関西空港
  2. 大阪、米原経由:近江塩津
  3. 絶景!近鉄奈良線経由:鶴橋
  4. 霜降り牛:松坂
  5. 関西線経由:名古屋
  6. 東海道線経由:名古屋

ゲームオーバーの影に怯えつつも、僕らは近鉄で一路鶴橋へ向かった。 手前の田園風景と、奥の山々の起伏とで、近鉄奈良線は眺めが素晴らしかった。 他の乗客が結構乗っていたため会話は少ないが、各々結構楽しんでいたようだ。

思ったより随分と観光をしている。もっと殺伐とした移動ばかりの旅になると思ったが、いいことだ。

第7投

昼食を目の前にして第7投。まだ500km以上残っているので不安が隠せない。 目は以下の通りで、期待は5もしくは6。

  1. 魚とみかん:和歌山
  2. ひこにゃん彦根
  3. 丹波路:篠山口(※深夜バス)
  4. 湖の西:堅田(鮒が待っているはず)
  5. 言わずもがな:八事日赤(サボテンスパ)
  6. とりにく:茨木(ケンタッキー食べ放題)

振ったのは誰だったか忘れてしまったが、無事に6を出して、 大阪は小野原の当時日本で唯一のケンタッキー食べ放題へと行き先が決まった。 が、どのバスに乗ればよいかわからない。 バスの運転手に系統を聞こうとしたら、冷たくあしらわれて途方にくれるも、 たまたま出くわした優しいおばちゃんにどのバスに乗ればよいかを教えてもらい、 なんとか辿り着くことができた。

食べ放題の内容は、フライドチキン以外にも フライドポテトやチキンナゲット、野菜(レタスとキャベツ千切り)、お米、 ドリンクバー、スープがついて、1200円で1時間であった。 フライドチキンはおいしいのだけど、何本も食べているとさすがに まとわりつく油分が気になる。烏龍茶を飲んでも油は落ちなかった。 結局、15分ほどで限界を迎えた。記録は4ピースだった。

大食いのPは黙々と食べ続けており、暇なので、旅の成功を祈って紙ナフキンで人形を作った。 紙ナフキンだけを使ったにしては結構うまくできていると思う。 f:id:nbisco:20191204145508p:plain

以下の図はPが食べた跡で、記録は8ピースだった。 f:id:nbisco:20100903130712j:plain

第8投

夏の厳しい日差しの中、満腹のPがサイコロを振った。 Pの出した目は2。静岡行きだ。 他の目は以下の通り。福井が2個あるのは、誰かの実家だったからだと思う。 ゴールに無事近づいてきて、一安心。

  1. GOAL一直線:東京
  2. 東海道:静岡
  3. 五十三次:浜松
  4. ゲームオーバー:福井
  5. ゲームオーバー:福井
  6. ゲームオーバー:塩尻

第9投

静岡で再びSと合流した。冷静に考えてなぜ合流できるかわからないが、 わざわざ合流してくれるのはありがたいことである。 最後かもしれないサイコロは、ディレクター的位置のTが投げることとなった。 目は以下の通り。みんな疲れていて、早く帰りたい気持ちでいっぱいだったので 大サービスな目である。

  1. さあゴールだ!:東京
  2. さあゴールだ!:東京
  3. さあゴールだ!:東京
  4. さあゴールだ!:東京
  5. まだ終わらんよ:三島
  6. 魚とともに爆死エンド:焼津

Tは無造作に投げた。サイコロの出した目は6で、魚とともに爆死エンドであった。ここで1/6を引くか。 よくがんばって高知からここまで帰ってきたなあ、っていう感慨が1/3、 終わってしまう寂しさが1/3、ようやく帰れるというほっとした感じが1/3、 というところで、結構あっけない終わりだった。

終わる場所が焼津というのも何だかしまらない気がするけど、終わりは終わり。 移動距離は約2000kmほどであった。

おわりに

振り返って懐かしめるので、文字として残しておいてよかったと思う。当時の旅行仲間とは全く連絡を取らなくなってしまったけど、元気だろうか。

実はこのあと同じメンバーで聖地平岸公園から東京へ戻るサイコロの旅をやったんだけど、そのときの日記データは見つからなかった。幸いにも多少は覚えているので、来年のアドベントカレンダーにでも。

*1:昔の話である。今は高姿勢・高カロリーになっている

*2:1999/09/12にロケ開始

*3:前から来る人は浴衣もしくはスーツ

*4:設定資料のみ。フィギュアとかなし。

30日でできる! OS自作入門の1~18日目

この記事は圧倒的令和ッ!!ぴょこりんクラスタ Advent Calendar 2019のために書いたものです。 ちなみにこのAdvent Calendarが何なのかについては、主催者による紹介記事を見てください。

はじめに

コンピュータをかじったことがある人間であれば、誰しも1度位はOSとかコンパイラを作ってみたいと 思ったことがあるだろう。ただ、実際に作る人はそんなに多くない。 自分自身はと言うと、時折発作のように思い出しては今更かなと思って何もしないクズ系ワナビーである。 そんな折、たまたまAmazonで"30日でできる! OS自作入門"が半額セールで買えたので、 これをひととおりやってみることにした。つまり、本記事はこれの作業記録である。

環境用意

あまりがんばらなくても用意できるものでやるという方針のもと、以下とした。 基本的な作業は、Virtualbox上のManjaro Linuxでやる。

以下、x日目は、 本の上での日数であり、実際の作業時間とは一致しない。

また、リポジトリは以下である。 github.com

1日目

Vimバイナリエディタとして使おうとして拾った設定がうまく動かずじたばたした。 拾ったやつはBufWritePreの%!xxd -r後に| endifが書いてあったんだけど、 それだと!の引数として解釈されるようで正しく動かなかった。 全部書いて:wqしたら、Command Not Foundだけ書いてあるファイルが出てきてつらくなった。

以下は正しく動く版のもの。

"バイナリ編集(xxd)モード(vim -b での起動、もしくは *.binファイルを開くと発動)
augroup BinaryXXD
    autocmd!
    autocmd BufReadPre  *.bin let &binary =1
    autocmd BufReadPost * if &binary | silent %!xxd -g 1
    autocmd BufReadPost * set ft=xxd | endif
    autocmd BufWritePre * if &binary | %!xxd -r
    autocmd BufWritePre * endif
    autocmd BufWritePost * if &binary | silent %!xxd -g 1
    autocmd BufWritePost * set nomod | endif
augroup END

バイナリファイルはとりあえず全部書いてみた。 バイナリファイルを作成するアセンブリコードについては、 バイナリファイルを読んでアセンブリコードを吐き出すスクリプトを作り、 写経したことにした。本に従って、アセンブラIntel形式で書き出した。

作ったイメージファイルは、Virtualboxに仮想フロッピーディスクとして認識させたら普通に動いた。 もっと苦労すると思ったけど、案外あっけない、hello world

f:id:nbisco:20191203223039p:plain
1日目

2~3日目

イメージの作り方がわからない。しかし、同じことをやっている人はたくさんいて、 その中でもきちんとログを残してくれた偉大な先人Makefile等を参考になんとか実施。 本では、スクリプトの中身の解説はまだなので、理解する前に写した。 画面はまっくらだけど、hlt命令を実行しているだけなので、これで正しい。

f:id:nbisco:20191203223138p:plain
2~3日目

4日目

Win98みたいなツールバーが出せるようになった。結構あっという間に画面の大枠が出来てしまった。

f:id:nbisco:20191203223219p:plain
4日目

ところで、なぜ第1引数がESP + 4なのか?それは単純でx86のCalling Conventionによるものであった。 32bitに関して言えば、ESP + 0は戻り先アドレス、ESP + 4は最左の引数、ESP + 8は次・・・みたいな感じで積まれるようである。 ここを参考にした。

5日目

フォントを手作りして、何か表示する回。 途中、sprintfがなくて困る。gcc-multilibを入れてもstaticにリンクできなかったので、 ここからsprintfを拝借した。 最初は小さいlibc(muslとか)をリンクすればいいかなと思ったけど、 ほしいのはsprintfだけだったので止めた。

また、手作りフォントについては、ここを参考に、pythonスクリプトをえいやで作ってなんとかした。

真ん中の数値は、緑画面の中央点の座標を表している。

f:id:nbisco:20191203223330p:plain
5日目

6日目

キーボードからの割り込みを拾ったよ、ということを表示する回。内容ではまるというよりは、Makefileではまる。 haribote.sysをddする際、countが正しく指定されていないことが問題で、原因はワンライナーの計算方法だった。 Makefileの変数内の$マークをエスケープ($を$$に置き換え)して、0.5足して、小数点以下切り捨てることで対応。

f:id:nbisco:20191203224035p:plain
6日目

7日目

キーボード入力とマウス入力を拾って、単にそのまま生の値を表示する回。 矢印は動かないし、自由に文字を打てないが、入力を拾えるようになったのは嬉しい。

定数をマクロに置き換えた際に写経ミス(8で割るのを忘れた)発生により、動作せずにしばらくはまった。 デバッガがないせいで原因がよくわからず、発見まで時間がかかった。デバッガがないのは本当につらい。 これ以外は特に問題なかった。

f:id:nbisco:20191203224532p:plain
7日目

8日目

マウス入力を拾って、どのボタンが押されたか、どちら向きに移動したか、矢印が今どこに いるかを表示する回。

マウスの矢印が動き始めたので感慨深い。拝借したsprintf関数が負の数に対応していなかったので修正した。 ふと思ったんだけど、BIOSでUSBキーボードが使えるということは、BIOSそのものがUSBドライバとキーボードドライバを持ってるってことなんだよな。OSのサポートなしでドライバ作るなんてBIOSメーカも大変だなあ・・・

f:id:nbisco:20191203224858p:plain
8日目

9日目

メモリ管理ができるようにして、メモリ総容量と現使用量を表示する回。 ただ、矢印がメモリ容量の文字のところに重なると、文字が消えてしまう。。。

memtest_subについては、Cでもvolatileをつければ大丈夫。ただし、今使っている gcc 7.4.0では、xor命令ではなくnot命令として出力されている様子。

f:id:nbisco:20191203225200p:plain
9日目

10日目

矢印が文字の上を通っても消えなくなるように、描画方法を工夫する回。

描画の重ね合わせ処理でメモリ管理関数を使ったが、特に問題なし(写経しているだけなので当然といえば当然なんだけど)。 マウスの矢印を動かしても、下の文字が消えないというのは結構感動する。何より、 動いているものをグラフィカルに見られるというのはよいもので、やったかいがあると思える。

f:id:nbisco:20191203225615p:plain
10日目

11日目

Windows98を思い出すウインドウを作り、その中でカウンタを表示する回。

カウンタにリーディング0がほしかったので、sprintf関数を修正した。 難しいところはなかったけど、しょうもない写しミスで苦労した。 手書きで写しているから、こういうミスがあると大変なんだよなあ・・・ ウインドウといっても、まだ動かしたり閉じたりはできないが、ずいぶん形になってきた。

f:id:nbisco:20191203225818p:plain
11日目

12日目

タイマー割り込みを使って、カーソルの点滅や、時間カウンタを実装する回。

8254タイマは初めて使ったけど、シンプルでわかりやすい。 今はもっぱらLocal APIC + TSCだから使う機会がない。HPETですら使わないんだもんね。 タイマーが使えるようになって、より一層OS感が出てきた気がする。

f:id:nbisco:20191203230022p:plain
12日目

13日目

割り込み周りの性能を改善をする回。 具体的には、割り込みハンドラごとに用意していたバッファを1つにまとめたこと、 バッファのデータ長を1バイトから4バイトに変えたこと。特に問題なし。

f:id:nbisco:20191203230351p:plain
13日目

14日目

解像度を大きくし、テキストボックスを作ってみる回。

解像度を変えられる(動的にではないけど)とぐっとOSらしくなってくる。 今まで320x200でやってた分、1024x768になるとめちゃ広く感じる。 左クリックすると、矢印の位置にウィンドウが移動する。左クリックをしたままだと、 ウィンドウがそのままついてくる。

ウィンドウを動かすこともできるようになったし、いよいよOSらしくなってきて 盛り上がってきた。

f:id:nbisco:20191203230754p:plain
14日目

15日目

マルチタスクにする回。

ついにマルチタスク!と言っても、まだスケジューラを用意したわけではなく、 一定周期で2つのタスクを切り替えるというもの。シンプル。

f:id:nbisco:20191203231117p:plain

16日目

複数のタスクの切り替え、タスクごとの優先度付けをできるようにする回。

優先度の付け方はLinuxでいうところのSCHED_FIFOに近い。 優先レベルごとにグループを作成し、動作可能なプログラムが存在するグループのうち、 優先レベルの最も高いグループ内で 優先度に従ってスケジューリングを行う。 優先レベルの低いグループに属するプログラムは動作させない。

今回は構造が変わるところが多く、複雑なので、こまめにコミットするようにした。

図では、4タスク(タスクA、タスクB0~B2)動作させているところ。 タスクB0への割当時間を1とすると、タスクB1への割当時間は2、 タスクB2への割当時間は4となるようにしている。 カウンタもだいたい合ってそうだよね。

f:id:nbisco:20191203231533p:plain
16日目

17日目

コンソール画面を作って、キーボード入力をできるようにする回。 tabを押すことで、タスクの切り替えもできるようになった。

これまでアルファベット大文字と数字だけだったのが、 アルファベット小文字、記号も入力できる。小文字と記号を入力できるように、 shiftキーをサポートし、ついでに*Lockをサポートした。 まだEnterキーは未サポート。

f:id:nbisco:20191203231857p:plain
17日目

18日目

Enterキー、画面スクロールのサポートと、コンソール用コマンドを作成した回。

Enterキーをサポートし、コンソール画面もスクロールができるようになった。 文字を打つだけでなく、 3つのコマンドも定義したので、 コンソールもそれっぽくなってきた。

  • mem: 全メモリ量と使用可能メモリ量の表示
  • cls: 画面のクリア
  • dir: FAT32メタデータを読んでファイル名リストの表示

コマンド入力するのに、strcmpが欲しくなったので自作。また、dirコマンドはFAT32を直接読むので、 これまでみたいに適当にやるのはダメである。ということで、 再度偉大な先人の記事に習って、 ディスクイメージ作成にddではなく、mformatコマンドとmcopyコマンドを使うようにした。

f:id:nbisco:20191203232304p:plain
18日目

19日目以降

そのうちやるつもり。

おわりに

手を動かして物事を理解する、というのは大変楽しいですね。

ソフトウェア工学素人がソフトウェアテストについて調査する

この記事は圧倒的令和ッ!!ぴょこりんクラスタ Advent Calendar 2019のために書いたものです。 ちなみにこのAdvent Calendarが何なのかについては、主催者による紹介記事を見てください。

この記事について

何を思ったかソフトウェアテストについてちょこっと調べたので、その結果をまとめる。

はじめに

ソフトウェアテストは、趣味でコード書いていたりするとあまり関わらない分野であると思う。 自分の場合、過去に家計簿システムを作ったが、そこでも特にテストらしいテストは書かず、 つど適当にデバッグして終えた。

しかし、テストを書かなくていいのは趣味の範囲までである。 ソフトウェアを製品として送り出す場合、品質を保証するという観点からテストは欠かせない。 品質が特に重要な場合、ISOのような標準規格でどのようなテストをしなければならないかを定められていることも有る。 例えば、自動車機能安全規格ISO26262では、ユニットテストにおいて、C0カバレッジ、C1カバレッジ、 MC/DCを100%達成する必要がある*1。 自動車ほど頑張らないかもしれないが、それでも似たような基準を満たす必要があるところは多いだろう。 ちなみに、C0カバレッジ、C1カバレッジ、MC/DCの意味は以下の通り。

  • C0カバレッジ: 全ての命令、つまり、全てのソースコードの行のうち、少なくとも1回実行されたものの割合。
  • C1カバレッジ: それぞれの判定における、それぞれの条件で、全て可能な結果を少なくとも1回は取ったものの割合。
  • MC/DC(Model Condition Decision Coverage): 以下を満たす*2ものの割合。
    • プログラムの全入口/出口を少なくとも1回はテストすること
    • プログラムの判定に含まれる全条件は可能な値を少なくとも1回はテストすること
    • プログラムの全判定は可能値を少なくとも1回はテストすること
    • プログラムの判定の全条件は判定の出力に独立して影響することを示すこと

これらの基準を満たすようなユニットテストを人間の手で書くのは大変である。 極端な例だが、以前少し話題になったこのソースコードを 見てみれば、上記の条件を満たすことが結構大変かもしれないと感じられるかも知れない。 要は、条件分岐が多いような複雑なソースコードの場合、そもそも人手でユニットテストを書くというのは重労働だ。 ユニットテストですら重労働、いわんや結合テスト(関数単体でなく、必要に応じて関数を結合してテストを行うこと)、統合テスト(システムとしてテストをすること)をや、というのは想像に難くない。 重労働なんて定性的なことを言っても仕方ないので数字を出すと、 ソフトウェア開発データ白書2018-2019によれば、 ソフトウェア開発にかかるコストのうち、だいたい4割超がテスト(結合テストと統合テスト。ユニットテストは分類にないので、設計工程に含まれている?) に割かれている。半分くらいテストしているというわけだ。

今回は、こんな大変なテストで楽をするための技術について調べた結果をざっとまとめる。

ソフトウェアテスト技術の分類*3

ソフトウェアテストと一口に言っても、目的は様々である。 ユニットテストはその部品が期待通り動作するか、結合テストはあるユニットが他のユニットと連動した際に 期待通り動作するか、統合テストは、ユニットをシステムとして組み上げたときに、期待通りの動作ができるか、など。 他にも、実際に意図通りに動作するかを顧客にテストしてもらう受け入れテストや、期待通りの性能が出せるかの性能テストなんてのもある。 偉大な先達は、これらの共通点を"observing a sample of executions"と表現し、 以下のとおり4W2Hで整理してくれた*4

  • WHY: なぜやるのか?バグを見つけるためなのか、リリース判定するためなのか、はたまたUIのユーザビリティを見るものか?この観点は、 テストオラクル(多少不正確かも知れないがテストの期待値と言い換えてもよいはず)の生成技術に関わるもの。
  • HOW: どのサンプルを観察するのか、また、そのサンプルはどうやって選ぶのか?この観点は、テストの入力をどうするか、 どうやってテストをするのか、いくつかあるテストのうち何を選択するか、の技術に関わるもの。
  • HOW MUCH: サンプルをどれくらい取ればよいか、また、得たサンプルのうちどれくらい採用すればよいか?この観点は、 テストの選択、停止ルール、十分性評価の技術に関わるもの。一般には、カバレージ分析や信頼性測定がよく使われる手法。
  • WHAT: 何を実行するか?一部に注目して実行するか、または全体を通して実行するか?この観点は、 テストの粒度を決める技術や、大きなシステムをテストできるようにするスタブなどのテスト支援技術に関わるもの。
  • WHERE: どこで実行するか?開発現場か、シミュレーション環境か、はたまた実環境か?何を実行するかとも関係が ある観点。この観点は、組み込みソフトウェアのテストに特に関わる。
  • WHEN: プロダクト・ライフサイクルのどこでやるか?一般には早く実施するほど、問題への対策が低コストで済むと 言われているが、実環境でなければわからないこともある。

今回は、HOWの観点のうち、特にテスト自動化技術に着目する(というか調査したのがここというだけで、 他が重要でないというわけではない)。

テスト自動化技術について

テスト自動化技術は、さらに以下の3つに分類できる。

  • テスト実行・結果確認の自動化
  • テスト環境構築の自動化
  • テスト入力生成の自動化

御存知の通り、完全なるテスト自動化は未だ達成できていない。 しかし、ユニットテストに関しては技術開発が進んできており、一般に使えるツールもそれなりにある。 例えば、テスト環境構築の一部*5とテスト実行・結果確認を支援してくれるツールとして、 xUnitフレームワークや、 Google Testが挙げられるだろう。

テスト入力生成の自動化はというと、こちらは現在も活発に研究がなされている。 テスト入力生成には3つのアプローチがある。

  • ランダムベースのアプローチ: ランダムに入力を作るアプローチ。DART*6と呼ばれる技術が 有名。DARTでは、関数のインタフェースを静的解析技術で抽出し、ランダムに生成したテストケースを入力して自動でテストを行う技術である。
  • モデルベースのアプローチ: ソフトウェアの振る舞いモデルや、仕様の形式記述をベースにテストを生成する技術*7。 このアプローチでは、シンボリック実行と呼ばれる技術が有名。シンボリック実行は、ソースコードを静的解析して実行パスを抽出し、各パスを通すにはどのような入力を与えればよいかを SATソルバを用いて求めることで、テスト入力を生成する*8。 シンボリック実行では、実際にソフトウェアは実行されず、あくまで形式的に検証する。網羅性という観点では大変効果的な手法であるが、 経路数の爆発等で実適用への大きな壁がある。経路数の爆発を抑えるため、一部の入力をランダムベースのアプローチで生成するコンコリックテスト(シンボリック実行に、一部具体的な値を用いて 実際にプログラムを動作させる)と呼ばれる技術の研究が行われている。 シンボリック実行の他にも、有界モデル検査(モデルの状態遷移を一定範囲に抑えて検査する技術)を利用してテスト生成する技術もある*9
  • サーチベースドソフトウェアテスティング: 何らかの評価関数(例えば、C1カバレージ)を予め定義し、それがよくなる方向に入力を生成する技術。入力生成には、遺伝的アルゴリズムのような メタヒューリスティクス*10を 応用している。

今回調べたのはサーチベースドソフトウェアテスティングのため、以降はこれについて述べる。

サーチベースドソフトウェアテスティングの現在

サーチベースドソフトウェアテスティング(長いのでSBSTと略す)の実装のうち、最も有名なツールの1つはEvoSuiteと言えるだろう。 EvoSuiteは、Java向けのユニットテストを生成してくれるツールであり、コンペでよい成績*11を残している優秀なツールである。 EvoSuiteはチュートリアルも充実しているため、Javaほぼ初心者の自分でも、チュートリアルを1から順にやっていくだけで簡単にユニットテストが自動生成できる(なので、この記事中で使い方に関するものは記載しない)。

EvoSuiteは優秀であり、ソフトウェアテストを作成するための作業時間を短縮できるという結果も示されているが*12、 EvoSuiteが苦手とすること、改善すべきこともまだまだたくさんある。いくつかを抜粋したものを以下に箇条書きで示し、関連しそうな最近の研究についても軽く述べる。

  • 評価関数の最適化方法の改善
  • マルチスレッドのような並列動作プログラムのテスト生成
  • 現実のバグを見つけること

評価関数の最適化方法の改善

SBSTは、すごくざっくり言えば、評価関数の出力をよくするように入力を調整する技術だと言うことができる。 Generating Test Input with Deep Reinforcement Learningでは、 その最適化に強化学習を応用したものが報告されている。ただ、現時点ではものすごく効果が出たというわけではなく、定式化をして簡単な評価をするにとどまっている様子。

マルチスレッドプログラム向けのテスト生成

マルチスレッドプログラムは、当然ながらシングルスレッドプログラムよりも設計・テスト作成が難しいので、 マルチスレッドプログラム向けのテスト入力生成技術も研究されている。 Effectiveness and Challenges in Generating Concurrent Tests for Thread-Safe Classesでは、 世の中にある並列動作プログラム向けのテスト入力生成ツールについて、現実のバグを見つけられるかどうかを評価した論文である*13。 論文で評価した技術を以下に箇条書きでまとめる。並行動作するプログラムの動作パターン数の爆発をどう抑えるかというところでみんな苦労している。

  • 評価対象の分類とツール名
    • random based techniques:ランダムな関数コールシーケンスと入力を生成し、テストするアプローチ。 テストオラクルには、linearizability*14を利用。 難しい解析をせずに入力が作れるところが利点。欠点は、ランダムに入力生成するので、狙ってケースを作成できない点である。
      • BALLERINA(ICSE 2012): 計算量を減らすために、同時に動作するスレッドは2つだけ、かつ、スレッド間で共有するオブジェクトは1つだけ、という仮定を置いてモデル化。 さらにテストオラクルをクラスタリングし、判定にかかる計算量を減らした。
      • CONTEGE(PLDI 2012): 基本的にはBALLERINAと同じだが、こちらはlinearizabilityをうまく判定する機構を作った様子。BALLERINAよりもfalse alarmを減らした。
    • coverage based techniques: ランダムに生成していると冗長なパターンが増えて効率が悪いので、 重複しないように、つまり、スレッド間のインターリービングパターンのカバレージを増やすようにテストケースを生成するもの。 なお、このインターリービングカバレージの計算の効率化が技術課題。そもそもカバレージ計算が難しく、考慮しなければいけない事項が落ちがちというのが悩みどころ。
      • consuite(ICST 2013): EvoSuiteを拡張し、並行テストの生成をできるようにしたもの。カバレージとして満たすべきところを 統計的に算出し*15、テスト対象を絞るもの。 共有メモリのコンテキストを考慮しないため、特定のケースのエラーしか報告できない。また、共有メモリへのアクセス順序が保証できない。
      • AutoConTest(ICSE 2016): consuiteの改善。共有メモリのコンテキストを意識したインターリービングカバレージ計算ができるようになった。
      • covcon(ICSE 2017): 並行実施されるメソッドペア集合の頻度情報を収集。特に頻度の低いものについてテストを生成することで高速化。
    • sequential-test-based techniques: 検出するバグの種別を絞ることで計算量を減らすアプローチ。 並列動作を並列動作のままモデル化するのではなく、直列化*16をしているので、 モデル化としては不十分というところがつらい点。また、こういうモデル化をしたとしても、計算は相変わらず大変である。
      • OMEN: deadlock検出
      • NARADA: データ競合
      • INTRUDER: atomicity違反
      • MINION: assertion違反

評価の結果、上記のどれか1つでもバグを検出できた件数は、8件/47件であった。原因分析の結果は以下の通りで、なかなか厳しい。

  • 原因1: 現実と仮定が合っていない。いずれも2つのメソッド、1つの共有オブジェクトという仮定をおいているが、現実と離れている。
  • 原因2: 環境依存。DB接続とか、固有のファイルが必要とかでバグが再現しない。concurrentな環境だと mockがうまく使えなかったりするらしい。
  • 原因3: wait-notify機構に未対応

現実のバグを見つけることについて

マルチスレッドプログラムのバグを見つけるのが難しいことはわかったが、シングルスレッドプログラムではどうか? そんな疑問に答えてくれるのがUsing Search-Based Test Generation to Discover Real Faults in Guavaである。 この論文では、EvoSuiteを用いて、Google作のJavaライブラリであるGuava*17のリアルバグを検出できるかどうかを評価した。 結果、3件/9件のバグを検出できた。検出できなかった原因の分析は以下の通り。

  • 入力に特殊な値が求められるもの(論文中の例: 1文字の文字列に対して、マッチしない正規表現パターンを適用してsplitしようとすると、空文字列が返ってくる)
  • 特定のデータ型でのみバグが発現するもの
  • 複雑なクラスのインスタンスが入力として与えられるもの
  • 特定のメソッドコール列が必要なもの(論文中の例: 優先度付きキューに対し、add/removeを繰り返していると、正しいものがremoveできなくなる)

試しに、"1文字の文字列に対して~"のを見てみたが、 人間がソースコードを見ても理解するのが大変であった。そもそも、何が特殊かを判断する基準をどう定義するかが難しい問題であり、 これを見つけるのは難しいだろうなあ・・・

終わりに

今回の記事では、ソフトウェアテスト、特にテスト入力自動生成について軽く調べた結果をまとめた。 テスト自動生成は夢があるが、まだ道半ばと言ったところ。いつか、テストを勝手に作れるようになる日は来るかなあ。

*1:"安全系組み込みソフトウェア開発におけるユニットテストの効率化 ~Concolic Testingの活用事例~", ソフトウェア・シンポジウム 2015 in 和歌山, 岸本渉, 株式会社デンソー

*2:https://hldc.co.jp/06/02/14688/

*3:"Software Testing Research: Achievements, Challenges, Dreams", FOSE2007, Antonia Bertolino

*4:"Software Testing Research: Achievements, Challenges, Dreams", FOSE2007, Antonia Bertolino

*5:完全に環境を再現するわけではないので一部

*6:DART: Directed Automated Random Testing, Patrice Godefroid, et al.

*7:"A Symbolic Framework for Model-Based Testing", L. Frantzen, et al.

*8:http://jasst.jp/symposium/jasst15tokai/pdf/S4-1.pdf

*9:CBMC https://www.cprover.org/cbmc/

*10:http://www.orsj.or.jp/~wiki/wiki/index.php/%E3%83%A1%E3%82%BF%E3%83%92%E3%83%A5%E3%83%BC%E3%83%AA%E3%82%B9%E3%83%86%E3%82%A3%E3%82%AF%E3%82%B9

*11:SBST 2017 Unit Tool Competitionで優勝

*12:"AUTOMATED UNIT TEST GENERATION DURING SOFTWARE DEVELOPMENT", ISSTA 2015, José Miguel Rojas, et al.

*13:こういう論文があると初心者としては全体が何となく知れるのでうれしい

*14:スレッド間のatomicityが正しく保たれたと仮定を置き、スレッド実行を直列化した際に得ることができる結果か否かを判定する技術

*15:具体的には調べていないのでわからないが・・・

*16:自分の理解では、あるスレッドが動作しているときは 他のスレッドが動作しないというモデル化、というところだけど、誰か正確なところを教えてほしい

*17:https://github.com/google/guava