Skip to content
48 changes: 48 additions & 0 deletions docs/paper/reductions.typ
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@
"PrecedenceConstrainedScheduling": [Precedence Constrained Scheduling],
"PrimeAttributeName": [Prime Attribute Name],
"QuadraticAssignment": [Quadratic Assignment],
"QuadraticDiophantineEquations": [Quadratic Diophantine Equations],
"QuantifiedBooleanFormulas": [Quantified Boolean Formulas (QBF)],
"RectilinearPictureCompression": [Rectilinear Picture Compression],
"ResourceConstrainedScheduling": [Resource Constrained Scheduling],
Expand Down Expand Up @@ -3257,6 +3258,53 @@ A classical NP-complete problem from Garey and Johnson @garey1979[Ch.~3, p.~76],
]
}

#{
let x = load-model-example("QuadraticDiophantineEquations")
let a = x.instance.a
let b = x.instance.b
let c = x.instance.c
let config = x.optimal_config
let xval = config.at(0) + 1
let yval = int((c - a * xval * xval) / b)
// Enumerate all valid x values for the table
let max-x = calc.floor(calc.sqrt(c / a))
let rows = range(1, max-x + 1).map(xi => {
let rem = c - a * xi * xi
let feasible = rem > 0 and calc.rem(rem, b) == 0
let yi = if feasible { int(rem / b) } else { none }
(xi, rem, feasible, yi)
})
[
#problem-def("QuadraticDiophantineEquations")[
Given positive integers $a$, $b$, $c$, determine whether there exist positive integers $x$, $y$ such that $a x^2 + b y = c$.
][
Quadratic Diophantine equations of the form $a x^2 + b y = c$ form one of the simplest families of mixed-degree Diophantine problems. The variable $y$ is entirely determined by $x$ via $y = (c - a x^2) slash b$, so the decision problem reduces to checking whether any $x in {1, dots, floor(sqrt(c slash a))}$ yields a positive integer $y$. This can be done in $O(sqrt(c))$ time by trial#footnote[No algorithm improving on brute-force trial of all candidate $x$ values is known; the registered complexity `sqrt(c)` reflects this direct enumeration bound.].

*Example.* Let $a = #a$, $b = #b$, $c = #c$. Then $x$ ranges over $1, dots, #max-x$:

#pred-commands(
"pred create --example QuadraticDiophantineEquations -o qde.json",
"pred solve qde.json --solver brute-force",
"pred evaluate qde.json --config " + config.map(str).join(","),
)

#align(center, table(
columns: 4,
align: center,
table.header([$x$], [$c - a x^2$], [Divisible by $b$?], [$y$]),
..rows.map(((xi, rem, ok, yi)) => (
[$#xi$],
[$#rem$],
[#if ok [Yes] else [No]],
[#if yi != none [$#yi$] else [$dash$]],
)).flatten(),
))

The instance is satisfiable: $x = #xval, y = #yval$ gives $#a dot #xval^2 + #b dot #yval = #c$.
]
]
}

#{
let x = load-model-example("ClosestVectorProblem")
let basis = x.instance.basis
Expand Down
10 changes: 10 additions & 0 deletions problemreductions-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ Flags by problem type:
ProductionPlanning --num-periods, --demands, --capacities, --setup-costs, --production-costs, --inventory-costs, --cost-bound
SubsetSum --sizes, --target
ThreePartition --sizes, --bound
QuadraticDiophantineEquations --coeff-a, --coeff-b, --coeff-c
SumOfSquaresPartition --sizes, --num-groups
ExpectedRetrievalCost --probabilities, --num-sectors
PaintShop --sequence
Expand Down Expand Up @@ -754,6 +755,15 @@ pub struct CreateArgs {
/// Target string for StringToStringCorrection (comma-separated symbol indices, e.g., "0,1,3,2")
#[arg(long)]
pub target_string: Option<String>,
/// Coefficient a for QuadraticDiophantineEquations (coefficient of x²)
#[arg(long)]
pub coeff_a: Option<u64>,
/// Coefficient b for QuadraticDiophantineEquations (coefficient of y)
#[arg(long)]
pub coeff_b: Option<u64>,
/// Constant c for QuadraticDiophantineEquations (right-hand side of ax² + by = c)
#[arg(long)]
pub coeff_c: Option<u64>,
}

#[derive(clap::Args)]
Expand Down
36 changes: 35 additions & 1 deletion problemreductions-cli/src/commands/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use anyhow::{bail, Context, Result};
use problemreductions::export::{ModelExample, ProblemRef, ProblemSide, RuleExample};
use problemreductions::models::algebraic::{
ClosestVectorProblem, ConsecutiveBlockMinimization, ConsecutiveOnesMatrixAugmentation,
ConsecutiveOnesSubmatrix, FeasibleBasisExtension, SparseMatrixCompression, BMF,
ConsecutiveOnesSubmatrix, FeasibleBasisExtension, QuadraticDiophantineEquations,
SparseMatrixCompression, BMF,
};
use problemreductions::models::formula::Quantifier;
use problemreductions::models::graph::{
Expand Down Expand Up @@ -193,7 +194,10 @@ fn all_data_flags_empty(args: &CreateArgs) -> bool {
&& args.conjuncts_spec.is_none()
&& args.deps.is_none()
&& args.query.is_none()
&& args.coeff_a.is_none()
&& args.coeff_b.is_none()
&& args.rhs.is_none()
&& args.coeff_c.is_none()
&& args.required_columns.is_none()
}

Expand Down Expand Up @@ -728,6 +732,7 @@ fn example_for(canonical: &str, graph_type: Option<&str>) -> &'static str {
"IntegerKnapsack" => "--sizes 3,4,5,2,7 --values 4,5,7,3,9 --capacity 15",
"SubsetSum" => "--sizes 3,7,1,8,2,4 --target 11",
"ThreePartition" => "--sizes 4,5,6,4,6,5 --bound 15",
"QuadraticDiophantineEquations" => "--coeff-a 3 --coeff-b 5 --coeff-c 53",
"BoyceCoddNormalFormViolation" => {
"--n 6 --sets \"0,1:2;2:3;3,4:5\" --target 0,1,2,3,4,5"
}
Expand Down Expand Up @@ -2418,6 +2423,32 @@ pub fn create(args: &CreateArgs, out: &OutputConfig) -> Result<()> {
)
}

// QuadraticDiophantineEquations
"QuadraticDiophantineEquations" => {
let a = args.coeff_a.ok_or_else(|| {
anyhow::anyhow!(
"QuadraticDiophantineEquations requires --coeff-a, --coeff-b, and --coeff-c\n\n\
Usage: pred create QuadraticDiophantineEquations --coeff-a 3 --coeff-b 5 --coeff-c 53"
)
})?;
let b = args.coeff_b.ok_or_else(|| {
anyhow::anyhow!(
"QuadraticDiophantineEquations requires --coeff-b\n\n\
Usage: pred create QuadraticDiophantineEquations --coeff-a 3 --coeff-b 5 --coeff-c 53"
)
})?;
let c = args.coeff_c.ok_or_else(|| {
anyhow::anyhow!(
"QuadraticDiophantineEquations requires --coeff-c\n\n\
Usage: pred create QuadraticDiophantineEquations --coeff-a 3 --coeff-b 5 --coeff-c 53"
)
})?;
(
ser(QuadraticDiophantineEquations::try_new(a, b, c).map_err(anyhow::Error::msg)?)?,
resolved_variant.clone(),
)
}

// SumOfSquaresPartition
"SumOfSquaresPartition" => {
let sizes_str = args.sizes.as_deref().ok_or_else(|| {
Expand Down Expand Up @@ -7703,7 +7734,10 @@ mod tests {
storage: None,
quantifiers: None,
homologous_pairs: None,
coeff_a: None,
coeff_b: None,
rhs: None,
coeff_c: None,
required_columns: None,
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/models/algebraic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//! - [`ConsecutiveBlockMinimization`]: Consecutive Block Minimization
//! - [`ConsecutiveOnesSubmatrix`]: Consecutive Ones Submatrix (column selection with C1P)
//! - [`QuadraticAssignment`]: Quadratic Assignment Problem
//! - [`QuadraticDiophantineEquations`]: Decide ax² + by = c in positive integers
//! - [`SparseMatrixCompression`]: Sparse Matrix Compression by row overlay

pub(crate) mod bmf;
Expand All @@ -18,6 +19,7 @@ pub(crate) mod consecutive_ones_submatrix;
pub(crate) mod feasible_basis_extension;
pub(crate) mod ilp;
pub(crate) mod quadratic_assignment;
pub(crate) mod quadratic_diophantine_equations;
pub(crate) mod qubo;
pub(crate) mod sparse_matrix_compression;

Expand All @@ -29,6 +31,7 @@ pub use consecutive_ones_submatrix::ConsecutiveOnesSubmatrix;
pub use feasible_basis_extension::FeasibleBasisExtension;
pub use ilp::{Comparison, LinearConstraint, ObjectiveSense, VariableDomain, ILP};
pub use quadratic_assignment::QuadraticAssignment;
pub use quadratic_diophantine_equations::QuadraticDiophantineEquations;
pub use qubo::QUBO;
pub use sparse_matrix_compression::SparseMatrixCompression;

Expand All @@ -44,6 +47,7 @@ pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::M
specs.extend(consecutive_ones_submatrix::canonical_model_example_specs());
specs.extend(feasible_basis_extension::canonical_model_example_specs());
specs.extend(quadratic_assignment::canonical_model_example_specs());
specs.extend(quadratic_diophantine_equations::canonical_model_example_specs());
specs.extend(sparse_matrix_compression::canonical_model_example_specs());
specs
}
Loading
Loading