nmatrix 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -71,7 +71,8 @@ class NMatrix
71
71
  #
72
72
  def map(&bl)
73
73
  return enum_for(:map) unless block_given?
74
- cp = self.cast(dtype: :object)
74
+ # NMatrix-jruby currently supports only doubles
75
+ cp = jruby? ? self : self.cast(dtype: :object)
75
76
  cp.map!(&bl)
76
77
  cp
77
78
  end
@@ -220,7 +221,7 @@ class NMatrix
220
221
 
221
222
  return enum_for(:inject_rank, dimen, initial, dtype) unless block_given?
222
223
 
223
- new_shape = shape
224
+ new_shape = shape.dup
224
225
  new_shape[dimen] = 1
225
226
 
226
227
  first_as_acc = false
@@ -0,0 +1,24 @@
1
+ class NMatrix
2
+
3
+ # discussion in https://github.com/SciRuby/nmatrix/issues/374
4
+
5
+ def matrix_solve rhs
6
+ if rhs.shape[1] > 1
7
+ nmatrix = NMatrix.new :copy
8
+ nmatrix.shape = rhs.shape
9
+ res = []
10
+ #Solve a matrix and store the vectors in a matrix
11
+ (0...rhs.shape[1]).each do |i|
12
+ res << self.solve(rhs.col(i)).s.toArray.to_a
13
+ end
14
+ #res is in col major format
15
+ result = ArrayGenerator.getArrayColMajorDouble res.to_java :double, rhs.shape[0], rhs.shape[1]
16
+ nmatrix.s = ArrayRealVector.new result
17
+
18
+ return nmatrix
19
+ else
20
+ return self.solve rhs
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,13 @@
1
+ # Source: https://github.com/marcandre/backports/blob/master/lib/backports/rails/enumerable.rb
2
+ module Enumerable
3
+ # Standard in rails... See official documentation[http://api.rubyonrails.org/classes/Enumerable.html]
4
+ # Modified from rails 2.3 to not rely on size
5
+ def sum(identity = 0, &block)
6
+ if block_given?
7
+ map(&block).sum(identity)
8
+ else
9
+ inject { |sum, element| sum + element } || identity
10
+ end
11
+ end unless method_defined? :sum
12
+
13
+ end
@@ -0,0 +1,4 @@
1
+ DataTypeError = Class.new(StandardError)
2
+ StorageTypeError = Class.new(StandardError)
3
+ ShapeError = Class.new(StandardError)
4
+ NotInvertibleError = Class.new(StandardError)
@@ -0,0 +1,501 @@
1
+ #--
2
+ # = NMatrix
3
+ #
4
+ # A linear algebra library for scientific computation in Ruby.
5
+ # NMatrix is part of SciRuby.
6
+ #
7
+ # NMatrix was originally inspired by and derived from NArray, by
8
+ # Masahiro Tanaka: http://narray.rubyforge.org
9
+ #
10
+ # == Copyright Information
11
+ #
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
+ #
15
+ # Please see LICENSE.txt for additional copyright notices.
16
+ #
17
+ # == Contributing
18
+ #
19
+ # By contributing source code to SciRuby, you agree to be bound by
20
+ # our Contributor Agreement:
21
+ #
22
+ # * https://github.com/SciRuby/sciruby/wiki/Contributor-Agreement
23
+ #
24
+ # == math.rb
25
+ #
26
+ # Math functionality for NMatrix, along with any NMatrix instance
27
+ # methods that correspond to ATLAS/BLAS/LAPACK functions (e.g.,
28
+ # laswp).
29
+ #++
30
+
31
+ class NMatrix
32
+
33
+ #
34
+ # call-seq:
35
+ # getrf! -> Array
36
+ #
37
+ # LU factorization of a general M-by-N matrix +A+ using partial pivoting with
38
+ # row interchanges. The LU factorization is A = PLU, where P is a row permutation
39
+ # matrix, L is a lower triangular matrix with unit diagonals, and U is an upper
40
+ # triangular matrix (note that this convention is different from the
41
+ # clapack_getrf behavior, but matches the standard LAPACK getrf).
42
+ # +A+ is overwritten with the elements of L and U (the unit
43
+ # diagonal elements of L are not saved). P is not returned directly and must be
44
+ # constructed from the pivot array ipiv. The row indices in ipiv are indexed
45
+ # starting from 1.
46
+ # Only works for dense matrices.
47
+ #
48
+ # * *Returns* :
49
+ # - The IPIV vector. The L and U matrices are stored in A.
50
+ # * *Raises* :
51
+ # - +StorageTypeError+ -> ATLAS functions only work on dense matrices.
52
+ #
53
+ def getrf!
54
+ ipiv = LUDecomposition.new(self.twoDMat).getPivot.to_a
55
+ return ipiv
56
+ end
57
+
58
+ #
59
+ # call-seq:
60
+ # geqrf! -> shape.min x 1 NMatrix
61
+ #
62
+ # QR factorization of a general M-by-N matrix +A+.
63
+ #
64
+ # The QR factorization is A = QR, where Q is orthogonal and R is Upper Triangular
65
+ # +A+ is overwritten with the elements of R and Q with Q being represented by the
66
+ # elements below A's diagonal and an array of scalar factors in the output NMatrix.
67
+ #
68
+ # The matrix Q is represented as a product of elementary reflectors
69
+ # Q = H(1) H(2) . . . H(k), where k = min(m,n).
70
+ #
71
+ # Each H(i) has the form
72
+ #
73
+ # H(i) = I - tau * v * v'
74
+ #
75
+ # http://www.netlib.org/lapack/explore-html/d3/d69/dgeqrf_8f.html
76
+ #
77
+ # Only works for dense matrices.
78
+ #
79
+ # * *Returns* :
80
+ # - Vector TAU. Q and R are stored in A. Q is represented by TAU and A
81
+ # * *Raises* :
82
+ # - +StorageTypeError+ -> LAPACK functions only work on dense matrices.
83
+ #
84
+ def geqrf!
85
+ # The real implementation is in lib/nmatrix/lapacke.rb
86
+ raise(NotImplementedError, "geqrf! requires the nmatrix-lapacke gem")
87
+ end
88
+
89
+ #
90
+ # call-seq:
91
+ # ormqr(tau) -> NMatrix
92
+ # ormqr(tau, side, transpose, c) -> NMatrix
93
+ #
94
+ # Returns the product Q * c or c * Q after a call to geqrf! used in QR factorization.
95
+ # +c+ is overwritten with the elements of the result NMatrix if supplied. Q is the orthogonal matrix
96
+ # represented by tau and the calling NMatrix
97
+ #
98
+ # Only works on float types, use unmqr for complex types.
99
+ #
100
+ # == Arguments
101
+ #
102
+ # * +tau+ - vector containing scalar factors of elementary reflectors
103
+ # * +side+ - direction of multiplication [:left, :right]
104
+ # * +transpose+ - apply Q with or without transpose [false, :transpose]
105
+ # * +c+ - NMatrix multplication argument that is overwritten, no argument assumes c = identity
106
+ #
107
+ # * *Returns* :
108
+ #
109
+ # - Q * c or c * Q Where Q may be transposed before multiplication.
110
+ #
111
+ #
112
+ # * *Raises* :
113
+ # - +StorageTypeError+ -> LAPACK functions only work on dense matrices.
114
+ # - +TypeError+ -> Works only on floating point matrices, use unmqr for complex types
115
+ # - +TypeError+ -> c must have the same dtype as the calling NMatrix
116
+ #
117
+ def ormqr(tau, side=:left, transpose=false, c=nil)
118
+ # The real implementation is in lib/nmatrix/lapacke.rb
119
+ raise(NotImplementedError, "ormqr requires the nmatrix-lapacke gem")
120
+
121
+ end
122
+
123
+ #
124
+ # call-seq:
125
+ # unmqr(tau) -> NMatrix
126
+ # unmqr(tau, side, transpose, c) -> NMatrix
127
+ #
128
+ # Returns the product Q * c or c * Q after a call to geqrf! used in QR factorization.
129
+ # +c+ is overwritten with the elements of the result NMatrix if it is supplied. Q is the orthogonal matrix
130
+ # represented by tau and the calling NMatrix
131
+ #
132
+ # Only works on complex types, use ormqr for float types.
133
+ #
134
+ # == Arguments
135
+ #
136
+ # * +tau+ - vector containing scalar factors of elementary reflectors
137
+ # * +side+ - direction of multiplication [:left, :right]
138
+ # * +transpose+ - apply Q as Q or its complex conjugate [false, :complex_conjugate]
139
+ # * +c+ - NMatrix multplication argument that is overwritten, no argument assumes c = identity
140
+ #
141
+ # * *Returns* :
142
+ #
143
+ # - Q * c or c * Q Where Q may be transformed to its complex conjugate before multiplication.
144
+ #
145
+ #
146
+ # * *Raises* :
147
+ # - +StorageTypeError+ -> LAPACK functions only work on dense matrices.
148
+ # - +TypeError+ -> Works only on floating point matrices, use unmqr for complex types
149
+ # - +TypeError+ -> c must have the same dtype as the calling NMatrix
150
+ #
151
+ def unmqr(tau, side=:left, transpose=false, c=nil)
152
+ # The real implementation is in lib/nmatrix/lapacke.rb
153
+ raise(NotImplementedError, "unmqr requires the nmatrix-lapacke gem")
154
+ end
155
+
156
+ #
157
+ # call-seq:
158
+ # potrf!(upper_or_lower) -> NMatrix
159
+ #
160
+ # Cholesky factorization of a symmetric positive-definite matrix -- or, if complex,
161
+ # a Hermitian positive-definite matrix +A+.
162
+ # The result will be written in either the upper or lower triangular portion of the
163
+ # matrix, depending on whether the argument is +:upper+ or +:lower+.
164
+ # Also the function only reads in the upper or lower part of the matrix,
165
+ # so it doesn't actually have to be symmetric/Hermitian.
166
+ # However, if the matrix (i.e. the symmetric matrix implied by the lower/upper
167
+ # half) is not positive-definite, the function will return nonsense.
168
+ #
169
+ # This functions requires either the nmatrix-atlas or nmatrix-lapacke gem
170
+ # installed.
171
+ #
172
+ # * *Returns* :
173
+ # the triangular portion specified by the parameter
174
+ # * *Raises* :
175
+ # - +StorageTypeError+ -> ATLAS functions only work on dense matrices.
176
+ # - +ShapeError+ -> Must be square.
177
+ # - +NotImplementedError+ -> If called without nmatrix-atlas or nmatrix-lapacke gem
178
+ #
179
+ def potrf!(which)
180
+ # The real implementation is in the plugin files.
181
+ cholesky = CholeskyDecomposition.new(self.twoDMat)
182
+ if which == :upper
183
+ u = create_dummy_nmatrix
184
+ twoDMat = cholesky.getLT
185
+ u.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1]))
186
+ return u
187
+ else
188
+ l = create_dummy_nmatrix
189
+ twoDMat = cholesky.getL
190
+ l.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1]))
191
+ return l
192
+ end
193
+ end
194
+
195
+ def potrf_upper!
196
+ potrf! :upper
197
+ end
198
+
199
+ def potrf_lower!
200
+ potrf! :lower
201
+ end
202
+
203
+
204
+ #
205
+ # call-seq:
206
+ # factorize_cholesky -> [upper NMatrix, lower NMatrix]
207
+ #
208
+ # Calculates the Cholesky factorization of a matrix and returns the
209
+ # upper and lower matrices such that A=LU and L=U*, where * is
210
+ # either the transpose or conjugate transpose.
211
+ #
212
+ # Unlike potrf!, this makes method requires that the original is matrix is
213
+ # symmetric or Hermitian. However, it is still your responsibility to make
214
+ # sure it is positive-definite.
215
+ def factorize_cholesky
216
+ # raise "Matrix must be symmetric/Hermitian for Cholesky factorization" unless self.hermitian?
217
+ cholesky = CholeskyDecomposition.new(self.twoDMat)
218
+ l = create_dummy_nmatrix
219
+ twoDMat = cholesky.getL
220
+ l.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1]))
221
+ u = create_dummy_nmatrix
222
+ twoDMat = cholesky.getLT
223
+ u.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1]))
224
+ return [u,l]
225
+ end
226
+
227
+ #
228
+ # call-seq:
229
+ # factorize_lu -> ...
230
+ #
231
+ # LU factorization of a matrix. Optionally return the permutation matrix.
232
+ # Note that computing the permutation matrix will introduce a slight memory
233
+ # and time overhead.
234
+ #
235
+ # == Arguments
236
+ #
237
+ # +with_permutation_matrix+ - If set to *true* will return the permutation
238
+ # matrix alongwith the LU factorization as a second return value.
239
+ #
240
+ def factorize_lu with_permutation_matrix=nil
241
+ raise(NotImplementedError, "only implemented for dense storage") unless self.stype == :dense
242
+ raise(NotImplementedError, "matrix is not 2-dimensional") unless self.dimensions == 2
243
+ t = self.clone
244
+ pivot = create_dummy_nmatrix
245
+ twoDMat = LUDecomposition.new(self.twoDMat).getP
246
+ pivot.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1]))
247
+ return [t,pivot]
248
+ end
249
+
250
+ #
251
+ # call-seq:
252
+ # factorize_qr -> [Q,R]
253
+ #
254
+ # QR factorization of a matrix without column pivoting.
255
+ # Q is orthogonal and R is upper triangular if input is square or upper trapezoidal if
256
+ # input is rectangular.
257
+ #
258
+ # Only works for dense matrices.
259
+ #
260
+ # * *Returns* :
261
+ # - Array containing Q and R matrices
262
+ #
263
+ # * *Raises* :
264
+ # - +StorageTypeError+ -> only implemented for desnse storage.
265
+ # - +ShapeError+ -> Input must be a 2-dimensional matrix to have a QR decomposition.
266
+ #
267
+ def factorize_qr
268
+
269
+ raise(NotImplementedError, "only implemented for dense storage") unless self.stype == :dense
270
+ raise(ShapeError, "Input must be a 2-dimensional matrix to have a QR decomposition") unless self.dim == 2
271
+ qrdecomp = QRDecomposition.new(self.twoDMat)
272
+
273
+ qmat = create_dummy_nmatrix
274
+ qtwoDMat = qrdecomp.getQ
275
+ qmat.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(qtwoDMat.getData, @shape[0], @shape[1]))
276
+
277
+ rmat = create_dummy_nmatrix
278
+ rtwoDMat = qrdecomp.getR
279
+ rmat.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(rtwoDMat.getData, @shape[0], @shape[1]))
280
+ return [qmat,rmat]
281
+
282
+ end
283
+
284
+ # Solve the matrix equation AX = B, where A is +self+, B is the first
285
+ # argument, and X is returned. A must be a nxn square matrix, while B must be
286
+ # nxm. Only works with dense matrices and non-integer, non-object data types.
287
+ #
288
+ # == Arguments
289
+ #
290
+ # * +b+ - the right hand side
291
+ #
292
+ # == Options
293
+ #
294
+ # * +form+ - Signifies the form of the matrix A in the linear system AX=B.
295
+ # If not set then it defaults to +:general+, which uses an LU solver.
296
+ # Other possible values are +:lower_tri+, +:upper_tri+ and +:pos_def+ (alternatively,
297
+ # non-abbreviated symbols +:lower_triangular+, +:upper_triangular+,
298
+ # and +:positive_definite+ can be used.
299
+ # If +:lower_tri+ or +:upper_tri+ is set, then a specialized linear solver for linear
300
+ # systems AX=B with a lower or upper triangular matrix A is used. If +:pos_def+ is chosen,
301
+ # then the linear system is solved via the Cholesky factorization.
302
+ # Note that when +:lower_tri+ or +:upper_tri+ is used, then the algorithm just assumes that
303
+ # all entries in the lower/upper triangle of the matrix are zeros without checking (which
304
+ # can be useful in certain applications).
305
+ #
306
+ #
307
+ # == Usage
308
+ #
309
+ # a = NMatrix.new [2,2], [3,1,1,2], dtype: dtype
310
+ # b = NMatrix.new [2,1], [9,8], dtype: dtype
311
+ # a.solve(b)
312
+ #
313
+ # # solve an upper triangular linear system more efficiently:
314
+ # require 'benchmark'
315
+ # require 'nmatrix/lapacke'
316
+ # rand_mat = NMatrix.random([10000, 10000], dtype: :float64)
317
+ # a = rand_mat.triu
318
+ # b = NMatrix.random([10000, 10], dtype: :float64)
319
+ # Benchmark.bm(10) do |bm|
320
+ # bm.report('general') { a.solve(b) }
321
+ # bm.report('upper_tri') { a.solve(b, form: :upper_tri) }
322
+ # end
323
+ # # user system total real
324
+ # # general 73.170000 0.670000 73.840000 ( 73.810086)
325
+ # # upper_tri 0.180000 0.000000 0.180000 ( 0.182491)
326
+ #
327
+ def solve(b, opts = {})
328
+ raise(ShapeError, "Must be called on square matrix") unless self.dim == 2 && self.shape[0] == self.shape[1]
329
+ raise(ShapeError, "number of rows of b must equal number of cols of self") if
330
+ self.shape[1] != b.shape[0]
331
+ raise(ArgumentError, "only works with dense matrices") if self.stype != :dense
332
+ raise(ArgumentError, "only works for non-integer, non-object dtypes") if
333
+ integer_dtype? or object_dtype? or b.integer_dtype? or b.object_dtype?
334
+
335
+ opts = { form: :general }.merge(opts)
336
+ x = b.clone
337
+ n = self.shape[0]
338
+ nrhs = b.shape[1]
339
+
340
+ nmatrix = create_dummy_nmatrix
341
+ case opts[:form]
342
+ when :general, :upper_tri, :upper_triangular, :lower_tri, :lower_triangular
343
+ #LU solver
344
+ solver = LUDecomposition.new(self.twoDMat).getSolver
345
+ nmatrix.s = solver.solve(b.s)
346
+ return nmatrix
347
+ when :pos_def, :positive_definite
348
+ solver = CholeskyDecomposition.new(self.twoDMat).getSolver
349
+ nmatrix.s = solver.solve(b.s)
350
+ return nmatrix
351
+ else
352
+ raise(ArgumentError, "#{opts[:form]} is not a valid form option")
353
+ end
354
+
355
+ end
356
+
357
+ #
358
+ # call-seq:
359
+ # det -> determinant
360
+ #
361
+ # Calculate the determinant by way of LU decomposition. This is accomplished
362
+ # using clapack_getrf, and then by taking the product of the diagonal elements. There is a
363
+ # risk of underflow/overflow.
364
+ #
365
+ # There are probably also more efficient ways to calculate the determinant.
366
+ # This method requires making a copy of the matrix, since clapack_getrf
367
+ # modifies its input.
368
+ #
369
+ # For smaller matrices, you may be able to use +#det_exact+.
370
+ #
371
+ # This function is guaranteed to return the same type of data in the matrix
372
+ # upon which it is called.
373
+ #
374
+ # Integer matrices are converted to floating point matrices for the purposes of
375
+ # performing the calculation, as xGETRF can't work on integer matrices.
376
+ #
377
+ # * *Returns* :
378
+ # - The determinant of the matrix. It's the same type as the matrix's dtype.
379
+ # * *Raises* :
380
+ # - +ShapeError+ -> Must be used on square matrices.
381
+ #
382
+ def det
383
+ raise(ShapeError, "determinant can be calculated only for square matrices") unless self.dim == 2 && self.shape[0] == self.shape[1]
384
+ self.det_exact2
385
+ end
386
+
387
+ #
388
+ # call-seq:
389
+ # complex_conjugate -> NMatrix
390
+ # complex_conjugate(new_stype) -> NMatrix
391
+ #
392
+ # Get the complex conjugate of this matrix. See also complex_conjugate! for
393
+ # an in-place operation (provided the dtype is already +:complex64+ or
394
+ # +:complex128+).
395
+ #
396
+ # Doesn't work on list matrices, but you can optionally pass in the stype you
397
+ # want to cast to if you're dealing with a list matrix.
398
+ #
399
+ # * *Arguments* :
400
+ # - +new_stype+ -> stype for the new matrix.
401
+ # * *Returns* :
402
+ # - If the original NMatrix isn't complex, the result is a +:complex128+ NMatrix. Otherwise, it's the original dtype.
403
+ #
404
+ def complex_conjugate(new_stype = self.stype)
405
+ self.cast(new_stype, NMatrix::upcast(dtype, :complex64)).complex_conjugate!
406
+ end
407
+
408
+ #
409
+ # call-seq:
410
+ # conjugate_transpose -> NMatrix
411
+ #
412
+ # Calculate the conjugate transpose of a matrix. If your dtype is already
413
+ # complex, this should only require one copy (for the transpose).
414
+ #
415
+ # * *Returns* :
416
+ # - The conjugate transpose of the matrix as a copy.
417
+ #
418
+ def conjugate_transpose
419
+ self.transpose.complex_conjugate!
420
+ end
421
+
422
+ #
423
+ # call-seq:
424
+ # absolute_sum -> Numeric
425
+ #
426
+ # == Arguments
427
+ # - +incx+ -> the skip size (defaults to 1, no skip)
428
+ # - +n+ -> the number of elements to include
429
+ #
430
+ # Return the sum of the contents of the vector. This is the BLAS asum routine.
431
+ def asum incx=1, n=nil
432
+ if self.shape == [1]
433
+ return self[0].abs unless self.complex_dtype?
434
+ return self[0].real.abs + self[0].imag.abs
435
+ end
436
+ return method_missing(:asum, incx, n) unless vector?
437
+ NMatrix::BLAS::asum(self, incx, self.size / incx)
438
+ end
439
+ alias :absolute_sum :asum
440
+
441
+ #
442
+ # call-seq:
443
+ # norm2 -> Numeric
444
+ #
445
+ # == Arguments
446
+ # - +incx+ -> the skip size (defaults to 1, no skip)
447
+ # - +n+ -> the number of elements to include
448
+ #
449
+ # Return the 2-norm of the vector. This is the BLAS nrm2 routine.
450
+ def nrm2 incx=1, n=nil
451
+ self.twoDMat.getFrobeniusNorm()
452
+ end
453
+ alias :norm2 :nrm2
454
+
455
+ #
456
+ # call-seq:
457
+ # scale! -> NMatrix
458
+ #
459
+ # == Arguments
460
+ # - +alpha+ -> Scalar value used in the operation.
461
+ # - +inc+ -> Increment used in the scaling function. Should generally be 1.
462
+ # - +n+ -> Number of elements of +vector+.
463
+ #
464
+ # This is a destructive method, modifying the source NMatrix. See also #scale.
465
+ # Return the scaling result of the matrix. BLAS scal will be invoked if provided.
466
+
467
+ def scale!(alpha, incx=1, n=nil)
468
+ #FIXME
469
+ # raise(DataTypeError, "Incompatible data type for the scaling factor") unless
470
+ # NMatrix::upcast(self.dtype, NMatrix::min_dtype(alpha)) == self.dtype
471
+ raise(DataTypeError, "Incompatible data type for the scaling factor") if
472
+ self.dtype == :int8
473
+ @s.mapMultiplyToSelf(alpha)
474
+ return self
475
+ end
476
+
477
+ #
478
+ # call-seq:
479
+ # scale -> NMatrix
480
+ #
481
+ # == Arguments
482
+ # - +alpha+ -> Scalar value used in the operation.
483
+ # - +inc+ -> Increment used in the scaling function. Should generally be 1.
484
+ # - +n+ -> Number of elements of +vector+.
485
+ #
486
+ # Return the scaling result of the matrix. BLAS scal will be invoked if provided.
487
+
488
+ def scale(alpha, incx=1, n=nil)
489
+ # FIXME
490
+ # raise(DataTypeError, "Incompatible data type for the scaling factor") unless
491
+ # NMatrix::upcast(self.dtype, NMatrix::min_dtype(alpha)) == self.dtype
492
+ raise(DataTypeError, "Incompatible data type for the scaling factor") if
493
+ self.dtype == :byte || self.dtype == :int8 || self.dtype == :int16 ||
494
+ self.dtype == :int32 || self.dtype == :int64
495
+ nmatrix = NMatrix.new :copy
496
+ nmatrix.shape = @shape.clone
497
+ nmatrix.s = ArrayRealVector.new(@s.toArray.clone).mapMultiplyToSelf(alpha)
498
+ return nmatrix
499
+ end
500
+
501
+ end