nmatrix 0.2.3 → 0.2.4

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.
@@ -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