|
23 | 23 | #include <utility> |
24 | 24 | #include <vector> |
25 | 25 |
|
| 26 | +#include "absl/container/btree_map.h" |
26 | 27 | #include "absl/container/flat_hash_map.h" |
27 | 28 | #include "absl/container/flat_hash_set.h" |
28 | 29 | #include "absl/flags/flag.h" |
@@ -98,6 +99,14 @@ struct CpModelProtoWithMapping { |
98 | 99 | // Returns a constant CpModelProto variable created on-demand. |
99 | 100 | int LookupConstant(int64_t value); |
100 | 101 |
|
| 102 | + void AddImplication(absl::Span<const int> e, int l) { |
| 103 | + ConstraintProto* ct = proto.add_constraints(); |
| 104 | + for (int e_lit : e) { |
| 105 | + ct->add_enforcement_literal(e_lit); |
| 106 | + } |
| 107 | + ct->mutable_bool_and()->add_literals(l); |
| 108 | + } |
| 109 | + |
101 | 110 | // Convert a flatzinc argument to a variable or a list of variable. |
102 | 111 | // Note that we always encode a constant argument with a constant variable. |
103 | 112 | int LookupVar(const fz::Argument& argument); |
@@ -1382,7 +1391,7 @@ void CpModelProtoWithMapping::PutSetBooleansInCommonDomain( |
1382 | 1391 | } |
1383 | 1392 | } |
1384 | 1393 | } |
1385 | | -// array_var_set_element, set_le, set_le_reif, set_lt, set_lt_reif. |
| 1394 | +// set_le, set_le_reif, set_lt, set_lt_reif. |
1386 | 1395 | void CpModelProtoWithMapping::ExtractSetConstraint( |
1387 | 1396 | const fz::Constraint& fz_ct) { |
1388 | 1397 | if (fz_ct.type == "array_set_element") { |
@@ -1452,6 +1461,52 @@ void CpModelProtoWithMapping::ExtractSetConstraint( |
1452 | 1461 | false_range->mutable_linear()); |
1453 | 1462 | } |
1454 | 1463 | } |
| 1464 | + } else if (fz_ct.type == "array_var_set_element") { |
| 1465 | + const int index = LookupVar(fz_ct.arguments[0]); |
| 1466 | + const Domain index_domain = ReadDomainFromProto(proto.variables(index)); |
| 1467 | + const int64_t min_index = index_domain.Min(); |
| 1468 | + |
| 1469 | + const std::shared_ptr<SetVariable> target_var = |
| 1470 | + LookupSetVar(fz_ct.arguments[2]); |
| 1471 | + absl::btree_map<int64_t, int> target_values_to_literals; |
| 1472 | + for (int i = 0; i < target_var->sorted_values.size(); ++i) { |
| 1473 | + target_values_to_literals[target_var->sorted_values[i]] = |
| 1474 | + TrueLiteral(target_var->var_indices[i]); |
| 1475 | + } |
| 1476 | + |
| 1477 | + BoolArgumentProto* exactly_one = |
| 1478 | + proto.add_constraints()->mutable_exactly_one(); |
| 1479 | + for (const int64_t value : index_domain.Values()) { |
| 1480 | + const int index_literal = GetOrCreateLiteralForVarEqValue(index, value); |
| 1481 | + exactly_one->add_literals(index_literal); |
| 1482 | + |
| 1483 | + std::shared_ptr<SetVariable> set_var = |
| 1484 | + LookupSetVarAt(fz_ct.arguments[1], value - min_index); |
| 1485 | + absl::btree_map<int64_t, int> set_values_to_literals; |
| 1486 | + for (int i = 0; i < set_var->sorted_values.size(); ++i) { |
| 1487 | + set_values_to_literals[set_var->sorted_values[i]] = |
| 1488 | + TrueLiteral(set_var->var_indices[i]); |
| 1489 | + } |
| 1490 | + |
| 1491 | + for (const auto& [value, set_literal] : set_values_to_literals) { |
| 1492 | + const auto it = target_values_to_literals.find(value); |
| 1493 | + if (it == target_values_to_literals.end()) { |
| 1494 | + // index is selected => set_literal[value] is false. |
| 1495 | + AddImplication({index_literal}, FalseLiteral(set_literal)); |
| 1496 | + } else { |
| 1497 | + // index is selected => set_literal[value] == target_literal[value]. |
| 1498 | + AddImplication({index_literal, set_literal}, it->second); |
| 1499 | + AddImplication({index_literal, it->second}, set_literal); |
| 1500 | + } |
| 1501 | + } |
| 1502 | + |
| 1503 | + // Properly handle the case where not all target literals are reached. |
| 1504 | + for (const auto& [value, target_literal] : target_values_to_literals) { |
| 1505 | + if (!set_values_to_literals.contains(value)) { |
| 1506 | + AddImplication({index_literal}, FalseLiteral(target_literal)); |
| 1507 | + } |
| 1508 | + } |
| 1509 | + } |
1455 | 1510 | } else if (fz_ct.type == "set_card") { |
1456 | 1511 | std::shared_ptr<SetVariable> set_var = LookupSetVar(fz_ct.arguments[0]); |
1457 | 1512 | VarOrValue var_or_value = LookupVarOrValue(fz_ct.arguments[1]); |
@@ -1553,8 +1608,8 @@ void CpModelProtoWithMapping::ExtractSetConstraint( |
1553 | 1608 | FillDomainInProto(set_domain, domain_reduction_ct->mutable_linear()); |
1554 | 1609 |
|
1555 | 1610 | // Then propagate any remove from the set domain to the variable domain. |
1556 | | - // Note that the reif part is an equivalence. We do not want false implies |
1557 | | - // var in set (which contains the value of the var). |
| 1611 | + // Note that the reif part is an equivalence. We do not want false |
| 1612 | + // implies var in set (which contains the value of the var). |
1558 | 1613 | for (int i = 0; i < set_var->sorted_values.size(); ++i) { |
1559 | 1614 | const int64_t value = set_var->sorted_values[i]; |
1560 | 1615 | const int set_value_literal = set_var->var_indices[i]; |
@@ -1652,25 +1707,17 @@ void CpModelProtoWithMapping::ExtractSetConstraint( |
1652 | 1707 | {LookupSetVar(fz_ct.arguments[0]), LookupSetVar(fz_ct.arguments[1])}, |
1653 | 1708 | {&x_literals, &y_literals}); |
1654 | 1709 |
|
1655 | | - const auto add_implication = [&](absl::Span<const int> e, int l) { |
1656 | | - ConstraintProto* ct = proto.add_constraints(); |
1657 | | - for (int e_lit : e) { |
1658 | | - ct->add_enforcement_literal(e_lit); |
1659 | | - } |
1660 | | - ct->mutable_bool_and()->add_literals(l); |
1661 | | - }; |
1662 | | - |
1663 | 1710 | // Implement the comparison logic. |
1664 | 1711 | for (int i = 0; i < x_literals.size(); ++i) { |
1665 | 1712 | const int x_lit = x_literals[i]; |
1666 | 1713 | const int y_lit = y_literals[i]; |
1667 | 1714 | if (fz_ct.type == "set_subset") { |
1668 | | - add_implication({x_lit}, y_lit); |
| 1715 | + AddImplication({x_lit}, y_lit); |
1669 | 1716 | } else if (fz_ct.type == "set_superset") { |
1670 | | - add_implication({y_lit}, x_lit); |
| 1717 | + AddImplication({y_lit}, x_lit); |
1671 | 1718 | } else if (fz_ct.type == "set_eq") { |
1672 | | - add_implication({x_lit}, y_lit); |
1673 | | - add_implication({y_lit}, x_lit); |
| 1719 | + AddImplication({x_lit}, y_lit); |
| 1720 | + AddImplication({y_lit}, x_lit); |
1674 | 1721 | } else { |
1675 | 1722 | LOG(FATAL) << "Unsupported " << fz_ct.type; |
1676 | 1723 | } |
|
0 commit comments