ruby-numo / numo-linalg

Linear Algebra Library for Ruby/Numo::NArray
BSD 3-Clause "New" or "Revised" License
38 stars 9 forks source link

Fix bug on the dot method that occurs when performing vector-matrix product #11

Closed yoshoku closed 6 years ago

yoshoku commented 6 years ago

Problem

I found a bug on the Numo::Linalg.dot method. The bug occurs when performing vector-matrix product:

> require ‘numo/linalg/autoloader’
=> true
> a=Numo::DFloat.new(3,5).rand
=> Numo::DFloat#shape=[3,5]
[[0.0617545, 0.373067, 0.794815, 0.201042, 0.116041],
 [0.344032, 0.539948, 0.737815, 0.165089, 0.0508827],
 [0.108065, 0.0687079, 0.904121, 0.478644, 0.342969]]
> b=Numo::DFloat.new(3).rand
=> Numo::DFloat#shape=[3]
[0.164541, 0.74603, 0.138994]
> b.dot(a)
=> Numo::DFloat#shape=[5]
[0.28184, 0.473752, 0.80688, 0, 0]

My environment running the above codes is as follows:

$ ruby -v
ruby 2.2.9p480 (2017-12-15 revision 61259) [x86_64-darwin17]
$ gem list | grep numo
numo-linalg (0.1.2)
numo-narray (0.9.1.2)

And I used Intel MKL and OpenBLAS for the background libraries.

Solution

When performing vector-matrix product, the Numo::Linalg.dot method calls the gemv function on BLAS with setting transpose option. Even if the transpose option is set, the gemv function does not need to invert the size of rows and columns of a matrix. However, because the size of rows and columns are inverted on another line, the bug occurs. Thus, I added a code to invert the size of rows and columns just before the gemv function is called.

Test

I confirmed that the bug was fixed and a new bug was not introduced in matrix-vector product.

> require 'numo/linalg/autoloader'
=> true
> a=Numo::DFloat.new(3,5).rand
=> Numo::DFloat#shape=[3,5]
[[0.0617545, 0.373067, 0.794815, 0.201042, 0.116041],
 [0.344032, 0.539948, 0.737815, 0.165089, 0.0508827],
 [0.108065, 0.0687079, 0.904121, 0.478644, 0.342969]]
> b=Numo::DFloat.new(3).rand
=> Numo::DFloat#shape=[3]
[0.164541, 0.74603, 0.138994]
> b.dot(a)
=> Numo::DFloat#shape=[5]
[0.28184, 0.473752, 0.80688, 0.222769, 0.104724]
> a.transpose.dot(b)
=> Numo::DFloat#shape=[5]
[0.28184, 0.473752, 0.80688, 0.222769, 0.104724]