Skip to content

Commit 974ce86

Browse files
committed
creation and elementwise operation and basic setup
1 parent 007a627 commit 974ce86

20 files changed

+436
-0
lines changed

Gemfile

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
source 'https://rubygems.org'
2+
gemspec

Rakefile

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
2+
require "bundler/gem_tasks"
3+
require 'rake'
4+
require 'rake/extensiontask'
5+
require "rake/testtask"
6+
require "rdoc/task"
7+
8+
Rake::ExtensionTask.new do |ext|
9+
ext.name = 'nmatrix'
10+
ext.ext_dir = 'ext/'
11+
ext.lib_dir = 'lib/'
12+
ext.source_pattern = '**/*.{c,cpp, h}'
13+
end
14+
15+
task :console do
16+
cmd = ['irb', "-r './lib/nmatrix.rb'"]
17+
run(*cmd)
18+
end
19+
20+
task :pry do
21+
cmd = ['pry', "-r './lib/nmatrix.rb'"]
22+
run(*cmd)
23+
end
24+
25+
def run(*cmd)
26+
sh(cmd.join(' '))
27+
end
28+
29+
RDoc::Task.new do |rdoc|
30+
rdoc.main = "README.md"
31+
rdoc.rdoc_files.include(%w{README.md LICENSE CONTRIBUTING.md lib ext})
32+
end
33+
34+
Rake::TestTask.new(:test) do |t|
35+
t.libs << "test"
36+
t.libs << "lib"
37+
t.test_files = FileList['test/**/*_test.rb']
38+
end
39+
40+
task :default => :test

ext/blas.c

Whitespace-only changes.

ext/extconf.rb

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
require_relative 'mkmf.rb'
2+
3+
extension_name = 'nmatrix'
4+
5+
nmatrix_path = Gem::Specification.find_all_by_name('nmatrix').compact
6+
abort "Cannot locate NMatrix installation" unless nmatrix_path
7+
nmatrix_header_dir = File.join(nmatrix_path[0].require_path)
8+
9+
$INSTALLFILES = [
10+
['ruby_nmatrix.h' , '$(archdir)'],
11+
# ['ruby_nmatrix.hpp' , '$(archdir)'],
12+
['nmatrix_config.h', '$(archdir)'],
13+
]
14+
15+
$DEBUG = true
16+
$CFLAGS = ["-Wall -Werror=return-type",$CFLAGS].join(" ")
17+
$CXXFLAGS = ["-Wall -Werror=return-type",$CXXFLAGS].join(" ")
18+
$CPPFLAGS = ["-Wall -Werror=return-type",$CPPFLAGS].join(" ")
19+
20+
21+
LIBDIR = RbConfig::CONFIG['libdir']
22+
INCLUDEDIR = RbConfig::CONFIG['includedir']
23+
24+
HEADER_DIRS = [
25+
'/opt/local/include',
26+
'/usr/local/include',
27+
INCLUDEDIR,
28+
'/usr/include',
29+
nmatrix_header_dir
30+
]
31+
32+
LIB_DIRS = [
33+
'/opt/local/lib',
34+
'/usr/local/lib',
35+
LIBDIR,
36+
'/usr/lib',
37+
nmatrix_header_dir
38+
]
39+
40+
dir_config(extension_name, HEADER_DIRS, LIB_DIRS)
41+
42+
# have_library('af')
43+
44+
basenames = %w{ruby_nmatrix}
45+
$objs = basenames.map { |b| "#{b}.o" }
46+
$srcs = basenames.map { |b| "#{b}.cpp" }
47+
48+
create_conf_h("nmatrix_config.h")
49+
create_makefile(extension_name)

ext/lapack.c

Whitespace-only changes.

