Skip to content

Fix missing array dimensions in QUBin sparse constructor calls - #58

Merged
bernalde merged 6 commits into
mainfrom
copilot/fix-sparse-constructor-dimensions
Mar 18, 2026
Merged

Fix missing array dimensions in QUBin sparse constructor calls#58
bernalde merged 6 commits into
mainfrom
copilot/fix-sparse-constructor-dimensions

Conversation

Copilot AI commented Dec 3, 2025

Copy link
Copy Markdown
Contributor

The QUBin parser used sparse(I, J, V) and sparsevec(I, V) without explicit dimensions, causing Julia to infer size from max indices. This produces wrong dimensions when some variables have no linear/quadratic terms, leading to DimensionMismatch errors when calling QUBOTools.value(model, state) on the deserialized model.

Changes

  • src/library/format/qubin/parser.jl: Pass dimension n (already read from file) to sparse constructors

    • sparsevec(li, lv)sparsevec(li, lv, n)
    • sparse(qi, qj, qv)sparse(qi, qj, qv, n, n)
  • test/unit/library/formats.jl: Added regression test for a 3-variable model where variable 3 has no terms. The test performs a QUBin write/read round-trip and verifies:

    • The underlying sparse structures have the correct size (length(L) == 3, size(Q) == (3, 3)) via internal form accessors, providing a clear failure message if the bug resurfaces
    • QUBOTools.value(dst_model, [1, 0, 1]) == 1.0 and QUBOTools.value(dst_model, [1, 1, 1]) == 3.0, which exercise L' * ψ and ψ' * Q * ψ and would throw DimensionMismatch on the unfixed parser
  • .github/workflows/ci.yml: Added julia-actions/cache@v2 to cache the Julia depot and speed up CI runs.

Example

# Model with n=3 but only terms for variables 1 and 2
li, lv = [1], [1.0]
qi, qj, qv = [1], [2], [2.0]

# Without fix: wrong dimensions inferred from max indices
sparse(qi, qj, qv)         # (1, 2) matrix — wrong
sparsevec(li, lv)          # length-1 vector — wrong

# With fix: explicit dimensions
sparse(qi, qj, qv, 3, 3)   # (3, 3) matrix — correct
sparsevec(li, lv, 3)        # length-3 vector — correct

# Before fix: throws DimensionMismatch
QUBOTools.value(dst_model, [1, 0, 1])  # ✗ DimensionMismatch

# After fix: returns correct result
QUBOTools.value(dst_model, [1, 0, 1])  # ✓ 1.0
Original prompt

This section details on the original issue you should resolve

<issue_title>Array dimensions missing in sparse(I, J, V, [m, n]) constructor</issue_title>
<issue_description>https://github.com/JuliaQUBO/QUBOTools.jl/blob/46493c498b70e94f2fa49daf0e38a278fea33d09/src/library/format/qubin/parser.jl#L47C1-L47C48</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI changed the title [WIP] Fix array dimensions in sparse constructor Fix missing array dimensions in QUBin sparse constructor calls Dec 3, 2025
Copilot AI requested a review from bernalde December 3, 2025 20:13
@bernalde
bernalde marked this pull request as ready for review December 4, 2025 01:02
@bernalde

bernalde commented Dec 4, 2025

Copy link
Copy Markdown
Member

@copilot Address this:
[julia-buildpkg] Caching of the julia depot was not detected
Consider using julia-actions/cache to speed up runs https://github.com/julia-actions/cache To ignore, set input ignore-no-cache: true

Copilot AI commented Dec 4, 2025

Copy link
Copy Markdown
Contributor Author

