cbc 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: 1d3dcf4c5bbcc2757b6b06c4e15dfcd898bc345b1b15b5633f760e0d3539e607
4
+ data.tar.gz: a939b6d0d0b8694c5e6e8d3f8d737a07a263dc1decbb1cc0cedcf3795567fda9
5
+ SHA512:
6
+ metadata.gz: 608d2f2389cf608e34be2ad1675016177630c28d95fcc3c6ad2643c7a45bca2cf535cc54319031c1037e79a1d09d86d51e77c7fc42705751ccf98c2f56ba6547
7
+ data.tar.gz: 2e54fe9d70908e10d03d22119697f9c72d2589ba32defa1fafcf48244e0f44ef9a8c4416d548a2d6a522180f7371a71eec6f435327f17a0606d4f38a3a2726db
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ## 0.1.0 (2022-04-13)
2
+
3
+ - First release
data/LICENSE.txt ADDED
@@ -0,0 +1,244 @@
1
+ Eclipse Public License - v 2.0
2
+
3
+ THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
4
+ LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
5
+ CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
6
+
7
+ 1. DEFINITIONS
8
+ “Contribution” means:
9
+
10
+ a) in the case of the initial Contributor, the initial content Distributed
11
+ under this Agreement, and
12
+ b) in the case of each subsequent Contributor:
13
+ i) changes to the Program, and
14
+ ii) additions to the Program;
15
+ where such changes and/or additions to the Program originate from and
16
+ are Distributed by that particular Contributor. A Contribution
17
+ “originates” from a Contributor if it was added to the Program by such
18
+ Contributor itself or anyone acting on such Contributor's behalf.
19
+ Contributions do not include changes or additions to the Program that
20
+ are not Modified Works. “Contributor” means any person or entity that
21
+ Distributes the Program.
22
+
23
+ “Licensed Patents” mean patent claims licensable by a Contributor which are
24
+ necessarily infringed by the use or sale of its Contribution alone or when
25
+ combined with the Program.
26
+
27
+ “Program” means the Contributions Distributed in accordance with this
28
+ Agreement.
29
+
30
+ “Recipient” means anyone who receives the Program under this Agreement or
31
+ any Secondary License (as applicable), including Contributors.
32
+
33
+ “Derivative Works” shall mean any work, whether in Source Code or other
34
+ form, that is based on (or derived from) the Program and for which the
35
+ editorial revisions, annotations, elaborations, or other modifications
36
+ represent, as a whole, an original work of authorship.
37
+
38
+ “Modified Works” shall mean any work in Source Code or other form that
39
+ results from an addition to, deletion from, or modification of the contents
40
+ of the Program, including, for purposes of clarity any new file in Source
41
+ Code form that contains any contents of the Program. Modified Works shall
42
+ not include works that contain only declarations, interfaces, types,
43
+ classes, structures, or files of the Program solely in each case in order
44
+ to link to, bind by name, or subclass the Program or Modified Works
45
+ thereof.
46
+
47
+ “Distribute” means the acts of a) distributing or b) making available in
48
+ any manner that enables the transfer of a copy.
49
+
50
+ “Source Code” means the form of a Program preferred for making
51
+ modifications, including but not limited to software source code,
52
+ documentation source, and configuration files.
53
+
54
+ “Secondary License” means either the GNU General Public License, Version
55
+ 2.0, or any later versions of that license, including any exceptions or
56
+ additional permissions as identified by the initial Contributor.
57
+
58
+ 2. GRANT OF RIGHTS
59
+
60
+ a) Subject to the terms of this Agreement, each Contributor hereby grants
61
+ Recipient a non-exclusive, worldwide, royalty-free copyright license to
62
+ reproduce, prepare Derivative Works of, publicly display, publicly perform,
63
+ Distribute and sublicense the Contribution of such Contributor, if any, and
64
+ such Derivative Works.
65
+
66
+ b) Subject to the terms of this Agreement, each Contributor hereby grants
67
+ Recipient a non-exclusive, worldwide, royalty-free patent license under
68
+ Licensed Patents to make, use, sell, offer to sell, import and otherwise
69
+ transfer the Contribution of such Contributor, if any, in Source Code or
70
+ other form. This patent license shall apply to the combination of the
71
+ Contribution and the Program if, at the time the Contribution is added by
72
+ the Contributor, such addition of the Contribution causes such combination
73
+ to be covered by the Licensed Patents. The patent license shall not apply
74
+ to any other combinations which include the Contribution. No hardware per
75
+ se is licensed hereunder.
76
+
77
+ c) Recipient understands that although each Contributor grants the licenses
78
+ to its Contributions set forth herein, no assurances are provided by any
79
+ Contributor that the Program does not infringe the patent or other
80
+ intellectual property rights of any other entity. Each Contributor
81
+ disclaims any liability to Recipient for claims brought by any other entity
82
+ based on infringement of intellectual property rights or otherwise. As a
83
+ condition to exercising the rights and licenses granted hereunder, each
84
+ Recipient hereby assumes sole responsibility to secure any other
85
+ intellectual property rights needed, if any. For example, if a third party
86
+ patent license is required to allow Recipient to Distribute the Program, it
87
+ is Recipient's responsibility to acquire that license before distributing
88
+ the Program.
89
+
90
+ d) Each Contributor represents that to its knowledge it has sufficient
91
+ copyright rights in its Contribution, if any, to grant the copyright
92
+ license set forth in this Agreement.
93
+
94
+ e) Notwithstanding the terms of any Secondary License, no Contributor makes
95
+ additional grants to any Recipient (other than those set forth in this
96
+ Agreement) as a result of such Recipient's receipt of the Program under the
97
+ terms of a Secondary License (if permitted under the terms of Section 3).
98
+
99
+ 3. REQUIREMENTS
100
+
101
+ 3.1 If a Contributor Distributes the Program in any form, then:
102
+
103
+ a) the Program must also be made available as Source Code, in accordance
104
+ with section 3.2, and the Contributor must accompany the Program with a
105
+ statement that the Source Code for the Program is available under this
106
+ Agreement, and informs Recipients how to obtain it in a reasonable manner
107
+ on or through a medium customarily used for software exchange; and
108
+
109
+ b) the Contributor may Distribute the Program under a license different
110
+ than this Agreement, provided that such license:
111
+
112
+ i) effectively disclaims on behalf of all other Contributors all
113
+ warranties and conditions, express and implied, including warranties or
114
+ conditions of title and non-infringement, and implied warranties or
115
+ conditions of merchantability and fitness for a particular purpose;
116
+
117
+ ii) effectively excludes on behalf of all other Contributors all
118
+ liability for damages, including direct, indirect, special, incidental
119
+ and consequential damages, such as lost profits;
120
+
121
+ iii) does not attempt to limit or alter the recipients' rights in the
122
+ Source Code under section 3.2; and
123
+
124
+ iv) requires any subsequent distribution of the Program by any party to
125
+ be under a license that satisfies the requirements of this section 3.
126
+
127
+ 3.2 When the Program is Distributed as Source Code:
128
+
129
+ a) it must be made available under this Agreement, or if the Program (i)
130
+ is combined with other material in a separate file or files made available
131
+ under a Secondary License, and (ii) the initial Contributor attached to
132
+ the Source Code the notice described in Exhibit A of this Agreement, then
133
+ the Program may be made available under the terms of such Secondary
134
+ Licenses, and
135
+
136
+ b) a copy of this Agreement must be included with each copy of the
137
+ Program.
138
+
139
+ 3.3 Contributors may not remove or alter any copyright, patent, trademark,
140
+ attribution notices, disclaimers of warranty, or limitations of liability
141
+ (‘notices’) contained within the Program from any copy of the Program which
142
+ they Distribute, provided that Contributors may add their own appropriate
143
+ notices.
144
+
145
+ 4. COMMERCIAL DISTRIBUTION
146
+
147
+ Commercial distributors of software may accept certain responsibilities with
148
+ respect to end users, business partners and the like. While this license is
149
+ intended to facilitate the commercial use of the Program, the Contributor who
150
+ includes the Program in a commercial product offering should do so in a manner
151
+ which does not create potential liability for other Contributors. Therefore,
152
+ if a Contributor includes the Program in a commercial product offering, such
153
+ Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify
154
+ every other Contributor (“Indemnified Contributor”) against any losses,
155
+ damages and costs (collectively “Losses”) arising from claims, lawsuits and
156
+ other legal actions brought by a third party against the Indemnified
157
+ Contributor to the extent caused by the acts or omissions of such Commercial
158
+ Contributor in connection with its distribution of the Program in a commercial
159
+ product offering. The obligations in this section do not apply to any claims
160
+ or Losses relating to any actual or alleged intellectual property
161
+ infringement. In order to qualify, an Indemnified Contributor must: a)
162
+ promptly notify the Commercial Contributor in writing of such claim, and b)
163
+ allow the Commercial Contributor to control, and cooperate with the Commercial
164
+ Contributor in, the defense and any related settlement negotiations. The
165
+ Indemnified Contributor may participate in any such claim at its own expense.
166
+
167
+ For example, a Contributor might include the Program in a commercial product
168
+ offering, Product X. That Contributor is then a Commercial Contributor. If
169
+ that Commercial Contributor then makes performance claims, or offers
170
+ warranties related to Product X, those performance claims and warranties are
171
+ such Commercial Contributor's responsibility alone. Under this section, the
172
+ Commercial Contributor would have to defend claims against the other
173
+ Contributors related to those performance claims and warranties, and if a
174
+ court requires any other Contributor to pay any damages as a result, the
175
+ Commercial Contributor must pay those damages.
176
+
177
+ 5. NO WARRANTY
178
+
179
+ EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED
180
+ BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT
181
+ WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
182
+ WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
183
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
184
+ responsible for determining the appropriateness of using and distributing the
185
+ Program and assumes all risks associated with its exercise of rights under
186
+ this Agreement, including but not limited to the risks and costs of program
187
+ errors, compliance with applicable laws, damage to or loss of data, programs
188
+ or equipment, and unavailability or interruption of operations.
189
+
190
+ 6. DISCLAIMER OF LIABILITY
191
+
192
+ EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED
193
+ BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY
194
+ LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
195
+ CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER
196
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
197
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
198
+ OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
199
+ HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
200
+
201
+ 7. GENERAL
202
+
203
+ If any provision of this Agreement is invalid or unenforceable under
204
+ applicable law, it shall not affect the validity or enforceability of the
205
+ remainder of the terms of this Agreement, and without further action by the
206
+ parties hereto, such provision shall be reformed to the minimum extent
207
+ necessary to make such provision valid and enforceable.
208
+
209
+ If Recipient institutes patent litigation against any entity (including a
210
+ cross-claim or counterclaim in a lawsuit) alleging that the Program itself
211
+ (excluding combinations of the Program with other software or hardware)
212
+ infringes such Recipient's patent(s), then such Recipient's rights granted
213
+ under Section 2(b) shall terminate as of the date such litigation is filed.
214
+
215
+ All Recipient's rights under this Agreement shall terminate if it fails to
216
+ comply with any of the material terms or conditions of this Agreement and does
217
+ not cure such failure in a reasonable period of time after becoming aware of
218
+ such noncompliance. If all Recipient's rights under this Agreement terminate,
219
+ Recipient agrees to cease use and distribution of the Program as soon as
220
+ reasonably practicable. However, Recipient's obligations under this Agreement
221
+ and any licenses granted by Recipient relating to the Program shall continue
222
+ and survive.
223
+
224
+ Everyone is permitted to copy and distribute copies of this Agreement, but in
225
+ order to avoid inconsistency the Agreement is copyrighted and may only be
226
+ modified in the following manner. The Agreement Steward reserves the right to
227
+ publish new versions (including revisions) of this Agreement from time to
228
+ time. No one other than the Agreement Steward has the right to modify this
229
+ Agreement. The Eclipse Foundation is the initial Agreement Steward. The
230
+ Eclipse Foundation may assign the responsibility to serve as the Agreement
231
+ Steward to a suitable separate entity. Each new version of the Agreement will
232
+ be given a distinguishing version number. The Program (including
233
+ Contributions) may always be Distributed subject to the version of the
234
+ Agreement under which it was received. In addition, after a new version of the
235
+ Agreement is published, Contributor may elect to Distribute the Program
236
+ (including its Contributions) under the new version.
237
+
238
+ Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives
239
+ no rights or licenses to the intellectual property of any Contributor under
240
+ this Agreement, whether expressly, by implication, estoppel or otherwise. All
241
+ rights in the Program not expressly granted under this Agreement are reserved.
242
+ Nothing in this Agreement is intended to be enforceable by any entity that is
243
+ not a Contributor or Recipient. No third-party beneficiary rights are created
244
+ under this Agreement.
data/README.md ADDED
@@ -0,0 +1,105 @@
1
+ # Cbc Ruby
2
+
3
+ [Cbc](https://github.com/coin-or/Cbc) - the mixed-integer programming solver - for Ruby
4
+
5
+ [![Build Status](https://github.com/ankane/cbc-ruby/workflows/build/badge.svg?branch=master)](https://github.com/ankane/cbc-ruby/actions)
6
+
7
+ ## Installation
8
+
9
+ First, install Cbc. For Homebrew, use:
10
+
11
+ ```sh
12
+ brew install cbc
13
+ ```
14
+
15
+ And for Ubuntu, use:
16
+
17
+ ```sh
18
+ sudo apt-get install coinor-libcbc3
19
+ ```
20
+
21
+ Then add this line to your application’s Gemfile:
22
+
23
+ ```ruby
24
+ gem "cbc"
25
+ ```
26
+
27
+ ## Getting Started
28
+
29
+ *The API is fairly low-level at the moment*
30
+
31
+ Load a problem
32
+
33
+ ```ruby
34
+ model =
35
+ Cbc.load_problem(
36
+ sense: :minimize,
37
+ start: [0, 3, 6],
38
+ index: [0, 1, 2, 0, 1, 2],
39
+ value: [2, 3, 2, 2, 4, 1],
40
+ col_lower: [0, 0],
41
+ col_upper: [1e30, 1e30],
42
+ obj: [8, 10],
43
+ row_lower: [7, 12, 6],
44
+ row_upper: [1e30, 1e30, 1e30],
45
+ col_type: [:integer, :continuous]
46
+ )
47
+ ```
48
+
49
+ Solve
50
+
51
+ ```ruby
52
+ model.solve
53
+ ```
54
+
55
+ Write the problem to an LP or MPS file (LP requires Cbc 2.10.0+)
56
+
57
+ ```ruby
58
+ model.write_lp("hello.lp")
59
+ # or
60
+ model.write_mps("hello") # adds mps.gz
61
+ ```
62
+
63
+ Read a problem from an LP or MPS file (LP requires Cbc 2.10.0+)
64
+
65
+ ```ruby
66
+ model = Cbc.read_lp("hello.lp")
67
+ # or
68
+ model = Cbc.read_mps("hello.mps.gz")
69
+ ```
70
+
71
+ ## Reference
72
+
73
+ Set the log level (requires Cbc 2.10.0+)
74
+
75
+ ```ruby
76
+ model.solve(log_level: 1) # 0 = off, 3 = max
77
+ ```
78
+
79
+ Set the time limit in seconds (requires Cbc 2.10.0+)
80
+
81
+ ```ruby
82
+ model.solve(time_limit: 30)
83
+ ```
84
+
85
+ ## History
86
+
87
+ View the [changelog](https://github.com/ankane/cbc-ruby/blob/master/CHANGELOG.md)
88
+
89
+ ## Contributing
90
+
91
+ Everyone is encouraged to help improve this project. Here are a few ways you can help:
92
+
93
+ - [Report bugs](https://github.com/ankane/cbc-ruby/issues)
94
+ - Fix bugs and [submit pull requests](https://github.com/ankane/cbc-ruby/pulls)
95
+ - Write, clarify, or fix documentation
96
+ - Suggest or add new features
97
+
98
+ To get started with development:
99
+
100
+ ```sh
101
+ git clone https://github.com/ankane/cbc-ruby.git
102
+ cd cbc-ruby
103
+ bundle install
104
+ bundle exec rake test
105
+ ```
data/lib/cbc/ffi.rb ADDED
@@ -0,0 +1,83 @@
1
+ module Cbc
2
+ module FFI
3
+ extend Fiddle::Importer
4
+
5
+ libs = Array(Cbc.ffi_lib).dup
6
+ begin
7
+ dlload Fiddle.dlopen(libs.shift)
8
+ rescue Fiddle::DLError => e
9
+ retry if libs.any?
10
+ raise e
11
+ end
12
+
13
+ # https://github.com/coin-or/Cbc/blob/releases/2.9.9/Cbc/src/Cbc_C_Interface.h
14
+
15
+ OBJ_SENSE = {
16
+ minimize: 1,
17
+ ignore: 0,
18
+ maximize: -1
19
+ }
20
+
21
+ STATUS = {
22
+ -1 => :not_started,
23
+ 0 => :finished,
24
+ 1 => :stopped,
25
+ 2 => :abandoned,
26
+ 5 => :interrupted
27
+ }
28
+
29
+ SECONDARY_STATUS = {
30
+ -1 => :unset,
31
+ 0 => :completed,
32
+ 1 => :infeasible,
33
+ 2 => :stopped_gap,
34
+ 3 => :stopped_nodes,
35
+ 4 => :stopped_time,
36
+ 5 => :stopped_user,
37
+ 6 => :stopped_solutions,
38
+ 7 => :unbounded,
39
+ 8 => :stopped_iterations
40
+ }
41
+
42
+ typealias "CoinBigIndex", "int"
43
+
44
+ # version info
45
+ extern "char * Cbc_getVersion(void)"
46
+
47
+ # load models
48
+ extern "Cbc_Model * Cbc_newModel(void)"
49
+ extern "void Cbc_loadProblem(Cbc_Model *model, int numcols, int numrows, CoinBigIndex *start, int *index, double *value, double *collb, double *colub, double *obj, double *rowlb, double *rowub)"
50
+ extern "void Cbc_setObjSense(Cbc_Model *model, double sense)"
51
+ extern "int Cbc_isInteger(Cbc_Model * model, int i)"
52
+ extern "void Cbc_setContinuous(Cbc_Model *model, int iColumn)"
53
+ extern "void Cbc_setInteger(Cbc_Model *model, int iColumn)"
54
+ extern "void Cbc_deleteModel(Cbc_Model *model)"
55
+
56
+ # read and write
57
+ extern "int Cbc_readMps(Cbc_Model *model, char *filename)"
58
+ extern "void Cbc_writeMps(Cbc_Model *model, char *filename)"
59
+
60
+ # solve
61
+ extern "int Cbc_getNumCols(Cbc_Model *model)"
62
+ extern "int Cbc_getNumRows(Cbc_Model *model)"
63
+ extern "int Cbc_solve(Cbc_Model *model)"
64
+ extern "double * Cbc_getColSolution(Cbc_Model *model)"
65
+ extern "int Cbc_isAbandoned(Cbc_Model *model)"
66
+ extern "int Cbc_isProvenOptimal(Cbc_Model *model)"
67
+ extern "int Cbc_isProvenInfeasible(Cbc_Model *model)"
68
+ extern "int Cbc_isContinuousUnbounded(Cbc_Model *model)"
69
+ extern "double Cbc_getObjValue(Cbc_Model *model)"
70
+ extern "int Cbc_status(Cbc_Model *model)"
71
+ extern "int Cbc_secondaryStatus(Cbc_Model *model)"
72
+
73
+ if Gem::Version.new(FFI.Cbc_getVersion.to_s) >= Gem::Version.new("2.10.0")
74
+ extern "int Cbc_readLp(Cbc_Model *model, char *filename)"
75
+ extern "void Cbc_writeLp(Cbc_Model *model, char *filename)"
76
+
77
+ extern "double Cbc_getMaximumSeconds(Cbc_Model *model)"
78
+ extern "void Cbc_setMaximumSeconds(Cbc_Model *model, double maxSeconds)"
79
+ extern "int Cbc_getLogLevel(Cbc_Model *model)"
80
+ extern "void Cbc_setLogLevel(Cbc_Model *model, int logLevel)"
81
+ end
82
+ end
83
+ end
data/lib/cbc/model.rb ADDED
@@ -0,0 +1,154 @@
1
+ module Cbc
2
+ class Model
3
+ def initialize
4
+ @model = FFI.Cbc_newModel
5
+ ObjectSpace.define_finalizer(self, self.class.finalize(@model))
6
+
7
+ @below210 = Gem::Version.new(Cbc.lib_version) < Gem::Version.new("2.10.0")
8
+ FFI.Cbc_setLogLevel(model, 0) unless @below210
9
+ end
10
+
11
+ def load_problem(sense:, start:, index:, value:, col_lower:, col_upper:, obj:, row_lower:, row_upper:, col_type:)
12
+ start_size = start.size
13
+ index_size = index.size
14
+ num_cols = col_lower.size
15
+ num_rows = row_lower.size
16
+
17
+ FFI.Cbc_loadProblem(
18
+ model, num_cols, num_rows,
19
+ big_index_array(start, start_size), int_array(index, index_size), double_array(value, index_size),
20
+ double_array(col_lower, num_cols), double_array(col_upper, num_cols), double_array(obj, num_cols),
21
+ double_array(row_lower, num_rows), double_array(row_upper, num_rows)
22
+ )
23
+ FFI.Cbc_setObjSense(model, FFI::OBJ_SENSE.fetch(sense))
24
+
25
+ if col_type.size != num_cols
26
+ raise ArgumentError, "wrong size (given #{value.size}, expected #{size})"
27
+ end
28
+
29
+ col_type.each_with_index do |v, i|
30
+ case v
31
+ when :integer
32
+ FFI.Cbc_setInteger(model, i)
33
+ when :continuous
34
+ FFI.Cbc_setContinuous(model, i)
35
+ else
36
+ raise ArgumentError, "Unknown col_type"
37
+ end
38
+ end
39
+ end
40
+
41
+ def read_lp(filename)
42
+ check_version
43
+ check_status FFI.Cbc_readLp(model, filename)
44
+ end
45
+
46
+ def read_mps(filename)
47
+ check_status FFI.Cbc_readMps(model, filename)
48
+ end
49
+
50
+ def write_lp(filename)
51
+ check_version
52
+ FFI.Cbc_writeLp(model, filename)
53
+ end
54
+
55
+ def write_mps(filename)
56
+ FFI.Cbc_writeMps(model, filename)
57
+ end
58
+
59
+ def solve(log_level: nil, time_limit: nil)
60
+ with_options(log_level: log_level, time_limit: time_limit) do
61
+ # do not check status
62
+ FFI.Cbc_solve(model)
63
+ end
64
+
65
+ num_cols = FFI.Cbc_getNumCols(model)
66
+
67
+ status = FFI::STATUS[FFI.Cbc_status(model)]
68
+ secondary_status = FFI::SECONDARY_STATUS[FFI.Cbc_secondaryStatus(model)]
69
+
70
+ ret_status =
71
+ case status
72
+ when :not_started, :finished
73
+ if FFI.Cbc_isProvenOptimal(model)
74
+ :optimal
75
+ elsif FFI.Cbc_isProvenInfeasible(model)
76
+ :infeasible
77
+ else
78
+ secondary_status
79
+ end
80
+ else
81
+ secondary_status
82
+ end
83
+
84
+ {
85
+ status: ret_status,
86
+ objective: FFI.Cbc_getObjValue(model),
87
+ primal_col: read_double_array(FFI.Cbc_getColSolution(model), num_cols)
88
+ }
89
+ end
90
+
91
+ def self.finalize(model)
92
+ # must use proc instead of stabby lambda
93
+ proc { FFI.Cbc_deleteModel(model) }
94
+ end
95
+
96
+ private
97
+
98
+ def model
99
+ @model
100
+ end
101
+
102
+ def check_status(status)
103
+ if status != 0
104
+ raise Error, "Bad status: #{status}"
105
+ end
106
+ end
107
+
108
+ def check_version
109
+ if @below210
110
+ raise Error, "This feature requires Cbc 2.10.0+"
111
+ end
112
+ end
113
+
114
+ def double_array(value, size)
115
+ base_array(value, size, "d")
116
+ end
117
+
118
+ def int_array(value, size)
119
+ base_array(value, size, "i!")
120
+ end
121
+ alias_method :big_index_array, :int_array
122
+
123
+ def base_array(value, size, format)
124
+ if value.size != size
125
+ # TODO add variable name to message
126
+ raise ArgumentError, "wrong size (given #{value.size}, expected #{size})"
127
+ end
128
+ Fiddle::Pointer[value.pack("#{format}#{size}")]
129
+ end
130
+
131
+ def read_double_array(ptr, size)
132
+ ptr[0, size * Fiddle::SIZEOF_DOUBLE].unpack("d#{size}")
133
+ end
134
+
135
+ def with_options(log_level:, time_limit:)
136
+ if log_level
137
+ check_version
138
+ previous_log_level = FFI.Cbc_getLogLevel(model)
139
+ FFI.Cbc_setLogLevel(model, log_level)
140
+ end
141
+
142
+ if time_limit
143
+ check_version
144
+ previous_time_limit = FFI.Cbc_getMaximumSeconds(model)
145
+ FFI.Cbc_setMaximumSeconds(model, time_limit)
146
+ end
147
+
148
+ yield
149
+ ensure
150
+ FFI.Cbc_setLogLevel(model, previous_log_level) if previous_log_level
151
+ FFI.Cbc_setMaximumSeconds(model, previous_time_limit) if previous_time_limit
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,3 @@
1
+ module Cbc
2
+ VERSION = "0.1.0"
3
+ end
data/lib/cbc.rb ADDED
@@ -0,0 +1,51 @@
1
+ # stdlib
2
+ require "fiddle/import"
3
+
4
+ # modules
5
+ require "cbc/model"
6
+ require "cbc/version"
7
+
8
+ module Cbc
9
+ class Error < StandardError; end
10
+
11
+ class << self
12
+ attr_accessor :ffi_lib
13
+ end
14
+ lib_name =
15
+ if Gem.win_platform?
16
+ # TODO test
17
+ ["CbcSolver.dll"]
18
+ elsif RbConfig::CONFIG["host_os"] =~ /darwin/i
19
+ ["libCbcSolver.dylib"]
20
+ else
21
+ # coinor-libcbc-dev has libCbcSolver.so
22
+ # coinor-libcbc3 has libCbcSolver.so.3
23
+ ["libCbcSolver.so", "libCbcSolver.so.3"]
24
+ end
25
+ self.ffi_lib = lib_name
26
+
27
+ # friendlier error message
28
+ autoload :FFI, "cbc/ffi"
29
+
30
+ def self.lib_version
31
+ FFI.Cbc_getVersion.to_s
32
+ end
33
+
34
+ def self.read_lp(filename)
35
+ model = Model.new
36
+ model.read_lp(filename)
37
+ model
38
+ end
39
+
40
+ def self.read_mps(filename)
41
+ model = Model.new
42
+ model.read_mps(filename)
43
+ model
44
+ end
45
+
46
+ def self.load_problem(**options)
47
+ model = Model.new
48
+ model.load_problem(**options)
49
+ model
50
+ end
51
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cbc
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: 2022-04-14 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: andrew@ankane.org
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - CHANGELOG.md
20
+ - LICENSE.txt
21
+ - README.md
22
+ - lib/cbc.rb
23
+ - lib/cbc/ffi.rb
24
+ - lib/cbc/model.rb
25
+ - lib/cbc/version.rb
26
+ homepage: https://github.com/ankane/cbc-ruby
27
+ licenses:
28
+ - EPL-2.0
29
+ metadata: {}
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '2.7'
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubygems_version: 3.3.7
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: Mixed-integer programming for Ruby
49
+ test_files: []