ext/mkmf.rb

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
require "mkmf"
2+
3+
if RUBY_VERSION < '1.9'
4+
raise NotImplementedError, "Sorry, you need at least Ruby 1.9!"
5+
end
6+
7+
# Function derived from NArray's extconf.rb.
8+
def create_conf_h(file) #:nodoc:
9+
print "creating #{file}\n"
10+
File.open(file, 'w') do |hfile|
11+
header_guard = file.upcase.sub(/\s|\./, '_')
12+
13+
hfile.puts "#ifndef #{header_guard}"
14+
hfile.puts "#define #{header_guard}"
15+
hfile.puts
16+
17+
# FIXME: Find a better way to do this:
18+
hfile.puts "#define RUBY_2 1" if RUBY_VERSION >= '2.0'
19+
20+
for line in $defs
21+
line =~ /^-D(.*)/
22+
hfile.printf "#define %s 1\n", $1
23+
end
24+
25+
hfile.puts
26+
hfile.puts "#endif"
27+
end
28+
end
29+
30+
def find_newer_gplusplus #:nodoc:
31+
print "checking for apparent GNU g++ binary with C++0x/C++11 support... "
32+
[9,8,7,6,5,4,3].each do |minor|
33+
ver = "4.#{minor}"
34+
gpp = "g++-#{ver}"
35+
result = `which #{gpp}`
36+
next if result.empty?
37+
CONFIG['CXX'] = gpp
38+
puts ver
39+
return CONFIG['CXX']
40+
end
41+
false
42+
end
43+
44+
def gplusplus_version
45+
cxxvar = proc { |n| `#{CONFIG['CXX']} -E -dM - <#{File::NULL} | grep #{n}`.chomp.split(' ')[2] }
46+
major = cxxvar.call('__GNUC__')
47+
minor = cxxvar.call('__GNUC_MINOR__')
48+
patch = cxxvar.call('__GNUC_PATCHLEVEL__')
49+
50+
raise("unable to determine g++ version (match to get version was nil)") if major.nil? || minor.nil? || patch.nil?
51+
52+
"#{major}.#{minor}.#{patch}"
53+
end
54+
55+
56+
if /cygwin|mingw/ =~ RUBY_PLATFORM
57+
CONFIG["DLDFLAGS"] << " --output-lib libnmatrix.a"
58+
end
59+
60+
# Fix compiler pairing
61+
if CONFIG['CC'] == 'clang' && CONFIG['CXX'] != 'clang++'
62+
puts "WARNING: CONFIG['CXX'] is not 'clang++' even though CONFIG['CC'] is 'clang'.",
63+
"WARNING: Force to use clang++ together with clang."
64+
65+
CONFIG['CXX'] = 'clang++'
66+
end
67+
68+
if CONFIG['CXX'] == 'clang++'
69+
$CXX_STANDARD = 'c++11'
70+
else
71+
version = gplusplus_version
72+
if version < '4.3.0' && CONFIG['CXX'] == 'g++' # see if we can find a newer G++, unless it's been overridden by user
73+
if !find_newer_gplusplus
74+
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++.")
75+
end
76+
version = gplusplus_version
77+
end
78+
79+
if version < '4.7.0'
80+
$CXX_STANDARD = 'c++0x'
81+
else
82+
$CXX_STANDARD = 'c++11'
83+
end
84+
puts "using C++ standard... #{$CXX_STANDARD}"
85+
puts "g++ reports version... " + `#{CONFIG['CXX']} --version|head -n 1|cut -f 3 -d " "`
86+
end
87+
88+
# For release, these next two should both be changed to -O3.
89+
$CFLAGS += " -O3 "
90+
#$CFLAGS += " -static -O0 -g "
91+
$CXXFLAGS += " -O3 -std=#{$CXX_STANDARD} " #-fmax-errors=10 -save-temps
92+
#$CXXFLAGS += " -static -O0 -g -std=#{$CXX_STANDARD} "
93+
94+
CONFIG['warnflags'].gsub!('-Wshorten-64-to-32', '') # doesn't work except in Mac-patched gcc (4.2)
95+
CONFIG['warnflags'].gsub!('-Wdeclaration-after-statement', '')
96+
CONFIG['warnflags'].gsub!('-Wimplicit-function-declaration', '')
97+
98+
have_func("rb_array_const_ptr", "ruby.h")
99+
have_macro("FIX_CONST_VALUE_PTR", "ruby.h")
100+
have_macro("RARRAY_CONST_PTR", "ruby.h")
101+
have_macro("RARRAY_AREF", "ruby.h")

