Skip to content
Merged
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
4 changes: 2 additions & 2 deletions src/example_db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ fn validate_model_uniqueness(models: &[ModelExample]) -> Result<()> {

/// Build the full example database from specs.
///
/// Fast — specs store concrete instances and pre-computed solutions,
/// no solver is called.
/// ILP rule examples call the ILP solver at build time to compute solutions
/// dynamically (feature-gated behind `ilp-solver`).
pub fn build_example_db() -> Result<ExampleDb> {
let model_db = build_model_db()?;
let rule_db = build_rule_db()?;
Expand Down
29 changes: 29 additions & 0 deletions src/example_db/specs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,32 @@ where
let target = reduction.target_problem();
assemble_rule_example(&source, target, vec![solution])
}

/// Reduce the source to an ILP, solve it, and assemble the rule example.
///
/// This is the standard pattern for canonical ILP rule examples: reduce once,
/// solve the ILP, extract the source config, and build the example — avoiding
/// the double `reduce_to()` that would occur with `rule_example_with_witness`.
#[cfg(feature = "ilp-solver")]
pub fn rule_example_via_ilp<S, V>(source: S) -> RuleExample
where
S: Problem + Serialize + ReduceTo<crate::models::algebraic::ILP<V>>,
V: crate::models::algebraic::VariableDomain,
<S as ReduceTo<crate::models::algebraic::ILP<V>>>::Result:
ReductionResult<Source = S, Target = crate::models::algebraic::ILP<V>>,
{
use crate::export::SolutionPair;
let reduction = source.reduce_to();
let ilp_solution = crate::solvers::ILPSolver::new()
.solve(reduction.target_problem())
.expect("canonical example must be ILP-solvable");
let source_config = reduction.extract_solution(&ilp_solution);
assemble_rule_example(
&source,
reduction.target_problem(),
vec![SolutionPair {
source_config,
target_config: ilp_solution,
}],
)
}
24 changes: 1 addition & 23 deletions src/rules/bmf_ilp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,34 +114,12 @@ impl ReduceTo<ILP<bool>> for BMF {

#[cfg(feature = "example-db")]
pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
use crate::export::SolutionPair;
vec![crate::example_db::specs::RuleExampleSpec {
id: "bmf_to_ilp",
build: || {
// 2x2 identity matrix, rank 2
let source = BMF::new(vec![vec![true, false], vec![false, true]], 2);
// B = [[1,0],[0,1]], C = [[1,0],[0,1]]
// b: [1,0,0,1], c: [1,0,0,1]
let source_config = vec![1, 0, 0, 1, 1, 0, 0, 1];
let reduction: ReductionBMFToILP = ReduceTo::<ILP<bool>>::reduce_to(&source);
// Build target config by encoding:
// p_{0,0,0}=1, p_{0,0,1}=0, p_{0,1,0}=0, p_{0,1,1}=0
// p_{1,0,0}=0, p_{1,0,1}=0, p_{1,1,0}=0, p_{1,1,1}=1
// w: [1,0,0,1], e: [0,0,0,0]
let target_config = vec![
1, 0, 0, 1, // B
1, 0, 0, 1, // C
1, 0, 0, 0, 0, 0, 0, 1, // P
1, 0, 0, 1, // W
0, 0, 0, 0, // E
];
crate::example_db::specs::rule_example_with_witness::<_, ILP<bool>>(
source,
SolutionPair {
source_config,
target_config,
},
)
crate::example_db::specs::rule_example_via_ilp::<_, bool>(source)
},
}]
}
Expand Down
14 changes: 1 addition & 13 deletions src/rules/bottlenecktravelingsalesman_ilp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ impl ReduceTo<ILP<i32>> for BottleneckTravelingSalesman {

#[cfg(feature = "example-db")]
pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
use crate::export::SolutionPair;
vec![crate::example_db::specs::RuleExampleSpec {
id: "bottlenecktravelingsalesman_to_ilp",
build: || {
Expand All @@ -183,18 +182,7 @@ pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::Ru
crate::topology::SimpleGraph::new(4, vec![(0, 1), (1, 2), (2, 3), (3, 0)]),
vec![1, 2, 3, 4],
);
let reduction = ReduceTo::<ILP<i32>>::reduce_to(&source);
let ilp_solution = crate::solvers::ILPSolver::new()
.solve(reduction.target_problem())
.expect("canonical example must be solvable");
let source_config = reduction.extract_solution(&ilp_solution);
crate::example_db::specs::rule_example_with_witness::<_, ILP<i32>>(
source,
SolutionPair {
source_config,
target_config: ilp_solution,
},
)
crate::example_db::specs::rule_example_via_ilp::<_, i32>(source)
},
}]
}
Expand Down
12 changes: 1 addition & 11 deletions src/rules/capacityassignment_ilp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,6 @@ impl ReduceTo<ILP<bool>> for CapacityAssignment {

#[cfg(feature = "example-db")]
pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
use crate::export::SolutionPair;

vec![crate::example_db::specs::RuleExampleSpec {
id: "capacityassignment_to_ilp",
build: || {
Expand All @@ -121,15 +119,7 @@ pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::Ru
vec![vec![8, 4], vec![7, 3]],
12,
);
crate::example_db::specs::rule_example_with_witness::<_, ILP<bool>>(
source,
SolutionPair {
// link 0 → cap 1, link 1 → cap 0
source_config: vec![1, 0],
// x_{0,0}=0, x_{0,1}=1, x_{1,0}=1, x_{1,1}=0
target_config: vec![0, 1, 1, 0],
},
)
crate::example_db::specs::rule_example_via_ilp::<_, bool>(source)
},
}]
}
Expand Down
58 changes: 1 addition & 57 deletions src/rules/consecutiveblockminimization_ilp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ impl ReduceTo<ILP<bool>> for ConsecutiveBlockMinimization {

#[cfg(feature = "example-db")]
pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
use crate::export::SolutionPair;
vec![crate::example_db::specs::RuleExampleSpec {
id: "consecutiveblockminimization_to_ilp",
build: || {
Expand All @@ -122,62 +121,7 @@ pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::Ru
vec![vec![true, false, true], vec![false, true, true]],
2,
);
// Permutation [2,0,1] => columns reordered as [2,0,1]
// Row 0: A[0,2]=1, A[0,0]=1, A[0,1]=0 => [1,1,0] => 1 block
// Row 1: A[1,2]=1, A[1,0]=0, A[1,1]=1 => [1,0,1] => 2 blocks
// Total = 3 > 2, try [0,2,1]:
// Row 0: A[0,0]=1, A[0,2]=1, A[0,1]=0 => [1,1,0] => 1 block
// Row 1: A[1,0]=0, A[1,2]=1, A[1,1]=1 => [0,1,1] => 1 block
// Total = 2 <= 2. Good.
let source_config = vec![0, 2, 1];
let reduction: ReductionCBMToILP = ReduceTo::<ILP<bool>>::reduce_to(&source);
// Encode x_{c,p}: column c at position p
// c=0 at p=0: x_{0*3+0}=1, c=2 at p=1: x_{2*3+1}=1, c=1 at p=2: x_{1*3+2}=1
let n = 3;
let mut target_config = vec![0; reduction.target.num_vars];
// x_{0,0} = 1
target_config[0 * n + 0] = 1;
// x_{2,1} = 1
target_config[2 * n + 1] = 1;
// x_{1,2} = 1
target_config[1 * n + 2] = 1;
// a values
let a_offset = n * n;
let m = 2;
let matrix = vec![vec![true, false, true], vec![false, true, true]];
let perm = [0, 2, 1];
for r in 0..m {
for p in 0..n {
if matrix[r][perm[p]] {
target_config[a_offset + r * n + p] = 1;
}
}
}
// b values
let b_offset = n * n + m * n;
for r in 0..m {
for p in 0..n {
let a_cur = if matrix[r][perm[p]] { 1 } else { 0 };
let a_prev = if p > 0 && matrix[r][perm[p - 1]] {
1
} else {
0
};
if p == 0 {
target_config[b_offset + r * n + p] = a_cur;
} else if a_cur > a_prev {
target_config[b_offset + r * n + p] = 1;
}
}
}

crate::example_db::specs::rule_example_with_witness::<_, ILP<bool>>(
source,
SolutionPair {
source_config,
target_config,
},
)
crate::example_db::specs::rule_example_via_ilp::<_, bool>(source)
},
}]
}
Expand Down
14 changes: 2 additions & 12 deletions src/rules/consistencyofdatabasefrequencytables_ilp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl ReductionCDFTToILP {
}

