nmatrix 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
-