SVX日記

2004|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|03|04|05|06|07|08|09|10|11|12|

2024-12-06(Fri) 自分を見詰め、字を詰める

  ここしばらく、Factorioに夢中なのだが、仕事の方でも実にエキサイティングである。一部の勢力からの自分の評価が極めて低いことを知ってしまったのである。

  しかし、一時的には腹が立ったものの、しばらくして、その勢力からの評価が低いことは、むしろ望ましいことなのではないかということに気づいてしまった。その勢力の考え方は、決して自分の信念と相容れないからだ。一方で、自分が好きな人、尊敬する人たちからは変わらず手放しでの高評価を受け続けているのだし、まぁ、それでいいかと。

  自分としては、マズローの4段階目「承認の欲求」で自身について納得しつつ、5段階目「自己実現の欲求」を半ば達成しつつあるような心境だ。乱れた心も整いつつあるのを感じる。

  考えてみれば、生殺与奪の権利を持っているのはこっちなのだ。金もあるし。それで自ら好きな仕事だけしてればいい立場になったのだから、それが一部からの低評価との引き換えだとしても別にいいやと。自分の信念に背くような仕事の仕方すんの、ヤだしね。それさえ無理なら、袂を分かつさ。

  なんだかキャプテンハーロックの気持ちってこうだったのかもと思えてきた。どんな大勢力が相手だろうと、俺の旗の下に、俺は自由に生きる。それがアルカディア。それが男。それでいい。

  そんなこんなで、片や落胆しつつ、いつも以上に楽しんで仕事をしているのだが、その中で「字詰め」処理を行う必要が生じてしまった。Rubyで。長い一文を、例えば18文字、で折り返す処理である。これが意外と難しい。え!? そんなん、1行じゃん?

print(target.gsub(/(.{18})/, "\\1\n"))

  ……って思うかもしれんが、それは甘い。

 その話をカミさんにしたら、そんなの
借りときゃいいのに、という反応。いや
、そりゃそうだけど、2km弱を乗った
ところで何になるってんだ、などといい
つつ、なぜかRotary-EVの素晴
らしさについて語りだしてしまうオレw
。ほとんど乗らないワシらにはオーバー
 :

  まず、英文字と漢字とは幅が違うので、同じ1文字と数えると右端が揃わない。それよりなにより「禁則処理」がなされない。句点(。)や読点(、)が行頭に位置してしまっている。そんなの気にしないという向きもあろうが、自分はイヤだ。そんな処理もできないのかと思われるのは恥ずかしい。

  しかし、これが意外と難しい。組版するわけではないので、次行への追い出しのみの実装でよいのだが、先頭から処理していくと、遡るような処理が必要になるのだ。例えば、

「その時、彼は『こんにちは(笑)。』と書き込んだの。」

  を、18文字で詰めると、

「その時、彼は『こんにちは(笑)。』
と書き込んだの。」

  だが、17文字で詰めると、

「その時、彼は『こんにちは
(笑)。』と書き込んだの。」

  1文字でなく、5文字も減らす必要が生じるのだ。

  こんな典型的な処理、どこかで誰かが書いているだろう、と思って検索してみたが、良いものが見つからない。思い返せば、彼の「電脳倶楽部」の創刊号で祝一平編集長自らがPDSとしてCで書いて公開した「wrap.x」がまさにそれなのだが、コードを入手する手段がない。当時はまるで興味をそそられなかったプログラムだったが、ディスクマガジン用のリーダを書こうと思えば、そら一番に必要になるコードだよなぁ。いまさらに深く納得。

  それなりにうんうん唸って、何度か書き直して、そこそこ納得できるコードが書けたが、丸一日かかってしまった。正規表現とかを駆使すればもっとシンプルかもしれないが、そう得意ではないし、ハナモゲるのがイヤなので、使っていない。

