Exemplo n.º 1
0
    def __init__(
        self,
        hilbert: AbstractHilbert,
        operators: List[str] = None,
        weights: List[Union[float, complex]] = None,
        *,
        cutoff: float = 1.0e-10,
        dtype: DType = complex,
    ):
        """
        Constructs a new ``PauliStrings`` operator given a set of Pauli operators.
        This class has two possible forms for initialization: ``PauliStrings(hilbert, operators, ...)`` or  ``PauliStrings(operators, ...)``.
        When no hilbert argument is passed, the hilbert defaults to Qubit, where the number of qubits is automatically deduced from the operators.

        Args:
           hilbert: A hilbert space, optional (is no ``AbstractHilbert`` is passed, default is Qubit)
           operators (list(string)): A list of Pauli operators in string format, e.g. ['IXX', 'XZI'].
           weights: A list of amplitudes of the corresponding Pauli operator.
           cutoff (float): a cutoff to remove small matrix elements

        Examples:
           Constructs a new ``PauliStrings`` operator X_0*X_1 + 3.*Z_0*Z_1 with both construction schemes.

           >>> import netket as nk
           >>> operators, weights = ['XX','ZZ'], [1,3]
           >>> op = nk.operator.PauliStrings(operators, weights)
           >>> op.hilbert
           Qubit(N=2)
           >>> op.hilbert.size
           2
           >>> hilbert = nk.hilbert.Spin(1/2, 2)
           >>> op = nk.operator.PauliStrings(hilbert, operators, weights)
           >>> op.hilbert
           Spin(s=1/2, N=2)
        """
        if hilbert is None:
            raise ValueError("None-valued hilbert passed.")

        if not isinstance(hilbert, AbstractHilbert):
            # if first argument is not Hilbert, then shift all arguments by one
            hilbert, operators, weights = None, hilbert, operators

        if operators is None:
            raise ValueError(
                "None valued operators passed. (Might arised when passing None valued hilbert explicitly)"
            )

        if len(operators) == 0:
            raise ValueError("No Pauli operators passed.")

        if weights is None:
            # default weight is 1
            weights = [True for i in operators]

        if len(weights) != len(operators):
            raise ValueError("weights should have the same length as operators.")

        if not np.isscalar(cutoff) or cutoff < 0:
            raise ValueError("invalid cutoff in PauliStrings.")

        _hilb_size = len(operators[0])
        consistent = all(len(op) == _hilb_size for op in operators)
        if not consistent:
            raise ValueError("Pauli strings have inhomogeneous lengths.")

        consistent = all(bool(valid_pauli_regex.search(op)) for op in operators)
        if not consistent:
            raise ValueError(
                """Operators in string must be one of
                the Pauli operators X,Y,Z, or the identity I"""
            )

        if hilbert is None:
            hilbert = Qubit(_hilb_size)

        super().__init__(hilbert)
        if self.hilbert.local_size != 2:
            raise ValueError(
                "PauliStrings only work for local hilbert size 2 where PauliMatrices are defined"
            )

        self._cutoff = cutoff
        b_weights = np.asarray(weights, dtype=dtype)
        self._is_hermitian = np.allclose(b_weights.imag, 0.0)

        self._orig_operators = np.array(operators, dtype=str)
        self._orig_weights = np.array(weights, dtype=dtype)
        self._dtype = dtype

        self._initialized = False
Exemplo n.º 2
0
#
# Small hilbert space tests
#

# Spin 1/2
hilberts["Spin 1/2 Small"] = Spin(s=0.5, N=10)

# Spin 3
hilberts["Spin 1/2 with total Sz Small"] = Spin(s=3, total_sz=1.0, N=4)

# Boson
hilberts["Fock Small"] = Fock(n_max=3, N=5)

# Qubit
hilberts["Qubit Small"] = Qubit(N=1)

# Custom Hilbert
hilberts["Custom Hilbert Small"] = CustomHilbert(local_states=[-1232, 132, 0],
                                                 N=5)

# Custom Hilbert
hilberts["DoubledHilbert[Spin]"] = DoubledHilbert(Spin(0.5, N=5))

hilberts["DoubledHilbert[Spin(total_sz=0.5)]"] = DoubledHilbert(
    Spin(0.5, N=5, total_sz=0.5))

hilberts["DoubledHilbert[Fock]"] = DoubledHilbert(Spin(0.5, N=5))

hilberts["DoubledHilbert[CustomHilbert]"] = DoubledHilbert(
    CustomHilbert(local_states=[-1232, 132, 0], N=5))
