Skip to content
Open
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
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"

[compat]
DataFrames = "1"
JLD2 = "0.5, 0.6"
JuMP = "^1.15"
Requires = "1"
SpecialFunctions = "2"
StaticArrays = "1.9.18"
julia = "1.6"

[extras]
Expand Down
22 changes: 22 additions & 0 deletions docs/RULES_hs85_hs89.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# OptimizationProblems.jl Rules — HS85 & HS89 Example

| Rule | HS85 | HS89 | How to Check |
|------|------|------|--------------|
| File Structure | src/ADNLPProblems/hs85.jl, src/PureJuMP/hs85.jl, src/Meta/hs85.jl | src/ADNLPProblems/hs89.jl, src/PureJuMP/hs89.jl, src/Meta/hs89.jl | Check for all three files per problem |
| Header | HS-style header: source, classification, implementation date | Same | Parse header comments for required fields |
| Mathematical Expressions | All intermediates, constraints, objective explicit, match paper | Same | Compare expressions to paper and extracted JSON |
| Variable Bounds | Explicit bounds and x0 in ADNLP and PureJuMP | Same | Check for bounds and x0 in both files |
| Metadata | References, classification, origin, scalable, etc. in Meta file | Same | Parse Meta file for required metadata |
| Naming | hs85.jl in ADNLPProblems, hs85.jl in PureJuMP, hs85.jl in Meta | hs89.jl in ADNLPProblems, hs89.jl in PureJuMP, hs89.jl in Meta | Check file/function names against repository conventions |
| Allocation | Constraint function minimizes allocations (relaxed for complex) | Same | Run allocation test or allow allocation |
| Ipopt Solve | Problem solves with Ipopt (PureJuMP) | Same | Run Ipopt solver and check for solution |
| Reviewer Markdown | Summary, PDF screenshot, extraction uncertainties, test results | Same | Generate reviewer markdown file |
| Duplication | No duplicate (by name, structure, metadata) | Same | Check for similar names/metadata |
| Traceability | Origin clear and referenced in header/Meta | Same | Check Meta/header |
| Scalability | Marked if scalable (not for hs85/hs89) | Same | Check Meta/implementation |
| Multiple Problems | One PDF = one problem (for hs85/hs89) | Same | Allow multiple if needed |
| Uncertainty | Warn if extraction unclear (not for hs85/hs89) | Same | Parse extraction JSON for uncertainties |

---

This table is tailored to HS85 and HS89. Use as a checklist for similar problems and PRs.
73 changes: 73 additions & 0 deletions docs/check_rules.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Script to check OptimizationProblems.jl rules for HS85/HS89
using JSON

function check_problem(problem::String)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea :).

result = Dict()
adnlp_path = "src/ADNLPProblems/$problem.jl"
jump_path = "src/PureJuMP/$problem.jl"
meta_path = "src/Meta/$problem.jl"
# Check that the required files exist for the problem: ADNLPProblems, PureJuMP, and Meta.
result["ADNLP"] = isfile(adnlp_path)
result["PureJuMP"] = isfile(jump_path)
result["Meta"] = isfile(meta_path)
# Check that the header of the ADNLPProblems file for this problem contains a reference to "Hock and Schittkowski" in the first 10 lines, to ensure proper attribution/documentation.
header_ok = false
if result["ADNLP"] || result["PureJuMP"]
adnlp_header_ok = false
jump_header_ok = false
if result["ADNLP"]
adnlp_lines = readlines(adnlp_path)
k = min(length(adnlp_lines), 20)
adnlp_header_ok = any(occursin("Hock and Schittkowski", adnlp_lines[i]) for i in 1:k)
end
if result["PureJuMP"]
jump_lines = readlines(jump_path)
k = min(length(jump_lines), 20)
jump_header_ok = any(occursin("Hock and Schittkowski", jump_lines[i]) for i in 1:k)
end
header_ok = adnlp_header_ok || jump_header_ok
end
result["Header"] = header_ok
Comment on lines +14 to +30
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure to understand what you are checking here ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code checks if the first 10 lines (the "header") of the src/ADNLPProblems/$problem.jl file mention "Hock and Schittkowski" for proper documentation of source. Once you commit, will change it to meta, kept adnlp as placeholder for now.

# Check that the ADNLPProblems file for problem defines lower bounds (lvar), upper bounds (uvar), and an initial point (x0).
bounds_ok = false
if result["ADNLP"]
adnlp_file = String(read(adnlp_path))
has_x0 = occursin("x0", adnlp_file)
has_bounds_in_code = occursin("lvar", adnlp_file) && occursin("uvar", adnlp_file)
has_bounds_required = true
if result["Meta"]
meta_file = String(read(meta_path))
if occursin(":has_bounds => false", meta_file)
has_bounds_required = false
end
end
bounds_ok = has_x0 && (has_bounds_in_code || !has_bounds_required)
end
result["Bounds"] = bounds_ok
# Check that the Meta file for this problem contains both a "Source" and a "classification" entry.
meta_ok = false
if result["Meta"]
meta = String(read(meta_path))
meta_ok = occursin(":name => \"$problem\"", meta) && occursin(":best_known_upper_bound", meta)
end
result["Metadata"] = meta_ok
# Allocation check is currently not implemented (set to false as a placeholder).
result["Allocation"] = false
# Ipopt solve check is not performed by this script.
# Marked as "manual" for reviewer attention.
result["IpoptSolve"] = "manual"
# Check whether reviewer markdown exists (optional, but useful for PR traceability).
result["ReviewerMarkdown"] = isfile("docs/review_$problem.md") || isfile("docs/review/$problem.md")
return result
end

