nmatrix 0.1.0.rc2 → 0.1.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/History.txt +16 -0
- data/README.rdoc +1 -1
- data/ext/nmatrix/ruby_nmatrix.c +16 -6
- data/ext/nmatrix/storage/dense/dense.cpp +2 -7
- data/lib/nmatrix/lapack.rb +65 -4
- data/lib/nmatrix/version.rb +1 -1
- data/spec/00_nmatrix_spec.rb +42 -6
- data/spec/02_slice_spec.rb +6 -0
- data/spec/shortcuts_spec.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9bccc178bd2c4a0ee318f3a0808e7f3c52cfbc3f
|
4
|
+
data.tar.gz: eec9ec0890b8ab958c123452f98064883de0ea33
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab789cf265f5461e75e0425ce126c45e52ff627b69bfa0a5a94018260254708ec11c9e0e67a9f94e7dab0696fe1171c56d8043304b59848bfede52761e33924f
|
7
|
+
data.tar.gz: b8f8cfe0c81c7ce46306afcd9b5e469e84856aae990b6e42e52ca299234fe03801bd7f0c4ba585f14786909f1dbe88b10e5b12b3ef16c37935b8efa06e58b7ed
|
data/.travis.yml
CHANGED
data/History.txt
CHANGED
@@ -583,3 +583,19 @@
|
|
583
583
|
* NMatrix::random now raises an exception when rational matrices
|
584
584
|
are requested
|
585
585
|
|
586
|
+
=== 0.1.0.rc3 / 2014-03-27
|
587
|
+
|
588
|
+
* No major enhancements.
|
589
|
+
|
590
|
+
* 2 minor enhancements:
|
591
|
+
|
592
|
+
* Exposed NMatrix::LAPACK::geev for LAPACK's xGEEV
|
593
|
+
|
594
|
+
* Added out-of-place complex conjugate for dense and yale storage
|
595
|
+
(by @rve)
|
596
|
+
|
597
|
+
* 1 bug fixes:
|
598
|
+
|
599
|
+
* Fixed critical bug with transposing a matrix reference slice (by
|
600
|
+
@rajatkapoor)
|
601
|
+
|
data/README.rdoc
CHANGED
@@ -38,7 +38,7 @@ If you want to obtain the latest (development) code, you should generally do:
|
|
38
38
|
bundle install
|
39
39
|
bundle exec rake compile
|
40
40
|
bundle exec rake repackage
|
41
|
-
gem install pkg/nmatrix-0.1.0.
|
41
|
+
gem install pkg/nmatrix-0.1.0.rc3.gem
|
42
42
|
|
43
43
|
Detailed instructions are available for {Mac}[https://github.com/SciRuby/nmatrix/wiki/Installation#mac-os-x] and {Linux}[https://github.com/SciRuby/nmatrix/wiki/Installation#linux].
|
44
44
|
We are currently working on Mavericks (Mac OS X) installation instructions, but in general, you'll need Homebrew and should
|
data/ext/nmatrix/ruby_nmatrix.c
CHANGED
@@ -154,6 +154,7 @@ static VALUE nm_multiply(VALUE left_v, VALUE right_v);
|
|
154
154
|
static VALUE nm_det_exact(VALUE self);
|
155
155
|
static VALUE nm_inverse_exact(VALUE self, VALUE inverse);
|
156
156
|
static VALUE nm_complex_conjugate_bang(VALUE self);
|
157
|
+
static VALUE nm_complex_conjugate(VALUE self);
|
157
158
|
static VALUE nm_reshape_bang(VALUE self, VALUE arg);
|
158
159
|
|
159
160
|
static nm::dtype_t interpret_dtype(int argc, VALUE* argv, nm::stype_t stype);
|
@@ -260,6 +261,7 @@ void Init_nmatrix() {
|
|
260
261
|
rb_define_method(cNMatrix, "det_exact", (METHOD)nm_det_exact, 0);
|
261
262
|
rb_define_protected_method(cNMatrix, "__inverse_exact__", (METHOD)nm_inverse_exact, 1);
|
262
263
|
rb_define_method(cNMatrix, "complex_conjugate!", (METHOD)nm_complex_conjugate_bang, 0);
|
264
|
+
rb_define_method(cNMatrix, "complex_conjugate", (METHOD)nm_complex_conjugate, 0);
|
263
265
|
rb_define_protected_method(cNMatrix, "reshape_bang", (METHOD)nm_reshape_bang, 1);
|
264
266
|
|
265
267
|
rb_define_protected_method(cNMatrix, "__dense_each__", (METHOD)nm_dense_each, 0);
|
@@ -975,11 +977,10 @@ static VALUE nm_hermitian(VALUE self) {
|
|
975
977
|
|
976
978
|
/*
|
977
979
|
* call-seq:
|
978
|
-
*
|
980
|
+
* complex_conjugate_bang -> NMatrix
|
979
981
|
*
|
980
982
|
* Transform the matrix (in-place) to its complex conjugate. Only works on complex matrices.
|
981
983
|
*
|
982
|
-
* FIXME: For non-complex matrices, someone needs to implement a non-in-place complex conjugate (which doesn't use a bang).
|
983
984
|
* Bang should imply that no copy is being made, even temporarily.
|
984
985
|
*/
|
985
986
|
static VALUE nm_complex_conjugate_bang(VALUE self) {
|
@@ -1017,13 +1018,22 @@ static VALUE nm_complex_conjugate_bang(VALUE self) {
|
|
1017
1018
|
reinterpret_cast<nm::Complex128*>(elem)[p].i = -reinterpret_cast<nm::Complex128*>(elem)[p].i;
|
1018
1019
|
}
|
1019
1020
|
|
1020
|
-
}
|
1021
|
-
rb_raise(nm_eDataTypeError, "can only calculate in-place complex conjugate on matrices of type :complex64 or :complex128");
|
1022
|
-
}
|
1023
|
-
|
1021
|
+
}
|
1024
1022
|
return self;
|
1025
1023
|
}
|
1026
1024
|
|
1025
|
+
/*
|
1026
|
+
* call-seq:
|
1027
|
+
* complex_conjugate -> NMatrix
|
1028
|
+
*
|
1029
|
+
* Transform the matrix (non-in-place) to its complex conjugate. Only works on complex matrices.
|
1030
|
+
*
|
1031
|
+
*/
|
1032
|
+
static VALUE nm_complex_conjugate(VALUE self) {
|
1033
|
+
VALUE copy;
|
1034
|
+
return nm_complex_conjugate_bang(nm_init_copy(copy,self));
|
1035
|
+
}
|
1036
|
+
|
1027
1037
|
|
1028
1038
|
/*
|
1029
1039
|
* call-seq:
|
@@ -742,7 +742,6 @@ void nm_dense_storage_coords(const DENSE_STORAGE* s, const size_t slice_pos, siz
|
|
742
742
|
coords_out[i] = (temp_pos - temp_pos % s->stride[i])/s->stride[i] - s->offset[i];
|
743
743
|
temp_pos = temp_pos % s->stride[i];
|
744
744
|
}
|
745
|
-
|
746
745
|
}
|
747
746
|
|
748
747
|
/*
|
@@ -834,16 +833,13 @@ STORAGE* nm_dense_storage_copy_transposed(const STORAGE* rhs_base) {
|
|
834
833
|
DENSE_STORAGE* rhs = (DENSE_STORAGE*)rhs_base;
|
835
834
|
|
836
835
|
nm_dense_storage_register(rhs);
|
837
|
-
|
838
836
|
size_t *shape = NM_ALLOC_N(size_t, rhs->dim);
|
839
837
|
|
840
|
-
// swap shape
|
838
|
+
// swap shape
|
841
839
|
shape[0] = rhs->shape[1];
|
842
840
|
shape[1] = rhs->shape[0];
|
843
841
|
|
844
842
|
DENSE_STORAGE *lhs = nm_dense_storage_create(rhs->dtype, shape, rhs->dim, NULL, 0);
|
845
|
-
lhs->offset[0] = rhs->offset[1];
|
846
|
-
lhs->offset[1] = rhs->offset[0];
|
847
843
|
|
848
844
|
nm_dense_storage_register(lhs);
|
849
845
|
|
@@ -916,8 +912,7 @@ void ref_slice_copy_transposed(const DENSE_STORAGE* rhs, DENSE_STORAGE* lhs) {
|
|
916
912
|
|
917
913
|
LDType* lhs_els = reinterpret_cast<LDType*>(lhs->elements);
|
918
914
|
RDType* rhs_els = reinterpret_cast<RDType*>(rhs->elements);
|
919
|
-
|
920
|
-
size_t count = nm_storage_count_max_elements(lhs);
|
915
|
+
size_t count = nm_storage_count_max_elements(lhs);;
|
921
916
|
size_t* temp_coords = NM_ALLOCA_N(size_t, lhs->dim);
|
922
917
|
size_t coord_swap_temp;
|
923
918
|
|
data/lib/nmatrix/lapack.rb
CHANGED
@@ -140,10 +140,11 @@ class NMatrix
|
|
140
140
|
]
|
141
141
|
end
|
142
142
|
|
143
|
+
|
143
144
|
#
|
144
145
|
# call-seq:
|
145
|
-
# gesvd -> [u, sigma, v_transpose]
|
146
|
-
# gesvd -> [u, sigma, v_conjugate_transpose] # complex
|
146
|
+
# gesvd(matrix) -> [u, sigma, v_transpose]
|
147
|
+
# gesvd(matrix) -> [u, sigma, v_conjugate_transpose] # complex
|
147
148
|
#
|
148
149
|
# Compute the singular value decomposition of a matrix using LAPACK's GESVD function.
|
149
150
|
#
|
@@ -158,8 +159,8 @@ class NMatrix
|
|
158
159
|
|
159
160
|
#
|
160
161
|
# call-seq:
|
161
|
-
# gesdd -> [u, sigma, v_transpose]
|
162
|
-
# gesdd -> [u, sigma, v_conjugate_transpose] # complex
|
162
|
+
# gesdd(matrix) -> [u, sigma, v_transpose]
|
163
|
+
# gesdd(matrix) -> [u, sigma, v_conjugate_transpose] # complex
|
163
164
|
#
|
164
165
|
# Compute the singular value decomposition of a matrix using LAPACK's GESDD function. This uses a divide-and-conquer
|
165
166
|
# strategy. See also #gesvd.
|
@@ -173,6 +174,66 @@ class NMatrix
|
|
173
174
|
result
|
174
175
|
end
|
175
176
|
|
177
|
+
def alloc_evd_result(matrix)
|
178
|
+
[
|
179
|
+
NMatrix.new(matrix.shape[0], dtype: matrix.dtype),
|
180
|
+
NMatrix.new(matrix.shape[0], dtype: matrix.dtype),
|
181
|
+
NMatrix.new([matrix.shape[0],1], dtype: matrix.dtype),
|
182
|
+
NMatrix.new([matrix.shape[0],1], dtype: matrix.dtype),
|
183
|
+
]
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
#
|
188
|
+
# call-seq:
|
189
|
+
# geev(matrix) -> [eigenvalues, left_eigenvectors, right_eigenvectors]
|
190
|
+
# geev(matrix, :left) -> [eigenvalues, left_eigenvectors]
|
191
|
+
# geev(matrix, :right) -> [eigenvalues, right_eigenvectors]
|
192
|
+
#
|
193
|
+
# Perform eigenvalue decomposition on a matrix using LAPACK's xGEEV function.
|
194
|
+
#
|
195
|
+
def geev(matrix, which=:both)
|
196
|
+
result = alloc_evd_result(matrix)
|
197
|
+
jobvl = (which == :both || which == :left) ? :left : false
|
198
|
+
jobvr = (which == :both || which == :right) ? :right : false
|
199
|
+
|
200
|
+
# Copy the matrix so it doesn't get overwritten.
|
201
|
+
temporary_matrix = matrix.clone
|
202
|
+
|
203
|
+
# Outputs
|
204
|
+
real_eigenvalues = NMatrix.new([matrix.shape[0], 1], dtype: matrix.dtype)
|
205
|
+
imag_eigenvalues = NMatrix.new([matrix.shape[0], 1], dtype: matrix.dtype)
|
206
|
+
|
207
|
+
left_output = jobvl == :left ? matrix.clone_structure : NMatrix.new(1, dtype: matrix.dtype)
|
208
|
+
right_output = jobvr == :right ? matrix.clone_structure : NMatrix.new(1, dtype: matrix.dtype)
|
209
|
+
|
210
|
+
NMatrix::LAPACK::lapack_geev(jobvl, # compute left eigenvectors of A?
|
211
|
+
jobvr, # compute right eigenvectors of A? (left eigenvectors of A**T)
|
212
|
+
matrix.shape[0], # order of the matrix
|
213
|
+
temporary_matrix,# input matrix (used as work)
|
214
|
+
matrix.shape[0], # leading dimension of matrix
|
215
|
+
real_eigenvalues,# real part of computed eigenvalues
|
216
|
+
imag_eigenvalues,# imag part of computed eigenvalues
|
217
|
+
left_output, # left eigenvectors, if applicable
|
218
|
+
left_output.shape[0], # leading dimension of left_output
|
219
|
+
right_output, # right eigenvectors, if applicable
|
220
|
+
right_output.shape[0], # leading dimension of right_output
|
221
|
+
2*matrix.shape[0])
|
222
|
+
|
223
|
+
# Put the real and imaginary parts together
|
224
|
+
eigenvalues = real_eigenvalues.to_a.flatten.map.with_index do |real,i|
|
225
|
+
imag_eigenvalues[i] != 0 ? Complex(real, imag_eigenvalues[i]) : real
|
226
|
+
end
|
227
|
+
|
228
|
+
if which == :both
|
229
|
+
return [eigenvalues, left_output.transpose, right_output.transpose]
|
230
|
+
elsif which == :left
|
231
|
+
return [eigenvalues, left_output.transpose]
|
232
|
+
else
|
233
|
+
return [eigenvalues, right_output]
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
176
237
|
end
|
177
238
|
end
|
178
239
|
end
|
data/lib/nmatrix/version.rb
CHANGED
data/spec/00_nmatrix_spec.rb
CHANGED
@@ -291,12 +291,6 @@ describe NMatrix do
|
|
291
291
|
expect(lambda { NMatrix.new(3,dtype: :int8)[1,1] }).to_not raise_error
|
292
292
|
end
|
293
293
|
|
294
|
-
it "calculates the complex conjugate in-place" do
|
295
|
-
n = NMatrix.new(:dense, 3, [1,2,3,4,5,6,7,8,9], :complex128)
|
296
|
-
n.complex_conjugate!
|
297
|
-
# FIXME: Actually test that values are correct.
|
298
|
-
end
|
299
|
-
|
300
294
|
it "converts from list to yale properly" do
|
301
295
|
m = NMatrix.new(3, 0, stype: :list)
|
302
296
|
m[0,2] = 333
|
@@ -519,4 +513,46 @@ describe 'NMatrix' do
|
|
519
513
|
expect(n[0,0..-2]).to eq(NMatrix.new([1,4],[1,2,3,4]))
|
520
514
|
end
|
521
515
|
end
|
516
|
+
|
517
|
+
context "#complex_conjugate!" do
|
518
|
+
[:dense, :yale, :list].each do |stype|
|
519
|
+
context(stype) do
|
520
|
+
it "should work in-place for complex dtypes" do
|
521
|
+
pending("not yet implemented for list stype") if stype == :list
|
522
|
+
n = NMatrix.new([2,3], [Complex(2,3)], stype: stype, dtype: :complex128)
|
523
|
+
n.complex_conjugate!
|
524
|
+
expect(n).to eq(NMatrix.new([2,3], [Complex(2,-3)], stype: stype, dtype: :complex128))
|
525
|
+
end
|
526
|
+
|
527
|
+
[:object, :int64].each do |dtype|
|
528
|
+
it "should work in-place for non-complex dtypes" do
|
529
|
+
pending("not yet implemented for list stype") if stype == :list
|
530
|
+
n = NMatrix.new([2,3], 1, stype: stype, dtype: dtype)
|
531
|
+
n.complex_conjugate!
|
532
|
+
expect(n).to eq(NMatrix.new([2,3], [1], stype: stype, dtype: dtype))
|
533
|
+
end
|
534
|
+
end
|
535
|
+
end
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
context "#complex_conjugate" do
|
540
|
+
[:dense, :yale, :list].each do |stype|
|
541
|
+
context(stype) do
|
542
|
+
it "should work out-of-place for complex dtypes" do
|
543
|
+
pending("not yet implemented for list stype") if stype == :list
|
544
|
+
n = NMatrix.new([2,3], [Complex(2,3)], stype: stype, dtype: :complex128)
|
545
|
+
expect(n.complex_conjugate).to eq(NMatrix.new([2,3], [Complex(2,-3)], stype: stype, dtype: :complex128))
|
546
|
+
end
|
547
|
+
|
548
|
+
[:object, :int64].each do |dtype|
|
549
|
+
it "should work out-of-place for non-complex dtypes" do
|
550
|
+
pending("not yet implemented for list stype") if stype == :list
|
551
|
+
n = NMatrix.new([2,3], 1, stype: stype, dtype: dtype)
|
552
|
+
expect(n.complex_conjugate).to eq(NMatrix.new([2,3], [1], stype: stype, dtype: dtype))
|
553
|
+
end
|
554
|
+
end
|
555
|
+
end
|
556
|
+
end
|
557
|
+
end
|
522
558
|
end
|
data/spec/02_slice_spec.rb
CHANGED
@@ -314,6 +314,12 @@ describe "Slice operation" do
|
|
314
314
|
|
315
315
|
it "correctly transposes slices" do
|
316
316
|
expect(@m[0...3,0].transpose).to eq NMatrix[[0, 3, 6]]
|
317
|
+
expect(@m[0...3,1].transpose).to eq NMatrix[[1, 4, 7]]
|
318
|
+
expect(@m[0...3,2].transpose).to eq NMatrix[[2, 5, 8]]
|
319
|
+
expect(@m[0,0...3].transpose).to eq NMatrix[[0], [1], [2]]
|
320
|
+
expect(@m[1,0...3].transpose).to eq NMatrix[[3], [4], [5]]
|
321
|
+
expect(@m[2,0...3].transpose).to eq NMatrix[[6], [7], [8]]
|
322
|
+
expect(@m[1..2,1..2].transpose).to eq NMatrix[[4, 7], [5, 8]]
|
317
323
|
end
|
318
324
|
|
319
325
|
it "adds slices" do
|
data/spec/shortcuts_spec.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nmatrix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.
|
4
|
+
version: 0.1.0.rc3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Woods
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2014-03-
|
13
|
+
date: 2014-03-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rdoc
|