Congratulations!

[Valid RSS] This is a valid RSS feed.

Recommendations

This feed is valid, but interoperability with the widest range of feed readers could be improved by implementing the following recommendations.

Source: http://ynomura.dip.jp/index.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <rss version="2.0">
  3.   <channel>
  4.      <title>Weblog on mebius.tokaichiba.jp</title>
  5.      <link>http://ynomura.dip.jp/</link>
  6.      <description>かつてJR横浜線 十日市場駅近くのMebius (CPU:Pentium 150MHz)より発信していたウェブログです。</description>
  7.      <language>ja</language>
  8.      <copyright>Copyright 2017</copyright>
  9.      <lastBuildDate>Sun, 09 Apr 2017 20:30:28 +0900</lastBuildDate>
  10.      <generator>http://www.sixapart.com/movabletype/</generator>
  11.      <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  12.  
  13.            <item>
  14.         <title>ROC曲線を理解する</title>
  15.         <description><![CDATA[<p>2値の予測(判別、識別、…)に用いる特徴量の良し悪しを評価する1つの方法として、ROC曲線というものがある。<br />
  16. 実際は正で予測も正であるデータの数をTP(True Positive)、<br />
  17. 実際は負で予測も負であるデータの数をTN(True Negative)、<br />
  18. 実際は負で予測は正であるデータの数をFP(False Positive)、<br />
  19. 実際は正で予測は負であるデータの数をFN(False Negative)、<br />
  20. と呼ぶ時、<br />
  21. TPR(True Positive Ratio)=TP/(TP+FN)を縦軸、<br />
  22. FPR(False Positive Ratio)=FP/(FP+TN)を横軸、<br />
  23. としたグラフである。
  24. </p>
  25. <p>ROC曲線の例<br />
  26. <a href="/archives/images/ROC1.png">
  27. <img src="/archives/images/ROC1.png" width="320" height="240" alt="ROC curve sample" />
  28. </a>
  29. </p>
  30.  
  31. <p>ROC曲線は、必ず(0,0)から始まって(1,1)で終わる。<br />
  32. 特徴量が全く予測の役に立たない、ランダムな値であれば、TPR=FPRの線になる。<br />
  33. ROC曲線より下の面積、AUR(Area Under ROC curve)(または単にAUC(Area Under the Curve))が大きいほど、特徴量の値の全域に渡って良い特徴量だとされる。
  34. 理想的な特徴量だと、ROC曲線はFPR=0とTPR=1の線になる。
  35. </p>
  36.  
  37. <p>ROC曲線は機械学習で識別器の評価によく用いられるらしいので、とりあえず覚えておこうと思ったのだが、筆者はこれの理解にえらく苦労したので、調べたことや考えたことをメモする。<br />
  38. <a href="/archives/2009/09/16.html">統計学の検定</a>と同様、こういう確率と論理を組み合わせたものは、人によって向き不向きがあるのだと思いたい。</p>
  39.  
  40. <p>TP,TN,FP,FNの関係を再度整理すると、次のようになる。
  41. <table border="1">
  42. <tr><th rowspan="2" colspan="2"><th colspan="2">予測</tr>
  43. <tr><th bgcolor="maroon">+<th bgcolor="navy">−</tr>
  44. <tr><th rowspan="2">実<br />際<th>+<td align="center" bgcolor="maroon">TP<td align="center" bgcolor="navy">FN (Type II error)</tr>
  45. <tr><th>−<td align="center" bgcolor="maroon">FP (Type I error)<td align="center" bgcolor="navy">TN</tr>
  46. </table>
  47. PやNは予測がPositiveかNegativeかであり、TやFはそれが正解かどうかである。<br />
  48. FPは誤検出のことであり、統計学の検定でも使われる「第一種の過誤」(検定では帰無仮説を棄却できないのに棄却する条件に誤ってヒットしてしまうこと)である。<br />
  49. FNは検出不能であり、「第二種の過誤」(検定では帰無仮説が誤りなのに棄却する条件にヒットしないこと)である。
  50. </p>
  51.  
  52. 予測の精度に関する尺度としては、Accuracy, Presicision, Recall, F値があり、それぞれ次のように定義される。
  53. <dl>
  54. <dt>Accuracy = (TP+TN) / (TP+TN+FP+FN)</dt><dd>予測の正解率。</dd>
  55. <dt>Precision = TP / (TP+FP)</dt><dd>Positiveと予測される中の正解率。</dd>
  56. <dt>Recall = TP / (TP+FN)</dt><dd>実際にPositiveの内、Positiveと予測される割合。検出力、Sensitivity。</dd>
  57. <dt>F値(F-measure, F1 score) = ((Precision<sup>-1</sup> + Recall<sup>-1</sup>)/2)<sup>-1</sup></dt><dd>PrecisionとRecallの調和平均。統計学のF分布に従うF値とは関係ない。<br />
  58. PrecisionとRecallはトレードオフの関係にあるので、それらをバランス良く合成した尺度。</dd>
  59. </dl>
  60.  
  61. <p>予測の精度はAccuracyで評価するのが簡単だが、実際の正のデータ数と負のデータ数に偏りがあると、データ数が少ない方の正解率が低くても、データ数が多い方の正解率が高ければAccuracyが高くなってしまうので、Accuracyだけでは適切に評価できない。<br />
  62. そのような場合にPrecisionやRecallが用いられるが、これらは一般に特徴量の閾値によってトレードオフの関係があり、セットで評価しないといけないので、単純比較には向かない。そこで用いられるスカラー値が、F値や、ROC曲線のAUCである。<br />
  63. Precision-Recall曲線のAUCも使われることがあるが、Presicionは実際の正のデータの割合に依存するので、正のデータの割合が同じでないと比較には使えない。実際の正のデータの割合が極端に小さい場合など、Precisionが大きな意味を持つ場合にはPrecision-Recall曲線が用いられる。
  64. </p>
  65.  
  66. <p>
  67. ROC曲線は、TPR=TP/(TP+FN)とFPR=FP/(FP+TN)のグラフである。TPRを陽性率、FPRを偽陽性率と呼ぶこともある。TPRはRecallと同じである。FPRはfall-out(副産物)と呼ばれることもある。
  68. </p>
  69. <p>
  70. 次の図の3つのROC曲線が、正のデータと負のデータがどのように分布する特徴量に対応するかを考えてみる。<br />
  71. <a href="/archives/images/ROC2.png">
  72. <img src="/archives/images/ROC2.png" width="240" height="240" alt="ROC curve sample 2" />
  73. </a><br />
  74. </p>
  75. <p>
  76. 例えば、次のような分布になる特徴量だと、青いROC曲線になる。<br />
  77. <a href="/archives/images/ROC3.png">
  78. <img src="/archives/images/ROC3.png" width="320" height="240" alt="distribution of totally independent feature" />
  79. </a><br />
  80. 横軸は特徴量、縦軸は赤い部分が正のデータの分布、青い部分が負のデータの分布を表している。このグラフでは、正のデータも負のデータも一様分布している。閾値tより右ならPositive、左ならNegativeと予測する時、tを右端から左に動かすと、TPRもFPRも0から1に向かって増大するが、常にTPR=FPRである。正のデータと負のデータの割合はグラフの形状には関係しない。
  81. </p>
  82. <p>
  83. 次のような、正のデータと負のデータが完全に分かれる理想的な特徴量だと、緑のROC曲線になる。<br />
  84. <a href="/archives/images/ROC4.png">
  85. <img src="/archives/images/ROC4.png" width="320" height="240" alt="distribution of ideal feature" />
  86. </a><br />
  87. tを右端から左に動かすと、FPR=0のままTPRが0から1に変化し、青のゾーンに入ると、FPRが0から1に変化する。
  88. </p>
  89. <p>
  90. 次のような分布だと、赤いROC曲線になる。<br />
  91. <a href="/archives/images/ROC5.png">
  92. <img src="/archives/images/ROC5.png" width="320" height="240" alt="distribution of which makes ROC curve perfect arc" />
  93. </a><br />
  94. tを右端から左へ動かすと、FPRよりもTPRの方が早く上昇する。なるべく正のデータと負のデータの分布が分離している良い特徴量ほどFPRが上昇する前にTPRが上昇するので、AUCが大きくなることがわかる。<br />
  95. </p>
  96.  
  97. <p>AUCはどれくらいだと良いか、という基準は一般的なものも色々あるようだが、大体、最低0.7は無いと有効ではないとされるようである。
  98. </p>
  99. <p>なお、特徴量の最良の閾値(cut-off)はROC曲線の(0,1)に最も近い点とする、という方法を複数の箇所で目にしたが、明確な理論的根拠がある訳ではなく、必ずしもそれに限定されないようである。そもそも、(0,1)に最も近いというのがユークリッド距離で良いのかどうかがわからない。
  100. </p>]]></description>
  101.         <link>http://ynomura.dip.jp/archives/2017/04/roc.html</link>
  102.         <guid>http://ynomura.dip.jp/archives/2017/04/roc.html</guid>
  103.                  <category domain="http://www.sixapart.com/ns/types#category">PC一般</category>
  104.        
  105.        
  106.         <pubDate>Sun, 09 Apr 2017 20:30:28 +0900</pubDate>
  107.      </item>
  108.            <item>
  109.         <title>pandasでmergeせずにgroupbyで間接参照したい</title>
  110.         <description><![CDATA[<p>この前、pandasを使っていて、次のような感じの、関連する2つのテーブル、access_logとchoice_logがある時に、結合したテーブルを作らずにchoice毎のtimestampの最小値を求めたかったのだが、どう書けば良いのかわからなかった。
  111. </p>
  112. <blockquote><pre>
  113. import pandas as pd
  114. import numpy as np
  115. access_log = pd.DataFrame({'session': [100, 101, 102, 103, 104, 105, 106, 107, 108, 109],
  116.                           'timestamp': [314, 159, 265, 358, 979, 323, 846, 264, 338, 327]})
  117. choice_log = pd.DataFrame({'session': [100, 100, 101, 102, 102, 103, 104, 104, 105, 106, 106, 107, 108, 108, 109],
  118.                           'choice':  ['A', 'B', 'C', 'D', 'E', 'A', 'B', 'C', 'D', 'E', 'A', 'B', 'C', 'D', 'E']})
  119. >>> access_log
  120.   session  timestamp
  121. 0      100        314
  122. 1      101        159
  123. 2      102        265
  124. 3      103        358
  125. 4      104        979
  126. 5      105        323
  127. 6      106        846
  128. 7      107        264
  129. 8      108        338
  130. 9      109        327
  131. >>> choice_log
  132.   choice  session
  133. 0       A      100
  134. 1       B      100
  135. 2       C      101
  136. 3       D      102
  137. 4       E      102
  138. 5       A      103
  139. 6       B      104
  140. 7       C      104
  141. 8       D      105
  142. 9       E      106
  143. 10      A      106
  144. 11      B      107
  145. 12      C      108
  146. 13      D      108
  147. 14      E      109
  148. >>>
  149. </pre></blockquote>
  150. <p>結合テーブルを作るなら、次のように書ける。
  151. </p>
  152. <blockquote><pre>
  153. merged = choice_log.merge(access_log, on='session', how='left')
  154. result = merged.groupby('choice')['timestamp'].min()
  155. >>> result
  156. choice
  157. A    314
  158. B    264
  159. C    159
  160. D    265
  161. E    265
  162. Name: timestamp, dtype: int64
  163. >>>
  164. </pre></blockquote>
  165.  
  166. <p>実際にあったテーブルは巨大で、他にも列がたくさんあり、単純に結合テーブルを作るとRAMが足りなくなってメモリスワップが多発したので、結合テーブルを作らずにこれと同じことがしたかったのだが、その書き方がわからなかった。<br />
  167. 結局access_log.set_index('session').to_dict()のようにして一時的なdictを作って、スワップを多発させながら処理してしまった。<br />
  168. それが心残りだったので、改めてpandasのドキュメントを拾い読みしながら方法を探してみた。
  169. </p>
  170. <ol>
  171. <li>単純に、別のテーブルを参照する関数をSeries.mapに渡す
  172. <blockquote><pre>
  173. def session_to_timestamp(session_series):
  174.    return session_series.map(lambda x: access_log[access_log.session==x]['timestamp'].iat[0])
  175.  
  176. result = choice_log.groupby('choice').agg(lambda x: session_to_timestamp(x).min())
  177. </pre></blockquote>
  178. <p>Seriesの先頭の要素を取り出す方法には、.iat[0]の他に.iloc[0]や.values[0]などがあり、筆者が試した所values[0]の方が速かったりしたが、pandasのドキュメントに書かれているのはilocとiatなので、ここでは添字が整数なら高速なiatを用いた。</p>
  179. </li>
  180. <li>リスト内包表現(list comprehension)で別のテーブルを参照する
  181. <blockquote><pre>
  182. def session_to_timestamp(session_series):
  183.    return [access_log[access_log.session==x]['timestamp'].iat[0] for x in session_series]
  184.  
  185. result = choice_log.groupby('choice').agg(lambda x: min(session_to_timestamp(x)))
  186. </pre></blockquote>
  187. <p>リストにはminメソッドが無いので、session_to_timestamp(x).min()とはできない。</p>
  188. </li>
  189. <li>isinを使ったBoolean Indexingで別の表のサブセットを得る
  190. <blockquote><pre>
  191. def session_to_timestamp(session_series):
  192.    return access_log[access_log.session.isin(session_series.values)]['timestamp']
  193.  
  194. result = choice_log.groupby('choice').agg(lambda x: session_to_timestamp(x).min())
  195. </pre></blockquote>
  196. </li>
  197. <li>別の表からSeriesを作ってSeries.mapに渡す
  198. <blockquote><pre>
  199. def session_to_timestamp(session_series):
  200.    return session_series.map(access_log.set_index('session').timestamp)
  201.  
  202. result = choice_log.groupby('choice').agg(lambda x: session_to_timestamp(x).min())
  203. </pre></blockquote>
  204. <p>一見シンプルで美しそうだが、set_index()はコピーを返すので、timestampの一時的なdictを作るのと変わらない。しかも、グループ数だけ新たなテーブルを作るので、無駄である。</p>
  205. </li>
  206. </ol>
  207.  
  208. <p>これらの処理時間を色々測ってみたが、2つのテーブルのサイズやグループの数によって変わり、どう比較すれば良いかわからなかったので、省略する。<br />
  209. 大まかな傾向としては、1.と2.の処理時間はchoice_logのサイズに依存し、3.と4.の処理時間はsession_logのサイズに依存するようだった。4.はset_indexした中間テーブルを事前に作っておくと高速化するが、それでも、大抵の場合3.が一番速かった。<br />
  210. いずれの方法も最速になる場合があるようなので、場合毎に色々試してみるしかなさそうである。</p>
  211. <p>肝心のメモリ使用量は、適当な測り方がわからなかった。<br />
  212. そもそも、スワップしながらの処理時間が問題だったので、単純にメモリ使用量では測れないと思う。
  213. </p>
  214.  
  215. <p>他にも、以下のような方向で書き方を考えてみたが、うまくできなかった。
  216. </p>
  217. <ul>
  218. <li>groupbyでaggregateでなくtransformしてmin()<br />
  219. transformする時に別のテーブルを参照することを考えたが、transformするとgroup解除されてしまうので、使えなかった。transformする時にmin()するのなら、min()した値を増殖させるだけ無駄なので、確実にaggregateの方が効率が良い。
  220. </li>
  221. <li>pandas.DataFrame.lookupを使う<br />
  222. 引数としてindexしか受けられないので、使えなかった。
  223. </li>
  224. <li>pandas.DataFrame.joinを使う<br />
  225. pandas.DataFrame.mergeを使うのと変わらなかった。
  226. </li>
  227. </ul>
  228.  
  229. <p>そもそも、lambda式を使わずに書く方法は無いのだろうか。<br />
  230. teratailとかStack Overflowとかで聞いた方が早いか。
  231. </p>]]></description>
  232.         <link>http://ynomura.dip.jp/archives/2017/03/pandasmergegrou.html</link>
  233.         <guid>http://ynomura.dip.jp/archives/2017/03/pandasmergegrou.html</guid>
  234.                  <category domain="http://www.sixapart.com/ns/types#category">PC一般</category>
  235.        
  236.        
  237.         <pubDate>Fri, 31 Mar 2017 20:00:01 +0900</pubDate>
  238.      </item>
  239.            <item>
  240.         <title>pandas.read_csv+numpy.bincountでエラー</title>
  241.         <description><![CDATA[<p>ちょっと前に、はやりのAIのプログラミングでよく使われるPythonとNumPyとPandasを使い始めたのだが、PandasでCSVファイルを読み込んで、各ラベルの出現回数を得る為にNumPyのbincountメソッドを使うと、次のようなエラーが出て、困った。
  242. <blockquote>
  243. TypeError: Cannot cast array data from dtype('int64') to dtype('int32') according to the rule 'safe'
  244. </blockquote>
  245. その時使った環境は、Windows 7(32bit版)+Python 3.5.2(Anaconda 4.1.1 (32-bit))である。Mac OS Xでは出なかった。
  246. </p>
  247. <p>これは、32bitのPythonを使っていると起こることらしい。例えば、32bit Pythonで次のプログラムを実行すると、同じエラーが出る。
  248. <blockquote><pre>
  249. import numpy as np
  250. import pandas as pd
  251. import io
  252.  
  253. data = np.random.randint(10, size=30)
  254. buf = io.StringIO("\n".join(str(x) for x in data))
  255. df = pd.read_csv(buf, header=None)
  256. x = df[0].values
  257. print(x)
  258. print(np.bincount(x)) #Error on 32bit Python
  259. </pre></blockquote>
  260. これは、Pandasが32bit Pythonでもint64を使うのが原因のようである。
  261. </p>
  262.  
  263. <p>このエラーを回避するには、bincountに渡すデータの型をint32にすれば良い。
  264. <blockquote><pre>print(np.bincount(x.astype('int32'))) #also OK on 32bit Python</pre></blockquote>
  265. 出力例
  266. <blockquote>
  267. [1 0 6 7 1 7 7 6 9 5 6 2 8 0 7 6 7 8 9 7 8 9 8 0 2 1 2 6 0 3]<br />
  268. [4 3 3 1 0 1 5 6 4 3]
  269. </blockquote>
  270. </p>
  271.  
  272. <p>または、np.unique(return_counts=True)を使う方法があり、こちらの方が、大抵の場合はnp.bincountを使うよりも好ましいとされるようである。
  273. <blockquote><pre>
  274. print(np.unique(x, return_counts=True))
  275. </pre></blockquote>
  276. 出力例
  277. <blockquote>
  278. (array([0, 1, 2, 3, 5, 6, 7, 8, 9]), array([4, 3, 3, 1, 1, 5, 6, 4, 3]))
  279. </blockquote>
  280. 確かに、np.unique(return_counts=True)の方が、データに負の値があっても使えるし、大きな値が混ざってても配列が巨大にならないので、安全そうである。
  281. </p>
  282.  
  283. <p>なお、今動作しているPythonが32bitか64bitかを判定する方法は、いくつかあるようである。
  284. <u>例1</u>
  285. <blockquote><pre>
  286. import platform
  287. platform.architecture()
  288. </pre></blockquote>
  289.  
  290. 出力(上がMacOSX、下がWin32)
  291. <blockquote>
  292. ('64bit', '')<br />
  293. ('32bit', 'WindowsPE')
  294. </blockquote>
  295.  
  296. <u>例2</u>
  297. <blockquote><pre>
  298. import sys
  299. "%x" % sys.maxsize
  300. </pre></blockquote>
  301. 出力(上がMacOSX、下がWin32)
  302. <blockquote>
  303. '7fffffffffffffff'<br />
  304. '7fffffff'
  305. </blockquote>
  306.  
  307. <u>例3</u>(platform.architecture()の実装にも使われている方法)
  308. <blockquote><pre>
  309. import struct
  310. struct.calcsize("P") * 8
  311. </pre></blockquote>
  312. 出力(上がMacOSX、下がWin32)
  313. <blockquote>
  314. 64<br />
  315. 32
  316. </blockquote>
  317. </p>
  318. ]]></description>
  319.         <link>http://ynomura.dip.jp/archives/2017/03/pandasread_csvn.html</link>
  320.         <guid>http://ynomura.dip.jp/archives/2017/03/pandasread_csvn.html</guid>
  321.                  <category domain="http://www.sixapart.com/ns/types#category">PC一般</category>
  322.        
  323.        
  324.         <pubDate>Sun, 05 Mar 2017 20:47:33 +0900</pubDate>
  325.      </item>
  326.            <item>
  327.         <title>Carbon EmacsにPython 3環境導入</title>
  328.         <description><![CDATA[<p>筆者はMacで未だにEmacs 22ベースのCarbon Emacsを多用している。Emacs 24ベースのCocoa Emacsもインストールはしているのだが、色々な環境をCarbon Emacsに作ってしまっているので、移行するのが億劫なのである。</p>
  329.  
  330. <p>最近、Python 3を使い始めたのだが、Carbon Emacsのpython.elはPython 2にしか対応していないので、何とかPython 3に対応させる方法は無いかと探した結果、<br />
  331. <a href="http://www.loveshack.ukfsn.org/emacs/">http://www.loveshack.ukfsn.org/emacs/</a><br />
  332. から<br />
  333. python.el<br />
  334. emacs.py<br />
  335. sym-comp.el<br />
  336. の3つをダウンロードして、Emacs.app/内に置けば良いことがわかった。(python.elとemacs.pyは既にあるものを置換、sym-comp.elはpython.elと同じディレクトリに追加)<br />
  337. そして、Emacsを立ち上げて、M-x customize-groupとし、<br />
  338. "Python Default Version" = 3<br />
  339. "Python Python Command" = python3<br />
  340. にすれば完成である。</p>
  341.  
  342. <p>これで、C-c TABとM-TABを駆使すればシンボルの補完ができて、まあまあコーディングが楽になるのだが、やっぱり補完機能は便利にしたいので、<br />
  343. <a href="http://cortyuming.hateblo.jp/entry/20111224/p1">Pythonの補完をEmacsでシンプルに最小労力で手早く使えるようにする - 牌語備忘録 -pygo</a><br />
  344. を参考にして、<a href="https://www.emacswiki.org/emacs/AutoComplete">auto-complete.el</a> + <a href="http://chrispoole.com/downloads/ac-python.el">ac-python.el</a>をインストールした。<br />
  345. auto-complete.elは、Emacs 22で動作実績のある、auto-complete-1.3.1.tar.bz2をどこかから入手した。</p>
  346.  
  347. <p>そして、.emacsに次の4行を書けば完成である。
  348. <blockquote><pre>(require 'auto-complete)
  349. (require 'auto-complete-config)
  350. (ac-config-default)
  351. (require 'ac-python)</pre></blockquote></p>
  352.  
  353. <p>これで、python-modeにして、<code>import math</code>と書いてC-c TABして、<code>math.</code>と打つと、math.sqrtやらmath.piやらが補完候補として自動的に現れるようになった。</p>]]></description>
  354.         <link>http://ynomura.dip.jp/archives/2017/03/carbon_emacspyt.html</link>
  355.         <guid>http://ynomura.dip.jp/archives/2017/03/carbon_emacspyt.html</guid>
  356.                  <category domain="http://www.sixapart.com/ns/types#category">PC一般</category>
  357.        
  358.        
  359.         <pubDate>Wed, 01 Mar 2017 23:37:59 +0900</pubDate>
  360.      </item>
  361.            <item>
  362.         <title>対石田流の定跡で悩む</title>
  363.         <description><![CDATA[筆者は石田流が苦手である。後手になって、初手から▲7六歩△3四歩▲7五歩とされると、これは大変なことになったな、と思ってしまう。同じぐらいの実力(アマ三段程度)同士だと、石田流にされると3局に2局は負けてると思う。
  364. 先週は将棋大会があり、石田流対策としては、▲7六歩△3四歩▲7五歩には△4二玉、下図の局面から仕掛けるなら△9二飛▲8五桂△8二飛▲8六歩△8四飛、の2つだけを覚えて臨んだら、予選の1局目から▲7六歩△3四歩▲7五歩とされ、次の図の局面を迎えてしまった。
  365. <img src="/archives/images/20161123-1.png">
  366. このような局面から△9二飛▲8五桂△8二飛▲8六歩△8四飛と飛車を端に振ってすぐ戻して浮くのは、過去に何かの本で読んだもので、多分定跡だと思う。もし△9二飛▲8五桂△8二飛の次に▲8六飛とされたらどうすればいいんだろう、と不安に思っていたが、他に何も思い付かなかったので、定跡と信じて△9二飛、▲8五桂、△8二飛と手早く指した。
  367. <img src="/archives/images/20161123-2.png">
  368. すると、ノータイムで実際に▲8六飛とされてしまい、長考に沈んでしまった。
  369. 後で調べると、ここまでは2004年のNHK杯の三浦−行方戦と全く同じ進行であり、その対局ではやはり▲8六歩と指されていた。他にも部分的に同じ形から△9二飛▲8五桂△8二飛としたプロの棋譜を4つぐらい見つけたが、次の手は全て▲8六歩△8四飛だったし、激指14で分析しても▲8六飛は評価が低いので、良くない手なのだと思うが、これの咎め方がよくわからない。
  370. <img src="/archives/images/20161123-3.png">
  371. 次に何をやっても▲7三桂成がある。それには△8六飛(次図)とする一手だが、▲同角でも△7三桂の後に先攻されてすぐ桂損を回復されるし、▲6三成桂と踏み込まれる手も気になる。
  372. <img src="/archives/images/20161123-4.png">
  373. 筆者の実戦は、▲8六飛の後、△7四歩▲7三桂成△8六飛▲同角△7三桂▲7四歩△同銀▲7一飛(次図)と先着され、△6二金と受けたら▲9一飛成から大暴れされ、なす術無く、十数手後には激指の先手の評価値が+1000という必敗の形勢になってしまった。
  374. <img src="/archives/images/20161123-5.png">
  375. 激指によると、△6二金が悪手で、ここまで来たら桂取りが銀取りにならないように△6三銀と戻るのが良いらしいが、そこまで後手を引いて駒損を回復されて龍まで作られてしまうのでは、何をやってるのかわからないと思う。
  376. ただ、△7四歩では△6五歩の方が良さそうである。▲7三桂成と歩を取られるのなら逃げておこうと思って△7四歩と避けたのだが、△7三桂と取り返した後に▲7四歩と取る手が桂取りの先手になるし、△7四歩が無くても△7三桂には▲7四歩と突き出す所なので、意味が無かった。▲8六飛の後、△6五歩▲7三桂成△8六飛▲同角△7三桂▲7四歩△同銀▲7一飛△5五角というのが激指の推奨手順である。
  377. <img src="/archives/images/20161123-6.png">
  378. 激指はこれで-400(後手少しリード)くらいの評価を示しているが、筆者にはこれで後手が指せる理由がわからない。次に△3六桂とやっても▲3九玉と引かれるので攻め方がわからないし、やはり▲9一飛成から暴れられて、筆者の実力ではその勢いを止められないように思う。
  379. ただ、もし△5五角に▲5六歩とされれば、△3六桂で一気に後手勝勢になりそうである。△3六桂に▲3九玉だと△6六角が王手で危険なので▲1七玉しか無いが、△1五歩とすれば受けが難しいと思う。
  380. <img src="/archives/images/20161123-7.png">
  381. ▲5五歩なら△1六歩▲2六玉△2八桂成である。
  382. こうなることを期待して、▲8六飛には△6五歩とするべきなのだろうか。]]></description>
  383.         <link>http://ynomura.dip.jp/archives/2016/11/post_58.html</link>
  384.         <guid>http://ynomura.dip.jp/archives/2016/11/post_58.html</guid>
  385.                  <category domain="http://www.sixapart.com/ns/types#category">将棋</category>
  386.        
  387.        
  388.         <pubDate>Sun, 27 Nov 2016 20:28:50 +0900</pubDate>
  389.      </item>
  390.            <item>
  391.         <title>980</title>
  392.         <description><![CDATA[惜しい。
  393. <a href="/archives/images/TOEICIPresult20161023.jpg"><img src="/archives/images/TOEICIPresult20161023.jpg" width="408" height="172"></a>]]></description>
  394.         <link>http://ynomura.dip.jp/archives/2016/11/980.html</link>
  395.         <guid>http://ynomura.dip.jp/archives/2016/11/980.html</guid>
  396.                  <category domain="http://www.sixapart.com/ns/types#category">雑記</category>
  397.        
  398.        
  399.         <pubDate>Tue, 08 Nov 2016 23:55:53 +0900</pubDate>
  400.      </item>
  401.            <item>
  402.         <title>psvn.el+Subversion 1.7がネストされたワーキングコピーでエラーになる件</title>
  403.         <description><![CDATA[<p>筆者は<a href="http://www.xsteve.at/prg/emacs/psvn.el">psvn.el</a>を6年くらい愛用している。仕事でSubversionを使ってるのだが、Subversionのクライアントソフトとして、周囲がTortoiseSVNを使う中、一人で頑にpsvn.elを使っている。マウス操作やトラックパッド操作が必要なく、全てがキーボード操作で完結するのが、個人的に気持ち良いのである。
  404. </p>
  405. <p>最近、仕事で使うSubversionのバージョンが1.6から1.8に変わり、それまで使っていた、2009年のバージョンのpsvn.elが動かなくなった。Subversion 1.7でワーキングコピーの形式が大幅に変わったからである。
  406. </p>
  407. <p>そこで、Subversion 1.7にも対応している、最新のpsvn.el(2015-07-20版)をダウンロードして使い始めた所、ワーキングコピーのルートディレクトリにチェックアウトしたワーキングコピーでM-x svn-statusすると、<blockquote>Wrong type argument: stringp, nil</blockquote>というエラーが出て使えなかった。つまり、<pre>
  408. svn co (URL1) aaa
  409. cd aaa
  410. svn co (URL2) bbb
  411. </pre>
  412. とした時のディレクトリbbbの下でM-x svn-statusができなかった。<br />
  413. svn coの代わりに、svn propsetでsvn:externalsを指定してbbbを取得しても同じエラーになった。<br />
  414. ディレクトリaaaの下でsvn switchして別のワーキングコピーを取得した場合は同じ問題が起こらないのだが、あいにくURL1とURL2とでSubversionのリポジトリが異なる為に、svn switchでbbbを取得することができないのである。
  415. </p>
  416. <p>これが筆者としては非常に困ったので、自力で修正してみた。<br />
  417. 変更箇所をdiff形式で示す。</p>
  418. <p>修正案1
  419. <blockquote><pre>
  420. <span class="diffold">--- psvn.el.org 2015-07-20, 21:42:00</span>
  421. <span class="diffnew">+++ psvn.el 2016-09-30</span>
  422. <span class="grayout">@@ -6063,6 +6063,7 @@
  423.         ;; it doesn't, e.g we reached / already.
  424.         (setq parent (expand-file-name (concat wc-root "..")))
  425.         (or (and (< (length parent) (length wc-root))
  426. <span class="diffnew">+                 (not (file-exists-p (concat wc-root (svn-wc-adm-dir-name))))  ;; stop if .svn or equivalent exists</span>
  427.                  (svn-status-base-dir-1 (expand-file-name (concat wc-root ".."))))
  428.             wc-root)))))</span>
  429. </pre></blockquote>
  430.  
  431. svn-status-base-dir-1関数の中で、ワーキングコピーのルートディレクトリを探すのに、できるだけ上位のディレクトリを探すようで、上に辿る途中にエラーになるので、.svnを発見したらそれ以上遡らないようにするものである。</p>
  432.  
  433. <p>修正案2
  434. <blockquote><pre>
  435. <span class="diffold">--- psvn.el.org 2015-07-20, 21:42:00</span>
  436. <span class="diffnew">+++ psvn.el 2016-10-10</span>
  437. <span class="grayout">@@ -3084,7 +3084,7 @@
  438.     (let ((svn-process-buffer-name "*svn-info-output*"))
  439.       (when (get-buffer svn-process-buffer-name)
  440.         (kill-buffer svn-process-buffer-name))
  441. <span class="diffold">-      (svn-run nil t 'parse-info "info" ".")</span>
  442. <span class="diffnew">+      (svn-run nil t 'parse-info "info" default-directory)</span>
  443.       (svn-status-parse-info-result)))
  444.   (unless (eq arg t)
  445.     (svn-status-update-buffer)))</span>
  446. </pre></blockquote>
  447.  
  448. 原因がよくわからないが、途中にワーキングコピーのルートディレクトリがあると、そこから1つ上に遡った時に、カレントディレクトリがdefault-directoryでなく、もう1つ上のディレクトリにずれてしまうようで、カレントディレクトリがワーキングコピー中でないと <code>svn info .</code> がエラーになる(*)ので、 <code>svn info</code> する時に常にdefault-directoryを使うように変えるものである。
  449. </p>
  450.  
  451. <p>どちらも適切な修正かどうかはわからないが、とりあえず筆者の環境(Linux + Subversion 1.8 + Emacs 2.4)では標記の問題は解決した。
  452. </p>]]></description>
  453.         <link>http://ynomura.dip.jp/archives/2016/10/psvnelsubversio.html</link>
  454.         <guid>http://ynomura.dip.jp/archives/2016/10/psvnelsubversio.html</guid>
  455.                  <category domain="http://www.sixapart.com/ns/types#category">UNIX</category>
  456.        
  457.        
  458.         <pubDate>Mon, 10 Oct 2016 14:11:57 +0900</pubDate>
  459.      </item>
  460.            <item>
  461.         <title>被写界深度の計算式を導いてみた</title>
  462.         <description><![CDATA[被写界深度というのは、レンズを通して見た映像の、ピントが合っているように見える、奥行き方向の範囲のことである。
  463. 昨年、フォトマスター検定という試験を受ける為に勉強した中で、被写界深度を求める式が何故このようになるのかがわからず、気になっていた。
  464. 先月、フォトマスター検定について講義する機会があったので、そのネタとして、被写界深度の式を導いてみた。
  465.  
  466. <img src="/archives/images/DoF1.svg" border="1" width="651" height="250">
  467. 図1
  468.  
  469. まず、被写界深度が何故存在するかというと、ピントが合っていない距離の点は点でなく丸になって映る(ボケる)が、その丸(錯乱円)が十分に小さいと、ほとんどボケてるように見えないからである。
  470. その十分に小さい錯乱円の直径=許容ボケをδとすると、フィルム(デジカメだとセンサー)上のδに対応して、光軸上のフィルム/センサーの前後に、その範囲に焦点を結ぶとピントが合って見える範囲=焦点深度が存在する。
  471. <img src="/archives/images/DoF2.svg" border="1" width="333" height="237">
  472. 図2
  473.  
  474. この焦点深度の幅を2εとすると、F値(絞り値)=レンズ焦点距離(f)÷レンズ口径(Φ)を使って、f >> εなのでε/δ = F、すなわちε = Fδと近似できる。
  475. この焦点深度に対応する、被写体側の範囲が、被写界深度である。
  476.  
  477. ここで、「ガウスの結像公式」(以下、単に「結像公式」)というのを用いる。結像公式とは、凸レンズからa離れた位置から発せられる光が、凸レンズを通って反対側のb離れた位置に焦点を結ぶ時、aとbの関係を、レンズ焦点距離fを用いて、
  478. <img src="/archives/images/DoF01.png" alt="\frac{1}{f}=\frac{1}{a}+\frac{1}{b}, Gaussian form of the lens equation">
  479. と表すものである。ちなみに、レンズの焦点距離とは、無限遠から来る光が焦点を結ぶ位置のことである。(上式でa=∞とするとb=fとなる)
  480.  
  481. この結像公式を用いて、焦点深度と被写界深度の関係を式にする。
  482. 図1のように、sをレンズから合焦位置までの距離、s<sub>n</sub>を被写界の近点、s<sub>f</sub>を被写界の遠点、tをレンズからフィルム/センサーまでの距離とすると、
  483. <img src="/archives/images/DoF02.png">
  484. となる。これらの連立方程式を、tを消去して、s<sub>n</sub>とs<sub>f</sub>について解く。
  485. (1)よりt=sf/(s-f)が得られるので、これを(2),(3)に代入すると、
  486. <img src="/archives/images/DoF03.png" alt="s_n=\frac{(t+\epsilon)f}{(t+\epsilon)-f}=\frac{(\frac{sf}{s-f}+\epsilon)f}{(\frac{sf}{s-f}+\epsilon)-f}=\frac{(sf+\epsilon(s-f))f}{f^2+\epsilon(s-f)}">
  487. <img src="/archives/images/DoF04.png" alt="s_f=\frac{(t-\epsilon)f}{(t-\epsilon)-f}=\frac{(\frac{sf}{s-f}-\epsilon)f}{(\frac{sf}{s-f}-\epsilon)-f}=\frac{(sf-\epsilon(s-f))f}{f^2-\epsilon(s-f)}">
  488. が得られる。
  489. ここで、s,f>>εなので、s&plusmn;ε&asymp;s, f&plusmn;ε&asymp;f, sf&plusmn;ε<sup>2</sup>&asymp;sfと近似できることを用いて、簡略化する。
  490. <img src="/archives/images/DoF05.png" alt="s_n=\frac{(sf+\epsilon(s-f))f}{f^2+\epsilon(s-f)}=\frac{((s-\epsilon)(f+\epsilon)+\epsilon^2))f}{f(f-\epsilon)+\epsilon s}\approx\frac{sf^2}{f^2+\epsilon s}">
  491. <img src="/archives/images/DoF06.png" alt="s_f=\frac{(sf-\epsilon(s-f))f}{f^2-\epsilon(s-f)}=\frac{((s+\epsilon)(f-\epsilon)+\epsilon^2))f}{f(f+\epsilon)-\epsilon s}\approx\frac{sf^2}{f^2-\epsilon s}">
  492.  
  493. これにε=Fδを代入すれば、被写界深度の近点と遠点を求める式になるのだが、フォトマスター検定の参考書では過焦点距離を用いた式になっているので、もう少し変形を進める。
  494. 過焦点距離とは、被写界深度の遠点が無限遠に届く、最短の撮影距離である。焦点深度と結像公式を用いて被写界深度の近点、遠点と同じ要領で、過焦点距離Hについても式を立てると、
  495. <img src="/archives/images/DoF07.png">
  496. となる。下の式からt=f+εが得られ、それを用いて上の式をHについて解くと、
  497. <img src="/archives/images/DoF08.png" alt="H=\frac{tf}{t-f}=\frac{(f+\epsilon)f}{\epsilon}\approx\frac{f^2}{\epsilon}=\frac{f^2}{F\delta}">
  498. すなわち<strong>過焦点距離=レンズ焦点距離<sup>2</sup>÷(絞り値×許容ボケ)</strong>と求まる。これを用いてs<sub>n</sub>, s<sub>f</sub>をさらに整理する。
  499. <img src="/archives/images/DoF09.png" alt="s_n\approx\frac{sf^2}{f^2+\epsilon s}=\frac{sf^2}{f^2+\frac{f^2}{H}s}=\frac{Hs}{H+s}">
  500. <img src="/archives/images/DoF10.png" alt="s_f\approx\frac{sf^2}{f^2-\epsilon s}=\frac{sf^2}{f^2-\frac{f^2}{H}s}=\frac{Hs}{H-s}">
  501.  
  502. 従って、
  503. 被写界近点=(過焦点距離×合焦距離)÷(過焦点距離+合焦距離)
  504. 被写界遠点=(過焦点距離×合焦距離)÷(過焦点距離−合焦距離)
  505. である。
  506.  
  507. なお、過焦点距離の計算には許容ボケが必要になるが、許容ボケは通常、フィルムやセンサーの対角線長÷1300、が用いられる。
  508. 35mmフィルムなら、√(36<sup>2</sup>+24<sup>2</sup>)/1300≒0.03328 (≒1/30) mm、
  509. フォーサーズ/マイクロフォーサーズなら√(17.3<sup>2</sup>+13<sup>2</sup>)/1300≒0.01665 (≒1/60) mm、である。
  510. ]]></description>
  511.         <link>http://ynomura.dip.jp/archives/2016/07/post_57.html</link>
  512.         <guid>http://ynomura.dip.jp/archives/2016/07/post_57.html</guid>
  513.                  <category domain="http://www.sixapart.com/ns/types#category">雑記</category>
  514.        
  515.        
  516.         <pubDate>Tue, 05 Jul 2016 19:57:23 +0900</pubDate>
  517.      </item>
  518.            <item>
  519.         <title>角換わり棒銀の定跡形で悩む</title>
  520.         <description><![CDATA[昨日は毎年参加している将棋大会だった。
  521. 昨年は<a href="/archives/2015/06/4_1.html">ベスト4まで行った</a>のだが、今年は1回戦敗退だった。
  522. 筆者はこの所公私共に多忙で、ほとんど将棋を指していなかったので、予選突破できただけで上出来である。予選敗退した場合の抽選の指導対局に備えて駒落ちの定跡本を携えていたが、出番が無かった。
  523.  
  524. 今年は、予選の2局と決勝の1局全て、筆者が苦手とする角換わりを仕掛けられ、全て棒銀で応対した。予選の2局はデタラメな攻めが都合良く炸裂して、一昨年に優勝し昨年準優勝した強敵(一昨年に1回戦で負けた相手)にも勝って大満足だったのだが、決勝の1回戦は、昨年予選で勝った相手に課題の多い負け方をしてしまった。
  525.  
  526. <img src="/archives/images/20160604-1.png" alt="" /> 図1
  527.  
  528. 図1は角換わり棒銀の定跡である。筆者は角換わりには棒銀と決めているので、この局面には何度か遭遇している。1回戦は先手を持ってこの局面になったのだが、ここから後手は△1九角、▲2七飛、△1七歩成、▲同歩、△1八銀と指してきた(図2)。よくある手らしいが、筆者は初めて見た。
  529.  
  530. <img src="/archives/images/20160604-2.png" alt="" /> 図2
  531.  
  532. これに普通に▲2六飛と応対し、△2四歩に部分的な定跡通りに▲1二角と打った(図3)。
  533.  
  534. <img src="/archives/images/20160604-3.png" alt="" /> 図3
  535.  
  536. ▲1二角と打つ時、もし△3三桂とされたらどうすれば良いんだろう、と不安に思いながら指したのだが、実際に△3三桂とされ、焦った。その後、自信無く、▲2四飛△2二歩▲1三香成と進めた。
  537.  
  538. △1九角〜△1八銀が入っていない、図1の形では、△2四同歩に▲1二角△2二金▲3四角成△3三金▲2四馬が定跡である。これだけは覚えていた。
  539. 激指14で解析すると、やはり図1からは定跡通り△2四同歩▲1二角△2二金〜▲2四馬が最善であり、▲1二角△3三桂には▲2四飛△2二歩▲2一角成として▲8三香を狙うのが良いらしい。しかし、本局の図3からはそうでなく、
  540. ・▲1二角△3三桂▲2四飛△2二歩には▲6八玉が最善(次善は▲4八金と本譜の▲1三香成)
  541. ・▲1二角△3三桂▲2四飛に△2二歩でなく△2三歩が最善
  542. ・▲1二角では▲2四飛が最善(△2三歩なら▲1四飛で飛車成りが防げない)
  543. だったようだ。前の2つは難しいが、最後のは少し考えたらわかることである。次の△3三桂ばかり気にして、▲1二角以外の手を読まなかったのが失敗だった。
  544.  
  545. それでも、▲1三香成までにそれほどひどい手はない。▲1三香成の後、△2九銀成▲同飛△3七角成▲4八金△1五馬(図4)と進んだが、ここで絶好の機会を逃した。
  546.  
  547. <img src="/archives/images/20160604-4.png" alt="" /> 図4
  548.  
  549. 香を打ったら馬が死ぬと勘違いして▲1六香と打ったら、△2五馬と寄られて空振りした。
  550. ここでは▲1六銀で馬が死んでいたし、▲2四銀でも△2五馬なら▲3三銀が馬取りでひどいので馬を切る一手だっただろう。
  551.  
  552. 実戦はこの後、お互いに怪しい手が多かったので省略するが、飛車をいじめられ、大悪手を指して挽回不能になってしまった。その攻める手は大悪手とわかっていながら、他に粘る手を全く思い付かなかったのである。激指で解析すると、色々粘る手はあったようだが、どれも筆者には理解できなかった。直接の敗因は▲6八玉を怠って飛車をいじめられたことだが、図4のチャンスを逃したのが運命の分かれ道だったと思う。
  553. △2九銀成〜△3七角成とされる前にどこかで▲4八金と防ぐべきだったかも知れないが、△4五桂の当たりが強くなるので、やるなら△3三桂の前だと思うが、△3三桂の前には別に有効な手があったので、適当なタイミングが無かったと思う。
  554.  
  555. それより、図2から▲2六飛△3五銀とされた場合にどうすれば良いのかがわからない。感想戦では後手が自信無かったと言っていたが、激指14では△3五銀が最善であり、▲5六飛に△2九銀不成でも△4二金▲2三歩成でも後手やや良しと計算される。図1から▲5六飛まで先手に変化の余地はなく、もしそうなら図1は既に先手がまずいことになる。プロの棋戦には見つからなかったが、プロが図2の△1八銀を見落とすはずがない。プロも激指14も最善としない△1八銀に対策が見つからないとはどういうことなのだろう。
  556. 激指14の最善手は、▲2六飛△3五銀▲5六飛△2九銀不成▲4八金△5四桂▲7五歩という難解な手順である。△2九銀不成に▲5三飛成は次善手で、その後△5二金▲5六龍△3七角成▲6八玉△4四桂▲6六龍△1五馬で後手やや良しだそうだが、アマチュアとしては駒損でも龍ができて気持ちが楽になるので、これを選択すべきか。]]></description>
  557.         <link>http://ynomura.dip.jp/archives/2016/06/post_56.html</link>
  558.         <guid>http://ynomura.dip.jp/archives/2016/06/post_56.html</guid>
  559.                  <category domain="http://www.sixapart.com/ns/types#category">将棋</category>
  560.        
  561.        
  562.         <pubDate>Sun, 05 Jun 2016 23:27:27 +0900</pubDate>
  563.      </item>
  564.            <item>
  565.         <title>CppUTestでテスト駆動開発(1)</title>
  566.         <description><![CDATA[<p>図書館で、「テスト駆動開発による組み込みプログラミング」という本に目を引かれ、流し読みしたら結構面白かったので、借りて帰ったのだが、筆者はこの所公私共に多忙で、ほとんど読めないまま返却期限を迎えてしまった。<br />
  567. とりあえず、その本で推薦されていた、<a href="http://cpputest.github.io">CppUTest</a>というユニットテストフレームワークを使ってみた。
  568. </p>
  569. <p>筆者は、凄まじく高コストで生産性の低い日本企業のソフトウェア開発を数年間目の当たりにした後、21世紀に入った頃にテストファーストを含むExtreme Programmingの考え方に全面的に共感し、その時にCUnitというユニットテストフレームワークを使ったことがあるのだが、その価値がわからなかった。わざわざそんなのを使わなくても、ユニットテストを駆動する短いテストドライバを自分で書けば事足りると思ったし、実際、これまでそのようにしてきて困ったことが無い。
  570. </p>
  571. <p>しかし、今回、この本でUnityやCppUTestの話を読むと、ユニットテストフレームワークには最先端の考え方が反映されており、この枠に嵌められてユニットテストを書いたりTDDをすれば、手軽に世界のトップクラスのインテリジェンスに触れられるような気がして、面白そうだと思った。
  572. </p>
  573. <p>そこで、CppUTestを使ってみることにした。
  574. </p>
  575. <p>書籍の第3章のLEDドライバの例を題材に、TDD(テスト駆動開発)方式で、まずは未実装のエラーが出る実行可能なテストを作ってみる。
  576. </p>
  577. LedDriver/LedDriverTest.cpp
  578. <blockquote><code><pre>
  579. #include "CppUTest/TestHarness.h"
  580.  
  581. TEST_GROUP(LedDriver)
  582. {
  583.  void setup()
  584.  {
  585.  }
  586.  void teardown()
  587.  {
  588.  }
  589. };
  590.  
  591. TEST(LedDriver, LedsOffAfterCreate)
  592. {
  593.  FAIL("Start here");
  594. }
  595. </pre></code></blockquote>
  596.  
  597. test_main.cpp
  598. <blockquote><code><pre>
  599. //from README.md
  600. #include &lt;CppUTest/CommandLineTestRunner.h&gt;
  601.  
  602. int main(int ac, char** av)
  603. {
  604.   return CommandLineTestRunner::RunAllTests(ac, av);
  605. }
  606. </pre></code></blockquote>
  607.  
  608. Makefile
  609. <blockquote><code><pre>
  610. CXX = g++
  611. CPPUTEST_HOME := $(HOME)/tmp/cpputest
  612.  
  613. #from README.md
  614. CPPFLAGS += -I$(CPPUTEST_HOME)/include
  615. CXXFLAGS += -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorNewMacros.h
  616. CFLAGS += -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorMallocMacros.h
  617. LD_LIBRARIES = -L$(CPPUTEST_HOME)/lib -lCppUTest -lCppUTestExt
  618.  
  619. TARGET = test_main
  620. SRCS = test_main.cpp LedDriver/LedDriverTest.cpp
  621. OBJS = $(SRCS:.cpp=.o)
  622.  
  623. all: $(TARGET)
  624.  
  625. $(TARGET): $(OBJS)
  626. $(CXX) -o $@ $^ $(CXXFLAGS) $(LD_LIBRARIES)
  627.  
  628. %.o: %.cpp
  629. # GNU make implicit rule + "-o $@"
  630. $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
  631.  
  632. .PHONY: check
  633. check: $(TARGET)
  634. ./$(TARGET) -v
  635.  
  636. .PHONY: clean
  637. clean:
  638. rm -f $(TARGET) $(OBJS) *.gcno *.gcov *~ */*~
  639. find . -name "*.gcda" | xargs rm -f
  640. </pre></code></blockquote>
  641.  
  642. <p>これでmake checkとすると、1つのテストが失敗し、"Start here"と表示される。<br />
  643. 筆者は普段、テストの実行はmake testであるが、make checkが多数派らしいので、今後はそれに倣うことにした。(make testはPerlの世界に多い?)
  644. </p>
  645. <p>MakefileにLedDriver.cのコンパイルが無いのは、TDDの、エラーにならない限りは作らない原則に従っているからである。
  646. </p>
  647. <p>次に、LedDriver/LedDriverTest.cppにテストを追加し、それがpassするようにLedDriver.cを開発するのを繰り返す。<br />
  648. 途中と詳細説明を省略するが、例えば途中段階では次のようになった。
  649. </p>
  650. LedDriver/LedDriverTest.cpp
  651. <blockquote><code><pre>
  652. #include "CppUTest/TestHarness.h"
  653. extern "C" {
  654. #include "LedDriver.h"
  655. }
  656.  
  657. static uint16_t virtualLeds;
  658.  
  659. TEST_GROUP(LedDriver)
  660. {
  661.  void setup()
  662.  {
  663.    LedDriver_Create(&virtualLeds);
  664.  }
  665.  void teardown()
  666.  {
  667.  }
  668. };
  669.  
  670. TEST(LedDriver, LedsOffAfterCreate)
  671. {
  672. uint16_t virtualLeds = 0xffff;
  673. LedDriver_Create(&virtualLeds);
  674. LONGS_EQUAL(0, virtualLeds);
  675. }
  676.  
  677. TEST(LedDriver, TurnOnLedOne)
  678. {
  679. LedDriver_TurnOn(1);
  680. LONGS_EQUAL(1, virtualLeds);
  681. }
  682.  
  683. TEST(LedDriver, TurnOffLedOne)
  684. {
  685. LedDriver_TurnOn(1);
  686. LedDriver_TurnOff(1);
  687. LONGS_EQUAL(0, virtualLeds);
  688. }
  689.  
  690. TEST(LedDriver, TurnOnMultipleLeds)
  691. {
  692. LedDriver_TurnOn(9);
  693. LedDriver_TurnOn(8);
  694. LONGS_EQUAL(0x0180, virtualLeds);
  695. }
  696.  
  697. TEST(LedDriver, AllOn)
  698. {
  699. LedDriver_TurnAllOn();
  700. LONGS_EQUAL(0xffff, virtualLeds);
  701. }
  702. TEST(LedDriver, TurnOffAnyLed)
  703. {
  704. LedDriver_TurnAllOn();
  705. LedDriver_TurnOff(8);
  706. LONGS_EQUAL(0xff7f, virtualLeds);
  707. }
  708.  
  709. IGNORE_TEST(LedDriver, LedMemoryIsNotReadable)
  710. {
  711. // TODO: let LED state read-only
  712. }
  713. </pre></code></blockquote>
  714.  
  715. LedDriver/LedDriver.h
  716. <blockquote><code><pre>
  717. #pragma once
  718. #include &lt;stdint.h&gt;
  719.  
  720. extern void LedDriver_Create(uint16_t *address);
  721. extern void LedDriver_Destroy(void);
  722. extern void LedDriver_TurnOn(int ledNumber);
  723. extern void LedDriver_TurnOff(int ledNumber);
  724. extern void LedDriver_TurnAllOn(void);
  725. </pre></code></blockquote>
  726.  
  727. LedDriver/LedDriver.c
  728. <blockquote><code><pre>
  729. #include "LedDriver.h"
  730.  
  731. enum {ALL_LEDS_ON = ~0, ALL_LEDS_OFF = ~ALL_LEDS_ON};
  732.  
  733. static uint16_t *ledsAddress;
  734.  
  735. static uint16_t convertLedNumberToBit(int ledNumber)
  736. {
  737. return 1 << (ledNumber - 1);
  738. }
  739.  
  740. void LedDriver_Create(uint16_t *address)
  741. {
  742. ledsAddress = address;
  743. *ledsAddress = ALL_LEDS_OFF;
  744. }
  745.  
  746. void LedDriver_Destroy(void)
  747. {
  748. }
  749.  
  750. void LedDriver_TurnOn(int ledNumber)
  751. {
  752. *ledsAddress |= convertLedNumberToBit(ledNumber);
  753. }
  754.  
  755. void LedDriver_TurnOff(int ledNumber)
  756. {
  757. *ledsAddress &= ~convertLedNumberToBit(ledNumber);
  758. }
  759.  
  760. void LedDriver_TurnAllOn(void)
  761. {
  762. *ledsAddress = ALL_LEDS_ON;
  763. }
  764. </pre></code></blockquote>
  765.  
  766. Makefile
  767. <blockquote><code><pre>
  768. CXX = g++
  769. CC = gcc
  770. CPPUTEST_HOME := $(HOME)/tmp/cpputest
  771.  
  772. #from README.md
  773. CPPFLAGS += -I$(CPPUTEST_HOME)/include
  774. CXXFLAGS += -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorNewMacros.h
  775. CFLAGS += -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorMallocMacros.h
  776. LD_LIBRARIES = -L$(CPPUTEST_HOME)/lib -lCppUTest -lCppUTestExt
  777.  
  778. TARGET = test_main
  779. SRCS = test_main.cpp LedDriver/LedDriverTest.cpp
  780. CSRCS = LedDriver/LedDriver.c
  781. OBJS = $(SRCS:.cpp=.o) $(CSRCS:.c=.o)
  782.  
  783. all: $(TARGET)
  784.  
  785. $(TARGET): $(OBJS)
  786. $(CXX) -o $@ $^ $(CXXFLAGS) $(LD_LIBRARIES)
  787.  
  788. %.o: %.cpp
  789. # GNU make implicit rule + "-o $@"
  790. $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
  791.  
  792. %.o: %.c
  793. # GNU make implicit rule + "-o $@"
  794. $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
  795.  
  796. .PHONY: check
  797. check: $(TARGET)
  798. ./$(TARGET) -v
  799.  
  800. .PHONY: clean
  801. clean:
  802. rm -f $(TARGET) $(OBJS) *.gcno *.gcov *~ */*~
  803. find . -name "*.gcda" | xargs rm -f
  804. </pre></code></blockquote>
  805.  
  806. <p>make checkすると、"OK (7 tests, 6 ran, 6 checks, 1 ignored, ...)"となる。<br />
  807. ignoredなのは「実行可能なリマインダ」である。
  808. </p>
  809.  
  810. <p>ところで、CppUTestには簡単なメモリリーク検出機能がある。各TEST()の実行前にTEST_GROUPのsetup()が、実行後にteardown()が呼び出されるが、そのsetup()前とteardown()後とでメモリ確保状態を比較するようである。<br />
  811. 試しに、LedDriver/LedDriver.cのLedDriver_TurnAllOn()を
  812. <blockquote><code><pre>
  813. #include &lt;stdlib.h&gt;
  814. void LedDriver_TurnAllOn(void)
  815. {
  816. void *p = malloc(1);
  817. *ledsAddress = ALL_LEDS_ON;
  818. }
  819. </pre></code></blockquote>
  820. に変えてmake checkとすると、次のエラーメッセージが出た。
  821. <blockquote><samp><pre>
  822. TEST(LedDriver, AllOn)
  823. LedDriver/LedDriverTest.cpp:46: error: Failure in TEST(LedDriver, AllOn)
  824. Memory leak(s) found.
  825. Alloc num (6) Leak size: 1 Allocated at: LedDriver/LedDriver.c and line: 35. Type: "malloc"
  826. </pre></samp></blockquote>
  827. </p>
  828. <p>うまく使えば便利そうである。<br />
  829. CppUTestに触れてみて、TDDをきちんと勉強しようと思った。
  830. </p>]]></description>
  831.         <link>http://ynomura.dip.jp/archives/2016/05/cpputest1.html</link>
  832.         <guid>http://ynomura.dip.jp/archives/2016/05/cpputest1.html</guid>
  833.                  <category domain="http://www.sixapart.com/ns/types#category">PC一般</category>
  834.        
  835.        
  836.         <pubDate>Sun, 29 May 2016 18:22:12 +0900</pubDate>
  837.      </item>
  838.            <item>
  839.         <title>&quot;Sum and Product Puzzle&quot;をPythonで解いてみた</title>
  840.         <description><![CDATA[<p>
  841. 昔、多分NetNewsのfj.sci.mathかどこかだと思うが、次のような問題が流れていた。
  842. <blockquote>
  843. 司会と A さん, B さんがいます.
  844. <br />
  845. 司会 「今から Joker を除いたトランプ 52 枚から無作為に 2 枚を取り出し, A さんにはその二数の積を, B さんには和を教えます. その数から元の二数が何であるかを考えてください」
  846. <br />
  847. A, B 「はい」
  848. <br />
  849. 司会 「(B さんにわからないよう, A さんに積を教える)」
  850. <br />
  851. 司会 「(A さんにわからないよう, B さんに和を教える)」
  852. <br />
  853. A さん 「教えてもらった数からは元の二数はわかりません」
  854. <br />
  855. B さん 「私もわかりません. でも, A さんが『わからない』と言うのはわかっていました」
  856. <br />
  857. A さん 「それなら私はわかりました」
  858. <br />
  859. B さん 「それなら私もわかりました」
  860. <br />
  861. さて, A さん, B さんの聞いた数はそれぞれいくつでしょう?
  862. </blockquote>
  863. これだけで答えが1つに特定できることが驚きであり、取ってあった。それをたまたま見つけたので、もう一度やってみた(解説は後述)。<br />
  864. 一見どこから手を付ければ良いのかわからないが、「A さんが『わからない』と言うのはわかっていました」からBさんの数字を考えてみると、ほぼ答えまで絞られるので、解くのにそれほど時間はかからない。
  865. </p>
  866. <p>
  867. NetNewsの元の投稿は探せなかったが、その代わりに、この問題の元ネタが見つかった。
  868. 元の問題は1969年に発表されたもので、その後に<a href="https://www.math.uni-bielefeld.de/~sillke/PUZZLES/logic_sum_product">様々なバリエーション</a>が作られ、一連の問題は"Sum and Product Puzzle"と呼ばれているらしい。参考文献[1]によると、1979年にMartin Gardnerが"the Impossible Puzzle"と呼んで紹介した頃の英語版の1つは次のようなものだったらしい。
  869. <blockquote>
  870. Two numbers m and n are chosen such that 2 &le; m &le; n &le; 99. Mr. S is told their sum and Mr. P is told their product. The following dialogue ensues:<br />
  871. Mr. P: I don&rsquo;t know the numbers.<br />
  872. Mr. S: I knew you didn&rsquo;t know. I don&rsquo;t know either.<br />
  873. Mr. P: Now I know the numbers.<br />
  874. Mr. S: Now I know them too.<br />
  875. <br />
  876. In view of the above dialogue, what are the numbers?<br />
  877. </blockquote>
  878. 元の2数の範囲が2〜99なだけで、後は全く同じである。おそらく同じようにして解けるのだが、範囲が広い為に格段に面倒である。<br />
  879. どうせ、部分的にヒューリスティックに絞り込んでいるが、しらみ潰しに探しているのと大差無い。おそらく、整数の範囲を制限しているので、しらみ潰しに探す以外に解法は無いと思う。(例えば「2より大きいあらゆる偶数は素数の和で表せる」というゴールドバッハ予想も、整数の範囲を制限しているので、単独では使えない。m+nとしてあり得る188は7+181 = 31+157 = 37+151 = 61+127 = 79+109であり、99以下の素数の和ではないので、m,nが共に素数である組み合わせが無い。)<br />
  880. プログラミングの勘を取り戻す為のリハビリを兼ねて、プログラムを作ってしらみ潰しに探すことにした。
  881. </p>
  882. <blockquote><pre>
  883. #!/usr/bin/python
  884.  
  885. MIN = 2
  886. MAX = 99
  887.  
  888. def good_factors(p):
  889.    """Generates pairs of factors of p"""
  890.    return [(m,n) for m in range(MIN, MAX+1) for n in range(MIN, MAX+1) if m <= n and m*n == p]
  891.  
  892. def good_summands(s):
  893.    """Generates pairs of summands of s"""
  894.    return [(m,n) for m in range(MIN, MAX+1) for n in range(MIN, MAX+1) if m+n == s and m <= n]
  895.  
  896. def fact1(m, n):
  897.    """Mr. P: I don't know the numbers."""
  898.    return len(good_factors(m*n)) > 1
  899.  
  900. def fact2(m, n):
  901.    """Mr. S: I knew you didn't know."""
  902.    for (m_, n_) in good_summands(m+n):
  903.        if not fact1(m_, n_):
  904.            return False
  905.    return True
  906.  
  907. # This is not necessary but just writing straightforward
  908. def fact3(m, n):
  909.    """Mr. S: I don't know either."""
  910.    return len(good_summands(m+n)) > 1
  911.  
  912. def fact4(m, n):
  913.    """Mr. P: Now I know the numbers."""
  914.    fact2_compliers = [(m,n) for (m,n) in good_factors(m*n) if fact2(m,n)]
  915.    return len(fact2_compliers) == 1
  916.  
  917. def fact5(m, n):
  918.    """Mr. S: Now I know them too."""
  919.    fact4_compliers = [(m,n) for (m,n) in good_summands(m+n) if fact4(m,n)]
  920.    return len(fact4_compliers) == 1
  921.  
  922. result = [(m,n) for m in range(MIN, MAX+1) for n in range(MIN, MAX+1) if m <= n and fact1(m,n) and fact2(m,n) and fact3(m,n) and fact4(m,n) and fact5(m,n)]
  923.  
  924. print "result =", result
  925. </pre></blockquote>
  926. <p>これを実行すると、(m,n)の正解である(4,13)が出力される。<br />
  927. MIN = 1, MAX = 13にすると、冒頭のトランプの問題の元の2数も計算できる。
  928. </p>
  929. <p>但し、心持ち関数型プログラミングっぽくしてみたが、これだととても時間がかかる(Intel Core i5 1.6GHzのCPUでも2分以上)。次のように、good_factors()とgood_summands()が計算結果をキャッシュするように書き換えると、20倍くらい速くなった。
  930. <blockquote><pre>
  931. good_factors_dict = {}
  932. def good_factors(p):
  933.    """Generates pairs of factors of p"""
  934.    if not good_factors_dict.has_key(p):
  935.        good_factors_dict[p] = [(m,n) for m in range(MIN, MAX+1) for n in range(MIN, MAX+1) if m <= n and m*n == p]
  936.    return good_factors_dict[p]
  937.  
  938. good_summands_dict = {}
  939. def good_summands(s):
  940.    """Generates pairs of summands of s"""
  941.    if not good_summands_dict.has_key(s):
  942.        good_summands_dict[s] = [(m,n) for m in range(MIN, MAX+1) for n in range(MIN, MAX+1) if m+n == s and m <= n]
  943.    return good_summands_dict[s]
  944. </pre></blockquote>
  945. </p>
  946. <p>◆参考文献<br />
  947. [1] "Sum and Product in Dynamic Epistemic Logic"<br />
  948. H. P. van Ditmarsch, et al.<br />
  949. J Logic Computation (2008) 18 (4): 563-588<br />
  950. First published online: December 21, 2007<br />
  951. <a href="http://www.cs.otago.ac.nz/staffpriv/hans/sumpro/sumandproduct06.pdf">http://www.cs.otago.ac.nz/staffpriv/hans/sumpro/sumandproduct06.pdf</a>
  952. </p>]]></description>
  953.         <link>http://ynomura.dip.jp/archives/2016/05/sum_and_product.html</link>
  954.         <guid>http://ynomura.dip.jp/archives/2016/05/sum_and_product.html</guid>
  955.                  <category domain="http://www.sixapart.com/ns/types#category">数学</category>
  956.        
  957.        
  958.         <pubDate>Wed, 04 May 2016 00:20:59 +0900</pubDate>
  959.      </item>
  960.            <item>
  961.         <title>3手目角交換からの▲4五角について</title>
  962.         <description><![CDATA[10年以上前だろうか、Yahoo!将棋やハンゲームでネット将棋をよく指していた頃、後手を持って、▲7六歩に△3四歩とすると、いきなり角交換をされて▲4五角と打たれることがよくあった。
  963.  
  964. <img src="/archives/images/sjchgaikak1.png" />
  965.  
  966. これである。本当によくやられた。流行だったのだろうか。
  967.  
  968. 筆者は、これをされるのが本当に嫌だった。
  969. といっても、よく負けたからではない。むしろ同程度のレーティング(アマ三段程度)の相手によく勝った。後手を持って勝率は6割を超えていたと思う。
  970.  
  971. 何故嫌だったかと考えると、この手は自ら損をしに行く無謀な手だと思っており、それに勝っても嬉しくないからだった。
  972. この後に特に気を付けるべき手があった経験は無く、つまりハメ手でもなく、しかも先手が角を手放してまで入手した一歩がものを言う展開になったこともほとんどなく、単に混沌とした展開に持ち込んで相手のミスを誘うだけの、乱暴な手だと思っていた。
  973.  
  974. 昔からあるこの手に有名な定跡が見当たらないのも、この▲4五角にて後手良し、が共通見解だからだと今でも思っている。自ら不利な状況を選択する手で、その先に有効な手が無さそうであれば、対策を研究する必要があまり無い。何せ、ミスしなければ勝てるのだから。
  975. ▲7六歩に△4四歩(ハメ手なのだろうか、年配の知人で何度負けてもこれを愛用する人が居た)(追記:パックマンという名が付いているらしい)ほど無謀だとは思わないが、そういうことをされると、勝って当然で負けたら悔しい、指すだけ損の将棋になるので、やる気を無くしたのである。
  976.  
  977. 昨年、図書館で「イメージと読みの将棋観」(日本将棋連盟)という本を借りたら、プロにこの▲4五角をどう思うかを尋ねた結果として、総じて先手不利と書かれており、やっぱりな、と思った。
  978. そんな中、この間、実家で、昔買って読んでなかった将棋の本の中に、この▲4五角をテーマにした本があるのを見つけた。「筋違い角と相振り飛車」(木屋太二著 森内俊之監修)という本である。
  979. これまで、筋違い角というのは、下の図のように、5四や5六に角を打つことだと思っていた。
  980. <img src="/archives/images/sjchgaikak8.png" />
  981. この本を読んで、まず、3手目角交換からの▲4五角も筋違い角と呼ぶことに驚いた。(筆者だけか)
  982. 続いて、この▲4五角がプロも監修するような立派な戦法であることに驚いた。
  983.  
  984. 調べてみると、5手目▲4五角の筋違い角はプロの公式戦も1990年以降に50局以上あるので、プロ的にも完全に無い手ではなさそうである。ただ、勝率は後手が6割くらい勝っている。
  985.  
  986. この本は筋違い角側の視点で書かれており、▲3四角の後に▲1六角と引いて大体筋違い角有利となるので、筋違い角を仕掛けられる側としてはあまり参考にならなかった。
  987.  
  988.  
  989. この機会に、これまでに考えたり読んだりした、3手目角交換からの▲4五角の対策を思い出してみた。
  990. 3手目角交換からの▲4五角を頻繁にやられた時期に最初に考えたのは、▲4五角に対して△5二金右▲3四角△6五角であった。
  991. <img src="/archives/images/sjchgaikak2.png" />
  992. 歩損がなく手得なので、悪いはずがない。実際、当時はほとんどこのように指して、まあまあ勝てたと記憶している。
  993.  
  994. しかし、一歩得の代償に角を手放すのは損だと信じると、もっと良くできるはずである。そう思って調べて知ったのが、▲4五角に対して△5二金右▲3四角△6四歩▲8八銀▽6五歩である。
  995. <img src="/archives/images/sjchgaikak3.png" />
  996. △6四歩に▲6六歩とすると△6五歩▲同歩△6六角があるので、▲6六歩とできないのがミソである。
  997. この筋違い角は、▲6六歩とできないと角が狭いので、これで角を攻める展開になれば、後手が指しやすそうである。確か、以前は決定版と言われていた対策だったと思う。
  998. ただ、筆者はあまりこの対策で勝てた記憶が無い。もろに筋違い角を指す人の研究にはまるからだろうか。上述の「筋違い角と相振り飛車」にも後手のこの対策を撃破する手順が複数書かれているので、それを食らっていたのかも知れない。
  999.  
  1000. 一度やってみたいと思っているのは、▲4五角に対して△6二銀▲3四角△3二金▲6六歩△3三銀▲7八角△8四角である。
  1001. <img src="/archives/images/sjchgaikak4.png" />
  1002. これを▲6八飛と受けると、△9五角で王手飛車が掛かるのである。
  1003. <img src="/archives/images/sjchgaikak5.png" />
  1004. それでも先手が一歩得なので後手有利とは言い切れないが、アマチュアレベルでは序盤の飛角交換は飛車有利ではないだろうか。
  1005.  
  1006. しかしながら、上述の「イメージと読みの将棋観」に載っていた、藤井九段の腰掛銀+△4五歩が最強の対策かなという気がする。
  1007. <img src="/archives/images/sjchgaikak9.png" />
  1008. これは相当に先手が動きづらそうである。
  1009.  
  1010. 手順の一例は、▲7六歩△3四歩▲2二角成△同銀▲4五角の後、
  1011. △6二銀 ▲3四角 △3二金 ▲6六歩 △6四歩 ▲8八銀 △6三銀 ▲7七銀
  1012. △5四銀 ▲6八飛 △4四歩 ▲6七角 △4五歩
  1013. である。△4五歩を阻止するには先に▲4六歩とする必要があるが、先手は角打ちの隙を与えずに▲4六歩とすることが難しいので、実現しやすそうな対策である。
  1014. ]]></description>
  1015.         <link>http://ynomura.dip.jp/archives/2016/03/post_55.html</link>
  1016.         <guid>http://ynomura.dip.jp/archives/2016/03/post_55.html</guid>
  1017.                  <category domain="http://www.sixapart.com/ns/types#category">将棋</category>
  1018.        
  1019.        
  1020.         <pubDate>Sun, 13 Mar 2016 22:19:16 +0900</pubDate>
  1021.      </item>
  1022.            <item>
  1023.         <title>ローカルメールサーバーのセットアップ</title>
  1024.         <description><![CDATA[このweblogは長年自宅サーバーのMovableTypeで運用しているが、これまでメール通知の設定をしていなかった。従って、コメントがあってもメール通知されず、自らMovableTypeの管理画面を開かないと気付かなかった。
  1025.  
  1026. メール通知の設定をしなかったのは、その為にはMovableTypeが稼働するサーバーにメールサーバーを立ち上げる必要があり、セキュリティに自信が無かったからである。システムのどこかに欠陥が発生して、24時間、宅外に大量のメールを発信し続けてしまうような事態は絶対に発生させたくないのである。
  1027.  
  1028. しかし、コメントを頂いたのに気付かず、1週間くらい承認待ちのままだったことが何度かあり、その度に、やっぱりメールサーバーを立ち上げようかと思ったのだが、以前はコメントもトラックバックも<a href="/archives/2013/12/hgwheezysqueeze.html">SPAMの嵐だった</a>ので、メール通知しても紛れてわからないので無駄だと思った。
  1029.  
  1030. その後、<a href="/archives/2013/12/hgwheezysqueeze.html#mt-keystrokes">ほとんどのSPAMがブロックできるようになった</a>が、コメントもトラックバックも1通も届かない日が増えると油断するようになり、昨年夏にも1度、5日ほど未承認のコメントに気付かないことがあった。
  1031. それ以来、毎日確認するようにしているが、それが面倒になってきたので、やっぱりメールサーバーを立ち上げてメール通知の設定をすることにした。
  1032.  
  1033.  
  1034. メールサーバーのプログラムは、安全上の理由でSendmailを避け、Postfixを選択した。
  1035. POP3サーバーは、慣れ親しんだqpopperがDebianに見つからなかったので、Dovecotを選択した。安全で導入が簡単な、定番の組み合わせである。
  1036.  
  1037. その他に、メールサーバーの仕様として、次のように決めた。
  1038. ・宅外にはリレーしない
  1039. ・宅内でサーバーからPOP3で取り出す
  1040. ・サーバー内の全てのアカウント宛のメールをPOP3で取り出せるようにする
  1041.  
  1042.  
  1043. 以下、実際に行ったことを記す。
  1044.  
  1045. ■Postfixのセットアップ
  1046. 1. aptitudeで"postfix"を選択してインストール実行
  1047.  
  1048. 2. Postfix Configurationの画面で
  1049. No configuration
  1050. Internet Site
  1051. Internet with smarthost
  1052. Satellite system
  1053. Local only
  1054. の中から"Local only"を選択
  1055.  
  1056. 3. サービス起動時に<blockquote>warning: inet_protocols: disabling IPv6 name/address support: Address family not supported by protocol</blockquote>と出た(IPv6の準備はしていないから)ので、/etc/postfix/main.cfに<blockquote>inet_protocols = ipv4</blockquote>を追加
  1057.  
  1058. 4. 念の為、<blockquote>inet_interfaces = loopback-only
  1059. relayhost =</blockquote>であることを確認
  1060.  
  1061.  
  1062. ■Dovecotのセットアップ
  1063. 1. aptitudeで"dovecot-pop3d"を選択してインストール実行
  1064.  
  1065. 2. 途中、<blockquote>Error: socket() failed: Address family not supported by protocol</blockquote>というエラーになり(これもこのサーバーがIPv6に非対応だから)、aptitude上で"C"(= Half-configured)マークが付いたので、/etc/dovecot/dovecot.confに<blockquote>listen = *</blockquote>を追加して、aptitudeでそのまま(gを2回押して)再実行
  1066.  
  1067. 3. LAN内のPCからメール受信すると、<blockquote>pop3(user01): Error: file_dotlock_create(/var/mail/user01) failed: Permission denied (euid=1001(user01) egid=100(users) missing +w perm: /var/mail, we're not in group 8(mail), dir owned by 0:8 mode=0775) (set mail_privileged_group=mail)</blockquote>というエラーが出て、受信したメールが/var/spool/mail/から消えなかったので、/etc/dovecot/conf.d/10-mail.confに<blockquote>mail_privileged_group = mail</blockquote>を追加
  1068.  
  1069.  
  1070. ■全ての宛先のメールを特定のアカウントに転送する設定
  1071. Dovecotのデフォルト設定では、uidが500以上のアカウントしか受け付けないようになっており、しかもrootでのログインは一切受け付けないようになっている(/etc/dovecot/conf.d/10-mail.confのfirst_valid_uidの説明を参照)ので、root宛のメールも取り出したければ、root宛のメールを別のアカウントに転送するしかない。
  1072.  
  1073. 1. /etc/postfix/main.cfに<blockquote>virtual_alias_maps = regexp:/etc/postfix/virtual</blockquote>を追加
  1074.  
  1075. 2. /etc/postfix/virtualを次の内容で作成<blockquote>/.+@.+/ user01</blockquote>(postmap /etc/postfix/virtualは省略)
  1076.  
  1077. 3. Postfixを再起動
  1078.  
  1079. Perlの正規表現しか覚えていない身としては、virtual_alias_mapsの<code>regexp:</code>は<code>pcre:</code>にしたかったが、postfix-pcreというパッケージを別途インストールする必要があるので、諦めた。
  1080. ※pcre = perl compatible regular expression
  1081.  
  1082. なお、Webで検索すると、virtual_alias_mapsを設定するのではなく、<blockquote>luser_relay = user01
  1083. local_recipient_maps =</blockquote>とすれば良いという情報がいくつもあるが、それだと実在のアカウントのメールが転送されなかった。
  1084. 筆者の環境では他にも設定が必要なのかも知れない(これだけだとlocal_recipient_mapsがキャンセルされないのかも)が、深追いしなかった。
  1085.  
  1086.  
  1087. ■MovableTypeのメールアドレス変更
  1088. プロバイダーのメールアドレスを設定していたので、ローカルサーバーのメールアドレスに変更する必要があったが、設定したメールアドレスが、MovableTypeの管理画面のシステム・メニューにもシステム全体の設定画面にも各ブログの設定画面にも見当たらず、CGIのスクリプトやmt-staticの中をgrepしても見当たらなかったので、結構難儀してしまった。
  1089.  
  1090. ネットでキャプチャー画面付きの説明を見つけてやっと、MovableTypeの管理画面の「現在のログイン名:」の横のユーザー名をクリックすれば出てくることがわかった。]]></description>
  1091.         <link>http://ynomura.dip.jp/archives/2016/01/post_54.html</link>
  1092.         <guid>http://ynomura.dip.jp/archives/2016/01/post_54.html</guid>
  1093.                  <category domain="http://www.sixapart.com/ns/types#category">ウェブログ環境構築</category>
  1094.        
  1095.        
  1096.         <pubDate>Sun, 24 Jan 2016 21:33:05 +0900</pubDate>
  1097.      </item>
  1098.            <item>
  1099.         <title>特定の文字列を含まないという正規表現</title>
  1100.         <description><![CDATA[正規表現で、特定の文字列を含まないパターンを記述するのは難しい。
  1101.  
  1102. その文字列の文字数が少なければ、例えば"ABC"を含まないとするなら<blockquote><code>([^A]|A[^B]|AB[^C])*</code></blockquote>という方法がありそうで、筆者は時々やってしまうのだが、これは正しくない。"AABC"があると"AA"がA[^B]にマッチ、"ABABC"があると"ABA"がAB[^C]にマッチしてスルーしてしまうし、"A"や"AB"で終わるとマッチしないからである。
  1103. この方向で進めると、一例としては、<blockquote><code>([^A]|A(B?A)*([^AB]|B[^AC]))*(A(B?A)*B?)?</code></blockquote>という式になるそうだが(<a href="http://www.din.or.jp/~ohzaki/regex.htm#WithoutXYZ">大崎 博基さんの「Perl正規表現雑技」</a>より)、これは少なくとも筆者には読めない。
  1104.  
  1105. 特定の文字を含まない、という式は、例えば"A"を含まないなら<code>[^A]*</code>と簡単に書けるのに、特定の文字列を含まない、となると途端に難しくなるのは不思議である。
  1106.  
  1107. 特定の文字列を含まない行にマッチする、よく知られたパターンとして、<blockquote><font size="+1"><code>(?!.*ABC).*</code></font></blockquote>というやつがある。<code>(?!...)</code>はnegative lookahead assertion(否定先読み)というやつで、その先に...が続かない、という条件を表す。<code>(?=...)</code>はその先に...が続くというpositive lookahead assertionであり、<code>ABC(?=DEF)</code>は"ABCDEF"の"ABC"にマッチし、<code>ABC(?!DEF)</code>は"ABCDEF"の一部でない"ABC"にマッチする。
  1108. <code>(?=...)</code>や<code>(?!...)</code>は、POSIX仕様などの正規表現の古い仕様には含まれず、grepなど一部使えない処理系があるが(Emacsもサポートしていない。外部コマンドを活用しろということらしい)、PerlやJavaScriptでもサポートされており、現在はほとんどの処理系で使えると言える。
  1109.  
  1110. <code>(?!.*ABC).*</code>の弱点は、文字列全体のマッチにしか使えないことである。例えば、文字列中の"STA"〜"END"の部分を検索したいが、途中に"ABC"を含む場合は除外したいと思って、<code>STA(?!.*ABC).*END</code>と書くと、"STAxxENDxABC"のように、"END"の後に"ABC"がある場合もマッチしなくなってしまう。
  1111.  
  1112. 今回、そういうのが必要になって、悩みながら、何かいい方法は無いかと思ってWeb上を探してみたら、<blockquote><font size="+1"><code>((?!ABC).)*</code></font></blockquote>というのを見つけた。この文字から先が"ABC"でない任意の文字が0個以上、である。すごい発想だと思った。
  1113.  
  1114. Web上には<code>(.(?!ABC))*</code>と書いている例もあり、同じだと勘違いして、早速<code>(.(?!ABC))*</code>を使い始めたのだが、よく考えると<code>(.(?!ABC))*</code>には問題があることに気付いた。これだと、"ABC"を2文字目から検索することになり、先頭がABCの場合に除外されず、マッチしてしまうのである。さらに、例えば、途中に"EN"を含まない"STA"〜"END"の部分を検索するつもりで<code>STA(.(?!EN))*END</code>と書くと、途中に"EN"が無くても、"END"の直前の1文字が必ず<code>.(?!EN)</code>に当てはまらない("END"の"EN"で引っ掛かる)ので、何にもマッチしなくなってしまう。
  1115. <code>((?!ABC).)*</code>にはこれらの問題は起こらない。
  1116. それと対称にして、<code>(?&lt;!)</code>のnegative lookbehind assertionを使って<code>(.(?&lt;ABC))*</code>としても上記の問題は起こらないが、より複雑だし、手元のPerlで試すと10&percnt;ほどの速度低下が見られたので、これを使うメリットは無いだろう。
  1117.  
  1118. 結局、外側の()によって後で参照可能なグループが増えないように、<code>(?:(?!ABC).)*</code>という形にすることによって、筆者の問題は解決した。
  1119. ]]></description>
  1120.         <link>http://ynomura.dip.jp/archives/2015/12/post_53.html</link>
  1121.         <guid>http://ynomura.dip.jp/archives/2015/12/post_53.html</guid>
  1122.                  <category domain="http://www.sixapart.com/ns/types#category">PC一般</category>
  1123.        
  1124.        
  1125.         <pubDate>Fri, 25 Dec 2015 20:55:05 +0900</pubDate>
  1126.      </item>
  1127.            <item>
  1128.         <title>スパコン「京」を目撃</title>
  1129.         <description><![CDATA[昨日、神戸市他が主催する、<a href="http://www.city.kobe.lg.jp/information/press/2015/10/20151023041601.html">一般向けセミナー「意外と知らない?暮らしを支えるスパコンの働き」</a>に行ってきた。
  1130.  
  1131. その前の見学会で、スーパーコンピューター「京」を見てきた。
  1132. <a href="/archives/images/Kei20151205.JPG"><img src="/archives/images/Kei20151205.JPG" width="320" height="188"></a>
  1133. 下の階でポスターの展示をゆっくり見てたら、「京」を見る時間が10分くらいしか無くなってしまった。
  1134. 見学室に入ると、説明員の方が会場からの質問を受けていた。次々に質問がなされていて、
  1135. 「京」は一般向けに時間貸ししていること(部分的に借りれる)、
  1136. 「京」の100%を借りると一時間百数十万円であること、
  1137. 「京」を100%使う用途も20以上あるが他の人が使えなくなるので月1〜2日に決めていること、
  1138. CPUはSPARCというやつ、
  1139. OSがLinuxであること、
  1140. 「京」の候補地は最後に神戸と仙台に絞られ、インフラの利で神戸に決まったこと、
  1141. 2020年運用開始予定のポスト「京」も今と同じ場所に作られること、
  1142. がわかった。
  1143.  
  1144. セミナーの開会の挨拶では、文部科学省の人がスパコン研究プロジェクトの必要性を熱く語っておられた。
  1145. 「行政事業レビュー」で「数ある事業の中で最も説明されてこなかったのがスパコン事業だ」と厳しく追及された件は、実際には色々説明していたが、政治家に発せられたその一言だけをマスコミが取り上げてフォローしないから世間的にスパコン研究が無駄という印象になっているのが実態であること、なぜ「2位じゃダメなんでしょうか」の理由は、単純明快なので何度も言われてきたことだが、1位のものを製造する技術があって初めて国際的な競争力になるから、ときっちり説明された。
  1146.  
  1147. 講演は4つなされた。セミナーは撮影禁止だったので、細かい内容は伏せるが、無難な概要と、筆者がした質問と講演者からの回答を記しておく。
  1148.  
  1149. 1. 「シミュレーション事始め」
  1150.  シミュレーションするには、物理モデルを作って、四則演算のみのアルゴリズムにして、プログラムを作る、精度を上げるには解像度を上げる(シミュレーションする三次元的な位置を細かく取る)必要があり、3乗や4乗(三次元+時間)のオーダーで計算量が増えるのでスパコンが必要になる、スパコンの根幹の技術は複数台のコンピューターを接続する技術、という一般的な話。
  1151. Q:インターネット上の複数台のコンピューターを接続して並列計算を行う場合の接続技術とスパコン内のプロセッサーの接続技術との特徴的な違いは?
  1152. A:距離と遅延。隣のノードの計算結果が頻繁に必要になる場合はスパコンが有利。
  1153.  
  1154. 2. 「『京』が拓く天気予報の未来」
  1155.  スパコンによるシミュレーションと、全方位レーダーによる高速で詳細な雨雲の観測などの最新の観測技術を組み合わせることによって、雨雲が無い状態から30分後に発生するゲリラ豪雨も10分や15分前に予測できるようになるなど、新たなことができるようになる可能性が色々あるという話。
  1156.  
  1157. 3. 「世界最先端スパコンが変えるタイヤづくり」
  1158.  タイヤの分子構造を兵庫県にあるSPring-8で計測して「京」てシミュレーションすることによって、低転がり抵抗、高グリップ性能のタイヤの耐摩耗性能を倍にする方法を発見したという話。
  1159. Q:動的な物理モデルの正確さはどのようにして確認したのか、正確でなかった時はどうやって改良したのか?
  1160. A:やはり高性能な計測機器を用いて実物の動きを計測しながらモデルを作成している。
  1161.  
  1162. 4. 「電気自動車高性能化への挑戦:スパコンと放射光が解き明かす電池の姿」
  1163.  SPring-8と「京」を用いることによって原子構造、電子構造のシミュレーションを実現し、充電式電池の性能を向上する構造を見つることができたという話。
  1164. ]]></description>
  1165.         <link>http://ynomura.dip.jp/archives/2015/12/post_52.html</link>
  1166.         <guid>http://ynomura.dip.jp/archives/2015/12/post_52.html</guid>
  1167.                  <category domain="http://www.sixapart.com/ns/types#category">雑記</category>
  1168.        
  1169.        
  1170.         <pubDate>Sun, 06 Dec 2015 12:43:53 +0900</pubDate>
  1171.      </item>
  1172.      
  1173.   </channel>
  1174. </rss>
  1175.  

If you would like to create a banner that links to this page (i.e. this validation result), do the following:

  1. Download the "valid RSS" banner.

  2. Upload the image to your own server. (This step is important. Please do not link directly to the image on this server.)

  3. Add this HTML to your page (change the image src attribute if necessary):

If you would like to create a text link instead, here is the URL you can use:

http://www.feedvalidator.org/check.cgi?url=http%3A//ynomura.dip.jp/index.xml

Copyright © 2002-9 Sam Ruby, Mark Pilgrim, Joseph Walton, and Phil Ringnalda