Class: KnnBall::Ball

Inherits:
Object
  • Object
show all
Defined in:
lib/knnball/ball.rb

Overview

This class represents a ball in the tree.

The value of this ball will be its center while its radius is the distance between the center and the most far sub-ball.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(value, dimension = 1, left = nil, right = nil) ⇒ Ball

Returns a new instance of Ball.

Parameters:

  • value

    the value associated to this ball

  • actual_dimension

    the dimension used for sorting left and right tree



21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/knnball/ball.rb', line 21

def initialize(value, dimension = 1, left = nil, right = nil)
  unless (value.respond_to?(:include?) && value.respond_to?(:[]))
    raise ArgumentError.new("Value must at least respond to methods include? and [].")
  end
  unless (value.include?(:point))
    raise ArgumentError.new("value must contains :point key but has only #{value.keys.inspect}")
  end
  @value = value
  @right = right
  @dimension = dimension
  @left = left
end

Instance Attribute Details

#dimensionObject

Returns the value of attribute dimension.



17
18
19
# File 'lib/knnball/ball.rb', line 17

def dimension
  @dimension
end

#leftObject

Returns the value of attribute left.



17
18
19
# File 'lib/knnball/ball.rb', line 17

def left
  @left
end

#rightObject

Returns the value of attribute right.



17
18
19
# File 'lib/knnball/ball.rb', line 17

def right
  @right
end

#valueObject

Returns the value of attribute value.



17
18
19
# File 'lib/knnball/ball.rb', line 17

def value
  @value
end

Instance Method Details

#centerObject



34
35
36
# File 'lib/knnball/ball.rb', line 34

def center
  value[:point]
end

#complete?Boolean

Return true if this ball has a left and a right ball

Returns:

  • (Boolean)


103
104
105
# File 'lib/knnball/ball.rb', line 103

def complete?
  ! (@left.nil? || @right.nil?)
end

#countObject



91
92
93
# File 'lib/knnball/ball.rb', line 91

def count
  1 + (left.nil? ? 0 : left.count) + (right.nil? ? 0 : right.count)
end

#distance(coordinates) ⇒ Object

Compute euclidien distance.

Parameters:

  • coordinates

    an array of coord or a Ball instance



78
79
80
81
# File 'lib/knnball/ball.rb', line 78

def distance(coordinates)
  coordinates = coordinates.center if coordinates.respond_to?(:center)
  Math.sqrt([center, coordinates].transpose.map {|a,b| (b - a)**2}.reduce {|d1,d2| d1 + d2})
end

#leaf?Boolean

Retrieve true if this is a leaf ball.

A leaf ball has no sub_balls.

Returns:

  • (Boolean)


98
99
100
# File 'lib/knnball/ball.rb', line 98

def leaf?
  @left.nil? && @right.nil?
end

#nearest(target, min) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/knnball/ball.rb', line 38

def nearest(target, min)
  result = nil
  d = [quick_distance(target), min[0]].min
  if d < min[0]
    min[0] = d
    result = self
  end
  
  # determine if we need to dive into sub tree
  dp = (center[dimension-1] - target[dimension-1]).abs
  new_result = nil
  if(dp < min[0])
    # must dive into both left and right
    unless(left.nil?)
      new_result = left.nearest(target, min)
      result = new_result unless new_result.nil?
    end
    unless right.nil?
      new_result = right.nearest(target, min)
      result = new_result unless new_result.nil?
    end
  else
    # only need to dive in one
    if(target[dimension-1] < center[dimension-1])
      unless(left.nil?)
        new_result = left.nearest(target, min)
      end
    else
      unless(right.nil?)
        new_result = right.nearest(target, min)
      end
    end
    result = new_result unless new_result.nil?
  end
  return result
end

#quick_distance(coordinates) ⇒ Object

Quickly compute a distance using Manhattan



84
85
86
87
88
89
# File 'lib/knnball/ball.rb', line 84

def quick_distance(coordinates)
  distance(coordinates)
#      coordinates = coordinates.center if coordinates.respond_to?(:center)
#      [center, coordinates].transpose.map {|a,b| (b - a)**2}.reduce {|d1,d2| d1 + d2}
#      [center, coordinates].transpose.map {|a,b| (b - a).abs}.reduce {|d1,d2| d1 + d2}
end

#to_aObject

Generate an Array from this Ball.

index 0 contains the value object, index 1 contains the left ball or nil, index 2 contains the right ball or nil.



112
113
114
115
116
117
118
# File 'lib/knnball/ball.rb', line 112

def to_a
  if leaf?
    [@value, nil, nil]
  else
    [@value, (@left.nil? ? nil : @left.to_a), (@right.nil? ? nil : @right.to_a)]
  end
end

#to_hObject

Generate a Hash from this Ball instance.

The generated instance contains keys :id, :left and :right



123
124
125
126
127
128
129
# File 'lib/knnball/ball.rb', line 123

def to_h
  if leaf?
    {:value => @value, :left => nil, :right => nil} 
  else
    {:value => @value, :left => (@left.nil? ? nil : @left.to_h), :right => (@right.nil? ? nil : @right.to_h)}
  end
end