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
28 changes: 28 additions & 0 deletions docs/paper/reductions.typ
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@
"QuadraticDiophantineEquations": [Quadratic Diophantine Equations],
"QuantifiedBooleanFormulas": [Quantified Boolean Formulas (QBF)],
"RectilinearPictureCompression": [Rectilinear Picture Compression],
"RegisterSufficiency": [Register Sufficiency],
"ResourceConstrainedScheduling": [Resource Constrained Scheduling],
"RootedTreeStorageAssignment": [Rooted Tree Storage Assignment],
"SchedulingToMinimizeWeightedCompletionTime": [Scheduling to Minimize Weighted Completion Time],
Expand Down Expand Up @@ -4170,6 +4171,33 @@ A classical NP-complete problem from Garey and Johnson @garey1979[Ch.~3, p.~76],
]
}

#{
let x = load-model-example("RegisterSufficiency")
let n = x.instance.num_vertices
let arcs = x.instance.arcs
let K = x.instance.bound
let sigma = x.optimal_config
// Build evaluation order (position -> vertex)
let order = range(n).map(pos =>
range(n).find(v => sigma.at(v) == pos)
)
[
#problem-def("RegisterSufficiency")[
Given a directed acyclic graph $G = (V, A)$ with $n = |V|$ vertices, where each arc $(v, u) in A$ means vertex $v$ depends on vertex $u$, and a positive integer $K$, determine whether there exists an evaluation ordering $v_(pi(0)), v_(pi(1)), dots, v_(pi(n-1))$ of all vertices such that the computation can be performed using at most $K$ registers. A value must reside in a register from the moment it is computed until all vertices that depend on it have been evaluated.
][
Register Sufficiency is problem SS19 (also A11 PO1) in Garey & Johnson @garey1979. NP-complete via reduction from 3-SAT @sethi1975. Remains NP-complete even when all vertices have out-degree at most 2. For expression trees (DAGs with tree structure), the Sethi--Ullman algorithm solves the problem in $O(n)$ time @sethiUllman1970. For general DAGs, Kessler's dynamic programming over register states runs in $O(n^2 dot 2^n)$ time @kessler1998.

*Example.* Let $n = #n$ vertices with arcs (dependencies): #{arcs.map(a => $v_#(a.at(0)) arrow.r v_#(a.at(1))$).join(", ")}. Bound $K = #K$. The evaluation order $pi = (#order.map(v => $v_#v$).join(", "))$ achieves a maximum of $#K$ registers.

#pred-commands(
"pred create --example RegisterSufficiency -o register-sufficiency.json",
"pred solve register-sufficiency.json --solver brute-force",
"pred evaluate register-sufficiency.json --config " + x.optimal_config.map(str).join(","),
)
]
]
}

#{
let x = load-model-example("RuralPostman")
let nv = x.instance.graph.num_vertices
Expand Down
29 changes: 29 additions & 0 deletions docs/paper/references.bib
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
@article{sethi1975,
author = {Ravi Sethi},
title = {Complete Register Allocation Problems},
journal = {SIAM Journal on Computing},
volume = {4},
number = {3},
pages = {226--248},
year = {1975},
doi = {10.1137/0204020}
}

@article{sethiUllman1970,
author = {Ravi Sethi and Jeffrey D. Ullman},
title = {The Generation of Optimal Code for Arithmetic Expressions},
journal = {Journal of the ACM},
volume = {17},
number = {4},
pages = {715--728},
year = {1970},
doi = {10.1145/321607.321620}
}

