Skip to content

Preserve solver statistics compatibility - #119

Merged
bernalde merged 1 commit into
mainfrom
fix/solver-statistics-followup
Jul 29, 2026
Merged

bernalde merged 1 commit into
mainfrom
fix/solver-statistics-followup

Conversation

@bernalde

Copy link
Copy Markdown
Member

Summary

  • record per-iteration variance in solution.stats.variances, using nothing when an iteration did not run the configured variance check
  • restore the documented on_iteration callback signature and preserve the released top-level statistics properties as deprecated aliases
  • make infeasible debug logging safe and remove the superseded statistics buffers
  • cover feasible and infeasible statistics, compatibility aliases, callback behavior, and debug logging

Context

This is a focused compatibility and correctness follow-up to #118. It also gives #112 a stable statistics API so its benchmark can read the final checked variance without installing a callback.

Validation

  • julia +1.12 --project=. --startup-file=no -e 'using Pkg; Pkg.test(; coverage=false)'
  • julia +1.12 --project=docs/ --startup-file=no -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()'
  • julia +1.12 --project=docs/ --startup-file=no docs/make.jl local
  • git diff --check

Refs #118
Refs #112

@bernalde
bernalde merged commit a6a3ed1 into main Jul 29, 2026
11 checks passed
@bernalde
bernalde deleted the fix/solver-statistics-followup branch July 29, 2026 17:24
Comment thread src/solution.jl
Comment on lines +87 to +104
function Base.getproperty(solution::Solution, name::Symbol)
if name === :energies || name === :bond_dims || name === :elapsed_times
Base.depwarn(
"`solution.$name` is deprecated; use `solution.stats.$name` instead.",
name,
)
return getproperty(getfield(solution, :stats), name)
end

return getfield(solution, name)
end

function Base.propertynames(::Solution, _private::Bool=false)
fields = fieldnames(Solution)
aliases = (:energies, :bond_dims, :elapsed_times)
return (fields..., aliases...)
end

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The new stats interface will only appear in the next release together with other breaking-changes. We are still on the v0.* of the solver precisely because we are still experimenting and refining the API. Do you see any gain in keeping the old, clunkier way around?

Suggested change
function Base.getproperty(solution::Solution, name::Symbol)
if name === :energies || name === :bond_dims || name === :elapsed_times
Base.depwarn(
"`solution.$name` is deprecated; use `solution.stats.$name` instead.",
name,
)
return getproperty(getfield(solution, :stats), name)
end
return getfield(solution, name)
end
function Base.propertynames(::Solution, _private::Bool=false)
fields = fieldnames(Solution)
aliases = (:energies, :bond_dims, :elapsed_times)
return (fields..., aliases...)
end

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed in PR #112 commit b9de6e3. I removed the transitional getproperty/propertynames aliases and their documentation/tests, leaving solution.stats as the canonical interface for the next breaking release.

Comment thread test/constrained_solve.jl
Comment on lines 197 to +222
@test !is_feasible(psi)
@test isempty(psi.stats.energies)
@test isempty(psi.stats.bond_dims)
@test isempty(psi.stats.elapsed_times)
@test isempty(psi.stats.variances)
@test length(psi.stats.max_bonds.projections) == 1
@test all(>(0), psi.stats.max_bonds.projections)
@test psi.stats.max_bonds.objective > 0
@test psi.stats.max_bonds.initial_state == 0
@test psi.stats.max_bonds.hamiltonian > 0
@test [0, 0] ∉ psi
@test_throws DomainError TenSolver.sample(psi)

io = IOBuffer()
E_debug, psi_debug = with_logger(ConsoleLogger(io, Logging.Debug)) do
minimize(
zeros(2, 2);
constraints=impossible,
verbosity=0,
)
end
debug_log = String(take!(io))
@test E_debug == Inf
@test !is_feasible(psi_debug)
@test occursin("empty feasible subspace", debug_log)
@test !occursin("Exception while generating log record", debug_log)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Considering #102, we should think before adding trivial tests.
For example, why are we checking if the bond dimensions are non-negative when it is so by construction?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed in PR #112 commit b9de6e3. I removed the positivity assertions and duplicate solver calls, retained the semantic infeasible/logging checks, and folded mixed variance-cadence coverage into the existing statistics solve.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants