Skip to content

Commit

Permalink
creation and elementwise operation and basic setup
Browse files Browse the repository at this point in the history
  • Loading branch information
prasunanand committed Oct 31, 2018
1 parent 007a627 commit 974ce86
Show file tree
Hide file tree
Showing 20 changed files with 436 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Gemfile
@@ -0,0 +1,2 @@
source 'https://rubygems.org'
gemspec
40 changes: 40 additions & 0 deletions Rakefile
@@ -0,0 +1,40 @@

require "bundler/gem_tasks"
require 'rake'
require 'rake/extensiontask'
require "rake/testtask"
require "rdoc/task"

Rake::ExtensionTask.new do |ext|
ext.name = 'nmatrix'
ext.ext_dir = 'ext/'
ext.lib_dir = 'lib/'
ext.source_pattern = '**/*.{c,cpp, h}'
end

task :console do
cmd = ['irb', "-r './lib/nmatrix.rb'"]
run(*cmd)
end

task :pry do
cmd = ['pry', "-r './lib/nmatrix.rb'"]
run(*cmd)
end

def run(*cmd)
sh(cmd.join(' '))
end

RDoc::Task.new do |rdoc|
rdoc.main = "README.md"
rdoc.rdoc_files.include(%w{README.md LICENSE CONTRIBUTING.md lib ext})
end

Rake::TestTask.new(:test) do |t|
t.libs << "test"
t.libs << "lib"
t.test_files = FileList['test/**/*_test.rb']
end

task :default => :test
Empty file added ext/blas.c
Empty file.
49 changes: 49 additions & 0 deletions ext/extconf.rb
@@ -0,0 +1,49 @@
require_relative 'mkmf.rb'

extension_name = 'nmatrix'

nmatrix_path = Gem::Specification.find_all_by_name('nmatrix').compact
abort "Cannot locate NMatrix installation" unless nmatrix_path
nmatrix_header_dir = File.join(nmatrix_path[0].require_path)

$INSTALLFILES = [
['ruby_nmatrix.h' , '$(archdir)'],
# ['ruby_nmatrix.hpp' , '$(archdir)'],
['nmatrix_config.h', '$(archdir)'],
]

$DEBUG = true
$CFLAGS = ["-Wall -Werror=return-type",$CFLAGS].join(" ")
$CXXFLAGS = ["-Wall -Werror=return-type",$CXXFLAGS].join(" ")
$CPPFLAGS = ["-Wall -Werror=return-type",$CPPFLAGS].join(" ")


LIBDIR = RbConfig::CONFIG['libdir']
INCLUDEDIR = RbConfig::CONFIG['includedir']

HEADER_DIRS = [
'/opt/local/include',
'/usr/local/include',
INCLUDEDIR,
'/usr/include',
nmatrix_header_dir
]

LIB_DIRS = [
'/opt/local/lib',
'/usr/local/lib',
LIBDIR,
'/usr/lib',
nmatrix_header_dir
]

dir_config(extension_name, HEADER_DIRS, LIB_DIRS)

# have_library('af')

basenames = %w{ruby_nmatrix}
$objs = basenames.map { |b| "#{b}.o" }
$srcs = basenames.map { |b| "#{b}.cpp" }

create_conf_h("nmatrix_config.h")
create_makefile(extension_name)
Empty file added ext/lapack.c
Empty file.
101 changes: 101 additions & 0 deletions ext/mkmf.rb
@@ -0,0 +1,101 @@
require "mkmf"

if RUBY_VERSION < '1.9'
raise NotImplementedError, "Sorry, you need at least Ruby 1.9!"
end

# Function derived from NArray's extconf.rb.
def create_conf_h(file) #:nodoc:
print "creating #{file}\n"
File.open(file, 'w') do |hfile|
header_guard = file.upcase.sub(/\s|\./, '_')

hfile.puts "#ifndef #{header_guard}"
hfile.puts "#define #{header_guard}"
hfile.puts

# FIXME: Find a better way to do this:
hfile.puts "#define RUBY_2 1" if RUBY_VERSION >= '2.0'

for line in $defs
line =~ /^-D(.*)/
hfile.printf "#define %s 1\n", $1
end

hfile.puts
hfile.puts "#endif"
end
end

def find_newer_gplusplus #:nodoc:
print "checking for apparent GNU g++ binary with C++0x/C++11 support... "
[9,8,7,6,5,4,3].each do |minor|
ver = "4.#{minor}"
gpp = "g++-#{ver}"
result = `which #{gpp}`
next if result.empty?
CONFIG['CXX'] = gpp
puts ver
return CONFIG['CXX']
end
false
end

