1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 74 75 76 77 78 79
|
module Neighbor
class SparseVector
attr_reader :dimensions, :indices, :values
NO_DEFAULT = Object.new
def initialize(value, dimensions = NO_DEFAULT)
if value.is_a?(Hash)
if dimensions == NO_DEFAULT
raise ArgumentError, "missing dimensions"
end
from_hash(value, dimensions)
else
unless dimensions == NO_DEFAULT
raise ArgumentError, "extra argument"
end
from_array(value)
end
end
def to_s
"{#{@indices.zip(@values).map { |i, v| "#{i.to_i + 1}:#{v.to_f}" }.join(",")}}/#{@dimensions.to_i}"
end
def to_a
arr = Array.new(dimensions, 0.0)
@indices.zip(@values) do |i, v|
arr[i] = v
end
arr
end
private
def from_hash(data, dimensions)
elements = data.select { |_, v| v != 0 }.sort
@dimensions = dimensions.to_i
@indices = elements.map { |v| v[0].to_i }
@values = elements.map { |v| v[1].to_f }
end
def from_array(arr)
arr = arr.to_a
@dimensions = arr.size
@indices = []
@values = []
arr.each_with_index do |v, i|
if v != 0
@indices << i
@values << v.to_f
end
end
end
class << self
def from_text(string)
elements, dimensions = string.split("/", 2)
indices = []
values = []
elements[1..-2].split(",").each do |e|
index, value = e.split(":", 2)
indices << index.to_i - 1
values << value.to_f
end
from_parts(dimensions.to_i, indices, values)
end
private
def from_parts(dimensions, indices, values)
vec = allocate
vec.instance_variable_set(:@dimensions, dimensions)
vec.instance_variable_set(:@indices, indices)
vec.instance_variable_set(:@values, values)
vec
end
end
end
end
|