メインマシン(Ubuntu)が起動しなくなった

今朝のこと。Ubuntu 16.04 のメインマシン(apostrophe)を見るとソフトウェアのアップデートが表示されていたので、アップデートした。すると、アップデートを完了するにはマシンの再起動が必要だというので、再起動したところ、起動しなくなってしまった。DELL のロゴマークが表示された状態で止まっていて、それっきり動きがない。
ともかく朝で時間がないので、そのまま様子を見ることにして(つまりほうっておいて)出かけたわけだ。
で、今帰ってきてみたら今朝と同じ状態のまま。マシンの電源を切ったり入れたりしてみるも変化がない。どういうわけだ。明日明後日と用事があってまとまった時間が取れそうにないんだけど、最悪再インストールかも。どうしたもんかね。

[追記]

Ubuntu のインストールディスクを入れて起動してみたけどダメだった。というか、DELL のロゴマークが表示されている状態で止まってるってここは、OS 以前の BIOS の途中で止まってるってことじゃなかろうか。こりゃダメかな。

球面上の点を平面上にステレオ投影する

先週のさらに続き。先週は、球面上の点を平面上に投影するのに X, Y 座標をそのまま使って水平投影したけど、今度はステレオ投影というのをやってみる。
ステレオ投影は Wikipedia に詳しく載っている。
先週と同じように、下半球の点 300 個を XY 平面(赤道面)上に投影する。やってみたのが下の図。

コードは次の通り。

#!/usr/bin/env ruby
# encoding: utf-8 require 'csv' def sp(x, y, z)
[x / (1.0 - z), y / (1.0 - z)]
end csv = File.open(ARGV.shift, "r") csv.each_line do |line|
x, y, z = line.parse_csv.map{|v| v.to_f }
r = Math.sqrt(x * x + y * y + z * z)
print sp(x, y, z).map{|v| v * r }.to_csv
end

やっつけ仕事なので、ヘルプもないけど、先週の gss_gen コマンド(--cartesian オプション付き)の結果を入力として、投影点の座標を CSV で出力する。

多数の点を球面上に一様分布させる(2)

一昨日の続き。最初と最後の点を極から移動(位置調整)するのを実装した。ついでに、gem 化して RubyGems.org にアップしておいた。gem install gss_generator でインストールできる。
使い方は次の通り。

^o^ > gss_gen --cartesian --relocate 1.0 600 > c600r.csv

--cartesian はデカルト座標系で出力、--relocate は位置調整のオプション。結果は CSV 形式で標準出力に出力するので c600r.csv ファイルにリダイレクトしている。

結果を一昨日と同様の図にしたものを載せる。

最初の点が極(中心)からずれて、一様性が増しているのがわかる。

多数の点を球面上に一様分布させる

ちょっと面白いものを見つけた。

cf. LEDドームのLEDの並びを決めるのに使用した計算式 – jakaladaのブログ

球面上に任意個の点を一様分布させる、座標を求めるもの。一般化螺旋集合(generalized spiral set)というものを使っている。元の資料(論文)はここ。

cf. 多数の点を球面上に一様分布させるソフトウェアGSS Generator

上のリンク先のブログでは Python を使っているので、Ruby でやってみた。

#!/usr/bin/env ruby
# encoding: utf-8

require 'gss'
require 'optparse'
require 'csv'

options = {}
opts = OptionParser.new
opts.banner = "Generate points with uniform distribution on the sphere."
opts.on("-c", "--cartesian", "Cartesian coordinate."){|v|
  options[:cartesian] = true
}
opts.on_tail("-h", "--help", "Show this message."){|v|
  print opts.help
  exit
}
opts.on_tail("-v", "--version", "Show version."){|v|
  puts "v#{GSS::VERSION}"
  exit
}
opts.parse!

r = ARGV.shift.to_f
n = ARGV.shift.to_i

gss = GSS::GSS.new
points = gss.generate(r, n)
points.each do |p|
  if options[:cartesian]
    coord = p.to_cartesian
    print coord.to_csv
  else
    print [p.r, p.theta, p.phi].to_csv
  end
end
# encoding: utf-8

require "gss/polar_point"

