nmatrix 0.0.9 → 0.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/History.txt +95 -1
  4. data/LICENSE.txt +2 -2
  5. data/README.rdoc +24 -26
  6. data/Rakefile +32 -16
  7. data/ext/nmatrix/data/complex.h +2 -2
  8. data/ext/nmatrix/data/data.cpp +27 -51
  9. data/ext/nmatrix/data/data.h +92 -4
  10. data/ext/nmatrix/data/meta.h +2 -2
  11. data/ext/nmatrix/data/rational.h +2 -2
  12. data/ext/nmatrix/data/ruby_object.h +2 -2
  13. data/ext/nmatrix/extconf.rb +87 -86
  14. data/ext/nmatrix/math.cpp +45 -40
  15. data/ext/nmatrix/math/asum.h +3 -3
  16. data/ext/nmatrix/math/geev.h +2 -2
  17. data/ext/nmatrix/math/gemm.h +6 -2
  18. data/ext/nmatrix/math/gemv.h +6 -2
  19. data/ext/nmatrix/math/ger.h +2 -2
  20. data/ext/nmatrix/math/gesdd.h +2 -2
  21. data/ext/nmatrix/math/gesvd.h +2 -2
  22. data/ext/nmatrix/math/getf2.h +2 -2
  23. data/ext/nmatrix/math/getrf.h +2 -2
  24. data/ext/nmatrix/math/getri.h +2 -2
  25. data/ext/nmatrix/math/getrs.h +7 -3
  26. data/ext/nmatrix/math/idamax.h +2 -2
  27. data/ext/nmatrix/math/inc.h +12 -6
  28. data/ext/nmatrix/math/laswp.h +2 -2
  29. data/ext/nmatrix/math/long_dtype.h +2 -2
  30. data/ext/nmatrix/math/math.h +16 -10
  31. data/ext/nmatrix/math/nrm2.h +3 -3
  32. data/ext/nmatrix/math/potrs.h +7 -3
  33. data/ext/nmatrix/math/rot.h +2 -2
  34. data/ext/nmatrix/math/rotg.h +2 -2
  35. data/ext/nmatrix/math/scal.h +2 -2
  36. data/ext/nmatrix/math/swap.h +2 -2
  37. data/ext/nmatrix/math/trsm.h +7 -3
  38. data/ext/nmatrix/nm_memory.h +60 -0
  39. data/ext/nmatrix/nmatrix.cpp +13 -47
  40. data/ext/nmatrix/nmatrix.h +37 -12
  41. data/ext/nmatrix/ruby_constants.cpp +4 -2
  42. data/ext/nmatrix/ruby_constants.h +4 -2
  43. data/ext/nmatrix/ruby_nmatrix.c +937 -170
  44. data/ext/nmatrix/storage/common.cpp +2 -2
  45. data/ext/nmatrix/storage/common.h +2 -2
  46. data/ext/nmatrix/storage/{dense.cpp → dense/dense.cpp} +253 -100
  47. data/ext/nmatrix/storage/{dense.h → dense/dense.h} +6 -5
  48. data/ext/nmatrix/storage/{list.cpp → list/list.cpp} +517 -98
  49. data/ext/nmatrix/storage/{list.h → list/list.h} +13 -6
  50. data/ext/nmatrix/storage/storage.cpp +48 -19
  51. data/ext/nmatrix/storage/storage.h +4 -4
  52. data/ext/nmatrix/storage/yale/class.h +112 -43
  53. data/ext/nmatrix/storage/yale/iterators/base.h +2 -2
  54. data/ext/nmatrix/storage/yale/iterators/iterator.h +2 -2
  55. data/ext/nmatrix/storage/yale/iterators/row.h +2 -2
  56. data/ext/nmatrix/storage/yale/iterators/row_stored.h +2 -2
  57. data/ext/nmatrix/storage/yale/iterators/row_stored_nd.h +4 -3
  58. data/ext/nmatrix/storage/yale/iterators/stored_diagonal.h +2 -2
  59. data/ext/nmatrix/storage/yale/math/transpose.h +2 -2
  60. data/ext/nmatrix/storage/yale/yale.cpp +343 -52
  61. data/ext/nmatrix/storage/yale/yale.h +7 -3
  62. data/ext/nmatrix/types.h +2 -2
  63. data/ext/nmatrix/util/io.cpp +5 -5
  64. data/ext/nmatrix/util/io.h +2 -2
  65. data/ext/nmatrix/util/sl_list.cpp +40 -27
  66. data/ext/nmatrix/util/sl_list.h +3 -3
  67. data/ext/nmatrix/util/util.h +2 -2
  68. data/lib/nmatrix.rb +2 -2
  69. data/lib/nmatrix/blas.rb +2 -2
  70. data/lib/nmatrix/enumerate.rb +17 -6
  71. data/lib/nmatrix/io/market.rb +2 -3
  72. data/lib/nmatrix/io/mat5_reader.rb +2 -2
  73. data/lib/nmatrix/io/mat_reader.rb +2 -2
  74. data/lib/nmatrix/lapack.rb +46 -46
  75. data/lib/nmatrix/math.rb +213 -20
  76. data/lib/nmatrix/monkeys.rb +24 -2
  77. data/lib/nmatrix/nmatrix.rb +394 -9
  78. data/lib/nmatrix/nvector.rb +2 -64
  79. data/lib/nmatrix/rspec.rb +2 -2
  80. data/lib/nmatrix/shortcuts.rb +14 -61
  81. data/lib/nmatrix/version.rb +11 -3
  82. data/lib/nmatrix/yale_functions.rb +4 -4
  83. data/nmatrix.gemspec +2 -7
  84. data/scripts/mac-brew-gcc.sh +11 -8
  85. data/scripts/mac-mavericks-brew-gcc.sh +22 -0
  86. data/spec/00_nmatrix_spec.rb +116 -7
  87. data/spec/01_enum_spec.rb +17 -3
  88. data/spec/02_slice_spec.rb +11 -3
  89. data/spec/blas_spec.rb +5 -2
  90. data/spec/elementwise_spec.rb +5 -2
  91. data/spec/io_spec.rb +27 -17
  92. data/spec/lapack_spec.rb +157 -9
  93. data/spec/math_spec.rb +95 -4
  94. data/spec/nmatrix_yale_spec.rb +21 -26
  95. data/spec/rspec_monkeys.rb +27 -0
  96. data/spec/rspec_spec.rb +2 -2
  97. data/spec/shortcuts_spec.rb +5 -10
  98. data/spec/slice_set_spec.rb +6 -2
  99. data/spec/spec_helper.rb +3 -2
  100. data/spec/stat_spec.rb +174 -158
  101. metadata +15 -15
