Skip to content

第5章の「日ごとのスケジュールの列挙」のロジックと実装について #10

Description

@enakai00

誤植というわけではないのですが、第5章で実装されているロジックについて気づいた点があったので共有させてください。書籍改訂時などの参考にしていただければ幸いです。

p.165 の is_OK() 関数

「ルート関係」のコメント以下の部分では、指定された荷物の配送先を(部分集合として)含むすべての経路の中から、移動時間(移動距離の合計)が最小のものを検索しています。ただ今回の問題設定では、「指定された荷物の配送先だけを通る経路」が最短時間になるのは自明なので、余計な訪問先を含む経路を含めて探索する理由がわからず、書籍を読んでいて少し混乱しました。(より一般的な問題設定では、あえて回り道をした方が時間が短くなる場合もあるとは思いますが、この点について、書籍内で一言説明があればよかったです。)

DataFrame を使わない実装による高速化

上記の探索をやめて、「指定された荷物の配送先だけを通る経路」を最初から選択する形で再実装してみました。この際、DataFrame で中間データを取り回すのをやめて、List, Dictionary だけを使うようにした所、実行速度がかなり高速化されました。(リンク先の実行結果に実行時間が記録されていますが、並列実行なしでも十分気軽に(?)試せる実行時間になっていると思います。(is_OK() 関数内での探索をやめた影響もあると思いますが、それよりは、DataFrame の検索のオーバーヘッドが削減された影響の方が大きいと想像しています。)

書籍の実装との結果のズレについて

上記の再実装による結果と書籍の実装の結果を比較すると、(理屈の上では一致するはずですが)一致しない部分がありました。原因を調べてみたところ、2地点間の距離を計算する際に、np.floor で小数点以下を切り捨てているために丸め誤差が生じて、三角不等式が成り立たない場合がおきているようでした。

t = np.array([[np.floor(np.linalg.norm(_K[k] - _K[l])) for k in K] for l in K])

再実装の最後にある「距離の丸め誤差について」で具体例を示していますが、4 - 5 よりも(間に 7 を挟んだ) 4 - 7 - 5 の方が移動時間が短くなっています。

このため、書籍の実装では、余計な訪問先を含む方が移動時間が短くなるケースを発見して、そちらの経路を採用することがあるようです。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions