diff --git a/docs/index.rst b/docs/index.rst index 851dd653..ede5bf00 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -45,6 +45,13 @@ As shown below, a typical eigenvalue problem is broken up into three pieces: 1) Subspace Hamiltonians Loading Molecular data +.. toctree:: + :maxdepth: 1 + :caption: Tools + :hidden: + + Logging + .. toctree:: :maxdepth: 2 :caption: Tutorials diff --git a/docs/logging.ipynb b/docs/logging.ipynb new file mode 100644 index 00000000..ea9c55e0 --- /dev/null +++ b/docs/logging.ipynb @@ -0,0 +1,136 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "ab95cab7-0251-429b-b032-285d99ac0120", + "metadata": {}, + "source": [ + "# Logging\n", + "\n", + "The Python interface for Fulqrum has verbose logging functionality built in. Here we show an example of logging inside the Jupyter notebook from which this docuement is generated." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "2cb548ff-572f-48ff-866e-6fdb496c06f4", + "metadata": {}, + "outputs": [], + "source": [ + "import fulqrum as fq" + ] + }, + { + "cell_type": "markdown", + "id": "32711ed5-d447-4df4-b686-c0151b5dc8b7", + "metadata": {}, + "source": [ + "## Formatting the logger\n", + "\n", + "Here we show how to format the logger for useful output. Importantly, when using Jupyter notebooks we need to include `force=True` in the config in order to have the logs show up in the cell output" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "c0d613c5-e7b9-42ef-8a40-c166b014677b", + "metadata": {}, + "outputs": [], + "source": [ + "import logging\n", + "\n", + "logging.basicConfig(\n", + " level=logging.INFO,\n", + " force=True,\n", + " format=\"%(asctime)s - %(levelname)s - %(name)s - %(message)s\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "df505263-a762-46f1-8ab0-65cacdfed18e", + "metadata": {}, + "source": [ + "## Small example\n", + "\n", + "Here we load a molecule, transform it, build a subspace, and finally put them all together in a `SubspaceHamiltonian`. Having set the logging config above, the ouput from each logger entry will be displayed in the cell output." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "46c3b7e9-2bb9-459a-9be2-fd892e321003", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2026-08-19 06:59:27,767 - INFO - fulqrum.core.fermi_operator - Extended JW time: 0.758 ms\n", + "2026-08-19 06:59:27,768 - INFO - fulqrum.core.subspace - Initializing Subspace\n", + "2026-08-19 06:59:27,769 - INFO - fulqrum.core.subspace - Full subspace bit-strings\n", + "2026-08-19 06:59:27,769 - INFO - fulqrum.core.subspace - Subspace size: 4096\n", + "2026-08-19 06:59:27,769 - INFO - fulqrum.core.subspace - Number of bits: 12\n", + "2026-08-19 06:59:27,769 - INFO - fulqrum.core.subspace - Using all bitset blocks: True\n", + "2026-08-19 06:59:27,770 - INFO - fulqrum.core.subspace - Reserve multiplier: 2\n", + "2026-08-19 06:59:27,770 - INFO - fulqrum.core.subspace - Subspace total init time: 1.587 ms\n", + "2026-08-19 06:59:27,771 - INFO - fulqrum.core.linear_operator - Initializing SubspaceHamiltonian\n", + "2026-08-19 06:59:27,771 - INFO - fulqrum.core.linear_operator - Number of qubits: 12\n", + "2026-08-19 06:59:27,771 - INFO - fulqrum.core.linear_operator - Num. diagonal terms 78\n", + "2026-08-19 06:59:27,772 - INFO - fulqrum.core.linear_operator - Num. off-diagonal terms 552\n", + "2026-08-19 06:59:27,772 - INFO - fulqrum.core.qubit_operator - Term grouping time: 0.076 ms\n", + "2026-08-19 06:59:27,772 - INFO - fulqrum.core.linear_operator - Term grouping time: 0.344 ms\n", + "2026-08-19 06:59:27,773 - INFO - fulqrum.core.qubit_operator - Starting ladder int grouping, ladder_width = 2\n", + "2026-08-19 06:59:27,773 - INFO - fulqrum.core.qubit_operator - Ladder int grouping time: 0.096 ms\n", + "2026-08-19 06:59:27,773 - INFO - fulqrum.core.linear_operator - Num. off-diagonal groups: 83\n", + "2026-08-19 06:59:27,774 - INFO - fulqrum.core.spmv - Initializing FulqrumSpMV\n", + "2026-08-19 06:59:27,774 - INFO - fulqrum.core.spmv - Operator is real\n", + "2026-08-19 06:59:27,775 - INFO - fulqrum.core.spmv - Operator type = 2\n", + "2026-08-19 06:59:27,776 - INFO - fulqrum.core.spmv - FulqrumSpMV total init time: 1.683 ms\n", + "2026-08-19 06:59:27,776 - INFO - fulqrum.core.linear_operator - SubspaceHamiltonian total init time: 4.945 ms\n" + ] + } + ], + "source": [ + "fop = fq.FermionicOperator.from_json(\"./data/lih.json\")\n", + "op = fop.extended_jw_transformation()\n", + "\n", + "counts = []\n", + "for kk in range(2**op.width):\n", + " counts.append(bin(kk)[2:].zfill(op.width))\n", + "\n", + "S = fq.Subspace([counts])\n", + "Hsub = fq.SubspaceHamiltonian(op, S)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a30c27e6-6fcc-4933-8bf8-f912d14fe116", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.14.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/fulqrum/convert/integrals.pyx b/fulqrum/convert/integrals.pyx index fef7e018..8f0d4260 100644 --- a/fulqrum/convert/integrals.pyx +++ b/fulqrum/convert/integrals.pyx @@ -17,6 +17,9 @@ import time import numpy as np from ..core.fermi_operator cimport FermionicOperator +import logging +logger = logging.getLogger(__name__) + include "../core/includes/types.pxi" @@ -55,7 +58,7 @@ def integrals_to_fq_fermionic_op(double_or_complex[:,::1] one_body_integrals, do return fop -def fcidump_to_fq_fermionic_op(fcidump_path: str | Path, bool verbose=False) -> FermionicOperator: +def fcidump_to_fq_fermionic_op(fcidump_path: str | Path) -> FermionicOperator: """Load one- and two-body integrals as numpy arrays into Fulqrum fermionic operator from FCIDUMP file. @@ -65,16 +68,16 @@ def fcidump_to_fq_fermionic_op(fcidump_path: str | Path, bool verbose=False) -> Returns: FermionicOperator: Converted operator. """ + logger.info("Starting import of FCIDump file") from pyscf import ao2mo, tools - st = time.perf_counter() + scf_start = time.perf_counter() mf_as = tools.fcidump.to_scf(fcidump_path) hcore = mf_as.get_hcore() num_spatial_orbitals = hcore.shape[0] eri = ao2mo.restore(1, mf_as._eri, num_spatial_orbitals) nuclear_repulsion_energy = mf_as.mol.energy_nuc() - ft = time.perf_counter() - if verbose: - print("FCIDump import time", round(ft-st, 3)) + scf_stop = time.perf_counter() + logger.info("PySCF load time: %s ms", round((scf_stop - scf_start) * 1000, 3)) st = time.perf_counter() cdef FermionicOperator out = integrals_to_fq_fermionic_op( @@ -83,6 +86,5 @@ def fcidump_to_fq_fermionic_op(fcidump_path: str | Path, bool verbose=False) -> constant=nuclear_repulsion_energy, ) ft = time.perf_counter() - if verbose: - print("Operator conversion time", round(ft-st, 3)) + logger.info("Integrals to FermionicOperator time: %s ms", round((ft - st) * 1000, 3)) return out diff --git a/fulqrum/core/fermi_operator.pyx b/fulqrum/core/fermi_operator.pyx index a40ebbd3..72915a58 100644 --- a/fulqrum/core/fermi_operator.pyx +++ b/fulqrum/core/fermi_operator.pyx @@ -26,10 +26,14 @@ from ..convert import fcidump_to_fq_fermionic_op from pathlib import Path +import time import warnings import numpy as np cimport numpy as np +import logging +logger = logging.getLogger(__name__) + include "includes/base_header.pxi" include "includes/converters.pxi" include "includes/io.pxi" @@ -443,24 +447,33 @@ cdef class FermionicOperator(): Returns: FermionicOperator: Deflated operator """ + st = time.perf_counter() cdef size_t kk cdef FermionicOperator out = FermionicOperator(self.width) out.oper = self.oper.combine_repeat_indices() + ft = time.perf_counter() + logger.info("Combine repeat indices time: %s ms", round((ft - st) * 1000, 3)) return out def combine_repeat_terms(self, double atol=1e-12): """In-place sort terms by their standard weight """ + st = time.perf_counter() cdef FermionicOperator out = FermionicOperator(self.width) out.oper = self.oper.combine_repeat_terms(atol) + ft = time.perf_counter() + logger.info("Combine repeat terms time: %s ms", round((ft - st) * 1000, 3)) return out def extended_jw_transformation(self): """Jordan-Wigner transformation over extended alphabet from Fermionic -> Qubit operator """ + st = time.perf_counter() cdef QubitOperator out = QubitOperator(self.width) out.oper = self.oper.extended_jw_transformation() + ft = time.perf_counter() + logger.info("Extended JW time: %s ms", round((ft - st) * 1000, 3)) return out @cython.boundscheck(False) diff --git a/fulqrum/core/linear_operator.py b/fulqrum/core/linear_operator.py index 1361d99d..aec25147 100644 --- a/fulqrum/core/linear_operator.py +++ b/fulqrum/core/linear_operator.py @@ -13,6 +13,7 @@ """Fulqrum linearoperator module""" import os +import time import numpy as np from scipy.sparse.linalg import LinearOperator @@ -21,6 +22,10 @@ from .subspace import Subspace from ..exceptions import FulqrumError +import logging + +logger = logging.getLogger(__name__) + class SubspaceHamiltonian(LinearOperator): """Encapsulates the details of a subspace Hamiltonian problem @@ -35,15 +40,25 @@ def __init__(self, hamiltonian, subspace=None): """A SciPy `LinearOperator` that represents a Hamiltonian restricted to the given subspace. """ + logger.info("Initializing SubspaceHamiltonian") + hsub_init_start = time.perf_counter() if subspace: if hamiltonian.width != subspace.width: raise FulqrumError("Operator and subspace widths do not match") else: subspace = Subspace() + logger.info("Number of qubits: %s", hamiltonian.width) self.diag_H, self.off_H = hamiltonian.split_diagonal() self.diag_H, self.const_energy = self.diag_H.remove_constant_terms() + logger.info("Num. diagonal terms %s", self.diag_H.size()) + logger.info("Num. off-diagonal terms %s", self.off_H.size()) # if there are no off-diagonal terms then we pass a dummy empty array of len=1 + group_start = time.perf_counter() self.off_H.group_sort() + group_stop = time.perf_counter() + logger.info( + "Term grouping time: %s ms", round((group_stop - group_start) * 1000, 3) + ) self.group_ptrs = np.zeros(1, dtype=np.uintp) self.group_ladder_ptrs = np.zeros(1, dtype=np.uintp) @@ -58,6 +73,8 @@ def __init__(self, hamiltonian, subspace=None): ) self.group_ladder_ptrs = self.off_H.group_ladder_bin_starts() + logger.info("Num. off-diagonal groups: %s", self.group_ptrs.shape[0] - 1) + self.spmv = FulqrumSpMV( self.diag_H, self.const_energy, @@ -71,6 +88,11 @@ def __init__(self, hamiltonian, subspace=None): shape=(len(subspace),) * 2, dtype=np.dtype(float) if self.spmv.is_real else np.dtype(complex), ) + hsub_init_stop = time.perf_counter() + logger.info( + "SubspaceHamiltonian total init time: %s ms", + round((hsub_init_stop - hsub_init_start) * 1000, 3), + ) @property def num_groups(self): @@ -90,16 +112,15 @@ def update_subspace(self, subspace): self.spmv.update_subspace(subspace) self.shape = (len(subspace),) * 2 - def diagonal_vector(self, verbose=False, disable_fast_mode=False): + def diagonal_vector(self, disable_fast_mode=False): """Return diagonal vector of Hamiltonian in subspace Parameters: - verbose (bool): optional, verbose output, default=False disable_fast_mode (bool): optional, disable fast computation for type=2 Hamiltonians, default=False Returns: ndarray: Complex vector for diagonal of Hamiltonian """ - return self.spmv.diagonal_vector(verbose, disable_fast_mode) + return self.spmv.diagonal_vector(disable_fast_mode) def minimum_diagonal_energy(self): """Return the minimum diagonal energy @@ -165,6 +186,7 @@ def matvec(self, x): Returns: ndarray: Output vector after SpMV on input vector """ + start = time.perf_counter() col_vec = False if len(x.shape) == 2: col_vec = True @@ -176,38 +198,34 @@ def matvec(self, x): out = self.spmv.matvec(x) if col_vec: out = out.view().reshape(x.shape[0], 1) + stop = time.perf_counter() + logger.info("Matvec time: %s ms", round((stop - start) * 1000, 3)) return out - def to_csr_linearoperator(self, verbose=False): + def to_csr_linearoperator(self): """Convert subspace Hamiltonian to a LinearOperator wrapping a CSR matrix - Parameters: - verbose (bool): Turn on verbose mode, default=False. - Returns: CSRLinearOperator: LinearOperator wrapping a CSR matrix. """ - M = self.spmv.to_csr_array(verbose=verbose) + M = self.spmv.to_csr_array() return CSRLinearOperator(M, self.spmv.is_real) - def to_csr_linearoperator_fast(self, verbose=False): + def to_csr_linearoperator_fast(self): """Convert subspace Hamiltonian to a CSR LinearOperator faster but with a copy - Parameters: - verbose (bool): Turn on verbose mode, default=False. + Returns: + CSRLinearOperator: LinearOperator wrapping a CSR matrix. """ - M = self.spmv.to_csrlike(verbose).to_csr_array(verbose) + M = self.spmv.to_csrlike().to_csr_array() return CSRLinearOperator(M, self.spmv.is_real) - def _to_linearoperator(self, verbose=False): + def _to_linearoperator(self): """Convert subspace Hamiltonian to a CSR-like format LinearOperator This saves a matrix-traversal at the expense of a non-standard data type - - Parameters: - verbose (bool): Turn on verbose mode, default=False. """ - out = self.spmv.to_csrlike(verbose) + out = self.spmv.to_csrlike() return out diff --git a/fulqrum/core/qubit_operator.pyx b/fulqrum/core/qubit_operator.pyx index 9425ba1b..616de229 100644 --- a/fulqrum/core/qubit_operator.pyx +++ b/fulqrum/core/qubit_operator.pyx @@ -33,10 +33,14 @@ from .constants import np_width_t from collections.abc import Iterable from pathlib import Path +import time import numbers import numpy as np cimport numpy as np +import logging +logger = logging.getLogger(__name__) + include "includes/base_header.pxi" include "includes/elements_header.pxi" include "includes/bitset_utils_header.pxi" @@ -49,9 +53,6 @@ include "includes/diag_header.pxi" cdef const OperatorTerm_t EmptyOperatorTerm - - - cdef class QubitOperator(): """Operator class for qubit terms consisting of Pauli operators,projection operators, and ladder operators @@ -709,7 +710,10 @@ cdef class QubitOperator(): def group_sort(self): """Inplace sorting of operator terms into groups that represent matrix-elements. """ + cdef double st = time.perf_counter() self.oper.group_sort() + cdef double ft = time.perf_counter() + logger.info("Term grouping time: %s ms", round((ft - st) * 1000, 3)) def offdiag_weight_sort(self): """In-place sort terms by their off-diagonal weight @@ -745,8 +749,11 @@ cdef class QubitOperator(): Returns: QubitOperator: Operator with repeat terms combined """ + cdef double st = time.perf_counter() cdef QubitOperator out = QubitOperator(self.oper.width) out.oper = self.oper.combine_repeat_terms(atol) + cdef double ft = time.perf_counter() + logger.info("Combine repeat terms time: %s ms", round((ft - st) * 1000, 3)) return out @cython.boundscheck(False) @@ -811,7 +818,11 @@ cdef class QubitOperator(): """ if not self.oper.type == 2: raise FulqrumError("Operator must be type=2") + logger.info("Starting ladder int grouping, ladder_width = %s", ladder_width) + cdef double st = time.perf_counter() self.oper.group_term_sort_by_ladder_int(ladder_width) + cdef double ft = time.perf_counter() + logger.info("Ladder int grouping time: %s ms", round((ft - st) * 1000, 3)) def group_ladder_bin_starts(self): if not self.oper.type == 2: diff --git a/fulqrum/core/spmv.pyx b/fulqrum/core/spmv.pyx index f756b0ef..bd7fd53e 100644 --- a/fulqrum/core/spmv.pyx +++ b/fulqrum/core/spmv.pyx @@ -25,11 +25,16 @@ from .constants cimport width_t from .constants import np_width_t from ..exceptions import FulqrumError + from cython.parallel cimport prange, parallel import time import numpy as np import scipy.sparse as sp import psutil + +import logging +logger = logging.getLogger(__name__) + cimport numpy as np np.import_array() @@ -60,6 +65,8 @@ cdef class FulqrumSpMV(): size_t[::1]& group_ptrs, size_t[::1]& group_ladder_ptrs): + logger.info("Initializing FulqrumSpMV") + spmv_start = time.perf_counter() cdef size_t kk self.diag_oper = diag_hamiltonian.oper self.const_energy = const_energy @@ -79,7 +86,14 @@ cdef class FulqrumSpMV(): set_group_offdiag_indices(self.oper.terms, self.group_offdiag_inds, &self.group_ptrs[0], self.num_groups) + # Log is operator is real or not + if self.is_real: + logger.info("Operator is real") + else: + logger.info("Operator is complex") + if self.oper.type == 2: + logger.info("Operator type = 2") self.fast_diag = fast_diag_compatible(self.diag_oper) if self.oper.terms.size(): self.group_rowint_length = hamiltonian.group_rowint_length() @@ -89,7 +103,8 @@ cdef class FulqrumSpMV(): else: # Need to set memoryview but not used self.group_rowint_length = np.zeros(1, dtype=np_width_t) - + else: + logger.info("Operator type = 1") if self.diag_oper.terms.size() > 0 or self.const_energy: self.has_nonzero_diag = 1 # Init diagonal memoryview to None because @@ -102,6 +117,8 @@ cdef class FulqrumSpMV(): # grabbing a pointer to the data is going to complain self.real_diag_vec = np.empty(shape=(1,), dtype=float) self.complex_diag_vec = np.empty(shape=(1,), dtype=complex) + spmv_stop = time.perf_counter() + logger.info("FulqrumSpMV total init time: %s ms", round((spmv_stop - spmv_start)*1000, 3)) def __repr__(self): out = f"(self.subspace_dim + 1) < max_int): int_64 = 0 nnz = indptr64[self.subspace_dim] + logger.info("CSR NNZ: %s ", nnz) + logger.info("CSR use int64 indices: %s ", True if int_64 else False) # check if matrix will fit into memory if int_64: # indptr + indices + data sizes total_bytes = (self.subspace_dim + 1) * 8 + nnz * 8 + nnz * data_size else: total_bytes = (self.subspace_dim + 1) * 4 + nnz * 4 + nnz * data_size - if (psutil.virtual_memory().available) < total_bytes: + logger.info("Est. CSR matrix size: %s Mb", round(total_bytes/(1024**2), 3)) + mem = psutil.virtual_memory().available + logger.info("Available memory size: %s Mb", round(mem/(1024**2), 3)) + if mem < total_bytes: raise FulqrumError(f"Sparse matrix of size {round(total_bytes/(1024**2), 3)}Mb does not fit within available memory.") - if verbose: - print(f'Est. matrix size: {round(total_bytes/(1024**2), 3)}Mb') if int_64: indices64 = np.zeros(nnz, dtype=np.int64) @@ -485,11 +498,10 @@ cdef class FulqrumSpMV(): &complex_data[0], compute_values) stop = time.perf_counter() - if verbose: - if not compute_values: - print('CSR structure time', round(stop-start, 3)) - else: - print('CSR fill time', round(stop-start, 3)) + if not compute_values: + logger.info("CSR structure time: %s ms", round((stop - start)*1000, 3)) + else: + logger.info("CSR fill time: %s ms", round((stop - start)*1000, 3)) if int_64: if self.is_real: mat = sp.csr_array((real_data, indices64, indptr64), @@ -507,23 +519,22 @@ cdef class FulqrumSpMV(): start = time.perf_counter() quicksort_indices(mat.indices, mat.indptr, mat.data) stop = time.perf_counter() - if verbose: - print('CSR indices sort time', round(stop-start, 3)) + logger.info("CSR indices sort time: %s ms", round((stop - start)*1000, 3)) + csr_stop = time.perf_counter() + logger.info("CSR total matrix build time: %s ms", round((csr_stop - csr_start)*1000, 3)) return mat - def to_csrlike(self, int verbose=0): + def to_csrlike(self): # This is here to prevent a circular import from .linear_operator import CSRLikeLinearOperator # Compute diag vec if we have not done so already + logger.info("Building CSR matrix fast-mode") cdef double stop, start start = time.perf_counter() self.compute_diag_vector() - stop = time.perf_counter() - if verbose: - print(f"Diagonal vector build time: {round(stop-start, 3)}") cdef CSRLike csrlike = CSRLike(self.subspace_dim, self.is_real) - start = time.perf_counter() if csrlike.type_string == 'd32': + logger.info("CSR fast-mode double and int32") if self.oper.type == 1: csrlike_builder(self.oper.terms, self.subspace.subspace.bitstrings, @@ -553,6 +564,7 @@ cdef class FulqrumSpMV(): csrlike.data_d32.cols, csrlike.data_d32.data) elif csrlike.type_string == 'd64': + logger.info("CSR fast-mode double and int64") if self.oper.type == 1: csrlike_builder(self.oper.terms, self.subspace.subspace.bitstrings, @@ -582,6 +594,7 @@ cdef class FulqrumSpMV(): csrlike.data_d64.cols, csrlike.data_d64.data) elif csrlike.type_string == 'z32': + logger.info("CSR fast-mode complex and int32") if self.oper.type == 1: csrlike_builder(self.oper.terms, self.subspace.subspace.bitstrings, @@ -611,6 +624,7 @@ cdef class FulqrumSpMV(): csrlike.data_z32.cols, csrlike.data_z32.data) elif csrlike.type_string == 'z64': + logger.info("CSR fast-mode complex and int64") if self.oper.type == 1: csrlike_builder(self.oper.terms, self.subspace.subspace.bitstrings, @@ -641,8 +655,7 @@ cdef class FulqrumSpMV(): csrlike.data_z64.data) stop = time.perf_counter() - if verbose: - print(f'LinearOperator build time: {round(stop-start, 3)}') + logger.info("CSR fast-mode total build time: %s ms", round((stop - start)*1000, 3)) return CSRLikeLinearOperator(csrlike) diff --git a/fulqrum/core/subspace.pyx b/fulqrum/core/subspace.pyx index 9ae5c6a5..daeec393 100644 --- a/fulqrum/core/subspace.pyx +++ b/fulqrum/core/subspace.pyx @@ -16,12 +16,16 @@ from libcpp.algorithm cimport sort as stdsort from libcpp cimport bool from libc.math cimport abs +import time import itertools import math cimport cython import numpy as np cimport numpy as np +import logging +logger = logging.getLogger(__name__) + from ..exceptions import FulqrumError from .bitset cimport bitset_t, to_string from .bitset_view cimport BitsetView @@ -134,13 +138,17 @@ cdef class Subspace(): """ if not subspace_strs: return + logger.info("Initializing Subspace") + sub_start = time.perf_counter() cdef int input_bitsets = 0 cdef vector[string] alpha_strs cdef vector[string] beta_strs cdef size_t size, num_qubits if len(subspace_strs) == 0: + logger.info("Empty subspace") return elif len(subspace_strs) == 1: + logger.info("Full subspace bit-strings") iterator = subspace_strs[0] iterator.sort() num_qubits = len(next(iter(iterator))) @@ -148,6 +156,7 @@ cdef class Subspace(): if isinstance(iterator[0], Bitset): input_bitsets = 1 elif len(subspace_strs) == 2: + logger.info("Cartesian-product subspace bit-strings") alpha_strs = subspace_strs[0] beta_strs = subspace_strs[1] stdsort(alpha_strs.begin(), alpha_strs.end()) @@ -166,12 +175,17 @@ cdef class Subspace(): self.subspace.num_qubits = num_qubits self.subspace.size = size + logger.info("Subspace size: %s", size) + logger.info("Number of bits: %s", num_qubits) + if not use_all_bitset_blocks: self.subspace.bitstrings = BitsetHashMapWrapper(use_all_bitset_blocks) + logger.info("Using all bitset blocks: %s", use_all_bitset_blocks) if reserve_multiplier < 1: raise ValueError( f"`reserve_multiplier(={reserve_multiplier})` must be >= 1" ) + logger.info("Reserve multiplier: %s", reserve_multiplier) # The +1 is here because insertion would fail for a dim=1 subspace otherwise self.subspace.bitstrings.reserve(self.subspace.size * reserve_multiplier + 1) @@ -194,6 +208,8 @@ cdef class Subspace(): temp_bits = bitset_t(beta_strs[idx]+alpha_strs[jj], 0, num_qubits) self.subspace.bitstrings.insert_unique(temp_bits, counter) counter += 1 + sub_stop = time.perf_counter() + logger.info("Subspace total init time: %s ms", round((sub_stop - sub_start)*1000, 3)) def __dealloc__(self): # Clear hash table upon deallocation of class diff --git a/tutorials/n2_full_sqd_loop.ipynb b/tutorials/n2_full_sqd_loop.ipynb index eeff6171..2c00eaa0 100644 --- a/tutorials/n2_full_sqd_loop.ipynb +++ b/tutorials/n2_full_sqd_loop.ipynb @@ -458,7 +458,7 @@ " Hsub.update_subspace(S)\n", " # Convert the SubspaceHamiltonian into a CSR format sparse matrix,\n", " # which will also be wrapped in a LinearOperator for faster eigensolving.\n", - " Hsub_csr_linop = Hsub.to_csr_linearoperator_fast(verbose=False)\n", + " Hsub_csr_linop = Hsub.to_csr_linearoperator_fast()\n", " proj_end = time.perf_counter()\n", " print(f\" Operator projection took: {proj_end - proj_start:4f} seconds\")\n", "\n", @@ -523,7 +523,7 @@ ], "metadata": { "kernelspec": { - "display_name": "fq-public", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -537,7 +537,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.13" + "version": "3.14.4" } }, "nbformat": 4,