nmatrix 0.0.4 → 0.0.5

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 80c122ef6be8531eccdf14ff07426f8302660a14
4
+ data.tar.gz: 74335afd35279bcb817691e94c3017883ae3fed5
5
+ SHA512:
6
+ metadata.gz: 2d1573ca2c204fb33897870fc350779db8800c0ce41b263c3ae0628647ebd85e31ff5080e7a02bdf76f043a184274c5d197384d6322827250583d68c743d0ca6
7
+ data.tar.gz: 07446f0f43a91fed625330975a6f9d443b9b497ddc694bd6d7b54cb5e54da191a98444fb8d4c6097d594862e57e76c24d84133daac84eda68688699428920c7d
data/History.txt CHANGED
@@ -78,7 +78,7 @@
78
78
  * Now requires packable-1.3.5 or higher, fixing a problem with MATLAB
79
79
  .mat v5 file I/O (specific to doubles)
80
80
 
81
- === 0.0.4 / 2013-??-??
81
+ === 0.0.4 / 2013-05-17
82
82
 
83
83
  * 3 major enhancements
84
84
 
@@ -122,4 +122,70 @@
122
122
 
123
123
  * Fixed gem install command in Rakefile (by @jpmckinney)
124
124
 
125
- * Fixed Spanish language compile issue (by @imcsk8 and @agarie)
125
+ * Fixed Spanish language compile issue (by @imcsk8 and @agarie)
126
+
127
+ === 0.0.5 / 2013-??-??
128
+
129
+ * 4 major enhancements
130
+
131
+ * NVector orientation is now controlled by its shape, not by the
132
+ @orientation property
133
+
134
+ * NVector default orientation is now a row vector rather than a
135
+ column, as this is more efficient for Yale storage
136
+
137
+ * NVector objects may now be created with dtypes other than dense
138
+
139
+ * Exposure of additional ATLAS-implemented BLAS functions,
140
+ including native rational and Ruby object support, for xANUM (sum
141
+ of the absolute values of a vector) and xNRM2 (2-norm of a
142
+ vector); and Ruby helper functions BLAS::anum and BLAS::nrm2
143
+ which should do more careful argument sanity checking
144
+
145
+ * 9 minor enhancements
146
+
147
+ * Added #yale_vector_insert to NMatrix::YaleFunctions, to speed up
148
+ insertion of multiple items into a Yale matrix
149
+
150
+ * Added #yale_nd_row, #yale_nd_row_as_hash, #yale_nd_row_as_array,
151
+ #yale_nd_row_as_set, #yale_nd_row_as_sorted_set, #yale_row,
152
+ #yale_row_as_hash, #yale_row_as_array, #yale_row_as_set,
153
+ #yale_row_as_sorted_set, #yale_nd_row_size to
154
+ NMatrix::YaleFunctions in order to speed up getting multiple
155
+ items from some row of a Yale matrix
156
+
157
+ * Improved #yale_ija, #yale_a, #yale_d by allowing an optional
158
+ index argument, which returns a single array value instead of
159
+ copying and returning the entire array
160
+
161
+ * Improved sorting algorithm for Yale matrix multiplication;
162
+ instead of selection sort, now uses quicksort; and subs in
163
+ insertion sort for small partitions
164
+
165
+ * Slicing a single row or column now returns an NVector instead
166
+ of an NMatrix (does not yet work for n-dimensional matrices)
167
+
168
+ * Improved function documentation for NVector and NMatrix
169
+
170
+ * Added #min, #max, #to_a, #shuffle, #shuffle!, #absolute_sum,
171
+ #norm2 functions to NVector
172
+
173
+ * Aliased missing dimension of NVector#each_stored_with_indices to
174
+ #each_stored_with_index, which only yields a value and i or j
175
+ (not both i and j) depending on the vector orientation
176
+
177
+ * Added #each_row, #each_column to NMatrix
178
+
179
+ * 5 bug fixes:
180
+
181
+ * Dense iterators now return self (an NMatrix) in order to be
182
+ consistent with Ruby Array behavior (by @cjfuller)
183
+
184
+ * Fixed Yale resize problem (by @v0dro)
185
+
186
+ * Fixed Yale nx1 times 1xn multiplication problem
187
+
188
+ * Fixed Yale sorting-following-multiplication problem
189
+
190
+ * NMatrix::read() now raises an exception when asked to read a file
191
+ that does not exist
data/Manifest.txt CHANGED
@@ -30,6 +30,7 @@ lib/nmatrix/nmatrix.rb
30
30
  lib/nmatrix/nvector.rb
