Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] measure assumes all LinearCombination objects provide a sparse matrix #6264

Closed
1 task done
albi3ro opened this issue Sep 12, 2024 · 0 comments · Fixed by #6278
Closed
1 task done

[BUG] measure assumes all LinearCombination objects provide a sparse matrix #6264

albi3ro opened this issue Sep 12, 2024 · 0 comments · Fixed by #6278
Labels
bug 🐛 Something isn't working

Comments

@albi3ro
Copy link
Contributor

albi3ro commented Sep 12, 2024

Expected behavior

I would expect measure to use sum_of_terms, full_dot_product, or state_diagonalizing_gates when the observable does not provide a sparse matrix. Choice between methods is dependent on performance heuristics. But at least one that does not error out.

Actual behavior

It always chooses csr_dot_products when we don't need to differentiate the LinearCombination. Even when the observable doesn't support one.

Additional information

We should be following the same logic for both LinearCombination and Sum. Though this probably will probably also occur for Sum when the measurement process has overlapping wires and more than 7 wires.

Source code

H = qml.Hamiltonian([1,1], [qml.Hermitian(np.eye(2), 0), qml.X(0)])
@qml.qnode(qml.device('default.qubit'), interface=None)
def circuit():
    return qml.expval(H)

circuit()

Tracebacks

File ~/Prog/pennylane/pennylane/devices/qubit/measure.py:110, in csr_dot_products(measurementprocess, state, is_state_batched)
    108     res = new_bra.multiply(ket).sum(axis=1).getA()
    109 else:
--> 110     Hmat = measurementprocess.obs.sparse_matrix(wire_order=list(range(total_wires)))
    111     state = math.toarray(state).flatten()
    113     # Find the expectation value using the <\psi|H|\psi> matrix contraction

File ~/Prog/pennylane/pennylane/ops/op_math/sum.py:351, in Sum.sparse_matrix(self, wire_order)
    347     return self.pauli_rep.to_mat(wire_order=wire_order or self.wires, format="csr")
    349 gen = ((op.sparse_matrix(), op.wires) for op in self)
--> 351 reduced_mat, sum_wires = math.reduce_matrices(gen, reduce_func=math.add)
    353 wire_order = wire_order or self.wires
    355 return math.expand_matrix(reduced_mat, sum_wires, wire_order=wire_order)

File ~/Prog/pennylane/pennylane/math/matrix_manipulation.py:310, in reduce_matrices(mats_and_wires_gen, reduce_func)
    307     mat2 = expand_matrix(mat2, wires2, wire_order=expanded_wires)
    308     return reduce_func(mat1, mat2), expanded_wires
--> 310 reduced_mat, final_wires = reduce(expand_and_reduce, mats_and_wires_gen)
    312 return reduced_mat, final_wires

File ~/Prog/pennylane/pennylane/ops/op_math/sum.py:349, in <genexpr>(.0)
    346 if self.pauli_rep:  # Get the sparse matrix from the PauliSentence representation
    347     return self.pauli_rep.to_mat(wire_order=wire_order or self.wires, format="csr")
--> 349 gen = ((op.sparse_matrix(), op.wires) for op in self)
    351 reduced_mat, sum_wires = math.reduce_matrices(gen, reduce_func=math.add)
    353 wire_order = wire_order or self.wires

File ~/Prog/pennylane/pennylane/ops/op_math/sprod.py:262, in SProd.sparse_matrix(self, wire_order)
    260 if self.pauli_rep:  # Get the sparse matrix from the PauliSentence representation
    261     return self.pauli_rep.to_mat(wire_order=wire_order or self.wires, format="csr")
--> 262 mat = self.base.sparse_matrix(wire_order=wire_order).multiply(self.scalar)
    263 mat.eliminate_zeros()
    264 return mat

File ~/Prog/pennylane/pennylane/operation.py:891, in Operator.sparse_matrix(self, wire_order)
    873 def sparse_matrix(self, wire_order: Optional[WiresLike] = None) -> csr_matrix:
    874     r"""Representation of the operator as a sparse matrix in the computational basis.
    875 
    876     If ``wire_order`` is provided, the numerical representation considers the position of the
   (...)
    889 
    890     """
--> 891     canonical_sparse_matrix = self.compute_sparse_matrix(
    892         *self.parameters, **self.hyperparameters
    893     )
    895     return expand_matrix(canonical_sparse_matrix, wires=self.wires, wire_order=wire_order)

File ~/Prog/pennylane/pennylane/operation.py:871, in Operator.compute_sparse_matrix(*params, **hyperparams)
    852 @staticmethod
    853 def compute_sparse_matrix(
    854     *params: TensorLike, **hyperparams: dict[str, Any]
    855 ) -> csr_matrix:  # pylint:disable=unused-argument
    856     r"""Representation of the operator as a sparse matrix in the computational basis (static method).
    857 
    858     The canonical matrix is the textbook matrix representation that does not consider wires.
   (...)
    869         scipy.sparse._csr.csr_matrix: sparse matrix representation
    870     """
--> 871     raise SparseMatrixUndefinedError

SparseMatrixUndefinedError:

System information

master

Existing GitHub issues

  • I have searched existing GitHub issues to make sure the issue does not already exist.
@albi3ro albi3ro added the bug 🐛 Something isn't working label Sep 12, 2024
mudit2812 pushed a commit that referenced this issue Sep 23, 2024
…e. (#6278)

There are a couple of scenarios when `csr_dot_products` is not usable
for `Sum` and `Hamiltonians`:
1. When not all of the ops has a sparse matrix
2. When it's a legacy Hamiltonian and one of the ops are multi-wired.

Fixes #6264

[sc-73590]
[sc-73868]

---------

Co-authored-by: Pietropaolo Frisoni <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant