def __init__( self, hilbert: AbstractHilbert, operators: Union[List[Array], Array] = [], acting_on: Union[List[int], List[List[int]]] = [], constant: numbers.Number = 0, dtype: Optional[DType] = None, ): r""" Constructs a new ``LocalOperator`` given a hilbert space and (if specified) a constant level shift. Args: hilbert (netket.AbstractHilbert): Hilbert space the operator acts on. operators (list(numpy.array) or numpy.array): A list of operators, in matrix form. acting_on (list(numpy.array) or numpy.array): A list of sites, which the corresponding operators act on. constant (float): Level shift for operator. Default is 0.0. Examples: Constructs a ``LocalOperator`` without any operators. >>> from netket.hilbert import CustomHilbert >>> from netket.operator import LocalOperator >>> hi = CustomHilbert(local_states=[-1, 1])**20 >>> empty_hat = LocalOperator(hi) >>> print(len(empty_hat.acting_on)) 0 """ super().__init__(hilbert) self.mel_cutoff = 1.0e-6 self._initialized = None if not all([ _is_sorted(hilbert.states_at_index(i)) for i in range(hilbert.size) ]): raise ValueError( dedent( """LocalOperator needs an hilbert space with sorted state values at every site. """)) # Canonicalize input. From now on input is guaranteed to be in canonical order operators, acting_on, dtype = canonicalize_input(self.hilbert, operators, acting_on, constant, dtype=dtype) self._dtype = dtype self._constant = np.array(constant, dtype=dtype) self._operators_dict = {} for (op, aon) in zip(operators, acting_on): self._add_operator(aon, op)
def __init__( self, hilbert: AbstractHilbert, operators: Union[List[Array], Array] = [], acting_on: Union[List[int], List[List[int]]] = [], constant: numbers.Number = 0, dtype: Optional[DType] = None, ): r""" Constructs a new ``LocalOperator`` given a hilbert space and (if specified) a constant level shift. Args: hilbert (netket.AbstractHilbert): Hilbert space the operator acts on. operators (list(numpy.array) or numpy.array): A list of operators, in matrix form. acting_on (list(numpy.array) or numpy.array): A list of sites, which the corresponding operators act on. constant (float): Level shift for operator. Default is 0.0. Examples: Constructs a ``LocalOperator`` without any operators. >>> from netket.hilbert import CustomHilbert >>> from netket.operator import LocalOperator >>> hi = CustomHilbert(local_states=[-1, 1])**20 >>> empty_hat = LocalOperator(hi) >>> print(len(empty_hat.acting_on)) 0 """ super().__init__(hilbert) self._constant = constant if not all( [_is_sorted(hilbert.states_at_index(i)) for i in range(hilbert.size)] ): raise ValueError( dedent( """LocalOperator needs an hilbert space with sorted state values at every site. """ ) ) # check if passing a single operator or a list of operators if isinstance(acting_on, numbers.Number): acting_on = [acting_on] is_nested = any(hasattr(i, "__len__") for i in acting_on) if not is_nested: operators = [operators] acting_on = [acting_on] operators = [np.asarray(operator) for operator in operators] # If we asked for a specific dtype, enforce it. if dtype is None: dtype = functools.reduce( lambda dt, op: np.promote_types(dt, op.dtype), operators, np.float32 ) self._dtype = dtype self._init_zero() self.mel_cutoff = 1.0e-6 self._nonzero_diagonal = np.abs(self._constant) >= self.mel_cutoff """True if at least one element in the diagonal of the operator is nonzero""" for op, act in zip(operators, acting_on): if len(act) > 0: self._add_operator(op, act)
def pack_internals( hilbert: AbstractHilbert, operators_dict: dict, constant, dtype: DType, mel_cutoff: float, ): """ Take the internal lazy representation of a local operator and returns the arrays needed for the numba implementation. This takes as input a dictionary with Tuples as keys, the `acting_on` and matrices as values. The keys represent the sites upon which the matrix acts. It is assumed that the integer in the tuples are sorted. Returns a dictionary with all the data fields """ op_acting_on = list(operators_dict.keys()) operators = list(operators_dict.values()) n_operators = len(operators_dict) """Analyze the operator strings and precompute arrays for get_conn inference""" acting_size = np.array([len(aon) for aon in op_acting_on], dtype=np.intp) max_acting_on_sz = np.max(acting_size) max_local_hilbert_size = max( [max(map(hilbert.size_at_index, aon)) for aon in op_acting_on]) max_op_size = max(map(lambda x: x.shape[0], operators)) acting_on = np.full((n_operators, max_acting_on_sz), -1, dtype=np.intp) for (i, aon) in enumerate(op_acting_on): acting_on[i][:len(aon)] = aon local_states = np.full( (n_operators, max_acting_on_sz, max_local_hilbert_size), np.nan) basis = np.full((n_operators, max_acting_on_sz), 1e10, dtype=np.int64) diag_mels = np.full((n_operators, max_op_size), np.nan, dtype=dtype) mels = np.full( (n_operators, max_op_size, max_op_size - 1), np.nan, dtype=dtype, ) x_prime = np.full( (n_operators, max_op_size, max_op_size - 1, max_acting_on_sz), -1, dtype=np.float64, ) n_conns = np.full((n_operators, max_op_size), -1, dtype=np.intp) for (i, (aon, op)) in enumerate(operators_dict.items()): aon_size = len(aon) n_local_states_per_site = np.asarray( [hilbert.size_at_index(i) for i in aon]) ## add an operator to local_states for (j, site) in enumerate(aon): local_states[i, j, :hilbert.shape[site]] = np.asarray( hilbert.states_at_index(site)) ba = 1 for s in range(aon_size): basis[i, s] = ba ba *= hilbert.shape[aon_size - s - 1] # eventually could support sparse matrices # if isinstance(op, sparse.spmatrix): # op = op.todense() _append_matrix( op, diag_mels[i], mels[i], x_prime[i], n_conns[i], aon_size, local_states[i], mel_cutoff, n_local_states_per_site, ) nonzero_diagonal = (np.any(np.abs(diag_mels) >= mel_cutoff) or np.abs(constant) >= mel_cutoff) max_conn_size = 1 if nonzero_diagonal else 0 for op in operators: nnz_mat = np.abs(op) > mel_cutoff nnz_mat[np.diag_indices(nnz_mat.shape[0])] = False nnz_rows = np.sum(nnz_mat, axis=1) max_conn_size += np.max(nnz_rows) return { "acting_on": acting_on, "acting_size": acting_size, "diag_mels": diag_mels, "mels": mels, "x_prime": x_prime, "n_conns": n_conns, "local_states": local_states, "basis": basis, "nonzero_diagonal": nonzero_diagonal, "max_conn_size": max_conn_size, }