rams 0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 67e00b03b834709c1fe99786d347e930d4446738
4
- data.tar.gz: 92e7882abc5840a724ec73a9966180150bedddd4
3
+ metadata.gz: 892ffe4b05f309fee78d179745713f1880362428
4
+ data.tar.gz: a659e1f65de80be3dae780ea30cb3b3ed504e5f9
5
5
  SHA512:
6
- metadata.gz: a8d314f2631447ae0a8d500b5b358f55fe319cb6a60a44c21ac439a032c9a7b0504654ac14bbe1b81bc9c52687ec04e68f8d6b3d617e305f143912d8cff748ad
7
- data.tar.gz: d9944355d64f23fd6c43ddc841e668ae9f6d272eeec906b1df9809a01df987a59514e43600528619eec3a34db7df0dafb0e6f0557542438452b3b2a5b68e3b73
6
+ metadata.gz: dcd53a0bd69bf259195e74ad33162b4176a89d55388ca400516da6b43916d819d2a613ade587906d3b26bf07897b105d20f7098487e839bfbbb0f99dcc1e723b
7
+ data.tar.gz: 45cd3f47128cb9c4ee68ece0e9e309495b0b2049e53522aa3914aa404147164183ce67b0b0e4ceb49dbc4118f31174d192215ee7407f328a403edec651063fc3
data/lib/rams/model.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'tempfile'
2
2
  require_relative 'variable'
3
+ require_relative 'solvers/cbc'
4
+ require_relative 'solvers/clp'
3
5
  require_relative 'solvers/glpk'
4
6
 
5
7
  module RAMS
@@ -28,7 +30,11 @@ module RAMS
28
30
  attr_accessor :objective, :args, :verbose
29
31
  attr_reader :solver, :sense, :variables, :constraints
30
32
 
31
- SOLVERS = { glpk: RAMS::Solvers::GLPK.new }.freeze
33
+ SOLVERS = {
34
+ cbc: RAMS::Solvers::CBC.new,
35
+ clp: RAMS::Solvers::CLP.new,
36
+ glpk: RAMS::Solvers::GLPK.new
37
+ }.freeze
32
38
 
33
39
  def initialize
34
40
  @solver = :glpk
@@ -0,0 +1,45 @@
1
+ require_relative 'solver'
2
+
3
+ module RAMS
4
+ module Solvers
5
+ # Interface to COIN-OR Branch-and-Cut
6
+ class CBC < Solver
7
+ def solver_command(model_file, solution_file, args)
8
+ ['cbc', model_file.path] + args + ['printingOptions', 'all', 'solve', 'solution', solution_file.path]
9
+ end
10
+
11
+ private
12
+
13
+ def parse_status(model, lines)
14
+ return :undefined if lines.count < 1
15
+ status = lines.first
16
+ return :optimal if status =~ /Optimal/
17
+ return :feasible if status =~ /Stopped/
18
+ return :infeasible if status =~ /Infeasible/
19
+ return :unbounded if status =~ /Unbounded/
20
+ :undefined
21
+ end
22
+
23
+ def parse_objective(model, lines)
24
+ return nil if lines.count < 1
25
+ objective = lines.first.split[-1].to_f
26
+ model.sense == :max ? -objective : objective
27
+ end
28
+
29
+ def parse_primal(model, lines)
30
+ lines[model.constraints.count + 1, model.variables.count].map do |l|
31
+ comps = l.split
32
+ [model.variables[comps[1]], comps[2].to_f]
33
+ end.to_h
34
+ end
35
+
36
+ def parse_dual(model, lines)
37
+ lines[1, model.constraints.count].map do |l|
38
+ comps = l.split
39
+ dual = model.sense == :max ? -comps[3].to_f : comps[3].to_f
40
+ [model.constraints[comps[1]], dual]
41
+ end.to_h
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,45 @@
1
+ require_relative 'solver'
2
+
3
+ module RAMS
4
+ module Solvers
5
+ # Interface to COIN-OR Linear Programming
6
+ class CLP < Solver
7
+ def solver_command(model_file, solution_file, args)
8
+ ['clp', model_file.path] + args + ['printingOptions', 'all', 'solve', 'solution', solution_file.path]
9
+ end
10
+
11
+ private
12
+
13
+ def parse_status(model, lines)
14
+ return :undefined if lines.count < 1
15
+ status = lines.first
16
+ return :optimal if status =~ /optimal/
17
+ return :feasible if status =~ /stopped/
18
+ return :infeasible if status =~ /infeasible/
19
+ return :unbounded if status =~ /unbounded/
20
+ :undefined
21
+ end
22
+
23
+ def parse_objective(model, lines)
24
+ return nil if lines.count < 2
25
+ objective = lines[1].split[-1].to_f
26
+ model.sense == :max ? -objective : objective
27
+ end
28
+
29
+ def parse_primal(model, lines)
30
+ lines[model.constraints.count + 2, model.variables.count].map do |l|
31
+ comps = l.split
32
+ [model.variables[comps[1]], comps[2].to_f]
33
+ end.to_h
34
+ end
35
+
36
+ def parse_dual(model, lines)
37
+ lines[2, model.constraints.count].map do |l|
38
+ comps = l.split
39
+ dual = model.sense == :max ? -comps[3].to_f : comps[3].to_f
40
+ [model.constraints[comps[1]], dual]
41
+ end.to_h
42
+ end
43
+ end
44
+ end
45
+ end
@@ -4,36 +4,35 @@ module RAMS
4
4
  module Solvers
