Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
CpSolver.cs
Go to the documentation of this file.
1// Copyright 2010-2025 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14using System;
15using System.Collections.Generic;
16using System.Runtime.CompilerServices;
17
18namespace Google.OrTools.Sat
19{
29public class CpSolver : IDisposable
30{
31 private LogCallback? _log_callback;
32 private BestBoundCallback? _best_bound_callback;
33 private SolveWrapper? _solve_wrapper;
34 private Queue<Term> _terms;
35 private bool _disposed = false;
36
37 public double ObjectiveValue => Response!.ObjectiveValue;
38
39 public double BestObjectiveBound => Response!.BestObjectiveBound;
40
41 public string? StringParameters { get; set; }
42
43 public CpSolverResponse? Response { get; private set; }
44
45 public CpSolverStatus Solve(CpModel model, SolutionCallback? cb = null)
46 {
47 // Setup search.
48 CreateSolveWrapper();
49 if (StringParameters is not null)
50 {
51 _solve_wrapper!.SetStringParameters(StringParameters);
52 }
53
54 if (_log_callback is not null)
55 {
56 _solve_wrapper!.AddLogCallbackFromClass(_log_callback);
57 }
58
59 if (_best_bound_callback is not null)
60 {
61 _solve_wrapper!.AddBestBoundCallbackFromClass(_best_bound_callback);
62 }
63
64 if (cb is not null)
65 {
66 _solve_wrapper!.AddSolutionCallback(cb);
67 }
68
69 Response = _solve_wrapper!.Solve(model.Model);
70
71 // Cleanup search.
72 if (cb is not null)
73 {
74 _solve_wrapper.ClearSolutionCallback(cb);
75 }
76
77 ReleaseSolveWrapper();
78
79 return Response.Status;
80 }
81
83 [MethodImpl(MethodImplOptions.Synchronized)]
84 public void StopSearch() => _solve_wrapper?.StopSearch();
85
87
89 {
90 _log_callback?.Dispose();
91 _log_callback = new LogCallbackDelegate(del);
92 }
93
94 public void ClearLogCallback()
95 {
96 _log_callback?.Dispose();
97 _log_callback = null;
98 }
99
101 {
102 _best_bound_callback?.Dispose();
103 _best_bound_callback = new BestBoundCallbackDelegate(del);
104 }
105
107 {
108 _best_bound_callback?.Dispose();
109 _best_bound_callback = null;
110 }
111
112 public long Value(IntVar intVar)
113 {
114 var index = intVar.GetIndex();
115 var value = index >= 0 ? Response!.Solution[index] : -Response!.Solution[-index - 1];
116 return value;
117 }
118
119 public long Value(LinearExpr e)
120 {
121 long constant = 0;
122 long coefficient = 1;
123 var expr = e;
124 if (_terms is null)
125 {
126 _terms = new Queue<Term>();
127 }
128 else
129 {
130 _terms.Clear();
131 }
132
133 do
134 {
135 switch (expr)
136 {
137 case LinearExprBuilder a:
138 constant += coefficient * a.Offset;
139 if (coefficient == 1)
140 {
141 foreach (var sub in a.Terms)
142 {
143 _terms.Enqueue(sub);
144 }
145 }
146 else
147 {
148 foreach (var sub in a.Terms)
149 {
150 _terms.Enqueue(new Term(sub.expr, sub.coefficient * coefficient));
151 }
152 }
153
154 break;
155 case IntVar intVar:
156 var index = intVar.GetIndex();
157 var value = index >= 0 ? Response!.Solution[index] : -Response!.Solution[-index - 1];
158 constant += coefficient * value;
159 break;
160 case NotBoolVar:
161 throw new ArgumentException("Cannot evaluate a literal in an integer expression.");
162 default:
163 throw new ArgumentException("Cannot evaluate '" + expr + "' in an integer expression");
164 }
165
166 if (!_terms.TryDequeue(out var term))
167 {
168 break;
169 }
170
171 expr = term.expr;
172 coefficient = term.coefficient;
173 } while (true);
174
175 return constant;
176 }
177
178 public bool BooleanValue(ILiteral literal)
179 {
180 if (literal is BoolVar || literal is NotBoolVar)
181 {
182 var index = literal.GetIndex();
183 if (index >= 0)
184 {
185 return Response!.Solution[index] != 0;
186 }
187 else
188 {
189 return Response!.Solution[-index - 1] == 0;
190 }
191 }
192 else
193 {
194 throw new ArgumentException("Cannot evaluate '" + literal.ToString() + "' as a boolean literal");
195 }
196 }
197
198 public long NumBranches() => Response!.NumBranches;
199
200 public long NumConflicts() => Response!.NumConflicts;
201
202 public double WallTime() => Response!.WallTime;
203
204 public string SolveLog() => Response!.SolveLog;
205
206 public IList<int> SufficientAssumptionsForInfeasibility() => Response!.SufficientAssumptionsForInfeasibility;
207
208 public string SolutionInfo() => Response!.SolutionInfo;
209
215 protected virtual void Dispose(bool disposing)
216 {
217 if (_disposed)
218 {
219 return;
220 }
221
222 if (disposing)
223 {
224 _best_bound_callback?.Dispose();
225 _log_callback?.Dispose();
226 ReleaseSolveWrapper();
227 }
228
229 _disposed = true;
230 }
231
235 public void Dispose()
236 {
237 Dispose(true);
238 GC.SuppressFinalize(this);
239 }
240
241 [MethodImpl(MethodImplOptions.Synchronized)]
242 private void CreateSolveWrapper()
243 {
244 _solve_wrapper?.Dispose();
245 _solve_wrapper = new SolveWrapper();
246 }
247
248 [MethodImpl(MethodImplOptions.Synchronized)]
249 private void ReleaseSolveWrapper()
250 {
251 _solve_wrapper?.Dispose();
252 _solve_wrapper = null;
253 }
254}
255
256class LogCallbackDelegate : LogCallback
257{
258 private readonly StringToVoidDelegate _delegate_;
259
260 public LogCallbackDelegate(StringToVoidDelegate del) => _delegate_ = del;
261
262 public override void NewMessage(string message) => _delegate_(message);
263}
264
265class BestBoundCallbackDelegate : BestBoundCallback
266{
267 private readonly DoubleToVoidDelegate _delegate;
268
269 public BestBoundCallbackDelegate(DoubleToVoidDelegate del) => _delegate = del;
270
271 public override void NewBestBound(double bound) => _delegate(bound);
272}
273
274} // namespace Google.OrTools.Sat
override void NewBestBound(double bound)
BestBoundCallbackDelegate(DoubleToVoidDelegate del)
Holds a Boolean variable.
Wrapper class around the cp_model proto.
Definition CpModel.cs:24
CpModelProto Model
The underlying CpModelProto.
Definition CpModel.cs:41
static string SolverResponseStats(Google.OrTools.Sat.CpSolverResponse response)
The response returned by a solver trying to solve a CpModelProto.
Wrapper around the SAT solver.
Definition CpSolver.cs:30
void Dispose()
Releases all resources used by the CpSolver.
Definition CpSolver.cs:235
long Value(IntVar intVar)
Definition CpSolver.cs:112
void SetBestBoundCallback(DoubleToVoidDelegate del)
Definition CpSolver.cs:100
IList< int > SufficientAssumptionsForInfeasibility()
void StopSearch()
Stops the search asynchronously.
virtual void Dispose(bool disposing)
Releases unmanaged resources and optionally releases managed resources.
Definition CpSolver.cs:215
CpSolverResponse? Response
Definition CpSolver.cs:43
CpSolverStatus Solve(CpModel model, SolutionCallback? cb=null)
Definition CpSolver.cs:45
bool BooleanValue(ILiteral literal)
Definition CpSolver.cs:178
long Value(LinearExpr e)
Definition CpSolver.cs:119
void SetLogCallback(StringToVoidDelegate del)
Definition CpSolver.cs:88
Holds a integer variable with a discrete domain.
A builder class for linear expressions.
Holds a linear expression: sum (ai * xi) + b.
LogCallbackDelegate(StringToVoidDelegate del)
override void NewMessage(string message)
Holds a Boolean variable or its negation.
int GetIndex()
Returns the logical index of the literal.
CpSolverStatus
The status returned by a solver trying to solve a CpModelProto.
delegate void DoubleToVoidDelegate(double bound)
delegate void StringToVoidDelegate(string message)