class String
 
    def char_wide
        self.getbyte(0) < 0xE0 ? 1 : 2                          # 文字の表示幅を返す
    end
 
    def each_wline(w_max)
        loop {
            c_max = 0; w = 0; self.each_char {|c|               # 仮分割位置を算出する
                w + c.char_wide > w_max and break
                c_max += 1; w += c.char_wide
                c == "\n" and break
            }
            if(self.size > c_max)                               # 1 行分を適切に切り出す
                c = c_max.times {|cr|
                    # 行末禁則文字
                    '([{「『([{'\
                        .include?(self[c_max - cr - 1, 1]) and next     # 仮分割位置の直前(行末)の文字
                    # 行頭禁則文字
                    '),.]}、。」』っッー)]}'\
                        .include?(self[c_max - cr, 1]) and next         # 仮分割位置の直後(行頭)の文字
                    break(c_max - cr)
                }
                yield(self.slice!(0, c))
            else                                                # 残りを返す
                yield(self)
                break
            end
        }
    end
end
 
target.each_wline(38) {|l|
    puts("\t|%s|" % l)
}

  結果はこう。

	| その話をカミさんにしたら、そんなの借|
	|りときゃいいのに、という反応。いや、そ|
	|りゃそうだけど、2km弱を乗ったところで|
	|何になるってんだ、などといいつつ、なぜ|
	|かRotary-EVの素晴らしさについて語りだ|
	|してしまうオレw。ほとんど乗らないワシ|
	|らにはオーバースペックすぎるんだって、|
	|なんていいながら、サイトで見積もりまで|
	|してしまう。天井が黒くって、ロードス|
	|ターとお揃いじゃん。並べたらいい感じじ|
	|ゃない? ……って、そらそうだけど、ホ|
	|ラ、500万だってよ。500万ってさ、1年を|
	|働いてようやく余るかっていう金額だよ。|
	|MX-30のために1年働くって思ったら……い|
	|や、そういうのも意外と悪くないんじゃな|
	|いかw。オレ、チョロいなぁ……。
|
	| 前にも言ったが、代車を貸すほど効率的|
	|なプロモーションはないよなぁ。あー、|
	|やっぱり借りて、明日の仕事はブッチして|
	|しまうべきだったなぁ。人生で最高レベル|
	|の失敗をしたかもしれん……。
|

  関数名の「each_wline」の「w」は「wrap.x」へのリスペクトである。

  書いていて気づいたのだが、既に「半角、全角」という世ではないこともあって、ネット上にコードが見つからないのかもしれない。プロポーショナルな環境の場合、自分で詰めるべきではなく、CSSなどを使うべきなのだろう。

  ついでに、コードを書いたあと、思いついてChatGPTにコードを書かせてみたが、なぜか行頭禁則しか扱ってないし、動かしても何の処理もされなかった。やはり元となるようなサンプルコードがある場合限定なのかもしれん。

  あ、ちな、上記のコードには、一部の禁則文字しか定義していないし、分離禁止文字も実装していない。あしからず。


2024-12-08(Sun) 続・自分を見詰め、字を詰める

  自分語りっぽい内容だが、まぁ、ブログってのは日記なんでね。

  思い返せば、小学校の5年だ。担任が社会の先生なので、社会の授業内容が一風変わっていた。丸1年かけて「瓦」の製造を行う「自動工場」と「伝統手工業」の両者について、見学、インタビューを通じて、比較していくというものだった。それは、今でも強く覚えているくらいに、自分には楽しい取り組みで、追加のインタビューに行くメンバの募集にも手を挙げ、担任の車で「伝統手工業」の作業場を再訪したりした。

  次は、中学校の2年だ。音楽の授業で「アイネ・クライネ・ナハトムジーク」の冒頭を探してきてテープにダビング、印象をまとめて発表すること、というチーム課題が出た。自分は、ちょうどSHARPのX1を買ってもらってしばらくした頃だったので「冒頭部分はオレが作るから」とMMLを書いてPSGで鳴らしてテープに録音し、発表に臨んだ。ところが、PSGの音色はファミコン以下なので、曲が流れ始めるなり授業は爆笑の渦。先生は「面白いね、ちょっと間違ってる音もありましたけど」と苦笑い。しかし、忘れられないのは、その直後に誰かに言われた「お前、音楽5だぜ」だ。

  別に「やってみたかったからやった」だけで、そんな狙いは一切なかったので、そう言われても「そんなもんかな」としか思わなかったが、気づけば、上述の小学校の時も似たようなことがあった。いま考えると、そういう「点稼ぎ」にフォーカスして生きている人間は、その頃からいたし、その年齢でそうだということは、おそらく親もそういう人間なのだろう。別に「悪いこと」とまでは言わないけれど。

  ここ数年「歌」を続けている。カラオケでの練習の際に「機械採点」機能を使っているが、それにフォーカスして歌うことはない。だって歌の本質は「聴衆へのメッセージ」だろ? 誰かに聴かせることは滅多にないけど、その軸足を動かすことはない。絶対に。

  例え話だが、自分はいつものストリートで歌っている。少しずつファンもついてきて、みんな楽しんでくれている。中には、歌い出す前から、帽子の中に千円を入れてくれる人もいる。それに対して、今日も最高の歌を聴かせるぜ、と心に誓うことはあっても、明日も千円を入れてくれますか、と尋ねることはない。た・の・ま・れ・て・も、決してそれはしない。それでストリートの管理者からの評価が下がろうが知ったことか。それは信念だ。それが通せないのであれば、そのストリートを去るまでのことだ。ファンには申し訳ないけれど。

  とはいえ、悲しいかな最近の日本では、本質よりも「点稼ぎ」へフォーカスしている団体は珍しくもないんだよな。警察とかマスコミとか……歪んだルールルールルールゥー……。

  さて、昨日の字詰めの続きだ。実は昨日のコードは「AIの回答内容」を折り返して表示させたい、という用途で書いたものなのだが、よく考えたら「幅xx文字で字詰めして答えて」とAIに指示する方法もあるのではないか、と思いついた。

  で、早速、ChatGPTで試してみた。

Q. 野球のルールについて、400文字程度、漢字で幅19文字で字詰めして、説明してください。
 
A. 以下は、幅19文字で字詰めした野球のルール説明です。
 
野球は九回まで攻守を交
代し得点を競う競技です。
攻撃側は打者が投手から
投じられる球を打ち、一
塁から三塁を回り本塁へ
戻ることで得点します。
一方守備側は三つのアウ
トを取ると攻守交代とな
ります。打者はストライ
クを三つ取られるか、飛
球やゴロを守備側に捕球
されるとアウトとなりま
す。攻撃側は打者が出塁
し次の塁を狙い、走者と
して得点を目指します。
最終的に得点が多いチー
ムが勝者となります。

  おい。全部で200文字にも満たないし、幅も11文字じゃねーか。「19文字になっていませんが。」とやり直させたが、なぜか12文字に変更した挙げ句に「各行が正確に19文字になっています。」と断言してきた。どういう勘定なんだ、それは。ダメだこりゃ。ま、そういうのが不得意ってことはわかったよ。

  一方で、ここしばらくは手元で動かすAIにも興味を持っている。先日「3.1-Swallow」ってのがいいよ、と聞いたので試してみることに。ところが、ggufをダウンロードできる場所にたどり着いたものの、似たようなファイル名のサイズ違いが20個以上も並んでいるではないか。どうやら量子化という、いわば圧縮レベルを変えたものが、ズラズラと並んでいるらしい。

  あまり詳しくはないが、LLMの基本はベクトルの集合。浮動小数点の組で表現されているそれを整数化することにより、圧縮するのが量子化らしい。それにより、精度は低下するが、サイズが小さくなり、演算も速くなる。そういえば、最近のCPUにはNPUというAI向けの演算器が乗っているらしいが、速度のために精度を犠牲にした演算器だと認識している。それと同じことか。

  詳しくはわからんが、なんでも、Q5_K_M, Q5_K_S, Q4_K_Mくらいが、バランスのよい量子化レベルらしい。知らずに最初に試したIQ1_Mには「こんにちは。」を無限に繰り返されたしなw。なるほど。

  つうわけで、3.1-SwallowのQ5_K_Mに尋ねてみた。