5
5
  # Interface to the GNU Linear Programming Kit
6
6
  class GLPK < Solver
7
- def solver_command(model_file, solution_file)
8
- ['glpsol', '--lp', model_file.path, '--output', solution_file.path]
7
+ def solver_command(model_file, solution_file, args)
8
+ ['glpsol', '--lp', model_file.path, '--output', solution_file.path] + args
9
9
  end
10
10
 
11
11
  private
12
12
 
13
- def parse_status(lines)
13
+ def parse_status(_model, lines)
14
14
  status = lines.select { |l| l =~ /^Status/ }.first
15
15
  return :optimal if status =~ /OPTIMAL/
16
16
  return :feasible if status =~ /FEASIBLE/
17
17
  return :infeasible if status =~ /EMPTY/
18
+ return :unbounded if status =~ /UNBOUNDED/
18
19
  :undefined
19
20
  end
20
21
 
21
- def parse_objective(lines)
22
+ def parse_objective(_model, lines)
22
23
  lines.select { |l| l =~ /^Objective/ }.first.split[3].to_f
23
24
  end
24
25
 
25
26
  def parse_primal(model, lines)
26
- primal = model.variables.values.map { |v| [v, 0.0] }.to_h
27
27
  start_idx = lines.index { |l| l =~ /Column name/ } + 2
28
28
  length = lines[start_idx, lines.length].index { |l| l == '' }
29
- primal.update(lines[start_idx, length].map { |l| [model.variables[l[7, 12].strip], l[23, 13].to_f] }.to_h)
29
+ lines[start_idx, length].map { |l| [model.variables[l[7, 12].strip], l[23, 13].to_f] }.to_h
30
30
  end
31
31
 
32
32
  def parse_dual(model, lines)
33
- duals = model.constraints.values.map { |c| [c, 0.0] }.to_h
34
33
  start_idx = lines.index { |l| l =~ /Row name/ } + 2
35
34
  length = lines[start_idx, lines.length].index { |l| l == '' }
36
- duals.update(lines[start_idx, length].map { |l| [model.constraints[l[7, 12].strip], l[-13, 13].to_f] }.to_h)
35
+ lines[start_idx, length].map { |l| [model.constraints[l[7, 12].strip], l[-13, 13].to_f] }.to_h
37
36
  end
38
37
  end
39
38
  end
@@ -39,7 +39,7 @@ module RAMS
39
39
 
40
40
  # rubocop:disable MethodLength
41
41
  def call_solver(model, model_file, solution_file)
42
- command = solver_command(model_file, solution_file) + model.args
42
+ command = solver_command(model_file, solution_file, model.args)
43
43
  _, stdout, stderr, exit_code = Open3.popen3(*command)
44
44
 
45
45
  begin
@@ -54,25 +54,25 @@ module RAMS
54
54
  end
55
55
  # rubocop:enable MethodLength
56
56
 
57
- def solver_command(_model_file, _solution_file)
57
+ def solver_command(_model_file, _solution_file, _args)
58
58
  raise NotImplementedError
59
59
  end
60
60
 
61
61
  def parse_solution(model, solution_text)
62
62
  lines = solution_text.split "\n"
63
63
  RAMS::Solution.new(
64
- parse_status(lines),
65
- parse_objective(lines),
64
+ parse_status(model, lines),
65
+ parse_objective(model, lines),
66
66
  parse_primal(model, lines),
67
67
  parse_dual(model, lines)
68
68
  )
69
69
  end
70
70
 
71
- def parse_status(_lines)
71
+ def parse_status(_model, _lines)
72
72
  raise NotImplementedError
73
73
  end
74
74
 
75
- def parse_objective(_lines)
75
+ def parse_objective(_model, _lines)
76
76
  raise NotImplementedError
77
77
  end
78
78
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rams
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan J. O'Neil
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-07 00:00:00.000000000 Z
11
+ date: 2017-01-08 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A library for solving MILPs in Ruby.
14
14
  email:
@@ -23,6 +23,8 @@ files:
23
23
  - lib/rams/model.rb
24
24
  - lib/rams/numeric.rb
25
25
  - lib/rams/solution.rb
26
+ - lib/rams/solvers/cbc.rb
27
+ - lib/rams/solvers/clp.rb
26
28
  - lib/rams/solvers/glpk.rb
27
29
  - lib/rams/solvers/solver.rb
28
30
  - lib/rams/variable.rb