Skip to content
9 changes: 9 additions & 0 deletions docs/paper/reductions.typ
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"SubsetSum": [Subset Sum],
"MinimumFeedbackArcSet": [Minimum Feedback Arc Set],
"MinimumFeedbackVertexSet": [Minimum Feedback Vertex Set],
"ResourceConstrainedScheduling": [Resource Constrained Scheduling],
"ShortestCommonSupersequence": [Shortest Common Supersequence],
"MinimumSumMulticenter": [Minimum Sum Multicenter],
"SubgraphIsomorphism": [Subgraph Isomorphism],
Expand Down Expand Up @@ -1196,6 +1197,14 @@ Biclique Cover is equivalent to factoring the biadjacency matrix $M$ of the bipa
*Example.* Let $A = {3, 7, 1, 8, 2, 4}$ ($n = 6$) and target $B = 11$. Selecting $A' = {3, 8}$ gives sum $3 + 8 = 11 = B$. Another solution: $A' = {7, 4}$ with sum $7 + 4 = 11 = B$.
]

#problem-def("ResourceConstrainedScheduling")[
Given a set $T$ of $n$ unit-length tasks, $m$ identical processors, $r$ resources with bounds $B_i$ ($1 <= i <= r$), resource requirements $R_i (t)$ for each task $t$ and resource $i$ ($0 <= R_i (t) <= B_i$), and an overall deadline $D in ZZ^+$, determine whether there exists an $m$-processor schedule $sigma : T -> {0, dots, D-1}$ such that for every time slot $u$, at most $m$ tasks are scheduled at $u$ and $sum_(t : sigma(t) = u) R_i (t) <= B_i$ for each resource $i$.
][
RESOURCE CONSTRAINED SCHEDULING is problem SS10 in Garey & Johnson's compendium @garey1979. It is NP-complete in the strong sense, even for $r = 1$ resource and $m = 3$ processors, by reduction from 3-PARTITION @garey1975. For $m = 2$ processors with arbitrary $r$, the problem is solvable in polynomial time via bipartite matching. The general case subsumes bin-packing-style constraints across multiple resource dimensions.

*Example.* Let $n = 6$ tasks, $m = 3$ processors, $r = 1$ resource with $B_1 = 20$, and deadline $D = 2$. Resource requirements: $R_1(t_1) = 6$, $R_1(t_2) = 7$, $R_1(t_3) = 7$, $R_1(t_4) = 6$, $R_1(t_5) = 8$, $R_1(t_6) = 6$. Schedule: slot 0 $arrow.l {t_1, t_2, t_3}$ (3 tasks, resource $= 20$), slot 1 $arrow.l {t_4, t_5, t_6}$ (3 tasks, resource $= 20$). Both constraints satisfied; answer: YES.
]