# docker exec -it ollama-alpha ollama run Swallow-8B-Instruct-v0.1-Q5_K_M
>>> 野球のルールについて、400文字程度、漢字で幅19文字で字詰めして、説明してください。
野球は9人ずつの二チームが交互に攻撃と守備を行う競技です。攻撃側は打者1人と走者3人(一塁、二塁、三塁)を出し、相手の守備側から点を得ることを目指します。守備側は投手1人が投球し、他の8人が守備位置につき、打者の打撃を阻止したり、走者をアウトにすることで攻撃を終わらせます。
 
試合は9イニングで行われ、各イニングは3アウトになるまで続けられます。3アウトになると攻守が交代します。攻撃側は投手の投球を受けて打撃し、走者が出た場合には次の塁を目指して走ります。
 
守備側は投手にボールを投げさせて打者の打撃を阻止したり、打球を処理してアウトにすることで攻撃を終わらせます。走者がアウトになると攻撃は終了し、次のイニングに移行します。
 
野球では、守備側が3つのアウトを取るか、攻撃側が得点を挙げて勝利するかのいずれかで試合が決まります。
 
>>> Send a message (/? for help)

  幅の指定は無視かよ! まぁ、400文字程度にはなっているけど。こういうのが不得意なのは、AIに共通する性質なのだろうか。

Q. ひろゆきっぽい感じでお願いします。
 
A. 以下は「ひろゆき」っぽい論調を意識しつつ、19文字幅に整形した野球ルールの説明です。
 
野球って九回まで攻守交代
して得点を競う競技なんで
すよね。でも、実際これっ
て守備がアウト三つ取った
ら交代になるんですよ。攻
撃側は球を打って一塁から
三塁回って本塁に戻ると得
点になるんですけど、守備
側が飛球とかゴロ捕ったら
アウトなんですよね。で、 
最終的に点数が多い方が勝
ちなんですけど、これって
時間かかりすぎじゃないで
すか?もっと効率的な方法
とか考えないんですかね?

  爆笑w。最後は説明じゃなくて、あなたの感想ですよねw。こういうの、ChatGPTは得意だよなぁ。これはもう、ホント賞賛しかない。

  ……あ、最後に字詰めについてその後に気づいたことだ。まさにこの行のように、しばしば自分は行頭を「……」から始める表現を用いることがある。って、言いつつ、まさにこのように、しばしば自分は文を「っ」から始める表現を用いることもある……これ、どちらも行頭禁則に抵触する表現だ。が、これはアリって気がする。

〜〜を「……」から始める表現を用いることがある。
って、言いつつ、まさにこのように、しばしば〜〜

  一方で、昔から笑いながらの発言を示す表現に(笑)がある(笑)。が、それも最近だと草生える、という表現が一般的だw。新しい表現なので、句点の扱いに困るのだが自分は句点の前に付けている。まぁ、正式な表現ではないからルールなんてなく、好きにさせてもらうwww。が、この場合に限って「w」は行頭禁則がふさわしい気がするのだよな。つまり、これはイヤだ。

〜〜いからルールなんてなく、好きにさせてもらう
www。が、この場合に限って「w」は行頭禁則が〜〜

  そういうことを言い出すと、英語圏のスマイリーはどうするんだとか、キリのない話になっていく。結局、アルゴリズムではなく、状況に応じた字詰めが必要ということか。まぁ、いいか;-P。