✲゚。.ヾ(⌒(ノ'ω')ノ☆.。

変色系男子の日常。

自転車買っちゃった 🚲

最近会社で自転車がよく話題に挙がる。その影響で僕も自転車を買ってしまった。買ったのは DAHON の K3 というミニベロ1。2018/08/17 時点で、まだ公式サイトの製品ラインナップにすら載っていない2くらい新しい車種!

福岡市内のミニベロ専門店で、予算 5 万円のつもりが店員さんに推されて、結果的に予算の倍費やしてしまった 😂

K3 の外観はこんな感じ。

f:id:quanon:20180817230050j:plain

タイヤサイズは 14 ㌅と小さいけど、大きなギアのおかげでなかなかスピードが出る!

折りたたむとこんな感じ。タイヤサイズが小さいおかげで折りたたむと非常にコンパクトだし、重量も 7.8kg と軽い!そのため、家の中に持ち込みやすくてとても便利だ 😆

f:id:quanon:20180817231301j:plain

この自転車のおかげで行動範囲が広がって、遠くに安いお肉を買いに行けるようになった ❤️ ありがとう、ナツキ号 🚲 ナツキ号はこのミニベロの名前です。

唯一残念なポイントは、走行中にシートポストが下がってしまうこと。これは店舗に相談してみる。

結果的に満足な買い物でした 💪😎


  1. タイヤの径が小さい自転車のこと。小径車。

  2. 次年度のカタログ (PDF) に掲載されている。

読書はグルメ

「読書ってやっぱりグルメみたいだな」熱いシャワーを浴びながら、ふとそう思った。

いろいろな文章がある。小川洋子川上弘美のように淡くて静寂な文章もあれば、西尾維新のように濃密で胸焼けしそうな文章もある。村上春樹のように、一見無害さを装いながらも強烈な個性を匂わせていく文章もある。そこには濃淡があり、色彩があり、そして抑揚がある。

一口に豚骨ラーメンといっても提供する店舗によって味が千差万別であることとよく似ている。だから、読書をグルメに例えることはなかなか絶妙な比喩だと思う。

それにしても「本好きの下剋上」がおもしろすぎて、ページをめくる手がとまらない!

香水

一日の中でささやかな喜びを感じる瞬間というのは確かに存在する。ランチのひと口目だったり、お風呂に浸かる瞬間だったり、温かい布団にくるまるときだったり。僕にとっては肌着を脱ぐときもそういう瞬間に含まれる。脱いだ瞬間にふわっといい香りが漂うからだ。通勤前につけた香水の残り香だ。男性、それなりの年になると「加齢臭」というキーワードが嫌でも気になってくるなかで、自分の抜け殻からいい香りがするというのはとても幸せなことだ。

僕は大学のときから香水を使っている。基本的には同じものしかつけない。はじめは ブルガリ プールオム でその次は サムライ ライト だ。こだわりが強いわけではないので、香りこそ気に入って買ったけど、どちらも家電量販店やディスカウントストアで安価で手に入るものだ。

去年か一昨年、友だちが香水がほしいということで複数人で阪急に見に行った。いかにもプロフェッショナルな店員さんがそれぞれに合いそうな香水を選んでいった。長年の経験と感によるあざやかなチョイスだった。そこである男友達が買った香水の香りがどうしても気になって、僕も後日同じものを買った。彼は阪急で定価で買ったが、けちくさいてせこい僕は Amazon で注文した。その香水が ヴェルサーチ ヴェルセンス だ。それからずっと愛用しているけど、香りが未だに大好きでたまらない。

よく考えると、香水って庶民でもブランドのよさを味わえる数少ない品物だと思う。もちろん値段もピンキリで、高級なものはとても手が届かないだろうけど。気が向いたら、また新しいものを探しに行きたい。今度はデパートでちゃんと定価で買うぞ。

casualties

ノルウェイの森Wikipedia を読んでいたら次の文章が気になった。村上春樹本人の物語ついての述懐だ。

この話は基本的にカジュアルティーズ(うまい訳語を持たない。戦闘員の減損とでも言うのか)についての話なのだ。それは僕のまわりで死んでいった、あるいは失われていったすくなからざるカジュアルティーズについての話であり、あるいは僕自身の中で死んで失われていったすくなからざるカジュアルティーズについての話である

この「カジュアルティーズ」が聞き慣れない単語で、歯にはさまったサラダチキンの断片のように気になってしまった。そこで簡単に調べてみた。

casualties の単数形である casualty を英和辞典で調べると

(事故・戦闘などの) 死傷者、被害者、人的損失
(戦争における) 損耗兵力
[-ties] 死傷者数、犠牲者数

とある。英英辞典で調べると

someone who is hurt or killed in an accident or war

とある。つまり「本人の意志とは関係なく事故や戦争の犠牲になった人々」というニュアンスが含まれるのだろうか。「犠牲者」と訳せる他の英単語に victim があるけど、こちらは犯罪や災害、病気の被害者というニュアンスがあるようだ。

たしかに小説には、読者としてあるいはもしかしたら作者としても、登場人物の望まぬ犠牲と向き合わなければならないときがある。しかし、その犠牲がなくては物語が核心に迫ることはどうしてもできないできない。そういう犠牲者に対して casualties という英単語は非常にしっくりくるように思える。

村上春樹が聞き慣れない英単語をさらっと使っていても、不思議と気取った感じがしない。むしろ適切な言葉を丁寧に選び出している感じがして好感が持てる。海外暮らしの長い作家特有の能力なのかもしれない。

渇きと潤い

風呂上がり、喉が渇いている。渇ききっている。喉はおろか食堂から胃までのあらゆる細胞が水分を欲している。冷蔵庫からキンキンに冷えた赤ラベルを取り出す。遠くの獲物を逃さんとするスナイパーの鋭い視線のように冷えている。ウィルキンソンのウォッカトニックだ。プルタブを開ける。クゥカッシュッッッと勢いのよい音が聞こえたかと思うと、ウィルキンソン独特の強烈な炭酸の抜けるシュゥワアアアアアアアアアという音が突き抜ける。無数の泡たちが宇宙の果てを目指して、我先にと駆け上っていく。そして、やや出遅れた泡たちを飲み込むように、僕は飲みくちに喰らいつく。むさぼるように液体を喉に流し込む。ひからびていた喉の渇きが一瞬で癒される。潤いが喉から食道、そして胃を満たしていく。そのままの勢いで潤いは僕の身体を貫通し、足先を伝って地面に抜け出してしまいそうだ。少し遅れて強炭酸がその存在を猛烈にアピールしてくる。さらに遅れて感じる、爽快なうまさ。

これが生きているということだ。

尊敬と嫉妬と羨望と

僕の周りには尊敬できる同僚や友人がたくさんいる。見習いたい点や憧れる点、あるいは優れた技能やしっかりとした価値観を持っている。だから尊敬できる。

でも僕の言う「尊敬」は本当に尊敬なのかとふと疑問に思った。それは自分を不当に貶めた上での正当ではない評価のように思えてしまった。たとえば「僕なんかそんなこととてもできないのにすごいね」とか「僕なんかどうあがいても手に入れられないものを持っていていいね」とか。どうしても「僕なんか」が枕詞についてしまう。それは断じて尊敬ではなく、明らかに嫉妬と呼ぶべきものじゃないだろうか。そして、わざとらしく前かがみになって「あなたって僕なんかと比べてとても背が高くて格好いいですね」といわれて愉快に思う奇特なひとが、この世界にひとりとしているだろうか。

尊敬と嫉妬はどちらも相手に対する羨望の念を含んでいて、明確に区分けできるものではないかもしれない。夕暮れと夜空の境目が曖昧なように。それでも「これは尊敬だろうか?嫉妬だろうか?」あるいは「僕は相手を正当に、客観的な立場から評価しているだろうか?」と自問することが大切だと思った。必ずしも尊敬がよくて嫉妬が悪いというわけではないと思う。自分の誰かを羨むような思いを、時には俯瞰視点から、自分から切り離したものとして観察することが大切なんだと思う。

大好きなウォッカトニックの在庫がちょうど切れてしまった。ちょうど金曜日で助かった。土日で買い出しにいけばいい。致命的なことにならなくてよかった。まあこんなときに売れきれていたりするのが人生なんだけどね。マーフィーがなんとやら。まあ仮にそうなったとしても、きっと新しい出会いがあることでしょう。それもまた、いや、それこそが人生 😇

ダイクストラ法によるグラフの最短経路の計算を Ruby で書く

「なっとく!アルゴリズム」という本を読んでいる。アルゴリズムの説明が平易かつ丁寧で、イラストもかわいいのでお気に入りだ。

なっとく!アルゴリズム

なっとく!アルゴリズム

この書籍の第 7 章で ダイクストラ法 というグラフの最短経路を求めるためのアルゴリズムが紹介されている。書中には説明のために Python のコードが載っているが、今回は復習を兼ねて Ruby で書き直し、かつオブジェクト指向で実装してみることにした。

以下の重み付き有向グラフの最短経路を求める。

f:id:quanon:20170323232856p:plain

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 オブジェクトの複製というコストが掛かっている。