guruby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/guruby.rb +5 -0
- data/lib/guruby/constr.rb +12 -0
- data/lib/guruby/env.rb +25 -0
- data/lib/guruby/expr.rb +35 -0
- data/lib/guruby/ext.rb +8 -0
- data/lib/guruby/ext/constants.rb +1899 -0
- data/lib/guruby/ext/gurobi.rb +37 -0
- data/lib/guruby/model.rb +121 -0
- data/lib/guruby/var.rb +88 -0
- metadata +67 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Gurobi
|
4
|
+
extend FFI::Library
|
5
|
+
ffi_lib File.join(ENV['GUROBI_HOME'], 'lib/libgurobi56.so')
|
6
|
+
|
7
|
+
attach_function :GRBloadenv, [:pointer, :string], :int
|
8
|
+
attach_function :GRBsetintparam, [:pointer, :string, :int], :int
|
9
|
+
attach_function :GRBgeterrormsg, [:pointer], :string
|
10
|
+
attach_function :GRBfreeenv, [:pointer], :void
|
11
|
+
|
12
|
+
attach_function :GRBnewmodel, [:pointer, :pointer, :string, :int,
|
13
|
+
:pointer, :pointer, :pointer, :pointer,
|
14
|
+
:pointer], :int
|
15
|
+
attach_function :GRBupdatemodel, [:pointer], :int
|
16
|
+
attach_function :GRBfreemodel, [:pointer], :int
|
17
|
+
|
18
|
+
attach_function :GRBaddvar, [:pointer, :int, :pointer, :pointer,
|
19
|
+
:double, :double, :double, :char, :string], :int
|
20
|
+
attach_function :GRBaddvars, [:pointer, :int, :int, :pointer, :pointer,
|
21
|
+
:pointer, :pointer, :pointer, :pointer,
|
22
|
+
:pointer, :pointer], :int
|
23
|
+
attach_function :GRBaddconstr, [:pointer, :int, :pointer, :pointer, :char,
|
24
|
+
:double, :string], :int
|
25
|
+
attach_function :GRBoptimize, [:pointer], :int
|
26
|
+
attach_function :GRBcomputeIIS, [:pointer], :int
|
27
|
+
attach_function :GRBwrite, [:pointer, :string], :int
|
28
|
+
|
29
|
+
attach_function :GRBsetintattr, [:pointer, :string, :int], :int
|
30
|
+
|
31
|
+
attach_function :GRBgetintattr, [:pointer, :string, :pointer], :int
|
32
|
+
attach_function :GRBgetdblattr, [:pointer, :string, :pointer], :int
|
33
|
+
attach_function :GRBgetdblattrarray, [:pointer, :string, :int, :int,
|
34
|
+
:pointer], :int
|
35
|
+
attach_function :GRBsetdblattrarray, [:pointer, :string, :int, :int,
|
36
|
+
:pointer], :int
|
37
|
+
end
|
data/lib/guruby/model.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
require_relative 'ext'
|
2
|
+
|
3
|
+
module Guruby
|
4
|
+
class Model
|
5
|
+
attr_reader :ptr, :environment, :variables, :constraints
|
6
|
+
|
7
|
+
def initialize(env)
|
8
|
+
@environment = env
|
9
|
+
|
10
|
+
@ptr = FFI::MemoryPointer.new :pointer
|
11
|
+
Gurobi.GRBnewmodel env.ptr, @ptr, 'model', 0, nil, nil, nil, nil, nil
|
12
|
+
@ptr = @ptr.read_pointer
|
13
|
+
|
14
|
+
# Ensure the model is freed
|
15
|
+
ObjectSpace.define_finalizer self, self.class.finalize(@ptr)
|
16
|
+
|
17
|
+
@var_count = 0
|
18
|
+
@variables = []
|
19
|
+
@constraints = []
|
20
|
+
end
|
21
|
+
|
22
|
+
# Add new objects (variables and constraints) to the model
|
23
|
+
def <<(obj)
|
24
|
+
case obj
|
25
|
+
when Variable
|
26
|
+
add_variable obj
|
27
|
+
when Constraint
|
28
|
+
add_constraint obj
|
29
|
+
else
|
30
|
+
fail TypeError
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Update the model
|
35
|
+
def update
|
36
|
+
ret = Gurobi.GRBupdatemodel @ptr
|
37
|
+
fail if ret != 0
|
38
|
+
end
|
39
|
+
|
40
|
+
# Write the model to a file
|
41
|
+
def write(filename)
|
42
|
+
Gurobi.GRBwrite @ptr, filename
|
43
|
+
end
|
44
|
+
|
45
|
+
# Set the sense of the model
|
46
|
+
def set_sense(sense)
|
47
|
+
ret = Gurobi.GRBsetintattr @ptr, GRB_INT_ATTR_MODELSENSE, sense
|
48
|
+
fail if ret != 0
|
49
|
+
end
|
50
|
+
|
51
|
+
# Optimize the model
|
52
|
+
def optimize
|
53
|
+
ret = Gurobi.GRBoptimize @ptr
|
54
|
+
fail if ret != 0
|
55
|
+
end
|
56
|
+
|
57
|
+
# Get the status of the model
|
58
|
+
def status
|
59
|
+
intptr = FFI::MemoryPointer.new :pointer
|
60
|
+
ret = Gurobi.GRBgetintattr @ptr, GRB_INT_ATTR_STATUS, intptr
|
61
|
+
fail if ret != 0
|
62
|
+
intptr.read_int
|
63
|
+
end
|
64
|
+
|
65
|
+
# Compute an irreducible inconsistent subsytem for the model
|
66
|
+
def compute_IIS
|
67
|
+
ret = Gurobi.GRBcomputeIIS @ptr
|
68
|
+
fail if ret != 0
|
69
|
+
end
|
70
|
+
|
71
|
+
# The value of the objective function
|
72
|
+
def objective_value
|
73
|
+
dblptr = FFI::MemoryPointer.new :pointer
|
74
|
+
ret = Gurobi.GRBgetdblattr @ptr, GRB_DBL_ATTR_OBJVAL, dblptr
|
75
|
+
fail if ret != 0
|
76
|
+
dblptr.read_double
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
# Free the model
|
82
|
+
def self.finalize(ptr)
|
83
|
+
proc { Gurobi.GRBfreemodel ptr }
|
84
|
+
end
|
85
|
+
|
86
|
+
# Add a new variable to the model
|
87
|
+
def add_variable(var)
|
88
|
+
ret = Gurobi.GRBaddvar @ptr, 0, nil, nil, var.coefficient,
|
89
|
+
var.lower_bound, var.upper_bound,
|
90
|
+
var.type.ord, var.name
|
91
|
+
fail if ret != 0
|
92
|
+
|
93
|
+
# Update the variable to track the index in the model
|
94
|
+
var.instance_variable_set :@model, self
|
95
|
+
var.instance_variable_set :@index, @var_count
|
96
|
+
@var_count += 1
|
97
|
+
|
98
|
+
@variables << var
|
99
|
+
end
|
100
|
+
|
101
|
+
# Add a new constraint to the model
|
102
|
+
def add_constraint(constr)
|
103
|
+
terms = constr.expression.terms
|
104
|
+
indexes_buffer = FFI::MemoryPointer.new :int, terms.length
|
105
|
+
indexes_buffer.write_array_of_int(terms.each_key.map do |var|
|
106
|
+
var.instance_variable_get(:@index)
|
107
|
+
end)
|
108
|
+
|
109
|
+
values_buffer = FFI::MemoryPointer.new :double, terms.length
|
110
|
+
values_buffer.write_array_of_double terms.values
|
111
|
+
|
112
|
+
ret = Gurobi.GRBaddconstr @ptr, terms.length,
|
113
|
+
indexes_buffer, values_buffer,
|
114
|
+
constr.sense.ord, constr.rhs, constr.name
|
115
|
+
fail if ret != 0
|
116
|
+
|
117
|
+
@constraints << constr
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
data/lib/guruby/var.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
module Guruby
|
2
|
+
class Variable
|
3
|
+
attr_reader :lower_bound, :upper_bound, :coefficient, :type, :name, :model
|
4
|
+
|
5
|
+
def initialize(lb, ub, coeff, type, name = nil)
|
6
|
+
@lower_bound = lb
|
7
|
+
@upper_bound = ub
|
8
|
+
@coefficient = coeff
|
9
|
+
@type = type
|
10
|
+
@name = name
|
11
|
+
|
12
|
+
# These will be populated when this is added to a model
|
13
|
+
@model = nil
|
14
|
+
@index = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
# Set the variable lower bound
|
18
|
+
def lower_bound=(lb)
|
19
|
+
set_double_attribute GRB_DBL_ATTR_LB, lb
|
20
|
+
@lower_bound = lb
|
21
|
+
end
|
22
|
+
|
23
|
+
# Set the variable upper bound
|
24
|
+
def upper_bound=(ub)
|
25
|
+
set_double_attribute GRB_DBL_ATTR_UB, ub
|
26
|
+
@upper_bound = ub
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get the final value of this variable
|
30
|
+
def value
|
31
|
+
# Model must be solved to have a value
|
32
|
+
return nil unless @model && @model.status == GRB_OPTIMAL
|
33
|
+
|
34
|
+
dblptr = FFI::MemoryPointer.new :pointer
|
35
|
+
Gurobi::GRBgetdblattrarray @model.instance_variable_get(:@ptr),
|
36
|
+
GRB_DBL_ATTR_X, @index, 1, dblptr
|
37
|
+
value = dblptr.read_array_of_double(1)[0]
|
38
|
+
|
39
|
+
case @type
|
40
|
+
when GRB_INTEGER
|
41
|
+
value.round
|
42
|
+
when GRB_BINARY
|
43
|
+
[false, true][value.round]
|
44
|
+
else
|
45
|
+
value
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Create a {LinExpr} consisting of a single term
|
50
|
+
# which is this variable multiplied by a constant
|
51
|
+
def *(coeff)
|
52
|
+
fail TypeError unless coeff.is_a? Numeric
|
53
|
+
|
54
|
+
LinExpr.new({ self => coeff })
|
55
|
+
end
|
56
|
+
|
57
|
+
def +(other)
|
58
|
+
case other
|
59
|
+
when LinExpr
|
60
|
+
other + self * 1
|
61
|
+
when Variable
|
62
|
+
self * 1 + other * 1
|
63
|
+
else
|
64
|
+
fail TypeError
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Produce the name of the variable and the value if the model is solved
|
69
|
+
def inspect
|
70
|
+
if @model && @model.status == GRB_OPTIMAL
|
71
|
+
value = self.value
|
72
|
+
else
|
73
|
+
value = '?'
|
74
|
+
end
|
75
|
+
|
76
|
+
"#{@name} = #{value}"
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def set_double_attribute(name, value)
|
82
|
+
buffer = FFI::MemoryPointer.new :double, 1
|
83
|
+
buffer.write_array_of_double [value]
|
84
|
+
ret = Gurobi.GRBsetdblattrarray model.ptr, name, @index, 1, buffer
|
85
|
+
fail if ret != 0
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: guruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Mior
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-08-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.9'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.9'
|
27
|
+
description: Guruby is a Ruby interface to the Gurobi solver
|
28
|
+
email: michael.mior@gmail.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- lib/guruby.rb
|
34
|
+
- lib/guruby/constr.rb
|
35
|
+
- lib/guruby/env.rb
|
36
|
+
- lib/guruby/expr.rb
|
37
|
+
- lib/guruby/ext.rb
|
38
|
+
- lib/guruby/ext/constants.rb
|
39
|
+
- lib/guruby/ext/gurobi.rb
|
40
|
+
- lib/guruby/model.rb
|
41
|
+
- lib/guruby/var.rb
|
42
|
+
homepage: https://github.com/michaelmior/guruby
|
43
|
+
licenses:
|
44
|
+
- GPLv3
|
45
|
+
metadata: {}
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
requirements: []
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 2.4.6
|
63
|
+
signing_key:
|
64
|
+
specification_version: 4
|
65
|
+
summary: A Ruby interface to the Gurobi solver
|
66
|
+
test_files: []
|
67
|
+
has_rdoc:
|