function main()
problems = isempty(ARGS) ? ["hs85", "hs89"] : ARGS
results = Dict()
for p in problems
results[p] = check_problem(p)
end
println(JSON.json(results, 2))
end

main()
66 changes: 66 additions & 0 deletions docs/extract_hs85.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"problem": "hs85",
"source": "Hock and Schittkowski, Problem 85",
"variables": ["x1", "x2", "x3", "x4", "x5"],
"bounds": {
"lvar": [704.4148, 68.6, 0.0, 193.0, 25.0],
"uvar": [906.3855, 288.88, 134.75, 287.0966, 84.1988],
"x0": [900.0, 80.0, 115.0, 267.0, 27.0]
},
"objective": "-5.843e-7 * y17 + 1.17e-4 * y14 + 2.358e-5 * y13 + 1.502e-6 * y16 + 0.0321 * y12 + 0.004324 * y5 + 1e-4 * c15 / c16 + 37.48 * y2 / c12 + 0.1365",
"constraints": [
"1.5 * x2 - x3 >= 0",
"y1 - 213.1 >= 0",
"405.23 - y1 >= 0",
"y2 - a2 >= 0",
"y3 - a3 >= 0",
"y4 - a4 >= 0",
"y5 - a5 >= 0",
"y6 - a6 >= 0",
"y7 - a7 >= 0",
"y8 - a8 >= 0",
"y9 - a9 >= 0",
"y10 - a10 >= 0",
"y11 - a11 >= 0",
"y12 - a12 >= 0",
"y13 - a13 >= 0",
"y14 - a14 >= 0",
"y15 - a15 >= 0",
"y16 - a16 >= 0",
"y17 - a17 >= 0",
"b2 - y2 >= 0",
"b3 - y3 >= 0",
"b4 - y4 >= 0",
"b5 - y5 >= 0",
"b6 - y6 >= 0",
"b7 - y7 >= 0",
"b8 - y8 >= 0",
"b9 - y9 >= 0",
"b10 - y10 >= 0",
"b11 - y11 >= 0",
"b12 - y12 >= 0",
"b13 - y13 >= 0",
"b14 - y14 >= 0",
"b15 - y15 >= 0",
"b16 - y16 >= 0",
"b17 - y17 >= 0",
"y4 - (0.28 / 0.72) * y5 >= 0",
"21 - 3496 * y2 / c12 >= 0",
"62212 / c17 - 110.6 - y1 >= 0",
"x1 - lvar1 >= 0",
"x2 - lvar2 >= 0",
"x3 - lvar3 >= 0",
"x4 - lvar4 >= 0",
"x5 - lvar5 >= 0",
"uvar1 - x1 >= 0",
"uvar2 - x2 >= 0",
"uvar3 - x3 >= 0",
"uvar4 - x4 >= 0",
"uvar5 - x5 >= 0"
],
"metadata": {
"classification": "QGR-P1-(1,...,6)",
"implementation": "AI/JSO, 03/2026"
},
"uncertainties": []
}
21 changes: 21 additions & 0 deletions docs/extract_hs89.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"problem": "hs89",
"source": "Hock and Schittkowski, Problem 89",
"variables": ["x1", "x2", "x3"],
"bounds": {
"lvar": "none",
"uvar": "none",
"x0": [0.0, 0.0, 0.0]
},
"objective": "sum_{j=1}^{30} A_j * rho_j(x)\nwhere rho_j(x) = - (exp(-mu_j^2 * r) + 2*exp(-mu_j^2*(x2^2 + x3^2)) + 2*exp(-mu_j^2*x3^2) + 1) / mu_j^2\nr = x1^2 + x2^2 + x3^2\nA_j = 2*sin(mu_j)/(mu_j + sin(mu_j)*cos(mu_j))\nmu_j: first 30 positive roots of tan(mu) = mu",
"constraints": [
"c(x) = termA + termB - 2/15 = 0",
"termA = sum_{j=1}^{30} A_j^2 * rho_j(x)^2 * (sin(2*mu_j)/(2*mu_j) + 1)/2",
"termB = sum_{i=1}^{29} sum_{j=i+1}^{30} A_i * A_j * rho_i(x) * rho_j(x) * (sin(mu_i+mu_j)/(mu_i+mu_j) + sin(mu_i-mu_j)/(mu_i-mu_j))"
],
"metadata": {
"classification": "QGR-P1-(1,...,6)",
"implementation": "AI/JSO, 03/2026"
},
"uncertainties": []
}
Loading