今日のRuby

実数直積集合の距離関数(see: wikipedia:距離空間)をナイーブに実装。

module Matric

  class << self

    def chebyshev(array1, array2, k)
      raise "All elements in 'array1' shall be real numbers" 
        unless array1.all?{|i| i.is_a?(Fixnum) || i.is_a?(Float)}
      raise "All elements in 'array2' shall be real numbers" 
        unless array2.all?{|i| i.is_a?(Fixnum) || i.is_a?(Float)}
      raise "The argument 'k' shall be a natural number" unless  k.is_a?(Fixnum) && k > 0
      pairs = pair(array1, array2)
      pairs.map{|p|
        (p[0] - p[1]).abs ** k
      }.reduce{|i, j|
        i + j
      } ** (1.0 / k)
    end

    def city_block(array1, array2)
      return chebyshev(array1, array2, 1)
    end

    def euclidean(array1, array2)
      return chebyshev(array1, array2, 2)
    end

    private
    def pair(array1, array2)
      raise if array1.size != array2.size
      return Array.new(array1.size) do |i|
        [array1[i], array2[i]]
      end
    end
    
  end

end

チェビシェフ距離を定義して、そのアプリケーションとしてユークリッド距離とマンハッタン距離を実装してます。

テストケース。このテストは同じものを与えて距離が0になるかどうかしかテストしていない。不十分。

require 'test/unit'
require File.join(File.dirname(__FILE__), "matric")

class TestMatric < Test::Unit::TestCase

  def setup
    @data1 = [0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1,
              1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
              1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0,
              1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1,
              1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0,
              0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0,
              1, 0, 0, 1]
    @data2 = [1, 0, 0, 1, 1, 1, 1, 1, 1, 0]
    @trash_data = [1, 2, 3, 4, 5, 6, "a", 1]
  end
  
  def test_chebyshev
    begin
      Matric.chebyshev(@data1, @data1, false)
      assert(false)
    rescue
      assert(true)
    end

    begin
      Matric.chebyshev(@data1, @data2, 1)
      assert(false)
    rescue
      assert(true)
    end
    
    begin
      Matric.chebyshev(@data1, @trash_data, 1)
      assert(false)
    rescue
      assert(true)
    end

  end

  def test_city_block
    assert(Matric.city_block(@data1, @data1) == 0)
  end

  def test_euclidean
    assert(Matric.city_block(@data1, @data1) == 0)
  end

end