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 +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) {
|