diff --git a/.standard.yml b/.standard.yml new file mode 100644 index 00000000..aec4258c --- /dev/null +++ b/.standard.yml @@ -0,0 +1,3 @@ +fix: true +parallel: true +format: progress diff --git a/.travis.yml b/.travis.yml index a81c0fbb..f1327471 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,9 @@ before_install: ./travis.sh before_install install: ./travis.sh install -script: ./travis.sh script +script: + - ./travis.sh script + - bundle exec rake standard # Define extra configurations to add to the build matrix. # The idea here is that the USE_ATLAS=1 option should exercise all the ruby @@ -48,7 +50,7 @@ matrix: - rvm: jruby-9.0.5.0 env: USE_OPENBLAS=1 - rvm: jruby-9.0.5.0 - env: USE_REF=1 + env: USE_REF=1 # NOTE: The following two ruby versions on OSX are currently unavailable - os: osx rvm: 2.0.0-p648 diff --git a/Gemfile b/Gemfile index 1fc5029f..b355624e 100644 --- a/Gemfile +++ b/Gemfile @@ -1,10 +1,10 @@ -source 'https://rubygems.org' +source "https://rubygems.org" -#main gemspec -gemspec :name => 'nmatrix' +# main gemspec +gemspec name: "nmatrix" -#plugin gemspecs -Dir['nmatrix-*.gemspec'].each do |gemspec_file| +# plugin gemspecs +Dir["nmatrix-*.gemspec"].each do |gemspec_file| plugin_name = gemspec_file.match(/(nmatrix-.*)\.gemspec/)[1] - gemspec(:name => plugin_name, :development_group => :plugin) + gemspec(name: plugin_name, development_group: :plugin) end diff --git a/Rakefile b/Rakefile index b7e36b7b..7f57b4a7 100644 --- a/Rakefile +++ b/Rakefile @@ -1,21 +1,20 @@ -# -*- ruby -*- - -require 'rubygems' -require 'rubygems/package_task' -require 'bundler' - -#Specify plugins to build on the command line like: -#rake whatever nmatrix_plugins=atlas,lapacke -#or -#rake whatever nmatrix_plugins=all -#If you want to build *only* plugins and not the core nmatrix gem: -#rake whatever nmatrix_plugins=all nmatrix_core=false +require "rubygems" +require "rubygems/package_task" +require "bundler" +require "standard/rake" + +# Specify plugins to build on the command line like: +# rake whatever nmatrix_plugins=atlas,lapacke +# or +# rake whatever nmatrix_plugins=all +# If you want to build *only* plugins and not the core nmatrix gem: +# rake whatever nmatrix_plugins=all nmatrix_core=false if ENV["nmatrix_plugins"] == "all" gemspecs = Dir["*.gemspec"] else plugins = [] plugins = ENV["nmatrix_plugins"].split(",") if ENV["nmatrix_plugins"] - gemspecs = ["nmatrix.gemspec"] #always include the main nmatrix gem + gemspecs = ["nmatrix.gemspec"] # always include the main nmatrix gem plugins.each do |plugin| gemspecs << "nmatrix-#{plugin}.gemspec" end @@ -28,20 +27,20 @@ gemspecs.map! { |gemspec| eval(IO.read(gemspec)) } begin Bundler.setup(:default, :development) rescue Bundler::BundlerError => e - $stderr.puts e.message - $stderr.puts "Run `bundle install` to install missing gems" + warn e.message + warn "Run `bundle install` to install missing gems" exit e.status_code end desc "Build and install into system gems." -task :install => :repackage do +task install: :repackage do gemspecs.each do |gemspec| gem_file = "pkg/#{gemspec.name}-#{gemspec.version}.gem" system "gem install '#{gem_file}'" end end -require 'rake' +require "rake" require "rake/extensiontask" gemspecs.each do |gemspec| @@ -51,7 +50,7 @@ gemspecs.each do |gemspec| Rake::ExtensionTask.new do |ext| ext.name = ext_name ext.ext_dir = "ext/#{ext_name}" - ext.lib_dir = 'lib/' + ext.lib_dir = "lib/" ext.source_pattern = "**/*.{c,cpp,h}" end end @@ -61,98 +60,93 @@ gemspecs.each do |gemspec| Gem::PackageTask.new(gemspec).define end -require 'rspec/core/rake_task' -require 'rspec/core' +require "rspec/core/rake_task" +require "rspec/core" namespace :spec do - #We need a separate rake task for each plugin, rather than one big task that - #runs all of the specs. This is because there's no way to tell rspec - #to run the specs in a certain order with (say) "nmatrix/atlas" require'd - #for some of the specs, but not for others, without splitting them up like - #this. + # We need a separate rake task for each plugin, rather than one big task that + # runs all of the specs. This is because there's no way to tell rspec + # to run the specs in a certain order with (say) "nmatrix/atlas" require'd + # for some of the specs, but not for others, without splitting them up like + # this. spec_tasks = [] gemspecs.each do |gemspec| test_files = gemspec.test_files test_files.keep_if { |file| file =~ /_spec\.rb$/ } - test_files -= ['spec/nmatrix_yale_spec.rb', 'spec/blas_spec.rb', 'spec/lapack_core_spec.rb'] if /java/ === RUBY_PLATFORM + test_files -= ["spec/nmatrix_yale_spec.rb", "spec/blas_spec.rb", "spec/lapack_core_spec.rb"] if /java/ === RUBY_PLATFORM next if test_files.empty? spec_tasks << gemspec.name RSpec::Core::RakeTask.new(gemspec.name) do |spec| spec.pattern = FileList.new(test_files) end end - task :all => spec_tasks + task all: spec_tasks end +task spec: "spec:all" - -task :spec => "spec:all" - -BASEDIR = Pathname( __FILE__ ).dirname.relative_path_from( Pathname.pwd ) -SPECDIR = BASEDIR + 'spec' +BASEDIR = Pathname(__FILE__).dirname.relative_path_from(Pathname.pwd) +SPECDIR = BASEDIR + "spec" VALGRIND_OPTIONS = [ - "--tool=memcheck", - #"--leak-check=yes", - "--num-callers=15", - #"--error-limit=no", - "--partial-loads-ok=yes", - "--undef-value-errors=no" #, - #"--dsymutil=yes" + "--tool=memcheck", + # "--leak-check=yes", + "--num-callers=15", + # "--error-limit=no", + "--partial-loads-ok=yes", + "--undef-value-errors=no", # , + # "--dsymutil=yes" ] CALLGRIND_OPTIONS = [ - "--tool=callgrind", - "--dump-instr=yes", - "--simulate-cache=yes", - "--collect-jumps=yes" + "--tool=callgrind", + "--dump-instr=yes", + "--simulate-cache=yes", + "--collect-jumps=yes", ] VALGRIND_MEMORYFILL_OPTIONS = [ - "--freelist-vol=100000000", - "--malloc-fill=6D", - "--free-fill=66 ", + "--freelist-vol=100000000", + "--malloc-fill=6D", + "--free-fill=66 ", ] GDB_OPTIONS = [] - task :console do |task| - cmd = [ 'irb', "-r './lib/nmatrix.rb'" ] - run *cmd + run("irb", "-r './lib/nmatrix.rb'") end task :pry do |task| - cmd = [ 'pry', "-r './lib/nmatrix.rb'" ] - run *cmd + run("pry", "-r './lib/nmatrix.rb'") end namespace :pry do - task :valgrind => [ :compile ] do |task| - cmd = [ 'valgrind' ] + VALGRIND_OPTIONS - cmd += ['ruby', '-Ilib:ext', "-r './lib/nmatrix.rb'", "-r 'pry'", "-e 'binding.pry'"] - run *cmd + task valgrind: [:compile] do |task| + cmd = ["valgrind"] + VALGRIND_OPTIONS + cmd += ["ruby", "-Ilib:ext", "-r './lib/nmatrix.rb'", "-r 'pry'", "-e 'binding.pry'"] + run(*cmd) end end namespace :console do - CONSOLE_CMD = ['irb', "-r './lib/nmatrix.rb'"] + CONSOLE_CMD = ["irb", "-r './lib/nmatrix.rb'"] desc "Run console under GDB." - task :gdb => [ :compile ] do |task| - cmd = [ 'gdb' ] + GDB_OPTIONS - cmd += [ '--args' ] - cmd += CONSOLE_CMD - run( *cmd ) + task gdb: [:compile] do |task| + cmd = ["gdb"] + GDB_OPTIONS + cmd += ["--args"] + cmd += CONSOLE_CMD + run(*cmd) end desc "Run console under Valgrind." - task :valgrind => [ :compile ] do |task| - cmd = [ 'valgrind' ] + VALGRIND_OPTIONS - cmd += CONSOLE_CMD - run( *cmd ) + task valgrind: [:compile] do |task| + cmd = ["valgrind"] + VALGRIND_OPTIONS + cmd += CONSOLE_CMD + run(*cmd) end end -task :default => :spec +task default: :spec def run *cmd sh(cmd.join(" ")) @@ -163,58 +157,55 @@ namespace :spec do # spurious (and eminently ignorable) warnings from the ruby # interpreter - RSPEC_CMD = [ 'ruby', '-S', 'rspec', '-Ilib:ext', SPECDIR.to_s ] + RSPEC_CMD = ["ruby", "-S", "rspec", "-Ilib:ext", SPECDIR.to_s] - #desc "Run the spec for generator.rb" - #task :generator do |task| + # desc "Run the spec for generator.rb" + # task :generator do |task| # run 'rspec spec/generator_spec.rb' - #end + # end desc "Run specs under GDB." - task :gdb => [ :compile ] do |task| - cmd = [ 'gdb' ] + GDB_OPTIONS - cmd += [ '--args' ] + task gdb: [:compile] do |task| + cmd = ["gdb"] + GDB_OPTIONS + cmd += ["--args"] cmd += RSPEC_CMD - run( *cmd ) + run(*cmd) end desc "Run specs under cgdb." - task :cgdb => [ :compile ] do |task| - cmd = [ 'cgdb' ] + GDB_OPTIONS - cmd += [ '--args' ] + task cgdb: [:compile] do |task| + cmd = ["cgdb"] + GDB_OPTIONS + cmd += ["--args"] cmd += RSPEC_CMD - run( *cmd ) + run(*cmd) end desc "Run specs under Valgrind." - task :valgrind => [ :compile ] do |task| - cmd = [ 'valgrind' ] + VALGRIND_OPTIONS + task valgrind: [:compile] do |task| + cmd = ["valgrind"] + VALGRIND_OPTIONS cmd += RSPEC_CMD - run( *cmd ) + run(*cmd) end desc "Run specs under Callgrind." - task :callgrind => [ :compile ] do |task| - cmd = [ 'valgrind' ] + CALLGRIND_OPTIONS + task callgrind: [:compile] do |task| + cmd = ["valgrind"] + CALLGRIND_OPTIONS cmd += RSPEC_CMD - run( *cmd ) + run(*cmd) end - end - -LEAKCHECK_CMD = [ 'ruby', '-Ilib:ext', "#{SPECDIR}/leakcheck.rb" ] - +LEAKCHECK_CMD = ["ruby", "-Ilib:ext", "#{SPECDIR}/leakcheck.rb"] desc "Run leakcheck script." -task :leakcheck => [ :compile ] do |task| - cmd = [ 'valgrind' ] + VALGRIND_OPTIONS +task leakcheck: [:compile] do |task| + cmd = ["valgrind"] + VALGRIND_OPTIONS cmd += LEAKCHECK_CMD - run( *cmd ) + run(*cmd) end namespace :clean do - #the generated Makefile doesn't have a soclean target, should this be removed? + # the generated Makefile doesn't have a soclean target, should this be removed? task :so do |task| gemspecs.each do |gemspec| next unless gemspec.extensions @@ -222,10 +213,10 @@ namespace :clean do ext_name = extconf.match(/ext\/(.*)\/extconf\.rb/)[1] tmp_path = "tmp/#{RUBY_PLATFORM}/#{ext_name}/#{RUBY_VERSION}" chdir tmp_path do - if RUBY_PLATFORM =~ /mswin/ + if RUBY_PLATFORM.match?(/mswin/) `nmake soclean` else - mkcmd = ENV['MAKE'] || %w[gmake make].find { |c| system("#{c} -v >> /dev/null 2>&1") } + mkcmd = ENV["MAKE"] || %w[gmake make].find { |c| system("#{c} -v >> /dev/null 2>&1") } `#{mkcmd} soclean` end end @@ -234,13 +225,12 @@ namespace :clean do end end - desc "Check the manifest for correctness" task :check_manifest do |task| manifest_files = File.read("Manifest.txt").split git_files = `git ls-files |grep -v 'spec/'`.split - ignore_files = %w{.gitignore .rspec ext/nmatrix/binary_format.txt scripts/ttable_helper.rb} + ignore_files = %w[.gitignore .rspec ext/nmatrix/binary_format.txt scripts/ttable_helper.rb] possible_files = git_files - ignore_files @@ -260,14 +250,13 @@ task :check_manifest do |task| if extra_files.empty? && missing_files.empty? STDERR.puts "Manifest looks good!" end - end require "rdoc/task" -#separate out docs for plugins? +# separate out docs for plugins? RDoc::Task.new do |rdoc| rdoc.main = "README.rdoc" - rdoc.rdoc_files.include(%w{README.rdoc History.txt LICENSE.txt CONTRIBUTING.md lib ext}) + rdoc.rdoc_files.include(%w[README.rdoc History.txt LICENSE.txt CONTRIBUTING.md lib ext]) rdoc.options << "--exclude=ext/nmatrix/extconf.rb" rdoc.options << "--exclude=ext/nmatrix_atlas/extconf.rb" rdoc.options << "--exclude=ext/nmatrix/ttable_helper.rb" @@ -277,8 +266,7 @@ end # jruby tasks namespace :jruby do - - PROJECT_DIR = File.expand_path(".",Dir.pwd) + PROJECT_DIR = File.expand_path(".", Dir.pwd) BUILD_DIR = "build" CLASSES_DIR = "../build/classes" @@ -290,37 +278,37 @@ namespace :jruby do jars = Dir["#{VENDOR_DIR}/*.jar"] - desc 'Compile java classes' + desc "Compile java classes" task :javac do - unless RUBY_PLATFORM == 'java' - abort 'Please run with JRuby' + unless RUBY_PLATFORM == "java" + abort "Please run with JRuby" end sh "mkdir -p #{JRUBY_DIR}/build/classes" Dir.chdir("#{JRUBY_DIR}/nmatrix") - classes = Dir['**/*.java'] - sh "javac -classpath #{jars.join(':')} -d #{CLASSES_DIR} #{classes.join(' ')}" + classes = Dir["**/*.java"] + sh "javac -classpath #{jars.join(":")} -d #{CLASSES_DIR} #{classes.join(" ")}" end - desc 'Package java classes in a jar file' + desc "Package java classes in a jar file" task :jar do - unless RUBY_PLATFORM == 'java' - abort 'Please run with JRuby' + unless RUBY_PLATFORM == "java" + abort "Please run with JRuby" end sh "mkdir -p #{TARGET_DIR}" Dir.chdir("#{JRUBY_DIR}/build/classes") - classes = Dir['**/*.class'] - sh "jar -cf #{TARGET_DIR}/nmatrix.jar #{classes.join(' ')}" + classes = Dir["**/*.class"] + sh "jar -cf #{TARGET_DIR}/nmatrix.jar #{classes.join(" ")}" end - task :all => [:javac, :jar] + task all: [:javac, :jar] end desc "Compile java classes and Package them in a jar file" -task :jruby => 'jruby:all' +task jruby: "jruby:all" namespace :travis do task :env do - if /java/ === RUBY_PLATFORM + if /java/.match?(RUBY_PLATFORM) puts "Building for jruby" sh "mkdir ext/nmatrix_java/vendor" puts "Downloading tar file." @@ -340,7 +328,7 @@ namespace :travis do puts "- #{name}: #{ENV[name]}" end - require 'rbconfig' + require "rbconfig" puts "\n# RbConfig::MAKEFILE_CONFIG values:" %w[ CC CXX CPPFLAGS CFLAGS CXXFLAGS @@ -348,7 +336,7 @@ namespace :travis do puts "- #{name}: #{RbConfig::MAKEFILE_CONFIG[name]}" end - cc = RbConfig::MAKEFILE_CONFIG['CC'] + cc = RbConfig::MAKEFILE_CONFIG["CC"] puts "\n$ #{cc} -v\n#{`#{cc} -v 2>&1`}" end end diff --git a/ext/nmatrix/extconf.rb b/ext/nmatrix/extconf.rb index f321c382..d46dd02e 100644 --- a/ext/nmatrix/extconf.rb +++ b/ext/nmatrix/extconf.rb @@ -28,43 +28,43 @@ require File.expand_path("../../../lib/nmatrix/mkmf", __FILE__) $INSTALLFILES = [ - ['nmatrix.h' , '$(archdir)'], - ['nmatrix.hpp' , '$(archdir)'], - ['nmatrix_config.h', '$(archdir)'], - ['nm_memory.h' , '$(archdir)'], - ['ruby_constants.h', '$(archdir)'] + ["nmatrix.h", "$(archdir)"], + ["nmatrix.hpp", "$(archdir)"], + ["nmatrix_config.h", "$(archdir)"], + ["nm_memory.h", "$(archdir)"], + ["ruby_constants.h", "$(archdir)"], ] -if /cygwin|mingw/ =~ RUBY_PLATFORM - $INSTALLFILES << ['libnmatrix.a', '$(archdir)'] +if /cygwin|mingw/.match?(RUBY_PLATFORM) + $INSTALLFILES << ["libnmatrix.a", "$(archdir)"] end $DEBUG = true -$CFLAGS = ["-Wall -Werror=return-type",$CFLAGS].join(" ") -$CXXFLAGS = ["-Wall -Werror=return-type",$CXXFLAGS].join(" ") -$CPPFLAGS = ["-Wall -Werror=return-type",$CPPFLAGS].join(" ") +$CFLAGS = ["-Wall -Werror=return-type", $CFLAGS].join(" ") +$CXXFLAGS = ["-Wall -Werror=return-type", $CXXFLAGS].join(" ") +$CPPFLAGS = ["-Wall -Werror=return-type", $CPPFLAGS].join(" ") # When adding objects here, make sure their directories are included in CLEANOBJS down at the bottom of extconf.rb. -basenames = %w{nmatrix ruby_constants data/data util/io math util/sl_list storage/common storage/storage storage/dense/dense storage/yale/yale storage/list/list} +basenames = %w[nmatrix ruby_constants data/data util/io math util/sl_list storage/common storage/storage storage/dense/dense storage/yale/yale storage/list/list] $objs = basenames.map { |b| "#{b}.o" } $srcs = basenames.map { |b| "#{b}.cpp" } -#$libs += " -lprofiler " +# $libs += " -lprofiler " create_conf_h("nmatrix_config.h") create_makefile("nmatrix") -Dir.mkdir("data") unless Dir.exists?("data") -Dir.mkdir("util") unless Dir.exists?("util") -Dir.mkdir("storage") unless Dir.exists?("storage") +Dir.mkdir("data") unless Dir.exist?("data") +Dir.mkdir("util") unless Dir.exist?("util") +Dir.mkdir("storage") unless Dir.exist?("storage") Dir.chdir("storage") do - Dir.mkdir("yale") unless Dir.exists?("yale") - Dir.mkdir("list") unless Dir.exists?("list") - Dir.mkdir("dense") unless Dir.exists?("dense") + Dir.mkdir("yale") unless Dir.exist?("yale") + Dir.mkdir("list") unless Dir.exist?("list") + Dir.mkdir("dense") unless Dir.exist?("dense") end # to clean up object files in subdirectories: -open('Makefile', 'a') do |f| - clean_objs_paths = %w{data storage storage/dense storage/yale storage/list util}.map { |d| "#{d}/*.#{CONFIG["OBJEXT"]}" } - f.write("CLEANOBJS := $(CLEANOBJS) #{clean_objs_paths.join(' ')}") +open("Makefile", "a") do |f| + clean_objs_paths = %w[data storage storage/dense storage/yale storage/list util].map { |d| "#{d}/*.#{CONFIG["OBJEXT"]}" } + f.write("CLEANOBJS := $(CLEANOBJS) #{clean_objs_paths.join(" ")}") end diff --git a/ext/nmatrix_atlas/extconf.rb b/ext/nmatrix_atlas/extconf.rb index bd4a08a3..0737cf5c 100644 --- a/ext/nmatrix_atlas/extconf.rb +++ b/ext/nmatrix_atlas/extconf.rb @@ -27,20 +27,20 @@ require "nmatrix/mkmf" -#$INSTALLFILES = [['nmatrix.h', '$(archdir)'], ['nmatrix.hpp', '$(archdir)'], ['nmatrix_config.h', '$(archdir)'], ['nm_memory.h', '$(archdir)']] -if /cygwin|mingw/ =~ RUBY_PLATFORM - #$INSTALLFILES << ['libnmatrix.a', '$(archdir)'] +# $INSTALLFILES = [['nmatrix.h', '$(archdir)'], ['nmatrix.hpp', '$(archdir)'], ['nmatrix_config.h', '$(archdir)'], ['nm_memory.h', '$(archdir)']] +if /cygwin|mingw/.match?(RUBY_PLATFORM) + # $INSTALLFILES << ['libnmatrix.a', '$(archdir)'] end $DEBUG = true -#not the right way to add this include directory -$CFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix",$CFLAGS].join(" ") -$CXXFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix",$CXXFLAGS].join(" ") -$CPPFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix",$CPPFLAGS].join(" ") +# not the right way to add this include directory +$CFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix", $CFLAGS].join(" ") +$CXXFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix", $CXXFLAGS].join(" ") +$CPPFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix", $CPPFLAGS].join(" ") # When adding objects here, make sure their directories are included in CLEANOBJS down at the bottom of extconf.rb. # Why not just autogenerate this list from all .c/.cpp files in directory? -basenames = %w{nmatrix_atlas math_atlas} +basenames = %w[nmatrix_atlas math_atlas] $objs = basenames.map { |b| "#{b}.o" } $srcs = basenames.map { |b| "#{b}.cpp" } @@ -48,7 +48,7 @@ # --with-atlas-lib or --with-atlas-include and tell the compiler where to look # for ATLAS. The same for all the others # -#dir_config("clapack", ["/usr/local/atlas/include"], []) +# dir_config("clapack", ["/usr/local/atlas/include"], []) # # @@ -60,14 +60,14 @@ idefaults = {lapack: ["/usr/include/atlas"], cblas: ["/usr/local/atlas/include", "/usr/include/atlas"], - atlas: ["/usr/local/atlas/include", "/usr/include/atlas"]} + atlas: ["/usr/local/atlas/include", "/usr/include/atlas"],} # For some reason, if we try to look for /usr/lib64/atlas on a Mac OS X Mavericks system, and the directory does not # exist, it will give a linker error -- even if the lib dir is already correctly included with -L. So we need to check # that Dir.exists?(d) for each. -ldefaults = {lapack: ["/usr/local/lib", "/usr/local/atlas/lib", "/usr/lib64/atlas"].delete_if { |d| !Dir.exists?(d) }, - cblas: ["/usr/local/lib", "/usr/local/atlas/lib", "/usr/lib64/atlas"].delete_if { |d| !Dir.exists?(d) }, - atlas: ["/usr/local/lib", "/usr/local/atlas/lib", "/usr/lib", "/usr/lib64/atlas"].delete_if { |d| !Dir.exists?(d) }} +ldefaults = {lapack: ["/usr/local/lib", "/usr/local/atlas/lib", "/usr/lib64/atlas"].delete_if { |d| !Dir.exist?(d) }, + cblas: ["/usr/local/lib", "/usr/local/atlas/lib", "/usr/lib64/atlas"].delete_if { |d| !Dir.exist?(d) }, + atlas: ["/usr/local/lib", "/usr/local/atlas/lib", "/usr/lib", "/usr/lib64/atlas"].delete_if { |d| !Dir.exist?(d) },} if have_library("clapack") # Usually only applies for Mac OS X $libs += " -lclapack " @@ -94,7 +94,6 @@ have_header("clapack.h") end - # Although have_func is supposed to take a list as its second argument, I find that it simply # applies a :to_s to the second arg and doesn't actually check each one. We may want to put # have_func calls inside an :each block which checks atlas/clapack.h, cblas.h, clapack.h, and @@ -105,20 +104,20 @@ have_func("cblas_dgemm", "cblas.h") -#have_func("rb_scan_args", "ruby.h") +# have_func("rb_scan_args", "ruby.h") -#find_library("lapack", "clapack_dgetrf") -#find_library("cblas", "cblas_dgemm") -#find_library("atlas", "ATL_dgemmNN") +# find_library("lapack", "clapack_dgetrf") +# find_library("cblas", "cblas_dgemm") +# find_library("atlas", "ATL_dgemmNN") # Order matters here: ATLAS has to go after LAPACK: http://mail.scipy.org/pipermail/scipy-user/2007-January/010717.html $libs += " -llapack -lcblas -latlas " -#$libs += " -lprofiler " +# $libs += " -lprofiler " create_conf_h("nmatrix_atlas_config.h") create_makefile("nmatrix_atlas") # to clean up object files in subdirectories: -open('Makefile', 'a') do |f| - clean_objs_paths = %w{ }.map { |d| "#{d}/*.#{CONFIG["OBJEXT"]}" } - f.write("CLEANOBJS := $(CLEANOBJS) #{clean_objs_paths.join(' ')}") +open("Makefile", "a") do |f| + clean_objs_paths = %w[].map { |d| "#{d}/*.#{CONFIG["OBJEXT"]}" } + f.write("CLEANOBJS := $(CLEANOBJS) #{clean_objs_paths.join(" ")}") end diff --git a/ext/nmatrix_fftw/extconf.rb b/ext/nmatrix_fftw/extconf.rb index ad992229..7929fdc1 100644 --- a/ext/nmatrix_fftw/extconf.rb +++ b/ext/nmatrix_fftw/extconf.rb @@ -24,29 +24,29 @@ # # This file checks FFTW3 and other necessary headers/shared objects. -require 'nmatrix/mkmf' +require "nmatrix/mkmf" -fftw_libdir = RbConfig::CONFIG['libdir'] -fftw_incdir = RbConfig::CONFIG['includedir'] -fftw_srcdir = RbConfig::CONFIG['srcdir'] +fftw_libdir = RbConfig::CONFIG["libdir"] +fftw_incdir = RbConfig::CONFIG["includedir"] +fftw_srcdir = RbConfig::CONFIG["srcdir"] -$CFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix -I$(srcdir)/lapacke/include",$CFLAGS].join(" ") -$CXXFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix -I$(srcdir)/lapacke/include -std=c++11",$CXXFLAGS].join(" ") -$CPPFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix -I$(srcdir)/lapacke/include -std=c++11",$CPPFLAGS].join(" ") +$CFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix -I$(srcdir)/lapacke/include", $CFLAGS].join(" ") +$CXXFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix -I$(srcdir)/lapacke/include -std=c++11", $CXXFLAGS].join(" ") +$CPPFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix -I$(srcdir)/lapacke/include -std=c++11", $CPPFLAGS].join(" ") flags = " --include=#{fftw_incdir} --libdir=#{fftw_libdir}" if have_library("fftw3") $CFLAGS += [" -lfftw3 -lm #{$CFLAGS} #{$flags}"].join(" ") - dir_config('nmatrix_fftw', fftw_incdir, fftw_libdir) - dir_config('nmatrix_fftw') + dir_config("nmatrix_fftw", fftw_incdir, fftw_libdir) + dir_config("nmatrix_fftw") end create_conf_h("nmatrix_fftw_config.h") create_makefile("nmatrix_fftw") # to clean up object files in subdirectories: -open('Makefile', 'a') do |f| - clean_objs_paths = %w{ }.map { |d| "#{d}/*.#{CONFIG["OBJEXT"]}" } - f.write("CLEANOBJS := $(CLEANOBJS) #{clean_objs_paths.join(' ')}") +open("Makefile", "a") do |f| + clean_objs_paths = %w[].map { |d| "#{d}/*.#{CONFIG["OBJEXT"]}" } + f.write("CLEANOBJS := $(CLEANOBJS) #{clean_objs_paths.join(" ")}") end diff --git a/ext/nmatrix_lapacke/extconf.rb b/ext/nmatrix_lapacke/extconf.rb index 569db958..b5e9dc11 100644 --- a/ext/nmatrix_lapacke/extconf.rb +++ b/ext/nmatrix_lapacke/extconf.rb @@ -27,31 +27,31 @@ require "nmatrix/mkmf" -#$INSTALLFILES = [['nmatrix.h', '$(archdir)'], ['nmatrix.hpp', '$(archdir)'], ['nmatrix_config.h', '$(archdir)'], ['nm_memory.h', '$(archdir)']] -if /cygwin|mingw/ =~ RUBY_PLATFORM - #$INSTALLFILES << ['libnmatrix.a', '$(archdir)'] +# $INSTALLFILES = [['nmatrix.h', '$(archdir)'], ['nmatrix.hpp', '$(archdir)'], ['nmatrix_config.h', '$(archdir)'], ['nm_memory.h', '$(archdir)']] +if /cygwin|mingw/.match?(RUBY_PLATFORM) + # $INSTALLFILES << ['libnmatrix.a', '$(archdir)'] end $DEBUG = true -#not the right way to add this include directory -$CFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix -I$(srcdir)/lapacke/include",$CFLAGS].join(" ") -$CXXFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix -I$(srcdir)/lapacke/include",$CXXFLAGS].join(" ") -$CPPFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix -I$(srcdir)/lapacke/include",$CPPFLAGS].join(" ") +# not the right way to add this include directory +$CFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix -I$(srcdir)/lapacke/include", $CFLAGS].join(" ") +$CXXFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix -I$(srcdir)/lapacke/include", $CXXFLAGS].join(" ") +$CPPFLAGS = ["-Wall -Werror=return-type -I$(srcdir)/../nmatrix -I$(srcdir)/lapacke/include", $CPPFLAGS].join(" ") # When adding objects here, make sure their directories are included in CLEANOBJS down at the bottom of extconf.rb. # Why not just autogenerate this list from all .c/.cpp files in directory? -basenames = %w{nmatrix_lapacke math_lapacke lapacke} +basenames = %w[nmatrix_lapacke math_lapacke lapacke] $objs = basenames.map { |b| "#{b}.o" } $srcs = basenames.map { |b| "#{b}.cpp" } # For some reason, if we try to look for /usr/lib64/atlas on a Mac OS X Mavericks system, and the directory does not # exist, it will give a linker error -- even if the lib dir is already correctly included with -L. So we need to check # that Dir.exists?(d) for each. -ldefaults = {lapack: ["/usr/local/lib"].delete_if { |d| !Dir.exists?(d) } } +ldefaults = {lapack: ["/usr/local/lib"].delete_if { |d| !Dir.exist?(d) }} -# It is not clear how this variable should be defined, or if it is necessary at all. +# It is not clear how this variable should be defined, or if it is necessary at all. # See issue https://github.com/SciRuby/nmatrix/issues/403 -idefaults = {lapack: [] } +idefaults = {lapack: []} unless have_library("lapack") dir_config("lapack", idefaults[:lapack], ldefaults[:lapack]) @@ -59,15 +59,15 @@ # Order matters here: ATLAS has to go after LAPACK: http://mail.scipy.org/pipermail/scipy-user/2007-January/010717.html $libs += " -llapack " -#To use the Intel MKL, comment out the line above, and also comment out the bit above with have_library and dir_config for lapack. -#Then add something like the line below (for exactly what linker flags to use see https://software.intel.com/en-us/articles/intel-mkl-link-line-advisor ): -#$libs += " -L${MKLROOT}/lib/intel64 -lmkl_intel_lp64 -lmkl_core -lmkl_sequential " +# To use the Intel MKL, comment out the line above, and also comment out the bit above with have_library and dir_config for lapack. +# Then add something like the line below (for exactly what linker flags to use see https://software.intel.com/en-us/articles/intel-mkl-link-line-advisor ): +# $libs += " -L${MKLROOT}/lib/intel64 -lmkl_intel_lp64 -lmkl_core -lmkl_sequential " create_conf_h("nmatrix_lapacke_config.h") create_makefile("nmatrix_lapacke") # to clean up object files in subdirectories: -open('Makefile', 'a') do |f| - clean_objs_paths = %w{ }.map { |d| "#{d}/*.#{CONFIG["OBJEXT"]}" } - f.write("CLEANOBJS := $(CLEANOBJS) #{clean_objs_paths.join(' ')}") +open("Makefile", "a") do |f| + clean_objs_paths = %w[].map { |d| "#{d}/*.#{CONFIG["OBJEXT"]}" } + f.write("CLEANOBJS := $(CLEANOBJS) #{clean_objs_paths.join(" ")}") end diff --git a/ext/nmatrix_lapacke/make_lapacke_cpp.rb b/ext/nmatrix_lapacke/make_lapacke_cpp.rb index eec204e7..01aa5c26 100644 --- a/ext/nmatrix_lapacke/make_lapacke_cpp.rb +++ b/ext/nmatrix_lapacke/make_lapacke_cpp.rb @@ -1,6 +1,6 @@ -#We want this to be a C++ file since our complex types require C++. +# We want this to be a C++ file since our complex types require C++. -File.open("lapacke.cpp","w") do |file| +File.open("lapacke.cpp", "w") do |file| file.puts "//This file is auto-generated by make_lapacke_cpp.rb" file.puts "//It includes all source files in the lapacke/ subdirectory" Dir["lapacke/**/*.c"].each do |file2| diff --git a/lib/nmatrix.rb b/lib/nmatrix.rb index 084e3238..e9c34271 100644 --- a/lib/nmatrix.rb +++ b/lib/nmatrix.rb @@ -25,4 +25,4 @@ # This file is a stub that only loads the main NMatrix file. # -require 'nmatrix/nmatrix.rb' +require "nmatrix/nmatrix.rb" diff --git a/lib/nmatrix/atlas.rb b/lib/nmatrix/atlas.rb index 28fda0ac..096b2bb6 100644 --- a/lib/nmatrix/atlas.rb +++ b/lib/nmatrix/atlas.rb @@ -27,18 +27,17 @@ # nice ruby interfaces for ATLAS functions. #++ -require 'nmatrix/nmatrix.rb' - #need to have nmatrix required first or else bad things will happen -require_relative 'lapack_ext_common' +require "nmatrix/nmatrix.rb" +# need to have nmatrix required first or else bad things will happen +require_relative "lapack_ext_common" NMatrix.register_lapack_extension("nmatrix-atlas") require "nmatrix_atlas.so" class NMatrix - - #Add functions from the ATLAS C extension to the main LAPACK and BLAS modules. - #This will overwrite the original functions where applicable. + # Add functions from the ATLAS C extension to the main LAPACK and BLAS modules. + # This will overwrite the original functions where applicable. module LAPACK class << self NMatrix::ATLAS::LAPACK.singleton_methods.each do |m| @@ -68,8 +67,8 @@ def posv(uplo, a, b) unless a.stype == :dense && b.stype == :dense raise(DataTypeError, "only works for non-integer, non-object dtypes") \ - if a.integer_dtype? || a.object_dtype? || \ - b.integer_dtype? || b.object_dtype? + if a.integer_dtype? || a.object_dtype? || \ + b.integer_dtype? || b.object_dtype? x = b.clone clone = a.clone @@ -83,78 +82,81 @@ def posv(uplo, a, b) x.transpose end - def geev(matrix, which=:both) + def geev(matrix, which = :both) raise(StorageTypeError, "LAPACK functions only work on dense matrices") \ unless matrix.dense? raise(ShapeError, "eigenvalues can only be computed for square matrices") \ unless matrix.dim == 2 && matrix.shape[0] == matrix.shape[1] - jobvl = (which == :both || which == :left) ? :t : false - jobvr = (which == :both || which == :right) ? :t : false + jobvl = which == :both || which == :left ? :t : false + jobvr = which == :both || which == :right ? :t : false n = matrix.shape[0] # Outputs eigenvalues = NMatrix.new([n, 1], dtype: matrix.dtype) - # For real dtypes this holds only the real part of the eigenvalues. + # For real dtypes this holds only the real part of the eigenvalues. imag_eigenvalues = matrix.complex_dtype? ? nil : NMatrix.new([n, 1], \ - dtype: matrix.dtype) # For complex dtypes, this is unused. + dtype: matrix.dtype) # For complex dtypes, this is unused. left_output = jobvl ? matrix.clone_structure : nil right_output = jobvr ? matrix.clone_structure : nil # lapack_geev is a pure LAPACK routine so it expects column-major matrices, # so we need to transpose the input as well as the output. temporary_matrix = matrix.transpose - NMatrix::LAPACK::lapack_geev(jobvl, # compute left eigenvectors of A? - jobvr, # compute right eigenvectors of A? (left eigenvectors of A**T) - n, # order of the matrix - temporary_matrix,# input matrix (used as work) - n, # leading dimension of matrix - eigenvalues,# real part of computed eigenvalues - imag_eigenvalues,# imag part of computed eigenvalues - left_output, # left eigenvectors, if applicable - n, # leading dimension of left_output - right_output, # right eigenvectors, if applicable - n, # leading dimension of right_output - 2*n) + NMatrix::LAPACK.lapack_geev(jobvl, # compute left eigenvectors of A? + jobvr, # compute right eigenvectors of A? (left eigenvectors of A**T) + n, # order of the matrix + temporary_matrix, # input matrix (used as work) + n, # leading dimension of matrix + eigenvalues, # real part of computed eigenvalues + imag_eigenvalues, # imag part of computed eigenvalues + left_output, # left eigenvectors, if applicable + n, # leading dimension of left_output + right_output, # right eigenvectors, if applicable + n, # leading dimension of right_output + 2 * n) left_output = left_output.transpose if jobvl right_output = right_output.transpose if jobvr - # For real dtypes, transform left_output and right_output into correct forms. # If the j'th and the (j+1)'th eigenvalues form a complex conjugate # pair, then the j'th and (j+1)'th columns of the matrix are # the real and imag parts of the eigenvector corresponding # to the j'th eigenvalue. - if !matrix.complex_dtype? + unless matrix.complex_dtype? complex_indices = [] n.times do |i| complex_indices << i if imag_eigenvalues[i] != 0.0 end - if !complex_indices.empty? + unless complex_indices.empty? # For real dtypes, put the real and imaginary parts together - eigenvalues = eigenvalues + imag_eigenvalues * \ - Complex(0.0,1.0) - left_output = left_output.cast(dtype: \ - NMatrix.upcast(:complex64, matrix.dtype)) if left_output - right_output = right_output.cast(dtype: NMatrix.upcast(:complex64, \ - matrix.dtype)) if right_output + eigenvalues += imag_eigenvalues * \ + Complex(0.0, 1.0) + if left_output + left_output = left_output.cast(dtype: \ + NMatrix.upcast(:complex64, matrix.dtype)) + end + if right_output + right_output = right_output.cast(dtype: NMatrix.upcast(:complex64, \ + matrix.dtype)) + end end complex_indices.each_slice(2) do |i, _| if right_output - right_output[0...n,i] = right_output[0...n,i] + \ - right_output[0...n,i+1] * Complex(0.0,1.0) - right_output[0...n,i+1] = \ - right_output[0...n,i].complex_conjugate + right_output[0...n, i] = right_output[0...n, i] + \ + right_output[0...n, i + 1] * Complex(0.0, 1.0) + right_output[0...n, i + 1] = \ + right_output[0...n, i].complex_conjugate end if left_output - left_output[0...n,i] = left_output[0...n,i] + \ - left_output[0...n,i+1] * Complex(0.0,1.0) - left_output[0...n,i+1] = left_output[0...n,i].complex_conjugate + left_output[0...n, i] = left_output[0...n, i] + \ + left_output[0...n, i + 1] * Complex(0.0, 1.0) + left_output[0...n, i + 1] = left_output[0...n, i].complex_conjugate end end end @@ -168,7 +170,7 @@ def geev(matrix, which=:both) end end - def gesvd(matrix, workspace_size=1) + def gesvd(matrix, workspace_size = 1) result = alloc_svd_result(matrix) m = matrix.shape[0] @@ -177,16 +179,16 @@ def gesvd(matrix, workspace_size=1) # This is a pure LAPACK function so it expects column-major functions. # So we need to transpose the input as well as the output. matrix = matrix.transpose - NMatrix::LAPACK::lapack_gesvd(:a, :a, m, n, matrix, \ - m, result[1], result[0], m, result[2], n, workspace_size) + NMatrix::LAPACK.lapack_gesvd(:a, :a, m, n, matrix, \ + m, result[1], result[0], m, result[2], n, workspace_size) result[0] = result[0].transpose result[2] = result[2].transpose result end - def gesdd(matrix, workspace_size=nil) + def gesdd(matrix, workspace_size = nil) min_workspace_size = matrix.shape.min * \ - (6 + 4 * matrix.shape.min) + matrix.shape.max + (6 + 4 * matrix.shape.min) + matrix.shape.max workspace_size = min_workspace_size if \ workspace_size.nil? || workspace_size < min_workspace_size @@ -198,8 +200,8 @@ def gesdd(matrix, workspace_size=nil) # This is a pure LAPACK function so it expects column-major functions. # So we need to transpose the input as well as the output. matrix = matrix.transpose - NMatrix::LAPACK::lapack_gesdd(:a, m, n, matrix, m, result[1], \ - result[0], m, result[2], n, workspace_size) + NMatrix::LAPACK.lapack_gesdd(:a, m, n, matrix, m, result[1], \ + result[0], m, result[2], n, workspace_size) result[0] = result[0].transpose result[2] = result[2].transpose result @@ -209,13 +211,13 @@ def gesdd(matrix, workspace_size=nil) def invert! raise(StorageTypeError, "invert only works on dense matrices currently") \ - unless self.dense? + unless dense? raise(ShapeError, "Cannot invert non-square matrix") \ unless shape[0] == shape[1] raise(DataTypeError, "Cannot invert an integer matrix in-place") \ - if self.integer_dtype? + if integer_dtype? # Even though we are using the ATLAS plugin, we still might be missing # CLAPACK (and thus clapack_getri) if we are on OS X. @@ -223,22 +225,22 @@ def invert! # Get the pivot array; factor the matrix # We can't used getrf! here since it doesn't have the clapack behavior, # so it doesn't play nicely with clapack_getri - n = self.shape[0] - pivot = NMatrix::LAPACK::clapack_getrf(:row, n, n, self, n) + n = shape[0] + pivot = NMatrix::LAPACK.clapack_getrf(:row, n, n, self, n) # Now calculate the inverse using the pivot array - NMatrix::LAPACK::clapack_getri(:row, n, self, n, pivot) + NMatrix::LAPACK.clapack_getri(:row, n, self, n, pivot) self else - __inverse__(self,true) + __inverse__(self, true) end end def potrf!(which) raise(StorageTypeError, "ATLAS functions only work on dense matrices") \ - unless self.dense? + unless dense? raise(ShapeError, "Cholesky decomposition only valid for square matrices") \ - unless self.dim == 2 && self.shape[0] == self.shape[1] + unless dim == 2 && shape[0] == shape[1] - NMatrix::LAPACK::clapack_potrf(:row, which, self.shape[0], self, self.shape[1]) + NMatrix::LAPACK.clapack_potrf(:row, which, shape[0], self, shape[1]) end end diff --git a/lib/nmatrix/blas.rb b/lib/nmatrix/blas.rb index 6ef41b72..30f6dd2f 100644 --- a/lib/nmatrix/blas.rb +++ b/lib/nmatrix/blas.rb @@ -28,8 +28,7 @@ #++ module NMatrix::BLAS - - #Add functions from C extension to main BLAS module + # Add functions from C extension to main BLAS module class << self if jruby? # BLAS functionalities for JRuby need to be implemented @@ -73,18 +72,19 @@ class << self # - +ArgumentError+ -> The dtype of the matrices must be equal. # def gemm(a, b, c = nil, alpha = 1.0, beta = 0.0, - transpose_a = false, transpose_b = false, m = nil, - n = nil, k = nil, lda = nil, ldb = nil, ldc = nil) + transpose_a = false, transpose_b = false, m = nil, + n = nil, k = nil, lda = nil, ldb = nil, ldc = nil) - raise(ArgumentError, 'Expected dense NMatrices as first two arguments.') \ - unless a.is_a?(NMatrix) and b.is_a? \ - (NMatrix) and a.stype == :dense and b.stype == :dense + raise(ArgumentError, "Expected dense NMatrices as first two arguments.") \ + unless a.is_a?(NMatrix) && b.is_a?(\ + NMatrix + ) && (a.stype == :dense) && (b.stype == :dense) - raise(ArgumentError, 'Expected nil or dense NMatrix as third argument.') \ - unless c.nil? or (c.is_a?(NMatrix) \ - and c.stype == :dense) - raise(ArgumentError, 'NMatrix dtype mismatch.') \ - unless a.dtype == b.dtype and (c ? a.dtype == c.dtype : true) + raise(ArgumentError, "Expected nil or dense NMatrix as third argument.") \ + unless c.nil? || (c.is_a?(NMatrix) \ + && (c.stype == :dense)) + raise(ArgumentError, "NMatrix dtype mismatch.") \ + unless (a.dtype == b.dtype) && (c ? a.dtype == c.dtype : true) # First, set m, n, and k, which depend on whether we're taking the # transpose of a and b. @@ -106,7 +106,7 @@ def gemm(a, b, c = nil, alpha = 1.0, beta = 0.0, end n ||= transpose_b ? b.shape[0] : b.shape[1] - c = NMatrix.new([m, n], dtype: a.dtype) + c = NMatrix.new([m, n], dtype: a.dtype) end # I think these are independent of whether or not a transpose occurs. @@ -115,16 +115,16 @@ def gemm(a, b, c = nil, alpha = 1.0, beta = 0.0, ldc ||= c.shape[1] # NM_COMPLEX64 and NM_COMPLEX128 both require complex alpha and beta. - if a.dtype == :complex64 or a.dtype == :complex128 + if (a.dtype == :complex64) || (a.dtype == :complex128) alpha = Complex(1.0, 0.0) if alpha == 1.0 beta = Complex(0.0, 0.0) if beta == 0.0 end # For argument descriptions, see: http://www.netlib.org/blas/dgemm.f ::NMatrix::BLAS.cblas_gemm(:row, transpose_a, transpose_b, - m, n, k, alpha, a, lda, b, ldb, beta, c, ldc) + m, n, k, alpha, a, lda, b, ldb, beta, c, ldc) - return c + c end # @@ -155,17 +155,17 @@ def gemm(a, b, c = nil, alpha = 1.0, beta = 0.0, # - ++ -> # def gemv(a, x, y = nil, alpha = 1.0, beta = 0.0, - transpose_a = false, m = nil, n = nil, lda = nil, - incx = nil, incy = nil) - raise(ArgumentError, 'Expected dense NMatrices as first two arguments.') \ - unless a.is_a?(NMatrix) and x.is_a?(NMatrix) and \ - a.stype == :dense and x.stype == :dense + transpose_a = false, m = nil, n = nil, lda = nil, + incx = nil, incy = nil) + raise(ArgumentError, "Expected dense NMatrices as first two arguments.") \ + unless a.is_a?(NMatrix) && x.is_a?(NMatrix) && \ + (a.stype == :dense) && (x.stype == :dense) - raise(ArgumentError, 'Expected nil or dense NMatrix as third argument.') \ - unless y.nil? or (y.is_a?(NMatrix) and y.stype == :dense) + raise(ArgumentError, "Expected nil or dense NMatrix as third argument.") \ + unless y.nil? || (y.is_a?(NMatrix) && (y.stype == :dense)) - raise(ArgumentError, 'NMatrix dtype mismatch.') \ - unless a.dtype == x.dtype and (y ? a.dtype == y.dtype : true) + raise(ArgumentError, "NMatrix dtype mismatch.") \ + unless (a.dtype == x.dtype) && (y ? a.dtype == y.dtype : true) m ||= transpose_a == :transpose ? a.shape[1] : a.shape[0] n ||= transpose_a == :transpose ? a.shape[0] : a.shape[1] @@ -176,7 +176,7 @@ def gemv(a, x, y = nil, alpha = 1.0, beta = 0.0, raise(ArgumentError, "dimensions don't match") \ unless y.shape[0] == m && y.shape[1] == 1 else - y = NMatrix.new([m,1], dtype: a.dtype) + y = NMatrix.new([m, 1], dtype: a.dtype) end lda ||= a.shape[1] @@ -184,9 +184,9 @@ def gemv(a, x, y = nil, alpha = 1.0, beta = 0.0, incy ||= 1 ::NMatrix::BLAS.cblas_gemv(transpose_a, m, n, - alpha, a, lda, x, incx, beta, y, incy) + alpha, a, lda, x, incx, beta, y, incy) - return y + y end # @@ -214,33 +214,32 @@ def gemv(a, x, y = nil, alpha = 1.0, beta = 0.0, # - +ArgumentError+ -> Need to supply n for non-standard incx, # incy values. # - def rot(x, y, c, s, incx = 1, incy = 1, n = nil, in_place=false) - raise(ArgumentError, 'Expected dense NMatrices as first two arguments.') \ - unless x.is_a?(NMatrix) and y.is_a?(NMatrix) \ - and x.stype == :dense and y.stype == :dense + def rot(x, y, c, s, incx = 1, incy = 1, n = nil, in_place = false) + raise(ArgumentError, "Expected dense NMatrices as first two arguments.") \ + unless x.is_a?(NMatrix) && y.is_a?(NMatrix) \ + && (x.stype == :dense) && (y.stype == :dense) - raise(ArgumentError, 'NMatrix dtype mismatch.') \ + raise(ArgumentError, "NMatrix dtype mismatch.") \ unless x.dtype == y.dtype - raise(ArgumentError, 'Need to supply n for non-standard incx, incy values') \ + raise(ArgumentError, "Need to supply n for non-standard incx, incy values") \ if n.nil? && incx != 1 && incx != -1 && incy != 1 && incy != -1 - n ||= [x.size/incx.abs, y.size/incy.abs].min + n ||= [x.size / incx.abs, y.size / incy.abs].min if in_place ::NMatrix::BLAS.cblas_rot(n, x, incx, y, incy, c, s) - return [x,y] + return [x, y] else xx = x.clone yy = y.clone ::NMatrix::BLAS.cblas_rot(n, xx, incx, yy, incy, c, s) - return [xx,yy] + return [xx, yy] end end - # # call-seq: # rot!(x, y, c, s) -> [NMatrix, NMatrix] @@ -249,10 +248,9 @@ def rot(x, y, c, s, incx = 1, incy = 1, n = nil, in_place=false) # # See rot for arguments. def rot!(x, y, c, s, incx = 1, incy = 1, n = nil) - rot(x,y,c,s,incx,incy,n,true) + rot(x, y, c, s, incx, incy, n, true) end - # # call-seq: # rotg(ab) -> [Numeric, Numeric] @@ -277,7 +275,6 @@ def rotg(ab) ::NMatrix::BLAS.cblas_rotg(ab) end - # # call-seq: # asum(x, incx, n) -> Numeric @@ -302,8 +299,8 @@ def asum(x, incx = 1, n = nil) unless x.is_a?(NMatrix) raise(RangeError, "n out of range") \ - if n*incx > x.size || n*incx <= 0 || n <= 0 - ::NMatrix::BLAS.cblas_asum(n, x, incx) + if n * incx > x.size || n * incx <= 0 || n <= 0 + ::NMatrix::BLAS.cblas_asum(n, x, incx) end # @@ -329,8 +326,8 @@ def nrm2(x, incx = 1, n = nil) unless x.is_a?(NMatrix) raise(RangeError, "n out of range") \ - if n*incx > x.size || n*incx <= 0 || n <= 0 - ::NMatrix::BLAS.cblas_nrm2(n, x, incx) + if n * incx > x.size || n * incx <= 0 || n <= 0 + ::NMatrix::BLAS.cblas_nrm2(n, x, incx) end # @@ -350,10 +347,10 @@ def nrm2(x, incx = 1, n = nil) # - +ArgumentError+ -> Expected dense NMatrix for arg 0 # - +RangeError+ -> n out of range # - def scal(alpha, vector, incx=1, n=nil) + def scal(alpha, vector, incx = 1, n = nil) n ||= vector.size / incx raise(ArgumentError, "Expected dense NMatrix for arg 0") unless vector.is_a?(NMatrix) - raise(RangeError, "n out of range") if n*incx > vector.size || n*incx <= 0 || n <= 0 + raise(RangeError, "n out of range") if n * incx > vector.size || n * incx <= 0 || n <= 0 ::NMatrix::BLAS.cblas_scal(n, alpha, vector, incx) end @@ -361,17 +358,17 @@ def scal(alpha, vector, incx=1, n=nil) # now require nmatrix-atlas or nmatrix-lapcke to run properly, so we can just # implemented their stubs in Ruby. def cblas_trmm(order, side, uplo, trans_a, diag, m, n, alpha, a, lda, b, ldb) - raise(NotImplementedError,"cblas_trmm requires either the + raise(NotImplementedError, "cblas_trmm requires either the nmatrix-lapacke or nmatrix-atlas gem") end def cblas_syrk(order, uplo, trans, n, k, alpha, a, lda, beta, c, ldc) - raise(NotImplementedError,"cblas_syrk requires either the + raise(NotImplementedError, "cblas_syrk requires either the nmatrix-lapacke or nmatrix-atlas gem") end def cblas_herk(order, uplo, trans, n, k, alpha, a, lda, beta, c, ldc) - raise(NotImplementedError,"cblas_herk requires either the + raise(NotImplementedError, "cblas_herk requires either the nmatrix-lapacke or nmatrix-atlas gem") end end diff --git a/lib/nmatrix/cruby/math.rb b/lib/nmatrix/cruby/math.rb index 90d515da..d8a7b414 100644 --- a/lib/nmatrix/cruby/math.rb +++ b/lib/nmatrix/cruby/math.rb @@ -29,7 +29,6 @@ #++ class NMatrix - # # call-seq: # getrf! -> Array @@ -51,24 +50,24 @@ class NMatrix # - +StorageTypeError+ -> ATLAS functions only work on dense matrices. # def getrf! - raise(StorageTypeError, "ATLAS functions only work on dense matrices") unless self.dense? - - #For row-major matrices, clapack_getrf uses a different convention than - #described above (U has unit diagonal elements instead of L and columns - #are interchanged rather than rows). For column-major matrices, clapack - #uses the stanard conventions. So we just transpose the matrix before - #and after calling clapack_getrf. - #Unfortunately, this is not a very good way, uses a lot of memory. - temp = self.transpose - ipiv = NMatrix::LAPACK::clapack_getrf(:col, self.shape[0], self.shape[1], temp, self.shape[0]) + raise(StorageTypeError, "ATLAS functions only work on dense matrices") unless dense? + + # For row-major matrices, clapack_getrf uses a different convention than + # described above (U has unit diagonal elements instead of L and columns + # are interchanged rather than rows). For column-major matrices, clapack + # uses the stanard conventions. So we just transpose the matrix before + # and after calling clapack_getrf. + # Unfortunately, this is not a very good way, uses a lot of memory. + temp = transpose + ipiv = NMatrix::LAPACK.clapack_getrf(:col, shape[0], shape[1], temp, shape[0]) temp = temp.transpose - self[0...self.shape[0], 0...self.shape[1]] = temp + self[0...shape[0], 0...shape[1]] = temp - #for some reason, in clapack_getrf, the indices in ipiv start from 0 - #instead of 1 as in LAPACK. - ipiv.each_index { |i| ipiv[i]+=1 } + # for some reason, in clapack_getrf, the indices in ipiv start from 0 + # instead of 1 as in LAPACK. + ipiv.each_index { |i| ipiv[i] += 1 } - return ipiv + ipiv end # @@ -130,10 +129,9 @@ def geqrf! # - +TypeError+ -> Works only on floating point matrices, use unmqr for complex types # - +TypeError+ -> c must have the same dtype as the calling NMatrix # - def ormqr(tau, side=:left, transpose=false, c=nil) + def ormqr(tau, side = :left, transpose = false, c = nil) # The real implementation is in lib/nmatrix/lapacke.rb raise(NotImplementedError, "ormqr requires the nmatrix-lapacke gem") - end # @@ -164,7 +162,7 @@ def ormqr(tau, side=:left, transpose=false, c=nil) # - +TypeError+ -> Works only on floating point matrices, use unmqr for complex types # - +TypeError+ -> c must have the same dtype as the calling NMatrix # - def unmqr(tau, side=:left, transpose=false, c=nil) + def unmqr(tau, side = :left, transpose = false, c = nil) # The real implementation is in lib/nmatrix/lapacke.rb raise(NotImplementedError, "unmqr requires the nmatrix-lapacke gem") end @@ -205,7 +203,6 @@ def potrf_lower! potrf! :lower end - # # call-seq: # factorize_cholesky -> [upper NMatrix, lower NMatrix] @@ -218,10 +215,10 @@ def potrf_lower! # symmetric or Hermitian. However, it is still your responsibility to make # sure it is positive-definite. def factorize_cholesky - raise "Matrix must be symmetric/Hermitian for Cholesky factorization" unless self.hermitian? - l = self.clone.potrf_lower!.tril! + raise "Matrix must be symmetric/Hermitian for Cholesky factorization" unless hermitian? + l = clone.potrf_lower!.tril! u = l.conjugate_transpose - [u,l] + [u, l] end # @@ -237,11 +234,11 @@ def factorize_cholesky # +with_permutation_matrix+ - If set to *true* will return the permutation # matrix alongwith the LU factorization as a second return value. # - def factorize_lu with_permutation_matrix=nil - raise(NotImplementedError, "only implemented for dense storage") unless self.stype == :dense - raise(NotImplementedError, "matrix is not 2-dimensional") unless self.dimensions == 2 + def factorize_lu with_permutation_matrix = nil + raise(NotImplementedError, "only implemented for dense storage") unless stype == :dense + raise(NotImplementedError, "matrix is not 2-dimensional") unless dimensions == 2 - t = self.clone + t = clone pivot = t.getrf! return t unless with_permutation_matrix @@ -266,26 +263,26 @@ def factorize_lu with_permutation_matrix=nil # - +ShapeError+ -> Input must be a 2-dimensional matrix to have a QR decomposition. # def factorize_qr - raise(NotImplementedError, "only implemented for dense storage") unless self.stype == :dense - raise(ShapeError, "Input must be a 2-dimensional matrix to have a QR decomposition") unless self.dim == 2 + raise(NotImplementedError, "only implemented for dense storage") unless stype == :dense + raise(ShapeError, "Input must be a 2-dimensional matrix to have a QR decomposition") unless dim == 2 - rows, columns = self.shape - r = self.clone - tau = r.geqrf! + rows, columns = shape + r = clone + tau = r.geqrf! - #Obtain Q - q = self.complex_dtype? ? r.unmqr(tau) : r.ormqr(tau) + # Obtain Q + q = complex_dtype? ? r.unmqr(tau) : r.ormqr(tau) - #Obtain R + # Obtain R if rows <= columns r.upper_triangle! - #Need to account for upper trapezoidal structure if R is a tall rectangle (rows > columns) + # Need to account for upper trapezoidal structure if R is a tall rectangle (rows > columns) else r[0...columns, 0...columns].upper_triangle! r[columns...rows, 0...columns] = 0 end - [q,r] + [q, r] end # Solve the matrix equation AX = B, where A is +self+, B is the first @@ -332,16 +329,16 @@ def factorize_qr # # upper_tri 0.180000 0.000000 0.180000 ( 0.182491) # def solve(b, opts = {}) - raise(ShapeError, "Must be called on square matrix") unless self.dim == 2 && self.shape[0] == self.shape[1] + raise(ShapeError, "Must be called on square matrix") unless dim == 2 && shape[0] == shape[1] raise(ShapeError, "number of rows of b must equal number of cols of self") if - self.shape[1] != b.shape[0] - raise(ArgumentError, "only works with dense matrices") if self.stype != :dense + shape[1] != b.shape[0] + raise(ArgumentError, "only works with dense matrices") if stype != :dense raise(ArgumentError, "only works for non-integer, non-object dtypes") if - integer_dtype? or object_dtype? or b.integer_dtype? or b.object_dtype? + integer_dtype? || object_dtype? || b.integer_dtype? || b.object_dtype? - opts = { form: :general }.merge(opts) + opts = {form: :general}.merge(opts) x = b.clone - n = self.shape[0] + n = shape[0] nrhs = b.shape[1] case opts[:form] @@ -358,17 +355,17 @@ def solve(b, opts = {}) x.transpose when :upper_tri, :upper_triangular raise(ArgumentError, "upper triangular solver does not work with complex dtypes") if - complex_dtype? or b.complex_dtype? + complex_dtype? || b.complex_dtype? # this is the correct function call; see https://github.com/SciRuby/nmatrix/issues/374 - NMatrix::BLAS::cblas_trsm(:row, :left, :upper, false, :nounit, n, nrhs, 1.0, self, n, x, nrhs) + NMatrix::BLAS.cblas_trsm(:row, :left, :upper, false, :nounit, n, nrhs, 1.0, self, n, x, nrhs) x when :lower_tri, :lower_triangular raise(ArgumentError, "lower triangular solver does not work with complex dtypes") if - complex_dtype? or b.complex_dtype? - NMatrix::BLAS::cblas_trsm(:row, :left, :lower, false, :nounit, n, nrhs, 1.0, self, n, x, nrhs) + complex_dtype? || b.complex_dtype? + NMatrix::BLAS.cblas_trsm(:row, :left, :lower, false, :nounit, n, nrhs, 1.0, self, n, x, nrhs) x when :pos_def, :positive_definite - u, l = self.factorize_cholesky + u, l = factorize_cholesky z = l.solve(b, form: :lower_tri) u.solve(z, form: :upper_tri) else @@ -411,19 +408,19 @@ def solve(b, opts = {}) # def least_squares(b, tolerance: 10e-6) raise(ArgumentError, "least squares approximation only works for non-complex types") if - self.complex_dtype? + complex_dtype? - rows, columns = self.shape + rows, columns = shape raise(ShapeError, "system must be under-determined ( rows > columns )") unless rows > columns - #Perform economical QR factorization - r = self.clone + # Perform economical QR factorization + r = clone tau = r.geqrf! q_transpose_b = r.ormqr(tau, :left, :transpose, b) - #Obtain R from geqrf! intermediate + # Obtain R from geqrf! intermediate r[0...columns, 0...columns].upper_triangle! r[columns...rows, 0...columns] = 0 @@ -433,7 +430,7 @@ def least_squares(b, tolerance: 10e-6) if diagonal.any? { |x| x.abs < tolerance } warn "warning: A diagonal element of R in A = QR is close to zero ;" << - " indicates a possible loss of precision" + " indicates a possible loss of precision" end # Transform the system A * X = B to R1 * X = B2 where B2 = Q1_t * B @@ -442,8 +439,8 @@ def least_squares(b, tolerance: 10e-6) nrhs = b2.shape[1] - #Solve the upper triangular system - NMatrix::BLAS::cblas_trsm(:row, :left, :upper, false, :nounit, r1.shape[0], nrhs, 1.0, r1, r1.shape[0], b2, nrhs) + # Solve the upper triangular system + NMatrix::BLAS.cblas_trsm(:row, :left, :upper, false, :nounit, r1.shape[0], nrhs, 1.0, r1, r1.shape[0], b2, nrhs) b2 end @@ -458,8 +455,8 @@ def least_squares(b, tolerance: 10e-6) # Optionally accepts a +workspace_size+ parameter, which will be honored only if it is larger than what LAPACK # requires. # - def gesvd!(workspace_size=1) - NMatrix::LAPACK::gesvd(self, workspace_size) + def gesvd!(workspace_size = 1) + NMatrix::LAPACK.gesvd(self, workspace_size) end # @@ -472,12 +469,10 @@ def gesvd!(workspace_size=1) # Optionally accepts a +workspace_size+ parameter, which will be honored only if it is larger than what LAPACK # requires. # - def gesvd(workspace_size=1) - self.clone.gesvd!(workspace_size) + def gesvd(workspace_size = 1) + clone.gesvd!(workspace_size) end - - # # call-seq: # gesdd! -> [u, sigma, v_transpose] @@ -489,8 +484,8 @@ def gesvd(workspace_size=1) # Optionally accepts a +workspace_size+ parameter, which will be honored only if it is larger than what LAPACK # requires. # - def gesdd!(workspace_size=nil) - NMatrix::LAPACK::gesdd(self, workspace_size) + def gesdd!(workspace_size = nil) + NMatrix::LAPACK.gesdd(self, workspace_size) end # @@ -504,8 +499,8 @@ def gesdd!(workspace_size=nil) # Optionally accepts a +workspace_size+ parameter, which will be honored only if it is larger than what LAPACK # requires. # - def gesdd(workspace_size=nil) - self.clone.gesdd!(workspace_size) + def gesdd(workspace_size = nil) + clone.gesdd!(workspace_size) end # @@ -532,27 +527,27 @@ def gesdd(workspace_size=nil) # # * +:covention+ - Possible values are +:lapack+ and +:intuitive+. Default is +:intuitive+. See above for details. # - def laswp!(ary, opts={}) - raise(StorageTypeError, "ATLAS functions only work on dense matrices") unless self.dense? - opts = { convention: :intuitive }.merge(opts) + def laswp!(ary, opts = {}) + raise(StorageTypeError, "ATLAS functions only work on dense matrices") unless dense? + opts = {convention: :intuitive}.merge(opts) if opts[:convention] == :intuitive if ary.length != ary.uniq.length raise(ArgumentError, "No duplicated entries in the order array are allowed under convention :intuitive") end - n = self.shape[1] + n = shape[1] p = [] order = (0...n).to_a - 0.upto(n-2) do |i| + 0.upto(n - 2) do |i| p[i] = order.index(ary[i]) order[i], order[p[i]] = order[p[i]], order[i] end - p[n-1] = n-1 + p[n - 1] = n - 1 else p = ary end - NMatrix::LAPACK::laswp(self, p) + NMatrix::LAPACK.laswp(self, p) end # @@ -579,8 +574,8 @@ def laswp!(ary, opts={}) # # * +:covention+ - Possible values are +:lapack+ and +:intuitive+. Default is +:lapack+. See above for details. # - def laswp(ary, opts={}) - self.clone.laswp!(ary, opts) + def laswp(ary, opts = {}) + clone.laswp!(ary, opts) end # @@ -609,28 +604,28 @@ def laswp(ary, opts={}) # - +ShapeError+ -> Must be used on square matrices. # def det - raise(ShapeError, "determinant can be calculated only for square matrices") unless self.dim == 2 && self.shape[0] == self.shape[1] + raise(ShapeError, "determinant can be calculated only for square matrices") unless dim == 2 && shape[0] == shape[1] # Cast to a dtype for which getrf is implemented - new_dtype = self.integer_dtype? ? :float64 : self.dtype - copy = self.cast(:dense, new_dtype) + new_dtype = integer_dtype? ? :float64 : dtype + copy = cast(:dense, new_dtype) # Need to know the number of permutations. We'll add up the diagonals of # the factorized matrix. pivot = copy.getrf! - num_perm = 0 #number of permutations + num_perm = 0 # number of permutations pivot.each_with_index do |swap, i| - #pivot indexes rows starting from 1, instead of 0, so need to subtract 1 here - num_perm += 1 if swap-1 != i + # pivot indexes rows starting from 1, instead of 0, so need to subtract 1 here + num_perm += 1 if swap - 1 != i end prod = num_perm % 2 == 1 ? -1 : 1 # odd permutations => negative - [shape[0],shape[1]].min.times do |i| - prod *= copy[i,i] + [shape[0], shape[1]].min.times do |i| + prod *= copy[i, i] end # Convert back to an integer if necessary - new_dtype != self.dtype ? prod.round : prod #prevent rounding errors + new_dtype != dtype ? prod.round : prod # prevent rounding errors end # @@ -650,8 +645,8 @@ def det # * *Returns* : # - If the original NMatrix isn't complex, the result is a +:complex128+ NMatrix. Otherwise, it's the original dtype. # - def complex_conjugate(new_stype = self.stype) - self.cast(new_stype, NMatrix::upcast(dtype, :complex64)).complex_conjugate! + def complex_conjugate(new_stype = stype) + cast(new_stype, NMatrix.upcast(dtype, :complex64)).complex_conjugate! end # @@ -665,7 +660,7 @@ def complex_conjugate(new_stype = self.stype) # - The conjugate transpose of the matrix as a copy. # def conjugate_transpose - self.transpose.complex_conjugate! + transpose.complex_conjugate! end # @@ -677,15 +672,15 @@ def conjugate_transpose # - +n+ -> the number of elements to include # # Return the sum of the contents of the vector. This is the BLAS asum routine. - def asum incx=1, n=nil - if self.shape == [1] - return self[0].abs unless self.complex_dtype? + def asum incx = 1, n = nil + if shape == [1] + return self[0].abs unless complex_dtype? return self[0].real.abs + self[0].imag.abs end return method_missing(:asum, incx, n) unless vector? - NMatrix::BLAS::asum(self, incx, self.size / incx) + NMatrix::BLAS.asum(self, incx, size / incx) end - alias :absolute_sum :asum + alias absolute_sum asum # # call-seq: @@ -696,11 +691,11 @@ def asum incx=1, n=nil # - +n+ -> the number of elements to include # # Return the 2-norm of the vector. This is the BLAS nrm2 routine. - def nrm2 incx=1, n=nil + def nrm2 incx = 1, n = nil return method_missing(:nrm2, incx, n) unless vector? - NMatrix::BLAS::nrm2(self, incx, self.size / incx) + NMatrix::BLAS.nrm2(self, incx, size / incx) end - alias :norm2 :nrm2 + alias norm2 nrm2 # # call-seq: @@ -714,12 +709,12 @@ def nrm2 incx=1, n=nil # This is a destructive method, modifying the source NMatrix. See also #scale. # Return the scaling result of the matrix. BLAS scal will be invoked if provided. - def scale!(alpha, incx=1, n=nil) + def scale!(alpha, incx = 1, n = nil) raise(DataTypeError, "Incompatible data type for the scaling factor") unless - NMatrix::upcast(self.dtype, NMatrix::min_dtype(alpha)) == self.dtype - return NMatrix::BLAS::scal(alpha, self, incx, self.size / incx) if NMatrix::BLAS.method_defined? :scal - self.each_stored_with_indices do |e, *i| - self[*i] = e*alpha + NMatrix.upcast(dtype, NMatrix.min_dtype(alpha)) == dtype + return NMatrix::BLAS.scal(alpha, self, incx, size / incx) if NMatrix::BLAS.method_defined? :scal + each_stored_with_indices do |e, *i| + self[*i] = e * alpha end end @@ -734,11 +729,10 @@ def scale!(alpha, incx=1, n=nil) # # Return the scaling result of the matrix. BLAS scal will be invoked if provided. - def scale(alpha, incx=1, n=nil) - return self.clone.scale!(alpha, incx, n) + def scale(alpha, incx = 1, n = nil) + clone.scale!(alpha, incx, n) end - alias :permute_columns :laswp - alias :permute_columns! :laswp! - + alias permute_columns laswp + alias permute_columns! laswp! end diff --git a/lib/nmatrix/enumerate.rb b/lib/nmatrix/enumerate.rb index 5c5808c6..835524fa 100644 --- a/lib/nmatrix/enumerate.rb +++ b/lib/nmatrix/enumerate.rb @@ -38,13 +38,13 @@ class NMatrix # For dense, this actually calls a specialized each iterator (in C). For yale and list, it relies upon # #each_with_indices (which is about as fast as reasonably possible for C code). def each &bl - if self.stype == :dense - self.__dense_each__(&bl) + if stype == :dense + __dense_each__(&bl) elsif block_given? - self.each_with_indices(&bl) + each_with_indices(&bl) else # Handle case where no block is given Enumerator.new do |yielder| - self.each_with_indices do |params| + each_with_indices do |params| yielder.yield params end end @@ -57,7 +57,7 @@ def each &bl # flat_map { |elem| block } -> Array # # Maps using Enumerator (returns an Array or an Enumerator) - alias_method :flat_map, :map + alias flat_map map ## # call-seq: @@ -72,7 +72,7 @@ def each &bl def map(&bl) return enum_for(:map) unless block_given? # NMatrix-jruby currently supports only doubles - cp = jruby? ? self : self.cast(dtype: :object) + cp = jruby? ? self : cast(dtype: :object) cp.map!(&bl) cp end @@ -88,20 +88,19 @@ def map(&bl) def map! return enum_for(:map!) unless block_given? iterated = false - self.each_stored_with_indices do |e, *i| + each_stored_with_indices do |e, *i| iterated = true self[*i] = (yield e) end - #HACK: if there's a single element in a non-dense matrix, it won't iterate and - #won't change the default value; this ensures that it does get changed. - unless iterated then - self.each_with_indices do |e, *i| + # HACK: if there's a single element in a non-dense matrix, it won't iterate and + # won't change the default value; this ensures that it does get changed. + unless iterated + each_with_indices do |e, *i| self[*i] = (yield e) end end end - # # call-seq: # each_rank() -> NMatrix @@ -115,24 +114,24 @@ def map! # # @param [Fixnum] dimen the rank being iterated over. # - def each_rank(dimen=0, get_by=:reference) + def each_rank(dimen = 0, get_by = :reference) return enum_for(:each_rank, dimen, get_by) unless block_given? - (0...self.shape[dimen]).each do |idx| - yield self.rank(dimen, idx, get_by) + (0...shape[dimen]).each do |idx| + yield rank(dimen, idx, get_by) end self end - alias :each_along_dim :each_rank + alias each_along_dim each_rank # # call-seq: # each_row { |row| block } -> NMatrix # # Iterate through each row, referencing it as an NMatrix slice. - def each_row(get_by=:reference) + def each_row(get_by = :reference) return enum_for(:each_row, get_by) unless block_given? - (0...self.shape[0]).each do |i| - yield self.row(i, get_by) + (0...shape[0]).each do |i| + yield row(i, get_by) end self end @@ -142,10 +141,10 @@ def each_row(get_by=:reference) # each_column { |column| block } -> NMatrix # # Iterate through each column, referencing it as an NMatrix slice. - def each_column(get_by=:reference) + def each_column(get_by = :reference) return enum_for(:each_column, get_by) unless block_given? - (0...self.shape[1]).each do |j| - yield self.column(j, get_by) + (0...shape[1]).each do |j| + yield column(j, get_by) end self end @@ -158,15 +157,14 @@ def each_column(get_by=:reference) # # Note: If you have a 3-dimensional matrix, the first dimension contains rows, # the second contains columns, and the third contains layers. - def each_layer(get_by=:reference) + def each_layer(get_by = :reference) return enum_for(:each_layer, get_by) unless block_given? - (0...self.shape[2]).each do |k| - yield self.layer(k, get_by) + (0...shape[2]).each do |k| + yield layer(k, get_by) end self end - # # call-seq: # each_stored_with_index -> Enumerator @@ -174,14 +172,14 @@ def each_layer(get_by=:reference) # Allow iteration across a vector NMatrix's stored values. See also @each_stored_with_indices # def each_stored_with_index(&block) - raise(NotImplementedError, "only works for dim 2 vectors") unless self.dim <= 2 + raise(NotImplementedError, "only works for dim 2 vectors") unless dim <= 2 return enum_for(:each_stored_with_index) unless block_given? - self.each_stored_with_indices do |v, i, j| + each_stored_with_indices do |v, i, j| if shape[0] == 1 - yield(v,j) + yield(v, j) elsif shape[1] == 1 - yield(v,i) + yield(v, i) else method_missing(:each_stored_with_index, &block) end @@ -189,7 +187,6 @@ def each_stored_with_index(&block) self end - ## # call-seq: # inject_rank() -> Enumerator @@ -215,9 +212,8 @@ def each_stored_with_index(&block) # is the result of the reduction at that position along the specified # dimension. # - def inject_rank(dimen=0, initial=nil, dtype=nil) - - raise(RangeError, "requested dimension (#{dimen}) does not exist (shape: #{shape})") if dimen > self.dim + def inject_rank(dimen = 0, initial = nil, dtype = nil) + raise(RangeError, "requested dimension (#{dimen}) does not exist (shape: #{shape})") if dimen > dim return enum_for(:inject_rank, dimen, initial, dtype) unless block_given? @@ -226,11 +222,11 @@ def inject_rank(dimen=0, initial=nil, dtype=nil) first_as_acc = false - if initial then - acc = NMatrix.new(new_shape, initial, :dtype => dtype || self.dtype, stype: self.stype) + if initial + acc = NMatrix.new(new_shape, initial, dtype: dtype || self.dtype, stype: stype) else each_rank(dimen) do |sub_mat| - acc = (sub_mat.is_a?(NMatrix) and !dtype.nil? and dtype != self.dtype) ? sub_mat.cast(self.stype, dtype) : sub_mat + acc = sub_mat.is_a?(NMatrix) && !dtype.nil? && (dtype != self.dtype) ? sub_mat.cast(stype, dtype) : sub_mat break end first_as_acc = true @@ -247,7 +243,6 @@ def inject_rank(dimen=0, initial=nil, dtype=nil) acc end - alias :reduce_along_dim :inject_rank - alias :inject_along_dim :inject_rank - + alias reduce_along_dim inject_rank + alias inject_along_dim inject_rank end diff --git a/lib/nmatrix/fftw.rb b/lib/nmatrix/fftw.rb index f685295d..f349b46a 100644 --- a/lib/nmatrix/fftw.rb +++ b/lib/nmatrix/fftw.rb @@ -27,11 +27,10 @@ # nice ruby interfaces for FFTW functions. #++ -require 'nmatrix/nmatrix.rb' +require "nmatrix/nmatrix.rb" require "nmatrix_fftw.so" class NMatrix - # Compute 1D FFT of the matrix using FFTW default parameters. # @return [NMatrix] NMatrix of dtype :complex128 containing computed values. # @example Compute 1D FFT of an NMatrix. @@ -43,8 +42,8 @@ class NMatrix # ], dtype: :complex128) # nm.fft def fft - input = self.dtype == :complex128 ? self : self.cast(dtype: :complex128) - plan = NMatrix::FFTW::Plan.new([self.size]) + input = dtype == :complex128 ? self : cast(dtype: :complex128) + plan = NMatrix::FFTW::Plan.new([size]) plan.set_input input plan.execute plan.output @@ -53,9 +52,9 @@ def fft # Compute 2D FFT of a 2D matrix using FFTW default parameters. # @return [NMatrix] NMatrix of dtype :complex128 containing computed values. def fft2 - raise ShapeError, "Shape must be 2 (is #{self.shape})" if self.shape.size != 2 - input = self.dtype == :complex128 ? self : self.cast(dtype: :complex128) - plan = NMatrix::FFTW::Plan.new(self.shape, dim: 2) + raise ShapeError, "Shape must be 2 (is #{shape})" if shape.size != 2 + input = dtype == :complex128 ? self : cast(dtype: :complex128) + plan = NMatrix::FFTW::Plan.new(shape, dim: 2) plan.set_input input plan.execute plan.output @@ -71,9 +70,9 @@ class Plan # # @see http://www.fftw.org/fftw3_doc/Real_002dto_002dReal-Transform-Kinds.html#Real_002dto_002dReal-Transform-Kinds REAL_REAL_FFT_KINDS_HASH = { - r2hc: 0, - hc2r: 1, - dht: 2, + r2hc: 0, + hc2r: 1, + dht: 2, redft00: 3, redft01: 4, redft10: 5, @@ -81,30 +80,30 @@ class Plan rodft00: 7, rodft01: 9, rodft10: 8, - rodft11: 10 + rodft11: 10, } - # Hash holding the numerical values of the flags that are passed in the + # Hash holding the numerical values of the flags that are passed in the # `flags` argument of a FFTW planner routine. Multiple flags can be passed # to one instance of the planner. Their values are OR'd ('|') and then passed. # For example, for passing the FFTW_ESTIMATE constant, use :estimate. # # nmatrix-fftw supports the following flags into the planning routine: - # * :estimate - Equivalent to FFTW_ESTIMATE. Specifies that, instead of - # actual measurements of different algorithms, a simple heuristic is - # used to pick a (probably sub-optimal) plan quickly. With this flag, + # * :estimate - Equivalent to FFTW_ESTIMATE. Specifies that, instead of + # actual measurements of different algorithms, a simple heuristic is + # used to pick a (probably sub-optimal) plan quickly. With this flag, # the input/output arrays are not overwritten during planning. # * :measure - Equivalent to FFTW_MEASURE. Tells FFTW to find an optimized # plan by actually computing several FFTs and measuring their execution - # time. Depending on your machine, this can take some time (often a few + # time. Depending on your machine, this can take some time (often a few # seconds). # * :patient - Equivalent to FFTW_PATIENT. Like FFTW_MEASURE, but considers - # a wider range of algorithms and often produces a “more optimal” plan + # a wider range of algorithms and often produces a “more optimal” plan # (especially for large transforms), but at the expense of several times # longer planning time (especially for large transforms). - # * :exhaustive - Equivalent to FFTW_EXHAUSTIVE. Like FFTW_PATIENT, but - # considers an even wider range of algorithms, including many that we - # think are unlikely to be fast, to produce the most optimal plan but + # * :exhaustive - Equivalent to FFTW_EXHAUSTIVE. Like FFTW_PATIENT, but + # considers an even wider range of algorithms, including many that we + # think are unlikely to be fast, to produce the most optimal plan but # with a substantially increased planning time. # # @see http://www.fftw.org/fftw3_doc/Planner-Flags.html#Planner-Flags @@ -112,28 +111,28 @@ class Plan estimate: 64, measure: 0, exhaustive: 8, - patient: 32 + patient: 32, } # Hash holding numerical values of the direction in which a :complex_complex # type FFT should be performed. # # @see http://www.fftw.org/fftw3_doc/Complex-One_002dDimensional-DFTs.html#Complex-One_002dDimensional-DFTs - # (The fourth argument, sign, can be either FFTW_FORWARD (-1) or + # (The fourth argument, sign, can be either FFTW_FORWARD (-1) or # FFTW_BACKWARD (+1), and indicates the direction of the transform you are # interested in; technically, it is the sign of the exponent in the transform) FFT_DIRECTION_HASH = { forward: -1, - backward: 1 + backward: 1, } # Hash holding numerical equivalents of the DFT type. Used for determining # DFT type in C level. DATA_TYPE_HASH = { complex_complex: 0, - real_complex: 1, - complex_real: 2, - real_real: 3 + real_complex: 1, + complex_real: 2, + real_real: 3, } # Array holding valid options that can be passed into NMatrix::FFTW::Plan @@ -149,7 +148,7 @@ class Plan attr_reader :size # @!attribute [r] type - # @return [Symbol] Type of the plan. Can be :complex_complex, + # @return [Symbol] Type of the plan. Can be :complex_complex, # :complex_real, :real_complex or :real_real attr_reader :type @@ -171,12 +170,12 @@ class Plan attr_reader :dim # @!attribute [r] input - # @return [NMatrix] Input NMatrix. Will be valid once the + # @return [NMatrix] Input NMatrix. Will be valid once the # NMatrix::FFTW::Plan#set_input method has been called. attr_reader :input # @!attribute [r] output - # @return [NMatrix] Output NMatrix. Will be valid once the + # @return [NMatrix] Output NMatrix. Will be valid once the # NMatrix::FFTW::Plan#execute method has been called. attr_reader :output @@ -191,11 +190,11 @@ class Plan # Create a plan for a DFT. The FFTW library requires that you first create # a plan for performing a DFT, so that FFTW can optimize its algorithms # according to your computer's hardware and various user supplied options. - # - # @see http://www.fftw.org/doc/Using-Plans.html + # + # @see http://www.fftw.org/doc/Using-Plans.html # For a comprehensive explanation of the FFTW planner. # @param shape [Array, Fixnum] Specify the shape of the plan. For 1D - # fourier transforms this can be a single number specifying the length of + # fourier transforms this can be a single number specifying the length of # the input. For multi-dimensional transforms, specify an Array containing # the length of each dimension. # @param [Hash] opts the options to create a message with. @@ -216,12 +215,12 @@ class Plan # at http://www.fftw.org/fftw3_doc/Planner-Flags.html#Planner-Flags. # @see REAL_REAL_FFT_KINDS_HASH # @option opts [Symbol] :direction (:forward) The direction of a DFT of - # type :complex_complex. Technically, it is the sign of the exponent in + # type :complex_complex. Technically, it is the sign of the exponent in # the transform. :forward corresponds to -1 and :backward to +1. # @see FFT_DIRECTION_HASH # @option opts [Array] :real_real_kind When the type of transform is :real_real, # specify the kind of transform that should be performed FOR EACH AXIS - # of input. The position of the symbol in the Array corresponds to the + # of input. The position of the symbol in the Array corresponds to the # axis of the input. The number of elements in :real_real_kind must be equal to # :dim. Can accept one of the inputs specified in REAL_REAL_FFT_KINDS_HASH. # @see REAL_REAL_FFT_KINDS_HASH @@ -237,13 +236,13 @@ class Plan # plan.set_input input # plan.execute # print plan.output - def initialize shape, opts={} + def initialize shape, opts = {} verify_opts opts opts = { dim: 1, flags: :estimate, direction: :forward, - type: :complex_complex + type: :complex_complex, }.merge(opts) @type = opts[:type] @@ -252,19 +251,19 @@ def initialize shape, opts={} @shape = shape.is_a?(Array) ? shape : [shape] @size = @shape[0...@dim].inject(:*) @flags = opts[:flags].is_a?(Array) ? opts[:flags] : [opts[:flags]] - @real_real_kind = opts[:real_real_kind] + @real_real_kind = opts[:real_real_kind] raise ArgumentError, ":real_real_kind option must be specified for :real_real type transforms" if - @real_real_kind.nil? and @type == :real_real + @real_real_kind.nil? && (@type == :real_real) raise ArgumentError, "Specify kind of transform of each axis of input." if - @real_real_kind and @real_real_kind.size != @dim + @real_real_kind && (@real_real_kind.size != @dim) raise ArgumentError, "dim (#{@dim}) cannot be more than size of shape #{@shape.size}" if @dim > @shape.size - @plan_data = c_create_plan(@shape, @size, @dim, - combine_flags(@flags), FFT_DIRECTION_HASH[@direction], + @plan_data = c_create_plan(@shape, @size, @dim, + combine_flags(@flags), FFT_DIRECTION_HASH[@direction], DATA_TYPE_HASH[@type], encoded_rr_kind) end @@ -280,7 +279,7 @@ def set_input ip raise ArgumentError, "stype must be dense." if ip.stype != :dense raise ArgumentError, "size of input (#{ip.size}) cannot be greater than planned input size #{@size}" if ip.size != @size - + case @type when :complex_complex, :complex_real raise ArgumentError, "dtype must be complex128." if ip.dtype != :complex128 @@ -299,21 +298,22 @@ def set_input ip # sucessfully computed, 'true' will be returned and you can access the # computed output from the NMatrix::FFTW::Plan#output accessor. def execute - @output = - case @type - when :complex_complex - @input.clone_structure - when :real_complex - NMatrix.new([@input.size/2 + 1], dtype: :complex128) - when :complex_real, :real_real - NMatrix.new([@input.size], dtype: :float64) - else - raise TypeError, "Invalid type #{@type}" - end + @output = + case @type + when :complex_complex + @input.clone_structure + when :real_complex + NMatrix.new([@input.size / 2 + 1], dtype: :complex128) + when :complex_real, :real_real + NMatrix.new([@input.size], dtype: :float64) + else + raise TypeError, "Invalid type #{@type}" + end c_execute(@output, @plan_data, DATA_TYPE_HASH[@type]) end - private + + private # Combine flags received from the user (Symbols) into their respective # numeric equivalents and then 'OR' (|) all of them so the resulting number @@ -340,4 +340,4 @@ def encoded_rr_kind end end end -end \ No newline at end of file +end diff --git a/lib/nmatrix/homogeneous.rb b/lib/nmatrix/homogeneous.rb index d52e6675..6ddf63f9 100644 --- a/lib/nmatrix/homogeneous.rb +++ b/lib/nmatrix/homogeneous.rb @@ -63,34 +63,33 @@ class << self # 0.0 0.5 0.866025 0.0 # 0.0 0.0 0.0 1.0 # - def x_rotation angle_in_radians, opts={} + def x_rotation angle_in_radians, opts = {} c = Math.cos(angle_in_radians) s = Math.sin(angle_in_radians) NMatrix.new(4, [1.0, 0.0, 0.0, 0.0, 0.0, c, -s, 0.0, - 0.0, s, c, 0.0, - 0.0, 0.0, 0.0, 1.0], {dtype: :float64}.merge(opts)) + 0.0, s, c, 0.0, + 0.0, 0.0, 0.0, 1.0,], {dtype: :float64}.merge(opts)) end - def y_rotation angle_in_radians, opts={} + def y_rotation angle_in_radians, opts = {} c = Math.cos(angle_in_radians) s = Math.sin(angle_in_radians) - NMatrix.new(4, [ c, 0.0, s, 0.0, + NMatrix.new(4, [c, 0.0, s, 0.0, 0.0, 1.0, 0.0, 0.0, - -s, 0.0, c, 0.0, - 0.0, 0.0, 0.0, 1.0], {dtype: :float64}.merge(opts)) + -s, 0.0, c, 0.0, + 0.0, 0.0, 0.0, 1.0,], {dtype: :float64}.merge(opts)) end - def z_rotation angle_in_radians, opts={} + def z_rotation angle_in_radians, opts = {} c = Math.cos(angle_in_radians) s = Math.sin(angle_in_radians) - NMatrix.new(4, [ c, -s, 0.0, 0.0, - s, c, 0.0, 0.0, + NMatrix.new(4, [c, -s, 0.0, 0.0, + s, c, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0], {dtype: :float64}.merge(opts)) + 0.0, 0.0, 0.0, 1.0,], {dtype: :float64}.merge(opts)) end - # # call-seq: # translation(x, y, z) -> NMatrix @@ -136,7 +135,7 @@ def translation *args else NMatrix.eye(4, opts) end - n[0..2,3] = xyz + n[0..2, 3] = xyz n end end @@ -157,46 +156,46 @@ def translation *args # n.quaternion # => [1, 0, 0, 0] # def quaternion - raise(ShapeError, "Expected square matrix") if self.shape[0] != self.shape[1] - raise(ShapeError, "Expected 3x3 rotation (or 4x4 homogeneous) matrix") if self.shape[0] > 4 || self.shape[0] < 3 + raise(ShapeError, "Expected square matrix") if shape[0] != shape[1] + raise(ShapeError, "Expected 3x3 rotation (or 4x4 homogeneous) matrix") if shape[0] > 4 || shape[0] < 3 - q = NMatrix.new([4], dtype: self.dtype == :float32 ? :float32: :float64) - rotation_trace = self[0,0] + self[1,1] + self[2,2] + q = NMatrix.new([4], dtype: dtype == :float32 ? :float32 : :float64) + rotation_trace = self[0, 0] + self[1, 1] + self[2, 2] if rotation_trace >= 0 - self_w = self.shape[0] == 4 ? self[3,3] : 1.0 + self_w = shape[0] == 4 ? self[3, 3] : 1.0 root_of_homogeneous_trace = Math.sqrt(rotation_trace + self_w) q[0] = root_of_homogeneous_trace * 0.5 s = 0.5 / root_of_homogeneous_trace - q[1] = (self[2,1] - self[1,2]) * s - q[2] = (self[0,2] - self[2,0]) * s - q[3] = (self[1,0] - self[0,1]) * s + q[1] = (self[2, 1] - self[1, 2]) * s + q[2] = (self[0, 2] - self[2, 0]) * s + q[3] = (self[1, 0] - self[0, 1]) * s else h = 0 - h = 1 if self[1,1] > self[0,0] - h = 2 if self[2,2] > self[h,h] + h = 1 if self[1, 1] > self[0, 0] + h = 2 if self[2, 2] > self[h, h] - case_macro = Proc.new do |i,j,k,ii,jj,kk| + case_macro = proc { |i, j, k, ii, jj, kk| qq = NMatrix.new([4], dtype: :float64) - self_w = self.shape[0] == 4 ? self[3,3] : 1.0 - s = Math.sqrt( (self[ii,ii] - (self[jj,jj] + self[kk,kk])) + self_w) - qq[i] = s*0.5 + self_w = shape[0] == 4 ? self[3, 3] : 1.0 + s = Math.sqrt((self[ii, ii] - (self[jj, jj] + self[kk, kk])) + self_w) + qq[i] = s * 0.5 s = 0.5 / s - qq[j] = (self[ii,jj] + self[jj,ii]) * s - qq[k] = (self[kk,ii] + self[ii,kk]) * s - qq[0] = (self[kk,jj] - self[jj,kk]) * s + qq[j] = (self[ii, jj] + self[jj, ii]) * s + qq[k] = (self[kk, ii] + self[ii, kk]) * s + qq[0] = (self[kk, jj] - self[jj, kk]) * s qq - end + } case h when 0 - q = case_macro.call(1,2,3, 0,1,2) + q = case_macro.call(1, 2, 3, 0, 1, 2) when 1 - q = case_macro.call(2,3,1, 1,2,0) + q = case_macro.call(2, 3, 1, 1, 2, 0) when 2 - q = case_macro.call(3,1,2, 2,0,1) + q = case_macro.call(3, 1, 2, 2, 0, 1) end - self_w = self.shape[0] == 4 ? self[3,3] : 1.0 + self_w = shape[0] == 4 ? self[3, 3] : 1.0 if self_w != 1 s = 1.0 / Math.sqrt(self_w) q[0] *= s @@ -226,16 +225,16 @@ def quaternion # q.angle_vector # => [1, 0, 0, 0] # def angle_vector - raise(ShapeError, "Expected length-4 vector or matrix (quaternion)") if self.shape[0] != 4 + raise(ShapeError, "Expected length-4 vector or matrix (quaternion)") if shape[0] != 4 raise("Expected unit quaternion") if self[0] > 1 - xyz = NMatrix.new([3], dtype: self.dtype) + xyz = NMatrix.new([3], dtype: dtype) angle = 2 * Math.acos(self[0]) - s = Math.sqrt(1.0 - self[0]*self[0]) + s = Math.sqrt(1.0 - self[0] * self[0]) xyz[0..2] = self[1..3] xyz /= s if s >= 0.001 # avoid divide by zero - return [angle, xyz] + [angle, xyz] end -end \ No newline at end of file +end diff --git a/lib/nmatrix/io/fortran_format.rb b/lib/nmatrix/io/fortran_format.rb index 61b68b4f..3ff76994 100644 --- a/lib/nmatrix/io/fortran_format.rb +++ b/lib/nmatrix/io/fortran_format.rb @@ -24,32 +24,30 @@ # == io/matlab/fortran_format.rb # # A parser for making sense of FORTRAN formats. -# => Only handles R (real), F (float) and E (exponential) format codes. +# => Only handles R (real), F (float) and E (exponential) format codes. #++ class NMatrix module IO module FortranFormat - # Class for reading strings in FORTRAN format for specifying attributes - # of numerical data in a file. Supports F (float), E (exponential) and + # of numerical data in a file. Supports F (float), E (exponential) and # R (real). - # + # # == Usage - # + # # p = NMatrix::IO::FortranFormat::Reader.new("(16I5)") # v = p.parse - # puts v #=> { :format_code => "INT_ID", + # puts v #=> { :format_code => "INT_ID", # #=> :repeat => 16, # #=> :field_width => 5 } class Reader - - # Accepts a string in FORTRAN format and initializes the - # NMatrix::IO::FortranFormat::Reader object for further parsing of the + # Accepts a string in FORTRAN format and initializes the + # NMatrix::IO::FortranFormat::Reader object for further parsing of the # data. - # + # # == Arguments - # + # # * +string+ - FORTRAN format string to be parsed. def initialize string @string = string @@ -57,14 +55,14 @@ def initialize string # Parses the FORTRAN format string passed in initialize and returns # a hash of the results. - # + # # == Result Hash Format - # + # # Take note that some of the below parameters may be absent in the hash # depending on the type of string being parsed. - # - # * +:format_code+ - A string containing the format code of the read data. - # Can be "INT_ID", "FP_ID" or "EXP_ID" + # + # * +:format_code+ - A string containing the format code of the read data. + # Can be "INT_ID", "FP_ID" or "EXP_ID" # * +:repeat+ - Number of times this format will repeat in a line. # * +:field_width+ - Width of the numerical part of the number. # * +:post_decimal_width+ - Width of the numerals after the decimal point. @@ -85,9 +83,10 @@ def parse @result end - private + private + def parentheses_missing? - true if @string[0] != '(' or @string[-1] != ')' + true if (@string[0] != "(") || (@string[-1] != ")") end # Changing any of the following regular expressions can lead to disaster @@ -95,7 +94,7 @@ def valid_fortran_format? @mdata = @string.match(/\A(\d*)(I)(\d+)\z/) # check for integer format @mdata = @string.match(/\A(\d*)(F)(\d+)\.(\d+)\z/) \ if @mdata.nil? # check for floating point if not integer - @mdata = @string.match(/\A(\d*)(E)(\d+)\.(\d+)(E)?(\d*)\z/) \ + @mdata = @string.match(/\A(\d*)(E)(\d+)\.(\d+)(E)?(\d*)\z/) \ if @mdata.nil? # check for exponential format if not floating point @mdata @@ -113,26 +112,25 @@ def load_result def create_integer_hash @result[:format_code] = "INT_ID" - @result[:repeat] = @mdata[1].to_i if !@mdata[1].empty? + @result[:repeat] = @mdata[1].to_i unless @mdata[1].empty? @result[:field_width] = @mdata[3].to_i end def create_float_hash @result[:format_code] = "FP_ID" - @result[:repeat] = @mdata[1].to_i if !@mdata[1].empty? + @result[:repeat] = @mdata[1].to_i unless @mdata[1].empty? @result[:field_width] = @mdata[3].to_i @result[:post_decimal_width] = @mdata[4].to_i end def create_exp_hash @result[:format_code] = "EXP_ID" - @result[:repeat] = @mdata[1].to_i if !@mdata[1].empty? + @result[:repeat] = @mdata[1].to_i unless @mdata[1].empty? @result[:field_width] = @mdata[3].to_i @result[:post_decimal_width] = @mdata[4].to_i - @result[:exponent_width] = @mdata[6].to_i if !@mdata[6].empty? + @result[:exponent_width] = @mdata[6].to_i unless @mdata[6].empty? end end - end end -end \ No newline at end of file +end diff --git a/lib/nmatrix/io/harwell_boeing.rb b/lib/nmatrix/io/harwell_boeing.rb index 6155c7c3..79f3830f 100644 --- a/lib/nmatrix/io/harwell_boeing.rb +++ b/lib/nmatrix/io/harwell_boeing.rb @@ -29,45 +29,44 @@ # => Returned NMatrix is of type :float64 #++ -require_relative './fortran_format.rb' +require_relative "./fortran_format.rb" class NMatrix module IO module HarwellBoeing - class << self - # Loads the contents of a valid Harwell Boeing format file and + # Loads the contents of a valid Harwell Boeing format file and # returns an NMatrix object with the values of the file and optionally # only the header info. - # + # # Supports only assembled, non-symmetric, real matrices. File name must # have matrix type as extension. - # + # # Example - test_file.rua - # + # # == Arguments - # + # # * +file_path+ - Path of the Harwell Boeing file to load. # * +opts+ - Options for specifying whether you want # the values and header or only the header. - # + # # == Options - # + # # * +:header+ - If specified as *true*, will return only the header of # the HB file.Will return the NMatrix object and # header as an array if left blank. - # + # # == Usage - # + # # mat, head = NMatrix::IO::HarwellBoeing.load("test_file.rua") - # + # # head = NMatrix::IO::HarwellBoeing.load("test_file.rua", {header: true}) - # + # # == Alternate Usage - # + # # You can specify the file using NMatrix::IO::Reader.new("path/to/file") # and then call *header* or *values* on the resulting object. - def load file_path, opts={} + def load file_path, opts = {} hb_obj = NMatrix::IO::HarwellBoeing::Reader.new(file_path) return hb_obj.header if opts[:header] @@ -78,8 +77,10 @@ def load file_path, opts={} class Reader def initialize file_name - raise(IOError, "Unsupported file format. Specify file as \ - file_name.rua.") if !file_name.match(/.*\.[rR][uU][aA]/) + unless /.*\.[rR][uU][aA]/.match?(file_name) + raise(IOError, "Unsupported file format. Specify file as \ + file_name.rua.") + end @file_name = file_name @header = {} @@ -87,7 +88,7 @@ def initialize file_name end def header - return @header if !@header.empty? + return @header unless @header.empty? @file = File.open @file_name, "r" line = @file.gets @@ -110,8 +111,10 @@ def header @header[:mxtype] = line[0...3] - raise(IOError, "Currently supports only real, assembled, unsymmetric \ - matrices.") if !@header[:mxtype].match(/RUA/) + unless /RUA/.match?(@header[:mxtype]) + raise(IOError, "Currently supports only real, assembled, unsymmetric \ + matrices.") + end @header[:nrow] = line[13...28].strip.to_i @header[:ncol] = line[28...42].strip.to_i @@ -133,30 +136,30 @@ def header def values @header = header if @header.empty? @file.lineno = 5 if @file.lineno != 5 - @matrix = NMatrix.new([ @header[:nrow], @header[:ncol] ], - 0, dtype: :float64) + @matrix = NMatrix.new([@header[:nrow], @header[:ncol]], + 0, dtype: :float64) read_column_pointers read_row_indices read_values @file.close - + assemble_matrix @matrix end - private + private def read_column_pointers - @col_ptrs = [] + @col_ptrs = [] pointer_lines = @header[:ptrcrd] pointers_per_line = @header[:ptrfmt][:repeat] pointer_width = @header[:ptrfmt][:field_width] - @col_ptrs = read_numbers :to_i, pointer_lines, pointers_per_line, - pointer_width + @col_ptrs = read_numbers :to_i, pointer_lines, pointers_per_line, + pointer_width @col_ptrs.map! {|c| c -= 1} end @@ -167,8 +170,8 @@ def read_row_indices indices_per_line = @header[:indfmt][:repeat] row_width = @header[:indfmt][:field_width] - @row_indices = read_numbers :to_i, row_lines, indices_per_line, - row_width + @row_indices = read_numbers :to_i, row_lines, indices_per_line, + row_width @row_indices.map! {|r| r -= 1} end @@ -177,16 +180,16 @@ def read_values @vals = [] value_lines = @header[:valcrd] values_per_line = @header[:valfmt][:repeat] - value_width = @header[:valfmt][:field_width] + value_width = @header[:valfmt][:field_width] - @vals = read_numbers :to_f, value_lines, values_per_line, - value_width + @vals = read_numbers :to_f, value_lines, values_per_line, + value_width end def read_numbers to_dtype, num_of_lines, numbers_per_line, number_width data = [] - num_of_lines.times do + num_of_lines.times do line = @file.gets index = 0 @@ -206,7 +209,7 @@ def read_numbers to_dtype, num_of_lines, numbers_per_line, number_width def assemble_matrix col = 0 @col_ptrs[0..-2].each_index do |index| - @col_ptrs[index].upto(@col_ptrs[index+1] - 1) do |row_ptr| + @col_ptrs[index].upto(@col_ptrs[index + 1] - 1) do |row_ptr| row = @row_indices[row_ptr] @matrix[row, col] = @vals[row_ptr] end @@ -215,7 +218,6 @@ def assemble_matrix end end end - end end -end \ No newline at end of file +end diff --git a/lib/nmatrix/io/market.rb b/lib/nmatrix/io/market.rb index b9950f07..27c71812 100644 --- a/lib/nmatrix/io/market.rb +++ b/lib/nmatrix/io/market.rb @@ -40,20 +40,19 @@ # * http://math.nist.gov/MatrixMarket/formats.html module NMatrix::IO::Market CONVERTER_AND_DTYPE = { - :real => [:to_f, :float64], - :complex => [:to_c, :complex128], - :integer => [:to_i, :int64], - :pattern => [:to_i, :byte] + real: [:to_f, :float64], + complex: [:to_c, :complex128], + integer: [:to_i, :int64], + pattern: [:to_i, :byte], } #:nodoc: ENTRY_TYPE = { - :byte => :integer, :int8 => :integer, :int16 => :integer, - :int32 => :integer, :int64 => :integer,:float32 => :real, - :float64 => :real, :complex64 => :complex, :complex128 => :complex + byte: :integer, int8: :integer, int16: :integer, + int32: :integer, int64: :integer, float32: :real, + float64: :real, complex64: :complex, complex128: :complex, } #:nodoc: class << self - # call-seq: # load(filename) -> NMatrix # @@ -64,7 +63,6 @@ class << self # * *Raises* : # - +IOError+ -> expected type code line beginning with '%%MatrixMarket matrix' def load(filename) - f = File.new(filename, "r") header = f.gets @@ -78,7 +76,7 @@ def load(filename) symmetry = header[4].downcase.to_sym converter, default_dtype = CONVERTER_AND_DTYPE[entry_type] - if header[2] == 'coordinate' + if header[2] == "coordinate" load_coordinate f, converter, default_dtype, entry_type, symmetry else load_array f, converter, default_dtype, entry_type, symmetry @@ -99,8 +97,8 @@ def load(filename) # - +DataTypeError+ -> MatrixMarket does not support Ruby objects. # - +ArgumentError+ -> Expected two-dimensional NMatrix. def save(matrix, filename, options = {}) - options = {:pattern => false, - :symmetry => :general}.merge(options) + options = {pattern: false, + symmetry: :general,}.merge(options) mode = matrix.stype == :dense ? :array : :coordinate if [:object].include?(matrix.dtype) @@ -111,13 +109,13 @@ def save(matrix, filename, options = {}) raise(ArgumentError, "expected two-dimensional NMatrix") \ if matrix.dim != 2 - f = File.new(filename, 'w') + f = File.new(filename, "w") f.puts "%%MatrixMarket matrix #{mode} #{entry_type} #{options[:symmetry]}" if matrix.stype == :dense save_array matrix, f, options[:symmetry] - elsif [:list,:yale].include?(matrix.stype) + elsif [:list, :yale].include?(matrix.stype) save_coordinate matrix, f, options[:symmetry], options[:pattern] end @@ -126,7 +124,6 @@ def save(matrix, filename, options = {}) true end - protected def save_coordinate matrix, file, symmetry, pattern @@ -149,27 +146,26 @@ def save_coordinate matrix, file, symmetry, pattern rows.each_pair do |i, columns| columns.each_pair do |j, val| next if symmetry != :general && j > i - file.puts(pattern ? "\t#{i+1}\t#{j+1}" : "\t#{i+1}\t#{j+1}\t#{val}") + file.puts(pattern ? "\t#{i + 1}\t#{j + 1}" : "\t#{i + 1}\t#{j + 1}\t#{val}") end end file end - def save_array matrix, file, symmetry file.puts [matrix.shape[0], matrix.shape[1]].join("\t") if symmetry == :general (0...matrix.shape[1]).each do |j| (0...matrix.shape[0]).each do |i| - file.puts matrix[i,j] + file.puts matrix[i, j] end end else # :symmetric, :'skew-symmetric', :hermitian (0...matrix.shape[1]).each do |j| (j...matrix.shape[0]).each do |i| - file.puts matrix[i,j] + file.puts matrix[i, j] end end end @@ -177,7 +173,6 @@ def save_array matrix, file, symmetry file end - def load_array file, converter, dtype, entry_type, symmetry mat = nil @@ -192,15 +187,15 @@ def load_array file, converter, dtype, entry_type, symmetry (0...mat.shape[1]).each do |j| (0...mat.shape[0]).each do |i| datum = file.gets.chomp.send(converter) - mat[i,j] = datum + mat[i, j] = datum unless i == j || symmetry == :general if symmetry == :symmetric - mat[j,i] = datum + mat[j, i] = datum elsif symmetry == :hermitian - mat[j,i] = Complex.new(datum.real, -datum.imag) + mat[j, i] = Complex.new(datum.real, -datum.imag) elsif symmetry == :'skew-symmetric' - mat[j,i] = -datum + mat[j, i] = -datum end end end @@ -211,17 +206,15 @@ def load_array file, converter, dtype, entry_type, symmetry mat end - # Creates a :list NMatrix from a coordinate-list MatrixMarket file. def load_coordinate file, converter, dtype, entry_type, symmetry - mat = nil # Read until we get the dimensions and nonzeros while line = file.gets line.chomp! line.lstrip! - line, comment = line.split('%', 2) # ignore comments + line, comment = line.split("%", 2) # ignore comments if line.size > 4 shape0, shape1 = line.split mat = NMatrix.new(:list, [shape0.to_i, shape1.to_i], 0, dtype) @@ -233,7 +226,7 @@ def load_coordinate file, converter, dtype, entry_type, symmetry while line = file.gets line.chomp! line.lstrip! - line, comment = line.split('%', 2) # ignore comments + line, comment = line.split("%", 2) # ignore comments next unless line.size >= 5 # ignore empty lines diff --git a/lib/nmatrix/io/mat5_reader.rb b/lib/nmatrix/io/mat5_reader.rb index 589f0184..956116da 100644 --- a/lib/nmatrix/io/mat5_reader.rb +++ b/lib/nmatrix/io/mat5_reader.rb @@ -27,10 +27,9 @@ # #++ -require_relative './mat_reader.rb' +require_relative "./mat_reader.rb" module NMatrix::IO::Matlab - # Reader (and eventual writer) for a version 5 .mat file. class Mat5Reader < MatReader #:nodoc: attr_reader :file_header, :first_tag_field, :first_data_field @@ -41,7 +40,7 @@ class Compressed #:nodoc: attr_reader :byte_order def initialize(stream = nil, byte_order = nil, content_or_bytes = nil) - @stream = stream + @stream = stream @byte_order = byte_order if content_or_bytes.is_a?(String) @@ -68,7 +67,7 @@ def padded_bytes end def write_packed(packedio, options = {}) - packedio << [compressed, {:bytes => padded_bytes}.merge(options)] + packedio << [compressed, {bytes: padded_bytes}.merge(options)] end def read_packed(packedio, options) @@ -77,10 +76,11 @@ def read_packed(packedio, options) end protected + def extract - require 'zlib' + require "zlib" - zstream = Zlib::Inflate.new #(-Zlib::MAX_WBITS) # No header + zstream = Zlib::Inflate.new # (-Zlib::MAX_WBITS) # No header returning(zstream.inflate(@compressed)) do zstream.finish @@ -90,17 +90,18 @@ def extract end MatrixDataStruct = Struct.new( - :cells, :logical, :global, :complex, - :nonzero_max,:matlab_class, :dimensions, - :matlab_name, :real_part,:imaginary_part, - :row_index, :column_index) + :cells, :logical, :global, :complex, + :nonzero_max, :matlab_class, :dimensions, + :matlab_name, :real_part, :imaginary_part, + :row_index, :column_index + ) class MatrixData < MatrixDataStruct #:nodoc: include Packable def write_packed(packedio, options) raise NotImplementedError - packedio << [info, {:bytes => padded_bytes}.merge(options)] + packedio << [info, {bytes: padded_bytes}.merge(options)] end # call-seq: @@ -120,9 +121,9 @@ def write_packed(packedio, options) # See also to_nm, which is responsible for NMatrix instantiation. def to_ruby case matlab_class - when :mxSPARSE then return to_nm - when :mxCELL then return self.cells.collect { |c| c.to_ruby } - else return to_nm + when :mxSPARSE then to_nm + when :mxCELL then cells.collect { |c| c.to_ruby } + else to_nm end end @@ -134,9 +135,9 @@ def to_ruby # TODO: Needs to be verified that unsigned MATLAB types are being # converted to the correct NMatrix signed dtypes. def guess_dtype_from_mdtype - dtype = MatReader::MDTYPE_TO_DTYPE[self.real_part.tag.data_type] + dtype = MatReader::MDTYPE_TO_DTYPE[real_part.tag.data_type] - return dtype unless self.complex + return dtype unless complex dtype == :float32 ? :complex64 : :complex128 end @@ -152,23 +153,22 @@ def guess_dtype_from_mdtype # def unpacked_data(real_mdtype = nil, imag_mdtype = nil) # Get Matlab data type and unpack args - real_mdtype ||= self.real_part.tag.data_type + real_mdtype ||= real_part.tag.data_type real_unpack_args = MatReader::MDTYPE_UNPACK_ARGS[real_mdtype] # zip real and complex components together, or just return real component - if self.complex - imag_mdtype ||= self.imaginary_part.tag.data_type + if complex + imag_mdtype ||= imaginary_part.tag.data_type imag_unpack_args = MatReader::MDTYPE_UNPACK_ARGS[imag_mdtype] - unpacked_real = self.real_part.data.unpack(real_unpack_args) - unpacked_imag = self.imaginary_part.data.unpack(imag_unpack_args) + unpacked_real = real_part.data.unpack(real_unpack_args) + unpacked_imag = imaginary_part.data.unpack(imag_unpack_args) unpacked_real.zip(unpacked_imag).flatten else - length = self.dimensions.inject(1) { |a,b| a * b } # get the product - self.real_part.data.unpack(*(real_unpack_args*length)) + length = dimensions.inject(1) { |a, b| a * b } # get the product + real_part.data.unpack(*(real_unpack_args * length)) end - end # Unpacks and repacks data into the appropriate format for NMatrix. @@ -185,8 +185,7 @@ def unpacked_data(real_mdtype = nil, imag_mdtype = nil) # This function calls repack and complex_merge, which are both defined in # io.cpp. def repacked_data(to_dtype = nil) - - real_mdtype = self.real_part.tag.data_type + real_mdtype = real_part.tag.data_type # Figure out what dtype to use based on the MATLAB data-types # (mdtypes). They could be different for real and imaginary, so call @@ -194,12 +193,12 @@ def repacked_data(to_dtype = nil) components = [] # real and imaginary parts or just the real part - if self.complex - imag_mdtype = self.imaginary_part.tag.data_type + if complex + imag_mdtype = imaginary_part.tag.data_type # Make sure we convert both mdtypes do the same dtype to_dtype ||= NMatrix.upcast(MatReader::MDTYPE_TO_DTYPE[real_mdtype], \ - MatReader::MDTYPE_TO_DTYPE[imag_mdtype]) + MatReader::MDTYPE_TO_DTYPE[imag_mdtype]) # Let's make sure we don't try to send NMatrix complex integers. # We need complex floating points. @@ -209,8 +208,8 @@ def repacked_data(to_dtype = nil) STDERR.puts "imag: Requesting dtype #{to_dtype.inspect}" # Repack the imaginary part - components[1] = ::NMatrix::IO::Matlab.repack( self.imaginary_part.data, \ - imag_mdtype, :dtype => to_dtype ) + components[1] = ::NMatrix::IO::Matlab.repack(imaginary_part.data, \ + imag_mdtype, dtype: to_dtype) else @@ -219,7 +218,7 @@ def repacked_data(to_dtype = nil) # Sometimes repacking isn't necessary -- sometimes the format is already good if MatReader::NO_REPACK.include?(real_mdtype) STDERR.puts "No repack" - return [self.real_part.data, to_dtype] + return [real_part.data, to_dtype] end end @@ -227,12 +226,14 @@ def repacked_data(to_dtype = nil) # Repack the real part STDERR.puts "real: Requesting dtype #{to_dtype.inspect}" components[0] = ::NMatrix::IO::Matlab.repack( \ - self.real_part.data, real_mdtype, :dtype => to_dtype ) + real_part.data, real_mdtype, dtype: to_dtype + ) # Merge the two parts if complex, or just return the real part. - [self.complex ? ::NMatrix::IO::Matlab.complex_merge( \ - components[0], components[1], to_dtype ) : components[0], - to_dtype] + [complex ? ::NMatrix::IO::Matlab.complex_merge( \ + components[0], components[1], to_dtype + ) : components[0], + to_dtype,] end # Unpacks and repacks index data into the appropriate format for NMatrix. @@ -241,9 +242,11 @@ def repacked_data(to_dtype = nil) # repack, just returns directly. def repacked_indices repacked_row_indices = ::NMatrix::IO::Matlab.repack( \ - self.row_index.data, :miINT32, :itype ) + row_index.data, :miINT32, :itype + ) repacked_col_indices = ::NMatrix::IO::Matlab.repack( \ - self.column_index.data, :miINT32, :itype ) + column_index.data, :miINT32, :itype + ) [repacked_row_indices, repacked_col_indices] end @@ -271,26 +274,26 @@ def repacked_indices # def to_nm(dtype = nil) # Hardest part is figuring out from_dtype, from_index_dtype, and dtype. - dtype ||= guess_dtype_from_mdtype - from_dtype = MatReader::MDTYPE_TO_DTYPE[self.real_part.tag.data_type] + dtype ||= guess_dtype_from_mdtype + from_dtype = MatReader::MDTYPE_TO_DTYPE[real_part.tag.data_type] # Create the same kind of matrix that MATLAB saved. case matlab_class when :mxSPARSE raise(NotImplementedError, "expected .mat row indices to be of type :miINT32") unless row_index.tag.data_type == :miINT32 raise(NotImplementedError, "expected .mat column indices to be of type :miINT32") unless column_index.tag.data_type == :miINT32 - #require 'pry' - #binding.pry + # require 'pry' + # binding.pry # MATLAB always uses :miINT32 for indices according to the spec ia_ja = repacked_indices data_str, repacked_dtype = repacked_data(dtype) - NMatrix.new(:yale, self.dimensions.reverse, repacked_dtype, \ - ia_ja[0], ia_ja[1], data_str, repacked_dtype) + NMatrix.new(:yale, dimensions.reverse, repacked_dtype, \ + ia_ja[0], ia_ja[1], data_str, repacked_dtype) else # Call regular dense constructor. - NMatrix.new(:dense, self.dimensions.reverse, unpacked_data, dtype).transpose + NMatrix.new(:dense, dimensions.reverse, unpacked_data, dtype).transpose end end @@ -299,63 +302,65 @@ def read_packed(packedio, options) self.matlab_class = MatReader::MCLASSES[flags_class % 16] - self.logical = (flags_class >> 8) % 2 == 1 ? true : false - self.global = (flags_class >> 9) % 2 == 1 ? true : false - self.complex = (flags_class >> 10) % 2 == 1 ? true : false + self.logical = (flags_class >> 8) % 2 == 1 + self.global = (flags_class >> 9) % 2 == 1 + self.complex = (flags_class >> 10) % 2 == 1 dimensions_tag_data = packedio.read([Element, options]) self.dimensions = dimensions_tag_data.data begin - name_tag_data = packedio.read([Element, options]) + name_tag_data = packedio.read([Element, options]) self.matlab_name = name_tag_data.data.is_a?(Array) ? \ - name_tag_data.data.collect { |i| i.chr }.join('') : \ + name_tag_data.data.collect { |i| i.chr }.join("") : \ name_tag_data.data.chr - rescue ElementDataIOError => e STDERR.puts "ERROR: Failure while trying to read Matlab variable name: #{name_tag_data.inspect}" - STDERR.puts 'Element Tag:' + STDERR.puts "Element Tag:" STDERR.puts " #{e.tag}" - STDERR.puts 'Previously, I read these dimensions:' + STDERR.puts "Previously, I read these dimensions:" STDERR.puts " #{dimensions_tag_data.inspect}" STDERR.puts "Unpack options were: #{options.inspect}" raise(e) end - if self.matlab_class == :mxCELL + if matlab_class == :mxCELL # Read what may be a series of matrices self.cells = [] STDERR.puts("Warning: Cell array does not yet support reading multiple dimensions") if dimensions.size > 2 || (dimensions[0] > 1 && dimensions[1] > 1) - number_of_cells = dimensions.inject(1) { |prod,i| prod * i } - number_of_cells.times { self.cells << \ - packedio.read([Element, options]) } + number_of_cells = dimensions.inject(1) { |prod, i| prod * i } + number_of_cells.times { + cells << \ + packedio.read([Element, options]) + } else - read_opts = [RawElement, {:bytes => options[:bytes], \ - :endian => :native}] + read_opts = [RawElement, {bytes: options[:bytes], \ + endian: :native,},] - if self.matlab_class == :mxSPARSE + if matlab_class == :mxSPARSE self.column_index = packedio.read(read_opts) self.row_index = packedio.read(read_opts) end - self.real_part = packedio.read(read_opts) - self.imaginary_part = packedio.read(read_opts) if self.complex + self.real_part = packedio.read(read_opts) + self.imaginary_part = packedio.read(read_opts) if complex end end def ignore_padding(packedio, bytes) - packedio.read([Integer, {:unsigned => true, \ - :bytes => bytes}]) if bytes > 0 + if bytes > 0 + packedio.read([Integer, {unsigned: true, \ + bytes: bytes,},]) + end end end - MDTYPE_UNPACK_ARGS = MatReader::MDTYPE_UNPACK_ARGS.merge({ - :miCOMPRESSED => [Compressed, {}], - :miMATRIX => [MatrixData, {}] - }) + miCOMPRESSED: [Compressed, {}], + miMATRIX: [MatrixData, {}], + }) FIRST_TAG_FIELD_POS = 128 @@ -371,13 +376,13 @@ def initialize(stream, options = {}) end def to_a - returning(Array.new) do |ary| - self.each { |el| ary << el } + returning([]) do |ary| + each { |el| ary << el } end end def to_ruby - ary = self.to_a + ary = to_a if ary.size == 1 ary.first.to_ruby @@ -390,19 +395,19 @@ def guess_byte_order stream.seek(Header::BYTE_ORDER_POS) mi = stream.read(Header::BYTE_ORDER_LENGTH) stream.seek(0) - mi == 'IM' ? :little : :big + mi == "IM" ? :little : :big end def seek_and_read_file_header stream.seek(0) - stream.read(FIRST_TAG_FIELD_POS).unpack(Header, {:endian => byte_order}) + stream.read(FIRST_TAG_FIELD_POS).unpack(Header, {endian: byte_order}) end def each(&block) - stream.each(Element, {:endian => byte_order}) do |element| + stream.each(Element, {endian: byte_order}) do |element| if element.data.is_a?(Compressed) - StringIO.new(element.data.content, 'rb').each(Element, \ - {:endian => byte_order}) do |compressed_element| + StringIO.new(element.data.content, "rb").each(Element, \ + {endian: byte_order}) do |compressed_element| yield compressed_element.data end @@ -420,42 +425,41 @@ def each(&block) # Internal Classes. class Header < Struct.new(:desc, :data_offset, :version, :endian) #:nodoc: - include Packable - BYTE_ORDER_LENGTH = 2 - DESC_LENGTH = 116 + BYTE_ORDER_LENGTH = 2 + DESC_LENGTH = 116 DATA_OFFSET_LENGTH = 8 VERSION_LENGTH = 2 BYTE_ORDER_POS = 126 # TODO: TEST WRITE. def write_packed(packedio, options) - packedio << [desc, {:bytes => DESC_LENGTH }] << - [data_offset, {:bytes => DATA_OFFSET_LENGTH }] << - [version, {:bytes => VERSION_LENGTH }] << - [byte_order, {:bytes => BYTE_ORDER_LENGTH }] + packedio << [desc, {bytes: DESC_LENGTH}] << + [data_offset, {bytes: DATA_OFFSET_LENGTH}] << + [version, {bytes: VERSION_LENGTH}] << + [byte_order, {bytes: BYTE_ORDER_LENGTH}] end def read_packed(packedio, options) self.desc, self.data_offset, self.version, self.endian = packedio >> - [String, {:bytes => DESC_LENGTH }] >> - [String, {:bytes => DATA_OFFSET_LENGTH }] >> - [Integer, {:bytes => VERSION_LENGTH, :endian => options[:endian] }] >> - [String, {:bytes => 2 }] + [String, {bytes: DESC_LENGTH}] >> + [String, {bytes: DATA_OFFSET_LENGTH}] >> + [Integer, {bytes: VERSION_LENGTH, endian: options[:endian]}] >> + [String, {bytes: 2}] - self.desc.strip! - self.data_offset.strip! - self.data_offset = nil if self.data_offset.empty? + desc.strip! + data_offset.strip! + self.data_offset = nil if data_offset.empty? - self.endian == 'IM' ? :little : :big + endian == "IM" ? :little : :big end end class Tag < Struct.new(:data_type, :raw_data_type, :bytes, :small) #:nodoc: include Packable - DATA_TYPE_OPTS = BYTES_OPTS = {:bytes => 4, :signed => false} + DATA_TYPE_OPTS = BYTES_OPTS = {bytes: 4, signed: false} LENGTH = DATA_TYPE_OPTS[:bytes] + BYTES_OPTS[:bytes] # TODO: TEST WRITE. @@ -464,7 +468,7 @@ def write_packed packedio, options end def small? - self.bytes > 0 and self.bytes <= 4 + (bytes > 0) && (bytes <= 4) end def size @@ -473,32 +477,31 @@ def size def read_packed packedio, options self.raw_data_type = packedio.read([Integer, \ - DATA_TYPE_OPTS.merge(options)]) + DATA_TYPE_OPTS.merge(options),]) # Borrowed from a SciPy patch - upper = self.raw_data_type >> 16 - lower = self.raw_data_type & 0xFFFF + upper = raw_data_type >> 16 + lower = raw_data_type & 0xFFFF if upper > 0 # Small data element format - raise IOError, 'Small data element format indicated, but length is more than 4 bytes!' if upper > 4 + raise IOError, "Small data element format indicated, but length is more than 4 bytes!" if upper > 4 - self.bytes = upper + self.bytes = upper self.raw_data_type = lower else self.bytes = packedio.read([Integer, BYTES_OPTS.merge(options)]) end - self.data_type = MatReader::MDTYPES[self.raw_data_type] + self.data_type = MatReader::MDTYPES[raw_data_type] end def inspect - "#<#{self.class.to_s} data_type=#{data_type}[#{raw_data_type}][#{raw_data_type.to_s(2)}] bytes=#{bytes} size=#{size}#{small? ? ' small' : ''}>" + "#<#{self.class} data_type=#{data_type}[#{raw_data_type}][#{raw_data_type.to_s(2)}] bytes=#{bytes} size=#{size}#{small? ? " small" : ""}>" end end - class ElementDataIOError < IOError #:nodoc: attr_reader :tag @@ -512,7 +515,6 @@ def to_s end end - class Element < Struct.new(:tag, :data) #:nodoc: include Packable @@ -521,10 +523,10 @@ def write_packed packedio, options end def read_packed(packedio, options) - raise(ArgumentError, 'Missing mandatory option :endian.') \ - unless options.has_key?(:endian) + raise(ArgumentError, "Missing mandatory option :endian.") \ + unless options.key?(:endian) - tag = packedio.read([Tag, {:endian => options[:endian]}]) + tag = packedio.read([Tag, {endian: options[:endian]}]) data_type = MDTYPE_UNPACK_ARGS[tag.data_type] self.tag = tag @@ -536,16 +538,15 @@ def read_packed(packedio, options) self.data = [] else - number_of_reads = data_type[1].has_key?(:bytes) ? \ + number_of_reads = data_type[1].key?(:bytes) ? \ tag.bytes / data_type[1][:bytes] : 1 - data_type[1].merge!({:endian => options[:endian]}) + data_type[1][:endian] = options[:endian] - if number_of_reads == 1 - self.data = packedio.read(data_type) + self.data = if number_of_reads == 1 + packedio.read(data_type) else - self.data = - returning(Array.new) do |ary| + returning([]) do |ary| number_of_reads.times { ary << packedio.read(data_type) } end end @@ -553,7 +554,6 @@ def read_packed(packedio, options) begin ignore_padding(packedio, (tag.bytes + tag.size) % 8) \ unless [:miMATRIX, :miCOMPRESSED].include?(tag.data_type) - rescue EOFError STDERR.puts self.tag.inspect raise(ElementDataIOError.new(tag, "Ignored too much")) @@ -563,7 +563,7 @@ def read_packed(packedio, options) def ignore_padding(packedio, bytes) if bytes > 0 - #STDERR.puts "Ignored #{8 - bytes} on #{self.tag.data_type}" + # STDERR.puts "Ignored #{8 - bytes} on #{self.tag.data_type}" ignored = packedio.read(8 - bytes) ignored_unpacked = ignored.unpack("C*") raise(IOError, "Nonzero padding detected: #{ignored_unpacked}") \ @@ -580,20 +580,19 @@ def to_ruby # manually, or pass the raw string of bytes into NMatrix. class RawElement < Element #:nodoc: def read_packed(packedio, options) - raise(ArgumentError, 'Missing mandatory option :endian.') \ - unless options.has_key?(:endian) + raise(ArgumentError, "Missing mandatory option :endian.") \ + unless options.key?(:endian) - self.tag = packedio.read([Tag, {:endian => options[:endian]}]) - self.data = packedio.read([String, {:endian => options[:endian], \ - :bytes => tag.bytes }]) + self.tag = packedio.read([Tag, {endian: options[:endian]}]) + self.data = packedio.read([String, {endian: options[:endian], \ + bytes: tag.bytes,},]) begin ignore_padding(packedio, (tag.bytes + tag.size) % 8) \ unless [:miMATRIX, :miCOMPRESSED].include?(tag.data_type) - rescue EOFError - STDERR.puts self.tag.inspect - raise ElementDataIOError.new(tag, 'Ignored too much.') + STDERR.puts tag.inspect + raise ElementDataIOError.new(tag, "Ignored too much.") end end end @@ -601,6 +600,5 @@ def read_packed(packedio, options) ##################### # End of Mat5Reader # ##################### - end end diff --git a/lib/nmatrix/io/mat_reader.rb b/lib/nmatrix/io/mat_reader.rb index e1e5c465..e581dc66 100644 --- a/lib/nmatrix/io/mat_reader.rb +++ b/lib/nmatrix/io/mat_reader.rb @@ -27,84 +27,83 @@ # #++ -require 'packable' +require "packable" module NMatrix::IO::Matlab - # Class for parsing a .mat file stream. # # The full format of .mat files is available here: # * http://www.mathworks.com/help/pdf_doc/matlab/matfile_format.pdf class MatReader #:nodoc: MDTYPE_UNPACK_ARGS = { - :miINT8 => [Integer, {:signed => true, :bytes => 1}], - :miUINT8 => [Integer, {:signed => false, :bytes => 1}], - :miINT16 => [Integer, {:signed => true, :bytes => 2}], - :miUINT16 => [Integer, {:signed => false, :bytes => 2}], - :miINT32 => [Integer, {:signed => true, :bytes => 4}], - :miUINT32 => [Integer, {:signed => false, :bytes => 4}], - :miSINGLE => [Float, {:precision => :single, - :bytes => 4, :endian => :native}], - :miDOUBLE => [Float, {:precision => :double, - :bytes => 4, :endian => :native}], - :miINT64 => [Integer, {:signed => true, :bytes => 8}], - :miUINT64 => [Integer, {:signed => false, :bytes => 8}] + miINT8: [Integer, {signed: true, bytes: 1}], + miUINT8: [Integer, {signed: false, bytes: 1}], + miINT16: [Integer, {signed: true, bytes: 2}], + miUINT16: [Integer, {signed: false, bytes: 2}], + miINT32: [Integer, {signed: true, bytes: 4}], + miUINT32: [Integer, {signed: false, bytes: 4}], + miSINGLE: [Float, {precision: :single, + bytes: 4, endian: :native,},], + miDOUBLE: [Float, {precision: :double, + bytes: 4, endian: :native,},], + miINT64: [Integer, {signed: true, bytes: 8}], + miUINT64: [Integer, {signed: false, bytes: 8}], } DTYPE_PACK_ARGS = { - :byte => [Integer, {:signed => false, - :bytes => 1}], - :int8 => [Integer, {:signed => true, - :bytes => 1}], - :int16 => [Integer, {:signed => true, - :bytes => 2}], - :int32 => [Integer, {:signed => true, - :bytes => 4}], - :int64 => [Integer, {:signed => true, - :bytes => 8}], - :float32 => [Float, {:precision => :single, - :bytes => 4, :endian => :native}], - :float64 => [Float, {:precision => :double, - :bytes => 8, :endian => :native}], - :complex64 => [Float, {:precision => :single, - :bytes => 4, :endian => :native}], #2x - :complex128 => [Float, {:precision => :double, - :bytes => 8, :endian => :native}] + byte: [Integer, {signed: false, + bytes: 1,},], + int8: [Integer, {signed: true, + bytes: 1,},], + int16: [Integer, {signed: true, + bytes: 2,},], + int32: [Integer, {signed: true, + bytes: 4,},], + int64: [Integer, {signed: true, + bytes: 8,},], + float32: [Float, {precision: :single, + bytes: 4, endian: :native,},], + float64: [Float, {precision: :double, + bytes: 8, endian: :native,},], + complex64: [Float, {precision: :single, + bytes: 4, endian: :native,},], # 2x + complex128: [Float, {precision: :double, + bytes: 8, endian: :native,},], } ITYPE_PACK_ARGS = { - :uint8 => [Integer, {:signed => false, :bytes => 1}], - :uint16 => [Integer, {:signed => false, :bytes => 2}], - :uint32 => [Integer, {:signed => false, :bytes => 4}], - :uint64 => [Integer, {:signed => false, :bytes => 8}], + uint8: [Integer, {signed: false, bytes: 1}], + uint16: [Integer, {signed: false, bytes: 2}], + uint32: [Integer, {signed: false, bytes: 4}], + uint64: [Integer, {signed: false, bytes: 8}], } NO_REPACK = [:miINT8, :miUINT8, :miINT16, - :miINT32, :miSINGLE, :miDOUBLE, :miINT64] + :miINT32, :miSINGLE, :miDOUBLE, :miINT64,] # Convert from MATLAB dtype to NMatrix dtype. MDTYPE_TO_DTYPE = { - :miUINT8 => :byte, - :miINT8 => :int8, - :miINT16 => :int16, - :miUINT16 => :int16, - :miINT32 => :int32, - :miUINT32 => :int32, - :miINT64 => :int64, - :miUINT64 => :int64, - :miSINGLE => :float32, - :miDOUBLE => :float64 + miUINT8: :byte, + miINT8: :int8, + miINT16: :int16, + miUINT16: :int16, + miINT32: :int32, + miUINT32: :int32, + miINT64: :int64, + miUINT64: :int64, + miSINGLE: :float32, + miDOUBLE: :float64, } MDTYPE_TO_ITYPE = { - :miUINT8 => :uint8, - :miINT8 => :uint8, - :miINT16 => :uint16, - :miUINT16 => :uint16, - :miINT32 => :uint32, - :miUINT32 => :uint32, - :miINT64 => :uint64, - :miUINT64 => :uint64 + miUINT8: :uint8, + miINT8: :uint8, + miINT16: :uint16, + miUINT16: :uint16, + miINT32: :uint32, + miUINT32: :uint32, + miINT64: :uint64, + miUINT64: :uint64, } # Before release v7.1 (release 14) matlab (TM) used the system @@ -112,52 +111,51 @@ class MatReader #:nodoc: # and later use Unicode. When saving character data, R14 checks if it # can be encoded in 7-bit ascii, and saves in that format if so. MDTYPES = [ - nil, - :miINT8, - :miUINT8, - :miINT16, - :miUINT16, - :miINT32, - :miUINT32, - :miSINGLE, - nil, - :miDOUBLE, - nil, - nil, - :miINT64, - :miUINT64, - :miMATRIX, - :miCOMPRESSED, - :miUTF8, - :miUTF16, - :miUTF32 - ] + nil, + :miINT8, + :miUINT8, + :miINT16, + :miUINT16, + :miINT32, + :miUINT32, + :miSINGLE, + nil, + :miDOUBLE, + nil, + nil, + :miINT64, + :miUINT64, + :miMATRIX, + :miCOMPRESSED, + :miUTF8, + :miUTF16, + :miUTF32, + ] MCLASSES = [ - nil, - :mxCELL, - :mxSTRUCT, - :mxOBJECT, - :mxCHAR, - :mxSPARSE, - :mxDOUBLE, - :mxSINGLE, - :mxINT8, - :mxUINT8, - :mxINT16, - :mxUINT16, - :mxINT32, - :mxUINT32, - :mxINT64, - :mxUINT64, - :mxFUNCTION, - :mxOPAQUE, - :mxOBJECT_CLASS_FROM_MATRIX_H - ] + nil, + :mxCELL, + :mxSTRUCT, + :mxOBJECT, + :mxCHAR, + :mxSPARSE, + :mxDOUBLE, + :mxSINGLE, + :mxINT8, + :mxUINT8, + :mxINT16, + :mxUINT16, + :mxINT32, + :mxUINT32, + :mxINT64, + :mxUINT64, + :mxFUNCTION, + :mxOPAQUE, + :mxOBJECT_CLASS_FROM_MATRIX_H, + ] attr_reader :byte_order - # call-seq: # new(stream, options = {}) -> MatReader # @@ -165,7 +163,7 @@ class MatReader #:nodoc: # - +ArgumentError+ -> First argument must be IO. # def initialize(stream, options = {}) - raise ArgumentError, 'First arg must be IO.' unless stream.is_a?(::IO) + raise ArgumentError, "First arg must be IO." unless stream.is_a?(::IO) @stream = stream @byte_order = options[:byte_order] || guess_byte_order diff --git a/lib/nmatrix/io/point_cloud.rb b/lib/nmatrix/io/point_cloud.rb index 77111a15..66283eb7 100644 --- a/lib/nmatrix/io/point_cloud.rb +++ b/lib/nmatrix/io/point_cloud.rb @@ -36,7 +36,6 @@ # Note that this implementation does not take the width or height parameters # into account. module NMatrix::IO::PointCloud - # For UINT, just add 1 to the index. INT_DTYPE_BY_SIZE = [:int8, :int8, :int16, :int32, :int64, :int64] #:nodoc: FLOAT_DTYPE_BY_SIZE = {4 => :float32, 8 => :float64} #:nodoc: @@ -56,30 +55,29 @@ def load(filename) class MetaReader #:nodoc: ENTRIES = [:version, :fields, :size, :type, - :count, :width, :height, :viewpoint, :points, :data] + :count, :width, :height, :viewpoint, :points, :data,] ASSIGNS = [:version=, :fields=, :size=, :type=, - :count=, :width=, :height=, :viewpoint=, :points=, :data=] + :count=, :width=, :height=, :viewpoint=, :points=, :data=,] CONVERT = [:to_s, :downcase_to_sym, :to_i, :downcase_to_sym, - :to_i, :to_i, :to_i, :to_f, :to_i, :downcase_to_sym] + :to_i, :to_i, :to_i, :to_f, :to_i, :downcase_to_sym,] - DTYPE_CONVERT = {:byte => :to_i, :int8 => :to_i, :int16 => :to_i, - :int32 => :to_i, :float32 => :to_f, :float64 => :to_f} + DTYPE_CONVERT = {byte: :to_i, int8: :to_i, int16: :to_i, + int32: :to_i, float32: :to_f, float64: :to_f,} # For UINT, just add 1 to the index. INT_DTYPE_BY_SIZE = {1 => :int8, 2 => :int16, 4 => :int32, - 8 => :int64, 16 => :int64} + 8 => :int64, 16 => :int64,} FLOAT_DTYPE_BY_SIZE = {1 => :float32, 2 => :float32, 4 => :float32, - 8 => :float64,16 => :float64} + 8 => :float64, 16 => :float64,} class << self - # Given a type and a number of bytes, figure out an appropriate dtype def dtype_by_type_and_size t, s if t == :f FLOAT_DTYPE_BY_SIZE[s] elsif t == :u return :byte if s == 1 - INT_DTYPE_BY_SIZE[s*2] + INT_DTYPE_BY_SIZE[s * 2] else INT_DTYPE_BY_SIZE[s] end @@ -103,34 +101,34 @@ def dtype_by_type_and_size t, s def initialize filename f = File.new(filename, "r") - ENTRIES.each.with_index do |entry,i| + ENTRIES.each.with_index do |entry, i| read_entry(f, entry, ASSIGNS[i], CONVERT[i]) end raise(NotImplementedError, "only ASCII supported currently") \ - unless self.data.first == :ascii + unless data.first == :ascii - @matrix = NMatrix.new(self.shape, dtype: self.dtype) + @matrix = NMatrix.new(shape, dtype: dtype) # Do we want to use to_i or to_f? - convert = DTYPE_CONVERT[self.dtype] + convert = DTYPE_CONVERT[dtype] i = 0 while line = f.gets - @matrix[i,:*] = line.chomp.split.map { |f| f.send(convert) } + @matrix[i, :*] = line.chomp.split.map { |f| f.send(convert) } i += 1 end - raise(IOError, "premature end of file") if i < self.points[0] - + raise(IOError, "premature end of file") if i < points[0] end - attr_accessor *ENTRIES + attr_accessor(*ENTRIES) attr_reader :matrix - protected + protected + # Read the current entry of the header. - def read_entry f, entry, assign=nil, convert=nil + def read_entry f, entry, assign = nil, convert = nil assign ||= (entry.to_s + "=").to_sym while line = f.gets @@ -138,33 +136,32 @@ def read_entry f, entry, assign=nil, convert=nil line = line.chomp.split(/\s*#/)[0] # ignore the comments after any data # Split, remove the entry name, and convert to the correct type. - self.send(assign, - line.split.tap { |t| t.shift }.map do |f| - if convert.nil? - f - elsif convert == :downcase_to_sym - f.downcase.to_sym - else - f.send(convert) - end - end) + send(assign, + line.split.tap { |t| t.shift }.map { |f| + if convert.nil? + f + elsif convert == :downcase_to_sym + f.downcase.to_sym + else + f.send(convert) + end + }) # We don't really want to loop. break end - self.send(entry) + send(entry) end - # Determine the dtype for a matrix based on the types and # sizes given in the PCD. # Call this only after read_entry has been called. def dtype @dtype ||= begin - dtypes = self.type.map.with_index do |t,k| + dtypes = type.map.with_index { |t, k| MetaReader.dtype_by_type_and_size(t, size[k]) - end.sort.uniq + }.sort.uniq # This could probably save one comparison at most, but we assume that # worst case isn't going to happen very often. @@ -181,8 +178,8 @@ def dtype # Determine the shape of the matrix. def shape @shape ||= [ - self.points[0], - self.fields.size + points[0], + fields.size, ] end end diff --git a/lib/nmatrix/jruby/decomposition.rb b/lib/nmatrix/jruby/decomposition.rb index 787a0b3a..9e6a2fc2 100644 --- a/lib/nmatrix/jruby/decomposition.rb +++ b/lib/nmatrix/jruby/decomposition.rb @@ -1,5 +1,4 @@ class NMatrix - # discussion in https://github.com/SciRuby/nmatrix/issues/374 def matrix_solve rhs @@ -7,18 +6,17 @@ def matrix_solve rhs nmatrix = NMatrix.new :copy nmatrix.shape = rhs.shape res = [] - #Solve a matrix and store the vectors in a matrix + # Solve a matrix and store the vectors in a matrix (0...rhs.shape[1]).each do |i| - res << self.solve(rhs.col(i)).s.toArray.to_a + res << solve(rhs.col(i)).s.toArray.to_a end - #res is in col major format + # res is in col major format result = ArrayGenerator.getArrayColMajorDouble res.to_java :double, rhs.shape[0], rhs.shape[1] nmatrix.s = ArrayRealVector.new result - return nmatrix + nmatrix else - return self.solve rhs + solve rhs end end - -end \ No newline at end of file +end diff --git a/lib/nmatrix/jruby/enumerable.rb b/lib/nmatrix/jruby/enumerable.rb index 5cfaed92..8756b853 100644 --- a/lib/nmatrix/jruby/enumerable.rb +++ b/lib/nmatrix/jruby/enumerable.rb @@ -2,12 +2,13 @@ module Enumerable # Standard in rails... See official documentation[http://api.rubyonrails.org/classes/Enumerable.html] # Modified from rails 2.3 to not rely on size - def sum(identity = 0, &block) - if block_given? - map(&block).sum(identity) - else - inject { |sum, element| sum + element } || identity + unless method_defined? :sum + def sum(identity = 0, &block) + if block_given? + map(&block).sum(identity) + else + inject { |sum, element| sum + element } || identity + end end - end unless method_defined? :sum - -end \ No newline at end of file + end +end diff --git a/lib/nmatrix/jruby/error.rb b/lib/nmatrix/jruby/error.rb index a1e7cf7e..53aacd93 100644 --- a/lib/nmatrix/jruby/error.rb +++ b/lib/nmatrix/jruby/error.rb @@ -1,4 +1,4 @@ DataTypeError = Class.new(StandardError) StorageTypeError = Class.new(StandardError) ShapeError = Class.new(StandardError) -NotInvertibleError = Class.new(StandardError) \ No newline at end of file +NotInvertibleError = Class.new(StandardError) diff --git a/lib/nmatrix/jruby/math.rb b/lib/nmatrix/jruby/math.rb index 27b8327e..1346f62a 100644 --- a/lib/nmatrix/jruby/math.rb +++ b/lib/nmatrix/jruby/math.rb @@ -29,7 +29,6 @@ #++ class NMatrix - # # call-seq: # getrf! -> Array @@ -51,8 +50,8 @@ class NMatrix # - +StorageTypeError+ -> ATLAS functions only work on dense matrices. # def getrf! - ipiv = LUDecomposition.new(self.twoDMat).getPivot.to_a - return ipiv + ipiv = LUDecomposition.new(twoDMat).getPivot.to_a + ipiv end # @@ -114,10 +113,9 @@ def geqrf! # - +TypeError+ -> Works only on floating point matrices, use unmqr for complex types # - +TypeError+ -> c must have the same dtype as the calling NMatrix # - def ormqr(tau, side=:left, transpose=false, c=nil) + def ormqr(tau, side = :left, transpose = false, c = nil) # The real implementation is in lib/nmatrix/lapacke.rb raise(NotImplementedError, "ormqr requires the nmatrix-lapacke gem") - end # @@ -148,7 +146,7 @@ def ormqr(tau, side=:left, transpose=false, c=nil) # - +TypeError+ -> Works only on floating point matrices, use unmqr for complex types # - +TypeError+ -> c must have the same dtype as the calling NMatrix # - def unmqr(tau, side=:left, transpose=false, c=nil) + def unmqr(tau, side = :left, transpose = false, c = nil) # The real implementation is in lib/nmatrix/lapacke.rb raise(NotImplementedError, "unmqr requires the nmatrix-lapacke gem") end @@ -178,7 +176,7 @@ def unmqr(tau, side=:left, transpose=false, c=nil) # def potrf!(which) # The real implementation is in the plugin files. - cholesky = CholeskyDecomposition.new(self.twoDMat) + cholesky = CholeskyDecomposition.new(twoDMat) if which == :upper u = create_dummy_nmatrix twoDMat = cholesky.getLT @@ -200,7 +198,6 @@ def potrf_lower! potrf! :lower end - # # call-seq: # factorize_cholesky -> [upper NMatrix, lower NMatrix] @@ -214,14 +211,14 @@ def potrf_lower! # sure it is positive-definite. def factorize_cholesky # raise "Matrix must be symmetric/Hermitian for Cholesky factorization" unless self.hermitian? - cholesky = CholeskyDecomposition.new(self.twoDMat) + cholesky = CholeskyDecomposition.new(twoDMat) l = create_dummy_nmatrix twoDMat = cholesky.getL l.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1])) u = create_dummy_nmatrix twoDMat = cholesky.getLT u.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1])) - return [u,l] + [u, l] end # @@ -237,14 +234,14 @@ def factorize_cholesky # +with_permutation_matrix+ - If set to *true* will return the permutation # matrix alongwith the LU factorization as a second return value. # - def factorize_lu with_permutation_matrix=nil - raise(NotImplementedError, "only implemented for dense storage") unless self.stype == :dense - raise(NotImplementedError, "matrix is not 2-dimensional") unless self.dimensions == 2 - t = self.clone + def factorize_lu with_permutation_matrix = nil + raise(NotImplementedError, "only implemented for dense storage") unless stype == :dense + raise(NotImplementedError, "matrix is not 2-dimensional") unless dimensions == 2 + t = clone pivot = create_dummy_nmatrix twoDMat = LUDecomposition.new(self.twoDMat).getP pivot.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1])) - return [t,pivot] + [t, pivot] end # @@ -265,10 +262,9 @@ def factorize_lu with_permutation_matrix=nil # - +ShapeError+ -> Input must be a 2-dimensional matrix to have a QR decomposition. # def factorize_qr - - raise(NotImplementedError, "only implemented for dense storage") unless self.stype == :dense - raise(ShapeError, "Input must be a 2-dimensional matrix to have a QR decomposition") unless self.dim == 2 - qrdecomp = QRDecomposition.new(self.twoDMat) + raise(NotImplementedError, "only implemented for dense storage") unless stype == :dense + raise(ShapeError, "Input must be a 2-dimensional matrix to have a QR decomposition") unless dim == 2 + qrdecomp = QRDecomposition.new(twoDMat) qmat = create_dummy_nmatrix qtwoDMat = qrdecomp.getQ @@ -277,8 +273,7 @@ def factorize_qr rmat = create_dummy_nmatrix rtwoDMat = qrdecomp.getR rmat.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(rtwoDMat.getData, @shape[0], @shape[1])) - return [qmat,rmat] - + [qmat, rmat] end # Solve the matrix equation AX = B, where A is +self+, B is the first @@ -325,33 +320,32 @@ def factorize_qr # # upper_tri 0.180000 0.000000 0.180000 ( 0.182491) # def solve(b, opts = {}) - raise(ShapeError, "Must be called on square matrix") unless self.dim == 2 && self.shape[0] == self.shape[1] + raise(ShapeError, "Must be called on square matrix") unless dim == 2 && shape[0] == shape[1] raise(ShapeError, "number of rows of b must equal number of cols of self") if - self.shape[1] != b.shape[0] - raise(ArgumentError, "only works with dense matrices") if self.stype != :dense + shape[1] != b.shape[0] + raise(ArgumentError, "only works with dense matrices") if stype != :dense raise(ArgumentError, "only works for non-integer, non-object dtypes") if - integer_dtype? or object_dtype? or b.integer_dtype? or b.object_dtype? + integer_dtype? || object_dtype? || b.integer_dtype? || b.object_dtype? - opts = { form: :general }.merge(opts) + opts = {form: :general}.merge(opts) x = b.clone - n = self.shape[0] + n = shape[0] nrhs = b.shape[1] nmatrix = create_dummy_nmatrix case opts[:form] when :general, :upper_tri, :upper_triangular, :lower_tri, :lower_triangular - #LU solver - solver = LUDecomposition.new(self.twoDMat).getSolver + # LU solver + solver = LUDecomposition.new(twoDMat).getSolver nmatrix.s = solver.solve(b.s) return nmatrix when :pos_def, :positive_definite - solver = CholeskyDecomposition.new(self.twoDMat).getSolver + solver = CholeskyDecomposition.new(twoDMat).getSolver nmatrix.s = solver.solve(b.s) return nmatrix else raise(ArgumentError, "#{opts[:form]} is not a valid form option") end - end # @@ -380,8 +374,8 @@ def solve(b, opts = {}) # - +ShapeError+ -> Must be used on square matrices. # def det - raise(ShapeError, "determinant can be calculated only for square matrices") unless self.dim == 2 && self.shape[0] == self.shape[1] - self.det_exact2 + raise(ShapeError, "determinant can be calculated only for square matrices") unless dim == 2 && shape[0] == shape[1] + det_exact2 end # @@ -401,8 +395,8 @@ def det # * *Returns* : # - If the original NMatrix isn't complex, the result is a +:complex128+ NMatrix. Otherwise, it's the original dtype. # - def complex_conjugate(new_stype = self.stype) - self.cast(new_stype, NMatrix::upcast(dtype, :complex64)).complex_conjugate! + def complex_conjugate(new_stype = stype) + cast(new_stype, NMatrix.upcast(dtype, :complex64)).complex_conjugate! end # @@ -416,7 +410,7 @@ def complex_conjugate(new_stype = self.stype) # - The conjugate transpose of the matrix as a copy. # def conjugate_transpose - self.transpose.complex_conjugate! + transpose.complex_conjugate! end # @@ -428,15 +422,15 @@ def conjugate_transpose # - +n+ -> the number of elements to include # # Return the sum of the contents of the vector. This is the BLAS asum routine. - def asum incx=1, n=nil - if self.shape == [1] - return self[0].abs unless self.complex_dtype? + def asum incx = 1, n = nil + if shape == [1] + return self[0].abs unless complex_dtype? return self[0].real.abs + self[0].imag.abs end return method_missing(:asum, incx, n) unless vector? - NMatrix::BLAS::asum(self, incx, self.size / incx) + NMatrix::BLAS.asum(self, incx, size / incx) end - alias :absolute_sum :asum + alias absolute_sum asum # # call-seq: @@ -447,10 +441,10 @@ def asum incx=1, n=nil # - +n+ -> the number of elements to include # # Return the 2-norm of the vector. This is the BLAS nrm2 routine. - def nrm2 incx=1, n=nil - self.twoDMat.getFrobeniusNorm() + def nrm2 incx = 1, n = nil + twoDMat.getFrobeniusNorm end - alias :norm2 :nrm2 + alias norm2 nrm2 # # call-seq: @@ -464,14 +458,14 @@ def nrm2 incx=1, n=nil # This is a destructive method, modifying the source NMatrix. See also #scale. # Return the scaling result of the matrix. BLAS scal will be invoked if provided. - def scale!(alpha, incx=1, n=nil) - #FIXME + def scale!(alpha, incx = 1, n = nil) + # FIXME # raise(DataTypeError, "Incompatible data type for the scaling factor") unless # NMatrix::upcast(self.dtype, NMatrix::min_dtype(alpha)) == self.dtype raise(DataTypeError, "Incompatible data type for the scaling factor") if - self.dtype == :int8 + dtype == :int8 @s.mapMultiplyToSelf(alpha) - return self + self end # @@ -485,17 +479,16 @@ def scale!(alpha, incx=1, n=nil) # # Return the scaling result of the matrix. BLAS scal will be invoked if provided. - def scale(alpha, incx=1, n=nil) + def scale(alpha, incx = 1, n = nil) # FIXME # raise(DataTypeError, "Incompatible data type for the scaling factor") unless # NMatrix::upcast(self.dtype, NMatrix::min_dtype(alpha)) == self.dtype raise(DataTypeError, "Incompatible data type for the scaling factor") if - self.dtype == :byte || self.dtype == :int8 || self.dtype == :int16 || - self.dtype == :int32 || self.dtype == :int64 + dtype == :byte || dtype == :int8 || dtype == :int16 || + dtype == :int32 || dtype == :int64 nmatrix = NMatrix.new :copy nmatrix.shape = @shape.clone nmatrix.s = ArrayRealVector.new(@s.toArray.clone).mapMultiplyToSelf(alpha) - return nmatrix + nmatrix end - end diff --git a/lib/nmatrix/jruby/nmatrix_java.rb b/lib/nmatrix/jruby/nmatrix_java.rb index d49221af..203b4b13 100644 --- a/lib/nmatrix/jruby/nmatrix_java.rb +++ b/lib/nmatrix/jruby/nmatrix_java.rb @@ -1,30 +1,30 @@ -require 'java' -require_relative '../../../ext/nmatrix_java/vendor/commons-math3-3.6.1.jar' -require_relative '../../../ext/nmatrix_java/target/nmatrix.jar' - -java_import 'org.apache.commons.math3.linear.ArrayRealVector' -java_import 'org.apache.commons.math3.linear.RealMatrix' -java_import 'org.apache.commons.math3.linear.MatrixUtils' -java_import 'org.apache.commons.math3.linear.DecompositionSolver' -java_import 'org.apache.commons.math3.linear.LUDecomposition' -java_import 'org.apache.commons.math3.linear.QRDecomposition' -java_import 'org.apache.commons.math3.linear.CholeskyDecomposition' -java_import 'MatrixGenerator' -java_import 'ArrayGenerator' -java_import 'MathHelper' -java_import 'ArrayComparator' +require "java" +require_relative "../../../ext/nmatrix_java/vendor/commons-math3-3.6.1.jar" +require_relative "../../../ext/nmatrix_java/target/nmatrix.jar" + +java_import "org.apache.commons.math3.linear.ArrayRealVector" +java_import "org.apache.commons.math3.linear.RealMatrix" +java_import "org.apache.commons.math3.linear.MatrixUtils" +java_import "org.apache.commons.math3.linear.DecompositionSolver" +java_import "org.apache.commons.math3.linear.LUDecomposition" +java_import "org.apache.commons.math3.linear.QRDecomposition" +java_import "org.apache.commons.math3.linear.CholeskyDecomposition" +java_import "MatrixGenerator" +java_import "ArrayGenerator" +java_import "MathHelper" +java_import "ArrayComparator" class NMatrix - include_package 'org.apache.commons.math3.analysis.function' + include_package "org.apache.commons.math3.analysis.function" attr_accessor :shape, :dim, :dtype, :stype, :s def initialize(*args) if args[-1] == :copy - @shape = [2,2] - @s = [0,0,0,0] + @shape = [2, 2] + @s = [0, 0, 0, 0] @dim = shape.is_a?(Array) ? shape.length : 2 else - if (args.length <= 3) + if args.length <= 3 @shape = args[0] if args[1].is_a?(Array) elements = args[1] @@ -44,16 +44,16 @@ def initialize(*args) hash = args[1] @dtype = hash[:dtype] @stype = hash[:stype] - elements = Array.new(shape*shape) unless shape.is_a? Array + elements = Array.new(shape * shape) unless shape.is_a? Array else - elements = Array.new(shape*shape) unless shape.is_a? Array + elements = Array.new(shape * shape) unless shape.is_a? Array end end end else offset = 0 - if (!args[0].is_a?(Symbol) && !args[0].is_a?(String)) + if !args[0].is_a?(Symbol) && !args[0].is_a?(String) @stype = :dense else offset = 1 @@ -62,42 +62,41 @@ def initialize(*args) end @shape = args[offset] - elements = args[offset+1] + elements = args[offset + 1] end - - @shape = [shape,shape] unless shape.is_a?(Array) + @shape = [shape, shape] unless shape.is_a?(Array) # @dtype = interpret_dtype(argc-1-offset, argv+offset+1, stype); # @dtype = args[:dtype] if args[:dtype] @dtype_sym = nil @stype_sym = nil @default_val_num = nil @capacity_num = nil - @size = (0...@shape.size).inject(1) { |x,i| x * @shape[i] } + @size = (0...@shape.size).inject(1) { |x, i| x * @shape[i] } - j=0 + j = 0 - if (elements.is_a?(ArrayRealVector)) + if elements.is_a?(ArrayRealVector) @s = elements # elsif elements.java_class.to_s == "[D" # @s = ArrayRealVector.new(elements) else storage = Array.new(size) - elements = [elements,elements] unless elements.is_a?(Array) + elements = [elements, elements] unless elements.is_a?(Array) if size > elements.length (0...size).each do |i| - j=0 unless j!=elements.length + j = 0 unless j != elements.length storage[i] = elements[j] - j+=1 + j += 1 end else storage = elements end - if @dtype == :object - @s = storage + @s = if @dtype == :object + storage else - @s = ArrayRealVector.new(storage.to_java Java::double) + ArrayRealVector.new(storage.to_java(Java::double)) end end @@ -120,22 +119,20 @@ def clone # ArrayRealVector#clone is disable, hence use copy # that returns a deep copy of the object. result.s = @s.copy - return result + result end def entries - return @s.toArray.to_a + @s.toArray.to_a end def twoDMat - return MatrixUtils.createRealMatrix MatrixGenerator.getMatrixDouble(self.s.toArray, @shape[0], @shape[1]) + MatrixUtils.createRealMatrix MatrixGenerator.getMatrixDouble(s.toArray, @shape[0], @shape[1]) end - def dtype - return @dtype - end + attr_reader :dtype - #FIXME + # FIXME def self.guess_dtype arg :float32 end @@ -145,93 +142,87 @@ def stype end def cast_full *args - if args.is_a? Hash - self.dtype = args[:dtype] + self.dtype = if args.is_a? Hash + args[:dtype] else - self.dtype = args[1] + args[1] end - return self + self end def default_value - return nil + nil end def __list_default_value__ - #not implemented currently + # not implemented currently end def __yale_default_value__ - #not implemented currently + # not implemented currently end def [] *args - return xslice(args) + xslice(args) end def slice(*args) - return xslice(args) + xslice(args) end def []=(*args) to_return = nil - if args.length > @dim+1 - raise(ArgumentError, "wrong number of arguments (#{args.length} for #{effective_dim(dim+1)})" ) + if args.length > @dim + 1 + raise(ArgumentError, "wrong number of arguments (#{args.length} for #{effective_dim(dim + 1)})") else slice = get_slice(@dim, args, @shape) dense_storage_set(slice, args[-1]) to_return = args[-1] end - return to_return + to_return end def is_ref? - end # def dim # shape.is_a?(Array) ? shape.length : 2 # end - alias :dimensions :dim + alias dimensions dim def effective_dim(s) d = 0 (0...@dim).each do |i| - d+=1 unless @shape[i] == 1 + d += 1 unless @shape[i] == 1 end - return d + d end - alias :effective_dimensions :effective_dim - - + alias effective_dimensions effective_dim protected def create_dummy_nmatrix nmatrix = NMatrix.new(:copy) - nmatrix.shape = self.shape - nmatrix.dim = self.dim - nmatrix.dtype = self.dtype - nmatrix.stype = self.stype - return nmatrix + nmatrix.shape = shape + nmatrix.dim = dim + nmatrix.dtype = dtype + nmatrix.stype = stype + nmatrix end def __list_to_hash__ - end public - def shape - @shape - end + attr_reader :shape - def supershape s - if (s[:src] == @s) + def supershape s + if s[:src] == @s return shape - # easy case (not a slice) + # easy case (not a slice) else @s = s[:src] end @@ -241,8 +232,8 @@ def supershape s new_shape[index] = shape[index] end - return new_shape - end + new_shape + end def offset # ArrayRealVector takes care of the offset value when indexing a Vector. @@ -255,49 +246,47 @@ def det_exact # raise Exception.new("can only calculate exact determinant for dense matrices") # return nil # end - raise(DataTypeError, "cannot call det_exact on unsigned type") if(self.dtype == :byte) - if (@dim != 2 || @shape[0] != @shape[1]) + raise(DataTypeError, "cannot call det_exact on unsigned type") if dtype == :byte + if @dim != 2 || @shape[0] != @shape[1] raise(ShapeError, "matrices must be square to have a determinant defined") return nil end to_return = nil - if (dtype == :object) + if dtype == :object # to_return = *reinterpret_cast(result); else - to_return = LUDecomposition.new(self.twoDMat).getDeterminant() + to_return = LUDecomposition.new(twoDMat).getDeterminant end - return to_return.round(3) + to_return.round(3) end def det_exact2 - if (@dim != 2 || @shape[0] != @shape[1]) + if @dim != 2 || @shape[0] != @shape[1] raise(ShapeError, "matrices must be square to have a determinant defined") return nil end to_return = nil - if (dtype == :object) + if dtype == :object # to_return = *reinterpret_cast(result); else - to_return = LUDecomposition.new(self.twoDMat).getDeterminant() + to_return = LUDecomposition.new(twoDMat).getDeterminant end - return to_return.round(3) + to_return.round(3) end def complex_conjugate! - end - protected def count_max_elements - return size + size end def reshape_bang arg - if(@stype == :dense) + if @stype == :dense shape_ary = arg size = count_max_elements new_size = 1 @@ -307,12 +296,12 @@ def reshape_bang arg new_size *= shape[index] end - if (size == new_size) + if size == new_size self.shape = shape self.dim = dim return self else - raise(ArgumentError, "reshape cannot resize; size of new and old matrices must match") + raise(ArgumentError, "reshape cannot resize; size of new and old matrices must match") end else raise(NotImplementedError, "reshape in place only for dense stype") @@ -338,103 +327,104 @@ def interpret_shape(shape_ary, dim) raise(ArgumentError, "Expected an array of numbers or a single Fixnum for matrix shape") end - return shape + shape end - public def each_with_indices nmatrix = create_dummy_nmatrix stride = get_stride(self) offset = 0 - #Create indices and initialize them to zero - coords = Array.new(dim){ 0 } + # Create indices and initialize them to zero + coords = Array.new(dim) { 0 } - shape_copy = Array.new(dim) - (0...size).each do |k| - dense_storage_coords(nmatrix, k, coords, stride, offset) - slice_index = dense_storage_pos(coords,stride) - ary = Array.new - if (@dtype == :object) - ary << self.s[slice_index] - else - ary << self.s.toArray.to_a[slice_index] - end - (0...dim).each do |p| - ary << coords[p] - end + shape_copy = Array.new(dim) + if block_given? + (0...size).each do |k| + dense_storage_coords(nmatrix, k, coords, stride, offset) + slice_index = dense_storage_pos(coords, stride) + ary = [] + ary << if @dtype == :object + s[slice_index] + else + s.toArray.to_a[slice_index] + end + (0...dim).each do |p| + ary << coords[p] + end - # yield the array which now consists of the value and the indices - yield(ary) - end if block_given? + # yield the array which now consists of the value and the indices + yield(ary) + end + end - return nmatrix + nmatrix end - def each_stored_with_indices nmatrix = create_dummy_nmatrix stride = get_stride(self) offset = 0 - #Create indices and initialize them to zero - coords = Array.new(dim){ 0 } + # Create indices and initialize them to zero + coords = Array.new(dim) { 0 } - shape_copy = Array.new(dim) + shape_copy = Array.new(dim) - (0...size).each do |k| - dense_storage_coords(nmatrix, k, coords, stride, offset) - slice_index = dense_storage_pos(coords,stride) - ary = Array.new - if (@dtype == :object) - ary << self.s[slice_index] - else - ary << self.s.toArray.to_a[slice_index] - end - (0...dim).each do |p| - ary << coords[p] + if block_given? + (0...size).each do |k| + dense_storage_coords(nmatrix, k, coords, stride, offset) + slice_index = dense_storage_pos(coords, stride) + ary = [] + ary << if @dtype == :object + s[slice_index] + else + s.toArray.to_a[slice_index] + end + (0...dim).each do |p| + ary << coords[p] + end + # yield the array which now consists of the value and the indices + yield(ary) end - # yield the array which now consists of the value and the indices - yield(ary) - end if block_given? + end - return nmatrix + nmatrix end def map_stored - end def each_ordered_stored_with_indices - end - protected def __dense_each__ nmatrix = create_dummy_nmatrix stride = get_stride(self) offset = 0 - #Create indices and initialize them to zero - coords = Array.new(dim){ 0 } + # Create indices and initialize them to zero + coords = Array.new(dim) { 0 } - shape_copy = Array.new(dim) - (0...size).each do |k| - if (@dtype == :object) - dense_storage_coords(nmatrix, k, coords, stride, offset) - slice_index = dense_storage_pos(coords,stride) - yield self.s[slice_index] - else - dense_storage_coords(nmatrix, k, coords, stride, offset) - slice_index = dense_storage_pos(coords,stride) - yield self.s.toArray.to_a[slice_index] + shape_copy = Array.new(dim) + if block_given? + (0...size).each do |k| + if @dtype == :object + dense_storage_coords(nmatrix, k, coords, stride, offset) + slice_index = dense_storage_pos(coords, stride) + yield s[slice_index] + else + dense_storage_coords(nmatrix, k, coords, stride, offset) + slice_index = dense_storage_pos(coords, stride) + yield s.toArray.to_a[slice_index] + end end - end if block_given? - if (@dtype == :object) + end + if @dtype == :object return @s.to_enum else - return @s.toArray().to_a.to_enum + return @s.toArray.to_a.to_enum end end @@ -442,97 +432,89 @@ def __dense_map__ nmatrix = create_dummy_nmatrix stride = get_stride(self) offset = 0 - coords = Array.new(dim){ 0 } - shape_copy = Array.new(dim) + coords = Array.new(dim) { 0 } + shape_copy = Array.new(dim) - s= Java::double[size].new + s = Java::double[size].new (0...size).each do |k| dense_storage_coords(nmatrix, k, coords, stride, offset) - slice_index = dense_storage_pos(coords,stride) + slice_index = dense_storage_pos(coords, stride) y = yield @s.getEntry(slice_index) @s.setEntry(slice_index, y) end nmatrix.s = ArrayRealVector.new s - return nmatrix + nmatrix end def __dense_map_pair__ - end def __list_map_merged_stored__ - end def __list_map_stored__ - end def __yale_map_merged_stored__ - end def __yale_map_stored__ - end def __yale_stored_diagonal_each_with_indices__ - end def __yale_stored_nondiagonal_each_with_indices__ - end - public def ==(otherNmatrix) result = false - if (otherNmatrix.is_a?(NMatrix)) - #check dimension - if (@dim != otherNmatrix.dim) + if otherNmatrix.is_a?(NMatrix) + # check dimension + if @dim != otherNmatrix.dim raise(ShapeError, "cannot compare matrices with different dimension") end - #check shape + # check shape (0...dim).each do |i| - if (@shape[i] != otherNmatrix.shape[i]) - raise(ShapeError, "cannot compare matrices with different shapes"); + if @shape[i] != otherNmatrix.shape[i] + raise(ShapeError, "cannot compare matrices with different shapes") end end - #check the entries - if dtype == :object - result = @s == otherNmatrix.s + # check the entries + result = if dtype == :object + @s == otherNmatrix.s else - result = ArrayComparator.equals(@s.toArray, otherNmatrix.s.toArray) + ArrayComparator.equals(@s.toArray, otherNmatrix.s.toArray) end end result end - def =~ (other) + def =~(other) lha = @s.toArray.to_a rha = other.s.toArray.to_a resultArray = Array.new(lha.length) - if (other.is_a?(NMatrix)) - #check dimension - if (@dim != other.dim) + if other.is_a?(NMatrix) + # check dimension + if @dim != other.dim raise(ShapeError, "cannot compare matrices with different dimension") return nil end - #check shape + # check shape (0...dim).each do |i| - if (@shape[i] != other.shape[i]) - raise(ShapeError, "cannot compare matrices with different shapes"); + if @shape[i] != other.shape[i] + raise(ShapeError, "cannot compare matrices with different shapes") return nil end end - #check the entries + # check the entries (0...lha.length).each do |i| - resultArray[i] = lha[i] == rha[i] ? true : false + resultArray[i] = lha[i] == rha[i] end result = NMatrix.new(:copy) result.shape = @shape @@ -542,26 +524,26 @@ def =~ (other) result end - def !~ (other) + def !~(other) lha = @s.toArray.to_a rha = other.s.toArray.to_a resultArray = Array.new(lha.length) - if (other.is_a?(NMatrix)) - #check dimension - if (@dim != other.dim) + if other.is_a?(NMatrix) + # check dimension + if @dim != other.dim raise(ShapeError, "cannot compare matrices with different dimension") return nil end - #check shape + # check shape (0...dim).each do |i| - if (@shape[i] != other.shape[i]) - raise(ShapeError, "cannot compare matrices with different shapes"); + if @shape[i] != other.shape[i] + raise(ShapeError, "cannot compare matrices with different shapes") return nil end end - #check the entries + # check the entries (0...lha.length).each do |i| - resultArray[i] = lha[i] != rha[i] ? true : false + resultArray[i] = lha[i] != rha[i] end result = NMatrix.new(:copy) result.shape = @shape @@ -571,26 +553,26 @@ def !~ (other) result end - def <= (other) + def <=(other) lha = @s.toArray.to_a rha = other.s.toArray.to_a resultArray = Array.new(lha.length) - if (other.is_a?(NMatrix)) - #check dimension - if (@dim != other.dim) + if other.is_a?(NMatrix) + # check dimension + if @dim != other.dim raise(ShapeError, "cannot compare matrices with different dimension") return nil end - #check shape + # check shape (0...dim).each do |i| - if (@shape[i] != other.shape[i]) - raise(ShapeError, "cannot compare matrices with different shapes"); + if @shape[i] != other.shape[i] + raise(ShapeError, "cannot compare matrices with different shapes") return nil end end - #check the entries + # check the entries (0...lha.length).each do |i| - resultArray[i] = lha[i] <= rha[i] ? true : false + resultArray[i] = lha[i] <= rha[i] end result = NMatrix.new(:copy) result.shape = @shape @@ -600,26 +582,26 @@ def <= (other) result end - def >= (other) + def >=(other) lha = @s.toArray.to_a rha = other.s.toArray.to_a resultArray = Array.new(lha.length) - if (other.is_a?(NMatrix)) - #check dimension - if (@dim != other.dim) + if other.is_a?(NMatrix) + # check dimension + if @dim != other.dim raise(ShapeError, "cannot compare matrices with different dimension") return nil end - #check shape + # check shape (0...dim).each do |i| - if (@shape[i] != other.shape[i]) - raise(ShapeError, "cannot compare matrices with different shapes"); + if @shape[i] != other.shape[i] + raise(ShapeError, "cannot compare matrices with different shapes") return nil end end - #check the entries + # check the entries (0...lha.length).each do |i| - resultArray[i] = lha[i] >= rha[i] ? true : false + resultArray[i] = lha[i] >= rha[i] end result = NMatrix.new(:copy) result.shape = @shape @@ -629,26 +611,26 @@ def >= (other) result end - def < (other) + def <(other) lha = @s.toArray.to_a rha = other.s.toArray.to_a resultArray = Array.new(lha.length) - if (other.is_a?(NMatrix)) - #check dimension - if (@dim != other.dim) + if other.is_a?(NMatrix) + # check dimension + if @dim != other.dim raise(ShapeError, "cannot compare matrices with different dimension") return nil end - #check shape + # check shape (0...dim).each do |i| - if (@shape[i] != other.shape[i]) - raise(ShapeError, "cannot compare matrices with different shapes"); + if @shape[i] != other.shape[i] + raise(ShapeError, "cannot compare matrices with different shapes") return nil end end - #check the entries + # check the entries (0...lha.length).each do |i| - resultArray[i] = lha[i] < rha[i] ? true : false + resultArray[i] = lha[i] < rha[i] end result = NMatrix.new(:copy) result.shape = @shape @@ -658,26 +640,26 @@ def < (other) result end - def > (other) + def >(other) lha = @s.toArray.to_a rha = other.s.toArray.to_a resultArray = Array.new(lha.length) - if (other.is_a?(NMatrix)) - #check dimension - if (@dim != other.dim) + if other.is_a?(NMatrix) + # check dimension + if @dim != other.dim raise(ShapeError, "cannot compare matrices with different dimension") return nil end - #check shape + # check shape (0...dim).each do |i| - if (@shape[i] != other.shape[i]) - raise(ShapeError, "cannot compare matrices with different shapes"); + if @shape[i] != other.shape[i] + raise(ShapeError, "cannot compare matrices with different shapes") return nil end end - #check the entries + # check the entries (0...lha.length).each do |i| - resultArray[i] = lha[i] > rha[i] ? true : false + resultArray[i] = lha[i] > rha[i] end result = NMatrix.new(:copy) result.shape = @shape @@ -693,14 +675,14 @@ def > (other) def dot(other) result = nil - if (other.is_a?(NMatrix)) - #check dimension - if (@shape.length!=2 || other.shape.length!=2) + if other.is_a?(NMatrix) + # check dimension + if @shape.length != 2 || other.shape.length != 2 raise(NotImplementedError, "please convert array to nx1 or 1xn NMatrix first") return nil end - #check shape - if (@shape[1] != other.shape[0]) + # check shape + if @shape[1] != other.shape[0] raise(ArgumentError, "incompatible dimensions") return nil end @@ -710,65 +692,64 @@ def dot(other) # end result = create_dummy_nmatrix - result.shape = [@shape[0],other.shape[1]] + result.shape = [@shape[0], other.shape[1]] twoDMat = self.twoDMat.multiply(other.twoDMat) - result.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0],other.shape[1])) + result.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], other.shape[1])) else - raise(ArgumentError, "cannot have dot product with a scalar"); + raise(ArgumentError, "cannot have dot product with a scalar") end - return result; + result end def symmetric? - return is_symmetric(false) + is_symmetric(false) end def is_symmetric(hermitian) is_symmetric = true - if (@shape[0] == @shape[1] and @dim == 2) + if (@shape[0] == @shape[1]) && (@dim == 2) if @stype == :dense - if (hermitian) - #Currently, we are not dealing with complex matrices. + if hermitian + # Currently, we are not dealing with complex matrices. eps = 0 - is_symmetric = MatrixUtils.isSymmetric(self.twoDMat, eps) + is_symmetric = MatrixUtils.isSymmetric(twoDMat, eps) else eps = 0 - is_symmetric = MatrixUtils.isSymmetric(self.twoDMat, eps) + is_symmetric = MatrixUtils.isSymmetric(twoDMat, eps) end else - #TODO: Implement, at the very least, yale_is_symmetric. Model it after yale/transp.template.c. + # TODO: Implement, at the very least, yale_is_symmetric. Model it after yale/transp.template.c. # raise Exception.new("symmetric? and hermitian? only implemented for dense currently") end end - return is_symmetric ? true : false + is_symmetric ? true : false end def hermitian? - return is_symmetric(true) + is_symmetric(true) end def capacity - end # // protected methods protected - def __inverse__(matrix, bool =true) + def __inverse__(matrix, bool = true) # if (:stype != :dense) # raise Exception.new("needs exact determinant implementation for this matrix stype") # return nil # end - if (@dim != 2 || @shape[0] != @shape[1]) + if @dim != 2 || @shape[0] != @shape[1] raise Exception.new("matrices must be square to have an inverse defined") return nil end to_return = nil - if (dtype == :RUBYOBJ) + if dtype == :RUBYOBJ # to_return = *reinterpret_cast(result); else to_return = create_dummy_nmatrix @@ -776,7 +757,7 @@ def __inverse__(matrix, bool =true) to_return.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1])) end - return to_return + to_return end def __inverse__! @@ -785,19 +766,19 @@ def __inverse__! # return nil # end - if (@dim != 2 || @shape[0] != @shape[1]) + if @dim != 2 || @shape[0] != @shape[1] raise Exception.new("matrices must be square to have an inverse defined") return nil end to_return = nil - if (dtype == :RUBYOBJ) + if dtype == :RUBYOBJ # to_return = *reinterpret_cast(result); else twoDMat = MatrixUtils.inverse(self.twoDMat) @s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1])) end - return self + self end def __inverse_exact__ @@ -806,12 +787,12 @@ def __inverse_exact__ # return nil # end - if (@dim != 2 || @shape[0] != @shape[1]) + if @dim != 2 || @shape[0] != @shape[1] raise Exception.new("matrices must be square to have an inverse defined") return nil end to_return = nil - if (dtype == :RUBYOBJ) + if dtype == :RUBYOBJ # to_return = *reinterpret_cast(result); else to_return = create_dummy_nmatrix @@ -819,8 +800,7 @@ def __inverse_exact__ to_return.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, @shape[0], @shape[1])) end - return to_return - + to_return end private @@ -833,8 +813,8 @@ def __hessenberg__(param) end # load jruby implementation of operators. -require_relative './slice.rb' -require_relative './operators.rb' -require_relative './decomposition.rb' -require_relative './error.rb' -require_relative './enumerable.rb' \ No newline at end of file +require_relative "./slice.rb" +require_relative "./operators.rb" +require_relative "./decomposition.rb" +require_relative "./error.rb" +require_relative "./enumerable.rb" diff --git a/lib/nmatrix/jruby/operators.rb b/lib/nmatrix/jruby/operators.rb index c1298c55..8b982592 100644 --- a/lib/nmatrix/jruby/operators.rb +++ b/lib/nmatrix/jruby/operators.rb @@ -1,15 +1,14 @@ class NMatrix - # A dummy matrix is a matrix without the elements atrribute. # NMatrix#create_dummy_matrix prevents creating copies as @s is set explicitly. def +(other) result = create_dummy_nmatrix - if (other.is_a?(NMatrix)) - #check dimension - raise(ShapeError, "Cannot add matrices with different dimension") if (@dim != other.dim) - #check shape + if other.is_a?(NMatrix) + # check dimension + raise(ShapeError, "Cannot add matrices with different dimension") if @dim != other.dim + # check shape (0...dim).each do |i| - raise(ShapeError, "Cannot add matrices with different shapes") if (@shape[i] != other.shape[i]) + raise(ShapeError, "Cannot add matrices with different shapes") if @shape[i] != other.shape[i] end result.s = @s.copy.add(other.s) else @@ -20,12 +19,12 @@ def +(other) def -(other) result = create_dummy_nmatrix - if (other.is_a?(NMatrix)) - #check dimension - raise(ShapeError, "Cannot subtract matrices with different dimension") if (@dim != other.dim) - #check shape + if other.is_a?(NMatrix) + # check dimension + raise(ShapeError, "Cannot subtract matrices with different dimension") if @dim != other.dim + # check shape (0...dim).each do |i| - raise(ShapeError, "Cannot subtract matrices with different shapes") if (@shape[i] != other.shape[i]) + raise(ShapeError, "Cannot subtract matrices with different shapes") if @shape[i] != other.shape[i] end result.s = @s.copy.subtract(other.s) else @@ -36,12 +35,12 @@ def -(other) def *(other) result = create_dummy_nmatrix - if (other.is_a?(NMatrix)) - #check dimension - raise(ShapeError, "Cannot multiply matrices with different dimension") if (@dim != other.dim) - #check shape + if other.is_a?(NMatrix) + # check dimension + raise(ShapeError, "Cannot multiply matrices with different dimension") if @dim != other.dim + # check shape (0...dim).each do |i| - raise(ShapeError, "Cannot multiply matrices with different shapes") if (@shape[i] != other.shape[i]) + raise(ShapeError, "Cannot multiply matrices with different shapes") if @shape[i] != other.shape[i] end result.s = @s.copy.ebeMultiply(other.s) else @@ -52,12 +51,12 @@ def *(other) def /(other) result = create_dummy_nmatrix - if (other.is_a?(NMatrix)) - #check dimension - raise(ShapeError, "Cannot divide matrices with different dimension") if (@dim != other.dim) - #check shape + if other.is_a?(NMatrix) + # check dimension + raise(ShapeError, "Cannot divide matrices with different dimension") if @dim != other.dim + # check shape (0...dim).each do |i| - raise(ShapeError, "Cannot divide matrices with different shapes") if (@shape[i] != other.shape[i]) + raise(ShapeError, "Cannot divide matrices with different shapes") if @shape[i] != other.shape[i] end result.s = @s.copy.ebeDivide(other.s) else @@ -78,43 +77,43 @@ def %(other) raise Exception.new("modulus not supported in NMatrix-jruby") end - def atan2(other, scalar=false) + def atan2(other, scalar = false) result = create_dummy_nmatrix - if scalar - result.s = ArrayRealVector.new MathHelper.atan2Scalar(other, @s.toArray) + result.s = if scalar + ArrayRealVector.new MathHelper.atan2Scalar(other, @s.toArray) else - if other.is_a? NMatrix - result.s = ArrayRealVector.new MathHelper.atan2(other.s.toArray, @s.toArray) + result.s = if other.is_a? NMatrix + ArrayRealVector.new MathHelper.atan2(other.s.toArray, @s.toArray) else - result.s = ArrayRealVector.new MathHelper.atan2Scalar2(other, @s.toArray) + ArrayRealVector.new MathHelper.atan2Scalar2(other, @s.toArray) end end result end - def ldexp(other, scalar=false) + def ldexp(other, scalar = false) result = create_dummy_nmatrix - if scalar - result.s = ArrayRealVector.new MathHelper.ldexpScalar(other, @s.toArray) + result.s = if scalar + ArrayRealVector.new MathHelper.ldexpScalar(other, @s.toArray) else - if other.is_a? NMatrix - result.s = ArrayRealVector.new MathHelper.ldexp(other.s.toArray, @s.toArray) + result.s = if other.is_a? NMatrix + ArrayRealVector.new MathHelper.ldexp(other.s.toArray, @s.toArray) else - result.s = ArrayRealVector.new MathHelper.ldexpScalar2(other, @s.toArray) + ArrayRealVector.new MathHelper.ldexpScalar2(other, @s.toArray) end end result end - def hypot(other, scalar=false) + def hypot(other, scalar = false) result = create_dummy_nmatrix - if scalar - result.s = ArrayRealVector.new MathHelper.hypotScalar(other, @s.toArray) + result.s = if scalar + ArrayRealVector.new MathHelper.hypotScalar(other, @s.toArray) else - if other.is_a? NMatrix - result.s = ArrayRealVector.new MathHelper.hypot(other.s.toArray, @s.toArray) + result.s = if other.is_a? NMatrix + ArrayRealVector.new MathHelper.hypot(other.s.toArray, @s.toArray) else - result.s = ArrayRealVector.new MathHelper.hypotScalar(other, @s.toArray) + ArrayRealVector.new MathHelper.hypotScalar(other, @s.toArray) end end result @@ -122,49 +121,49 @@ def hypot(other, scalar=false) def sin result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Sin.new()) + result.s = @s.copy.mapToSelf(Sin.new) result end def cos result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Cos.new()) + result.s = @s.copy.mapToSelf(Cos.new) result end def tan result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Tan.new()) + result.s = @s.copy.mapToSelf(Tan.new) result end def asin result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Asin.new()) + result.s = @s.copy.mapToSelf(Asin.new) result end def acos result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Acos.new()) + result.s = @s.copy.mapToSelf(Acos.new) result end def atan result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Atan.new()) + result.s = @s.copy.mapToSelf(Atan.new) result end def sinh result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Sinh.new()) + result.s = @s.copy.mapToSelf(Sinh.new) result end def cosh result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Cosh.new()) + result.s = @s.copy.mapToSelf(Cosh.new) result end @@ -172,57 +171,57 @@ def tanh result = NMatrix.new(:copy) result.shape = @shape result.dim = @dim - result.s = @s.copy.mapToSelf(Tanh.new()) + result.s = @s.copy.mapToSelf(Tanh.new) result end def asinh result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Asinh.new()) + result.s = @s.copy.mapToSelf(Asinh.new) result end def acosh result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Acosh.new()) + result.s = @s.copy.mapToSelf(Acosh.new) result end def atanh result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Atanh.new()) + result.s = @s.copy.mapToSelf(Atanh.new) result end def exp result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Exp.new()) + result.s = @s.copy.mapToSelf(Exp.new) result end def log(val = :natural) result = create_dummy_nmatrix - if val == :natural - result.s = @s.copy.mapToSelf(Log.new()) + result.s = if val == :natural + @s.copy.mapToSelf(Log.new) else - result.s = ArrayRealVector.new MathHelper.log(val, @s.toArray) + ArrayRealVector.new MathHelper.log(val, @s.toArray) end result end def log2 - self.log(2) + log(2) end def log10 result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Log10.new()) + result.s = @s.copy.mapToSelf(Log10.new) result end def sqrt result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Sqrt.new()) + result.s = @s.copy.mapToSelf(Sqrt.new) result end @@ -240,7 +239,7 @@ def erfc def cbrt result = create_dummy_nmatrix - result.s = @s.copy.mapToSelf(Cbrt.new()) + result.s = @s.copy.mapToSelf(Cbrt.new) result end @@ -260,7 +259,7 @@ def floor result = create_dummy_nmatrix # Need to be changed later result.dtype = :int64 - result.s = @s.copy.mapToSelf(Floor.new()) + result.s = @s.copy.mapToSelf(Floor.new) result end @@ -268,7 +267,7 @@ def ceil result = create_dummy_nmatrix # Need to be changed later result.dtype = :int64 - result.s = @s.copy.mapToSelf(Ceil.new()) + result.s = @s.copy.mapToSelf(Ceil.new) result end @@ -279,5 +278,4 @@ def round result.s = ArrayRealVector.new MathHelper.round(@s.toArray) result end - -end \ No newline at end of file +end diff --git a/lib/nmatrix/jruby/slice.rb b/lib/nmatrix/jruby/slice.rb index d08cbcd7..cdf53e2a 100644 --- a/lib/nmatrix/jruby/slice.rb +++ b/lib/nmatrix/jruby/slice.rb @@ -1,9 +1,8 @@ class NMatrix - def get_slice(dim, args, shape_array) slice = {} - slice[:coords]=[] - slice[:lengths]=[] + slice[:coords] = [] + slice[:lengths] = [] slice[:single] = true argc = args.length @@ -12,55 +11,55 @@ def get_slice(dim, args, shape_array) (0...dim).each do |r| v = t == argc ? nil : args[t] - if(argc - t + r < dim && shape_array[r] ==1) + if argc - t + r < dim && shape_array[r] == 1 slice[:coords][r] = 0 slice[:lengths][r] = 1 - elsif v.is_a?(Fixnum) + elsif v.is_a?(Integer) v_ = v.to_i.to_int - if (v_ < 0) # checking for negative indexes - slice[:coords][r] = shape_array[r]+v_ + slice[:coords][r] = if v_ < 0 # checking for negative indexes + shape_array[r] + v_ else - slice[:coords][r] = v_ + v_ end slice[:lengths][r] = 1 - t+=1 - elsif (v.is_a?(Symbol) && v == :*) + t += 1 + elsif v.is_a?(Symbol) && v == :* slice[:coords][r] = 0 slice[:lengths][r] = shape_array[r] slice[:single] = false - t+=1 + t += 1 elsif v.is_a?(Range) begin_ = v.begin end_ = v.end excl = v.exclude_end? - slice[:coords][r] = (begin_ < 0) ? shape[r] + begin_ : begin_ + slice[:coords][r] = begin_ < 0 ? shape[r] + begin_ : begin_ # Exclude last element for a...b range - if (end_ < 0) - slice[:lengths][r] = shape_array[r] + end_ - slice[:coords][r] + (excl ? 0 : 1) + slice[:lengths][r] = if end_ < 0 + shape_array[r] + end_ - slice[:coords][r] + (excl ? 0 : 1) else - slice[:lengths][r] = end_ - slice[:coords][r] + (excl ? 0 : 1) + end_ - slice[:coords][r] + (excl ? 0 : 1) end slice[:single] = false - t+=1 + t += 1 else raise(ArgumentError, "expected Fixnum or Range for slice component instead of #{v.class}") end - if (slice[:coords][r] > shape_array[r] || slice[:coords][r] + slice[:lengths][r] > shape_array[r]) + if slice[:coords][r] > shape_array[r] || slice[:coords][r] + slice[:lengths][r] > shape_array[r] raise(RangeError, "slice is larger than matrix in dimension #{r} (slice component #{t})") end end - return slice + slice end def get_stride(nmatrix) - stride = Array.new() + stride = [] (0...nmatrix.dim).each do |i| - stride[i] = 1; - (i+1...dim).each do |j| + stride[i] = 1 + (i + 1...dim).each do |j| stride[i] *= nmatrix.shape[j] end end @@ -70,54 +69,54 @@ def get_stride(nmatrix) def xslice(args) result = nil - if self.dim < args.length - raise(ArgumentError,"wrong number of arguments (#{args} for #{effective_dim(self)})") + if dim < args.length + raise(ArgumentError, "wrong number of arguments (#{args} for #{effective_dim(self)})") else - result = Array.new() + result = [] slice = get_slice(@dim, args, @shape) stride = get_stride(self) if slice[:single] - if (@dtype == :object) - result = @s[dense_storage_get(slice,stride)] + if @dtype == :object + result = @s[dense_storage_get(slice, stride)] else - s = @s.toArray().to_a - result = @s.getEntry(dense_storage_get(slice,stride)) + s = @s.toArray.to_a + result = @s.getEntry(dense_storage_get(slice, stride)) end else - result = dense_storage_get(slice,stride) + result = dense_storage_get(slice, stride) end end - return result + result end - #its by ref + # its by ref def xslice_ref(args) result = nil - if self.dim < args.length - raise(ArgumentError,"wrong number of arguments (#{args} for #{effective_dim(self)})") + if dim < args.length + raise(ArgumentError, "wrong number of arguments (#{args} for #{effective_dim(self)})") else - result = Array.new() + result = [] slice = get_slice(@dim, args, @shape) stride = get_stride(self) - if slice[:single] - if (@dtype == :object) - result = @s[dense_storage_get(slice,stride)] + result = if slice[:single] + if @dtype == :object + @s[dense_storage_get(slice, stride)] else - result = @s.getEntry(dense_storage_get(slice,stride)) + @s.getEntry(dense_storage_get(slice, stride)) end else - result = dense_storage_ref(slice,stride) + dense_storage_ref(slice, stride) end end - return result + result end - def dense_storage_get(slice,stride) + def dense_storage_get(slice, stride) if slice[:single] - return dense_storage_pos(slice[:coords],stride) + dense_storage_pos(slice[:coords], stride) else shape = @shape.dup (0...@dim).each do |i| @@ -128,84 +127,85 @@ def dense_storage_get(slice,stride) result = NMatrix.new(:copy) result.dim = dim result.dtype = @dtype - resultShape= Array.new(dim) + resultShape = Array.new(dim) (0...dim).each do |i| - resultShape[i] = slice[:lengths][i] + resultShape[i] = slice[:lengths][i] end result.shape = resultShape dest = {} src[:stride] = get_stride(self) - if (@dtype == :object) - src[:elements] = @s + src[:elements] = if @dtype == :object + @s else - src[:elements] = @s.toArray().to_a + @s.toArray.to_a end dest[:stride] = get_stride(result) dest[:shape] = resultShape dest[:elements] = [] temp = [] - s = (slice_copy(src, dest, slice[:lengths], 0, psrc,0)) + s = slice_copy(src, dest, slice[:lengths], 0, psrc, 0) # if # arr = Java::double[s.length].new - if (@dtype == :object) - arr = Java::boolean[s.length].new + arr = if @dtype == :object + Java::boolean[s.length].new else - arr = Java::double[s.length].new + Java::double[s.length].new end (0...s.length).each do |i| arr[i] = s[i] end - if (@dtype == :object) - result.s = arr + result.s = if @dtype == :object + arr else - result.s = ArrayRealVector.new(arr) + ArrayRealVector.new(arr) end - return result + result end end - def slice_copy(src, dest,lengths, pdest, psrc,n) - if @dim-n>1 + def slice_copy(src, dest, lengths, pdest, psrc, n) + if @dim - n > 1 (0...lengths[n]).each do |i| - slice_copy(src, dest, lengths,pdest+dest[:stride][n]*i,psrc+src[:stride][n]*i,n+1) + slice_copy(src, dest, lengths, pdest + dest[:stride][n] * i, psrc + src[:stride][n] * i, n + 1) end else (0...dest[:shape][n]).each do |p| - dest[:elements][p+pdest] = src[:elements][p+psrc] + dest[:elements][p + pdest] = src[:elements][p + psrc] end end dest[:elements] end - def dense_storage_coords(s, slice_pos, coords_out, stride, offset) #array, int, array - temp_pos = slice_pos; + # array, int, array + def dense_storage_coords(s, slice_pos, coords_out, stride, offset) + temp_pos = slice_pos (0...dim).each do |i| - coords_out[i] = (temp_pos - temp_pos % stride[i])/stride[i] - offset[i]; + coords_out[i] = (temp_pos - temp_pos % stride[i]) / stride[i] - offset[i] temp_pos = temp_pos % stride[i] end - return temp_pos + temp_pos end - def dense_storage_pos(coords,stride) - pos = 0; + def dense_storage_pos(coords, stride) + pos = 0 offset = 0 (0...@dim).each do |i| - pos += coords[i] * stride[i] ; + pos += coords[i] * stride[i] end - return pos + offset; + pos + offset end def slice_set(dest, lengths, pdest, rank, v, v_size, v_offset) - if (dim - rank > 1) + if dim - rank > 1 (0...lengths[rank]).each do |i| - slice_set(dest, lengths, pdest + dest[:stride][rank] * i, rank + 1, v, v_size, v_offset); + slice_set(dest, lengths, pdest + dest[:stride][rank] * i, rank + 1, v, v_size, v_offset) end else (0...lengths[rank]).each do |p| - v_offset %= v_size if(v_offset >= v_size) + v_offset %= v_size if v_offset >= v_size # elem = dest[:elements] # elem[p + pdest] = v[v_offset] if @dtype == :object @@ -226,10 +226,10 @@ def dense_storage_set(slice, right) right = right.s.toArray.to_a end - if(right.is_a?(Array)) + if right.is_a?(Array) v_size = right.length v = right - if (dtype == :RUBYOBJ) + if dtype == :RUBYOBJ # nm_register_values(reinterpret_cast(v), v_size) end @@ -238,13 +238,13 @@ def dense_storage_set(slice, right) end else v = [right] - if (@dtype == :RUBYOBJ) + if @dtype == :RUBYOBJ # nm_register_values(reinterpret_cast(v), v_size) end end - if(slice[:single]) + if slice[:single] # reinterpret_cast(s->elements)[nm_dense_storage_pos(s, slice->coords)] = v; - pos = dense_storage_pos(slice[:coords],stride) + pos = dense_storage_pos(slice[:coords], stride) if @dtype == :object @s[pos] = v[0] else @@ -256,9 +256,8 @@ def dense_storage_set(slice, right) dest[:stride] = get_stride(self) dest[:shape] = shape # dest[:elements] = @s.toArray().to_a - dense_pos = dense_storage_pos(slice[:coords],stride) + dense_pos = dense_storage_pos(slice[:coords], stride) slice_set(dest, slice[:lengths], dense_pos, 0, v, v_size, v_offset) end end - -end \ No newline at end of file +end diff --git a/lib/nmatrix/lapack_core.rb b/lib/nmatrix/lapack_core.rb index 2d5e4b9e..8d48ec00 100644 --- a/lib/nmatrix/lapack_core.rb +++ b/lib/nmatrix/lapack_core.rb @@ -33,10 +33,8 @@ #++ class NMatrix - module LAPACK - - #Add functions from C extension to main LAPACK module + # Add functions from C extension to main LAPACK module class << self NMatrix::Internal::LAPACK.singleton_methods.each do |m| define_method m, NMatrix::Internal::LAPACK.method(m).to_proc @@ -71,18 +69,17 @@ def laswp(matrix, ipiv) raise(StorageTypeError, "LAPACK functions only work on :dense NMatrix instances") unless matrix.stype == :dense raise(ArgumentError, "expected Array ipiv to have no more entries than NMatrix a has columns") if ipiv.size > matrix.shape[1] - clapack_laswp(matrix.shape[0], matrix, matrix.shape[1], 0, ipiv.size-1, ipiv, 1) + clapack_laswp(matrix.shape[0], matrix, matrix.shape[1], 0, ipiv.size - 1, ipiv, 1) end def alloc_svd_result(matrix) [ NMatrix.new(matrix.shape[0], dtype: matrix.dtype), - NMatrix.new([[matrix.shape[0],matrix.shape[1]].min,1], dtype: matrix.abs_dtype), - NMatrix.new(matrix.shape[1], dtype: matrix.dtype) + NMatrix.new([[matrix.shape[0], matrix.shape[1]].min, 1], dtype: matrix.abs_dtype), + NMatrix.new(matrix.shape[1], dtype: matrix.dtype), ] end - # # call-seq: # gesvd(matrix) -> [u, sigma, v_transpose] @@ -95,8 +92,8 @@ def alloc_svd_result(matrix) # # Requires either the nmatrix-lapacke or nmatrix-atlas gem. # - def gesvd(matrix, workspace_size=1) - raise(NotImplementedError,"gesvd requires either the nmatrix-atlas or nmatrix-lapacke gem") + def gesvd(matrix, workspace_size = 1) + raise(NotImplementedError, "gesvd requires either the nmatrix-atlas or nmatrix-lapacke gem") end # @@ -112,8 +109,8 @@ def gesvd(matrix, workspace_size=1) # # Requires either the nmatrix-lapacke or nmatrix-atlas gem. # - def gesdd(matrix, workspace_size=nil) - raise(NotImplementedError,"gesvd requires either the nmatrix-atlas or nmatrix-lapacke gem") + def gesdd(matrix, workspace_size = nil) + raise(NotImplementedError, "gesvd requires either the nmatrix-atlas or nmatrix-lapacke gem") end # @@ -142,7 +139,7 @@ def gesdd(matrix, workspace_size=nil) # # Only available if nmatrix-lapack or nmatrix-atlas is installed. # - def geev(matrix, which=:both) + def geev(matrix, which = :both) raise(NotImplementedError, "geev requires either the nmatrix-atlas or nmatrix-lapack gem") end @@ -150,31 +147,31 @@ def geev(matrix, which=:both) # now require nmatrix-atlas to run properly, so we can just # implemented their stubs in Ruby. def lapack_gesvd(jobu, jobvt, m, n, a, lda, s, u, ldu, vt, ldvt, lwork) - raise(NotImplementedError,"lapack_gesvd requires the nmatrix-atlas gem") + raise(NotImplementedError, "lapack_gesvd requires the nmatrix-atlas gem") end def lapack_gesdd(jobz, m, n, a, lda, s, u, ldu, vt, ldvt, lwork) - raise(NotImplementedError,"lapack_gesdd requires the nmatrix-atlas gem") + raise(NotImplementedError, "lapack_gesdd requires the nmatrix-atlas gem") end def lapack_geev(jobvl, jobvr, n, a, lda, w, wi, vl, ldvl, vr, ldvr, lwork) - raise(NotImplementedError,"lapack_geev requires the nmatrix-atlas gem") + raise(NotImplementedError, "lapack_geev requires the nmatrix-atlas gem") end def clapack_potrf(order, uplo, n, a, lda) - raise(NotImplementedError,"clapack_potrf requires the nmatrix-atlas gem") + raise(NotImplementedError, "clapack_potrf requires the nmatrix-atlas gem") end def clapack_potri(order, uplo, n, a, lda) - raise(NotImplementedError,"clapack_potri requires the nmatrix-atlas gem") + raise(NotImplementedError, "clapack_potri requires the nmatrix-atlas gem") end def clapack_potrs(order, uplo, n, nrhs, a, lda, b, ldb) - raise(NotImplementedError,"clapack_potrs requires the nmatrix-atlas gem") + raise(NotImplementedError, "clapack_potrs requires the nmatrix-atlas gem") end def clapack_getri(order, n, a, lda, ipiv) - raise(NotImplementedError,"clapack_getri requires the nmatrix-atlas gem") + raise(NotImplementedError, "clapack_getri requires the nmatrix-atlas gem") end end end diff --git a/lib/nmatrix/lapack_ext_common.rb b/lib/nmatrix/lapack_ext_common.rb index 39c22693..83305574 100644 --- a/lib/nmatrix/lapack_ext_common.rb +++ b/lib/nmatrix/lapack_ext_common.rb @@ -27,22 +27,22 @@ #++ class NMatrix - def NMatrix.register_lapack_extension(name) - if (defined? @@lapack_extension) + def self.register_lapack_extension(name) + if defined? @@lapack_extension raise "Attempting to load #{name} when #{@@lapack_extension} is already loaded. You can only load one LAPACK extension." end @@lapack_extension = name end - alias_method :internal_dot, :dot + alias internal_dot dot def dot(right_v) - if (right_v.is_a?(NMatrix) && self.stype == :dense && right_v.stype == :dense && - self.dim == 2 && right_v.dim == 2 && self.shape[1] == right_v.shape[0]) + if right_v.is_a?(NMatrix) && stype == :dense && right_v.stype == :dense && + dim == 2 && right_v.dim == 2 && shape[1] == right_v.shape[0] - result_dtype = NMatrix.upcast(self.dtype,right_v.dtype) - left = self.dtype == result_dtype ? self : self.cast(dtype: result_dtype) + result_dtype = NMatrix.upcast(dtype, right_v.dtype) + left = dtype == result_dtype ? self : cast(dtype: result_dtype) right = right_v.dtype == result_dtype ? right_v : right_v.cast(dtype: result_dtype) left = left.clone if left.is_ref? @@ -52,18 +52,18 @@ def dot(right_v) result_n = right.shape[1] left_n = left.shape[1] vector = result_n == 1 - result = NMatrix.new([result_m,result_n], dtype: result_dtype) + result = NMatrix.new([result_m, result_n], dtype: result_dtype) if vector NMatrix::BLAS.cblas_gemv(false, result_m, left_n, 1, left, left_n, right, 1, 0, result, 1) else NMatrix::BLAS.cblas_gemm(:row, false, false, result_m, result_n, left_n, 1, left, left_n, right, result_n, 0, result, result_n) end - return result + result else - #internal_dot will handle non-dense matrices (and also dot-products for NMatrix's with dim=1), - #and also all error-handling if the input is not valid - self.internal_dot(right_v) + # internal_dot will handle non-dense matrices (and also dot-products for NMatrix's with dim=1), + # and also all error-handling if the input is not valid + internal_dot(right_v) end end end diff --git a/lib/nmatrix/lapack_plugin.rb b/lib/nmatrix/lapack_plugin.rb index e55ee481..f614ab08 100644 --- a/lib/nmatrix/lapack_plugin.rb +++ b/lib/nmatrix/lapack_plugin.rb @@ -30,15 +30,15 @@ # by both of these gems (e.g. NMatrix#potrf! or NMatrix::LAPACK.geev), # but doesn't care which one is installed, they can # just `require 'nmatrix/lapack_plugin'` rather than having to choose between -# `require 'nmatrix/lapacke'` or `require 'nmatrix/lapacke'` +# `require 'nmatrix/lapacke'` or `require 'nmatrix/lapacke'` #++ begin - require 'nmatrix/atlas' + require "nmatrix/atlas" rescue LoadError begin - require 'nmatrix/lapacke' + require "nmatrix/lapacke" rescue LoadError - raise(LoadError,"Either nmatrix-atlas or nmatrix-lapacke must be installed") + raise(LoadError, "Either nmatrix-atlas or nmatrix-lapacke must be installed") end end diff --git a/lib/nmatrix/lapacke.rb b/lib/nmatrix/lapacke.rb index 1296b99e..8967340b 100644 --- a/lib/nmatrix/lapacke.rb +++ b/lib/nmatrix/lapacke.rb @@ -27,16 +27,16 @@ # nice ruby interfaces for LAPACK functions. #++ -require 'nmatrix/nmatrix.rb' #need to have nmatrix required first or else bad things will happen -require_relative 'lapack_ext_common' +require "nmatrix/nmatrix.rb" # need to have nmatrix required first or else bad things will happen +require_relative "lapack_ext_common" NMatrix.register_lapack_extension("nmatrix-lapacke") require "nmatrix_lapacke.so" class NMatrix - #Add functions from the LAPACKE C extension to the main LAPACK and BLAS modules. - #This will overwrite the original functions where applicable. + # Add functions from the LAPACKE C extension to the main LAPACK and BLAS modules. + # This will overwrite the original functions where applicable. module LAPACK class << self NMatrix::LAPACKE::LAPACK.singleton_methods.each do |m| @@ -59,7 +59,7 @@ def posv(uplo, a, b) raise(ShapeError, "a must be square") unless a.dim == 2 && a.shape[0] == a.shape[1] raise(ShapeError, "number of rows of b must equal number of cols of a") unless a.shape[1] == b.shape[0] raise(StorageTypeError, "only works with dense matrices") unless a.stype == :dense && b.stype == :dense - raise(DataTypeError, "only works for non-integer, non-object dtypes") if + raise(DataTypeError, "only works for non-integer, non-object dtypes") if a.integer_dtype? || a.object_dtype? || b.integer_dtype? || b.object_dtype? x = b.clone @@ -71,12 +71,12 @@ def posv(uplo, a, b) x end - def geev(matrix, which=:both) + def geev(matrix, which = :both) raise(StorageTypeError, "LAPACK functions only work on dense matrices") unless matrix.dense? raise(ShapeError, "eigenvalues can only be computed for square matrices") unless matrix.dim == 2 && matrix.shape[0] == matrix.shape[1] - jobvl = (which == :both || which == :left) ? :t : false - jobvr = (which == :both || which == :right) ? :t : false + jobvl = which == :both || which == :left ? :t : false + jobvr = which == :both || which == :right ? :t : false # Copy the matrix so it doesn't get overwritten. temporary_matrix = matrix.clone @@ -88,47 +88,46 @@ def geev(matrix, which=:both) left_output = jobvl ? matrix.clone_structure : nil right_output = jobvr ? matrix.clone_structure : nil - NMatrix::LAPACK::lapacke_geev(:row, - jobvl, # compute left eigenvectors of A? - jobvr, # compute right eigenvectors of A? (left eigenvectors of A**T) - n, # order of the matrix - temporary_matrix,# input matrix (used as work) - n, # leading dimension of matrix - eigenvalues,# real part of computed eigenvalues - imag_eigenvalues,# imag part of computed eigenvalues - left_output, # left eigenvectors, if applicable - n, # leading dimension of left_output - right_output, # right eigenvectors, if applicable - n) # leading dimension of right_output - + NMatrix::LAPACK.lapacke_geev(:row, + jobvl, # compute left eigenvectors of A? + jobvr, # compute right eigenvectors of A? (left eigenvectors of A**T) + n, # order of the matrix + temporary_matrix, # input matrix (used as work) + n, # leading dimension of matrix + eigenvalues, # real part of computed eigenvalues + imag_eigenvalues, # imag part of computed eigenvalues + left_output, # left eigenvectors, if applicable + n, # leading dimension of left_output + right_output, # right eigenvectors, if applicable + n) # leading dimension of right_output # For real dtypes, transform left_output and right_output into correct forms. # If the j'th and the (j+1)'th eigenvalues form a complex conjugate # pair, then the j'th and (j+1)'th columns of the matrix are # the real and imag parts of the eigenvector corresponding # to the j'th eigenvalue. - if !matrix.complex_dtype? + unless matrix.complex_dtype? complex_indices = [] n.times do |i| complex_indices << i if imag_eigenvalues[i] != 0.0 end - if !complex_indices.empty? + unless complex_indices.empty? # For real dtypes, put the real and imaginary parts together - eigenvalues = eigenvalues + imag_eigenvalues*Complex(0.0,1.0) + eigenvalues += imag_eigenvalues * Complex(0.0, 1.0) left_output = left_output.cast(dtype: NMatrix.upcast(:complex64, matrix.dtype)) if left_output right_output = right_output.cast(dtype: NMatrix.upcast(:complex64, matrix.dtype)) if right_output end complex_indices.each_slice(2) do |i, _| if right_output - right_output[0...n,i] = right_output[0...n,i] + right_output[0...n,i+1]*Complex(0.0,1.0) - right_output[0...n,i+1] = right_output[0...n,i].complex_conjugate + right_output[0...n, i] = right_output[0...n, i] + right_output[0...n, i + 1] * Complex(0.0, 1.0) + right_output[0...n, i + 1] = right_output[0...n, i].complex_conjugate end if left_output - left_output[0...n,i] = left_output[0...n,i] + left_output[0...n,i+1]*Complex(0.0,1.0) - left_output[0...n,i+1] = left_output[0...n,i].complex_conjugate + left_output[0...n, i] = left_output[0...n, i] + left_output[0...n, i + 1] * Complex(0.0, 1.0) + left_output[0...n, i + 1] = left_output[0...n, i].complex_conjugate end end end @@ -142,73 +141,73 @@ def geev(matrix, which=:both) end end - def gesvd(matrix, workspace_size=1) + def gesvd(matrix, workspace_size = 1) result = alloc_svd_result(matrix) m = matrix.shape[0] n = matrix.shape[1] - superb = NMatrix.new([[m,n].min], dtype: matrix.abs_dtype) + superb = NMatrix.new([[m, n].min], dtype: matrix.abs_dtype) - NMatrix::LAPACK::lapacke_gesvd(:row, :a, :a, m, n, matrix, n, result[1], result[0], m, result[2], n, superb) + NMatrix::LAPACK.lapacke_gesvd(:row, :a, :a, m, n, matrix, n, result[1], result[0], m, result[2], n, superb) result end - def gesdd(matrix, workspace_size=nil) + def gesdd(matrix, workspace_size = nil) result = alloc_svd_result(matrix) m = matrix.shape[0] n = matrix.shape[1] - NMatrix::LAPACK::lapacke_gesdd(:row, :a, m, n, matrix, n, result[1], result[0], m, result[2], n) + NMatrix::LAPACK.lapacke_gesdd(:row, :a, m, n, matrix, n, result[1], result[0], m, result[2], n) result end end end def getrf! - raise(StorageTypeError, "LAPACK functions only work on dense matrices") unless self.dense? + raise(StorageTypeError, "LAPACK functions only work on dense matrices") unless dense? - ipiv = NMatrix::LAPACK::lapacke_getrf(:row, self.shape[0], self.shape[1], self, self.shape[1]) + ipiv = NMatrix::LAPACK.lapacke_getrf(:row, shape[0], shape[1], self, shape[1]) - return ipiv + ipiv end def invert! - raise(StorageTypeError, "invert only works on dense matrices currently") unless self.dense? + raise(StorageTypeError, "invert only works on dense matrices currently") unless dense? raise(ShapeError, "Cannot invert non-square matrix") unless shape[0] == shape[1] - raise(DataTypeError, "Cannot invert an integer matrix in-place") if self.integer_dtype? + raise(DataTypeError, "Cannot invert an integer matrix in-place") if integer_dtype? # Get the pivot array; factor the matrix - n = self.shape[0] - pivot = NMatrix::LAPACK::lapacke_getrf(:row, n, n, self, n) + n = shape[0] + pivot = NMatrix::LAPACK.lapacke_getrf(:row, n, n, self, n) # Now calculate the inverse using the pivot array - NMatrix::LAPACK::lapacke_getri(:row, n, self, n, pivot) + NMatrix::LAPACK.lapacke_getri(:row, n, self, n, pivot) self end def potrf!(which) - raise(StorageTypeError, "LAPACK functions only work on dense matrices") unless self.dense? - raise(ShapeError, "Cholesky decomposition only valid for square matrices") unless self.dim == 2 && self.shape[0] == self.shape[1] + raise(StorageTypeError, "LAPACK functions only work on dense matrices") unless dense? + raise(ShapeError, "Cholesky decomposition only valid for square matrices") unless dim == 2 && shape[0] == shape[1] - NMatrix::LAPACK::lapacke_potrf(:row, which, self.shape[0], self, self.shape[1]) + NMatrix::LAPACK.lapacke_potrf(:row, which, shape[0], self, shape[1]) end def solve(b, opts = {}) - raise(ShapeError, "Must be called on square matrix") unless self.dim == 2 && self.shape[0] == self.shape[1] - raise(ShapeError, "number of rows of b must equal number of cols of self") if - self.shape[1] != b.shape[0] - raise(ArgumentError, "only works with dense matrices") if self.stype != :dense - raise(ArgumentError, "only works for non-integer, non-object dtypes") if - integer_dtype? or object_dtype? or b.integer_dtype? or b.object_dtype? - - opts = { form: :general }.merge(opts) + raise(ShapeError, "Must be called on square matrix") unless dim == 2 && shape[0] == shape[1] + raise(ShapeError, "number of rows of b must equal number of cols of self") if + shape[1] != b.shape[0] + raise(ArgumentError, "only works with dense matrices") if stype != :dense + raise(ArgumentError, "only works for non-integer, non-object dtypes") if + integer_dtype? || object_dtype? || b.integer_dtype? || b.object_dtype? + + opts = {form: :general}.merge(opts) x = b.clone - n = self.shape[0] + n = shape[0] nrhs = b.shape[1] - case opts[:form] + case opts[:form] when :general clone = self.clone ipiv = NMatrix::LAPACK.lapacke_getrf(:row, n, n, clone, n) @@ -216,16 +215,16 @@ def solve(b, opts = {}) x when :upper_tri, :upper_triangular raise(ArgumentError, "upper triangular solver does not work with complex dtypes") if - complex_dtype? or b.complex_dtype? - NMatrix::BLAS::cblas_trsm(:row, :left, :upper, false, :nounit, n, nrhs, 1.0, self, n, x, nrhs) + complex_dtype? || b.complex_dtype? + NMatrix::BLAS.cblas_trsm(:row, :left, :upper, false, :nounit, n, nrhs, 1.0, self, n, x, nrhs) x when :lower_tri, :lower_triangular raise(ArgumentError, "lower triangular solver does not work with complex dtypes") if - complex_dtype? or b.complex_dtype? - NMatrix::BLAS::cblas_trsm(:row, :left, :lower, false, :nounit, n, nrhs, 1.0, self, n, x, nrhs) + complex_dtype? || b.complex_dtype? + NMatrix::BLAS.cblas_trsm(:row, :left, :lower, false, :nounit, n, nrhs, 1.0, self, n, x, nrhs) x when :pos_def, :positive_definite - u, l = self.factorize_cholesky + u, l = factorize_cholesky z = l.solve(b, form: :lower_tri) u.solve(z, form: :upper_tri) else @@ -235,13 +234,13 @@ def solve(b, opts = {}) # # call-seq: - # geqrf! -> shape.min x 1 NMatrix + # geqrf! -> shape.min x 1 NMatrix # - # QR factorization of a general M-by-N matrix +A+. + # QR factorization of a general M-by-N matrix +A+. # # The QR factorization is A = QR, where Q is orthogonal and R is Upper Triangular - # +A+ is overwritten with the elements of R and Q with Q being represented by the - # elements below A's diagonal and an array of scalar factors in the output NMatrix. + # +A+ is overwritten with the elements of R and Q with Q being represented by the + # elements below A's diagonal and an array of scalar factors in the output NMatrix. # # The matrix Q is represented as a product of elementary reflectors # Q = H(1) H(2) . . . H(k), where k = min(m,n). @@ -251,7 +250,7 @@ def solve(b, opts = {}) # H(i) = I - tau * v * v' # # http://www.netlib.org/lapack/explore-html/d3/d69/dgeqrf_8f.html - # + # # Only works for dense matrices. # # * *Returns* : @@ -260,52 +259,51 @@ def solve(b, opts = {}) # - +StorageTypeError+ -> LAPACK functions only work on dense matrices. # def geqrf! - raise(StorageTypeError, "LAPACK functions only work on dense matrices") unless self.dense? - - tau = NMatrix.new([self.shape.min,1], dtype: self.dtype) - NMatrix::LAPACK::lapacke_geqrf(:row, self.shape[0], self.shape[1], self, self.shape[1], tau) - + raise(StorageTypeError, "LAPACK functions only work on dense matrices") unless dense? + + tau = NMatrix.new([shape.min, 1], dtype: dtype) + NMatrix::LAPACK.lapacke_geqrf(:row, shape[0], shape[1], self, shape[1], tau) + tau end - + # # call-seq: # ormqr(tau) -> NMatrix # ormqr(tau, side, transpose, c) -> NMatrix # - # Returns the product Q * c or c * Q after a call to geqrf! used in QR factorization. - # +c+ is overwritten with the elements of the result NMatrix if supplied. Q is the orthogonal matrix + # Returns the product Q * c or c * Q after a call to geqrf! used in QR factorization. + # +c+ is overwritten with the elements of the result NMatrix if supplied. Q is the orthogonal matrix # represented by tau and the calling NMatrix - # + # # Only works on float types, use unmqr for complex types. # # == Arguments # # * +tau+ - vector containing scalar factors of elementary reflectors # * +side+ - direction of multiplication [:left, :right] - # * +transpose+ - apply Q with or without transpose [false, :transpose] + # * +transpose+ - apply Q with or without transpose [false, :transpose] # * +c+ - NMatrix multplication argument that is overwritten, no argument assumes c = identity # # * *Returns* : # - # - Q * c or c * Q Where Q may be transposed before multiplication. - # + # - Q * c or c * Q Where Q may be transposed before multiplication. + # # # * *Raises* : # - +StorageTypeError+ -> LAPACK functions only work on dense matrices. # - +TypeError+ -> Works only on floating point matrices, use unmqr for complex types # - +TypeError+ -> c must have the same dtype as the calling NMatrix # - def ormqr(tau, side=:left, transpose=false, c=nil) - raise(StorageTypeError, "LAPACK functions only work on dense matrices") unless self.dense? - raise(TypeError, "Works only on floating point matrices, use unmqr for complex types") if self.complex_dtype? - raise(TypeError, "c must have the same dtype as the calling NMatrix") if c and c.dtype != self.dtype + def ormqr(tau, side = :left, transpose = false, c = nil) + raise(StorageTypeError, "LAPACK functions only work on dense matrices") unless dense? + raise(TypeError, "Works only on floating point matrices, use unmqr for complex types") if complex_dtype? + raise(TypeError, "c must have the same dtype as the calling NMatrix") if c && (c.dtype != dtype) + # Default behaviour produces Q * I = Q if c is not supplied. + result = c ? c.clone : NMatrix.identity(shape[0], dtype: dtype) + NMatrix::LAPACK.lapacke_ormqr(:row, side, transpose, result.shape[0], result.shape[1], tau.shape[0], self, shape[1], tau, result, result.shape[1]) - #Default behaviour produces Q * I = Q if c is not supplied. - result = c ? c.clone : NMatrix.identity(self.shape[0], dtype: self.dtype) - NMatrix::LAPACK::lapacke_ormqr(:row, side, transpose, result.shape[0], result.shape[1], tau.shape[0], self, self.shape[1], tau, result, result.shape[1]) - result end @@ -314,40 +312,38 @@ def ormqr(tau, side=:left, transpose=false, c=nil) # unmqr(tau) -> NMatrix # unmqr(tau, side, transpose, c) -> NMatrix # - # Returns the product Q * c or c * Q after a call to geqrf! used in QR factorization. - # +c+ is overwritten with the elements of the result NMatrix if it is supplied. Q is the orthogonal matrix + # Returns the product Q * c or c * Q after a call to geqrf! used in QR factorization. + # +c+ is overwritten with the elements of the result NMatrix if it is supplied. Q is the orthogonal matrix # represented by tau and the calling NMatrix - # + # # Only works on complex types, use ormqr for float types. # # == Arguments # # * +tau+ - vector containing scalar factors of elementary reflectors # * +side+ - direction of multiplication [:left, :right] - # * +transpose+ - apply Q as Q or its complex conjugate [false, :complex_conjugate] + # * +transpose+ - apply Q as Q or its complex conjugate [false, :complex_conjugate] # * +c+ - NMatrix multplication argument that is overwritten, no argument assumes c = identity # # * *Returns* : # - # - Q * c or c * Q Where Q may be transformed to its complex conjugate before multiplication. - # + # - Q * c or c * Q Where Q may be transformed to its complex conjugate before multiplication. + # # # * *Raises* : # - +StorageTypeError+ -> LAPACK functions only work on dense matrices. # - +TypeError+ -> Works only on floating point matrices, use unmqr for complex types # - +TypeError+ -> c must have the same dtype as the calling NMatrix # - def unmqr(tau, side=:left, transpose=false, c=nil) - raise(StorageTypeError, "ATLAS functions only work on dense matrices") unless self.dense? - raise(TypeError, "Works only on complex matrices, use ormqr for normal floating point matrices") unless self.complex_dtype? - raise(TypeError, "c must have the same dtype as the calling NMatrix") if c and c.dtype != self.dtype - - #Default behaviour produces Q * I = Q if c is not supplied. - result = c ? c.clone : NMatrix.identity(self.shape[0], dtype: self.dtype) - NMatrix::LAPACK::lapacke_unmqr(:row, side, transpose, result.shape[0], result.shape[1], tau.shape[0], self, self.shape[1], tau, result, result.shape[1]) - - result - end + def unmqr(tau, side = :left, transpose = false, c = nil) + raise(StorageTypeError, "ATLAS functions only work on dense matrices") unless dense? + raise(TypeError, "Works only on complex matrices, use ormqr for normal floating point matrices") unless complex_dtype? + raise(TypeError, "c must have the same dtype as the calling NMatrix") if c && (c.dtype != dtype) + # Default behaviour produces Q * I = Q if c is not supplied. + result = c ? c.clone : NMatrix.identity(shape[0], dtype: dtype) + NMatrix::LAPACK.lapacke_unmqr(:row, side, transpose, result.shape[0], result.shape[1], tau.shape[0], self, shape[1], tau, result, result.shape[1]) + result + end end diff --git a/lib/nmatrix/math.rb b/lib/nmatrix/math.rb index f71ea7a2..d30caa32 100644 --- a/lib/nmatrix/math.rb +++ b/lib/nmatrix/math.rb @@ -29,11 +29,10 @@ #++ class NMatrix - module NMMath #:nodoc: METHODS_ARITY_2 = [:atan2, :ldexp, :hypot] METHODS_ARITY_1 = [:cos, :sin, :tan, :acos, :asin, :atan, :cosh, :sinh, :tanh, :acosh, - :asinh, :atanh, :exp, :log2, :log10, :sqrt, :cbrt, :erf, :erfc, :gamma, :-@] + :asinh, :atanh, :exp, :log2, :log10, :sqrt, :cbrt, :erf, :erfc, :gamma, :-@,] end # Methods for generating permutation matrix from LU factorization results. @@ -43,7 +42,7 @@ def permutation_matrix_from(pivot_array) perm_arry = permutation_array_for(pivot_array) n = NMatrix.zeros(perm_arry.size, dtype: :byte) - perm_arry.each_with_index { |e, i| n[e,i] = 1 } + perm_arry.each_with_index { |e, i| n[e, i] = 1 } n end @@ -51,9 +50,9 @@ def permutation_matrix_from(pivot_array) def permutation_array_for(pivot_array) perm_arry = Array.new(pivot_array.size) { |i| i } perm_arry.each_index do |i| - #the pivot indices returned by LAPACK getrf are indexed starting - #from 1, so we need to subtract 1 here - perm_arry[i], perm_arry[pivot_array[i]-1] = perm_arry[pivot_array[i]-1], perm_arry[i] + # the pivot indices returned by LAPACK getrf are indexed starting + # from 1, so we need to subtract 1 here + perm_arry[i], perm_arry[pivot_array[i] - 1] = perm_arry[pivot_array[i] - 1], perm_arry[i] end perm_arry @@ -75,11 +74,11 @@ def permutation_array_for(pivot_array) # - +DataTypeError+ -> cannot invert an integer matrix in-place. # def invert! - raise(StorageTypeError, "invert only works on dense matrices currently") unless self.dense? - raise(ShapeError, "Cannot invert non-square matrix") unless self.dim == 2 && self.shape[0] == self.shape[1] - raise(DataTypeError, "Cannot invert an integer matrix in-place") if self.integer_dtype? + raise(StorageTypeError, "invert only works on dense matrices currently") unless dense? + raise(ShapeError, "Cannot invert non-square matrix") unless dim == 2 && shape[0] == shape[1] + raise(DataTypeError, "Cannot invert an integer matrix in-place") if integer_dtype? - #No internal implementation of getri, so use this other function + # No internal implementation of getri, so use this other function __inverse__(self, true) end @@ -100,17 +99,17 @@ def invert! # - +ShapeError+ -> matrix must be square. # def invert - #write this in terms of invert! so plugins will only have to overwrite - #invert! and not invert - if self.integer_dtype? - cloned = self.cast(dtype: :float64) + # write this in terms of invert! so plugins will only have to overwrite + # invert! and not invert + if integer_dtype? + cloned = cast(dtype: :float64) cloned.invert! else - cloned = self.clone + cloned = clone cloned.invert! end end - alias :inverse :invert + alias inverse invert # call-seq: # exact_inverse! -> NMatrix @@ -122,14 +121,14 @@ def invert # - +DataTypeError+ -> cannot invert an integer matrix in-place. # - +NotImplementedError+ -> cannot find exact inverse of matrix with size greater than 3 # def exact_inverse! - raise(ShapeError, "Cannot invert non-square matrix") unless self.dim == 2 && self.shape[0] == self.shape[1] - raise(DataTypeError, "Cannot invert an integer matrix in-place") if self.integer_dtype? - #No internal implementation of getri, so use this other function - n = self.shape[0] - if n>3 + raise(ShapeError, "Cannot invert non-square matrix") unless dim == 2 && shape[0] == shape[1] + raise(DataTypeError, "Cannot invert an integer matrix in-place") if integer_dtype? + # No internal implementation of getri, so use this other function + n = shape[0] + if n > 3 raise(NotImplementedError, "Cannot find exact inverse of matrix of size greater than 3") else - clond=self.clone + clond = clone __inverse_exact__(clond, n, n) end end @@ -151,19 +150,17 @@ def exact_inverse! # - +NotImplementedError+ -> cannot find exact inverse of matrix with size greater than 3 # def exact_inverse - #write this in terms of exact_inverse! so plugins will only have to overwrite - #exact_inverse! and not exact_inverse - if self.integer_dtype? - cloned = self.cast(dtype: :float64) + # write this in terms of exact_inverse! so plugins will only have to overwrite + # exact_inverse! and not exact_inverse + if integer_dtype? + cloned = cast(dtype: :float64) cloned.exact_inverse! else - cloned = self.clone + cloned = clone cloned.exact_inverse! end end - alias :invert_exactly :exact_inverse - - + alias invert_exactly exact_inverse # # call-seq: @@ -202,13 +199,13 @@ def exact_inverse def pinv(tolerance = 1e-15) raise DataTypeError, "pinv works only with matrices of float or complex data type" unless [:float32, :float64, :complex64, :complex128].include?(dtype) - if self.complex_dtype? - u, s, vt = self.complex_conjugate.gesvd # singular value decomposition + if complex_dtype? + u, s, vt = complex_conjugate.gesvd # singular value decomposition else - u, s, vt = self.gesvd + u, s, vt = gesvd end - rows = self.shape[0] - cols = self.shape[1] + rows = shape[0] + cols = shape[1] if rows < cols u_reduced = u vt_reduced = vt[0..rows - 1, 0..cols - 1].transpose @@ -225,9 +222,8 @@ def pinv(tolerance = 1e-15) multiplier = u_reduced.dot(NMatrix.diagonal(s.to_a)).transpose vt_reduced.dot(multiplier) end - alias :pseudo_inverse :pinv - alias :pseudoinverse :pinv - + alias pseudo_inverse pinv + alias pseudoinverse pinv # # call-seq: @@ -242,15 +238,15 @@ def pinv(tolerance = 1e-15) # - +DataTypeError+ -> cannot calculate adjugate of an integer matrix in-place. # def adjugate! - raise(StorageTypeError, "adjugate only works on dense matrices currently") unless self.dense? - raise(ShapeError, "Cannot calculate adjugate of a non-square matrix") unless self.dim == 2 && self.shape[0] == self.shape[1] - raise(DataTypeError, "Cannot calculate adjugate of an integer matrix in-place") if self.integer_dtype? - d = self.det - self.invert! - self.map! { |e| e * d } + raise(StorageTypeError, "adjugate only works on dense matrices currently") unless dense? + raise(ShapeError, "Cannot calculate adjugate of a non-square matrix") unless dim == 2 && shape[0] == shape[1] + raise(DataTypeError, "Cannot calculate adjugate of an integer matrix in-place") if integer_dtype? + d = det + invert! + map! { |e| e * d } self end - alias :adjoint! :adjugate! + alias adjoint! adjugate! # # call-seq: @@ -269,14 +265,14 @@ def adjugate! # - +ShapeError+ -> matrix must be square. # def adjugate - raise(StorageTypeError, "adjugate only works on dense matrices currently") unless self.dense? - raise(ShapeError, "Cannot calculate adjugate of a non-square matrix") unless self.dim == 2 && self.shape[0] == self.shape[1] - d = self.det - mat = self.invert + raise(StorageTypeError, "adjugate only works on dense matrices currently") unless dense? + raise(ShapeError, "Cannot calculate adjugate of a non-square matrix") unless dim == 2 && shape[0] == shape[1] + d = det + mat = invert mat.map! { |e| e * d } mat end - alias :adjoint :adjugate + alias adjoint adjugate # Reduce self to upper hessenberg form using householder transforms. # @@ -296,13 +292,12 @@ def hessenberg! shape[0] != shape[1] raise StorageTypeError, "Matrix must be dense" if stype != :dense raise TypeError, "Works with float matrices only" unless - [:float64,:float32].include?(dtype) + [:float64, :float32].include?(dtype) __hessenberg__(self) self end - # call-seq: # matrix_norm -> Numeric # @@ -325,18 +320,18 @@ def hessenberg! # - +ArgumentError+ -> unrecognized norm # def matrix_norm type = 2 - raise(NotImplementedError, "norm can be calculated only for 2D matrices") unless self.dim == 2 - raise(NotImplementedError, "norm only implemented for dense storage") unless self.stype == :dense - raise(ArgumentError, "norm not defined for byte dtype")if self.dtype == :byte + raise(NotImplementedError, "norm can be calculated only for 2D matrices") unless dim == 2 + raise(NotImplementedError, "norm only implemented for dense storage") unless stype == :dense + raise(ArgumentError, "norm not defined for byte dtype") if dtype == :byte case type when nil, 2, -2 - return self.two_matrix_norm (type == -2) + return two_matrix_norm (type == -2) when 1, -1 - return self.one_matrix_norm (type == -1) + return one_matrix_norm (type == -1) when :frobenius, :fro - return self.fro_matrix_norm + return fro_matrix_norm when :infinity, :inf, :'-inf', :'-infinity' - return self.inf_matrix_norm (type == :'-inf' || type == :'-infinity') + return inf_matrix_norm (type == :'-inf' || type == :'-infinity') else raise ArgumentError.new("argument must be a valid integer or symbol") end @@ -352,14 +347,14 @@ def matrix_norm type = 2 # == References # # * http://stattrek.com/matrix-algebra/covariance-matrix.aspx - def cov(opts={}) + def cov(opts = {}) raise TypeError, "Only works for non-integer dtypes" if integer_dtype? - opts = { - for_sample_data: true + opts = { + for_sample_data: true, }.merge(opts) denominator = opts[:for_sample_data] ? rows - 1 : rows - ones = NMatrix.ones [rows,1] + ones = NMatrix.ones [rows, 1] deviation_scores = self - ones.dot(ones.transpose).dot(self) / rows deviation_scores.transpose.dot(deviation_scores) / denominator end @@ -368,7 +363,7 @@ def cov(opts={}) def corr raise NotImplementedError, "Does not work for complex dtypes" if complex_dtype? standard_deviation = std - cov / (standard_deviation.transpose.dot(standard_deviation)) + cov / standard_deviation.transpose.dot(standard_deviation) end # Raise a square matrix to a power. Be careful of numeric overflows! @@ -386,10 +381,10 @@ def corr # http://www.amazon.com/Solve-Computer-Prentice-Hall-International-Science/dp/0134340019/ref=sr_1_1?ie=UTF8&qid=1422605572&sr=8-1&keywords=how+to+solve+it+by+computer def pow n raise ShapeError, "Only works with 2D square matrices." if - shape[0] != shape[1] or shape.size != 2 + (shape[0] != shape[1]) || (shape.size != 2) raise TypeError, "Only works with integer powers" unless n.is_a?(Integer) - sequence = (integer_dtype? ? self.cast(dtype: :int64) : self).clone + sequence = (integer_dtype? ? cast(dtype: :int64) : self).clone product = NMatrix.eye shape[0], dtype: sequence.dtype, stype: sequence.stype if n == 0 @@ -405,7 +400,7 @@ def pow n # Decompose n to reduce the number of multiplications. while n > 0 product = product.dot(sequence) if n % 2 == 1 - n = n / 2 + n /= 2 sequence = sequence.dot(sequence) end @@ -430,30 +425,30 @@ def pow n # [3.0, 3.0, 3.0, 4.0, 4.0, 4.0] ] # def kron_prod(mat) - unless self.dimensions==2 and mat.dimensions==2 + unless (dimensions == 2) && (mat.dimensions == 2) raise ShapeError, "Implemented for 2D NMatrix objects only." end # compute the shape [n,m] of the product matrix - n, m = self.shape[0]*mat.shape[0], self.shape[1]*mat.shape[1] + n, m = shape[0] * mat.shape[0], shape[1] * mat.shape[1] # compute the entries of the product matrix kron_prod_array = [] - if self.yale? + if yale? # +:yale+ requires to get the row by copy in order to apply +#transpose+ to it - self.each_row(getby=:copy) do |selfr| + each_row(getby = :copy) do |selfr| mat.each_row do |matr| kron_prod_array += (selfr.transpose.dot matr).to_flat_a end end else - self.each_row do |selfr| + each_row do |selfr| mat.each_row do |matr| kron_prod_array += (selfr.transpose.dot matr).to_flat_a end end end - NMatrix.new([n,m], kron_prod_array) + NMatrix.new([n, m], kron_prod_array) end # @@ -469,10 +464,10 @@ def kron_prod(mat) # - The trace of the matrix (a numeric value) # def trace - raise(ShapeError, "Expected square matrix") unless self.shape[0] == self.shape[1] && self.dim == 2 + raise(ShapeError, "Expected square matrix") unless shape[0] == shape[1] && dim == 2 - (0...self.shape[0]).inject(0) do |total,i| - total + self[i,i] + (0...shape[0]).inject(0) do |total, i| + total + self[i, i] end end @@ -487,14 +482,14 @@ def trace # # @see #inject_rank # - def mean(dimen=0) + def mean(dimen = 0) reduce_dtype = nil - if integer_dtype? then + if integer_dtype? reduce_dtype = :float64 end - inject_rank(dimen, 0.0, reduce_dtype) do |mean, sub_mat| + inject_rank(dimen, 0.0, reduce_dtype) { |mean, sub_mat| mean + sub_mat - end / shape[dimen] + } / shape[dimen] end ## @@ -507,12 +502,12 @@ def mean(dimen=0) # Calculates the sum along the specified dimension. # # @see #inject_rank - def sum(dimen=0) + def sum(dimen = 0) inject_rank(dimen, 0.0) do |sum, sub_mat| sum + sub_mat end end - alias :cumsum :sum + alias cumsum sum ## # call-seq: @@ -523,10 +518,10 @@ def sum(dimen=0) # # @see #inject_rank # - def min(dimen=0) + def min(dimen = 0) inject_rank(dimen) do |min, sub_mat| - if min.is_a? NMatrix then - min * (min <= sub_mat).cast(self.stype, self.dtype) + ((min)*0.0 + (min > sub_mat).cast(self.stype, self.dtype)) * sub_mat + if min.is_a? NMatrix + min * (min <= sub_mat).cast(stype, dtype) + (min * 0.0 + (min > sub_mat).cast(stype, dtype)) * sub_mat else min <= sub_mat ? min : sub_mat end @@ -542,17 +537,16 @@ def min(dimen=0) # # @see #inject_rank # - def max(dimen=0) + def max(dimen = 0) inject_rank(dimen) do |max, sub_mat| - if max.is_a? NMatrix then - max * (max >= sub_mat).cast(self.stype, self.dtype) + ((max)*0.0 + (max < sub_mat).cast(self.stype, self.dtype)) * sub_mat + if max.is_a? NMatrix + max * (max >= sub_mat).cast(stype, dtype) + (max * 0.0 + (max < sub_mat).cast(stype, dtype)) * sub_mat else max >= sub_mat ? max : sub_mat end end end - ## # call-seq: # variance() -> NMatrix @@ -564,14 +558,14 @@ def max(dimen=0) # # @see #inject_rank # - def variance(dimen=0) + def variance(dimen = 0) reduce_dtype = nil - if integer_dtype? then + if integer_dtype? reduce_dtype = :float64 end m = mean(dimen) inject_rank(dimen, 0.0, reduce_dtype) do |var, sub_mat| - var + (m - sub_mat)*(m - sub_mat)/(shape[dimen]-1) + var + (m - sub_mat) * (m - sub_mat) / (shape[dimen] - 1) end end @@ -587,11 +581,10 @@ def variance(dimen=0) # # @see #inject_rank # - def std(dimen=0) + def std(dimen = 0) variance(dimen).sqrt end - # # call-seq: # abs_dtype -> Symbol @@ -599,16 +592,15 @@ def std(dimen=0) # Returns the dtype of the result of a call to #abs. In most cases, this is the same as dtype; it should only differ # for :complex64 (where it's :float32) and :complex128 (:float64). def abs_dtype - if self.dtype == :complex64 + if dtype == :complex64 :float32 - elsif self.dtype == :complex128 + elsif dtype == :complex128 :float64 else - self.dtype + dtype end end - # # call-seq: # abs -> NMatrix @@ -616,62 +608,61 @@ def abs_dtype # Maps all values in a matrix to their absolute values. def abs if stype == :dense - self.__dense_map__ { |v| v.abs } + __dense_map__ { |v| v.abs } elsif stype == :list # FIXME: Need __list_map_stored__, but this will do for now. - self.__list_map_merged_stored__(nil, nil) { |v,dummy| v.abs } + __list_map_merged_stored__(nil, nil) { |v, dummy| v.abs } else - self.__yale_map_stored__ { |v| v.abs } - end.cast(self.stype, abs_dtype) + __yale_map_stored__ { |v| v.abs } + end.cast(stype, abs_dtype) end # Norm calculation methods # Frobenius norm: the Euclidean norm of the matrix, treated as if it were a vector def fro_matrix_norm - #float64 has to be used in any case, since nrm2 will not yield correct result for float32 - self_cast = self.cast(:dtype => :float64) + # float64 has to be used in any case, since nrm2 will not yield correct result for float32 + self_cast = cast(dtype: :float64) - column_vector = self_cast.reshape([self.size, 1]) + column_vector = self_cast.reshape([size, 1]) - return column_vector.nrm2 + column_vector.nrm2 end # 2-norm: the largest/smallest singular value of the matrix def two_matrix_norm minus = false + self_cast = cast(dtype: :float64) - self_cast = self.cast(:dtype => :float64) - - #TODO: confirm if this is the desired svd calculation + # TODO: confirm if this is the desired svd calculation svd = self_cast.gesvd return svd[1][0, 0] unless minus - return svd[1][svd[1].rows-1, svd[1].cols-1] + svd[1][svd[1].rows - 1, svd[1].cols - 1] end # 1-norm: the maximum/minimum absolute column sum of the matrix def one_matrix_norm minus = false - #TODO: change traversing method for sparse matrices - number_of_columns = self.cols + # TODO: change traversing method for sparse matrices + number_of_columns = cols col_sums = [] number_of_columns.times do |i| - col_sums << self.col(i).inject(0) { |sum, number| sum += number.abs} + col_sums << col(i).inject(0) { |sum, number| sum += number.abs} end return col_sums.max unless minus - return col_sums.min + col_sums.min end # Infinity norm: the maximum/minimum absolute row sum of the matrix def inf_matrix_norm minus = false - number_of_rows = self.rows + number_of_rows = rows row_sums = [] number_of_rows.times do |i| - row_sums << self.row(i).inject(0) { |sum, number| sum += number.abs} + row_sums << row(i).inject(0) { |sum, number| sum += number.abs} end return row_sums.max unless minus - return row_sums.min + row_sums.min end # @@ -687,9 +678,9 @@ def inf_matrix_norm minus = false # def positive_definite? raise(ShapeError, "positive definite calculated only for square matrices") unless - self.dim == 2 && self.shape[0] == self.shape[1] + dim == 2 && shape[0] == shape[1] cond = 0 - while cond != self.cols + while cond != cols if self[0..cond, 0..cond].det <= 0 return false end @@ -705,132 +696,131 @@ def positive_definite? # Gives rank of the matrix based on the singular value decomposition. # The rank of a matrix is computed as the number of diagonal elements in Sigma that are larger than a tolerance # - #* *Returns* : + # * *Returns* : # - An integer equal to the rank of the matrix - #* *Raises* : + # * *Raises* : # - +ShapeError+ -> Is only computable on 2-D matrices # - def svd_rank(tolerence="default") + def svd_rank(tolerence = "default") raise(ShapeError, "rank calculated only for 2-D matrices") unless - self.dim == 2 + dim == 2 - sigmas = self.gesvd[1].to_a.flatten + sigmas = gesvd[1].to_a.flatten eps = NMatrix::FLOAT64_EPSILON # epsilon depends on the width of the number - if (self.dtype == :float32 || self.dtype == :complex64) + if dtype == :float32 || dtype == :complex64 eps = NMatrix::FLOAT32_EPSILON end case tolerence when "default" - tolerence = self.shape.max * sigmas.max * eps # tolerence of a Matrix A is max(size(A))*eps(norm(A)). norm(A) is nearly equal to max(sigma of A) + tolerence = shape.max * sigmas.max * eps # tolerence of a Matrix A is max(size(A))*eps(norm(A)). norm(A) is nearly equal to max(sigma of A) end - return sigmas.map { |x| x > tolerence ? 1 : 0 }.reduce(:+) + sigmas.map { |x| x > tolerence ? 1 : 0 }.reduce(:+) end + protected - -protected # Define the element-wise operations for lists. Note that the __list_map_merged_stored__ iterator returns a Ruby Object # matrix, which we then cast back to the appropriate type. If you don't want that, you can redefine these functions in # your own code. {add: :+, sub: :-, mul: :*, div: :/, pow: :**, mod: :%}.each_pair do |ewop, op| define_method("__list_elementwise_#{ewop}__") do |rhs| - self.__list_map_merged_stored__(rhs, nil) { |l,r| l.send(op,r) }.cast(stype, NMatrix.upcast(dtype, rhs.dtype)) + __list_map_merged_stored__(rhs, nil) { |l, r| l.send(op, r) }.cast(stype, NMatrix.upcast(dtype, rhs.dtype)) end define_method("__dense_elementwise_#{ewop}__") do |rhs| - self.__dense_map_pair__(rhs) { |l,r| l.send(op,r) }.cast(stype, NMatrix.upcast(dtype, rhs.dtype)) + __dense_map_pair__(rhs) { |l, r| l.send(op, r) }.cast(stype, NMatrix.upcast(dtype, rhs.dtype)) end define_method("__yale_elementwise_#{ewop}__") do |rhs| - self.__yale_map_merged_stored__(rhs, nil) { |l,r| l.send(op,r) }.cast(stype, NMatrix.upcast(dtype, rhs.dtype)) + __yale_map_merged_stored__(rhs, nil) { |l, r| l.send(op, r) }.cast(stype, NMatrix.upcast(dtype, rhs.dtype)) end define_method("__list_scalar_#{ewop}__") do |rhs| - self.__list_map_merged_stored__(rhs, nil) { |l,r| l.send(op,r) }.cast(stype, NMatrix.upcast(dtype, NMatrix.min_dtype(rhs))) + __list_map_merged_stored__(rhs, nil) { |l, r| l.send(op, r) }.cast(stype, NMatrix.upcast(dtype, NMatrix.min_dtype(rhs))) end define_method("__yale_scalar_#{ewop}__") do |rhs| - self.__yale_map_stored__ { |l| l.send(op,rhs) }.cast(stype, NMatrix.upcast(dtype, NMatrix.min_dtype(rhs))) + __yale_map_stored__ { |l| l.send(op, rhs) }.cast(stype, NMatrix.upcast(dtype, NMatrix.min_dtype(rhs))) end define_method("__dense_scalar_#{ewop}__") do |rhs| - self.__dense_map__ { |l| l.send(op,rhs) }.cast(stype, NMatrix.upcast(dtype, NMatrix.min_dtype(rhs))) + __dense_map__ { |l| l.send(op, rhs) }.cast(stype, NMatrix.upcast(dtype, NMatrix.min_dtype(rhs))) end end # These don't actually take an argument -- they're called reverse-polish style on the matrix. # This group always gets casted to float64. [:log, :log2, :log10, :sqrt, :sin, :cos, :tan, :acos, :asin, :atan, :cosh, :sinh, :tanh, :acosh, - :asinh, :atanh, :exp, :erf, :erfc, :gamma, :cbrt, :round].each do |ewop| + :asinh, :atanh, :exp, :erf, :erfc, :gamma, :cbrt, :round,].each do |ewop| define_method("__list_unary_#{ewop}__") do - self.__list_map_stored__(nil) { |l| Math.send(ewop, l) }.cast(stype, NMatrix.upcast(dtype, :float64)) + __list_map_stored__(nil) { |l| Math.send(ewop, l) }.cast(stype, NMatrix.upcast(dtype, :float64)) end define_method("__yale_unary_#{ewop}__") do - self.__yale_map_stored__ { |l| Math.send(ewop, l) }.cast(stype, NMatrix.upcast(dtype, :float64)) + __yale_map_stored__ { |l| Math.send(ewop, l) }.cast(stype, NMatrix.upcast(dtype, :float64)) end define_method("__dense_unary_#{ewop}__") do - self.__dense_map__ { |l| Math.send(ewop, l) }.cast(stype, NMatrix.upcast(dtype, :float64)) + __dense_map__ { |l| Math.send(ewop, l) }.cast(stype, NMatrix.upcast(dtype, :float64)) end end #:stopdoc: # log takes an optional single argument, the base. Default to natural log. def __list_unary_log__(base) - self.__list_map_stored__(nil) { |l| Math.log(l, base) }.cast(stype, NMatrix.upcast(dtype, :float64)) + __list_map_stored__(nil) { |l| Math.log(l, base) }.cast(stype, NMatrix.upcast(dtype, :float64)) end def __yale_unary_log__(base) - self.__yale_map_stored__ { |l| Math.log(l, base) }.cast(stype, NMatrix.upcast(dtype, :float64)) + __yale_map_stored__ { |l| Math.log(l, base) }.cast(stype, NMatrix.upcast(dtype, :float64)) end def __dense_unary_log__(base) - self.__dense_map__ { |l| Math.log(l, base) }.cast(stype, NMatrix.upcast(dtype, :float64)) + __dense_map__ { |l| Math.log(l, base) }.cast(stype, NMatrix.upcast(dtype, :float64)) end # These are for negating matrix contents using -@ def __list_unary_negate__ - self.__list_map_stored__(nil) { |l| -l }.cast(stype, dtype) + __list_map_stored__(nil) { |l| -l }.cast(stype, dtype) end def __yale_unary_negate__ - self.__yale_map_stored__ { |l| -l }.cast(stype, dtype) + __yale_map_stored__ { |l| -l }.cast(stype, dtype) end def __dense_unary_negate__ - self.__dense_map__ { |l| -l }.cast(stype, dtype) + __dense_map__ { |l| -l }.cast(stype, dtype) end #:startdoc: # These are for rounding each value of a matrix. Takes an optional argument def __list_unary_round__(precision) - if self.complex_dtype? - self.__list_map_stored__(nil) { |l| Complex(l.real.round(precision), l.imag.round(precision)) } - .cast(stype, dtype) + if complex_dtype? + __list_map_stored__(nil) { |l| Complex(l.real.round(precision), l.imag.round(precision)) } + .cast(stype, dtype) else - self.__list_map_stored__(nil) { |l| l.round(precision) }.cast(stype, dtype) + __list_map_stored__(nil) { |l| l.round(precision) }.cast(stype, dtype) end end def __yale_unary_round__(precision) - if self.complex_dtype? - self.__yale_map_stored__ { |l| Complex(l.real.round(precision), l.imag.round(precision)) } - .cast(stype, dtype) + if complex_dtype? + __yale_map_stored__ { |l| Complex(l.real.round(precision), l.imag.round(precision)) } + .cast(stype, dtype) else - self.__yale_map_stored__ { |l| l.round(precision) }.cast(stype, dtype) + __yale_map_stored__ { |l| l.round(precision) }.cast(stype, dtype) end end def __dense_unary_round__(precision) - if self.complex_dtype? - self.__dense_map__ { |l| Complex(l.real.round(precision), l.imag.round(precision)) } - .cast(stype, dtype) + if complex_dtype? + __dense_map__ { |l| Complex(l.real.round(precision), l.imag.round(precision)) } + .cast(stype, dtype) else - self.__dense_map__ { |l| l.round(precision) }.cast(stype, dtype) + __dense_map__ { |l| l.round(precision) }.cast(stype, dtype) end end # These are for calculating the floor or ceil of matrix def dtype_for_floor_or_ceil - if self.integer_dtype? or [:complex64, :complex128, :object].include?(self.dtype) + if integer_dtype? || [:complex64, :complex128, :object].include?(dtype) return_dtype = dtype - elsif [:float32, :float64].include?(self.dtype) + elsif [:float32, :float64].include?(dtype) return_dtype = :int64 end @@ -841,30 +831,30 @@ def dtype_for_floor_or_ceil define_method("__list_unary_#{meth}__") do return_dtype = dtype_for_floor_or_ceil - if [:complex64, :complex128].include?(self.dtype) - self.__list_map_stored__(nil) { |l| Complex(l.real.send(meth), l.imag.send(meth)) }.cast(stype, return_dtype) + if [:complex64, :complex128].include?(dtype) + __list_map_stored__(nil) { |l| Complex(l.real.send(meth), l.imag.send(meth)) }.cast(stype, return_dtype) else - self.__list_map_stored__(nil) { |l| l.send(meth) }.cast(stype, return_dtype) + __list_map_stored__(nil) { |l| l.send(meth) }.cast(stype, return_dtype) end end define_method("__yale_unary_#{meth}__") do return_dtype = dtype_for_floor_or_ceil - if [:complex64, :complex128].include?(self.dtype) - self.__yale_map_stored__ { |l| Complex(l.real.send(meth), l.imag.send(meth)) }.cast(stype, return_dtype) + if [:complex64, :complex128].include?(dtype) + __yale_map_stored__ { |l| Complex(l.real.send(meth), l.imag.send(meth)) }.cast(stype, return_dtype) else - self.__yale_map_stored__ { |l| l.send(meth) }.cast(stype, return_dtype) + __yale_map_stored__ { |l| l.send(meth) }.cast(stype, return_dtype) end end define_method("__dense_unary_#{meth}__") do return_dtype = dtype_for_floor_or_ceil - if [:complex64, :complex128].include?(self.dtype) - self.__dense_map__ { |l| Complex(l.real.send(meth), l.imag.send(meth)) }.cast(stype, return_dtype) + if [:complex64, :complex128].include?(dtype) + __dense_map__ { |l| Complex(l.real.send(meth), l.imag.send(meth)) }.cast(stype, return_dtype) else - self.__dense_map__ { |l| l.send(meth) }.cast(stype, return_dtype) + __dense_map__ { |l| l.send(meth) }.cast(stype, return_dtype) end end end @@ -873,51 +863,51 @@ def dtype_for_floor_or_ceil # See also monkeys.rb, which contains Math module patches to let the first # arg be a scalar [:atan2, :ldexp, :hypot].each do |ewop| - define_method("__list_elementwise_#{ewop}__") do |rhs,order| - if order then - self.__list_map_merged_stored__(rhs, nil) { |r,l| Math.send(ewop,l,r) } + define_method("__list_elementwise_#{ewop}__") do |rhs, order| + if order + __list_map_merged_stored__(rhs, nil) { |r, l| Math.send(ewop, l, r) } else - self.__list_map_merged_stored__(rhs, nil) { |l,r| Math.send(ewop,l,r) } + __list_map_merged_stored__(rhs, nil) { |l, r| Math.send(ewop, l, r) } end.cast(stype, NMatrix.upcast(dtype, :float64)) end define_method("__dense_elementwise_#{ewop}__") do |rhs, order| - if order then - self.__dense_map_pair__(rhs) { |r,l| Math.send(ewop,l,r) } + if order + __dense_map_pair__(rhs) { |r, l| Math.send(ewop, l, r) } else - self.__dense_map_pair__(rhs) { |l,r| Math.send(ewop,l,r) } + __dense_map_pair__(rhs) { |l, r| Math.send(ewop, l, r) } end.cast(stype, NMatrix.upcast(dtype, :float64)) end define_method("__yale_elementwise_#{ewop}__") do |rhs, order| - if order then - self.__yale_map_merged_stored__(rhs, nil) { |r,l| Math.send(ewop,l,r) } + if order + __yale_map_merged_stored__(rhs, nil) { |r, l| Math.send(ewop, l, r) } else - self.__yale_map_merged_stored__(rhs, nil) { |l,r| Math.send(ewop,l,r) } + __yale_map_merged_stored__(rhs, nil) { |l, r| Math.send(ewop, l, r) } end.cast(stype, NMatrix.upcast(dtype, :float64)) end - define_method("__list_scalar_#{ewop}__") do |rhs,order| - if order then - self.__list_map_stored__(nil) { |l| Math.send(ewop, rhs, l) } + define_method("__list_scalar_#{ewop}__") do |rhs, order| + if order + __list_map_stored__(nil) { |l| Math.send(ewop, rhs, l) } else - self.__list_map_stored__(nil) { |l| Math.send(ewop, l, rhs) } + __list_map_stored__(nil) { |l| Math.send(ewop, l, rhs) } end.cast(stype, NMatrix.upcast(dtype, :float64)) end - define_method("__yale_scalar_#{ewop}__") do |rhs,order| - if order then - self.__yale_map_stored__ { |l| Math.send(ewop, rhs, l) } + define_method("__yale_scalar_#{ewop}__") do |rhs, order| + if order + __yale_map_stored__ { |l| Math.send(ewop, rhs, l) } else - self.__yale_map_stored__ { |l| Math.send(ewop, l, rhs) } + __yale_map_stored__ { |l| Math.send(ewop, l, rhs) } end.cast(stype, NMatrix.upcast(dtype, :float64)) end - define_method("__dense_scalar_#{ewop}__") do |rhs,order| + define_method("__dense_scalar_#{ewop}__") do |rhs, order| if order - self.__dense_map__ { |l| Math.send(ewop, rhs, l) } + __dense_map__ { |l| Math.send(ewop, rhs, l) } else - self.__dense_map__ { |l| Math.send(ewop, l, rhs) } + __dense_map__ { |l| Math.send(ewop, l, rhs) } end.cast(stype, NMatrix.upcast(dtype, :float64)) end end @@ -925,23 +915,23 @@ def dtype_for_floor_or_ceil # Equality operators do not involve a cast. We want to get back matrices of TrueClass and FalseClass. {eqeq: :==, neq: :!=, lt: :<, gt: :>, leq: :<=, geq: :>=}.each_pair do |ewop, op| define_method("__list_elementwise_#{ewop}__") do |rhs| - self.__list_map_merged_stored__(rhs, nil) { |l,r| l.send(op,r) } + __list_map_merged_stored__(rhs, nil) { |l, r| l.send(op, r) } end define_method("__dense_elementwise_#{ewop}__") do |rhs| - self.__dense_map_pair__(rhs) { |l,r| l.send(op,r) } + __dense_map_pair__(rhs) { |l, r| l.send(op, r) } end define_method("__yale_elementwise_#{ewop}__") do |rhs| - self.__yale_map_merged_stored__(rhs, nil) { |l,r| l.send(op,r) } + __yale_map_merged_stored__(rhs, nil) { |l, r| l.send(op, r) } end define_method("__list_scalar_#{ewop}__") do |rhs| - self.__list_map_merged_stored__(rhs, nil) { |l,r| l.send(op,r) } + __list_map_merged_stored__(rhs, nil) { |l, r| l.send(op, r) } end define_method("__yale_scalar_#{ewop}__") do |rhs| - self.__yale_map_stored__ { |l| l.send(op,rhs) } + __yale_map_stored__ { |l| l.send(op, rhs) } end define_method("__dense_scalar_#{ewop}__") do |rhs| - self.__dense_map__ { |l| l.send(op,rhs) } + __dense_map__ { |l| l.send(op, rhs) } end end end diff --git a/lib/nmatrix/mkmf.rb b/lib/nmatrix/mkmf.rb index 8c5d0526..ee2dfdb8 100644 --- a/lib/nmatrix/mkmf.rb +++ b/lib/nmatrix/mkmf.rb @@ -1,23 +1,23 @@ require "mkmf" -if RUBY_VERSION < '1.9' +if RUBY_VERSION < "1.9" raise NotImplementedError, "Sorry, you need at least Ruby 1.9!" end # Function derived from NArray's extconf.rb. def create_conf_h(file) #:nodoc: print "creating #{file}\n" - File.open(file, 'w') do |hfile| - header_guard = file.upcase.sub(/\s|\./, '_') + File.open(file, "w") do |hfile| + header_guard = file.upcase.sub(/\s|\./, "_") hfile.puts "#ifndef #{header_guard}" hfile.puts "#define #{header_guard}" hfile.puts # FIXME: Find a better way to do this: - hfile.puts "#define RUBY_2 1" if RUBY_VERSION >= '2.0' + hfile.puts "#define RUBY_2 1" if RUBY_VERSION >= "2.0" - for line in $defs + $defs.each do |line| line =~ /^-D(.*)/ hfile.printf "#define %s 1\n", $1 end @@ -29,72 +29,71 @@ def create_conf_h(file) #:nodoc: def find_newer_gplusplus #:nodoc: print "checking for apparent GNU g++ binary with C++0x/C++11 support... " - [9,8,7,6,5,4,3].each do |minor| + [9, 8, 7, 6, 5, 4, 3].each do |minor| ver = "4.#{minor}" gpp = "g++-#{ver}" result = `which #{gpp}` next if result.empty? - CONFIG['CXX'] = gpp + CONFIG["CXX"] = gpp puts ver - return CONFIG['CXX'] + return CONFIG["CXX"] end false end def gplusplus_version - cxxvar = proc { |n| `#{CONFIG['CXX']} -E -dM - <#{File::NULL} | grep #{n}`.chomp.split(' ')[2] } - major = cxxvar.call('__GNUC__') - minor = cxxvar.call('__GNUC_MINOR__') - patch = cxxvar.call('__GNUC_PATCHLEVEL__') + cxxvar = proc { |n| `#{CONFIG["CXX"]} -E -dM - <#{File::NULL} | grep #{n}`.chomp.split(" ")[2] } + major = cxxvar.call("__GNUC__") + minor = cxxvar.call("__GNUC_MINOR__") + patch = cxxvar.call("__GNUC_PATCHLEVEL__") raise("unable to determine g++ version (match to get version was nil)") if major.nil? || minor.nil? || patch.nil? "#{major}.#{minor}.#{patch}" end - -if /cygwin|mingw/ =~ RUBY_PLATFORM +if /cygwin|mingw/.match?(RUBY_PLATFORM) CONFIG["DLDFLAGS"] << " --output-lib libnmatrix.a" end # Fix compiler pairing -if CONFIG['CC'] == 'clang' && CONFIG['CXX'] != 'clang++' +if CONFIG["CC"] == "clang" && CONFIG["CXX"] != "clang++" puts "WARNING: CONFIG['CXX'] is not 'clang++' even though CONFIG['CC'] is 'clang'.", - "WARNING: Force to use clang++ together with clang." + "WARNING: Force to use clang++ together with clang." - CONFIG['CXX'] = 'clang++' + CONFIG["CXX"] = "clang++" end -if CONFIG['CXX'] == 'clang++' - $CXX_STANDARD = 'c++11' +if CONFIG["CXX"] == "clang++" + $CXX_STANDARD = "c++11" else version = gplusplus_version - if version < '4.3.0' && CONFIG['CXX'] == 'g++' # see if we can find a newer G++, unless it's been overridden by user - if !find_newer_gplusplus + if version < "4.3.0" && CONFIG["CXX"] == "g++" # see if we can find a newer G++, unless it's been overridden by user + unless find_newer_gplusplus raise("You need a version of g++ which supports -std=c++0x or -std=c++11. If you're on a Mac and using Homebrew, we recommend using mac-brew-gcc.sh to install a more recent g++.") end version = gplusplus_version end - if version < '4.7.0' - $CXX_STANDARD = 'c++0x' + $CXX_STANDARD = if version < "4.7.0" + "c++0x" else - $CXX_STANDARD = 'c++11' + "c++11" end puts "using C++ standard... #{$CXX_STANDARD}" - puts "g++ reports version... " + `#{CONFIG['CXX']} --version|head -n 1|cut -f 3 -d " "` + puts "g++ reports version... " + `#{CONFIG["CXX"]} --version|head -n 1|cut -f 3 -d " "` end # For release, these next two should both be changed to -O3. $CFLAGS += " -O3 " -#$CFLAGS += " -static -O0 -g " +# $CFLAGS += " -static -O0 -g " $CXXFLAGS += " -O3 -std=#{$CXX_STANDARD} " #-fmax-errors=10 -save-temps -#$CXXFLAGS += " -static -O0 -g -std=#{$CXX_STANDARD} " +# $CXXFLAGS += " -static -O0 -g -std=#{$CXX_STANDARD} " -if CONFIG.has_key?('warnflags') - CONFIG['warnflags'].gsub!('-Wshorten-64-to-32', '') # doesn't work except in Mac-patched gcc (4.2) - CONFIG['warnflags'].gsub!('-Wdeclaration-after-statement', '') - CONFIG['warnflags'].gsub!('-Wimplicit-function-declaration', '') +if CONFIG.key?("warnflags") + CONFIG["warnflags"].gsub!("-Wshorten-64-to-32", "") # doesn't work except in Mac-patched gcc (4.2) + CONFIG["warnflags"].gsub!("-Wdeclaration-after-statement", "") + CONFIG["warnflags"].gsub!("-Wimplicit-function-declaration", "") end - + have_func("rb_array_const_ptr", "ruby.h") diff --git a/lib/nmatrix/monkeys.rb b/lib/nmatrix/monkeys.rb index ceaa516c..81e15724 100644 --- a/lib/nmatrix/monkeys.rb +++ b/lib/nmatrix/monkeys.rb @@ -42,7 +42,7 @@ class Array # instead of :float64) -- optional. # stype :: Optional storage type (defaults to :dense) def to_nm(shape = nil, dtype = nil, stype = :dense) - elements = self.dup + elements = dup guess_dtype = ->(type) { case type @@ -58,8 +58,6 @@ def to_nm(shape = nil, dtype = nil, stype = :dense) shape << shapey.map {|s| if s.respond_to?(:size) && s.respond_to?(:map) guess_shape.call(s) - else - nil end } if shape.last.any? {|s| (s != shape.last.first) || s.nil?} @@ -85,7 +83,7 @@ def to_nm(shape = nil, dtype = nil, stype = :dense) matrix = NMatrix.new(:dense, shape, elements, dtype) - if stype != :dense then matrix.cast(stype, dtype) else matrix end + stype != :dense ? matrix.cast(stype, dtype) : matrix end end @@ -96,17 +94,16 @@ def returning(value) end end - module Math #:nodoc: class << self NMatrix::NMMath::METHODS_ARITY_2.each do |meth| define_method "nm_#{meth}" do |arg0, arg1| - if arg0.is_a? NMatrix then + if arg0.is_a? NMatrix arg0.send(meth, arg1) - elsif arg1.is_a? NMatrix then + elsif arg1.is_a? NMatrix arg1.send(meth, arg0, true) else - self.send("old_#{meth}".to_sym, arg0, arg1) + send("old_#{meth}".to_sym, arg0, arg1) end end alias_method "old_#{meth}".to_sym, meth @@ -117,17 +114,17 @@ class << self class String def underscore - self.gsub(/::/, '/'). - gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). - gsub(/([a-z\d])([A-Z])/,'\1_\2'). - tr("-", "_"). - downcase + gsub(/::/, "/") + .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') + .gsub(/([a-z\d])([A-Z])/, '\1_\2') + .tr("-", "_") + .downcase end end # Since `autoload` will most likely be deprecated (due to multi-threading concerns), # we'll use `const_missing`. See: https://www.ruby-forum.com/topic/3036681 for more info. -module AutoloadPatch #:nodoc +module AutoloadPatch # :nodoc: def const_missing(name) file = name.to_s.underscore require "nmatrix/io/#{file}" diff --git a/lib/nmatrix/nmatrix.rb b/lib/nmatrix/nmatrix.rb index 9fb8d1cf..a3d8fe92 100644 --- a/lib/nmatrix/nmatrix.rb +++ b/lib/nmatrix/nmatrix.rb @@ -37,26 +37,26 @@ def jruby? end if jruby? - require_relative 'jruby/nmatrix_java' + require_relative "jruby/nmatrix_java" else - if File.exist?("lib/nmatrix/nmatrix.so") #|| File.exist?("lib/nmatrix/nmatrix.bundle") + if File.exist?("lib/nmatrix/nmatrix.so") # || File.exist?("lib/nmatrix/nmatrix.bundle") # Development require_relative "nmatrix/nmatrix.so" else # Gem require_relative "../nmatrix.so" - require_relative './io/mat_reader' - require_relative './io/mat5_reader' - require_relative './io/market' - require_relative './io/point_cloud' + require_relative "./io/mat_reader" + require_relative "./io/mat5_reader" + require_relative "./io/market" + require_relative "./io/point_cloud" - require_relative './lapack_core.rb' - require_relative './yale_functions.rb' + require_relative "./lapack_core.rb" + require_relative "./yale_functions.rb" end end -require_relative './math.rb' -require_relative './monkeys' +require_relative "./math.rb" +require_relative "./monkeys" # NMatrix is a matrix class that supports both multidimensional arrays # (`:dense` stype) and sparse storage (`:list` or `:yale` stypes) and 13 data @@ -83,7 +83,7 @@ class << self def load_mat(file_path) NMatrix::IO::Matlab::Mat5Reader.new(File.open(file_path, "rb+")).to_ruby end - alias :load :load_mat + alias load load_mat end end end @@ -97,7 +97,7 @@ class << self # * *Returns* : # - A Mat5Reader object. def load_matlab_file(file_path) - NMatrix::IO::Matlab::Mat5Reader.new(File.open(file_path, 'rb')).to_ruby + NMatrix::IO::Matlab::Mat5Reader.new(File.open(file_path, "rb")).to_ruby end # call-seq: @@ -113,8 +113,8 @@ def load_pcd_file(file_path) # Calculate the size of an NMatrix of a given shape. def size(shape) - shape = [shape,shape] unless shape.is_a?(Array) - (0...shape.size).inject(1) { |x,i| x * shape[i] } + shape = [shape, shape] unless shape.is_a?(Array) + (0...shape.size).inject(1) { |x, i| x * shape[i] } end # Make N-D coordinate arrays for vectorized evaluations of @@ -145,27 +145,27 @@ def size(shape) # x.to_a #<= [[1, 1], [2, 2], [3, 3]] # y.to_a #<= [[4, 5], [4, 5], [4, 5]] def meshgrid(vectors, options = {}) - raise(ArgumentError, 'Expected at least 2 arrays.') if vectors.size < 2 + raise(ArgumentError, "Expected at least 2 arrays.") if vectors.size < 2 options[:indexing] ||= :xy - raise(ArgumentError, 'Indexing must be :xy of :ij') unless [:ij, :xy].include? options[:indexing] + raise(ArgumentError, "Indexing must be :xy of :ij") unless [:ij, :xy].include? options[:indexing] mats = vectors.map { |arr| arr.respond_to?(:flatten) ? arr.flatten : arr.to_flat_array } mats[0], mats[1] = mats[1], mats[0] if options[:indexing] == :xy new_dim = mats.size lengths = mats.map(&:size) - result = mats.map.with_index do |matrix, axis| + result = mats.map.with_index { |matrix, axis| if options[:sparse] new_shape = Array.new(new_dim, 1) new_shape[axis] = lengths[axis] new_elements = matrix else before_axis = lengths[0...axis].reduce(:*) - after_axis = lengths[(axis+1)..-1].reduce(:*) + after_axis = lengths[(axis + 1)..-1].reduce(:*) new_shape = lengths - new_elements = after_axis ? matrix.map{ |el| [el] * after_axis }.flatten : matrix + new_elements = after_axis ? matrix.map { |el| [el] * after_axis }.flatten : matrix new_elements *= before_axis if before_axis end NMatrix.new(new_shape, new_elements) - end + } result[0], result[1] = result[1], result[0] if options[:indexing] == :xy result end @@ -173,27 +173,27 @@ def meshgrid(vectors, options = {}) # TODO: Make this actually pretty. def pretty_print(q) #:nodoc: - if self.shape.size > 1 and self.shape[1] > 100 - self.inspect.pretty_print(q) - elsif self.dim > 3 || self.dim == 1 - self.to_a.pretty_print(q) + if (shape.size > 1) && (shape[1] > 100) + inspect.pretty_print(q) + elsif dim > 3 || dim == 1 + to_a.pretty_print(q) else # iterate through the whole matrix and find the longest number - longest = Array.new(self.shape[1], 0) - self.each_column.with_index do |col, j| + longest = Array.new(shape[1], 0) + each_column.with_index do |col, j| col.each do |elem| elem_len = elem.inspect.size longest[j] = elem_len if longest[j] < elem_len end end - if self.dim == 3 + if dim == 3 q.group(0, "\n{ layers:", "}") do - self.each_layer.with_index do |layer,k| + each_layer.with_index do |layer, k| q.group(0, "\n [\n", " ]\n") do - layer.each_row.with_index do |row,i| + layer.each_row.with_index do |row, i| q.group(0, " [", "]\n") do - q.seplist(self[i,0...self.shape[1],k].to_flat_array, lambda { q.text ", "}, :each_with_index) { |v,j| q.text v.inspect.rjust(longest[j]) } + q.seplist(self[i, 0...shape[1], k].to_flat_array, lambda { q.text ", "}, :each_with_index) { |v, j| q.text v.inspect.rjust(longest[j]) } end end end @@ -201,13 +201,13 @@ def pretty_print(q) #:nodoc: end else # dim 2 q.group(0, "\n[\n ", "]") do - self.each_row.with_index do |row, i| + each_row.with_index do |row, i| q.group(1, " [", "]\n") do - q.seplist(row.to_a, -> { q.text ", " }, :each_with_index) do |v,j| + q.seplist(row.to_a, -> { q.text ", " }, :each_with_index) do |v, j| q.text v.inspect.rjust(longest[j]) end end - q.breakable unless i + 1 == self.shape[0] + q.breakable unless i + 1 == shape[0] end end end @@ -237,28 +237,26 @@ def pretty_print(q) #:nodoc: # provide a :default, as 0 may behave differently from its Float or Complex equivalent. If no option # is given, Integer 0 will be used. def cast(*params) - if (params.size > 0 && params[0].is_a?(Hash)) + if params.size > 0 && params[0].is_a?(Hash) opts = { - :stype => self.stype, - :dtype => self.dtype, - :default => self.stype == :dense ? 0 : self.default_value + stype: stype, + dtype: dtype, + default: stype == :dense ? 0 : default_value, }.merge(params[0]) - self.cast_full(opts[:stype], opts[:dtype], opts[:default]) + cast_full(opts[:stype], opts[:dtype], opts[:default]) else - params << self.stype if params.size == 0 - params << self.dtype if params.size == 1 - #HACK: the default value can cause an exception if dtype is not complex - #and default_value is. (The ruby C code apparently won't convert these.) - #Perhaps this should be fixed in the C code (in rubyval_to_cval). + params << stype if params.size == 0 + params << dtype if params.size == 1 + # HACK: the default value can cause an exception if dtype is not complex + # and default_value is. (The ruby C code apparently won't convert these.) + # Perhaps this should be fixed in the C code (in rubyval_to_cval). default_value = maybe_get_noncomplex_default_value(params[1]) - params << (self.stype == :dense ? 0 : default_value) if params.size == 2 - self.cast_full(*params) + params << (stype == :dense ? 0 : default_value) if params.size == 2 + cast_full(*params) end - end - # # call-seq: # rows -> Integer @@ -291,18 +289,18 @@ def cols # == References # # * http://en.wikipedia.org/wiki/Main_diagonal - def diagonal main_diagonal=true + def diagonal main_diagonal = true diag_size = [cols, rows].min diag = NMatrix.new [diag_size], dtype: dtype if main_diagonal - 0.upto(diag_size-1) do |i| - diag[i] = self[i,i] + 0.upto(diag_size - 1) do |i| + diag[i] = self[i, i] end else row = 0 - (diag_size-1).downto(0) do |col| - diag[row] = self[row,col] + (diag_size - 1).downto(0) do |col| + diag[row] = self[row, col] row += 1 end end @@ -319,9 +317,9 @@ def diagonal main_diagonal=true def to_hash if stype == :yale h = {} - each_stored_with_indices do |val,i,j| + each_stored_with_indices do |val, i, j| next if val == 0 # Don't bother storing the diagonal zero values -- only non-zeros. - if h.has_key?(i) + if h.key?(i) h[i][j] = val else h[i] = {j => val} @@ -330,33 +328,31 @@ def to_hash h else # dense and list should use a C internal function. # FIXME: Write a C internal to_h function. - m = stype == :dense ? self.cast(:list, self.dtype) : self + m = stype == :dense ? cast(:list, dtype) : self m.__list_to_hash__ end end - alias :to_h :to_hash - + alias to_h to_hash def inspect #:nodoc: original_inspect = super() - original_inspect = original_inspect[0...original_inspect.size-1] + original_inspect = original_inspect[0...original_inspect.size - 1] original_inspect + " " + inspect_helper.join(" ") + ">" end def __yale_ary__to_s(sym) #:nodoc: - ary = self.send("__yale_#{sym.to_s}__".to_sym) + ary = send("__yale_#{sym}__".to_sym) - '[' + ary.collect { |a| a ? a : 'nil'}.join(',') + ']' + "[" + ary.collect { |a| a || "nil"}.join(",") + "]" end - # call-seq: # integer_dtype?() -> Boolean # # Checks if dtype is an integer type # def integer_dtype? - [:byte, :int8, :int16, :int32, :int64].include?(self.dtype) + [:byte, :int8, :int16, :int32, :int64].include?(dtype) end # call-seq: @@ -375,7 +371,7 @@ def float_dtype? # Checks if dtype is a complex type # def complex_dtype? - [:complex64, :complex128].include?(self.dtype) + [:complex64, :complex128].include?(dtype) end ## @@ -388,7 +384,6 @@ def object_dtype? dtype == :object end - # # call-seq: # to_f -> Float @@ -399,7 +394,7 @@ def object_dtype? # Raises an IndexError if the matrix does not have just a single element. # def to_f - raise IndexError, 'to_f only valid for matrices with a single element' unless shape.all? { |e| e == 1 } + raise IndexError, "to_f only valid for matrices with a single element" unless shape.all? { |e| e == 1 } self[*Array.new(shape.size, 0)] end @@ -411,11 +406,11 @@ def to_f # Converts an NMatrix to a one-dimensional Ruby Array. # def to_flat_array - ary = Array.new(self.size) - self.each.with_index { |v,i| ary[i] = v } + ary = Array.new(size) + each.with_index { |v, i| ary[i] = v } ary end - alias :to_flat_a :to_flat_array + alias to_flat_a to_flat_array # # call-seq: @@ -424,12 +419,11 @@ def to_flat_array # Returns the total size of the NMatrix based on its shape. # def size - NMatrix.size(self.shape) + NMatrix.size(shape) end - def to_s #:nodoc: - self.to_flat_array.to_s + to_flat_array.to_s end # @@ -440,7 +434,7 @@ def to_s #:nodoc: # Useful when we take slices of n-dimensional matrices where n > 2. # def nvector? - self.effective_dim < self.dim + effective_dim < dim end # @@ -450,10 +444,9 @@ def nvector? # Shortcut function for determining whether the effective dimension is 1. See also #nvector? # def vector? - self.effective_dim == 1 + effective_dim == 1 end - # # call-seq: # to_a -> Array @@ -461,20 +454,20 @@ def vector? # Converts an NMatrix to an array of arrays, or an NMatrix of effective dimension 1 to an array. # # Does not yet work for dimensions > 2 - def to_a(dimen=nil) - if self.dim == 2 + def to_a(dimen = nil) + if dim == 2 - return self.to_flat_a if self.shape[0] == 1 + return to_flat_a if shape[0] == 1 ary = [] begin - self.each_row do |row| + each_row do |row| ary << row.to_flat_a end - #rescue NotImplementedError # Oops. Try copying instead - # self.each_row(:copy) do |row| - # ary << row.to_a.flatten - # end + # rescue NotImplementedError # Oops. Try copying instead + # self.each_row(:copy) do |row| + # ary << row.to_a.flatten + # end end ary else @@ -482,7 +475,6 @@ def to_a(dimen=nil) end end - # # call-seq: # rank(dimension, row_or_column_number) -> NMatrix @@ -492,17 +484,16 @@ def to_a(dimen=nil) # # See @row (dimension = 0), @column (dimension = 1) def rank(shape_idx, rank_idx, meth = :copy) - - if shape_idx > (self.dim-1) + if shape_idx > (dim - 1) raise(RangeError, "#rank call was out of bounds") end - params = Array.new(self.dim) - params.each.with_index do |v,d| - params[d] = d == shape_idx ? rank_idx : 0...self.shape[d] + params = Array.new(dim) + params.each.with_index do |v, d| + params[d] = d == shape_idx ? rank_idx : 0...shape[d] end - meth == :reference ? self[*params] : self.slice(*params) + meth == :reference ? self[*params] : slice(*params) end # @@ -530,7 +521,7 @@ def column(column_number, get_by = :copy) rank(1, column_number, get_by) end - alias :col :column + alias col column # # call-seq: @@ -554,10 +545,9 @@ def row(row_number, get_by = :copy) # Returns the last element stored in an NMatrix # def last - self[*Array.new(self.dim, -1)] + self[*Array.new(dim, -1)] end - # # call-seq: # reshape(new_shape) -> NMatrix @@ -570,20 +560,19 @@ def last # * *Returns* : # - A copy with a different shape. # - def reshape new_shape,*shapes - if new_shape.is_a?Integer - newer_shape = [new_shape]+shapes - else # new_shape is an Array - newer_shape = new_shape + def reshape new_shape, *shapes + newer_shape = if new_shape.is_a? Integer + [new_shape] + shapes + else # new_shape is an Array + new_shape end t = reshape_clone_structure(newer_shape) - left_params = [:*]*newer_shape.size - right_params = [:*]*self.shape.size + left_params = [:*] * newer_shape.size + right_params = [:*] * shape.size t[*left_params] = self[*right_params] t end - # # call-seq: # reshape!(new_shape) -> NMatrix @@ -595,16 +584,16 @@ def reshape new_shape,*shapes # * *Arguments* : # - +new_shape+ -> Array of positive Integer. # - def reshape! new_shape,*shapes - if self.is_ref? + def reshape! new_shape, *shapes + if is_ref? raise(ArgumentError, "This operation cannot be performed on reference slices") else - if new_shape.is_a?Integer - shape = [new_shape]+shapes - else # new_shape is an Array - shape = new_shape + shape = if new_shape.is_a? Integer + [new_shape] + shapes + else # new_shape is an Array + new_shape end - self.reshape_bang(shape) + reshape_bang(shape) end end @@ -624,53 +613,52 @@ def reshape! new_shape,*shapes # def transpose(permute = nil) if permute.nil? - if self.dim == 1 - return self.clone - elsif self.dim == 2 - new_shape = [self.shape[1], self.shape[0]] + if dim == 1 + return clone + elsif dim == 2 + new_shape = [shape[1], shape[0]] else - raise(ArgumentError, "need permutation array of size #{self.dim}") + raise(ArgumentError, "need permutation array of size #{dim}") end - elsif !permute.is_a?(Array) || permute.sort.uniq != (0...self.dim).to_a + elsif !permute.is_a?(Array) || permute.sort.uniq != (0...dim).to_a raise(ArgumentError, "invalid permutation array") else # Figure out the new shape based on the permutation given as an argument. - new_shape = permute.map { |p| self.shape[p] } + new_shape = permute.map { |p| shape[p] } end - if self.dim > 2 # FIXME: For dense, several of these are basically equivalent to reshape. + if dim > 2 # FIXME: For dense, several of these are basically equivalent to reshape. # Make the new data structure. - t = self.reshape_clone_structure(new_shape) + t = reshape_clone_structure(new_shape) - self.each_stored_with_indices do |v,*indices| + each_stored_with_indices do |v, *indices| p_indices = permute.map { |p| indices[p] } t[*p_indices] = v end t - elsif self.list? # TODO: Need a C list transposition algorithm. + elsif list? # TODO: Need a C list transposition algorithm. # Make the new data structure. - t = self.reshape_clone_structure(new_shape) + t = reshape_clone_structure(new_shape) - self.each_column.with_index do |col,j| - t[j,:*] = col.to_flat_array + each_column.with_index do |col, j| + t[j, :*] = col.to_flat_array end t else # Call C versions of Yale and List transpose, which do their own copies if jruby? nmatrix = NMatrix.new :copy - nmatrix.shape = [@shape[1],@shape[0]] + nmatrix.shape = [@shape[1], @shape[0]] twoDMat = self.twoDMat.transpose - nmatrix.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData(), shape[1],shape[0])) + nmatrix.s = ArrayRealVector.new(ArrayGenerator.getArrayDouble(twoDMat.getData, shape[1], shape[0])) return nmatrix else - self.clone_transpose + clone_transpose end end end - # call-seq: # matrix1.concat(*m2) -> NMatrix # matrix1.concat(*m2, rank) -> NMatrix @@ -698,8 +686,8 @@ def concat(*matrices) # Find the first matching dimension and concatenate along that (unless rank is specified) if rank.nil? - rank = self.dim-1 - self.shape.reverse_each.with_index do |s,i| + rank = dim - 1 + shape.reverse_each.with_index do |s, i| matrices.each do |m| if m.shape[i] != s rank -= 1 @@ -708,23 +696,23 @@ def concat(*matrices) end end elsif rank.is_a?(Symbol) # Convert to numeric - rank = {:row => 0, :column => 1, :col => 1, :lay => 2, :layer => 2}[rank] + rank = {row: 0, column: 1, col: 1, lay: 2, layer: 2}[rank] end # Need to figure out the new shape. - new_shape = self.shape.dup - new_shape[rank] = matrices.inject(self.shape[rank]) { |total,m| total + m.shape[rank] } + new_shape = shape.dup + new_shape[rank] = matrices.inject(shape[rank]) { |total, m| total + m.shape[rank] } # Now figure out the options for constructing the concatenated matrix. - opts = {stype: self.stype, default: self.default_value, dtype: self.dtype} - if self.yale? + opts = {stype: stype, default: default_value, dtype: dtype} + if yale? # We can generally predict the new capacity for Yale. Subtract out the number of rows # for each matrix being concatenated, and then add in the number of rows for the new # shape. That takes care of the diagonal. The rest of the capacity is represented by # the non-diagonal non-default values. - new_cap = matrices.inject(self.capacity - self.shape[0]) do |total,m| + new_cap = matrices.inject(capacity - shape[0]) { |total, m| total + m.capacity - m.shape[0] - end - self.shape[0] + new_shape[0] + } - shape[0] + new_shape[0] opts = {capacity: new_cap}.merge(opts) end @@ -733,13 +721,13 @@ def concat(*matrices) # Figure out where to start concatenation. We don't know where it will end, # because each matrix may have own size along concat dimension. - pos = Array.new(self.dim) { 0 } + pos = Array.new(dim) { 0 } matrices.unshift(self) matrices.each do |m| # Figure out where to start and stop the concatenation. We'll use # NMatrices instead of Arrays because then we can do elementwise addition. - ranges = m.shape.map.with_index { |s,i| pos[i]...(pos[i] + s) } + ranges = m.shape.map.with_index { |s, i| pos[i]...(pos[i] + s) } n[*ranges] = m @@ -765,7 +753,6 @@ def dconcat(*matrices) concat(*matrices, :layer) end - # # call-seq: # upper_triangle -> NMatrix @@ -780,21 +767,20 @@ def dconcat(*matrices) # - +k+ -> Positive integer. How many extra diagonals to include in the upper triangular portion. # def upper_triangle(k = 0) - raise(NotImplementedError, "only implemented for 2D matrices") if self.shape.size > 2 + raise(NotImplementedError, "only implemented for 2D matrices") if shape.size > 2 - t = self.clone_structure - (0...self.shape[0]).each do |i| + t = clone_structure + (0...shape[0]).each do |i| if i - k < 0 t[i, :*] = self[i, :*] else - t[i, 0...(i-k)] = 0 - t[i, (i-k)...self.shape[1]] = self[i, (i-k)...self.shape[1]] + t[i, 0...(i - k)] = 0 + t[i, (i - k)...shape[1]] = self[i, (i - k)...shape[1]] end end t end - alias :triu :upper_triangle - + alias triu upper_triangle # # call-seq: @@ -809,17 +795,16 @@ def upper_triangle(k = 0) # - +k+ -> Integer. How many extra diagonals to include in the deletion. # def upper_triangle!(k = 0) - raise(NotImplementedError, "only implemented for 2D matrices") if self.shape.size > 2 + raise(NotImplementedError, "only implemented for 2D matrices") if shape.size > 2 - (0...self.shape[0]).each do |i| + (0...shape[0]).each do |i| if i - k >= 0 - self[i, 0...(i-k)] = 0 + self[i, 0...(i - k)] = 0 end end self end - alias :triu! :upper_triangle! - + alias triu! upper_triangle! # # call-seq: @@ -835,21 +820,20 @@ def upper_triangle!(k = 0) # - +k+ -> Integer. How many extra diagonals to include in the lower triangular portion. # def lower_triangle(k = 0) - raise(NotImplementedError, "only implemented for 2D matrices") if self.shape.size > 2 + raise(NotImplementedError, "only implemented for 2D matrices") if shape.size > 2 - t = self.clone_structure - (0...self.shape[0]).each do |i| + t = clone_structure + (0...shape[0]).each do |i| if i + k >= shape[0] t[i, :*] = self[i, :*] else - t[i, (i+k+1)...self.shape[1]] = 0 - t[i, 0..(i+k)] = self[i, 0..(i+k)] + t[i, (i + k + 1)...shape[1]] = 0 + t[i, 0..(i + k)] = self[i, 0..(i + k)] end end t end - alias :tril :lower_triangle - + alias tril lower_triangle # # call-seq: @@ -864,17 +848,16 @@ def lower_triangle(k = 0) # - +k+ -> Integer. How many extra diagonals to include in the deletion. # def lower_triangle!(k = 0) - raise(NotImplementedError, "only implemented for 2D matrices") if self.shape.size > 2 + raise(NotImplementedError, "only implemented for 2D matrices") if shape.size > 2 - (0...self.shape[0]).each do |i| + (0...shape[0]).each do |i| if i + k < shape[0] - self[i, (i+k+1)...self.shape[1]] = 0 + self[i, (i + k + 1)...shape[1]] = 0 end end self end - alias :tril! :lower_triangle! - + alias tril! lower_triangle! # # call-seq: @@ -898,11 +881,8 @@ def layer(layer_number, get_by = :copy) else layer end - end - - # # call-seq: # shuffle! -> ... @@ -913,14 +893,13 @@ def layer(layer_number, get_by = :copy) # TODO: Write more efficient version for Yale, list. # TODO: Generalize for more dimensions. def shuffle!(*args) - method_missing(:shuffle!, *args) if self.effective_dim > 1 - ary = self.to_flat_a + method_missing(:shuffle!, *args) if effective_dim > 1 + ary = to_flat_a ary.shuffle!(*args) - ary.each.with_index { |v,idx| self[idx] = v } + ary.each.with_index { |v, idx| self[idx] = v } self end - # # call-seq: # shuffle -> ... @@ -931,12 +910,11 @@ def shuffle!(*args) # TODO: Write more efficient version for Yale, list. # TODO: Generalize for more dimensions. def shuffle(*args) - method_missing(:shuffle!, *args) if self.effective_dim > 1 - t = self.clone + method_missing(:shuffle!, *args) if effective_dim > 1 + t = clone t.shuffle!(*args) end - # # call-seq: # sorted_indices -> Array @@ -945,11 +923,10 @@ def shuffle(*args) # def sorted_indices return method_missing(:sorted_indices) unless vector? - ary = self.to_flat_array - ary.each_index.sort_by { |i| ary[i] } # from: http://stackoverflow.com/a/17841159/170300 + ary = to_flat_array + ary.each_index.sort_by { |i| ary[i] } # from: http://stackoverflow.com/a/17841159/170300 end - # # call-seq: # binned_sorted_indices -> Array @@ -959,43 +936,40 @@ def sorted_indices # def binned_sorted_indices return method_missing(:sorted_indices) unless vector? - ary = self.to_flat_array + ary = to_flat_array ary2 = [] - last_bin = ary.each_index.sort_by { |i| [ary[i]] }.inject([]) do |result, element| + last_bin = ary.each_index.sort_by { |i| [ary[i]] }.inject([]) { |result, element| if result.empty? || ary[result[-1]] == ary[element] result << element else ary2 << result [element] end - end + } ary2 << last_bin unless last_bin.empty? ary2 end - def method_missing name, *args, &block #:nodoc: - if name.to_s =~ /^__list_elementwise_.*__$/ + if /^__list_elementwise_.*__$/.match?(name.to_s) raise NotImplementedError, "requested undefined list matrix element-wise operation" - elsif name.to_s =~ /^__yale_scalar_.*__$/ + elsif /^__yale_scalar_.*__$/.match?(name.to_s) raise NotImplementedError, "requested undefined yale scalar element-wise operation" else super(name, *args, &block) end end - def respond_to?(method, include_all = false) #:nodoc: if [:shuffle, :shuffle!, :each_with_index, :sorted_indices, :binned_sorted_indices, :nrm2, :asum].include?(method.intern) # vector-only methods - return vector? + vector? elsif [:each_layer, :layer].include?(method.intern) # 3-or-more dimensions only - return dim > 2 + dim > 2 else super end end - # # call-seq: # inject -> symbol @@ -1003,8 +977,8 @@ def respond_to?(method, include_all = false) #:nodoc: # This overrides the inject function to use map_stored for yale matrices # def inject(sym) - return super(sym) unless self.yale? - return self.map_stored.inject(sym) + return super(sym) unless yale? + map_stored.inject(sym) end # Returns the index of the first occurence of the specified value. Returns @@ -1013,7 +987,7 @@ def inject(sym) def index(value) index = nil - self.each_with_indices do |yields| + each_with_indices do |yields| if yields.first == value yields.shift index = yields @@ -1034,9 +1008,9 @@ def index(value) # you should probably use +zeros_like+. # def clone_structure(capacity = nil) - opts = {stype: self.stype, default: self.default_value, dtype: self.dtype} - opts = {capacity: capacity}.merge(opts) if self.yale? - NMatrix.new(self.shape, opts) + opts = {stype: stype, default: default_value, dtype: dtype} + opts = {capacity: capacity}.merge(opts) if yale? + NMatrix.new(shape, opts) end # @@ -1053,7 +1027,7 @@ def clone_structure(capacity = nil) # m.repeat(2, 0).to_a #<= [[1, 2], [3, 4], [1, 2], [3, 4]] # m.repeat(2, 1).to_a #<= [[1, 2, 1, 2], [3, 4, 3, 4]] def repeat(count, axis) - raise(ArgumentError, 'Matrix should be repeated at least 2 times.') if count < 2 + raise(ArgumentError, "Matrix should be repeated at least 2 times.") if count < 2 new_shape = shape new_shape[axis] *= count new_matrix = NMatrix.new(new_shape, dtype: dtype) @@ -1067,14 +1041,14 @@ def repeat(count, axis) end # This is how you write an individual element-wise operation function: - #def __list_elementwise_add__ rhs + # def __list_elementwise_add__ rhs # self.__list_map_merged_stored__(rhs){ |l,r| l+r }.cast(self.stype, NMatrix.upcast(self.dtype, rhs.dtype)) - #end -protected + # end + protected def inspect_helper #:nodoc: ary = [] - ary << "shape:[#{shape.join(',')}]" << "dtype:#{dtype}" << "stype:#{stype}" + ary << "shape:[#{shape.join(",")}]" << "dtype:#{dtype}" << "stype:#{stype}" if stype == :yale ary << "capacity:#{capacity}" @@ -1091,39 +1065,35 @@ def inspect_helper #:nodoc: ary end - # Clone the structure as needed for a reshape def reshape_clone_structure(new_shape) #:nodoc: - raise(ArgumentError, "reshape cannot resize; size of new and old matrices must match") unless self.size == new_shape.inject(1) { |p,i| p *= i } + raise(ArgumentError, "reshape cannot resize; size of new and old matrices must match") unless size == new_shape.inject(1) { |p, i| p *= i } - opts = {stype: self.stype, default: self.default_value, dtype: self.dtype} - if self.yale? + opts = {stype: stype, default: default_value, dtype: dtype} + if yale? # We can generally predict the change in capacity for Yale. - opts = {capacity: self.capacity - self.shape[0] + new_shape[0]}.merge(opts) + opts = {capacity: capacity - shape[0] + new_shape[0]}.merge(opts) end NMatrix.new(new_shape, opts) end - # Helper for converting a matrix into an array of arrays recursively def to_a_rec(dimen = 0) #:nodoc: - return self.flat_map { |v| v } if dimen == self.dim-1 + return flat_map { |v| v } if dimen == dim - 1 ary = [] - self.each_rank(dimen) do |sect| - ary << sect.to_a_rec(dimen+1) + each_rank(dimen) do |sect| + ary << sect.to_a_rec(dimen + 1) end ary end - # NMatrix constructor helper for sparse matrices. Uses multi-slice-setting to initialize a matrix # with a given array of initial values. def __sparse_initial_set__(ary) #:nodoc: - self[0...self.shape[0],0...self.shape[1]] = ary + self[0...shape[0], 0...shape[1]] = ary end - # This function assumes that the shapes of the two matrices have already # been tested and are the same. # @@ -1137,14 +1107,13 @@ def __sparse_initial_set__(ary) #:nodoc: # cast and then run the comparison. For now, let's assume that people aren't going # to be doing this very often, and we can optimize as needed. def dense_eql_sparse? m #:nodoc: - m.each_with_indices do |v,*indices| + m.each_with_indices do |v, *indices| return false if self[*indices] != v end - return true + true end - alias :sparse_eql_sparse? :dense_eql_sparse? - + alias sparse_eql_sparse? dense_eql_sparse? # # See the note in #cast about why this is necessary. @@ -1155,20 +1124,19 @@ def dense_eql_sparse? m #:nodoc: # def maybe_get_noncomplex_default_value(to_dtype) #:nodoc: default_value = 0 - unless self.stype == :dense then - if self.dtype.to_s.start_with?('complex') and not to_dtype.to_s.start_with?('complex') then - default_value = self.default_value.real + unless stype == :dense + default_value = if dtype.to_s.start_with?("complex") && !to_dtype.to_s.start_with?("complex") + self.default_value.real else - default_value = self.default_value + self.default_value end end default_value end - end -require_relative './shortcuts.rb' -require_relative './enumerate.rb' +require_relative "./shortcuts.rb" +require_relative "./enumerate.rb" -require_relative './version.rb' -require_relative './blas.rb' +require_relative "./version.rb" +require_relative "./blas.rb" diff --git a/lib/nmatrix/rspec.rb b/lib/nmatrix/rspec.rb index 398781d6..c3137f69 100644 --- a/lib/nmatrix/rspec.rb +++ b/lib/nmatrix/rspec.rb @@ -26,25 +26,24 @@ # NMatrix (particularly #be_within). # -require 'rspec' +require "rspec" # Amend RSpec to allow #be_within for matrices. module RSpec::Matchers::BuiltIn class BeWithin - def of(expected) @expected = expected - @unit = '' - if expected.is_a?(NMatrix) - @tolerance = if @delta.is_a?(NMatrix) - @delta.abs - elsif @delta.is_a?(Array) - NMatrix.new(:dense, expected.shape, @delta, :object).abs.cast(:dtype => expected.abs_dtype) - else - (NMatrix.ones_like(expected) * @delta).abs - end + @unit = "" + @tolerance = if expected.is_a?(NMatrix) + if @delta.is_a?(NMatrix) + @delta.abs + elsif @delta.is_a?(Array) + NMatrix.new(:dense, expected.shape, @delta, :object).abs.cast(dtype: expected.abs_dtype) + else + (NMatrix.ones_like(expected) * @delta).abs + end else - @tolerance = @delta + @delta end self @@ -52,7 +51,7 @@ def of(expected) def percent_of(expected) @expected = expected - @unit = '%' + @unit = "%" @tolerance = @expected.abs * @delta / 100.0 # <- only change is to reverse abs and @delta self end @@ -63,13 +62,12 @@ def matches?(actual) raise needs_subtractable unless @actual.respond_to? :- res = (@actual - @expected).abs <= @tolerance - #if res.is_a?(NMatrix) + # if res.is_a?(NMatrix) # require 'pry' # binding.pry - #end + # end res.is_a?(NMatrix) ? !res.any? { |x| !x } : res end - end end diff --git a/lib/nmatrix/shortcuts.rb b/lib/nmatrix/shortcuts.rb index 07ff50fd..829d4064 100644 --- a/lib/nmatrix/shortcuts.rb +++ b/lib/nmatrix/shortcuts.rb @@ -33,110 +33,115 @@ #++ class NMatrix - # Methods for generating magic matrix. module MagicHelpers class << self def odd_magic(nm, shape) row = shape - 1 - col = shape / 2 - nm[row,col] = 1 + col = shape / 2 + nm[row, col] = 1 (2..shape * shape).each do |index| - if nm[(row + 1) % shape,(col + 1) % shape] == 0 + if nm[(row + 1) % shape, (col + 1) % shape] == 0 row = (row + 1) % shape col = (col + 1) % shape else row = (row - 1 + shape) % shape end - nm[row,col] = index + nm[row, col] = index end end - + def doubly_even_magic(nm, shape) mini_square_num = shape / 4 - count = 1 + count = 1 inv_count = shape * shape shape.times do |row| shape.times do |col| - if col >= mini_square_num and col < shape - mini_square_num - if row >= mini_square_num and row < shape - mini_square_num - nm[row,col] = count - else - nm[row,col] = inv_count + nm[row, col] = if (col >= mini_square_num) && (col < shape - mini_square_num) + if (row >= mini_square_num) && (row < shape - mini_square_num) + count + else + inv_count end - elsif row < mini_square_num or row >= shape - mini_square_num - nm[row,col] = count + elsif (row < mini_square_num) || (row >= shape - mini_square_num) + count else - nm[row,col] = inv_count + inv_count end count += 1 - inv_count -= 1 + inv_count -= 1 end end end - + def singly_even_magic(nm, shape) half_shape = shape / 2 complementary_pair = (shape - 2) / 4 swap_col = NMatrix.new([shape]) - index = 0 - mini_magic = NMatrix.new([half_shape,half_shape], 0, dtype: nm.dtype) + index = 0 + mini_magic = NMatrix.new([half_shape, half_shape], 0, dtype: nm.dtype) odd_magic mini_magic, half_shape half_shape.times do |row| half_shape.times do |col| - nm[row,col] = mini_magic[row,col] - nm[row + half_shape,col + half_shape] = mini_magic[row,col] + half_shape * half_shape - nm[row,col + half_shape] = mini_magic[row,col] + 2 * half_shape * half_shape - nm[row + half_shape,col] = mini_magic[row,col] + 3 * half_shape * half_shape - end + nm[row, col] = mini_magic[row, col] + nm[row + half_shape, col + half_shape] = mini_magic[row, col] + half_shape * half_shape + nm[row, col + half_shape] = mini_magic[row, col] + 2 * half_shape * half_shape + nm[row + half_shape, col] = mini_magic[row, col] + 3 * half_shape * half_shape + end end - + (1..complementary_pair).each do |complementary_entry| swap_col[index] = complementary_entry index += 1 end - + (shape - complementary_pair + 2..shape).each do |center| swap_col[index] = center index += 1 - end - + end + (1..half_shape).each do |row| (1..index).each do |col| - temp = nm[row - 1,swap_col[col - 1] - 1] - nm[row - 1,swap_col[col - 1] - 1] = nm[row + half_shape - 1,swap_col[col - 1] - 1] - nm[row + half_shape - 1,swap_col[col - 1] - 1] = temp + temp = nm[row - 1, swap_col[col - 1] - 1] + nm[row - 1, swap_col[col - 1] - 1] = nm[row + half_shape - 1, swap_col[col - 1] - 1] + nm[row + half_shape - 1, swap_col[col - 1] - 1] = temp end end - temp = nm[complementary_pair,0] - nm[complementary_pair,0] = nm[complementary_pair + half_shape,0] - nm[complementary_pair + half_shape,0] = temp - - temp = nm[complementary_pair + half_shape,complementary_pair] - nm[complementary_pair + half_shape,complementary_pair] = nm[complementary_pair,complementary_pair] - nm[complementary_pair,complementary_pair] = temp - end - end - end - + temp = nm[complementary_pair, 0] + nm[complementary_pair, 0] = nm[complementary_pair + half_shape, 0] + nm[complementary_pair + half_shape, 0] = temp + + temp = nm[complementary_pair + half_shape, complementary_pair] + nm[complementary_pair + half_shape, complementary_pair] = nm[complementary_pair, complementary_pair] + nm[complementary_pair, complementary_pair] = temp + end + end + end + # call-seq: # m.dense? -> true or false # # Determine if +m+ is a dense matrix. - def dense?; return stype == :dense; end + def dense? + stype == :dense + end # call-seq: # m.yale? -> true or false # # Determine if +m+ is a Yale matrix. - def yale?; return stype == :yale; end + def yale? + stype == :yale + end # call-seq: # m.list? -> true or false # # Determine if +m+ is a list-of-lists matrix. - def list?; return stype == :list; end + def list? + stype == :list + end class << self # call-seq: @@ -197,7 +202,7 @@ def [](*params) end # A row vector should be stored as 1xN, not N - #shape.unshift(1) if shape.size == 1 + # shape.unshift(1) if shape.size == 1 # Then flatten the array. NMatrix.new(shape, params.flatten, options) @@ -230,9 +235,9 @@ def [](*params) # NMatrix.zeros([1, 5], dtype: :int32) # => 0 0 0 0 0 # def zeros(shape, opts = {}) - NMatrix.new(shape, 0, {:dtype => :float64}.merge(opts)) + NMatrix.new(shape, 0, {dtype: :float64}.merge(opts)) end - alias :zeroes :zeros + alias zeroes zeros # # call-seq: @@ -254,8 +259,8 @@ def zeros(shape, opts = {}) # NMatrix.ones([2, 3], dtype: :int32) # => 1 1 1 # 1 1 1 # - def ones(shape, opts={}) - NMatrix.new(shape, 1, {:dtype => :float64, :default => 1}.merge(opts)) + def ones(shape, opts = {}) + NMatrix.new(shape, 1, {dtype: :float64, default: 1}.merge(opts)) end # call-seq: @@ -312,16 +317,16 @@ def zeros_like(nm) # NMatrix.eye(2, dtype: :int32, stype: :yale) # => 1 0 # 0 1 # - def eye(shape, opts={}) + def eye(shape, opts = {}) # Fill the diagonal with 1's. - m = NMatrix.zeros(shape, {:dtype => :float64}.merge(opts)) + m = NMatrix.zeros(shape, {dtype: :float64}.merge(opts)) (0...m.shape[0]).each do |i| m[i, i] = 1 end m end - alias :identity :eye + alias identity eye # # call-seq: @@ -344,12 +349,12 @@ def eye(shape, opts={}) # 0.5 0.3333333333333333 0.25 # 0.3333333333333333 0.25 0.2 # - def hilbert(shape, opts={}) - m = NMatrix.new([shape,shape], {:dtype => :float64}.merge(opts)) + def hilbert(shape, opts = {}) + m = NMatrix.new([shape, shape], {dtype: :float64}.merge(opts)) 0.upto(shape - 1) do |i| 0.upto(i) do |j| - m[i,j] = 1.0 / (j + i + 1) - m[j,i] = m[i,j] if i != j + m[i, j] = 1.0 / (j + i + 1) + m[j, i] = m[i, j] if i != j end end m @@ -376,27 +381,27 @@ def hilbert(shape, opts={}) # 30.0, -180.0, 180.0 # # - def inv_hilbert(shape, opts={}) - opts = {:dtype => :float64}.merge(opts) - m = NMatrix.new([shape,shape],opts) - combination = NMatrix.new([2*shape,2*shape],opts) - #combinations refers to the combination of n things taken k at a time - 0.upto(2*shape-1) do |i| + def inv_hilbert(shape, opts = {}) + opts = {dtype: :float64}.merge(opts) + m = NMatrix.new([shape, shape], opts) + combination = NMatrix.new([2 * shape, 2 * shape], opts) + # combinations refers to the combination of n things taken k at a time + 0.upto(2 * shape - 1) do |i| 0.upto(i) do |j| - if j != 0 and j != i - combination[i,j] = combination[i-1,j] + combination[i-1,j-1] + combination[i, j] = if (j != 0) && (j != i) + combination[i - 1, j] + combination[i - 1, j - 1] else - combination[i,j] = 1 + 1 end end end - 0.upto(shape-1) do |i| + 0.upto(shape - 1) do |i| 0.upto(i) do |j| - m[i,j] = combination[shape + j,shape - i - 1] * ((i+j)+1) * \ - combination[shape + i,shape - j - 1] * (-1) ** ((i+j)) * \ - combination[(i+j),i] * combination[(i+j),i] - m[j,i] = m[i,j] if i != j + m[i, j] = combination[shape + j, shape - i - 1] * ((i + j) + 1) * \ + combination[shape + i, shape - j - 1] * (-1)**((i + j)) * \ + combination[(i + j), i] * combination[(i + j), i] + m[j, i] = m[i, j] if i != j end end m @@ -428,39 +433,38 @@ def inv_hilbert(shape, opts={}) # 0 0 0 4 # # - def diagonal(entries, opts={}) + def diagonal(entries, opts = {}) m = NMatrix.zeros(entries.size, - {:dtype => guess_dtype(entries[0]), :capacity => entries.size + 1}.merge(opts) - ) + {dtype: guess_dtype(entries[0]), capacity: entries.size + 1}.merge(opts)) entries.each_with_index do |n, i| - m[i,i] = n + m[i, i] = n end m end - alias :diag :diagonal - alias :diagonals :diagonal + alias diag diagonal + alias diagonals diagonal # Generate a block-diagonal NMatrix from the supplied 2D square matrices. # # * *Arguments* # - +*params+ -> An array that collects all arguments passed to the method. The method - # can receive any number of arguments. Optionally, the last entry of +params+ is - # a hash of options from NMatrix#initialize. All other entries of +params+ are - # the blocks of the desired block-diagonal matrix. Each such matrix block can be - # supplied as a square 2D NMatrix object, or alternatively as an array of arrays + # can receive any number of arguments. Optionally, the last entry of +params+ is + # a hash of options from NMatrix#initialize. All other entries of +params+ are + # the blocks of the desired block-diagonal matrix. Each such matrix block can be + # supplied as a square 2D NMatrix object, or alternatively as an array of arrays # (with dimensions corresponding to a square matrix), or alternatively as a number. # * *Returns* # - NMatrix of block-diagonal form filled with specified matrices # as the blocks along the diagonal. # - # * *Example* + # * *Example* # # a = NMatrix.new([2,2], [1,2,3,4]) # b = NMatrix.new([1,1], [123], dtype: :float64) # c = Array.new(2) { [[10,10], [10,10]] } # d = Array[[1,2,3], [4,5,6], [7,8,9]] # m = NMatrix.block_diagonal(a, b, *c, d, 10.0, 11, dtype: :int64, stype: :yale) - # => + # => # [ # [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] # [3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] @@ -481,10 +485,10 @@ def block_diagonal(*params) params.each_index do |i| params[i] = params[i].to_nm if params[i].is_a?(Array) # Convert Array to NMatrix - params[i] = NMatrix.new([1,1], [params[i]]) if params[i].is_a?(Numeric) # Convert number to NMatrix + params[i] = NMatrix.new([1, 1], [params[i]]) if params[i].is_a?(Numeric) # Convert number to NMatrix end - block_sizes = [] #holds the size of each matrix block + block_sizes = [] # holds the size of each matrix block params.each do |b| unless b.is_a?(NMatrix) raise(ArgumentError, "Only NMatrix or appropriate Array objects or single numbers allowed") @@ -494,22 +498,22 @@ def block_diagonal(*params) block_sizes << b.shape[0] end - block_diag_mat = NMatrix.zeros(block_sizes.inject(0,:+), options) + block_diag_mat = NMatrix.zeros(block_sizes.inject(0, :+), options) (0...params.length).each do |n| # First determine the size and position of the n'th block in the block-diagonal matrix block_size = block_sizes[n] - block_pos = block_sizes[0...n].inject(0,:+) + block_pos = block_sizes[0...n].inject(0, :+) # populate the n'th block in the block-diagonal matrix (0...block_size).each do |i| (0...block_size).each do |j| - block_diag_mat[block_pos+i,block_pos+j] = params[n][i,j] + block_diag_mat[block_pos + i, block_pos + j] = params[n][i, j] end end end - return block_diag_mat + block_diag_mat end - alias :block_diag :block_diagonal + alias block_diag block_diagonal # # call-seq: @@ -533,19 +537,17 @@ def block_diagonal(*params) # # NMatrix.random([2, 2], :dtype => :byte, :scale => 255) # => [ [252, 108] [44, 12] ] # - def random(shape, opts={}) + def random(shape, opts = {}) scale = opts.delete(:scale) || 1.0 - if opts[:seed].nil? - rng = Random.new + rng = if opts[:seed].nil? + Random.new else - rng = Random.new(opts[:seed]) + Random.new(opts[:seed]) end - random_values = [] - # Construct the values of the final matrix based on the dimension. if opts[:dtype] == :complex64 || opts[:dtype] == :complex128 NMatrix.size(shape).times { |i| random_values << Complex(rng.rand(scale), rng.rand(scale)) } @@ -553,11 +555,11 @@ def random(shape, opts={}) NMatrix.size(shape).times { |i| random_values << rng.rand(scale) } end - NMatrix.new(shape, random_values, {:dtype => :float64, :stype => :dense}.merge(opts)) + NMatrix.new(shape, random_values, {dtype: :float64, stype: :dense}.merge(opts)) end - alias :rand :random - - # + alias rand random + + # # call-seq: # magic(shape) -> NMatrix # magic(shape, dtype: dtype) -> NMatrix @@ -568,9 +570,9 @@ def random(shape, opts={}) # - An arrangement of the numbers from 1 to n^2 (n-squared) in the matrix, with each number occurring exactly once. # - The sum of the entries of any row, any column, or any main diagonal is the same. # - This sum must be n(n^2+1)/2. - # + # # See: http://www.mathworks.com/help/matlab/ref/magic.html - # + # # * *Arguments* : # - +shape+ -> Array (or integer for square matrix) specifying the dimensions. # - +dtype+ -> (optional) Default is +:float64+ @@ -578,14 +580,14 @@ def random(shape, opts={}) # - NMatrix with the above given properties. # # Examples: - # + # # NMatrix.magic(3) # => [ [4.0, 9.0, 2.0] [3.0, 5.0, 7.0] [8.0, 1.0, 6.0] ] - # + # # NMatrix.magic(4, dtype :int32) # => [ [ 1, 15, 14, 4] # [12, 6, 7, 9] # [ 8, 10, 11, 5] # [13, 3, 2, 16] ] - # + # # NMatrix.magic(6,dtype: :int64) # => [ [31, 9, 2, 22, 27, 20] # [ 3, 32, 7, 21, 23, 25] # [35, 1, 6, 26, 19, 24] @@ -593,19 +595,19 @@ def random(shape, opts={}) # [30, 5, 34, 12, 14, 16] # [ 8, 28, 33, 17, 10, 15] ] # - def magic(shape, opts={}) + def magic(shape, opts = {}) raise(ArgumentError, "shape of two is not allowed") if shape == 2 - nm = NMatrix.new([shape,shape], 0, {:dtype => :float64}.merge(opts)) + nm = NMatrix.new([shape, shape], 0, {dtype: :float64}.merge(opts)) if shape % 2 != 0 MagicHelpers.odd_magic nm, shape elsif shape % 4 == 0 MagicHelpers.doubly_even_magic nm, shape - else + else MagicHelpers.singly_even_magic nm, shape end nm end - + # # call-seq: # linspace(base, limit) -> 1x100 NMatrix @@ -642,24 +644,23 @@ def magic(shape, opts={}) # ] # def linspace(base, limit, shape = [100]) - - # Convert shape to array format - shape = [shape] if shape.is_a? Integer - - #Calculate number of elements + # Convert shape to array format + shape = [shape] if shape.is_a? Integer + + # Calculate number of elements count = shape.inject(:*) - + # Linear spacing between elements calculated in step # step = limit - base / (count - 1) # [Result Sequence] = [0->N sequence] * step + [Base] step = (limit - base) * (1.0 / (count - 1)) - result = NMatrix.seq(shape, {:dtype => :float64}) * step + result = NMatrix.seq(shape, {dtype: :float64}) * step result += NMatrix.new(shape, base) result end # call-seq: - # logspace(base, limit) -> 1x50 NMatrix with exponent_base = 10 + # logspace(base, limit) -> 1x50 NMatrix with exponent_base = 10 # logspace(base, limit, shape , exponent_base:) -> NMatrix # logspace(base, :pi, n) -> 1xn NMatrix with interval [10 ^ base, Math::PI] # @@ -679,12 +680,12 @@ def linspace(base, limit, shape = [100]) # # NMatrix.logspace(1,:pi,7) # =>[ - # 10.0000, - # 8.2450, - # 6.7980, - # 5.6050, - # 4.6213, - # 3.8103, + # 10.0000, + # 8.2450, + # 6.7980, + # 5.6050, + # 4.6213, + # 3.8103, # 3.1416 # ] # @@ -696,14 +697,13 @@ def linspace(base, limit, shape = [100]) # ] # def logspace(base, limit, shape = [50], exponent_base: 10) - - #Calculate limit for [10 ^ base ... Math::PI] if limit = :pi - limit = Math.log(Math::PI, exponent_base = 10) if limit == :pi + # Calculate limit for [10 ^ base ... Math::PI] if limit = :pi + limit = Math.log(Math::PI, exponent_base = 10) if limit == :pi shape = [shape] if shape.is_a? Integer - #[base...limit] -> [exponent_base ** base ... exponent_base ** limit] + # [base...limit] -> [exponent_base ** base ... exponent_base ** limit] result = NMatrix.linspace(base, limit, shape) - result.map {|element| exponent_base ** element} + result.map {|element| exponent_base**element} end # @@ -742,24 +742,23 @@ def logspace(base, limit, shape = [50], exponent_base: 10) # ] # def linspace(base, limit, shape = [100]) - - # Convert shape to array format - shape = [shape] if shape.is_a? Integer - - #Calculate number of elements + # Convert shape to array format + shape = [shape] if shape.is_a? Integer + + # Calculate number of elements count = shape.inject(:*) - + # Linear spacing between elements calculated in step # step = limit - base / (count - 1) # [Result Sequence] = [0->N sequence] * step + [Base] step = (limit - base) * (1.0 / (count - 1)) - result = NMatrix.seq(shape, {:dtype => :float64}) * step + result = NMatrix.seq(shape, {dtype: :float64}) * step result += NMatrix.new(shape, base) result end # call-seq: - # logspace(base, limit) -> 1x50 NMatrix with exponent_base = 10 + # logspace(base, limit) -> 1x50 NMatrix with exponent_base = 10 # logspace(base, limit, shape , exponent_base:) -> NMatrix # logspace(base, :pi, n) -> 1xn NMatrix with interval [10 ^ base, Math::PI] # @@ -779,12 +778,12 @@ def linspace(base, limit, shape = [100]) # # NMatrix.logspace(1,:pi,7) # =>[ - # 10.0000, - # 8.2450, - # 6.7980, - # 5.6050, - # 4.6213, - # 3.8103, + # 10.0000, + # 8.2450, + # 6.7980, + # 5.6050, + # 4.6213, + # 3.8103, # 3.1416 # ] # @@ -796,14 +795,13 @@ def linspace(base, limit, shape = [100]) # ] # def logspace(base, limit, shape = [50], exponent_base: 10) - - #Calculate limit for [10 ^ base ... Math::PI] if limit = :pi - limit = Math.log(Math::PI, exponent_base = 10) if limit == :pi + # Calculate limit for [10 ^ base ... Math::PI] if limit = :pi + limit = Math.log(Math::PI, exponent_base = 10) if limit == :pi shape = [shape] if shape.is_a? Integer - #[base...limit] -> [exponent_base ** base ... exponent_base ** limit] + # [base...limit] -> [exponent_base ** base ... exponent_base ** limit] result = NMatrix.linspace(base, limit, shape) - result.map {|element| exponent_base ** element} + result.map {|element| exponent_base**element} end # @@ -835,25 +833,23 @@ def logspace(base, limit, shape = [50], exponent_base: 10) # 3.0 4.0 5.0 # 6.0 7.0 8.0 # - def seq(shape, options={}) - + def seq(shape, options = {}) # Construct the values of the final matrix based on the dimension. - values = (0 ... NMatrix.size(shape)).to_a + values = (0...NMatrix.size(shape)).to_a # It'll produce :int32, except if a dtype is provided. - NMatrix.new(shape, values, {:stype => :dense}.merge(options)) + NMatrix.new(shape, values, {stype: :dense}.merge(options)) end - {:bindgen => :byte, :indgen => :int64, :findgen => :float32, :dindgen => :float64, - :cindgen => :complex64, :zindgen => :complex128, - :rbindgen => :object}.each_pair do |meth, dtype| - define_method(meth) { |shape| NMatrix.seq(shape, :dtype => dtype) } + {bindgen: :byte, indgen: :int64, findgen: :float32, dindgen: :float64, + cindgen: :complex64, zindgen: :complex128, + rbindgen: :object,}.each_pair do |meth, dtype| + define_method(meth) { |shape| NMatrix.seq(shape, dtype: dtype) } end end end module NVector #:nodoc: - class << self # # call-seq: @@ -879,9 +875,9 @@ class << self # def new(*args) stype = args[0].is_a?(Symbol) ? args.shift : :dense - shape = args[0].is_a?(Array) ? args.shift : [1,args.shift] + shape = args[0].is_a?(Array) ? args.shift : [1, args.shift] - if shape.size != 2 || !shape.include?(1) || shape == [1,1] + if shape.size != 2 || !shape.include?(1) || shape == [1, 1] raise(ArgumentError, "shape must be a Fixnum or an Array of positive Fixnums where exactly one value is 1") end @@ -914,9 +910,9 @@ def new(*args) # 0 # def zeros(size, dtype = :float64) - NMatrix.new([size,1], 0, dtype: dtype) + NMatrix.new([size, 1], 0, dtype: dtype) end - alias :zeroes :zeros + alias zeroes zeros # # call-seq: @@ -942,7 +938,7 @@ def zeros(size, dtype = :float64) # 1 # def ones(size, dtype = :float64) - NMatrix.new([size,1], 1, dtype: dtype) + NMatrix.new([size, 1], 1, dtype: dtype) end # @@ -969,7 +965,7 @@ def random(size, opts = {}) random_values = [] size.times { |i| random_values << rng.rand } - NMatrix.new([size,1], random_values, opts) + NMatrix.new([size, 1], random_values, opts) end # @@ -996,9 +992,9 @@ def random(size, opts = {}) # 2.0 # def seq(size, dtype = :int64) - values = (0 ... size).to_a + values = (0...size).to_a - NMatrix.new([size,1], values, dtype: dtype) + NMatrix.new([size, 1], values, dtype: dtype) end # @@ -1097,8 +1093,8 @@ def linspace(a, b, n = 100) step = (b - a) * (1.0 / (n - 1)) # dtype = :float64 is used to prevent integer coercion. - result = NVector.seq(n, :float64) * NMatrix.new([n,1], step, dtype: :float64) - result += NMatrix.new([n,1], a, dtype: :float64) + result = NVector.seq(n, :float64) * NMatrix.new([n, 1], step, dtype: :float64) + result += NMatrix.new([n, 1], a, dtype: :float64) result end @@ -1138,13 +1134,12 @@ def logspace(a, b, n = 100) # Formula: 10^a, 10^(a + step), ..., 10^b, where step = ((b-a) / (n-1)). result = NVector.linspace(a, b, n) - result.each_stored_with_index { |element, i| result[i] = 10 ** element } + result.each_stored_with_index { |element, i| result[i] = 10**element } result end end end - # This constant is intended as a simple constructor for NMatrix meant for # experimenting. # diff --git a/lib/nmatrix/version.rb b/lib/nmatrix/version.rb index e4c4a3b2..8de587da 100644 --- a/lib/nmatrix/version.rb +++ b/lib/nmatrix/version.rb @@ -30,10 +30,9 @@ module VERSION #:nodoc: MAJOR = 0 MINOR = 2 TINY = 4 - #PRE = "a" + # PRE = "a" STRING = [MAJOR, MINOR, TINY].compact.join(".") - #STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") + # STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end end - diff --git a/lib/nmatrix/yale_functions.rb b/lib/nmatrix/yale_functions.rb index 07f20c2a..30061d90 100644 --- a/lib/nmatrix/yale_functions.rb +++ b/lib/nmatrix/yale_functions.rb @@ -35,7 +35,7 @@ module NMatrix::YaleFunctions # # Returns the size of a given non-diagonal row. def yale_nd_row_size i - yale_ija(i+1) - yale_ija(i) + yale_ija(i + 1) - yale_ija(i) end # call-seq: @@ -45,27 +45,27 @@ def yale_nd_row_size i def yale_ja_at i yale_nd_row(i, :keys) end - alias :yale_nd_row_as_array :yale_ja_at + alias yale_nd_row_as_array yale_ja_at # call-seq: # yale_ja_set_at(i) -> Set # # Returns the non-diagonal column indices which are stored in a given row, as a Set. def yale_ja_set_at i - require 'set' + require "set" yale_nd_row(i, :keys).to_set end - alias :yale_nd_row_as_set :yale_ja_set_at + alias yale_nd_row_as_set yale_ja_set_at # call-seq: # yale_ja_sorted_set_at -> SortedSet # # Returns the non-diagonal column indices which are stored in a given row, as a Set. def yale_ja_sorted_set_at i - require 'set' + require "set" SortedSet.new(yale_nd_row(i, :keys)) end - alias :yale_nd_row_as_sorted_set :yale_ja_sorted_set_at + alias yale_nd_row_as_sorted_set yale_ja_sorted_set_at # call-seq: # yale_nd_row_as_hash(i) -> Hash @@ -81,30 +81,30 @@ def yale_nd_row_as_hash i # Returns the diagonal and non-digonal column indices stored in a given row. def yale_ja_d_keys_at i ary = yale_nd_row(i, :keys) - return ary if i >= self.shape[1] || self[i,i] == self.default_value + return ary if i >= shape[1] || self[i, i] == default_value ary << i end - alias :yale_row_as_array :yale_ja_d_keys_at + alias yale_row_as_array yale_ja_d_keys_at # call-seq: # yale_ja_d_keys_set_at(i) -> Set # # Returns the diagonal and non-diagonal column indices stored in a given row. def yale_ja_d_keys_set_at i - require 'set' + require "set" yale_ja_d_keys_at(i).to_set end - alias :yale_row_as_set :yale_ja_d_keys_set_at + alias yale_row_as_set yale_ja_d_keys_set_at # call-seq: # yale_ja_d_keys_sorted_set_at(i) -> SortedSet # # Returns the diagonal and non-diagonal column indices stored in a given row. def yale_ja_d_keys_sorted_set_at i - require 'set' + require "set" SortedSet.new(yale_row_as_array(i)) end - alias :yale_row_as_sorted_set :yale_ja_d_keys_sorted_set_at + alias yale_row_as_sorted_set yale_ja_d_keys_sorted_set_at # call-seq: # yale_row_as_hash(i) -> Hash @@ -112,7 +112,7 @@ def yale_ja_d_keys_sorted_set_at i # Returns the diagonal and non-diagonal column indices and entries stored in a given row. def yale_row_as_hash i h = yale_nd_row(i, :hash) - return h if i >= self.shape[1] || self[i,i] == self.default_value - h[i] = self[i,i] + return h if i >= shape[1] || self[i, i] == default_value + h[i] = self[i, i] end -end \ No newline at end of file +end diff --git a/nmatrix-atlas.gemspec b/nmatrix-atlas.gemspec index 1d478919..a7b99dfe 100644 --- a/nmatrix-atlas.gemspec +++ b/nmatrix-atlas.gemspec @@ -1,29 +1,28 @@ -lib = File.expand_path('../lib/', __FILE__) +lib = File.expand_path("../lib/", __FILE__) $:.unshift lib unless $:.include?(lib) -require 'nmatrix/version' +require "nmatrix/version" Gem::Specification.new do |gem| gem.name = "nmatrix-atlas" gem.version = NMatrix::VERSION::STRING gem.summary = "ATLAS backend for nmatrix" gem.description = "For using linear algebra fuctions provided by ATLAS" - gem.homepage = 'http://sciruby.com' - gem.authors = ['Will Levine', 'John Woods'] - gem.email = ['john.o.woods@gmail.com'] - gem.license = 'BSD-3-Clause' + gem.homepage = "http://sciruby.com" + gem.authors = ["Will Levine", "John Woods"] + gem.email = ["john.o.woods@gmail.com"] + gem.license = "BSD-3-Clause" - gem.files = ["lib/nmatrix/atlas.rb","lib/nmatrix/lapack_ext_common.rb"] + gem.files = ["lib/nmatrix/atlas.rb", "lib/nmatrix/lapack_ext_common.rb"] gem.files += `git ls-files -- ext/nmatrix_atlas`.split("\n") - gem.files += `git ls-files -- ext/nmatrix | grep ".h$"`.split("\n") #need nmatrix header files to compile - gem.test_files = `git ls-files -- spec`.split("\n") + gem.files += `git ls-files -- ext/nmatrix | grep ".h$"`.split("\n") # need nmatrix header files to compile + gem.test_files = `git ls-files -- spec`.split("\n") gem.test_files -= `git ls-files -- spec/plugins`.split("\n") gem.test_files += `git ls-files -- spec/plugins/atlas`.split("\n") - gem.extensions = ['ext/nmatrix_atlas/extconf.rb'] + gem.extensions = ["ext/nmatrix_atlas/extconf.rb"] gem.require_paths = ["lib"] - gem.required_ruby_version = '>= 1.9' + gem.required_ruby_version = ">= 1.9" - gem.add_dependency 'nmatrix', NMatrix::VERSION::STRING + gem.add_dependency "nmatrix", NMatrix::VERSION::STRING end - diff --git a/nmatrix-fftw.gemspec b/nmatrix-fftw.gemspec index 95445e32..64493240 100644 --- a/nmatrix-fftw.gemspec +++ b/nmatrix-fftw.gemspec @@ -1,29 +1,28 @@ -lib = File.expand_path('../lib/', __FILE__) +lib = File.expand_path("../lib/", __FILE__) $:.unshift lib unless $:.include?(lib) -require 'nmatrix/version' +require "nmatrix/version" Gem::Specification.new do |gem| gem.name = "nmatrix-fftw" gem.version = NMatrix::VERSION::STRING gem.summary = "FFTW backend for NMatrix" gem.description = "NMatrix extension for using fuctions provided by FFTW" - gem.homepage = 'http://sciruby.com' - gem.authors = ['Sameer Deshmukh', 'Magdalen Berns'] - gem.email = ['sameer.deshmukh93@gmail.com', 'm.berns@thismagpie.com'] - gem.license = 'BSD-3-Clause' + gem.homepage = "http://sciruby.com" + gem.authors = ["Sameer Deshmukh", "Magdalen Berns"] + gem.email = ["sameer.deshmukh93@gmail.com", "m.berns@thismagpie.com"] + gem.license = "BSD-3-Clause" - gem.files = ["lib/nmatrix/fftw.rb"] + gem.files = ["lib/nmatrix/fftw.rb"] gem.files += `git ls-files -- ext/nmatrix_fftw`.split("\n") - gem.files += `git ls-files -- ext/nmatrix | grep ".h$"`.split("\n") #need nmatrix header files to compile - gem.test_files = `git ls-files -- spec`.split("\n") + gem.files += `git ls-files -- ext/nmatrix | grep ".h$"`.split("\n") # need nmatrix header files to compile + gem.test_files = `git ls-files -- spec`.split("\n") gem.test_files -= `git ls-files -- spec/plugins`.split("\n") gem.test_files += `git ls-files -- spec/plugins/fftw`.split("\n") - gem.extensions = ['ext/nmatrix_fftw/extconf.rb'] + gem.extensions = ["ext/nmatrix_fftw/extconf.rb"] gem.require_paths = ["lib"] - gem.required_ruby_version = '>= 1.9' + gem.required_ruby_version = ">= 1.9" - gem.add_dependency 'nmatrix', NMatrix::VERSION::STRING + gem.add_dependency "nmatrix", NMatrix::VERSION::STRING end - diff --git a/nmatrix-lapacke.gemspec b/nmatrix-lapacke.gemspec index c90ffd29..a9e1f6a5 100644 --- a/nmatrix-lapacke.gemspec +++ b/nmatrix-lapacke.gemspec @@ -1,29 +1,28 @@ -lib = File.expand_path('../lib/', __FILE__) +lib = File.expand_path("../lib/", __FILE__) $:.unshift lib unless $:.include?(lib) -require 'nmatrix/version' +require "nmatrix/version" Gem::Specification.new do |gem| gem.name = "nmatrix-lapacke" gem.version = NMatrix::VERSION::STRING gem.summary = "general LAPACK backend for nmatrix using LAPACKE interface" gem.description = "For using linear algebra fuctions provided by LAPACK and BLAS" - gem.homepage = 'http://sciruby.com' - gem.authors = ['Will Levine', 'John Woods'] - gem.email = ['john.o.woods@gmail.com'] - gem.license = 'BSD-3-Clause' + gem.homepage = "http://sciruby.com" + gem.authors = ["Will Levine", "John Woods"] + gem.email = ["john.o.woods@gmail.com"] + gem.license = "BSD-3-Clause" - gem.files = ["lib/nmatrix/lapacke.rb","lib/nmatrix/lapack_ext_common.rb"] + gem.files = ["lib/nmatrix/lapacke.rb", "lib/nmatrix/lapack_ext_common.rb"] gem.files += `git ls-files -- ext/nmatrix_lapacke`.split("\n") - gem.files += `git ls-files -- ext/nmatrix | grep ".h$"`.split("\n") #need nmatrix header files to compile - gem.test_files = `git ls-files -- spec`.split("\n") + gem.files += `git ls-files -- ext/nmatrix | grep ".h$"`.split("\n") # need nmatrix header files to compile + gem.test_files = `git ls-files -- spec`.split("\n") gem.test_files -= `git ls-files -- spec/plugins`.split("\n") gem.test_files += `git ls-files -- spec/plugins/lapacke`.split("\n") - gem.extensions = ['ext/nmatrix_lapacke/extconf.rb'] + gem.extensions = ["ext/nmatrix_lapacke/extconf.rb"] gem.require_paths = ["lib"] - gem.required_ruby_version = '>= 1.9' + gem.required_ruby_version = ">= 1.9" - gem.add_dependency 'nmatrix', NMatrix::VERSION::STRING + gem.add_dependency "nmatrix", NMatrix::VERSION::STRING end - diff --git a/nmatrix.gemspec b/nmatrix.gemspec index 19ac5ad6..4e3c2fe3 100644 --- a/nmatrix.gemspec +++ b/nmatrix.gemspec @@ -1,9 +1,9 @@ -lib = File.expand_path('../lib/', __FILE__) +lib = File.expand_path("../lib/", __FILE__) $:.unshift lib unless $:.include?(lib) -require 'nmatrix/version' +require "nmatrix/version" -#get files that are used by plugins rather than the main nmatrix gem +# get files that are used by plugins rather than the main nmatrix gem plugin_files = [] Dir["nmatrix-*.gemspec"].each do |gemspec_file| gemspec = eval(File.read(gemspec_file)) @@ -16,52 +16,52 @@ Gem::Specification.new do |gem| gem.version = NMatrix::VERSION::STRING gem.summary = "NMatrix is a linear algebra library for Ruby" gem.description = "NMatrix is a linear algebra library for Ruby, written mostly in C and C++." - gem.homepage = 'http://sciruby.com' - gem.authors = ['John Woods', 'Chris Wailes', 'Aleksey Timin'] - gem.email = ['john.o.woods@gmail.com'] - gem.license = 'BSD-3-Clause' - gem.post_install_message = <<-EOF -*********************************************************** -Welcome to SciRuby: Tools for Scientific Computing in Ruby! + gem.homepage = "http://sciruby.com" + gem.authors = ["John Woods", "Chris Wailes", "Aleksey Timin"] + gem.email = ["john.o.woods@gmail.com"] + gem.license = "BSD-3-Clause" + gem.post_install_message = <<~EOF + *********************************************************** + Welcome to SciRuby: Tools for Scientific Computing in Ruby! -NMatrix requires a C/C++ compiler. Clang and GCC are -recommended. JRuby support is experimental, and requires -Java. + NMatrix requires a C/C++ compiler. Clang and GCC are + recommended. JRuby support is experimental, and requires + Java. -If you are upgrading from NMatrix 0.1.0 and rely on -ATLAS features, please check the README. + If you are upgrading from NMatrix 0.1.0 and rely on + ATLAS features, please check the README. -Faster matrix calculations and more advanced linear -algebra features are available by installing either -the nmatrix-atlas or nmatrix-lapacke plugins. + Faster matrix calculations and more advanced linear + algebra features are available by installing either + the nmatrix-atlas or nmatrix-lapacke plugins. -More explicit instructions for NMatrix and SciRuby should -be available on the SciRuby website, sciruby.com, or -through our mailing list (which can be found on our web- -site). + More explicit instructions for NMatrix and SciRuby should + be available on the SciRuby website, sciruby.com, or + through our mailing list (which can be found on our web- + site). -Thanks for trying out NMatrix! Happy coding! + Thanks for trying out NMatrix! Happy coding! -*********************************************************** -EOF + *********************************************************** + EOF - gem.files = `git ls-files -- ext/nmatrix`.split("\n") + gem.files = `git ls-files -- ext/nmatrix`.split("\n") gem.files += `git ls-files -- lib`.split("\n") gem.files -= plugin_lib_files - gem.test_files = `git ls-files -- spec`.split("\n") - gem.test_files -= `git ls-files -- spec/plugins`.split("\n") - gem.extensions = ['ext/nmatrix/extconf.rb'] + gem.test_files = `git ls-files -- spec`.split("\n") + gem.test_files -= `git ls-files -- spec/plugins`.split("\n") + gem.extensions = ["ext/nmatrix/extconf.rb"] gem.require_paths = ["lib"] - gem.required_ruby_version = '>= 1.9' + gem.required_ruby_version = ">= 1.9" - gem.add_dependency 'packable', '~> 1.3', '>= 1.3.5' - gem.add_development_dependency 'bundler', '~>1.6' - gem.add_development_dependency 'pry', '~>0.10' - gem.add_development_dependency 'rake', '~>10.3' - gem.add_development_dependency 'rake-compiler', '~>0.8' - gem.add_development_dependency 'rdoc', '~>4.0', '>=4.0.1' - gem.add_development_dependency 'rspec', '~>2.14' - gem.add_development_dependency 'rspec-longrun', '~>1.0' + gem.add_dependency "packable", "~> 1.3", ">= 1.3.5" + gem.add_development_dependency "bundler", "~>1.6" + gem.add_development_dependency "pry", "~> 0.10" + gem.add_development_dependency "rake", "~> 10.3" + gem.add_development_dependency "rake-compiler", "~> 0.8" + gem.add_development_dependency "rdoc", "~> 4.0", ">= 4.0.1" + gem.add_development_dependency "rspec", "~> 2.14" + gem.add_development_dependency "rspec-longrun", "~> 1.0" + gem.add_development_dependency "standard" end - diff --git a/scripts/switch_lapack_ubuntu.rb b/scripts/switch_lapack_ubuntu.rb index 71f5725f..560580d8 100755 --- a/scripts/switch_lapack_ubuntu.rb +++ b/scripts/switch_lapack_ubuntu.rb @@ -19,7 +19,6 @@ def run(cmd) system cmd end - run "update-alternatives --set liblapack.so.3 #{lapack_prefix}/liblapack.so.3" run "update-alternatives --set liblapack.so #{lapack_prefix}/liblapack.so" run "update-alternatives --set libblas.so.3 #{blas_prefix}/libblas.so.3" diff --git a/scripts/ttable_helper.rb b/scripts/ttable_helper.rb index 01decd1f..8c948cc2 100755 --- a/scripts/ttable_helper.rb +++ b/scripts/ttable_helper.rb @@ -3,113 +3,107 @@ # A helper file for generating and maintaining template tables. DTYPES = [ - :uint8_t, - :int8_t, - :int16_t, - :int32_t, - :int64_t, - :float32_t, - :float64_t, - :'nm::Complex64', - :'nm::Complex128', - :'nm::RubyObject' - ] + :uint8_t, + :int8_t, + :int16_t, + :int32_t, + :int64_t, + :float32_t, + :float64_t, + :'nm::Complex64', + :'nm::Complex128', + :'nm::RubyObject', +] def nullify(disabled = []) #:nodoc: - DTYPES.map { |t| if disabled.include?(t) then :NULL else t end } + DTYPES.map { |t| disabled.include?(t) ? :NULL : t } end ITYPES = [ - :uint8_t, - :uint16_t, - :uint32_t, - :uint64_t - ] + :uint8_t, + :uint16_t, + :uint32_t, + :uint64_t, +] EWOPS = [ - :'nm::EW_ADD', - :'nm::EW_SUB', - :'nm::EW_MUL', - :'nm::EW_DIV', - :'nm::EW_POW', - :'nm::EW_MOD', - :'nm::EW_EQEQ', - :'nm::EW_NEQ', - :'nm::EW_LT', - :'nm::EW_GT', - :'nm::EW_LEQ', - :'nm::EW_GEQ' - ] + :'nm::EW_ADD', + :'nm::EW_SUB', + :'nm::EW_MUL', + :'nm::EW_DIV', + :'nm::EW_POW', + :'nm::EW_MOD', + :'nm::EW_EQEQ', + :'nm::EW_NEQ', + :'nm::EW_LT', + :'nm::EW_GT', + :'nm::EW_LEQ', + :'nm::EW_GEQ', +] LR_ALLOWED = { - :uint8_t => DTYPES, - :int8_t => DTYPES, - :int16_t => DTYPES, - :int32_t => DTYPES, - :int64_t => DTYPES, - :float32_t => DTYPES, - :float64_t => DTYPES, - :'nm::Complex64' => DTYPES, - :'nm::Complex128' => DTYPES, - :'nm::RubyObject' => DTYPES + uint8_t: DTYPES, + int8_t: DTYPES, + int16_t: DTYPES, + int32_t: DTYPES, + int64_t: DTYPES, + float32_t: DTYPES, + float64_t: DTYPES, + 'nm::Complex64': DTYPES, + 'nm::Complex128': DTYPES, + 'nm::RubyObject': DTYPES, } lines = case ARGV[0] - when 'OPLR' - '{' + - EWOPS.map do |op| - - '{' + - DTYPES.map do |l_dtype| - - '{' + - LR_ALLOWED[l_dtype].map do |r_dtype| - if r_dtype == :NULL - 'NULL' - else - "fun<#{op}, #{l_dtype}, #{r_dtype}>" - end - end.join(', ') + - '}' - - end.join(",\n") + - '}' - - end.join(",\n") + - '}' - - when 'OPID' - '{' + - EWOPS.map do |op| - '{' + - ITYPES.map do |itype| - '{' + - DTYPES.map do |dtype| - - if dtype == :NULL - 'NULL' - else - "fun<#{op}, #{itype}, #{dtype}>" - end - - end.join(",") + - '}' - end.join(",\\\n") + - '}' - end.join(",\\\n") + - '}' - - when 'LR' - '{' + DTYPES.map do |l_dtype| - '{' + LR_ALLOWED[l_dtype].map do |r_dtype| + when "OPLR" + "{" + + EWOPS.map { |op| + "{" + + DTYPES.map { |l_dtype| + "{" + + LR_ALLOWED[l_dtype].map { |r_dtype| + if r_dtype == :NULL + "NULL" + else + "fun<#{op}, #{l_dtype}, #{r_dtype}>" + end + }.join(", ") + + "}" + }.join(",\n") + + "}" + }.join(",\n") + + "}" + + when "OPID" + "{" + + EWOPS.map { |op| + "{" + + ITYPES.map { |itype| + "{" + + DTYPES.map { |dtype| + if dtype == :NULL + "NULL" + else + "fun<#{op}, #{itype}, #{dtype}>" + end + }.join(",") + + "}" + }.join(",\\\n") + + "}" + }.join(",\\\n") + + "}" + + when "LR" + "{" + DTYPES.map { |l_dtype| + "{" + LR_ALLOWED[l_dtype].map { |r_dtype| if r_dtype == :NULL - 'NULL' + "NULL" else "fun<#{l_dtype}, #{r_dtype}>" end - end.join(', ') + '}' - end.join(",\n") + '}' + }.join(", ") + "}" + }.join(",\n") + "}" end puts lines diff --git a/spec/00_nmatrix_spec.rb b/spec/00_nmatrix_spec.rb index 8ff0f3d7..093a7c59 100644 --- a/spec/00_nmatrix_spec.rb +++ b/spec/00_nmatrix_spec.rb @@ -25,188 +25,188 @@ # Basic tests for NMatrix. These should load first, as they're # essential to NMatrix operation. # -require 'spec_helper' +require "spec_helper" describe NMatrix do it "creates a matrix with the new constructor" do - n = NMatrix.new([2,2], [0,1,2,3], dtype: :int64) - expect(n.shape).to eq([2,2]) - expect(n.entries).to eq([0,1,2,3]) + n = NMatrix.new([2, 2], [0, 1, 2, 3], dtype: :int64) + expect(n.shape).to eq([2, 2]) + expect(n.entries).to eq([0, 1, 2, 3]) expect(n.dtype).to eq(:int64) end it "adequately requires information to access a single entry of a dense matrix" do - n = NMatrix.new(:dense, 4, [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], :float64) - expect(n[0,0]).to eq(0) + n = NMatrix.new(:dense, 4, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], :float64) + expect(n[0, 0]).to eq(0) expect { n[0] }.to raise_error(ArgumentError) end it "calculates exact determinants on small dense matrices" do - expect(NMatrix.new(2, [1,2,3,4], stype: :dense, dtype: :int64).det_exact).to eq(-2) - expect(NMatrix.new(3, [1,2,3,0,5,6,7,8,0], stype: :dense, dtype: :int64) + expect(NMatrix.new(2, [1, 2, 3, 4], stype: :dense, dtype: :int64).det_exact).to eq(-2) + expect(NMatrix.new(3, [1, 2, 3, 0, 5, 6, 7, 8, 0], stype: :dense, dtype: :int64) .det_exact).to eq(-69) end it "calculates exact determinants on small yale square matrices" do - expect(NMatrix.new(2, [1,2,3,4], stype: :yale, dtype: :int64).det_exact).to eq(-2) - expect(NMatrix.new(3, [1,2,3,0,5,6,7,8,0], stype: :yale, dtype: :int64) + expect(NMatrix.new(2, [1, 2, 3, 4], stype: :yale, dtype: :int64).det_exact).to eq(-2) + expect(NMatrix.new(3, [1, 2, 3, 0, 5, 6, 7, 8, 0], stype: :yale, dtype: :int64) .det_exact).to eq(-69) end it "calculates exact determinants on small list square matrices" do - expect(NMatrix.new(2, [1,2,3,4], stype: :list, dtype: :int64).det_exact).to eq(-2) - expect(NMatrix.new(3, [1,2,3,0,5,6,7,8,0], stype: :list, dtype: :int64) + expect(NMatrix.new(2, [1, 2, 3, 4], stype: :list, dtype: :int64).det_exact).to eq(-2) + expect(NMatrix.new(3, [1, 2, 3, 0, 5, 6, 7, 8, 0], stype: :list, dtype: :int64) .det_exact).to eq(-69) end it "calculates inverse exact determinants on small dense matrices" do pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new(3, [1,2,3,0,1,4,5,6,0], stype: :dense, dtype: :int64) + a = NMatrix.new(3, [1, 2, 3, 0, 1, 4, 5, 6, 0], stype: :dense, dtype: :int64) inversed = a.method(:__inverse_exact__).call(a.clone, 3, 3) - b = NMatrix.new(3, [-24,18,5,20,-15,-4,-5,4,1], stype: :dense, dtype: :int64) + b = NMatrix.new(3, [-24, 18, 5, 20, -15, -4, -5, 4, 1], stype: :dense, dtype: :int64) expect(inversed).to eq(b) - c = NMatrix.new(3, [1,0,3,0,0,1,0,6,0], stype: :dense, dtype: :int64) + c = NMatrix.new(3, [1, 0, 3, 0, 0, 1, 0, 6, 0], stype: :dense, dtype: :int64) inversed = c.method(:__inverse_exact__).call(c.clone, 3, 3) - d = NMatrix.new(3, [1,-3,0,0,0,0,0,1,0], stype: :dense, dtype: :int64) + d = NMatrix.new(3, [1, -3, 0, 0, 0, 0, 0, 1, 0], stype: :dense, dtype: :int64) expect(inversed).to eq(d) - e = NMatrix.new(2, [3,1,2,1], stype: :dense, dtype: :int64) + e = NMatrix.new(2, [3, 1, 2, 1], stype: :dense, dtype: :int64) inversed = e.method(:__inverse_exact__).call(e.clone, 2, 2) - f = NMatrix.new(2, [1,-1,-2,3], stype: :dense, dtype: :int64) + f = NMatrix.new(2, [1, -1, -2, 3], stype: :dense, dtype: :int64) expect(inversed).to eq(f) end it "calculates inverse exact determinants on small yale matrices" do pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new(3, [1,2,3,0,1,4,5,6,0], stype: :yale, dtype: :int64) + a = NMatrix.new(3, [1, 2, 3, 0, 1, 4, 5, 6, 0], stype: :yale, dtype: :int64) inversed = a.method(:__inverse_exact__).call(a.clone, 3, 3) - b = NMatrix.new(3, [-24,18,5,20,-15,-4,-5,4,1], stype: :yale, dtype: :int64) + b = NMatrix.new(3, [-24, 18, 5, 20, -15, -4, -5, 4, 1], stype: :yale, dtype: :int64) expect(inversed).to eq(b) - c = NMatrix.new(3, [1,0,3,0,0,1,0,6,0], stype: :yale, dtype: :int64) + c = NMatrix.new(3, [1, 0, 3, 0, 0, 1, 0, 6, 0], stype: :yale, dtype: :int64) inversed = c.method(:__inverse_exact__).call(c.clone, 3, 3) - d = NMatrix.new(3, [1,-3,0,0,0,0,0,1,0], stype: :yale, dtype: :int64) + d = NMatrix.new(3, [1, -3, 0, 0, 0, 0, 0, 1, 0], stype: :yale, dtype: :int64) expect(inversed).to eq(d) - e = NMatrix.new(2, [3,1,2,1], stype: :yale, dtype: :int64) + e = NMatrix.new(2, [3, 1, 2, 1], stype: :yale, dtype: :int64) inversed = e.method(:__inverse_exact__).call(e.clone, 2, 2) - f = NMatrix.new(2, [1,-1,-2,3], stype: :yale, dtype: :int64) + f = NMatrix.new(2, [1, -1, -2, 3], stype: :yale, dtype: :int64) expect(inversed).to eq(f) end it "calculates inverse exact determinants on small list matrices" do pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new(3, [1,2,3,0,1,4,5,6,0], stype: :list, dtype: :int64) + a = NMatrix.new(3, [1, 2, 3, 0, 1, 4, 5, 6, 0], stype: :list, dtype: :int64) inversed = a.method(:__inverse_exact__).call(a.clone, 3, 3) - b = NMatrix.new(3, [-24,18,5,20,-15,-4,-5,4,1], stype: :list, dtype: :int64) + b = NMatrix.new(3, [-24, 18, 5, 20, -15, -4, -5, 4, 1], stype: :list, dtype: :int64) expect(inversed).to eq(b) - c = NMatrix.new(2, [3,1,2,1], stype: :list, dtype: :int64) + c = NMatrix.new(2, [3, 1, 2, 1], stype: :list, dtype: :int64) inversed = c.method(:__inverse_exact__).call(c.clone, 2, 2) - d = NMatrix.new(2, [1,-1,-2,3], stype: :list, dtype: :int64) + d = NMatrix.new(2, [1, -1, -2, 3], stype: :list, dtype: :int64) expect(inversed).to eq(d) end it "calculates determinants" do - expect(NMatrix.new(3, [-2,2,3,-1,1,3,2,0,-1], stype: :dense, dtype: :int64).det).to eq(6) + expect(NMatrix.new(3, [-2, 2, 3, -1, 1, 3, 2, 0, -1], stype: :dense, dtype: :int64).det).to eq(6) end it "allows casting to Ruby objects" do - m = NMatrix.new([3,3], [0,0,1,0,2,0,3,4,5], dtype: :int64, stype: :dense) + m = NMatrix.new([3, 3], [0, 0, 1, 0, 2, 0, 3, 4, 5], dtype: :int64, stype: :dense) n = m.cast(:dense, :object) expect(n).to eq(m) end it "allows casting from Ruby objects" do pending("not yet implemented for NMatrix-JRuby") if jruby? - m = NMatrix.new(:dense, [3,3], [0,0,1,0,2,0,3,4,5], :object) + m = NMatrix.new(:dense, [3, 3], [0, 0, 1, 0, 2, 0, 3, 4, 5], :object) n = m.cast(:dense, :int64) expect(m).to eq(n) end it "allows stype casting of a dim 2 matrix between dense, sparse, and list (different dtypes)" do - m = NMatrix.new(:dense, [3,3], [0,0,1,0,2,0,3,4,5], :int64). - cast(:yale, :int32). - cast(:dense, :float64). - cast(:list, :object). - cast(:dense, :int16). - cast(:list, :int32). - cast(:yale, :int64) #. - #cast(:list, :int32). - #cast(:dense, :int16) - #m.should.equal?(original) + m = NMatrix.new(:dense, [3, 3], [0, 0, 1, 0, 2, 0, 3, 4, 5], :int64) + .cast(:yale, :int32) + .cast(:dense, :float64) + .cast(:list, :object) + .cast(:dense, :int16) + .cast(:list, :int32) + .cast(:yale, :int64) # . + # cast(:list, :int32). + # cast(:dense, :int16) + # m.should.equal?(original) # For some reason this causes some weird garbage collector problems when we uncomment these. The above lines won't # work at all in IRB, but work fine when run in a regular Ruby session. end it "fills dense Ruby object matrix with nil" do - n = NMatrix.new([4,3], dtype: :object) + n = NMatrix.new([4, 3], dtype: :object) pending("not yet implemented for object dtype for NMatrix-JRuby") if jruby? - expect(n[0,0]).to eq(nil) + expect(n[0, 0]).to eq(nil) end it "fills dense with individual assignments" do - n = NMatrix.new([4,3], dtype: :float64) - n[0,0] = 14.0 - n[0,1] = 9.0 - n[0,2] = 3.0 - n[1,0] = 2.0 - n[1,1] = 11.0 - n[1,2] = 15.0 - n[2,0] = 0.0 - n[2,1] = 12.0 - n[2,2] = 17.0 - n[3,0] = 5.0 - n[3,1] = 2.0 - n[3,2] = 3.0 - - expect(n[0,0]).to eq(14.0) - expect(n[0,1]).to eq(9.0) - expect(n[0,2]).to eq(3.0) - expect(n[1,0]).to eq(2.0) - expect(n[1,1]).to eq(11.0) - expect(n[1,2]).to eq(15.0) - expect(n[2,0]).to eq(0.0) - expect(n[2,1]).to eq(12.0) - expect(n[2,2]).to eq(17.0) - expect(n[3,0]).to eq(5.0) - expect(n[3,1]).to eq(2.0) - expect(n[3,2]).to eq(3.0) + n = NMatrix.new([4, 3], dtype: :float64) + n[0, 0] = 14.0 + n[0, 1] = 9.0 + n[0, 2] = 3.0 + n[1, 0] = 2.0 + n[1, 1] = 11.0 + n[1, 2] = 15.0 + n[2, 0] = 0.0 + n[2, 1] = 12.0 + n[2, 2] = 17.0 + n[3, 0] = 5.0 + n[3, 1] = 2.0 + n[3, 2] = 3.0 + + expect(n[0, 0]).to eq(14.0) + expect(n[0, 1]).to eq(9.0) + expect(n[0, 2]).to eq(3.0) + expect(n[1, 0]).to eq(2.0) + expect(n[1, 1]).to eq(11.0) + expect(n[1, 2]).to eq(15.0) + expect(n[2, 0]).to eq(0.0) + expect(n[2, 1]).to eq(12.0) + expect(n[2, 2]).to eq(17.0) + expect(n[3, 0]).to eq(5.0) + expect(n[3, 1]).to eq(2.0) + expect(n[3, 2]).to eq(3.0) end it "fills dense with a single mass assignment" do - n = NMatrix.new([4,3], [14.0, 9.0, 3.0, 2.0, 11.0, 15.0, 0.0, 12.0, 17.0, 5.0, 2.0, 3.0]) - - expect(n[0,0]).to eq(14.0) - expect(n[0,1]).to eq(9.0) - expect(n[0,2]).to eq(3.0) - expect(n[1,0]).to eq(2.0) - expect(n[1,1]).to eq(11.0) - expect(n[1,2]).to eq(15.0) - expect(n[2,0]).to eq(0.0) - expect(n[2,1]).to eq(12.0) - expect(n[2,2]).to eq(17.0) - expect(n[3,0]).to eq(5.0) - expect(n[3,1]).to eq(2.0) - expect(n[3,2]).to eq(3.0) + n = NMatrix.new([4, 3], [14.0, 9.0, 3.0, 2.0, 11.0, 15.0, 0.0, 12.0, 17.0, 5.0, 2.0, 3.0]) + + expect(n[0, 0]).to eq(14.0) + expect(n[0, 1]).to eq(9.0) + expect(n[0, 2]).to eq(3.0) + expect(n[1, 0]).to eq(2.0) + expect(n[1, 1]).to eq(11.0) + expect(n[1, 2]).to eq(15.0) + expect(n[2, 0]).to eq(0.0) + expect(n[2, 1]).to eq(12.0) + expect(n[2, 2]).to eq(17.0) + expect(n[3, 0]).to eq(5.0) + expect(n[3, 1]).to eq(2.0) + expect(n[3, 2]).to eq(3.0) end it "fills dense with a single mass assignment, with dtype specified" do - m = NMatrix.new([4,3], [14.0, 9.0, 3.0, 2.0, 11.0, 15.0, 0.0, 12.0, 17.0, 5.0, 2.0, 3.0], dtype: :float32) - - expect(m[0,0]).to eq(14.0) - expect(m[0,1]).to eq(9.0) - expect(m[0,2]).to eq(3.0) - expect(m[1,0]).to eq(2.0) - expect(m[1,1]).to eq(11.0) - expect(m[1,2]).to eq(15.0) - expect(m[2,0]).to eq(0.0) - expect(m[2,1]).to eq(12.0) - expect(m[2,2]).to eq(17.0) - expect(m[3,0]).to eq(5.0) - expect(m[3,1]).to eq(2.0) - expect(m[3,2]).to eq(3.0) + m = NMatrix.new([4, 3], [14.0, 9.0, 3.0, 2.0, 11.0, 15.0, 0.0, 12.0, 17.0, 5.0, 2.0, 3.0], dtype: :float32) + + expect(m[0, 0]).to eq(14.0) + expect(m[0, 1]).to eq(9.0) + expect(m[0, 2]).to eq(3.0) + expect(m[1, 0]).to eq(2.0) + expect(m[1, 1]).to eq(11.0) + expect(m[1, 2]).to eq(15.0) + expect(m[2, 0]).to eq(0.0) + expect(m[2, 1]).to eq(12.0) + expect(m[2, 2]).to eq(17.0) + expect(m[3, 0]).to eq(5.0) + expect(m[3, 1]).to eq(2.0) + expect(m[3, 2]).to eq(3.0) end it "dense handles missing initialization value" do @@ -222,44 +222,44 @@ [:dense, :list, :yale].each do |storage_type| context storage_type do - it "can be duplicated" do - n = NMatrix.new([2,3], 1.1, stype: storage_type, dtype: :float64) + it "can be duplicated" do + n = NMatrix.new([2, 3], 1.1, stype: storage_type, dtype: :float64) # FIXME - pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? #and storage_type != :dense + pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? # and storage_type != :dense expect(n.stype).to eq(storage_type) - n[0,0] = 0.0 - n[0,1] = 0.1 - n[1,0] = 1.0 + n[0, 0] = 0.0 + n[0, 1] = 0.1 + n[1, 0] = 1.0 m = n.dup expect(m.shape).to eq(n.shape) expect(m.dim).to eq(n.dim) expect(m.object_id).not_to eq(n.object_id) expect(m.stype).to eq(storage_type) - expect(m[0,0]).to eq(n[0,0]) - m[0,0] = 3.0 - expect(m[0,0]).not_to eq(n[0,0]) + expect(m[0, 0]).to eq(n[0, 0]) + m[0, 0] = 3.0 + expect(m[0, 0]).not_to eq(n[0, 0]) end it "enforces shape boundaries" do - expect { NMatrix.new([1,10], 0, dtype: :int8, stype: storage_type, default: 0)[1,0] }.to raise_error(RangeError) - expect { NMatrix.new([1,10], 0, dtype: :int8, stype: storage_type, default: 0)[0,10] }.to raise_error(RangeError) + expect { NMatrix.new([1, 10], 0, dtype: :int8, stype: storage_type, default: 0)[1, 0] }.to raise_error(RangeError) + expect { NMatrix.new([1, 10], 0, dtype: :int8, stype: storage_type, default: 0)[0, 10] }.to raise_error(RangeError) end it "sets and gets" do n = NMatrix.new(2, 0, stype: storage_type, dtype: :int8) - n[0,1] = 1 - expect(n[0,0]).to eq(0) - expect(n[1,0]).to eq(0) - expect(n[0,1]).to eq(1) - expect(n[1,1]).to eq(0) + n[0, 1] = 1 + expect(n[0, 0]).to eq(0) + expect(n[1, 0]).to eq(0) + expect(n[0, 1]).to eq(1) + expect(n[1, 1]).to eq(0) end it "sets and gets references" do n = NMatrix.new(2, stype: storage_type, dtype: :int8, default: 0) - expect(n[0,1] = 1).to eq(1) - expect(n[0,1]).to eq(1) + expect(n[0, 1] = 1).to eq(1) + expect(n[0, 1]).to eq(1) end # Tests Ruby object versus any C dtype (in this case we use :int64) @@ -269,13 +269,13 @@ it "allows iteration of matrices" do n = nil if storage_type == :dense - n = NMatrix.new(:dense, [3,3], [1,2,3,4,5,6,7,8,9], dtype) + n = NMatrix.new(:dense, [3, 3], [1, 2, 3, 4, 5, 6, 7, 8, 9], dtype) else - n = NMatrix.new([3,4], 0, stype: storage_type, dtype: dtype) - n[0,0] = 1 - n[0,1] = 2 - n[2,3] = 4 - n[2,0] = 3 + n = NMatrix.new([3, 4], 0, stype: storage_type, dtype: dtype) + n[0, 0] = 1 + n[0, 1] = 2 + n[2, 3] = 4 + n[2, 0] = 3 end ary = [] @@ -284,45 +284,45 @@ end if storage_type == :dense - expect(ary).to eq([1,2,3,4,5,6,7,8,9]) + expect(ary).to eq([1, 2, 3, 4, 5, 6, 7, 8, 9]) else - expect(ary).to eq([1,2,0,0,0,0,0,0,3,0,0,4]) + expect(ary).to eq([1, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 4]) end end it "allows storage-based iteration of matrices" do - pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? and storage_type != :dense + pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? && (storage_type != :dense) STDERR.puts storage_type.inspect STDERR.puts dtype.inspect - n = NMatrix.new([3,3], 0, stype: storage_type, dtype: dtype) - n[0,0] = 1 - n[0,1] = 2 - n[2,0] = 5 if storage_type == :yale - n[2,1] = 4 - n[2,2] = 3 + n = NMatrix.new([3, 3], 0, stype: storage_type, dtype: dtype) + n[0, 0] = 1 + n[0, 1] = 2 + n[2, 0] = 5 if storage_type == :yale + n[2, 1] = 4 + n[2, 2] = 3 values = [] is = [] js = [] - n.each_stored_with_indices do |v,i,j| + n.each_stored_with_indices do |v, i, j| values << v is << i js << j end if storage_type == :yale - expect(is).to eq([0,1,2,0,2,2]) - expect(js).to eq([0,1,2,1,0,1]) - expect(values).to eq([1,0,3,2,5,4]) + expect(is).to eq([0, 1, 2, 0, 2, 2]) + expect(js).to eq([0, 1, 2, 1, 0, 1]) + expect(values).to eq([1, 0, 3, 2, 5, 4]) elsif storage_type == :list - expect(values).to eq([1,2,4,3]) - expect(is).to eq([0,0,2,2]) - expect(js).to eq([0,1,1,2]) + expect(values).to eq([1, 2, 4, 3]) + expect(is).to eq([0, 0, 2, 2]) + expect(js).to eq([0, 1, 1, 2]) elsif storage_type == :dense - expect(values).to eq([1,2,0,0,0,0,0,4,3]) - expect(is).to eq([0,0,0,1,1,1,2,2,2]) - expect(js).to eq([0,1,2,0,1,2,0,1,2]) + expect(values).to eq([1, 2, 0, 0, 0, 0, 0, 4, 3]) + expect(is).to eq([0, 0, 0, 1, 1, 1, 2, 2, 2]) + expect(js).to eq([0, 1, 2, 0, 1, 2, 0, 1, 2]) end end end @@ -330,61 +330,61 @@ end # dense and list, not yale - context "(storage: #{storage_type})" do - it "gets default value" do - pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? - expect(NMatrix.new(3, 0, stype: storage_type)[1,1]).to eq(0) - expect(NMatrix.new(3, 0.1, stype: storage_type)[1,1]).to eq(0.1) - expect(NMatrix.new(3, 1, stype: storage_type)[1,1]).to eq(1) - - end - it "returns shape and dim" do - expect(NMatrix.new([3,2,8], 0, stype: storage_type).shape).to eq([3,2,8]) - expect(NMatrix.new([3,2,8], 0, stype: storage_type).dim).to eq(3) - end + unless storage_type == :yale + context "(storage: #{storage_type})" do + it "gets default value" do + pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? + expect(NMatrix.new(3, 0, stype: storage_type)[1, 1]).to eq(0) + expect(NMatrix.new(3, 0.1, stype: storage_type)[1, 1]).to eq(0.1) + expect(NMatrix.new(3, 1, stype: storage_type)[1, 1]).to eq(1) + end + it "returns shape and dim" do + expect(NMatrix.new([3, 2, 8], 0, stype: storage_type).shape).to eq([3, 2, 8]) + expect(NMatrix.new([3, 2, 8], 0, stype: storage_type).dim).to eq(3) + end - it "returns number of rows and columns" do - expect(NMatrix.new([7, 4], 3, stype: storage_type).rows).to eq(7) - expect(NMatrix.new([7, 4], 3, stype: storage_type).cols).to eq(4) + it "returns number of rows and columns" do + expect(NMatrix.new([7, 4], 3, stype: storage_type).rows).to eq(7) + expect(NMatrix.new([7, 4], 3, stype: storage_type).cols).to eq(4) + end end - end unless storage_type == :yale + end end - it "handles dense construction" do - expect(NMatrix.new(3,0)[1,1]).to eq(0) - expect(lambda { NMatrix.new(3,dtype: :int8)[1,1] }).to_not raise_error + expect(NMatrix.new(3, 0)[1, 1]).to eq(0) + expect(lambda { NMatrix.new(3, dtype: :int8)[1, 1] }).to_not raise_error end it "converts from list to yale properly" do m = NMatrix.new(3, 0, stype: :list) - m[0,2] = 333 - m[2,2] = 777 + m[0, 2] = 333 + m[2, 2] = 777 n = m.cast(:yale, :int32) - #puts n.capacity - #n.extend NMatrix::YaleFunctions - #puts n.yale_ija.inspect - #puts n.yale_a.inspect - - expect(n[0,0]).to eq(0) - expect(n[0,1]).to eq(0) - expect(n[0,2]).to eq(333) - expect(n[1,0]).to eq(0) - expect(n[1,1]).to eq(0) - expect(n[1,2]).to eq(0) - expect(n[2,0]).to eq(0) - expect(n[2,1]).to eq(0) - expect(n[2,2]).to eq(777) + # puts n.capacity + # n.extend NMatrix::YaleFunctions + # puts n.yale_ija.inspect + # puts n.yale_a.inspect + + expect(n[0, 0]).to eq(0) + expect(n[0, 1]).to eq(0) + expect(n[0, 2]).to eq(333) + expect(n[1, 0]).to eq(0) + expect(n[1, 1]).to eq(0) + expect(n[1, 2]).to eq(0) + expect(n[2, 0]).to eq(0) + expect(n[2, 1]).to eq(0) + expect(n[2, 2]).to eq(777) end it "should return an enumerator when each is called without a block" do a = NMatrix.new(2, 1) - b = NMatrix.new(2, [-1,0,1,0]) + b = NMatrix.new(2, [-1, 0, 1, 0]) enums = [a.each, b.each] begin atans = [] - atans << Math.atan2(*enums.map(&:next)) while true + loop { atans << Math.atan2(*enums.map(&:next)) } rescue StopIteration end end @@ -401,7 +401,7 @@ it "should return the matrix being iterated over when each_stored_with_indices is called with a block" do # FIXME pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new(2,1) + a = NMatrix.new(2, 1) val = (a.each_stored_with_indices { }) expect(val).to eq(a) end @@ -411,14 +411,14 @@ context storage_type do it "should return the matrix being iterated over when each_stored_with_indices is called with a block" do pending("not yet implemented for Complex dtype for NMatrix-JRuby") if jruby? - n = NMatrix.new([2,3], 1.1, stype: storage_type, dtype: :float64, default: 0) + n = NMatrix.new([2, 3], 1.1, stype: storage_type, dtype: :float64, default: 0) val = (n.each_stored_with_indices { }) expect(val).to eq(n) end it "should return an enumerator when each_stored_with_indices is called without a block" do pending("not yet implemented for Complex dtype for NMatrix-JRuby") if jruby? - n = NMatrix.new([2,3], 1.1, stype: storage_type, dtype: :float64, default: 0) + n = NMatrix.new([2, 3], 1.1, stype: storage_type, dtype: :float64, default: 0) val = n.each_stored_with_indices expect(val).to be_a Enumerator end @@ -431,50 +431,49 @@ end end - -describe 'NMatrix' do +describe "NMatrix" do context "#upper_triangle" do it "should create a copy with the lower corner set to zero" do - n = NMatrix.seq(4)+1 - expect(n.upper_triangle).to eq(NMatrix.new(4, [1,2,3,4,0,6,7,8,0,0,11,12,0,0,0,16])) - expect(n.upper_triangle(2)).to eq(NMatrix.new(4, [1,2,3,4,5,6,7,8,9,10,11,12,0,14,15,16])) + n = NMatrix.seq(4) + 1 + expect(n.upper_triangle).to eq(NMatrix.new(4, [1, 2, 3, 4, 0, 6, 7, 8, 0, 0, 11, 12, 0, 0, 0, 16])) + expect(n.upper_triangle(2)).to eq(NMatrix.new(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 14, 15, 16])) end end context "#lower_triangle" do it "should create a copy with the lower corner set to zero" do - n = NMatrix.seq(4)+1 - expect(n.lower_triangle).to eq(NMatrix.new(4, [1,0,0,0,5,6,0,0,9,10,11,0,13,14,15,16])) - expect(n.lower_triangle(2)).to eq(NMatrix.new(4, [1,2,3,0,5,6,7,8,9,10,11,12,13,14,15,16])) + n = NMatrix.seq(4) + 1 + expect(n.lower_triangle).to eq(NMatrix.new(4, [1, 0, 0, 0, 5, 6, 0, 0, 9, 10, 11, 0, 13, 14, 15, 16])) + expect(n.lower_triangle(2)).to eq(NMatrix.new(4, [1, 2, 3, 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])) end end context "#upper_triangle!" do it "should create a copy with the lower corner set to zero" do - n = NMatrix.seq(4)+1 - expect(n.upper_triangle!).to eq(NMatrix.new(4, [1,2,3,4,0,6,7,8,0,0,11,12,0,0,0,16])) - n = NMatrix.seq(4)+1 - expect(n.upper_triangle!(2)).to eq(NMatrix.new(4, [1,2,3,4,5,6,7,8,9,10,11,12,0,14,15,16])) + n = NMatrix.seq(4) + 1 + expect(n.upper_triangle!).to eq(NMatrix.new(4, [1, 2, 3, 4, 0, 6, 7, 8, 0, 0, 11, 12, 0, 0, 0, 16])) + n = NMatrix.seq(4) + 1 + expect(n.upper_triangle!(2)).to eq(NMatrix.new(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 14, 15, 16])) end end context "#lower_triangle!" do it "should create a copy with the lower corner set to zero" do - n = NMatrix.seq(4)+1 - expect(n.lower_triangle!).to eq(NMatrix.new(4, [1,0,0,0,5,6,0,0,9,10,11,0,13,14,15,16])) - n = NMatrix.seq(4)+1 - expect(n.lower_triangle!(2)).to eq(NMatrix.new(4, [1,2,3,0,5,6,7,8,9,10,11,12,13,14,15,16])) + n = NMatrix.seq(4) + 1 + expect(n.lower_triangle!).to eq(NMatrix.new(4, [1, 0, 0, 0, 5, 6, 0, 0, 9, 10, 11, 0, 13, 14, 15, 16])) + n = NMatrix.seq(4) + 1 + expect(n.lower_triangle!(2)).to eq(NMatrix.new(4, [1, 2, 3, 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])) end end context "#rank" do it "should get the rank of a 2-dimensional matrix" do - n = NMatrix.seq([2,3]) - expect(n.rank(0, 0)).to eq(N[[0,1,2]]) + n = NMatrix.seq([2, 3]) + expect(n.rank(0, 0)).to eq(N[[0, 1, 2]]) end it "should raise an error when the rank is out of bounds" do - n = NMatrix.seq([2,3]) + n = NMatrix.seq([2, 3]) expect { n.rank(2, 0) }.to raise_error(RangeError) end end @@ -483,47 +482,47 @@ it "should change the shape of a matrix without the contents changing" do # FIXME pending("not yet implemented for NMatrix-JRuby") if jruby? - n = NMatrix.seq(4)+1 - expect(n.reshape([8,2]).to_flat_array).to eq(n.to_flat_array) + n = NMatrix.seq(4) + 1 + expect(n.reshape([8, 2]).to_flat_array).to eq(n.to_flat_array) end it "should permit a change of dimensionality" do # FIXME pending("not yet implemented for NMatrix-JRuby") if jruby? - n = NMatrix.seq(4)+1 - expect(n.reshape([8,1,2]).to_flat_array).to eq(n.to_flat_array) + n = NMatrix.seq(4) + 1 + expect(n.reshape([8, 1, 2]).to_flat_array).to eq(n.to_flat_array) end it "should prevent a resize" do - n = NMatrix.seq(4)+1 - expect { n.reshape([5,2]) }.to raise_error(ArgumentError) + n = NMatrix.seq(4) + 1 + expect { n.reshape([5, 2]) }.to raise_error(ArgumentError) end it "should do the reshape operation in place" do - n = NMatrix.seq(4)+1 - expect(n.reshape!([8,2]).eql?(n)).to eq(true) # because n itself changes + n = NMatrix.seq(4) + 1 + expect(n.reshape!([8, 2]).eql?(n)).to eq(true) # because n itself changes end it "should do the reshape operation in place, changing dimension" do # FIXME pending("not yet implemented for NMatrix-JRuby") if jruby? n = NMatrix.seq(4) - a = n.reshape!([4,2,2]) - expect(n).to eq(NMatrix.seq([4,2,2])) - expect(a).to eq(NMatrix.seq([4,2,2])) + a = n.reshape!([4, 2, 2]) + expect(n).to eq(NMatrix.seq([4, 2, 2])) + expect(a).to eq(NMatrix.seq([4, 2, 2])) end it "reshape and reshape! must produce same result" do # FIXME pending("not yet implemented for NMatrix-JRuby") if jruby? - n = NMatrix.seq(4)+1 - a = NMatrix.seq(4)+1 - expect(n.reshape!([8,2])==a.reshape(8,2)).to eq(true) # because n itself changes + n = NMatrix.seq(4) + 1 + a = NMatrix.seq(4) + 1 + expect(n.reshape!([8, 2]) == a.reshape(8, 2)).to eq(true) # because n itself changes end it "should prevent a resize in place" do - n = NMatrix.seq(4)+1 - expect { n.reshape!([5,2]) }.to raise_error(ArgumentError) + n = NMatrix.seq(4) + 1 + expect { n.reshape!([5, 2]) }.to raise_error(ArgumentError) end end @@ -532,7 +531,7 @@ context(stype) do it "should transpose a #{stype} matrix (2-dimensional)" do n = NMatrix.seq(4, stype: stype) - expect(n.transpose.to_a.flatten).to eq([0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15]) + expect(n.transpose.to_a.flatten).to eq([0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15]) end end end @@ -540,23 +539,23 @@ [:dense, :list].each do |stype| context(stype) do it "should transpose a #{stype} matrix (3-dimensional)" do - n = NMatrix.new([4,4,1], [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], stype: stype) - expect(n.transpose([2,1,0]).to_flat_array).to eq([0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15]) - expect(n.transpose([1,0,2]).to_flat_array).to eq([0,4,8,12,1,5,9,13,2,6,10,14,3,7,11,15]) - expect(n.transpose([0,2,1]).to_flat_array).to eq(n.to_flat_array) # for dense, make this reshape! + n = NMatrix.new([4, 4, 1], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], stype: stype) + expect(n.transpose([2, 1, 0]).to_flat_array).to eq([0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15]) + expect(n.transpose([1, 0, 2]).to_flat_array).to eq([0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15]) + expect(n.transpose([0, 2, 1]).to_flat_array).to eq(n.to_flat_array) # for dense, make this reshape! end end it "should just copy a 1-dimensional #{stype} matrix" do - n = NMatrix.new([3], [1,2,3], stype: stype) + n = NMatrix.new([3], [1, 2, 3], stype: stype) expect(n.transpose).to eq n expect(n.transpose).not_to be n end it "should check permute argument if supplied for #{stype} matrix" do - n = NMatrix.new([2,2], [1,2,3,4], stype: stype) - expect{n.transpose *4 }.to raise_error(ArgumentError) - expect{n.transpose [1,1,2] }.to raise_error(ArgumentError) + n = NMatrix.new([2, 2], [1, 2, 3, 4], stype: stype) + expect {n.transpose [4] }.to raise_error(ArgumentError) + expect {n.transpose [1, 1, 2] }.to raise_error(ArgumentError) end end end @@ -567,8 +566,8 @@ it "should work like vector product on a #{stype} (1-dimensional)" do # FIXME pending("not yet implemented for NMatrix-JRuby") if jruby? - m = NMatrix.new([3], [1,2,3], stype: stype) - expect(m.dot(m)).to eq (NMatrix.new([1],[14])) + m = NMatrix.new([3], [1, 2, 3], stype: stype) + expect(m.dot(m)).to eq NMatrix.new([1], [14]) end end end @@ -579,34 +578,37 @@ [:dense, :list, :yale].each do |right| context ("#{left}?#{right}") do it "tests equality of two equal matrices" do - n = NMatrix.new([3,4], [0,0,1,2,0,0,3,4,0,0,0,0], stype: left) - m = NMatrix.new([3,4], [0,0,1,2,0,0,3,4,0,0,0,0], stype: right) + n = NMatrix.new([3, 4], [0, 0, 1, 2, 0, 0, 3, 4, 0, 0, 0, 0], stype: left) + m = NMatrix.new([3, 4], [0, 0, 1, 2, 0, 0, 3, 4, 0, 0, 0, 0], stype: right) - expect(n==m).to eq(true) + expect(n == m).to eq(true) end it "tests equality of two unequal matrices" do - n = NMatrix.new([3,4], [0,0,1,2,0,0,3,4,0,0,0,1], stype: left) - m = NMatrix.new([3,4], [0,0,1,2,0,0,3,4,0,0,0,0], stype: right) + n = NMatrix.new([3, 4], [0, 0, 1, 2, 0, 0, 3, 4, 0, 0, 0, 1], stype: left) + m = NMatrix.new([3, 4], [0, 0, 1, 2, 0, 0, 3, 4, 0, 0, 0, 0], stype: right) - expect(n==m).to eq(false) + expect(n == m).to eq(false) end it "tests equality of matrices with different shapes" do - n = NMatrix.new([2,2], [1,2, 3,4], stype: left) - m = NMatrix.new([2,3], [1,2, 3,4, 5,6], stype: right) - x = NMatrix.new([1,4], [1,2, 3,4], stype: right) + n = NMatrix.new([2, 2], [1, 2, 3, 4], stype: left) + m = NMatrix.new([2, 3], [1, 2, 3, 4, 5, 6], stype: right) + x = NMatrix.new([1, 4], [1, 2, 3, 4], stype: right) - expect{n==m}.to raise_error(ShapeError) - expect{n==x}.to raise_error(ShapeError) + expect {n == m}.to raise_error(ShapeError) + expect {n == x}.to raise_error(ShapeError) end - it "tests equality of matrices with different dimension" do - n = NMatrix.new([2,1], [1,2], stype: left) - m = NMatrix.new([2], [1,2], stype: right) + # yale must have dimension 2 + if left != :yale && right != :yale + it "tests equality of matrices with different dimension" do + n = NMatrix.new([2, 1], [1, 2], stype: left) + m = NMatrix.new([2], [1, 2], stype: right) - expect{n==m}.to raise_error(ShapeError) - end if left != :yale && right != :yale # yale must have dimension 2 + expect {n == m}.to raise_error(ShapeError) + end + end end end end @@ -614,27 +616,27 @@ context "#concat" do it "should default to horizontal concatenation" do - n = NMatrix.new([1,3], [1,2,3]) - expect(n.concat(n)).to eq(NMatrix.new([1,6], [1,2,3,1,2,3])) + n = NMatrix.new([1, 3], [1, 2, 3]) + expect(n.concat(n)).to eq(NMatrix.new([1, 6], [1, 2, 3, 1, 2, 3])) end it "should permit vertical concatenation" do - n = NMatrix.new([1,3], [1,2,3]) - expect(n.vconcat(n)).to eq(NMatrix.new([2,3], [1,2,3])) + n = NMatrix.new([1, 3], [1, 2, 3]) + expect(n.vconcat(n)).to eq(NMatrix.new([2, 3], [1, 2, 3])) end it "should permit depth concatenation on tensors" do # FIXME pending("not yet implemented for NMatrix-JRuby") if jruby? - n = NMatrix.new([1,3,1], [1,2,3]) - expect(n.dconcat(n)).to eq(NMatrix.new([1,3,2], [1,1,2,2,3,3])) + n = NMatrix.new([1, 3, 1], [1, 2, 3]) + expect(n.dconcat(n)).to eq(NMatrix.new([1, 3, 2], [1, 1, 2, 2, 3, 3])) end it "should work on matrices with different size along concat dim" do n = N[[1, 2, 3], - [4, 5, 6]] + [4, 5, 6]] m = N[[7], - [8]] + [8]] # FIXME pending("not yet implemented for NMatrix-JRuby") if jruby? @@ -644,7 +646,7 @@ it "should work on matrices with different size along concat dim" do n = N[[1, 2, 3], - [4, 5, 6]] + [4, 5, 6]] m = N[[7, 8, 9]] @@ -657,15 +659,15 @@ context "#[]" do it "should return values based on indices" do - n = NMatrix.new([2,5], [1,2,3,4,5,6,7,8,9,0]) - expect(n[1,0]).to eq 6 - expect(n[1,0..3]).to eq NMatrix.new([1,4],[6,7,8,9]) + n = NMatrix.new([2, 5], [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]) + expect(n[1, 0]).to eq 6 + expect(n[1, 0..3]).to eq NMatrix.new([1, 4], [6, 7, 8, 9]) end it "should work for negative indices" do - n = NMatrix.new([1,5], [1,2,3,4,5]) + n = NMatrix.new([1, 5], [1, 2, 3, 4, 5]) expect(n[-1]).to eq(5) - expect(n[0,0..-2]).to eq(NMatrix.new([1,4],[1,2,3,4])) + expect(n[0, 0..-2]).to eq(NMatrix.new([1, 4], [1, 2, 3, 4])) end end @@ -675,18 +677,18 @@ it "should work in-place for complex dtypes" do pending("not yet implemented for list stype") if stype == :list pending("not yet implemented for Complex dtype for NMatrix-JRuby") if jruby? - n = NMatrix.new([2,3], [Complex(2,3)], stype: stype, dtype: :complex128) + n = NMatrix.new([2, 3], [Complex(2, 3)], stype: stype, dtype: :complex128) n.complex_conjugate! - expect(n).to eq(NMatrix.new([2,3], [Complex(2,-3)], stype: stype, dtype: :complex128)) + expect(n).to eq(NMatrix.new([2, 3], [Complex(2, -3)], stype: stype, dtype: :complex128)) end [:object, :int64].each do |dtype| it "should work in-place for non-complex dtypes" do pending("not yet implemented for list stype") if stype == :list pending("not yet implemented for Complex dtype for NMatrix-JRuby") if jruby? - n = NMatrix.new([2,3], 1, stype: stype, dtype: dtype) + n = NMatrix.new([2, 3], 1, stype: stype, dtype: dtype) n.complex_conjugate! - expect(n).to eq(NMatrix.new([2,3], [1], stype: stype, dtype: dtype)) + expect(n).to eq(NMatrix.new([2, 3], [1], stype: stype, dtype: dtype)) end end end @@ -699,16 +701,16 @@ it "should work out-of-place for complex dtypes" do pending("not yet implemented for list stype") if stype == :list pending("not yet implemented for Complex dtype for NMatrix-JRuby") if jruby? - n = NMatrix.new([2,3], [Complex(2,3)], stype: stype, dtype: :complex128) - expect(n.complex_conjugate).to eq(NMatrix.new([2,3], [Complex(2,-3)], stype: stype, dtype: :complex128)) + n = NMatrix.new([2, 3], [Complex(2, 3)], stype: stype, dtype: :complex128) + expect(n.complex_conjugate).to eq(NMatrix.new([2, 3], [Complex(2, -3)], stype: stype, dtype: :complex128)) end [:object, :int64].each do |dtype| it "should work out-of-place for non-complex dtypes" do pending("not yet implemented for list stype") if stype == :list pending("not yet implemented for Complex dtype for NMatrix-JRuby") if jruby? - n = NMatrix.new([2,3], 1, stype: stype, dtype: dtype) - expect(n.complex_conjugate).to eq(NMatrix.new([2,3], [1], stype: stype, dtype: dtype)) + n = NMatrix.new([2, 3], 1, stype: stype, dtype: dtype) + expect(n.complex_conjugate).to eq(NMatrix.new([2, 3], [1], stype: stype, dtype: dtype)) end end end @@ -718,10 +720,10 @@ context "#inject" do it "should sum columns of yale matrix correctly" do n = NMatrix.new([4, 3], stype: :yale, default: 0) - n[0,0] = 1 - n[1,1] = 2 - n[2,2] = 4 - n[3,2] = 8 + n[0, 0] = 1 + n[1, 1] = 2 + n[2, 2] = 4 + n[3, 2] = 8 column_sums = [] n.cols.times do |i| column_sums << n.col(i).inject(:+) @@ -732,41 +734,41 @@ context "#index" do it "returns index of first occurence of an element for a vector" do - n = NMatrix.new([5], [0,22,22,11,11]) + n = NMatrix.new([5], [0, 22, 22, 11, 11]) expect(n.index(22)).to eq([1]) end it "returns index of first occurence of an element for 2-D matrix" do - n = NMatrix.new([3,3], [23,11,23, - 44, 2, 0, - 33, 0, 32]) + n = NMatrix.new([3, 3], [23, 11, 23, + 44, 2, 0, + 33, 0, 32,]) - expect(n.index(0)).to eq([1,2]) + expect(n.index(0)).to eq([1, 2]) end it "returns index of first occerence of an element for N-D matrix" do - n = NMatrix.new([3,3,3], [23,11,23, 44, 2, 0, 33, 0, 32, - 23,11,23, 44, 2, 0, 33, 0, 32, - 23,11,23, 44, 2, 0, 33, 0, 32]) + n = NMatrix.new([3, 3, 3], [23, 11, 23, 44, 2, 0, 33, 0, 32, + 23, 11, 23, 44, 2, 0, 33, 0, 32, + 23, 11, 23, 44, 2, 0, 33, 0, 32,]) - expect(n.index(44)).to eq([0,1,0]) + expect(n.index(44)).to eq([0, 1, 0]) end end context "#last" do it "returns the last element of a 1-dimensional NMatrix" do - n = NMatrix.new([1,4], [1,2,3,4]) + n = NMatrix.new([1, 4], [1, 2, 3, 4]) expect(n.last).to eq(4) end it "returns the last element of a 2-dimensional NMatrix" do - n = NMatrix.new([2,2], [4,8,12,16]) + n = NMatrix.new([2, 2], [4, 8, 12, 16]) expect(n.last).to eq(16) end it "returns the last element of a 3-dimensional NMatrix" do - n = NMatrix.new([2,2,2], [1,2,3,4,5,6,7,8]) + n = NMatrix.new([2, 2, 2], [1, 2, 3, 4, 5, 6, 7, 8]) expect(n.last).to eq(8) end end @@ -774,36 +776,34 @@ context "#diagonal" do ALL_DTYPES.each do |dtype| before do - @square_matrix = NMatrix.new([3,3], [ - 23,11,23, + @square_matrix = NMatrix.new([3, 3], [ + 23, 11, 23, 44, 2, 0, - 33, 0, 32 - ], dtype: dtype - ) + 33, 0, 32, + ], dtype: dtype) - @rect_matrix = NMatrix.new([4,3], [ - 23,11,23, + @rect_matrix = NMatrix.new([4, 3], [ + 23, 11, 23, 44, 2, 0, - 33, 0,32, - 11,22,33 - ], dtype: dtype - ) + 33, 0, 32, + 11, 22, 33, + ], dtype: dtype) end it "returns main diagonal for square matrix" do - expect(@square_matrix.diagonal).to eq(NMatrix.new [3], [23,2,32]) + expect(@square_matrix.diagonal).to eq(NMatrix.new([3], [23, 2, 32])) end it "returns main diagonal for rectangular matrix" do - expect(@rect_matrix.diagonal).to eq(NMatrix.new [3], [23,2,32]) + expect(@rect_matrix.diagonal).to eq(NMatrix.new([3], [23, 2, 32])) end it "returns anti-diagonal for square matrix" do - expect(@square_matrix.diagonal(false)).to eq(NMatrix.new [3], [23,2,33]) + expect(@square_matrix.diagonal(false)).to eq(NMatrix.new([3], [23, 2, 33])) end it "returns anti-diagonal for rectangular matrix" do - expect(@square_matrix.diagonal(false)).to eq(NMatrix.new [3], [23,2,33]) + expect(@square_matrix.diagonal(false)).to eq(NMatrix.new([3], [23, 2, 33])) end end end @@ -814,8 +814,8 @@ end it "checks count argument" do - expect{@sample_matrix.repeat(1, 0)}.to raise_error(ArgumentError) - expect{@sample_matrix.repeat(-2, 0)}.to raise_error(ArgumentError) + expect {@sample_matrix.repeat(1, 0)}.to raise_error(ArgumentError) + expect {@sample_matrix.repeat(-2, 0)}.to raise_error(ArgumentError) end it "returns repeated matrix" do @@ -842,18 +842,20 @@ @expected_for_sparse = [NMatrix.new([1, 3], [1, 2, 3]), NMatrix.new([2, 1], [4, 5])] @expected_for_sparse_ij = [NMatrix.new([3, 1], [1, 2, 3]), NMatrix.new([1, 2], [4, 5])] # FIXME - @expected_3dim = [NMatrix.new([1, 3, 1], [1, 2, 3]).repeat(2, 0).repeat(2, 2), - NMatrix.new([2, 1, 1], [4, 5]).repeat(3, 1).repeat(2, 2), - NMatrix.new([1, 1, 2], [6, 7]).repeat(2, 0).repeat(3, 1)] unless jruby? + unless jruby? + @expected_3dim = [NMatrix.new([1, 3, 1], [1, 2, 3]).repeat(2, 0).repeat(2, 2), + NMatrix.new([2, 1, 1], [4, 5]).repeat(3, 1).repeat(2, 2), + NMatrix.new([1, 1, 2], [6, 7]).repeat(2, 0).repeat(3, 1),] + end @expected_3dim_sparse_ij = [NMatrix.new([3, 1, 1], [1, 2, 3]), NMatrix.new([1, 2, 1], [4, 5]), - NMatrix.new([1, 1, 2], [6, 7])] + NMatrix.new([1, 1, 2], [6, 7]),] end it "checks arrays count" do pending("Not yet implemented for NMatrix JRuby") if jruby? - expect{NMatrix.meshgrid([@x])}.to raise_error(ArgumentError) - expect{NMatrix.meshgrid([])}.to raise_error(ArgumentError) + expect {NMatrix.meshgrid([@x])}.to raise_error(ArgumentError) + expect {NMatrix.meshgrid([])}.to raise_error(ArgumentError) end it "flattens input arrays before use" do @@ -875,7 +877,7 @@ pending("Not yet implemented for NMatrix JRuby") if jruby? expect(NMatrix.meshgrid([@x, @y], indexing: :ij)).to eq(@expected_for_ij) expect(NMatrix.meshgrid([@x, @y], indexing: :xy)).to eq(@expected_result) - expect{NMatrix.meshgrid([@x, @y], indexing: :not_ij_not_xy)}.to raise_error(ArgumentError) + expect {NMatrix.meshgrid([@x, @y], indexing: :not_ij_not_xy)}.to raise_error(ArgumentError) end it "works well with both options set" do diff --git a/spec/01_enum_spec.rb b/spec/01_enum_spec.rb index 9a27822b..a897495c 100644 --- a/spec/01_enum_spec.rb +++ b/spec/01_enum_spec.rb @@ -25,13 +25,13 @@ # Enumerator tests for NMatrix. These should load early, as they # test functionality essential to matrix printing. # -require 'spec_helper' +require "spec_helper" describe "NMatrix enumeration for" do [:dense, :yale, :list].each do |stype| context stype do let(:n) { create_rectangular_matrix(stype) } - let(:m) { n[1..4,1..3] } + let(:m) { n[1..4, 1..3] } if stype == :yale it "should iterate properly along each row of a slice" do @@ -41,16 +41,16 @@ jj = [] m.extend NMatrix::YaleFunctions m.each_row do |row| - row.each_with_indices do |v,i,j| + row.each_with_indices do |v, i, j| vv << v ii << i jj << j end end - expect(vv).to eq([7,8,9, 12,13,0, 0,0,0, 0,17,18]) - expect(ii).to eq([0]*12) - expect(jj).to eq([0,1,2]*4) + expect(vv).to eq([7, 8, 9, 12, 13, 0, 0, 0, 0, 0, 17, 18]) + expect(ii).to eq([0] * 12) + expect(jj).to eq([0, 1, 2] * 4) end it "should iterate along diagonal portion of A array" do @@ -58,13 +58,13 @@ vv = [] ii = [] jj = [] - n.send :__yale_stored_diagonal_each_with_indices__ do |v,i,j| + n.send :__yale_stored_diagonal_each_with_indices__ do |v, i, j| vv << v ii << i jj << j end - expect(vv).to eq([1,7,13,0,19]) - expect(ii).to eq([0,1,2,3,4]) + expect(vv).to eq([1, 7, 13, 0, 19]) + expect(ii).to eq([0, 1, 2, 3, 4]) expect(jj).to eq(ii) end @@ -73,31 +73,31 @@ vv = [] ii = [] jj = [] - n.send :__yale_stored_nondiagonal_each_with_indices__ do |v,i,j| + n.send :__yale_stored_nondiagonal_each_with_indices__ do |v, i, j| vv << v ii << i jj << j end - expect(vv).to eq([2,3,4,5, 6,8,9,10, 11,12,14,15, 16,17,18,20]) - expect(ii).to eq([[0]*4, [1]*4, [2]*4, [4]*4].flatten) - expect(jj).to eq([1,2,3,4, 0,2,3,5, 0,1,4,5, 0,2,3,5]) + expect(vv).to eq([2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 20]) + expect(ii).to eq([[0] * 4, [1] * 4, [2] * 4, [4] * 4].flatten) + expect(jj).to eq([1, 2, 3, 4, 0, 2, 3, 5, 0, 1, 4, 5, 0, 2, 3, 5]) end it "should iterate along a sliced diagonal portion of an A array" do pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? - m = n[0..3,1..3] + m = n[0..3, 1..3] vv = [] ii = [] jj = [] - m.send :__yale_stored_diagonal_each_with_indices__ do |v,i,j| + m.send :__yale_stored_diagonal_each_with_indices__ do |v, i, j| vv << v ii << i jj << j end - expect(vv).to eq([7,13,0]) - expect(ii).to eq([1,2,3]) - expect(jj).to eq([0,1,2]) + expect(vv).to eq([7, 13, 0]) + expect(ii).to eq([1, 2, 3]) + expect(jj).to eq([0, 1, 2]) end it "should iterate along a sliced non-diagonal portion of a sliced A array" do @@ -107,15 +107,15 @@ jj = [] n.extend NMatrix::YaleFunctions m.extend NMatrix::YaleFunctions - m.send :__yale_stored_nondiagonal_each_with_indices__ do |v,i,j| + m.send :__yale_stored_nondiagonal_each_with_indices__ do |v, i, j| vv << v ii << i jj << j end - expect(ii).to eq([0,0, 1, 3,3 ]) - expect(jj).to eq([1,2, 0, 1,2 ]) - expect(vv).to eq([8,9, 12, 17,18]) + expect(ii).to eq([0, 0, 1, 3, 3]) + expect(jj).to eq([1, 2, 0, 1, 2]) + expect(vv).to eq([8, 9, 12, 17, 18]) end it "should visit each stored element of the matrix in order by indices" do @@ -123,15 +123,15 @@ vv = [] ii = [] jj = [] - n.each_ordered_stored_with_indices do |v,i,j| + n.each_ordered_stored_with_indices do |v, i, j| vv << v ii << i jj << j end expect(vv).to eq([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 16, 17, 18, 19, 20]) - expect(ii).to eq([[0]*5, [1]*5, [2]*5, [3]*1, [4]*5].flatten) - expect(jj).to eq([0,1,2,3,4, 0,1,2,3,5, 0,1,2,4,5, 3, 0,2,3,4,5]) + expect(ii).to eq([[0] * 5, [1] * 5, [2] * 5, [3] * 1, [4] * 5].flatten) + expect(jj).to eq([0, 1, 2, 3, 4, 0, 1, 2, 3, 5, 0, 1, 2, 4, 5, 3, 0, 2, 3, 4, 5]) end it "should visit each stored element of the slice in order by indices" do @@ -139,14 +139,14 @@ vv = [] ii = [] jj = [] - m.each_ordered_stored_with_indices do |v,i,j| + m.each_ordered_stored_with_indices do |v, i, j| vv << v ii << i jj << j end - expect(ii).to eq([0,0,0, 1,1, 2, 3,3 ]) - expect(jj).to eq([0,1,2, 0,1, 2, 1,2 ]) - expect(vv).to eq([7,8,9, 12,13, 0, 17,18 ]) + expect(ii).to eq([0, 0, 0, 1, 1, 2, 3, 3]) + expect(jj).to eq([0, 1, 2, 0, 1, 2, 1, 2]) + expect(vv).to eq([7, 8, 9, 12, 13, 0, 17, 18]) end end @@ -154,33 +154,32 @@ vv = [] ii = [] jj = [] - n.each_with_indices do |v,i,j| + n.each_with_indices do |v, i, j| vv << v ii << i jj << j end - expect(vv).to eq([1,2,3,4,5,0,6,7,8,9,0,10,11,12,13,0,14,15,0,0,0,0,0,0,16,0,17,18,19,20]) - expect(ii).to eq([[0]*6, [1]*6, [2]*6, [3]*6, [4]*6].flatten) - expect(jj).to eq([0,1,2,3,4,5]*5) + expect(vv).to eq([1, 2, 3, 4, 5, 0, 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 0, 0, 16, 0, 17, 18, 19, 20]) + expect(ii).to eq([[0] * 6, [1] * 6, [2] * 6, [3] * 6, [4] * 6].flatten) + expect(jj).to eq([0, 1, 2, 3, 4, 5] * 5) end it "should visit each cell in the slice as if dense, making indices available" do vv = [] ii = [] jj = [] - m.each_with_indices do |v,i,j| + m.each_with_indices do |v, i, j| vv << v ii << i jj << j end - expect(jj).to eq([0,1,2]*4) - expect(ii).to eq([[0]*3, [1]*3, [2]*3, [3]*3].flatten) - expect(vv).to eq([7,8,9,12,13,0,0,0,0,0,17,18]) - + expect(jj).to eq([0, 1, 2] * 4) + expect(ii).to eq([[0] * 3, [1] * 3, [2] * 3, [3] * 3].flatten) + expect(vv).to eq([7, 8, 9, 12, 13, 0, 0, 0, 0, 0, 17, 18]) end - if stype == :list or stype == :dense then + if (stype == :list) || (stype == :dense) it "should correctly map to a matrix with a single element" do nm = N.new([1], [2.0], stype: stype) expect(nm.map { |e| e**2 }).to eq N.new([1], [4.0], stype: stype) diff --git a/spec/02_slice_spec.rb b/spec/02_slice_spec.rb index 80d1b0a8..e00db3d4 100644 --- a/spec/02_slice_spec.rb +++ b/spec/02_slice_spec.rb @@ -25,48 +25,48 @@ # Test of slice operations. High priority tests since reference # slicing is needed for pretty_print. # -require 'spec_helper' +require "spec_helper" describe "Slice operation" do include RSpec::Longrun::DSL [:dense, :list, :yale].each do |stype| context "for #{stype}" do - #GC.start # don't have to do this, but it helps to make sure we've cleaned up our pointers properly. + # GC.start # don't have to do this, but it helps to make sure we've cleaned up our pointers properly. let(:stype_matrix) { create_matrix(stype) } it "should correctly return a row of a reference-slice" do n = create_rectangular_matrix(stype) - stype_matrix = n[1..4,1..3] + stype_matrix = n[1..4, 1..3] expect(stype_matrix.row(1, :copy)).to eq(stype_matrix.row(1, :reference)) - expect(stype_matrix.row(1, :copy).to_flat_array).to eq([12,13,0]) + expect(stype_matrix.row(1, :copy).to_flat_array).to eq([12, 13, 0]) end if stype == :yale it "should binary search for the left boundary of a partial row of stored indices correctly" do - #FIXME + # FIXME pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? n = NMatrix.new(10, stype: :yale, dtype: :int32) - n[3,0] = 1 - #n[3,2] = 2 - n[3,3] = 3 - n[3,4] = 4 - n[3,6] = 5 - n[3,8] = 6 - n[3,9] = 7 + n[3, 0] = 1 + # n[3,2] = 2 + n[3, 3] = 3 + n[3, 4] = 4 + n[3, 6] = 5 + n[3, 8] = 6 + n[3, 9] = 7 vs = [] is = [] js = [] - n[3,1..9].each_stored_with_indices do |v,i,j| + n[3, 1..9].each_stored_with_indices do |v, i, j| vs << v is << i js << j end - expect(vs).to eq([3,4,5,6,7]) - expect(js).to eq([2,3,5,7,8]) - expect(is).to eq([0,0,0,0,0]) + expect(vs).to eq([3, 4, 5, 6, 7]) + expect(js).to eq([2, 3, 5, 7, 8]) + expect(is).to eq([0, 0, 0, 0, 0]) end elsif stype == :list it "should iterate across a partial row of stored indices" do @@ -75,59 +75,59 @@ js = [] STDERR.puts("now") if stype == :yale - stype_matrix[2,1..2].each_stored_with_indices do |v,i,j| + stype_matrix[2, 1..2].each_stored_with_indices do |v, i, j| vs << v is << i js << j end - expect(vs).to eq([7,8]) - expect(is).to eq([0,0]) - expect(js).to eq([0,1]) + expect(vs).to eq([7, 8]) + expect(is).to eq([0, 0]) + expect(js).to eq([0, 1]) end end unless stype == :dense it "should iterate across a row of stored indices" do - #FIXME + # FIXME pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? vs = [] is = [] js = [] - stype_matrix[2,0..2].each_stored_with_indices do |v,i,j| + stype_matrix[2, 0..2].each_stored_with_indices do |v, i, j| vs << v is << i js << j end - expect(vs).to eq(stype == :yale ? [8,6,7] : [6,7,8]) - expect(is).to eq([0,0,0]) - expect(js).to eq(stype == :yale ? [2,0,1] : [0,1,2]) + expect(vs).to eq(stype == :yale ? [8, 6, 7] : [6, 7, 8]) + expect(is).to eq([0, 0, 0]) + expect(js).to eq(stype == :yale ? [2, 0, 1] : [0, 1, 2]) end it "should iterate across a submatrix of stored indices" do - #FIXME + # FIXME pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? vs = [] is = [] js = [] - stype_matrix[0..1,1..2].each_stored_with_indices do |v,i,j| + stype_matrix[0..1, 1..2].each_stored_with_indices do |v, i, j| vs << v is << i js << j end - expect(vs).to eq(stype == :yale ? [4,1,2,5] : [1,2,4,5]) - expect(is).to eq(stype == :yale ? [1,0,0,1] : [0,0,1,1]) - expect(js).to eq(stype == :yale ? [0,0,1,1] : [0,1,0,1]) + expect(vs).to eq(stype == :yale ? [4, 1, 2, 5] : [1, 2, 4, 5]) + expect(is).to eq(stype == :yale ? [1, 0, 0, 1] : [0, 0, 1, 1]) + expect(js).to eq(stype == :yale ? [0, 0, 1, 1] : [0, 1, 0, 1]) end end it "should return correct supershape" do pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? - x = NMatrix.random([10,12]) - y = x[0...8,5...12] - expect(y.shape).to eq([8,7]) - expect(y.supershape).to eq([10,12]) + x = NMatrix.random([10, 12]) + y = x[0...8, 5...12] + expect(y.shape).to eq([8, 7]) + expect(y.supershape).to eq([10, 12]) end it "should have #is_ref? method" do @@ -140,70 +140,70 @@ end it "reference should compare with non-reference" do - expect(stype_matrix.slice(1..2,0..1)).to eq(stype_matrix[1..2, 0..1]) - expect(stype_matrix[1..2,0..1]).to eq(stype_matrix.slice(1..2, 0..1)) - expect(stype_matrix[1..2,0..1]).to eq(stype_matrix[1..2, 0..1]) + expect(stype_matrix.slice(1..2, 0..1)).to eq(stype_matrix[1..2, 0..1]) + expect(stype_matrix[1..2, 0..1]).to eq(stype_matrix.slice(1..2, 0..1)) + expect(stype_matrix[1..2, 0..1]).to eq(stype_matrix[1..2, 0..1]) end context "with copying" do - it 'should return an NMatrix' do - n = stype_matrix.slice(0..1,0..1) - expect(nm_eql(n, NMatrix.new([2,2], [0,1,3,4], dtype: :int32))).to be true + it "should return an NMatrix" do + n = stype_matrix.slice(0..1, 0..1) + expect(nm_eql(n, NMatrix.new([2, 2], [0, 1, 3, 4], dtype: :int32))).to be true end - it 'should return a copy of 2x2 matrix to self elements' do + it "should return a copy of 2x2 matrix to self elements" do pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? - n = stype_matrix.slice(1..2,0..1) - expect(n.shape).to eql([2,2]) + n = stype_matrix.slice(1..2, 0..1) + expect(n.shape).to eql([2, 2]) - expect(n[1,1]).to eq(stype_matrix[2,1]) - n[1,1] = -9 - expect(stype_matrix[2,1]).to eql(7) + expect(n[1, 1]).to eq(stype_matrix[2, 1]) + n[1, 1] = -9 + expect(stype_matrix[2, 1]).to eql(7) end - it 'should return a 1x2 matrix without refs to self elements' do - #FIXME + it "should return a 1x2 matrix without refs to self elements" do + # FIXME pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? - n = stype_matrix.slice(0,1..2) - expect(n.shape).to eql([1,2]) + n = stype_matrix.slice(0, 1..2) + expect(n.shape).to eql([1, 2]) - expect(n[0]).to eq(stype_matrix[0,1]) - expect(n[1]).to eq(stype_matrix[0,2]) + expect(n[0]).to eq(stype_matrix[0, 1]) + expect(n[1]).to eq(stype_matrix[0, 2]) n[0] = -9 - expect(stype_matrix[0,1]).to eql(1) - expect(stype_matrix[0,2]).to eql(2) + expect(stype_matrix[0, 1]).to eql(1) + expect(stype_matrix[0, 2]).to eql(2) end - it 'should return a 2x1 matrix without refs to self elements' do + it "should return a 2x1 matrix without refs to self elements" do pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? stype_matrix.extend NMatrix::YaleFunctions - n = stype_matrix.slice(0..1,1) - expect(n.shape).to eql([2,1]) + n = stype_matrix.slice(0..1, 1) + expect(n.shape).to eql([2, 1]) - expect(n[0]).to eq(stype_matrix[0,1]) - expect(n[1]).to eq(stype_matrix[1,1]) + expect(n[0]).to eq(stype_matrix[0, 1]) + expect(n[1]).to eq(stype_matrix[1, 1]) n[0] = -9 - expect(stype_matrix[0,1]).to eql(1) - expect(stype_matrix[1,1]).to eql(4) + expect(stype_matrix[0, 1]).to eql(1) + expect(stype_matrix[1, 1]).to eql(4) end - it 'should be correct slice for range 0..2 and 0...3' do - expect(stype_matrix.slice(0..2,0..2)).to eq(stype_matrix.slice(0...3,0...3)) + it "should be correct slice for range 0..2 and 0...3" do + expect(stype_matrix.slice(0..2, 0..2)).to eq(stype_matrix.slice(0...3, 0...3)) end [:dense, :list, :yale].each do |cast_type| it "should cast copied slice from #{stype.upcase} to #{cast_type.upcase}" do - expect(nm_eql(stype_matrix.slice(1..2, 1..2).cast(cast_type, :int32), stype_matrix.slice(1..2,1..2))).to be true - expect(nm_eql(stype_matrix.slice(0..1, 1..2).cast(cast_type, :int32), stype_matrix.slice(0..1,1..2))).to be true - expect(nm_eql(stype_matrix.slice(1..2, 0..1).cast(cast_type, :int32), stype_matrix.slice(1..2,0..1))).to be true - expect(nm_eql(stype_matrix.slice(0..1, 0..1).cast(cast_type, :int32), stype_matrix.slice(0..1,0..1))).to be true + expect(nm_eql(stype_matrix.slice(1..2, 1..2).cast(cast_type, :int32), stype_matrix.slice(1..2, 1..2))).to be true + expect(nm_eql(stype_matrix.slice(0..1, 1..2).cast(cast_type, :int32), stype_matrix.slice(0..1, 1..2))).to be true + expect(nm_eql(stype_matrix.slice(1..2, 0..1).cast(cast_type, :int32), stype_matrix.slice(1..2, 0..1))).to be true + expect(nm_eql(stype_matrix.slice(0..1, 0..1).cast(cast_type, :int32), stype_matrix.slice(0..1, 0..1))).to be true # Non square - expect(nm_eql(stype_matrix.slice(0..2, 1..2).cast(cast_type, :int32), stype_matrix.slice(0..2,1..2))).to be true - #require 'pry' - #binding.pry if cast_type == :yale - expect(nm_eql(stype_matrix.slice(1..2, 0..2).cast(cast_type, :int32), stype_matrix.slice(1..2,0..2))).to be true + expect(nm_eql(stype_matrix.slice(0..2, 1..2).cast(cast_type, :int32), stype_matrix.slice(0..2, 1..2))).to be true + # require 'pry' + # binding.pry if cast_type == :yale + expect(nm_eql(stype_matrix.slice(1..2, 0..2).cast(cast_type, :int32), stype_matrix.slice(1..2, 0..2))).to be true # Full expect(nm_eql(stype_matrix.slice(0..2, 0..2).cast(cast_type, :int32), stype_matrix)).to be true @@ -212,131 +212,128 @@ end # Yale: - #context "by copy" do - #it "should correctly preserve zeros" do - # stype_matrix = NMatrix.new(:yale, 3, :int64) - # column_slice = stype_matrix.column(2, :copy) - # column_slice[0].should == 0 - # column_slice[1].should == 0 - # column_slice[2].should == 0 - #end - #end + # context "by copy" do + # it "should correctly preserve zeros" do + # stype_matrix = NMatrix.new(:yale, 3, :int64) + # column_slice = stype_matrix.column(2, :copy) + # column_slice[0].should == 0 + # column_slice[1].should == 0 + # column_slice[2].should == 0 + # end + # end context "by reference" do - it 'should return an NMatrix' do - n = stype_matrix[0..1,0..1] - expect(nm_eql(n, NMatrix.new([2,2], [0,1,3,4], dtype: :int32))).to be true + it "should return an NMatrix" do + n = stype_matrix[0..1, 0..1] + expect(nm_eql(n, NMatrix.new([2, 2], [0, 1, 3, 4], dtype: :int32))).to be true end - it 'should return a 2x2 matrix with refs to self elements' do - #FIXME + it "should return a 2x2 matrix with refs to self elements" do + # FIXME pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? # and :cast_type != :dense - n = stype_matrix[1..2,0..1] - expect(n.shape).to eql([2,2]) + n = stype_matrix[1..2, 0..1] + expect(n.shape).to eql([2, 2]) - expect(n[0,0]).to eq(stype_matrix[1,0]) - n[0,0] = -9 - expect(stype_matrix[1,0]).to eql(-9) + expect(n[0, 0]).to eq(stype_matrix[1, 0]) + n[0, 0] = -9 + expect(stype_matrix[1, 0]).to eql(-9) end - it 'should return a 1x2 vector with refs to self elements' do - #FIXME + it "should return a 1x2 vector with refs to self elements" do + # FIXME pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? # and :cast_type != :dense - n = stype_matrix[0,1..2] - expect(n.shape).to eql([1,2]) + n = stype_matrix[0, 1..2] + expect(n.shape).to eql([1, 2]) - expect(n[0]).to eq(stype_matrix[0,1]) + expect(n[0]).to eq(stype_matrix[0, 1]) n[0] = -9 - expect(stype_matrix[0,1]).to eql(-9) + expect(stype_matrix[0, 1]).to eql(-9) end - it 'should return a 2x1 vector with refs to self elements' do + it "should return a 2x1 vector with refs to self elements" do pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? - n = stype_matrix[0..1,1] - expect(n.shape).to eql([2,1]) + n = stype_matrix[0..1, 1] + expect(n.shape).to eql([2, 1]) - expect(n[0]).to eq(stype_matrix[0,1]) + expect(n[0]).to eq(stype_matrix[0, 1]) n[0] = -9 - expect(stype_matrix[0,1]).to eql(-9) + expect(stype_matrix[0, 1]).to eql(-9) end - it 'should slice again' do + it "should slice again" do n = stype_matrix[1..2, 1..2] - expect(nm_eql(n[1,0..1], NVector.new(2, [7,8], dtype: :int32).transpose)).to be true + expect(nm_eql(n[1, 0..1], NVector.new(2, [7, 8], dtype: :int32).transpose)).to be true end - it 'should be correct slice for range 0..2 and 0...3' do - expect(stype_matrix[0..2,0..2]).to eq(stype_matrix[0...3,0...3]) + it "should be correct slice for range 0..2 and 0...3" do + expect(stype_matrix[0..2, 0..2]).to eq(stype_matrix[0...3, 0...3]) end - it 'should correctly handle :* slice notation' do - expect(stype_matrix[:*,0]).to eq stype_matrix[0...stype_matrix.shape[0], 0] + it "should correctly handle :* slice notation" do + expect(stype_matrix[:*, 0]).to eq stype_matrix[0...stype_matrix.shape[0], 0] end if stype == :dense - [:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |left_dtype| - [:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |right_dtype| - + [:byte, :int8, :int16, :int32, :int64, :float32, :float64].each do |left_dtype| + [:byte, :int8, :int16, :int32, :int64, :float32, :float64].each do |right_dtype| # Won't work if they're both 1-byte, due to overflow. - next if [:byte,:int8].include?(left_dtype) && [:byte,:int8].include?(right_dtype) + next if [:byte, :int8].include?(left_dtype) && [:byte, :int8].include?(right_dtype) # For now, don't bother testing int-int mult. - #next if [:int8,:int16,:int32,:int64].include?(left_dtype) && [:int8,:int16,:int32,:int64].include?(right_dtype) - it "handles #{left_dtype.to_s} dot #{right_dtype.to_s} matrix multiplication" do - #STDERR.puts "dtype=#{dtype.to_s}" - #STDERR.puts "2" - - nary = if left_dtype.to_s =~ /complex/ - COMPLEX_MATRIX43A_ARRAY - else - MATRIX43A_ARRAY - end - - mary = if right_dtype.to_s =~ /complex/ - COMPLEX_MATRIX32A_ARRAY - else - MATRIX32A_ARRAY - end - - n = NMatrix.new([4,3], nary, dtype: left_dtype)[1..3,1..2] - m = NMatrix.new([3,2], mary, dtype: right_dtype)[1..2,0..1] + # next if [:int8,:int16,:int32,:int64].include?(left_dtype) && [:int8,:int16,:int32,:int64].include?(right_dtype) + it "handles #{left_dtype} dot #{right_dtype} matrix multiplication" do + # STDERR.puts "dtype=#{dtype.to_s}" + # STDERR.puts "2" + + nary = if /complex/.match?(left_dtype.to_s) + COMPLEX_MATRIX43A_ARRAY + else + MATRIX43A_ARRAY + end + + mary = if /complex/.match?(right_dtype.to_s) + COMPLEX_MATRIX32A_ARRAY + else + MATRIX32A_ARRAY + end + + n = NMatrix.new([4, 3], nary, dtype: left_dtype)[1..3, 1..2] + m = NMatrix.new([3, 2], mary, dtype: right_dtype)[1..2, 0..1] r = n.dot m - expect(r.shape).to eql([3,2]) - - expect(r[0,0]).to eq(219.0) - expect(r[0,1]).to eq(185.0) - expect(r[1,0]).to eq(244.0) - expect(r[1,1]).to eq(205.0) - expect(r[2,0]).to eq(42.0) - expect(r[2,1]).to eq(35.0) - + expect(r.shape).to eql([3, 2]) + + expect(r[0, 0]).to eq(219.0) + expect(r[0, 1]).to eq(185.0) + expect(r[1, 0]).to eq(244.0) + expect(r[1, 1]).to eq(205.0) + expect(r[2, 0]).to eq(42.0) + expect(r[2, 1]).to eq(35.0) end end end context "operations" do - it "correctly transposes slices" do - expect(stype_matrix[0...3,0].transpose).to eq NMatrix[[0, 3, 6]] - expect(stype_matrix[0...3,1].transpose).to eq NMatrix[[1, 4, 7]] - expect(stype_matrix[0...3,2].transpose).to eq NMatrix[[2, 5, 8]] - expect(stype_matrix[0,0...3].transpose).to eq NMatrix[[0], [1], [2]] - expect(stype_matrix[1,0...3].transpose).to eq NMatrix[[3], [4], [5]] - expect(stype_matrix[2,0...3].transpose).to eq NMatrix[[6], [7], [8]] - expect(stype_matrix[1..2,1..2].transpose).to eq NMatrix[[4, 7], [5, 8]] + expect(stype_matrix[0...3, 0].transpose).to eq NMatrix[[0, 3, 6]] + expect(stype_matrix[0...3, 1].transpose).to eq NMatrix[[1, 4, 7]] + expect(stype_matrix[0...3, 2].transpose).to eq NMatrix[[2, 5, 8]] + expect(stype_matrix[0, 0...3].transpose).to eq NMatrix[[0], [1], [2]] + expect(stype_matrix[1, 0...3].transpose).to eq NMatrix[[3], [4], [5]] + expect(stype_matrix[2, 0...3].transpose).to eq NMatrix[[6], [7], [8]] + expect(stype_matrix[1..2, 1..2].transpose).to eq NMatrix[[4, 7], [5, 8]] end it "adds slices" do - expect(NMatrix[[0,0,0]] + stype_matrix[1,0..2]).to eq NMatrix[[3, 4, 5]] + expect(NMatrix[[0, 0, 0]] + stype_matrix[1, 0..2]).to eq NMatrix[[3, 4, 5]] end it "scalar adds to slices" do - expect(stype_matrix[1,0..2]+1).to eq NMatrix[[4, 5, 6]] + expect(stype_matrix[1, 0..2] + 1).to eq NMatrix[[4, 5, 6]] end it "compares slices to scalars" do - #FIXME + # FIXME pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? (stype_matrix[1, 0..2] > 2).each { |e| expect(e != 0).to be true } end @@ -358,43 +355,42 @@ expect(els[1]).to eq [4, 0, 1] expect(els[2]).to eq [5, 0, 2] end - end end - example 'should be cleaned up by garbage collector without errors' do + example "should be cleaned up by garbage collector without errors" do step "reference slice" do 1.times do - n = stype_matrix[1..2,0..1] + n = stype_matrix[1..2, 0..1] end GC.start end step "reference slice of casted-copy" do - expect(stype_matrix).to eq(NMatrix.new([3,3], (0..9).to_a, dtype: :int32).cast(stype, :int32)) + expect(stype_matrix).to eq(NMatrix.new([3, 3], (0..9).to_a, dtype: :int32).cast(stype, :int32)) n = nil 1.times do - m = NMatrix.new([2,2], [1,2,3,4]).cast(stype, :int32) - n = m[0..1,0..1] + m = NMatrix.new([2, 2], [1, 2, 3, 4]).cast(stype, :int32) + n = m[0..1, 0..1] end GC.start - expect(n).to eq(NMatrix.new([2,2], [1,2,3,4]).cast(stype, :int32)) + expect(n).to eq(NMatrix.new([2, 2], [1, 2, 3, 4]).cast(stype, :int32)) end end [:dense, :list, :yale].each do |cast_type| it "should cast a square reference-slice from #{stype.upcase} to #{cast_type.upcase}" do - expect(nm_eql(stype_matrix[1..2, 1..2].cast(cast_type), stype_matrix[1..2,1..2])).to be true - expect(nm_eql(stype_matrix[0..1, 1..2].cast(cast_type), stype_matrix[0..1,1..2])).to be true - expect(nm_eql(stype_matrix[1..2, 0..1].cast(cast_type), stype_matrix[1..2,0..1])).to be true - expect(nm_eql(stype_matrix[0..1, 0..1].cast(cast_type), stype_matrix[0..1,0..1])).to be true + expect(nm_eql(stype_matrix[1..2, 1..2].cast(cast_type), stype_matrix[1..2, 1..2])).to be true + expect(nm_eql(stype_matrix[0..1, 1..2].cast(cast_type), stype_matrix[0..1, 1..2])).to be true + expect(nm_eql(stype_matrix[1..2, 0..1].cast(cast_type), stype_matrix[1..2, 0..1])).to be true + expect(nm_eql(stype_matrix[0..1, 0..1].cast(cast_type), stype_matrix[0..1, 0..1])).to be true end it "should cast a rectangular reference-slice from #{stype.upcase} to #{cast_type.upcase}" do # Non square - expect(nm_eql(stype_matrix[0..2, 1..2].cast(cast_type), stype_matrix[0..2,1..2])).to be true # FIXME: memory problem. - expect(nm_eql(stype_matrix[1..2, 0..2].cast(cast_type), stype_matrix[1..2,0..2])).to be true # this one is fine + expect(nm_eql(stype_matrix[0..2, 1..2].cast(cast_type), stype_matrix[0..2, 1..2])).to be true # FIXME: memory problem. + expect(nm_eql(stype_matrix[1..2, 0..2].cast(cast_type), stype_matrix[1..2, 0..2])).to be true # this one is fine end it "should cast a square full-matrix reference-slice from #{stype.upcase} to #{cast_type.upcase}" do diff --git a/spec/03_nmatrix_monkeys_spec.rb b/spec/03_nmatrix_monkeys_spec.rb index f5305b17..23ed4677 100644 --- a/spec/03_nmatrix_monkeys_spec.rb +++ b/spec/03_nmatrix_monkeys_spec.rb @@ -1,24 +1,24 @@ -require 'spec_helper' +require "spec_helper" describe NMatrix do describe "#to_a" do it "creates an Array with the same dimensions" do - n = NMatrix.seq([3,2]) + n = NMatrix.seq([3, 2]) expect(n.to_a).to eq([[0, 1], [2, 3], [4, 5]]) end it "creates an Array with the proper element type" do - n = NMatrix.seq([3,2], dtype: :float64) + n = NMatrix.seq([3, 2], dtype: :float64) expect(n.to_a).to eq([[0.0, 1.0], [2.0, 3.0], [4.0, 5.0]]) end it "properly interprets list matrices" do - n = NMatrix.seq([3,2], stype: :list) + n = NMatrix.seq([3, 2], stype: :list) expect(n.to_a).to eq([[0, 1], [2, 3], [4, 5]]) end it "properly interprets yale matrices" do - n = NMatrix.seq([3,2], stype: :yale) + n = NMatrix.seq([3, 2], stype: :yale) expect(n.to_a).to eq([[0, 1], [2, 3], [4, 5]]) end end @@ -30,26 +30,26 @@ let(:a) {(0..5).to_a} it "uses a given shape and type" do - expect(a.to_nm([3,2]).dtype).to eq :int64 - expect(a.to_nm([3,2])).to eq(NMatrix.seq([3,2])) + expect(a.to_nm([3, 2]).dtype).to eq :int64 + expect(a.to_nm([3, 2])).to eq(NMatrix.seq([3, 2])) end it "guesses dtype based on first element" do a[0] = 0.0 - expect(a.to_nm([3,2]).dtype).to eq :float64 + expect(a.to_nm([3, 2]).dtype).to eq :float64 end it "defaults to dtype :object if necessary" do - #FIXME + # FIXME pending("not yet implemented for object dtype for NMatrix-JRuby") if jruby? - a = %w(this is an array of strings) - expect(a.to_nm([3,2]).dtype).to eq :object - expect(a.to_nm([3,2])).to eq(NMatrix.new([3,2], a, dtype: :object)) + a = %w[this is an array of strings] + expect(a.to_nm([3, 2]).dtype).to eq :object + expect(a.to_nm([3, 2])).to eq(NMatrix.new([3, 2], a, dtype: :object)) end it "attempts to intuit the shape of the Array" do a = [[0, 1], [2, 3], [4, 5]] - expect(a.to_nm).to eq(NMatrix.new([3,2], a.flatten)) + expect(a.to_nm).to eq(NMatrix.new([3, 2], a.flatten)) expect(a.to_nm.dtype).to eq :int64 end @@ -61,7 +61,7 @@ it "intuits shape of Array into multiple dimensions" do a = [[[0], [1]], [[2], [3]], [[4], [5]]] - expect(a.to_nm).to eq(NMatrix.new([3,2,1], a.flatten)) + expect(a.to_nm).to eq(NMatrix.new([3, 2, 1], a.flatten)) expect(a).to eq(a.to_nm.to_a) end @@ -72,9 +72,8 @@ it "does not permanently alter the Array" do a = [[0, 1], [2, 3], [4, 5]] - expect(a.to_nm).to eq(NMatrix.new([3,2], a.flatten)) + expect(a.to_nm).to eq(NMatrix.new([3, 2], a.flatten)) expect(a).to eq([[0, 1], [2, 3], [4, 5]]) end end end - diff --git a/spec/blas_spec.rb b/spec/blas_spec.rb index c2ab05b3..6f0c1fc5 100644 --- a/spec/blas_spec.rb +++ b/spec/blas_spec.rb @@ -25,13 +25,12 @@ # Tests for properly exposed BLAS functions. # -require 'spec_helper' +require "spec_helper" describe NMatrix::BLAS do [:byte, :int8, :int16, :int32, :int64, :float32, :float64, :complex64, :complex128, - :object - ].each do |dtype| + :object],.each do |dtype| context dtype do it "exposes cblas_scal" do x = NMatrix.new([3, 1], [1, 2, 3], dtype: dtype) @@ -40,7 +39,7 @@ end it "exposes cblas_imax" do - u = NMatrix.new([3,1], [1, 4, 3], dtype: dtype) + u = NMatrix.new([3, 1], [1, 4, 3], dtype: dtype) index = NMatrix::BLAS.cblas_imax(3, u, 1) expect(index).to eq(1) end @@ -53,41 +52,41 @@ # would greatly simplify the calling of cblas_trsm in terms of arguments, and which would be accessible # as NMatrix::BLAS::trsm) it "exposes unfriendly cblas_trsm" do - a = NMatrix.new(3, [4,-1.0/2, -3.0/4, -2, 2, -1.0/4, -4, -2, -1.0/2], dtype: dtype) - b = NMatrix.new([3,1], [-1, 17, -9], dtype: dtype) - NMatrix::BLAS::cblas_trsm(:row, :right, :lower, :transpose, :nonunit, 1, 3, 1.0, a, 3, b, 3) + a = NMatrix.new(3, [4, -1.0 / 2, -3.0 / 4, -2, 2, -1.0 / 4, -4, -2, -1.0 / 2], dtype: dtype) + b = NMatrix.new([3, 1], [-1, 17, -9], dtype: dtype) + NMatrix::BLAS.cblas_trsm(:row, :right, :lower, :transpose, :nonunit, 1, 3, 1.0, a, 3, b, 3) # These test results all come from actually running a matrix through BLAS. We use them to ensure that NMatrix's # version of these functions give similar results. - expect(b[0]).to eq(-1.0/4) - expect(b[1]).to eq(33.0/4) + expect(b[0]).to eq(-1.0 / 4) + expect(b[1]).to eq(33.0 / 4) expect(b[2]).to eq(-13) - NMatrix::BLAS::cblas_trsm(:row, :right, :upper, :transpose, :unit, 1, 3, 1.0, a, 3, b, 3) + NMatrix::BLAS.cblas_trsm(:row, :right, :upper, :transpose, :unit, 1, 3, 1.0, a, 3, b, 3) - expect(b[0]).to eq(-15.0/2) + expect(b[0]).to eq(-15.0 / 2) expect(b[1]).to eq(5) expect(b[2]).to eq(-13) - - NMatrix::BLAS::cblas_trsm(:row, :left, :lower, :transpose, :nounit, 3, 1, 1.0, a, 3, b, 1) - expect(b[0]).to eq(307.0/8) - expect(b[1]).to eq(57.0/2) + NMatrix::BLAS.cblas_trsm(:row, :left, :lower, :transpose, :nounit, 3, 1, 1.0, a, 3, b, 1) + + expect(b[0]).to eq(307.0 / 8) + expect(b[1]).to eq(57.0 / 2) expect(b[2]).to eq(26.0) - - NMatrix::BLAS::cblas_trsm(:row, :left, :upper, :transpose, :unit, 3, 1, 1.0, a, 3, b, 1) - expect(b[0]).to eq(307.0/8) - expect(b[1]).to eq(763.0/16) - expect(b[2]).to eq(4269.0/64) + NMatrix::BLAS.cblas_trsm(:row, :left, :upper, :transpose, :unit, 3, 1, 1.0, a, 3, b, 1) + + expect(b[0]).to eq(307.0 / 8) + expect(b[1]).to eq(763.0 / 16) + expect(b[2]).to eq(4269.0 / 64) end # trmm multiplies two matrices, where one of the two is required to be # triangular it "exposes cblas_trmm" do - a = NMatrix.new([3,3], [1,1,1, 0,1,2, 0,0,-1], dtype: dtype) - b = NMatrix.new([3,3], [1,2,3, 4,5,6, 7,8,9], dtype: dtype) + a = NMatrix.new([3, 3], [1, 1, 1, 0, 1, 2, 0, 0, -1], dtype: dtype) + b = NMatrix.new([3, 3], [1, 2, 3, 4, 5, 6, 7, 8, 9], dtype: dtype) begin NMatrix::BLAS.cblas_trmm(:row, :left, :upper, false, :not_unit, 3, 3, 1, a, 3, b, 3) @@ -95,88 +94,85 @@ pending e.to_s end - product = NMatrix.new([3,3], [12,15,18, 18,21,24, -7,-8,-9], dtype: dtype) + product = NMatrix.new([3, 3], [12, 15, 18, 18, 21, 24, -7, -8, -9], dtype: dtype) expect(b).to eq(product) end end end - #should have a separate test for complex + # should have a separate test for complex [:float32, :float64, :complex64, :complex128, :object].each do |dtype| context dtype do - it "exposes cblas rot" do - x = NMatrix.new([5,1], [1,2,3,4,5], dtype: dtype) - y = NMatrix.new([5,1], [-5,-4,-3,-2,-1], dtype: dtype) - x, y = NMatrix::BLAS::rot(x, y, 1.0/2, Math.sqrt(3)/2, -1) + x = NMatrix.new([5, 1], [1, 2, 3, 4, 5], dtype: dtype) + y = NMatrix.new([5, 1], [-5, -4, -3, -2, -1], dtype: dtype) + x, y = NMatrix::BLAS.rot(x, y, 1.0 / 2, Math.sqrt(3) / 2, -1) expect(x).to be_within(1e-4).of( - NMatrix.new([5,1], [-0.3660254037844386, -0.7320508075688772, -1.098076211353316, -1.4641016151377544, -1.8301270189221928], dtype: dtype) + NMatrix.new([5, 1], [-0.3660254037844386, -0.7320508075688772, -1.098076211353316, -1.4641016151377544, -1.8301270189221928], dtype: dtype) ) expect(y).to be_within(1e-4).of( - NMatrix.new([5,1], [-6.830127018922193, -5.464101615137754, -4.098076211353316, -2.732050807568877, -1.3660254037844386], dtype: dtype) + NMatrix.new([5, 1], [-6.830127018922193, -5.464101615137754, -4.098076211353316, -2.732050807568877, -1.3660254037844386], dtype: dtype) ) end - end end [:float32, :float64, :complex64, :complex128, :object].each do |dtype| context dtype do - it "exposes cblas rotg" do pending("broken for :object") if dtype == :object - ab = NMatrix.new([2,1], [6,-8], dtype: dtype) + ab = NMatrix.new([2, 1], [6, -8], dtype: dtype) begin - c,s = NMatrix::BLAS::rotg(ab) + c, s = NMatrix::BLAS.rotg(ab) rescue NotImplementedError => e pending e.to_s end if [:float32, :float64].include?(dtype) expect(ab[0]).to be_within(1e-6).of(-10) - expect(ab[1]).to be_within(1e-6).of(-5.0/3) - expect(c).to be_within(1e-6).of(-3.0/5) + expect(ab[1]).to be_within(1e-6).of(-5.0 / 3) + expect(c).to be_within(1e-6).of(-3.0 / 5) else pending "need correct test cases" expect(ab[0]).to be_within(1e-6).of(10) - expect(ab[1]).to be_within(1e-6).of(5.0/3) - expect(c).to be_within(1e-6).of(3.0/5) + expect(ab[1]).to be_within(1e-6).of(5.0 / 3) + expect(c).to be_within(1e-6).of(3.0 / 5) end - expect(s).to be_within(1e-6).of(4.0/5) + expect(s).to be_within(1e-6).of(4.0 / 5) end # Note: this exposes gemm, not cblas_gemm (which is the unfriendly CBLAS no-error-checking version) it "exposes gemm" do - n = NMatrix.new([4,3], [14.0,9.0,3.0, 2.0,11.0,15.0, 0.0,12.0,17.0, 5.0,2.0,3.0], dtype: dtype) - m = NMatrix.new([3,2], [12.0,25.0, 9.0,10.0, 8.0,5.0], dtype: dtype) + n = NMatrix.new([4, 3], [14.0, 9.0, 3.0, 2.0, 11.0, 15.0, 0.0, 12.0, 17.0, 5.0, 2.0, 3.0], dtype: dtype) + m = NMatrix.new([3, 2], [12.0, 25.0, 9.0, 10.0, 8.0, 5.0], dtype: dtype) - #c = NMatrix.new([4,2], dtype) - r = NMatrix::BLAS.gemm(n, m) #, c) - #c.should equal(r) # check that both are same memory address + # c = NMatrix.new([4,2], dtype) + r = NMatrix::BLAS.gemm(n, m) # , c) + # c.should equal(r) # check that both are same memory address - expect(r).to eq(NMatrix.new([4,2], [273,455,243,235,244,205,102,160], dtype: dtype)) + expect(r).to eq(NMatrix.new([4, 2], [273, 455, 243, 235, 244, 205, 102, 160], dtype: dtype)) end it "exposes gemv" do - a = NMatrix.new([4,3], [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0], dtype: dtype) - x = NMatrix.new([3,1], [2.0, 1.0, 0.0], dtype: dtype) + a = NMatrix.new([4, 3], [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0], dtype: dtype) + x = NMatrix.new([3, 1], [2.0, 1.0, 0.0], dtype: dtype) y = NMatrix::BLAS.gemv(a, x) - expect(y).to eq(NMatrix.new([4,1],[4.0,13.0,22.0,31.0],dtype: dtype)) + expect(y).to eq(NMatrix.new([4, 1], [4.0, 13.0, 22.0, 31.0], dtype: dtype)) end it "exposes asum" do pending("broken for :object") if dtype == :object - x = NMatrix.new([4,1], [-1,2,3,4], dtype: dtype) + x = NMatrix.new([4, 1], [-1, 2, 3, 4], dtype: dtype) expect(NMatrix::BLAS.asum(x)).to eq(10) end it "exposes asum for single element" do - if [:complex64,:complex128].include?(dtype) - x = NMatrix.new([1], [Complex(-3,2)], dtype: dtype) + if [:complex64, :complex128].include?(dtype) + x = NMatrix.new([1], [Complex(-3, 2)], dtype: dtype) expect(x.asum).to eq(5.0) else x = NMatrix.new([1], [-1], dtype: dtype) @@ -187,16 +183,16 @@ it "exposes nrm2" do pending("broken for :object") if dtype == :object - if dtype =~ /complex/ - x = NMatrix.new([3,1], [Complex(1,2),Complex(3,4),Complex(0,6)], dtype: dtype) - y = NMatrix.new([3,1], [Complex(0,0),Complex(0,0),Complex(0,0)], dtype: dtype) + if /complex/.match?(dtype) + x = NMatrix.new([3, 1], [Complex(1, 2), Complex(3, 4), Complex(0, 6)], dtype: dtype) + y = NMatrix.new([3, 1], [Complex(0, 0), Complex(0, 0), Complex(0, 0)], dtype: dtype) nrm2 = 8.12403840463596 else - x = NMatrix.new([4,1], [2,-4,3,5], dtype: dtype) - y = NMatrix.new([3,1], [0,0,0], dtype: dtype) + x = NMatrix.new([4, 1], [2, -4, 3, 5], dtype: dtype) + y = NMatrix.new([3, 1], [0, 0, 0], dtype: dtype) nrm2 = 5.385164807134504 end - + err = case dtype when :float32, :complex64 1e-6 @@ -204,12 +200,11 @@ 1e-14 else 1e-14 - end + end expect(NMatrix::BLAS.nrm2(x, 1, 3)).to be_within(err).of(nrm2) expect(NMatrix::BLAS.nrm2(y, 1, 3)).to be_within(err).of(0) end - end end end diff --git a/spec/elementwise_spec.rb b/spec/elementwise_spec.rb index 3c2b1584..63d0971a 100644 --- a/spec/elementwise_spec.rb +++ b/spec/elementwise_spec.rb @@ -25,7 +25,7 @@ # Element-wise operation tests. # -require 'spec_helper' +require "spec_helper" describe NMatrix do context "yale" do @@ -33,28 +33,28 @@ @n = NMatrix.new(3, stype: :yale, dtype: :int64) @n.extend NMatrix::YaleFunctions unless jruby? @m = NMatrix.new(3, stype: :yale, dtype: :int64) - @n[0,0] = 52 - @n[0,2] = 5 - @n[1,1] = 40 - @n[0,1] = 30 - @n[2,0] = 6 - @m[1,1] = -48 - @m[0,2] = -5 + @n[0, 0] = 52 + @n[0, 2] = 5 + @n[1, 1] = 40 + @n[0, 1] = 30 + @n[2, 0] = 6 + @m[1, 1] = -48 + @m[0, 2] = -5 @n.extend NMatrix::YaleFunctions unless jruby? end it "should perform scalar math" do pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? x = @n * 3 - expect(x[0,0]).to eq(52 * 3) - expect(x[0,1]).to eq(30 * 3) - expect(x[0,2]).to eq(5 * 3) - expect(x[1,1]).to eq(40 * 3) - expect(x[2,0]).to eq(6 * 3) + expect(x[0, 0]).to eq(52 * 3) + expect(x[0, 1]).to eq(30 * 3) + expect(x[0, 2]).to eq(5 * 3) + expect(x[1, 1]).to eq(40 * 3) + expect(x[2, 0]).to eq(6 * 3) r = NMatrix.new(3, stype: :yale, dtype: :int64) y = r + 3 - expect(y[0,0]).to eq(3) + expect(y[0, 0]).to eq(3) end it "should refuse to perform a dot operation on a yale with non-zero default" do @@ -66,126 +66,125 @@ end it "should perform element-wise addition" do - expect(@n+@m).to eq(NMatrix.new(:dense, 3, [52,30,0,0,-8,0,6,0,0], :int64).cast(:yale, :int64)) + expect(@n + @m).to eq(NMatrix.new(:dense, 3, [52, 30, 0, 0, -8, 0, 6, 0, 0], :int64).cast(:yale, :int64)) end it "should perform element-wise subtraction" do - expect(@n-@m).to eq(NMatrix.new(:dense, 3, [52,30,10,0,88,0,6,0,0], :int64).cast(:yale, :int64)) + expect(@n - @m).to eq(NMatrix.new(:dense, 3, [52, 30, 10, 0, 88, 0, 6, 0, 0], :int64).cast(:yale, :int64)) end it "should perform element-wise multiplication" do - r = NMatrix.new(:dense, 3, [0,0,-25,0,-1920,0,0,0,0], :int64).cast(:yale, :int64) + r = NMatrix.new(:dense, 3, [0, 0, -25, 0, -1920, 0, 0, 0, 0], :int64).cast(:yale, :int64) m = NMatrix.new(2, stype: :yale, dtype: :int64) - expect(@n*@m).to eq(r) + expect(@n * @m).to eq(r) end it "should perform element-wise division" do pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? r = NMatrix.new(:dense, 3, [52, 30, -2, 0, -1, 0, 6, 0, 0], :int64).cast(:yale, :int64) - expect(@n/(@m+1)).to eq(r) + expect(@n / (@m + 1)).to eq(r) end it "should perform element-wise modulo" do pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? m = NMatrix.new(3, stype: :yale, dtype: :int64, default: 0) + 5 - expect(@n % m).to eq(NMatrix.new(:dense, 3, [2,0,0,0,0,0,1,0,0], :int64).cast(:yale, :int64)) + expect(@n % m).to eq(NMatrix.new(:dense, 3, [2, 0, 0, 0, 0, 0, 1, 0, 0], :int64).cast(:yale, :int64)) end it "should handle element-wise equality (=~)" do - expect(@n =~ @m).to eq(NMatrix.new(:dense, 3, [false,false,false,true,false,true,false,true,true], :object).cast(:yale, :object, false)) + expect(@n =~ @m).to eq(NMatrix.new(:dense, 3, [false, false, false, true, false, true, false, true, true], :object).cast(:yale, :object, false)) end it "should handle element-wise inequality (!~)" do - expect(@n !~ @m).to eq(NMatrix.new(:dense, 3, [true,true,true,false,true,false,true,false,false], :object).cast(:yale, :object, true)) + expect(@n !~ @m).to eq(NMatrix.new(:dense, 3, [true, true, true, false, true, false, true, false, false], :object).cast(:yale, :object, true)) end it "should handle element-wise less-than (<)" do - expect(@m < @n).to eq(NMatrix.new(:dense, 3, [true,true,true,false,true,false,true,false,false], :object).cast(:yale, :object, true)) + expect(@m < @n).to eq(NMatrix.new(:dense, 3, [true, true, true, false, true, false, true, false, false], :object).cast(:yale, :object, true)) end it "should handle element-wise greater-than (>)" do - expect(@n > @m).to eq(NMatrix.new(:dense, 3, [true,true,true,false,true,false,true,false,false], :object).cast(:yale, :object, false)) + expect(@n > @m).to eq(NMatrix.new(:dense, 3, [true, true, true, false, true, false, true, false, false], :object).cast(:yale, :object, false)) end it "should handle element-wise greater-than-or-equals (>=)" do - expect(@n >= @m).to eq(NMatrix.new(:dense, 3, true, :object).cast(:yale,:object, true)) + expect(@n >= @m).to eq(NMatrix.new(:dense, 3, true, :object).cast(:yale, :object, true)) end it "should handle element-wise less-than-or-equals (<=)" do - r = NMatrix.new(:dense, 3, [false,false,false,true,false,true,false,true,true], :object).cast(:yale, :object, false) + r = NMatrix.new(:dense, 3, [false, false, false, true, false, true, false, true, true], :object).cast(:yale, :object, false) expect(@n <= @m).to eq(r) end end - context "list" do before :each do @n = NMatrix.new(:list, 2, 0, :int64) @m = NMatrix.new(:list, 2, 0, :int64) - @n[0,0] = 52 - @m[1,1] = -48 - @n[1,1] = 40 + @n[0, 0] = 52 + @m[1, 1] = -48 + @n[1, 1] = 40 end it "should perform scalar math" do pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? x = @n * 3 - expect(x[0,0]).to eq(52 * 3) - expect(x[1,1]).to eq(40 * 3) - expect(x[0,1]).to eq(0) + expect(x[0, 0]).to eq(52 * 3) + expect(x[1, 1]).to eq(40 * 3) + expect(x[0, 1]).to eq(0) r = NMatrix.new(3, stype: :list, default: 1) y = r + 3 - expect(y[0,0]).to eq(4) + expect(y[0, 0]).to eq(4) end it "should perform element-wise addition" do r = NMatrix.new(2, stype: :list, dtype: :int64, default: 0) - r[0,0] = 52 - r[1,1] = -8 + r[0, 0] = 52 + r[1, 1] = -8 q = @n + @m expect(q).to eq(r) end it "should perform element-wise subtraction" do r = NMatrix.new(:dense, 2, [52, 0, 0, 88], :int64).cast(:list, :int64) - expect(@n-@m).to eq(r) + expect(@n - @m).to eq(r) end it "should perform element-wise multiplication" do r = NMatrix.new(:dense, 2, [52, 0, 0, -1920], :int64).cast(:list, :int64) m = NMatrix.new(:list, 2, 1, :int64) - m[1,1] = -48 - expect(@n*m).to eq(r) + m[1, 1] = -48 + expect(@n * m).to eq(r) end it "should perform element-wise division" do m = NMatrix.new(:list, 2, 1, :int64) - m[1,1] = 2 + m[1, 1] = 2 r = NMatrix.new(:dense, 2, [52, 0, 0, 20], :int64).cast(:list, :int64) - expect(@n/m).to eq(r) + expect(@n / m).to eq(r) end it "should perform element-wise modulo" do pending("not yet implemented for sparse matrices for NMatrix-JRuby") if jruby? m = NMatrix.new(:list, 2, 1, :int64) - m[0,0] = 50 - m[1,1] = 40 + m[0, 0] = 50 + m[1, 1] = 40 (@n % m) end it "should handle element-wise equality (=~)" do r = NMatrix.new(:list, 2, false, :object) - r[0,1] = true - r[1,0] = true + r[0, 1] = true + r[1, 0] = true expect(@n =~ @m).to eq(r) end it "should handle element-wise inequality (!~)" do r = NMatrix.new(:list, 2, false, :object) - r[0,0] = true - r[1,1] = true + r[0, 0] = true + r[1, 1] = true expect(@n !~ @m).to eq(r) end @@ -196,8 +195,8 @@ it "should handle element-wise greater-than (>)" do r = NMatrix.new(:list, 2, false, :object) - r[0,0] = true - r[1,1] = true + r[0, 0] = true + r[1, 1] = true expect(@n > @m).to eq(r) end @@ -207,8 +206,8 @@ it "should handle element-wise less-than-or-equals (<=)" do r = NMatrix.new(:list, 2, false, :object) - r[0,1] = true - r[1,0] = true + r[0, 1] = true + r[1, 0] = true expect(@n <= @m).to eq(r) end end @@ -216,95 +215,95 @@ context "dense" do context "scalar arithmetic" do before :each do - @n = NMatrix.new(:dense, 2, [1,2,3,4], :int64) + @n = NMatrix.new(:dense, 2, [1, 2, 3, 4], :int64) end it "works for integers" do - expect(@n+1).to eq(NMatrix.new(:dense, 2, [2,3,4,5], :int64)) + expect(@n + 1).to eq(NMatrix.new(:dense, 2, [2, 3, 4, 5], :int64)) end - #it "works for complex64" do + # it "works for complex64" do # n = @n.cast(:dtype => :complex64) # (n + 10.0).to_a.should == [Complex(11.0), Complex(12.0), Complex(13.0), Complex(14.0)] - #end + # end end context "elementwise arithmetic" do before :each do - @n = NMatrix.new(:dense, 2, [1,2,3,4], :int64) - @m = NMatrix.new(:dense, 2, [-4,-1,0,66], :int64) + @n = NMatrix.new(:dense, 2, [1, 2, 3, 4], :int64) + @m = NMatrix.new(:dense, 2, [-4, -1, 0, 66], :int64) end it "adds" do - r = @n+@m - expect(r).to eq(NMatrix.new(:dense, [2,2], [-3, 1, 3, 70], :int64)) + r = @n + @m + expect(r).to eq(NMatrix.new(:dense, [2, 2], [-3, 1, 3, 70], :int64)) end it "subtracts" do - r = @n-@m - expect(r).to eq(NMatrix.new(:dense, [2,2], [5, 3, 3, -62], :int64)) + r = @n - @m + expect(r).to eq(NMatrix.new(:dense, [2, 2], [5, 3, 3, -62], :int64)) end it "multiplies" do - r = @n*@m - expect(r).to eq(NMatrix.new(:dense, [2,2], [-4, -2, 0, 264], :int64)) + r = @n * @m + expect(r).to eq(NMatrix.new(:dense, [2, 2], [-4, -2, 0, 264], :int64)) end it "divides in the Ruby way" do pending("not yet implemented int dtype for NMatrix-JRuby") if jruby? m = @m.clone - m[1,0] = 3 - r = @n/m - expect(r).to eq(NMatrix.new(:dense, [2,2], [-1, -2, 1, 0], :int64)) + m[1, 0] = 3 + r = @n / m + expect(r).to eq(NMatrix.new(:dense, [2, 2], [-1, -2, 1, 0], :int64)) end it "exponentiates" do - r = @n ** 2 + r = @n**2 # TODO: We might have problems with the dtype. - expect(r).to eq(NMatrix.new(:dense, [2,2], [1, 4, 9, 16], :int64)) + expect(r).to eq(NMatrix.new(:dense, [2, 2], [1, 4, 9, 16], :int64)) end it "modulo" do pending("not yet implemented int dtype for NMatrix-JRuby") if jruby? - expect(@n % (@m + 2)).to eq(NMatrix.new(:dense, [2,2], [-1, 0, 1, 4], :int64)) + expect(@n % (@m + 2)).to eq(NMatrix.new(:dense, [2, 2], [-1, 0, 1, 4], :int64)) end end context "elementwise comparisons" do before :each do - @n = NMatrix.new(:dense, 2, [1,2,3,4], :int64) - @m = NMatrix.new(:dense, 2, [-4,-1,3,2], :int64) + @n = NMatrix.new(:dense, 2, [1, 2, 3, 4], :int64) + @m = NMatrix.new(:dense, 2, [-4, -1, 3, 2], :int64) end it "equals" do r = @n =~ @m - expect(r).to eq(NMatrix.new(:dense, [2,2], [false, false, true, false], :object)) + expect(r).to eq(NMatrix.new(:dense, [2, 2], [false, false, true, false], :object)) end it "is not equal" do r = @n !~ @m - expect(r).to eq(NMatrix.new(:dense, [2,2], [true, true, false, true], :object)) + expect(r).to eq(NMatrix.new(:dense, [2, 2], [true, true, false, true], :object)) end it "is less than" do r = @n < @m - expect(r).to eq(NMatrix.new(:dense, [2,2], false, :object)) + expect(r).to eq(NMatrix.new(:dense, [2, 2], false, :object)) end it "is greater than" do r = @n > @m - expect(r).to eq(NMatrix.new(:dense, [2,2], [true, true, false, true], :object)) + expect(r).to eq(NMatrix.new(:dense, [2, 2], [true, true, false, true], :object)) end it "is less than or equal to" do r = @n <= @m - expect(r).to eq(NMatrix.new(:dense, [2,2], [false, false, true, false], :object)) + expect(r).to eq(NMatrix.new(:dense, [2, 2], [false, false, true, false], :object)) end it "is greater than or equal to" do - n = NMatrix.new(:dense, [2,2], [1, 2, 2, 4], :int64) + n = NMatrix.new(:dense, [2, 2], [1, 2, 2, 4], :int64) r = n >= @m - expect(r).to eq(NMatrix.new(:dense, [2,2], [true, true, false, true], :object)) + expect(r).to eq(NMatrix.new(:dense, [2, 2], [true, true, false, true], :object)) end end end diff --git a/spec/homogeneous_spec.rb b/spec/homogeneous_spec.rb index 4c186780..8cac2305 100644 --- a/spec/homogeneous_spec.rb +++ b/spec/homogeneous_spec.rb @@ -25,74 +25,73 @@ # Specs for the homogeneous transformation matrix methods. # -require 'spec_helper' +require "spec_helper" require "./lib/nmatrix/homogeneous.rb" -require 'pry' +require "pry" -describe 'NMatrix' do +describe "NMatrix" do context ".x_rotation" do it "should generate a matrix representing a rotation about the x axis" do - x = NMatrix.x_rotation(Math::PI/6) - expect(x).to be_within(1e-8).of(NMatrix.new([4,4], [1.0, 0.0, 0.0, 0.0, - 0.0, Math.cos(Math::PI/6), -0.5, 0.0, - 0.0, 0.5, Math.cos(Math::PI/6), 0.0, - 0.0, 0.0, 0.0, 1.0] )) + x = NMatrix.x_rotation(Math::PI / 6) + expect(x).to be_within(1e-8).of(NMatrix.new([4, 4], [1.0, 0.0, 0.0, 0.0, + 0.0, Math.cos(Math::PI / 6), -0.5, 0.0, + 0.0, 0.5, Math.cos(Math::PI / 6), 0.0, + 0.0, 0.0, 0.0, 1.0,])) end end - context ".y_rotation" do it "should generate a matrix representing a rotation about the y axis" do - y = NMatrix.y_rotation(Math::PI/6) - expect(y).to be_within(1e-8).of(NMatrix.new([4,4], [Math.cos(Math::PI/6), 0.0, 0.5, 0.0, - 0.0, 1.0, 0.0, 0.0, - -0.5, 0.0, Math.cos(Math::PI/6), 0.0, - 0.0, 0.0, 0.0, 1.0] )) + y = NMatrix.y_rotation(Math::PI / 6) + expect(y).to be_within(1e-8).of(NMatrix.new([4, 4], [Math.cos(Math::PI / 6), 0.0, 0.5, 0.0, + 0.0, 1.0, 0.0, 0.0, + -0.5, 0.0, Math.cos(Math::PI / 6), 0.0, + 0.0, 0.0, 0.0, 1.0,])) end end context ".z_rotation" do it "should generate a matrix representing a rotation about the z axis" do - z = NMatrix.z_rotation(Math::PI/6) - expect(z).to be_within(1e-8).of(NMatrix.new([4,4], [Math.cos(Math::PI/6), -0.5, 0.0, 0.0, - 0.5, Math.cos(Math::PI/6), 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0] )) + z = NMatrix.z_rotation(Math::PI / 6) + expect(z).to be_within(1e-8).of(NMatrix.new([4, 4], [Math.cos(Math::PI / 6), -0.5, 0.0, 0.0, + 0.5, Math.cos(Math::PI / 6), 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0,])) end end context ".translation" do it "should generate a translation matrix from an Array" do - t = NMatrix.translation([4,5,6]) - expect(t).to be_within(1e-8).of(NMatrix.new([4,4], [1, 0, 0, 4, - 0, 1, 0, 5, - 0, 0, 1, 6, - 0, 0, 0, 1] )) + t = NMatrix.translation([4, 5, 6]) + expect(t).to be_within(1e-8).of(NMatrix.new([4, 4], [1, 0, 0, 4, + 0, 1, 0, 5, + 0, 0, 1, 6, + 0, 0, 0, 1,])) end it "should generate a translation matrix from x, y, and z values" do - t = NMatrix.translation(4,5,6) - expect(t).to be_within(1e-8).of(NMatrix.new([4,4], [1, 0, 0, 4, - 0, 1, 0, 5, - 0, 0, 1, 6, - 0, 0, 0, 1] )) + t = NMatrix.translation(4, 5, 6) + expect(t).to be_within(1e-8).of(NMatrix.new([4, 4], [1, 0, 0, 4, + 0, 1, 0, 5, + 0, 0, 1, 6, + 0, 0, 0, 1,])) end it "should generate a translation matrix from an NMatrix with correctly inferred dtype" do pending("not yet implemented for NMatrix-JRuby") if jruby? - t = NMatrix.translation(NMatrix.new([3,1], [4,5,6], dtype: :float64) ) - expect(t).to be_within(1e-8).of(NMatrix.new([4,4], [1, 0, 0, 4, - 0, 1, 0, 5, - 0, 0, 1, 6, - 0, 0, 0, 1] )) + t = NMatrix.translation(NMatrix.new([3, 1], [4, 5, 6], dtype: :float64)) + expect(t).to be_within(1e-8).of(NMatrix.new([4, 4], [1, 0, 0, 4, + 0, 1, 0, 5, + 0, 0, 1, 6, + 0, 0, 0, 1,])) expect(t.dtype).to be(:float64) end end context "#quaternion" do it "should generate a singularity-free quaternion" do - transform = NMatrix.new([4,4], [-0.9995825,-0.02527934,-0.0139845,50.61761,-0.02732551,0.9844284,0.1736463,-22.95566,0.009376526,0.1739562,-0.9847089,7.1521,0,0,0,1]) + transform = NMatrix.new([4, 4], [-0.9995825, -0.02527934, -0.0139845, 50.61761, -0.02732551, 0.9844284, 0.1736463, -22.95566, 0.009376526, 0.1739562, -0.9847089, 7.1521, 0, 0, 0, 1]) q = transform.quaternion expect(Math.sqrt(q[0]**2 + q[1]**2 + q[2]**2 + q[3]**2)).to be_within(1e-6).of(1.0) end diff --git a/spec/io/fortran_format_spec.rb b/spec/io/fortran_format_spec.rb index db9a1f44..60d65121 100644 --- a/spec/io/fortran_format_spec.rb +++ b/spec/io/fortran_format_spec.rb @@ -25,31 +25,31 @@ # Basic tests for NMatrix::IO::FortranFormat. # -require './lib/nmatrix' +require "./lib/nmatrix" describe NMatrix::IO::FortranFormat do it "parses integer FORTRAN formats" do - int_fmt = NMatrix::IO::FortranFormat::Reader.new('(16I5)').parse + int_fmt = NMatrix::IO::FortranFormat::Reader.new("(16I5)").parse expect(int_fmt[:format_code]).to eq "INT_ID" expect(int_fmt[:repeat]) .to eq 16 - expect(int_fmt[:field_width]).to eq 5 + expect(int_fmt[:field_width]).to eq 5 - int_fmt = NMatrix::IO::FortranFormat::Reader.new('(I4)').parse + int_fmt = NMatrix::IO::FortranFormat::Reader.new("(I4)").parse expect(int_fmt[:format_code]).to eq "INT_ID" expect(int_fmt[:field_width]).to eq 4 end it "parses floating point FORTRAN formats" do - fp_fmt = NMatrix::IO::FortranFormat::Reader.new('(10F7.1)').parse + fp_fmt = NMatrix::IO::FortranFormat::Reader.new("(10F7.1)").parse expect(fp_fmt[:format_code]) .to eq "FP_ID" expect(fp_fmt[:repeat]) .to eq 10 expect(fp_fmt[:field_width]) .to eq 7 expect(fp_fmt[:post_decimal_width]).to eq 1 - fp_fmt = NMatrix::IO::FortranFormat::Reader.new('(F4.2)').parse + fp_fmt = NMatrix::IO::FortranFormat::Reader.new("(F4.2)").parse expect(fp_fmt[:format_code]) .to eq "FP_ID" expect(fp_fmt[:field_width]) .to eq 4 @@ -57,7 +57,7 @@ end it "parses exponential FORTRAN formats" do - exp_fmt = NMatrix::IO::FortranFormat::Reader.new('(2E8.3E3)').parse + exp_fmt = NMatrix::IO::FortranFormat::Reader.new("(2E8.3E3)").parse expect(exp_fmt[:format_code]) .to eq "EXP_ID" expect(exp_fmt[:repeat]) .to eq 2 @@ -65,24 +65,24 @@ expect(exp_fmt[:post_decimal_width]).to eq 3 expect(exp_fmt[:exponent_width]) .to eq 3 - exp_fmt = NMatrix::IO::FortranFormat::Reader.new('(3E3.6)').parse + exp_fmt = NMatrix::IO::FortranFormat::Reader.new("(3E3.6)").parse expect(exp_fmt[:format_code]) .to eq "EXP_ID" expect(exp_fmt[:repeat]) .to eq 3 expect(exp_fmt[:field_width]) .to eq 3 expect(exp_fmt[:post_decimal_width]).to eq 6 - exp_fmt = NMatrix::IO::FortranFormat::Reader.new('(E4.5)').parse + exp_fmt = NMatrix::IO::FortranFormat::Reader.new("(E4.5)").parse expect(exp_fmt[:format_code]) .to eq "EXP_ID" expect(exp_fmt[:field_width]) .to eq 4 expect(exp_fmt[:post_decimal_width]).to eq 5 end - ['I3', '(F4)', '(E3.', '(E4.E5)'].each do |bad_format| + ["I3", "(F4)", "(E3.", "(E4.E5)"].each do |bad_format| it "doesn't let bad input through : #{bad_format}" do expect { NMatrix::IO::FortranFormat::Reader.new(bad_format).parse }.to raise_error(IOError) + end end end -end diff --git a/spec/io/harwell_boeing_spec.rb b/spec/io/harwell_boeing_spec.rb index 36e1e16c..a2d00c13 100644 --- a/spec/io/harwell_boeing_spec.rb +++ b/spec/io/harwell_boeing_spec.rb @@ -25,7 +25,7 @@ # Basic tests for NMatrix::IO::HarwelBoeing. # TODO : After the fortran format thing is done -require 'spec_helper' +require "spec_helper" require "./lib/nmatrix" describe NMatrix::IO::HarwellBoeing do @@ -38,8 +38,8 @@ def check_file_header header expect(header[:indcrd]) .to eq(1) expect(header[:valcrd]) .to eq(3) expect(header[:rhscrd]) .to eq(0) - - expect(header[:mxtype]) .to eq('RUA') + + expect(header[:mxtype]) .to eq("RUA") expect(header[:nrow]) .to eq(5) expect(header[:ncol]) .to eq(5) expect(header[:nnzero]) .to eq(13) @@ -47,52 +47,52 @@ def check_file_header header expect(header[:ptrfmt]) .to eq({ format_code: "INT_ID", - repeat: 6, - field_width: 3 - }) - expect(header[:indfmt]) .to eq({ + repeat: 6, + field_width: 3, + }) + expect(header[:indfmt]) .to eq({ format_code: "INT_ID", - repeat: 13, - field_width: 3 - }) - expect(header[:valfmt]) .to eq({ - format_code: "EXP_ID", - repeat: 5, - field_width: 15, - post_decimal_width: 8 - }) - expect(header[:rhsfmt]) .to eq({ - format_code: "EXP_ID", - repeat: 5, - field_width: 15, - post_decimal_width: 8 - }) + repeat: 13, + field_width: 3, + }) + expect(header[:valfmt]) .to eq({ + format_code: "EXP_ID", + repeat: 5, + field_width: 15, + post_decimal_width: 8, + }) + expect(header[:rhsfmt]) .to eq({ + format_code: "EXP_ID", + repeat: 5, + field_width: 15, + post_decimal_width: 8, + }) end it "loads a Harwell Boeing file values and header (currently real only)" do n, h = NMatrix::IO::HarwellBoeing.load("spec/io/test.rua") - expect(n.is_a? NMatrix).to eq(true) + expect(n.is_a?(NMatrix)).to eq(true) expect(n.cols) .to eq(5) expect(n.rows) .to eq(5) - expect(n[0,0]) .to eq(11) - expect(n[4,4]) .to eq(55) + expect(n[0, 0]) .to eq(11) + expect(n[4, 4]) .to eq(55) - expect(h.is_a? Hash).to eq(true) + expect(h.is_a?(Hash)).to eq(true) check_file_header(h) end it "loads only the header of the file when specified" do h = NMatrix::IO::HarwellBoeing.load("spec/io/test.rua", header: true) - expect(h.is_a? Hash).to eq(true) + expect(h.is_a?(Hash)).to eq(true) check_file_header(h) end it "raises error for wrong Harwell Boeing file name" do - expect{ + expect { NMatrix::IO::HarwellBoeing.load("spec/io/wrong.afx") }.to raise_error(IOError) end -end \ No newline at end of file +end diff --git a/spec/io_spec.rb b/spec/io_spec.rb index 9d7b7d59..cbaef265 100644 --- a/spec/io_spec.rb +++ b/spec/io_spec.rb @@ -25,12 +25,12 @@ # Basic tests for NMatrix::IO. # require "tmpdir" # Used to avoid cluttering the repository. -require 'spec_helper' +require "spec_helper" require "./lib/nmatrix" describe NMatrix::IO do let(:tmp_dir) { Dir.mktmpdir } - let(:test_out) { File.join(tmp_dir, 'test-out') } + let(:test_out) { File.join(tmp_dir, "test-out") } it "repacks a string" do pending("not yet implemented for NMatrix-JRuby") if jruby? @@ -41,29 +41,29 @@ pending("not yet implemented for NMatrix-JRuby") if jruby? ia = NMatrix::IO::Matlab.repack("\0\1\3\3\4", :miUINT8, :itype) ja = NMatrix::IO::Matlab.repack("\0\1\3\0\0\0\0\0\0\0\0", :miUINT8, :itype) - n = NMatrix.new(:yale, [4,4], :byte, ia, ja, "\2\3\5\4", :byte) - expect(n[0,0]).to eq(2) - expect(n[1,1]).to eq(3) - expect(n[1,3]).to eq(5) - expect(n[3,0]).to eq(4) - expect(n[2,2]).to eq(0) - expect(n[3,3]).to eq(0) + n = NMatrix.new(:yale, [4, 4], :byte, ia, ja, "\2\3\5\4", :byte) + expect(n[0, 0]).to eq(2) + expect(n[1, 1]).to eq(3) + expect(n[1, 3]).to eq(5) + expect(n[3, 0]).to eq(4) + expect(n[2, 2]).to eq(0) + expect(n[3, 3]).to eq(0) end it "reads MATLAB .mat file containing a single square sparse matrix" do pending("not yet implemented for NMatrix-JRuby") if jruby? n = NMatrix::IO::Matlab.load_mat("spec/4x4_sparse.mat") - expect(n[0,0]).to eq(2) - expect(n[1,1]).to eq(3) - expect(n[1,3]).to eq(5) - expect(n[3,0]).to eq(4) - expect(n[2,2]).to eq(0) - expect(n[3,3]).to eq(0) + expect(n[0, 0]).to eq(2) + expect(n[1, 1]).to eq(3) + expect(n[1, 3]).to eq(5) + expect(n[3, 0]).to eq(4) + expect(n[2, 2]).to eq(0) + expect(n[3, 3]).to eq(0) end it "reads MATLAB .mat file containing a single dense integer matrix" do n = NMatrix::IO::Matlab.load_mat("spec/4x5_dense.mat") - m = NMatrix.new([4,5], [16,17,18,19,20,15,14,13,12,11,6,7,8,9,10,5,4,3,2,1]) + m = NMatrix.new([4, 5], [16, 17, 18, 19, 20, 15, 14, 13, 12, 11, 6, 7, 8, 9, 10, 5, 4, 3, 2, 1]) expect(n).to eq(m) end @@ -85,21 +85,19 @@ n = NMatrix::IO::PointCloud.load("spec/test.pcd") expect(n.column(0).sort.uniq.size).to eq(1) expect(n.column(0).sort.uniq.first).to eq(207.008) - expect(n[0,3]).to eq(0) + expect(n[0, 3]).to eq(0) end it "raises an error when reading a non-existent file" do pending("not yet implemented for NMatrix-JRuby") if jruby? fn = rand(10000000).to_i.to_s - while File.exist?(fn) - fn = rand(10000000).to_i.to_s - end - expect{ NMatrix.read(fn) }.to raise_error(Errno::ENOENT) + fn = rand(10000000).to_i.to_s while File.exist?(fn) + expect { NMatrix.read(fn) }.to raise_error(Errno::ENOENT) end it "reads and writes NMatrix dense" do pending("not yet implemented for NMatrix-JRuby") if jruby? - n = NMatrix.new(:dense, [4,3], [0,1,2,3,4,5,6,7,8,9,10,11], :int32) + n = NMatrix.new(:dense, [4, 3], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], :int32) n.write(test_out) m = NMatrix.read(test_out) @@ -108,7 +106,7 @@ it "reads and writes NMatrix dense as symmetric" do pending("not yet implemented for NMatrix-JRuby") if jruby? - n = NMatrix.new(:dense, 3, [0,1,2,1,3,4,2,4,5], :int16) + n = NMatrix.new(:dense, 3, [0, 1, 2, 1, 3, 4, 2, 4, 5], :int16) n.write(test_out, :symmetric) m = NMatrix.read(test_out) @@ -117,7 +115,7 @@ it "reads and writes NMatrix dense as skew" do pending("not yet implemented for NMatrix-JRuby") if jruby? - n = NMatrix.new(:dense, 3, [0,1,2,-1,3,4,-2,-4,5], :float64) + n = NMatrix.new(:dense, 3, [0, 1, 2, -1, 3, 4, -2, -4, 5], :float64) n.write(test_out, :skew) m = NMatrix.read(test_out) @@ -126,7 +124,7 @@ it "reads and writes NMatrix dense as hermitian" do pending("not yet implemented for NMatrix-JRuby") if jruby? - n = NMatrix.new(:dense, 3, [0,1,2,1,3,4,2,4,5], :complex64) + n = NMatrix.new(:dense, 3, [0, 1, 2, 1, 3, 4, 2, 4, 5], :complex64) n.write(test_out, :hermitian) m = NMatrix.read(test_out) @@ -135,10 +133,10 @@ it "reads and writes NMatrix dense as upper" do pending("not yet implemented for NMatrix-JRuby") if jruby? - n = NMatrix.new(:dense, 3, [-1,1,2,3,4,5,6,7,8], :int32) + n = NMatrix.new(:dense, 3, [-1, 1, 2, 3, 4, 5, 6, 7, 8], :int32) n.write(test_out, :upper) - m = NMatrix.new(:dense, 3, [-1,1,2,0,4,5,0,0,8], :int32) # lower version of the same + m = NMatrix.new(:dense, 3, [-1, 1, 2, 0, 4, 5, 0, 0, 8], :int32) # lower version of the same o = NMatrix.read(test_out) expect(o).to eq(m) @@ -147,10 +145,10 @@ it "reads and writes NMatrix dense as lower" do pending("not yet implemented for NMatrix-JRuby") if jruby? - n = NMatrix.new(:dense, 3, [-1,1,2,3,4,5,6,7,8], :int32) + n = NMatrix.new(:dense, 3, [-1, 1, 2, 3, 4, 5, 6, 7, 8], :int32) n.write(test_out, :lower) - m = NMatrix.new(:dense, 3, [-1,0,0,3,4,0,6,7,8], :int32) # lower version of the same + m = NMatrix.new(:dense, 3, [-1, 0, 0, 3, 4, 0, 6, 7, 8], :int32) # lower version of the same o = NMatrix.read(test_out) expect(o).to eq(m) diff --git a/spec/lapack_core_spec.rb b/spec/lapack_core_spec.rb index 2b93be7b..5cfdb7d1 100644 --- a/spec/lapack_core_spec.rb +++ b/spec/lapack_core_spec.rb @@ -29,7 +29,7 @@ # internal implmentations. # -require 'spec_helper' +require "spec_helper" describe "NMatrix::LAPACK functions with internal implementations" do # where integer math is allowed @@ -39,18 +39,18 @@ # element of piv, though maybe I misunderstand smth. It would make # more sense if piv were [2,1,3,3] it "exposes clapack laswp" do - a = NMatrix.new(:dense, [3,4], [1,2,3,4,5,6,7,8,9,10,11,12], dtype) - NMatrix::LAPACK::clapack_laswp(3, a, 4, 0, 3, [2,1,3,0], 1) - b = NMatrix.new(:dense, [3,4], [3,2,4,1,7,6,8,5,11,10,12,9], dtype) + a = NMatrix.new(:dense, [3, 4], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], dtype) + NMatrix::LAPACK.clapack_laswp(3, a, 4, 0, 3, [2, 1, 3, 0], 1) + b = NMatrix.new(:dense, [3, 4], [3, 2, 4, 1, 7, 6, 8, 5, 11, 10, 12, 9], dtype) expect(a).to eq(b) end # This spec is OK, because the default behavior for permute_columns # is :intuitive, which is different from :lapack (default laswp behavior) it "exposes NMatrix#permute_columns and #permute_columns! (user-friendly laswp)" do - a = NMatrix.new(:dense, [3,4], [1,2,3,4,5,6,7,8,9,10,11,12], dtype) - b = NMatrix.new(:dense, [3,4], [3,2,4,1,7,6,8,5,11,10,12,9], dtype) - piv = [2,1,3,0] + a = NMatrix.new(:dense, [3, 4], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], dtype) + b = NMatrix.new(:dense, [3, 4], [3, 2, 4, 1, 7, 6, 8, 5, 11, 10, 12, 9], dtype) + piv = [2, 1, 3, 0] r = a.permute_columns(piv) expect(r).not_to eq(a) expect(r).to eq(b) @@ -63,7 +63,6 @@ # where integer math is not allowed [:float32, :float64, :complex64, :complex128].each do |dtype| context dtype do - # clapack_getrf performs a LU decomposition, but unlike the # standard LAPACK getrf, it's the upper matrix that has unit diagonals # and the permutation is done in columns not rows. See the code for @@ -71,12 +70,12 @@ # Also the rows in the pivot vector are indexed starting from 0, # rather than 1 as in LAPACK it "calculates LU decomposition using clapack_getrf (row-major, square)" do - a = NMatrix.new(3, [4,9,2,3,5,7,8,1,6], dtype: dtype) - ipiv = NMatrix::LAPACK::clapack_getrf(:row, a.shape[0], a.shape[1], a, a.shape[1]) - b = NMatrix.new(3,[9, 2.0/9, 4.0/9, - 5, 53.0/9, 7.0/53, - 1, 52.0/9, 360.0/53], dtype: dtype) - ipiv_true = [1,2,2] + a = NMatrix.new(3, [4, 9, 2, 3, 5, 7, 8, 1, 6], dtype: dtype) + ipiv = NMatrix::LAPACK.clapack_getrf(:row, a.shape[0], a.shape[1], a, a.shape[1]) + b = NMatrix.new(3, [9, 2.0 / 9, 4.0 / 9, + 5, 53.0 / 9, 7.0 / 53, + 1, 52.0 / 9, 360.0 / 53,], dtype: dtype) + ipiv_true = [1, 2, 2] # delta varies for different dtypes err = case dtype @@ -84,21 +83,21 @@ 1e-6 when :float64, :complex128 1e-15 - end + end expect(a).to be_within(err).of(b) expect(ipiv).to eq(ipiv_true) end it "calculates LU decomposition using clapack_getrf (row-major, rectangular)" do - a = NMatrix.new([3,4], GETRF_EXAMPLE_ARRAY, dtype: dtype) - ipiv = NMatrix::LAPACK::clapack_getrf(:row, a.shape[0], a.shape[1], a, a.shape[1]) - #we can't use GETRF_SOLUTION_ARRAY here, because of the different - #conventions of clapack_getrf - b = NMatrix.new([3,4],[10.0, -0.1, 0.0, 0.4, - 3.0, 9.3, 20.0/93, 38.0/93, - 1.0, 7.1, 602.0/93, 251.0/602], dtype: dtype) - ipiv_true = [2,2,2] + a = NMatrix.new([3, 4], GETRF_EXAMPLE_ARRAY, dtype: dtype) + ipiv = NMatrix::LAPACK.clapack_getrf(:row, a.shape[0], a.shape[1], a, a.shape[1]) + # we can't use GETRF_SOLUTION_ARRAY here, because of the different + # conventions of clapack_getrf + b = NMatrix.new([3, 4], [10.0, -0.1, 0.0, 0.4, + 3.0, 9.3, 20.0 / 93, 38.0 / 93, + 1.0, 7.1, 602.0 / 93, 251.0 / 602,], dtype: dtype) + ipiv_true = [2, 2, 2] # delta varies for different dtypes err = case dtype @@ -106,24 +105,24 @@ 1e-6 when :float64, :complex128 1e-15 - end + end expect(a).to be_within(err).of(b) expect(ipiv).to eq(ipiv_true) end - #Normally we wouldn't check column-major routines, since all our matrices - #are row-major, but we use the column-major version in #getrf!, so we - #want to test it here. + # Normally we wouldn't check column-major routines, since all our matrices + # are row-major, but we use the column-major version in #getrf!, so we + # want to test it here. it "calculates LU decomposition using clapack_getrf (col-major, rectangular)" do - #this is supposed to represent the 3x2 matrix + # this is supposed to represent the 3x2 matrix # -1 2 # 0 3 # 1 -2 - a = NMatrix.new([1,6], [-1,0,1,2,3,-2], dtype: dtype) - ipiv = NMatrix::LAPACK::clapack_getrf(:col, 3, 2, a, 3) - b = NMatrix.new([1,6], [-1,0,-1,2,3,0], dtype: dtype) - ipiv_true = [0,1] + a = NMatrix.new([1, 6], [-1, 0, 1, 2, 3, -2], dtype: dtype) + ipiv = NMatrix::LAPACK.clapack_getrf(:col, 3, 2, a, 3) + b = NMatrix.new([1, 6], [-1, 0, -1, 2, 3, 0], dtype: dtype) + ipiv_true = [0, 1] # delta varies for different dtypes err = case dtype @@ -131,17 +130,17 @@ 1e-6 when :float64, :complex128 1e-15 - end + end expect(a).to be_within(err).of(b) expect(ipiv).to eq(ipiv_true) end it "calculates LU decomposition using #getrf! (rectangular)" do - a = NMatrix.new([3,4], GETRF_EXAMPLE_ARRAY, dtype: dtype) + a = NMatrix.new([3, 4], GETRF_EXAMPLE_ARRAY, dtype: dtype) ipiv = a.getrf! - b = NMatrix.new([3,4], GETRF_SOLUTION_ARRAY, dtype: dtype) - ipiv_true = [2,3,3] + b = NMatrix.new([3, 4], GETRF_SOLUTION_ARRAY, dtype: dtype) + ipiv_true = [2, 3, 3] # delta varies for different dtypes err = case dtype @@ -149,18 +148,18 @@ 1e-6 when :float64, :complex128 1e-14 - end + end expect(a).to be_within(err).of(b) expect(ipiv).to eq(ipiv_true) end it "calculates LU decomposition using #getrf! (square)" do - a = NMatrix.new([4,4], [0,1,2,3, 1,1,1,1, 0,-1,-2,0, 0,2,0,2], dtype: dtype) + a = NMatrix.new([4, 4], [0, 1, 2, 3, 1, 1, 1, 1, 0, -1, -2, 0, 0, 2, 0, 2], dtype: dtype) ipiv = a.getrf! - b = NMatrix.new([4,4], [1,1,1,1, 0,2,0,2, 0,-0.5,-2,1, 0,0.5,-1,3], dtype: dtype) - ipiv_true = [2,4,3,4] + b = NMatrix.new([4, 4], [1, 1, 1, 1, 0, 2, 0, 2, 0, -0.5, -2, 1, 0, 0.5, -1, 3], dtype: dtype) + ipiv_true = [2, 4, 3, 4] expect(a).to eq(b) expect(ipiv).to eq(ipiv_true) @@ -168,92 +167,92 @@ # Together, these calls are basically xGESV from LAPACK: http://www.netlib.org/lapack/double/dgesv.f it "exposes clapack_getrs" do - a = NMatrix.new(3, [-2,4,-3, 3,-2,1, 0,-4,3], dtype: dtype) - ipiv = NMatrix::LAPACK::clapack_getrf(:row, 3, 3, a, 3) - b = NMatrix.new([3,1], [-1, 17, -9], dtype: dtype) + a = NMatrix.new(3, [-2, 4, -3, 3, -2, 1, 0, -4, 3], dtype: dtype) + ipiv = NMatrix::LAPACK.clapack_getrf(:row, 3, 3, a, 3) + b = NMatrix.new([3, 1], [-1, 17, -9], dtype: dtype) - NMatrix::LAPACK::clapack_getrs(:row, false, 3, 1, a, 3, ipiv, b, 3) + NMatrix::LAPACK.clapack_getrs(:row, false, 3, 1, a, 3, ipiv, b, 3) expect(b[0]).to eq(5) - expect(b[1]).to eq(-15.0/2) + expect(b[1]).to eq(-15.0 / 2) expect(b[2]).to eq(-13) end it "solves matrix equation (non-vector rhs) using clapack_getrs" do - a = NMatrix.new(3, [-2,4,-3, 3,-2,1, 0,-4,3], dtype: dtype) - b = NMatrix.new([3,2], [-1,2, 17,1, -9,-4], dtype: dtype) + a = NMatrix.new(3, [-2, 4, -3, 3, -2, 1, 0, -4, 3], dtype: dtype) + b = NMatrix.new([3, 2], [-1, 2, 17, 1, -9, -4], dtype: dtype) n = a.shape[0] nrhs = b.shape[1] - ipiv = NMatrix::LAPACK::clapack_getrf(:row, n, n, a, n) + ipiv = NMatrix::LAPACK.clapack_getrf(:row, n, n, a, n) # Even though we pass :row to clapack_getrs, it still interprets b as # column-major, so need to transpose b before and after: b = b.transpose - NMatrix::LAPACK::clapack_getrs(:row, false, n, nrhs, a, n, ipiv, b, n) + NMatrix::LAPACK.clapack_getrs(:row, false, n, nrhs, a, n, ipiv, b, n) b = b.transpose - b_true = NMatrix.new([3,2], [5,1, -7.5,1, -13,0], dtype: dtype) + b_true = NMatrix.new([3, 2], [5, 1, -7.5, 1, -13, 0], dtype: dtype) expect(b).to eq(b_true) end - #posv is like potrf+potrs - #posv is implemented in both nmatrix-atlas and nmatrix-lapacke, so the spec - #needs to be shared here + # posv is like potrf+potrs + # posv is implemented in both nmatrix-atlas and nmatrix-lapacke, so the spec + # needs to be shared here it "solves a (symmetric positive-definite) matrix equation using posv (vector rhs)" do - a = NMatrix.new(3, [4, 0,-1, + a = NMatrix.new(3, [4, 0, -1, 0, 2, 1, - 0, 0, 1], dtype: dtype) - b = NMatrix.new([3,1], [4,2,0], dtype: dtype) + 0, 0, 1,], dtype: dtype) + b = NMatrix.new([3, 1], [4, 2, 0], dtype: dtype) begin - x = NMatrix::LAPACK::posv(:upper, a, b) + x = NMatrix::LAPACK.posv(:upper, a, b) rescue NotImplementedError => e pending e.to_s end - x_true = NMatrix.new([3,1], [1, 1, 0], dtype: dtype) + x_true = NMatrix.new([3, 1], [1, 1, 0], dtype: dtype) err = case dtype when :float32, :complex64 1e-5 when :float64, :complex128 1e-14 - end + end expect(x).to be_within(err).of(x_true) end it "solves a (symmetric positive-definite) matrix equation using posv (non-vector rhs)" do - a = NMatrix.new(3, [4, 0,-1, + a = NMatrix.new(3, [4, 0, -1, 0, 2, 1, - 0, 0, 1], dtype: dtype) - b = NMatrix.new([3,2], [4,-1, 2,-1, 0,0], dtype: dtype) + 0, 0, 1,], dtype: dtype) + b = NMatrix.new([3, 2], [4, -1, 2, -1, 0, 0], dtype: dtype) begin - x = NMatrix::LAPACK::posv(:upper, a, b) + x = NMatrix::LAPACK.posv(:upper, a, b) rescue NotImplementedError => e pending e.to_s end - x_true = NMatrix.new([3,2], [1,0, 1,-1, 0,1], dtype: dtype) + x_true = NMatrix.new([3, 2], [1, 0, 1, -1, 0, 1], dtype: dtype) err = case dtype when :float32, :complex64 1e-5 when :float64, :complex128 1e-14 - end + end expect(x).to be_within(err).of(x_true) end it "calculates the singular value decomposition with NMatrix#gesvd" do - #example from Wikipedia + # example from Wikipedia m = 4 n = 5 - mn_min = [m,n].min - a = NMatrix.new([m,n],[1,0,0,0,2, 0,0,3,0,0, 0,0,0,0,0, 0,4,0,0,0], dtype: dtype) + mn_min = [m, n].min + a = NMatrix.new([m, n], [1, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0], dtype: dtype) begin u, s, vt = a.gesvd @@ -261,16 +260,16 @@ pending e.to_s end - s_true = NMatrix.new([mn_min,1], [4,3,Math.sqrt(5),0], dtype: a.abs_dtype) - u_true = NMatrix.new([m,m], [0,0,1,0, 0,1,0,0, 0,0,0,-1, 1,0,0,0], dtype: dtype) - vt_true = NMatrix.new([n,n], [0,1,0,0,0, 0,0,1,0,0, Math.sqrt(0.2),0,0,0,Math.sqrt(0.8), 0,0,0,1,0, -Math.sqrt(0.8),0,0,0,Math.sqrt(0.2)], dtype: dtype) + s_true = NMatrix.new([mn_min, 1], [4, 3, Math.sqrt(5), 0], dtype: a.abs_dtype) + u_true = NMatrix.new([m, m], [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0], dtype: dtype) + vt_true = NMatrix.new([n, n], [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, Math.sqrt(0.2), 0, 0, 0, Math.sqrt(0.8), 0, 0, 0, 1, 0, -Math.sqrt(0.8), 0, 0, 0, Math.sqrt(0.2)], dtype: dtype) err = case dtype when :float32, :complex64 1e-5 when :float64, :complex128 1e-14 - end + end expect(s).to be_within(err).of(s_true) expect(u).to be_within(err).of(u_true) @@ -282,11 +281,11 @@ end it "calculates the singular value decomposition with NMatrix#gesdd" do - #example from Wikipedia + # example from Wikipedia m = 4 n = 5 - mn_min = [m,n].min - a = NMatrix.new([m,n],[1,0,0,0,2, 0,0,3,0,0, 0,0,0,0,0, 0,4,0,0,0], dtype: dtype) + mn_min = [m, n].min + a = NMatrix.new([m, n], [1, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0], dtype: dtype) begin u, s, vt = a.gesdd @@ -294,26 +293,25 @@ pending e.to_s end - s_true = NMatrix.new([mn_min,1], [4,3,Math.sqrt(5),0], dtype: a.abs_dtype) - u_true = NMatrix.new([m,m], [0,0,1,0, 0,1,0,0, 0,0,0,-1, 1,0,0,0], dtype: dtype) - vt_true = NMatrix.new([n,n], [0,1,0,0,0, 0,0,1,0,0, Math.sqrt(0.2),0,0,0,Math.sqrt(0.8), 0,0,0,1,0, -Math.sqrt(0.8),0,0,0,Math.sqrt(0.2)], dtype: dtype) + s_true = NMatrix.new([mn_min, 1], [4, 3, Math.sqrt(5), 0], dtype: a.abs_dtype) + u_true = NMatrix.new([m, m], [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0], dtype: dtype) + vt_true = NMatrix.new([n, n], [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, Math.sqrt(0.2), 0, 0, 0, Math.sqrt(0.8), 0, 0, 0, 1, 0, -Math.sqrt(0.8), 0, 0, 0, Math.sqrt(0.2)], dtype: dtype) err = case dtype when :float32, :complex64 1e-5 when :float64, :complex128 1e-14 - end + end expect(s).to be_within(err).of(s_true) expect(u).to be_within(err).of(u_true) expect(vt).to be_within(err).of(vt_true) end - it "calculates eigenvalues and eigenvectors NMatrix::LAPACK.geev (real matrix, complex eigenvalues)" do n = 3 - a = NMatrix.new([n,n], [-1,0,0, 0,1,-2, 0,1,-1], dtype: dtype) + a = NMatrix.new([n, n], [-1, 0, 0, 0, 1, -2, 0, 1, -1], dtype: dtype) begin eigenvalues, vl, vr = NMatrix::LAPACK.geev(a) @@ -321,20 +319,20 @@ pending e.to_s end - eigenvalues_true = NMatrix.new([n,1], [Complex(0,1), -Complex(0,1), -1], dtype: NMatrix.upcast(dtype, :complex64)) - vr_true = NMatrix.new([n,n],[0,0,1, - 2/Math.sqrt(6),2/Math.sqrt(6),0, - Complex(1,-1)/Math.sqrt(6),Complex(1,1)/Math.sqrt(6),0], dtype: NMatrix.upcast(dtype, :complex64)) - vl_true = NMatrix.new([n,n],[0,0,1, - Complex(-1,1)/Math.sqrt(6),Complex(-1,-1)/Math.sqrt(6),0, - 2/Math.sqrt(6),2/Math.sqrt(6),0], dtype: NMatrix.upcast(dtype, :complex64)) + eigenvalues_true = NMatrix.new([n, 1], [Complex(0, 1), -Complex(0, 1), -1], dtype: NMatrix.upcast(dtype, :complex64)) + vr_true = NMatrix.new([n, n], [0, 0, 1, + 2 / Math.sqrt(6), 2 / Math.sqrt(6), 0, + Complex(1, -1) / Math.sqrt(6), Complex(1, 1) / Math.sqrt(6), 0,], dtype: NMatrix.upcast(dtype, :complex64)) + vl_true = NMatrix.new([n, n], [0, 0, 1, + Complex(-1, 1) / Math.sqrt(6), Complex(-1, -1) / Math.sqrt(6), 0, + 2 / Math.sqrt(6), 2 / Math.sqrt(6), 0,], dtype: NMatrix.upcast(dtype, :complex64)) err = case dtype when :float32, :complex64 1e-6 when :float64, :complex128 1e-15 - end + end expect(eigenvalues).to be_within(err).of(eigenvalues_true) expect(vr).to be_within(err).of(vr_true) @@ -347,7 +345,7 @@ it "calculates eigenvalues and eigenvectors NMatrix::LAPACK.geev (real matrix, real eigenvalues)" do n = 3 - a = NMatrix.new([n,n], [2,0,0, 0,3,2, 0,1,2], dtype: dtype) + a = NMatrix.new([n, n], [2, 0, 0, 0, 3, 2, 0, 1, 2], dtype: dtype) begin eigenvalues, vl, vr = NMatrix::LAPACK.geev(a) @@ -355,25 +353,25 @@ pending e.to_s end - eigenvalues_true = NMatrix.new([n,1], [1, 4, 2], dtype: dtype) + eigenvalues_true = NMatrix.new([n, 1], [1, 4, 2], dtype: dtype) # For some reason, some of the eigenvectors have different signs # when we use the complex versions of geev. This is totally fine, since # they are still normalized eigenvectors even with the sign flipped. if a.complex_dtype? - vr_true = NMatrix.new([n,n],[0,0,1, - 1/Math.sqrt(2),2/Math.sqrt(5),0, - -1/Math.sqrt(2),1/Math.sqrt(5),0], dtype: dtype) - vl_true = NMatrix.new([n,n],[0,0,1, - -1/Math.sqrt(5),1/Math.sqrt(2),0, - 2/Math.sqrt(5),1/Math.sqrt(2),0], dtype: dtype) + vr_true = NMatrix.new([n, n], [0, 0, 1, + 1 / Math.sqrt(2), 2 / Math.sqrt(5), 0, + -1 / Math.sqrt(2), 1 / Math.sqrt(5), 0,], dtype: dtype) + vl_true = NMatrix.new([n, n], [0, 0, 1, + -1 / Math.sqrt(5), 1 / Math.sqrt(2), 0, + 2 / Math.sqrt(5), 1 / Math.sqrt(2), 0,], dtype: dtype) else - vr_true = NMatrix.new([n,n],[0,0,1, - 1/Math.sqrt(2),-2/Math.sqrt(5),0, - -1/Math.sqrt(2),-1/Math.sqrt(5),0], dtype: dtype) - vl_true = NMatrix.new([n,n],[0,0,1, - 1/Math.sqrt(5),-1/Math.sqrt(2),0, - -2/Math.sqrt(5),-1/Math.sqrt(2),0], dtype: dtype) + vr_true = NMatrix.new([n, n], [0, 0, 1, + 1 / Math.sqrt(2), -2 / Math.sqrt(5), 0, + -1 / Math.sqrt(2), -1 / Math.sqrt(5), 0,], dtype: dtype) + vl_true = NMatrix.new([n, n], [0, 0, 1, + 1 / Math.sqrt(5), -1 / Math.sqrt(2), 0, + -2 / Math.sqrt(5), -1 / Math.sqrt(2), 0,], dtype: dtype) end err = case dtype @@ -381,7 +379,7 @@ 1e-6 when :float64, :complex128 1e-15 - end + end expect(eigenvalues).to be_within(err).of(eigenvalues_true) expect(vr).to be_within(err).of(vr_true) @@ -394,7 +392,7 @@ it "calculates eigenvalues and eigenvectors NMatrix::LAPACK.geev (left eigenvectors only)" do n = 3 - a = NMatrix.new([n,n], [-1,0,0, 0,1,-2, 0,1,-1], dtype: dtype) + a = NMatrix.new([n, n], [-1, 0, 0, 0, 1, -2, 0, 1, -1], dtype: dtype) begin eigenvalues, vl = NMatrix::LAPACK.geev(a, :left) @@ -402,17 +400,17 @@ pending e.to_s end - eigenvalues_true = NMatrix.new([n,1], [Complex(0,1), -Complex(0,1), -1], dtype: NMatrix.upcast(dtype, :complex64)) - vl_true = NMatrix.new([n,n],[0,0,1, - Complex(-1,1)/Math.sqrt(6),Complex(-1,-1)/Math.sqrt(6),0, - 2/Math.sqrt(6),2/Math.sqrt(6),0], dtype: NMatrix.upcast(dtype, :complex64)) + eigenvalues_true = NMatrix.new([n, 1], [Complex(0, 1), -Complex(0, 1), -1], dtype: NMatrix.upcast(dtype, :complex64)) + vl_true = NMatrix.new([n, n], [0, 0, 1, + Complex(-1, 1) / Math.sqrt(6), Complex(-1, -1) / Math.sqrt(6), 0, + 2 / Math.sqrt(6), 2 / Math.sqrt(6), 0,], dtype: NMatrix.upcast(dtype, :complex64)) err = case dtype when :float32, :complex64 1e-6 when :float64, :complex128 1e-15 - end + end expect(eigenvalues).to be_within(err).of(eigenvalues_true) expect(vl).to be_within(err).of(vl_true) @@ -420,7 +418,7 @@ it "calculates eigenvalues and eigenvectors NMatrix::LAPACK.geev (right eigenvectors only)" do n = 3 - a = NMatrix.new([n,n], [-1,0,0, 0,1,-2, 0,1,-1], dtype: dtype) + a = NMatrix.new([n, n], [-1, 0, 0, 0, 1, -2, 0, 1, -1], dtype: dtype) begin eigenvalues, vr = NMatrix::LAPACK.geev(a, :right) @@ -428,17 +426,17 @@ pending e.to_s end - eigenvalues_true = NMatrix.new([n,1], [Complex(0,1), -Complex(0,1), -1], dtype: NMatrix.upcast(dtype, :complex64)) - vr_true = NMatrix.new([n,n],[0,0,1, - 2/Math.sqrt(6),2/Math.sqrt(6),0, - Complex(1,-1)/Math.sqrt(6),Complex(1,1)/Math.sqrt(6),0], dtype: NMatrix.upcast(dtype, :complex64)) + eigenvalues_true = NMatrix.new([n, 1], [Complex(0, 1), -Complex(0, 1), -1], dtype: NMatrix.upcast(dtype, :complex64)) + vr_true = NMatrix.new([n, n], [0, 0, 1, + 2 / Math.sqrt(6), 2 / Math.sqrt(6), 0, + Complex(1, -1) / Math.sqrt(6), Complex(1, 1) / Math.sqrt(6), 0,], dtype: NMatrix.upcast(dtype, :complex64)) err = case dtype when :float32, :complex64 1e-6 when :float64, :complex128 1e-15 - end + end expect(eigenvalues).to be_within(err).of(eigenvalues_true) expect(vr).to be_within(err).of(vr_true) @@ -450,7 +448,7 @@ context dtype do it "calculates eigenvalues and eigenvectors NMatrix::LAPACK.geev (complex matrix)" do n = 3 - a = NMatrix.new([n,n], [Complex(0,1),0,0, 0,3,2, 0,1,2], dtype: dtype) + a = NMatrix.new([n, n], [Complex(0, 1), 0, 0, 0, 3, 2, 0, 1, 2], dtype: dtype) begin eigenvalues, vl, vr = NMatrix::LAPACK.geev(a) @@ -458,20 +456,20 @@ pending e.to_s end - eigenvalues_true = NMatrix.new([n,1], [1, 4, Complex(0,1)], dtype: dtype) - vr_true = NMatrix.new([n,n],[0,0,1, - 1/Math.sqrt(2),2/Math.sqrt(5),0, - -1/Math.sqrt(2),1/Math.sqrt(5),0], dtype: dtype) - vl_true = NMatrix.new([n,n],[0,0,1, - -1/Math.sqrt(5),1/Math.sqrt(2),0, - 2/Math.sqrt(5),1/Math.sqrt(2),0], dtype: dtype) + eigenvalues_true = NMatrix.new([n, 1], [1, 4, Complex(0, 1)], dtype: dtype) + vr_true = NMatrix.new([n, n], [0, 0, 1, + 1 / Math.sqrt(2), 2 / Math.sqrt(5), 0, + -1 / Math.sqrt(2), 1 / Math.sqrt(5), 0,], dtype: dtype) + vl_true = NMatrix.new([n, n], [0, 0, 1, + -1 / Math.sqrt(5), 1 / Math.sqrt(2), 0, + 2 / Math.sqrt(5), 1 / Math.sqrt(2), 0,], dtype: dtype) err = case dtype when :float32, :complex64 1e-6 when :float64, :complex128 1e-15 - end + end expect(eigenvalues).to be_within(err).of(eigenvalues_true) expect(vr).to be_within(err).of(vr_true) diff --git a/spec/leakcheck.rb b/spec/leakcheck.rb index 23b16d13..81303c5e 100644 --- a/spec/leakcheck.rb +++ b/spec/leakcheck.rb @@ -1,16 +1,16 @@ require "./lib/nmatrix" # Fixed: -#n = NMatrix.new(:yale, [8,2], :int64) -#m = NMatrix.new(:yale, [2,8], :int64) -#100.times do +# n = NMatrix.new(:yale, [8,2], :int64) +# m = NMatrix.new(:yale, [2,8], :int64) +# 100.times do # n.dot(m) -#end -#GC.start +# end +# GC.start # Remaining: 100.times do |t| n = NMatrix.new(:dense, 1000, :float64) - n[0,t] = 1.0 - puts n[t,0] + n[0, t] = 1.0 + puts n[t, 0] end diff --git a/spec/math_spec.rb b/spec/math_spec.rb index e1ee8d45..196f0cc9 100644 --- a/spec/math_spec.rb +++ b/spec/math_spec.rb @@ -26,27 +26,26 @@ # versions of unfriendly BLAS and LAPACK functions. # -require 'spec_helper' +require "spec_helper" describe "math" do context "elementwise math functions" do - - [:dense,:list,:yale].each do |stype| + [:dense, :list, :yale].each do |stype| context stype do - - [:int64,:float64].each do |dtype| + [:int64, :float64].each do |dtype| context dtype do before :each do - @size = [2,2] - @m = NMatrix.seq(@size, dtype: dtype, stype: stype)+1 + @size = [2, 2] + @m = NMatrix.seq(@size, dtype: dtype, stype: stype) + 1 @a = @m.to_a.flatten end NMatrix::NMMath::METHODS_ARITY_1.each do |meth| - #skip inverse regular trig functions - next if meth.to_s.start_with?('a') and (not meth.to_s.end_with?('h')) \ - and NMatrix::NMMath::METHODS_ARITY_1.include?( - meth.to_s[1...meth.to_s.length].to_sym) + # skip inverse regular trig functions + next if meth.to_s.start_with?("a") && !meth.to_s.end_with?("h") \ + && NMatrix::NMMath::METHODS_ARITY_1.include?( + meth.to_s[1...meth.to_s.length].to_sym + ) next if meth == :atanh if meth == :-@ @@ -57,19 +56,19 @@ end it "should correctly apply elementwise #{meth}" do - - expect(@m.send(meth)).to eq N.new(@size, @a.map{ |e| Math.send(meth, e) }, - dtype: :float64, stype: stype) + expect(@m.send(meth)).to eq N.new(@size, @a.map { |e| Math.send(meth, e) }, + dtype: :float64, stype: stype) end end NMatrix::NMMath::METHODS_ARITY_2.each do |meth| next if meth == :atan2 it "should correctly apply elementwise #{meth}" do - expect(@m.send(meth, @m)).to eq N.new(@size, @a.map{ |e| - Math.send(meth, e, e) }, - dtype: :float64, - stype: stype) + expect(@m.send(meth, @m)).to eq N.new(@size, @a.map { |e| + Math.send(meth, e, e) + }, + dtype: :float64, + stype: stype) end it "should correctly apply elementwise #{meth} with a scalar first arg" do @@ -83,30 +82,29 @@ it "should correctly apply elementwise natural log" do expect(@m.log).to eq N.new(@size, [0, Math.log(2), Math.log(3), Math.log(4)], - dtype: :float64, stype: stype) + dtype: :float64, stype: stype) end it "should correctly apply elementwise log with arbitrary base" do - expect(@m.log(3)).to eq N.new(@size, [0, Math.log(2,3), 1, Math.log(4,3)], - dtype: :float64, stype: stype) + expect(@m.log(3)).to eq N.new(@size, [0, Math.log(2, 3), 1, Math.log(4, 3)], + dtype: :float64, stype: stype) end context "inverse trig functions" do before :each do - @m = NMatrix.seq(@size, dtype: dtype, stype: stype)/4 + @m = NMatrix.seq(@size, dtype: dtype, stype: stype) / 4 @a = @m.to_a.flatten end [:asin, :acos, :atan, :atanh].each do |atf| - it "should correctly apply elementwise #{atf}" do expect(@m.send(atf)).to eq N.new(@size, - @a.map{ |e| Math.send(atf, e) }, - dtype: :float64, stype: stype) + @a.map { |e| Math.send(atf, e) }, + dtype: :float64, stype: stype) end end it "should correctly apply elementtwise atan2" do - expect(@m.atan2(@m*0+1)).to eq N.new(@size, + expect(@m.atan2(@m * 0 + 1)).to eq N.new(@size, @a.map { |e| Math.send(:atan2, e, 1) }, dtype: :float64, stype: stype) end @@ -115,26 +113,25 @@ end it "should correctly apply elementwise atan2 with a scalar second arg" do - expect(@m.atan2(1)).to eq N.new(@size, @a.map { |e| Math.send(:atan2, e, 1) }, dtype: :float64, stype: stype) + expect(@m.atan2(1)).to eq N.new(@size, @a.map { |e| Math.send(:atan2, e, 1) }, dtype: :float64, stype: stype) end end end end context "Floor and ceil for #{stype}" do - [:floor, :ceil].each do |meth| ALL_DTYPES.each do |dtype| context dtype do before :each do - @size = [2,2] - @m = NMatrix.seq(@size, dtype: dtype, stype: stype)+1 unless jruby? and dtype == :object + @size = [2, 2] + @m = NMatrix.seq(@size, dtype: dtype, stype: stype) + 1 unless jruby? && (dtype == :object) @a = @m.to_a.flatten end - if dtype.to_s.match(/int/) or [:byte, :object].include?(dtype) + if dtype.to_s.match(/int/) || [:byte, :object].include?(dtype) it "should return #{dtype} for #{dtype}" do - pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :object) expect(@m.send(meth)).to eq N.new(@size, @a.map { |e| e.send(meth) }, dtype: dtype, stype: stype) @@ -144,14 +141,13 @@ expect(@m.send(meth).integer_dtype?).to eq true end end - elsif dtype.to_s.match(/float/) + elsif /float/.match?(dtype.to_s) it "should return dtype int64 for #{dtype}" do - expect(@m.send(meth)).to eq N.new(@size, @a.map { |e| e.send(meth) }, dtype: dtype, stype: stype) expect(@m.send(meth).dtype).to eq :int64 end - elsif dtype.to_s.match(/complex/) + elsif /complex/.match?(dtype.to_s) it "should properly calculate #{meth} for #{dtype}" do pending("not yet implemented for NMatrix-JRuby") if jruby? @@ -170,40 +166,49 @@ ALL_DTYPES.each do |dtype| context dtype do before :each do - @size = [2,2] + @size = [2, 2] @mat = NMatrix.new @size, [1.33334, 0.9998, 1.9999, -8.9999], dtype: dtype, stype: stype - @ans = @mat.to_a.flatten unless jruby? and dtype == :object + @ans = @mat.to_a.flatten unless jruby? && (dtype == :object) + end + + unless /complex/.match?(dtype) + it "rounds" do + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :object) + expect(@mat.round).to eq(N.new(@size, @ans.map { |a| a.round}, + dtype: dtype, stype: stype)) + end + end + + unless /complex/.match?(dtype) + it "rounds with args" do + pending("not yet implemented for NMatrix-JRuby") if jruby? + expect(@mat.round(2)).to eq(N.new(@size, @ans.map { |a| a.round(2)}, + dtype: dtype, stype: stype)) + end end - it "rounds" do - pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object - expect(@mat.round).to eq(N.new(@size, @ans.map { |a| a.round}, - dtype: dtype, stype: stype)) - end unless(/complex/ =~ dtype) - - it "rounds with args" do - pending("not yet implemented for NMatrix-JRuby") if jruby? - expect(@mat.round(2)).to eq(N.new(@size, @ans.map { |a| a.round(2)}, - dtype: dtype, stype: stype)) - end unless(/complex/ =~ dtype) - - it "rounds complex with args" do - pending("not yet implemented for NMatrix-JRuby") if jruby? - puts @mat.round(2) - expect(@mat.round(2)).to be_within(0.0001).of(N.new [2,2], @ans.map {|a| - Complex(a.real.round(2), a.imag.round(2))},dtype: dtype, stype: stype) - end if(/complex/ =~ dtype) - - it "rounds complex" do - pending("not yet implemented for NMatrix-JRuby") if jruby? - expect(@mat.round).to eq(N.new [2,2], @ans.map {|a| - Complex(a.real.round, a.imag.round)},dtype: dtype, stype: stype) - end if(/complex/ =~ dtype) + if /complex/.match?(dtype) + it "rounds complex with args" do + pending("not yet implemented for NMatrix-JRuby") if jruby? + puts @mat.round(2) + expect(@mat.round(2)).to be_within(0.0001).of(N.new([2, 2], @ans.map {|a| + Complex(a.real.round(2), a.imag.round(2)) + }, dtype: dtype, stype: stype)) + end + end + + if /complex/.match?(dtype) + it "rounds complex" do + pending("not yet implemented for NMatrix-JRuby") if jruby? + expect(@mat.round).to eq(N.new([2, 2], @ans.map {|a| + Complex(a.real.round, a.imag.round) + }, dtype: dtype, stype: stype)) + end + end end end end - end end end @@ -211,21 +216,21 @@ NON_INTEGER_DTYPES.each do |dtype| context dtype do before do - @m = NMatrix.new([3,4], GETRF_EXAMPLE_ARRAY, dtype: dtype) + @m = NMatrix.new([3, 4], GETRF_EXAMPLE_ARRAY, dtype: dtype) @err = case dtype when :float32, :complex64 1e-6 when :float64, :complex128 1e-14 - end + end end - #haven't check this spec yet. Also it doesn't check all the elements of the matrix. + # haven't check this spec yet. Also it doesn't check all the elements of the matrix. it "should correctly factorize a matrix" do pending("not yet implemented for :object dtype") if dtype == :object pending("not yet implemented for NMatrix-JRuby") if jruby? a = @m.factorize_lu - expect(a).to be_within(@err).of(NMatrix.new([3,4], GETRF_SOLUTION_ARRAY, dtype: dtype)) + expect(a).to be_within(@err).of(NMatrix.new([3, 4], GETRF_SOLUTION_ARRAY, dtype: dtype)) end it "also returns the permutation matrix" do @@ -234,9 +239,9 @@ a, p = @m.factorize_lu perm_matrix: true - expect(a).to be_within(@err).of(NMatrix.new([3,4], GETRF_SOLUTION_ARRAY, dtype: dtype)) + expect(a).to be_within(@err).of(NMatrix.new([3, 4], GETRF_SOLUTION_ARRAY, dtype: dtype)) - p_true = NMatrix.new([3,3], [0,0,1,1,0,0,0,1,0], dtype: dtype) + p_true = NMatrix.new([3, 3], [0, 0, 1, 1, 0, 0, 0, 1, 0], dtype: dtype) expect(p).to eq(p_true) end end @@ -244,9 +249,8 @@ NON_INTEGER_DTYPES.each do |dtype| context dtype do - it "calculates cholesky decomposition using potrf (lower)" do - #a = NMatrix.new([3,3],[1,1,1, 1,2,2, 1,2,6], dtype: dtype) + # a = NMatrix.new([3,3],[1,1,1, 1,2,2, 1,2,6], dtype: dtype) # We use the matrix # 1 1 1 # 1 2 2 @@ -255,11 +259,11 @@ # we need only store the lower-half of the matrix. pending("not yet implemented for NMatrix-JRuby") if jruby? pending("not yet implemented for :object dtype") if dtype == :object - a = NMatrix.new([3,3],[1,0,0, 1,2,0, 1,2,6], dtype: dtype) + a = NMatrix.new([3, 3], [1, 0, 0, 1, 2, 0, 1, 2, 6], dtype: dtype) begin r = a.potrf!(:lower) - b = NMatrix.new([3,3],[1,0,0, 1,1,0, 1,1,2], dtype: dtype) + b = NMatrix.new([3, 3], [1, 0, 0, 1, 1, 0, 1, 1, 2], dtype: dtype) expect(a).to eq(b) expect(r).to eq(b) rescue NotImplementedError @@ -271,11 +275,11 @@ pending("not yet implemented for :object dtype") if dtype == :object pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new([3,3],[1,1,1, 0,2,2, 0,0,6], dtype: dtype) + a = NMatrix.new([3, 3], [1, 1, 1, 0, 2, 2, 0, 0, 6], dtype: dtype) begin r = a.potrf!(:upper) - b = NMatrix.new([3,3],[1,1,1, 0,1,1, 0,0,2], dtype: dtype) + b = NMatrix.new([3, 3], [1, 1, 1, 0, 1, 1, 0, 0, 2], dtype: dtype) expect(a).to eq(b) expect(r).to eq(b) rescue NotImplementedError @@ -285,11 +289,11 @@ it "calculates cholesky decomposition using #factorize_cholesky" do pending("not yet implemented for :object dtype") if dtype == :object - a = NMatrix.new([3,3],[1,2,1, 2,13,5, 1,5,6], dtype: dtype) + a = NMatrix.new([3, 3], [1, 2, 1, 2, 13, 5, 1, 5, 6], dtype: dtype) begin - u,l = a.factorize_cholesky + u, l = a.factorize_cholesky - l_true = NMatrix.new([3,3],[1,0,0, 2,3,0, 1,1,2], dtype: dtype) + l_true = NMatrix.new([3, 3], [1, 0, 0, 2, 3, 0, 1, 1, 2], dtype: dtype) u_true = l_true.transpose expect(u).to eq(u_true) expect(l).to eq(l_true) @@ -302,32 +306,30 @@ NON_INTEGER_DTYPES.each do |dtype| context dtype do - it "calculates QR decomposition using factorize_qr for a square matrix" do pending("not yet implemented for :object dtype") if dtype == :object - a = NMatrix.new(3, [12.0, -51.0, 4.0, - 6.0, 167.0, -68.0, - -4.0, 24.0, -41.0] , dtype: dtype) + a = NMatrix.new(3, [12.0, -51.0, 4.0, + 6.0, 167.0, -68.0, + -4.0, 24.0, -41.0,], dtype: dtype) - q_solution = NMatrix.new([3,3], Q_SOLUTION_ARRAY_2, dtype: dtype) + q_solution = NMatrix.new([3, 3], Q_SOLUTION_ARRAY_2, dtype: dtype) - r_solution = NMatrix.new([3,3], [-14.0, -21.0, 14, - 0.0, -175, 70, - 0.0, 0.0, -35] , dtype: dtype) + r_solution = NMatrix.new([3, 3], [-14.0, -21.0, 14, + 0.0, -175, 70, + 0.0, 0.0, -35,], dtype: dtype) err = case dtype when :float32, :complex64 1e-4 when :float64, :complex128 1e-13 - end + end begin - q,r = a.factorize_qr + q, r = a.factorize_qr expect(q).to be_within(err).of(q_solution) expect(r).to be_within(err).of(r_solution) - rescue NotImplementedError pending "Suppressing a NotImplementedError when the lapacke plugin is not available" end @@ -337,31 +339,30 @@ pending("not yet implemented for NMatrix-JRuby") if jruby? pending("not yet implemented for :object dtype") if dtype == :object - a = NMatrix.new([4,2], [34.0, 21.0, - 23.0, 53.0, - 26.0, 346.0, - 23.0, 121.0] , dtype: dtype) + a = NMatrix.new([4, 2], [34.0, 21.0, + 23.0, 53.0, + 26.0, 346.0, + 23.0, 121.0,], dtype: dtype) - q_solution = NMatrix.new([4,4], Q_SOLUTION_ARRAY_1, dtype: dtype) + q_solution = NMatrix.new([4, 4], Q_SOLUTION_ARRAY_1, dtype: dtype) - r_solution = NMatrix.new([4,2], [-53.75872022286244, -255.06559574252242, - 0.0, 269.34836526051555, - 0.0, 0.0, - 0.0, 0.0] , dtype: dtype) + r_solution = NMatrix.new([4, 2], [-53.75872022286244, -255.06559574252242, + 0.0, 269.34836526051555, + 0.0, 0.0, + 0.0, 0.0,], dtype: dtype) err = case dtype when :float32, :complex64 1e-4 when :float64, :complex128 1e-13 - end + end begin - q,r = a.factorize_qr + q, r = a.factorize_qr expect(q).to be_within(err).of(q_solution) expect(r).to be_within(err).of(r_solution) - rescue NotImplementedError pending "Suppressing a NotImplementedError when the lapacke plugin is not available" end @@ -371,25 +372,24 @@ pending("not yet implemented for NMatrix-JRuby") if jruby? pending("not yet implemented for :object dtype") if dtype == :object - a = NMatrix.new([3,4], [123,31,57,81,92,14,17,36,42,34,11,28], dtype: dtype) + a = NMatrix.new([3, 4], [123, 31, 57, 81, 92, 14, 17, 36, 42, 34, 11, 28], dtype: dtype) - q_solution = NMatrix.new([3,3], Q_SOLUTION_ARRAY_3, dtype: dtype) + q_solution = NMatrix.new([3, 3], Q_SOLUTION_ARRAY_3, dtype: dtype) - r_solution = NMatrix.new([3,4], R_SOLUTION_ARRAY, dtype: dtype) + r_solution = NMatrix.new([3, 4], R_SOLUTION_ARRAY, dtype: dtype) err = case dtype when :float32, :complex64 1e-4 when :float64, :complex128 1e-13 - end + end begin - q,r = a.factorize_qr + q, r = a.factorize_qr expect(q).to be_within(err).of(q_solution) expect(r).to be_within(err).of(r_solution) - rescue NotImplementedError pending "Suppressing a NotImplementedError when the lapacke plugin is not available" end @@ -397,51 +397,48 @@ it "calculates QR decomposition such that A - QR ~ 0" do pending("not yet implemented for :object dtype") if dtype == :object - a = NMatrix.new([3,3], [ 9.0, 0.0, 26.0, - 12.0, 0.0, -7.0, - 0.0, 4.0, 0.0] , dtype: dtype) + a = NMatrix.new([3, 3], [9.0, 0.0, 26.0, + 12.0, 0.0, -7.0, + 0.0, 4.0, 0.0,], dtype: dtype) err = case dtype when :float32, :complex64 1e-4 when :float64, :complex128 1e-13 - end + end begin - q,r = a.factorize_qr + q, r = a.factorize_qr a_expected = q.dot(r) expect(a_expected).to be_within(err).of(a) - rescue NotImplementedError pending "Suppressing a NotImplementedError when the lapacke plugin is not available" end end - it "calculates the orthogonal matrix Q in QR decomposition" do pending("not yet implemented for :object dtype") if dtype == :object - a = N.new([2,2], [34.0, 21, 23, 53] , dtype: dtype) + a = N.new([2, 2], [34.0, 21, 23, 53], dtype: dtype) err = case dtype when :float32, :complex64 1e-4 when :float64, :complex128 1e-13 - end + end begin - q,r = a.factorize_qr + q, r = a.factorize_qr - #Q is orthogonal if Q x Q.transpose = I + # Q is orthogonal if Q x Q.transpose = I product = q.dot(q.transpose) - expect(product[0,0]).to be_within(err).of(1) - expect(product[1,0]).to be_within(err).of(0) - expect(product[0,1]).to be_within(err).of(0) - expect(product[1,1]).to be_within(err).of(1) - + expect(product[0, 0]).to be_within(err).of(1) + expect(product[1, 0]).to be_within(err).of(0) + expect(product[0, 1]).to be_within(err).of(0) + expect(product[1, 1]).to be_within(err).of(1) rescue NotImplementedError pending "Suppressing a NotImplementedError when the lapacke plugin is not available" end @@ -450,47 +447,46 @@ end ALL_DTYPES.each do |dtype| - next if dtype == :byte #doesn't work for unsigned types + next if dtype == :byte # doesn't work for unsigned types context dtype do err = case dtype when :float32, :complex64 1e-4 - else #integer matrices will return :float64 + else # integer matrices will return :float64 1e-13 - end + end it "should correctly invert a matrix in place (bang)" do pending("not yet implemented for :object dtype") if dtype == :object - a = NMatrix.new(:dense, 5, [1, 8,-9, 7, 5, + a = NMatrix.new(:dense, 5, [1, 8, -9, 7, 5, 0, 1, 0, 4, 4, 0, 0, 1, 2, 5, - 0, 0, 0, 1,-5, - 0, 0, 0, 0, 1 ], dtype) - b = NMatrix.new(:dense, 5, [1,-8, 9, 7, 17, - 0, 1, 0,-4,-24, - 0, 0, 1,-2,-15, + 0, 0, 0, 1, -5, + 0, 0, 0, 0, 1,], dtype) + b = NMatrix.new(:dense, 5, [1, -8, 9, 7, 17, + 0, 1, 0, -4, -24, + 0, 0, 1, -2, -15, 0, 0, 0, 1, 5, 0, 0, 0, 0, 1,], dtype) if a.integer_dtype? - expect{a.invert!}.to raise_error(DataTypeError) + expect {a.invert!}.to raise_error(DataTypeError) else - #should return inverse as well as modifying a + # should return inverse as well as modifying a r = a.invert! expect(a).to be_within(err).of(b) expect(r).to be_within(err).of(b) end end - it "should correctly invert a dense matrix out-of-place" do pending("not yet implemented for :object dtype") if dtype == :object - a = NMatrix.new(:dense, 3, [1,2,3,0,1,4,5,6,0], dtype) + a = NMatrix.new(:dense, 3, [1, 2, 3, 0, 1, 4, 5, 6, 0], dtype) - if a.integer_dtype? - b = NMatrix.new(:dense, 3, [-24,18,5,20,-15,-4,-5,4,1], :float64) + b = if a.integer_dtype? + NMatrix.new(:dense, 3, [-24, 18, 5, 20, -15, -4, -5, 4, 1], :float64) else - b = NMatrix.new(:dense, 3, [-24,18,5,20,-15,-4,-5,4,1], dtype) + NMatrix.new(:dense, 3, [-24, 18, 5, 20, -15, -4, -5, 4, 1], dtype) end expect(a.invert).to be_within(err).of(b) @@ -498,16 +494,16 @@ it "should correctly find exact inverse" do pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new(:dense, 3, [1,2,3,0,1,4,5,6,0], dtype) - b = NMatrix.new(:dense, 3, [-24,18,5,20,-15,-4,-5,4,1], dtype) + a = NMatrix.new(:dense, 3, [1, 2, 3, 0, 1, 4, 5, 6, 0], dtype) + b = NMatrix.new(:dense, 3, [-24, 18, 5, 20, -15, -4, -5, 4, 1], dtype) expect(a.exact_inverse).to be_within(err).of(b) end it "should correctly find exact inverse" do pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new(:dense, 2, [1,3,3,8], dtype) - b = NMatrix.new(:dense, 2, [-8,3,3,-1], dtype) + a = NMatrix.new(:dense, 2, [1, 3, 3, 8], dtype) + b = NMatrix.new(:dense, 2, [-8, 3, 3, -1], dtype) expect(a.exact_inverse).to be_within(err).of(b) end @@ -522,7 +518,7 @@ pending("not yet implemented for :object dtype") if dtype == :object if dtype == :complex64 || dtype == :complex128 a = NMatrix.new([2, 2], [Complex(16, 81), Complex(91, 51), \ - Complex(13, 54), Complex(71, 24)], dtype: dtype) + Complex(13, 54), Complex(71, 24),], dtype: dtype) b = NMatrix.identity(2, dtype: dtype) begin @@ -548,7 +544,7 @@ pending("not yet implemented for :object dtype") if dtype == :object if dtype == :complex64 || dtype == :complex128 a = NMatrix.new([3, 2], [Complex(94, 11), Complex(87, 51), Complex(82, 39), \ - Complex(45, 16), Complex(25, 32), Complex(91, 43) ], dtype: dtype) + Complex(45, 16), Complex(25, 32), Complex(91, 43),], dtype: dtype) begin b = a.pinv # pseudo inverse @@ -573,17 +569,16 @@ end end - ALL_DTYPES.each do |dtype| - next if dtype == :byte #doesn't work for unsigned types + next if dtype == :byte # doesn't work for unsigned types context dtype do err = case dtype when :float32, :complex64 1e-4 - else #integer matrices will return :float64 + else # integer matrices will return :float64 1e-13 - end + end it "should correctly find adjugate a matrix in place (bang)" do pending("not yet implemented for :object dtype") if dtype == :object @@ -591,61 +586,57 @@ b = NMatrix.new(:dense, 2, [5, -3, -3, 2], dtype) if a.integer_dtype? - expect{a.adjugate!}.to raise_error(DataTypeError) + expect {a.adjugate!}.to raise_error(DataTypeError) else - #should return adjugate as well as modifying a + # should return adjugate as well as modifying a r = a.adjugate! expect(a).to be_within(err).of(b) expect(r).to be_within(err).of(b) end end - it "should correctly find adjugate of a matrix out-of-place" do pending("not yet implemented for :object dtype") if dtype == :object a = NMatrix.new(:dense, 3, [-3, 2, -5, -1, 0, -2, 3, -4, 1], dtype) - if a.integer_dtype? - b = NMatrix.new(:dense, 3, [-8, 18, -4, -5, 12, -1, 4, -6, 2], :float64) + b = if a.integer_dtype? + NMatrix.new(:dense, 3, [-8, 18, -4, -5, 12, -1, 4, -6, 2], :float64) else - b = NMatrix.new(:dense, 3, [-8, 18, -4, -5, 12, -1, 4, -6, 2], dtype) + NMatrix.new(:dense, 3, [-8, 18, -4, -5, 12, -1, 4, -6, 2], dtype) end expect(a.adjoint).to be_within(err).of(b) expect(a.adjugate).to be_within(err).of(b) end - end end - # TODO: Get it working with ROBJ too - [:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |left_dtype| - [:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |right_dtype| - + [:byte, :int8, :int16, :int32, :int64, :float32, :float64].each do |left_dtype| + [:byte, :int8, :int16, :int32, :int64, :float32, :float64].each do |right_dtype| # Won't work if they're both 1-byte, due to overflow. - next if [:byte,:int8].include?(left_dtype) && [:byte,:int8].include?(right_dtype) + next if [:byte, :int8].include?(left_dtype) && [:byte, :int8].include?(right_dtype) # For now, don't bother testing int-int mult. - #next if [:int8,:int16,:int32,:int64].include?(left_dtype) && [:int8,:int16,:int32,:int64].include?(right_dtype) - it "dense handles #{left_dtype.to_s} dot #{right_dtype.to_s} matrix multiplication" do - #STDERR.puts "dtype=#{dtype.to_s}" - #STDERR.puts "2" - - nary = if left_dtype.to_s =~ /complex/ - COMPLEX_MATRIX43A_ARRAY - else - MATRIX43A_ARRAY - end - - mary = if right_dtype.to_s =~ /complex/ - COMPLEX_MATRIX32A_ARRAY - else - MATRIX32A_ARRAY - end - - n = NMatrix.new([4,3], nary, dtype: left_dtype, stype: :dense) - m = NMatrix.new([3,2], mary, dtype: right_dtype, stype: :dense) + # next if [:int8,:int16,:int32,:int64].include?(left_dtype) && [:int8,:int16,:int32,:int64].include?(right_dtype) + it "dense handles #{left_dtype} dot #{right_dtype} matrix multiplication" do + # STDERR.puts "dtype=#{dtype.to_s}" + # STDERR.puts "2" + + nary = if /complex/.match?(left_dtype.to_s) + COMPLEX_MATRIX43A_ARRAY + else + MATRIX43A_ARRAY + end + + mary = if /complex/.match?(right_dtype.to_s) + COMPLEX_MATRIX32A_ARRAY + else + MATRIX32A_ARRAY + end + + n = NMatrix.new([4, 3], nary, dtype: left_dtype, stype: :dense) + m = NMatrix.new([3, 2], mary, dtype: right_dtype, stype: :dense) expect(m.shape[0]).to eq(3) expect(m.shape[1]).to eq(2) @@ -659,32 +650,31 @@ r = n.dot m - expect(r[0,0]).to eq(273.0) - expect(r[0,1]).to eq(455.0) - expect(r[1,0]).to eq(243.0) - expect(r[1,1]).to eq(235.0) - expect(r[2,0]).to eq(244.0) - expect(r[2,1]).to eq(205.0) - expect(r[3,0]).to eq(102.0) - expect(r[3,1]).to eq(160.0) + expect(r[0, 0]).to eq(273.0) + expect(r[0, 1]).to eq(455.0) + expect(r[1, 0]).to eq(243.0) + expect(r[1, 1]).to eq(235.0) + expect(r[2, 0]).to eq(244.0) + expect(r[2, 1]).to eq(205.0) + expect(r[3, 0]).to eq(102.0) + expect(r[3, 1]).to eq(160.0) - #r.dtype.should == :float64 unless left_dtype == :float32 && right_dtype == :float32 + # r.dtype.should == :float64 unless left_dtype == :float32 && right_dtype == :float32 end end end - [:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |left_dtype| - [:byte,:int8,:int16,:int32,:int64,:float32,:float64].each do |right_dtype| - + [:byte, :int8, :int16, :int32, :int64, :float32, :float64].each do |left_dtype| + [:byte, :int8, :int16, :int32, :int64, :float32, :float64].each do |right_dtype| # Won't work if they're both 1-byte, due to overflow. - next if [:byte,:int8].include?(left_dtype) && [:byte,:int8].include?(right_dtype) + next if [:byte, :int8].include?(left_dtype) && [:byte, :int8].include?(right_dtype) - it "dense handles #{left_dtype.to_s} dot #{right_dtype.to_s} vector multiplication" do - #STDERR.puts "dtype=#{dtype.to_s}" - #STDERR.puts "2" - n = NMatrix.new([4,3], [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0], dtype: left_dtype) + it "dense handles #{left_dtype} dot #{right_dtype} vector multiplication" do + # STDERR.puts "dtype=#{dtype.to_s}" + # STDERR.puts "2" + n = NMatrix.new([4, 3], [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0], dtype: left_dtype) - m = NMatrix.new([3,1], [2.0, 1.0, 0.0], dtype: right_dtype) + m = NMatrix.new([3, 1], [2.0, 1.0, 0.0], dtype: right_dtype) expect(m.shape[0]).to eq(3) expect(m.shape[1]).to eq(1) @@ -698,12 +688,12 @@ r = n.dot m # r.class.should == NVector - expect(r[0,0]).to eq(4) - expect(r[1,0]).to eq(13) - expect(r[2,0]).to eq(22) - expect(r[3,0]).to eq(31) + expect(r[0, 0]).to eq(4) + expect(r[1, 0]).to eq(13) + expect(r[2, 0]).to eq(22) + expect(r[3, 0]).to eq(31) - #r.dtype.should == :float64 unless left_dtype == :float32 && right_dtype == :float32 + # r.dtype.should == :float64 unless left_dtype == :float32 && right_dtype == :float32 end end end @@ -712,64 +702,68 @@ next if integer_dtype?(dtype) context "#cov dtype #{dtype}" do before do - @n = NMatrix.new( [5,3], [4.0,2.0,0.60, - 4.2,2.1,0.59, - 3.9,2.0,0.58, - 4.3,2.1,0.62, - 4.1,2.2,0.63], dtype: dtype) + @n = NMatrix.new([5, 3], [4.0, 2.0, 0.60, + 4.2, 2.1, 0.59, + 3.9, 2.0, 0.58, + 4.3, 2.1, 0.62, + 4.1, 2.2, 0.63,], dtype: dtype) end it "calculates sample covariance matrix" do - pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object - expect(@n.cov).to be_within(0.0001).of(NMatrix.new([3,3], - [0.025 , 0.0075, 0.00175, - 0.0075, 0.007 , 0.00135, - 0.00175, 0.00135 , 0.00043 ], dtype: dtype) - ) + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :object) + expect(@n.cov).to be_within(0.0001).of(NMatrix.new([3, 3], + [0.025, 0.0075, 0.00175, + 0.0075, 0.007, 0.00135, + 0.00175, 0.00135, 0.00043,], dtype: dtype)) end it "calculates population covariance matrix" do - pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object - expect(@n.cov(for_sample_data: false)).to be_within(0.0001).of(NMatrix.new([3,3], - [2.0000e-02, 6.0000e-03, 1.4000e-03, - 6.0000e-03, 5.6000e-03, 1.0800e-03, - 1.4000e-03, 1.0800e-03, 3.4400e-04], dtype: dtype) - ) + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :object) + expect(@n.cov(for_sample_data: false)).to be_within(0.0001).of(NMatrix.new([3, 3], + [2.0000e-02, 6.0000e-03, 1.4000e-03, + 6.0000e-03, 5.6000e-03, 1.0800e-03, + 1.4000e-03, 1.0800e-03, 3.4400e-04,], dtype: dtype)) end end context "#corr #{dtype}" do - it "calculates the correlation matrix" do - pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object - n = NMatrix.new([5,3], [4.0,2.0,0.60, - 4.2,2.1,0.59, - 3.9,2.0,0.58, - 4.3,2.1,0.62, - 4.1,2.2,0.63], dtype: dtype) - expect(n.corr).to be_within(0.001).of(NMatrix.new([3,3], - [1.00000, 0.56695, 0.53374, - 0.56695, 1.00000, 0.77813, - 0.53374, 0.77813, 1.00000], dtype: dtype)) - end unless dtype =~ /complex/ + unless /complex/.match?(dtype) + it "calculates the correlation matrix" do + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :object) + n = NMatrix.new([5, 3], [4.0, 2.0, 0.60, + 4.2, 2.1, 0.59, + 3.9, 2.0, 0.58, + 4.3, 2.1, 0.62, + 4.1, 2.2, 0.63,], dtype: dtype) + expect(n.corr).to be_within(0.001).of(NMatrix.new([3, 3], + [1.00000, 0.56695, 0.53374, + 0.56695, 1.00000, 0.77813, + 0.53374, 0.77813, 1.00000,], dtype: dtype)) + end + end end context "#symmetric? for #{dtype}" do it "should return true for symmetric matrix" do - n = NMatrix.new([3,3], [1.00000, 0.56695, 0.53374, - 0.56695, 1.00000, 0.77813, - 0.53374, 0.77813, 1.00000], dtype: dtype) + n = NMatrix.new([3, 3], [1.00000, 0.56695, 0.53374, + 0.56695, 1.00000, 0.77813, + 0.53374, 0.77813, 1.00000,], dtype: dtype) expect(n.symmetric?).to be_truthy end end context "#hermitian? for #{dtype}" do it "should return true for complex hermitian or non-complex symmetric matrix" do - n = NMatrix.new([3,3], [1.00000, 0.56695, 0.53374, - 0.56695, 1.00000, 0.77813, - 0.53374, 0.77813, 1.00000], dtype: dtype) unless dtype =~ /complex/ - n = NMatrix.new([3,3], [1.1, Complex(1.2,1.3), Complex(1.4,1.5), - Complex(1.2,-1.3), 1.9, Complex(1.8,1.7), - Complex(1.4,-1.5), Complex(1.8,-1.7), 1.3], dtype: dtype) if dtype =~ /complex/ + unless /complex/.match?(dtype) + n = NMatrix.new([3, 3], [1.00000, 0.56695, 0.53374, + 0.56695, 1.00000, 0.77813, + 0.53374, 0.77813, 1.00000,], dtype: dtype) + end + if /complex/.match?(dtype) + n = NMatrix.new([3, 3], [1.1, Complex(1.2, 1.3), Complex(1.4, 1.5), + Complex(1.2, -1.3), 1.9, Complex(1.8, 1.7), + Complex(1.4, -1.5), Complex(1.8, -1.7), 1.3,], dtype: dtype) + end expect(n.hermitian?).to be_truthy end end @@ -777,118 +771,117 @@ context "#permute_columns for #{dtype}" do it "check that #permute_columns works correctly by considering every premutation of a 3x3 matrix" do pending("not yet implemented for NMatrix-JRuby") if jruby? - n = NMatrix.new([3,3], [1,0,0, - 0,2,0, - 0,0,3], dtype: dtype) - expect(n.permute_columns([0,1,2], {convention: :intuitive})).to eq(NMatrix.new([3,3], [1,0,0, - 0,2,0, - 0,0,3], dtype: dtype)) - expect(n.permute_columns([0,2,1], {convention: :intuitive})).to eq(NMatrix.new([3,3], [1,0,0, - 0,0,2, - 0,3,0], dtype: dtype)) - expect(n.permute_columns([1,0,2], {convention: :intuitive})).to eq(NMatrix.new([3,3], [0,1,0, - 2,0,0, - 0,0,3], dtype: dtype)) - expect(n.permute_columns([1,2,0], {convention: :intuitive})).to eq(NMatrix.new([3,3], [0,0,1, - 2,0,0, - 0,3,0], dtype: dtype)) - expect(n.permute_columns([2,0,1], {convention: :intuitive})).to eq(NMatrix.new([3,3], [0,1,0, - 0,0,2, - 3,0,0], dtype: dtype)) - expect(n.permute_columns([2,1,0], {convention: :intuitive})).to eq(NMatrix.new([3,3], [0,0,1, - 0,2,0, - 3,0,0], dtype: dtype)) - expect(n.permute_columns([0,1,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [1,0,0, - 0,2,0, - 0,0,3], dtype: dtype)) - expect(n.permute_columns([0,2,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [1,0,0, - 0,0,2, - 0,3,0], dtype: dtype)) - expect(n.permute_columns([1,1,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [0,1,0, - 2,0,0, - 0,0,3], dtype: dtype)) - expect(n.permute_columns([1,2,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [0,0,1, - 2,0,0, - 0,3,0], dtype: dtype)) - expect(n.permute_columns([2,2,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [0,1,0, - 0,0,2, - 3,0,0], dtype: dtype)) - expect(n.permute_columns([2,1,2], {convention: :lapack})).to eq(NMatrix.new([3,3], [0,0,1, - 0,2,0, - 3,0,0], dtype: dtype)) + n = NMatrix.new([3, 3], [1, 0, 0, + 0, 2, 0, + 0, 0, 3,], dtype: dtype) + expect(n.permute_columns([0, 1, 2], {convention: :intuitive})).to eq(NMatrix.new([3, 3], [1, 0, 0, + 0, 2, 0, + 0, 0, 3,], dtype: dtype)) + expect(n.permute_columns([0, 2, 1], {convention: :intuitive})).to eq(NMatrix.new([3, 3], [1, 0, 0, + 0, 0, 2, + 0, 3, 0,], dtype: dtype)) + expect(n.permute_columns([1, 0, 2], {convention: :intuitive})).to eq(NMatrix.new([3, 3], [0, 1, 0, + 2, 0, 0, + 0, 0, 3,], dtype: dtype)) + expect(n.permute_columns([1, 2, 0], {convention: :intuitive})).to eq(NMatrix.new([3, 3], [0, 0, 1, + 2, 0, 0, + 0, 3, 0,], dtype: dtype)) + expect(n.permute_columns([2, 0, 1], {convention: :intuitive})).to eq(NMatrix.new([3, 3], [0, 1, 0, + 0, 0, 2, + 3, 0, 0,], dtype: dtype)) + expect(n.permute_columns([2, 1, 0], {convention: :intuitive})).to eq(NMatrix.new([3, 3], [0, 0, 1, + 0, 2, 0, + 3, 0, 0,], dtype: dtype)) + expect(n.permute_columns([0, 1, 2], {convention: :lapack})).to eq(NMatrix.new([3, 3], [1, 0, 0, + 0, 2, 0, + 0, 0, 3,], dtype: dtype)) + expect(n.permute_columns([0, 2, 2], {convention: :lapack})).to eq(NMatrix.new([3, 3], [1, 0, 0, + 0, 0, 2, + 0, 3, 0,], dtype: dtype)) + expect(n.permute_columns([1, 1, 2], {convention: :lapack})).to eq(NMatrix.new([3, 3], [0, 1, 0, + 2, 0, 0, + 0, 0, 3,], dtype: dtype)) + expect(n.permute_columns([1, 2, 2], {convention: :lapack})).to eq(NMatrix.new([3, 3], [0, 0, 1, + 2, 0, 0, + 0, 3, 0,], dtype: dtype)) + expect(n.permute_columns([2, 2, 2], {convention: :lapack})).to eq(NMatrix.new([3, 3], [0, 1, 0, + 0, 0, 2, + 3, 0, 0,], dtype: dtype)) + expect(n.permute_columns([2, 1, 2], {convention: :lapack})).to eq(NMatrix.new([3, 3], [0, 0, 1, + 0, 2, 0, + 3, 0, 0,], dtype: dtype)) end it "additional tests for #permute_columns with convention :intuitive" do pending("not yet implemented for NMatrix-JRuby") if jruby? - m = NMatrix.new([1,4], [0,1,2,3], dtype: dtype) - perm = [1,0,3,2] - expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,4], perm, dtype: dtype)) + m = NMatrix.new([1, 4], [0, 1, 2, 3], dtype: dtype) + perm = [1, 0, 3, 2] + expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1, 4], perm, dtype: dtype)) - m = NMatrix.new([1,5], [0,1,2,3,4], dtype: dtype) - perm = [1,0,4,3,2] - expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,5], perm, dtype: dtype)) + m = NMatrix.new([1, 5], [0, 1, 2, 3, 4], dtype: dtype) + perm = [1, 0, 4, 3, 2] + expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1, 5], perm, dtype: dtype)) - m = NMatrix.new([1,6], [0,1,2,3,4,5], dtype: dtype) - perm = [2,4,1,0,5,3] - expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,6], perm, dtype: dtype)) + m = NMatrix.new([1, 6], [0, 1, 2, 3, 4, 5], dtype: dtype) + perm = [2, 4, 1, 0, 5, 3] + expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1, 6], perm, dtype: dtype)) - m = NMatrix.new([1,7], [0,1,2,3,4,5,6], dtype: dtype) - perm = [1,3,5,6,0,2,4] - expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,7], perm, dtype: dtype)) + m = NMatrix.new([1, 7], [0, 1, 2, 3, 4, 5, 6], dtype: dtype) + perm = [1, 3, 5, 6, 0, 2, 4] + expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1, 7], perm, dtype: dtype)) - m = NMatrix.new([1,8], [0,1,2,3,4,5,6,7], dtype: dtype) - perm = [6,7,5,4,1,3,0,2] - expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1,8], perm, dtype: dtype)) + m = NMatrix.new([1, 8], [0, 1, 2, 3, 4, 5, 6, 7], dtype: dtype) + perm = [6, 7, 5, 4, 1, 3, 0, 2] + expect(m.permute_columns(perm, {convention: :intuitive})).to eq(NMatrix.new([1, 8], perm, dtype: dtype)) end end end context "#solve" do NON_INTEGER_DTYPES.each do |dtype| - it "solves linear equation for dtype #{dtype}" do pending("not yet implemented for :object dtype") if dtype == :object pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new [2,2], [3,1,1,2], dtype: dtype - b = NMatrix.new [2,1], [9,8], dtype: dtype + a = NMatrix.new [2, 2], [3, 1, 1, 2], dtype: dtype + b = NMatrix.new [2, 1], [9, 8], dtype: dtype - expect(a.solve(b)).to eq(NMatrix.new [2,1], [2,3], dtype: dtype) + expect(a.solve(b)).to eq(NMatrix.new([2, 1], [2, 3], dtype: dtype)) end it "solves linear equation for #{dtype} (non-symmetric matrix)" do pending("not yet implemented for :object dtype") if dtype == :object pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new [3,3], [1,1,1, -1,0,1, 3,4,6], dtype: dtype - b = NMatrix.new [3,1], [6,2,29], dtype: dtype + a = NMatrix.new [3, 3], [1, 1, 1, -1, 0, 1, 3, 4, 6], dtype: dtype + b = NMatrix.new [3, 1], [6, 2, 29], dtype: dtype err = case dtype when :float32, :complex64 1e-5 else 1e-14 - end + end - expect(a.solve(b)).to be_within(err).of(NMatrix.new([3,1], [1,2,3], dtype: dtype)) + expect(a.solve(b)).to be_within(err).of(NMatrix.new([3, 1], [1, 2, 3], dtype: dtype)) end it "solves linear equation for dtype #{dtype} (non-vector rhs)" do pending("not yet implemented for :object dtype") if dtype == :object pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new [3,3], [1,0,0, -1,0,1, 2,1,1], dtype: dtype - b = NMatrix.new [3,2], [1,0, 1,2, 4,2], dtype: dtype + a = NMatrix.new [3, 3], [1, 0, 0, -1, 0, 1, 2, 1, 1], dtype: dtype + b = NMatrix.new [3, 2], [1, 0, 1, 2, 4, 2], dtype: dtype - expect(a.solve(b)).to eq(NMatrix.new [3,2], [1,0, 0,0, 2,2], dtype: dtype) + expect(a.solve(b)).to eq(NMatrix.new([3, 2], [1, 0, 0, 0, 2, 2], dtype: dtype)) end end FLOAT_DTYPES.each do |dtype| context "when form: :lower_tri" do - let(:a) { NMatrix.new([3,3], [1, 0, 0, 2, 0.5, 0, 3, 3, 9], dtype: dtype) } + let(:a) { NMatrix.new([3, 3], [1, 0, 0, 2, 0.5, 0, 3, 3, 9], dtype: dtype) } it "solves a lower triangular linear system A * x = b with vector b" do pending("not yet implemented for NMatrix-JRuby") if jruby? - b = NMatrix.new([3,1], [1,2,3], dtype: dtype) + b = NMatrix.new([3, 1], [1, 2, 3], dtype: dtype) x = a.solve(b, form: :lower_tri) r = a.dot(x) - b expect(r.abs.max).to be_within(1e-6).of(0.0) @@ -896,7 +889,7 @@ it "solves a lower triangular linear system A * X = B with narrow B" do pending("not yet implemented for NMatrix-JRuby") if jruby? - b = NMatrix.new([3,2], [1,2,3,4,5,6], dtype: dtype) + b = NMatrix.new([3, 2], [1, 2, 3, 4, 5, 6], dtype: dtype) x = a.solve(b, form: :lower_tri) r = (a.dot(x) - b).abs.to_flat_a expect(r.max).to be_within(1e-6).of(0.0) @@ -904,7 +897,7 @@ it "solves a lower triangular linear system A * X = B with wide B" do pending("not yet implemented for NMatrix-JRuby") if jruby? - b = NMatrix.new([3,5], (1..15).to_a, dtype: dtype) + b = NMatrix.new([3, 5], (1..15).to_a, dtype: dtype) x = a.solve(b, form: :lower_tri) r = (a.dot(x) - b).abs.to_flat_a expect(r.max).to be_within(1e-6).of(0.0) @@ -912,11 +905,11 @@ end context "when form: :upper_tri" do - let(:a) { NMatrix.new([3,3], [3, 2, 1, 0, 2, 0.5, 0, 0, 9], dtype: dtype) } + let(:a) { NMatrix.new([3, 3], [3, 2, 1, 0, 2, 0.5, 0, 0, 9], dtype: dtype) } it "solves an upper triangular linear system A * x = b with vector b" do pending("not yet implemented for NMatrix-JRuby") if jruby? - b = NMatrix.new([3,1], [1,2,3], dtype: dtype) + b = NMatrix.new([3, 1], [1, 2, 3], dtype: dtype) x = a.solve(b, form: :upper_tri) r = a.dot(x) - b expect(r.abs.max).to be_within(1e-6).of(0.0) @@ -924,7 +917,7 @@ it "solves an upper triangular linear system A * X = B with narrow B" do pending("not yet implemented for NMatrix-JRuby") if jruby? - b = NMatrix.new([3,2], [1,2,3,4,5,6], dtype: dtype) + b = NMatrix.new([3, 2], [1, 2, 3, 4, 5, 6], dtype: dtype) x = a.solve(b, form: :upper_tri) r = (a.dot(x) - b).abs.to_flat_a expect(r.max).to be_within(1e-6).of(0.0) @@ -932,7 +925,7 @@ it "solves an upper triangular linear system A * X = B with a wide B" do pending("not yet implemented for NMatrix-JRuby") if jruby? - b = NMatrix.new([3,5], (1..15).to_a, dtype: dtype) + b = NMatrix.new([3, 5], (1..15).to_a, dtype: dtype) x = a.solve(b, form: :upper_tri) r = (a.dot(x) - b).abs.to_flat_a expect(r.max).to be_within(1e-6).of(0.0) @@ -940,25 +933,25 @@ end context "when form: :pos_def" do - let(:a) { NMatrix.new([3,3], [4, 1, 2, 1, 5, 3, 2, 3, 6], dtype: dtype) } + let(:a) { NMatrix.new([3, 3], [4, 1, 2, 1, 5, 3, 2, 3, 6], dtype: dtype) } it "solves a linear system A * X = b with positive definite A and vector b" do - b = NMatrix.new([3,1], [6,4,8], dtype: dtype) + b = NMatrix.new([3, 1], [6, 4, 8], dtype: dtype) pending("not yet implemented for NMatrix-JRuby") if jruby? begin x = a.solve(b, form: :pos_def) - expect(x).to be_within(1e-6).of(NMatrix.new([3,1], [1,0,1], dtype: dtype)) + expect(x).to be_within(1e-6).of(NMatrix.new([3, 1], [1, 0, 1], dtype: dtype)) rescue NotImplementedError "Suppressing a NotImplementedError when the lapacke or atlas plugin is not available" end end it "solves a linear system A * X = B with positive definite A and matrix B" do - b = NMatrix.new([3,2], [8,3,14,13,14,19], dtype: dtype) + b = NMatrix.new([3, 2], [8, 3, 14, 13, 14, 19], dtype: dtype) pending("not yet implemented for NMatrix-JRuby") if jruby? begin x = a.solve(b, form: :pos_def) - expect(x).to be_within(1e-6).of(NMatrix.new([3,2], [1,-1,2,1,1,3], dtype: dtype)) + expect(x).to be_within(1e-6).of(NMatrix.new([3, 2], [1, -1, 2, 1, 1, 3], dtype: dtype)) rescue NotImplementedError "Suppressing a NotImplementedError when the lapacke or atlas plugin is not available" end @@ -970,9 +963,9 @@ context "#least_squares" do it "finds the least squares approximation to the equation A * X = B" do pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new([3,2], [2.0, 0, -1, 1, 0, 2]) - b = NMatrix.new([3,1], [1.0, 0, -1]) - solution = NMatrix.new([2,1], [1.0 / 3 , -1.0 / 3], dtype: :float64) + a = NMatrix.new([3, 2], [2.0, 0, -1, 1, 0, 2]) + b = NMatrix.new([3, 1], [1.0, 0, -1]) + solution = NMatrix.new([2, 1], [1.0 / 3, -1.0 / 3], dtype: :float64) begin least_squares = a.least_squares(b) @@ -984,9 +977,9 @@ it "finds the least squares approximation to the equation A * X = B with high tolerance" do pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new([4,2], [1.0, 1, 1, 2, 1, 3,1,4]) - b = NMatrix.new([4,1], [6.0, 5, 7, 10]) - solution = NMatrix.new([2,1], [3.5 , 1.4], dtype: :float64) + a = NMatrix.new([4, 2], [1.0, 1, 1, 2, 1, 3, 1, 4]) + b = NMatrix.new([4, 1], [6.0, 5, 7, 10]) + solution = NMatrix.new([2, 1], [3.5, 1.4], dtype: :float64) begin least_squares = a.least_squares(b, tolerance: 10e-5) @@ -1001,22 +994,22 @@ FLOAT_DTYPES.each do |dtype| context dtype do before do - @n = NMatrix.new [5,5], + @n = NMatrix.new [5, 5], [0, 2, 0, 1, 1, 2, 2, 3, 2, 2, - 4,-3, 0, 1, 3, - 6, 1,-6,-5, 4, - 5, 6, 4, 1, 5], dtype: dtype + 4, -3, 0, 1, 3, + 6, 1, -6, -5, 4, + 5, 6, 4, 1, 5,], dtype: dtype end it "transforms a matrix to Hessenberg form" do pending("not yet implemented for NMatrix-JRuby") if jruby? - expect(@n.hessenberg).to be_within(0.0001).of(NMatrix.new([5,5], - [0.00000,-1.66667, 0.79432,-0.45191,-1.54501, - -9.00000, 2.95062,-6.89312, 3.22250,-0.19012, - 0.00000,-8.21682,-0.57379, 5.26966,-1.69976, - 0.00000, 0.00000,-3.74630,-0.80893, 3.99708, - 0.00000, 0.00000, 0.00000, 0.04102, 0.43211], dtype: dtype)) + expect(@n.hessenberg).to be_within(0.0001).of(NMatrix.new([5, 5], + [0.00000, -1.66667, 0.79432, -0.45191, -1.54501, + -9.00000, 2.95062, -6.89312, 3.22250, -0.19012, + 0.00000, -8.21682, -0.57379, 5.26966, -1.69976, + 0.00000, 0.00000, -3.74630, -0.80893, 3.99708, + 0.00000, 0.00000, 0.00000, 0.04102, 0.43211,], dtype: dtype)) end end end @@ -1029,48 +1022,50 @@ context "#pow #{dtype} #{stype}" do before do - @n = NMatrix.new [4,4], [0, 2, 0, 1, - 2, 2, 3, 2, - 4,-3, 0, 1, - 6, 1,-6,-5], dtype: dtype, stype: stype + @n = NMatrix.new [4, 4], [0, 2, 0, 1, + 2, 2, 3, 2, + 4, -3, 0, 1, + 6, 1, -6, -5,], dtype: dtype, stype: stype end it "raises a square matrix to even power" do - pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object - expect(@n.pow(4)).to eq(NMatrix.new([4,4], [292, 28,-63, -42, - 360, 96, 51, -14, - 448,-231,-24,-87, - -1168, 595,234, 523], - dtype: answer_dtype, - stype: stype)) + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :object) + expect(@n.pow(4)).to eq(NMatrix.new([4, 4], [292, 28, -63, -42, + 360, 96, 51, -14, + 448, -231, -24, -87, + -1168, 595, 234, 523,], + dtype: answer_dtype, + stype: stype)) end it "raises a square matrix to odd power" do - pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object - expect(@n.pow(9)).to eq(NMatrix.new([4,4],[-275128, 279917, 176127, 237451, - -260104, 394759, 166893, 296081, - -704824, 285700, 186411, 262002, - 3209256,-1070870,-918741,-1318584], - dtype: answer_dtype, stype: stype)) - end - - it "raises a sqaure matrix to negative power" do - expect(@n.pow(-3)).to be_within(0.00001).of (NMatrix.new([4,4], - [1.0647e-02, 4.2239e-04,-6.2281e-05, 2.7680e-03, - -1.6415e-02, 2.1296e-02, 1.0718e-02, 4.8589e-03, - 8.6956e-03,-8.6569e-03, 2.8993e-02, 7.2015e-03, - 5.0034e-02,-1.7500e-02,-3.6777e-02,-1.2128e-02], dtype: answer_dtype, - stype: stype)) - end unless stype =~ /yale/ or dtype == :object or ALL_DTYPES.grep(/int/).include? dtype + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :object) + expect(@n.pow(9)).to eq(NMatrix.new([4, 4], [-275128, 279917, 176127, 237451, + -260104, 394759, 166893, 296081, + -704824, 285700, 186411, 262002, + 3209256, -1070870, -918741, -1318584,], + dtype: answer_dtype, stype: stype)) + end + + unless stype =~ /yale/ || (dtype == :object) || ALL_DTYPES.grep(/int/).include?(dtype) + it "raises a sqaure matrix to negative power" do + expect(@n.pow(-3)).to be_within(0.00001).of NMatrix.new([4, 4], + [1.0647e-02, 4.2239e-04, -6.2281e-05, 2.7680e-03, + -1.6415e-02, 2.1296e-02, 1.0718e-02, 4.8589e-03, + 8.6956e-03, -8.6569e-03, 2.8993e-02, 7.2015e-03, + 5.0034e-02, -1.7500e-02, -3.6777e-02, -1.2128e-02,], dtype: answer_dtype, + stype: stype) + end + end it "raises a square matrix to zero" do - pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object - expect(@n.pow(0)).to eq(NMatrix.eye([4,4], dtype: answer_dtype, - stype: stype)) + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :object) + expect(@n.pow(0)).to eq(NMatrix.eye([4, 4], dtype: answer_dtype, + stype: stype)) end it "raises a square matrix to one" do - pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :object) expect(@n.pow(1)).to eq(@n) end end @@ -1081,17 +1076,17 @@ [:dense, :yale].each do |stype| context "#kron_prod #{dtype} #{stype}" do before do - @a = NMatrix.new([2,2], [1,2, - 3,4], dtype: dtype, stype: stype) - @b = NMatrix.new([2,3], [1,1,1, - 1,1,1], dtype: dtype, stype: stype) - @c = NMatrix.new([4,6], [1, 1, 1, 2, 2, 2, - 1, 1, 1, 2, 2, 2, - 3, 3, 3, 4, 4, 4, - 3, 3, 3, 4, 4, 4], dtype: dtype, stype: stype) + @a = NMatrix.new([2, 2], [1, 2, + 3, 4,], dtype: dtype, stype: stype) + @b = NMatrix.new([2, 3], [1, 1, 1, + 1, 1, 1,], dtype: dtype, stype: stype) + @c = NMatrix.new([4, 6], [1, 1, 1, 2, 2, 2, + 1, 1, 1, 2, 2, 2, + 3, 3, 3, 4, 4, 4, + 3, 3, 3, 4, 4, 4,], dtype: dtype, stype: stype) end it "computes the Kronecker product of two NMatrix objects" do - pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :object) expect(@a.kron_prod(@b)).to eq(@c) end end @@ -1103,15 +1098,15 @@ context dtype do pending("not yet implemented for :object dtype") if dtype == :object before do - @a = NMatrix.new([2,2], [1,2, - 3,4], dtype: dtype) - @b = NMatrix.new([3,3], [1,2,3, - 5,0,1, - 4,1,3], dtype: dtype) - @c = NMatrix.new([4,4], [1, 0, 1, 1, - 1, 2, 3, 1, - 3, 3, 3, 1, - 1, 2, 3, 4], dtype: dtype) + @a = NMatrix.new([2, 2], [1, 2, + 3, 4,], dtype: dtype) + @b = NMatrix.new([3, 3], [1, 2, 3, + 5, 0, 1, + 4, 1, 3,], dtype: dtype) + @c = NMatrix.new([4, 4], [1, 0, 1, 1, + 1, 2, 3, 1, + 3, 3, 3, 1, + 1, 2, 3, 4,], dtype: dtype) @err = case dtype when :float32, :complex64 1e-6 @@ -1119,7 +1114,7 @@ 1e-14 else 1e-64 # FIXME: should be 0, but be_within(0) does not work. - end + end end it "computes the determinant of 2x2 matrix" do pending("not yet implemented for :object dtype") if dtype == :object @@ -1136,18 +1131,18 @@ it "computes the exact determinant of 2x2 matrix" do pending("not yet implemented for :object dtype") if dtype == :object if dtype == :byte - expect{@a.det_exact}.to raise_error(DataTypeError) + expect {@a.det_exact}.to raise_error(DataTypeError) else - pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :object) expect(@a.det_exact).to be_within(@err).of(-2) end end it "computes the exact determinant of 3x3 matrix" do pending("not yet implemented for :object dtype") if dtype == :objectx if dtype == :byte - expect{@a.det_exact}.to raise_error(DataTypeError) + expect {@a.det_exact}.to raise_error(DataTypeError) else - pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :object) expect(@b.det_exact).to be_within(@err).of(-8) end end @@ -1156,37 +1151,37 @@ end context "#scale and #scale!" do - [:dense,:list,:yale].each do |stype| + [:dense, :list, :yale].each do |stype| ALL_DTYPES.each do |dtype| context "for #{dtype}" do before do @m = NMatrix.new([3, 3], [0, 1, 2, 3, 4, 5, - 6, 7, 8], stype: stype, dtype: dtype) + 6, 7, 8,], stype: stype, dtype: dtype) end it "scales the matrix by a given factor and return the result" do pending("not yet implemented for :object dtype") if dtype == :object if integer_dtype? dtype - expect{@m.scale 2.0}.to raise_error(DataTypeError) + expect {@m.scale 2.0}.to raise_error(DataTypeError) else - pending("not yet implemented for NMatrix-JRuby") if jruby? and (dtype == :complex64 || dtype == :complex128) - expect(@m.scale 2.0).to eq(NMatrix.new([3, 3], [0, 2, 4, - 6, 8, 10, - 12, 14, 16], stype: stype, dtype: dtype)) + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :complex64 || dtype == :complex128) + expect(@m.scale(2.0)).to eq(NMatrix.new([3, 3], [0, 2, 4, + 6, 8, 10, + 12, 14, 16,], stype: stype, dtype: dtype)) end end it "scales the matrix in place by a given factor" do pending("not yet implemented for :object dtype") if dtype == :object if dtype == :int8 - expect{@m.scale! 2}.to raise_error(DataTypeError) + expect {@m.scale! 2}.to raise_error(DataTypeError) else - pending("not yet implemented for NMatrix-JRuby") if jruby? and (dtype == :complex64 || dtype == :complex128) + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :complex64 || dtype == :complex128) @m.scale! 2 expect(@m).to eq(NMatrix.new([3, 3], [0, 2, 4, 6, 8, 10, - 12, 14, 16], stype: stype, dtype: dtype)) + 12, 14, 16,], stype: stype, dtype: dtype)) end end end @@ -1198,23 +1193,22 @@ context dtype do pending("not yet implemented for :object dtype") if dtype == :object before do - @n = NMatrix.new([3,3], [-4,-3,-2, - -1, 0, 1, - 2, 3, 4], dtype: dtype) + @n = NMatrix.new([3, 3], [-4, -3, -2, + -1, 0, 1, + 2, 3, 4,], dtype: dtype) @matrix_norm_TOLERANCE = 1.0e-10 end it "should default to 2-matrix_norm" do pending("not yet implemented for NMatrix-JRuby") if jruby? - if(dtype == :byte) - expect{@n.matrix_norm}.to raise_error(ArgumentError) + if dtype == :byte + expect {@n.matrix_norm}.to raise_error(ArgumentError) else begin expect(@n.matrix_norm).to be_within(@matrix_norm_TOLERANCE).of(7.348469228349535) - - rescue NotImplementedError - pending "Suppressing a NotImplementedError when the lapacke plugin is not available" + rescue NotImplementedError + pending "Suppressing a NotImplementedError when the lapacke plugin is not available" end end end @@ -1222,24 +1216,23 @@ it "should reject invalid arguments" do pending("not yet implemented for NMatrix-JRuby") if jruby? - expect{@n.matrix_norm(0.5)}.to raise_error(ArgumentError) + expect {@n.matrix_norm(0.5)}.to raise_error(ArgumentError) end it "should calculate 1 and 2(minus) matrix_norms correctly" do pending("not yet implemented for NMatrix-JRuby") if jruby? - if(dtype == :byte) - expect{@n.matrix_norm(1)}.to raise_error(ArgumentError) - expect{@n.matrix_norm(-2)}.to raise_error(ArgumentError) - expect{@n.matrix_norm(-1)}.to raise_error(ArgumentError) + if dtype == :byte + expect {@n.matrix_norm(1)}.to raise_error(ArgumentError) + expect {@n.matrix_norm(-2)}.to raise_error(ArgumentError) + expect {@n.matrix_norm(-1)}.to raise_error(ArgumentError) else expect(@n.matrix_norm(1)).to eq(7) begin - - #FIXME: change to the correct value when overflow issue is resolved - #expect(@n.matrix_norm(-2)).to eq(1.8628605857884395e-07) + # FIXME: change to the correct value when overflow issue is resolved + # expect(@n.matrix_norm(-2)).to eq(1.8628605857884395e-07) expect(@n.matrix_norm(-2)).to be_within(@matrix_norm_TOLERANCE).of(0.0) - rescue NotImplementedError - pending "Suppressing a NotImplementedError when the lapacke plugin is not available" + rescue NotImplementedError + pending "Suppressing a NotImplementedError when the lapacke plugin is not available" end expect(@n.matrix_norm(-1)).to eq(6) end @@ -1247,9 +1240,9 @@ it "should calculate infinity matrix_norms correctly" do pending("not yet implemented for NMatrix-JRuby") if jruby? - if(dtype == :byte) - expect{@n.matrix_norm(:inf)}.to raise_error(ArgumentError) - expect{@n.matrix_norm(:'-inf')}.to raise_error(ArgumentError) + if dtype == :byte + expect {@n.matrix_norm(:inf)}.to raise_error(ArgumentError) + expect {@n.matrix_norm(:'-inf')}.to raise_error(ArgumentError) else expect(@n.matrix_norm(:inf)).to eq(9) expect(@n.matrix_norm(:'-inf')).to eq(2) @@ -1258,8 +1251,8 @@ it "should calculate frobenius matrix_norms correctly" do pending("not yet implemented for NMatrix-JRuby") if jruby? - if(dtype == :byte) - expect{@n.matrix_norm(:fro)}.to raise_error(ArgumentError) + if dtype == :byte + expect {@n.matrix_norm(:fro)}.to raise_error(ArgumentError) else expect(@n.matrix_norm(:fro)).to be_within(@matrix_norm_TOLERANCE).of(7.745966692414834) end @@ -1269,95 +1262,86 @@ end context "#positive_definite?" do - it "should return true for positive_definite? matrix" do - n = NMatrix.new([3,3], [2, -1, -1, - -1, 2, -1, - -1, -1, 3]) - expect(n.positive_definite?).to be_truthy - end + it "should return true for positive_definite? matrix" do + n = NMatrix.new([3, 3], [2, -1, -1, + -1, 2, -1, + -1, -1, 3,]) + expect(n.positive_definite?).to be_truthy + end end - - context "#svd_rank" do + + context "#svd_rank" do FLOAT_DTYPES.each do |dtype| context dtype do - #examples from https://www.cliffsnotes.com/study-guides/algebra/linear-algebra/real-euclidean-vector-spaces/the-rank-of-a-matrix + # examples from https://www.cliffsnotes.com/study-guides/algebra/linear-algebra/real-euclidean-vector-spaces/the-rank-of-a-matrix it "calculates the rank of matrix using singular value decomposition with NMatrix on rectangular matrix without tolerence" do pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new([4,3],[2,-1,3, 1,0,1, 0,2,-1, 1,1,4], dtype: dtype) + a = NMatrix.new([4, 3], [2, -1, 3, 1, 0, 1, 0, 2, -1, 1, 1, 4], dtype: dtype) begin - rank = a.svd_rank() - - rank_true = 3 - expect(rank).to eq (rank_true) + rank = a.svd_rank + rank_true = 3 + expect(rank).to eq rank_true rescue NotImplementedError - pending "Suppressing a NotImplementedError when the lapacke plugin is not available" - end + pending "Suppressing a NotImplementedError when the lapacke plugin is not available" + end end it "calculates the rank of matrix using singular value decomposition with NMatrix on rectangular matrix with tolerence" do - - a = NMatrix.new([4,3],[2,-1,3, 1,0,1, 0,2,-1, 1,1,4], dtype: dtype) + a = NMatrix.new([4, 3], [2, -1, 3, 1, 0, 1, 0, 2, -1, 1, 1, 4], dtype: dtype) pending("not yet implemented for NMatrix-JRuby") if jruby? begin rank = a.svd_rank(4) - - rank_true = 1 - expect(rank).to eq (rank_true) + rank_true = 1 + expect(rank).to eq rank_true rescue NotImplementedError - pending "Suppressing a NotImplementedError when the lapacke plugin is not available" + pending "Suppressing a NotImplementedError when the lapacke plugin is not available" end end it "calculates the rank of matrix using singular value decomposition with NMatrix on square matrix without tolerence" do - - a = NMatrix.new([4,4],[1,-1,1,-1, -1,1,-1,1, 1,-1,1,-1, -1,1,-1,1], dtype: dtype) + a = NMatrix.new([4, 4], [1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1], dtype: dtype) pending("not yet implemented for NMatrix-JRuby") if jruby? begin - rank = a.svd_rank() - - rank_true = 1 - expect(rank).to eq (rank_true) + rank = a.svd_rank + rank_true = 1 + expect(rank).to eq rank_true rescue NotImplementedError - pending "Suppressing a NotImplementedError when the lapacke plugin is not available" + pending "Suppressing a NotImplementedError when the lapacke plugin is not available" end end it "calculates the rank of matrix using singular value decomposition with NMatrix on square matrix with very small tolerence(for float32)" do pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new([4,4],[1,-1,1,-1, -1,1,-1,1, 1,-1,1,-1, -1,1,-1,1], dtype: :float32) + a = NMatrix.new([4, 4], [1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1], dtype: :float32) begin rank = a.svd_rank(1.7881389169360773e-08) - - rank_true = 2 - expect(rank).to eq (rank_true) + rank_true = 2 + expect(rank).to eq rank_true rescue NotImplementedError - pending "Suppressing a NotImplementedError when the lapacke plugin is not available" + pending "Suppressing a NotImplementedError when the lapacke plugin is not available" end end it "calculates the rank of matrix using singular value decomposition with NMatrix on square matrix with very small tolerence(for float64)" do pending("not yet implemented for NMatrix-JRuby") if jruby? - a = NMatrix.new([4,4],[1,-1,1,-1, -1,1,-1,1, 1,-1,1,-1, -1,1,-1,1], dtype: :float64) + a = NMatrix.new([4, 4], [1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1], dtype: :float64) begin rank = a.svd_rank(1.7881389169360773e-08) - - rank_true = 1 - expect(rank).to eq (rank_true) + rank_true = 1 + expect(rank).to eq rank_true rescue NotImplementedError - pending "Suppressing a NotImplementedError when the lapacke plugin is not available" + pending "Suppressing a NotImplementedError when the lapacke plugin is not available" end end - end - end - end - + end + end end diff --git a/spec/nmatrix_yale_spec.rb b/spec/nmatrix_yale_spec.rb index 90b0f138..04cbf8cd 100644 --- a/spec/nmatrix_yale_spec.rb +++ b/spec/nmatrix_yale_spec.rb @@ -24,12 +24,11 @@ # # Basic tests for NMatrix's Yale storage type. # -require 'spec_helper' +require "spec_helper" require "./lib/nmatrix" describe NMatrix do context :yale do - it "compares two empty matrices" do n = NMatrix.new(4, stype: :yale, dtype: :float64) m = NMatrix.new(4, stype: :yale, dtype: :float64) @@ -40,177 +39,176 @@ n = NMatrix.new(2, stype: :yale, dtype: :float64) m = NMatrix.new(2, stype: :yale, dtype: :float64) - m[0,0] = 1 - m[0,1] = 1 + m[0, 0] = 1 + m[0, 1] = 1 expect(n).not_to eq(m) - n[0,0] = 1 + n[0, 0] = 1 expect(n).not_to eq(m) - n[0,1] = 1 + n[0, 1] = 1 expect(n).to eq(m) end it "compares two matrices following elementwise operations" do n = NMatrix.new(2, stype: :yale, dtype: :float64) m = NMatrix.new(2, stype: :yale, dtype: :float64) - n[0,1] = 1 - m[0,1] = -1 - x = n+m - expect(n+m).to eq(NMatrix.new(2, 0.0, stype: :yale)) + n[0, 1] = 1 + m[0, 1] = -1 + x = n + m + expect(n + m).to eq(NMatrix.new(2, 0.0, stype: :yale)) end it "sets diagonal values" do - n = NMatrix.new([2,3], stype: :yale, dtype: :float64) + n = NMatrix.new([2, 3], stype: :yale, dtype: :float64) n.extend(NMatrix::YaleFunctions) - n[1,1] = 0.1 - n[0,0] = 0.2 + n[1, 1] = 0.1 + n[0, 0] = 0.2 expect(n.yale_d).to eq([0.2, 0.1]) end it "gets non-diagonal rows as hashes" do - n = NMatrix.new([4,6], stype: :yale, dtype: :float64) + n = NMatrix.new([4, 6], stype: :yale, dtype: :float64) n.extend(NMatrix::YaleFunctions) - n[0,0] = 0.1 - n[0,2] = 0.2 - n[0,3] = 0.3 - n[1,5] = 0.4 + n[0, 0] = 0.1 + n[0, 2] = 0.2 + n[0, 3] = 0.3 + n[1, 5] = 0.4 h = n.yale_nd_row(0, :hash) expect(h).to eq({2 => 0.2, 3 => 0.3}) end it "gets non-diagonal occupied column indices for a given row" do - n = NMatrix.new([4,6], stype: :yale, dtype: :float64) + n = NMatrix.new([4, 6], stype: :yale, dtype: :float64) n.extend(NMatrix::YaleFunctions) - n[0,0] = 0.1 - n[0,2] = 0.2 - n[0,3] = 0.3 - n[1,5] = 0.4 + n[0, 0] = 0.1 + n[0, 2] = 0.2 + n[0, 3] = 0.3 + n[1, 5] = 0.4 a = n.yale_nd_row(0, :array) - expect(a).to eq([2,3]) + expect(a).to eq([2, 3]) end it "does not resize until necessary" do - n = NMatrix.new([2,3], stype: :yale, dtype: :float64) + n = NMatrix.new([2, 3], stype: :yale, dtype: :float64) n.extend(NMatrix::YaleFunctions) expect(n.yale_size).to eq(3) expect(n.capacity).to eq(5) - n[0,0] = 0.1 - n[0,1] = 0.2 - n[1,0] = 0.3 + n[0, 0] = 0.1 + n[0, 1] = 0.2 + n[1, 0] = 0.3 expect(n.yale_size).to eq(5) expect(n.capacity).to eq(5) end - it "sets when not resizing" do - n = NMatrix.new([2,3], stype: :yale, dtype: :float64) + n = NMatrix.new([2, 3], stype: :yale, dtype: :float64) n.extend(NMatrix::YaleFunctions) - n[0,0] = 0.1 - n[0,1] = 0.2 - n[1,0] = 0.3 + n[0, 0] = 0.1 + n[0, 1] = 0.2 + n[1, 0] = 0.3 expect(n.yale_a).to eq([0.1, 0.0, 0.0, 0.2, 0.3]) - expect(n.yale_ija).to eq([3,4,5,1,0]) + expect(n.yale_ija).to eq([3, 4, 5, 1, 0]) end it "sets when resizing" do - n = NMatrix.new([2,3], stype: :yale, dtype: :float64) + n = NMatrix.new([2, 3], stype: :yale, dtype: :float64) n.extend(NMatrix::YaleFunctions) - n[0,0] = 0.01 - n[1,1] = 0.1 - n[0,1] = 0.2 - n[1,0] = 0.3 - n[1,2] = 0.4 + n[0, 0] = 0.01 + n[1, 1] = 0.1 + n[0, 1] = 0.2 + n[1, 0] = 0.3 + n[1, 2] = 0.4 expect(n.yale_d).to eq([0.01, 0.1]) - expect(n.yale_ia).to eq([3,4,6]) - expect(n.yale_ja).to eq([1,0,2,nil]) + expect(n.yale_ia).to eq([3, 4, 6]) + expect(n.yale_ja).to eq([1, 0, 2, nil]) expect(n.yale_lu).to eq([0.2, 0.3, 0.4, nil]) end it "resizes without erasing values" do - require 'yaml' + require "yaml" - associations = File.open('spec/nmatrix_yale_resize_test_associations.yaml') { |y| YAML::load(y) } + associations = File.open("spec/nmatrix_yale_resize_test_associations.yaml") { |y| YAML.load(y) } - n = NMatrix.new([618,2801], stype: :yale, dtype: :byte, capacity: associations.size) - #n = NMatrix.new(:yale, [618, 2801], associations.size, :byte) + n = NMatrix.new([618, 2801], stype: :yale, dtype: :byte, capacity: associations.size) + # n = NMatrix.new(:yale, [618, 2801], associations.size, :byte) - associations.each_pair do |j,i| - n[i,j] = 1 - expect(n[i,j]).to be(1), "Value at #{i},#{j} not inserted correctly!" + associations.each_pair do |j, i| + n[i, j] = 1 + expect(n[i, j]).to be(1), "Value at #{i},#{j} not inserted correctly!" end - associations.each_pair do |j,i| - expect(n[i,j]).to be(1), "Value at #{i},#{j} erased during resize!" + associations.each_pair do |j, i| + expect(n[i, j]).to be(1), "Value at #{i},#{j} erased during resize!" end end it "sets values within rows" do - n = NMatrix.new([3,20], stype: :yale, dtype: :float64) + n = NMatrix.new([3, 20], stype: :yale, dtype: :float64) n.extend(NMatrix::YaleFunctions) - n[2,1] = 1.0 - n[2,0] = 1.5 - n[2,15] = 2.0 + n[2, 1] = 1.0 + n[2, 0] = 1.5 + n[2, 15] = 2.0 expect(n.yale_lu).to eq([1.5, 1.0, 2.0]) expect(n.yale_ja).to eq([0, 1, 15]) end it "gets values within rows" do - n = NMatrix.new([3,20], stype: :yale, dtype: :float64) - n[2,1] = 1.0 - n[2,0] = 1.5 - n[2,15] = 2.0 - expect(n[2,1]).to eq(1.0) - expect(n[2,0]).to eq(1.5) - expect(n[2,15]).to eq(2.0) + n = NMatrix.new([3, 20], stype: :yale, dtype: :float64) + n[2, 1] = 1.0 + n[2, 0] = 1.5 + n[2, 15] = 2.0 + expect(n[2, 1]).to eq(1.0) + expect(n[2, 0]).to eq(1.5) + expect(n[2, 15]).to eq(2.0) end it "sets values within large rows" do - n = NMatrix.new([10,300], stype: :yale, dtype: :float64) + n = NMatrix.new([10, 300], stype: :yale, dtype: :float64) n.extend(NMatrix::YaleFunctions) - n[5,1] = 1.0 - n[5,0] = 1.5 - n[5,15] = 2.0 - n[5,291] = 3.0 - n[5,292] = 4.0 - n[5,289] = 5.0 - n[5,290] = 6.0 - n[5,293] = 2.0 - n[5,299] = 7.0 - n[5,100] = 8.0 + n[5, 1] = 1.0 + n[5, 0] = 1.5 + n[5, 15] = 2.0 + n[5, 291] = 3.0 + n[5, 292] = 4.0 + n[5, 289] = 5.0 + n[5, 290] = 6.0 + n[5, 293] = 2.0 + n[5, 299] = 7.0 + n[5, 100] = 8.0 expect(n.yale_lu).to eq([1.5, 1.0, 2.0, 8.0, 5.0, 6.0, 3.0, 4.0, 2.0, 7.0]) expect(n.yale_ja).to eq([0, 1, 15, 100, 289, 290, 291, 292, 293, 299]) end it "gets values within large rows" do - n = NMatrix.new([10,300], stype: :yale, dtype: :float64) + n = NMatrix.new([10, 300], stype: :yale, dtype: :float64) n.extend(NMatrix::YaleFunctions) - n[5,1] = 1.0 - n[5,0] = 1.5 - n[5,15] = 2.0 - n[5,291] = 3.0 - n[5,292] = 4.0 - n[5,289] = 5.0 - n[5,290] = 6.0 - n[5,293] = 2.0 - n[5,299] = 7.0 - n[5,100] = 8.0 + n[5, 1] = 1.0 + n[5, 0] = 1.5 + n[5, 15] = 2.0 + n[5, 291] = 3.0 + n[5, 292] = 4.0 + n[5, 289] = 5.0 + n[5, 290] = 6.0 + n[5, 293] = 2.0 + n[5, 299] = 7.0 + n[5, 100] = 8.0 n.yale_ja.each_index do |idx| j = n.yale_ja[idx] - expect(n[5,j]).to eq(n.yale_lu[idx]) + expect(n[5, j]).to eq(n.yale_lu[idx]) end end it "dots two identical matrices" do a = NMatrix.new(4, stype: :yale, dtype: :float64) - a[0,1] = 4.0 - a[1,2] = 1.0 - a[1,3] = 1.0 - a[3,1] = 2.0 + a[0, 1] = 4.0 + a[1, 2] = 1.0 + a[1, 3] = 1.0 + a[3, 1] = 2.0 b = a.dup c = a.dot b - d = NMatrix.new(4, [0,0,4,4, 0,2,0,0, 0,0,0,0, 0,0,2,2], dtype: :float64, stype: :yale) + d = NMatrix.new(4, [0, 0, 4, 4, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2], dtype: :float64, stype: :yale) expect(c).to eq(d) end @@ -218,26 +216,25 @@ it "dots two identical matrices where a positive and negative partial sum cancel on the diagonal" do a = NMatrix.new(4, 0.0, stype: :yale) - a[0,0] = 1.0 - a[0,1] = 4.0 - a[1,2] = 2.0 - a[1,3] = -4.0 - a[3,1] = 4.0 - a[3,3] = 4.0 + a[0, 0] = 1.0 + a[0, 1] = 4.0 + a[1, 2] = 2.0 + a[1, 3] = -4.0 + a[3, 1] = 4.0 + a[3, 3] = 4.0 b = a.dup c = a.dot b c.extend(NMatrix::YaleFunctions) - expect(c.yale_ija.reject { |i| i.nil? }).to eq([5,8,9,9,11,1,2,3,3,1,2]) + expect(c.yale_ija.reject { |i| i.nil? }).to eq([5, 8, 9, 9, 11, 1, 2, 3, 3, 1, 2]) expect(c.yale_a.reject { |i| i.nil? }).to eq([1.0, -16.0, 0.0, 0.0, 0.0, 4.0, 8.0, -16.0, -16.0, 16.0, 8.0]) - end it "dots two vectors" do - n = NMatrix.new([16,1], 0, stype: :yale) - m = NMatrix.new([1,16], 0, stype: :yale) + n = NMatrix.new([16, 1], 0, stype: :yale) + m = NMatrix.new([1, 16], 0, stype: :yale) n[0] = m[0] = 1 n[1] = m[1] = 2 @@ -265,12 +262,12 @@ expect(nm.yale_a[0...107]).to eq(nmr.yale_a[0...107]) mn = m.dot(n) - expect(mn[0,0]).to eq(541) + expect(mn[0, 0]).to eq(541) end it "calculates the row key intersections of two matrices" do - a = NMatrix.new([3,9], [0,1], stype: :yale, dtype: :byte, default: 0) - b = NMatrix.new([3,9], [0,0,1,0,1], stype: :yale, dtype: :byte, default: 0) + a = NMatrix.new([3, 9], [0, 1], stype: :yale, dtype: :byte, default: 0) + b = NMatrix.new([3, 9], [0, 0, 1, 0, 1], stype: :yale, dtype: :byte, default: 0) a.extend NMatrix::YaleFunctions b.extend NMatrix::YaleFunctions @@ -280,7 +277,6 @@ expect(a.yale_ja_d_keys_at(ai) & b.yale_ja_d_keys_at(bi)).to eq(a.yale_row_keys_intersection(ai, b, bi)) end end - end end end diff --git a/spec/plugins/atlas/atlas_spec.rb b/spec/plugins/atlas/atlas_spec.rb index 3448603a..176ba263 100644 --- a/spec/plugins/atlas/atlas_spec.rb +++ b/spec/plugins/atlas/atlas_spec.rb @@ -25,20 +25,20 @@ # Tests for interfaces that are only exposed by nmatrix-atlas # -require 'spec_helper' +require "spec_helper" require "./lib/nmatrix/atlas" describe "NMatrix::LAPACK implementation from nmatrix-atlas plugin" do [:float32, :float64, :complex64, :complex128].each do |dtype| context dtype do it "exposes clapack_getri" do - a = NMatrix.new(:dense, 3, [1,0,4,1,1,6,-3,0,-10], dtype) - ipiv = NMatrix::LAPACK::clapack_getrf(:row, 3, 3, a, 3) # get pivot from getrf, use for getri + a = NMatrix.new(:dense, 3, [1, 0, 4, 1, 1, 6, -3, 0, -10], dtype) + ipiv = NMatrix::LAPACK.clapack_getrf(:row, 3, 3, a, 3) # get pivot from getrf, use for getri begin - NMatrix::LAPACK::clapack_getri(:row, 3, a, 3, ipiv) + NMatrix::LAPACK.clapack_getri(:row, 3, a, 3, ipiv) - b = NMatrix.new(:dense, 3, [-5,0,-2,-4,1,-1,1.5,0,0.5], dtype) + b = NMatrix.new(:dense, 3, [-5, 0, -2, -4, 1, -1, 1.5, 0, 0.5], dtype) expect(a).to eq(b) rescue NotImplementedError => e pending e.to_s @@ -53,58 +53,58 @@ it "exposes clapack_potrf upper" do pending "potrf requires clapack" unless NMatrix.has_clapack? - a = NMatrix.new(:dense, 3, [25,15,-5, 0,18,0, 0,0,11], dtype) - NMatrix::LAPACK::clapack_potrf(:row, :upper, 3, a, 3) - b = NMatrix.new(:dense, 3, [5,3,-1, 0,3,1, 0,0,3], dtype) + a = NMatrix.new(:dense, 3, [25, 15, -5, 0, 18, 0, 0, 0, 11], dtype) + NMatrix::LAPACK.clapack_potrf(:row, :upper, 3, a, 3) + b = NMatrix.new(:dense, 3, [5, 3, -1, 0, 3, 1, 0, 0, 3], dtype) expect(a).to eq(b) end it "exposes clapack_potrf lower" do pending "potrf requires clapack" unless NMatrix.has_clapack? - a = NMatrix.new(:dense, 3, [25,0,0, 15,18,0,-5,0,11], dtype) - NMatrix::LAPACK::clapack_potrf(:row, :lower, 3, a, 3) - b = NMatrix.new(:dense, 3, [5,0,0, 3,3,0, -1,1,3], dtype) + a = NMatrix.new(:dense, 3, [25, 0, 0, 15, 18, 0, -5, 0, 11], dtype) + NMatrix::LAPACK.clapack_potrf(:row, :lower, 3, a, 3) + b = NMatrix.new(:dense, 3, [5, 0, 0, 3, 3, 0, -1, 1, 3], dtype) expect(a).to eq(b) end it "exposes clapack_potri" do pending "potri requires clapack" unless NMatrix.has_clapack? - a = NMatrix.new(3, [4, 0,-1, + a = NMatrix.new(3, [4, 0, -1, 0, 2, 1, - 0, 0, 1], dtype: dtype) - NMatrix::LAPACK::clapack_potrf(:row, :upper, 3, a, 3) - NMatrix::LAPACK::clapack_potri(:row, :upper, 3, a, 3) - b = NMatrix.new(3, [0.5, -0.5, 1, 0, 1.5, -2, 0, 0, 4], dtype: dtype) + 0, 0, 1,], dtype: dtype) + NMatrix::LAPACK.clapack_potrf(:row, :upper, 3, a, 3) + NMatrix::LAPACK.clapack_potri(:row, :upper, 3, a, 3) + b = NMatrix.new(3, [0.5, -0.5, 1, 0, 1.5, -2, 0, 0, 4], dtype: dtype) err = case dtype when :float32, :complex64 1e-6 when :float64, :complex128 1e-14 - end + end expect(a).to be_within(err).of(b) end it "exposes clapack_potrs" do pending "potrs requires clapack" unless NMatrix.has_clapack? - a = NMatrix.new(3, [4, 0,-1, + a = NMatrix.new(3, [4, 0, -1, 0, 2, 1, - 0, 0, 1], dtype: dtype) - b = NMatrix.new([3,1], [3,0,2], dtype: dtype) + 0, 0, 1,], dtype: dtype) + b = NMatrix.new([3, 1], [3, 0, 2], dtype: dtype) - NMatrix::LAPACK::clapack_potrf(:row, :upper, 3, a, 3) - NMatrix::LAPACK::clapack_potrs(:row, :upper, 3, 1, a, 3, b, 3) + NMatrix::LAPACK.clapack_potrf(:row, :upper, 3, a, 3) + NMatrix::LAPACK.clapack_potrs(:row, :upper, 3, 1, a, 3, b, 3) - x = NMatrix.new([3,1], [3.5, -5.5, 11], dtype: dtype) + x = NMatrix.new([3, 1], [3.5, -5.5, 11], dtype: dtype) err = case dtype when :float32, :complex64 1e-5 when :float64, :complex128 1e-14 - end + end expect(b).to be_within(err).of(x) end @@ -114,14 +114,14 @@ [:float32, :float64, :complex64, :complex128].each do |dtype| context dtype do it "calculates the singular value decomposition with lapack_gesvd" do - #example from Wikipedia + # example from Wikipedia m = 4 n = 5 - mn_min = [m,n].min - a = NMatrix.new([m,n],[1,0,0,0,2, 0,0,3,0,0, 0,0,0,0,0, 0,4,0,0,0], dtype: dtype) - s = NMatrix.new([mn_min], 0, dtype: a.abs_dtype) #s is always real and always returned as float/double, never as complex - u = NMatrix.new([m,m], 0, dtype: dtype) - vt = NMatrix.new([n,n], 0, dtype: dtype) + mn_min = [m, n].min + a = NMatrix.new([m, n], [1, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0], dtype: dtype) + s = NMatrix.new([mn_min], 0, dtype: a.abs_dtype) # s is always real and always returned as float/double, never as complex + u = NMatrix.new([m, m], 0, dtype: dtype) + vt = NMatrix.new([n, n], 0, dtype: dtype) # This is a pure LAPACK function so it expects column-major functions # So we need to transpose the input as well as the output @@ -130,16 +130,16 @@ u = u.transpose vt = vt.transpose - s_true = NMatrix.new([mn_min], [4,3,Math.sqrt(5),0], dtype: a.abs_dtype) - u_true = NMatrix.new([m,m], [0,0,1,0, 0,1,0,0, 0,0,0,-1, 1,0,0,0], dtype: dtype) - vt_true = NMatrix.new([n,n], [0,1,0,0,0, 0,0,1,0,0, Math.sqrt(0.2),0,0,0,Math.sqrt(0.8), 0,0,0,1,0, -Math.sqrt(0.8),0,0,0,Math.sqrt(0.2)], dtype: dtype) + s_true = NMatrix.new([mn_min], [4, 3, Math.sqrt(5), 0], dtype: a.abs_dtype) + u_true = NMatrix.new([m, m], [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0], dtype: dtype) + vt_true = NMatrix.new([n, n], [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, Math.sqrt(0.2), 0, 0, 0, Math.sqrt(0.8), 0, 0, 0, 1, 0, -Math.sqrt(0.8), 0, 0, 0, Math.sqrt(0.2)], dtype: dtype) err = case dtype when :float32, :complex64 1e-5 when :float64, :complex128 1e-14 - end + end expect(s).to be_within(err).of(s_true) expect(u).to be_within(err).of(u_true) @@ -147,14 +147,14 @@ end it "calculates the singular value decomposition with lapack_gesdd" do - #example from Wikipedia + # example from Wikipedia m = 4 n = 5 - mn_min = [m,n].min - a = NMatrix.new([m,n],[1,0,0,0,2, 0,0,3,0,0, 0,0,0,0,0, 0,4,0,0,0], dtype: dtype) - s = NMatrix.new([mn_min], 0, dtype: a.abs_dtype) #s is always real and always returned as float/double, never as complex - u = NMatrix.new([m,m], 0, dtype: dtype) - vt = NMatrix.new([n,n], 0, dtype: dtype) + mn_min = [m, n].min + a = NMatrix.new([m, n], [1, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0], dtype: dtype) + s = NMatrix.new([mn_min], 0, dtype: a.abs_dtype) # s is always real and always returned as float/double, never as complex + u = NMatrix.new([m, m], 0, dtype: dtype) + vt = NMatrix.new([n, n], 0, dtype: dtype) # This is a pure LAPACK function so it expects column-major functions # So we need to transpose the input as well as the output @@ -163,16 +163,16 @@ u = u.transpose vt = vt.transpose - s_true = NMatrix.new([mn_min], [4,3,Math.sqrt(5),0], dtype: a.abs_dtype) - u_true = NMatrix.new([m,m], [0,0,1,0, 0,1,0,0, 0,0,0,-1, 1,0,0,0], dtype: dtype) - vt_true = NMatrix.new([n,n], [0,1,0,0,0, 0,0,1,0,0, Math.sqrt(0.2),0,0,0,Math.sqrt(0.8), 0,0,0,1,0, -Math.sqrt(0.8),0,0,0,Math.sqrt(0.2)], dtype: dtype) + s_true = NMatrix.new([mn_min], [4, 3, Math.sqrt(5), 0], dtype: a.abs_dtype) + u_true = NMatrix.new([m, m], [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0], dtype: dtype) + vt_true = NMatrix.new([n, n], [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, Math.sqrt(0.2), 0, 0, 0, Math.sqrt(0.8), 0, 0, 0, 1, 0, -Math.sqrt(0.8), 0, 0, 0, Math.sqrt(0.2)], dtype: dtype) err = case dtype when :float32, :complex64 1e-5 when :float64, :complex128 1e-14 - end + end expect(s).to be_within(err).of(s_true) expect(u).to be_within(err).of(u_true) @@ -181,49 +181,49 @@ it "exposes lapack_geev" do n = 3 - a = NMatrix.new([n,n], [-1,0,0, 0,1,-2, 0,1,-1], dtype: dtype) + a = NMatrix.new([n, n], [-1, 0, 0, 0, 1, -2, 0, 1, -1], dtype: dtype) w = NMatrix.new([n], dtype: dtype) - if a.complex_dtype? #for real dtypes, imaginary parts of eigenvalues are stored in separate vector - wi = nil + wi = if a.complex_dtype? # for real dtypes, imaginary parts of eigenvalues are stored in separate vector + nil else - wi = NMatrix.new([n], dtype: dtype) + NMatrix.new([n], dtype: dtype) end - vl = NMatrix.new([n,n], dtype: dtype) - vr = NMatrix.new([n,n], dtype: dtype) + vl = NMatrix.new([n, n], dtype: dtype) + vr = NMatrix.new([n, n], dtype: dtype) # This is a pure LAPACK routine so it expects column-major matrices, # so we need to transpose everything. a = a.transpose - NMatrix::LAPACK::lapack_geev(:left, :right, n, a, n, w, wi, vl, n, vr, n, 2*n) + NMatrix::LAPACK.lapack_geev(:left, :right, n, a, n, w, wi, vl, n, vr, n, 2 * n) vr = vr.transpose vl = vl.transpose - if !a.complex_dtype? - w = w + wi*Complex(0,1) + unless a.complex_dtype? + w += wi * Complex(0, 1) end - w_true = NMatrix.new([n], [Complex(0,1), -Complex(0,1), -1], dtype: NMatrix.upcast(dtype, :complex64)) + w_true = NMatrix.new([n], [Complex(0, 1), -Complex(0, 1), -1], dtype: NMatrix.upcast(dtype, :complex64)) if a.complex_dtype? - #For complex types the right/left eigenvectors are stored as columns - #of vr/vl. - vr_true = NMatrix.new([n,n],[0,0,1, - 2/Math.sqrt(6),2/Math.sqrt(6),0, - Complex(1,-1)/Math.sqrt(6),Complex(1,1)/Math.sqrt(6),0], dtype: dtype) - vl_true = NMatrix.new([n,n],[0,0,1, - Complex(-1,1)/Math.sqrt(6),Complex(-1,-1)/Math.sqrt(6),0, - 2/Math.sqrt(6),2/Math.sqrt(6),0], dtype: dtype) + # For complex types the right/left eigenvectors are stored as columns + # of vr/vl. + vr_true = NMatrix.new([n, n], [0, 0, 1, + 2 / Math.sqrt(6), 2 / Math.sqrt(6), 0, + Complex(1, -1) / Math.sqrt(6), Complex(1, 1) / Math.sqrt(6), 0,], dtype: dtype) + vl_true = NMatrix.new([n, n], [0, 0, 1, + Complex(-1, 1) / Math.sqrt(6), Complex(-1, -1) / Math.sqrt(6), 0, + 2 / Math.sqrt(6), 2 / Math.sqrt(6), 0,], dtype: dtype) else - #For real types, the real part of the first and second eigenvectors is - #stored in the first column, the imaginary part of the first (= the - #negative of the imaginary part of the second) eigenvector is stored - #in the second column, and the third eigenvector (purely real) is the - #third column. - vr_true = NMatrix.new([n,n],[0,0,1, - 2/Math.sqrt(6),0,0, - 1/Math.sqrt(6),-1/Math.sqrt(6),0], dtype: dtype) - vl_true = NMatrix.new([n,n],[0,0,1, - -1/Math.sqrt(6),1/Math.sqrt(6),0, - 2/Math.sqrt(6),0,0], dtype: dtype) + # For real types, the real part of the first and second eigenvectors is + # stored in the first column, the imaginary part of the first (= the + # negative of the imaginary part of the second) eigenvector is stored + # in the second column, and the third eigenvector (purely real) is the + # third column. + vr_true = NMatrix.new([n, n], [0, 0, 1, + 2 / Math.sqrt(6), 0, 0, + 1 / Math.sqrt(6), -1 / Math.sqrt(6), 0,], dtype: dtype) + vl_true = NMatrix.new([n, n], [0, 0, 1, + -1 / Math.sqrt(6), 1 / Math.sqrt(6), 0, + 2 / Math.sqrt(6), 0, 0,], dtype: dtype) end err = case dtype @@ -231,7 +231,7 @@ 1e-6 when :float64, :complex128 1e-15 - end + end expect(w).to be_within(err).of(w_true) expect(vr).to be_within(err).of(vr_true) diff --git a/spec/plugins/fftw/fftw_spec.rb b/spec/plugins/fftw/fftw_spec.rb index 14bc5f86..62e94b72 100644 --- a/spec/plugins/fftw/fftw_spec.rb +++ b/spec/plugins/fftw/fftw_spec.rb @@ -25,47 +25,46 @@ # Tests for interfaces that are only exposed by nmatrix-fftw # -require 'spec_helper' +require "spec_helper" require "./lib/nmatrix/fftw" describe NMatrix do context "#fft" do before do @answer = NMatrix.new([10], - [ - Complex(330.3200,0.0000) , Complex(-8.4039 ,-150.3269), - Complex(-99.4807,-68.6579) , Complex(-143.6861, -20.4273), - Complex(67.6207 , 8.5236), Complex(130.7800 , 0.0000), - Complex(67.6207 , -8.5236), Complex(-143.6861, 20.4273), - Complex(-99.4807 , 68.6579), Complex(-8.4039 ,150.3269) - ], dtype: :complex128) + [ + Complex(330.3200, 0.0000), Complex(-8.4039, -150.3269), + Complex(-99.4807, -68.6579), Complex(-143.6861, -20.4273), + Complex(67.6207, 8.5236), Complex(130.7800, 0.0000), + Complex(67.6207, -8.5236), Complex(-143.6861, 20.4273), + Complex(-99.4807, 68.6579), Complex(-8.4039, 150.3269), + ], dtype: :complex128) end it "computes an FFT of a complex NMatrix" do nm = NMatrix.new([10], [ - Complex(9.32,0), Complex(44,0), Complex(125,0), Complex(34,0), - Complex(31,0), Complex(44,0), Complex(12,0), Complex(1,0), - Complex(53.23,0),Complex(-23.23,0)], dtype: :complex128) + Complex(9.32, 0), Complex(44, 0), Complex(125, 0), Complex(34, 0), + Complex(31, 0), Complex(44, 0), Complex(12, 0), Complex(1, 0), + Complex(53.23, 0), Complex(-23.23, 0), + ], dtype: :complex128) expect(nm.fft.round(4)).to eq(@answer) end end context "#fft2" do it "computes 2D FFT if NMatrix has such shape" do - input = NMatrix.new([2,2], + input = NMatrix.new([2, 2], [ - Complex(9.3200,0), Complex(43.0000,0), - Complex(3.2000,0), Complex(4.0000,0) - ], dtype: :complex128 - ) - output = NMatrix.new([2,2], + Complex(9.3200, 0), Complex(43.0000, 0), + Complex(3.2000, 0), Complex(4.0000, 0), + ], dtype: :complex128) + output = NMatrix.new([2, 2], [ - Complex(59.520,0), Complex(-34.480,0), - Complex(45.120,0), Complex(-32.880,0), - ], dtype: :complex128 - ) - expect(input.fft2.round(4)).to eq(output) + Complex(59.520, 0), Complex(-34.480, 0), + Complex(45.120, 0), Complex(-32.880, 0), + ], dtype: :complex128) + expect(input.fft2.round(4)).to eq(output) end end end @@ -80,28 +79,28 @@ expect(plan.shape) .to eq([4]) expect(plan.size) .to eq(4) expect(plan.dim) .to eq(1) - expect(plan.flags) .to eq([:estimate]) + expect(plan.flags) .to eq([:estimate]) expect(plan.direction).to eq(:forward) end it "creates a new plan for multi dimensional DFT with options" do - plan = NMatrix::FFTW::Plan.new([10,5,8], + plan = NMatrix::FFTW::Plan.new([10, 5, 8], direction: :backward, flags: [:exhaustive, :estimate], dim: 3) - expect(plan.shape) .to eq([10,5,8]) - expect(plan.size) .to eq(10*5*8) + expect(plan.shape) .to eq([10, 5, 8]) + expect(plan.size) .to eq(10 * 5 * 8) expect(plan.dim) .to eq(3) expect(plan.flags) .to eq([:exhaustive, :estimate]) expect(plan.direction).to eq(:backward) end it "creates a new plan for real input/complex output" do - plan = NMatrix::FFTW::Plan.new([5,20,10,4,2], - direction: :forward, flags: [:patient, :exhaustive], dim: 5, + plan = NMatrix::FFTW::Plan.new([5, 20, 10, 4, 2], + direction: :forward, flags: [:patient, :exhaustive], dim: 5, type: :real_complex) - expect(plan.shape) .to eq([5,20,10,4,2]) - expect(plan.size) .to eq(5*20*10*4*2) + expect(plan.shape) .to eq([5, 20, 10, 4, 2]) + expect(plan.size) .to eq(5 * 20 * 10 * 4 * 2) expect(plan.dim) .to eq(5) expect(plan.flags) .to eq([:patient, :exhaustive]) expect(plan.type) .to eq(:real_complex) @@ -114,22 +113,22 @@ end it "creates a new plan for real input/real output" do - plan = NMatrix::FFTW::Plan.new([30,30], type: :real_real, - real_real_kind: [:rodft00, :redft10], dim: 2) + plan = NMatrix::FFTW::Plan.new([30, 30], type: :real_real, + real_real_kind: [:rodft00, :redft10], dim: 2) - expect(plan.shape).to eq([30,30]) - expect(plan.size) .to eq(30*30) + expect(plan.shape).to eq([30, 30]) + expect(plan.size) .to eq(30 * 30) expect(plan.dim) .to eq(2) expect(plan.flags).to eq([:estimate]) expect(plan.type) .to eq(:real_real) end it "creates a new plan for complex input/real output" do - plan = NMatrix::FFTW::Plan.new([30,400], type: :complex_real, - dim: 2, flags: [:patient, :exhaustive]) + plan = NMatrix::FFTW::Plan.new([30, 400], type: :complex_real, + dim: 2, flags: [:patient, :exhaustive]) - expect(plan.shape).to eq([30,400]) - expect(plan.size) .to eq(30*400) + expect(plan.shape).to eq([30, 400]) + expect(plan.size) .to eq(30 * 400) expect(plan.dim) .to eq(2) expect(plan.flags).to eq([:patient, :exhaustive]) expect(plan.type) .to eq(:complex_real) @@ -139,7 +138,7 @@ context "#set_input" do it "accepts nothing but complex128 input for the default or complex_real plan" do plan = NMatrix::FFTW::Plan.new(4) - input = NMatrix.new([4], [23.54,52.34,52.345,64], dtype: :float64) + input = NMatrix.new([4], [23.54, 52.34, 52.345, 64], dtype: :float64) expect { plan.set_input(input) }.to raise_error(ArgumentError) @@ -152,7 +151,7 @@ it "accepts nothing but float64 input for real_complex or real_real plan" do plan = NMatrix::FFTW::Plan.new(4, type: :real_complex) - input = NMatrix.new([4], [1,2,3,4], dtype: :int32) + input = NMatrix.new([4], [1, 2, 3, 4], dtype: :int32) expect { plan.set_input(input) @@ -164,30 +163,30 @@ it "calculates a basic 1D DFT" do input = NMatrix.new([10], [ - Complex(9.32,0), - Complex(44,0), - Complex(125,0), - Complex(34,0), - Complex(31,0), - Complex(44,0), - Complex(12,0), - Complex(1,0), - Complex(53.23,0), - Complex(-23.23,0), + Complex(9.32, 0), + Complex(44, 0), + Complex(125, 0), + Complex(34, 0), + Complex(31, 0), + Complex(44, 0), + Complex(12, 0), + Complex(1, 0), + Complex(53.23, 0), + Complex(-23.23, 0), ], dtype: :complex128) output = NMatrix.new([10], [ - Complex(330.3200,0.0000), - Complex(-8.4039 ,-150.3269), - Complex(-99.4807 , -68.6579), + Complex(330.3200, 0.0000), + Complex(-8.4039, -150.3269), + Complex(-99.4807, -68.6579), Complex(-143.6861, -20.4273), - Complex(67.6207 , 8.5236), - Complex(130.7800 , 0.0000), - Complex(67.6207 , -8.5236), + Complex(67.6207, 8.5236), + Complex(130.7800, 0.0000), + Complex(67.6207, -8.5236), Complex(-143.6861, 20.4273), - Complex(-99.4807 , 68.6579), - Complex(-8.4039 ,150.3269) + Complex(-99.4807, 68.6579), + Complex(-8.4039, 150.3269), ], dtype: :complex128) plan = NMatrix::FFTW::Plan.new(10) @@ -197,21 +196,19 @@ end it "calculates 2D DFT with options" do - input = NMatrix.new([2,2], + input = NMatrix.new([2, 2], [ - Complex(9.3200,0), Complex(43.0000,0), - Complex(3.2000,0), Complex(4.0000,0) - ], dtype: :complex128 - ) + Complex(9.3200, 0), Complex(43.0000, 0), + Complex(3.2000, 0), Complex(4.0000, 0), + ], dtype: :complex128) - output = NMatrix.new([2,2], + output = NMatrix.new([2, 2], [ - Complex(59.520,0), Complex(-34.480,0), - Complex(45.120,0), Complex(-32.880,0), - ], dtype: :complex128 - ) + Complex(59.520, 0), Complex(-34.480, 0), + Complex(45.120, 0), Complex(-32.880, 0), + ], dtype: :complex128) - plan = NMatrix::FFTW::Plan.new([2,2], + plan = NMatrix::FFTW::Plan.new([2, 2], direction: :forward, flags: :estimate, dim: 2) plan.set_input input expect(plan.execute).to eq(true) @@ -219,12 +216,11 @@ end it "calculates ND DFT with options" do - end it "calculates 1D real input/complex output DFT" do input = NMatrix.new([4], [3.10, 1.73, 1.04, 2.83], dtype: :float64) - output = NMatrix.new([3], + output = NMatrix.new([3], [Complex(8.70, 0), Complex(2.06, 1.1), Complex(-0.42, 0)], dtype: :complex128) plan = NMatrix::FFTW::Plan.new([4], type: :real_complex) plan.set_input input @@ -234,11 +230,11 @@ it "calculates 2D real input/complex output DFT" do input = NMatrix.new([16], [ - 1 , 5,54 ,656, - 4.3,1.32,-43.34,14 , - 1 , 5, 54,656, - 4.3,1.32,-43.34,14 - ], dtype: :float64) + 1, 5, 54, 656, + 4.3, 1.32, -43.34, 14, + 1, 5, 54, 656, + 4.3, 1.32, -43.34, 14, + ], dtype: :float64) output = NMatrix.new([9], [ Complex(1384.56, 0.0), @@ -249,11 +245,10 @@ Complex(0.0, 0.0), Complex(1479.44, 0.0), Complex(-201.28, 1276.64), - Complex(-1103.28, 0.0) - ], dtype: :complex128 - ) + Complex(-1103.28, 0.0), + ], dtype: :complex128) - plan = NMatrix::FFTW::Plan.new([4,4], type: :real_complex, dim: 2) + plan = NMatrix::FFTW::Plan.new([4, 4], type: :real_complex, dim: 2) plan.set_input input expect(plan.execute).to eq(true) expect(plan.output).to eq(output) @@ -262,19 +257,19 @@ it "calculates 1D complex input/real output DFT" do input = NMatrix.new([8], [ - Complex(9.32,0), - Complex(43.0,0), - Complex(3.20,0), - Complex(4.00,0), - Complex(5.32,0), - Complex(3.20,0), - Complex(4.00,0), - Complex(5.32,0) + Complex(9.32, 0), + Complex(43.0, 0), + Complex(3.20, 0), + Complex(4.00, 0), + Complex(5.32, 0), + Complex(3.20, 0), + Complex(4.00, 0), + Complex(5.32, 0), ], dtype: :complex128) output = NMatrix.new([8], [ - 115.04,59.1543,8.24,-51.1543,-72.96,-51.1543,8.24,59.1543 - ], dtype: :float64) + 115.04, 59.1543, 8.24, -51.1543, -72.96, -51.1543, 8.24, 59.1543, + ], dtype: :float64) plan = NMatrix::FFTW::Plan.new([8], type: :complex_real) plan.set_input input @@ -285,21 +280,21 @@ it "calculates 2D complex input/real output DFT" do input = NMatrix.new([9], [ - Complex(9.32,0), - Complex(43.0,0), - Complex(3.20,0), - Complex(4.00,0), - Complex(5.32,0), - Complex(3.20,0), - Complex(4.00,0), - Complex(5.32,0), - Complex(45.32,0) + Complex(9.32, 0), + Complex(43.0, 0), + Complex(3.20, 0), + Complex(4.00, 0), + Complex(5.32, 0), + Complex(3.20, 0), + Complex(4.00, 0), + Complex(5.32, 0), + Complex(45.32, 0), ], dtype: :complex128) output = NMatrix.new([9], [ - 118.24,-32.36,-32.36,83.86,-35.54,-33.14,83.86,-33.14,-35.54 - ], dtype: :float64) + 118.24, -32.36, -32.36, 83.86, -35.54, -33.14, 83.86, -33.14, -35.54, + ], dtype: :float64) - plan = NMatrix::FFTW::Plan.new([3,3], type: :complex_real, dim: 2) + plan = NMatrix::FFTW::Plan.new([3, 3], type: :complex_real, dim: 2) plan.set_input input expect(plan.execute).to eq(true) expect(plan.output.round(2)) .to eq(output) @@ -307,9 +302,9 @@ it "calculates basic 1D real input/real output DFT of kind RODFT00" do input = NMatrix.new([9], - [9.32,43.00,3.20,4.00,5.32,3.20,4.00,5.32,45.32], dtype: :float64) + [9.32, 43.00, 3.20, 4.00, 5.32, 3.20, 4.00, 5.32, 45.32], dtype: :float64) output = NMatrix.new([9], - [126.56,28.77,165.67,-24.76,105.52,-110.31,-1.23,-116.45,-14.44], + [126.56, 28.77, 165.67, -24.76, 105.52, -110.31, -1.23, -116.45, -14.44], dtype: :float64) plan = NMatrix::FFTW::Plan.new([9], type: :real_real, real_real_kind: [:rodft00]) plan.set_input input @@ -319,9 +314,9 @@ it "calculates basic 1D real input/real output DFT of kind REDFT10" do input = NMatrix.new([9], - [9.32,43.00,3.20,4.00,5.32,3.20,4.00,5.32,45.32], dtype: :float64) + [9.32, 43.00, 3.20, 4.00, 5.32, 3.20, 4.00, 5.32, 45.32], dtype: :float64) output = NMatrix.new([9], - [245.36,-6.12,126.84,-62.35,35.00,-109.42,-38.24,-92.49,-21.20], + [245.36, -6.12, 126.84, -62.35, 35.00, -109.42, -38.24, -92.49, -21.20], dtype: :float64) plan = NMatrix::FFTW::Plan.new([9], type: :real_real, real_real_kind: [:redft10]) @@ -332,13 +327,13 @@ it "calculates 2D DFT for real input/real output of kind REDFT10, REDFT11" do input = NMatrix.new([9], - [9.32,43.00,3.20,4.00,5.32,3.20,4.00,5.32,45.32], dtype: :float64) + [9.32, 43.00, 3.20, 4.00, 5.32, 3.20, 4.00, 5.32, 45.32], dtype: :float64) output = NMatrix.new([9], - [272.181,-249.015,66.045,72.334,23.907,-228.463,85.368,-105.331,30.836], + [272.181, -249.015, 66.045, 72.334, 23.907, -228.463, 85.368, -105.331, 30.836], dtype: :float64) - plan = NMatrix::FFTW::Plan.new([3,3], type: :real_real, - real_real_kind: [:redft10, :redft11], dim: 2) + plan = NMatrix::FFTW::Plan.new([3, 3], type: :real_real, + real_real_kind: [:redft10, :redft11], dim: 2) plan.set_input input expect(plan.execute).to eq(true) expect(plan.output.round(3)) .to eq(output) diff --git a/spec/plugins/lapacke/lapacke_spec.rb b/spec/plugins/lapacke/lapacke_spec.rb index 8e661334..32ebbde6 100644 --- a/spec/plugins/lapacke/lapacke_spec.rb +++ b/spec/plugins/lapacke/lapacke_spec.rb @@ -25,17 +25,17 @@ # Tests for interfaces that are only exposed by nmatrix-lapacke # -require 'spec_helper' +require "spec_helper" require "./lib/nmatrix/lapacke" describe "NMatrix::LAPACK functions implemented with LAPACKE interface" do [:float32, :float64, :complex64, :complex128].each do |dtype| context dtype do it "exposes lapacke_getrf" do - a = NMatrix.new([3,4], GETRF_EXAMPLE_ARRAY, dtype: dtype) + a = NMatrix.new([3, 4], GETRF_EXAMPLE_ARRAY, dtype: dtype) ipiv = NMatrix::LAPACK.lapacke_getrf(:row, 3, 4, a, 4) - b = NMatrix.new([3,4], GETRF_SOLUTION_ARRAY, dtype: dtype) - ipiv_true = [2,3,3] + b = NMatrix.new([3, 4], GETRF_SOLUTION_ARRAY, dtype: dtype) + ipiv_true = [2, 3, 3] # delta varies for different dtypes err = case dtype @@ -43,15 +43,15 @@ 1e-6 when :float64, :complex128 1e-14 - end + end expect(a).to be_within(err).of(b) expect(ipiv).to eq(ipiv_true) end it "exposes lapacke_getri" do - a = NMatrix.new(:dense, 3, [1,0,4,1,1,6,-3,0,-10], dtype) - ipiv = NMatrix::LAPACK::lapacke_getrf(:row, 3, 3, a, 3) # get pivot from getrf, use for getri + a = NMatrix.new(:dense, 3, [1, 0, 4, 1, 1, 6, -3, 0, -10], dtype) + ipiv = NMatrix::LAPACK.lapacke_getrf(:row, 3, 3, a, 3) # get pivot from getrf, use for getri # delta varies for different dtypes err = case dtype @@ -59,21 +59,21 @@ 1e-5 when :float64, :complex128 1e-14 - end + end - NMatrix::LAPACK::lapacke_getri(:row, 3, a, 3, ipiv) + NMatrix::LAPACK.lapacke_getri(:row, 3, a, 3, ipiv) - b = NMatrix.new(:dense, 3, [-5,0,-2,-4,1,-1,1.5,0,0.5], dtype) + b = NMatrix.new(:dense, 3, [-5, 0, -2, -4, 1, -1, 1.5, 0, 0.5], dtype) expect(a).to be_within(err).of(b) end it "exposes lapacke_getrs with vector solutions" do - a = NMatrix.new(3, [-2,4,-3,3,-2,1,0,-4,3], dtype: dtype) - ipiv = NMatrix::LAPACK::lapacke_getrf(:row, 3, 3, a, 3) - b = NMatrix.new([3,1], [-1, 17, -9], dtype: dtype) + a = NMatrix.new(3, [-2, 4, -3, 3, -2, 1, 0, -4, 3], dtype: dtype) + ipiv = NMatrix::LAPACK.lapacke_getrf(:row, 3, 3, a, 3) + b = NMatrix.new([3, 1], [-1, 17, -9], dtype: dtype) - #be careful! the leading dimenension (lda,ldb) is the number of rows for row-major in LAPACKE. Different from CLAPACK convention! - NMatrix::LAPACK::lapacke_getrs(:row, false, 3, 1, a, 3, ipiv, b, 1) + # be careful! the leading dimenension (lda,ldb) is the number of rows for row-major in LAPACKE. Different from CLAPACK convention! + NMatrix::LAPACK.lapacke_getrs(:row, false, 3, 1, a, 3, ipiv, b, 1) # delta varies for different dtypes err = case dtype @@ -81,20 +81,20 @@ 1e-5 when :float64, :complex128 1e-13 - end + end expect(b[0]).to be_within(err).of(5) - expect(b[1]).to be_within(err).of(-15.0/2) + expect(b[1]).to be_within(err).of(-15.0 / 2) expect(b[2]).to be_within(err).of(-13) end it "exposes lapacke_getrs with matrix solutions" do - a = NMatrix.new(3, [-2,4,-3,3,-2,1,0,-4,3], dtype: dtype) - ipiv = NMatrix::LAPACK::lapacke_getrf(:row, 3, 3, a, 3) - b = NMatrix.new([3,2], [-1, 2, 17, 10, -9, 1], dtype: dtype) + a = NMatrix.new(3, [-2, 4, -3, 3, -2, 1, 0, -4, 3], dtype: dtype) + ipiv = NMatrix::LAPACK.lapacke_getrf(:row, 3, 3, a, 3) + b = NMatrix.new([3, 2], [-1, 2, 17, 10, -9, 1], dtype: dtype) - #be careful! the leading dimenension (lda,ldb) is the number of rows for row-major in LAPACKE. Different from CLAPACK convention! - NMatrix::LAPACK::lapacke_getrs(:row, false, 3, 2, a, 3, ipiv, b, 2) + # be careful! the leading dimenension (lda,ldb) is the number of rows for row-major in LAPACKE. Different from CLAPACK convention! + NMatrix::LAPACK.lapacke_getrs(:row, false, 3, 2, a, 3, ipiv, b, 2) # delta varies for different dtypes err = case dtype @@ -102,115 +102,115 @@ 1e-4 when :float64, :complex128 1e-13 - end + end - x = NMatrix.new([3,2], [5, -1.5, -7.5, -21.25, -13, -28], dtype: dtype) + x = NMatrix.new([3, 2], [5, -1.5, -7.5, -21.25, -13, -28], dtype: dtype) expect(b).to be_within(err).of(x) end it "exposes lapacke_potrf" do # first do upper begin - a = NMatrix.new(:dense, 3, [25,15,-5, 0,18,0, 0,0,11], dtype) - NMatrix::LAPACK::lapacke_potrf(:row, :upper, 3, a, 3) - b = NMatrix.new(:dense, 3, [5,3,-1, 0,3,1, 0,0,3], dtype) + a = NMatrix.new(:dense, 3, [25, 15, -5, 0, 18, 0, 0, 0, 11], dtype) + NMatrix::LAPACK.lapacke_potrf(:row, :upper, 3, a, 3) + b = NMatrix.new(:dense, 3, [5, 3, -1, 0, 3, 1, 0, 0, 3], dtype) expect(a).to eq(b) end # then do lower - a = NMatrix.new(:dense, 3, [25,0,0, 15,18,0,-5,0,11], dtype) - NMatrix::LAPACK::lapacke_potrf(:row, :lower, 3, a, 3) - b = NMatrix.new(:dense, 3, [5,0,0, 3,3,0, -1,1,3], dtype) + a = NMatrix.new(:dense, 3, [25, 0, 0, 15, 18, 0, -5, 0, 11], dtype) + NMatrix::LAPACK.lapacke_potrf(:row, :lower, 3, a, 3) + b = NMatrix.new(:dense, 3, [5, 0, 0, 3, 3, 0, -1, 1, 3], dtype) expect(a).to eq(b) end it "exposes lapacke_potri" do - a = NMatrix.new(3, [4, 0,-1, + a = NMatrix.new(3, [4, 0, -1, 0, 2, 1, - 0, 0, 1], dtype: dtype) - NMatrix::LAPACK::lapacke_potrf(:row, :upper, 3, a, 3) - NMatrix::LAPACK::lapacke_potri(:row, :upper, 3, a, 3) - b = NMatrix.new(3, [0.5, -0.5, 1, 0, 1.5, -2, 0, 0, 4], dtype: dtype) + 0, 0, 1,], dtype: dtype) + NMatrix::LAPACK.lapacke_potrf(:row, :upper, 3, a, 3) + NMatrix::LAPACK.lapacke_potri(:row, :upper, 3, a, 3) + b = NMatrix.new(3, [0.5, -0.5, 1, 0, 1.5, -2, 0, 0, 4], dtype: dtype) err = case dtype when :float32, :complex64 1e-6 when :float64, :complex128 1e-14 - end + end expect(a).to be_within(err).of(b) end it "exposes lapacke_potrs with vector solution" do - a = NMatrix.new(3, [4, 0,-1, + a = NMatrix.new(3, [4, 0, -1, 0, 2, 1, - 0, 0, 1], dtype: dtype) - b = NMatrix.new([3,1], [3,0,2], dtype: dtype) + 0, 0, 1,], dtype: dtype) + b = NMatrix.new([3, 1], [3, 0, 2], dtype: dtype) - NMatrix::LAPACK::lapacke_potrf(:row, :upper, 3, a, 3) - #ldb is different from CLAPACK versions - NMatrix::LAPACK::lapacke_potrs(:row, :upper, 3, 1, a, 3, b, 1) + NMatrix::LAPACK.lapacke_potrf(:row, :upper, 3, a, 3) + # ldb is different from CLAPACK versions + NMatrix::LAPACK.lapacke_potrs(:row, :upper, 3, 1, a, 3, b, 1) - x = NMatrix.new([3,1], [3.5, -5.5, 11], dtype: dtype) + x = NMatrix.new([3, 1], [3.5, -5.5, 11], dtype: dtype) err = case dtype when :float32, :complex64 1e-5 when :float64, :complex128 1e-14 - end + end expect(b).to be_within(err).of(x) end it "exposes lapacke_potrs with matrix solution" do - a = NMatrix.new(3, [4, 0,-1, + a = NMatrix.new(3, [4, 0, -1, 0, 2, 1, - 0, 0, 1], dtype: dtype) - b = NMatrix.new([3,2], [3,4, - 0,4, - 2,0], dtype: dtype) + 0, 0, 1,], dtype: dtype) + b = NMatrix.new([3, 2], [3, 4, + 0, 4, + 2, 0,], dtype: dtype) - NMatrix::LAPACK::lapacke_potrf(:row, :upper, 3, a, 3) - #ldb is different from CLAPACK versions - NMatrix::LAPACK::lapacke_potrs(:row, :upper, 3, 2, a, 3, b, 2) + NMatrix::LAPACK.lapacke_potrf(:row, :upper, 3, a, 3) + # ldb is different from CLAPACK versions + NMatrix::LAPACK.lapacke_potrs(:row, :upper, 3, 2, a, 3, b, 2) - x = NMatrix.new([3,2], [3.5, 0, - -5.5, 4, - 11, -4], dtype: dtype) + x = NMatrix.new([3, 2], [3.5, 0, + -5.5, 4, + 11, -4,], dtype: dtype) err = case dtype when :float32, :complex64 1e-5 when :float64, :complex128 1e-14 - end + end expect(b).to be_within(err).of(x) end it "calculates the singular value decomposition with lapacke_gesvd" do - #example from Wikipedia + # example from Wikipedia m = 4 n = 5 - mn_min = [m,n].min - a = NMatrix.new([m,n],[1,0,0,0,2, 0,0,3,0,0, 0,0,0,0,0, 0,4,0,0,0], dtype: dtype) - s = NMatrix.new([mn_min], 0, dtype: a.abs_dtype) #s is always real and always returned as float/double, never as complex - u = NMatrix.new([m,m], 0, dtype: dtype) - vt = NMatrix.new([n,n], 0, dtype: dtype) - superb = NMatrix.new([mn_min-1], dtype: a.abs_dtype) + mn_min = [m, n].min + a = NMatrix.new([m, n], [1, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0], dtype: dtype) + s = NMatrix.new([mn_min], 0, dtype: a.abs_dtype) # s is always real and always returned as float/double, never as complex + u = NMatrix.new([m, m], 0, dtype: dtype) + vt = NMatrix.new([n, n], 0, dtype: dtype) + superb = NMatrix.new([mn_min - 1], dtype: a.abs_dtype) NMatrix::LAPACK.lapacke_gesvd(:row, :a, :a, m, n, a, n, s, u, m, vt, n, superb) - s_true = NMatrix.new([mn_min], [4,3,Math.sqrt(5),0], dtype: a.abs_dtype) - u_true = NMatrix.new([m,m], [0,0,1,0, 0,1,0,0, 0,0,0,-1, 1,0,0,0], dtype: dtype) - vt_true = NMatrix.new([n,n], [0,1,0,0,0, 0,0,1,0,0, Math.sqrt(0.2),0,0,0,Math.sqrt(0.8), 0,0,0,1,0, -Math.sqrt(0.8),0,0,0,Math.sqrt(0.2)], dtype: dtype) + s_true = NMatrix.new([mn_min], [4, 3, Math.sqrt(5), 0], dtype: a.abs_dtype) + u_true = NMatrix.new([m, m], [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0], dtype: dtype) + vt_true = NMatrix.new([n, n], [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, Math.sqrt(0.2), 0, 0, 0, Math.sqrt(0.8), 0, 0, 0, 1, 0, -Math.sqrt(0.8), 0, 0, 0, Math.sqrt(0.2)], dtype: dtype) err = case dtype when :float32, :complex64 1e-5 when :float64, :complex128 1e-14 - end + end expect(s).to be_within(err).of(s_true) expect(u).to be_within(err).of(u_true) @@ -218,27 +218,27 @@ end it "calculates the singular value decomposition with lapacke_gesdd" do - #example from Wikipedia + # example from Wikipedia m = 4 n = 5 - mn_min = [m,n].min - a = NMatrix.new([m,n],[1,0,0,0,2, 0,0,3,0,0, 0,0,0,0,0, 0,4,0,0,0], dtype: dtype) - s = NMatrix.new([mn_min], 0, dtype: a.abs_dtype) #s is always real and always returned as float/double, never as complex - u = NMatrix.new([m,m], 0, dtype: dtype) - vt = NMatrix.new([n,n], 0, dtype: dtype) + mn_min = [m, n].min + a = NMatrix.new([m, n], [1, 0, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0], dtype: dtype) + s = NMatrix.new([mn_min], 0, dtype: a.abs_dtype) # s is always real and always returned as float/double, never as complex + u = NMatrix.new([m, m], 0, dtype: dtype) + vt = NMatrix.new([n, n], 0, dtype: dtype) NMatrix::LAPACK.lapacke_gesdd(:row, :a, m, n, a, n, s, u, m, vt, n) - s_true = NMatrix.new([mn_min], [4,3,Math.sqrt(5),0], dtype: a.abs_dtype) - u_true = NMatrix.new([m,m], [0,0,1,0, 0,1,0,0, 0,0,0,-1, 1,0,0,0], dtype: dtype) - vt_true = NMatrix.new([n,n], [0,1,0,0,0, 0,0,1,0,0, Math.sqrt(0.2),0,0,0,Math.sqrt(0.8), 0,0,0,1,0, -Math.sqrt(0.8),0,0,0,Math.sqrt(0.2)], dtype: dtype) + s_true = NMatrix.new([mn_min], [4, 3, Math.sqrt(5), 0], dtype: a.abs_dtype) + u_true = NMatrix.new([m, m], [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0], dtype: dtype) + vt_true = NMatrix.new([n, n], [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, Math.sqrt(0.2), 0, 0, 0, Math.sqrt(0.8), 0, 0, 0, 1, 0, -Math.sqrt(0.8), 0, 0, 0, Math.sqrt(0.2)], dtype: dtype) err = case dtype when :float32, :complex64 1e-5 when :float64, :complex128 1e-14 - end + end expect(s).to be_within(err).of(s_true) expect(u).to be_within(err).of(u_true) @@ -247,44 +247,44 @@ it "calculates eigenvalues and eigenvectors using lapacke_geev" do n = 3 - a = NMatrix.new([n,n], [-1,0,0, 0,1,-2, 0,1,-1], dtype: dtype) + a = NMatrix.new([n, n], [-1, 0, 0, 0, 1, -2, 0, 1, -1], dtype: dtype) w = NMatrix.new([n], dtype: dtype) - if a.complex_dtype? #for real dtypes, imaginary parts of eigenvalues are stored in separate vector - wi = nil + wi = if a.complex_dtype? # for real dtypes, imaginary parts of eigenvalues are stored in separate vector + nil else - wi = NMatrix.new([n], dtype: dtype) + NMatrix.new([n], dtype: dtype) end - vl = NMatrix.new([n,n], dtype: dtype) - vr = NMatrix.new([n,n], dtype: dtype) + vl = NMatrix.new([n, n], dtype: dtype) + vr = NMatrix.new([n, n], dtype: dtype) NMatrix::LAPACK.lapacke_geev(:row, :t, :t, n, a, n, w, wi, vl, n, vr, n) - if !a.complex_dtype? - w = w + wi*Complex(0,1) + unless a.complex_dtype? + w += wi * Complex(0, 1) end - w_true = NMatrix.new([n], [Complex(0,1), -Complex(0,1), -1], dtype: NMatrix.upcast(dtype, :complex64)) + w_true = NMatrix.new([n], [Complex(0, 1), -Complex(0, 1), -1], dtype: NMatrix.upcast(dtype, :complex64)) if a.complex_dtype? - #For complex types the right/left eigenvectors are stored as columns - #of vr/vl. - vr_true = NMatrix.new([n,n],[0,0,1, - 2/Math.sqrt(6),2/Math.sqrt(6),0, - Complex(1,-1)/Math.sqrt(6),Complex(1,1)/Math.sqrt(6),0], dtype: dtype) - vl_true = NMatrix.new([n,n],[0,0,1, - Complex(-1,1)/Math.sqrt(6),Complex(-1,-1)/Math.sqrt(6),0, - 2/Math.sqrt(6),2/Math.sqrt(6),0], dtype: dtype) + # For complex types the right/left eigenvectors are stored as columns + # of vr/vl. + vr_true = NMatrix.new([n, n], [0, 0, 1, + 2 / Math.sqrt(6), 2 / Math.sqrt(6), 0, + Complex(1, -1) / Math.sqrt(6), Complex(1, 1) / Math.sqrt(6), 0,], dtype: dtype) + vl_true = NMatrix.new([n, n], [0, 0, 1, + Complex(-1, 1) / Math.sqrt(6), Complex(-1, -1) / Math.sqrt(6), 0, + 2 / Math.sqrt(6), 2 / Math.sqrt(6), 0,], dtype: dtype) else - #For real types, the real part of the first and second eigenvectors is - #stored in the first column, the imaginary part of the first (= the - #negative of the imaginary part of the second) eigenvector is stored - #in the second column, and the third eigenvector (purely real) is the - #third column. - vr_true = NMatrix.new([n,n],[0,0,1, - 2/Math.sqrt(6),0,0, - 1/Math.sqrt(6),-1/Math.sqrt(6),0], dtype: dtype) - vl_true = NMatrix.new([n,n],[0,0,1, - -1/Math.sqrt(6),1/Math.sqrt(6),0, - 2/Math.sqrt(6),0,0], dtype: dtype) + # For real types, the real part of the first and second eigenvectors is + # stored in the first column, the imaginary part of the first (= the + # negative of the imaginary part of the second) eigenvector is stored + # in the second column, and the third eigenvector (purely real) is the + # third column. + vr_true = NMatrix.new([n, n], [0, 0, 1, + 2 / Math.sqrt(6), 0, 0, + 1 / Math.sqrt(6), -1 / Math.sqrt(6), 0,], dtype: dtype) + vl_true = NMatrix.new([n, n], [0, 0, 1, + -1 / Math.sqrt(6), 1 / Math.sqrt(6), 0, + 2 / Math.sqrt(6), 0, 0,], dtype: dtype) end err = case dtype @@ -292,199 +292,197 @@ 1e-6 when :float64, :complex128 1e-15 - end + end expect(w).to be_within(err).of(w_true) expect(vr).to be_within(err).of(vr_true) expect(vl).to be_within(err).of(vl_true) end - + it "exposes lapacke_geqrf" do - a = NMatrix.new(3, [12.0, -51.0, 4.0, - 6.0, 167.0, -68.0, - -4.0, 24.0, -41.0] , dtype: dtype) + a = NMatrix.new(3, [12.0, -51.0, 4.0, + 6.0, 167.0, -68.0, + -4.0, 24.0, -41.0,], dtype: dtype) - b = NMatrix.new([3,1], 0, dtype: dtype) + b = NMatrix.new([3, 1], 0, dtype: dtype) - NMatrix::LAPACK::lapacke_geqrf(:row, a.shape[0], a.shape[1], a, a.shape[1], b) + NMatrix::LAPACK.lapacke_geqrf(:row, a.shape[0], a.shape[1], a, a.shape[1], b) - x = NMatrix.new([3,1], TAU_SOLUTION_ARRAY, dtype: dtype) - - y = NMatrix.new([3,3], GEQRF_SOLUTION_ARRAY, dtype: dtype) + x = NMatrix.new([3, 1], TAU_SOLUTION_ARRAY, dtype: dtype) + + y = NMatrix.new([3, 3], GEQRF_SOLUTION_ARRAY, dtype: dtype) err = case dtype when :float32, :complex64 1e-4 when :float64, :complex128 1e-14 - end - + end + expect(b).to be_within(err).of(x) - expect(a).to be_within(err).of(y) + expect(a).to be_within(err).of(y) end it "calculates QR decomposition in a compressed format using geqrf!" do - a = NMatrix.new(3, [12.0, -51.0, 4.0, - 6.0, 167.0, -68.0, - -4.0, 24.0, -41.0] , dtype: dtype) + a = NMatrix.new(3, [12.0, -51.0, 4.0, + 6.0, 167.0, -68.0, + -4.0, 24.0, -41.0,], dtype: dtype) tau = a.geqrf! - - x = NMatrix.new([3,1], TAU_SOLUTION_ARRAY, dtype: dtype) - - y = NMatrix.new([3,3], GEQRF_SOLUTION_ARRAY, dtype: dtype) + + x = NMatrix.new([3, 1], TAU_SOLUTION_ARRAY, dtype: dtype) + + y = NMatrix.new([3, 3], GEQRF_SOLUTION_ARRAY, dtype: dtype) err = case dtype when :float32, :complex64 1e-4 when :float64, :complex128 1e-14 - end - + end + expect(tau).to be_within(err).of(x) - expect(a).to be_within(err).of(y) + expect(a).to be_within(err).of(y) end it "exposes lapacke_ormqr and lapacke_unmqr" do - a = NMatrix.new([4,2], [34.0, 21.0, - 23.0, 53.0, - 26.0, 346.0, - 23.0, 121.0] , dtype: dtype) + a = NMatrix.new([4, 2], [34.0, 21.0, + 23.0, 53.0, + 26.0, 346.0, + 23.0, 121.0,], dtype: dtype) - tau = NMatrix.new([2,1], dtype: dtype) + tau = NMatrix.new([2, 1], dtype: dtype) result = NMatrix.identity(4, dtype: dtype) - - # get tau from geqrf, use for ormqr - NMatrix::LAPACK::lapacke_geqrf(:row, a.shape[0], a.shape[1], a, a.shape[1], tau) - #Q is stored in result + # get tau from geqrf, use for ormqr + NMatrix::LAPACK.lapacke_geqrf(:row, a.shape[0], a.shape[1], a, a.shape[1], tau) + + # Q is stored in result a.complex_dtype? ? - NMatrix::LAPACK::lapacke_unmqr(:row, :left, false, result.shape[0], result.shape[1], tau.shape[0], - a, a.shape[1], tau, result, result.shape[1]) + NMatrix::LAPACK.lapacke_unmqr(:row, :left, false, result.shape[0], result.shape[1], tau.shape[0], + a, a.shape[1], tau, result, result.shape[1]) : - NMatrix::LAPACK::lapacke_ormqr(:row, :left, false, result.shape[0], result.shape[1], tau.shape[0], - a, a.shape[1], tau, result, result.shape[1]) + NMatrix::LAPACK.lapacke_ormqr(:row, :left, false, result.shape[0], result.shape[1], tau.shape[0], + a, a.shape[1], tau, result, result.shape[1]) - x = NMatrix.new([4,4], Q_SOLUTION_ARRAY_1, dtype: dtype) + x = NMatrix.new([4, 4], Q_SOLUTION_ARRAY_1, dtype: dtype) err = case dtype when :float32, :complex64 1e-4 when :float64, :complex128 1e-14 - end + end - expect(result).to be_within(err).of(x) + expect(result).to be_within(err).of(x) end it "calculates the product of the orthogonal matrix with an arbitrary matrix" do - a = N.new([2,2], [34.0, 21, 23, 53] , dtype: dtype) + a = N.new([2, 2], [34.0, 21, 23, 53], dtype: dtype) + + tau = NMatrix.new([2, 1], dtype: dtype) + + # Result is the multiplicand that gets overriden : result = Q * result + result = NMatrix.new([2, 2], [2, 0, 0, 2], dtype: dtype) - tau = NMatrix.new([2,1], dtype: dtype) - - #Result is the multiplicand that gets overriden : result = Q * result - result = NMatrix.new([2,2], [2,0,0,2], dtype: dtype) - - # get tau from geqrf, use for ormqr - NMatrix::LAPACK::lapacke_geqrf(:row, a.shape[0], a.shape[1], a, a.shape[1], tau) + # get tau from geqrf, use for ormqr + NMatrix::LAPACK.lapacke_geqrf(:row, a.shape[0], a.shape[1], a, a.shape[1], tau) - #Q is stored in result + # Q is stored in result a.complex_dtype? ? - NMatrix::LAPACK::lapacke_unmqr(:row, :left, false, result.shape[0], result.shape[1], tau.shape[0], - a, a.shape[1], tau, result, result.shape[1]) + NMatrix::LAPACK.lapacke_unmqr(:row, :left, false, result.shape[0], result.shape[1], tau.shape[0], + a, a.shape[1], tau, result, result.shape[1]) : - NMatrix::LAPACK::lapacke_ormqr(:row, :left, false, result.shape[0], result.shape[1], tau.shape[0], - a, a.shape[1], tau, result, result.shape[1]) + NMatrix::LAPACK.lapacke_ormqr(:row, :left, false, result.shape[0], result.shape[1], tau.shape[0], + a, a.shape[1], tau, result, result.shape[1]) - x = NMatrix.new([2,2], [-1.6565668262559257 , -1.1206187354084205, - -1.1206187354084205 , 1.6565668262559263], dtype: dtype) + x = NMatrix.new([2, 2], [-1.6565668262559257, -1.1206187354084205, + -1.1206187354084205, 1.6565668262559263,], dtype: dtype) err = case dtype when :float32, :complex64 1e-4 when :float64, :complex128 1e-14 - end + end - expect(result).to be_within(err).of(x) + expect(result).to be_within(err).of(x) end - + it "calculates the orthogonal matrix Q using ormqr/unmqr after geqrf!" do - a = NMatrix.new([4,2], [34.0, 21.0, - 23.0, 53.0, - 26.0, 346.0, - 23.0, 121.0] , dtype: dtype) - - # get tau from geqrf, use for ormqr + a = NMatrix.new([4, 2], [34.0, 21.0, + 23.0, 53.0, + 26.0, 346.0, + 23.0, 121.0,], dtype: dtype) + + # get tau from geqrf, use for ormqr tau = a.geqrf! - #Q is stored in result + # Q is stored in result result = a.complex_dtype? ? a.unmqr(tau) : a.ormqr(tau) - - x = NMatrix.new([4,4], Q_SOLUTION_ARRAY_1, dtype: dtype) + x = NMatrix.new([4, 4], Q_SOLUTION_ARRAY_1, dtype: dtype) err = case dtype when :float32, :complex64 1e-4 when :float64, :complex128 1e-14 - end + end - expect(result).to be_within(err).of(x) + expect(result).to be_within(err).of(x) end end - + it "calculates the transpose of Q using ormqr/unmqr after geqrf!" do - a = NMatrix.new([4,2], [34.0, 21.0, - 23.0, 53.0, - 26.0, 346.0, - 23.0, 121.0] , dtype: dtype) - - # get tau from geqrf, use for ormqr - tau = a.geqrf! + a = NMatrix.new([4, 2], [34.0, 21.0, + 23.0, 53.0, + 26.0, 346.0, + 23.0, 121.0,], dtype: dtype) - #Q is stored in result - result = a.complex_dtype? ? a.unmqr(tau, :left, :complex_conjugate) : a.ormqr(tau, :left, :transpose) - + # get tau from geqrf, use for ormqr + tau = a.geqrf! - x = NMatrix.new([4,4], Q_SOLUTION_ARRAY_1, dtype: dtype) - x = x.transpose + # Q is stored in result + result = a.complex_dtype? ? a.unmqr(tau, :left, :complex_conjugate) : a.ormqr(tau, :left, :transpose) - err = case dtype - when :float32, :complex64 - 1e-4 - when :float64, :complex128 - 1e-14 - end + x = NMatrix.new([4, 4], Q_SOLUTION_ARRAY_1, dtype: dtype) + x = x.transpose - expect(result).to be_within(err).of(x) + err = case dtype + when :float32, :complex64 + 1e-4 + when :float64, :complex128 + 1e-14 + end + + expect(result).to be_within(err).of(x) end it "calculates the multiplication c * Q using ormqr/unmqr after geqrf!" do - a = NMatrix.new(3, [12.0, -51.0, 4.0, - 6.0, 167.0, -68.0, - -4.0, 24.0, -41.0] , dtype: dtype) - - # get tau from geqrf, use for ormqr - tau = a.geqrf! - c = NMatrix.new([2,3], [1,0,1,0,0,1], dtype: dtype) - - #Q is stored in result - result = a.complex_dtype? ? a.unmqr(tau, :right, false, c) : a.ormqr(tau, :right, false, c) - - solution = NMatrix.new([2,3], [-0.5714285714285714, 0.2228571428571429, 1.2742857142857142, - 0.28571428571428575, -0.1714285714285714, 0.9428571428571428] , dtype: dtype) - err = case dtype - when :float32, :complex64 - 1e-4 - when :float64, :complex128 - 1e-14 - end + a = NMatrix.new(3, [12.0, -51.0, 4.0, + 6.0, 167.0, -68.0, + -4.0, 24.0, -41.0,], dtype: dtype) + + # get tau from geqrf, use for ormqr + tau = a.geqrf! + c = NMatrix.new([2, 3], [1, 0, 1, 0, 0, 1], dtype: dtype) + + # Q is stored in result + result = a.complex_dtype? ? a.unmqr(tau, :right, false, c) : a.ormqr(tau, :right, false, c) + + solution = NMatrix.new([2, 3], [-0.5714285714285714, 0.2228571428571429, 1.2742857142857142, + 0.28571428571428575, -0.1714285714285714, 0.9428571428571428,], dtype: dtype) + err = case dtype + when :float32, :complex64 + 1e-4 + when :float64, :complex128 + 1e-14 + end - expect(result).to be_within(err).of(solution) + expect(result).to be_within(err).of(solution) end end end diff --git a/spec/rspec_monkeys.rb b/spec/rspec_monkeys.rb index e2f7a1fc..478b0e3b 100644 --- a/spec/rspec_monkeys.rb +++ b/spec/rspec_monkeys.rb @@ -27,20 +27,19 @@ module RSpec::Matchers::BuiltIn class BeWithin - def of(expected) @expected = expected - @unit = '' - if expected.is_a?(NMatrix) - @tolerance = if @delta.is_a?(NMatrix) - @delta.clone - elsif @delta.is_a?(Array) - NMatrix.new(:dense, expected.shape, @delta, expected.dtype) - else - NMatrix.ones_like(expected) * @delta - end + @unit = "" + @tolerance = if expected.is_a?(NMatrix) + if @delta.is_a?(NMatrix) + @delta.clone + elsif @delta.is_a?(Array) + NMatrix.new(:dense, expected.shape, @delta, expected.dtype) + else + NMatrix.ones_like(expected) * @delta + end else - @tolerance = @delta + @delta end self @@ -48,9 +47,9 @@ def of(expected) def percent_of(expected) @expected = expected - @unit = '%' + @unit = "%" @tolerance = @expected.abs * @delta / 100.0 # <- only change is to reverse abs and @delta self end end -end \ No newline at end of file +end diff --git a/spec/rspec_spec.rb b/spec/rspec_spec.rb index 1ac905c1..f1e70bd5 100644 --- a/spec/rspec_spec.rb +++ b/spec/rspec_spec.rb @@ -24,12 +24,12 @@ # # A spec for testing monkey patches to RSpec for NMatrix. # -require 'spec_helper' +require "spec_helper" describe "RSpec" do it "should permit #be_within to be used on a dense NMatrix" do pending("not yet implemented for NMatrix-JRuby") if jruby? - expect(NMatrix.new([4,1], 1.0, dtype: :complex128, stype: :dense) / 10000.0).to be_within(0.00000001).of(NMatrix.new([4,1], 0.0001, dtype: :float64, stype: :dense)) - expect(NMatrix.new([4,1], 1.0, dtype: :complex128, stype: :dense) / 10000.0).not_to be_within(0.00000001).of(NMatrix.new([4,1], 1.0, dtype: :float64, stype: :dense)) + expect(NMatrix.new([4, 1], 1.0, dtype: :complex128, stype: :dense) / 10000.0).to be_within(0.00000001).of(NMatrix.new([4, 1], 0.0001, dtype: :float64, stype: :dense)) + expect(NMatrix.new([4, 1], 1.0, dtype: :complex128, stype: :dense) / 10000.0).not_to be_within(0.00000001).of(NMatrix.new([4, 1], 1.0, dtype: :float64, stype: :dense)) end end diff --git a/spec/shortcuts_spec.rb b/spec/shortcuts_spec.rb index df75713e..7066eae1 100644 --- a/spec/shortcuts_spec.rb +++ b/spec/shortcuts_spec.rb @@ -25,8 +25,8 @@ # Specs for the shortcuts used in NMatrix and in NVector. # -require 'spec_helper' -require 'pry' +require "spec_helper" +require "pry" describe NMatrix do it "zeros() creates a matrix of zeros" do @@ -59,71 +59,71 @@ m = NMatrix.hilbert(3) hilbert3 = NMatrix.new([3, 3], [1.0, 0.5, 0.3333333333333333,\ - 0.5, 0.3333333333333333, 0.25, 0.3333333333333333, 0.25, 0.2]) + 0.5, 0.3333333333333333, 0.25, 0.3333333333333333, 0.25, 0.2,]) expect(m).to eq hilbert3 0.upto(2) do |i| 0.upto(2) do |j| - expect(m[i, j]).to be_within(0.000001).of(hilbert3[i,j]) + expect(m[i, j]).to be_within(0.000001).of(hilbert3[i, j]) end end end it "inv_hilbert() creates an inverse hilbert matrix" do m = NMatrix.inv_hilbert(6) - inv_hilbert6 = [3360.0, -88200.0, 564480.0, -1411200.0] - expect(m[2,0]).to be_within(0.000001).of(inv_hilbert6[0]) - expect(m[2,1]).to be_within(0.000001).of(inv_hilbert6[1]) - expect(m[2,2]).to be_within(0.000001).of(inv_hilbert6[2]) - expect(m[2,3]).to be_within(0.000001).of(inv_hilbert6[3]) + inv_hilbert6 = [3360.0, -88200.0, 564480.0, -1411200.0] + expect(m[2, 0]).to be_within(0.000001).of(inv_hilbert6[0]) + expect(m[2, 1]).to be_within(0.000001).of(inv_hilbert6[1]) + expect(m[2, 2]).to be_within(0.000001).of(inv_hilbert6[2]) + expect(m[2, 3]).to be_within(0.000001).of(inv_hilbert6[3]) m = NMatrix.inv_hilbert(3) - inv_hilbert3 = NMatrix.new([3, 3], [ 9.0, -36.0, 30.0, -36.0, 192.0, -180.0, 30.0, -180.0, 180.0] ) + inv_hilbert3 = NMatrix.new([3, 3], [9.0, -36.0, 30.0, -36.0, 192.0, -180.0, 30.0, -180.0, 180.0]) 0.upto(2) do |i| 0.upto(2) do |j| - expect(m[i, j]).to be_within(0.000001).of(inv_hilbert3[i,j]) + expect(m[i, j]).to be_within(0.000001).of(inv_hilbert3[i, j]) end end end it "diag() creates a matrix with pre-supplied diagonal" do - arr = [1,2,3,4] + arr = [1, 2, 3, 4] m = NMatrix.diag(arr) expect(m.is_a?(NMatrix)).to be true end it "diagonals() contains the seeded values on the diagonal" do - arr = [1,2,3,4] + arr = [1, 2, 3, 4] m = NMatrix.diagonals(arr) - expect(m[0,0]).to eq(arr[0]) - expect(m[1,1]).to eq(arr[1]) - expect(m[2,2]).to eq(arr[2]) - expect(m[3,3]).to eq(arr[3]) + expect(m[0, 0]).to eq(arr[0]) + expect(m[1, 1]).to eq(arr[1]) + expect(m[2, 2]).to eq(arr[2]) + expect(m[3, 3]).to eq(arr[3]) end ALL_DTYPES.each do |dtype| [:dense, :yale, :list].each do |stype| context "#block_diagonal #{dtype} #{stype}" do it "block_diagonal() creates a block-diagonal NMatrix" do - pending("not yet implemented for NMatrix-JRuby") if jruby? and dtype == :object - a = NMatrix.new([2,2], [1,2, - 3,4]) - b = NMatrix.new([1,1], [123.0]) - c = NMatrix.new([3,3], [1,2,3, - 1,2,3, - 1,2,3]) - d = Array[ [1,1,1], [2,2,2], [3,3,3] ] + pending("not yet implemented for NMatrix-JRuby") if jruby? && (dtype == :object) + a = NMatrix.new([2, 2], [1, 2, + 3, 4,]) + b = NMatrix.new([1, 1], [123.0]) + c = NMatrix.new([3, 3], [1, 2, 3, + 1, 2, 3, + 1, 2, 3,]) + d = Array[[1, 1, 1], [2, 2, 2], [3, 3, 3]] e = 12 m = NMatrix.block_diagonal(a, b, c, d, e, dtype: dtype, stype: stype) - expect(m).to eq(NMatrix.new([10,10], [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, - 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, - 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, - 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, - 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 12], dtype: dtype, stype: stype)) + expect(m).to eq(NMatrix.new([10, 10], [1, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 123, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, + 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, + 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, + 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 12,], dtype: dtype, stype: stype)) end end end @@ -138,22 +138,20 @@ end it "creates a matrix of random numbers with defined seed value" do - m1 = NMatrix.random(2,:seed => 62) - m2 = NMatrix.random(2,:seed => 62) - m3 = NMatrix.random(2,:seed => 65) - + m1 = NMatrix.random(2, seed: 62) + m2 = NMatrix.random(2, seed: 62) + m3 = NMatrix.random(2, seed: 65) expect(m1).to eq(m2) expect(m1).not_to eq(m3) - end it "creates a complex matrix of random numbers" do - m = NMatrix.random(2, :dtype => :complex128) + m = NMatrix.random(2, dtype: :complex128) end it "correctly accepts :scale parameter" do - m = NMatrix.random([2,2], dtype: :byte, scale: 255) + m = NMatrix.random([2, 2], dtype: :byte, scale: 255) m.each do |v| expect(v).to be >= 0 expect(v).to be < 255 @@ -172,21 +170,20 @@ end context "::magic" do - ALL_DTYPES.each do |dtype| context dtype do it "creates a matrix with numbers from 1 to n^n(n squared)" do pending("not yet implemented for NMatrix-JRuby") if jruby? a = NMatrix.magic(3, dtype: dtype) - magic3 = NMatrix.new([3,3], [4, 9, 2, 3, 5, 7, 8, 1, 6], dtype: dtype) + magic3 = NMatrix.new([3, 3], [4, 9, 2, 3, 5, 7, 8, 1, 6], dtype: dtype) expect(a).to eq magic3 b = NMatrix.magic(4, dtype: dtype) - magic4 = NMatrix.new([4,4], [1, 15, 14, 4, 12, 6, 7, 9, 8, 10, 11, 5, 13, 3, 2, 16], dtype: dtype) + magic4 = NMatrix.new([4, 4], [1, 15, 14, 4, 12, 6, 7, 9, 8, 10, 11, 5, 13, 3, 2, 16], dtype: dtype) expect(b).to eq magic4 c = NMatrix.magic(6, dtype: dtype) - magic6 = NMatrix.new([6,6], [31, 9, 2, 22, 27, 20, 3, 32, 7, 21, 23, 25, 35, 1, 6, 26, 19, 24, 4, 36, 29, 13, 18, 11, 30, 5, 34, 12, 14, 16, 8, 28, 33, 17, 10, 15], dtype: dtype) + magic6 = NMatrix.new([6, 6], [31, 9, 2, 22, 27, 20, 3, 32, 7, 21, 23, 25, 35, 1, 6, 26, 19, 24, 4, 36, 29, 13, 18, 11, 30, 5, 34, 12, 14, 16, 8, 28, 33, 17, 10, 15], dtype: dtype) expect(c).to eq magic6 end end @@ -205,10 +202,10 @@ it "creates a row vector when given only one shape parameter" do pending("not yet implemented for NMatrix-JRuby") if jruby? v = NMatrix.linspace(1, 10, 4) - #Expect a row vector only + # Expect a row vector only expect(v.shape.length).to eq(1) - ans = [1.0,4.0,7.0,10.0] + ans = [1.0, 4.0, 7.0, 10.0] expect(v[0]).to be_within(0.000001).of(ans[0]) expect(v[1]).to be_within(0.000001).of(ans[1]) @@ -218,15 +215,15 @@ it "creates a matrix of input shape with each entry linearly spaced in row major order" do pending("not yet implemented for NMatrix-JRuby") if jruby? - v = NMatrix.linspace(1, Math::PI, [2,2]) + v = NMatrix.linspace(1, Math::PI, [2, 2]) expect(v.dtype).to eq(:float64) ans = [1.0, 1.7138642072677612, 2.4277284145355225, 3.1415927410125732] - expect(v[0,0]).to be_within(0.000001).of(ans[0]) - expect(v[0,1]).to be_within(0.000001).of(ans[1]) - expect(v[1,0]).to be_within(0.000001).of(ans[2]) - expect(v[1,1]).to be_within(0.000001).of(ans[3]) + expect(v[0, 0]).to be_within(0.000001).of(ans[0]) + expect(v[0, 1]).to be_within(0.000001).of(ans[1]) + expect(v[1, 0]).to be_within(0.000001).of(ans[2]) + expect(v[1, 1]).to be_within(0.000001).of(ans[3]) end end @@ -237,7 +234,7 @@ expect(v.shape.length).to eq(1) - #Unit test taken from Matlab R2015b output of logspace(1,2,10) + # Unit test taken from Matlab R2015b output of logspace(1,2,10) ans = [10.0000, 12.9155, 16.6810, 21.5443, 27.8256, 35.9381, 46.4159, 59.9484, 77.4264, 100.0000] expect(v[0].round(4)).to be_within(0.000001).of(ans[0]) @@ -256,7 +253,7 @@ pending("not yet implemented for NMatrix-JRuby") if jruby? v = NMatrix.logspace(1, :pi, 7) - #Unit test taken from Matlab R2015b output of logspace(1,pi,10) + # Unit test taken from Matlab R2015b output of logspace(1,pi,10) ans = [10.0000, 8.2450, 6.7980, 5.6050, 4.6213, 3.8103, 3.1416] expect(v[0].round(4)).to be_within(0.000001).of(ans[0]) @@ -270,16 +267,16 @@ it "creates a matrix of input shape with each entry logarithmically spaced in row major order" do pending("not yet implemented for NMatrix-JRuby") if jruby? - v = NMatrix.logspace(1, 2, [3,2]) + v = NMatrix.logspace(1, 2, [3, 2]) ans = [10.0, 15.8489, 25.1189, 39.8107, 63.0957, 100.0] - expect(v[0,0].round(4)).to be_within(0.000001).of(ans[0]) - expect(v[0,1].round(4)).to be_within(0.000001).of(ans[1]) - expect(v[1,0].round(4)).to be_within(0.000001).of(ans[2]) - expect(v[1,1].round(4)).to be_within(0.000001).of(ans[3]) - expect(v[2,0].round(4)).to be_within(0.000001).of(ans[4]) - expect(v[2,1].round(4)).to be_within(0.000001).of(ans[5]) + expect(v[0, 0].round(4)).to be_within(0.000001).of(ans[0]) + expect(v[0, 1].round(4)).to be_within(0.000001).of(ans[1]) + expect(v[1, 0].round(4)).to be_within(0.000001).of(ans[2]) + expect(v[1, 1].round(4)).to be_within(0.000001).of(ans[3]) + expect(v[2, 0].round(4)).to be_within(0.000001).of(ans[4]) + expect(v[2, 1].round(4)).to be_within(0.000001).of(ans[5]) end end @@ -289,7 +286,7 @@ 2.times do |i| 2.times do |j| - expect(m[i,j]).to eq(value) + expect(m[i, j]).to eq(value) value += 1 end end @@ -313,7 +310,7 @@ 2.times do |i| 2.times do |j| - expect(m[i, j]/10).to be_within(Float::EPSILON).of(value.to_f/10) + expect(m[i, j] / 10).to be_within(Float::EPSILON).of(value.to_f / 10) value += 1 end end @@ -357,24 +354,24 @@ end it "diagonals() creates an NMatrix" do - arr = [1,2,3,4] + arr = [1, 2, 3, 4] m = NMatrix.diagonals(arr) expect(m.is_a?(NMatrix)).to be true end it "diagonals() contains the seeded values on the diagonal" do - arr = [1,2,3,4] + arr = [1, 2, 3, 4] m = NMatrix.diagonals(arr) - expect(m[0,0]).to eq(arr[0]) - expect(m[1,1]).to eq(arr[1]) - expect(m[2,2]).to eq(arr[2]) - expect(m[3,3]).to eq(arr[3]) + expect(m[0, 0]).to eq(arr[0]) + expect(m[1, 1]).to eq(arr[1]) + expect(m[2, 2]).to eq(arr[2]) + expect(m[3, 3]).to eq(arr[3]) end context "_like constructors" do before :each do - @nm_1d = NMatrix[5.0,0.0,1.0,2.0,3.0] - @nm_2d = NMatrix[[0.0,1.0],[2.0,3.0]] + @nm_1d = NMatrix[5.0, 0.0, 1.0, 2.0, 3.0] + @nm_2d = NMatrix[[0.0, 1.0], [2.0, 3.0]] end it "should create an nmatrix of ones with dimensions and type the same as its argument" do @@ -388,11 +385,9 @@ expect(NMatrix.zeros_like(@nm_2d)).to eq NMatrix[[0.0, 0.0], [0.0, 0.0]] end end - end describe "NVector" do - it "zeros() creates a vector of zeros" do v = NVector.zeros(4) @@ -419,7 +414,7 @@ it "seq() creates a vector of integers, sequentially" do v = NVector.seq(7) - expect(v).to eq(NMatrix.new([7,1], [0, 1, 2, 3, 4, 5, 6])) + expect(v).to eq(NMatrix.new([7, 1], [0, 1, 2, 3, 4, 5, 6])) end it "seq() only accepts integers as dimension" do @@ -431,40 +426,39 @@ it "indgen() creates a vector of integers as well as seq()" do v = NVector.indgen(7) - expect(v).to eq(NMatrix.new([7,1], [0, 1, 2, 3, 4, 5, 6])) + expect(v).to eq(NMatrix.new([7, 1], [0, 1, 2, 3, 4, 5, 6])) end it "findgen creates a vector of floats, sequentially" do v = NVector.findgen(2) - expect(v).to eq(NMatrix.new([2,1], [0.0, 1.0])) + expect(v).to eq(NMatrix.new([2, 1], [0.0, 1.0])) end it "bindgen() creates a vector of bytes, sequentially" do v = NVector.bindgen(4) - expect(v).to eq(NMatrix.new([4,1], [0, 1, 2, 3], dtype: :byte)) + expect(v).to eq(NMatrix.new([4, 1], [0, 1, 2, 3], dtype: :byte)) end it "cindgen() creates a vector of complexes, sequentially" do pending("not yet implemented for NMatrix-JRuby") if jruby? v = NVector.cindgen(2) - expect(v).to eq(NMatrix.new([2,1], [Complex(0.0, 0.0), Complex(1.0, 0.0)], dtype: :complex64)) + expect(v).to eq(NMatrix.new([2, 1], [Complex(0.0, 0.0), Complex(1.0, 0.0)], dtype: :complex64)) end it "linspace() creates a vector with n values equally spaced between a and b" do pending("not yet implemented for NMatrix-JRuby") if jruby? v = NVector.linspace(0, 2, 5) - expect(v).to eq(NMatrix.new([5,1], [0.0, 0.5, 1.0, 1.5, 2.0])) + expect(v).to eq(NMatrix.new([5, 1], [0.0, 0.5, 1.0, 1.5, 2.0])) end it "logspace() creates a vector with n values logarithmically spaced between decades 10^a and 10^b" do pending("not yet implemented for NMatrix-JRuby") if jruby? v = NVector.logspace(0, 3, 4) - expect(v).to eq(NMatrix.new([4,1], [1.0, 10.0, 100.0, 1000.0])) + expect(v).to eq(NMatrix.new([4, 1], [1.0, 10.0, 100.0, 1000.0])) end end describe "Inline constructor" do - it "creates a NMatrix with the given values" do m = NMatrix.new([2, 2], [1, 4, 6, 7]) n = NMatrix[[1, 4], [6, 7]] diff --git a/spec/slice_set_spec.rb b/spec/slice_set_spec.rb index 234b1b86..b71cc8b5 100644 --- a/spec/slice_set_spec.rb +++ b/spec/slice_set_spec.rb @@ -24,8 +24,8 @@ # # Test of slice set operations. -require 'spec_helper' -require 'pry' +require "spec_helper" +require "pry" describe "Set slice operation" do include RSpec::Longrun::DSL @@ -37,46 +37,45 @@ end example "set and unset a range of entries with single values" do - if stype == :yale step "verify correct arrangement of Yale IJA and A arrays" do @m.extend NMatrix::YaleFunctions unless jruby? if jruby? pending("not yet implemented for NMatrix-JRuby") else - expect(@m.yale_ija).to eq([4,6,8,10,1,2,0,2,0,1]) + expect(@m.yale_ija).to eq([4, 6, 8, 10, 1, 2, 0, 2, 0, 1]) end - expect(@m.yale_a).to eq([0,4,8,0, 1,2,3,5,6,7]) + expect(@m.yale_a).to eq([0, 4, 8, 0, 1, 2, 3, 5, 6, 7]) end end step "set and reset a single entry" do n = @m.clone - old_val = @m[0,0] - @m[0,0] = 100 - expect(@m[0,0]).to eq(100) - @m[0,0] = old_val + old_val = @m[0, 0] + @m[0, 0] = 100 + expect(@m[0, 0]).to eq(100) + @m[0, 0] = old_val expect(@m).to eq(n) end if stype == :yale n = @m.clone step "set a row of entries" do - n[0,0..2] = 0 - expect(n[0,0..2].to_flat_array).to eq([0,0,0]) - expect(n[1,0..2].to_flat_array).to eq([3,4,5]) - expect(n[2,0..2].to_flat_array).to eq([6,7,8]) + n[0, 0..2] = 0 + expect(n[0, 0..2].to_flat_array).to eq([0, 0, 0]) + expect(n[1, 0..2].to_flat_array).to eq([3, 4, 5]) + expect(n[2, 0..2].to_flat_array).to eq([6, 7, 8]) end step "set a second row of entries" do - n[2,0..2] = 0 - expect(n[2,0..2].to_flat_array).to eq([0,0,0]) - expect(n[1,0..2].to_flat_array).to eq([3,4,5]) + n[2, 0..2] = 0 + expect(n[2, 0..2].to_flat_array).to eq([0, 0, 0]) + expect(n[1, 0..2].to_flat_array).to eq([3, 4, 5]) end step "reset both rows of entries" do - n[0,0..2] = [0,1,2] - n[2,0..2] = [6,7,8] + n[0, 0..2] = [0, 1, 2] + n[2, 0..2] = [6, 7, 8] expect(n).to eq(@m) end end @@ -86,65 +85,65 @@ m = @m.clone step "set upper left-hand 2x2 corner to 100" do - m[0..1,0..1] = 100 + m[0..1, 0..1] = 100 if stype == :yale - expect(m.yale_ija).to eq([4, 6, 8, 10, 1, 2, 0, 2, 0, 1]) - expect(m.yale_a).to eq([100, 100, 8, 0, 100, 2, 100, 5, 6, 7]) + expect(m.yale_ija).to eq([4, 6, 8, 10, 1, 2, 0, 2, 0, 1]) + expect(m.yale_a).to eq([100, 100, 8, 0, 100, 2, 100, 5, 6, 7]) end - expect(m[0..1,0..1]).to eq(slice_result_a) - expect(m[2,0..1]).to eq(@m[2,0..1]) - expect(m[0..1,2]).to eq(@m[0..1,2]) + expect(m[0..1, 0..1]).to eq(slice_result_a) + expect(m[2, 0..1]).to eq(@m[2, 0..1]) + expect(m[0..1, 2]).to eq(@m[0..1, 2]) end step "set upper left-hand 2x2 corner to 0" do - m[0..1,0..1] = 0 + m[0..1, 0..1] = 0 if stype == :yale - expect([4,5,6,8,2,2,0,1]).to eq(m.yale_ija) - expect([0,0,8,0,2,5,6,7]).to eq(m.yale_a) + expect([4, 5, 6, 8, 2, 2, 0, 1]).to eq(m.yale_ija) + expect([0, 0, 8, 0, 2, 5, 6, 7]).to eq(m.yale_a) end - expect(m[0..1,0..1]).to eq(slice_result_b) + expect(m[0..1, 0..1]).to eq(slice_result_b) end m = @m.clone step "set lower left-hand 2x2 corner to 100" do - m[1..2,0..1] = 100 - expect(m[1..2,0..1]).to eq(slice_result_a) - expect(m[0,0..1]).to eq(@m[0,0..1]) - expect(m[1..2,2]).to eq(@m[1..2,2]) + m[1..2, 0..1] = 100 + expect(m[1..2, 0..1]).to eq(slice_result_a) + expect(m[0, 0..1]).to eq(@m[0, 0..1]) + expect(m[1..2, 2]).to eq(@m[1..2, 2]) end step "set lower left-hand 2x2 corner to 0" do - m[1..2,0..1] = 0 - expect(m[1..2,0..1]).to eq(slice_result_b) + m[1..2, 0..1] = 0 + expect(m[1..2, 0..1]).to eq(slice_result_b) end m = @m.clone step "set lower right-hand 2x2 corner to 100" do - m[1..2,1..2] = 100 - expect(m[1..2,1..2]).to eq(slice_result_a) - expect(m[0,1..2]).to eq(@m[0,1..2]) - expect(m[1..2,0]).to eq(@m[1..2,0]) + m[1..2, 1..2] = 100 + expect(m[1..2, 1..2]).to eq(slice_result_a) + expect(m[0, 1..2]).to eq(@m[0, 1..2]) + expect(m[1..2, 0]).to eq(@m[1..2, 0]) end step "set lower right-hand 2x2 corner to 0" do - m[1..2,1..2] = 0 - expect(m[1..2,1..2]).to eq(slice_result_b) + m[1..2, 1..2] = 0 + expect(m[1..2, 1..2]).to eq(slice_result_b) end m = @m.clone step "set upper right-hand 2x2 corner to 100" do - m[0..1,1..2] = 100 - expect(m[0..1,1..2]).to eq(slice_result_a) - expect(m[2,1..2]).to eq(@m[2,1..2]) - expect(m[0..1,0]).to eq(@m[0..1,0]) + m[0..1, 1..2] = 100 + expect(m[0..1, 1..2]).to eq(slice_result_a) + expect(m[2, 1..2]).to eq(@m[2, 1..2]) + expect(m[0..1, 0]).to eq(@m[0..1, 0]) end step "set upper right-hand 2x2 corner to 0" do - m[0..1,1..2] = 0 - expect(m[0..1,1..2]).to eq(slice_result_b) + m[0..1, 1..2] = 0 + expect(m[0..1, 1..2]).to eq(slice_result_b) end end @@ -152,11 +151,9 @@ pending("not yet implemented for int dtype for NMatrix-JRuby") if jruby? x = NMatrix.new(4, stype: :yale, dtype: :int16) x.extend NMatrix::YaleFunctions if stype == :yale - x[1..3,1..3] = @m - expect(x.to_flat_array).to eq([0,0,0,0, 0,0,1,2, 0,3,4,5, 0,6,7,8]) + x[1..3, 1..3] = @m + expect(x.to_flat_array).to eq([0, 0, 0, 0, 0, 0, 1, 2, 0, 3, 4, 5, 0, 6, 7, 8]) end - end end - end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index c422aff4..0ebb9227 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -25,101 +25,101 @@ # Common data and helper functions for testing. require "rspec/longrun" -#require "narray/narray" +# require "narray/narray" require "./lib/nmatrix" require "./lib/nmatrix/rspec" -ALL_DTYPES = [:byte,:int8,:int16,:int32,:int64, :float32,:float64, :object, - :complex64, :complex128] - +ALL_DTYPES = [:byte, :int8, :int16, :int32, :int64, :float32, :float64, :object, + :complex64, :complex128,] + NON_INTEGER_DTYPES = [:float32, :float64, :complex64, :complex128, - :object] + :object,] FLOAT_DTYPES = [:float32, :float64] - + MATRIX43A_ARRAY = [14.0, 9.0, 3.0, 2.0, 11.0, 15.0, 0.0, 12.0, 17.0, 5.0, 2.0, 3.0] MATRIX32A_ARRAY = [12.0, 25.0, 9.0, 10.0, 8.0, 5.0] COMPLEX_MATRIX43A_ARRAY = MATRIX43A_ARRAY.zip(MATRIX43A_ARRAY.reverse).collect { |ary| Complex(ary[0], ary[1]) } COMPLEX_MATRIX32A_ARRAY = MATRIX32A_ARRAY.zip(MATRIX32A_ARRAY.reverse).collect { |ary| Complex(ary[0], -ary[1]) } -#3x4 matrix used for testing various getrf and LU decomposition functions -GETRF_EXAMPLE_ARRAY = [-1,0,10,4,9,2,3,5,7,8,1,6] -GETRF_SOLUTION_ARRAY = [9.0, 2.0, 3.0, 5.0, 7.0/9, 58.0/9, -4.0/3, 19.0/9, -1.0/9, 1.0/29, 301.0/29, 130.0/29] +# 3x4 matrix used for testing various getrf and LU decomposition functions +GETRF_EXAMPLE_ARRAY = [-1, 0, 10, 4, 9, 2, 3, 5, 7, 8, 1, 6] +GETRF_SOLUTION_ARRAY = [9.0, 2.0, 3.0, 5.0, 7.0 / 9, 58.0 / 9, -4.0 / 3, 19.0 / 9, -1.0 / 9, 1.0 / 29, 301.0 / 29, 130.0 / 29] -TAU_SOLUTION_ARRAY = [1.8571428571428572,1.9938461538461538, 0.0] +TAU_SOLUTION_ARRAY = [1.8571428571428572, 1.9938461538461538, 0.0] -GEQRF_SOLUTION_ARRAY =[ -14.0, -21.0, 14.000000000000002, - 0.23076923076923078, -175.00000000000003, 70.00000000000001, - -0.15384615384615385, 0.055555555555555546, -35.0] +GEQRF_SOLUTION_ARRAY = [-14.0, -21.0, 14.000000000000002, + 0.23076923076923078, -175.00000000000003, 70.00000000000001, + -0.15384615384615385, 0.055555555555555546, -35.0,] -R_SOLUTION_ARRAY = [-159.2388143638353, -41.00131005172065, -56.75123892439876, -90.75048729628048, - 0.0, 25.137473501580676, 2.073591725046292, 9.790607357775713, - 0.0, 0.0, -20.83259700334131, -17.592414929551445] +R_SOLUTION_ARRAY = [-159.2388143638353, -41.00131005172065, -56.75123892439876, -90.75048729628048, + 0.0, 25.137473501580676, 2.073591725046292, 9.790607357775713, + 0.0, 0.0, -20.83259700334131, -17.592414929551445,] -Q_SOLUTION_ARRAY_1 = [-0.632455532033676, -0.5209522876558295, -0.3984263084135902, -0.41214704991068, - -0.42783756578748666, -0.20837937347171134, 0.876505919951498, 0.07259770177184455, - -0.48364246567281094, 0.8265854747306287,-0.015758658987033422, -0.2873988222474053, - -0.42783756578748666, 0.044081783789183565, -0.26971376257215296, 0.8615487797670971] +Q_SOLUTION_ARRAY_1 = [-0.632455532033676, -0.5209522876558295, -0.3984263084135902, -0.41214704991068, + -0.42783756578748666, -0.20837937347171134, 0.876505919951498, 0.07259770177184455, + -0.48364246567281094, 0.8265854747306287, -0.015758658987033422, -0.2873988222474053, + -0.42783756578748666, 0.044081783789183565, -0.26971376257215296, 0.8615487797670971,] -Q_SOLUTION_ARRAY_2 = [-0.8571428571428572, 0.3942857142857143, 0.33142857142857146, - -0.4285714285714286, -0.9028571428571428, -0.03428571428571425, - 0.28571428571428575, -0.1714285714285714, 0.9428571428571428] +Q_SOLUTION_ARRAY_2 = [-0.8571428571428572, 0.3942857142857143, 0.33142857142857146, + -0.4285714285714286, -0.9028571428571428, -0.03428571428571425, + 0.28571428571428575, -0.1714285714285714, 0.9428571428571428,] -Q_SOLUTION_ARRAY_3 = [-0.7724247413634004, -0.026670393594597247, -0.6345460653374136, +Q_SOLUTION_ARRAY_3 = [-0.7724247413634004, -0.026670393594597247, -0.6345460653374136, -0.5777485870360393, -0.38541856437557026, 0.7194853024298236, - -0.26375478973384403, 0.9223563413020934, 0.28229805268947933] + -0.26375478973384403, 0.9223563413020934, 0.28229805268947933,] def create_matrix(stype) #:nodoc: - m = NMatrix.new([3,3], 0, dtype: :int32, stype: stype, default: 0) - - m[0,0] = 0 - m[0,1] = 1 - m[0,2] = 2 - m[1,0] = 3 - m[1,1] = 4 - m[1,2] = 5 - m[2,0] = 6 - m[2,1] = 7 - m[2,2] = 8 + m = NMatrix.new([3, 3], 0, dtype: :int32, stype: stype, default: 0) + + m[0, 0] = 0 + m[0, 1] = 1 + m[0, 2] = 2 + m[1, 0] = 3 + m[1, 1] = 4 + m[1, 2] = 5 + m[2, 0] = 6 + m[2, 1] = 7 + m[2, 2] = 8 m end def create_rectangular_matrix(stype) #:nodoc: - m = NMatrix.new([5,6], 0, dtype: :int32, stype: stype, default: 0) - - m[0,0] = 1 - m[0,1] = 2 - m[0,2] = 3 - m[0,3] = 4 - m[0,4] = 5 - m[0,5] = 0 - - m[1,0] = 6 - m[1,1] = 7 - m[1,2] = 8 - m[1,3] = 9 - m[1,4] = 0 - m[1,5] = 10 - - m[2,0] = 11 - m[2,1] = 12 - m[2,2] = 13 - m[2,3] = 0 - m[2,4] = 14 - m[2,5] = 15 + m = NMatrix.new([5, 6], 0, dtype: :int32, stype: stype, default: 0) + + m[0, 0] = 1 + m[0, 1] = 2 + m[0, 2] = 3 + m[0, 3] = 4 + m[0, 4] = 5 + m[0, 5] = 0 + + m[1, 0] = 6 + m[1, 1] = 7 + m[1, 2] = 8 + m[1, 3] = 9 + m[1, 4] = 0 + m[1, 5] = 10 + + m[2, 0] = 11 + m[2, 1] = 12 + m[2, 2] = 13 + m[2, 3] = 0 + m[2, 4] = 14 + m[2, 5] = 15 # skip row 3 -- all 0 - m[3,0] = m[3,1] = m[3,2] = m[3,3] = m[3,4] = m[3,5] = 0 + m[3, 0] = m[3, 1] = m[3, 2] = m[3, 3] = m[3, 4] = m[3, 5] = 0 - m[4,0] = 16 - m[4,1] = 0 - m[4,2] = 17 - m[4,3] = 18 - m[4,4] = 19 - m[4,5] = 20 + m[4, 0] = 16 + m[4, 1] = 0 + m[4, 2] = 17 + m[4, 3] = 18 + m[4, 4] = 19 + m[4, 5] = 20 m end @@ -148,8 +148,8 @@ def nm_eql(n, m) #:nodoc: else # NMatrix n.shape[0].times do |i| n.shape[1].times do |j| - if n[i,j] != m[i,j] - puts "n[#{i},#{j}] != m[#{i},#{j}] (#{n[i,j]} != #{m[i,j]})" + if n[i, j] != m[i, j] + puts "n[#{i},#{j}] != m[#{i},#{j}] (#{n[i, j]} != #{m[i, j]})" return false end end @@ -159,14 +159,13 @@ def nm_eql(n, m) #:nodoc: end def integer_dtype? dtype - [:byte,:int8,:int16,:int32,:int64].include?(dtype) + [:byte, :int8, :int16, :int32, :int64].include?(dtype) end # If a focus: true option is supplied to any test, running `rake spec focus=true` # will run only the focused tests and nothing else. if ENV["focus"] == "true" RSpec.configure do |c| - c.filter_run :focus => true + c.filter_run focus: true end end - diff --git a/spec/stat_spec.rb b/spec/stat_spec.rb index 72b5c53a..5fb6f919 100644 --- a/spec/stat_spec.rb +++ b/spec/stat_spec.rb @@ -25,28 +25,28 @@ # Tests for statistical functions in NMatrix. # -require 'spec_helper' -require 'pry' +require "spec_helper" +require "pry" describe "Statistical functions" do context "mapping and reduction related functions" do [:dense, :yale, :list].each do |stype| context "on #{stype} matrices" do - let(:nm_1d) { NMatrix.new([5], [5.0,0.0,1.0,2.0,3.0], stype: stype) unless stype == :yale } - let(:nm_2d) { NMatrix.new([2,2], [0.0, 1.0, 2.0, 3.0], stype: stype) } + let(:nm_1d) { NMatrix.new([5], [5.0, 0.0, 1.0, 2.0, 3.0], stype: stype) unless stype == :yale } + let(:nm_2d) { NMatrix.new([2, 2], [0.0, 1.0, 2.0, 3.0], stype: stype) } it "behaves like Enumerable#reduce with no argument to reduce" do expect(nm_1d.reduce_along_dim(0) { |acc, el| acc + el }.to_f).to eq 11 unless stype == :yale - expect(nm_2d.reduce_along_dim(1) { |acc, el| acc + el }).to eq NMatrix.new([2,1], [1.0, 5.0], stype: stype) + expect(nm_2d.reduce_along_dim(1) { |acc, el| acc + el }).to eq NMatrix.new([2, 1], [1.0, 5.0], stype: stype) end it "should calculate the mean along the specified dimension" do pending("not yet implemented for NMatrix-JRuby") if jruby? - unless stype == :yale then + unless stype == :yale puts nm_1d.mean expect(nm_1d.mean).to eq NMatrix.new([1], [2.2], stype: stype, dtype: :float64) end - expect(nm_2d.mean).to eq NMatrix[[1.0,2.0], stype: stype] + expect(nm_2d.mean).to eq NMatrix[[1.0, 2.0], stype: stype] expect(nm_2d.mean(1)).to eq NMatrix[[0.5], [2.5], stype: stype] end @@ -87,8 +87,8 @@ end it "should convert to float if it contains only a single element" do - expect(NMatrix[4.0, stype: stype].to_f).to eq 4.0 unless stype == :yale - expect(NMatrix[[[[4.0]]], stype: stype].to_f).to eq 4.0 unless stype == :yale + expect(NMatrix[4.0, stype: stype].to_f).to eq 4.0 unless stype == :yale + expect(NMatrix[[[[4.0]]], stype: stype].to_f).to eq 4.0 unless stype == :yale expect(NMatrix[[4.0], stype: stype].to_f).to eq 4.0 end @@ -98,13 +98,13 @@ end it "should map a block to all elements" do - expect(nm_1d.map { |e| e ** 2 }).to eq NMatrix[25.0,0.0,1.0,4.0,9.0, stype: stype] unless stype == :yale - expect(nm_2d.map { |e| e ** 2 }).to eq NMatrix[[0.0,1.0],[4.0,9.0], stype: stype] + expect(nm_1d.map { |e| e**2 }).to eq NMatrix[25.0, 0.0, 1.0, 4.0, 9.0, stype: stype] unless stype == :yale + expect(nm_2d.map { |e| e**2 }).to eq NMatrix[[0.0, 1.0], [4.0, 9.0], stype: stype] end it "should map! a block to all elements in place" do - fct = Proc.new { |e| e ** 2 } - unless stype == :yale then + fct = proc { |e| e**2 } + unless stype == :yale expected1 = nm_1d.map(&fct) nm_1d.map!(&fct) expect(nm_1d).to eq expected1 @@ -135,36 +135,36 @@ it "should iterate correctly for reduce without a block" do pending("not yet implemented for NMatrix-JRuby") if jruby? - unless stype == :yale then + unless stype == :yale en = nm_1d.reduce_along_dim(0, 1.0) - expect(en.each { |a, e| a+e }.to_f).to eq 12 + expect(en.each { |a, e| a + e }.to_f).to eq 12 end en = nm_2d.reduce_along_dim(1, 1.0) - expect(en.each { |a, e| a+e }).to eq NMatrix[[2.0],[6.0], stype: stype] + expect(en.each { |a, e| a + e }).to eq NMatrix[[2.0], [6.0], stype: stype] end it "should iterate correctly for each_along_dim without a block" do - unless stype == :yale then + unless stype == :yale res = NMatrix.zeros_like(nm_1d[0...1]) en = nm_1d.each_along_dim(0) en.each { |e| res += e } expect(res.to_f).to eq 11 end - res = NMatrix.zeros_like (nm_2d[0...2, 0]) + res = NMatrix.zeros_like nm_2d[0...2, 0] en = nm_2d.each_along_dim(1) en.each { |e| res += e } expect(res).to eq NMatrix[[1.0], [5.0], stype: stype] end it "should yield matrices of matching dtype for each_along_dim" do - m = NMatrix.new([2,3], [1,2,3,3,4,5], dtype: :complex128, stype: stype) + m = NMatrix.new([2, 3], [1, 2, 3, 3, 4, 5], dtype: :complex128, stype: stype) m.each_along_dim(1) do |sub_m| expect(sub_m.dtype).to eq :complex128 end end it "should reduce to a matrix of matching dtype for reduce_along_dim" do - m = NMatrix.new([2,3], [1,2,3,3,4,5], dtype: :complex128, stype: stype) + m = NMatrix.new([2, 3], [1, 2, 3, 3, 4, 5], dtype: :complex128, stype: stype) m.reduce_along_dim(1) do |acc, sub_m| expect(sub_m.dtype).to eq :complex128 acc @@ -178,13 +178,13 @@ it "should allow overriding the dtype for reduce_along_dim" do pending("not yet implemented for NMatrix-JRuby") if jruby? - m = NMatrix[[1,2,3], [3,4,5], dtype: :complex128] + m = NMatrix[[1, 2, 3], [3, 4, 5], dtype: :complex128] m.reduce_along_dim(1, 0.0, :float64) do |acc, sub_m| expect(acc.dtype).to eq :float64 acc end - m = NMatrix[[1,2,3], [3,4,5], dtype: :complex128, stype: stype] + m = NMatrix[[1, 2, 3], [3, 4, 5], dtype: :complex128, stype: stype] m.reduce_along_dim(1, nil, :float64) do |acc, sub_m| expect(acc.dtype).to eq :float64 acc @@ -193,19 +193,19 @@ it "should convert integer dtypes to float when calculating mean" do pending("not yet implemented for NMatrix-JRuby") if jruby? - m = NMatrix[[1,2,3], [3,4,5], dtype: :int32, stype: stype] + m = NMatrix[[1, 2, 3], [3, 4, 5], dtype: :int32, stype: stype] expect(m.mean(0).dtype).to eq :float64 end it "should convert integer dtypes to float when calculating variance" do pending("not yet implemented for NMatrix-JRuby") if jruby? - m = NMatrix[[1,2,3], [3,4,5], dtype: :int32, stype: stype] + m = NMatrix[[1, 2, 3], [3, 4, 5], dtype: :int32, stype: stype] expect(m.variance(0).dtype).to eq :float64 end it "should convert integer dtypes to float when calculating standard deviation" do pending("not yet implemented for NMatrix-JRuby") if jruby? - m = NMatrix[[1,2,3], [3,4,5], dtype: :int32, stype: stype] + m = NMatrix[[1, 2, 3], [3, 4, 5], dtype: :int32, stype: stype] expect(m.std(0).dtype).to eq :float64 end end