Skip to content

Commit 7657a08

Browse files
isPANNclaudezazabap
authored
feat: add QuadraticDiophantineEquations model (#543) (#812)
* feat: add QuadraticDiophantineEquations model (#543) Add decision problem: given positive integers a, b, c, determine whether there exist positive integers x, y such that ax^2 + by = c. Single variable x with y derived; complexity O(sqrt(c)) by trial. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix agentic review issues: rename c_val→c getter, fix paper solve command - Rename `c_val()` getter to `c()` so user-facing catalog output shows the mathematical parameter name instead of an implementation detail - Add `--solver brute-force` to paper's `pred solve` command since QuadraticDiophantineEquations has no ILP reduction path Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: rename duplicate rhs CLI field to qde_rhs for QuadraticDiophantineEquations * fix: remove OLA→STMWCT rule file accidentally included from merge The file was brought in by a contaminated merge commit and does not belong to the QuadraticDiophantineEquations model PR. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: rename --qde-rhs to --coeff-c for consistency All three QDE parameters now use the coeff- prefix: --coeff-a, --coeff-b, --coeff-c. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: zazabap <sweynan@icloud.com>
1 parent 102b941 commit 7657a08

File tree

7 files changed

+491
-3
lines changed

7 files changed

+491
-3
lines changed

docs/paper/reductions.typ

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@
178178
"PrecedenceConstrainedScheduling": [Precedence Constrained Scheduling],
179179
"PrimeAttributeName": [Prime Attribute Name],
180180
"QuadraticAssignment": [Quadratic Assignment],
181+
"QuadraticDiophantineEquations": [Quadratic Diophantine Equations],
181182
"QuantifiedBooleanFormulas": [Quantified Boolean Formulas (QBF)],
182183
"RectilinearPictureCompression": [Rectilinear Picture Compression],
183184
"ResourceConstrainedScheduling": [Resource Constrained Scheduling],
@@ -3257,6 +3258,53 @@ A classical NP-complete problem from Garey and Johnson @garey1979[Ch.~3, p.~76],
32573258
]
32583259
}
32593260

3261+
#{
3262+
let x = load-model-example("QuadraticDiophantineEquations")
3263+
let a = x.instance.a
3264+
let b = x.instance.b
3265+
let c = x.instance.c
3266+
let config = x.optimal_config
3267+
let xval = config.at(0) + 1
3268+
let yval = int((c - a * xval * xval) / b)
3269+
// Enumerate all valid x values for the table
3270+
let max-x = calc.floor(calc.sqrt(c / a))
3271+
let rows = range(1, max-x + 1).map(xi => {
3272+
let rem = c - a * xi * xi
3273+
let feasible = rem > 0 and calc.rem(rem, b) == 0
3274+
let yi = if feasible { int(rem / b) } else { none }
3275+
(xi, rem, feasible, yi)
3276+
})
3277+
[
3278+
#problem-def("QuadraticDiophantineEquations")[
3279+
Given positive integers $a$, $b$, $c$, determine whether there exist positive integers $x$, $y$ such that $a x^2 + b y = c$.
3280+
][
3281+
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.].
3282+
3283+
*Example.* Let $a = #a$, $b = #b$, $c = #c$. Then $x$ ranges over $1, dots, #max-x$:
3284+
3285+
#pred-commands(
3286+
"pred create --example QuadraticDiophantineEquations -o qde.json",
3287+
"pred solve qde.json --solver brute-force",
3288+
"pred evaluate qde.json --config " + config.map(str).join(","),
3289+
)
3290+
3291+
#align(center, table(
3292+
columns: 4,
3293+
align: center,
3294+
table.header([$x$], [$c - a x^2$], [Divisible by $b$?], [$y$]),
3295+
..rows.map(((xi, rem, ok, yi)) => (
3296+
[$#xi$],
3297+
[$#rem$],
3298+
[#if ok [Yes] else [No]],
3299+
[#if yi != none [$#yi$] else [$dash$]],
3300+
)).flatten(),
3301+
))
3302+
3303+
The instance is satisfiable: $x = #xval, y = #yval$ gives $#a dot #xval^2 + #b dot #yval = #c$.
3304+
]
3305+
]
3306+
}
3307+
32603308
#{
32613309
let x = load-model-example("ClosestVectorProblem")
32623310
let basis = x.instance.basis

problemreductions-cli/src/cli.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ Flags by problem type:
249249
ProductionPlanning --num-periods, --demands, --capacities, --setup-costs, --production-costs, --inventory-costs, --cost-bound
250250
SubsetSum --sizes, --target
251251
ThreePartition --sizes, --bound
252+
QuadraticDiophantineEquations --coeff-a, --coeff-b, --coeff-c
252253
SumOfSquaresPartition --sizes, --num-groups
253254
ExpectedRetrievalCost --probabilities, --num-sectors
254255
PaintShop --sequence
@@ -754,6 +755,15 @@ pub struct CreateArgs {
754755
/// Target string for StringToStringCorrection (comma-separated symbol indices, e.g., "0,1,3,2")
755756
#[arg(long)]
756757
pub target_string: Option<String>,
758+
/// Coefficient a for QuadraticDiophantineEquations (coefficient of x²)
759+
#[arg(long)]
760+
pub coeff_a: Option<u64>,
761+
/// Coefficient b for QuadraticDiophantineEquations (coefficient of y)
762+
#[arg(long)]
763+
pub coeff_b: Option<u64>,
764+
/// Constant c for QuadraticDiophantineEquations (right-hand side of ax² + by = c)
765+
#[arg(long)]
766+
pub coeff_c: Option<u64>,
757767
}
758768

