diff --git a/ortools/sat/csharp/CpSolver.cs b/ortools/sat/csharp/CpSolver.cs
index 0b6c0dbe71..e050c9d454 100644
--- a/ortools/sat/csharp/CpSolver.cs
+++ b/ortools/sat/csharp/CpSolver.cs
@@ -26,238 +26,168 @@ namespace Google.OrTools.Sat
* variables in the best solution, as well as general statistics of the search.
*
*/
-public class CpSolver
+public sealed class CpSolver : IDisposable
{
- /** Solves the given model, and returns the solve status. */
- public CpSolverStatus Solve(CpModel model, SolutionCallback cb = null)
+ private LogCallback? _log_callback;
+ private BestBoundCallback? _best_bound_callback;
+ private SolveWrapper? _solve_wrapper;
+ private Queue _terms;
+ private bool _disposed = false;
+
+ public double ObjectiveValue => Response!.ObjectiveValue;
+
+ public double BestObjectiveBound => Response!.BestObjectiveBound;
+
+ public string? StringParameters { get; set; }
+
+ public CpSolverResponse? Response { get; private set; }
+
+ public CpSolverStatus Solve(CpModel model, SolutionCallback? cb = null)
{
// Setup search.
CreateSolveWrapper();
- if (string_parameters_ is not null)
+ if (StringParameters is not null)
{
- solve_wrapper_.SetStringParameters(string_parameters_);
- }
- if (log_callback_ is not null)
- {
- solve_wrapper_.AddLogCallbackFromClass(log_callback_);
- }
- if (best_bound_callback_ is not null)
- {
- solve_wrapper_.AddBestBoundCallbackFromClass(best_bound_callback_);
- }
- if (cb is not null)
- {
- solve_wrapper_.AddSolutionCallback(cb);
+ _solve_wrapper!.SetStringParameters(StringParameters);
}
- response_ = solve_wrapper_.Solve(model.Model);
+ if (_log_callback is not null)
+ {
+ _solve_wrapper!.AddLogCallbackFromClass(_log_callback);
+ }
+
+ if (_best_bound_callback is not null)
+ {
+ _solve_wrapper!.AddBestBoundCallbackFromClass(_best_bound_callback);
+ }
+
+ if (cb is not null)
+ {
+ _solve_wrapper!.AddSolutionCallback(cb);
+ }
+
+ Response = _solve_wrapper!.Solve(model.Model);
// Cleanup search.
if (cb is not null)
{
- solve_wrapper_.ClearSolutionCallback(cb);
+ _solve_wrapper.ClearSolutionCallback(cb);
}
+
ReleaseSolveWrapper();
- return response_.Status;
- }
-
- /** Deprecated, use Solve() instead. */
- [ObsoleteAttribute("This method is obsolete. Call Solve instead.", false)]
- public CpSolverStatus SolveWithSolutionCallback(CpModel model, SolutionCallback cb)
- {
- return Solve(model, cb);
- }
-
- /** Deprecated, use Solve() instead. */
- [ObsoleteAttribute("This method is obsolete. Call Solve instead with the enumerate_all_solutions parameter.",
- false)]
- public CpSolverStatus SearchAllSolutions(CpModel model, SolutionCallback cb)
- {
- string old_parameters = string_parameters_;
- string_parameters_ += " enumerate_all_solutions:true";
- Solve(model, cb);
- string_parameters_ = old_parameters;
- return response_.Status;
+ return Response.Status;
}
/** Stops the search asynchronously. */
[MethodImpl(MethodImplOptions.Synchronized)]
- public void StopSearch()
- {
- if (solve_wrapper_ is not null)
- {
- solve_wrapper_.StopSearch();
- }
- }
+ public void StopSearch() => _solve_wrapper?.StopSearch();
- [MethodImpl(MethodImplOptions.Synchronized)]
- private void CreateSolveWrapper()
- {
- solve_wrapper_ = new SolveWrapper();
- }
-
- [MethodImpl(MethodImplOptions.Synchronized)]
- private void ReleaseSolveWrapper()
- {
- solve_wrapper_ = null;
- }
-
- /** Statistics on the solution found as a string.*/
- public String ResponseStats()
- {
- return CpSatHelper.SolverResponseStats(response_);
- }
-
- /** The best objective value found during search.*/
- public double ObjectiveValue
- {
- get {
- return response_.ObjectiveValue;
- }
- }
-
- /**
- *
- * The best lower bound found when minimizing, of the best upper bound found when maximizing
- *
- */
- public double BestObjectiveBound
- {
- get {
- return response_.BestObjectiveBound;
- }
- }
-
- /** The parameters of the search, stored as a string */
- public string StringParameters
- {
- get {
- return string_parameters_;
- }
- set {
- string_parameters_ = value;
- }
- }
+ public string ResponseStats() => CpSatHelper.SolverResponseStats(Response);
public void SetLogCallback(StringToVoidDelegate del)
{
- log_callback_ = new LogCallbackDelegate(del);
+ _log_callback?.Dispose();
+ _log_callback = new LogCallbackDelegate(del);
}
public void ClearLogCallback()
{
- log_callback_ = null;
+ _log_callback?.Dispose();
+ _log_callback = null;
}
public void SetBestBoundCallback(DoubleToVoidDelegate del)
{
- best_bound_callback_ = new BestBoundCallbackDelegate(del);
+ _best_bound_callback?.Dispose();
+ _best_bound_callback = new BestBoundCallbackDelegate(del);
}
public void ClearBestBoundCallback()
{
- best_bound_callback_ = null;
+ _best_bound_callback?.Dispose();
+ _best_bound_callback = null;
}
- public CpSolverResponse Response
- {
- get {
- return response_;
- }
- }
-
- /**
- *
- * Returns the value of an integer variable in the last solution found.
- *
- */
public long Value(IntVar intVar)
{
- int index = intVar.GetIndex();
- long value = index >= 0 ? response_.Solution[index] : -response_.Solution[-index - 1];
+ var index = intVar.GetIndex();
+ var value = index >= 0 ? Response!.Solution[index] : -Response!.Solution[-index - 1];
return value;
}
- /**
- *
- * Returns the value of a linear expression in the last solution found.
- *
- */
public long Value(LinearExpr e)
{
long constant = 0;
long coefficient = 1;
- LinearExpr expr = e;
- if (terms_ is null)
+ var expr = e;
+ if (_terms is null)
{
- terms_ = new Queue();
+ _terms = new Queue();
}
else
{
- terms_.Clear();
+ _terms.Clear();
}
do
{
switch (expr)
{
- case LinearExprBuilder a:
- constant += coefficient * a.Offset;
- if (coefficient == 1)
- {
- foreach (Term sub in a.Terms)
+ case LinearExprBuilder a:
+ constant += coefficient * a.Offset;
+ if (coefficient == 1)
{
- terms_.Enqueue(sub);
+ foreach (var sub in a.Terms)
+ {
+ _terms.Enqueue(sub);
+ }
}
- }
- else
- {
- foreach (Term sub in a.Terms)
+ else
{
- terms_.Enqueue(new Term(sub.expr, sub.coefficient * coefficient));
+ foreach (var sub in a.Terms)
+ {
+ _terms.Enqueue(new Term(sub.expr, sub.coefficient * coefficient));
+ }
}
- }
- break;
- case IntVar intVar:
- int index = intVar.GetIndex();
- long value = index >= 0 ? response_.Solution[index] : -response_.Solution[-index - 1];
- constant += coefficient * value;
- break;
- case NotBoolVar:
- throw new ArgumentException("Cannot evaluate a literal in an integer expression.");
- default:
- throw new ArgumentException("Cannot evaluate '" + expr + "' in an integer expression");
+
+ break;
+ case IntVar intVar:
+ var index = intVar.GetIndex();
+ var value = index >= 0 ? Response!.Solution[index] : -Response!.Solution[-index - 1];
+ constant += coefficient * value;
+ break;
+ case NotBoolVar:
+ throw new ArgumentException("Cannot evaluate a literal in an integer expression.");
+ default:
+ throw new ArgumentException("Cannot evaluate '" + expr + "' in an integer expression");
}
- if (!terms_.TryDequeue(out var term))
+ if (!_terms.TryDequeue(out var term))
{
break;
}
+
expr = term.expr;
coefficient = term.coefficient;
- } while (true);
+ }
+ while (true);
return constant;
}
- /**
- *
- * Returns the Boolean value of a literal in the last solution found.
- *
- */
- public Boolean BooleanValue(ILiteral literal)
+ public bool BooleanValue(ILiteral literal)
{
if (literal is BoolVar || literal is NotBoolVar)
{
- int index = literal.GetIndex();
+ var index = literal.GetIndex();
if (index >= 0)
{
- return response_.Solution[index] != 0;
+ return Response!.Solution[index] != 0;
}
else
{
- return response_.Solution[-index - 1] == 0;
+ return Response!.Solution[-index - 1] == 0;
}
}
else
@@ -266,76 +196,61 @@ public class CpSolver
}
}
- /** Returns the number of branches explored during search. */
- public long NumBranches()
+ public long NumBranches() => Response!.NumBranches;
+
+ public long NumConflicts() => Response!.NumConflicts;
+
+ public double WallTime() => Response!.WallTime;
+
+ public IList SufficientAssumptionsForInfeasibility() => Response!.SufficientAssumptionsForInfeasibility;
+
+ public string SolutionInfo() => Response!.SolutionInfo;
+
+ public void Dispose()
{
- return response_.NumBranches;
+ if (_disposed)
+ {
+ return;
+ }
+
+ _best_bound_callback?.Dispose();
+ _log_callback?.Dispose();
+ ReleaseSolveWrapper();
+ _disposed = true;
}
- /** Returns the number of conflicts created during search. */
- public long NumConflicts()
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ private void CreateSolveWrapper()
{
- return response_.NumConflicts;
+ _solve_wrapper?.Dispose();
+ _solve_wrapper = new SolveWrapper();
}
- /** Returns the wall time of the search. */
- public double WallTime()
+ [MethodImpl(MethodImplOptions.Synchronized)]
+ private void ReleaseSolveWrapper()
{
- return response_.WallTime;
+ _solve_wrapper?.Dispose();
+ _solve_wrapper = null;
}
-
- public IList SufficientAssumptionsForInfeasibility()
- {
- return response_.SufficientAssumptionsForInfeasibility;
- }
-
- /**
- *
- * Returns some information on how the solution was found, or the reason why the model or the
- * parameters are invalid.
- *
- */
- public String SolutionInfo()
- {
- return response_.SolutionInfo;
- }
-
- private CpSolverResponse response_;
- private LogCallback log_callback_;
- private BestBoundCallback best_bound_callback_;
- private string string_parameters_;
- private SolveWrapper solve_wrapper_;
- private Queue terms_;
}
class LogCallbackDelegate : LogCallback
{
- public LogCallbackDelegate(StringToVoidDelegate del)
- {
- this.delegate_ = del;
- }
+ private readonly StringToVoidDelegate _delegate_;
- public override void NewMessage(string message)
- {
- delegate_(message);
- }
+ public LogCallbackDelegate(StringToVoidDelegate del) => _delegate_ = del;
- private StringToVoidDelegate delegate_;
+ public override void NewMessage(string message) => _delegate_(message);
}
class BestBoundCallbackDelegate : BestBoundCallback
{
- public BestBoundCallbackDelegate(DoubleToVoidDelegate del)
- {
- this.delegate_ = del;
- }
+ private readonly DoubleToVoidDelegate _delegate;
- public override void NewBestBound(double bound)
- {
- delegate_(bound);
- }
+ public BestBoundCallbackDelegate(DoubleToVoidDelegate del) => _delegate = del;
+
+ public override void NewBestBound(double bound) => _delegate(bound);
- private DoubleToVoidDelegate delegate_;
}
} // namespace Google.OrTools.Sat