SciRuby / nmatrix

Dense and sparse linear algebra library for Ruby via SciRuby
Other
469 stars 133 forks source link

There is a method in nmatrix for matrix exponential? #622

Open seoanezonjic opened 5 years ago

seoanezonjic commented 5 years ago

I need to use the matrix exponential operation as can be seen here: https://www.mathworks.com/help/matlab/ref/expm.html There is a method for this operation in nmatrix? If is not, how can I implement it using the nmatrix methods? Thanks in advance

translunar commented 5 years ago

I don't believe we've implemented one. I think the pseudocode for doing so is right there in the Matlab docs, so I'd be eager to get a pull request for it. (expm(X) = V*diag(exp(diag(D)))/V)

I also have code for a separate matrix exponential, for computing rotations, so if that's what you're looking for, I can point you that way. (It's in Python right now, and possibly has a bug.)

seoanezonjic commented 5 years ago

Yeah the pseudocode is that but V and D are given for this matlab function: [V,D] = eig(X) The documentation is in https://es.mathworks.com/help/matlab/ref/eig.html . I cannot find which methods in nmatrix are equivalent to this eig(). I'm new handling nmatrix and the tutorials don't cover this kind of topics. If you can point me which methods are equivalent to matlab's I can code this function myself. Furthermore, I'm working in an investigation project developed only in ruby, so I need the nmatrix implementation. Thanks in advance

translunar commented 5 years ago

The method you're looking for is from lapack and atlas. It's called geev.

You could look in:

The methods are documented elsewhere, but I find the specs are pretty good for seeing them actually used.

seoanezonjic commented 5 years ago

I have installed nmatrix-lapacke to implement the matlab method but I have the following problem, when I use the method geev as: eigenvalues, vl, vr = NMatrix::LAPACK.geev(nmatrix_object) I have the following error: geev requires either the nmatrix-atlas or nmatrix-lapack gem (NotImplementedError) So, I added to my script this require: require 'nmatrix-lapacke' but it breaks with the following error: require': cannot load such file -- nmatrix-lapacke (LoadError) When I do a gem list, the gem is listed:

backports (3.11.4)
bigdecimal (default: 1.3.0)
bundler (1.16.1)
colorize (0.8.1)
io-console (default: 0.4.6)
json (default: 2.0.2)
nmatrix (0.2.4)
nmatrix-lapacke (0.2.4)
openssl (default: 2.0.3)
packable (1.3.10)
pp (0.1.1)
psych (default: 2.2.2)
rake (12.3.1)
rdoc (default: 5.0.0)

Both gems, nmatrix and nmatrix-lapacke are installed using gem install. How the libraries must be loaded? and how the methods must be invoked?

translunar commented 5 years ago

I believe you want require "nmatrix/lapacke" and require "nmatrix/atlas".

seoanezonjic commented 5 years ago

I have tested the require that you suggest to me and now I have de following error:

/mnt/home/soft/rvm/.rvm/rubies/ruby-2.4.1/lib64/ruby/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:133:in `require': /mnt/home/users/pab_001_uma/pedro/.gem/ruby/2.4.1/gems/nmatrix-lapacke-0.2.4/lib/nmatrix_lapacke.so: undefined symbol: cblas_ctrsm - /mnt/home/users/pab_001_uma/pedro/.gem/ruby/2.4.1/gems/nmatrix-lapacke-0.2.4/lib/nmatrix_lapacke.so (LoadError)
    from /mnt/home/soft/rvm/.rvm/rubies/ruby-2.4.1/lib64/ruby/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:133:in `rescue in require'
    from /mnt/home/soft/rvm/.rvm/rubies/ruby-2.4.1/lib64/ruby/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:40:in `require'
    from /mnt/home/users/pab_001_uma/pedro/.gem/ruby/2.4.1/gems/nmatrix-lapacke-0.2.4/lib/nmatrix/lapacke.rb:35:in `<top (required)>'
    from /mnt/home/soft/rvm/.rvm/rubies/ruby-2.4.1/lib64/ruby/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:133:in `require'
    from /mnt/home/soft/rvm/.rvm/rubies/ruby-2.4.1/lib64/ruby/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:133:in `rescue in require'
    from /mnt/home/soft/rvm/.rvm/rubies/ruby-2.4.1/lib64/ruby/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:40:in `require'
    from ../ruby_code/kernels.rb:3:in `<main>'

My sysadmim has perform a deep research and he has checked the libraries with ldd:

ldd ~/.gem/ruby/2.4.1/gems/nmatrix-lapacke-0.2.4/lib/nmatrix_lapacke.so
    linux-vdso.so.1 (0x00007ffe02b7e000)
    libruby.so.2.4 => /mnt/home/soft/rvm/.rvm/rubies/ruby-2.4.1/lib64/libruby.so.2.4 (0x00007faeeec05000)
    liblapack.so => /mnt/home/soft/scalapack/res/lapack/3.4.2/lib/liblapack.so (0x00007faeee266000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00007faeee02d000)
    libgmp.so.10 => /usr/lib64/libgmp.so.10 (0x00007faeedda6000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007faeedba1000)
    libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007faeed966000)
    libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007faeed5dd000)
    libm.so.6 => /lib64/libm.so.6 (0x00007faeed2df000)
    libc.so.6 => /lib64/libc.so.6 (0x00007faeecf3a000)
    libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007faeecd23000)
    /lib64/ld-linux-x86-64.so.2 (0x0000562137d69000)
    libblas.so => /mnt/home/soft/scalapack/res/lapack/3.4.2/lib/libblas.so (0x00007faeeca9f000)
    libimf.so => /mnt/home/soft/intel/programs/x86_64/composer_xe_2013.1.117/ipp/../compiler/lib/intel64/libimf.so (0x00007faeec5e3000)
    libifport.so.5 => /mnt/home/soft/intel/programs/x86_64/composer_xe_2013.1.117/ipp/../compiler/lib/intel64/libifport.so.5 (0x00007faeec3b4000)
    libifcore.so.5 => /mnt/home/soft/intel/programs/x86_64/composer_xe_2013.1.117/ipp/../compiler/lib/intel64/libifcore.so.5 (0x00007faeec07d000)
    libsvml.so => /mnt/home/soft/intel/programs/x86_64/composer_xe_2013.1.117/ipp/../compiler/lib/intel64/libsvml.so (0x00007faeeb7af000)
    libintlc.so.5 => /mnt/home/soft/intel/programs/x86_64/composer_xe_2013.1.117/ipp/../compiler/lib/intel64/libintlc.so.5 (0x00007faeeb560000)

