with-eval-after-loadとrequireとautoloadとadd-hookと

発端

違いは何だ!!

まとめ

違ったら教えてください

  • 起動してずっと使ってる -> require
  • 起動時には必要ないけどmodeごとでは使う -> autoload
  • ライブラリでのsetqとかの設定 -> add-hook
  • ライブラリでのdefine-keyとかの設定 -> with-eval-after-load

調べた感じ

  • autoloadrequireは使うタイミングは似てる?
  • autoladは必要なときに読んでくるので起動時に必要ではないものを設定するといい
  • requireはこれが呼ばれたタイミングでライブラリ読むので起動時必要なものだけにしたほうが良さそう

起動時にjs2-modeが呼び出される

(require 'js2-mode)
(add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))

初めてjsファイルを開いた時にjs2-modeが読み出される

(autoload 'js2-mode "js2-mode" nil t)
(add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))

eval-after-loadwith-eval-after-loadadd-hookの違い

  • eval-after-loadwith-eval-after-loadの違いはwith-eval-after-loadはemacs24.4から新しく入ったマクロでprogn使わなくて良くなった
  • add-hookはバッファを呼び出すたびに呼ばれる
  • eval-after-loadは最初に設定しているライブラリがloadされるたびに呼ばれるが2回目以降は早いらしい

This macro arranges to evaluate body at the end of loading the file library, each time library is loaded. If library is already loaded, it evaluates body right away. 15.10 Hooks for Loading

  • setqとかはadd-hookがよくてdefine-keyとかはwith-eval-after-loadかな?

参考

YosemiteにEmacs24.4いれてみた

Yosemiteにする際についでにクリーンインストールしたので設定しなおした記録

書くこと

  • Emacs24.4をYosemiteに入れたところ
  • Emacsを上げて困ったこところ

Emacs24.4をYosemiteに入れたところ

inline patch当てなくていい人は1と5だけやればいい

  • 1 何はともあれまずはEmacsを取ってくる
$ curl -L -O http://ftpmirror.gnu.org/emacs/emacs-24.4.tar.gz
$ tar zxvf emacs-24.4.tar.gz
  • 2 今回はinline-pathもあてようと思うのでそっちも取ってくる
$ curl -L -O http://plamo.linet.gr.jp/~matsuki/mac/emacs-24.4-20140417-inline.patch
  • 3 パッチ当てるとビルドするときにライブラリが必要になるのでいくつか入れる
$ brew install autoconf automake
  • 4 パッチ当てる
$ cd emacs-24.4
$ patch -p1 < ../emacs-24.4-20140417-inline.patch

5 ビルドする

$ ./configure --with-ns --without-x | make -j2 | make install

以上でnextstep/Emacsができてるはずなので/Application以下に移動すると使えるようになる

困ったところ

1. helmがmakeできない