31
31
  lib/nmatrix/shortcuts.rb
32
32
  lib/nmatrix/version.rb
33
+ lib/nmatrix/yale_functions.rb
33
34
  ext/nmatrix/data/complex.h
34
35
  ext/nmatrix/data/data.cpp
35
36
  ext/nmatrix/data/data.h
data/README.rdoc CHANGED
@@ -52,10 +52,10 @@ Finally, try compiling again.
52
52
 
53
53
  == Documentation
54
54
 
55
- Carlos Agarie (@agarie) is currently working to improve the documentation. The best way to get help is by
56
- posting {issues}[https://github.com/SciRuby/nmatrix/issues] or sending e-mails to
57
- our {mailing list}[https://groups.google.com/forum/?fromgroups#!forum/sciruby-dev]. You may also email @agarie, or look
58
- for `agarie` on #sciruby at chat.freenode.net if you want to ask questions or offer suggestions.
55
+ Carlos Agarie (@agarie) is currently working to improve the documentation. The best way to get help is by posting
56
+ {issues}[https://github.com/SciRuby/nmatrix/issues] or sending e-mails to our
57
+ {mailing list}[https://groups.google.com/forum/?fromgroups#!forum/sciruby-dev]. You may also email @agarie, or look for
58
+ `agarie` on #sciruby at chat.freenode.net if you want to ask questions or offer suggestions.
59
59
 
60
60
  You can find the complete API documentation {on our website}[http://sciruby.com/nmatrix/docs/].
61
61
 
@@ -89,7 +89,7 @@ Read the instructions in +CONTRIBUTING.md+ if you want to help NMatrix.
89
89
 
90
90
  The following features exist in the current version of NMatrix (0.0.4):
91
91
 
92
- * Matrix storage containers: dense, yale, list (more to come)
92
+ * Matrix and vector storage containers: dense, yale, list (more to come)
93
93
  * Data types: uint8, int8, int16, int32, int64, float32, float64, complex64, complex128, rational64, rational128
94
94
  (incomplete)
95
95
  * Conversion between storage and data types (except from-complex, and from-float-to-rational)
@@ -102,7 +102,7 @@ The following features exist in the current version of NMatrix (0.0.4):
102
102
  * Matlab .MAT v5 file input
103
103
  * C and C++ API
104
104
  * BLAS internal implementations (no library) and ATLAS (with library) access:
105
- * Level 1: xROT, xROTG (BLAS dtypes only)
105
+ * Level 1: xROT, xROTG (BLAS dtypes only), xASUM, xNRM2
106
106
  * Level 2: xGEMV
107
107
  * Level 3: xGEMM, xTRSM
108
108
  * LAPACK ATLAS access:
@@ -116,6 +116,7 @@ The following features exist in the current version of NMatrix (0.0.4):
116
116
  * LU decomposition
117
117
  * Matrix inversions (requires LAPACK; BLAS dtypes only)
118
118
  * Determinant calculation for BLAS dtypes
119
+ * Vector 2-norms
119
120
  * Ruby/GSL interoperability (requires [SciRuby's fork of rb-gsl](http://github.com/SciRuby/rb-gsl))
120
121
 
121
122
  === Planned Features (Short-to-Medium Term)
@@ -126,7 +127,7 @@ These are features planned for NMatrix 0.1.0, our first beta.
126
127
  * exponentials and square roots
127
128
  * matrix inversions (LAPACK-free)
128
129
  * matrix decomposition/factorization
129
- * calculation of norms
130
+ * calculation of additional norms
130
131
  * tensor products
131
132
  * principal component analysis (PCA)
132
133
  * improved file I/O
data/Rakefile CHANGED
@@ -40,8 +40,10 @@ BASEDIR = Pathname( __FILE__ ).dirname.relative_path_from( Pathname.pwd )
40
40
  SPECDIR = BASEDIR + 'spec'
41
41
 
42
42
  VALGRIND_OPTIONS = [
43
- "--num-callers=50",
44
- "--error-limit=no",
43
+ "--tool=memcheck",
44
+ "--leak-check=yes",
45
+ "--num-callers=15",
46
+ #"--error-limit=no",
45
47
  "--partial-loads-ok=yes",
46
48
  "--undef-value-errors=no" #,
47
49
  #"--dsymutil=yes"
@@ -128,6 +130,15 @@ namespace :spec do
128
130
  end
129
131
 
130
132
 
133
+ LEAKCHECK_CMD = [ 'ruby', '-Ilib:ext', "#{SPECDIR}/leakcheck.rb" ]
134
+
135
+ desc "Run leakcheck script."
136
+ task :leakcheck => [ :compile ] do |task|
137
+ cmd = [ 'valgrind' ] + VALGRIND_OPTIONS
138
+ cmd += LEAKCHECK_CMD
139
+ run( *cmd )
140
+ end
141
+
131
142
  namespace :clean do
132
143
  task :so do |task|
133
144
  tmp_path = "tmp/#{RUBY_PLATFORM}/nmatrix/#{RUBY_VERSION}"
@@ -34,6 +34,7 @@
34
34
 
35
35
  #include <type_traits>
36
36
  #include <iostream>
37
+ #include <cmath>
37
38
 
38
39
  /*
39
40
  * Project Includes
@@ -363,10 +364,27 @@ inline std::ostream& operator<<(std::ostream& out, const Complex<Type>& rhs) {
363
364
 
364
365
  namespace std {
365
366
  template <typename FloatType, typename = typename std::enable_if<std::is_floating_point<FloatType>::value>::type>
366
- nm::Complex<FloatType> abs(const nm::Complex<FloatType>& value) {
367
+ nm::Complex<FloatType> piecewise_abs(const nm::Complex<FloatType>& value) {
367
368
  return nm::Complex<FloatType>(value.r < 0 ? -value.r : value.r,
368
369
  value.i < 0 ? -value.i : value.i);
369
370
  }
371
+
372
+ template <typename FloatType, typename = typename std::enable_if<std::is_floating_point<FloatType>::value>::type>
373
+ nm::Complex<FloatType> real_abs(const nm::Complex<FloatType>& value) {
374
+ return nm::Complex<FloatType>(value.r < 0 ? -value.r : value.r,
375
+ value.i);
376
+ }
377
+
378
+ template <typename FloatType, typename = typename std::enable_if<std::is_floating_point<FloatType>::value>::type>
379
+ nm::Complex<FloatType> imag_abs(const nm::Complex<FloatType>& value) {
380
+ return nm::Complex<FloatType>(value.r,
381
+ value.i < 0 ? -value.i : value.i);
382
+ }
383
+
384
+ template <typename FloatType, typename = typename std::enable_if<std::is_floating_point<FloatType>::value>::type>
385
+ double abs(const nm::Complex<FloatType>& value) {
386
+ return std::sqrt(double(value.r)*double(value.r) + double(value.i)*double(value.i));
387
+ }
370
388
  }
371
389
 
372
390
  #endif // COMPLEX_H
@@ -143,6 +143,14 @@ namespace nm {
143
143
 
144
144
  #define ITYPE_TEMPLATE_TABLE(fun, ret, ...) NAMED_ITYPE_TEMPLATE_TABLE(ttable, fun, ret, __VA_ARGS__)
145
145
 
146
+ #define NAMED_LR_ITYPE_TEMPLATE_TABLE(name, fun, ret, ...) \
147
+ static ret (*(name)[nm::NUM_ITYPES][nm::NUM_ITYPES])(__VA_ARGS__) = { \
148
+ { fun<uint8_t,uint8_t>, fun<uint8_t, uint16_t>, fun<uint8_t, uint32_t>, fun<uint8_t, uint64_t> }, \
149
+ { fun<uint16_t,uint8_t>, fun<uint16_t, uint16_t>, fun<uint16_t, uint32_t>, fun<uint16_t, uint64_t> }, \
150
+ { fun<uint32_t,uint8_t>, fun<uint32_t, uint16_t>, fun<uint32_t, uint32_t>, fun<uint32_t, uint64_t> }, \
151
+ { fun<uint64_t,uint8_t>, fun<uint64_t, uint16_t>, fun<uint64_t, uint32_t>, fun<uint64_t, uint64_t> } \
152
+ };
153
+
146
154
  /*
147
155
  * Same as DTYPE_TEMPLATE_TABLE but for functions that have two template
148
156
  * parameters.
@@ -440,6 +440,7 @@ namespace std {
440
440
  return obj.abs();
441
441
  }
442
442
 
443
+
443
444
  inline nm::RubyObject sqrt(const nm::RubyObject& obj) {
444
445
  VALUE cMath = rb_const_get(rb_cObject, rb_intern("Math"));
445
446
  return nm::RubyObject(rb_funcall(cMath, rb_intern("sqrt"), 1, obj.rval));
@@ -131,11 +131,11 @@ $srcs = [
131
131
  # (substituting in the path of your cblas.h and clapack.h for the path I used). -- JW 8/27/12
132
132
 
133
133
 
134
- unless have_library("lapack")
134
+ unless have_library("lapack") # && have_header("clapack.h")
135
135
  dir_config("lapack", ["/usr/include/atlas"], ["/usr/local/lib", "/usr/local/atlas/lib"])
136
136
  end
137
137
 
138
- unless have_library("cblas")
138
+ unless have_library("cblas") # && have_header("cblas.h")
139
139
  dir_config("cblas", ["/usr/local/atlas/include", "/usr/include/atlas"], ["/usr/local/lib", "/usr/local/atlas/lib"])
140
140
  end
141
141
 
@@ -198,8 +198,10 @@ else
198
198
  end
199
199
 
200
200
  # For release, these next two should both be changed to -O3.
201
- $CFLAGS += " -O0 -g "
202
- $CPPFLAGS += " -O0 -g -std=#{$CPP_STANDARD} " #-fmax-errors=10 -save-temps
201
+ $CFLAGS += " -O3 " #" -O0 -g "
202
+ # $CFLAGS += " -static -O0 -g "
203
+ $CPPFLAGS += " -O3 -std=#{$CPP_STANDARD} " #" -O0 -g -std=#{$CPP_STANDARD} " #-fmax-errors=10 -save-temps
204
+ # $CPPFLAGS += " -static -O0 -g -std=#{$CPP_STANDARD} "
203
205
 
204
206
  CONFIG['warnflags'].gsub!('-Wshorten-64-to-32', '') # doesn't work except in Mac-patched gcc (4.2)
205
207
  CONFIG['warnflags'].gsub!('-Wdeclaration-after-statement', '')
@@ -544,6 +544,28 @@ void Init_nmatrix() {
544
544
  // Ruby Methods //
545
545
  //////////////////
546
546
 
547
+
548
+ /*
549
+ * Slice constructor.
550
+ */
551
+ static SLICE* alloc_slice(size_t dim) {
552
+ SLICE* slice = ALLOC(SLICE);
553
+ slice->coords = ALLOC_N(size_t, dim);
554
+ slice->lengths = ALLOC_N(size_t, dim);
555
+ return slice;
556
+ }
557
+
558
+
559
+ /*
560
+ * Slice destructor.
561
+ */
562
+ static void free_slice(SLICE* slice) {
563
+ free(slice->coords);
564
+ free(slice->lengths);
565
+ free(slice);
566
+ }
567
+
568
+
547
569
  /*
548
570
  * Allocator.
549
571
  */
@@ -596,6 +618,8 @@ static void nm_delete(NMATRIX* mat) {
596
618
  nm_yale_storage_delete
597
619
  };
598
620
  ttable[mat->stype](mat->storage);
621
+
622
+ free(mat);
599
623
  }
600
624
 
601
625
  /*
@@ -608,6 +632,8 @@ static void nm_delete_ref(NMATRIX* mat) {
608
632
  nm_yale_storage_delete
609
633
  };
610
634
  ttable[mat->stype](mat->storage);
635
+
636
+ free(mat);
611
637
  }
612
638
 
613
639
  /*
@@ -671,7 +697,7 @@ static VALUE nm_upcast(VALUE self, VALUE t1, VALUE t2) {
671
697
 
672
698
  /*
673
699
  * call-seq:
674
- * each ->
700
+ * each -> Enumerator
675
701
  *
676
702
  * Iterate over the matrix as you would an Enumerable (e.g., Array).
677
703
  *
@@ -842,34 +868,51 @@ NMATRIX* nm_create(nm::stype_t stype, STORAGE* storage) {
842
868
  *
843
869
  * Create a new NMatrix.
844
870
  *
845
- * There are several ways to do this. At a minimum, dimensions and either a dtype or initial values are needed, e.g.,
871
+ * There are several ways to do this. In every case, the constructor needs to know the dtype, the dimensions, the stype,
872
+ * and either an initial capacity (:yale) or some number of initial values (:list needs exactly one initial value, but
873
+ * :dense can accept an array). In many cases, the parameters can be guessed from other parameters.
874
+ *
875
+ * Here is the full form for a :dense 3x4 :float64 matrix initialized to alternate the values 0.0, 1.0, and 2.0:
876
+ *
877
+ * NMatrix.new(:dense, [3,4], [0.0, 1.0, 2.0], :float64)
846
878
  *
847
- * NMatrix.new(3, :int64) # square 3x3 dense matrix
848
- * NMatrix.new([3,4], :float32) # 3x4 matrix
849
- * NMatrix.new(3, 0) # 3x3 dense matrix initialized to all zeros
850
- * NMatrix.new([3,3], [1,2,3]) # [[1,2,3],[1,2,3],[1,2,3]]
879
+ * Since :dense is the default, we can actually leave that out. Additionally, the constructor will parse 0.0 and
880
+ * interpret that to be a :float64. So we can actually short-hand this as follows:
851
881
  *
852
- * NMatrix will try to guess the dtype from the first value in the initial values array.
882
+ * NMatrix.new([3,4], [0.0,1,2])
853
883
  *
854
- * You can also provide the stype prior to the dimensions. However, non-dense matrices cannot take initial values, and
855
- * require a dtype (e.g., :int64):
884
+ * Note that :list and :yale matrices will not accept a default value array. For list storage, a single default value
885
+ * is permissible, which will be treated as the background for the sparse matrix and defaults to 0:
856
886
  *
857
- * NMatrix.new(:yale, [4,3], :int64)
858
- * NMatrix.new(:list, 5, :rational128)
887
+ * NMatrix.new(:list, [3,4], 0) # standard :int64 sparse matrix
888
+ * NMatrix.new(:list, [2,3], 1.0) # :float64 sparse matrix: [[1,1,1],[1,1,1]] (no storage used)
889
+ * NMatrix.new(:list, [3,4], [0,1]) # undefined behavior, will probably fill matrix with 0. Avoid this.
859
890
  *
860
- * For Yale, you can also give an initial size for the non-diagonal component of the matrix:
891
+ * For Yale storage, the default value must always be 0. Thus, if you provide an initial value, it will be interpreted
892
+ * as the initial matrix capacity.
861
893
  *
862
- * NMatrix.new(:yale, [4,3], 2, :int64)
894
+ * NMatrix.new(:yale, [4,3], :rational128) # Use default initial capacity. Most common.
895
+ * NMatrix.new(:yale, [3,4], 1000) # Error! Needs a dtype!
896
+ * NMatrix.new(:yale, [3,4], 1000, :int64) # Silly! Why would a 3x4 sparse matrix need storage space of 1,000?
897
+ * NMatrix.new(:yale, [3,4], 0.0, :float64) # Totally ignores non-sensical 3rd arg and creates 7 storage instead.
898
+ * NMatrix.new(:yale, [3,4], 8, :rational128) # Initial capacity of 8 rationals.
863
899
  *
864
- * Finally, you can be extremely specific, and define a matrix very exactly:
900
+ * That leaves only two other notes. First of all, if your matrix is square, you don't need to type [3,3] for 3x3.
901
+ * Instead, just do 3:
865
902
  *
866
- * NMatrix.new(:dense, [2,2,2], [0,1,2,3,4,5,6,7], :int8)
903
+ * NMatrix.new(3, [0,1,2], :rational128) # dense 3x3 rational matrix consisting of columns of 0s, 1s, and 2s
867
904
  *
868
- * There is one additional constructor for advanced users, which takes seven arguments and is only for creating Yale matrices
869
- * with known IA, JA, and A arrays. This is used primarily internally for IO, e.g., reading Matlab matrices, which are
870
- * stored in old Yale format.
905
+ * Secondly, if you create a dense matrix without initial values, you may see unpredictable results! It'll fill the
906
+ * matrix with whatever is already in memory, not with zeros.
871
907
  *
872
- * Just be careful! There are no overflow warnings in NMatrix.
908
+ * NMatrix.new(:dense, 4, :int64)
909
+ * # => [8, 140486578196280, 0, 0] [0, 0, 0, 0] [0, 0, 0, 140486608794928] [140486577962496, -4294967280, 1, 140734734392208]
910
+ *
911
+ * There is one additional constructor for advanced users, which takes seven arguments and is only for creating Yale
912
+ * matrices with known IA, JA, and A arrays. This is used primarily internally for IO, e.g., reading Matlab matrices,
913
+ * which are stored in old Yale (not our Yale) format. But be careful; there are no overflow warnings. All of these
914
+ * constructors are defined for power-users. Everyone else should probably resort to the shortcut functions defined in
915
+ * shortcuts.rb.
873
916
  */
874
917
  static VALUE nm_init(int argc, VALUE* argv, VALUE nm) {
875
918
 
@@ -1139,6 +1182,16 @@ void write_padded_dense_elements(std::ofstream& f, DENSE_STORAGE* storage, nm::s
1139
1182
  }
1140
1183
 
1141
1184
 
1185
+ /*
1186
+ * Helper function to get exceptions in the module Errno (e.g., ENOENT). Example:
1187
+ *
1188
+ * rb_raise(rb_get_errno_exc("ENOENT"), RSTRING_PTR(filename));
1189
+ */
1190
+ static VALUE rb_get_errno_exc(const char* which) {
1191
+ return rb_const_get(rb_const_get(rb_cObject, rb_intern("Errno")), rb_intern(which));
1192
+ }
1193
+
1194
+
1142
1195
 
1143
1196
  /*
1144
1197
  * Binary file writer for NMatrix standard format. file should be a path, which we aren't going to
@@ -1238,12 +1291,16 @@ static VALUE nm_write(int argc, VALUE* argv, VALUE self) {
1238
1291
  static VALUE nm_read(int argc, VALUE* argv, VALUE self) {
1239
1292
  using std::ifstream;
1240
1293
 
1294
+ VALUE file, force_;
1295
+
1241
1296
  // Read the arguments
1242
- if (argc < 1 || argc > 2) {
1243
- rb_raise(rb_eArgError, "expected one or two arguments");
1297
+ rb_scan_args(argc, argv, "11", &file, &force_);
1298
+ bool force = (force_ != Qnil && force_ != Qfalse);
1299
+
1300
+
1301
+ if (!RB_FILE_EXISTS(file)) { // FIXME: Errno::ENOENT
1302
+ rb_raise(rb_get_errno_exc("ENOENT"), RSTRING_PTR(file));
1244
1303
  }
1245
- VALUE file = argv[0];
1246
- bool force = argc == 1 ? false : argv[1];
1247
1304
 
1248
1305
  // Open a file stream
1249
1306
  ifstream f(RSTRING_PTR(file), std::ios::in | std::ios::binary);
@@ -1387,7 +1444,7 @@ static VALUE nm_mget(int argc, VALUE* argv, VALUE self) {
1387
1444
 
1388
1445
  /*
1389
1446
  * call-seq:
1390
- * matrix[indexes] -> ...
1447
+ * matrix[indices] -> ...
1391
1448
  *
1392
1449
  * Access the contents of an NMatrix at given coordinates by reference.
1393
1450
  *
@@ -1430,6 +1487,7 @@ static VALUE nm_mset(int argc, VALUE* argv, VALUE self) {
1430
1487
  switch(NM_STYPE(self)) {
1431
1488
  case nm::DENSE_STORE:
1432
1489
  nm_dense_storage_set(NM_STORAGE(self), slice, value);
1490
+ free(value);
1433
1491
  break;
1434
1492
  case nm::LIST_STORE:
1435
1493
  // Remove if it's a zero, insert otherwise
@@ -1439,12 +1497,15 @@ static VALUE nm_mset(int argc, VALUE* argv, VALUE self) {
1439
1497
  free(value);
1440
1498
  } else {
1441
1499
  nm_list_storage_insert(NM_STORAGE(self), slice, value);
1500
+ // no need to free value here since it was inserted directly into the list.
1442
1501
  }
1443
1502
  break;
1444
1503
  case nm::YALE_STORE:
1445
1504
  nm_yale_storage_set(NM_STORAGE(self), slice, value);
1505
+ free(value);
1446
1506
  break;
1447
1507
  }
1508
+ free_slice(slice);
1448
1509
 
1449
1510
  return argv[dim];
1450
1511
 
@@ -1620,15 +1681,21 @@ static VALUE nm_xslice(int argc, VALUE* argv, void* (*slice_func)(STORAGE*, SLIC
1620
1681
  NMATRIX* mat = ALLOC(NMATRIX);
1621
1682
  mat->stype = NM_STYPE(self);
1622
1683
  mat->storage = (STORAGE*)((*slice_func)( NM_STORAGE(self), slice ));
1623
- result = Data_Wrap_Struct(cNMatrix, mark_table[mat->stype], delete_func, mat);
1684
+
1685
+ // Do we want an NVector instead of an NMatrix?
1686
+ VALUE klass = cNMatrix, orient = Qnil;
1687
+ // FIXME: Generalize for n dimensional slicing somehow
1688
+ if (mat->storage->shape[0] == 1 || mat->storage->shape[1] == 1) klass = cNVector;
1689
+
1690
+ result = Data_Wrap_Struct(klass, mark_table[mat->stype], delete_func, mat);
1624
1691
  }
1625
1692
 
1626
- free(slice);
1693
+ free_slice(slice);
1627
1694
 
1628
1695
  } else if (NM_DIM(self) < (size_t)(argc)) {
1629
1696
  rb_raise(rb_eArgError, "Coordinates given exceed number of matrix dimensions");
1630
1697
  } else {
1631
- rb_raise(rb_eNotImpError, "This type slicing not supported yet");
1698
+ rb_raise(rb_eNotImpError, "This type of slicing not supported yet");
1632
1699
  }
1633
1700
 
1634
1701
  return result;
@@ -1689,11 +1756,6 @@ static VALUE elementwise_op(nm::ewop_t op, VALUE left_val, VALUE right_val) {
1689
1756
 
1690
1757
  VALUE result_val = Data_Wrap_Struct(CLASS_OF(left_val), mark[result->stype], nm_delete, result);
1691
1758
 
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"));
1696
-
1697
1759
  return result_val;
1698
1760
  }
1699
1761
 
@@ -1817,6 +1879,8 @@ nm::dtype_t nm_dtype_guess(VALUE v) {
1817
1879
  }
1818
1880
  }
1819
1881
 
1882
+
1883
+
1820
1884
  /*
1821
1885
  * Documentation goes here.
1822
1886
  */
@@ -1825,9 +1889,7 @@ static SLICE* get_slice(size_t dim, VALUE* c, VALUE self) {
1825
1889
  VALUE beg, end;
1826
1890
  int exl;
1827
1891
 
1828
- SLICE* slice = ALLOC(SLICE);
1829
- slice->coords = ALLOC_N(size_t,dim);
1830
- slice->lengths = ALLOC_N(size_t, dim);
1892
+ SLICE* slice = alloc_slice(dim);
1831
1893
  slice->single = true;
1832
1894
 
1833
1895
  for (r = 0; r < dim; ++r) {