時間

2009/07/10

「主筆」の文字列を保持するデータ構造の実装を始めてからかなり時間が経つが、まだコーディングも終わっていない。そもそも、テキストファイルの読み込み/文字コードの変換/マルチバイト-ワイドバイトの変換/データ構造への格納/構文強調表示処理/文字の描画位置の確定/画面への文字列の描画という7種類の処理を全て並列に処理させようと言う野心的な目標なのだから、そう簡単に終わるものとは考えていない。その上、ウインドウ幅での行折り返しに対応させるために、いくつかの余分なデータも保持させなければならないのだから、ますます事態は複雑化し混迷を極めている。

しかし、「主筆」の開発を進める一方で技術士の受験勉強もしなければならない。気がついてみれば、試験日まであと一ヶ月を切っている。論文を書く練習なども、このところ少しさぼり気味だったから、また復活させなければならない。時間は限りなく無いと言える。

どうやらこれは、エロ画像の収集に精を出している場合ではなさそうだ。

共連れ

2009/06/12

ビューとドキュメントの分割に手を付けたのは良いのだが、それをやるためにはどうしてもドキュメント部分の内部構造に大幅に手を入れなければならないようだ。

当面の所は既存ロジックを極力残したまま分割だけを先にやってしまおうと考えていたのだが、やはりどうにも構造がクソで流用するのも難しいと判断したのだ。

そういうことで、ここ数日は文字列操作の要となるデータ構造をどうするかということについて死ぬほど考えていた。

データとして保持しなければならないのは、文字そのものと文字の色、文字の幅である。色は構文強調表示で必要となり、文字の幅はプロポーショナルフォントを取り扱う上で必要となる。でもって、下記の操作に対して最悪でもlog(n)の計算量で処理を完了するようにしなければならない。
 ・文字列の追加
 ・文字列の削除
 ・文字の検索

ここで文字の検索といっているのは、何らかの方法で指定された位置に存在する、とある一文字が格納されているメモリアドレスを求める事を言っている。でもって「何らかの方法」というのには下記のような方法が考えられる。
 ・(行折り返しを考慮しない)行番号と、行頭からの文字数
 ・(行折り返しを考慮した)行番号と、行頭からの文字数

先頭から数えた文字数を用いて、配列のようにアドレッシングを行う可能性は低そうである。どちらかといえば、「画面上のココ」という指定をされて、その文字がメモリ空間中のどこに存在するのかを求める事の方が重要であると思われる。

また、表示や編集の処理を考えた場合、アドレッシングを方法を相互変換する機能も必要になるのは明白である。すなわち、
 ・文字を示すメモリアドレスから、行折り返しを考慮しない行番号と、行頭からの文字数を求める
 ・文字を示すメモリアドレスから、行折り返しを考慮した行番号と、行頭からの文字数を求める
 ・行折り返しを考慮しない行番号と行頭からの文字数から、行折り返しを考慮した行番号と行頭からの文字数を求める
 ・行折り返しを考慮した行番号と行頭からの文字数から、行折り返しを考慮しない行番号と行頭からの文字数を求める
という処理である。

上記の処理はいずれも、一見すると難しいような気もするが、計算量を考慮しない限りそれ程難易度の高いものではない。例えば、文字列を単純に配列に格納して、必要な都度文字列の先頭から総ナメにして要求された値を算出するようにしてやれば、よほどの馬鹿でもない限り実装することは可能なはずである。

だが、問題はこれらの処理を、文字数に対してlog(n)の計算量で解かなければならない所に存在する。

現在で主筆で使用しているロジックは、与えられた文字列を改行コードで区切って部分文字列を構築し、それら部分文字列を指し示すポインタを、単純な配列に入れて管理している。

だから、それこそ何の考えもなしに単一の配列に押し込んでいるよりかは幾分マシだとは言え、本質的には計算量はnに比例する。だから、余り大きなファイルを開くと性能が著しく劣化する。更に、一行の長さがあまりに長くなると、それこそ応答が返ってこないという事態になりかねないため、一行の最大長を10KBにするという制約を設けている。よって、これらの問題をここで一気に解消したいと考えている。

では、どういうデータ構造にすればいいのか。というか、計算量がlog(n)などという、言ってみればデータ量が増えれば増えるほど一文字当たりの計算量が減少するなどという、ご都合主義的な方法が存在するのだろうか?

答えから言えば、方法は存在する。存在するからこそ、こうして俺はゴタクを並べてblogを書いている。

方法としては、B+木を用いればいいはずである。無論「一意に識別できる値を使ってレコードを識別する」という処理ではないため、アルゴリズムは多少変則的なものになるが、それでも不可能ではない。というか、以前、こういった問題について考えたことがあり、その結果をこのページに記述している。要は、これと同じ事をしてやればいいはずなのである。

とは言っても、やはりそれが難しい。

とりあえずは、具体的なデータ構造や値の検索・更新の方法について、ある程度の目処が立ったところではあるが、実装はまだ全く手が着いていない。このままでは第21版の公開は、かなり遠い未来のこととなるであろう。

偽物

2009/05/26

「主筆」のビューとドキュメントの分割に手を着ける前に、とりあえずフォルダ構成を見直しておくことにした。現時点でも、現在公開している第20版には存在しない共有ライブラリが増えているし、フォルダ名がいくつか気に入らない奴が有るため、今の内にきれいにしておくことにしたのだ。

また、生成された共有ライブラリと、その共有ライブラリを使用するために必要となるヘッダファイルが、その共有ライブラリを開発するためのフォルダ内に格納されたままだと何かと都合が悪いため、別途includeとlibというフォルダを用意して、コンパイル後にそのフォルダにシンボリックリンクを作成するようにしておいた。

つまり、たとえばTaEdit/FOOというフォルダを作って、その中でlibFOO.soというライブラリを構築するようにしたとする。そうすると、libFOO.soそのものと、それを使うためのヘッダファイル、たとえばfoo.hは、TaEdit/FOOフォルダの中に存在する事になる。となると、そのlibFOO.soを使うプログラムは、コンパイル時にヘッダファイルとライブラリの検索パスとして、TaEdit/FOOというフォルダのパス名を指定してあげなければならなくなる。

とりあえず、使用するライブラリが1つだけであれば、それは大した事ではない。だが、そういったライブラリがだんだん増えてくると、コンパイル時に指定しなければならなくなるパス名が増えてくることになる。まぁ、だとしても、指定すればいいだけの話だと言ってしまえばそれまでだが、やはりそれでは美しくないため、外部に公開する奴は「公開されるためのフォルダ」を作って、そこに格納するようにしたほうがいい。そうしておけば物事がわかりやすくなるから、コンパイルするときにヘッダファイルが見つからないだの、リンク時にシンボルが見つからないだのと言われる可能性を減らすことができるようになる。

フォルダ構成の整理は、基本的にはMakefileをいじるだけだからそう大した話ではない。もっとも、複数人で開発している場合は、逆にほとんど不可能に等しい荒技ということになるのだが。

今現在は、COMの偽物の仕様ついて考えている。WindowsのCOMの様なことをやりたいとはいっても、しかし、COMそのものを作るつもりはないし、COMと張り合おうというつもりもない。ただ、自分が作ったアプリケーションの範囲内だけでつかわれる、それっぽくモジュールを分割できるような仕掛けが有ればそれでいいのだ。

そうすると、もっともストイックな実装としては、ただ、純粋仮想クラスを継承したオブジェクトを生成して、そのインスタンスを返してよこすだけのライブラリというのが考えられる。すなわち、そのライブラリで提供される関数を一回呼び出してやれば、IDocumentとか何とか、そんな感じの純粋仮想クラスのポインタを返す、そういうライブラリにしておくということだ。

だが、それではちょっとありがたみが薄い。どうせなら、そのライブラリのインタフェース仕様(つまり関数の仕様)や、オブジェクトのインタフェースとなる純粋仮想クラスに一定の規約を当てはめ、その規約を強制するようなライブラリを一枚かぶせるようにした方がいい。そもそも、共有ライブラリの動的ロードや実行時に関数を検索する処理など、ライブラリや実装するオブジェクトによらずみんな同じになるのだから、どうせなら処理を統合した方がいい。

とすると、その規約なりライブラリなりで、どこまで何をサポートするのかが問題となる。とりあえず、純粋仮想クラスを継承したオブジェクトを生成するという機能と、ライブラリ自体がエクスポートする関数は完全にC言語の仕様に準拠していること等と言った物事は、そもそもの目的であることからして外すわけには行かない。

だが、IUnknown::AddRefやIUnknown::Releaseといったメソッドにより提供される、インスタンス管理の機能は必要なのだろうか? 難しいことをやりたいわけでもなし、とりあえずオブジェクトを使う側で間違えなければ、わざわざインスタンス管理の機能をここで実装してやる必要はないものと思われる。もし、参照カウンタなりガーベッジコレクタなりでメモリ管理を行う様にしたいので有れば、それは別の機能として実現すればいいまでの話だ。

また、オブジェクトが提供する別のインタフェースを取得する機能も必要ではない。そんなものは適用にやればいい。COMではGUIDによりインタフェースなどに一意な名前を採番するようにしているが、それも簡略化していいはずだ。どうで、1アプリケーションに閉じた世界の話なのだ。世界中で一意にに識別できなければならない必要性などない。

微妙なのは、インタフェースを実装するライブラリをどこかに登録しておいて、オブジェクト生成時に、自動的に目的となるライブラリを検索できるようにする仕掛けがいるかどうかだ。COMではインタフェースに割り当てられたGUIDとDLLのファイル名をレジストリに登録しておいて、オブジェクトを生成する際にはDLLのファイル名や物理的な場所については意識しなくてもいいようになっている。だが、今回俺が作ろうとしているものには、そのような機能は必要であろうか?

