opt-rb 0.1.0 → 0.1.2
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 +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +31 -22
- data/lib/opt/expression.rb +7 -0
- data/lib/opt/problem.rb +14 -4
- data/lib/opt/product.rb +6 -0
- data/lib/opt/semi_continuous.rb +4 -0
- data/lib/opt/semi_integer.rb +4 -0
- data/lib/opt/solvers/abstract_solver.rb +8 -0
- data/lib/opt/solvers/highs_solver.rb +20 -1
- data/lib/opt/version.rb +1 -1
- data/lib/opt.rb +2 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36273c4c91e9009dd5f1b754e6d1c01fc0e4188a4ceeac85f1e9cbb76ec27274
|
4
|
+
data.tar.gz: 8b664c75defb3b7394ddef0c64bf6a743e8012eadbf8f6f2ccabff1dda67bec4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 388019490f5b877034117d3013bc41af1f633ba4762ab742b1b327386e0bed75277b9e1e3c70e0c5e82ea3c6578f22c89c46157173b5c81c2425a03afa66e853
|
7
|
+
data.tar.gz: 15dc32d76e91f2d80022427beca9f54709b894def409b877e172bea64b2f927a94071657368fc09abc8eee53b88e3c77d4129c0d946cfdb4a76aeb46fb890656
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
:fire: Convex optimization for Ruby
|
4
4
|
|
5
|
-
Supports
|
5
|
+
Supports Cbc, Clp, GLOP, GLPK, HiGHS, OSQP, and SCS
|
6
6
|
|
7
7
|
[](https://github.com/ankane/opt/actions)
|
8
8
|
|
@@ -14,15 +14,19 @@ Add this line to your application’s Gemfile:
|
|
14
14
|
gem "opt-rb"
|
15
15
|
```
|
16
16
|
|
17
|
-
And install
|
17
|
+
And install one or more solvers based on your problem types:
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
19
|
+
Solver | LP | QP | MIP | License
|
20
|
+
--- | --- | --- | --- | ---
|
21
|
+
[Cbc](https://github.com/ankane/cbc-ruby) | ✓ | | ✓ | EPL-2.0
|
22
|
+
[Clp](https://github.com/ankane/clp-ruby) | ✓ | | | EPL-2.0
|
23
|
+
[GLOP](https://github.com/ankane/or-tools-ruby) | ✓ | | | Apache-2.0
|
24
|
+
[GLPK](https://github.com/ankane/glpk-ruby) | ✓ | | ✓ | GPL-3.0-or-later
|
25
|
+
[HiGHS](https://github.com/ankane/highs-ruby) | ✓ | ✓ | ✓ | MIT
|
26
|
+
[OSQP](https://github.com/ankane/osqp-ruby) | ✓ | ✓ | | Apache-2.0
|
27
|
+
[SCS](https://github.com/ankane/scs-ruby) | ✓ | * | | MIT
|
28
|
+
|
29
|
+
\* supports, but not implemented yet
|
26
30
|
|
27
31
|
## Getting Started
|
28
32
|
|
@@ -46,29 +50,34 @@ Get the value of a variable
|
|
46
50
|
x1.value
|
47
51
|
```
|
48
52
|
|
53
|
+
QP
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
prob.minimize(x1 * x1)
|
57
|
+
```
|
58
|
+
|
49
59
|
MIP
|
50
60
|
|
51
61
|
```ruby
|
52
62
|
x1 = Opt::Integer.new(0.., "x1")
|
53
|
-
|
63
|
+
x2 = Opt::Binary.new("x2")
|
54
64
|
```
|
55
65
|
|
56
|
-
|
57
|
-
|
58
|
-
Solver | LP | QP | MIP | License
|
59
|
-
--- | --- | --- | --- | ---
|
60
|
-
Cbc | ✓ | | ✓ | EPL-2.0
|
61
|
-
Clp | ✓ | | | EPL-2.0
|
62
|
-
GLOP | ✓ | | | Apache-2.0
|
63
|
-
GLPK | ✓ | | ✓ | GPL-3.0-or-later
|
64
|
-
HiGHS | ✓ | ✓ | ✓ | MIT
|
65
|
-
OSQP | ✓ | ✓ | | Apache-2.0
|
66
|
-
SCS | ✓ | * | | MIT
|
66
|
+
MIP with semi-continuous variables - *HiGHS only at the moment* [unreleased]
|
67
67
|
|
68
|
-
|
68
|
+
```ruby
|
69
|
+
x1 = Opt::SemiContinuous.new(2.., "x1")
|
70
|
+
x2 = Opt::SemiInteger.new(2.., "x2")
|
71
|
+
```
|
69
72
|
|
70
73
|
## Reference
|
71
74
|
|
75
|
+
Specify the solver
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
prob.solve(solver: :cbc)
|
79
|
+
```
|
80
|
+
|
72
81
|
Enable verbose logging
|
73
82
|
|
74
83
|
```ruby
|
data/lib/opt/expression.rb
CHANGED
data/lib/opt/problem.rb
CHANGED
@@ -27,7 +27,10 @@ module Opt
|
|
27
27
|
|
28
28
|
vars = self.vars
|
29
29
|
raise Error, "No variables" if vars.empty?
|
30
|
-
|
30
|
+
has_semi_continuous_var = vars.any? { |v| v.is_a?(SemiContinuous) }
|
31
|
+
has_semi_integer_var = vars.any? { |v| v.is_a?(SemiInteger) }
|
32
|
+
has_integer_var = vars.any? { |v| v.is_a?(Integer) }
|
33
|
+
type = has_semi_continuous_var || has_semi_integer_var || has_integer_var ? :mip : :lp
|
31
34
|
quadratic = @indexed_objective.any? { |k, _| k.is_a?(Array) }
|
32
35
|
|
33
36
|
if quadratic
|
@@ -37,13 +40,16 @@ module Opt
|
|
37
40
|
|
38
41
|
raise Error, "No solvers found" if Opt.available_solvers.empty?
|
39
42
|
|
40
|
-
solver ||= (Opt.default_solvers[type] || Opt.available_solvers.find { |s| s.supports_type?(type) })
|
43
|
+
solver ||= (Opt.default_solvers[type] || Opt.available_solvers.find { |s| Opt.solvers[s].supports_type?(type) })
|
41
44
|
raise Error, "No solvers found for #{type}" unless solver
|
42
45
|
|
43
46
|
# TODO better error message
|
44
47
|
solver_cls = Opt.solvers.fetch(solver)
|
45
48
|
raise Error, "Solver does not support #{type}" unless solver_cls.supports_type?(type)
|
46
49
|
|
50
|
+
raise Error, "Solver does not support semi-continuous variables" if has_semi_continuous_var && !solver_cls.supports_semi_continuous_variables?
|
51
|
+
raise Error, "Solver does not support semi-integer variables" if has_semi_integer_var && !solver_cls.supports_semi_integer_variables?
|
52
|
+
|
47
53
|
col_lower = []
|
48
54
|
col_upper = []
|
49
55
|
obj = []
|
@@ -54,7 +60,8 @@ module Opt
|
|
54
60
|
col_lower << (var.bounds.begin || -Float::INFINITY)
|
55
61
|
upper = var.bounds.end
|
56
62
|
if upper && var.bounds.exclude_end?
|
57
|
-
|
63
|
+
case var
|
64
|
+
when Integer, SemiInteger
|
58
65
|
upper -= 1
|
59
66
|
else
|
60
67
|
upper -= Float::EPSILON
|
@@ -117,7 +124,7 @@ module Opt
|
|
117
124
|
case a
|
118
125
|
when Binary
|
119
126
|
b.round != 0
|
120
|
-
when Integer
|
127
|
+
when Integer, SemiInteger
|
121
128
|
b.round
|
122
129
|
else
|
123
130
|
b
|
@@ -149,6 +156,9 @@ module Opt
|
|
149
156
|
else
|
150
157
|
"#{var.name} #{end_op} #{bounds.end}"
|
151
158
|
end
|
159
|
+
if var.is_a?(SemiContinuous) || var.is_a?(SemiInteger)
|
160
|
+
var_str = "#{var_str} or #{var.name} = 0"
|
161
|
+
end
|
152
162
|
str << " #{var_str}\n"
|
153
163
|
end
|
154
164
|
str
|
data/lib/opt/product.rb
CHANGED
@@ -19,7 +19,7 @@ module Opt
|
|
19
19
|
a_index: index,
|
20
20
|
a_value: value,
|
21
21
|
offset: offset,
|
22
|
-
integrality: vars.map { |
|
22
|
+
integrality: vars.map { |var| integrality(var) }
|
23
23
|
)
|
24
24
|
when :qp
|
25
25
|
q_start = []
|
@@ -80,6 +80,17 @@ module Opt
|
|
80
80
|
}
|
81
81
|
end
|
82
82
|
|
83
|
+
private
|
84
|
+
|
85
|
+
def integrality(var)
|
86
|
+
case var
|
87
|
+
when SemiInteger then 3
|
88
|
+
when SemiContinuous then 2
|
89
|
+
when Integer then 1
|
90
|
+
else 0
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
83
94
|
def self.available?
|
84
95
|
defined?(Highs)
|
85
96
|
end
|
@@ -87,6 +98,14 @@ module Opt
|
|
87
98
|
def self.supported_types
|
88
99
|
[:lp, :qp, :mip]
|
89
100
|
end
|
101
|
+
|
102
|
+
def self.supports_semi_continuous_variables?
|
103
|
+
true
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.supports_semi_integer_variables?
|
107
|
+
true
|
108
|
+
end
|
90
109
|
end
|
91
110
|
end
|
92
111
|
end
|
data/lib/opt/version.rb
CHANGED
data/lib/opt.rb
CHANGED
@@ -5,6 +5,8 @@ require_relative "opt/constant"
|
|
5
5
|
require_relative "opt/variable"
|
6
6
|
require_relative "opt/integer"
|
7
7
|
require_relative "opt/binary"
|
8
|
+
require_relative "opt/semi_continuous"
|
9
|
+
require_relative "opt/semi_integer"
|
8
10
|
require_relative "opt/problem"
|
9
11
|
require_relative "opt/product"
|
10
12
|
require_relative "opt/version"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opt-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email: andrew@ankane.org
|
@@ -28,6 +28,8 @@ files:
|
|
28
28
|
- lib/opt/integer.rb
|
29
29
|
- lib/opt/problem.rb
|
30
30
|
- lib/opt/product.rb
|
31
|
+
- lib/opt/semi_continuous.rb
|
32
|
+
- lib/opt/semi_integer.rb
|
31
33
|
- lib/opt/solvers/abstract_solver.rb
|
32
34
|
- lib/opt/solvers/cbc_solver.rb
|
33
35
|
- lib/opt/solvers/clp_solver.rb
|
@@ -57,7 +59,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
59
|
- !ruby/object:Gem::Version
|
58
60
|
version: '0'
|
59
61
|
requirements: []
|
60
|
-
rubygems_version: 3.4.
|
62
|
+
rubygems_version: 3.4.10
|
61
63
|
signing_key:
|
62
64
|
specification_version: 4
|
63
65
|
summary: Convex optimization for Ruby
|