What can be happening with this? Thank you for your attention

translunar commented 5 years ago

Have you followed the instructions on our wiki for installing ATLAS, lapacke, the gems, etc? It looks like you've got two versions installed and it's finding the wrong ones.

seoanezonjic commented 5 years ago

Hi all In the last months I have received other work to finish, so it was impossible to me with nmatrix. Now, I can work in this project without problem. I fix the installation problem with the following commands:

gem install nmatrix -- --with-ldflags"=-lopenblas" 
gem install nmatrix-lapacke -- --with-ldflags"=$LDFLAGS" 

With these lines, nmatrix installs succesfully. Also, I've implemented the exponetial matrix as follows (with the matlab documentation):

matrix = NMatrix.new([3, 3],[1, 1, 0, 0, 0, 2, 0, 0, -1], dtype: :float32)
eigenvalues, eigenvectors = NMatrix::LAPACK.geev(matrix, :right)
eigenvalues.map!{|val| Math.exp(val)}
numerator = eigenvectors.dot(NMatrix.diagonal(eigenvalues, dtype: :float32))
matrix_result = numerator.dot(eigenvectors.pinv) #Matrix division A/B => A.dot(B.pinv) 

With the toy example this code works, but when I use a bigger real matrix the Math.exp complains by receive complex numbers. How I can deal with this problem? There is another aproximation as power series or something? Thank you in advance

abourque72 commented 4 years ago

You could do a check for when val is complex. Say val = a+bi. Then exp(val) = exp(a) (cos(b) + i sin(b)). Lemme know if you find this useful.