ビューの方から本物のライブラリ名を指定してオブジェクトを生成させるようにしたところで、あまり実害はなさそうな気がする。だが、ライブラリのファイル名とインタフェース名を事前に何かの設定ファイルに登録しておくようにすれば、アプリケーションでライブラリのファイルを保持する必要が無くなり、何か便利になるような気がする。

だが、それ以上の具体的な利点が見えない。必要だろうか? 不要だろうか? どっちでも良さそうな気がするが、きめなきゃ物事が進まない。どうしようか。

一刀両断

2009/05/22

正規表現の最適化なんか考えている場合ではない。技術士の勉強をしなければならないはずである。とりあえず、ここ数日は毎日論文の問題を解くようにしてはいる。だが、そもそも正解というものがない論文は、勉強したところでできるようになるものなのだろうか? それに、手元にある問題数が少ないため、もうやるべきものが無くなってしまった。 とりあえず、漢字の勉強でもしておいた方が良いのだろうか?

「主筆」のウインドウ幅で文字列を折り返して表示する対応に、そろそろ手を付けたいと考えている。だが、それをやるためには文字列の編集と表示という、最もコアな部分に手を入れなければならない。

大変残念なことに、文字列の編集に関わる処理や文字列の表示に関する部分は、「主筆」の中でも最も古いコードに類し、かなりいい加減な作りになっている。特に気に入らないのは、文字列の操作や編集を行うモジュールと、画面の表示を行うモジュールが強く結合していることだ。つまり、ビューがドキュメントの内部構造に立ち入った様な処理になっているということだ。

どう考えてもおかしいこの作りは、開発当初、モチベーションを維持することを目的に、とにかく動作するものをでっち上げようとしたことに起因する。過去の経験から、フリーソフトを作り上げるためにはモチベーションを持続させることが重要だと考え、その為に設計の基本ですら無視した開発を行ったのだ。

その甲斐あってか、とりあえずはテキストエディタとしての体をなしたモノを作り上げることができた。そういう意味ではその戦略は正解だったといえる。だが、今やその目的は消え、当初無視した設計上の不良がここに来てボディブローのように効いてきている。

コアな部分には手を入れずに、塩漬けにしたまま使い続けるのであれば、別に設計がどうであろうが問題はない。しかし、大規模に手を加えようとするとなると、このままではどうにも都合が悪い。だから、そろそろドキュメントとビューをスパッと切断するような大手術が必要になるものと思われる。

できれば、インタフェースを明確に定め、独立した共有ライブラリとして切り出すようにしたい。つまり、Windowsで言うところのCOMコンポーネントのようにしたいと考えている。まぁ、IDLがどうだとかGUIDがどうだのということをやるつもりはない。とりあえず、インタフェースとして純粋仮想クラスを定義し、その純粋仮想クラスを実装するオブジェクトを生成する、という程度のことはやりたい。そうすれば、主筆の本体部分がほぼ真っ二つに切断されることになり、かなり事態が単純化するはずである。

しかし、その為にはまたしてもかなりの作り込みが必要になる。それも相当に難しく、一度踏み出したら容易には後戻りできない危険な迷宮に足を踏み入れることになるものと予測される。それを、技術士の勉強をしなければならないと言っているような、今この時期に始めるべきか否か。

それが問題だ。

正規表現の最適化2

2009/05/09

答えから書いてしまうと、「α{a,b}{c,d}」という正規表現はc(b-a)>=a-1もしくはc=dが成立する場合に限り「α{a*c,b*d}」に変換することができる。

証明といえるような内容になっているかどうか判らないが、俺なりに考えた結果を書いてみる。

まず、そもそも論として、「α{a,b}{c,d}」を「α{a*c,b*d}」に変換できるとはどういう意味なのだろうか?

「α{a,b}{c,d}」というのは、昨日も書いたが「とある正規表現αがa回以上b回以下繰り返す」というものがc回以上d回以下繰り返す、という指定である。また「α{a*c,b*d}」とは、とある正規表現αがa*c回以上b*d回以下繰り返すという意味である。

でもって、「α{a,b}{c,d}」を「α{a*c,b*d}」に変換できるというのは、「α{a,b}{c,d}」が実質的に「α{a*c,b*d}」と同じ、すなわち、「α{a,b}{c,d}」という指定により繰り返されるαの個数が、a*c~b*dの範囲内に収まり、かつ、a*c~b*dの全ての値を取るということを意味している。

例えば、「α{2,3}{4,5}」という正規表現を考えてみる。

αの数が最も少ないパターンでは、内側の繰り返しが全部2回で、かつ、外側の繰り返しが4回の場合、合計で8回繰り返す場合である。つまり下記のようになる場合である。

 αα αα αα αα (半角空白は判りやすくするために入れた)

