or-tools 0.5.3 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c16581924f813458dc535d2a8804bf02a7f0a605fac108d14894f13ed7af984a
4
- data.tar.gz: 28bd124da203c4dd0ac50ee86aca3deb7ba283a1cbd711521985972a02bdcaa1
3
+ metadata.gz: c0e0f455741da72e3a215287df4ef1858893fb31d0b4be40db6ef9ab025e339c
4
+ data.tar.gz: 9291933eee08f800f48f3d83ca4f2d0fc71efb0a328134ba9667ca2ac8efb185
5
5
  SHA512:
6
- metadata.gz: 0612e5bfcf96ba9ec2591dab7bbfe175625f874ff89e87a168d771a0f81948cb4d8d29e31de0487470eb3b993ef53b793ac25a0b078c5cc54385d4cd3bb159f9
7
- data.tar.gz: dd548021defe7c1249ecee70790cb29f4c85a5ec04cace94cc9bfa0192b24d68e20040a7dd355b148f75f443bf882cc41ec3ea6613785a24aeb4a37674ca8017
6
+ metadata.gz: 61ccc7c5f3a6c3cdf1e3dffb1ee6572d0b8cde09d4684d50353efd6f2efcb93ca4ba940343f994a3bf65992e518331bd62a02ef74ecc52f2427e12350ea7a430
7
+ data.tar.gz: 589423f5b52c872b453569400ff1fd60bb1fcd3b0035e70aadbb47eedefec9b7f4187a5442893e50608529f836d2009bd77333aae3f64ce1b9d700df6fe020e7
data/CHANGELOG.md CHANGED
@@ -1,3 +1,24 @@
1
+ ## 0.6.2 (2022-02-09)
2
+
3
+ - Fixed segfaults with `Solver`
4
+
5
+ ## 0.6.1 (2022-01-22)
6
+
7
+ - Added installation instructions for Mac ARM
8
+ - Removed dependency on `lsb_release` for binary installation on Linux
9
+
10
+ ## 0.6.0 (2021-12-16)
11
+
12
+ - Updated OR-Tools to 9.2
13
+ - Renamed `add_product_equality` to `add_multiplication_equality`
14
+ - Removed `scale_objective_by`
15
+
16
+ ## 0.5.4 (2021-10-01)
17
+
18
+ - Updated OR-Tools to 9.1
19
+ - Added binary installation for Debian 11
20
+ - Deprecated `solve_with_solution_callback` and `search_for_all_solutions`
21
+
1
22
  ## 0.5.3 (2021-08-02)
2
23
 
3
24
  - Added more methods to `IntVar`, `IntervalVar`, and `Constraint`
data/NOTICE.txt CHANGED
@@ -1,5 +1,5 @@
1
- Copyright 2010-2018 Google LLC
2
- Copyright 2020-2021 Andrew Kane
1
+ Copyright 2010-2021 Google LLC
2
+ Copyright 2020-2022 Andrew Kane
3
3
 
4
4
  Licensed under the Apache License, Version 2.0 (the "License");
5
5
  you may not use this file except in compliance with the License.
data/README.md CHANGED
@@ -1,18 +1,18 @@
1
- # OR-Tools
1
+ # OR-Tools Ruby
2
2
 
