ruby-cbc 0.3.8 → 0.3.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +10 -22
- data/lib/ruby-cbc.rb +1 -0
- data/lib/ruby-cbc/conflict_solver.rb +73 -37
- data/lib/ruby-cbc/ilp/constraint.rb +1 -1
- data/lib/ruby-cbc/model.rb +2 -4
- data/lib/ruby-cbc/problem.rb +98 -56
- data/lib/ruby-cbc/utils/compressed_row_storage.rb +82 -0
- data/lib/ruby-cbc/version.rb +1 -1
- data/ruby-cbc.gemspec +2 -0
- metadata +31 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b400b079a0878a8b069de6806d0a39307ec7cbaa
|
4
|
+
data.tar.gz: c12f4fb20c21d4f0a2f56ee300f14ab7af90a693
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d60c2ca3659d4de0f4c2fc5619b372755b6d403fef0daa62f04117b4fab5a9c3808e9b1f1369e59445ffae46bc08ee31f393984e3714a887c31f2cea5758174
|
7
|
+
data.tar.gz: d57f7aad33405975ca485b8a3cdb7ab5da8646ef49a1966b8dc0a6bb6ec5ab66a26236f3293ac0b30e3be23136bde96c2ea66fc0d4623d40e264660368334f9c
|
data/Rakefile
CHANGED
@@ -10,29 +10,17 @@ ensure
|
|
10
10
|
Dir.chdir(original_dir)
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
#
|
15
|
-
# spec = Gem::Specification.load('ruby-cbc.gemspec')
|
16
|
-
# Rake::ExtensionTask.new('ruby-cbc', spec) do |ext|
|
17
|
-
# ext.lib_dir = 'lib/ruby-cbc'
|
18
|
-
# ext.tmp_dir = "tmp"
|
19
|
-
# ext.name = 'cbc_wrapper'
|
20
|
-
# end
|
13
|
+
RSpec::Core::RakeTask.new(:spec)
|
21
14
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
file EXTENSION => 'ext/ruby-cbc/cbc_wrap.c' do
|
29
|
-
puts "start"
|
30
|
-
in_dir('ext/ruby-cbc') do
|
31
|
-
system("ruby extconf.rb")
|
32
|
-
system("make")
|
33
|
-
end
|
15
|
+
spec = Gem::Specification.load('ruby-cbc.gemspec')
|
16
|
+
Rake::ExtensionTask.new('ruby-cbc', spec) do |ext|
|
17
|
+
ext.lib_dir = 'lib/ruby-cbc'
|
18
|
+
ext.tmp_dir = "tmp"
|
19
|
+
ext.name = 'cbc_wrapper'
|
34
20
|
end
|
35
21
|
|
36
|
-
|
22
|
+
task :default => [:spec]
|
37
23
|
|
38
|
-
task :
|
24
|
+
task :benchmark do
|
25
|
+
ruby "test/benchmark.rb"
|
26
|
+
end
|
data/lib/ruby-cbc.rb
CHANGED
@@ -2,66 +2,102 @@ module Cbc
|
|
2
2
|
|
3
3
|
class ConflictSolver
|
4
4
|
|
5
|
-
def initialize(
|
6
|
-
|
5
|
+
def initialize(problem)
|
6
|
+
# clone the model minus the objective
|
7
|
+
@model = Model.new
|
8
|
+
@model.vars = problem.model.vars
|
9
|
+
@model.constraints = problem.model.constraints
|
10
|
+
@problem = problem
|
7
11
|
end
|
8
12
|
|
9
|
-
# Assuming there is a conflict
|
10
13
|
def find_conflict
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
crs = Util::CompressedRowStorage.from_model(@model)
|
15
|
+
continuous = is_continuous_conflict?(crs)
|
16
|
+
unless continuous
|
17
|
+
p = Problem.from_compressed_row_storage(crs, continuous: false)
|
18
|
+
return [] unless infeasible?(p)
|
19
|
+
end
|
20
|
+
clusters = [crs.nb_constraints]
|
21
|
+
max_iter = 1
|
22
|
+
conflict_set_size = 0
|
15
23
|
loop do
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
24
|
+
range_idxs = first_failing(conflict_set_size, crs, continuous: continuous, max_iterations: max_iter)
|
25
|
+
break if range_idxs.nil?
|
26
|
+
puts "RANGE #{range_idxs}"
|
27
|
+
crs = crs.restrict_to_n_constraints(range_idxs.max + 1)
|
28
|
+
crs.move_constraint_to_start(range_idxs)
|
29
|
+
clusters.insert(0, range_idxs.size)
|
30
|
+
clusters[-1] = range_idxs.min - conflict_set_size
|
31
|
+
conflict_set_size += range_idxs.size
|
32
|
+
|
33
|
+
# Test conflict set
|
34
|
+
crs2 = crs.restrict_to_n_constraints(conflict_set_size)
|
35
|
+
problem = Problem.from_compressed_row_storage(crs2, continuous: continuous)
|
36
|
+
if infeasible?(problem)
|
37
|
+
puts "CONFLICT"
|
38
|
+
clusters.delete_at(-1)
|
39
|
+
break if clusters.size == conflict_set_size
|
40
|
+
|
41
|
+
crs = crs2
|
42
|
+
end
|
20
43
|
|
21
|
-
|
22
|
-
|
44
|
+
nb_clusters_one_constraint = 0
|
45
|
+
clusters.reverse_each do |nb_constraints|
|
46
|
+
break if nb_constraints > 1
|
47
|
+
nb_clusters_one_constraint += 1
|
48
|
+
end
|
49
|
+
if nb_clusters_one_constraint > 0
|
50
|
+
crs.move_constraint_to_start((crs.nb_constraints - nb_clusters_one_constraint)..(crs.nb_constraints - 1))
|
51
|
+
clusters[nb_clusters_one_constraint, clusters.size - nb_clusters_one_constraint] =
|
52
|
+
clusters[0, clusters.size - nb_clusters_one_constraint]
|
53
|
+
clusters[0, nb_clusters_one_constraint] = Array.new(nb_clusters_one_constraint, 1)
|
54
|
+
end
|
23
55
|
|
24
|
-
|
25
|
-
|
56
|
+
conflict_set_size = crs.nb_constraints - clusters[-1]
|
57
|
+
puts "CLUSTERS #{clusters.inspect}"
|
58
|
+
puts "VARS #{crs.col_idx.uniq.size}"
|
26
59
|
end
|
60
|
+
crs.model.constraints[0, conflict_set_size]
|
27
61
|
end
|
28
62
|
|
29
|
-
def is_continuous_conflict?
|
30
|
-
|
31
|
-
|
32
|
-
model.vars = @model.vars
|
33
|
-
model.constraints = @model.constraints
|
34
|
-
infeasible?(model, continuous: true)
|
63
|
+
def is_continuous_conflict?(crs)
|
64
|
+
problem = Problem.from_compressed_row_storage(crs, continuous: true)
|
65
|
+
infeasible?(problem)
|
35
66
|
end
|
36
67
|
|
37
68
|
private
|
38
69
|
# finds the first constraint from constraints that makes the problem infeasible
|
39
|
-
def first_failing(
|
40
|
-
|
41
|
-
|
70
|
+
def first_failing(conflict_set_size, crs, continuous: false, max_iterations: nil)
|
71
|
+
min_idx = conflict_set_size
|
72
|
+
max_idx = crs.nb_constraints - 1
|
42
73
|
|
43
74
|
loop do
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
75
|
+
unless max_iterations.nil?
|
76
|
+
return min_idx..max_idx if max_iterations <= 0
|
77
|
+
max_iterations -= 1
|
78
|
+
end
|
79
|
+
half_constraint_idx = (max_idx + min_idx) / 2
|
80
|
+
puts "Refining: [#{min_idx}:#{max_idx}] -> #{half_constraint_idx}"
|
81
|
+
crs2 = crs.restrict_to_n_constraints(half_constraint_idx + 1)
|
82
|
+
problem = Problem.from_compressed_row_storage(crs2, continuous: continuous)
|
83
|
+
if infeasible?(problem)
|
84
|
+
max_idx = half_constraint_idx
|
85
|
+
puts " INFEAS"
|
51
86
|
else
|
52
|
-
|
87
|
+
min_idx = half_constraint_idx + 1
|
88
|
+
puts " FEAS"
|
53
89
|
end
|
54
|
-
if
|
55
|
-
|
56
|
-
return
|
90
|
+
if max_idx == min_idx
|
91
|
+
puts "found: max = #{max_idx} min = #{min_idx} nb = #{crs.nb_constraints}"
|
92
|
+
return nil if max_idx > crs.nb_constraints
|
93
|
+
return min_idx..max_idx
|
57
94
|
end
|
58
95
|
end
|
59
96
|
# Shouldn't come here if the whole problem is infeasible
|
60
97
|
return nil
|
61
98
|
end
|
62
99
|
|
63
|
-
def infeasible?(
|
64
|
-
problem = Problem.new(model, continuous: continuous)
|
100
|
+
def infeasible?(problem)
|
65
101
|
problem.solve
|
66
102
|
problem.proven_infeasible?
|
67
103
|
end
|
data/lib/ruby-cbc/model.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require "set"
|
2
|
-
|
3
1
|
module Cbc
|
4
2
|
|
5
3
|
INF = 1.0 / 0.0 # Useful for ranges
|
@@ -24,7 +22,7 @@ module Cbc
|
|
24
22
|
attr_accessor :vars, :constraints, :objective, :name
|
25
23
|
|
26
24
|
def initialize(name: "ILP Problem")
|
27
|
-
@vars =
|
25
|
+
@vars = []
|
28
26
|
@constraints = []
|
29
27
|
@objective = nil
|
30
28
|
@name = name
|
@@ -82,7 +80,7 @@ module Cbc
|
|
82
80
|
end
|
83
81
|
|
84
82
|
def to_problem
|
85
|
-
Cbc::Problem.
|
83
|
+
Cbc::Problem.from_model(self)
|
86
84
|
end
|
87
85
|
|
88
86
|
def to_s
|
data/lib/ruby-cbc/problem.rb
CHANGED
@@ -1,55 +1,80 @@
|
|
1
1
|
module Cbc
|
2
2
|
class Problem
|
3
3
|
|
4
|
-
|
4
|
+
attr_accessor :model, :variable_index, :crs
|
5
5
|
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
def self.from_model(model, continuous: false)
|
7
|
+
crs = Util::CompressedRowStorage.from_model(model)
|
8
|
+
from_compressed_row_storage(crs, continuous: continuous)
|
9
|
+
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
vars_data[v] = VarData.new(v, idx, [], [])
|
11
|
+
def self.from_compressed_row_storage(crs, continuous: false)
|
12
|
+
new.tap do |p|
|
13
|
+
p.model = crs.model
|
14
|
+
p.variable_index = crs.variable_index
|
15
|
+
p.crs = crs
|
16
|
+
p.create_cbc_problem(continuous: continuous)
|
18
17
|
end
|
18
|
+
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
v_data.constraints << idx
|
24
|
-
v_data.coefs << term.mult
|
25
|
-
end
|
20
|
+
CCS = Struct.new(:col_ptr, :row_idx, :values) do
|
21
|
+
def nb_vars
|
22
|
+
col_ptr.size - 1
|
26
23
|
end
|
24
|
+
end
|
27
25
|
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
def self.crs_to_ccs(crs)
|
27
|
+
nb_per_column = Array.new(crs.col_idx.max.to_i + 1, 0)
|
28
|
+
nb_values = crs.values.size
|
31
29
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
crs.col_idx.each { |col_idx| nb_per_column[col_idx] += 1 }
|
31
|
+
|
32
|
+
ccs = CCS.new(Array.new(nb_per_column.size + 1), Array.new(nb_values), Array.new(nb_values))
|
33
|
+
ccs.col_ptr[0] = 0
|
34
|
+
idx = 0
|
35
|
+
while idx < nb_per_column.size
|
36
|
+
ccs.col_ptr[idx + 1] = ccs.col_ptr[idx] + nb_per_column[idx]
|
37
|
+
idx += 1
|
37
38
|
end
|
38
39
|
|
39
|
-
|
40
|
+
cols_idx = ccs.col_ptr.clone
|
41
|
+
row_idx = 0
|
42
|
+
end_row_idx = crs.row_ptr.size - 1
|
43
|
+
while row_idx < end_row_idx do
|
44
|
+
current_idx = crs.row_ptr[row_idx]
|
45
|
+
last_idx = crs.row_ptr[row_idx + 1] - 1
|
46
|
+
while current_idx <= last_idx do
|
47
|
+
col_idx = crs.col_idx[current_idx]
|
48
|
+
ccs_col_idx = cols_idx[col_idx]
|
49
|
+
cols_idx[col_idx] += 1
|
50
|
+
ccs.row_idx[ccs_col_idx] = row_idx
|
51
|
+
ccs.values[ccs_col_idx] = crs.values[current_idx]
|
52
|
+
current_idx += 1
|
53
|
+
end
|
54
|
+
row_idx += 1
|
55
|
+
end
|
56
|
+
ccs
|
57
|
+
end
|
40
58
|
|
41
|
-
|
59
|
+
def create_cbc_problem(continuous: false)
|
60
|
+
@int_arrays = []
|
61
|
+
@double_arrays = []
|
62
|
+
|
63
|
+
ccs = self.class.crs_to_ccs(@crs)
|
64
|
+
objective = Array.new(ccs.nb_vars, 0)
|
42
65
|
if model.objective
|
43
66
|
model.objective.terms.each do |term|
|
44
|
-
objective[
|
67
|
+
objective[@variable_index[term.var]] = term.mult
|
45
68
|
end
|
46
69
|
end
|
47
70
|
|
48
71
|
@cbc_model = Cbc_wrapper.Cbc_newModel
|
49
|
-
Cbc_wrapper.Cbc_loadProblem(
|
50
|
-
|
51
|
-
|
52
|
-
|
72
|
+
Cbc_wrapper.Cbc_loadProblem(
|
73
|
+
@cbc_model, ccs.nb_vars, @crs.nb_constraints,
|
74
|
+
to_int_array(ccs.col_ptr), to_int_array(ccs.row_idx),
|
75
|
+
to_double_array(ccs.values), nil, nil, to_double_array(objective),
|
76
|
+
nil, nil)
|
77
|
+
|
53
78
|
|
54
79
|
# Segmentation errors when setting name
|
55
80
|
# Cbc_wrapper.Cbc_setProblemName(@cbc_model, model.name) if model.name
|
@@ -59,18 +84,15 @@ module Cbc
|
|
59
84
|
Cbc_wrapper.Cbc_setObjSense(@cbc_model, obj_sense)
|
60
85
|
end
|
61
86
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
Cbc_wrapper.Cbc_setRowLower(@cbc_model, idx, c.bound)
|
68
|
-
when Ilp::Constraint::EQUALS
|
69
|
-
Cbc_wrapper.Cbc_setRowUpper(@cbc_model, idx, c.bound)
|
70
|
-
Cbc_wrapper.Cbc_setRowLower(@cbc_model, idx, c.bound)
|
71
|
-
end
|
87
|
+
idx = 0
|
88
|
+
while idx < @crs.nb_constraints do
|
89
|
+
c = model.constraints[idx]
|
90
|
+
set_constraint_bounds(c, idx)
|
91
|
+
idx += 1
|
72
92
|
end
|
73
|
-
|
93
|
+
idx = 0
|
94
|
+
while idx < ccs.nb_vars do
|
95
|
+
v = model.vars[idx]
|
74
96
|
if continuous
|
75
97
|
Cbc_wrapper.Cbc_setContinuous(@cbc_model, idx)
|
76
98
|
else
|
@@ -83,14 +105,28 @@ module Cbc
|
|
83
105
|
end
|
84
106
|
Cbc_wrapper.Cbc_setColLower(@cbc_model, idx, v.lower_bound) unless v.lower_bound.nil?
|
85
107
|
Cbc_wrapper.Cbc_setColUpper(@cbc_model, idx, v.upper_bound) unless v.upper_bound.nil?
|
108
|
+
idx += 1
|
86
109
|
end
|
87
110
|
|
88
111
|
ObjectSpace.define_finalizer(self, self.class.finalizer(@cbc_model, @int_arrays, @double_arrays))
|
89
112
|
|
90
113
|
@default_solve_params = {
|
91
|
-
|
92
|
-
|
114
|
+
log: 0,
|
115
|
+
}
|
116
|
+
|
117
|
+
|
118
|
+
end
|
93
119
|
|
120
|
+
def set_constraint_bounds(c, idx)
|
121
|
+
case c.type
|
122
|
+
when Ilp::Constraint::LESS_OR_EQ
|
123
|
+
Cbc_wrapper.Cbc_setRowUpper(@cbc_model, idx, c.bound)
|
124
|
+
when Ilp::Constraint::GREATER_OR_EQ
|
125
|
+
Cbc_wrapper.Cbc_setRowLower(@cbc_model, idx, c.bound)
|
126
|
+
when Ilp::Constraint::EQUALS
|
127
|
+
Cbc_wrapper.Cbc_setRowUpper(@cbc_model, idx, c.bound)
|
128
|
+
Cbc_wrapper.Cbc_setRowLower(@cbc_model, idx, c.bound)
|
129
|
+
end
|
94
130
|
end
|
95
131
|
|
96
132
|
def solve(params = {})
|
@@ -99,10 +135,12 @@ module Cbc
|
|
99
135
|
end
|
100
136
|
Cbc_wrapper.Cbc_solve(@cbc_model)
|
101
137
|
@solution = Cbc_wrapper::DoubleArray.frompointer(Cbc_wrapper.Cbc_getColSolution(@cbc_model))
|
138
|
+
@double_arrays << @solution
|
139
|
+
@solution
|
102
140
|
end
|
103
141
|
|
104
142
|
def value_of(var)
|
105
|
-
idx = @
|
143
|
+
idx = @variable_index[var]
|
106
144
|
return nil if idx.nil?
|
107
145
|
if var.kind == Ilp::Var::CONTINUOUS_KIND
|
108
146
|
@solution[idx]
|
@@ -141,7 +179,7 @@ module Cbc
|
|
141
179
|
end
|
142
180
|
|
143
181
|
def find_conflict
|
144
|
-
@conflict_set ||= ConflictSolver.new(
|
182
|
+
@conflict_set ||= ConflictSolver.new(self).find_conflict
|
145
183
|
end
|
146
184
|
|
147
185
|
def find_conflict_vars
|
@@ -163,21 +201,25 @@ module Cbc
|
|
163
201
|
private
|
164
202
|
|
165
203
|
def to_int_array(array)
|
166
|
-
c_array = Cbc_wrapper::IntArray.new(array.
|
167
|
-
|
204
|
+
c_array = Cbc_wrapper::IntArray.new(array.size)
|
205
|
+
idx = 0
|
206
|
+
while idx < array.size do
|
207
|
+
c_array[idx] = array[idx]
|
208
|
+
idx += 1
|
209
|
+
end
|
168
210
|
@int_arrays << c_array
|
169
211
|
c_array
|
170
212
|
end
|
171
213
|
|
172
214
|
def to_double_array(array)
|
173
|
-
c_array = Cbc_wrapper::DoubleArray.new(array.
|
174
|
-
|
215
|
+
c_array = Cbc_wrapper::DoubleArray.new(array.size)
|
216
|
+
idx = 0
|
217
|
+
while idx < array.size do
|
218
|
+
c_array[idx] = array[idx]
|
219
|
+
idx += 1
|
220
|
+
end
|
175
221
|
@double_arrays << c_array
|
176
222
|
c_array
|
177
223
|
end
|
178
|
-
|
179
|
-
VarData = Struct.new(:variable, :col_idx, :constraints, :coefs)
|
180
224
|
end
|
181
|
-
|
182
|
-
|
183
225
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Util
|
2
|
+
class CompressedRowStorage
|
3
|
+
|
4
|
+
attr_accessor :model, :variable_index, :row_ptr, :col_idx, :values
|
5
|
+
|
6
|
+
def self.from_model(model)
|
7
|
+
new.tap do |crs|
|
8
|
+
crs.model = model
|
9
|
+
crs.variable_index = {}
|
10
|
+
idx = 0
|
11
|
+
while idx < model.vars.size do
|
12
|
+
v = model.vars[idx]
|
13
|
+
crs.variable_index[v] = idx
|
14
|
+
idx += 1
|
15
|
+
end
|
16
|
+
crs.fill_matrix
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def nb_constraints
|
21
|
+
row_ptr.count - 1
|
22
|
+
end
|
23
|
+
|
24
|
+
def fill_matrix
|
25
|
+
nb_values = model.constraints.map { |c| c.terms.count }.inject(:+) || 0
|
26
|
+
@row_ptr = Array.new(model.constraints.count)
|
27
|
+
@col_idx = Array.new(nb_values)
|
28
|
+
@values = Array.new(nb_values)
|
29
|
+
|
30
|
+
nb_cols = 0
|
31
|
+
c_idx = 0
|
32
|
+
while c_idx < @model.constraints.size do
|
33
|
+
constraint = @model.constraints[c_idx]
|
34
|
+
@row_ptr[c_idx] = nb_cols
|
35
|
+
nb_insert = constraint.terms.count
|
36
|
+
@col_idx[nb_cols, nb_insert] = constraint.terms.map { |term| variable_index[term.var] }
|
37
|
+
@values[nb_cols, nb_insert] = constraint.terms.map { |term| term.mult }
|
38
|
+
nb_cols += nb_insert
|
39
|
+
c_idx += 1
|
40
|
+
end
|
41
|
+
@row_ptr << @col_idx.count
|
42
|
+
end
|
43
|
+
|
44
|
+
def restrict_to_n_constraints(nb_constraints)
|
45
|
+
length_of_values = @row_ptr[nb_constraints]
|
46
|
+
CompressedRowStorage.new.tap do |crs|
|
47
|
+
crs.model = @model
|
48
|
+
crs.variable_index = @variable_index
|
49
|
+
crs.row_ptr = @row_ptr[0, nb_constraints + 1]
|
50
|
+
crs.col_idx = @col_idx[0, length_of_values]
|
51
|
+
crs.values = @values[0, length_of_values]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def move_constraint_to_start(range_idxs)
|
56
|
+
# Move in the model
|
57
|
+
constraints = model.constraints[range_idxs]
|
58
|
+
@model.constraints = @model.constraints.clone
|
59
|
+
@model.constraints[constraints.count, range_idxs.max] = model.constraints[0, range_idxs.min]
|
60
|
+
@model.constraints[0, constraints.count] = constraints
|
61
|
+
|
62
|
+
# Move in the matrix
|
63
|
+
constraint_start_idx = @row_ptr[range_idxs.min]
|
64
|
+
nb_vars = @row_ptr[range_idxs.max + 1] - constraint_start_idx
|
65
|
+
offset= @row_ptr[range_idxs.min]
|
66
|
+
new_begin = @row_ptr[range_idxs].map! { |idx| idx - offset }
|
67
|
+
((range_idxs.count)..(range_idxs.max)).reverse_each do |idx|
|
68
|
+
@row_ptr[idx] = @row_ptr[idx - range_idxs.count] + nb_vars
|
69
|
+
end
|
70
|
+
@row_ptr[0, range_idxs.count] = new_begin
|
71
|
+
move_block_to_start(@col_idx, constraint_start_idx, nb_vars)
|
72
|
+
move_block_to_start(@values, constraint_start_idx, nb_vars)
|
73
|
+
end
|
74
|
+
|
75
|
+
def move_block_to_start(array, block_start_idx, nb_values)
|
76
|
+
to_move = array[block_start_idx, nb_values]
|
77
|
+
array[nb_values, block_start_idx] = array[0, block_start_idx]
|
78
|
+
array[0, nb_values] = to_move
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
data/lib/ruby-cbc/version.rb
CHANGED
data/ruby-cbc.gemspec
CHANGED
@@ -25,6 +25,8 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_development_dependency "rake-compiler"
|
26
26
|
spec.add_development_dependency "pry"
|
27
27
|
spec.add_development_dependency "pry-byebug"
|
28
|
+
spec.add_development_dependency "benchmark-ips"
|
29
|
+
spec.add_development_dependency "ruby-prof"
|
28
30
|
|
29
31
|
spec.add_dependency "cbc-wrapper", '~> 2.9.7.2'
|
30
32
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-cbc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Guillaume Verger
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -94,6 +94,34 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: benchmark-ips
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: ruby-prof
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
97
125
|
- !ruby/object:Gem::Dependency
|
98
126
|
name: cbc-wrapper
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -134,6 +162,7 @@ files:
|
|
134
162
|
- lib/ruby-cbc/ilp/var.rb
|
135
163
|
- lib/ruby-cbc/model.rb
|
136
164
|
- lib/ruby-cbc/problem.rb
|
165
|
+
- lib/ruby-cbc/utils/compressed_row_storage.rb
|
137
166
|
- lib/ruby-cbc/version.rb
|
138
167
|
- ruby-cbc.gemspec
|
139
168
|
homepage: https://github.com/gverger/ruby-cbc
|
@@ -161,4 +190,3 @@ signing_key:
|
|
161
190
|
specification_version: 4
|
162
191
|
summary: Wrapper around Cbc Linear Programming Solver
|
163
192
|
test_files: []
|
164
|
-
has_rdoc:
|