Class: Rulp::Problem

Inherits:
Object show all
Defined in:
lib/rulp/rulp.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(objective, objective_expression) ⇒ Problem

Returns a new instance of Problem.



88
89
90
91
92
93
94
# File 'lib/rulp/rulp.rb', line 88

def initialize(objective, objective_expression)
  @variables = Set.new
  @objective = objective
  @lp_file = nil
  @constraints = []
  self.objective = objective_expression
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args) ⇒ Object



116
117
118
# File 'lib/rulp/rulp.rb', line 116

def method_missing(method_name, *args)
  self.call(method_name, *args)
end

Instance Attribute Details

#lp_fileObject

Returns the value of attribute lp_file.



86
87
88
# File 'lib/rulp/rulp.rb', line 86

def lp_file
  @lp_file
end

#resultObject

Returns the value of attribute result.



86
87
88
# File 'lib/rulp/rulp.rb', line 86

def result
  @result
end

#traceObject

Returns the value of attribute trace.



86
87
88
# File 'lib/rulp/rulp.rb', line 86

def trace
  @trace
end

Instance Method Details

#[](*constraints) ⇒ Object



101
102
103
104
105
106
107
108
109
110
# File 'lib/rulp/rulp.rb', line 101

def [](*constraints)
  Rulp.log(Logger::INFO, "Got constraints")
  constraints = constraints.flatten.select{|x| x.kind_of?(Constraint)}
  Rulp.log(Logger::INFO, "Flattened constraints")
  @constraints.concat(constraints)
  Rulp.log(Logger::INFO, "Joint constraints")
  @variables.merge(constraints.flat_map(&:variables).uniq)
  Rulp.log(Logger::INFO, "Extracted variables")
  self
end

#bitsObject



141
142
143
144
# File 'lib/rulp/rulp.rb', line 141

def bits
  bits = @variables.select{|x| x.kind_of?(BV) }.join(" ")
  return "\nBinary\n #{bits}" if(bits.length > 0)
end

#boundsObject



146
147
148
149
150
151
# File 'lib/rulp/rulp.rb', line 146

def bounds
  @variables.map{|var|
    next unless var.bounds
    " #{var.bounds}"
  }.compact.join("\n")
end

#call(using = nil, options = {}) ⇒ Object



125
126
127
# File 'lib/rulp/rulp.rb', line 125

def call(using=nil, options={})
  Rulp.send(self.solver(using), self, options)
end

#constraintsObject



129
130
131
132
133
134
# File 'lib/rulp/rulp.rb', line 129

def constraints
  return  "0 #{@variables.first} = 0" if @constraints.length == 0
  @constraints.each.with_index.map{|constraint, i|
    " c#{i}: #{constraint}\n"
  }.join
end

#get_output_filenameObject



153
154
155
# File 'lib/rulp/rulp.rb', line 153

def get_output_filename
  "/tmp/rulp-#{Random.rand(0..1000)}.lp"
end

#inspectObject



206
207
208
# File 'lib/rulp/rulp.rb', line 206

def inspect
  to_s
end

#integersObject



136
137
138
139
# File 'lib/rulp/rulp.rb', line 136

def integers
  ints = @variables.select{|x| x.kind_of?(IV) }.join(" ")
  return "\nGeneral\n #{ints}" if(ints.length > 0)
end

#objective=(objective_expression) ⇒ Object



96
97
98
99
# File 'lib/rulp/rulp.rb', line 96

def objective=(objective_expression)
  @objective_expression = objective_expression.kind_of?(LV) ? 1 * objective_expression : objective_expression
  @variables.merge(@objective_expression.variables)
end

#output(filename = choose_file) ⇒ Object Also known as: save



157
158
159
# File 'lib/rulp/rulp.rb', line 157

def output(filename=choose_file)
  IO.write(filename, self)
end

#solve(opts = {}) ⇒ Object



112
113
114
# File 'lib/rulp/rulp.rb', line 112

def solve(opts={})
  Rulp.send(self.solver, self, opts)
end

#solve_with(type, options = {}) ⇒ Object



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/rulp/rulp.rb', line 161

def solve_with(type, options={})

  filename = get_output_filename
  solver = SOLVERS[type].new(filename, options)

  Rulp.log(Logger::INFO, "Writing problem")
  IO.write(filename, self)

  Rulp.exec("open #{filename}") if options[:open_definition]

  Rulp.log(Logger::INFO, "Solving problem")
  self.trace, time = _profile{ solver.solve }

  Rulp.exec("open #{solver.outfile}") if options[:open_solution]

  Rulp.log(Logger::DEBUG, "Solver took #{time}")

  Rulp.log(Logger::INFO, "Parsing result")

  unless solver.outfile
    raise "No output file detected. Solver failed"
    return
  end

  solver.store_results(@variables)

  if solver.unsuccessful
    outfile_contents = IO.read(solver.outfile)
    raise "Solve failed: solution infeasible" if outfile_contents.downcase.include?("infeasible") || outfile_contents.strip.length.zero?
    raise "Solve failed: all units undefined"
  end

  if options[:remove_lp_file]
    solver.remove_lp_file
  else
    self.lp_file = solver.filename
  end
  solver.remove_sol_file if options[:remove_sol_file]

  self.result = @objective_expression.evaluate

  Rulp.log(Logger::DEBUG, "Objective: #{result}\n#{@variables.map{|v|[v.name, "=", v.value].join(' ') if v.value}.compact.join("\n")}")
  return self.result
end

#solver(solver = nil) ⇒ Object



120
121
122
123
# File 'lib/rulp/rulp.rb', line 120

def solver(solver=nil)
  solver = solver || ENV["SOLVER"] || "Scip"
  solver = solver[0].upcase + solver[1..-1].downcase
end

#to_sObject



220
221
222
223
224
225
226
227
228
229
230
# File 'lib/rulp/rulp.rb', line 220

def to_s
  %Q(
#{'  '*0}#{@objective}
#{'  '*0} obj: #{@objective_expression}
#{'  '*0}Subject to
#{'  '*0}#{constraints}
#{'  '*0}Bounds
#{'  '*0}#{bounds}#{integers}#{bits}
#{'  '*0}End
  )
end

#write(output) ⇒ Object



210
211
212
213
214
215
216
217
218
# File 'lib/rulp/rulp.rb', line 210

def write(output)
  output.puts "#{@objective}"
  output.puts " obj: #{@objective_expression}"
  output.puts "Subject to"
  output.puts "#{constraints}"
  output.puts "Bounds"
  output.puts "#{bounds}#{integers}#{bits}"
  output.puts "End"
end