Skip to content

Add optional GenericTensorNetworks backend#31

Open
bernalde wants to merge 3 commits into
mainfrom
codex/gtn-backend-integration
Open

Add optional GenericTensorNetworks backend#31
bernalde wants to merge 3 commits into
mainfrom
codex/gtn-backend-integration

Conversation

@bernalde
Copy link
Copy Markdown
Member

@bernalde bernalde commented May 14, 2026

Summary

  • Add an internal pseudo-Boolean objective representation for QUBO/PUBO inputs.
  • Refactor solver dispatch around DMRGBackend and optional GTNBackend without making GenericTensorNetworks a hard dependency.
  • Add a Julia package extension that maps quadratic objectives to ProblemReductions.QUBO and higher-order PUBO terms to a small custom CSP.
  • Add GTNSolution, solution_space, QUBODrivers backend attributes, tests, and docs/README examples.

Notes

  • TenSolver remains scoped to QUBO/PUBO objectives; GTN-native structured problem families are not exposed by this PR.
  • Local validation used Julia 1.12 because the existing repository manifest is generated for Julia 1.12.

Validation

  • julia +1.12 --project=. -e "using Pkg; Pkg.resolve(); Pkg.instantiate()"
  • julia +1.12 --project=. -e "using Pkg; Pkg.test(; coverage=false)"

Copy link
Copy Markdown
Member Author

@bernalde bernalde left a comment

Choose a reason for hiding this comment

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

GitHub would not allow REQUEST_CHANGES because the authenticated account owns this PR, but the findings below are blocking and should be treated as request-changes.

Review summary:

  1. Blocking issues: GTNBackend.k > 1 paths exposed by the public API are broken for Float64 QUBOs. :kbest_sizes fails when combining GTN/Tropical sizes with the objective constant, and :configs/:count fail before TenSolver can return a result. These need either implementation plus tests or explicit rejection of unsupported combinations.
  2. Nonblocking issues: the one-variable DMRG path silently drops unknown kwargs, and solution_space gives an opaque failure when used with DMRG.
  3. Questions: none.
  4. Tests run and outcomes: julia +1.12 --project=. -e 'using Pkg; Pkg.test(; coverage=false)' passed; julia +1.12 --project=docs/ docs/make.jl passed; targeted GTNBackend(k=2) smoke tests failed as noted inline.
  5. Merge recommendation: I would not merge this until the blocking issues above are addressed.

item = _scalar(raw)

size = _try_read_size(item)
objective = isnothing(size) ? model.constant : model.constant + _primary_size(size)
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.

Blocking: The k > 1 size path currently returns GTN/Tropical values, so adding model.constant fails for a supported public option. Repro:

using TenSolver, GenericTensorNetworks, ProblemReductions
Q = [0.0 2.0; 0.0 0.0]
l = [-1.0, -1.0]
TenSolver.solution_space(Q, l, 3.0; backend=TenSolver.GTNBackend(property=:kbest_sizes, k=2))

This throws promotion of types Float64 and Tropical{Float64} failed at this line. Please unwrap GTN/Tropical size values to the underlying numeric objective before combining with the constant, or reject this property/type combination with a clear ArgumentError, and add a regression test for k > 1.

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 c96eb40: GTN/Tropical numeric wrappers are now unwrapped before objective arithmetic, and GTNBackend(property=:kbest_sizes, k=2) is covered in test/gtn.jl.

elseif property in (:count, :degeneracy)
return k == 1 ? GenericTensorNetworks.CountingMin() : GenericTensorNetworks.CountingMin(k)
elseif property in (:configs, :enumerate)
return k == 1 ? GenericTensorNetworks.ConfigsMin(; bounded=backend.bounded, tree_storage=backend.tree_storage) :
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.

Blocking: These ConfigsMin(k)/CountingMin(k) branches are exposed by GTNBackend.k, but they fail on a simple Float64 QUBO before TenSolver returns a result. GTNBackend(property=:configs, k=2) throws promotion of types Max2Poly{ConfigEnumerator...} and Float64 failed; :count, k=2 fails similarly. This makes the public k API only partially functional and untested. Please either implement a representation/typed conversion that GenericTensorNetworks supports for these k-best properties, or reject unsupported k/property/coefficient-type combinations up front, and cover the accepted behavior in test/gtn.jl.

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 c96eb40: unsupported :configs/:count with k > 1 now fail up front with ArgumentError, while :single, k > 1 remains supported and tested in test/gtn.jl.

Comment thread src/solver.jl
verbosity = 1,
on_iteration :: Union{Nothing, Function} = nothing,
callback_every :: Int = 1,
kwargs...
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.

Nonblocking: The exact one-variable path accepts arbitrary kwargs... and drops them, while the multi-variable DMRG path rejects unknown solver keywords through _minimize's signature. That means a typo such as iteration=5 is silently ignored only for one-variable models. Consider either listing the DMRG keywords that are intentionally ignored here or throwing on non-empty unexpected kwargs after removing the accepted solver knobs.

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 c96eb40: the one-variable path now accepts the known DMRG kwargs for compatibility and throws ArgumentError for unexpected keywords. Covered in test/backends.jl.

Comment thread src/backends.jl
model = pseudoboolean(args...)
selected_backend = backend isa AbstractBackend ? backend : backend_from_attribute(backend; property=isnothing(property) ? :configs : property)
selected_property = isnothing(property) && selected_backend isa GTNBackend ? selected_backend.property : (isnothing(property) ? :configs : property)
return _solve_backend(selected_backend, model; property=selected_property, kwargs...)
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.

Nonblocking: solution_space(...; backend=:dmrg) reaches this call with property=:configs, then fails later as an unsupported keyword to _minimize. Since solution_space is a new public API, it would be better to reject backends without solution-space support here with a direct ArgumentError.

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 c96eb40: solution_space(...; backend=:dmrg) now raises a direct ArgumentError for unsupported solution-space backends. Covered in test/backends.jl.

@bernalde
Copy link
Copy Markdown
Member Author

Commits pushed:

  • c96eb40 Address GTN backend review comments

Main changes made:

  • Fixed GTNBackend(property=:kbest_sizes, k>1) objective reconstruction by unwrapping GTN/Tropical numeric wrappers before adding the TenSolver constant.
  • Added explicit ArgumentErrors for unsupported GTNBackend(property=:configs, k>1) and GTNBackend(property=:count, k>1) on TenSolver pseudo-Boolean objectives.
  • Added direct ArgumentError handling for solution_space(...; backend=:dmrg).
  • Made the one-variable DMRG shortcut accept known DMRG keywords for API compatibility while rejecting unexpected keywords.
  • Documented the current k support limits in the GTN backend docstrings.

Tests run and results:

  • julia +1.12 --project=. -e 'using Test, TenSolver; include("test/backends.jl")' passed.
  • julia +1.12 --project=. -e 'using Pkg; Pkg.test(; coverage=false)' passed.
  • julia +1.12 --project=docs/ docs/make.jl passed.

Comments intentionally not addressed:

  • None.

Remaining risks or follow-up items:

  • Full k-best enumeration/counting for TenSolver pseudo-Boolean objectives remains unsupported for k > 1; this is now rejected clearly rather than failing inside GenericTensorNetworks. Implementing those modes can be a follow-up if we decide to support weighted k-best enumeration/counting.

@bernalde bernalde marked this pull request as ready for review May 14, 2026 23:35
@bernalde bernalde changed the title [codex] Add optional GenericTensorNetworks backend Add optional GenericTensorNetworks backend May 14, 2026
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.

1 participant