Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/models/set/set_splitting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ fn normalize_subsets(universe_size: usize, subsets: &[Vec<usize>]) -> (usize, Ve

for subset in subsets {
let mut remainder = subset.clone();
// Repeated occurrences represent the same set element.
remainder.sort_unstable();
remainder.dedup();
while remainder.len() > 3 {
let positive_aux = next_element;
let negative_aux = next_element + 1;
Expand Down Expand Up @@ -154,7 +157,7 @@ impl SetSplitting {
(universe_size, size2, size3)
}

/// Universe size after decomposing all subsets to size 2 or 3.
/// Universe size after deduplicating subsets and decomposing sizes above 3.
pub fn normalized_universe_size(&self) -> usize {
self.normalized_stats().0
}
Expand Down
13 changes: 11 additions & 2 deletions src/rules/setsplitting_betweenness.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
//! Reduction from Set Splitting to Betweenness.
//!
//! Decompose each subset to size 2 or 3 using complementarity pairs, then
//! Deduplicate each subset and decompose sizes above 3 using complementarity pairs, then
//! place a single pole element `p` in the Betweenness instance. A size-2
//! subset `{u, v}` becomes `(u, p, v)`, forcing opposite sides of the pole.
//! A size-3 subset `{u, v, w}` becomes `(u, d, v)` and `(d, p, w)` with one
//! fresh auxiliary element `d`, which is satisfiable exactly when the three
//! elements are not monochromatic with respect to the pole.
//! A singleton becomes two incompatible order constraints, preserving infeasibility.

use crate::models::misc::Betweenness;
use crate::models::set::SetSplitting;
Expand Down Expand Up @@ -63,6 +64,14 @@ impl ReduceTo<Betweenness> for SetSplitting {

for subset in normalized_subsets {
match subset.as_slice() {
[u] => {
// A singleton cannot contain both colors. These orders
// cannot both hold for three distinct elements.
let auxiliary = num_elements;
num_elements += 1;
triples.push((*u, pole, auxiliary));
triples.push((pole, *u, auxiliary));
}
[u, v] => triples.push((*u, pole, *v)),
[u, v, w] => {
let auxiliary = num_elements;
Expand All @@ -75,7 +84,7 @@ impl ReduceTo<Betweenness> for SetSplitting {
SetSplitting,
Betweenness,
>(
"normalized subset must contain two or three elements"
"normalized subset must contain one, two or three elements",
));
}
}
Expand Down
31 changes: 31 additions & 0 deletions src/unit_tests/rules/setsplitting_betweenness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,37 @@ fn test_setsplitting_to_betweenness_closed_loop() {
);
}

#[test]
fn test_repeated_elements_preserve_splittability() {
for (subset, feasible) in [
(vec![0, 0, 1], true),
(vec![1, 0, 1, 0, 1], true),
(vec![0, 0], false),
(vec![1, 1, 1, 1], false),
] {
let source = SetSplitting::new(2, vec![subset]);
assert_eq!(
BruteForce::new().solve(&source).unwrap().is_some(),
feasible
);
let reduction = ReduceTo::<Betweenness>::reduce_to(&source).unwrap();
assert_eq!(
BruteForce::new()
.solve(reduction.target_problem())
.unwrap()
.is_some(),
feasible
);
if feasible {
assert_satisfaction_round_trip_from_satisfaction_target(
&source,
&reduction,
"repeated elements",
);
}
}
}

#[test]
fn test_setsplitting_to_betweenness_issue_yes_instance_structure() {
let source = issue_yes_instance();
Expand Down
Loading