ruby-cbc 0.3.10 → 0.3.12

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.
@@ -1,5 +1,4 @@
1
1
  module Cbc
2
-
3
2
  INF = 1.0 / 0.0 # Useful for ranges
4
3
 
5
4
  def self.add_all(variables)
@@ -10,15 +9,13 @@ module Cbc
10
9
  when Ilp::Var
11
10
  Ilp::Term.new(variable)
12
11
  else
13
- raise 'Not a variable, a term or a numeric'
12
+ raise "Not a variable, a term or a numeric"
14
13
  end
15
14
  end
16
15
  Ilp::TermArray.new(to_add)
17
16
  end
18
17
 
19
18
  class Model
20
-
21
-
22
19
  attr_accessor :vars, :constraints, :objective, :name
23
20
 
24
21
  def initialize(name: "ILP Problem")
@@ -48,7 +45,7 @@ module Cbc
48
45
  var(Ilp::Var::CONTINUOUS_KIND, range, name)
49
46
  end
50
47
 
51
- def cont_var_array(length, range = nil, name: nil)
48
+ def cont_var_array(length, range = nil, names: nil)
52
49
  array_var(length, Ilp::Var::CONTINUOUS_KIND, range, names)
53
50
  end
54
51
 
@@ -57,12 +54,12 @@ module Cbc
57
54
  if constraint.instance_of? Ilp::Constraint
58
55
  self.constraints << constraint
59
56
  elsif constraint.instance_of? Array
60
- self.constraints += constraint
57
+ self.constraints.concat constraint
61
58
  elsif constraint.instance_of? Hash
62
- constraint.each do |name, c|
63
- self.constraints << c
64
- c.function_name = name.to_s
59
+ to_add = constraint.map do |name, cons|
60
+ cons.tap { |c| c.function_name = name.to_s }
65
61
  end
62
+ self.constraints.concat to_add
66
63
  else
67
64
  puts "Not a constraint: #{constraint}"
68
65
  end
@@ -84,30 +81,32 @@ module Cbc
84
81
  end
85
82
 
86
83
  def to_s
87
- str = ""
88
- if objective
89
- str << objective.to_s << "\n"
90
- else
91
- str << "Maximize\n 0 #{vars.first.to_s}\n"
92
- end
84
+ str = if objective
85
+ "#{objective}\n"
86
+ else
87
+ "Maximize\n 0 #{vars.first}\n"
88
+ end
89
+
93
90
  str << "\nSubject To\n"
94
91
  constraints.each do |cons|
95
- str << " " << cons.to_s << "\n"
92
+ str << " #{cons}\n"
96
93
  end
97
- bounded_vars = vars.select{ |v| v.kind != Ilp::Var::BINARY_KIND }
98
- if bounded_vars.any?
94
+ bounded_vars = vars.select { |v| v.kind != Ilp::Var::BINARY_KIND }
95
+ unless bounded_vars.empty?
99
96
  str << "\nBounds\n"
100
- bounded_vars.each { |v| str << " #{lb_to_s(v.lower_bound)} <= #{v} <= #{ub_to_s(v.upper_bound)}\n" }
97
+ bounded_vars.each do |v|
98
+ str << " #{lb_to_s(v.lower_bound)} <= #{v} <= #{ub_to_s(v.upper_bound)}\n"
99
+ end
101
100
  end
102
101
 
103
- int_vars = vars.select{ |v| v.kind == Ilp::Var::INTEGER_KIND }
104
- if int_vars.any?
102
+ int_vars = vars.select { |v| v.kind == Ilp::Var::INTEGER_KIND }
103
+ unless int_vars.empty?
105
104
  str << "\nGenerals\n"
106
105
  int_vars.each { |v| str << " #{v}\n" }
107
106
  end
108
107
 
109
- bin_vars = vars.select{ |v| v.kind == Ilp::Var::BINARY_KIND }
110
- if bin_vars.any?
108
+ bin_vars = vars.select { |v| v.kind == Ilp::Var::BINARY_KIND }
109
+ unless bin_vars.empty?
111
110
  str << "\nBinaries\n"
112
111
  bin_vars.each { |v| str << " #{v}\n" }
113
112
  end
@@ -116,35 +115,34 @@ module Cbc
116
115
  str
117
116
  end
118
117
 
119
- private
118
+ private
119
+
120
120
  def array_var(length, kind, range, names)
