nmatrix 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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) {