#!/usr/bin/ruby #-*- encoding: sjis -*- class MatlabRuby def initialize begin require 'matlab' @engine = Matlab::Engine::new rescue LoadError, RuntimeError require 'win32ole' @matlab = WIN32OLE::new('matlab.application') @matlab.MinimizeCommandWindow def @matlab.eval(str) self.Execute(str) end end end def self.cleanup if @matlab then @matlab.Quit else @engine.close end end def exec(str) return @matlab.Execute(str) rescue @engine.eval(str) end def size_ole(mat_name) @matlab.Execute("size(#{mat_name})") =~ /=\s+(\d+)\s+(\d+)/ return [$1.to_i, $2.to_i] end def size(mat_name) if @matlab then return size_ole(mat_name) end return [@engine.eval("size(#{mat_name}, 1)").to_i, @engine.eval("size(#{mat_name}, 2)").to_i] end def load_mat_ole(file) load_str = "load #{`cygpath -awl "#{file}"`.chomp};" #$stderr.puts load_str @matlab.Execute(load_str) end def get_mat_ole(mat_name, options = {}, &block) if block then block.call(@matlab) end column_selector = ':' if options[:use] then column_selector = "[#{options[:use].collect{|index| index + 1}.join(' ')}]" end row_selector = ':' if options[:denom] then size_str = @matlab.Execute("size(#{mat_name})") #$stderr.puts size_str size_str =~ /=\s+(\d+)\s+(\d+)/ rows = [] (1..($1.to_i)).step(options[:denom]){|v| rows << v} row_selector = "[#{rows.join(' ')}]" elsif options[:rows] then if options[:rows].kind_of?(Range) then row_selector = "#{options[:rows].first.to_i + 1}:#{options[:rows].end.to_i + 1}" end end limit_arg = "#{mat_name}(#{row_selector},#{column_selector})" $stderr.puts limit_arg @matlab.Execute("ans = #{limit_arg};") if options[:scale] then scale_arg = [] i = 0 while i < options[:scale].size if options[:scale][i] == 1 then i2 = i + 1 break_loop = false while true if i2 >= options[:scale].size then break_loop = true break elsif options[:scale][i2] != 1 then break end i2 += 1 end if (i2 - i) > 1 then scale_arg << "ans(:,#{i + 1}:#{i2})" else scale_arg << "ans(:,#{i + 1})" end break if break_loop i = i2 end scale_arg << "ans(:,#{i + 1}).*#{options[:scale][i]}" i += 1 end =begin # 旧バージョン、効率悪い options[:scale].each_with_index{|sf, i| if sf != 1 then scale_arg << "ans(:,#{i + 1}) .* #{sf}" else scale_arg << "ans(:,#{i + 1})" end } =end scale_arg = scale_arg.join(' ') $stderr.puts scale_arg @matlab.Execute("ans = [#{scale_arg}];") end res = @matlab.GetVariable('ans', 'base') res = res.split(/\n/) if res.kind_of?(String) && (RUBY_VERSION >= '1.9.0') return res end def load_mat(file) if @matlab then return load_mat_ole(file) end @engine.load(`cygpath -awl "#{file}"`.chomp, "-mat") end def get_mat(mat_name, options = {}, &block) if @matlab then return get_mat_ole(mat_name, options, &block) end if block then block.call(@engine) end mat_m = @engine.eval("size(#{mat_name}, 1)") return nil unless mat_m res = [] $stderr.puts mat_m.to_i denom = options[:denom] || 1 step_size = 2500 step_size -= (step_size % denom) #mat_m = 10000 blocks = (mat_m.to_i + (step_size - 1)) / step_size front = 1 last = step_size use_indexes = nil if options[:use] then use_indexes = options[:use].collect{|index| index + 1} end blocks.times{|block_index| block_mat = nil if use_indexes eval_str = '[' \ + use_indexes.collect{|index| "#{mat_name}(#{front}:#{last},#{index})" }.join(' ') \ + ']' #$stderr.puts eval_str block_mat = @engine.eval(eval_str) else block_mat = @engine.eval("#{mat_name}(#{front}:#{last},:)") end #$stderr.puts block_mat.inspect block = [] block_mat.m.times{|i| next unless i % denom == 0 row = [] block_mat.n.times{|j| row << block_mat[i, j] } block << row } if options[:scale] then block_new_t = [] block_t = block.transpose options[:scale].each_with_index{|sf, i| block_new_t << block_t[i].collect{|v| v * sf} } block = block_new_t.transpose end res += block front += step_size last += step_size if last > mat_m.to_i then last = mat_m.to_i end $stderr.print '.' } $stderr.puts return res end end if $0 == __FILE__ then matlab = MatlabRuby::new opt = {} ARGV.reject!{|arg| if arg =~ /^--([^=]+)=?/ then opt[$1.to_sym] = $' true else false end } opt[:denom] = opt[:denom].to_i if opt.include?(:denom) if ARGV.empty? then target = File::join(File::dirname(__FILE__), 'CVS_IGNORE', 'a.mat') matlab.load_mat(target) p matlab.get_mat('a', opt){|engine| } elsif ARGV.size >= 2 then matlab.load_mat(ARGV[0]) p matlab.get_mat(ARGV[1], opt){|engine| } else matlab.load_mat(ARGV[0]) p matlab.get_mat(File::basename(ARGV[0], '.*'), opt){|engine| } end end