`tfq_ps_decompose` truncates decomposed moments when `PhasedISwapPowGate` shares a `Moment` with `PhasedXPowGate` or `FSimGate`

Open
#1,141 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
74/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
python, tensorflow

Research direction

Read tensorflow_quantum/core/ops/tfq_ps_decompose_op.cc, especially TfqPsDecomposeOp::Compute around lines 71–147, and inspect the decomposition tests for tfq_ps_decompose. Reproduce the issue with the supplied circuit and compare the original and decomposed unitaries. Done means the output retains all six moments and the decomposed circuit matches the original unitary for the reproducer.

Written by the indexing model from the issue text.

Description

area/c++ area/core kind/bug-report

In TfqPsDecomposeOp::Compute (tensorflow_quantum/core/ops/tfq_ps_decompose_op.cc, lines 71–147), each Moment initializes int num_extra_moments = 0; and decomposes parameterized gates across cur_moment plus up to max_buffer_moments = 5 extra moments in temp_moment_list:

  • PISP (cirq.PhasedISwapPowGate, line 82) populates temp_moment_list[0..4] and sets num_extra_moments = 5;.
  • ISP (cirq.ISwapPowGate, line 102) populates temp_moment_list[0] and guards the update with if (num_extra_moments == 0) num_extra_moments = 1;.
  • PXP (cirq.PhasedXPowGate, line 115) populates temp_moment_list[0..1] and unconditionally assigns num_extra_moments = 2;.
  • FSIM (cirq.FSimGate, line 130) populates temp_moment_list[0..1] and unconditionally assigns num_extra_moments = 2;.

If a single Moment contains a parameterized PhasedISwapPowGate followed by a parameterized PhasedXPowGate or FSimGate on disjoint qubits, the later PXP or FSIM branch overwrites num_extra_moments from 5 down to 2. When extra moments are appended at lines 142–147, temp_moment_list[2] (YYP), temp_moment_list[3] (ZP), and temp_moment_list[4] (ZP) from the PhasedISwapPowGate decomposition are silently dropped, changing the circuit unitary and producing incorrect ParameterShift gradients.

Minimal Reproduction
import cirq
import numpy as np
import sympy
import tensorflow_quantum as tfq
from tensorflow_quantum.core.ops import tfq_ps_util_ops

q0, q1, q2 = cirq.GridQubit.rect(1, 3)
alpha = sympy.Symbol("alpha")
beta = sympy.Symbol("beta")

circuit = cirq.Circuit(
    cirq.Moment(
        cirq.PhasedISwapPowGate(phase_exponent=beta, exponent=alpha).on(q0, q1),
        cirq.PhasedXPowGate(phase_exponent=beta, exponent=alpha).on(q2),
    )
)

decomposed_tensor = tfq_ps_util_ops.tfq_ps_decompose(
    tfq.convert_to_tensor([circuit])
)
decomposed_circuit = tfq.from_tensor(decomposed_tensor)[0]

print("Moment count (expected 6, got):", len(decomposed_circuit.moments))
print(decomposed_circuit)

resolver = {"alpha": 0.35, "beta": 0.72}
u_orig = cirq.unitary(cirq.resolve_parameters(circuit, resolver))
u_decomp = cirq.unitary(cirq.resolve_parameters(decomposed_circuit, resolver))
print("Max unitary difference:", np.max(np.abs(u_orig - u_decomp)))

Observed output:

Moment count (expected 6, got): 3
(0, 0): ───Z^beta──────────────────XX────────────────
                                   │
(0, 1): ───────────────Z^(-beta)───XX^(-0.5*alpha)───

(0, 2): ───Z^(-beta)───X^alpha─────Z^beta────────────
Max unitary difference: 1.400898757622091
Possible Fix

Include <algorithm> and update num_extra_moments using std::max across all decomposed gate branches (num_extra_moments = std::max(num_extra_moments, 5); for PISP, 1 for ISP, and 2 for PXP and FSIM) so earlier decompositions in the same Moment are never truncated.

Related: #1140

Dominant language
Python
Stars
2.2k
Forks
674
Avg merge
1d 14h
Merged PRs (30d)
5

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from tensorflow/quantum

All issues in tensorflow/quantum

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.