mruby_tools 0.0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9aa01e1c7834a6b9ba351aa1e70df7399628dc8c
4
+ data.tar.gz: 42b72b7ca714f805e00a0f73b12439d1611dbd65
5
+ SHA512:
6
+ metadata.gz: 5aae2588bb3b849cba817a377f2995c55d7e0e8b27f770b9f5c991093f6c9f3032a7d2e9e64810bee44ffb8b616b2e6a1f55694297af1b8ca20bc22c1c4b5cde
7
+ data.tar.gz: 2e225121b919de40e9fbd803fbf0c3aa2cf5ebb7b0433c1bfa30e58e52cce864361f4248ef00b90892669a239d5908c0cab64b1cbf3ea72f1ee868f63dd34a40
@@ -0,0 +1 @@
1
+ # MRuby Tools
@@ -0,0 +1,55 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new :test do |t|
4
+ t.pattern = "test/*.rb"
5
+ t.warning = true
6
+ end
7
+
8
+
9
+ #
10
+ # METRICS
11
+ #
12
+
13
+ begin
14
+ require 'flog_task'
15
+ FlogTask.new do |t|
16
+ t.dirs = ['lib']
17
+ t.verbose = true
18
+ end
19
+ rescue LoadError
20
+ warn 'flog_task unavailable'
21
+ end
22
+
23
+ begin
24
+ require 'flay_task'
25
+ FlayTask.new do |t|
26
+ t.dirs = ['lib']
27
+ t.verbose = true
28
+ end
29
+ rescue LoadError
30
+ warn 'flay_task unavailable'
31
+ end
32
+
33
+ begin
34
+ require 'roodi_task'
35
+ # RoodiTask.new config: '.roodi.yml', patterns: ['lib/**/*.rb']
36
+ RoodiTask.new patterns: ['lib/**/*.rb']
37
+ rescue LoadError
38
+ warn "roodi_task unavailable"
39
+ end
40
+
41
+ #
42
+ # GEM BUILD / PUBLISH
43
+ #
44
+
45
+ begin
46
+ require 'buildar'
47
+
48
+ Buildar.new do |b|
49
+ b.gemspec_file = 'mruby_tools.gemspec'
50
+ b.version_file = 'VERSION'
51
+ b.use_git = true
52
+ end
53
+ rescue LoadError
54
+ warn "buildar tasks unavailable"
55
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1.1
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'tempfile'
4
+ require 'mruby_tools'
5
+
6
+ # args like: file1.rb file2.rb -o outfile
7
+ # possibly: file1.rb -o outfile file2.rb -c generated.c
8
+
9
+ opts = MRubyTools.args(ARGV)
10
+ outfile = opts.fetch(:outfile)
11
+
12
+ c_code = <<'EOF'
13
+ #include <stdlib.h>
14
+ #include <mruby.h>
15
+ #include <mruby/compile.h>
16
+ #include <mruby/string.h>
17
+
18
+ void check_exc(mrb_state *mrb, char *filename) {
19
+ if (mrb->exc) {
20
+ mrb_value exc = mrb_obj_value(mrb->exc);
21
+ mrb_value exc_msg = mrb_funcall(mrb, exc, "to_s", 0);
22
+ fprintf(stderr, "ERROR in %s - %s: %s\n",
23
+ filename,
24
+ mrb_obj_classname(mrb, exc),
25
+ mrb_str_to_cstr(mrb, exc_msg));
26
+ /* mrb_print_backtrace(mrb); # empty */
27
+ exit(1);
28
+ }
29
+ }
30
+
31
+ int
32
+ main(void)
33
+ {
34
+ mrb_state *mrb = mrb_open();
35
+ if (!mrb) {
36
+ printf("mrb problem");
37
+ exit(1);
38
+ }
39
+ EOF
40
+
41
+ c_code += opts.fetch(:rb_files).map { |rbf|
42
+ "\n" + MRubyTools.rb2c(rbf) + "\n\n"
43
+ }.join
44
+
45
+ c_code += <<EOF
46
+ mrb_close(mrb);
47
+ return 0;
48
+ }
49
+ EOF
50
+
51
+ puts c_code + "\n" if opts[:verbose]
52
+
53
+ file = opts[:cfile] || Tempfile.new(['generated', '.c'])
54
+ file.write(c_code)
55
+ file.close
56
+
57
+ msd = MRubyTools.mruby_src_dir
58
+
59
+ gcc_args = [
60
+ '-std=c99', "-I", File.join(msd, 'include'), file.path, "-o", outfile,
61
+ File.join(msd, 'build', 'host', 'lib', 'libmruby.a'), '-lm',
62
+ ]
63
+
64
+ puts "compiling..."
65
+ puts "created binary executable: #{outfile}" if system('gcc', *gcc_args)
@@ -0,0 +1,98 @@
1
+ SIMPLEX_PARAMS = [
2
+ # 1 (index 0)
3
+ [[1, 1],
4
+ [[2, 1],
5
+ [1, 2]],
6
+ [4, 3]],
7
+
8
+ [[3, 4],
9
+ [[1, 1],
10
+ [2, 1]],
11
+ [4, 5]],
12
+
13
+ [[2, -1],
14
+ [[1, 2],
15
+ [3, 2],],
16
+ [6, 12]],
17
+
18
+ [[60, 90, 300],
19
+ [[1, 1, 1],
20
+ [1, 3, 0],
21
+ [2, 0, 1]],
22
+ [600, 600, 900]],
23
+
24
+ # 5
25
+ [[70, 210, 140],
26
+ [[1, 1, 1],
27
+ [5, 4, 4],
28
+ [40, 20, 30]],
29
+ [100, 480, 3200]],
30
+
31
+ [[2, -1, 2],
32
+ [[2, 1, 0],
33
+ [1, 2, -2],
34
+ [0, 1, 2]],
35
+ [10, 20, 5]],
36
+
37
+ [[11, 16, 15],
38
+ [[1, 2, 3.to_f / 2],
39
+ [2.to_f / 3, 2.to_f / 3, 1],
40
+ [0.5, 1.to_f / 3, 0.5]],
41
+ [12_000, 4_600, 2_400]],
42
+
43
+ [[5, 4, 3],
44
+ [[2, 3, 1],
45
+ [4, 1, 2],
46
+ [3, 4, 2]],
47
+ [5, 11, 8]],
48
+
49
+ [[3, 2, -4],
50
+ [[1, 4, 0],
51
+ [2, 4,-2],
52
+ [1, 1,-2]],
53
+ [5, 6, 2]],
54
+
55
+ # 10
56
+ [[2, -1, 8],
57
+ [[2, -4, 6],
58
+ [-1, 3, 4],
59
+ [0, 0, 2]],
60
+ [3, 2, 1]],
61
+
62
+ [[100_000, 40_000, 18_000],
63
+ [[20, 6, 3],
64
+ [0, 1, 0],
65
+ [-1,-1, 1],
66
+ [-9, 1, 1]],
67
+ [182, 10, 0, 0]],
68
+
69
+ [[1, 2, 1, 2],
70
+ [[1, 0, 1, 0],
71
+ [0, 1, 0, 1],
72
+ [1, 1, 0, 0],
73
+ [0, 0, 1, 1]],
74
+ [1, 4, 2, 2]],
75
+
76
+ [[10, -57, -9, -24],
77
+ [[0.5, -5.5, -2.5, 9],
78
+ [0.5, -1.5, -0.5, 1],
79
+ [ 1, 0, 0, 0]],
80
+ [0, 0, 1]],
81
+
82
+ # 14 (index 13)
83
+ [[25, 20],
84
+ [[20, 12],
85
+ [1, 1]],
86
+ [1800, 8*15]],
87
+ ]
88
+
89
+ def simplices
90
+ SIMPLEX_PARAMS.map { |c, a, b| Simplex.new(c, a, b) }
91
+ end
92
+
93
+ puts "calculating #{SIMPLEX_PARAMS.size} simplex solutions, repeatedly..."
94
+ val, elapsed = Timer.loop_avg {
95
+ simplices.map { |s| s.solution }.join("\n")
96
+ }
97
+
98
+ puts "%0.8f s (avg) per solution" % (elapsed / SIMPLEX_PARAMS.size)
@@ -0,0 +1 @@
1
+ puts :goodbye_world
@@ -0,0 +1 @@
1
+ puts :hello_world
@@ -0,0 +1,2 @@
1
+ raise "stuff"
2
+ #raise StandardError, "things"
@@ -0,0 +1,164 @@
1
+ class Simplex
2
+ DEFAULT_MAX_PIVOTS = 10_000
3
+
4
+ class Error < RuntimeError; end
5
+ class UnboundedProblem < Error; end
6
+ class SanityCheck < Error; end
7
+ class TooManyPivots < Error; end
8
+
9
+ attr_accessor :max_pivots
10
+
11
+ # c - coefficients of objective function; size: num_vars
12
+ # a - inequality lhs coefficients; 2dim size: num_inequalities, num_vars
13
+ # b - inequality rhs constants size: num_inequalities
14
+ def initialize(c, a, b)
15
+ num_vars = c.size
16
+ num_inequalities = b.size
17
+ raise(ArgumentError, "a doesn't match b") unless a.size == num_inequalities
18
+ raise(ArgumentError, "a doesn't match c") unless a.first.size == num_vars
19
+
20
+ @max_pivots = DEFAULT_MAX_PIVOTS
21
+
22
+ # Problem dimensions; these never change
23
+ @num_non_slack_vars = num_vars
24
+ @num_constraints = num_inequalities
25
+ @num_vars = @num_non_slack_vars + @num_constraints
26
+
27
+ # Set up initial matrix A and vectors b, c
28
+ @c = c.map { |flt| -1 * flt } + Array.new(@num_constraints, 0)
29
+ @a = a.map.with_index { |ary, i|
30
+ if ary.size != @num_non_slack_vars
31
+ raise ArgumentError, "a is inconsistent"
32
+ end
33
+ ary + Array.new(@num_constraints) { |ci| ci == i ? 1 : 0 }
34
+ }
35
+ @b = b
36
+
37
+ # set initial solution: all non-slack variables = 0
38
+ @basic_vars = (@num_non_slack_vars...@num_vars).to_a
39
+ self.update_solution
40
+ end
41
+
42
+ # does not modify vector / matrix
43
+ def update_solution
44
+ @x = Array.new(@num_vars, 0)
45
+
46
+ @basic_vars.each { |basic_var|
47
+ idx = nil
48
+ @num_constraints.times { |i|
49
+ if @a[i][basic_var] == 1
50
+ idx =i
51
+ break
52
+ end
53
+ }
54
+ raise(SanityCheck, "no idx for basic_var #{basic_var} in a") unless idx
55
+ @x[basic_var] = @b[idx]
56
+ }
57
+ end
58
+
59
+ def solution
60
+ self.solve
61
+ self.current_solution
62
+ end
63
+
64
+ def solve
65
+ count = 0
66
+ while self.can_improve?
67
+ count += 1
68
+ raise(TooManyPivots, count.to_s) unless count < @max_pivots
69
+ self.pivot
70
+ end
71
+ end
72
+
73
+ def current_solution
74
+ @x[0...@num_non_slack_vars]
75
+ end
76
+
77
+ def can_improve?
78
+ !self.entering_variable.nil?
79
+ end
80
+
81
+ # idx of @c's minimum negative value
82
+ # nil when no improvement is possible
83
+ #
84
+ def entering_variable
85
+ (0...@c.size).select { |i| @c[i] < 0 }.min_by { |i| @c[i] }
86
+ end
87
+
88
+ def pivot
89
+ pivot_column = self.entering_variable or return nil
90
+ pivot_row = self.pivot_row(pivot_column) or raise UnboundedProblem
91
+ leaving_var = nil
92
+ @a[pivot_row].each_with_index { |a, i|
93
+ if a == 1 and @basic_vars.include?(i)
94
+ leaving_var = i
95
+ break
96
+ end
97
+ }
98
+ raise(SanityCheck, "no leaving_var") if leaving_var.nil?
99
+
100
+ @basic_vars.delete(leaving_var)
101
+ @basic_vars.push(pivot_column)
102
+ @basic_vars.sort!
103
+
104
+ pivot_ratio = 1.to_f / @a[pivot_row][pivot_column]
105
+
106
+ # update pivot row
107
+ @a[pivot_row] = @a[pivot_row].map { |val| val * pivot_ratio }
108
+ @b[pivot_row] = @b[pivot_row] * pivot_ratio
109
+
110
+ # update objective
111
+ # @c -= @c[pivot_column] * @a[pivot_row]
112
+ @c = @c.map.with_index { |val, i|
113
+ val - @c[pivot_column] * @a[pivot_row][i]
114
+ }
115
+
116
+ # update A and B
117
+ @num_constraints.times { |i|
118
+ next if i == pivot_row
119
+ r = @a[i][pivot_column]
120
+ @a[i] = @a[i].map.with_index { |val, j| val - r * @a[pivot_row][j] }
121
+ @b[i] = @b[i] - r * @b[pivot_row]
122
+ }
123
+
124
+ self.update_solution
125
+ end
126
+
127
+ def pivot_row(column_ix)
128
+ min_ratio = nil
129
+ idx = nil
130
+ @num_constraints.times { |i|
131
+ a, b = @a[i][column_ix], @b[i]
132
+ next if a == 0 or (b < 0) ^ (a < 0)
133
+ ratio = b.to_f / a
134
+ idx, min_ratio = i, ratio if min_ratio.nil? or ratio <= min_ratio
135
+ }
136
+ idx
137
+ end
138
+
139
+ def formatted_tableau
140
+ if self.can_improve?
141
+ pivot_column = self.entering_variable
142
+ pivot_row = self.pivot_row(pivot_column)
143
+ else
144
+ pivot_row = nil
145
+ end
146
+ c = @c.to_a.map { |flt| "%2.3f" % flt }
147
+ b = @b.to_a.map { |flt| "%2.3f" % flt }
148
+ a = @a.to_a.map { |vec| vec.to_a.map { |flt| "%2.3f" % flt } }
149
+ if pivot_row
150
+ a[pivot_row][pivot_column] = "*" + a[pivot_row][pivot_column]
151
+ end
152
+ max = (c + b + a + ["1234567"]).flatten.map(&:size).max
153
+ result = []
154
+ result << c.map { |str| str.rjust(max, " ") }
155
+ a.zip(b) do |arow, brow|
156
+ result << (arow + [brow]).map { |val| val.rjust(max, " ") }
157
+ result.last.insert(arow.length, "|")
158
+ end
159
+ lines = result.map { |ary| ary.join(" ") }
160
+ max_line_length = lines.map(&:length).max
161
+ lines.insert(1, "-"*max_line_length)
162
+ lines.join("\n")
163
+ end
164
+ end
@@ -0,0 +1,27 @@
1
+ module Timer
2
+ def self.now
3
+ Time.now
4
+ end
5
+
6
+ def self.since(t)
7
+ self.now - t
8
+ end
9
+
10
+ def self.elapsed(&work)
11
+ t = self.now
12
+ return yield, self.since(t)
13
+ end
14
+
15
+ def self.loop_avg(count = 999, seconds = 1, &work)
16
+ i = 0
17
+ start = self.now
18
+ val = nil
19
+ loop {
20
+ val = yield
21
+ i += 1
22
+ break if i >= count
23
+ break if self.since(start) > seconds
24
+ }
25
+ return val, self.since(start) / i.to_f
26
+ end
27
+ end
@@ -0,0 +1,48 @@
1
+ module MRubyTools
2
+ def self.rb2c(rb_filename, indent: ' ')
3
+ c_str = File.read(rb_filename)
4
+ size = c_str.size
5
+ c_str = c_str.gsub("\n", '\n').gsub('"', '\"')
6
+ c_str = File.read(rb_filename).gsub("\n", '\n').gsub('"', '\"')
7
+ [ "/* #{rb_filename} */",
8
+ 'mrb_load_nstring(mrb, "' + c_str + '", ' + "#{size});",
9
+ "check_exc(mrb, \"#{rb_filename}\");",
10
+ ].map { |s| indent + s }.join("\n")
11
+ end
12
+
13
+ def self.mruby_src_dir(env_var = 'MRUBY_SRC')
14
+ mruby_src_dir = ENV[env_var]
15
+ raise "env: MRUBY_SRC is required" unless mruby_src_dir
16
+ raise "bad MRUBY_SRC #{mruby_src_dir}" unless File.directory? mruby_src_dir
17
+ mruby_inc_dir = File.join(mruby_src_dir, 'include')
18
+ raise "bad MRUBY_SRC #{mruby_inc_dir}" unless File.directory? mruby_inc_dir
19
+ mruby_src_dir
20
+ end
21
+
22
+ def self.args(argv = ARGV)
23
+ rb_files = []
24
+ outfile = nil
25
+ cfile = nil
26
+ verbose = false
27
+
28
+ while !argv.empty?
29
+ arg = argv.shift
30
+ if arg == '-o'
31
+ outfile = argv.shift
32
+ raise "no outfile provided with -o" unless outfile
33
+ raise "#{outfile} is misnamed" if File.extname(outfile) == '.rb'
34
+ elsif arg == '-c'
35
+ cfile = File.open(argv.shift || 'generated.c', "w")
36
+ elsif arg == '-v'
37
+ verbose = true
38
+ else
39
+ rb_files << arg
40
+ end
41
+ end
42
+
43
+ { verbose: verbose,
44
+ cfile: cfile,
45
+ outfile: outfile || 'outfile',
46
+ rb_files: rb_files }
47
+ end
48
+ end
@@ -0,0 +1,28 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'mruby_tools'
3
+ s.summary = "MRI Ruby tools for assisting in MRuby development"
4
+ s.description = "TBD"
5
+ s.authors = ["Rick Hull"]
6
+ s.homepage = "https://github.com/rickhull/mruby-tools"
7
+ s.license = "LGPL-3.0"
8
+
9
+ s.required_ruby_version = "~> 2"
10
+
11
+ s.version = File.read(File.join(__dir__, 'VERSION')).chomp
12
+
13
+ s.files = %w[mruby_tools.gemspec VERSION README.md Rakefile]
14
+ %w[lib bin test examples].each { |dir|
15
+ s.files += Dir[File.join(dir, '**', '*.rb')]
16
+ }
17
+
18
+ s.executables << 'mrbt'
19
+
20
+ s.add_development_dependency "rake", "~> 0"
21
+ s.add_development_dependency "buildar", "~> 3.0"
22
+ # s.add_development_dependency "minitest", "~> 5.0"
23
+ # s.add_development_dependency "flog", "~> 0"
24
+ # s.add_development_dependency "flay", "~> 0"
25
+ # s.add_development_dependency "roodi", "~> 0"
26
+ # s.add_development_dependency "ruby-prof", "~> 0"
27
+ # s.add_development_dependency "benchmark-ips", "~> 2.0"
28
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mruby_tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Rick Hull
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-11-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: buildar
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ description: TBD
42
+ email:
43
+ executables:
44
+ - mrbt
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - README.md
49
+ - Rakefile
50
+ - VERSION
51
+ - bin/mrbt
52
+ - examples/driver.rb
53
+ - examples/goodbye_world.rb
54
+ - examples/hello_world.rb
55
+ - examples/raise.rb
56
+ - examples/simplex.rb
57
+ - examples/timer.rb
58
+ - lib/mruby_tools.rb
59
+ - mruby_tools.gemspec
60
+ homepage: https://github.com/rickhull/mruby-tools
61
+ licenses:
62
+ - LGPL-3.0
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - "~>"
71
+ - !ruby/object:Gem::Version
72
+ version: '2'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 2.6.8
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: MRI Ruby tools for assisting in MRuby development
84
+ test_files: []