#problem-def("ShortestCommonSupersequence")[
Given a finite alphabet $Sigma$, a set $R = {r_1, dots, r_m}$ of strings over $Sigma^*$, and a positive integer $K$, determine whether there exists a string $w in Sigma^*$ with $|w| lt.eq K$ such that every string $r_i in R$ is a _subsequence_ of $w$: there exist indices $1 lt.eq j_1 < j_2 < dots < j_(|r_i|) lt.eq |w|$ with $w[j_k] = r_i [k]$ for all $k$.
][
Expand Down
26 changes: 26 additions & 0 deletions docs/src/reductions/problem_schemas.json
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,32 @@
}
]
},
{
"name": "ResourceConstrainedScheduling",
"description": "Schedule unit-length tasks on m processors with resource constraints and a deadline",
"fields": [
{
"name": "num_processors",
"type_name": "usize",
"description": "Number of identical processors m"
},
{
"name": "resource_bounds",
"type_name": "Vec<u64>",
"description": "Resource bound B_i for each resource i"
},
{
"name": "resource_requirements",
"type_name": "Vec<Vec<u64>>",
"description": "R_i(t) for each task t and resource i (n x r matrix)"
},
{
"name": "deadline",
"type_name": "u64",
"description": "Overall deadline D"
}
]
},
{
"name": "RuralPostman",
"description": "Find a circuit covering required edges with total length at most B (Rural Postman Problem)",
Expand Down
39 changes: 23 additions & 16 deletions docs/src/reductions/reduction_graph.json
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,13 @@
"doc_path": "models/algebraic/struct.QUBO.html",
"complexity": "2^num_vars"
},
{
"name": "ResourceConstrainedScheduling",
"variant": {},
"category": "misc",
"doc_path": "models/misc/struct.ResourceConstrainedScheduling.html",
"complexity": "deadline ^ num_tasks"
},
{
"name": "RuralPostman",
"variant": {
Expand Down Expand Up @@ -535,7 +542,7 @@
},
{
"source": 4,
"target": 52,
"target": 53,
"overhead": [
{
"field": "num_spins",
Expand Down Expand Up @@ -699,7 +706,7 @@
},
{
"source": 20,
"target": 54,
"target": 55,
"overhead": [
{
"field": "num_elements",
Expand All @@ -710,7 +717,7 @@
},
{
"source": 21,
"target": 49,
"target": 50,
"overhead": [
{
"field": "num_clauses",
Expand Down Expand Up @@ -755,7 +762,7 @@
},
{
"source": 24,
"target": 52,
"target": 53,
"overhead": [
{
"field": "num_spins",
Expand Down Expand Up @@ -1201,7 +1208,7 @@
},
{
"source": 47,
"target": 51,
"target": 52,
"overhead": [
{
"field": "num_spins",
Expand All @@ -1211,7 +1218,7 @@
"doc_path": "rules/spinglass_qubo/index.html"
},
{
"source": 49,
"source": 50,
"target": 4,
"overhead": [
{
Expand All @@ -1226,7 +1233,7 @@
"doc_path": "rules/sat_circuitsat/index.html"
},
{
"source": 49,
"source": 50,
"target": 15,
"overhead": [
{
Expand All @@ -1241,7 +1248,7 @@
"doc_path": "rules/sat_coloring/index.html"
},
{
"source": 49,
"source": 50,
"target": 20,
"overhead": [
{
Expand All @@ -1256,7 +1263,7 @@
"doc_path": "rules/sat_ksat/index.html"
},
{
"source": 49,
"source": 50,
"target": 29,
"overhead": [
{
Expand All @@ -1271,7 +1278,7 @@
"doc_path": "rules/sat_maximumindependentset/index.html"
},
{
"source": 49,
"source": 50,
"target": 38,
"overhead": [
{
Expand All @@ -1286,7 +1293,7 @@
"doc_path": "rules/sat_minimumdominatingset/index.html"
},
{
"source": 51,
"source": 52,
"target": 47,
"overhead": [
{
Expand All @@ -1297,7 +1304,7 @@
"doc_path": "rules/spinglass_qubo/index.html"
},
{
"source": 52,
"source": 53,
"target": 24,
"overhead": [
{
Expand All @@ -1312,8 +1319,8 @@
"doc_path": "rules/spinglass_maxcut/index.html"
},
{
"source": 52,
"target": 51,
"source": 53,
"target": 52,
"overhead": [
{
"field": "num_spins",
Expand All @@ -1327,7 +1334,7 @@
"doc_path": "rules/spinglass_casts/index.html"
},
{
"source": 55,
"source": 56,
"target": 11,
"overhead": [
{
Expand All @@ -1342,7 +1349,7 @@
"doc_path": "rules/travelingsalesman_ilp/index.html"
},
{
"source": 55,
"source": 56,
"target": 47,
"overhead": [
{
Expand Down
17 changes: 12 additions & 5 deletions problemreductions-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ Flags by problem type:
LCS --strings
FAS --arcs [--weights] [--num-vertices]
FVS --arcs [--weights] [--num-vertices]
ResourceConstrainedScheduling --num-processors, --resource-bounds, --resource-requirements, --deadline
FlowShopScheduling --task-lengths, --deadline [--num-processors]
SCS --strings, --bound [--alphabet-size]
ILP, CircuitSAT (via reduction only)
Expand Down Expand Up @@ -382,15 +383,21 @@ pub struct CreateArgs {
/// Directed arcs for directed graph problems (e.g., 0>1,1>2,2>0)
#[arg(long)]
pub arcs: Option<String>,
/// Task lengths for FlowShopScheduling (semicolon-separated rows: "3,4,2;2,3,5;4,1,3")
/// Number of processors for ResourceConstrainedScheduling or FlowShopScheduling
#[arg(long)]
pub task_lengths: Option<String>,
/// Deadline for FlowShopScheduling
pub num_processors: Option<usize>,
/// Resource bounds for ResourceConstrainedScheduling (comma-separated, e.g., "20,15")
#[arg(long)]
pub resource_bounds: Option<String>,
/// Resource requirements for ResourceConstrainedScheduling (semicolon-separated rows, each row comma-separated, e.g., "6,3;7,4;5,2")
#[arg(long)]
pub resource_requirements: Option<String>,
/// Deadline for ResourceConstrainedScheduling or FlowShopScheduling
#[arg(long)]
pub deadline: Option<u64>,
/// Number of processors/machines for FlowShopScheduling
/// Task lengths for FlowShopScheduling (semicolon-separated rows: "3,4,2;2,3,5;4,1,3")
#[arg(long)]
pub num_processors: Option<usize>,
pub task_lengths: Option<String>,
/// Alphabet size for SCS (optional; inferred from max symbol + 1 if omitted)
#[arg(long)]
pub alphabet_size: Option<usize>,
Expand Down
39 changes: 37 additions & 2 deletions problemreductions-cli/src/commands/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use problemreductions::models::algebraic::{ClosestVectorProblem, BMF};
use problemreductions::models::graph::{GraphPartitioning, HamiltonianPath};
use problemreductions::models::misc::{
BinPacking, FlowShopScheduling, LongestCommonSubsequence, PaintShop,
ShortestCommonSupersequence, SubsetSum,
ResourceConstrainedScheduling, ShortestCommonSupersequence, SubsetSum,
};
use problemreductions::prelude::*;
use problemreductions::registry::collect_schemas;
Expand Down Expand Up @@ -57,9 +57,11 @@ fn all_data_flags_empty(args: &CreateArgs) -> bool {
&& args.pattern.is_none()
&& args.strings.is_none()
&& args.arcs.is_none()
&& args.num_processors.is_none()
&& args.resource_bounds.is_none()
&& args.resource_requirements.is_none()
&& args.task_lengths.is_none()
&& args.deadline.is_none()
&& args.num_processors.is_none()
&& args.alphabet_size.is_none()
}

Expand Down Expand Up @@ -744,6 +746,39 @@ pub fn create(args: &CreateArgs, out: &OutputConfig) -> Result<()> {
)
}

// ResourceConstrainedScheduling
"ResourceConstrainedScheduling" => {
let usage = "Usage: pred create ResourceConstrainedScheduling --num-processors 3 --resource-bounds \"20\" --resource-requirements \"6;7;7;6;8;6\" --deadline 2";
let num_processors = args
.num_processors
.ok_or_else(|| anyhow::anyhow!("ResourceConstrainedScheduling requires --num-processors\n\n{usage}"))?;
let bounds_str = args.resource_bounds.as_deref().ok_or_else(|| {
anyhow::anyhow!("ResourceConstrainedScheduling requires --resource-bounds\n\n{usage}")
})?;
let reqs_str = args.resource_requirements.as_deref().ok_or_else(|| {
anyhow::anyhow!("ResourceConstrainedScheduling requires --resource-requirements\n\n{usage}")
})?;
let deadline = args
.deadline
.ok_or_else(|| anyhow::anyhow!("ResourceConstrainedScheduling requires --deadline\n\n{usage}"))?;

let resource_bounds: Vec<u64> = util::parse_comma_list(bounds_str)?;
let resource_requirements: Vec<Vec<u64>> = reqs_str
.split(';')
.map(|row| util::parse_comma_list(row.trim()))
.collect::<Result<Vec<_>>>()?;

(
ser(ResourceConstrainedScheduling::new(
num_processors,
resource_bounds,
resource_requirements,
deadline,
))?,
resolved_variant.clone(),
)
}

// OptimalLinearArrangement — graph + bound
"OptimalLinearArrangement" => {
let (graph, _) = parse_graph(args).map_err(|e| {
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub mod prelude {
};
pub use crate::models::misc::{
BinPacking, Factoring, FlowShopScheduling, Knapsack, LongestCommonSubsequence, PaintShop,
ShortestCommonSupersequence, SubsetSum,
ResourceConstrainedScheduling, ShortestCommonSupersequence, SubsetSum,
};
pub use crate::models::set::{MaximumSetPacking, MinimumSetCovering};

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 @@ -7,6 +7,7 @@
//! - [`Knapsack`]: 0-1 Knapsack (maximize value subject to weight capacity)
//! - [`LongestCommonSubsequence`]: Longest Common Subsequence
//! - [`PaintShop`]: Minimize color switches in paint shop scheduling
//! - [`ResourceConstrainedScheduling`]: Schedule unit-length tasks on processors with resource constraints
//! - [`ShortestCommonSupersequence`]: Find a common supersequence of bounded length
//! - [`SubsetSum`]: Find a subset summing to exactly a target value

Expand All @@ -16,6 +17,7 @@ mod flow_shop_scheduling;
mod knapsack;
mod longest_common_subsequence;
pub(crate) mod paintshop;
pub(crate) mod resource_constrained_scheduling;
pub(crate) mod shortest_common_supersequence;
mod subset_sum;

Expand All @@ -25,6 +27,7 @@ pub use flow_shop_scheduling::FlowShopScheduling;
pub use knapsack::Knapsack;
pub use longest_common_subsequence::LongestCommonSubsequence;
pub use paintshop::PaintShop;
pub use resource_constrained_scheduling::ResourceConstrainedScheduling;
pub use shortest_common_supersequence::ShortestCommonSupersequence;
pub use subset_sum::SubsetSum;

Expand All @@ -34,5 +37,6 @@ pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::M
specs.extend(factoring::canonical_model_example_specs());
specs.extend(paintshop::canonical_model_example_specs());
specs.extend(shortest_common_supersequence::canonical_model_example_specs());
specs.extend(resource_constrained_scheduling::canonical_model_example_specs());
specs
}
Loading
Loading