@phdthesis{kessler1998,
author = {Christoph W. Kessler},
title = {Scheduling Expression {DAG}s for Minimal Register Need},
school = {Universit{\"a}t des Saarlandes},
year = {1998}
}

@inproceedings{wagner1975,
author = {Robert A. Wagner},
title = {On the Complexity of the Extended String-to-String Correction Problem},
Expand Down
1 change: 1 addition & 0 deletions problemreductions-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ Flags by problem type:
StringToStringCorrection --source-string, --target-string, --bound [--alphabet-size]
D2CIF --arcs, --capacities, --source-1, --sink-1, --source-2, --sink-2, --requirement-1, --requirement-2
MinimumDummyActivitiesPert --arcs [--num-vertices]
RegisterSufficiency --arcs, --bound [--num-vertices]
CBQ --domain-size, --relations, --conjuncts-spec
IntegerExpressionMembership --expression (JSON), --target
ILP, CircuitSAT (via reduction only)
Expand Down
33 changes: 32 additions & 1 deletion problemreductions-cli/src/commands/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use problemreductions::models::misc::{
IntegerExpressionMembership, JobShopScheduling, KnownValue, KthLargestMTuple,
LongestCommonSubsequence, MinimumTardinessSequencing, MultiprocessorScheduling, PaintShop,
PartiallyOrderedKnapsack, ProductionPlanning, QueryArg, RectilinearPictureCompression,
ResourceConstrainedScheduling, SchedulingToMinimizeWeightedCompletionTime,
RegisterSufficiency, ResourceConstrainedScheduling, SchedulingToMinimizeWeightedCompletionTime,
SchedulingWithIndividualDeadlines, SequencingToMinimizeMaximumCumulativeCost,
SequencingToMinimizeWeightedCompletionTime, SequencingToMinimizeWeightedTardiness,
SequencingWithReleaseTimesAndDeadlines, SequencingWithinIntervals, ShortestCommonSupersequence,
Expand Down Expand Up @@ -708,6 +708,9 @@ fn example_for(canonical: &str, graph_type: Option<&str>) -> &'static str {
}
"MinimumFeedbackArcSet" => "--arcs \"0>1,1>2,2>0\"",
"MinimumDummyActivitiesPert" => "--arcs \"0>2,0>3,1>3,1>4,2>5\" --num-vertices 6",
"RegisterSufficiency" => {
"--arcs \"2>0,2>1,3>1,4>2,4>3,5>0,6>4,6>5\" --bound 3 --num-vertices 7"
}
"StrongConnectivityAugmentation" => {
"--arcs \"0>1,1>2\" --candidate-arcs \"2>0:1\" --bound 1"
}
Expand Down Expand Up @@ -4220,6 +4223,34 @@ pub fn create(args: &CreateArgs, out: &OutputConfig) -> Result<()> {
)
}

// RegisterSufficiency
"RegisterSufficiency" => {
let usage = "Usage: pred create RegisterSufficiency --arcs \"2>0,2>1,3>1,4>2,4>3,5>0,6>4,6>5\" --bound 3 [--num-vertices N]";
let arcs_str = args.arcs.as_deref().ok_or_else(|| {
anyhow::anyhow!(
"RegisterSufficiency requires --arcs and --bound\n\n\
{usage}"
)
})?;
let bound = args.bound.ok_or_else(|| {
anyhow::anyhow!(
"RegisterSufficiency requires --bound\n\n\
{usage}"
)
})?;
if bound < 0 {
bail!("RegisterSufficiency --bound must be non-negative\n\n{usage}");
}
let bound = bound as usize;
let (graph, _) = parse_directed_graph(arcs_str, args.num_vertices)?;
let n = graph.num_vertices();
let arcs = graph.arcs();
(
ser(RegisterSufficiency::new(n, arcs, bound))?,
resolved_variant.clone(),
)
}

// MixedChinesePostman
"MixedChinesePostman" => {
let usage = "Usage: pred create MixedChinesePostman --graph 0-2,1-3,0-4,4-2 --arcs \"0>1,1>2,2>3,3>0\" --edge-weights 2,3,1,2 --arc-costs 2,3,1,4 [--num-vertices N]";
Expand Down
32 changes: 32 additions & 0 deletions problemreductions-cli/tests/cli_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4088,6 +4088,38 @@ fn test_create_rectilinear_picture_compression_rejects_ragged_matrix() {
);
}

#[test]
fn test_create_register_sufficiency() {
let output_file = std::env::temp_dir().join("pred_test_create_register_sufficiency.json");
let output = pred()
.args([
"-o",
output_file.to_str().unwrap(),
"create",
"RegisterSufficiency",
"--arcs",
"2>0,2>1,3>1,4>2,4>3,5>0,6>4,6>5",
"--bound",
"3",
"--num-vertices",
"7",
])
.output()
.unwrap();
assert!(
output.status.success(),
"stderr: {}",
String::from_utf8_lossy(&output.stderr)
);
let content = std::fs::read_to_string(&output_file).unwrap();
let json: serde_json::Value = serde_json::from_str(&content).unwrap();
assert_eq!(json["type"], "RegisterSufficiency");
assert_eq!(json["data"]["num_vertices"], 7);
assert_eq!(json["data"]["bound"], 3);
assert_eq!(json["data"]["arcs"].as_array().unwrap().len(), 8);
std::fs::remove_file(&output_file).ok();
}

#[test]
fn test_create_help_uses_generic_matrix_and_k_descriptions() {
let output = pred().args(["create", "--help"]).output().unwrap();
Expand Down
4 changes: 4 additions & 0 deletions src/models/misc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
//! - [`PrecedenceConstrainedScheduling`]: Schedule unit tasks on processors by deadline
//! - [`ProductionPlanning`]: Meet all period demands within capacity and total-cost bounds
//! - [`RectilinearPictureCompression`]: Cover 1-entries with bounded rectangles
//! - [`RegisterSufficiency`]: Evaluate DAG computation with bounded registers
//! - [`ResourceConstrainedScheduling`]: Schedule unit-length tasks on processors with resource constraints
//! - [`SchedulingWithIndividualDeadlines`]: Meet per-task deadlines on parallel processors
//! - [`StackerCrane`]: Minimize the total length of a closed walk through required arcs
Expand Down Expand Up @@ -89,6 +90,7 @@ pub(crate) mod partition;
mod precedence_constrained_scheduling;
mod production_planning;
mod rectilinear_picture_compression;
mod register_sufficiency;
pub(crate) mod resource_constrained_scheduling;
mod scheduling_to_minimize_weighted_completion_time;
mod scheduling_with_individual_deadlines;
Expand Down Expand Up @@ -134,6 +136,7 @@ pub use partition::Partition;
pub use precedence_constrained_scheduling::PrecedenceConstrainedScheduling;
pub use production_planning::ProductionPlanning;
pub use rectilinear_picture_compression::RectilinearPictureCompression;
pub use register_sufficiency::RegisterSufficiency;
pub use resource_constrained_scheduling::ResourceConstrainedScheduling;
pub use scheduling_to_minimize_weighted_completion_time::SchedulingToMinimizeWeightedCompletionTime;
pub use scheduling_with_individual_deadlines::SchedulingWithIndividualDeadlines;
Expand Down Expand Up @@ -195,6 +198,7 @@ pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::M
specs.extend(subset_sum::canonical_model_example_specs());
specs.extend(three_partition::canonical_model_example_specs());
specs.extend(cosine_product_integration::canonical_model_example_specs());
specs.extend(register_sufficiency::canonical_model_example_specs());
specs.extend(kth_largest_m_tuple::canonical_model_example_specs());
specs
}
Loading
Loading