module GSS
  class GSS
    def generate(r, n)
      theta_1 = Math::PI
      phi_1 = 0.0

      points = []
      points << PolarPoint.new(r, theta_1, phi_1)
      2.upto(n) do |k|
        h_k = -1.0 + 2.0 * (k - 1) / (n - 1)
        theta_k = Math.acos(h_k)
        phi_k = points.last.phi + 3.6 / Math.sqrt(n) * 1 / Math.sqrt(1 - h_k ** 2)
        phi_k = phi_k.infinite? ? 0.0 : phi_k % (Math::PI * 2.0)
        points << PolarPoint.new(r, theta_k, phi_k)
      end
      points
    end
  end # of class GSS
end # of module GSS
# encoding: utf-8
module GSS
  class PolarPoint
    attr_reader :r, :theta, :phi

    def initialize(r, theta, phi)
      @r = r
      @theta = theta
      @phi = phi
    end

    def to_cartesian
      x = @r * Math.sin(@theta) * Math.cos(@phi)
      y = @r * Math.sin(@theta) * Math.sin(@phi)
      z = @r * Math.cos(@theta)
      [x, y, z]
    end
  end # of class PolarPoint
end # of module GSS

最初のがコマンドで、あとの2つがライブラリ。引数に球の半径と配置したい点の個数を指定すると、各点の極座標を CSV 形式で出力する。

^o^ > ruby -Ilib exe/gss_gen 1.0 600

極座標じゃなく、デカルト座標(XYZ座標)がほしい時には --cartesian オプション。

^o^ > ruby -Ilib exe/gss_gen --cartesian 1.0 600

下の図は、発生させた600個の点のうち下半分の300個を XY 平面上に投影した図。

各点を順に線でつないでみると、螺旋になっているのがよくわかる。

……なんか螺旋が逆になってるな。元論文じゃ球面を下から見たと書いてあるからそのせいか?

ともあれ、それらしいのはできた。ただし、最初と最後の点の座標を調整するのはやってない。時間があったらやってみよう。

SinatraでSECURITY WARNING: No secret option provided to Rack::Session::Cookie.というワーニングが出たときの対処法

Sinatra でアプリを作ってるんだけど、セッションを利用するとタイトルのようなワーニングが出た。もっと詳しく書くと次のとおり。

SECURITY WARNING: No secret option provided to Rack::Session::Cookie.
This poses a security threat. It is strongly recommended that you
provide a secret to prevent exploits that may be possible from crafted
cookies. This will not be supported in future versions of Rack, and
future versions will even invalidate your existing user cookies.

ググってみても見つかるのは、Rails のバージョンを上げろとか、Rack のバージョンを 1.4.1 にしろとかいうのばっかり。Rails は使ってないし、Rack は 1.6.5 なんだけどなあ。そんな中で見つけたのが↓このページ。

cf. SECURITY WARNING: No secret option provided to Rack::Session::Cookie

config.ru で :session_secret に値を設定すればいいらしい。
具体的には次のようにした。

enable :sessions
set :session_secret, 'somethingverysecret1234'

これでめでたくワーニングが出なくなった。

Ubuntuで作ったwheelパッケージをWindowsにインストールする

このあいだ Ubuntu で作った wheel パッケージ、Windows にインストールしてみた。
pure Python なのであたりまえだけど、何の問題もなくインストールできた。

^o^ > pip install myapp-0.0.1-py2-none-any.whl
Processing c:\users\hiro\documents\tmp\myapp-0.0.1-py2-none-any.whl
Installing collected packages: myapp
Successfully installed myapp-0.0.1

動作確認。

^o^ > myapp foo bar baz
['C:\\Python27\\Scripts\\myapp', 'foo', 'bar', 'baz']

^o^ > which myapp
C:/Python27/Scripts/myapp.EXE

へぇ、Windows だと .EXE ファイルができるんだ。

Elixir 練習問題 StringsAndBinaries-7

defmodule Sales do
  def csv_to_list(filename) do
    {:ok, file} = File.open(filename, [:read])
    headers = (IO.read(file, :line) |> parse_csv_atom)
    IO.stream(file, :line)
    |> Enum.map(fn l -> parse_csv(l) end)
    |> Enum.map(fn sales -> Enum.zip(headers, sales) end)
  end

  defp parse_csv_atom(line) do
    String.trim(line, "\n")
    |> String.split(",")
    |> Enum.map(&String.to_atom/1)
  end

  defp parse_csv(line) do
    [id, ship_to, net_amount] = (String.trim(line, "\n") |> String.split(","))
    [String.to_integer(id), String.to_atom(String.trim(ship_to, ":")), String.to_float(net_amount)]
  end
