Class: Amor::Model

Inherits:
Object
  • Object
show all
Defined in:
lib/amor/model.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeModel

Returns a new instance of Model.



8
9
10
11
12
# File 'lib/amor/model.rb', line 8

def initialize
  @variables = Array.new
  @indices = Hash.new
  @constraints = Array.new
end

Instance Attribute Details

#blocksObject (readonly)

Returns the value of attribute blocks.



6
7
8
# File 'lib/amor/model.rb', line 6

def blocks
  @blocks
end

#boundedObject (readonly)

Returns the value of attribute bounded.



6
7
8
# File 'lib/amor/model.rb', line 6

def bounded
  @bounded
end

#constraintsObject (readonly)

Returns the value of attribute constraints.



6
7
8
# File 'lib/amor/model.rb', line 6

def constraints
  @constraints
end

#solvedObject (readonly)

Returns the value of attribute solved.



6
7
8
# File 'lib/amor/model.rb', line 6

def solved
  @solved
end

Class Method Details

.from_file(filename) ⇒ Object

Create a model from a file



64
65
66
# File 'lib/amor/model.rb', line 64

def self.from_file(filename)
  Model.from_string(File.read(filename))
end

.from_string(string) ⇒ Object

Create a model from a given string



57
58
59
60
61
# File 'lib/amor/model.rb', line 57

def self.from_string(string)
  model = Model.new
  model.instance_eval(string)
  return model
end

Instance Method Details

#binary(variable) ⇒ Object Also known as: bin



124
125
126
127
# File 'lib/amor/model.rb', line 124

def binary(variable)
  variable.type = :binary
  return variable
end

#blockObject

Creates a new block and makes sure that constraints added in yield are added to block



177
178
179
180
181
182
# File 'lib/amor/model.rb', line 177

def block
  (@blocks ||= Array.new) << Block.new
  @in_block = @blocks.last
  yield
  @in_block = nil
end

#dec_stringObject



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/amor/model.rb', line 184

def dec_string
  result = ["PRESOLVED 0", "NBLOCKS #{@blocks.size}"]

  @blocks.each_with_index do |block, i|
    result << block.dec_string(i + 1)
  end

  result << "MASTERCONSS"
  # Remaining constraints
  @blocks.inject(@constraints) {|mem, block| mem - block.constraints}.each do |constraint|
    result << constraint.lp_name
  end

  result.join("\n")
end

#for_all(container) ⇒ Object Also known as: forall



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

def for_all(container)
  container.each do |e|
    result = yield(e)
    if result.is_a?(Constraint)
      self.st result
    end
  end
  return nil
end

#gcgObject



204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/amor/model.rb', line 204

def gcg
  self.save_lp('__temp.lp')
  self.save_dec('__temp.dec')
  gcg_result = `gcg -f __temp.lp -d __temp.dec`
  File.open('gcg.log', 'w') {|file| file.puts gcg_result}
  File.delete('__temp.lp')
  File.delete('__temp.dec')

  parse_scip_output gcg_result

rescue Errno::ENOENT => e
  puts "Could not find GCG. Please make sure that GCG is installed and you can execute 'gcg'."
  raise e
end

#integer(variable) ⇒ Object Also known as: int



118
119
120
121
# File 'lib/amor/model.rb', line 118

def integer(variable)
  variable.type = :integer
  return variable
end

#internal_index(index) ⇒ Object



68
69
70
# File 'lib/amor/model.rb', line 68

def internal_index(index)
  @indices[index]
end

#lp_stringObject



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/amor/model.rb', line 72