121
121
  ar = Array.new(length) { var(kind, range, nil) }
122
- ar.zip(names).map{ |var, name| var.name = name } unless names.nil?
122
+ ar.zip(names).each { |var, name| var.name = name } unless names.nil?
123
123
  ar
124
124
  end
125
125
 
126
126
  def var(kind, range, name)
127
- if range.nil?
128
- v = Ilp::Var.new(kind: kind, name: name)
129
- @vars << v
130
- return v
131
- end
132
- v = Ilp::Var.new(kind: kind, name: name, lower_bound: range.min, upper_bound: range.max)
127
+ v = if range.nil?
128
+ Ilp::Var.new(kind: kind, name: name)
129
+ else
130
+ Ilp::Var.new(kind: kind, name: name, lower_bound: range.min, upper_bound: range.max)
131
+ end
133
132
  @vars << v
134
133
  v
135
134
  end
136
135
 
137
136
  def lb_to_s(lb)
138
- return "-inf" if ! lb || lb == -Cbc::INF
137
+ return "-inf" if lb.nil? || lb == -Cbc::INF
139
138
  return "+inf" if lb == Cbc::INF
140
- return "#{lb}"
139
+ lb.to_s
141
140
  end
142
141
 
143
142
  def ub_to_s(ub)
144
- return "+inf" if ! ub || ub == Cbc::INF
143
+ return "+inf" if ub.nil? || ub == Cbc::INF
145
144
  return "-inf" if ub == -Cbc::INF
146
- return "#{ub}"
145
+ ub.to_s
147
146
  end
148
-
149
147
  end
150
148
  end
@@ -1,6 +1,5 @@
1
1
  module Cbc
2
2
  class Problem
3
-
4
3
  attr_accessor :model, :variable_index, :crs
5
4
 
6
5
  def self.from_model(model, continuous: false)
@@ -40,10 +39,10 @@ module Cbc
40
39
  cols_idx = ccs.col_ptr.clone
41
40
  row_idx = 0
42
41
  end_row_idx = crs.row_ptr.size - 1
43
- while row_idx < end_row_idx do
42
+ while row_idx < end_row_idx
44
43
  current_idx = crs.row_ptr[row_idx]
45
44
  last_idx = crs.row_ptr[row_idx + 1] - 1
46
- while current_idx <= last_idx do
45
+ while current_idx <= last_idx
47
46
  col_idx = crs.col_idx[current_idx]
48
47
  ccs_col_idx = cols_idx[col_idx]
49
48
  cols_idx[col_idx] += 1
@@ -75,7 +74,6 @@ module Cbc
75
74
  to_double_array(ccs.values), nil, nil, to_double_array(objective),
76
75
  nil, nil)
77
76
 
78
-
79
77
  # Segmentation errors when setting name
80
78
  # Cbc_wrapper.Cbc_setProblemName(@cbc_model, model.name) if model.name
81
79
 
@@ -85,13 +83,13 @@ module Cbc
85
83
  end
86
84
 
87
85
  idx = 0
88
- while idx < @crs.nb_constraints do
86
+ while idx < @crs.nb_constraints
89
87
  c = @crs.model.constraints[idx]
90
88
  set_constraint_bounds(c, idx)
91
89
  idx += 1
92
90
  end
93
91
  idx = 0
94
- while idx < ccs.nb_vars do
92
+ while idx < ccs.nb_vars
95
93
  v = @crs.model.vars[idx]
96
94
  if continuous
97
95
  Cbc_wrapper.Cbc_setContinuous(@cbc_model, idx)
@@ -111,10 +109,8 @@ module Cbc
111
109
  ObjectSpace.define_finalizer(self, self.class.finalizer(@cbc_model, @int_arrays, @double_arrays))
112
110
 
113
111
  @default_solve_params = {
114
- log: 0,
112
+ log: 0
115
113
  }
116
-
117
-
118
114
  end
119
115
 
120
116
  def set_constraint_bounds(c, idx)
@@ -198,12 +194,12 @@ module Cbc
198
194
  Cbc_wrapper.Cbc_writeMps(@cbc_model, "test")
199
195
  end
200
196
 
201
- private
197
+ private
202
198
 
203
199
  def to_int_array(array)
204
200
  c_array = Cbc_wrapper::IntArray.new(array.size)
205
201
  idx = 0
206
- while idx < array.size do
202
+ while idx < array.size
207
203
  c_array[idx] = array[idx]