759769
#[derive(clap::Args)]

problemreductions-cli/src/commands/create.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use anyhow::{bail, Context, Result};
99
use problemreductions::export::{ModelExample, ProblemRef, ProblemSide, RuleExample};
1010
use problemreductions::models::algebraic::{
1111
ClosestVectorProblem, ConsecutiveBlockMinimization, ConsecutiveOnesMatrixAugmentation,
12-
ConsecutiveOnesSubmatrix, FeasibleBasisExtension, SparseMatrixCompression, BMF,
12+
ConsecutiveOnesSubmatrix, FeasibleBasisExtension, QuadraticDiophantineEquations,
13+
SparseMatrixCompression, BMF,
1314
};
1415
use problemreductions::models::formula::Quantifier;
1516
use problemreductions::models::graph::{
@@ -193,7 +194,10 @@ fn all_data_flags_empty(args: &CreateArgs) -> bool {
193194
&& args.conjuncts_spec.is_none()
194195
&& args.deps.is_none()
195196
&& args.query.is_none()
197+
&& args.coeff_a.is_none()
198+
&& args.coeff_b.is_none()
196199
&& args.rhs.is_none()
200+
&& args.coeff_c.is_none()
197201
&& args.required_columns.is_none()
198202
}
199203

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

2426+
// QuadraticDiophantineEquations
2427+
"QuadraticDiophantineEquations" => {
2428+
let a = args.coeff_a.ok_or_else(|| {
2429+
anyhow::anyhow!(
2430+
"QuadraticDiophantineEquations requires --coeff-a, --coeff-b, and --coeff-c\n\n\
2431+
Usage: pred create QuadraticDiophantineEquations --coeff-a 3 --coeff-b 5 --coeff-c 53"
2432+
)
2433+
})?;
2434+
let b = args.coeff_b.ok_or_else(|| {
2435+
anyhow::anyhow!(
2436+
"QuadraticDiophantineEquations requires --coeff-b\n\n\
2437+
Usage: pred create QuadraticDiophantineEquations --coeff-a 3 --coeff-b 5 --coeff-c 53"
2438+
)
2439+
})?;
2440+
let c = args.coeff_c.ok_or_else(|| {
2441+
anyhow::anyhow!(
2442+
"QuadraticDiophantineEquations requires --coeff-c\n\n\
2443+
Usage: pred create QuadraticDiophantineEquations --coeff-a 3 --coeff-b 5 --coeff-c 53"
2444+
)
2445+
})?;
2446+
(
2447+
ser(QuadraticDiophantineEquations::try_new(a, b, c).map_err(anyhow::Error::msg)?)?,
2448+
resolved_variant.clone(),
2449+
)
2450+
}
2451+
24212452
// SumOfSquaresPartition
24222453
"SumOfSquaresPartition" => {
24232454
let sizes_str = args.sizes.as_deref().ok_or_else(|| {
@@ -7703,7 +7734,10 @@ mod tests {
77037734
storage: None,
77047735
quantifiers: None,
77057736
homologous_pairs: None,
7737+
coeff_a: None,
7738+
coeff_b: None,
77067739
rhs: None,
7740+
coeff_c: None,
77077741
required_columns: None,
77087742
}
77097743
}

src/models/algebraic/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
//! - [`ConsecutiveBlockMinimization`]: Consecutive Block Minimization
99
//! - [`ConsecutiveOnesSubmatrix`]: Consecutive Ones Submatrix (column selection with C1P)
1010
//! - [`QuadraticAssignment`]: Quadratic Assignment Problem
11+
//! - [`QuadraticDiophantineEquations`]: Decide ax² + by = c in positive integers
1112
//! - [`SparseMatrixCompression`]: Sparse Matrix Compression by row overlay
1213
1314
pub(crate) mod bmf;
@@ -18,6 +19,7 @@ pub(crate) mod consecutive_ones_submatrix;
1819
pub(crate) mod feasible_basis_extension;
1920
pub(crate) mod ilp;
2021
pub(crate) mod quadratic_assignment;
22+
pub(crate) mod quadratic_diophantine_equations;
2123
pub(crate) mod qubo;
2224
pub(crate) mod sparse_matrix_compression;
2325

@@ -29,6 +31,7 @@ pub use consecutive_ones_submatrix::ConsecutiveOnesSubmatrix;
2931
pub use feasible_basis_extension::FeasibleBasisExtension;
3032
pub use ilp::{Comparison, LinearConstraint, ObjectiveSense, VariableDomain, ILP};
3133
pub use quadratic_assignment::QuadraticAssignment;
34+
pub use quadratic_diophantine_equations::QuadraticDiophantineEquations;
3235
pub use qubo::QUBO;
3336
pub use sparse_matrix_compression::SparseMatrixCompression;
3437

@@ -44,6 +47,7 @@ pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::M
4447
specs.extend(consecutive_ones_submatrix::canonical_model_example_specs());
4548
specs.extend(feasible_basis_extension::canonical_model_example_specs());
4649
specs.extend(quadratic_assignment::canonical_model_example_specs());
50+
specs.extend(quadratic_diophantine_equations::canonical_model_example_specs());
4751
specs.extend(sparse_matrix_compression::canonical_model_example_specs());
4852
specs
4953
}

0 commit comments

Comments
 (0)