Optimization with any finite domain - #109
Conversation
fd91c23 to
361c499
Compare
d5256a2 to
4e78d6c
Compare
bernalde
left a comment
There was a problem hiding this comment.
Maintainer review — any finite domain (Closes #108)
Clean, well-scoped generalization: it drops the [0,1]/[-1,1] whitelist from validate_solve_domain so DMRG accepts any finite, real, unique domain, and tightens the SumConstraint guard to reject non-nonnegative-integer domains with a clear error — matching the PR's honest note that constraint support stays limited. Minimal surface (no new keyword), good layering. No blocking code issues. One design Question and one nonblocking test gap below; also an environmental CI note.
What I verified
- Widened range holds against the framework contract. Physical domain values live only in the
Doperator diagonal (diagm(domain)) andSolution.domain; ITensors still sees a Qudit of dimdwith integer state labels0:(d-1), so arbitrary real domains don't violate its contract. Confirmed a non-integer solve end to end:minimize(zeros(2,2), [-2,3]; domain=[0.0,0.5,1.0])→E=-2.0,x=[1.0,0.0](correct). - The tightened guard fails fast, not silently. Confirmed
SumConstraintoverdomain=[-1,1]and over the non-integer nonnegdomain=[0.0,1.5]both throwArgumentError: SumConstraint only supports nonnegative integer domains.— the second case previously slipped past the oldminimum(alphabet) < 0guard into the integer partial-sum automaton, so this is a real hardening. - Tests cover the extremes, not one interior example: sparse non-contiguous
[-2,0,3](hand-checkedE=-18), reversed[1,-1](normalization to[-1.0,1.0]), singleton[0](thed=1edge), empty and non-real domains (validation errors), all cross-checked againstbrute_force(…; domain=…). No staledomain_dimreferences remain; docs add a doctested sparse-domain example.
Findings
Question — the accepted domain surface is wider than what's documented or tested. validate_solve_domain (src/backends/dmrg.jl:47) admits any Real domain, and non-integer domains genuinely work for the objective (verified above) — but every test uses integer domains, and the docs scope the domain to ⊆ ℤ, while the PR body claims non-integer support. That's three sources disagreeing on the contract. Please pick one: either make non-integer support real (a doctest/regression over a fractional domain + a doc line), or, if integer domains are the intended surface for now, tighten the validator to integers so the accepted input matches the documented and tested contract rather than silently accepting more than the PR stands behind.
Nonblocking — no test for the changed SumConstraint guard. The guard's condition and message changed (and it now catches the previously-silent non-integer-nonneg case), but nothing exercises the error path. Add a one-line @test_throws ArgumentError for a SumConstraint under a signed and/or fractional domain to lock the fail-fast behavior in.
Tests / CI
Full Pkg.test() passes locally (0 failures). On the PR head, build, documenter/deploy, and every ubuntu/macOS job across lts/1/pre are green. Julia 1 - windows-latest failed — but at ITensors-dependency precompile (ArgumentError: Package Accessors … is required but does not seem to be installed, cascading through Transducers → NDTensors → ITensors), before any TenSolver test runs. This PR changes no Project.toml dependency; main's latest run is green on all three Windows jobs, and this PR's own pre-windows job passed — so it's a transient Windows dependency-materialization flake, not a code defect.
Merge-readiness
No blocking code issues; approving on the merits. Two things before merge, both outside the code: get a green Windows run (re-run the flaked job — the current UNSTABLE state is that failure), and settle the domain-surface Question above (it can be a one-line doc/validator tweak or a follow-up, your call). main is not branch-protected, so no formal approval gate is reported.
| elseif !all(value -> value isa Real, domain) | ||
| throw(ArgumentError("`domain` values must be real numbers")) | ||
| throw(ArgumentError("`domain` must contain at least one value.")) | ||
| elseif !all(u -> u isa Real, domain) |
There was a problem hiding this comment.
Question: this accepts any Real domain, and non-integer domains do work for the objective — I verified minimize(zeros(2,2), [-2,3]; domain=[0.0,0.5,1.0]) returns the correct E=-2.0. But no test uses a non-integer domain and the docs scope the domain to ⊆ ℤ, while the PR description claims non-integer support. The accepted surface should match the documented and tested one: either add a fractional-domain doctest/test (and a doc line) to stand behind the claim, or tighten this check to integers so unsupported inputs fail fast instead of silently doing more than the PR verifies.
| function constraint_to_dfa(constraint::SumConstraint{S}, nsites::Integer, alphabet) where {S} | ||
| if minimum(alphabet) < 0 | ||
| throw(ArgumentError("SumConstraint only supports nonnegative domains.")) | ||
| if !all(a -> isinteger(a) && a >= 0, alphabet) |
There was a problem hiding this comment.
Nonblocking: this guard's condition and message changed here, and it now also catches non-integer nonnegative domains that the previous minimum(alphabet) < 0 check let slip into the integer partial-sum automaton (I confirmed SumConstraint over domain=[0.0,1.5] now errors cleanly, where before it would not). Worth a one-line @test_throws ArgumentError — a SumConstraint under a signed and/or fractional domain — so this fail-fast behavior can't silently regress.
Remove the Ising restriction added in #107.
Now DMRG optimization accepts any finite domain.
Note: While the optimization itself supports non-integer domains,
the constraint support is still feeble: SumConstraint requires nonnegative integers, while other constraints are compared with exact equality.
Close #108.