end

IO.inspect Sales.csv_to_list("sales.csv")
^o^ > cat sales.csv
id,ship_to,net_amount
123,:NC,100.00
124,:OK,35.50
125,:TX,24.00
126,:TX,44.80
127,:NC,25.00
128,:MA,10.00
129,:CA,102.00
130,:NC,50.00

^o^ > elixir practice_11_7.exs
[[id: 123, ship_to: :NC, net_amount: 100.0],
 [id: 124, ship_to: :OK, net_amount: 35.5],
 [id: 125, ship_to: :TX, net_amount: 24.0],
 [id: 126, ship_to: :TX, net_amount: 44.8],
 [id: 127, ship_to: :NC, net_amount: 25.0],
 [id: 128, ship_to: :MA, net_amount: 10.0],
 [id: 129, ship_to: :CA, net_amount: 102.0],
 [id: 130, ship_to: :NC, net_amount: 50.0]]

Elixir 練習問題 StringsAndBinaries-6

defmodule Str do
  def capitalize(word) do
    String.to_charlist(word)
    |> to_upper([])
    |> to_string
  end

  defp to_upper([], result) do
    Enum.reverse(result)
  end
  defp to_upper([32|tail], result) do
    to_upper(tail, [32|result])
  end
  defp to_upper([?.|tail], result) do
    to_upper(tail, result)
  end
  defp to_upper([c|tail], result) do
    to_lower(tail, [upcase(c)|result])
  end
  defp upcase(c) when c <= ?Z, do: c
  defp upcase(c),              do: c - 32

  defp to_lower([], result) do
    Enum.reverse(result)
  end
  defp to_lower([32|tail], result) do
    to_lower(tail, [32|result])
  end
  defp to_lower([?.|tail], result) do
    to_upper(tail, [?.|result])
  end
  defp to_lower([c|tail], result) do
    to_lower(tail, [lowcase(c)|result])
  end
  defp lowcase(c) when c >= 97, do: c
  defp lowcase(c),              do: c + 32
end


IO.puts Str.capitalize("oh. a DOG. woof. ")
^o^ > elixir practice_11_6.exs
Oh. A dog. Woof.

Elixir 練習問題 StringsAndBinaries-5

defmodule Str do
  def center(slist) do
    len = longest(slist)
    slist
    |> Enum.map(fn s -> _center(s, len) end)
    |> Enum.each(&IO.puts/1)
  end

  defp longest(slist) do
    slist
    |> Enum.map(&String.length/1)
    |> Enum.max
  end

  defp _center(str, len) do
    l = div(len - String.length(str), 2)
    String.duplicate(" ", l) <> str
  end
end


Str.center(["cat", "zebra", "elephant"])
^o^ > elixir practice_11_5.exs
  cat
 zebra
elephant

Elixir 練習問題 StringsAndBinaries-4

defmodule Calculater do
  def calculate(charlist) do
    parse(charlist)
    |> calc
  end

  defp parse(charlist) do
    tokenize(charlist, [[]])
    |> _parse
  end

  defp tokenize([], result) do
    Enum.reverse(result)
  end
  defp tokenize([32|tail], result) do
    tokenize(tail, [[] | result])
  end
  defp tokenize([head|tail], [cur|rest]) do
    tokenize(tail, [cur ++ [head] | rest])
  end

  defp _parse([opnd1, op, opnd2]) do
    num1 = number(opnd1, 0)
    num2 = number(opnd2, 0)
    {op, num1, num2}
  end

  defp number([], value) do
    value
  end
  defp number([digit|tail], value) do
    number(tail, value * 10 + digit - ?0)
  end

  defp calc({'+', n1, n2}), do: n1 + n2
  defp calc({'-', n1, n2}), do: n1 - n2
  defp calc({'*', n1, n2}), do: n1 * n2
  defp calc({'/', n1, n2}), do: n1 / n2
end


IO.puts Calculater.calculate('123 + 27')
IO.puts Calculater.calculate('123 - 23')
IO.puts Calculater.calculate('100 * 2')
IO.puts Calculater.calculate('100 / 5')
^o^ > elixir practice_11_4.exs
150
100
200
20.0