Skip to content

Commit

Permalink
only double dtypes for now
Browse files Browse the repository at this point in the history
  • Loading branch information
christopherzimmerman committed Oct 14, 2019
1 parent 91e0f74 commit 3b349ea
Show file tree
Hide file tree
Showing 7 changed files with 239 additions and 387 deletions.
189 changes: 90 additions & 99 deletions src/core/vector/index.cr
Original file line number Diff line number Diff line change
@@ -1,118 +1,109 @@
require "../../libs/gsl"
require "../../vector/*"

# Creates indexing methods for each support data type of gsl.
# Since all the calls are virtually identical, and since
# only the pointers are passed around, this is an easy way
# to avoid duplicate code for no reason.
macro vector_indexing_abstract(type_, dtype, prefix)
module Bottle::Core::VectorIndex
include Bottle::Core::Exceptions
extend self
module Bottle::Core::VectorIndex
include Bottle::Core::Exceptions
extend self

# Gets a single element from a vector at a given index, the core
# indexing operation of a vector
#
# ```
# vec = Vector.new [1, 2, 3, 4, 5]
# vec[0] # => 1
# ```
def get_vector_element_at_index(vector : Pointer({{ type_ }}), index : Int32)
LibGsl.{{ prefix }}_get(vector, index)
end
# Gets a single element from a vector at a given index, the core
# indexing operation of a vector
#
# ```
# vec = Vector.new [1, 2, 3, 4, 5]
# vec[0] # => 1
# ```
def get_vector_element_at_index(vector : Pointer(LibGsl::GslVector), index : Int32)
LibGsl.gsl_vector_get(vector, index)
end

# Sets a single element from a vector at a given index
#
# ```
# vec = Vector.new [1, 2, 3]
# vec[0] = 10
# vec # => [10, 2, 3]
# ```
def set_vector_element_at_index(vector : Pointer({{ type_ }}), index : Int32, value : Number)
LibGsl.{{ prefix }}_set(vector, index, value)
end
# Sets a single element from a vector at a given index
#
# ```
# vec = Vector.new [1, 2, 3]
# vec[0] = 10
# vec # => [10, 2, 3]
# ```
def set_vector_element_at_index(vector : Pointer(LibGsl::GslVector), index : Int32, value : Number)
LibGsl.gsl_vector_set(vector, index, value)
end

# Gets multiple elements from a vector at given indexes. This returns
# a `copy` since there is no way to create a contiguous slice of memory
#
# ```
# vec = Vector.new [1, 2, 3]
# vec[[1, 2]] # => [2, 3]
# ```
def get_vector_elements_at_indexes(vector : Pointer({{ type_ }}), indexes : Array(Int32))
sz = indexes.size
ptv = LibGsl.{{ prefix }}_alloc(sz)
indexes.each_with_index do |el, index|
val = get_vector_element_at_index(vector, el)
set_vector_element_at_index(ptv, index, val)
end
return Vector.new ptv, ptv.value.data
# Gets multiple elements from a vector at given indexes. This returns
# a `copy` since there is no way to create a contiguous slice of memory
#
# ```
# vec = Vector.new [1, 2, 3]
# vec[[1, 2]] # => [2, 3]
# ```
def get_vector_elements_at_indexes(vector : Pointer(LibGsl::GslVector), indexes : Array(Int32))
sz = indexes.size
ptv = LibGsl.gsl_vector_alloc(sz)
indexes.each_with_index do |el, index|
val = get_vector_element_at_index(vector, el)
set_vector_element_at_index(ptv, index, val)
end
return Vector.new ptv, ptv.value.data
end

# Sets multiple elements of a vector by the given indexes.
#
# ```
# vec = Vector.new [1, 2, 3]
# vec[[0, 1]] = [10, 9]
# vec # => [10, 9, 3]
# ```
def set_vector_element_at_indexes(vector : Pointer({{ type_ }}), indexes : Array(Int32), values : Array(Number))
indexes.each_with_index do |idx, index|
LibGsl.{{ prefix }}_set(vector, idx, values[index])
end
# Sets multiple elements of a vector by the given indexes.
#
# ```
# vec = Vector.new [1, 2, 3]
# vec[[0, 1]] = [10, 9]
# vec # => [10, 9, 3]
# ```
def set_vector_element_at_indexes(vector : Pointer(LibGsl::GslVector), indexes : Array(Int32), values : Array(Number))
indexes.each_with_index do |idx, index|
LibGsl.gsl_vector_set(vector, idx, values[index])
end
end