def lp_string
  result = @objective.lp_string
  result << "\nSubject To\n"
  result << @constraints.each_with_index.map do |constraint, i|
    " #{constraint.lp_string}"
  end.join("\n")

  # Bounds section
  bounded_vars = @variables.each_with_index.select{|v| v[0].lb}
  result << "\nBounds" if bounded_vars.size > 0
  bounded_vars.each{|v| result << "\n 0 <= x#{v[1]+1}"}

  # Variable type section
  integer_vars = @variables.each_with_index.select{|v| v[0].type == :integer}
  result << "\nGenerals\n " if integer_vars.size > 0
  result << integer_vars.map{|v| "x#{v[1]+1}"}.join(" ")

  binary_vars = @variables.each_with_index.select{|v| v[0].type == :binary}
  result << "\nBinary\n " if binary_vars.size > 0
  result << binary_vars.map{|v| "x#{v[1]+1}"}.join(" ")

  result << "\nEnd"
  return result
end

#max(expression) ⇒ Object Also known as: maximize

Add a maximization objective



42
43
44
# File 'lib/amor/model.rb', line 42

def max(expression)
  @objective = Objective.new(:maximize, expression)
end

#min(expression) ⇒ Object Also known as: minimize

Add a minimization objective



36
37
38
# File 'lib/amor/model.rb', line 36

def min(expression)
  @objective = Objective.new(:minimize, expression)
end

#objectiveObject Also known as: obj



25
26
27
28
29
30
31
# File 'lib/amor/model.rb', line 25

def objective
  if @solved
    @objective_value
  else
    @objective
  end
end

#parse_scip_output(scip_result) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/amor/model.rb', line 148

def parse_scip_output(scip_result)
  solution_section = false
  scip_result.each_line do |line|
    if !@solved && line =~ /problem is solved \[([\w\s]*)\]/
      @solved = true
      if $1 == 'optimal solution found'
        @bounded = true
      elsif $1 == 'unbounded'
        @bounded = false
      elsif $1 == 'infeasible'
        @infeasible = true
      else
        raise "Unknown solve status: #{$1}"
      end
    end

    solution_section = true if line =~ /primal solution:/
    solution_section = false if line =~ /Statistics/n

    if solution_section
      @objective_value = $1 if line =~ /objective value:\s*([\.\d]+)/
      if line =~ /x(\d+)\s*([\.\d]+)/
        @variables[$1.to_i-1].value = $2.to_f
      end
    end
  end
end

#positive(variable) ⇒ Object



130
131
132
133
# File 'lib/amor/model.rb', line 130

def positive(variable)
  variable.lb = 0
  return variable
end

#save_dec(filename) ⇒ Object



200
201
202
# File 'lib/amor/model.rb', line 200

def save_dec(filename)
  File.open(filename, 'w') {|file| file.puts self.dec_string}
end

#save_lp(filename) ⇒ Object



97
98
99
# File 'lib/amor/model.rb', line 97

def save_lp(filename)
  File.open(filename, 'w') {|file| file.puts self.lp_string}
end

#scipObject



135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/amor/model.rb', line 135

def scip
  self.save_lp('__temp.lp')
  scip_result = `scip -f __temp.lp`
  File.open('scip.log', 'w') {|file| file.puts scip_result}
  File.delete('__temp.lp')

  parse_scip_output scip_result

rescue Errno::ENOENT => e
  puts "Could not find SCIP. Please make sure that SCIP is installed and you can execute 'scip'."
  raise e
end

#st(constraint) ⇒ Object Also known as: subject_to

Add a constraint



48
49
50
51
52
53
# File 'lib/amor/model.rb', line 48

def st(constraint)
  constraint.index = @constraints.size
  @constraints << constraint
  @in_block.add_constraint(constraint) if @in_block
  return constraint
end

#sum(container) ⇒ Object



112
113
114
115
116
# File 'lib/amor/model.rb', line 112

def sum(container)
  container[1..-1].inject(yield(container[0])) do |m, e|
    m + yield(e)
  end
end

#x(index) ⇒ Object Also known as: var

Return the variable for that index if already existing or a new one



15
16
17
18
19
20
21
22
# File 'lib/amor/model.rb', line 15

def x(index)
  variable = @variables[@indices[index] ||= @indices.size] ||= Variable.new(self, index)
  if @solved
    variable.value || 0
  else
    variable
  end
end