Class: Neighbor::Vector
- Inherits:
-
ActiveRecord::Type::Value
- Object
- ActiveRecord::Type::Value
- Neighbor::Vector
- Defined in:
- lib/neighbor/vector.rb
Class Method Summary collapse
- .cast(value, dimensions:, normalize:, column_info:) ⇒ Object
- .column_info(model, attribute_name) ⇒ Object
Instance Method Summary collapse
- #cast(value) ⇒ Object
-
#column_info ⇒ Object
need to be careful to avoid loading column info before needed.
- #deserialize(value) ⇒ Object
-
#initialize(dimensions:, normalize:, model:, attribute_name:) ⇒ Vector
constructor
A new instance of Vector.
- #serialize(value) ⇒ Object
Constructor Details
#initialize(dimensions:, normalize:, model:, attribute_name:) ⇒ Vector
Returns a new instance of Vector.
3 4 5 6 7 8 9 |
# File 'lib/neighbor/vector.rb', line 3 def initialize(dimensions:, normalize:, model:, attribute_name:) super() @dimensions = dimensions @normalize = normalize @model = model @attribute_name = attribute_name end |
Class Method Details
.cast(value, dimensions:, normalize:, column_info:) ⇒ Object
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/neighbor/vector.rb', line 11 def self.cast(value, dimensions:, normalize:, column_info:) value = value.to_a.map(&:to_f) dimensions ||= column_info[:dimensions] raise Error, "Expected #{dimensions} dimensions, not #{value.size}" if dimensions && value.size != dimensions raise Error, "Values must be finite" unless value.all?(&:finite?) if normalize norm = Math.sqrt(value.sum { |v| v * v }) # store zero vector as all zeros # since NaN makes the distance always 0 # could also throw error # safe to update in-place since earlier map dups value.map! { |v| v / norm } if norm > 0 end value end |
.column_info(model, attribute_name) ⇒ Object
33 34 35 36 37 38 39 40 |
# File 'lib/neighbor/vector.rb', line 33 def self.column_info(model, attribute_name) attribute_name = attribute_name.to_s column = model.columns.detect { |c| c.name == attribute_name } { type: column.try(:type), dimensions: column.try(:limit) } end |
Instance Method Details
#cast(value) ⇒ Object
47 48 49 |
# File 'lib/neighbor/vector.rb', line 47 def cast(value) self.class.cast(value, dimensions: @dimensions, normalize: @normalize, column_info: column_info) unless value.nil? end |
#column_info ⇒ Object
need to be careful to avoid loading column info before needed
43 44 45 |
# File 'lib/neighbor/vector.rb', line 43 def column_info @column_info ||= self.class.column_info(@model, @attribute_name) end |
#deserialize(value) ⇒ Object
61 62 63 |
# File 'lib/neighbor/vector.rb', line 61 def deserialize(value) value[1..-1].split(",").map(&:to_f) unless value.nil? end |
#serialize(value) ⇒ Object
51 52 53 54 55 56 57 58 59 |
# File 'lib/neighbor/vector.rb', line 51 def serialize(value) unless value.nil? if column_info[:type] == :vector "[#{cast(value).join(", ")}]" else "(#{cast(value).join(", ")})" end end end |