rulp 0.0.24 → 0.0.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rulp/rulp.rb +12 -1
- data/lib/solvers/cbc.rb +3 -2
- data/lib/solvers/glpk.rb +11 -5
- data/lib/solvers/gurobi.rb +3 -2
- data/lib/solvers/scip.rb +3 -3
- data/lib/solvers/solver.rb +1 -0
- data/test/test_basic_suite.rb +2 -2
- data/test/test_infeasible.rb +28 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 29755e45e91f606add5cc434cc9dd4a1cb6fd57a
|
4
|
+
data.tar.gz: e2b000cfe7ffec6160fcdb445eb5a79040bfdbb9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5be883579ca22e2b86d5106204b4cc2213205bf7b0a49147f956522ebd550fa8670e5fa0671bf3ffe1982edaf5eb6a1f690155d21b2e2c5b1427260f508db93b
|
7
|
+
data.tar.gz: 31011b0958fe5c4a3b9109db4463099472b905e468afe00d5355c9666b71e4e06ee69091d46858aa46b99227704c572f4b178624cf684d96be96bdb02f785bc1
|
data/lib/rulp/rulp.rb
CHANGED
@@ -21,7 +21,7 @@ module Rulp
|
|
21
21
|
attr_accessor :expressions
|
22
22
|
extend Rulp::Log
|
23
23
|
self.print_solver_outputs = true
|
24
|
-
|
24
|
+
self.log_level = Logger::DEBUG
|
25
25
|
MIN = "Minimize"
|
26
26
|
MAX = "Maximize"
|
27
27
|
|
@@ -174,8 +174,19 @@ module Rulp
|
|
174
174
|
Rulp.log(Logger::DEBUG, "Solver took #{time}")
|
175
175
|
|
176
176
|
Rulp.log(Logger::INFO, "Parsing result")
|
177
|
+
|
178
|
+
unless solver.outfile
|
179
|
+
raise "No output file detected. Solver failed"
|
180
|
+
return
|
181
|
+
end
|
182
|
+
|
177
183
|
solver.store_results(@variables)
|
178
184
|
|
185
|
+
if solver.unsuccessful
|
186
|
+
raise "Solve failed: solution infeasible" if IO.read(solver.outfile).downcase.include?("infeasible")
|
187
|
+
raise "Solve failed: all units undefined"
|
188
|
+
end
|
189
|
+
|
179
190
|
solver.remove_lp_file if options[:remove_lp_file]
|
180
191
|
solver.remove_sol_file if options[:remove_sol_file]
|
181
192
|
|
data/lib/solvers/cbc.rb
CHANGED
@@ -19,7 +19,7 @@ class Cbc < Solver
|
|
19
19
|
|
20
20
|
def store_results(variables)
|
21
21
|
rows = IO.read(@outfile).split("\n")
|
22
|
-
|
22
|
+
objective_str = rows[0].split(/\s+/)[-1]
|
23
23
|
vars_by_name = {}
|
24
24
|
rows[1..-1].each do |row|
|
25
25
|
cols = row.strip.split(/\s+/)
|
@@ -28,6 +28,7 @@ class Cbc < Solver
|
|
28
28
|
variables.each do |var|
|
29
29
|
var.value = vars_by_name[var.to_s].to_f
|
30
30
|
end
|
31
|
-
|
31
|
+
self.unsuccessful = rows[0].start_with?('Infeasible')
|
32
|
+
return objective_str.to_f
|
32
33
|
end
|
33
34
|
end
|
data/lib/solvers/glpk.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class Glpk < Solver
|
2
2
|
def solve
|
3
|
-
command = "#{executable} --lp #{@filename} %s --cuts --
|
3
|
+
command = "#{executable} --lp #{@filename} %s --cuts --output #{@outfile}"
|
4
4
|
command %= options[:gap] ? "--mipgap #{options[:gap]}" : ""
|
5
5
|
exec(command)
|
6
6
|
end
|
@@ -11,10 +11,16 @@ class Glpk < Solver
|
|
11
11
|
|
12
12
|
def store_results(variables)
|
13
13
|
rows = IO.read(@outfile).split("\n")
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
objective_str = rows[5].split(/\s+/)[-2]
|
15
|
+
vars_by_name = {}
|
16
|
+
rows[1..-1].each do |row|
|
17
|
+
cols = row.strip.split(/\s+/)
|
18
|
+
vars_by_name[cols[1].to_s] = cols[3].to_f
|
17
19
|
end
|
18
|
-
|
20
|
+
variables.each do |var|
|
21
|
+
var.value = vars_by_name[var.to_s].to_f
|
22
|
+
end
|
23
|
+
self.unsuccessful = rows[-3].downcase.include?('infeasible')
|
24
|
+
return objective_str.to_f
|
19
25
|
end
|
20
26
|
end
|
data/lib/solvers/gurobi.rb
CHANGED
@@ -14,7 +14,7 @@ class Gurobi < Solver
|
|
14
14
|
|
15
15
|
def store_results(variables)
|
16
16
|
rows = IO.read(@outfile).split("\n")
|
17
|
-
|
17
|
+
objective_str = rows[0].split(/\s+/)[-1]
|
18
18
|
vars_by_name = {}
|
19
19
|
rows[1..-1].each do |row|
|
20
20
|
cols = row.strip.split(/\s+/)
|
@@ -23,6 +23,7 @@ class Gurobi < Solver
|
|
23
23
|
variables.each do |var|
|
24
24
|
var.value = vars_by_name[var.to_s].to_f
|
25
25
|
end
|
26
|
-
|
26
|
+
self.unsuccessful = rows.length.zero?
|
27
|
+
return objective_str.to_f
|
27
28
|
end
|
28
29
|
end
|
data/lib/solvers/scip.rb
CHANGED
@@ -44,7 +44,7 @@ class Scip < Solver
|
|
44
44
|
stripped = start.sub(/Statistics.+/m, "").strip
|
45
45
|
rows = stripped.split("\n")
|
46
46
|
|
47
|
-
|
47
|
+
objective_str = rows[0].split(/\s+/)[-1]
|
48
48
|
|
49
49
|
vars_by_name = {}
|
50
50
|
rows[1..-1].each do |row|
|
@@ -54,7 +54,7 @@ class Scip < Solver
|
|
54
54
|
variables.each do |var|
|
55
55
|
var.value = vars_by_name[var.to_s].to_f
|
56
56
|
end
|
57
|
-
|
58
|
-
return
|
57
|
+
self.unsuccessful = !(Float(objective_str) rescue false)
|
58
|
+
return objective_str.to_f
|
59
59
|
end
|
60
60
|
end
|
data/lib/solvers/solver.rb
CHANGED
data/test/test_basic_suite.rb
CHANGED
@@ -48,11 +48,11 @@ class BasicSuite < Minitest::Test
|
|
48
48
|
|
49
49
|
# Integer variables respect integer bounds
|
50
50
|
Rulp::Min(X_f).(solver)
|
51
|
-
|
51
|
+
assert_in_delta X_f.value, -345.4321, 0.001
|
52
52
|
|
53
53
|
# Integer variables respect integer bounds
|
54
54
|
Rulp::Max(X_f).(solver)
|
55
|
-
|
55
|
+
assert_in_delta X_f.value, 345.4321, 0.001
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
##
|
3
|
+
#
|
4
|
+
# Given 50 items of varying prices
|
5
|
+
# Get the minimal sum of 10 items that equals at least $15 dollars
|
6
|
+
#
|
7
|
+
##
|
8
|
+
class InfeasibleTest < Minitest::Test
|
9
|
+
def setup
|
10
|
+
@items = 30.times.map(&Shop_Item_b)
|
11
|
+
items_count = @items.sum
|
12
|
+
@items_costs = @items.map{|item| item * Random.rand(1.0...5.0)}.sum
|
13
|
+
|
14
|
+
@problem =
|
15
|
+
Rulp::Min( @items_costs ) [
|
16
|
+
items_count >= 10,
|
17
|
+
@items_costs >= 150_000
|
18
|
+
]
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_simple
|
22
|
+
each_solver do |solver|
|
23
|
+
assert_raises RuntimeError do
|
24
|
+
@problem.send(solver)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rulp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.25
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wouter Coppieters
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-29 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A simple Ruby LP description DSL
|
14
14
|
email: wc@pico.net.nz
|
@@ -40,6 +40,7 @@ files:
|
|
40
40
|
- test/test_basic_suite.rb
|
41
41
|
- test/test_boolean.rb
|
42
42
|
- test/test_helper.rb
|
43
|
+
- test/test_infeasible.rb
|
43
44
|
- test/test_save_to_file.rb
|
44
45
|
- test/test_simple.rb
|
45
46
|
homepage:
|
@@ -61,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
61
62
|
version: '0'
|
62
63
|
requirements: []
|
63
64
|
rubyforge_project:
|
64
|
-
rubygems_version: 2.
|
65
|
+
rubygems_version: 2.4.5
|
65
66
|
signing_key:
|
66
67
|
specification_version: 4
|
67
68
|
summary: Ruby Linear Programming
|
@@ -69,6 +70,7 @@ test_files:
|
|
69
70
|
- test/test_basic_suite.rb
|
70
71
|
- test/test_boolean.rb
|
71
72
|
- test/test_helper.rb
|
73
|
+
- test/test_infeasible.rb
|
72
74
|
- test/test_save_to_file.rb
|
73
75
|
- test/test_simple.rb
|
74
76
|
has_rdoc:
|