次に少ないのは、内側の繰り返しが2回の奴が3つと3回の奴が1つ、でもって、外側の繰り返しが4回の場合である。つまり、下記のようなパターンである。

 ααα αα αα αα
    あるいは
 αα ααα αα αα
    あるいは
 αα αα ααα αα
    あるいは
 αα αα αα ααα

同様に、最も多くなるのは内側の繰り返しが全部3回で、かつ、外側の繰り返しが5回になる場合である。すなわち、下記のようなパターンである。

 ααα ααα ααα ααα ααα

こうやって考えていくと、「α{a,b}{c,d}」と指定された場合、全体の繰り返し数の最小は必ずa*c回、最大の繰り返し数はb*d回になると言うことができる。

ということは、「α{a,b}{c,d}」による繰り返し回数が、a*c回~b*d回の全てのパターンを取りうるのであれば、「α{a*c,b*d}」に変換できると言うことになる。

ちなみに、「α{2,3}{4,5}」の取りうる繰り返し回数を列挙すると下記のようになる。

外側の繰り返し回数内側の繰り返し回数合計
42,2,2,28
42,2,2,39
42,2,3,29
42,2,3,310
42,3,2,29
42,3,2,310
42,3,3,210
42,3,3,311
43,2,2,29
43,2,2,310
43,2,3,210
43,2,3,311
43,3,2,210
43,3,2,311
43,3,3,211
43,3,3,312
52,2,2,2,210
52,2,2,2,311
52,2,2,3,211
52,2,2,3,312
52,2,3,2,211
52,2,3,2,312
52,2,3,3,212
52,2,3,3,313
52,3,2,2,211
52,3,2,2,312
52,3,2,3,212
52,3,2,3,313
52,3,3,2,212
52,3,3,2,313
52,3,3,3,213
52,3,3,3,314
53,2,2,2,211
53,2,2,2,312
53,2,2,3,212
53,2,2,3,313
53,2,3,2,212
53,2,3,2,313
53,2,3,3,213
53,2,3,3,314
53,3,2,2,212
53,3,2,2,313
53,3,2,3,213
53,3,2,3,314
53,3,3,2,213
53,3,3,2,314
53,3,3,3,214
53,3,3,3,315


重複はあるが、最小の8回(=2*4)から最大の15回(=3*5)の全ての値を取るため、「α{2,3}{4,5}」は「α{8,15}」と同じであると言うことができる。

では、いかなる条件が成立した場合に、「α{a,b}{c,d}」による繰り返し回数がa*c回~b*d回の全ての値を取るのだろうか?

それを明らかにするために、まずは外側の数量子の値が同じだった場合、すなわち「α{a,b}{x,x}」という指定だった場合について考えてみる。つまり、

 命題:{a,b}{x,x}が指定されたとき、任意のax~bxの繰り返し回数を取りうる

の、証明を試みる。

何か泥臭いが、帰納的に証明する。

まず、x=1の場合、すなわち{a,b}{1,1}の場合にa~bの任意の値を取りうるか否かについて考える。{a,b}の指定は、a~b回の任意回の繰り返しであることを示すのだから、{a,b}{1,1}がa~bの任意回の値を取れるのは明らかである。

次に、x=2の場合、すなわち{a,b}{2,2}の場合について考えてみる。

x=2つまり外側の繰り返し回数が2回なので、内側の(a~b回)を2回繰り返す、すなわち、

 (a~b回)+(a~b回)=(2a~2b回)

が成立することを考える。

ここでまた泥臭いが、1回目の内側の繰り返し回数が、a回からb回に変化するのを順番に追っていってみる。

 (a+0回)+(a~b回)=((a+0)+a~(a+0)+b回)=(2a~a+b回)
 (a+1回)+(a~b回)=((a+1)+a~(a+1)+b回)=(2a+1~a+b+1回)
 (a+2回)+(a~b回)=((a+2)+a~(a+2)+b回)=(2a+2~a+b+2回)
  ・・・
 (b-2回)+(a~b回)=((b-2)+a~(b-2)+b回)=(a+b-2~2b-2回)
 (b-1回)+(a~b回)=((b-1)+a~(b-1)+b回)=(a+b-1~2b-1回)
 (b-0回)+(a~b回)=((b-0)+a~(b-0)+b回)=(a+b~2b回)

1つめの式により、2a回からa+b回の任意の繰り返し回数が生成できることが判る。また、それ以降の式の最大繰り返し回数が、a+bから2bまで1つずつ順番に増加して行くことから、結果として、2a回~2b回の任意の繰り返し回数を取ることができることが判る。すなわち、(a~b回)+(a~b回)=(2a~2b回)は成立する。

次に、x=3の場合、すなわち{a,b}{3,3}の場合について考えてみる。

x=3つまり外側の繰り返し回数が3回なので、内側の(a~b回)を3回繰り返す、すなわち、

 (a~b回)+(a~b回)+(a~b回)=(3a~3b回)

が成立することを考える。

ここで、(a~b回)+(a~b回)=(2a~2b回)が成立することを利用して、上記の式を下記のように変形する。

 (a~b回)+(2a~2b回)=(3a~3b回)