208
204
  idx += 1
209
205
  end
@@ -214,7 +210,7 @@ module Cbc
214
210
  def to_double_array(array)
215
211
  c_array = Cbc_wrapper::DoubleArray.new(array.size)
216
212
  idx = 0
217
- while idx < array.size do
213
+ while idx < array.size
218
214
  c_array[idx] = array[idx]
219
215
  idx += 1
220
216
  end
@@ -1,121 +1,123 @@
1
- module Util
2
- class CompressedRowStorage
1
+ module Cbc
2
+ module Util
3
+ class CompressedRowStorage
4
+ attr_accessor :model, :variable_index, :row_ptr, :col_idx, :values
3
5
 
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
6
+ def self.from_model(model)
7
+ new.tap do |crs|
8
+ crs.model = model
9
+ crs.make_variable_index
10
+ crs.fill_matrix
15
11
  end
16
- crs.fill_matrix
17
12
  end
18
- end
19
13
 
20
- def nb_constraints
21
- row_ptr.count - 1
22
- end
14
+ def nb_constraints
15
+ row_ptr.size - 1
16
+ end
23
17
 
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)
18
+ def make_variable_index
19
+ indexes = @model.vars.size.times.to_a
20
+ @variable_index = model.vars.zip(indexes).to_h
21
+ end
29
22
 
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
23
+ def init_matrix
24
+ nb_values = model.constraints.map { |c| c.terms.size }.inject(:+) || 0
25
+ @row_ptr = Array.new(model.constraints.size)
26
+ @col_idx = Array.new(nb_values)
27
+ @values = Array.new(nb_values)
40
28
  end
41
- @row_ptr << @col_idx.count
42
- end
43
29
 
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.clone
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
- crs.delete_missing_vars
30
+ def fill_matrix
31
+ init_matrix
32
+ nb_cols = 0
33
+ c_idx = 0
34
+ while c_idx < @model.constraints.size
35
+ constraint = @model.constraints[c_idx]
36
+ @row_ptr[c_idx] = nb_cols
37
+ nb_insert = constraint.terms.size
38
+ @col_idx[nb_cols, nb_insert] = constraint.terms.map { |term| variable_index[term.var] }
39
+ @values[nb_cols, nb_insert] = constraint.terms.map(&:mult)
40
+ nb_cols += nb_insert
41
+ c_idx += 1
42
+ end
43
+ @row_ptr << @col_idx.size
53
44
  end
54
- end
55
45
 
56
- def present_var_indices
57
- is_present = Array.new(@variable_index.count, false)
58
- @col_idx.each do |col_idx|
59
- is_present[col_idx] = true
46
+ def restrict_to_n_constraints(nb_constraints)
47
+ length_of_values = @row_ptr[nb_constraints]
48
+ CompressedRowStorage.new.tap do |crs|
49
+ crs.model = @model.clone
50
+ crs.variable_index = @variable_index
51
+ crs.row_ptr = @row_ptr[0, nb_constraints + 1]
52
+ crs.col_idx = @col_idx[0, length_of_values]
53
+ crs.values = @values[0, length_of_values]
54
+ crs.delete_missing_vars
55
+ end
56
+ end
57
+
58
+ def present_var_indexes
59
+ present = Array.new(@variable_index.size, false)
60
+ @col_idx.each { |col_idx| present[col_idx] = true }
61
+ present
60
62
  end
61
- is_present
62
- end
63
63
 
64
- def delete_missing_vars
65
- at_least_one_missing = false
66
- here = present_var_indices
67
- new_idx = Array.new(@variable_index.count, -1)
68
- idx = 0
69
- current_index = 0
70
- while idx < new_idx.size do
71
- if here[idx]
64
+ def new_indexes
65
+ present = present_var_indexes
66
+ return nil if present.all?
67
+ new_idx = Array.new(@variable_index.size, -1)
68
+ current_index = 0
69
+ new_idx.size.times.each do |idx|
70
+ next unless present[idx]
72
71
  new_idx[idx] = current_index
73
72
  current_index += 1
74
- else
75
- at_least_one_missing = true
76
73
  end
77
- idx += 1
74
+ new_idx
78
75
  end
79
76
 