Exemplo n.º 3
0
    def __init__(
        self,
        operators: List[str],
        weights: List[Union[float, complex]],
        cutoff: float = 1.0e-10,
        dtype: DType = complex,
    ):
        """
        Constructs a new ``PauliStrings`` operator given a set of Pauli operators.

        Args:
           operators (list(string)): A list of Pauli operators in string format, e.g. ['IXX', 'XZI'].
           weights: A list of amplitudes of the corresponding Pauli operator.
           cutoff (float): a cutoff to remove small matrix elements

        Examples:
           Constructs a new ``PauliStrings`` operator X_0*X_1 + 3.*Z_0*Z_1.

           >>> import netket as nk
           >>> op = nk.operator.PauliStrings(operators=['XX','ZZ'], weights=[1,3])
           >>> op.hilbert.size
           2
        """
        if len(operators) == 0:
            raise ValueError("No Pauli operators passed.")

        if len(weights) != len(operators):
            raise ValueError(
                "weights should have the same length as operators.")

        if not np.isscalar(cutoff) or cutoff < 0:
            raise ValueError("invalid cutoff in PauliStrings.")

        _n_qubits = len(operators[0])
        consistent = all(len(op) == _n_qubits for op in operators)
        if not consistent:
            raise ValueError("Pauli strings have inhomogeneous lengths.")

        def valid_match(strg, search=re.compile(r"^[XYZI]+$").search):
            return bool(search(strg))

        consistent = all(valid_match(op) for op in operators)
        if not consistent:
            raise ValueError("""Operators in string must be one of
                the Pauli operators X,Y,Z, or the identity I""")

        self._n_qubits = _n_qubits
        super().__init__(Qubit(_n_qubits))

        n_operators = len(operators)

        self._cutoff = cutoff
        b_weights = np.asarray(weights, dtype=dtype)

        b_to_change = [] * n_operators
        b_z_check = [] * n_operators

        acting = {}

        def find_char(s, ch):
            return [i for i, ltr in enumerate(s) if ltr == ch]

        def append(key, k):
            # convert list to tuple
            key = tuple(key)
            if key in acting:
                acting[key].append(k)
            else:
                acting[key] = [k]

        _n_z_check_max = 0

        for i, op in enumerate(operators):
            b_to_change = []
            b_z_check = []
            b_weights = weights[i]

            x_ops = find_char(op, "X")
            if len(x_ops):
                b_to_change += x_ops

            y_ops = find_char(op, "Y")
            if len(y_ops):
                b_to_change += y_ops
                b_weights *= (1.0j)**(len(y_ops))
                b_z_check += y_ops

            z_ops = find_char(op, "Z")
            if len(z_ops):
                b_z_check += z_ops

            _n_z_check_max = max(_n_z_check_max, len(b_z_check))
            append(b_to_change, (b_weights, b_z_check))

        # now group together operators with same final state
        n_operators = len(acting)
        _n_op_max = max(list(map(lambda x: len(x), list(acting.values()))),
                        default=n_operators)

        # unpacking the dictionary into fixed-size arrays
        _sites = np.empty((n_operators, _n_qubits), dtype=np.intp)
        _ns = np.empty((n_operators), dtype=np.intp)
        _n_op = np.empty(n_operators, dtype=np.intp)
        _weights = np.empty((n_operators, _n_op_max), dtype=dtype)
        _nz_check = np.empty((n_operators, _n_op_max), dtype=np.intp)
        _z_check = np.empty((n_operators, _n_op_max, _n_z_check_max),
                            dtype=np.intp)

        for i, act in enumerate(acting.items()):
            sites = act[0]
            nsi = len(sites)
            _sites[i, :nsi] = sites
            _ns[i] = nsi
            values = act[1]
            _n_op[i] = len(values)
            for j in range(_n_op[i]):
                _weights[i, j] = values[j][0]
                _nz_check[i, j] = len(values[j][1])
                _z_check[i, j, :_nz_check[i, j]] = values[j][1]

        self._sites = _sites
        self._ns = _ns
        self._n_op = _n_op
        self._weights = _weights
        self._nz_check = _nz_check
        self._z_check = _z_check

        self._x_prime_max = np.empty((n_operators, _n_qubits))
        self._mels_max = np.empty((n_operators), dtype=dtype)
        self._n_operators = n_operators
        self._dtype = dtype
        self._is_hermitian = np.allclose(self._weights.imag, 0.0)