# Normalizes a slice range to allow indexing to work with gsl. This means
# bounding nil ranges and disallowing inclusive ranges
def convert_range_to_slice(range : Range(Int32| Nil, Int32 | Nil), size : UInt64)
if !range.excludes_end?
raise RangeError.new("Vectors do not support indexing with inclusive ranges. Always use '...'")
end

i = range.begin
j = range.end
# Normalizes a slice range to allow indexing to work with gsl. This means
# bounding nil ranges and disallowing inclusive ranges
def convert_range_to_slice(range : Range(Int32| Nil, Int32 | Nil), size : UInt64)
if !range.excludes_end?
raise RangeError.new("Vectors do not support indexing with inclusive ranges. Always use '...'")
end

start = (i.nil? ? 0 : i).as(UInt64 | Int32).to_u64
finish = (j.nil? ? size : j).as(UInt64 | Int32).to_u64
i = range.begin
j = range.end

return start...finish
end
start = (i.nil? ? 0 : i).as(UInt64 | Int32).to_u64
finish = (j.nil? ? size : j).as(UInt64 | Int32).to_u64

# Returns a view of a vector defined by a given range. Currently only
# supports single strided ranges due to limitations of Crystal
#
# ```
# vec = Vector.new [1, 2, 3, 4, 5]
# vec[2...4] # => [3, 4]
# ```
def get_vector_elements_at_range(vector : Pointer({{ type_ }}), range, size)
newr = convert_range_to_slice(range, size)
vv = LibGsl.{{ prefix }}_subvector(vector, newr.begin, newr.end - newr.begin)
return Vector.new vv.vector, vv.vector.data
end
return start...finish
end

# Sets elements of a vector to given values based on the given range
#
# ```
# vec = Vector.new [1, 2, 3, 4, 5]
# vec[1...] = [10, 9, 8, 7]
# vec # => [1, 10, 9, 8, 7]
# ```
def set_vector_elements_at_range(vector : Pointer({{ type_ }}), range, size, values)
newr = convert_range_to_slice(range, size)
newr.each_with_index do |el, index|
LibGsl.{{ prefix }}_set(vector, el, values[index])
end
end
# Returns a view of a vector defined by a given range. Currently only
# supports single strided ranges due to limitations of Crystal
#
# ```
# vec = Vector.new [1, 2, 3, 4, 5]
# vec[2...4] # => [3, 4]
# ```
def get_vector_elements_at_range(vector : Pointer(LibGsl::GslVector), range, size)
newr = convert_range_to_slice(range, size)
vv = LibGsl.gsl_vector_subvector(vector, newr.begin, newr.end - newr.begin)
return Vector.new vv.vector, vv.vector.data
end

def copy_vector(vector : Vector({{ type_ }}, {{ dtype }}))
ptv = LibGsl.{{ prefix }}_alloc(vector.size)
LibGsl.{{ prefix }}_memcpy(ptv, vector.ptr)
return Vector.new ptv, ptv.value.data
# Sets elements of a vector to given values based on the given range
#
# ```
# vec = Vector.new [1, 2, 3, 4, 5]
# vec[1...] = [10, 9, 8, 7]
# vec # => [1, 10, 9, 8, 7]
# ```
def set_vector_elements_at_range(vector : Pointer(LibGsl::GslVector), range, size, values)
newr = convert_range_to_slice(range, size)
newr.each_with_index do |el, index|
LibGsl.gsl_vector_set(vector, el, values[index])
end
end

def copy_vector(vector : Vector(LibGsl::GslVector, Float64))
ptv = LibGsl.gsl_vector_alloc(vector.size)
LibGsl.gsl_vector_memcpy(ptv, vector.ptr)
return Vector.new ptv, ptv.value.data
end
end

vector_indexing_abstract LibGsl::GslVector, Float64, gsl_vector
vector_indexing_abstract LibGsl::GslVectorInt, Int32, gsl_vector_int
end
Loading

0 comments on commit 3b349ea

Please sign in to comment.