helmが(require 'cl-lib)してるんだけど,そんなものはないって怒られる

原因

makeするときは/usr/local/bin/emacsの方を使っているのが原因っぽかった
/usr/local/bin/emacsのバージョンが21くらいでcl-libが入ったので24からなのでほんとにそんなものはなかった
Cocoa Emacsにしなかったらこんなことにはならなかったな?

解決策

バージョンが24以上のemacsを入れる

brew install emacs

2. zlcが動かない

(wrong-number-of-arguments (2 . 4) 0)こんなかんじのエラーが出る

以下に詳しくのってた

emacs24.4 にアップデートして困ってることとか

zlc-minibuffer-complete(completion--do-completion)(completion--do-completion (minibuffer-prompt-end) (point-max)) にすれば動くようになりました。

らしい

参考

OS X Mavericksにemacs 24.4.50を導入

emacsでScala環境設定

Scala開発環境の覚え書き

前提

インストール

brew で入れたもの

el-getでemacsに入れたもの

実際

brew を使って要りそうなものを入れる(sbtが何なのかよくわかってないけどなんかみんな入れてた)

brew install scala
brew install sbt

emacsにはel-getscala-mode2とensimeを入れる
scala-modeもあったんだけどscala-mode2のがemacs24向けらしい

設定

パスは通ってるのでemacsの設定ファイルに以下を書くだけ

(require 'scala-mode2)
(require 'ensime)
(add-hook 'scala-mode-hook 'ensime-scala-mode-hook)

~/.sbt/0.13/plugins/plugins.sbtに以下をついか(なかったら作る)

resolvers += Resolver.sonatypeRepo("snapshots")

addSbtPlugin("org.ensime" % "ensime-sbt" % "0.1.5-SNAPSHOT")

ちょっと書いて見よう

参考

Rails4でActiveAdminとdeviseとcancancanをつかって管理者ページを作る

環境

  • Rails 4.1.2
  • ruby 2.1.1
  • devise 3.3.0
  • active_admin 1.0.0 pre
  • cancancan 1.9.2

Gemfile

gem 'rails', '4.1.2'
gem 'cancancan'
gem 'devise'
gem 'activeadmin', github: 'activeadmin'

bundleする

$ bundle install

まずはdeviseでモデルを作る. roleでadminかどうかを判定するのでUserコントローラに追加

$ rails generate devise:install
$ rails generate devise User
$ rails generate migration add_role_to_users role:integer
$ rake db:migrate

Deviseのモデルを使うのでActiveAdminでUserモデルをつくらないようにするために--skip-users

$ rails generate active_admin:install --skip-users
 create  config/initializers/active_admin.rb
      create  app/admin
      create  app/admin/dashboard.rb
       route  ActiveAdmin.routes(self)
    generate  active_admin:assets
      create  app/assets/javascripts/active_admin.js.coffee
      create  app/assets/stylesheets/active_admin.css.scss
      create  db/migrate/20140829091410_create_active_admin_comments.rb
$ rake db:migrate

これするとconfig/intializers/active_admin.rbのなかを幾つか変えないといけない

config.current_user_method = :current_admin_user
↓
config.current_user_method = :current_user

config.logout_link_path = :destroy_admin_user_session_path
↓
config.logout_link_path = :destroy_user_session_path

またapp/application_controller.rbに以下を追加

def authenticate_admin_user!
  authenticate_user!
  unless current_user.admin?
    flash[:alert] = "This area is restricted to administrators only."
    redirect_to root_path
  end
end

userモデルはadmin?は持ってないので以下をmodel/user.rbに追加(Rails 4からenumが使える)

enum role: %(admin normal)

cancancanいらなかった!!!

roleが3つ以上あるといる気がするけどめんどくさそう

参考

Railsで新規にWebサービスを立ち上げる際にやったことまとめ [Rails] Devise and Active Admin Single User Model

集合知プログラミング 2章をrubyで書いた

書きました。

APIを使うところは省略しています

critics = {
  'Lisa Rose' => { 'Lady in the Water' => 2.5, 'Snakes on a Plane' => 3.5, 'Just My Luck' => 3.0, 'Superman Returns' => 3.5, 'You, Me and Dupree' => 2.5, 'The Night Listener' => 3.0 },
  'Gene Seymour' => { 'Lady in the Water' => 3.0, 'Snakes on a Plane' => 3.5, 'Just My Luck' => 1.5, 'Superman Returns' => 5.0, 'The Night Listener' => 3.0, 'You, Me and Dupree' => 3.5 },
  'Michael Phillips' => { 'Lady in the Water' => 2.5, 'Snakes on a Plane' => 3.0, 'Superman Returns' => 3.5, 'The Night Listener' => 4.0 },
  'Claudia Puig' => { 'Snakes on a Plane' => 3.5, 'Just My Luck' => 3.0, 'The Night Listener' => 4.5, 'Superman Returns' => 4.0, 'You, Me and Dupree' => 2.5 },
  'Mick LaSalle' => { 'Lady in the Water' => 3.0, 'Snakes on a Plane' => 4.0, 'Just My Luck' => 2.0, 'Superman Returns' => 3.0, 'The Night Listener' => 3.0, 'You, Me and Dupree' => 2.0 },
  'Jack Matthews' => { 'Lady in the Water' => 3.0, 'Snakes on a Plane' => 4.0, 'The Night Listener' => 3.0, 'Superman Returns' => 5.0, 'You, Me and Dupree' => 3.5 },
  'Toby' => { 'Snakes on a Plane' => 4.5, 'You, Me and Dupree' => 1.0, 'Superman Returns' => 4.0 } }

def sim_distance(prefs, person1, person2)
  si = prefs[person1].select { |k, _v| prefs[person2].key?(k) }.keys
  return 0 if si.size.zero?

  sum_of_square = si.inject(0) do |a, e|
    a + (prefs[person1][e] - prefs[person2][e])**2
  end

  1 / (1 + sum_of_square)
end

def sim_piason(prefs, person1, person2)
  si = prefs[person1].keys.select { |k| prefs[person2].key?(k) }
  n = si.size
  return 0 if n.zero?

  sum1 = si.inject(0) { |a, e| a + prefs[person1][e] }
  sum2 = si.inject(0) { |a, e| a + prefs[person2][e] }
  p_sum = si.inject(0) { |a, e| a + (prefs[person2][e] * prefs[person1][e]) }

  sum1_sq = si.inject(0) { |a, e| a + prefs[person1][e]**2 }
  sum2_sq = si.inject(0) { |a, e| a + prefs[person2][e]**2 }

  s_xy = p_sum - (sum1 * sum2 / n)
  s_xx = sum1_sq - (sum1**2 / n)
  s_yy = sum2_sq - (sum2**2 / n)

  return 0 if Math.sqrt(s_xx * s_yy).zero?

  s_xy / Math.sqrt(s_xx * s_yy)
end

def top_match(pref, person, n = 5, similarity = method(:sim_piason))
  personp = ->(x) { x == person }
  cal_sim = ->(p) { [p, similarity.call(pref, p, person)] }
  descend = ->((_, p1), (_, p2)) { p2 <=> p1 }

  pref.keys.reject(&personp).map(&cal_sim).sort(&descend)[0...n]
end

def get_recommendation(pref, person, similarity = method(:sim_piason))
  personp = ->(x) { x == person }
  cal_sim = ->(p) { [p, similarity.call(pref, p, person)] }
  gt_zero = ->(x) { x[1] > 0 }
  person_has_item = ->(x) { pref[person].key?(x) }

  totals = {}
  sim_sum = {}

  pref.keys.reject(&personp).map(&cal_sim).select(&gt_zero).each do |other, sim|
    pref[other].keys.reject(&person_has_item).each do |item|
      totals[item] = (totals[item] || 0) +  pref[other][item] * sim
      sim_sum[item] = (sim_sum[item] || 0) + sim
    end
  end

  totals.map do |(k, v)|
    [(v / sim_sum[k]), k]
  end.sort.reverse
end

def transform_prefs(prefs)
  prefs.each_with_object({}) do |(person, items), a|
    items.each do |movie, v|
      a[movie] ||= {}
      a[movie][person] = v
    end
  end
end

def calculate_similar_item(prefs, n = 10)
  item_pref = transform_prefs(prefs)

  item_pref.keys.each_with_object({}) do |item, a|
    a[item] = top_match(item_pref, item, n, method(:sim_distance))
  end
end

def get_recommended_items(prefs, item_match, user)
  user_rating = prefs[user]
  scores = {}
  total_sim = {}

  user_rating.each do |item, rating|
    item_match[item].reject { |item2, _| user_rating.keys.include?(item2) }.each do |item2, sim|
      scores[item2] = (scores[item2] || 0) + sim * rating
      total_sim[item2] = (total_sim[item2] || 0) + sim
    end
  end

  scores.map do |item, score|
    [(score / total_sim[item]), item]
  end.sort.reverse
end

if __FILE__ == $PROGRAM_NAME
  # p transform_prefs(critics)
  # p sim_piason(critics, 'Lisa Rose', 'Gene Seymour')
  # p sim_distance(critics, 'Lisa Rose', 'Gene Seymour')
  # p top_match(critics, 'Toby', 3)
  # p get_recommendation(critics, 'Toby')

  item_sim = calculate_similar_item(critics)
  p get_recommended_items(critics, item_sim, 'Toby')
end

今日解いた問題3

今日というか今日と昨日

単一始点最短経路問題(ベルマンフォード)

ある頂点sからのすべての頂点の最短経路 d[j] > d[i] + costこの条件を1度使っただけでは明らかに最短にならないので update変更がなくなるまでループを繰り返す

INF = 100_000

G = [[INF, 2, 5, INF, INF, INF, INF],
     [2, INF, 4, 6, 10, INF, INF],
     [5, 4, INF, 2, INF, INF, INF],
     [INF, 6, 2, INF, INF, 1, INF],
     [INF, 10, INF, INF, INF, 3, 5],
     [INF, INF, INF, 1, 3, INF, 9],
     [INF, INF, INF, INF, 5, 9, INF]]

def shotest_path(s)
  d = Array.new(G.size, INF)

  d[s] = 0

  loop do
    update = false

    G.each_with_index do |row, i|
      row.each_with_index do |cost, j|
        next if cost == INF || d[i] == INF

        if d[j] > d[i] + cost
          d[j] = d[i] + cost
          update = true
        end
      end
    end

    break unless update
  end

  d
end

p shotest_path(0) # => [0, 2, 5, 7, 11, 8, 16]

単一始点最短経路問題(ダイクストラ)

ベルマンフォードと目的は一緒
まだ訪れていない頂点の中から最短の頂点を見つけてそこから他の頂点への経路のコストを得る

INF = 100_000

G = [[INF, 2, 5, INF, INF, INF, INF],
     [2, INF, 4, 6, 10, INF, INF],
     [5, 4, INF, 2, INF, INF, INF],
     [INF, 6, 2, INF, INF, 1, INF],
     [INF, 10, INF, INF, INF, 3, 5],
     [INF, INF, INF, 1, 3, INF, 9],
     [INF, INF, INF, INF, 5, 9, INF]]

def dijkstra(s)
  size = G.size
  d = Array.new(size, INF)
  used =  Array.new(size, false)
  d[s] = 0

  loop do
    min_node = -1

    size.times do |i|
      min_node = i if !used[i] && (min_node == -1 || d[min_node] > d[i])
    end

    break if min_node == -1
    used[min_node] = true

    size.times do |i|
      d[i] = [d[min_node] + G[min_node][i], d[i]].min
    end
  end

  d
end

p dijkstra(0) # => [0, 2, 5, 7, 11, 8, 16]

全点対最短経路( ワーシャルフロイド)

すべての頂点からそれ以外のすべての頂点の最短経路
iからjまでのパスの中で頂点k通るか通らないかのDP
通るときはg[i][k] + g[k][j]で通らない時はg[i][j]
ホントはd[k][i][j]とかなるんだけどループ内で省略してる

INF = 100_000

def warshall_floyd

  g = [[0, 2, 5, INF, INF, INF, INF],
       [2, 0, 4, 6, 10, INF, INF],
       [5, 4, 0, 2, INF, INF, INF],
       [INF, 6, 2, 0, INF, 1, INF],
       [INF, 10, INF, 0, INF, 3, 5],
       [INF, INF, INF, 1, 3, 0, 9],
       [INF, INF, INF, INF, 5, 9, 0]]

  size = g.size

  size.times do |k|
    size.times do |i|
      size.times do |j|
        g[i][j] = [g[i][j], g[i][k] + g[k][j]].min
      end
    end
  end

  g
end

p warshall_floyd # [[0, 2, 5, 7, 11, 8, 16], [2, 0, 4, 6, 10, 7, 15], [5, 4, 0, 2, 6, 3, 11], [7, 6, 2, 0, 4, 1, 9], [7, 6, 2, 0, 4, 1, 5], [8, 7, 3, 1, 3, 0, 8], [12, 11, 7, 5, 5, 6, 0]]

アリ本のP102
2番めの最短経路をだす問題
priority_queueがなかったのでかなり汚い感じになった
基本方針はすべての頂点に対して2番めの最短経路も持っとくこと

N = 4
M = 4
INF = 100_000

G = [[INF, 100, INF, INF],
     [100, INF, 250, 200],
     [INF, 250, INF, 100],
     [INF, 200, 100, INF]]

def solve
  d1 = Array.new(N, INF)
  used1 = Array.new(N, false)
  d2 = Array.new(N, INF)
  used2 = Array.new(N, false)

  d1[0] = 0
  d2[0] = 0

  loop do
    v = [-1, 1]

    N.times do |i|
      v = [i, 1] if !used1[i] && (v[0] == -1 || d1[v[0]] > d1[i])
      v = [i, 2] if !used2[i] && (v[0] == -1 || d2[v[0]] > d2[i])
    end

    break if v[0] == -1
    eval("used#{v[1]}[#{v[0]}]=true")

    N.times do |i|
      d = eval("d#{v[1]}[#{v[0]}]") + G[v[0]][i]

      if d < d1[i]
        d, d1[i] = d[i], d
      end

      if d > d1[i] && d < d2[i]
        d2[i] = d
      end
    end
  end

  d2[N-1]
end

p solve # => 450

今日解いた問題2

彩色問題

アリ本の93ページ
隣接したりノードが同じ色にならないように色をぬる。
今回は2色で塗ることができるかという問題
特に2色でぬれるグラフを2部グラフという

コードで言うと0が塗ってないノードなので下の2つを繰り返す感じ

  • 隣接したノードjが0ならノードjに対して色(-c)を塗る
  • 隣接したノードjと現在のノードがiが同じ色c(1 or 0)ならfalseを返す
G1 = [[0, 1, 1],
      [1, 0, 1],
      [1, 1, 0]].freeze

G2 = [[0, 1, 0, 1],
      [1, 0, 1, 0],
      [0, 1, 0, 1],
      [1, 0, 1, 0]].freeze

s = G2.size
$color = Array.new(s, 0)         # 0は塗ってない 1と-1が塗った

def dfs(i, c)
  $color[i] = c

  G2[i].each_with_index do |e, j|
    next unless e == 1
    return false if $color[j] == c
    return false if $color[j].zero? && !dfs(j, -c)
  end

  true
end

s.times do |i|
  next unless $color[i].zero?
  unless dfs(i, 1)
    puts 'NO'
    break
  end
  puts 'YES'
end