ここでx=2の場合と同じように、1回目の内側の繰り返し回数が、a回からb回に変化するのを順番に追っていってみる。

 (a+0回)+(2a~2b回)=((a+0)+2a~(a+0)+2b回)=(3a~a+2b回)
 (a+1回)+(2a~2b回)=((a+1)+2a~(a+1)+2b回)=(3a+1~a+2b+1回)
 (a+2回)+(2a~2b回)=((a+2)+2a~(a+2)+2b回)=(3a+2~a+2b+2回)
  ・・・
 (b-2回)+(2a~2b回)=((b-2)+2a~(b-2)+2b回)=(2a+b-2~3b-2回)
 (b-1回)+(2a~2b回)=((b-1)+2a~(b-1)+2b回)=(2a+b-1~3b-1回)
 (b-0回)+(2a~2b回)=((b-0)+2a~(b-0)+2b回)=(2a+b~3b回)

x=2の場合と同様である。1つめの式により、3a回からa+2b回の任意の繰り返し回数が生成でき、また、それ以降の式の最大繰り返し回数が、a+2bから3bまで1つずつ順番に増加して行くことから、結果として、3a回~3b回の任意の繰り返し回数を取ることができることが判る。すなわち、(a~b回)+(a~b回)+(a~b回)=(3a~3b回)は成立する。

一般化してn回の場合も同様に、

 (a~b回)1+・・・+(a~b回)(n-1)=((n-1)a~(n-1)b回)

が成立することから、

 (a~b回)1+・・・+(a~b回)n=(na~nb回)

は、

 (a~b回)+((n-1)a~(n-1)b回)=(na~nb回)

となり、今までと同じように、

 (a+0回)+((n-1)a~(n-1)b回)=((a+0)+(n-1)a~(a+0)+(n-1)b回)=(na~a+(n-1)b回)
 (a+1回)+((n-1)a~(n-1)b回)=((a+1)+(n-1)a~(a+1)+(n-1)b回)=(na+1~a+(n-1)b+1回)
 (a+2回)+((n-1)a~(n-1)b回)=((a+2)+(n-1)a~(a+2)+(n-1)b回)=(na+2~a+(n-1)b+2回)
  ・・・
 (b-2回)+((n-1)a~(n-1)b回)=((b-2)+(n-1)a~(b-2)+(n-1)b回)=((n-1)a+b-2~nb-2回)
 (b-1回)+((n-1)a~(n-1)b回)=((b-1)+(n-1)a~(b-1)+(n-1)b回)=((n-1)a+b-1~nb-1回)
 (b-0回)+((n-1)a~(n-1)b回)=((b-0)+(n-1)a~(b-0)+(n-1)b回)=((n-1)a+b~nb回)

となり、(a~b回)1+・・・+(a~b回)n=(na~nb回)が成立する。

以上のことから、「α{a,b}{x,x}」は、常に「α{a*x,b*x}」に変換できると言うことができる。

次に、外側の繰り返し回数に幅がある場合、すなわち「α{a,b}{c,d}」の場合に、ac~bd回の任意の繰り返し回数を生成できるか否かについて考えてみる。

ここで、以下のような複数の変換について考えてみる。

 「α{a,b}{c+0,c+0}」を「α{a(c+0),b(c+0)}」にする
 「α{a,b}{c+1,c+1}」を「α{a(c+1),b(c+1)}」にする
 「α{a,b}{c+2,c+2}」を「α{a(c+2),b(c+2)}」にする
  ・・・
 「α{a,b}{d-1,d-1}」を「α{a(d-1),b(d-1)}」にする
 「α{a,b}{d-0,d-1}」を「α{a(d-0),b(d-0)}」にする

つまり、外側の繰り返し回数を固定にして、一つずつ増やしていった場合について、それぞれの変換について考えてみる。上記の変換は、外側の繰り返し回数が同じであるため、今までの証明から全て成立するということができる。

ここで、変換後の「α{ac,bc}」「α{a(c+1),b(c+1)}」・・・「α{ad,bd}」の繰り返し回数の範囲が互いに重複しているのであれば、「α{a,b}{c,d}」の繰り返し回数が、ac~bd回の全ての繰り返し回数の値を取ることができると言うことができるはずである。

数直線で書くと、こんな感じになるだろうか。



式で書くと、b(c+0)+1>=a(c+1) かつ b(c+1)+1>=a(c+2) かつ ・・・ かつ b(d-1)+1>=a(d-0) という条件式になる。表現を変えれば、下記のようになる。



上記の式は、下記のように書き換えられる。



ここで、iは必ず正の値であり、かつ、単調増大であること、及び、aとbの値は変わらないことから、iがもっとも小さいとき、すなわちi=cの場合にi(b-a)>=a-1が成立すれば、iがcからdまで変化する場合の、全ての場合について成立すると言うことができる。

以上のことから、c(b-a)>=a-1が成立する、あるいは、c=dが成立するならば、「α{a,b}{c,d}」=「α{a*c,b*d}」が成立すると言うことができる。


と、こんなもんでどうだろうか? あっているだろうか?

正規表現の最適化1

2009/05/07

下らないことを考えてみた。

正規表現で、繰り返しを表す記号(数量子とか言うらしい)には、*とか、?とか、+とか、{a,b}とか、いろいろある。また、その中にも最長一致とか最短一致とか強欲なマッチとかいろいろな種類がある。

とりあえず、最長・最短・強欲の種別は無視するとして、*・?・+・{a,b}の指定に関して、正規表現を最適化することについて考えてみた。

*は0回以上の繰り返しを表す。すなわち機械的に{0,}に置き換えることができる。同様に、+は{1,}に、?は{1,0}に置き換えることができる。また、{a,b}の形式でbが省略された場合は、bに十分大きな値(例えばINT_MAX)が指定されたと考えれば、全ての数量子は{a,b}の形に正規化することができる。

そこまではいい。問題はここから。

α{a,b}{c,d}と指定されたら何が起きるのか、ということについて考えてみる。この指定の直接的な意味としては、正規表現αが、最低a回・最大b回繰り返し、かつ、それが最低c回・最大d回繰り返すということになる。つまり二重の繰り返しになるということだ。

だが、素直に考えるとこれは無駄である。例えば、α{0,1}{0,INT_MAX}と指定された場合は、内側の{0,1}の指定は全く意味が無くただの無駄以外の何物でもない。すなわち、α{0,INT_MAX}と最適化してあげるのが妥当である。

同じように、α{2,3}{4,5}と指定された場合にはα{8,15}としてあげることができるはずである。そうすれば、マッチを行う際の処理効率が大幅に向上するはずだ。(まぁ、元よりこんなアホな指定をする人間が悪いという考え方もあるのだが)

そう考えると、一般的にα{a,b}{c,d}と指定された場合は、α{a*c,b*d}と変換してあげることができるような気がする。

しかし、よく考えるとこの変換には無理がある。例えば、α{20,21}{2,3}という指定について考えてみる。この場合、先の変換公式に従うとα{40,63}という形になるのだが、実はα{20,21}{2,3}とα{40,63}とは等しくないのである。

すなわち、α{40,63}とした場合は、正規表現αが最低40回・最大63回繰り返すと言うことを意味しているのだが、α{20,21}{2,3}とした場合は、αが40回・41回・42回・60回・61回・62回・63回のいずれかの繰り返しになると言うことを意味する。よって、この変換は成立しない。

よくよく考えると、ある特定の条件が成立した場合だけα{a,b}{c,d}をα{a*c,b*d}に変換できるということに気がついた。だが、その条件については、今日はもう疲れたからまた今度書くことにする。

あな

2009/05/01

スーツを新調した。

別に、この年になってから性に目覚めておしゃれに気を遣うようになったためでもなければ、季節の変わり目だからという訳でもない。単に、スーツのズボンに穴が空いたためである。

いつも人に笑われるが、俺は外出する際には常に鞄は肩から提げるようにしている。典型的なオタク臭の漂うあのスタイルである。それは通勤の際も同様であり、必ず鞄は肩にかけている。その都合上、鞄の生地とスーツの腿のところがこすれて、気を付けてないとズボンに穴が空いてしまうのだ。

俺的には穴が空こうがズボンをはいていなかろうが、別にどうでも良いとしか思っていないのだが、しかし、曲がりなりにも客商売である以上、最低限まともな格好をしている必要がある。例えよれていようが型が古かろうが、最低限、穴や破れの無いスーツっぽい布きれでチンコとすね毛を隠さねばならない。これはサラリーをもらう社会人として必須である。

そういうことで、手取りが少なくなり、ますます生活が苦しくなりつつあるこの状況下でありながらも、思い切ってスーツを買ってしまった。

だがそもそも、穴が空かなければ無駄な支出を削減することができるのだから、例の腐臭漂うスタイルをやめればいいのではないかとも思うのだが、しかしこれはそう簡単な問題ではない。あの格好はいろいろな条件を勘案するともっとも安全であるという結果が導き出されるスタイルのなである。

まず第一に楽である。わざわざ手で鞄を持つ必要がないため、疲れにくい。第二に、置き忘れる心配がない。手で持っているとついどこかに置きたくなるが、そうすると置き忘れる危険性がある。手放さなければ置き忘れる心配はない。第三に、痴漢に間違われるリスクを軽減することができる。電車内で、鞄で股間を護り、両手を上に上げていることで、あらぬ言いがかりを付けられるスキをなくすことができる。

