ruby-cbc 0.3.8 → 0.3.9
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 +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:
|