Class: R::Vector
- Includes:
- Enumerable, BinaryOperators, ExecBinOp, ExecUniOp, IndexedObject, LogicalOperators, UnaryOperators
- Defined in:
- lib/R_interface/rvector.rb
Constant Summary collapse
- CHUNK_SIZE =
1M rows per page
1_000_000
Constants inherited from Object
Instance Attribute Summary
Attributes inherited from Object
Instance Method Summary collapse
-
#<=>(other_vector) ⇒ Object
-------------------------------------------------------------------------------------- @TODO: SHOULD DEFINE COMPARISON BETWEEN TWO VECTORS --------------------------------------------------------------------------------------.
- #class ⇒ Object
- #each(mode = :vec) ⇒ Object
-
#each_with_index(result = :vec) ⇒ Object
-------------------------------------------------------------------------------------- Need to override each_with_index, as R indexing starts at 1 --------------------------------------------------------------------------------------.
-
#initialize(r_interop) ⇒ Vector
constructor
--------------------------------------------------------------------------------------.
- #map(&block) ⇒ Object
-
#pop ⇒ Object
--------------------------------------------------------------------------------------.
- #stitch(halo: 0, &block) ⇒ Object
-
#to_ary ⇒ Object
Return Ruby array so RSpec/eq and array conversion don't forward to_ary to R.
-
#unboxed_get(index = nil, depth = 0) ⇒ Object
(also: #>>, #<<)
-------------------------------------------------------------------------------------- Unbox vector to Ruby.
Methods included from LogicalOperators
Methods included from ExecUniOp
Methods included from UnaryOperators
Methods included from ExecBinOp
Methods included from BinaryOperators
#!=, #%, #*, #**, #+, #-, #/, #<, #<=, #>, #>=, #_, #eq, #int_div, #til
Methods included from IndexedObject
Methods inherited from Object
#==, build, build_class_probe_count, build_from_r_class_string, build_from_wrapper_tag, #call, class_probe_fetch_r_class, increment_build_class_probe_count!, #inspect, #instance_of?, #instance_variable_get, #instance_variable_set, #is_a?, #method_missing, #nil?, #pretty_print, #rclass, reset_build_counters!, #respond_to?, #send, #to_i, #to_ruby, #to_s, #typeof
Constructor Details
#initialize(r_interop) ⇒ Vector
43 44 45 |
# File 'lib/R_interface/rvector.rb', line 43 def initialize(r_interop) super(r_interop) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class R::Object
Instance Method Details
#<=>(other_vector) ⇒ Object
@TODO: SHOULD DEFINE COMPARISON BETWEEN TWO VECTORS
204 205 206 |
# File 'lib/R_interface/rvector.rb', line 204 def <=>(other_vector) ::Kernel.raise(::NotImplementedError, "R::Vector#<=> is not implemented") end |
#each(mode = :vec) ⇒ Object
165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/R_interface/rvector.rb', line 165 def each(mode = :vec) case mode when :vec (1..length.unboxed_get(0)).each do |i| yield self[i] end when :native (0...length.unboxed_get(0)).each do |i| yield unboxed_get(i) end else ::Kernel.raise("Type #{mode.inspect} is unknown for method :each") end end |
#each_with_index(result = :vec) ⇒ Object
Need to override each_with_index, as R indexing starts at 1
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/R_interface/rvector.rb', line 184 def each_with_index(result = :vec) case result when :vec (1..length.unboxed_get(0)).each do |i| yield self[i], i end when :native (0...length.unboxed_get(0)).each do |i| yield unboxed_get(i), i end else ::Kernel.raise("Type #{result} is unknown for method :each") end end |
#map(&block) ⇒ Object
159 160 161 162 163 |
# File 'lib/R_interface/rvector.rb', line 159 def map(&block) stitch(halo: 0) do |data| data.map(&block) end end |
#pop ⇒ Object
110 111 112 113 |
# File 'lib/R_interface/rvector.rb', line 110 def pop # Return unboxed first element as a Ruby scalar unboxed_get(0) end |
#stitch(halo: 0, &block) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/R_interface/rvector.rb', line 117 def stitch(halo: 0, &block) len = atomic_vector_length # 2. Allocate result vector in R res_name = ::R::Support.generate_var_name ::R.bridge.eval_r("#{res_name} <- numeric(#{len})") # 3. Process in chunks with Halo offset = 0 while offset < len current_chunk_size = [CHUNK_SIZE, len - offset].min # Calculate extended range for Halo # R indices start at 1, but pull_double_vector uses 0-based offset pull_offset = [0, offset - halo].max pull_end = [len, offset + current_chunk_size + halo].min actual_pull_size = pull_end - pull_offset # 3.1 Pull chunk with Halo data = ::R.bridge.pull_double_vector(@r_interop, len, pull_offset, actual_pull_size) # 3.2 Process in Ruby # The block receives the data with halo. # It's up to the block to handle the context, # but the result should be the same size as data. result_data_with_halo = block.call(data) # 3.3 Extract the "inner" part (discard halo results) # The offset of our chunk within the pulled data is (offset - pull_offset) inner_start = offset - pull_offset inner_result = result_data_with_halo[inner_start, current_chunk_size] # 3.4 Push only the inner chunk back to R ::R.bridge.push_double_vector(inner_result, res_name, offset, len) offset += current_chunk_size end # 4. Return as R::Object (wrapped as Vector) ::R::Object.build(res_name) end |
#to_ary ⇒ Object
Return Ruby array so RSpec/eq and array conversion don't forward to_ary to R. Must always return an Array (length-1 vector unboxes to scalar via >> nil, so wrap in [v]).
101 102 103 104 |
# File 'lib/R_interface/rvector.rb', line 101 def to_ary v = self >> nil v.is_a?(::Array) ? v : [v] end |
#unboxed_get(index = nil, depth = 0) ⇒ Object Also known as: >>, <<
Unbox vector to Ruby. Atomic vectors: length 1 → scalar, length > 1 → Array of scalars. Recursion depth is checked; vectors do not recurse into R::Object (elements are scalars).
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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/R_interface/rvector.rb', line 51 def unboxed_get(index = nil, depth = 0) if depth >= ::R::Support::MAX_UNBOX_DEPTH ::Kernel.raise(::R::UnboxDepthError, "unbox: list too deep (max depth #{::R::Support::MAX_UNBOX_DEPTH} exceeded)") end if index.nil? arr = ::R.bridge.pull_vector(@r_interop) return (arr.length == 1 ? arr[0] : arr) end # For indexed unboxing, use binary transport + result protocol (no printed-text parsing). idx = index len = atomic_vector_length ::Kernel.raise(::IndexError.new("index #{idx} out of array bounds: 0...#{len - 1}")) if idx >= len type = atomic_vector_typeof case type when 'integer' data = ::R.bridge.pull_integer_vector(@r_interop, 1, idx, 1) data[0] when 'character' var_name = ::R::Support.generate_var_name assignment = "#{var_name} <- #{@r_interop}[[#{idx + 1}]]" envelope = ::R.bridge.eval_r_with_result(assignment) raise "Result protocol: no envelope for character element #{@r_interop}[[#{idx + 1}]]" unless envelope raise "Result protocol: expected scalar_character, got #{envelope[:type]}" unless envelope[:type] == :scalar_character v = envelope[:value] (v.is_a?(::String) && v =~ /^rb_obj_\d+$/) ? ::R::Support.get_ruby_object(v) : v when 'logical' var_name = ::R::Support.generate_var_name assignment = "#{var_name} <- #{@r_interop}[[#{idx + 1}]]" envelope = ::R.bridge.eval_r_with_result(assignment) raise "Result protocol: no envelope for logical element #{@r_interop}[[#{idx + 1}]]" unless envelope raise "Result protocol: expected scalar_logical, got #{envelope[:type]}" unless envelope[:type] == :scalar_logical case envelope[:value] when true then true when false then false else nil end else data = ::R.bridge.pull_double_vector(@r_interop, 1, idx, 1) data[0] end end |