Skip to content

Commit

Permalink
!2249 [PY] Enable get matrix of parameterized operator with given Par…
Browse files Browse the repository at this point in the history
…ameterResolver

Merge pull request !2249 from donghufeng/dev/fix_subs
  • Loading branch information
donghufeng authored and gitee-org committed Jan 10, 2024
2 parents 970bd92 + e4c5c74 commit 35bc679
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,18 @@ mindquantum.core.operators.FermionOperator
返回:
FermionOperator,从字符串加载的FermionOperator。

.. py:method:: matrix(n_qubits: int = None)
.. py:method:: matrix(n_qubits: int = None, pr=None)
将此费米子运算符转换为jordan_wigner映射下的csr_matrix。

参数:
- **n_qubits** (int) - 结果矩阵的总量子比特数。如果是None,则该值将是最大局域量子比特数。默认值: ``None``。
- **pr** (ParameterResolver, dict, numpy.ndarray, list, numbers.Number) - 含参费米子算符的参数。默认值: ``None``。

.. py:method:: params_name
:property:

获取费米子算符的所有参数。

.. py:method:: normal_ordered()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,18 @@ mindquantum.core.operators.QubitOperator
返回:
QubitOperator,从字符串加载的QubitOperator。

.. py:method:: matrix(n_qubits: int = None)
.. py:method:: matrix(n_qubits: int = None, pr=None)
将此玻色子算符转换为csr_matrix。

参数:
- **n_qubits** (int) - 结果矩阵的量子比特数目。如果是None,则该值将是最大局域量子比特数。默认值: ``None``。
- **pr** (ParameterResolver, dict, numpy.ndarray, list, numbers.Number) - 含参玻色子算符的参数。默认值: ``None``。

.. py:method:: params_name
:property:

获取玻色子算符的所有参数。

.. py:method:: parameterized
:property:
Expand Down
31 changes: 25 additions & 6 deletions mindquantum/core/operators/fermion_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@
from mindquantum.dtype.dtype import str_dtype_map
from mindquantum.mqbackend import EQ_TOLERANCE
from mindquantum.third_party.interaction_operator import InteractionOperator
from mindquantum.utils.type_value_check import _check_int_type, _require_package
from mindquantum.utils.type_value_check import (
_check_and_generate_pr_type,
_check_int_type,
_require_package,
)


@lru_cache()
Expand Down Expand Up @@ -537,20 +541,27 @@ def hermitian(self) -> "FermionOperator":
"""
return FermionOperator(FermionOperator_.hermitian_conjugated(self), internal=True)

def matrix(self, n_qubits: int = None): # pylint: disable=too-many-branches
def matrix(self, n_qubits: int = None, pr=None): # pylint: disable=too-many-branches
"""
Convert this fermion operator to csr_matrix under jordan_wigner mapping.
Args:
n_qubits (int): The total qubit of final matrix. If None, the value will be
the maximum local qubit number. Default: None.
pr (ParameterResolver, dict, numpy.ndarray, list, numbers.Number): The parameter
resolver for parameterized FermionOperator. Default: None.
"""
if self.parameterized:
raise RuntimeError("Cannot convert a parameterized fermion operator to matrix.")
if pr is None:
pr = ParameterResolver()
pr = _check_and_generate_pr_type(pr, self.params_name)
np_type = mq.to_np_type(self.dtype)
ops = self
if self.parameterized:
ops = copy.copy(self)
ops = ops.subs(pr)
if not self.terms:
raise ValueError("Cannot convert empty fermion operator to matrix")
n_qubits_local = self.count_qubits()
n_qubits_local = ops.count_qubits()
if n_qubits_local == 0 and n_qubits is None:
raise ValueError("You should specific n_qubits for converting a identity fermion operator.")
if n_qubits is None:
Expand All @@ -561,7 +572,7 @@ def matrix(self, n_qubits: int = None): # pylint: disable=too-many-branches
f"Given n_qubits {n_qubits} is small than qubit of fermion operator, which is {n_qubits_local}."
)
out = 0
for term, coeff in self.terms.items():
for term, coeff in ops.terms.items():
coeff = coeff.const
if not term:
out += csr_matrix(np.identity(2**n_qubits, dtype=np_type)) * coeff
Expand All @@ -583,6 +594,14 @@ def matrix(self, n_qubits: int = None): # pylint: disable=too-many-branches
out += tmp * coeff
return out

@property
def params_name(self):
"""Get all parameters of this operator."""
names = []
for pr in self.terms.values():
names.extend([i for i in pr.params_name if i not in names])
return names

def normal_ordered(self) -> "FermionOperator":
"""
Return the normal ordered form of the Fermion Operator.
Expand Down
27 changes: 24 additions & 3 deletions mindquantum/core/operators/qubit_operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@
from mindquantum.core.parameterresolver import ParameterResolver, PRConvertible
from mindquantum.dtype.dtype import str_dtype_map
from mindquantum.mqbackend import EQ_TOLERANCE
from mindquantum.utils.type_value_check import _check_int_type, _require_package
from mindquantum.utils.type_value_check import (
_check_and_generate_pr_type,
_check_int_type,
_require_package,
)