def gplusplus_version
cxxvar = proc { |n| `#{CONFIG['CXX']} -E -dM - <#{File::NULL} | grep #{n}`.chomp.split(' ')[2] }
major = cxxvar.call('__GNUC__')
minor = cxxvar.call('__GNUC_MINOR__')
patch = cxxvar.call('__GNUC_PATCHLEVEL__')

raise("unable to determine g++ version (match to get version was nil)") if major.nil? || minor.nil? || patch.nil?

"#{major}.#{minor}.#{patch}"
end


if /cygwin|mingw/ =~ RUBY_PLATFORM
CONFIG["DLDFLAGS"] << " --output-lib libnmatrix.a"
end

# Fix compiler pairing
if CONFIG['CC'] == 'clang' && CONFIG['CXX'] != 'clang++'
puts "WARNING: CONFIG['CXX'] is not 'clang++' even though CONFIG['CC'] is 'clang'.",
"WARNING: Force to use clang++ together with clang."

CONFIG['CXX'] = 'clang++'
end

if CONFIG['CXX'] == 'clang++'
$CXX_STANDARD = 'c++11'
else
version = gplusplus_version
if version < '4.3.0' && CONFIG['CXX'] == 'g++' # see if we can find a newer G++, unless it's been overridden by user
if !find_newer_gplusplus
raise("You need a version of g++ which supports -std=c++0x or -std=c++11. If you're on a Mac and using Homebrew, we recommend using mac-brew-gcc.sh to install a more recent g++.")
end
version = gplusplus_version
end

if version < '4.7.0'
$CXX_STANDARD = 'c++0x'
else
$CXX_STANDARD = 'c++11'
end
puts "using C++ standard... #{$CXX_STANDARD}"
puts "g++ reports version... " + `#{CONFIG['CXX']} --version|head -n 1|cut -f 3 -d " "`
end

# For release, these next two should both be changed to -O3.
$CFLAGS += " -O3 "
#$CFLAGS += " -static -O0 -g "
$CXXFLAGS += " -O3 -std=#{$CXX_STANDARD} " #-fmax-errors=10 -save-temps
#$CXXFLAGS += " -static -O0 -g -std=#{$CXX_STANDARD} "

CONFIG['warnflags'].gsub!('-Wshorten-64-to-32', '') # doesn't work except in Mac-patched gcc (4.2)
CONFIG['warnflags'].gsub!('-Wdeclaration-after-statement', '')
CONFIG['warnflags'].gsub!('-Wimplicit-function-declaration', '')

have_func("rb_array_const_ptr", "ruby.h")
have_macro("FIX_CONST_VALUE_PTR", "ruby.h")
have_macro("RARRAY_CONST_PTR", "ruby.h")
have_macro("RARRAY_AREF", "ruby.h")
152 changes: 152 additions & 0 deletions ext/ruby_nmatrix.c
@@ -0,0 +1,152 @@
#include "ruby.h"
#include "stdio.h"

typedef struct NMATRIX_STRUCT
{
size_t ndims;
size_t count;
size_t* shape;
double* elements;
}nmatrix;

VALUE NMatrix = Qnil;

void Init_nmatrix();
VALUE nmatrix_init(int argc, VALUE* argv, VALUE self);
VALUE nm_get_elements(VALUE self);
VALUE nm_get_shape(VALUE self);
VALUE nm_alloc(VALUE klass);
void nm_free(nmatrix* mat);

VALUE nm_add(VALUE self, VALUE another);

#define DECL_ELEMENTWISE_RUBY_ACCESSOR(name) VALUE nm_##name(VALUE self, VALUE another);

DECL_ELEMENTWISE_RUBY_ACCESSOR(subtract)
DECL_ELEMENTWISE_RUBY_ACCESSOR(multiply)
DECL_ELEMENTWISE_RUBY_ACCESSOR(divide)


void Init_nmatrix() {
NMatrix = rb_define_class("NMatrix", rb_cObject);

rb_define_alloc_func(NMatrix, nm_alloc);
rb_define_method(NMatrix, "initialize", nmatrix_init, -1);
rb_define_method(NMatrix, "shape", nm_get_shape, 0);
rb_define_method(NMatrix, "elements", nm_get_elements, 0);

rb_define_method(NMatrix, "+", nm_add, 1);
rb_define_method(NMatrix, "-", nm_subtract, 1);
rb_define_method(NMatrix, "*", nm_multiply,1);
rb_define_method(NMatrix, "/", nm_divide,1);
}