というか、むしろ鞄を手に持って満員電車に乗っている奴らの方が不思議である。あれはわざとやっているのだろうか? 鞄を手に持ち下におろしていると、ちょうど手がケツの部分にあたる。それを判った上で、女のケツを触るべくしてわざとそうやっているのか、さもなくば著しく頭の働きが鈍く、現実が認識できていないのか、そのどちらかとしか思えない。そういった連中がいる限り、世の中から痴漢が無くなることはないだろうし、同時に、痴漢の冤罪が無くなることもないだろう。

いずれにせよ、いろいろな意味でのセキュリティ的観点から言って、鞄は手に持つものではなく肩に提げておくべきものであるという結論が導き出される。

だがこのスタイルにはいくつかの重大な欠点がある。まず、先にも書いたがスーツに穴があくという問題が挙げられる。ジーンズの生地ですらこすれて薄くなり、ついには貫通するぐらいなのだから、スーツのペラペラな布きれなどたちどころにやられてしまう。次に、このスタイルは自ら公衆に対してオタク・マニアの類、すなわち、被差別階級の所属であることを公言しているようなものだということである。大多数の人は、おそらくこのレッテルを背負うことを恐れ、忌み嫌うのだろうが、俺はもはやそのような問題は超越している。マニアは、他者からマニアであると蔑まれることは気にしない。

しかし、余分な出費が嵩む現実は残る。合理性を妥協するつもりはないが、穴が空く問題には何らかの対処が必要であろう。

経歴

2009/04/23

努力の甲斐あって、技術士の試験の受験申し込み手続きが完了したようだ。とりあえず、申し込みを受理したとか何とかそういった内容のメールが来た。これは、受験ができるという解釈で間違いないのだろうか? いずれにせよ、受験票が来る頃になってみれば判るだろう。

提出した業務経歴だが、これは当然の事ながら素直には書いていない。何せ、入社してから今年の3月末でちょうど7年なのである。入社直後には当然の事ながら研修が行われ、その間はもちろん仕事なんかしていない。配属後だって、右も左も判らないような新人に何ができるわけでもないし、さらには、しばらくの間仕事を離れて研修漬けだった期間もあるわけで、それを単純素直に書いたら「技術士にふさわしい業務の経歴が7年以上」という制約条件を満たすことができない。

だから、入社直後の期間については、そのころやっていた開発プロジェクトの名前を適当に書いておいた。まぁ、全く何も知らないものを書いて、変な突っ込みを受けてボロを出すわけにも行かないから、ある程度話ができるような物を挙げておいたのだが。また、しばらく研修で仕事をしていなかった時期については「○○の研究」ということでごまかしておいた。まぁ、内容の程度は別として、嘘は言っていない。

最近のものにしたって、普段はノーマルな受注開発を行っているノーマルな雑用係に過ぎないのだから、それをそのまま実体通りに書いても制約条件を満たすことはできない。受験要項を見ると「科学技術に関する事項についての計画・研究・設計・分析・試験・評価」をやっていることとある。だから、なんとしても語尾を「計画」「研究」「設計」「分析」「試験」「評価」のいずれかにしなければならない。しかしこのうち、「計画」「分析」「試験」「評価」というのは、ちょっと余りにも実体とかけ離れた感がある。とりあえず「設計」であればあながち嘘ではないので、全部これにしておいた。

順序にしたって、当然の事ながらオーバーラップする部分はあるはずで、それをそのまま書くことはシステム上の制約からして不可能である。だから、多少は実体とずれている部分がある。いや、はっきり言おう。かなりずれている。だが、こればかりは仕方がない。何せ、入社してから7年でパッツンパッツンなのである。期間を短くすることはできない。明らかに怪しいが、みっちり「設計」と「研究」に明け暮れていました、という内容にしておいた。

内容が何であれ、それを証明する「公印」は取ってきたのだし、問題は無かろう。経歴を証明する手だてもなければ、それを確認する術もないのだ。後は、(筆記試験に受かったらの話だが)口頭試問でボロが出ないようにすれば良いまでの話だ。まぁ、それが難しいのだが。

公印

2009/04/17

技術士の2次試験の申し込みが終わった。

技術士の2次試験は実務経験を求めており、業務経歴書を出さなければならない。俺の場合、1次試験に受かったのがついこの間の事なので、「7年以上の実務経験」という奴についての業務経歴書が必要になる。

とりあえず、今年の3月末で入社してから丸7年になるため、何とか適当なことを書いて業務経歴書を書き上げることぐらいは不可能ではない。入社1日目から研修もなくいきなり実務に携わっていました、というかなり無謀な経歴書ではあるが、書くだけならなんとでもなる。

しかし問題は、その業務経歴書には「会社の公印」というのが必要になるということだ。

そもそも「公印」というのが何なのかが判らない。gooの国語辞典を調べても、「公の印」としか書かれていない。これでは何の説明にもなっていない。まぁ、受験申し込みの要項をみると「所属部課の責任者の印」とあるから、課長か部長ぐらいの印があればいいのだろうと勝手に考えていた。しかし、だとしてもどんなハンコをもらえばいいのか? 要項には「無職の場合や自分が会社の社長の場合には、本人の私印を押せ」と記載されていることを考えると、少なくとも認印ではないものと考えられる。では、一体何なのか?

