ruby-cbc 0.3.10 → 0.3.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -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