@@ -9,8 +9,8 @@
9
9
  #
10
10
  # == Copyright Information
11
11
  #
12
- # SciRuby is Copyright (c) 2010 - 2013, Ruby Science Foundation
13
- # NMatrix is Copyright (c) 2013, Ruby Science Foundation
12
+ # SciRuby is Copyright (c) 2010 - 2014, Ruby Science Foundation
13
+ # NMatrix is Copyright (c) 2012 - 2014, John Woods and the Ruby Science Foundation
14
14
  #
15
15
  # Please see LICENSE.txt for additional copyright notices.
16
16
  #
@@ -41,6 +41,7 @@ class NMatrix
41
41
  def load_mat file_path
42
42
  NMatrix::IO::Matlab::Mat5Reader.new(File.open(file_path, "rb+")).to_ruby
43
43
  end
44
+ alias :load :load_mat
44
45
  end
45
46
 
46
47
  # FIXME: Remove autoloads
@@ -76,7 +77,9 @@ class NMatrix
76
77
 
77
78
  # TODO: Make this actually pretty.
78
79
  def pretty_print(q) #:nodoc:
79
- if self.dim > 3 || self.dim == 1
80
+ if self.shape.size > 1 and self.shape[1] > 100
81
+ self.inspect.pretty_print(q)
82
+ elsif self.dim > 3 || self.dim == 1
80
83
  self.to_a.pretty_print(q)
81
84
  else
82
85
  # iterate through the whole matrix and find the longest number
@@ -115,7 +118,6 @@ class NMatrix
115
118
  #alias :pp :pretty_print
116
119
 
117
120
 
118
-
119
121
  #
120
122
  # call-seq:
121
123
  # cast(stype, dtype, default) -> NMatrix
@@ -150,13 +152,17 @@ class NMatrix
150
152
  else
151
153
  params << self.stype if params.size == 0
152
154
  params << self.dtype if params.size == 1
153
- params << (self.stype == :dense ? 0 : self.default_value) if params.size == 2
154
-
155
+ #HACK: the default value can cause an exception if dtype is not complex
156
+ #and default_value is. (The ruby C code apparently won't convert these.)
157
+ #Perhaps this should be fixed in the C code (in rubyval_to_cval).
158
+ default_value = maybe_get_noncomplex_default_value(params[1])
159
+ params << (self.stype == :dense ? 0 : default_value) if params.size == 2
155
160
  self.cast_full(*params)
