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 +7 -0
- data/History.txt +68 -2
- data/Manifest.txt +1 -0
- data/README.rdoc +8 -7
- data/Rakefile +13 -2
- data/ext/nmatrix/data/complex.h +19 -1
- data/ext/nmatrix/data/data.h +8 -0
- data/ext/nmatrix/data/ruby_object.h +1 -0
- data/ext/nmatrix/extconf.rb +6 -4
- data/ext/nmatrix/nmatrix.cpp +97 -35
- data/ext/nmatrix/nmatrix.h +2 -0
- data/ext/nmatrix/ruby_constants.cpp +11 -1
- data/ext/nmatrix/ruby_constants.h +6 -1
- data/ext/nmatrix/storage/dense.cpp +2 -2
- data/ext/nmatrix/storage/yale.cpp +303 -49
- data/ext/nmatrix/storage/yale.h +3 -0
- data/ext/nmatrix/util/math.cpp +112 -0
- data/ext/nmatrix/util/math.h +372 -72
- data/lib/nmatrix/blas.rb +55 -9
- data/lib/nmatrix/nmatrix.rb +315 -2
- data/lib/nmatrix/nvector.rb +156 -95
- data/lib/nmatrix/version.rb +1 -1
- data/lib/nmatrix/yale_functions.rb +112 -0
- data/spec/blas_spec.rb +11 -0
- data/spec/elementwise_spec.rb +4 -1
- data/spec/io_spec.rb +8 -0
- data/spec/lapack_spec.rb +37 -15
- data/spec/leakcheck.rb +16 -0
- data/spec/math_spec.rb +6 -2
- data/spec/nmatrix_spec.rb +209 -3
- data/spec/nmatrix_yale_spec.rb +55 -0
- data/spec/nvector_spec.rb +33 -14
- data/spec/slice_spec.rb +26 -17
- data/spec/spec_helper.rb +17 -0
- metadata +60 -45
- data/ext/nmatrix/new_extconf.rb +0 -55
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
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
|
-
|
57
|
-
|
58
|
-
|
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
|
-
"--
|
44
|
-
"--
|
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}"
|
data/ext/nmatrix/data/complex.h
CHANGED
@@ -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>
|
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
|
data/ext/nmatrix/data/data.h
CHANGED
@@ -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.
|
data/ext/nmatrix/extconf.rb
CHANGED
@@ -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
|
-
$
|
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', '')
|
data/ext/nmatrix/nmatrix.cpp
CHANGED
@@ -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.
|
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
|
-
*
|
848
|
-
*
|
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
|
-
*
|
882
|
+
* NMatrix.new([3,4], [0.0,1,2])
|
853
883
|
*
|
854
|
-
*
|
855
|
-
*
|
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(:
|
858
|
-
* NMatrix.new(:list,
|
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,
|
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],
|
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
|
-
*
|
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(
|
903
|
+
* NMatrix.new(3, [0,1,2], :rational128) # dense 3x3 rational matrix consisting of columns of 0s, 1s, and 2s
|
867
904
|
*
|
868
|
-
*
|
869
|
-
* with
|
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
|
-
*
|
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
|
-
|
1243
|
-
|
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[
|
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
|
-
|
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
|
-
|
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 =
|
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) {
|