/// Encode a satisfying source assignment as a concrete ILP variable vector.
#[cfg_attr(not(any(test, feature = "example-db")), allow(dead_code))]
#[cfg_attr(not(test), allow(dead_code))]
pub(crate) fn encode_source_solution(&self, source_solution: &[usize]) -> Vec<usize> {
let mut target_solution = vec![0usize; self.target.num_vars];
let num_attributes = self.source.num_attributes();
Expand Down Expand Up @@ -204,7 +204,6 @@ impl ReduceTo<ILP<bool>> for ConsistencyOfDatabaseFrequencyTables {

#[cfg(feature = "example-db")]
pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
use crate::export::SolutionPair;
use crate::models::misc::{FrequencyTable, KnownValue};

vec![crate::example_db::specs::RuleExampleSpec {
Expand All @@ -223,16 +222,7 @@ pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::Ru
KnownValue::new(1, 2, 1),
],
);
let source_config = vec![0, 0, 0, 0, 1, 1, 0, 2, 1, 1, 0, 1, 1, 1, 1, 1, 2, 0];
let reduction = source.clone().reduce_to();
let target_config = reduction.encode_source_solution(&source_config);
crate::example_db::specs::rule_example_with_witness::<_, ILP<bool>>(
source,
SolutionPair {
source_config,
target_config,
},
)
crate::example_db::specs::rule_example_via_ilp::<_, bool>(source)
},
}]
}
Expand Down
12 changes: 1 addition & 11 deletions src/rules/directedtwocommodityintegralflow_ilp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ impl ReduceTo<ILP<i32>> for DirectedTwoCommodityIntegralFlow {

#[cfg(feature = "example-db")]
pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
use crate::export::SolutionPair;
use crate::topology::DirectedGraph;

vec![crate::example_db::specs::RuleExampleSpec {
Expand Down Expand Up @@ -178,16 +177,7 @@ pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::Ru
1,
1,
);
// first 8 = f1, next 8 = f2
// f1: arc(0,2)=1, arc(2,4)=1, rest=0 → [1,0,0,0,1,0,0,0]
// f2: arc(1,3)=1, arc(3,5)=1, rest=0 → [0,0,0,1,0,0,0,1]
crate::example_db::specs::rule_example_with_witness::<_, ILP<i32>>(
source,
SolutionPair {
source_config: vec![1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1],
target_config: vec![1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1],
},
)
crate::example_db::specs::rule_example_via_ilp::<_, i32>(source)
},
}]
}
Expand Down
16 changes: 1 addition & 15 deletions src/rules/disjointconnectingpaths_ilp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,6 @@ impl ReduceTo<ILP<bool>> for DisjointConnectingPaths<SimpleGraph> {

#[cfg(feature = "example-db")]
pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
use crate::export::SolutionPair;
use crate::rules::ReduceTo as _;

vec![crate::example_db::specs::RuleExampleSpec {
id: "disjointconnectingpaths_to_ilp",
build: || {
Expand All @@ -181,18 +178,7 @@ pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::Ru
SimpleGraph::new(6, vec![(0, 1), (1, 2), (3, 4), (4, 5)]),
vec![(0, 2), (3, 5)],
);
let reduction = ReduceTo::<ILP<bool>>::reduce_to(&source);
let ilp_solution = crate::solvers::ILPSolver::new()
.solve(reduction.target_problem())
.expect("canonical example must be solvable");
let source_config = reduction.extract_solution(&ilp_solution);
crate::example_db::specs::rule_example_with_witness::<_, ILP<bool>>(
source,
SolutionPair {
source_config,
target_config: ilp_solution,
},
)
crate::example_db::specs::rule_example_via_ilp::<_, bool>(source)
},
}]
}
Expand Down
13 changes: 2 additions & 11 deletions src/rules/factoring_ilp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,20 +223,11 @@ impl ReduceTo<ILP<i32>> for Factoring {

#[cfg(feature = "example-db")]
pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
use crate::export::SolutionPair;

vec![crate::example_db::specs::RuleExampleSpec {
id: "factoring_to_ilp",
build: || {
crate::example_db::specs::rule_example_with_witness::<_, ILP<i32>>(
Factoring::new(3, 3, 35),
SolutionPair {
source_config: vec![1, 0, 1, 1, 1, 1],
target_config: vec![
1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0,
],
},
)
let source = Factoring::new(3, 3, 35);
crate::example_db::specs::rule_example_via_ilp::<_, i32>(source)
},
}]
}
Expand Down
15 changes: 1 addition & 14 deletions src/rules/flowshopscheduling_ilp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,25 +207,12 @@ impl ReduceTo<ILP<i32>> for FlowShopScheduling {

#[cfg(feature = "example-db")]
pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
use crate::export::SolutionPair;

vec![crate::example_db::specs::RuleExampleSpec {
id: "flowshopscheduling_to_ilp",
build: || {
// 2 machines, 3 jobs, deadline 10
let source = FlowShopScheduling::new(2, vec![vec![2, 3], vec![3, 2], vec![1, 4]], 10);
let reduction = ReduceTo::<ILP<i32>>::reduce_to(&source);
let ilp_solution = crate::solvers::ILPSolver::new()
.solve(reduction.target_problem())
.expect("canonical example must be solvable");
let source_config = reduction.extract_solution(&ilp_solution);
crate::example_db::specs::rule_example_with_witness::<_, ILP<i32>>(
source,
SolutionPair {
source_config,
target_config: ilp_solution,
},
)
crate::example_db::specs::rule_example_via_ilp::<_, i32>(source)
},
}]
}
Expand Down
14 changes: 1 addition & 13 deletions src/rules/hamiltonianpath_ilp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,24 +109,12 @@ impl ReduceTo<ILP<bool>> for HamiltonianPath<SimpleGraph> {

#[cfg(feature = "example-db")]
pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
use crate::export::SolutionPair;
vec![crate::example_db::specs::RuleExampleSpec {
id: "hamiltonianpath_to_ilp",
build: || {
// Path graph: 0-1-2-3 (has Hamiltonian path)
let source = HamiltonianPath::new(SimpleGraph::new(4, vec![(0, 1), (1, 2), (2, 3)]));
let reduction = ReduceTo::<ILP<bool>>::reduce_to(&source);
let ilp_solution = crate::solvers::ILPSolver::new()
.solve(reduction.target_problem())
.expect("canonical example must be solvable");
let source_config = reduction.extract_solution(&ilp_solution);
crate::example_db::specs::rule_example_with_witness::<_, ILP<bool>>(
source,
SolutionPair {
source_config,
target_config: ilp_solution,
},
)
crate::example_db::specs::rule_example_via_ilp::<_, bool>(source)
},
}]
}
Expand Down
Loading
Loading