or-tools 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4c1a98e064635d769266167b02b577b491df6d60a26e55e422e03d914d566fd3
4
+ data.tar.gz: 8c034b6766e1b5cb8fe2839afff09c6fe595fb56ab7587f61eba67322ab4470e
5
+ SHA512:
6
+ metadata.gz: fdc91ed0bd1bc2b6ab1359a3dfad4a0ac0b68751886db1bed54a3b933198a9ead038238fdb9c0d2876a854b4885dbfe8d24f7f5ed540d34bb06c1033f4f3f897
7
+ data.tar.gz: 4eb55bac287388670459aaa37c9d0e9e8459da0a4328b98960dd9e315f9fd49279f1dacd7c9fdba6858c183deb8a56e9d0e958a5ac76eff19a1ae924b6e59d62
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ## 0.1.0 (2020-02-12)
2
+
3
+ - First release
data/LICENSE.txt ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
data/NOTICE.txt ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2020 Andrew Kane
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,246 @@
1
+ # OR-Tools
2
+
3
+ [OR-Tools](https://developers.google.com/optimization/) - operations research tools - for Ruby
4
+
5
+ ## Installation
6
+
7
+ Download the [OR-Tools C++ library](https://developers.google.com/optimization/install/cpp). Then run:
8
+
9
+ ```sh
10
+ bundle config build.or-tools --with-or-tools-dir=/path/to/or-tools
11
+ ```
12
+
13
+ Add this line to your application’s Gemfile:
14
+
15
+ ```ruby
16
+ gem 'or-tools'
17
+ ```
18
+
19
+ ## Getting Started
20
+
21
+ Constraint Optimization
22
+
23
+ - [CP-SAT Solver](#cp-sat-solver)
24
+
25
+ Bin Packing
26
+
27
+ - [The Knapsack Problem](#the-knapsack-problem)
28
+
29
+ Network Flows
30
+
31
+ - [Maximum Flows](#maximum-flows)
32
+ - [Minimum Cost Flows](#minimum-cost-flows)
33
+
34
+ ### CP-SAT Solver
35
+
36
+ [Guide](https://developers.google.com/optimization/cp/cp_solver)
37
+
38
+ Declare the model
39
+
40
+ ```ruby
41
+ model = ORTools::CpModel.new
42
+ ```
43
+
44
+ Create the variables
45
+
46
+ ```ruby
47
+ num_vals = 3
48
+ x = model.new_int_var(0, num_vals - 1, "x")
49
+ y = model.new_int_var(0, num_vals - 1, "y")
50
+ z = model.new_int_var(0, num_vals - 1, "z")
51
+ ```
52
+
53
+ Create the constraint
54
+
55
+ ```ruby
56
+ model.add_not_equal(x, y)
57
+ ```
58
+
59
+ Call the solver
60
+
61
+ ```ruby
62
+ solver = ORTools::CpSolver.new
63
+ status = solver.solve(model)
64
+ ```
65
+
66
+ Display the first solution
67
+
68
+ ```ruby
69
+ if status == :feasible
70
+ puts "x = #{solver.value(x)}"
71
+ puts "y = #{solver.value(y)}"
72
+ puts "z = #{solver.value(z)}"
73
+ end
74
+ ```
75
+
76
+ ### The Knapsack Problem
77
+
78
+ [Guide](https://developers.google.com/optimization/bin/knapsack)
79
+
80
+ Create the data
81
+
82
+ ```ruby
83
+ values = [
84
+ 360, 83, 59, 130, 431, 67, 230, 52, 93, 125, 670, 892, 600, 38, 48, 147,
85
+ 78, 256, 63, 17, 120, 164, 432, 35, 92, 110, 22, 42, 50, 323, 514, 28,
86
+ 87, 73, 78, 15, 26, 78, 210, 36, 85, 189, 274, 43, 33, 10, 19, 389, 276,
87
+ 312
88
+ ]
89
+ weights = [[
90
+ 7, 0, 30, 22, 80, 94, 11, 81, 70, 64, 59, 18, 0, 36, 3, 8, 15, 42, 9, 0,
91
+ 42, 47, 52, 32, 26, 48, 55, 6, 29, 84, 2, 4, 18, 56, 7, 29, 93, 44, 71,
92
+ 3, 86, 66, 31, 65, 0, 79, 20, 65, 52, 13
93
+ ]]
94
+ capacities = [850]
95
+ ```
96
+
97
+ Declare the solver
98
+
99
+ ```ruby
100
+ solver = ORTools::KnapsackSolver.new(:branch_and_bound, "KnapsackExample")
101
+ ```
102
+
103
+ Call the solver
104
+
105
+ ```ruby
106
+ solver.init(values, weights, capacities)
107
+ computed_value = solver.solve
108
+
109
+ packed_items = []
110
+ packed_weights = []
111
+ total_weight = 0
112
+ puts "Total value = #{computed_value}"
113
+ values.length.times do |i|
114
+ if solver.best_solution_contains?(i)
115
+ packed_items << i
116
+ packed_weights << weights[0][i]
117
+ total_weight += weights[0][i]
118
+ end
119
+ end
120
+ puts "Total weight: #{total_weight}"
121
+ puts "Packed items: #{packed_items}"
122
+ puts "Packed weights: #{packed_weights}"
123
+ ```
124
+
125
+ ### Maximum Flows
126
+
127
+ [Guide](https://developers.google.com/optimization/flow/maxflow)
128
+
129
+ Define the data
130
+
131
+ ```ruby
132
+ start_nodes = [0, 0, 0, 1, 1, 2, 2, 3, 3]
133
+ end_nodes = [1, 2, 3, 2, 4, 3, 4, 2, 4]
134
+ capacities = [20, 30, 10, 40, 30, 10, 20, 5, 20]
135
+ ```
136
+
137
+ Declare the solver and add the arcs
138
+
139
+ ```ruby
140
+ max_flow = ORTools::SimpleMaxFlow.new
141
+
142
+ start_nodes.length.times do |i|
143
+ max_flow.add_arc_with_capacity(start_nodes[i], end_nodes[i], capacities[i])
144
+ end
145
+ ```
146
+
147
+ Invoke the solver and display the results
148
+
149
+ ```ruby
150
+ if max_flow.solve(0, 4) == :optimal
151
+ puts "Max flow: #{max_flow.optimal_flow}"
152
+ puts
153
+ puts " Arc Flow / Capacity"
154
+ max_flow.num_arcs.times do |i|
155
+ puts "%1s -> %1s %3s / %3s" % [
156
+ max_flow.tail(i),
157
+ max_flow.head(i),
158
+ max_flow.flow(i),
159
+ max_flow.capacity(i)
160
+ ]
161
+ end
162
+ puts "Source side min-cut: #{max_flow.source_side_min_cut}"
163
+ puts "Sink side min-cut: #{max_flow.sink_side_min_cut}"
164
+ else
165
+ puts "There was an issue with the max flow input."
166
+ end
167
+ ```
168
+
169
+ ### Minimum Cost Flows
170
+
171
+ [Guide](https://developers.google.com/optimization/flow/mincostflow)
172
+
173
+ Define the data
174
+
175
+ ```ruby
176
+ start_nodes = [ 0, 0, 1, 1, 1, 2, 2, 3, 4]
177
+ end_nodes = [ 1, 2, 2, 3, 4, 3, 4, 4, 2]
178
+ capacities = [15, 8, 20, 4, 10, 15, 4, 20, 5]
179
+ unit_costs = [ 4, 4, 2, 2, 6, 1, 3, 2, 3]
180
+ supplies = [20, 0, 0, -5, -15]
181
+ ```
182
+
183
+ Declare the solver and add the arcs
184
+
185
+ ```ruby
186
+ min_cost_flow = ORTools::SimpleMinCostFlow.new
187
+
188
+ start_nodes.length.times do |i|
189
+ min_cost_flow.add_arc_with_capacity_and_unit_cost(
190
+ start_nodes[i], end_nodes[i], capacities[i], unit_costs[i]
191
+ )
192
+ end
193
+
194
+ supplies.length.times do |i|
195
+ min_cost_flow.set_node_supply(i, supplies[i])
196
+ end
197
+ ```
198
+
199
+ Invoke the solver and display the results
200
+
201
+ ```ruby
202
+ if min_cost_flow.solve == :optimal
203
+ puts "Minimum cost #{min_cost_flow.optimal_cost}"
204
+ puts
205
+ puts " Arc Flow / Capacity Cost"
206
+ min_cost_flow.num_arcs.times do |i|
207
+ cost = min_cost_flow.flow(i) * min_cost_flow.unit_cost(i)
208
+ puts "%1s -> %1s %3s / %3s %3s" % [
209
+ min_cost_flow.tail(i),
210
+ min_cost_flow.head(i),
211
+ min_cost_flow.flow(i),
212
+ min_cost_flow.capacity(i),
213
+ cost
214
+ ]
215
+ end
216
+ else
217
+ puts "There was an issue with the min cost flow input."
218
+ end
219
+ ```
220
+
221
+ ## History
222
+
223
+ View the [changelog](https://github.com/ankane/or-tools/blob/master/CHANGELOG.md)
224
+
225
+ ## Contributing
226
+
227
+ Everyone is encouraged to help improve this project. Here are a few ways you can help:
228
+
229
+ - [Report bugs](https://github.com/ankane/or-tools/issues)
230
+ - Fix bugs and [submit pull requests](https://github.com/ankane/or-tools/pulls)
231
+ - Write, clarify, or fix documentation
232
+ - Suggest or add new features
233
+
234
+ To get started with development:
235
+
236
+ ```sh
237
+ git clone https://github.com/ankane/or-tools.git
238
+ cd or-tools
239
+ bundle install
240
+ bundle exec rake compile -- --with-or-tools-dir=/path/to/or-tools
241
+ bundle exec rake test
242
+ ```
243
+
244
+ Resources
245
+
246
+ - [OR-Tools Reference](https://developers.google.com/optimization/reference)
@@ -0,0 +1,221 @@
1
+ // or-tools
2
+ #include <ortools/sat/cp_model.h>
3
+ #include <ortools/algorithms/knapsack_solver.h>
4
+ #include <ortools/graph/max_flow.h>
5
+ #include <ortools/graph/min_cost_flow.h>
6
+
7
+ // rice
8
+ #include <rice/Array.hpp>
9
+ #include <rice/Class.hpp>
10
+ #include <rice/Constructor.hpp>
11
+ #include <rice/Hash.hpp>
12
+ #include <rice/Module.hpp>
13
+ #include <rice/Symbol.hpp>
14
+
15
+ using operations_research::ArcIndex;
16
+ using operations_research::Domain;
17
+ using operations_research::FlowQuantity;
18
+ using operations_research::KnapsackSolver;
19
+ using operations_research::NodeIndex;
20
+ using operations_research::SimpleMaxFlow;
21
+ using operations_research::SimpleMinCostFlow;
22
+
23
+ using operations_research::sat::CpModelBuilder;
24
+ using operations_research::sat::CpSolverResponse;
25
+ using operations_research::sat::CpSolverStatus;
26
+ using operations_research::sat::IntVar;
27
+ using operations_research::sat::SolutionIntegerValue;
28
+
29
+ using Rice::Array;
30
+ using Rice::Constructor;
31
+ using Rice::Hash;
32
+ using Rice::Module;
33
+ using Rice::Object;
34
+ using Rice::Symbol;
35
+ using Rice::define_module;
36
+ using Rice::define_class_under;
37
+
38
+ template<>
39
+ inline
40
+ KnapsackSolver::SolverType from_ruby<KnapsackSolver::SolverType>(Object x)
41
+ {
42
+ std::string s = Symbol(x).str();
43
+ if (s == "branch_and_bound") {
44
+ return KnapsackSolver::KNAPSACK_MULTIDIMENSION_BRANCH_AND_BOUND_SOLVER;
45
+ } else {
46
+ throw std::runtime_error("Unknown solver type: " + s);
47
+ }
48
+ }
49
+
50
+ extern "C"
51
+ void Init_ext()
52
+ {
53
+ Module rb_mORTools = define_module("ORTools");
54
+
55
+ define_class_under<IntVar>(rb_mORTools, "IntVar");
56
+
57
+ define_class_under<CpModelBuilder>(rb_mORTools, "CpModel")
58
+ .define_constructor(Constructor<CpModelBuilder>())
59
+ .define_method(
60
+ "new_int_var",
61
+ *[](CpModelBuilder& self, int64 start, int64 end, std::string name) {
62
+ const Domain domain(start, end);
63
+ return self.NewIntVar(domain).WithName(name);
64
+ })
65
+ .define_method(
66
+ "add_not_equal",
67
+ *[](CpModelBuilder& self, IntVar x, IntVar y) {
68
+ // TODO return value
69
+ self.AddNotEqual(x, y);
70
+ });
71
+
72
+ define_class_under(rb_mORTools, "CpSolver")
73
+ .define_method(
74
+ "_solve",
75
+ *[](Object self, CpModelBuilder& model) {
76
+ return Solve(model.Build());
77
+ })
78
+ .define_method(
79
+ "_solution_integer_value",
80
+ *[](Object self, CpSolverResponse& response, IntVar& x) {
81
+ return SolutionIntegerValue(response, x);
82
+ });
83
+
84
+ define_class_under<CpSolverResponse>(rb_mORTools, "CpSolverResponse")
85
+ .define_method(
86
+ "status",
87
+ *[](CpSolverResponse& self) {
88
+ auto status = self.status();
89
+ if (status == CpSolverStatus::OPTIMAL) {
90
+ return Symbol("optimal");
91
+ } else if (status == CpSolverStatus::FEASIBLE) {
92
+ return Symbol("feasible");
93
+ } else if (status == CpSolverStatus::INFEASIBLE) {
94
+ return Symbol("infeasible");
95
+ } else if (status == CpSolverStatus::MODEL_INVALID) {
96
+ return Symbol("model_invalid");
97
+ } else {
98
+ throw std::runtime_error("Unknown solver status");
99
+ }
100
+ });
101
+
102
+ define_class_under<KnapsackSolver>(rb_mORTools, "KnapsackSolver")
103
+ .define_constructor(Constructor<KnapsackSolver, KnapsackSolver::SolverType, std::string>())
104
+ .define_method("_solve", &KnapsackSolver::Solve)
105
+ .define_method("best_solution_contains?", &KnapsackSolver::BestSolutionContains)
106
+ .define_method(
107
+ "init",
108
+ *[](KnapsackSolver& self, Array rb_values, Array rb_weights, Array rb_capacities) {
109
+ std::vector<int64> values;
110
+ for (std::size_t i = 0; i < rb_values.size(); ++i) {
111
+ values.push_back(from_ruby<int64>(rb_values[i]));
112
+ }
113
+
114
+ std::vector<std::vector<int64>> weights;
115
+ for (std::size_t i = 0; i < rb_weights.size(); ++i) {
116
+ Array rb_w = Array(rb_weights[i]);
117
+ std::vector<int64> w;
118
+ for (std::size_t j = 0; j < rb_w.size(); ++j) {
119
+ w.push_back(from_ruby<int64>(rb_w[j]));
120
+ }
121
+ weights.push_back(w);
122
+ }
123
+
124
+ std::vector<int64> capacities;
125
+ for (std::size_t i = 0; i < rb_capacities.size(); ++i) {
126
+ capacities.push_back(from_ruby<int64>(rb_capacities[i]));
127
+ }
128
+
129
+ self.Init(values, weights, capacities);
130
+ });
131
+
132
+ define_class_under<SimpleMaxFlow>(rb_mORTools, "SimpleMaxFlow")
133
+ .define_constructor(Constructor<SimpleMaxFlow>())
134
+ .define_method("add_arc_with_capacity", &SimpleMaxFlow::AddArcWithCapacity)
135
+ .define_method("num_nodes", &SimpleMaxFlow::NumNodes)
136
+ .define_method("num_arcs", &SimpleMaxFlow::NumArcs)
137
+ .define_method("tail", &SimpleMaxFlow::Tail)
138
+ .define_method("head", &SimpleMaxFlow::Head)
139
+ .define_method("capacity", &SimpleMaxFlow::Capacity)
140
+ .define_method("optimal_flow", &SimpleMaxFlow::OptimalFlow)
141
+ .define_method("flow", &SimpleMaxFlow::Flow)
142
+ .define_method(
143
+ "solve",
144
+ *[](SimpleMaxFlow& self, NodeIndex source, NodeIndex sink) {
145
+ auto status = self.Solve(source, sink);
146
+
147
+ if (status == SimpleMaxFlow::Status::OPTIMAL) {
148
+ return Symbol("optimal");
149
+ } else if (status == SimpleMaxFlow::Status::POSSIBLE_OVERFLOW) {
150
+ return Symbol("possible_overflow");
151
+ } else if (status == SimpleMaxFlow::Status::BAD_INPUT) {
152
+ return Symbol("bad_input");
153
+ } else if (status == SimpleMaxFlow::Status::BAD_RESULT) {
154
+ return Symbol("bad_result");
155
+ } else {
156
+ throw std::runtime_error("Unknown status");
157
+ }
158
+ })
159
+ .define_method(
160
+ "source_side_min_cut",
161
+ *[](SimpleMaxFlow& self) {
162
+ std::vector<NodeIndex> result;
163
+ self.GetSourceSideMinCut(&result);
164
+
165
+ Array ret;
166
+ for(auto const& it: result) {
167
+ ret.push(it);
168
+ }
169
+ return ret;
170
+ })
171
+ .define_method(
172
+ "sink_side_min_cut",
173
+ *[](SimpleMaxFlow& self) {
174
+ std::vector<NodeIndex> result;
175
+ self.GetSinkSideMinCut(&result);
176
+
177
+ Array ret;
178
+ for(auto const& it: result) {
179
+ ret.push(it);
180
+ }
181
+ return ret;
182
+ });
183
+
184
+ define_class_under<SimpleMinCostFlow>(rb_mORTools, "SimpleMinCostFlow")
185
+ .define_constructor(Constructor<SimpleMinCostFlow>())
186
+ .define_method("add_arc_with_capacity_and_unit_cost", &SimpleMinCostFlow::AddArcWithCapacityAndUnitCost)
187
+ .define_method("set_node_supply", &SimpleMinCostFlow::SetNodeSupply)
188
+ .define_method("optimal_cost", &SimpleMinCostFlow::OptimalCost)
189
+ .define_method("maximum_flow", &SimpleMinCostFlow::MaximumFlow)
190
+ .define_method("flow", &SimpleMinCostFlow::Flow)
191
+ .define_method("num_nodes", &SimpleMinCostFlow::NumNodes)
192
+ .define_method("num_arcs", &SimpleMinCostFlow::NumArcs)
193
+ .define_method("tail", &SimpleMinCostFlow::Tail)
194
+ .define_method("head", &SimpleMinCostFlow::Head)
195
+ .define_method("capacity", &SimpleMinCostFlow::Capacity)
196
+ .define_method("supply", &SimpleMinCostFlow::Supply)
197
+ .define_method("unit_cost", &SimpleMinCostFlow::UnitCost)
198
+ .define_method(
199
+ "solve",
200
+ *[](SimpleMinCostFlow& self) {
201
+ auto status = self.Solve();
202
+
203
+ if (status == SimpleMinCostFlow::Status::NOT_SOLVED) {
204
+ return Symbol("not_solved");
205
+ } else if (status == SimpleMinCostFlow::Status::OPTIMAL) {
206
+ return Symbol("optimal");
207
+ } else if (status == SimpleMinCostFlow::Status::FEASIBLE) {
208
+ return Symbol("feasible");
209
+ } else if (status == SimpleMinCostFlow::Status::INFEASIBLE) {
210
+ return Symbol("infeasible");
211
+ } else if (status == SimpleMinCostFlow::Status::UNBALANCED) {
212
+ return Symbol("unbalanced");
213
+ } else if (status == SimpleMinCostFlow::Status::BAD_RESULT) {
214
+ return Symbol("bad_result");
215
+ } else if (status == SimpleMinCostFlow::Status::BAD_COST_RANGE) {
216
+ return Symbol("bad_cost_range");
217
+ } else {
218
+ throw std::runtime_error("Unknown status");
219
+ }
220
+ });
221
+ }
@@ -0,0 +1,21 @@
1
+ require "mkmf-rice"
2
+
3
+ abort "Missing stdc++" unless have_library("stdc++")
4
+
5
+ $CXXFLAGS << " -std=c++11"
6
+
7
+ # or-tools warnings
8
+ $CXXFLAGS << " -Wno-sign-compare -Wno-shorten-64-to-32 -Wno-ignored-qualifiers"
9
+
10
+ inc, lib = dir_config("or-tools")
11
+
12
+ inc ||= "/usr/local/include"
13
+ lib ||= "/usr/local/lib"
14
+
15
+ $INCFLAGS << " -I#{inc}"
16
+
17
+ $LDFLAGS << " -Wl,-rpath,#{lib}"
18
+ $LDFLAGS << " -L#{lib}"
19
+ $LDFLAGS << " -lortools"
20
+
21
+ create_makefile("or_tools/ext")
data/lib/or-tools.rb ADDED
@@ -0,0 +1,11 @@
1
+ # ext
2
+ require "or_tools/ext"
3
+
4
+ # modules
5
+ require "or_tools/cp_solver"
6
+ require "or_tools/knapsack_solver"
7
+ require "or_tools/version"
8
+
9
+ module ORTools
10
+ class Error < StandardError; end
11
+ end
@@ -0,0 +1,12 @@
1
+ module ORTools
2
+ class CpSolver
3
+ def solve(model)
4
+ @response = _solve(model)
5
+ @response.status
6
+ end
7
+
8
+ def value(var)
9
+ _solution_integer_value(@response, var)
10
+ end
11
+ end
12
+ end
Binary file
@@ -0,0 +1,34 @@
1
+ module ORTools
2
+ class KnapsackSolver
3
+ def self.new(*args)
4
+ args = [:branch_and_bound, "KnapsackExample"] if args.empty?
5
+ super(*args)
6
+ end
7
+
8
+ def solve(*args)
9
+ return _solve if args.empty?
10
+
11
+ values, weights, capacities = *args
12
+ init(values, weights, capacities)
13
+ computed_value = _solve
14
+
15
+ packed_items = []
16
+ packed_weights = []
17
+ total_weight = 0
18
+ values.length.times do |i|
19
+ if best_solution_contains?(i)
20
+ packed_items << i
21
+ packed_weights << weights[0][i]
22
+ total_weight += weights[0][i]
23
+ end
24
+ end
25
+
26
+ {
27
+ total_value: computed_value,
28
+ total_weight: total_weight,
29
+ packed_items: packed_items,
30
+ packed_weights: packed_weights
31
+ }
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module ORTools
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: or-tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Kane
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-02-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rice
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '2.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '2.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake-compiler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '5'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '5'
83
+ description:
84
+ email: andrew@chartkick.com
85
+ executables: []
86
+ extensions:
87
+ - ext/or-tools/extconf.rb
88
+ extra_rdoc_files: []
89
+ files:
90
+ - CHANGELOG.md
91
+ - LICENSE.txt
92
+ - NOTICE.txt
93
+ - README.md
94
+ - ext/or-tools/ext.cpp
95
+ - ext/or-tools/extconf.rb
96
+ - lib/or-tools.rb
97
+ - lib/or_tools/cp_solver.rb
98
+ - lib/or_tools/ext.bundle
99
+ - lib/or_tools/knapsack_solver.rb
100
+ - lib/or_tools/version.rb
101
+ homepage: https://github.com/ankane/or-tools
102
+ licenses:
103
+ - MIT
104
+ metadata: {}
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '2.4'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubygems_version: 3.1.2
121
+ signing_key:
122
+ specification_version: 4
123
+ summary: Operations research tools for Ruby
124
+ test_files: []