VALUE nmatrix_init(int argc, VALUE* argv, VALUE self){
nmatrix* mat;
Data_Get_Struct(self, nmatrix, mat);

if(argc > 0){
mat->ndims = 2;
mat->count = 1;
mat->shape = ALLOC_N(size_t, mat->ndims);
for (size_t index = 0; index < mat->ndims; index++) {
mat->shape[index] = (size_t)FIX2LONG(RARRAY_AREF(argv[0], index));
mat->count *= mat->shape[index];
}
mat->elements = ALLOC_N(double, mat->count);
for (size_t index = 0; index < mat->count; index++) {
mat->elements[index] = (double)NUM2DBL(RARRAY_AREF(argv[1], index));
}
}

return self;
}

VALUE nm_alloc(VALUE klass)
{
nmatrix* mat = ALLOC(nmatrix);

return Data_Wrap_Struct(klass, NULL, nm_free, mat);
}

void nm_free(nmatrix* mat){
xfree(mat);
}

VALUE nm_get_elements(VALUE self){
nmatrix* input;

Data_Get_Struct(self, nmatrix, input);

VALUE* array = ALLOC_N(VALUE, input->count);
for (size_t index = 0; index < input->count; index++){
array[index] = DBL2NUM(input->elements[index]);
}

return rb_ary_new4(input->count, array);
}

VALUE nm_get_shape(VALUE self){
nmatrix* input;

Data_Get_Struct(self, nmatrix, input);

VALUE* array = ALLOC_N(VALUE, input->ndims);
for (size_t index = 0; index < input->ndims; index++){
array[index] = LONG2NUM(input->shape[index]);
}

return rb_ary_new4(input->ndims, array);
}

VALUE nm_add(VALUE self, VALUE another){
nmatrix* left;
nmatrix* right;
Data_Get_Struct(self, nmatrix, left);
Data_Get_Struct(another, nmatrix, right);

nmatrix* result = ALLOC(nmatrix);
result->count = left->count;
result->ndims = left->ndims;
result->shape = ALLOC_N(size_t, result->ndims);

for(size_t index = 0; index < result->ndims; index++){
result->shape[index] = left->shape[index];
}

result->elements = ALLOC_N(double, result->count);
for(size_t index = 0; index < left->count; index++){
result->elements[index] = left->elements[index] + right->elements[index];
}

return Data_Wrap_Struct(NMatrix, NULL, nm_free, result);
}

#define DEF_ELEMENTWISE_RUBY_ACCESSOR(name, oper) \
VALUE nm_##name(VALUE self, VALUE another){ \
nmatrix* left; \
nmatrix* right; \
Data_Get_Struct(self, nmatrix, left); \
Data_Get_Struct(another, nmatrix, right); \
\
nmatrix* result = ALLOC(nmatrix); \
result->count = left->count; \
result->ndims = left->ndims; \
result->shape = ALLOC_N(size_t, result->ndims); \
\
for(size_t index = 0; index < result->ndims; index++){ \
result->shape[index] = left->shape[index]; \
} \
\
result->elements = ALLOC_N(double, result->count); \
for(size_t index = 0; index < left->count; index++){ \
result->elements[index] = (left->elements[index]) oper (right->elements[index]); \
} \
\
return Data_Wrap_Struct(NMatrix, NULL, nm_free, result); \
}

DEF_ELEMENTWISE_RUBY_ACCESSOR(subtract, -)
DEF_ELEMENTWISE_RUBY_ACCESSOR(multiply, *)
DEF_ELEMENTWISE_RUBY_ACCESSOR(divide, /)
Empty file added ext/ruby_nmatrix.h
Empty file.
2 changes: 2 additions & 0 deletions lib/nmatrix.rb
@@ -0,0 +1,2 @@
require 'nmatrix/nmatrix.rb'
require 'nmatrix.so'
Empty file added lib/nmatrix/blas.rb
Empty file.
Empty file added lib/nmatrix/elementwise.rb
Empty file.
Empty file added lib/nmatrix/lapack.rb
Empty file.
10 changes: 10 additions & 0 deletions lib/nmatrix/nmatrix.rb
@@ -0,0 +1,10 @@
class NMatrix

# attr_reader :shape, :elements

# def initialize shape, elements
# @shape = shape
# @elements = elements
# end

end
8 changes: 8 additions & 0 deletions lib/nmatrix/version.rb
@@ -0,0 +1,8 @@
class NMatrix
module VERSION #:nodoc:
MAJOR = 0
MINOR = 0
TINY = 1
STRING = [MAJOR, MINOR, TINY].compact.join(".")
end
end

0 comments on commit 974ce86

Please sign in to comment.