@@ -197,9 +197,15 @@ void NeighborhoodGeneratorHelper::InitializeHelperData() {
197
197
198
198
const int num_variables = model_proto_.variables ().size ();
199
199
is_in_objective_.resize (num_variables, false );
200
+ has_positive_objective_coefficient_.resize (num_variables, false );
200
201
if (model_proto_.has_objective ()) {
201
- for (const int ref : model_proto_.objective ().vars ()) {
202
+ for (int i = 0 ; i < model_proto_.objective ().vars_size (); ++i) {
203
+ const int ref = model_proto_.objective ().vars (i);
204
+ const int64_t coeff = model_proto_.objective ().coeffs (i);
205
+ DCHECK_NE (coeff, 0 );
202
206
is_in_objective_[PositiveRef (ref)] = true ;
207
+ has_positive_objective_coefficient_[PositiveRef (ref)] =
208
+ ref == PositiveRef (ref) ? coeff > 0 : coeff < 0 ;
203
209
}
204
210
}
205
211
}
@@ -1318,6 +1324,26 @@ double NeighborhoodGenerator::Synchronize() {
1318
1324
return total_dtime;
1319
1325
}
1320
1326
1327
+ std::vector<int >
1328
+ NeighborhoodGeneratorHelper::ImprovableObjectiveVariablesWhileHoldingLock (
1329
+ const CpSolverResponse& initial_solution) const {
1330
+ std::vector<int > result;
1331
+ absl::ReaderMutexLock lock (&domain_mutex_);
1332
+ for (const int var : active_objective_variables_) {
1333
+ const auto & domain =
1334
+ model_proto_with_only_variables_.variables (var).domain ();
1335
+ bool at_best_value = false ;
1336
+ if (has_positive_objective_coefficient_[var]) {
1337
+ at_best_value = initial_solution.solution (var) == domain[0 ];
1338
+ } else {
1339
+ at_best_value =
1340
+ initial_solution.solution (var) == domain[domain.size () - 1 ];
1341
+ }
1342
+ if (!at_best_value) result.push_back (var);
1343
+ }
1344
+ return result;
1345
+ }
1346
+
1321
1347
namespace {
1322
1348
1323
1349
template <class T >
@@ -1407,21 +1433,20 @@ Neighborhood VariableGraphNeighborhoodGenerator::Generate(
1407
1433
{
1408
1434
absl::ReaderMutexLock graph_lock (&helper_.graph_mutex_ );
1409
1435
1436
+ std::vector<int > initial_vars =
1437
+ helper_.ImprovableObjectiveVariablesWhileHoldingLock (initial_solution);
1438
+ if (initial_vars.empty ()) {
1439
+ initial_vars = helper_.ActiveVariablesWhileHoldingLock ();
1440
+ }
1410
1441
// The number of active variables can decrease asynchronously.
1411
1442
// We read the exact number while locked.
1412
1443
const int num_active_vars =
1413
1444
helper_.ActiveVariablesWhileHoldingLock ().size ();
1414
- const int num_objective_variables =
1415
- helper_.ActiveObjectiveVariablesWhileHoldingLock ().size ();
1416
1445
const int target_size = std::ceil (data.difficulty * num_active_vars);
1417
1446
if (target_size == num_active_vars) return helper_.FullNeighborhood ();
1418
1447
1419
1448
const int first_var =
1420
- num_objective_variables > 0 // Prefer objective variables.
1421
- ? helper_.ActiveObjectiveVariablesWhileHoldingLock ()
1422
- [absl::Uniform<int >(random , 0 , num_objective_variables)]
1423
- : helper_.ActiveVariablesWhileHoldingLock ()[absl::Uniform<int >(
1424
- random , 0 , num_active_vars)];
1449
+ initial_vars[absl::Uniform<int >(random , 0 , initial_vars.size ())];
1425
1450
visited_variables_set[first_var] = true ;
1426
1451
visited_variables.push_back (first_var);
1427
1452
relaxed_variables.push_back (first_var);
@@ -1478,7 +1503,8 @@ Neighborhood ArcGraphNeighborhoodGenerator::Generate(
1478
1503
{
1479
1504
absl::ReaderMutexLock graph_lock (&helper_.graph_mutex_ );
1480
1505
num_active_vars = helper_.ActiveVariablesWhileHoldingLock ().size ();
1481
- active_objective_vars = helper_.ActiveObjectiveVariablesWhileHoldingLock ();
1506
+ active_objective_vars =
1507
+ helper_.ImprovableObjectiveVariablesWhileHoldingLock (initial_solution);
1482
1508
constraints_to_vars = helper_.ConstraintToVar ();
1483
1509
vars_to_constraints = helper_.VarToConstraint ();
1484
1510
}
@@ -1569,13 +1595,12 @@ Neighborhood ConstraintGraphNeighborhoodGenerator::Generate(
1569
1595
const int target_size = std::ceil (data.difficulty * num_active_vars);
1570
1596
if (target_size == num_active_vars) return helper_.FullNeighborhood ();
1571
1597
1572
- // Start by a random constraint.
1598
+ // Start from a random active constraint.
1573
1599
const int num_active_constraints = helper_.ConstraintToVar ().size ();
1574
- if (num_active_constraints != 0 ) {
1575
- next_constraints.push_back (
1576
- absl::Uniform<int >(random , 0 , num_active_constraints));
1577
- added_constraints[next_constraints.back ()] = true ;
1578
- }
1600
+ if (num_active_constraints == 0 ) return helper_.NoNeighborhood ();
1601
+ next_constraints.push_back (
1602
+ absl::Uniform<int >(random , 0 , num_active_constraints));
1603
+ added_constraints[next_constraints.back ()] = true ;
1579
1604
1580
1605
while (relaxed_variables.size () < target_size) {
1581
1606
// Stop if we have a full connected component.
@@ -1667,9 +1692,9 @@ Neighborhood DecompositionGraphNeighborhoodGenerator::Generate(
1667
1692
elements[i].tie_break = absl::Uniform<double >(random , 0.0 , 1.0 );
1668
1693
}
1669
1694
1670
- // We start by a random active variable.
1695
+ // We start from a random active variable.
1671
1696
//
1672
- // Note that while num_vars contains all variables, all the fixed variable
1697
+ // Note that while num_vars contains all variables, all the fixed variables
1673
1698
// will have no associated constraint, so we don't want to start from a
1674
1699
// random variable.
1675
1700
//
0 commit comments