nmatrix 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.gitignore +3 -0
  2. data/CONTRIBUTING.md +66 -0
  3. data/Gemfile +1 -1
  4. data/History.txt +68 -10
  5. data/LICENSE.txt +2 -2
  6. data/Manifest.txt +2 -0
  7. data/README.rdoc +90 -69
  8. data/Rakefile +18 -9
  9. data/ext/nmatrix/data/complex.h +7 -7
  10. data/ext/nmatrix/data/data.cpp +2 -7
  11. data/ext/nmatrix/data/data.h +7 -4
  12. data/ext/nmatrix/data/rational.h +2 -2
  13. data/ext/nmatrix/data/ruby_object.h +3 -10
  14. data/ext/nmatrix/extconf.rb +79 -54
  15. data/ext/nmatrix/new_extconf.rb +11 -12
  16. data/ext/nmatrix/nmatrix.cpp +94 -125
  17. data/ext/nmatrix/nmatrix.h +38 -17
  18. data/ext/nmatrix/ruby_constants.cpp +2 -15
  19. data/ext/nmatrix/ruby_constants.h +2 -14
  20. data/ext/nmatrix/storage/common.cpp +2 -2
  21. data/ext/nmatrix/storage/common.h +2 -2
  22. data/ext/nmatrix/storage/dense.cpp +206 -31
  23. data/ext/nmatrix/storage/dense.h +5 -2
  24. data/ext/nmatrix/storage/list.cpp +52 -4
  25. data/ext/nmatrix/storage/list.h +3 -2
  26. data/ext/nmatrix/storage/storage.cpp +6 -6
  27. data/ext/nmatrix/storage/storage.h +2 -2
  28. data/ext/nmatrix/storage/yale.cpp +202 -49
  29. data/ext/nmatrix/storage/yale.h +5 -4
  30. data/ext/nmatrix/ttable_helper.rb +108 -108
  31. data/ext/nmatrix/types.h +2 -15
  32. data/ext/nmatrix/util/io.cpp +2 -2
  33. data/ext/nmatrix/util/io.h +2 -2
  34. data/ext/nmatrix/util/lapack.h +2 -2
  35. data/ext/nmatrix/util/math.cpp +14 -14
  36. data/ext/nmatrix/util/math.h +2 -2
  37. data/ext/nmatrix/util/sl_list.cpp +2 -2
  38. data/ext/nmatrix/util/sl_list.h +2 -2
  39. data/ext/nmatrix/util/util.h +2 -2
  40. data/lib/nmatrix.rb +13 -35
  41. data/lib/nmatrix/blas.rb +182 -56
  42. data/lib/nmatrix/io/market.rb +38 -14
  43. data/lib/nmatrix/io/mat5_reader.rb +393 -278
  44. data/lib/nmatrix/io/mat_reader.rb +121 -107
  45. data/lib/nmatrix/lapack.rb +59 -14
  46. data/lib/nmatrix/monkeys.rb +32 -30
  47. data/lib/nmatrix/nmatrix.rb +204 -100
  48. data/lib/nmatrix/nvector.rb +166 -57
  49. data/lib/nmatrix/shortcuts.rb +364 -231
  50. data/lib/nmatrix/version.rb +8 -4
  51. data/nmatrix.gemspec +5 -3
  52. data/scripts/mac-brew-gcc.sh +1 -1
  53. data/spec/blas_spec.rb +80 -2
  54. data/spec/math_spec.rb +78 -32
  55. data/spec/nmatrix_list_spec.rb +55 -55
  56. data/spec/nmatrix_spec.rb +60 -117
  57. data/spec/nmatrix_yale_resize_test_associations.yaml +2802 -0
  58. data/spec/nmatrix_yale_spec.rb +214 -198
  59. data/spec/nvector_spec.rb +58 -2
  60. data/spec/shortcuts_spec.rb +156 -32
  61. data/spec/slice_spec.rb +229 -178
  62. data/spec/spec_helper.rb +2 -2
  63. metadata +71 -21
@@ -9,8 +9,8 @@
9
9
  //
10
10
  // == Copyright Information
11
11
  //
12
- // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
13
- // NMatrix is Copyright (c) 2012, Ruby Science Foundation
12
+ // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2013, Ruby Science Foundation
14
14
  //
15
15
  // Please see LICENSE.txt for additional copyright notices.
16
16
  //