156
161
  end
157
162
 
158
163
  end
159
164
 
165
+
160
166
  #
161
167
  # call-seq:
162
168
  # rows -> Integer
@@ -378,12 +384,283 @@ class NMatrix
378
384
  # - +row_number+ -> Integer.
379
385
  # - +get_by+ -> Type of slicing to use, +:copy+ or +:reference+.
380
386
  # * *Returns* :
381
- # - A NMatrix representing the requested row as a row vector.
387
+ # - An NMatrix representing the requested row as a row vector.
382
388
  #
383
389
  def row(row_number, get_by = :copy)
384
390
  rank(0, row_number, get_by)
385
391
  end
386
392
 
393
+
394
+ #
395
+ # call-seq:
396
+ # reshape(new_shape) -> NMatrix
397
+ #
398
+ # Clone a matrix, changing the shape in the process. Note that this function does not do a resize; the product of
399
+ # the new and old shapes' components must be equal.
400
+ #
401
+ # * *Arguments* :
402
+ # - +new_shape+ -> Array of positive Fixnums.
403
+ # * *Returns* :
404
+ # - A copy with a different shape.
405
+ #
406
+ def reshape new_shape
407
+ t = reshape_clone_structure(new_shape)
408
+ left_params = [:*]*new_shape.size
409
+ right_params = [:*]*self.shape.size
410
+ t[*left_params] = self[*right_params]
411
+ t
412
+ end
413
+
414
+
415
+ #
416
+ # call-seq:
417
+ # transpose -> NMatrix
418
+ # transpose(permutation) -> NMatrix
419
+ #
420
+ # Clone a matrix, transposing it in the process. If the matrix is two-dimensional, the permutation is taken to be [1,0]
421
+ # automatically (switch dimension 0 with dimension 1). If the matrix is n-dimensional, you must provide a permutation
422
+ # of +0...n+.
423
+ #
424
+ # * *Arguments* :
425
+ # - +permutation+ -> Optional Array giving a permutation.
426
+ # * *Returns* :
427
+ # - A copy of the matrix, but transposed.
428
+ #
429
+ def transpose(permute = nil)
430
+ if self.dim <= 2 # This will give an error if dim is 1.
431
+ new_shape = [self.shape[1], self.shape[0]]
432
+ elsif permute.nil?
433
+ raise(ArgumentError, "need permutation array of size #{self.dim}")
434
+ elsif permute.sort.uniq != (0...self.dim).to_a
435
+ raise(ArgumentError, "invalid permutation array")
436
+ else
437
+ # Figure out the new shape based on the permutation given as an argument.
438
+ new_shape = permute.map { |p| self.shape[p] }
439
+ end
440
+
441
+ if self.dim > 2 # FIXME: For dense, several of these are basically equivalent to reshape.
442
+
443
+ # Make the new data structure.
444
+ t = self.reshape_clone_structure(new_shape)
445
+
446
+ self.each_stored_with_indices do |v,*indices|
447
+ p_indices = permute.map { |p| indices[p] }
448
+ t[*p_indices] = v
449
+ end
450
+ t
451
+ elsif self.list? # TODO: Need a C list transposition algorithm.
452
+ # Make the new data structure.
453
+ t = self.reshape_clone_structure(new_shape)
454
+
455
+ self.each_column.with_index do |col,j|
456
+ t[j,:*] = col.to_flat_array
457
+ end
458
+ t
459
+ else
460
+ # Call C versions of Yale and List transpose, which do their own copies
461
+ self.clone_transpose
462
+ end
463
+ end
464
+
465
+
466
+ #
467
+ # call-seq:
468
+ # matrix1.concat(*m2) -> NMatrix
469
+ # matrix1.concat(*m2, rank) -> NMatrix
470
+ # matrix1.hconcat(*m2) -> NMatrix
471
+ # matrix1.vconcat(*m2) -> NMatrix
472
+ # matrix1.dconcat(*m3) -> NMatrix
473
+ #
474
+ # Joins two matrices together into a new larger matrix. Attempts to determine which direction to concatenate
475
+ # on by looking for the first common element of the matrix +shape+ in reverse. In other words, concatenating two
476
+ # columns together without supplying +rank+ will glue them into an n x 2 matrix.
477
+ #
478
+ # You can also use hconcat, vconcat, and dconcat for the first three ranks. concat performs an hconcat when no
479
+ # rank argument is provided.
480
+ #
481
+ # The two matrices must have the same +dim+.
482
+ #
483
+ # * *Arguments* :
484
+ # - +matrices+ -> one or more matrices
485
+ # - +rank+ -> Fixnum (for rank); alternatively, may use :row, :column, or :layer for 0, 1, 2, respectively
486
+ #
487
+ def concat *matrices
488
+ rank = nil
489
+ rank = matrices.pop unless matrices.last.is_a?(NMatrix)
490
+
491
+ # Find the first matching dimension and concatenate along that (unless rank is specified)
492
+ if rank.nil?
493
+ rank = self.dim-1
494
+ self.shape.reverse_each.with_index do |s,i|
495
+ matrices.each do |m|
496
+ if m.shape[i] != s
497
+ rank -= 1
498
+ break
499
+ end
500
+ end
501
+ end
502
+ elsif rank.is_a?(Symbol) # Convert to numeric
503
+ rank = {:row => 0, :column => 1, :col => 1, :lay => 2, :layer => 2}[rank]
504
+ end
505
+
506
+ # Need to figure out the new shape.
507
+ new_shape = self.shape.dup
508
+ new_shape[rank] = matrices.inject(self.shape[rank]) { |total,m| total + m.shape[rank] }
509
+
510
+ # Now figure out the options for constructing the concatenated matrix.
511
+ opts = {stype: self.stype, default: self.default_value, dtype: self.dtype}
512
+ if self.yale?
513
+ # We can generally predict the new capacity for Yale. Subtract out the number of rows
514
+ # for each matrix being concatenated, and then add in the number of rows for the new
515
+ # shape. That takes care of the diagonal. The rest of the capacity is represented by
516
+ # the non-diagonal non-default values.
517
+ new_cap = matrices.inject(self.capacity - self.shape[0]) do |total,m|
518
+ total + m.capacity - m.shape[0]
519
+ end - self.shape[0] + new_shape[0]
520
+ opts = {capacity: self.new_cap}.merge(opts)
521
+ end
522
+
523
+ # Do the actual construction.
524
+ n = NMatrix.new(new_shape, opts)
525
+
526
+ # Figure out where to start and stop the concatenation. We'll use NMatrices instead of
527
+ # Arrays because then we can do elementwise addition.
528
+ ranges = self.shape.map.with_index { |s,i| 0...self.shape[i] }
529
+
530
+ matrices.unshift(self)
531
+ matrices.each do |m|
532
+ n[*ranges] = m
533
+
534
+ # move over by the requisite amount
535
+ ranges[rank] = (ranges[rank].first + m.shape[rank])...(ranges[rank].last + m.shape[rank])
536
+ end
537
+
538
+ n
539
+ end
540
+
541
+ def hconcat *matrices
542
+ concat(*matrices, :column)
543
+ end
544
+
545
+ def vconcat *matrices
546
+ concat(*matrices, :row)
547
+ end
548
+
549
+ def dconcat *matrices
550
+ concat(*matrices, :layer)
551
+ end
552
+
553
+
554
+ #
555
+ # call-seq:
556
+ # upper_triangle -> NMatrix
557
+ # upper_triangle(k) -> NMatrix
558
+ # triu -> NMatrix
559
+ # triu(k) -> NMatrix
560
+ #
561
+ # Returns the upper triangular portion of a matrix. This is analogous to the +triu+ method
562
+ # in MATLAB.
563
+ #
564
+ # * *Arguments* :
565
+ # - +k+ -> Positive integer. How many extra diagonals to include in the upper triangular portion.
566
+ #
567
+ def upper_triangle(k = 0)
568
+ raise(NotImplementedError, "only implemented for 2D matrices") if self.shape.size > 2
569
+
570
+ t = self.clone_structure
571
+ (0...self.shape[0]).each do |i|
572
+ if i - k < 0
573
+ t[i, :*] = self[i, :*]
574
+ else
575
+ t[i, 0...(i-k)] = 0
576
+ t[i, (i-k)...self.shape[1]] = self[i, (i-k)...self.shape[1]]
577
+ end
578
+ end
579
+ t
580
+ end
581
+ alias :triu :upper_triangle
582
+
583
+
584
+ #
585
+ # call-seq:
586
+ # upper_triangle! -> NMatrix
587
+ # upper_triangle!(k) -> NMatrix
588
+ # triu! -> NMatrix
589
+ # triu!(k) -> NMatrix
590
+ #
591
+ # Deletes the lower triangular portion of the matrix (in-place) so only the upper portion remains.
592
+ #
593
+ # * *Arguments* :
594
+ # - +k+ -> Integer. How many extra diagonals to include in the deletion.
595
+ #
596
+ def upper_triangle!(k = 0)
597
+ raise(NotImplementedError, "only implemented for 2D matrices") if self.shape.size > 2
598
+
599
+ (0...self.shape[0]).each do |i|
600
+ if i - k >= 0
601
+ self[i, 0...(i-k)] = 0
602
+ end
603
+ end
604
+ self
605
+ end
606
+ alias :triu! :upper_triangle!
607
+
608
+
609
+ #
610
+ # call-seq:
611
+ # lower_triangle -> NMatrix
612
+ # lower_triangle(k) -> NMatrix
613
+ # tril -> NMatrix
614
+ # tril(k) -> NMatrix
615
+ #
616
+ # Returns the lower triangular portion of a matrix. This is analogous to the +tril+ method
617
+ # in MATLAB.
618
+ #
619
+ # * *Arguments* :
620
+ # - +k+ -> Integer. How many extra diagonals to include in the lower triangular portion.
621
+ #
622
+ def lower_triangle(k = 0)
623
+ raise(NotImplementedError, "only implemented for 2D matrices") if self.shape.size > 2
624
+
625
+ t = self.clone_structure
626
+ (0...self.shape[0]).each do |i|
627
+ if i + k >= shape[0]
628
+ t[i, :*] = self[i, :*]
629
+ else
630
+ t[i, (i+k+1)...self.shape[1]] = 0
631
+ t[i, 0..(i+k)] = self[i, 0..(i+k)]
632
+ end
633
+ end
634
+ t
635
+ end
636
+ alias :tril :lower_triangle
637
+
638
+
639
+ #
640
+ # call-seq:
641
+ # lower_triangle! -> NMatrix
642
+ # lower_triangle!(k) -> NMatrix
643
+ # tril! -> NMatrix
644
+ # tril!(k) -> NMatrix
645
+ #
646
+ # Deletes the upper triangular portion of the matrix (in-place) so only the lower portion remains.
647
+ #
648
+ # * *Arguments* :
649
+ # - +k+ -> Integer. How many extra diagonals to include in the deletion.
650
+ #
651
+ def lower_triangle!(k = 0)
652
+ raise(NotImplementedError, "only implemented for 2D matrices") if self.shape.size > 2
653
+
654
+ (0...self.shape[0]).each do |i|
655
+ if i + k < shape[0]
656
+ self[i, (i+k+1)...self.shape[1]] = 0
657
+ end
658
+ end
659
+ self
660
+ end
661
+ alias :tril! :lower_triangle!
662
+
663
+
387
664
  #
388
665
  # call-seq:
389
666
  # layer(layer_number) -> NMatrix
@@ -435,6 +712,43 @@ class NMatrix
435
712
  end
436
713
 
437
714
 
715
+ #
716
+ # call-seq:
717
+ # sorted_indices -> Array
718
+ #
719
+ # Returns an array of the indices ordered by value sorted.
720
+ #
721
+ def sorted_indices
722
+ return method_missing(:sorted_indices) unless vector?
723
+ ary = self.to_flat_array
724
+ ary.each_index.sort_by { |i| ary[i] } # from: http://stackoverflow.com/a/17841159/170300
725
+ end
726
+
727
+
728
+ #
729
+ # call-seq:
730
+ # binned_sorted_indices -> Array
731
+ #
732
+ # Returns an array of arrays of indices ordered by value sorted. Functions basically like +sorted_indices+, but
733
+ # groups indices together for those values that are the same.
734
+ #
735
+ def binned_sorted_indices
736
+ return method_missing(:sorted_indices) unless vector?
737
+ ary = self.to_flat_array
738
+ ary2 = []
739
+ last_bin = ary.each_index.sort_by { |i| [ary[i]] }.inject([]) do |result, element|
740
+ if result.empty? || ary[result[-1]] == ary[element]
741
+ result << element
742
+ else
743
+ ary2 << result
744
+ [element]
745
+ end
746
+ end
747
+ ary2 << last_bin unless last_bin.empty?
748
+ ary2
749
+ end
750
+
751
+
438
752
  def method_missing name, *args, &block #:nodoc:
