Skip to content

Fix factor-of-2 in PolyOptimizer quadratic coupling encoding - #135

Merged
gcattan merged 1 commit into
IBM:mainfrom
gcattan:fix/poly-optimizer-quadratic-scaling
Sep 7, 2026
Merged

Fix factor-of-2 in PolyOptimizer quadratic coupling encoding#135
gcattan merged 1 commit into
IBM:mainfrom
gcattan:fix/poly-optimizer-quadratic-scaling

Conversation

@gcattan

@gcattan gcattan commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Both quadratic branches of _encode() wrote half the coupling weight they should. The comments ("factor-of-2 symmetry accounted for") show the reasoning: the author assumed a symmetric pair contributes 2*J[i,j] to the energy and pre-divided by two.

It does not. Solvers read J through the 1/2 * s.J.s convention -- see the energy readout in CaSuDaSolver.solve(), and note that field = m @ J is exactly the gradient of that form -- under which the (i,j) and (j,i) entries and the leading 1/2 cancel, so a symmetric pair contributes J[i,j] undivided.

h was already correct, so the encoded landscape was not a rescaling of the target polynomial but a distortion of it: the linear part kept its weight while the quadratic part lost half of its own. Minimising -0.75x - 0.75y + xy over {0,1}^2 flattens the true optima (1,0)/(0,1) at -0.75 into a three-way tie with (1,1) at -0.5. Across 40 random polynomials, 37 encodings failed to be an affine image of their polynomial; doubling J fixes all 40 exactly.

p-kit already had the right convention elsewhere: TransverseFieldIsing.from_qubo uses -Q/4 for the pair coefficient under the identical (1+s)/2 mapping. The two converters disagreed by exactly this factor of 2.

test_quadratic_J had pinned the buggy value, having been written from the implementation rather than the mathematics, which is how this survived. It now asserts the derived value. The new tests check that J/h reproduce the polynomial up to an additive constant -- comparing only argmin is unsafe, since a mis-scaled coupling produces ties that an argmin assertion passes on an arbitrary tie-break.

DocplexOptimizer inherits the fix.

Both quadratic branches of _encode() wrote half the coupling weight they
should. The comments ("factor-of-2 symmetry accounted for") show the
reasoning: the author assumed a symmetric pair contributes 2*J[i,j] to the
energy and pre-divided by two.

It does not. Solvers read J through the 1/2 * s.J.s convention -- see the
energy readout in CaSuDaSolver.solve(), and note that `field = m @ J` is
exactly the gradient of that form -- under which the (i,j) and (j,i) entries
and the leading 1/2 cancel, so a symmetric pair contributes J[i,j]
undivided.

h was already correct, so the encoded landscape was not a rescaling of the
target polynomial but a distortion of it: the linear part kept its weight
while the quadratic part lost half of its own. Minimising -0.75x - 0.75y + xy
over {0,1}^2 flattens the true optima (1,0)/(0,1) at -0.75 into a three-way
tie with (1,1) at -0.5. Across 40 random polynomials, 37 encodings failed to
be an affine image of their polynomial; doubling J fixes all 40 exactly.

p-kit already had the right convention elsewhere: TransverseFieldIsing.from_qubo
uses -Q/4 for the pair coefficient under the identical (1+s)/2 mapping. The two
converters disagreed by exactly this factor of 2.

test_quadratic_J had pinned the buggy value, having been written from the
implementation rather than the mathematics, which is how this survived. It now
asserts the derived value. The new tests check that J/h reproduce the
polynomial up to an additive constant -- comparing only argmin is unsafe, since
a mis-scaled coupling produces ties that an argmin assertion passes on an
arbitrary tie-break.

DocplexOptimizer inherits the fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@toncho11

toncho11 commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Yes, looks good.

@gcattan
gcattan merged commit 4975276 into IBM:main Sep 7, 2026
7 of 8 checks passed
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