3
3
  [OR-Tools](https://github.com/google/or-tools) - operations research tools - for Ruby
4
4
 
5
- [![Build Status](https://github.com/ankane/or-tools/workflows/build/badge.svg?branch=master)](https://github.com/ankane/or-tools/actions)
5
+ [![Build Status](https://github.com/ankane/or-tools-ruby/workflows/build/badge.svg?branch=master)](https://github.com/ankane/or-tools-ruby/actions)
6
6
 
7
7
  ## Installation
8
8
 
9
9
  Add this line to your application’s Gemfile:
10
10
 
11
11
  ```ruby
12
- gem 'or-tools'
12
+ gem "or-tools"
13
13
  ```
14
14
 
15
- Installation can take a few minutes as OR-Tools downloads and builds.
15
+ Installation can take a few minutes as OR-Tools downloads and builds. For Mac ARM, also follow [these instructions](#additional-instructions).
16
16
 
17
17
  ## Higher Level Interfaces
18
18
 
@@ -2139,7 +2139,7 @@ model.add(seats[[0, 0]] == 1)
2139
2139
  # Solve model
2140
2140
  solver = ORTools::CpSolver.new
2141
2141
  solution_printer = WeddingChartPrinter.new(seats, names, num_tables, num_guests)
2142
- solver.solve_with_solution_callback(model, solution_printer)
2142
+ solver.solve(model, solution_printer)
2143
2143
 
2144
2144
  puts "Statistics"
2145
2145
  puts " - conflicts : %i" % solver.num_conflicts
@@ -2201,24 +2201,35 @@ possible_tables.each do |table|
2201
2201
  end
2202
2202
  ```
2203
2203
 
2204
+ ## Additional Instructions
2205
+
2206
+ ### Mac ARM
2207
+
2208
+ ARM binaries are not available for Mac yet, so use Homebrew to install OR-Tools before installing the gem.
2209
+
2210
+ ```sh
2211
+ brew install or-tools
2212
+ bundle config build.or-tools --with-or-tools-dir=/opt/homebrew
2213
+ ```
2214
+
2204
2215
  ## History
2205
2216
 
2206
- View the [changelog](https://github.com/ankane/or-tools/blob/master/CHANGELOG.md)
2217
+ View the [changelog](https://github.com/ankane/or-tools-ruby/blob/master/CHANGELOG.md)
2207
2218
 
2208
2219
  ## Contributing
2209
2220
 
2210
2221
  Everyone is encouraged to help improve this project. Here are a few ways you can help:
2211
2222
 
2212
- - [Report bugs](https://github.com/ankane/or-tools/issues)
2213
- - Fix bugs and [submit pull requests](https://github.com/ankane/or-tools/pulls)
2223
+ - [Report bugs](https://github.com/ankane/or-tools-ruby/issues)
2224
+ - Fix bugs and [submit pull requests](https://github.com/ankane/or-tools-ruby/pulls)
2214
2225
  - Write, clarify, or fix documentation
2215
2226
  - Suggest or add new features
2216
2227
 
2217
2228
  To get started with development:
2218
2229
 
2219
2230
  ```sh
2220
- git clone https://github.com/ankane/or-tools.git
2221
- cd or-tools
2231
+ git clone https://github.com/ankane/or-tools-ruby.git
2232
+ cd or-tools-ruby
2222
2233
  bundle install
2223
2234
  bundle exec rake compile
2224
2235
  bundle exec rake test
@@ -131,10 +131,21 @@ void init_constraint(Rice::Module& m) {
131
131
 
132
132
  Rice::define_class_under<SatParameters>(m, "SatParameters")
133
133
  .define_constructor(Rice::Constructor<SatParameters>())
134
- .define_method("max_time_in_seconds=",
135
- [](SatParameters& self, double value) {
136
- self.set_max_time_in_seconds(value);
137
- });
134
+ .define_method(
135
+ "max_time_in_seconds=",
136
+ [](SatParameters& self, double value) {
137
+ self.set_max_time_in_seconds(value);
138
+ })
139
+ .define_method(
140
+ "enumerate_all_solutions=",
141
+ [](SatParameters& self, bool value) {
142
+ self.set_enumerate_all_solutions(value);
143
+ })
144
+ .define_method(
145
+ "enumerate_all_solutions",
146
+ [](SatParameters& self) {
147
+ return self.enumerate_all_solutions();
148
+ });
138
149
 
139
150
  Rice::define_class_under<CpModelBuilder>(m, "CpModel")
140
151
  .define_constructor(Rice::Constructor<CpModelBuilder>())
@@ -276,9 +287,9 @@ void init_constraint(Rice::Module& m) {
276
287
  return self.AddModuloEquality(target, var, mod);
277
288
  })
278
289
  .define_method(
279
- "add_product_equality",
290
+ "add_multiplication_equality",
280
291
  [](CpModelBuilder& self, IntVar target, std::vector<IntVar> vars) {
281
- return self.AddProductEquality(target, vars);
292
+ return self.AddMultiplicationEquality(target, vars);
282
293
  })
283
294
  .define_method(
284
295
  "add_no_overlap",
@@ -295,11 +306,6 @@ void init_constraint(Rice::Module& m) {
295
306
  [](CpModelBuilder& self, LinearExpr expr) {
296
307
  self.Minimize(expr);
297
308
  })
298
- .define_method(
299
- "scale_objective_by",
300
- [](CpModelBuilder& self, double scaling) {
301
- self.ScaleObjectiveBy(scaling);
302
- })
303
309
  .define_method(
304
310
  "add_hint",
305
311
  [](CpModelBuilder& self, IntVar var, int64_t value) {
@@ -377,29 +383,23 @@ void init_constraint(Rice::Module& m) {
377
383
 
378
384
  Rice::define_class_under(m, "CpSolver")
379
385
  .define_method(
380
- "_solve_with_observer",
381
- [](Object self, CpModelBuilder& model, SatParameters& parameters, Object callback, bool all_solutions) {
386
+ "_solve",
387
+ [](Object self, CpModelBuilder& model, SatParameters& parameters, Object callback) {
382
388
  Model m;
383
389
 
384
- if (all_solutions) {
385
- // set parameters for SearchForAllSolutions
386
- parameters.set_enumerate_all_solutions(true);
390
+ if (!callback.is_nil()) {
391
+ // TODO figure out how to use callback with multiple cores
392
+ parameters.set_num_search_workers(1);
393
+
394
+ m.Add(NewFeasibleSolutionObserver(
395
+ [callback](const CpSolverResponse& r) {
396
+ // TODO find a better way to do this
397
+ callback.call("response=", r);
398
+ callback.call("on_solution_callback");
399
+ })
400
+ );
387
401
  }
388
- m.Add(NewSatParameters(parameters));
389
402
 
390
- m.Add(NewFeasibleSolutionObserver(
391
- [callback](const CpSolverResponse& r) {
392
- // TODO find a better way to do this
393
- callback.call("response=", r);
394
- callback.call("on_solution_callback");
395
- })
396
- );
397
- return SolveCpModel(model.Build(), &m);
398
- })
399
- .define_method(
400
- "_solve",
401
- [](Object self, CpModelBuilder& model, SatParameters& parameters) {
402
- Model m;
403
403
  m.Add(NewSatParameters(parameters));
404
404
  return SolveCpModel(model.Build(), &m);
405
405
  })
@@ -46,86 +46,14 @@ namespace Rice::detail
46
46
 
47
47
  void init_linear(Rice::Module& m) {
48
48
  Rice::define_class_under<LinearRange>(m, "LinearRange");
49
+
50
+ // TODO remove in 0.7.0
49
51
  auto rb_cLinearExpr = Rice::define_class_under<LinearExpr>(m, "LinearExpr");
52
+ rb_cLinearExpr.define_constructor(Rice::Constructor<LinearExpr>());
50
53
 
51
- Rice::define_class_under<MPVariable>(m, "MPVariable")
54
+ Rice::define_class_under<MPVariable, LinearExpr>(m, "MPVariable")
52
55
  .define_method("name", &MPVariable::name)
53
- .define_method("solution_value", &MPVariable::solution_value)
54
- .define_method(
55
- "+",
56
- [](MPVariable& self, LinearExpr& other) {
57
- LinearExpr s(&self);
58
- return s + other;
59
- })
60
- .define_method(
61
- "-",
62
- [](MPVariable& self, LinearExpr& other) {
63
- LinearExpr s(&self);
64
- return s - other;
65
- })
66
- .define_method(
67
- "*",
68
- [](MPVariable& self, double other) {
69
- LinearExpr s(&self);
70
- return s * other;
71
- })
72
- .define_method(
73
- "inspect",
74
- [](MPVariable& self) {
75
- return "#<ORTools::MPVariable @name=\"" + self.name() + "\">";
76
- });
77
-
78
- rb_cLinearExpr
79
- .define_constructor(Rice::Constructor<LinearExpr>())
80
- .define_method(
81
- "_add_linear_expr",
82
- [](LinearExpr& self, LinearExpr& other) {
83
- return self + other;
84
- })
85
- .define_method(
86
- "_add_mp_variable",
87
- [](LinearExpr& self, MPVariable &other) {
88
- LinearExpr o(&other);
89
- return self + o;
90
- })
91
- .define_method(
92
- "_gte_double",
93
- [](LinearExpr& self, double other) {
94
- LinearExpr o(other);
95
- return self >= o;
96
- })
97
- .define_method(
98
- "_gte_linear_expr",
99
- [](LinearExpr& self, LinearExpr& other) {
100
- return self >= other;
101
- })
102
- .define_method(
103
- "_lte_double",
104
- [](LinearExpr& self, double other) {
105
- LinearExpr o(other);
106
- return self <= o;
107
- })
108
- .define_method(
109
- "_lte_linear_expr",
110
- [](LinearExpr& self, LinearExpr& other) {
111
- return self <= other;
112
- })
113
- .define_method(
114
- "==",
115
- [](LinearExpr& self, double other) {
116
- LinearExpr o(other);
117
- return self == o;
118
- })
119
- .define_method(
120
- "to_s",
121
- [](LinearExpr& self) {
122
- return self.ToString();
123
- })
124
- .define_method(
125
- "inspect",
126
- [](LinearExpr& self) {
127
- return "#<ORTools::LinearExpr \"" + self.ToString() + "\">";
128
- });
56
+ .define_method("solution_value", &MPVariable::solution_value);
129
57
 
130
58
  Rice::define_class_under<MPConstraint>(m, "MPConstraint")
131
59
  .define_method("set_coefficient", &MPConstraint::SetCoefficient);
@@ -133,7 +61,8 @@ void init_linear(Rice::Module& m) {
133
61
  Rice::define_class_under<MPObjective>(m, "MPObjective")
134
62
  .define_method("value", &MPObjective::Value)
135
63
  .define_method("set_coefficient", &MPObjective::SetCoefficient)
136
- .define_method("set_maximization", &MPObjective::SetMaximization);
64
+ .define_method("set_maximization", &MPObjective::SetMaximization)
65
+ .define_method("set_minimization", &MPObjective::SetMinimization);
137
66
 
138
67
  Rice::define_class_under<MPSolver>(m, "Solver")
139
68
  .define_constructor(Rice::Constructor<MPSolver, std::string, MPSolver::OptimizationProblemType>())
@@ -155,21 +84,6 @@ void init_linear(Rice::Module& m) {
155
84
  .define_method("iterations", &MPSolver::iterations)
156
85
  .define_method("nodes", &MPSolver::nodes)
157
86
  .define_method("objective", &MPSolver::MutableObjective)
158
- .define_method(
159
- "maximize",
160
- [](MPSolver& self, LinearExpr& expr) {
161
- return self.MutableObjective()->MaximizeLinearExpr(expr);
162
- })
163
- .define_method(
164
- "minimize",
165
- [](MPSolver& self, LinearExpr& expr) {
166
- return self.MutableObjective()->MinimizeLinearExpr(expr);
167
- })
168
- .define_method(
169
- "add",
170
- [](MPSolver& self, const LinearRange& range) {
171
- return self.MakeRowConstraint(range);
172
- })
173
87
  .define_method(
174
88
  "constraint",
175
89
  [](MPSolver& self, double lb, double ub) {
@@ -1,31 +1,54 @@
1
+ require "csv"
1
2
  require "digest"
2
3
  require "fileutils"
3
4
  require "net/http"
4
5
  require "tmpdir"
5
6
 
6
- version = "9.0.9048"
7
+ version = "9.2.9972"
7
8
 
8
9
  if RbConfig::CONFIG["host_os"] =~ /darwin/i
9
- filename = "or-tools_MacOsX-11.2.3_v#{version}.tar.gz"
10
- checksum = "adf73a00d4ec49558b67be5ce3cfc8f30268da2253b35feb11d0d40700550bf6"
10
+ if RbConfig::CONFIG["host_cpu"] =~ /arm|aarch64/i
11
+ raise <<~MSG
12
+ Binary installation not available for this platform: Mac ARM
13
+
14
+ Run:
15
+ brew install or-tools
16
+ bundle config build.or-tools --with-or-tools-dir=/opt/homebrew
17
+
18
+ MSG
19
+ else
20
+ filename = "or-tools_MacOsX-12.0.1_v#{version}.tar.gz"
21
+ checksum = "796791a8ef84507d62e193e647cccb1c7725dae4f1474476e1777fe4a44ee3e0"
22
+ end
11
23
  else
12
- os = %x[lsb_release -is].chomp rescue nil
13
- os_version = %x[lsb_release -rs].chomp rescue nil
14
- if os == "Ubuntu" && os_version == "20.04"
15
- filename = "or-tools_ubuntu-20.04_v#{version}.tar.gz"
16
- checksum = "5565343c1c310d2885a40ce850ae7e3468299b3fee97ae8eed8425ce06bd4960"
17
- elsif os == "Ubuntu" && os_version == "18.04"
18
- filename = "or-tools_ubuntu-18.04_v#{version}.tar.gz"
19
- checksum = "08cf548d0179f7fa814bb7458be94cd1b8a3de14985e6a9faf6118a1d8571539"
20
- elsif os == "Debian" && os_version == "10"
21
- filename = "or-tools_debian-10_v#{version}.tar.gz"
22
- checksum = "063fb1d8765ae23b0bb25b9c561e904532713416fe0458f7db45a0f72190eb50"
23
- elsif os == "CentOS" && os_version == "8"
24
- filename = "or-tools_centos-8_v#{version}.tar.gz"
25
- checksum = "c98212ed4fc699d8ae70c1f53cd1d8dacd28e52970336fab5b86dedf7406f215"
26
- elsif os == "CentOS" && os_version == "7"
27
- filename = "or-tools_centos-7_v#{version}.tar.gz"
28
- checksum = "b992bda4614bbc703583b0e9edcd2ade54bacfb9909399b20c8aa95ff7197d68"
24
+ # try /etc/os-release with fallback to /usr/lib/os-release
25
+ # https://www.freedesktop.org/software/systemd/man/os-release.html
26
+ os_filename = File.exist?("/etc/os-release") ? "/etc/os-release" : "/usr/lib/os-release"
27
+
28
+ # for safety, parse rather than source
29
+ os_info = CSV.read(os_filename, col_sep: "=").to_h rescue {}
30
+
31
+ os = os_info["ID"]
32
+ os_version = os_info["VERSION_ID"]
33
+
34
+ if os == "ubuntu" && os_version == "20.04"
35
+ filename = "or-tools_amd64_ubuntu-20.04_v#{version}.tar.gz"
36
+ checksum = "985e3036eaecacfc8a0258ec2ebef429240491577d4e0896d68fc076e65451ec"
37
+ elsif os == "ubuntu" && os_version == "18.04"
38
+ filename = "or-tools_amd64_ubuntu-18.04_v#{version}.tar.gz"
39
+ checksum = "e36406c4fe8c111e1ace0ede9d0787ff0e98f11afd7db9cc074adfd0f55628a6"
40
+ elsif os == "debian" && os_version == "11"
41
+ filename = "or-tools_amd64_debian-11_v#{version}.tar.gz"
42
+ checksum = "bd49ee916213b2140ab255414d35a28f19dff7caf87632309753d3fc553f85dd"
43
+ elsif os == "debian" && os_version == "10"
44
+ filename = "or-tools_amd64_debian-10_v#{version}.tar.gz"
45
+ checksum = "b152fee584f0c8228fe2ff21b74c789870ff9b7064e42ca26305c6b5653f0064"
46
+ elsif os == "centos" && os_version == "8"
47
+ filename = "or-tools_amd64_centos-8_v#{version}.tar.gz"
48
+ checksum = "66ed4bb800acf92c672f7e68acdf4ea27bbfdb17bbddc02f8326cd55a97305f6"
49
+ elsif os == "centos" && os_version == "7"
50
+ filename = "or-tools_amd64_centos-7_v#{version}.tar.gz"
51
+ checksum = "4a5c1b1639a2828cd7e1ba82a574ef37876557b59e8aab8b81811bb750d53035"
29
52
  else
30
53
  platform =
31
54
  if Gem.win_platform?
data/lib/or-tools.rb CHANGED
@@ -5,17 +5,22 @@ require "or_tools/ext"
5
5
  require "or_tools/comparison"
6
6
  require "or_tools/comparison_operators"
7
7
  require "or_tools/bool_var"
8
+ require "or_tools/constant"
8
9
  require "or_tools/cp_model"
9
10
  require "or_tools/cp_solver"
10
11
  require "or_tools/cp_solver_solution_callback"
11
12
  require "or_tools/int_var"
12
13
  require "or_tools/knapsack_solver"
14
+ require "or_tools/linear_constraint"
13
15
  require "or_tools/linear_expr"
16
+ require "or_tools/mp_variable"
17
+ require "or_tools/product_cst"
14
18
  require "or_tools/routing_index_manager"
15
19
  require "or_tools/routing_model"
16
20
  require "or_tools/sat_linear_expr"
17
21
  require "or_tools/sat_int_var"
18
22
  require "or_tools/solver"
23
+ require "or_tools/sum_array"
19
24
  require "or_tools/version"
20
25
 
21
26
  # solution printers
@@ -8,8 +8,13 @@ module ORTools
8
8
  @right = right
9
9
  end
10
10
 
11
- def inspect
11
+ def to_s
12
12
  "#{left.inspect} #{operator} #{right.inspect}"
13
13
  end
14
+
15
+ # TODO add class
16
+ def inspect
17
+ to_s
18
+ end
14
19
  end
15
20
  end
@@ -0,0 +1,23 @@
1
+ module ORTools
2
+ class Constant < LinearExpr
3
+ def initialize(val)
4
+ @val = val
5
+ end
6
+
7
+ def to_s
8
+ @val.to_s
9
+ end
10
+
11
+ def add_self_to_coeff_map_or_stack(coeffs, multiplier, stack)
12
+ coeffs[OFFSET_KEY] += @val * multiplier
13
+ end
14
+ end
15
+
16
+ class FakeMPVariableRepresentingTheConstantOffset
17
+ def solution_value
18
+ 1
19
+ end
20
+ end
21
+
22
+ OFFSET_KEY = FakeMPVariableRepresentingTheConstantOffset.new
23
+ end
@@ -6,8 +6,8 @@ module ORTools
6
6
 
7
7
  def_delegators :@response, :objective_value, :num_conflicts, :num_branches, :wall_time
8
8
 
9
- def solve(model)
10
- @response = _solve(model, parameters)
9
+ def solve(model, observer = nil)
10
+ @response = _solve(model, parameters, observer)
11
11
  @response.status
12
12
  end
13
13
 
@@ -20,13 +20,19 @@ module ORTools
20
20
  end
21
21
 
22
22
  def solve_with_solution_callback(model, observer)
23
- @response = _solve_with_observer(model, parameters, observer, false)
24
- @response.status
23
+ warn "[or-tools] solve_with_solution_callback is deprecated; use solve(model, callback)"
24
+ solve(model, observer)
25
25
  end
26
26
 
27
27
  def search_for_all_solutions(model, observer)
28
- @response = _solve_with_observer(model, parameters, observer, true)
29
- @response.status
28
+ warn "[or-tools] search_for_all_solutions is deprecated; use solve() with solver.parameters.enumerate_all_solutions = true"
29
+ previous_value = parameters.enumerate_all_solutions
30
+ begin
31
+ parameters.enumerate_all_solutions = true
32
+ solve(model, observer)
33
+ ensure
34
+ parameters.enumerate_all_solutions = previous_value
35
+ end
30
36
  end
31
37
 
32
38
  def sufficient_assumptions_for_infeasibility
@@ -0,0 +1,50 @@
1
+ module ORTools
2
+ class LinearConstraint
3
+ attr_reader :expr, :lb, :ub
4
+
5
+ def initialize(expr, lb, ub)
6
+ @expr = expr
7
+ @lb = lb
8
+ @ub = ub
9
+ end
10
+
11
+ def to_s
12
+ if @lb > -Float::INFINITY && @ub < Float::INFINITY
13
+ if @lb == @ub
14
+ "#{@expr} == #{@lb}"
15
+ else
16
+ "#{@lb} <= #{@expr} <= #{@ub}"
17
+ end
18
+ elsif @lb > -Float::INFINITY
19
+ "#{@expr} >= #{@lb}"
20
+ elsif @ub < Float::INFINITY
21
+ "#{@expr} <= #{@ub}"
22
+ else
23
+ "Trivial inequality (always true)"
24
+ end
25
+ end
26
+
27
+ def inspect
28
+ "#<#{self.class.name} #{to_s}>"
29
+ end
30
+
31
+ def extract(solver)
32
+ coeffs = @expr.coeffs
33
+ constant = coeffs.delete(OFFSET_KEY) || 0.0
34
+ lb = -solver.infinity
35
+ ub = solver.infinity
36
+ if @lb > -Float::INFINITY
37
+ lb = @lb - constant
38
+ end
39
+ if @ub < Float::INFINITY
40
+ ub = @ub - constant
41
+ end
42
+
43
+ constraint = solver.constraint(lb, ub)
44
+ coeffs.each do |v, c|
45
+ constraint.set_coefficient(v, c.to_f)
46
+ end
47
+ constraint
48
+ end
49
+ end
50
+ end
@@ -1,27 +1,73 @@
1
1
  module ORTools
2
2
  class LinearExpr
3
- def +(other)
4
- if other.is_a?(LinearExpr)
5
- _add_linear_expr(other)
3
+ def solution_value
4
+ coeffs.sum { |var, coeff| var.solution_value * coeff }
5
+ end
6
+
7
+ def coeffs
8
+ coeffs = Hash.new(0.0)
9
+ stack = [[1.0, self]]
10
+ while stack.any?
11
+ current_multiplier, current_expression = stack.pop
12
+
13
+ # skip empty LinearExpr for backwards compatibility
14
+ next if current_expression.instance_of?(LinearExpr)
15
+
16
+ current_expression.add_self_to_coeff_map_or_stack(coeffs, current_multiplier, stack)
17
+ end
18
+ coeffs
19
+ end
20
+
21
+ def +(expr)
22
+ SumArray.new([self, expr])
23
+ end
24
+
25
+ def -(expr)
26
+ SumArray.new([self, -expr])
27
+ end
28
+
29
+ def *(other)
30
+ ProductCst.new(self, other)
31
+ end
32
+
33
+ def /(cst)
34
+ ProductCst.new(self, 1.0 / other)
35
+ end
36
+
37
+ def -@
38
+ ProductCst.new(self, -1)
39
+ end
40
+
41
+ def ==(arg)
42
+ if arg.is_a?(Numeric)
43
+ LinearConstraint.new(self, arg, arg)
6
44
  else
7
- _add_mp_variable(other)
45
+ LinearConstraint.new(self - arg, 0.0, 0.0)
8
46
  end
9
47
  end
10
48
 
11
- def >=(other)
12
- if other.is_a?(LinearExpr)
13
- _gte_linear_expr(other)
49
+ def >=(arg)
50
+ if arg.is_a?(Numeric)
51
+ LinearConstraint.new(self, arg, Float::INFINITY)
14
52
  else
15
- _gte_double(other)
53
+ LinearConstraint.new(self - arg, 0.0, Float::INFINITY)
16
54
  end
17
55
  end
18
56
 
19
- def <=(other)
20
- if other.is_a?(LinearExpr)
21
- _lte_linear_expr(other)
57
+ def <=(arg)
58
+ if arg.is_a?(Numeric)
59
+ LinearConstraint.new(self, -Float::INFINITY, arg)
22
60
  else
23
- _lte_double(other)
61
+ LinearConstraint.new(self - arg, -Float::INFINITY, 0.0)
24
62
  end
25
63
  end
64
+
65
+ def to_s
66
+ "(empty)"
67
+ end
68
+
69
+ def inspect
70
+ "#<#{self.class.name} #{to_s}>"
71
+ end
26
72
  end
27
73
  end
@@ -0,0 +1,12 @@
1
+ module ORTools
2
+ # TODO change to VariableExpr in 0.7.0
3
+ class MPVariable < LinearExpr
4
+ def add_self_to_coeff_map_or_stack(coeffs, multiplier, stack)
5
+ coeffs[self] += multiplier
6
+ end
7
+
8
+ def to_s
9
+ name
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,31 @@
1
+ module ORTools
2
+ class ProductCst < LinearExpr
3
+ attr_reader :expr, :coef
4
+
5
+ def initialize(expr, coef)
6
+ @expr = cast_to_lin_exp(expr)
7
+ # TODO improve message
8
+ raise TypeError, "expected numeric" unless coef.is_a?(Numeric)
9
+ @coef = coef
10
+ end
11
+
12
+ def to_s
13
+ if @coef == -1
14
+ "-#{@expr}"
15
+ else
16
+ "(#{@coef} * #{@expr})"
17
+ end
18
+ end
19
+
20
+ def add_self_to_coeff_map_or_stack(coeffs, multiplier, stack)
21
+ current_multiplier = multiplier * @coef
22
+ if current_multiplier
23
+ stack << [current_multiplier, @expr]
24
+ end
25
+ end
26
+
27
+ def cast_to_lin_exp(v)
28
+ v.is_a?(Numeric) ? Constant.new(v) : v
29
+ end
30
+ end
31
+ end
@@ -18,9 +18,13 @@ module ORTools
18
18
  SatLinearExpr.new([[self, -1]])
19
19
  end
20
20
 
21
- # for now
22
- def inspect
21
+ def to_s
23
22
  name
24
23
  end
24
+
25
+ # TODO add class
26
+ def inspect
27
+ to_s
28
+ end
25
29
  end
26
30
  end
@@ -24,7 +24,7 @@ module ORTools
24
24
  end
25
25
  end
26
26
 
27
- def inspect
27
+ def to_s
28
28
  vars.map do |v|
29
29
  k = v[0]
30
30
  k = k.respond_to?(:name) ? k.name : k.inspect
@@ -36,6 +36,11 @@ module ORTools
36
36
  end.join(" + ").sub(" + -", " - ")
37
37
  end
38
38
 
39
+ # TODO add class
40
+ def inspect
41
+ to_s
42
+ end
43
+
39
44
  private
40
45
 
41
46
  def add(other, sign)
@@ -1,7 +1,25 @@
1
1
  module ORTools
2
2
  class Solver
3
3
  def sum(arr)
4
- arr.sum(LinearExpr.new)
4
+ SumArray.new(arr)
5
+ end
6
+
7
+ def add(expr)
8
+ expr.extract(self)
9
+ end
10
+
11
+ def maximize(expr)
12
+ expr.coeffs.each do |v, c|
13
+ objective.set_coefficient(v, c)
14
+ end
15
+ objective.set_maximization
16
+ end
17
+
18
+ def minimize(expr)
19
+ expr.coeffs.each do |v, c|
20
+ objective.set_coefficient(v, c)
21
+ end
22
+ objective.set_minimization
5
23
  end
6
24
  end
7
25
  end
@@ -0,0 +1,23 @@
1
+ module ORTools
2
+ class SumArray < LinearExpr
3
+ attr_reader :array
4
+
5
+ def initialize(array)
6
+ @array = array.map { |v| cast_to_lin_exp(v) }
7
+ end
8
+
9
+ def add_self_to_coeff_map_or_stack(coeffs, multiplier, stack)
10
+ @array.reverse.each do |arg|
11
+ stack << [multiplier, arg]
12
+ end
13
+ end
14
+
15
+ def cast_to_lin_exp(v)
16
+ v.is_a?(Numeric) ? Constant.new(v) : v
17
+ end
18
+
19
+ def to_s
20
+ "(#{@array.map(&:to_s).join(" + ")})"
21
+ end
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module ORTools
2
- VERSION = "0.5.3"
2
+ VERSION = "0.6.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: or-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.6.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: 2021-08-03 00:00:00.000000000 Z
11
+ date: 2022-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rice
@@ -50,13 +50,17 @@ files:
50
50
  - lib/or_tools/bool_var.rb
51
51
  - lib/or_tools/comparison.rb
52
52
  - lib/or_tools/comparison_operators.rb
53
+ - lib/or_tools/constant.rb
53
54
  - lib/or_tools/cp_model.rb
54
55
  - lib/or_tools/cp_solver.rb
55
56
  - lib/or_tools/cp_solver_solution_callback.rb
56
57
  - lib/or_tools/int_var.rb
57
58
  - lib/or_tools/knapsack_solver.rb
59
+ - lib/or_tools/linear_constraint.rb
58
60
  - lib/or_tools/linear_expr.rb
61
+ - lib/or_tools/mp_variable.rb
59
62
  - lib/or_tools/objective_solution_printer.rb
63
+ - lib/or_tools/product_cst.rb
60
64
  - lib/or_tools/routing_index_manager.rb
61
65
  - lib/or_tools/routing_model.rb
62
66
  - lib/or_tools/sat_int_var.rb
@@ -64,11 +68,12 @@ files:
64
68
  - lib/or_tools/seating.rb
65
69
  - lib/or_tools/solver.rb
66
70
  - lib/or_tools/sudoku.rb
71
+ - lib/or_tools/sum_array.rb
67
72
  - lib/or_tools/tsp.rb
68
73
  - lib/or_tools/var_array_and_objective_solution_printer.rb
69
74
  - lib/or_tools/var_array_solution_printer.rb
70
75
  - lib/or_tools/version.rb
71
- homepage: https://github.com/ankane/or-tools
76
+ homepage: https://github.com/ankane/or-tools-ruby
72
77
  licenses:
73
78
  - MIT
74
79
  metadata: {}
@@ -87,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
87
92
  - !ruby/object:Gem::Version
88
93
  version: '0'
89
94
  requirements: []
90
- rubygems_version: 3.2.22
95
+ rubygems_version: 3.3.3
91
96
  signing_key:
92
97
  specification_version: 4
93
98
  summary: Operations research tools for Ruby