439
753
  if name.to_s =~ /^__list_elementwise_.*__$/
440
754
  raise NotImplementedError, "requested undefined list matrix element-wise operation"
@@ -447,7 +761,7 @@ class NMatrix
447
761
 
448
762
 
449
763
  def respond_to?(method) #:nodoc:
450
- if [:shuffle, :shuffle!, :each_with_index].include?(method.intern) # vector-only methods
764
+ if [:shuffle, :shuffle!, :each_with_index, :sorted_indices, :binned_sorted_indices, :nrm2, :asum].include?(method.intern) # vector-only methods
451
765
  return vector?
452
766
  elsif [:each_layer, :layer].include?(method.intern) # 3-or-more dimensions only
453
767
  return dim > 2
@@ -483,6 +797,35 @@ protected
483
797
  end
484
798
 
485
799
 
800
+ #
801
+ # call-seq:
802
+ # clone_structure -> NMatrix
803
+ #
804
+ # This function is like clone, but it only copies the structure and the default value.
805
+ # None of the other values are copied. It takes an optional capacity argument. This is
806
+ # mostly only useful for dense, where you may not want to initialize; for other types,
807
+ # you should probably use +zeros_like+.
808
+ #
809
+ def clone_structure(capacity = nil)
810
+ opts = {stype: self.stype, default: self.default_value, dtype: self.dtype}
811
+ opts = {capacity: capacity}.merge(opts) if self.yale?
812
+ NMatrix.new(self.shape, opts)
813
+ end
814
+
815
+
816
+ # Clone the structure as needed for a reshape
817
+ def reshape_clone_structure(new_shape) #:nodoc:
818
+ raise(ArgumentError, "reshape cannot resize; size of new and old matrices must match") unless self.size == new_shape.inject(1) { |p,i| p *= i }
819
+
820
+ opts = {stype: self.stype, default: self.default_value, dtype: self.dtype}
821
+ if self.yale?
822
+ # We can generally predict the change in capacity for Yale.
823
+ opts = {capacity: self.capacity - self.shape[0] + new_shape[0]}.merge(opts)
824
+ end
825
+ NMatrix.new(new_shape, opts)
826
+ end
827
+
828
+
486
829
  # Helper for converting a matrix into an array of arrays recursively