# pylint: disable=too-many-public-methods
Expand Down Expand Up @@ -495,23 +499,40 @@ def hermitian(self) -> "QubitOperator":
"""
return QubitOperator(QubitOperator_.hermitian_conjugated(self), internal=True)

def matrix(self, n_qubits: int = None):
def matrix(self, n_qubits: int = None, pr=None):
"""
Convert this qubit operator to csr_matrix.
Args:
n_qubits (int): The total qubits of final matrix. If ``None``, the value will be
the maximum local qubit number. Default: ``None``.
pr (ParameterResolver, dict, numpy.ndarray, list, numbers.Number): The parameter
resolver for parameterized QubitOperator. Default: None.
"""
if pr is None:
pr = ParameterResolver()
pr = _check_and_generate_pr_type(pr, self.params_name)
ops = self
if self.parameterized:
ops = copy.copy(self)
ops = ops.subs(pr)
if n_qubits is None:
n_qubits = -1
_check_int_type('n_qubits', n_qubits)
csr = QubitOperator_.sparsing(self, n_qubits)
csr = QubitOperator_.sparsing(ops, n_qubits)
data = np.array(csr.data, copy=False)
indptr = np.array(csr.get_indptr(), copy=False)
indices = np.array(csr.get_indices(), copy=False)
return csr_matrix((data, indices, indptr), (csr.n_row, csr.n_col))

@property
def params_name(self):
"""Get all parameters of this operator."""
names = []
for pr in self.terms.values():
names.extend([i for i in pr.params_name if i not in names])
return names

def relabel(self, logic_qubits: typing.List[int]) -> "QubitOperator":
"""
Relabel the qubit according to the given logic qubits order.
Expand Down
14 changes: 14 additions & 0 deletions tests/st/test_core/test_operators/test_fermion_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import os
import pickle

import numpy as np
import pytest

from mindquantum.core.operators import FermionOperator
Expand Down Expand Up @@ -244,3 +245,16 @@ def test_relabel():
f_op = FermionOperator('3^ 2 1 0')
f_op = f_op.relabel([1, 3, 0, 2])
assert f_op == -FermionOperator('3 2^ 1 0')


@pytest.mark.level0
@pytest.mark.platform_x86_cpu
def test_get_matrix():
"""
Description: Test get matrix of fermion operator.
Expectation: success.
"""
a = FermionOperator('0', 'a')
with pytest.raises(ValueError, match="Parameter a not in given parameter resolver."):
a.matrix()
assert np.allclose(a.matrix(pr={'a': 1}).toarray(), FermionOperator('0').matrix().toarray())
13 changes: 13 additions & 0 deletions tests/st/test_core/test_operators/test_qubit_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,16 @@ def test_relabel():
q_op = QubitOperator('Z0 Y1 X2 Z3')
q_op = q_op.relabel([1, 3, 0, 2])
assert q_op == QubitOperator('X0 Z1 Z2 Y3')


@pytest.mark.level0
@pytest.mark.platform_x86_cpu
def test_get_matrix():
"""
Description: Test get matrix of qubit operator.
Expectation: success.
"""
a = QubitOperator('X0', 'a')
with pytest.raises(ValueError, match="Parameter a not in given parameter resolver."):
a.matrix()
assert np.allclose(a.matrix(pr={'a': 1}).toarray(), QubitOperator('X0').matrix().toarray())

0 comments on commit 35bc679

Please sign in to comment.