ext/ruby_nmatrix.c

+152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#include "ruby.h"
2+
#include "stdio.h"
3+
4+
typedef struct NMATRIX_STRUCT
5+
{
6+
size_t ndims;
7+
size_t count;
8+
size_t* shape;
9+
double* elements;
10+
}nmatrix;
11+
12+
VALUE NMatrix = Qnil;
13+
14+
void Init_nmatrix();
15+
VALUE nmatrix_init(int argc, VALUE* argv, VALUE self);
16+
VALUE nm_get_elements(VALUE self);
17+
VALUE nm_get_shape(VALUE self);
18+
VALUE nm_alloc(VALUE klass);
19+
void nm_free(nmatrix* mat);
20+
21+
VALUE nm_add(VALUE self, VALUE another);
22+
23+
#define DECL_ELEMENTWISE_RUBY_ACCESSOR(name) VALUE nm_##name(VALUE self, VALUE another);
24+
25+
DECL_ELEMENTWISE_RUBY_ACCESSOR(subtract)
26+
DECL_ELEMENTWISE_RUBY_ACCESSOR(multiply)
27+
DECL_ELEMENTWISE_RUBY_ACCESSOR(divide)
28+
29+
30+
void Init_nmatrix() {
31+
NMatrix = rb_define_class("NMatrix", rb_cObject);
32+
33+
rb_define_alloc_func(NMatrix, nm_alloc);
34+
rb_define_method(NMatrix, "initialize", nmatrix_init, -1);
35+
rb_define_method(NMatrix, "shape", nm_get_shape, 0);
36+
rb_define_method(NMatrix, "elements", nm_get_elements, 0);
37+
38+
rb_define_method(NMatrix, "+", nm_add, 1);
39+
rb_define_method(NMatrix, "-", nm_subtract, 1);
40+
rb_define_method(NMatrix, "*", nm_multiply,1);
41+
rb_define_method(NMatrix, "/", nm_divide,1);
42+
}
43+
44+
45+
VALUE nmatrix_init(int argc, VALUE* argv, VALUE self){
46+
nmatrix* mat;
47+
Data_Get_Struct(self, nmatrix, mat);
48+
49+
if(argc > 0){
50+
mat->ndims = 2;
51+
mat->count = 1;
52+
mat->shape = ALLOC_N(size_t, mat->ndims);
53+
for (size_t index = 0; index < mat->ndims; index++) {
54+
mat->shape[index] = (size_t)FIX2LONG(RARRAY_AREF(argv[0], index));
55+
mat->count *= mat->shape[index];
56+
}
57+
mat->elements = ALLOC_N(double, mat->count);
58+
for (size_t index = 0; index < mat->count; index++) {
59+
mat->elements[index] = (double)NUM2DBL(RARRAY_AREF(argv[1], index));
60+
}
61+
}
62+
63+
return self;
64+
}
65+
66+
VALUE nm_alloc(VALUE klass)
67+
{
68+
nmatrix* mat = ALLOC(nmatrix);
69+
70+
return Data_Wrap_Struct(klass, NULL, nm_free, mat);
71+
}
72+
73+
void nm_free(nmatrix* mat){
74+
xfree(mat);
75+
}
76+
77+
VALUE nm_get_elements(VALUE self){
78+
nmatrix* input;
79+
80+
Data_Get_Struct(self, nmatrix, input);
81+
82+
VALUE* array = ALLOC_N(VALUE, input->count);
83+
for (size_t index = 0; index < input->count; index++){
84+
array[index] = DBL2NUM(input->elements[index]);
85+
}
86+
87+
return rb_ary_new4(input->count, array);
88+
}
89+
90+
VALUE nm_get_shape(VALUE self){
91+
nmatrix* input;
92+
93+
Data_Get_Struct(self, nmatrix, input);
94+
95+
VALUE* array = ALLOC_N(VALUE, input->ndims);
96+
for (size_t index = 0; index < input->ndims; index++){
97+
array[index] = LONG2NUM(input->shape[index]);
98+
}
99+
100+
return rb_ary_new4(input->ndims, array);
101+
}
102+
103+
VALUE nm_add(VALUE self, VALUE another){
104+
nmatrix* left;
105+
nmatrix* right;
106+
Data_Get_Struct(self, nmatrix, left);
107+
Data_Get_Struct(another, nmatrix, right);
108+
109+
nmatrix* result = ALLOC(nmatrix);
110+
result->count = left->count;
111+
result->ndims = left->ndims;
112+
result->shape = ALLOC_N(size_t, result->ndims);
113+
114+
for(size_t index = 0; index < result->ndims; index++){
115+
result->shape[index] = left->shape[index];
116+
}
117+
118+
result->elements = ALLOC_N(double, result->count);
119+
for(size_t index = 0; index < left->count; index++){
120+
result->elements[index] = left->elements[index] + right->elements[index];
121+
}
122+
123+
return Data_Wrap_Struct(NMatrix, NULL, nm_free, result);
124+
}
125+
126+
#define DEF_ELEMENTWISE_RUBY_ACCESSOR(name, oper) \
127+
VALUE nm_##name(VALUE self, VALUE another){ \
128+
nmatrix* left; \
129+
nmatrix* right; \
130+
Data_Get_Struct(self, nmatrix, left); \
131+
Data_Get_Struct(another, nmatrix, right); \
132+
\
133+
nmatrix* result = ALLOC(nmatrix); \
134+
result->count = left->count; \
135+
result->ndims = left->ndims; \
136+
result->shape = ALLOC_N(size_t, result->ndims); \
137+
\
138+
for(size_t index = 0; index < result->ndims; index++){ \
139+
result->shape[index] = left->shape[index]; \
140+
} \
141+
\
142+
result->elements = ALLOC_N(double, result->count); \
143+
for(size_t index = 0; index < left->count; index++){ \
144+
result->elements[index] = (left->elements[index]) oper (right->elements[index]); \
145+
} \
146+
\
147+
return Data_Wrap_Struct(NMatrix, NULL, nm_free, result); \
148+
}
149+
150+
DEF_ELEMENTWISE_RUBY_ACCESSOR(subtract, -)
151+
DEF_ELEMENTWISE_RUBY_ACCESSOR(multiply, *)
152+
DEF_ELEMENTWISE_RUBY_ACCESSOR(divide, /)

ext/ruby_nmatrix.h

Whitespace-only changes.

lib/nmatrix.rb

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
require 'nmatrix/nmatrix.rb'
2+
require 'nmatrix.so'

lib/nmatrix/blas.rb

Whitespace-only changes.

lib/nmatrix/elementwise.rb

Whitespace-only changes.

lib/nmatrix/lapack.rb

Whitespace-only changes.

lib/nmatrix/nmatrix.rb

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class NMatrix
2+
3+
# attr_reader :shape, :elements
4+
5+
# def initialize shape, elements
6+
# @shape = shape
7+
# @elements = elements
8+
# end
9+
10+
end

lib/nmatrix/version.rb

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class NMatrix
2+
module VERSION #:nodoc:
3+
MAJOR = 0
4+
MINOR = 0
5+
TINY = 1
6+
STRING = [MAJOR, MINOR, TINY].compact.join(".")
7+
end
8+
end

0 commit comments

Comments
 (0)