487
830
  def to_a_rec(dimen = 0) #:nodoc:
488
831
  return self.flat_map { |v| v } if dimen == self.dim-1
@@ -500,8 +843,50 @@ protected
500
843
  def __sparse_initial_set__(ary) #:nodoc:
501
844
  self[0...self.shape[0],0...self.shape[1]] = ary
502
845
  end
846
+
847
+
848
+ # Function assumes the dimensions and such have already been tested.
849
+ #
850
+ # Called from inside NMatrix: nm_eqeq
851
+ #
852
+ # There are probably more efficient ways to do this, but currently it's unclear how.
853
+ # We could use +each_row+, but for list matrices, it's still going to need to make a
854
+ # reference to each of those rows, and that is going to require a seek.
855
+ #
856
+ # It might be more efficient to convert one sparse matrix type to the other with a
857
+ # cast and then run the comparison. For now, let's assume that people aren't going
858
+ # to be doing this very often, and we can optimize as needed.
859
+ def dense_eql_sparse? m #:nodoc:
860
+ m.each_with_indices do |v,*indices|
861
+ return false if self[*indices] != v
862
+ end
863
+
864
+ return true
865
+ end
866
+ alias :sparse_eql_sparse? :dense_eql_sparse?
867
+
868
+
869
+ #
870
+ # See the note in #cast about why this is necessary.
871
+ # If this is a non-dense matrix with a complex dtype and to_dtype is
872
+ # non-complex, then this will convert the default value to noncomplex.
873
+ # Returns 0 if dense. Returns existing default_value if there isn't a
874
+ # mismatch.
875
+ #
876
+ def maybe_get_noncomplex_default_value(to_dtype) #:nodoc:
877
+ default_value = 0
878
+ unless self.stype == :dense then
879
+ if self.dtype.to_s.start_with?('complex') and not to_dtype.to_s.start_with?('complex') then
880
+ default_value = self.default_value.real
881
+ else
882
+ default_value = self.default_value
883
+ end
884
+ end
885
+ default_value
886
+ end
887
+
503
888
  end
504
889
 
505
890
  require_relative './shortcuts.rb'
506
891
  require_relative './math.rb'
507
- require_relative './enumerate.rb'
892
+ require_relative './enumerate.rb'