class NamedVector
Vectors with named dimensions. Infinite dimensional objects with simple vector calculus operations defined.
Attributes
Public Class Methods
adds a dimension iterator (iterate through the keys) to a Hash or NamedVector
@param obj [Hash, NamedVector] the object to add the method to.
# File lib/named_vector.rb, line 59 def self.add_dimension_iterator(obj) obj.define_singleton_method(:each_dimension) do |&block| self.keys.each do |key| block.call(key) end end end
Perform a dot product with another vector @param a [Hash, NamedVector] the vector or scalar to multiply this vector with. @param b [Hash, NamedVector] the vector or scalar to multiply this vector with.
# File lib/named_vector.rb, line 76 def self.dot_product(a, b) sum = 0.0 if a.keys.length < b.keys.length a.each_dimension {|i| sum+=a[i]*b[i]} else b.each_dimension {|i| sum+=b[i]*a[i]} end sum end
Mongo conversion @param doc [BSON::OrderedHash] the mongo document to retrieve the vector from.
# File lib/named_vector.rb, line 188 def self.from_mongo(doc) if doc.is_a?(self) then doc else hash = {} doc["keys"].each_with_index do |k, index| hash[k] = doc["dimensions"][index] end NamedVector.new(hash) end end
creates a new named vector @param dims [Hash<String,Fixnum>, Hash<Symbol,Fixnum>, Array<String>, Array<Symbol>] the dimensions to initialize the vectors with, either as a hash of assignments or simply the names of the dimensions.
# File lib/named_vector.rb, line 12 def initialize(*dims) @vector = Hash.new @keys = Set.new import_dimensions(dims) end
Mongo retrieval @param doc [BSON::OrderedHash] the mongo document to retrieve the vector from.
# File lib/named_vector.rb, line 179 def self.to_mongo(hash) if hash.is_a?(Hash) then hash else {"keys"=> hash.keys.to_a, "dimensions" => hash.keys.map {|i| hash[i]}} end end
Public Instance Methods
Perform a dot product with another vector @param value [Hash, Fixnum, Float, NamedVector] the vector or scalar to multiply this vector with. Scalar multiplication is destructive.
# File lib/named_vector.rb, line 43 def *(value) case value when Fixnum, Float #scalar multiplication product each_dimension {|i| @vector[i] = self[i]*value} when NamedVector #dot product NamedVector.dot_product(self, value) when Hash #dot product NamedVector.add_dimension_iterator(value) NamedVector.dot_product(self,value) else raise TypeError, "#{value.class} cannot be coerced to NamedVector." end end
fetches the value at the dimension specified @param key [Symbol, String] the dimension requested
# File lib/named_vector.rb, line 95 def [](key) @vector.fetch(key.to_s,0.0) end
assigns a value at the dimension specified @param key [Symbol, String] the dimension requested @param value [Fixnum, Float] the assignment for this dimension
# File lib/named_vector.rb, line 107 def []=(key,value) modify_dimension(key,value) end
Perform a dot product with another vector @param value [Hash, NamedVector] the vector to multiply this vector with.
# File lib/named_vector.rb, line 69 def dot_product(value) NamedVector.dot_product(self, value) end
iterates through each dimension of a vector
# File lib/named_vector.rb, line 87 def each_dimension @keys.each do |key| yield(key) end end
# File lib/named_vector.rb, line 144 def eql?(other) false unless other.keys == @keys all_keys = other.keys.merge(@keys) all_keys.each do |key| if other[key] != self[key] then return false end end true end
imports the dimension information in Array form @param dimsĀ [Array<Array>,Array<String>, Array<Symbol>, Array<Hash>, Array<Fixnum>, Array<Array>] values to initialize
# File lib/named_vector.rb, line 20 def import_dimensions(dims) if dims && dims.first case dims.first when Array array = dims.first if array.first.class == String @keys = Set.new(array.map {|i| i.to_s}) array.each {|d| self[d]+=1} end when Hash hash = dims.first hash.keys.each {|d| modify_dimension(d, hash[d])} when String, Symbol, Fixnum @keys = Set.new(dims.map {|i| i.to_s}) dims.each {|d| new_dimension(d)} end else @keys = [] end end
the Euclidean norm of a vector
# File lib/named_vector.rb, line 166 def norm Math.sqrt(squared_norm) end
normalizes the vector destructively.
# File lib/named_vector.rb, line 171 def normalize current_norm = norm if current_norm > 0 then self*(1.0/current_norm) end self end
the squared Euclidean norm of a vector
# File lib/named_vector.rb, line 138 def squared_norm norm = 0.0 each_dimension {|i| norm+=self[i]**2} norm end
# File lib/named_vector.rb, line 157 def to_a @vector.to_a end
# File lib/named_vector.rb, line 153 def to_s "<#NamedVector @keys=\"#{@keys.inspect}\", @vector=\"#{@vector.inspect}\">" end
Private Instance Methods
# File lib/named_vector.rb, line 99 def modify_dimension(key,value) new_dimension(key.to_s) @vector[key.to_s] = value end
# File lib/named_vector.rb, line 126 def new_dimension(name) sym_name = name.to_sym unless respond_to?(sym_name) @keys << name define_singleton_method(sym_name) { @vector.fetch(name,0.0) } define_singleton_method("#{sym_name}=") { |x| @vector[name] = x } end name end