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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 300747a1f97ca67851cda0264f649d1e7e0a4f126609c658efb4f3fc509f14f7
4
- data.tar.gz: 87fdcba2ec49277f3491f9a61b04ae74107b1df77d13c81392f63cf58989194f
3
+ metadata.gz: 36273c4c91e9009dd5f1b754e6d1c01fc0e4188a4ceeac85f1e9cbb76ec27274
4
+ data.tar.gz: 8b664c75defb3b7394ddef0c64bf6a743e8012eadbf8f6f2ccabff1dda67bec4
5
5
  SHA512:
6
- metadata.gz: 1c850b8f467bb5b0b9f1fc7a960db0232a2cddd26a129fa8db072b7701e4ccd6ddb0fa828042f16bb4d6263e05c2ea856796648ad7f2619971bca559afc97749
7
- data.tar.gz: 99e1b9798bb609fe56b844f21df02578e44984885076a631590569c47fc979c51113098c57f667ffccfbc4f86d91784bdd98eec7fc23ee9e5c38a9cc65ccabf3
6
+ metadata.gz: 388019490f5b877034117d3013bc41af1f633ba4762ab742b1b327386e0bed75277b9e1e3c70e0c5e82ea3c6578f22c89c46157173b5c81c2425a03afa66e853
7
+ data.tar.gz: 15dc32d76e91f2d80022427beca9f54709b894def409b877e172bea64b2f927a94071657368fc09abc8eee53b88e3c77d4129c0d946cfdb4a76aeb46fb890656
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 0.1.2 (2023-05-01)
2
+
3
+ - Added `value` method for expressions
4
+ - Fixed error selecting solver
5
+
6
+ ## 0.1.1 (2023-04-16)
7
+
8
+ - Added support for semi-continuous and semi-integer variables
9
+
1
10
  ## 0.1.0 (2023-01-25)
2
11
 
3
12
  - First release
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  :fire: Convex optimization for Ruby
4
4
 
5
- Supports [Cbc](https://github.com/ankane/cbc-ruby), [Clp](https://github.com/ankane/clp-ruby), [GLOP](https://github.com/ankane/or-tools-ruby), [GLPK](https://github.com/ankane/glpk-ruby), [HiGHS](https://github.com/ankane/highs-ruby), [OSQP](https://github.com/ankane/osqp-ruby), and [SCS](https://github.com/ankane/scs-ruby)
5
+ Supports Cbc, Clp, GLOP, GLPK, HiGHS, OSQP, and SCS
6
6
 
7
7
  [![Build Status](https://github.com/ankane/opt/workflows/build/badge.svg?branch=master)](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 a solver:
17
+ And install one or more solvers based on your problem types:
18
18
 
19
- - [Cbc](https://github.com/ankane/cbc-ruby#installation)
20
- - [Clp](https://github.com/ankane/clp-ruby#installation)
21
- - [GLOP](https://github.com/ankane/or-tools-ruby#installation)
22
- - [GLPK](https://github.com/ankane/glpk-ruby#installation)
23
- - [HiGHS](https://github.com/ankane/highs-ruby#installation)
24
- - [OSQP](https://github.com/ankane/osqp-ruby#installation)
25
- - [SCS](https://github.com/ankane/scs-ruby#installation)
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
- x1 = Opt::Binary.new("x1")
63
+ x2 = Opt::Binary.new("x2")
54
64
  ```
55
65
 
56
- ## Problem Types
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
- \* supports, but not implemented yet
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
@@ -57,6 +57,13 @@ module Opt
57
57
  end
58
58
  end
59
59
 
60
+ def value
61
+ values = parts.map(&:value)
62
+ return nil if values.any?(&:nil?)
63
+
64
+ values.sum
65
+ end
66
+
60
67
  def vars
61
68
  @vars ||= @parts.flat_map(&:vars)
62
69
  end
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
- type = vars.any? { |v| v.is_a?(Integer) } ? :mip : :lp
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
- if var.is_a?(Integer)
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
@@ -11,6 +11,12 @@ module Opt
11
11
  "#{inspect_part(@left)} * #{inspect_part(@right)}"
12
12
  end
13
13
 
14
+ def value
15
+ return nil if left.value.nil? || right.value.nil?
16
+
17
+ left.value * right.value
18
+ end
19
+
14
20
  def vars
15
21
  @vars ||= (@left.vars + @right.vars).uniq
16
22
  end
@@ -0,0 +1,4 @@
1
+ module Opt
2
+ class SemiContinuous < Variable
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Opt
2
+ class SemiInteger < Variable
3
+ end
4
+ end
@@ -4,6 +4,14 @@ module Opt
4
4
  def self.supports_type?(type)
5
5
  supported_types.include?(type)
6
6
  end
7
+
8
+ def self.supports_semi_continuous_variables?
9
+ false
10
+ end
11
+
12
+ def self.supports_semi_integer_variables?
13
+ false
14
+ end
7
15
  end
8
16
  end
9
17
  end
@@ -19,7 +19,7 @@ module Opt
19
19
  a_index: index,
20
20
  a_value: value,
21
21
  offset: offset,
22
- integrality: vars.map { |v| v.is_a?(Integer) ? 1 : 0 }
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
@@ -1,3 +1,3 @@
1
1
  module Opt
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.2"
3
3
  end
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.0
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-01-26 00:00:00.000000000 Z
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.1
62
+ rubygems_version: 3.4.10
61
63
  signing_key:
62
64
  specification_version: 4
63
65
  summary: Convex optimization for Ruby