mipper 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,186 @@
1
+ module MIPPeR
2
+ class GLPKModel < Model
3
+ attr_reader :ptr
4
+
5
+ def initialize
6
+ super
7
+
8
+ @var_count = 0
9
+ @constr_count = 0
10
+
11
+ # Constraint matrix initialization (see #add_constraints)
12
+ @ia = [0]
13
+ @ja = [0]
14
+ @ar = [0]
15
+
16
+ # Disable terminal output
17
+ GLPK.glp_term_out GLPK::GLP_OFF
18
+
19
+ # Construct a new model
20
+ @ptr = FFI::AutoPointer.new GLPK.glp_create_prob,
21
+ GLPK.method(:glp_delete_prob)
22
+ end
23
+
24
+ # Write the model to a file
25
+ def write(filename)
26
+ ret = GLPK.glp_write_lp @ptr, 0, filename
27
+ fail if ret != 0
28
+ end
29
+
30
+ # Set the sense of the model
31
+ def sense=(sense)
32
+ @sense = sense
33
+ sense = sense == :min ? GLPK::GLP_MIN : GLPK::GLP_MAX
34
+ GLPK.glp_set_obj_dir @ptr, sense
35
+ end
36
+
37
+ # Optimize the model
38
+ def optimize
39
+ # Ensure pending variables and constraints are added
40
+ update
41
+
42
+ # Run the solver and save the status for later
43
+ iocp = GLPK::IOCP.new
44
+ GLPK.glp_init_iocp iocp
45
+ iocp[:presolve] = GLPK::GLP_ON
46
+ @status = GLPK.glp_intopt @ptr, iocp
47
+ end
48
+
49
+ # Get the status of the model
50
+ def status
51
+ case @status
52
+ when 0, GLPK::GLP_EMIPGAP
53
+ :optimized
54
+ when GLPK::GLP_EBOUND, GLPK::GLP_EROOT, GLPK::GLP_ENOPFS
55
+ :invalid
56
+ else
57
+ :unknown
58
+ end
59
+ end
60
+
61
+ # The value of the objective function
62
+ def objective_value
63
+ GLPK.glp_mip_obj_val @ptr
64
+ end
65
+
66
+ # Get the value of a variable from the model
67
+ def variable_value(var)
68
+ GLPK.glp_mip_col_val(@ptr, var.index)
69
+ end
70
+
71
+ def set_variable_bounds(var_index, lb, ub)
72
+ # Determine the type of the variable bounds
73
+ if lb == ub
74
+ type = GLPK::GLP_FX
75
+ elsif lb.finite?
76
+ type = ub.finite? ? GLPK::GLP_DB : GLPK::GLP_LO
77
+ else
78
+ type = ub.finite? ? GLPK::GLP_UP : GLPK::GLP_FR
79
+ end
80
+
81
+ # Set the bounds on the variable
82
+ GLPK.glp_set_col_bnds(@ptr, var_index, type, lb, ub)
83
+ end
84
+
85
+ protected
86
+
87
+ # Add multiple variables to the model simultaneously
88
+ def add_variables(vars)
89
+ # Store all the variables in the model
90
+ GLPK.glp_add_cols(@ptr, vars.length)
91
+ vars.each { |var| store_variable var }
92
+ end
93
+
94
+ # Add multiple constraints at once
95
+ def add_constraints(constrs)
96
+ GLPK.glp_add_rows(@ptr, constrs.length)
97
+
98
+ # Store each constraint and initialize a matrix used to hold
99
+ # the coefficients of each value in the constraint matrix
100
+ #
101
+ # * ia - row (constraint) index
102
+ # * ja - column (variable) index
103
+ # * ar - constraint coefficient
104
+ constrs.each do |constr|
105
+ store_constraint constr
106
+ constr.expression.terms.each do |var, coeff|
107
+ @ia << constr.instance_variable_get(:@index)
108
+ @ja << var.instance_variable_get(:@index)
109
+ @ar << coeff
110
+ end
111
+ end
112
+
113
+ ia_buffer = FFI::MemoryPointer.new :pointer, @ia.length
114
+ ia_buffer.write_array_of_int @ia
115
+ ja_buffer = FFI::MemoryPointer.new :pointer, @ja.length
116
+ ja_buffer.write_array_of_int @ja
117
+ ar_buffer = FFI::MemoryPointer.new :pointer, @ar.length
118
+ ar_buffer.write_array_of_double @ar
119
+
120
+ GLPK.glp_load_matrix(@ptr, @ar.length - 1, ia_buffer, ja_buffer,
121
+ ar_buffer)
122
+
123
+ @constraints.concat constrs
124
+ end
125
+
126
+ private
127
+
128
+ # Save the constraint to the model and update the constraint pointers
129
+ def store_constraint(constr)
130
+ # Update the constraint to track the index in the model
131
+ index = @constr_count + 1
132
+ constr.instance_variable_set :@model, self
133
+ constr.instance_variable_set :@index, index
134
+ @constr_count += 1
135
+
136
+ # Set constraint properties
137
+ GLPK.glp_set_row_name(@ptr, index, constr.name)
138
+
139
+ case constr.sense
140
+ when :==
141
+ lb = ub = constr.rhs
142
+ type = GLPK::GLP_FX
143
+ when :>=
144
+ lb = constr.rhs
145
+ ub = Float::INFINITY
146
+ type = GLPK::GLP_LO
147
+ when :<=
148
+ lb = -Float::INFINITY
149
+ ub = constr.rhs
150
+ type = GLPK::GLP_UP
151
+ end
152
+ GLPK.glp_set_row_bnds(@ptr, index, type, lb, ub)
153
+ end
154
+
155
+ # Save the variable to the model and update the variable pointers
156
+ def store_variable(var)
157
+ # Update the variable to track the index in the model
158
+ index = @var_count + 1
159
+ var.instance_variable_set :@model, self
160
+ var.instance_variable_set :@index, index
161
+ @var_count += 1
162
+
163
+ @variables << var
164
+
165
+ # Set variable properties
166
+ GLPK.glp_set_col_name(@ptr, index, var.name)
167
+ GLPK.glp_set_col_kind(@ptr, index, glpk_type(var.type))
168
+ GLPK.glp_set_obj_coef(@ptr, index, var.coefficient)
169
+ set_variable_bounds index, var.lower_bound, var.upper_bound
170
+ end
171
+
172
+ # Get the constant GLPK uses to represent our variable types
173
+ def glpk_type(type)
174
+ case type
175
+ when :integer
176
+ GLPK::GLP_IV
177
+ when :binary
178
+ GLPK::GLP_BV
179
+ when :continuous
180
+ GLPK::GLP_CV
181
+ else
182
+ fail type
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'glpk/ext'
2
+
3
+ require_relative 'glpk/model'
@@ -0,0 +1,25 @@
1
+ module MIPPeR
2
+ module Gurobi
3
+ class Environment
4
+ attr_reader :ptr
5
+
6
+ def initialize
7
+ # Create a new environment object
8
+ @ptr = FFI::MemoryPointer.new :pointer
9
+ Gurobi.GRBloadenv @ptr, nil
10
+ @ptr = @ptr.read_pointer
11
+
12
+ # Disable output
13
+ Gurobi.GRBsetintparam @ptr, Gurobi::GRB_INT_PAR_OUTPUTFLAG, 0
14
+
15
+ # Ensure the environment is freed
16
+ ObjectSpace.define_finalizer self, self.class.finalize(@ptr)
17
+ end
18
+
19
+ # Free the environment
20
+ def self.finalize(ptr)
21
+ proc { Gurobi.GRBfreeenv ptr }
22
+ end
23
+ end
24
+ end
25
+ end