80
- return unless at_least_one_missing
81
-
82
- new_variable_index = {}
83
- @variable_index.each do |v, i|
84
- new_variable_index[v] = new_idx[i] if new_idx[i] != -1
77
+ def change_indexes(new_idx)
78
+ new_variable_index = {}
79
+ @variable_index.each do |v, i|
80
+ new_variable_index[v] = new_idx[i] if new_idx[i] != -1
81
+ end
82
+ @variable_index = new_variable_index
85
83
  end
86
- @variable_index = new_variable_index
87
- @col_idx.map! { |idx| new_idx[idx] }
88
- @model.vars = Array.new(@variable_index.size)
89
- @variable_index.each do |var, idx|
90
- @model.vars[idx] = var
84
+
85
+ def delete_missing_vars
86
+ new_idx = new_indexes
87
+ return if new_idx.nil?
88
+
89
+ change_indexes(new_idx)
90
+
91
+ @col_idx.map! { |i| new_idx[i] }
92
+ @model.vars = Array.new(@variable_index.size)
93
+ @variable_index.each { |var, i| @model.vars[i] = var }
91
94
  end
92
- end
93
95
 
94
- def move_constraint_to_start(range_idxs)
95
- # Move in the model
96
- constraints = model.constraints[range_idxs]
97
- @model.constraints = @model.constraints.clone
98
- @model.constraints[constraints.count, range_idxs.max] = model.constraints[0, range_idxs.min]
99
- @model.constraints[0, constraints.count] = constraints
96
+ def move_constraint_to_start(range_idxs)
97
+ # Move in the model
98
+ constraints = model.constraints[range_idxs]
99
+ @model.constraints = @model.constraints.clone
100
+ @model.constraints[constraints.size, range_idxs.max] = model.constraints[0, range_idxs.min]
101
+ @model.constraints[0, constraints.size] = constraints
100
102
 
101
- # Move in the matrix
102
- constraint_start_idx = @row_ptr[range_idxs.min]
103
- nb_vars = @row_ptr[range_idxs.max + 1] - constraint_start_idx
104
- offset= @row_ptr[range_idxs.min]
105
- new_begin = @row_ptr[range_idxs].map! { |idx| idx - offset }
106
- ((range_idxs.count)..(range_idxs.max)).reverse_each do |idx|
107
- @row_ptr[idx] = @row_ptr[idx - range_idxs.count] + nb_vars
103
+ # Move in the matrix
104
+ constraint_start_idx = @row_ptr[range_idxs.min]
105
+ nb_vars = @row_ptr[range_idxs.max + 1] - constraint_start_idx
106
+ offset = @row_ptr[range_idxs.min]
107
+ new_begin = @row_ptr[range_idxs].map! { |idx| idx - offset }
108
+ ((range_idxs.size)..(range_idxs.max)).reverse_each do |idx|
109
+ @row_ptr[idx] = @row_ptr[idx - range_idxs.size] + nb_vars
110
+ end
111
+ @row_ptr[0, range_idxs.size] = new_begin
112
+ move_block_to_start(@col_idx, constraint_start_idx, nb_vars)
113
+ move_block_to_start(@values, constraint_start_idx, nb_vars)
108
114
  end
109
- @row_ptr[0, range_idxs.count] = new_begin
110
- move_block_to_start(@col_idx, constraint_start_idx, nb_vars)
111
- move_block_to_start(@values, constraint_start_idx, nb_vars)
112
- end
113
115
 
114
- def move_block_to_start(array, block_start_idx, nb_values)
115
- to_move = array[block_start_idx, nb_values]
116
- array[nb_values, block_start_idx] = array[0, block_start_idx]
117
- array[0, nb_values] = to_move
116
+ def move_block_to_start(array, block_start_idx, nb_values)
117
+ to_move = array[block_start_idx, nb_values]
118
+ array[nb_values, block_start_idx] = array[0, block_start_idx]
119
+ array[0, nb_values] = to_move
120
+ end
118
121
  end
119
-
120
122
  end
121
123
  end
@@ -1,3 +1,3 @@
1
1
  module Cbc
2
- VERSION = "0.3.10"
2
+ VERSION = "0.3.12"
3
3
  end
@@ -28,5 +28,5 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency "benchmark-ips"
29
29
  spec.add_development_dependency "ruby-prof"
30
30
 
31
- spec.add_dependency "cbc-wrapper", '~> 2.9.7.2'
31
+ spec.add_dependency "cbc-wrapper", '~> 2.9.7.3'
32
32
  end