@@ -132,23 +132,23 @@ class Complex {
132
132
 
133
133
  template <typename OtherType>
134
134
  inline Complex<Type> operator*(const Complex<OtherType>& other) const {
135
- return Complex<Type>(this->r * other.r - this->i * other.i, this->r * other.i - this->i * other.r);
135
+ return Complex<Type>(this->r * other.r - this->i * other.i, this->r * other.i + this->i * other.r);
136
136
  }
137
137
 
138
138
  template <typename OtherType>
139
139
  inline Complex<Type>& operator*=(const Complex<OtherType>& other) {
140
140
  this->r = this->r * other.r - this->i * other.i;
141
- this->i = this->r * other.i - this->i * other.r;
141
+ this->i = this->r * other.i + this->i * other.r;
142
142
  return *this;
143
143
  }
144
144
 
145
145
  template <typename OtherType>
146
146
  inline Complex<Type> operator/(const Complex<OtherType>& other) const {
147
147
  Type new_r, new_i;
148
- Type denom = this->i * this->i + other.r * other.r;
148
+ Type denom = other.i * other.i + other.r * other.r;
149
149
 
150
150
  new_r = (this->r * other.r + this->i * other.i) / denom;
151
- new_i = (this->r * other.i - this->i * other.r) / denom;
151
+ new_i = (this->i * other.r - this->r * other.i) / denom;
152
152
 
153
153
  return Complex<Type>(new_r, new_i);
154
154
  }
@@ -199,7 +199,7 @@ class Complex {
199
199
 
200
200
  template <typename RationalType>
201
201
  inline Complex<Type> operator-(const Rational<RationalType>& other) const {
202
- return *this * Complex<Type>(other);
202
+ return *this - Complex<Type>(other);
203
203
  }
204
204
 
205
205
  template <typename RationalType>
@@ -9,8 +9,8 @@
9
9
  //
10
10
  // == Copyright Information
11
11
  //
12
- // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
13
- // NMatrix is Copyright (c) 2012, Ruby Science Foundation
12
+ // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2013, Ruby Science Foundation
14
14
  //
15
15
  // Please see LICENSE.txt for additional copyright notices.
16
16
  //
@@ -36,13 +36,8 @@
36
36
  */
37
37
 
38
38
  #include "types.h"
39
-
40
39
  #include "data.h"
41
40
 
42
- /*
43
- * Macros
44
- */
45
-
46
41
  /*
47
42
  * Global Variables
48
43
  */
@@ -9,8 +9,8 @@
9
9
  //
10
10
  // == Copyright Information
11
11
  //
12
- // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
13
- // NMatrix is Copyright (c) 2012, Ruby Science Foundation
12
+ // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2013, Ruby Science Foundation
14
14
  //
15
15
  // Please see LICENSE.txt for additional copyright notices.
16
16
  //
@@ -107,7 +107,8 @@ namespace nm {
107
107
  fun<nm::Complex128>, \
108
108
  fun<nm::Rational32>, \
109
109
  fun<nm::Rational64>, \
110
- fun<nm::Rational128> \
110
+ fun<nm::Rational128>, \
111
+ fun<nm::RubyObject> \
111
112
  };
112
113
 
113
114
  #define NAMED_DTYPE_TEMPLATE_TABLE_NO_ROBJ(name, fun, ret, ...) \
@@ -123,7 +124,7 @@ namespace nm {
123
124
  fun<nm::Complex128>, \
124
125
  fun<nm::Rational32>, \
125
126
  fun<nm::Rational64>, \
126
- fun<nm::Rational128>, \
127
+ fun<nm::Rational128> \
127
128
  };
128
129
 
129
130
  /*
@@ -615,6 +616,8 @@ namespace nm {
615
616
  {fun<nm::EW_GEQ, uint32_t, uint8_t>,fun<nm::EW_GEQ, uint32_t, int8_t>,fun<nm::EW_GEQ, uint32_t, int16_t>,fun<nm::EW_GEQ, uint32_t, int32_t>,fun<nm::EW_GEQ, uint32_t, int64_t>,fun<nm::EW_GEQ, uint32_t, float32_t>,fun<nm::EW_GEQ, uint32_t, float64_t>,fun<nm::EW_GEQ, uint32_t, nm::Complex64>,fun<nm::EW_GEQ, uint32_t, nm::Complex128>,fun<nm::EW_GEQ, uint32_t, nm::Rational32>,fun<nm::EW_GEQ, uint32_t, nm::Rational64>,fun<nm::EW_GEQ, uint32_t, nm::Rational128>,fun<nm::EW_GEQ, uint32_t, nm::RubyObject>},\
616
617
  {fun<nm::EW_GEQ, uint64_t, uint8_t>,fun<nm::EW_GEQ, uint64_t, int8_t>,fun<nm::EW_GEQ, uint64_t, int16_t>,fun<nm::EW_GEQ, uint64_t, int32_t>,fun<nm::EW_GEQ, uint64_t, int64_t>,fun<nm::EW_GEQ, uint64_t, float32_t>,fun<nm::EW_GEQ, uint64_t, float64_t>,fun<nm::EW_GEQ, uint64_t, nm::Complex64>,fun<nm::EW_GEQ, uint64_t, nm::Complex128>,fun<nm::EW_GEQ, uint64_t, nm::Rational32>,fun<nm::EW_GEQ, uint64_t, nm::Rational64>,fun<nm::EW_GEQ, uint64_t, nm::Rational128>,fun<nm::EW_GEQ, uint64_t, nm::RubyObject>}}};
617
618
 
619
+
620
+
618
621
  /*
619
622
  * Defines a static array that holds function pointers to left dtype, right
620
623
  * dtype, and itype templated versions of the specified function.
@@ -9,8 +9,8 @@
9
9
  //
10
10
  // == Copyright Information
11
11
  //
12
- // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
13
- // NMatrix is Copyright (c) 2012, Ruby Science Foundation
12
+ // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2013, Ruby Science Foundation
14
14
  //
15
15
  // Please see LICENSE.txt for additional copyright notices.
16
16
  //
@@ -9,8 +9,8 @@
9
9
  //
10
10
  // == Copyright Information
11
11
  //
12
- // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
13
- // NMatrix is Copyright (c) 2012, Ruby Science Foundation
12
+ // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2013, Ruby Science Foundation
14
14
  //
15
15
  // Please see LICENSE.txt for additional copyright notices.
16
16
  //
@@ -50,17 +50,10 @@
50
50
  if (TYPE(val) != T_DATA || (RDATA(val)->dfree != (RUBY_DATA_FUNC)nm_delete && RDATA(val)->dfree != (RUBY_DATA_FUNC)nm_delete_ref)) \
51
51
  rb_raise(rb_eTypeError, "Expected NMatrix on left-hand side of operation.");
52
52
 
53
- /*
54
- * Types
55
- */
56
-
57
- /*
58
- * Data
59
- */
60
-
61
53
  /*
62
54
  * Classes and Functions
63
55
  */
56
+
64
57
  namespace nm {
65
58
  template<typename T, typename U>
66
59
  struct made_from_same_template : std::false_type {};
@@ -8,8 +8,8 @@
8
8
  #
9
9
  # == Copyright Information
10
10
  #
11
- # SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
12
- # NMatrix is Copyright (c) 2012, Ruby Science Foundation
11
+ # SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
12
+ # NMatrix is Copyright (c) 2013, Ruby Science Foundation
13
13
  #
14
14
  # Please see LICENSE.txt for additional copyright notices.
15
15
  #
@@ -29,7 +29,7 @@ require "mkmf"
29
29
 
30
30
 
31
31
  # Function derived from NArray's extconf.rb.
32
- def have_type(type, header=nil)
32
+ def have_type(type, header=nil) #:nodoc:
33
33
  printf "checking for %s... ", type
34
34
  STDOUT.flush
35
35
 
@@ -60,31 +60,36 @@ SRC
60
60
  end
61
61
 
62
62
  # Function derived from NArray's extconf.rb.
63
- def create_conf_h(file)
63
+ def create_conf_h(file) #:nodoc:
64
64
  print "creating #{file}\n"
65
65
  File.open(file, 'w') do |hfile|
66
- header_guard = file.upcase.sub(/\s|\./, '_')
67
-
68
- hfile.puts "#ifndef #{header_guard}"
69
- hfile.puts "#define #{header_guard}"
70
- hfile.puts
71
-
72
- for line in $defs
73
- line =~ /^-D(.*)/
74
- hfile.printf "#define %s 1\n", $1
75
- end
76
-
77
- hfile.puts
78
- hfile.puts "#endif"
66
+ header_guard = file.upcase.sub(/\s|\./, '_')
67
+
68
+ hfile.puts "#ifndef #{header_guard}"
69
+ hfile.puts "#define #{header_guard}"
70
+ hfile.puts
71
+
72
+ # FIXME: Find a better way to do this:
73
+ if RUBY_VERSION >= '2.0'
74
+ hfile.puts "#define RUBY_2 1"
75
+ end
76
+
77
+ for line in $defs
78
+ line =~ /^-D(.*)/
79
+ hfile.printf "#define %s 1\n", $1
80
+ end
81
+
82
+ hfile.puts
83
+ hfile.puts "#endif"
79
84
  end
80
85
  end
81
86
 
82
87
  if RUBY_VERSION < '1.9'
83
- raise(NotImplementedError, "Sorry, you need Ruby 1.9!")
88
+ raise(NotImplementedError, "Sorry, you need at least Ruby 1.9!")
84
89
  else
85
90
  $INSTALLFILES = [['nmatrix.h', '$(archdir)'], ['nmatrix.hpp', '$(archdir)'], ['nmatrix_config.h', '$(archdir)']]
86
91
  if /cygwin|mingw/ =~ RUBY_PLATFORM
87
- $INSTALLFILES << ['libnmatrix.a', '$(archdir)']
92
+ $INSTALLFILES << ['libnmatrix.a', '$(archdir)']
88
93
  end
89
94
  end
90
95
 
@@ -96,24 +101,28 @@ $DEBUG = true
96
101
  $CFLAGS = ["-Wall ",$CFLAGS].join(" ")
97
102
 
98
103
  $srcs = [
99
- 'nmatrix.cpp',
100
- 'ruby_constants.cpp',
101
-
102
- 'data/data.cpp',
103
- 'util/math.cpp',
104
- 'util/sl_list.cpp',
105
- 'util/io.cpp',
106
- 'storage/common.cpp',
107
- 'storage/storage.cpp',
108
- 'storage/dense.cpp',
109
- 'storage/yale.cpp',
110
- 'storage/list.cpp'
111
- ]
104
+ 'nmatrix.cpp',
105
+ 'ruby_constants.cpp',
106
+
107
+ 'data/data.cpp',
108
+ 'util/math.cpp',
109
+ 'util/sl_list.cpp',
110
+ 'util/io.cpp',
111
+ 'storage/common.cpp',
112
+ 'storage/storage.cpp',
113
+ 'storage/dense.cpp',
114
+ 'storage/yale.cpp',
115
+ 'storage/list.cpp'
116
+ ]
112
117
  # add smmp in to get generic transp; remove smmp2 to eliminate funcptr transp
113
118
 
114
- # The next line allows the user to supply --with-atlas-include=/usr/local/atlas, for example,
115
- # and tell the compiler where to look for ATLAS.
116
- dir_config("atlas")
119
+ # The next line allows the user to supply --with-atlas-dir=/usr/local/atlas,
120
+ # --with-atlas-lib or --with-atlas-include and tell the compiler where to look
121
+ # for ATLAS. The same for all the others
122
+ #
123
+ #dir_config("clapack", ["/usr/local/atlas/include"], [])
124
+ #
125
+ #
117
126
 
118
127
  # Is g++ having trouble finding your header files?
119
128
  # Try this:
@@ -121,15 +130,31 @@ dir_config("atlas")
121
130
  # export CPLUS_INCLUDE_PATH=/usr/local/atlas/include
122
131
  # (substituting in the path of your cblas.h and clapack.h for the path I used). -- JW 8/27/12
123
132
 
124
- find_library("lapack", "clapack_dgetrf", "/usr/local/lib", "/usr/local/atlas/lib")
125
- find_header("clapack.h", "/usr/local/atlas/include")
126
- have_header("clapack.h")
127
133
 
128
- find_library("cblas", "cblas_dgemm", "/usr/local/lib", "/usr/local/atlas/lib")
129
- find_library("atlas", "ATL_dgemmNN", "/usr/local/lib", "/usr/local/atlas/lib", "/usr/lib")
130
- find_header("cblas.h", "/usr/local/atlas/include")
134
+ unless have_library("lapack")
135
+ dir_config("lapack", ["/usr/include/atlas"], ["/usr/local/lib", "/usr/local/atlas/lib"])
136
+ end
137
+
138
+ unless have_library("cblas")
139
+ dir_config("cblas", ["/usr/local/atlas/include", "/usr/include/atlas"], ["/usr/local/lib", "/usr/local/atlas/lib"])
140
+ end
141
+
142
+ unless have_library("atlas")
143
+ dir_config("atlas", ["/usr/local/atlas/include", "/usr/include/atlas"], ["/usr/local/atlas/lib", "/usr/local/lib", "/usr/lib"])
144
+ end
145
+
146
+ #find_library("lapack", "clapack_dgetrf")
147
+ have_header("clapack.h")
131
148
  have_header("cblas.h")
132
149
 
150
+ have_func("clapack_dgetrf", "clapack.h")
151
+
152
+
153
+ #find_library("cblas", "cblas_dgemm")
154
+ #find_library("atlas", "ATL_dgemmNN")
155
+
156
+ have_func("cblas_dgemm", "cblas.h")
157
+
133
158
  # Order matters here: ATLAS has to go after LAPACK: http://mail.scipy.org/pipermail/scipy-user/2007-January/010717.html
134
159
  $libs += " -llapack -lcblas -latlas "
135
160
 
@@ -138,8 +163,8 @@ $objs = %w{nmatrix ruby_constants data/data util/io util/math util/sl_list stora
138
163
  #CONFIG['CXX'] = 'clang++'
139
164
  CONFIG['CXX'] = 'g++'
140
165
 
141
- def find_newer_gplusplus
142
- [7,6,5,4,3].each do |minor|
166
+ def find_newer_gplusplus #:nodoc:
167
+ [8,7,6,5,4,3].each do |minor|
143
168
  result = `which g++-4.#{minor}`
144
169
  next if result.empty?
145
170
  CONFIG['CXX'] = "g++-4.#{minor}"
@@ -148,16 +173,16 @@ def find_newer_gplusplus
148
173
  false
149
174
  end
150
175
 
151
- def gplusplus_version
152
- `#{CONFIG['CXX']} -v 2>&1`.lines.to_a.last.match(/gcc\sversion\s(\d\.\d.\d)/).captures.first
176
+ def gplusplus_version #:nodoc:
177
+ `LANG="en_US" #{CONFIG['CXX']} -v 2>&1`.lines.to_a.last.match(/gcc\sversion\s(\d\.\d.\d)/).captures.first
153
178
  end
154
179
 
155
180
 
156
181
  if CONFIG['CXX'] == 'clang++'
157
- $CPP_STANDARD = 'c++11'
182
+ $CPP_STANDARD = 'c++11'
158
183
 
159
184
  else
160
- version = gplusplus_version
185
+ version = gplusplus_version
161
186
  if version < '4.3.0' && CONFIG['CXX'] == 'g++' # see if we can find a newer G++, unless it's been overridden by user
162
187
  if !find_newer_gplusplus
163
188
  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++.")
@@ -165,16 +190,16 @@ else
165
190
  version = gplusplus_version
166
191
  end
167
192
 
168
- if version < '4.7.0'
169
- $CPP_STANDARD = 'c++0x'
170
- else
171
- $CPP_STANDARD = 'c++11'
172
- end
193
+ if version < '4.7.0'
194
+ $CPP_STANDARD = 'c++0x'
195
+ else
196
+ $CPP_STANDARD = 'c++11'
197
+ end
173
198
  end
174
199
 
175
200
  # For release, these next two should both be changed to -O3.
176
- $CFLAGS += " -O0 "
177
- $CPPFLAGS += " -O0 -std=#{$CPP_STANDARD} " #-fmax-errors=10 -save-temps
201
+ $CFLAGS += " -O0 -g "
202
+ $CPPFLAGS += " -O0 -g -std=#{$CPP_STANDARD} " #-fmax-errors=10 -save-temps
178
203
 
179
204
  CONFIG['warnflags'].gsub!('-Wshorten-64-to-32', '') # doesn't work except in Mac-patched gcc (4.2)
180
205
  CONFIG['warnflags'].gsub!('-Wdeclaration-after-statement', '')
@@ -31,26 +31,25 @@ $CFLAGS = '-I. -fPIC -Wall -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fst
31
31
  CONFIG['CXXFLAGS'] = '-std=c++11'
32
32
 
33
33
  if clang_path = find_executable('clang') and clang_pp_path = find_executable('clang++')
34
- CONFIG['CC'] = clang_path
35
- CONFIG['CXX'] = clang_pp_path
34
+ CONFIG['CC'] = clang_path
35
+ CONFIG['CXX'] = clang_pp_path
36
36
  end
37
37
 
38
38
  # Necessary header files.
39
- find_header('ruby/config.h')
39
+ find_header('ruby/config.h')
40
40
 
41
41
  # List the source files that need to be compiled.
42
42
  $srcs = [
43
- # 'nmatrix.cpp',
44
- 'ruby_constants.cpp',
45
-
46
- 'data/data.cpp',
47
- 'math.cpp',
48
- 'storage/storage.cpp',
49
- 'storage/dense.cpp'
50
- ]
43
+ # 'nmatrix.cpp',
44
+ 'ruby_constants.cpp',
45
+
46
+ 'data/data.cpp',
47
+ 'math.cpp',
48
+ 'storage/storage.cpp',
49
+ 'storage/dense.cpp'
50
+ ]
51
51
 
52
52
  $objs = $srcs.map { |f| f.sub('.cpp', '.o') }
53
53
 
54
54
  # Create the actual Makefile.
55
55
  create_makefile('NMatrix')
56
-
@@ -9,8 +9,8 @@
9
9
  //
10
10
  // == Copyright Information
11
11
  //
12
- // SciRuby is Copyright (c) 2010 - 2012, Ruby Science Foundation
13
- // NMatrix is Copyright (c) 2012, Ruby Science Foundation
12
+ // SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
+ // NMatrix is Copyright (c) 2013, Ruby Science Foundation
14
14
  //
15
15
  // Please see LICENSE.txt for additional copyright notices.
16
16
  //
@@ -23,9 +23,9 @@
23
23
  //
24
24
  // == nmatrix.cpp
25
25
  //
26
- // Main C++ source file for NMatrix. Contains Init_nmatrix and most Ruby instance and
27
- // class methods for NMatrix. Also responsible for calling Init methods on related
28
- // modules.
26
+ // Main C++ source file for NMatrix. Contains Init_nmatrix and most Ruby
27
+ // instance and class methods for NMatrix. Also responsible for calling Init
28
+ // methods on related modules.
29
29
 
30
30
  /*
31
31
  * Standard Includes
@@ -44,6 +44,7 @@ extern "C" {
44
44
  /*
45
45
  * Project Includes
46
46
  */
47
+
47
48
  #include "types.h"
48
49
  #include "data/data.h"
49
50
  #include "util/math.h"
@@ -58,26 +59,11 @@ extern "C" {
58
59
  * Macros
59
60
  */
60
61
 
61
- /*
62
- * If no block is given, return an enumerator. This copied straight out of ruby's include/ruby/intern.h.
63
- *
64
- * rb_enumeratorize is located in enumerator.c.
65
- *
66
- * VALUE rb_enumeratorize(VALUE obj, VALUE meth, int argc, VALUE *argv) {
67
- * return enumerator_init(enumerator_allocate(rb_cEnumerator), obj, meth, argc, argv);
68
- * }
69
- */
70
- #define RETURN_ENUMERATOR(obj, argc, argv) do { \
71
- if (!rb_block_given_p()) \
72
- return rb_enumeratorize((obj), ID2SYM(rb_frame_this_func()), \
73
- (argc), (argv)); \
74
- } while (0)
75
62
 
76
63
  /*
77
64
  * Global Variables
78
65
  */
79
66
 
80
-
81
67
  namespace nm {
82
68
 
83
69
  /*
@@ -144,7 +130,6 @@ namespace nm {
144
130
  return bytes_written;
145
131
  }
146
132
 
147
-
148
133
  /*
149
134
  * We need to specialize for Hermitian matrices. The next six functions accomplish that specialization, basically
150
135
  * by ensuring that non-complex matrices cannot read or write hermitians (which would cause big problems).
@@ -187,7 +172,6 @@ namespace nm {
187
172
  }
188
173
  }
189
174
 
190
-
191
175
  /*
192
176
  * Read the elements of a dense storage matrix from a binary file, padded to 64-bits.
193
177
  *
@@ -259,8 +243,6 @@ namespace nm {
259
243
  if (bytes_read % 8) f.ignore(bytes_read % 8);
260
244
  }
261
245
 
262
-
263
-
264
246
  template <typename DType, typename IType>
265
247
  void write_padded_yale_elements(std::ofstream& f, YALE_STORAGE* storage, size_t length, nm::symm_t symm) {
266
248
  if (symm != nm::NONSYMM) rb_raise(rb_eNotImpError, "Yale matrices can only be read/written in full form");
@@ -299,8 +281,6 @@ namespace nm {
299
281
  f.read(reinterpret_cast<char*>(&padding), bytes_read % 8);
300
282
  }
301
283
 
302
-
303
-
304
284
  /*
305
285
  * Write the elements of a dense storage matrix to a binary file, padded to 64-bits.
306
286
  */
@@ -340,7 +320,6 @@ namespace nm {
340
320
 
341
321
  } // end of namespace nm
342
322
 
343
-
344
323
  extern "C" {
345
324
 
346
325
  /*
@@ -365,6 +344,7 @@ static VALUE nm_dim(VALUE self);
365
344
  static VALUE nm_shape(VALUE self);
366
345
  static VALUE nm_capacity(VALUE self);
367
346
  static VALUE nm_each(VALUE nmatrix);
347
+ static VALUE nm_each_stored_with_indices(VALUE nmatrix);
368
348
 
369
349
  static SLICE* get_slice(size_t dim, VALUE* c, VALUE self);
370
350
  static VALUE nm_xslice(int argc, VALUE* argv, void* (*slice_func)(STORAGE*, SLICE*), void (*delete_func)(NMATRIX*), VALUE self);
@@ -429,16 +409,11 @@ static VALUE nm_upcast(VALUE self, VALUE t1, VALUE t2);
429
409
  static double get_time(void);
430
410
  #endif
431
411
 
432
- /*
433
- * Functions
434
- */
435
-
436
412
  ///////////////////
437
413
  // Ruby Bindings //
438
414
  ///////////////////
439
415
 
440
416
  void Init_nmatrix() {
441
-
442
417
  ///////////////////////
443
418
  // Class Definitions //
444
419
  ///////////////////////
@@ -447,8 +422,16 @@ void Init_nmatrix() {
447
422
  cNVector = rb_define_class("NVector", cNMatrix);
448
423
 
449
424
  // Special exceptions
450
- nm_eDataTypeError = rb_define_class("DataTypeError", rb_eStandardError);
451
- nm_eStorageTypeError = rb_define_class("StorageTypeError", rb_eStandardError);
425
+
426
+ /*
427
+ * Exception raised when there's a problem with data.
428
+ */
429
+ nm_eDataTypeError = rb_define_class("DataTypeError", rb_eStandardError);
430
+
431
+ /*
432
+ * Exception raised when something goes wrong with the storage of a matrix.
433
+ */
434
+ nm_eStorageTypeError = rb_define_class("StorageTypeError", rb_eStandardError);
452
435
 
453
436
  ///////////////////
454
437
  // Class Methods //
@@ -487,8 +470,8 @@ void Init_nmatrix() {
487
470
  rb_define_method(cNMatrix, "is_ref?", (METHOD)nm_is_ref, 0);
488
471
  rb_define_method(cNMatrix, "dimensions", (METHOD)nm_dim, 0);
489
472
 
490
- rb_define_method(cNMatrix, "to_hash", (METHOD)nm_to_hash, 0);
491
- rb_define_alias(cNMatrix, "to_h", "to_hash");
473
+ rb_define_protected_method(cNMatrix, "to_hash_c", (METHOD)nm_to_hash, 0); // handles list and dense, which are n-dimensional
474
+ //rb_define_alias(cNMatrix, "to_h", "to_hash");
492
475
 
493
476
  rb_define_method(cNMatrix, "shape", (METHOD)nm_shape, 0);
494
477
  rb_define_method(cNMatrix, "det_exact", (METHOD)nm_det_exact, 0);
@@ -496,6 +479,7 @@ void Init_nmatrix() {
496
479
  rb_define_method(cNMatrix, "complex_conjugate!", (METHOD)nm_complex_conjugate_bang, 0);
497
480
 
498
481
  rb_define_method(cNMatrix, "each", (METHOD)nm_each, 0);
482
+ rb_define_method(cNMatrix, "each_stored_with_indices", (METHOD)nm_each_stored_with_indices, 0);
499
483
 
500
484
  rb_define_method(cNMatrix, "==", (METHOD)nm_eqeq, 1);
501
485
 
@@ -574,8 +558,6 @@ static VALUE nm_alloc(VALUE klass) {
574
558
  return Data_Wrap_Struct(klass, NULL, nm_delete, mat);
575
559
  }
576
560
 
577
-
578
-
579
561
  /*
580
562
  * Find the capacity of an NMatrix. The capacity only differs from the size for
581
563
  * Yale matrices, which occasionally allocate more space than they need. For
@@ -629,6 +611,9 @@ static void nm_delete_ref(NMATRIX* mat) {
629
611
  }
630
612
 
631
613
  /*
614
+ * call-seq:
615
+ * dtype -> Symbol
616
+ *
632
617
  * Get the data type (dtype) of a matrix, e.g., :byte, :int8, :int16, :int32,
633
618
  * :int64, :float32, :float64, :complex64, :complex128, :rational32,
634
619
  * :rational64, :rational128, or :object (the last is a Ruby object).
@@ -638,8 +623,10 @@ static VALUE nm_dtype(VALUE self) {
638
623
  return ID2SYM(dtype);
639
624
  }
640
625
 
641
-
642
626
  /*
627
+ * call-seq:
628
+ * itype -> Symbol or nil
629
+ *
643
630
  * Get the index data type (dtype) of a matrix. Defined only for yale; others return nil.
644
631
  */
645
632
  static VALUE nm_itype(VALUE self) {
@@ -650,7 +637,6 @@ static VALUE nm_itype(VALUE self) {
650
637
  return Qnil;
651
638
  }
652
639
 
653
-
654
640
  /*
655
641
  * Get the index data type (dtype) of a matrix. Defined only for yale; others return nil.
656
642
  */
@@ -665,8 +651,10 @@ static VALUE nm_itype_by_shape(VALUE self, VALUE shape_arg) {
665
651
  return ID2SYM(itype_id);
666
652
  }
667
653
 
668
-
669
654
  /*
655
+ * call-seq:
656
+ * upcast(first_dtype, second_dtype) ->
657
+ *
670
658
  * Given a binary operation between types t1 and t2, what type will be returned?
671
659
  *
672
660
  * This is a singleton method on NMatrix, e.g., NMatrix.upcast(:int32, :int64)
@@ -680,62 +668,11 @@ static VALUE nm_upcast(VALUE self, VALUE t1, VALUE t2) {
680
668
  }
681
669
 
682
670
 
683
- /*
684
- * Each: Yield objects directly (suitable only for a dense matrix of Ruby objects).
685
- */
686
- static VALUE nm_dense_each_direct(VALUE nm) {
687
- DENSE_STORAGE* s = NM_STORAGE_DENSE(nm);
688
-
689
- RETURN_ENUMERATOR(nm, 0, 0);
690
-
691
- for (size_t i = 0; i < nm_storage_count_max_elements(s); ++i)
692
- rb_yield( reinterpret_cast<VALUE*>(s->elements)[i] );
693
-
694
- return nm;
695
- }
696
-
697
- /*
698
- * Each: Copy matrix elements into Ruby VALUEs before operating on them (suitable for a dense matrix).
699
- */
700
- static VALUE nm_dense_each_indirect(VALUE nm) {
701
- DENSE_STORAGE* s = NM_STORAGE_DENSE(nm);
702
-
703
- RETURN_ENUMERATOR(nm, 0, 0);
704
-
705
- for (size_t i = 0; i < nm_storage_count_max_elements(s); ++i) {
706
- VALUE v = rubyobj_from_cval((char*)(s->elements) + i*DTYPE_SIZES[NM_DTYPE(nm)], NM_DTYPE(nm)).rval;
707
- rb_yield( v ); // yield to the copy we made
708
- }
709
-
710
- return nm;
711
- }
712
-
713
671
 
714
672
  /*
715
- * Borrowed this function from NArray. Handles 'each' iteration on a dense
716
- * matrix.
673
+ * call-seq:
674
+ * each ->
717
675
  *
718
- * Additionally, handles separately matrices containing VALUEs and matrices
719
- * containing other types of data.
720
- */
721
- static VALUE nm_dense_each(VALUE nmatrix) {
722
- volatile VALUE nm = nmatrix; // Not sure this actually does anything.
723
-
724
- if (NM_DTYPE(nm) == nm::RUBYOBJ) {
725
-
726
- // matrix of Ruby objects -- yield those objects directly
727
- return nm_dense_each_direct(nm);
728
-
729
- } else {
730
-
731
- // We're going to copy the matrix element into a Ruby VALUE and then operate on it. This way user can't accidentally
732
- // modify it and cause a seg fault.
733
- return nm_dense_each_indirect(nm);
734
- }
735
- }
736
-
737
-
738
- /*
739
676
  * Iterate over the matrix as you would an Enumerable (e.g., Array).
740
677
  *
741
678
  * Currently only works for dense.
@@ -751,6 +688,26 @@ static VALUE nm_each(VALUE nmatrix) {
751
688
  }
752
689
  }
753
690
 
691
+ /*
692
+ * Iterate over the sparse entries of any matrix. For dense and yale, this iterates over non-zero
693
+ * entries; for list, this iterates over non-default entries. Yields dim+1 values for each entry:
694
+ * i, j, ..., and the entry itself.
695
+ */
696
+ static VALUE nm_each_stored_with_indices(VALUE nmatrix) {
697
+ volatile VALUE nm = nmatrix;
698
+
699
+ switch(NM_STYPE(nm)) {
700
+ case nm::YALE_STORE:
701
+ return nm_yale_each_stored_with_indices(nm);
702
+ case nm::DENSE_STORE:
703
+ return nm_dense_each_with_indices(nm);
704
+ case nm::LIST_STORE:
705
+ return nm_list_each_stored_with_indices(nm);
706
+ default:
707
+ rb_raise(nm_eDataTypeError, "Not a proper storage type");
708
+ }
709
+ }
710
+
754
711
 
755
712
 
756
713
  /*
@@ -803,6 +760,9 @@ DEF_ELEMENTWISE_RUBY_ACCESSOR(LT, lt)
803
760
  DEF_ELEMENTWISE_RUBY_ACCESSOR(GT, gt)
804
761
 
805
762
  /*
763
+ * call-seq:
764
+ * hermitian? -> Boolean
765
+ *
806
766
  * Is this matrix hermitian?
807
767
  *
808
768
  * Definition: http://en.wikipedia.org/wiki/Hermitian_matrix
@@ -814,6 +774,9 @@ static VALUE nm_hermitian(VALUE self) {
814
774
  }
815
775
 
816
776
  /*
777
+ * call-seq:
778
+ * complex_conjugate -> NMatrix
779
+ *
817
780
  * Transform the matrix (in-place) to its complex conjugate. Only works on complex matrices.
818
781
  *
819
782
  * FIXME: For non-complex matrices, someone needs to implement a non-in-place complex conjugate (which doesn't use a bang).
@@ -860,7 +823,6 @@ static VALUE nm_complex_conjugate_bang(VALUE self) {
860
823
  return self;
861
824
  }
862
825
 
863
-
864
826
  /*
865
827
  * Helper function for creating a matrix. You have to create the storage and pass it in, but you don't
866
828
  * need to worry about deleting it.
@@ -875,6 +837,9 @@ NMATRIX* nm_create(nm::stype_t stype, STORAGE* storage) {
875
837
  }
876
838
 
877
839
  /*
840
+ * call-seq:
841
+ * new -> NMatrix
842
+ *
878
843
  * Create a new NMatrix.
879
844
  *
880
845
  * There are several ways to do this. At a minimum, dimensions and either a dtype or initial values are needed, e.g.,
@@ -999,7 +964,7 @@ static VALUE nm_init(int argc, VALUE* argv, VALUE nm) {
999
964
  break;
1000
965
 
1001
966
  case nm::YALE_STORE:
1002
- nmatrix->storage = (STORAGE*)nm_yale_storage_create(dtype, shape, dim, init_cap);
967
+ nmatrix->storage = (STORAGE*)nm_yale_storage_create(dtype, shape, dim, init_cap, nm::UINT8);
1003
968
  nm_yale_storage_init((YALE_STORAGE*)(nmatrix->storage));
1004
969
  break;
1005
970
  }
@@ -1007,11 +972,13 @@ static VALUE nm_init(int argc, VALUE* argv, VALUE nm) {
1007
972
  return nm;
1008
973
  }
1009
974
 
1010
-
1011
975
  /*
976
+ * call-seq:
977
+ * to_hash -> Hash
978
+ *
1012
979
  * Create a Ruby Hash from an NMatrix.
1013
980
  *
1014
- * Currently only works for list storage.
981
+ * This is an internal C function which handles list stype only.
1015
982
  */
1016
983
  static VALUE nm_to_hash(VALUE self) {
1017
984
  if (NM_STYPE(self) != nm::LIST_STORE) {
@@ -1021,7 +988,6 @@ static VALUE nm_to_hash(VALUE self) {
1021
988
  return nm_list_storage_to_hash(NM_STORAGE_LIST(self), NM_DTYPE(self));
1022
989
  }
1023
990
 
1024
-
1025
991
  /*
1026
992
  * Copy constructor for changing dtypes and stypes.
1027
993
  */
@@ -1046,7 +1012,6 @@ static VALUE nm_init_cast_copy(VALUE self, VALUE new_stype_symbol, VALUE new_dty
1046
1012
  return Data_Wrap_Struct(CLASS_OF(self), mark[lhs->stype], nm_delete, lhs);
1047
1013
  }
1048
1014
 
1049
-
1050
1015
  /*
1051
1016
  * Copy constructor for transposing.
1052
1017
  */
@@ -1066,7 +1031,6 @@ static VALUE nm_init_transposed(VALUE self) {
1066
1031
  return Data_Wrap_Struct(CLASS_OF(self), mark[lhs->stype], nm_delete, lhs);
1067
1032
  }
1068
1033
 
1069
-
1070
1034
  /*
1071
1035
  * Copy constructor for no change of dtype or stype (used for #initialize_copy hook).
1072
1036
  */
@@ -1089,7 +1053,6 @@ static VALUE nm_init_copy(VALUE copy, VALUE original) {
1089
1053
  return copy;
1090
1054
  }
1091
1055
 
1092
-
1093
1056
  /*
1094
1057
  * Get major, minor, and release components of NMatrix::VERSION. Store in function parameters.
1095
1058
  */
@@ -1339,7 +1302,7 @@ static VALUE nm_read(int argc, VALUE* argv, VALUE self) {
1339
1302
  f.read(reinterpret_cast<char*>(&ndnz), sizeof(uint32_t));
1340
1303
  f.read(reinterpret_cast<char*>(&length), sizeof(uint32_t));
1341
1304
 
1342
- s = nm_yale_storage_create(dtype, shape, dim, length); // set length as init capacity
1305
+ s = nm_yale_storage_create(dtype, shape, dim, length, itype); // set length as init capacity
1343
1306
 
1344
1307
  read_padded_yale_elements(f, reinterpret_cast<YALE_STORAGE*>(s), length, symm, dtype, itype);
1345
1308
  } else {
@@ -1402,9 +1365,10 @@ static VALUE nm_is_ref(VALUE self) {
1402
1365
  return Qfalse;
1403
1366
  }
1404
1367
 
1405
-
1406
-
1407
1368
  /*
1369
+ * call-seq:
1370
+ * slice -> ...
1371
+ *
1408
1372
  * Access the contents of an NMatrix at given coordinates, using copying.
1409
1373
  *
1410
1374
  * n.slice(3,3) # => 5.0
@@ -1422,6 +1386,9 @@ static VALUE nm_mget(int argc, VALUE* argv, VALUE self) {
1422
1386
  }
1423
1387
 
1424
1388
  /*
1389
+ * call-seq:
1390
+ * matrix[indexes] -> ...
1391
+ *
1425
1392
  * Access the contents of an NMatrix at given coordinates by reference.
1426
1393
  *
1427
1394
  * n[3,3] # => 5.0
@@ -1528,9 +1495,10 @@ static VALUE nm_multiply(VALUE left_v, VALUE right_v) {
1528
1495
  return Qnil;
1529
1496
  }
1530
1497
 
1531
-
1532
-
1533
1498
  /*
1499
+ * call-seq:
1500
+ * matrix.factorize_lu -> ...
1501
+ *
1534
1502
  * LU factorization of a matrix.
1535
1503
  *
1536
1504
  * FIXME: For some reason, getrf seems to require that the matrix be transposed first -- and then you have to transpose the
@@ -1573,6 +1541,9 @@ static VALUE nm_factorize_lu(VALUE self) {
1573
1541
  }
1574
1542
 
1575
1543
  /*
1544
+ * call-seq:
1545
+ * dim -> Integer
1546
+ *
1576
1547
  * Get the number of dimensions of a matrix.
1577
1548
  *
1578
1549
  * In other words, if you set your matrix to be 3x4, the dim is 2. If the
@@ -1586,6 +1557,9 @@ static VALUE nm_dim(VALUE self) {
1586
1557
  }
1587
1558
 
1588
1559
  /*
1560
+ * call-seq:
1561
+ * shape -> Array
1562
+ *
1589
1563
  * Get the shape (dimensions) of a matrix.
1590
1564
  */
1591
1565
  static VALUE nm_shape(VALUE self) {
@@ -1601,6 +1575,9 @@ static VALUE nm_shape(VALUE self) {
1601
1575
  }
1602
1576
 
1603
1577
  /*
1578
+ * call-seq:
1579
+ * stype -> Symbol
1580
+ *
1604
1581
  * Get the storage type (stype) of a matrix, e.g., :yale, :dense, or :list.
1605
1582
  */
1606
1583
  static VALUE nm_stype(VALUE self) {
@@ -1609,6 +1586,9 @@ static VALUE nm_stype(VALUE self) {
1609
1586
  }
1610
1587
 
1611
1588
  /*
1589
+ * call-seq:
1590
+ * symmetric? -> Boolean
1591
+ *
1612
1592
  * Is this matrix symmetric?
1613
1593
  */
1614
1594
  static VALUE nm_symmetric(VALUE self) {
@@ -1665,7 +1645,6 @@ static VALUE elementwise_op(nm::ewop_t op, VALUE left_val, VALUE right_val) {
1665
1645
  nm_dense_storage_ew_op,
1666
1646
  nm_list_storage_ew_op,
1667
1647
  nm_yale_storage_ew_op
1668
- // NULL
1669
1648
  };
1670
1649
 
1671
1650
  NMATRIX *result = ALLOC(NMATRIX), *left;
@@ -1708,10 +1687,15 @@ static VALUE elementwise_op(nm::ewop_t op, VALUE left_val, VALUE right_val) {
1708
1687
  }
1709
1688
  }
1710
1689
 
1711
- return Data_Wrap_Struct(cNMatrix, mark[result->stype], nm_delete, result);
1712
- }
1690
+ VALUE result_val = Data_Wrap_Struct(CLASS_OF(left_val), mark[result->stype], nm_delete, result);
1713
1691
 
1692
+ // If we're dealing with a vector, need to make sure the @orientation matches.
1693
+ // FIXME: Eventually we probably need to make this an internal property of NVector.
1694
+ if (CLASS_OF(left_val) == cNVector)
1695
+ rb_iv_set(result_val, "@orientation", rb_iv_get(left_val, "@orientation"));
1714
1696
 
1697
+ return result_val;
1698
+ }
1715
1699
 
1716
1700
  /*
1717
1701
  * Check to determine whether matrix is a reference to another matrix.
@@ -1751,7 +1735,6 @@ static VALUE is_symmetric(VALUE self, bool hermitian) {
1751
1735
  return Qfalse;
1752
1736
  }
1753
1737
 
1754
-
1755
1738
  ///////////////////////
1756
1739
  // Utility Functions //
1757
1740
  ///////////////////////
@@ -1996,12 +1979,10 @@ static nm::stype_t interpret_stype(VALUE arg) {
1996
1979
  }
1997
1980
  }
1998
1981
 
1999
-
2000
1982
  //////////////////
2001
1983
  // Math Helpers //
2002
1984
  //////////////////
2003
1985
 
2004
-
2005
1986
  STORAGE* matrix_storage_cast_alloc(NMATRIX* matrix, nm::dtype_t new_dtype) {
2006
1987
  if (matrix->storage->dtype == new_dtype && !is_ref(matrix))
2007
1988
  return matrix->storage;
@@ -2010,7 +1991,6 @@ STORAGE* matrix_storage_cast_alloc(NMATRIX* matrix, nm::dtype_t new_dtype) {
2010
1991
  return cast_copy_storage[matrix->stype][matrix->stype](matrix->storage, new_dtype);
2011
1992
  }
2012
1993
 
2013
-
2014
1994
  STORAGE_PAIR binary_storage_cast_alloc(NMATRIX* left_matrix, NMATRIX* right_matrix) {
2015
1995
  STORAGE_PAIR casted;
2016
1996
  nm::dtype_t new_dtype = Upcast[left_matrix->storage->dtype][right_matrix->storage->dtype];
@@ -2021,7 +2001,6 @@ STORAGE_PAIR binary_storage_cast_alloc(NMATRIX* left_matrix, NMATRIX* right_matr
2021
2001
  return casted;
2022
2002
  }
2023
2003
 
2024
-
2025
2004
  static VALUE matrix_multiply_scalar(NMATRIX* left, VALUE scalar) {
2026
2005
  rb_raise(rb_eNotImpError, "matrix-scalar multiplication not implemented yet");
2027
2006
  return Qnil;
@@ -2070,10 +2049,6 @@ static VALUE matrix_multiply(NMATRIX* left, NMATRIX* right) {
2070
2049
  return Qnil; // Only if we try to multiply list matrices should we return Qnil.
2071
2050
  }
2072
2051
 
2073
-
2074
-
2075
-
2076
-
2077
2052
  /*
2078
2053
  * Calculate the exact determinant of a dense matrix.
2079
2054
  *
@@ -2093,14 +2068,10 @@ static VALUE nm_det_exact(VALUE self) {
2093
2068
  return rubyobj_from_cval(result, NM_DTYPE(self)).rval;
2094
2069
  }
2095
2070
 
2096
-
2097
-
2098
-
2099
2071
  /////////////////
2100
2072
  // Exposed API //
2101
2073
  /////////////////
2102
2074
 
2103
-
2104
2075
  /*
2105
2076
  * Create a dense matrix. Used by the NMatrix GSL fork. Unlike nm_create, this one copies all of the
2106
2077
  * arrays and such passed in -- so you don't have to allocate and pass a new shape object for every
@@ -2142,7 +2113,6 @@ VALUE rb_nmatrix_dense_create(nm::dtype_t dtype, size_t* shape, size_t dim, void
2142
2113
  return Data_Wrap_Struct(klass, nm_dense_storage_mark, nm_dense_storage_delete, nm);
2143
2114
  }
2144
2115
 
2145
-
2146
2116
  /*
2147
2117
  * Create a dense vector. Used by the NMatrix GSL fork.
2148
2118
  *
@@ -2158,4 +2128,3 @@ VALUE rb_nvector_dense_create(nm::dtype_t dtype, void* elements, size_t length)
2158
2128
  }
2159
2129
 
2160
2130
  } // end of extern "C"
2161
-