@copilot Address this:
[julia-buildpkg] Caching of the julia depot was not detected
Consider using `ju...

Added julia-actions/cache@v2 to the CI workflow in commit 831547f. This will cache the Julia depot to speed up subsequent workflow runs.

Copilot AI requested a review from bernalde December 4, 2025 01:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes QUBin parsing so sparse linear/quadratic forms preserve the declared model dimension n even when some variables have no terms (e.g., trailing variables).

Changes:

  • Pass n into sparsevec(li, lv, n) when parsing the linear form.
  • Pass (n, n) into sparse(qi, qj, qv, n, n) when parsing the quadratic form.
  • Add a unit test covering a 3-variable model where variable 3 has no linear/quadratic terms, and enable Julia CI caching.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/library/format/qubin/parser.jl Ensures parsed sparse vector/matrix are constructed with the correct explicit dimensions.
test/unit/library/formats.jl Adds a regression test intended to validate dimension preservation for sparse forms with “missing” variables.
.github/workflows/ci.yml Adds julia-actions/cache@v2 to speed up CI package operations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread test/unit/library/formats.jl Outdated

@bernalde bernalde left a comment

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 reproduced the regression on main and confirmed the parser change fixes it. The remaining issue is test coverage: the new QUBin regression test still passes on main, so it does not actually guard the broken behavior.

Tested locally on this branch with Julia 1.12.0:

  • JULIA_DEPOT_PATH=$PWD/.julia-depot:$HOME/.julia julia --project=. -e "using Pkg; Pkg.test()"
  • JULIA_DEPOT_PATH=$PWD/.julia-depot:$HOME/.julia QUBOTOOLS_FOREIGN_TESTS=true julia --project=. -e "using Pkg; Pkg.test()"

Both passed here. On main, a QUBin round-trip for a model with an unreferenced variable still fails at QUBOTools.value(dst_model, [1, 0, 1]) with DimensionMismatch: Vector x has a length 1 but y has a length 3.

Comment thread test/unit/library/formats.jl Outdated

Copilot AI commented Mar 18, 2026

Copy link
Copy Markdown
Contributor Author

I reproduced the regression on main and confirmed the parser change fixes it. The remaining issue is test coverage: the new QUBin regression test still passes on main, so it does not actually guar...

Updated in commit 621176d. The test now calls QUBOTools.value(dst_model, [1, 0, 1]) and QUBOTools.value(dst_model, [1, 1, 1]) after the round-trip, which exercises L' * ψ and ψ' * Q * ψ and would throw DimensionMismatch on main where the sparse structures have wrong dimensions.

Copilot AI requested a review from bernalde March 18, 2026 01:19

@bernalde bernalde left a comment

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 reproduced the bug on main and confirmed the parser fix is correct. The value() assertions in the latest commit are the right approach to catch the regression, since dimension() reads the stored n from the HDF5 file (the Form.n field) rather than deriving it from the sparse array sizes, and _compare_models only compares non-zero terms via findnz, meaning neither check would detect undersized sparse structures.

Testing summary (Julia 1.12.0, Linux):

  • All 612 tests pass on the PR branch (including the new "sparse dimensions" testset).
  • On main, value(dst_model, [1, 0, 1]) throws DimensionMismatch("Vector x has a length 1 but y has a length 3") exactly as expected.
  • The expected values in the assertions are correct: for the model with L = {1 => 1.0}, Q = {(1,2) => 2.0}, value([1,0,1]) = 1.0 and value([1,1,1]) = 3.0.

The core fix (passing n to sparsevec and sparse) is minimal and correct. There are a few items to address before merging, noted inline.

Comment thread src/library/format/qubin/parser.jl
Comment thread src/library/format/qubin/parser.jl
Comment thread test/unit/library/formats.jl Outdated
Comment thread test/unit/library/formats.jl Outdated
Comment thread .github/workflows/ci.yml
Comment thread .gitignore Outdated
Copilot AI and others added 5 commits March 17, 2026 22:50
Co-authored-by: bernalde <8647329+bernalde@users.noreply.github.com>
Co-authored-by: bernalde <8647329+bernalde@users.noreply.github.com>
…to .gitignore

Co-authored-by: bernalde <8647329+bernalde@users.noreply.github.com>
…ated .gitignore entry

Co-authored-by: bernalde <8647329+bernalde@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@bernalde
bernalde force-pushed the copilot/fix-sparse-constructor-dimensions branch from 31a4cba to a8103cb Compare March 18, 2026 03:01
@bernalde
bernalde merged commit 947ddb9 into main Mar 18, 2026
4 checks passed
@bernalde
bernalde deleted the copilot/fix-sparse-constructor-dimensions branch March 18, 2026 22:14
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.

Array dimensions missing in sparse(I, J, V, [m, n]) constructor

3 participants