casualties
ノルウェイの森 の Wikipedia を読んでいたら次の文章が気になった。村上春樹本人の物語ついての述懐だ。
この話は基本的にカジュアルティーズ(うまい訳語を持たない。戦闘員の減損とでも言うのか)についての話なのだ。それは僕のまわりで死んでいった、あるいは失われていったすくなからざるカジュアルティーズについての話であり、あるいは僕自身の中で死んで失われていったすくなからざるカジュアルティーズについての話である
この「カジュアルティーズ」が聞き慣れない単語で、歯にはさまったサラダチキンの断片のように気になってしまった。そこで簡単に調べてみた。
casualties の単数形である casualty を英和辞典で調べると
(事故・戦闘などの) 死傷者、被害者、人的損失
(戦争における) 損耗兵力
[-ties] 死傷者数、犠牲者数
とある。英英辞典で調べると
someone who is hurt or killed in an accident or war
とある。つまり「本人の意志とは関係なく事故や戦争の犠牲になった人々」というニュアンスが含まれるのだろうか。「犠牲者」と訳せる他の英単語に victim があるけど、こちらは犯罪や災害、病気の被害者というニュアンスがあるようだ。
たしかに小説には、読者としてあるいはもしかしたら作者としても、登場人物の望まぬ犠牲と向き合わなければならないときがある。しかし、その犠牲がなくては物語が核心に迫ることはどうしてもできないできない。そういう犠牲者に対して casualties という英単語は非常にしっくりくるように思える。
村上春樹が聞き慣れない英単語をさらっと使っていても、不思議と気取った感じがしない。むしろ適切な言葉を丁寧に選び出している感じがして好感が持てる。海外暮らしの長い作家特有の能力なのかもしれない。
渇きと潤い
風呂上がり、喉が渇いている。渇ききっている。喉はおろか食堂から胃までのあらゆる細胞が水分を欲している。冷蔵庫からキンキンに冷えた赤ラベルを取り出す。遠くの獲物を逃さんとするスナイパーの鋭い視線のように冷えている。ウィルキンソンのウォッカトニックだ。プルタブを開ける。クゥカッシュッッッと勢いのよい音が聞こえたかと思うと、ウィルキンソン独特の強烈な炭酸の抜けるシュゥワアアアアアアアアアという音が突き抜ける。無数の泡たちが宇宙の果てを目指して、我先にと駆け上っていく。そして、やや出遅れた泡たちを飲み込むように、僕は飲みくちに喰らいつく。むさぼるように液体を喉に流し込む。ひからびていた喉の渇きが一瞬で癒される。潤いが喉から食道、そして胃を満たしていく。そのままの勢いで潤いは僕の身体を貫通し、足先を伝って地面に抜け出してしまいそうだ。少し遅れて強炭酸がその存在を猛烈にアピールしてくる。さらに遅れて感じる、爽快なうまさ。
これが生きているということだ。
尊敬と嫉妬と羨望と
僕の周りには尊敬できる同僚や友人がたくさんいる。見習いたい点や憧れる点、あるいは優れた技能やしっかりとした価値観を持っている。だから尊敬できる。
でも僕の言う「尊敬」は本当に尊敬なのかとふと疑問に思った。それは自分を不当に貶めた上での正当ではない評価のように思えてしまった。たとえば「僕なんかそんなこととてもできないのにすごいね」とか「僕なんかどうあがいても手に入れられないものを持っていていいね」とか。どうしても「僕なんか」が枕詞についてしまう。それは断じて尊敬ではなく、明らかに嫉妬と呼ぶべきものじゃないだろうか。そして、わざとらしく前かがみになって「あなたって僕なんかと比べてとても背が高くて格好いいですね」といわれて愉快に思う奇特なひとが、この世界にひとりとしているだろうか。
尊敬と嫉妬はどちらも相手に対する羨望の念を含んでいて、明確に区分けできるものではないかもしれない。夕暮れと夜空の境目が曖昧なように。それでも「これは尊敬だろうか?嫉妬だろうか?」あるいは「僕は相手を正当に、客観的な立場から評価しているだろうか?」と自問することが大切だと思った。必ずしも尊敬がよくて嫉妬が悪いというわけではないと思う。自分の誰かを羨むような思いを、時には俯瞰視点から、自分から切り離したものとして観察することが大切なんだと思う。
–
大好きなウォッカトニックの在庫がちょうど切れてしまった。ちょうど金曜日で助かった。土日で買い出しにいけばいい。致命的なことにならなくてよかった。まあこんなときに売れきれていたりするのが人生なんだけどね。マーフィーがなんとやら。まあ仮にそうなったとしても、きっと新しい出会いがあることでしょう。それもまた、いや、それこそが人生 😇
ダイクストラ法によるグラフの最短経路の計算を Ruby で書く
「なっとく!アルゴリズム」という本を読んでいる。アルゴリズムの説明が平易かつ丁寧で、イラストもかわいいのでお気に入りだ。
- 作者: アディティア・Y・バーガバ
- 出版社/メーカー: 翔泳社
- 発売日: 2017/01/31
- メディア: Kindle版
- この商品を含むブログを見る
この書籍の第 7 章で ダイクストラ法 というグラフの最短経路を求めるためのアルゴリズムが紹介されている。書中には説明のために Python のコードが載っているが、今回は復習を兼ねて Ruby で書き直し、かつオブジェクト指向で実装してみることにした。
以下の重み付き有向グラフの最短経路を求める。
require('forwardable') class Node attr_reader :name def initialize(name) self.name = name end def ==(other) name == other.name end private attr_writer :name end class Edge attr_reader :from, :to, :weight def initialize(from, to, weight = nil) self.from = from self.to = to self.weight = weight end private attr_writer :from, :to, :weight end class Graph attr_reader :edges def initialize(edges) self.edges = edges end def nodes @nodes ||= edges.flat_map { |edge| [edge.from, edge.to] }.uniq end def neighbor_edges_of(node) edges.select { |edge| edge.from == node } end def start_node @start_node ||= (nodes - edges.map(&:to)).first end def finish_node @finish_node ||= (nodes - edges.map(&:from)).first end private attr_writer :edges end class DijkstrasAlgorithm class Node < Node attr_accessor :cost, :parent def initialize(name:, cost: nil, parent: nil) super(name) self.cost = cost self.parent = parent self.processed = false end def processed! self.processed = true end def processed? processed end private attr_accessor :processed end extend Forwardable private_class_method :new def self.call(graph) new(graph).send(:call) end private attr_accessor :graph def_delegators :graph, :nodes, :edges, :neighbor_edges_of, :start_node, :finish_node def initialize(original_graph) initialize_graph_by(original_graph) initialize_node_properties end def call update_node_costs! build_shortest_route end def initialize_graph_by(original_graph) new_nodes = initialize_nodes_by(original_graph.nodes) new_edges = initialize_edges_by(original_graph.edges, new_nodes) self.graph = Graph.new(new_edges) end def initialize_nodes_by(original_nodes) original_nodes.map { |original_node| Node.new(name: original_node.name) } end def initialize_edges_by(original_edges, new_nodes) original_edges.map do |original_edge| Edge.new( new_nodes.find { |new_node| new_node == original_edge.from }, new_nodes.find { |new_node| new_node == original_edge.to }, original_edge.weight ) end end def initialize_node_properties start_edges = edges.select { |edge| edge.from == start_node } nodes.each do |node| next node if start_node == node start_edge = start_edges.find { |edge| edge.to == node } if start_edge node.cost = start_edge.weight node.parent = start_node else node.cost = Float::INFINITY node.parent = nil end end end def update_node_costs! loop do node = find_lowest_cost_node break unless node neighbor_edges_of(node).each do |edge| new_cost = node.cost + edge.weight if edge.to.cost > new_cost edge.to.cost = new_cost edge.to.parent = node end end node.processed! end true end def build_shortest_route ordered_nodes = [finish_node] loop do node = nodes.find { |node| node == ordered_nodes.first.parent } ordered_nodes.unshift(node) break unless node.parent end ordered_nodes.map { |node| "(#{node.name})" }.join(' -> ') end def find_lowest_cost_node nodes .reject { |node| node.cost.nil? || node.processed? } .min_by(&:cost) end end start = Node.new('start') a = Node.new('a') b = Node.new('b') finish = Node.new('finish') graph = Graph.new([ Edge.new(start, a, 6), Edge.new(start, b, 2), Edge.new(a, finish, 1), Edge.new(b, a, 3), Edge.new(b, finish, 5) ]) DijkstrasAlgorithm.call(graph) #=> (start) -> (b) -> (a) -> (finish) # 念のため別のグラフにもアルゴリズムを適用してみる。 start = Node.new('start') a = Node.new('a') b = Node.new('b') c = Node.new('c') d = Node.new('d') finish = Node.new('finish') graph = Graph.new([ Edge.new(start, a, 5), Edge.new(start, b, 0), Edge.new(a, c, 15), Edge.new(a, d, 20), Edge.new(b, c, 30), Edge.new(b, d, 35), Edge.new(c, finish, 20), Edge.new(d, finish, 10) ]) DijkstrasAlgorithm.call(graph) #=> (start) -> (a) -> (d) -> (finish)
Hash オブジェクトを使って単純に Ruby に翻訳するだけならすぐに終わったけど、クラスを定義してオブジェクト指向で書き直すと非常に時間がかかった。
Graph の構成要素である Node に経路探索コストをそのまま保存している点が気になる。グラフというデータ構造と経路探索コストの計算というアルゴリズムをどうにかして切り離せないだろうか。でも疲れたのでここまで。
↓
アルゴリズムの計算に特化した専用の Node クラスを用意することで、アルゴリズム実行時の副作用を限定できた。ただ代償として、Graph オブジェクトの複製というコストが掛かっている。
ジェットストリームと初期化されたアンドロイド
社会人になって使う頻度が格段に増したものがいくつかある。その中でも毎日よく使っているのが黒ボールペンだ。メモに使ったり、勉強に使ったり、手帳を書くのに使ったり。僕は油性の ジェットストリーム を愛用している。非常になめらかな書き味で、文字を書くのが快適だ。そして、するすると文字を書けると、書くという行為自体がとても楽しくなる。素晴らしいペンだ。
ペンを多用しているので、それなりの頻度でインクが切れてしまう。そうすると、博多駅の東急ハンズや地元のドンキホーテで新しい替芯を買って、芯を交換する。そのときにとても残念でならないことがひとつある。それが、なめらかな書き味との別れだ。新しい芯はペン先が馴染んでいないためか、非常に書き味が悪い。天下のジェットストリームといえどもだ。少し前まで味わっていた至上の書き心地がとても恋しくなる。
失われた書き味と空っぽになってしまった替芯。それらからは、初期化されたアンドロイドを連想する。スマートフォンではなく、知能を持ったロボットであるアンドロイド。長いときをともにすごし、色々な思い出を作ってきたアンドロイド。しかし彼 (彼女かもしれない) は長い起動時間によって不具合が蓄積し、それはやがて致命的になった。そして、完全な死を回避するためには OS の初期化を余儀なくされてしまった。初期化が終わると、全てを忘れてしまった彼は音声を口にする。「ハジメマシテ。アナタガ ワタシノ ゴシュジンデスカ?」。
このような心を押しつぶすような別れを幾度もなく繰り返してきた僕。でも、僕は新しい相棒とまた新たな思い出を築いていくのだ。やがて訪れる新たな別れの時まで。悲しみのループを繰り返し、僕は少しでもタフになれただろうか。あの暁美ほむらのように。
買い物バグ
どうも僕は買い物に関するバグを抱えているようだ。精算後に商品をレジにそのまま置いていってしまうことが多い。そして今日はその逆で、商品を受け取り精算も済ませたのに、まだ何かしらの処理が残っていると勘違いして、レジの前に居座ってしまった。これまた恥ずかしい。
証明における Q.E.D. (Quod Erat Demonstrandum: かく示された、証明終了) と同様の語句が、買い物におけるおいても存在すると仮定する。買い物終了。僕はこの S.E.D をどのタイミングで示すべきかの判断が著しく苦手なようだ。処理途中で示してしまうこともあれば、示しあぐねてしまうこともある。
これは何かの障害なんだろうか。でも、別に障害だろうが障害でなかろうが、そんなことはどうでもいい。事実困っているし、しばしば恥ずかしい目に合うし、こういった問題が生じないように毎回意識することも難しい。
今日、靴下を買った後にレジに立ち尽くし、一人だけ時間の静止した世界を生きてしまったので書いた。参ったね。
チキンチリ
世の中にはさまざまなチキンがいる。形而上学的チキンと非形而上学的チキン。慎ましいチキンと軽率なチキン。そして、生きたチキンと死んだチキン。
今日出会ったのは、死んだチキンの中の調理されたチキンというサブカテゴリにある「チキンチリ」と呼ばれる存在。昼の華味鳥で出会った。穏やかに陽の沈みゆく北欧の夕暮れのように赤くきらめくソースをまとっている。そして、ソースのとろみがチキンの柔らかさを引き立てている。
チリと言葉には辛いイメージがあるが、辛みと呼べるものはほとんど沈みきっていた。むしろ、わずかな辛みの残滓が、チキンに備わった甘味を引き立てていた。甘いチキンの周りには、これまた甘くてジューシーな野菜が色とりどりに添えられていた。夕暮れの後に待っている賑やかな夜会の始まりがそう遠くないことを思わせる。華味鳥というレストランには、たくさんの明るいイメージや予兆を料理に乗せて提供してくれる、すばらしい場所だ。