guruby 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|