締め切りは4月20日で、その前の日は土日で会社が休みであることを考えると、時間は限りなく無いに等しい。仕方がないから、ヤケクソで総務の人に電話して訊いてみたら、どうやら「公印」として使える事業部長名の印鑑があるという。とりあえず、それをもらってくれば間違いないようだ。

困った。

事業部長というのは、俺から見れば上司の上司の上司の上司の上司である。はっきり言うが、顔を見たこともなければ口をきいたこともない。名前を知っているかどうかというレベルの人だ。課長か部長であれば、多少内容がいい加減であったとしても、なぁなぁで承認してもらうこともできるだろうが、こんなエンもユカリもないおっさんを丸め込むことができるのだろうか?

できるもできないも無い。やるしかない。この時点ですでに申し込みも受験料の支払いも終わっているのだ。受験料1万4千円を無駄にしないためにも、なんとしても印を取ってこなければならない。それも、日程的にはその日の内にやらなければ間に合わない。

そして俺はやった。成し遂げた。かなり無理のある経歴書の内容も受験申込書も、一言一句直すことなく認めさせた。出してしまった後だからいうが、受験申込書に書いた会社の部署名が間違っていたが、それも含めて認めさせた。というか、気づかれる前に印を取ってきた。

まぁ、受験の申し込みだけで、そう大した書類ではないから、ほとんど何のチェックも入らなかっただけなのではあるが、それでも内向的な俺が即日で公印を取ってきたいうのは、大変なことである。俺的には、これを片づけただけですでにおなかいっぱいである。

だが、試験自体はこれからである。そもそも、まだ書類を提出したばっかりで、受験できるかどうかも判らない。とりあえず、受験が認められることを神に祈りつつ、筆記試験の勉強でもすることにしよう。

げんこうといっしょ

2009/03/22

2月半ばほどから微妙に忙しかったのだが、3月に入ってからは本格的に苦しいことになってしまった。「現行システムと同じことをするプログラム」なる物を作っていたのだが、その現行システムというやつが何をどうしてそういう結果になるのかが理解できない酷い代物であるため、開発に苦労したのだ。

たとえ既存部分のプログラムが見苦しい代物であったとしても、業務処理がはっきりとしていれば、「現行システムと同じ処理をするプログラム」と作ること自体は不可能ではない。なぜならば、既存部分を全く無視して業務用件から仕様を導き出せばいいのだから。しかし、そもそもの業務用件が複雑怪奇な場合はそうもいかなくなる。

なぜならば、業務処理内容が複雑だと、その仕様を理解している人間が存在しなくなってしまうのだ。つまり、客に「この処理はどうすればいいのか」と聞いても「よくわからないから、それは現行と同じようにしておくように」と言われるだけで、何をどうすればいいのかについて教えてもらえなくなるのだ。

いわゆるレガシーという奴である。

しかし、どうしてそういうことになるのだろうか? そもそも、業務システムという奴は、元々人間が手でやっていた仕事を機械でやらせるようにしただけの代物のはずである。ということは、もとはそれほど複雑な物ではなかったはずなのである。それなのになぜ、奇っ怪な化け物になってしまうのだろうか?

いろいろ理由はあるのだろうが、俺が思うに、システムというのは使われ出すと、仕様の元となった業務自体に影響を与えるからなのだと思う。つまり、業務を元にシステムの仕様が決められたはずなのに、システムが逆に業務に影響を与えるのではないかと思うのだ。(というか、そういう話をどこかで聞いたことがある気がする)

システムを使う側はシステムの中身については一切知らない。ただ、入力と出力が見えるだけである。そして、とにかくそれを使って仕事をしなければならない。そうなると、システムにあわせて人間が業務処理を変えてしまう可能性が出てくる、というか確実にそうなる。

そして、そうなると今度は、人間が業務処理を変えたのにあわせてシステム側が改修される。改修されたらまたそれに合わせて人間が仕事のやり方を変える・・・。そういったことの繰り返しで、長年の間に誰にも仕様が把握できない怪物が育ってゆくのである。

そうなるとその怪物には誰にも手が出せなくなる。手が出せないからそのまま放置しておく。するとますます怪物が成長する・・・。悪循環の繰り返しである。

おまけに、その悪循環を断ち切るべくシステムを作り直したとしても、システムを作るときには決してビジネスフローが見直されることがないため、新規にできた物は結局現行と同じ複雑怪奇な怪物だったりするためたちが悪い。

おそらく、「できた物」が「元となった仕様」に影響を与えるという問題は、元の仕様が人間そのものである限り、決して根本的には解決できない問題なのだろう。しかし、だとしても設計書やその他の文書として「どんな処理を行っているのか」について、ちゃんと書いておけばこんな苦労はしなくて済むはずである。なぜ、そんな当たり前のことができ無いのだろうか?

不思議だ。