diff --git a/pyproject.toml b/pyproject.toml index a8712aa46..e3f5a1e3a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,6 @@ members = [ [dependency-groups] dev = [ - "nanobind", "maturin>=1.2,<2.0", # For building (should match build requirements) "setuptools>=62.6", # Build system "pre-commit", # Git hooks diff --git a/python/quantum-pecos/src/pecos/qeclib/generic/check.py b/python/quantum-pecos/src/pecos/qeclib/generic/check.py index a2afe6883..fe9b7694a 100644 --- a/python/quantum-pecos/src/pecos/qeclib/generic/check.py +++ b/python/quantum-pecos/src/pecos/qeclib/generic/check.py @@ -41,6 +41,8 @@ def __init__( paulis: str, a: Qubit, out: Bit, + *, + with_barriers: bool = False, ) -> None: """Initialize a stabilizer check measurement. @@ -50,6 +52,8 @@ def __init__( Can be a single character (applied to all qubits) or one character per qubit. a: Ancilla qubit used for the check measurement. out: Classical bit to store the measurement result. + with_barriers: Whether to insert barrier instructions between operations to prevent + gate reordering. Defaults to False. Raises: Exception: If check weight is less than 2. @@ -84,12 +88,20 @@ def __init__( ) for i in range(n): + if with_barriers: + self.extend( + Barrier(a, d[i]), # to preserve order + ) + self.extend( - Barrier(a, d[i]), # to preserve order self.cp(ps[i], a, d[i]), - Barrier(a, d[i]), # to preserve order ) + if with_barriers: + self.extend( + Barrier(a, d[i]), # to preserve order + ) + self.extend( H(a), Measure(a) > out, diff --git a/python/quantum-pecos/src/pecos/qeclib/generic/check_1flag.py b/python/quantum-pecos/src/pecos/qeclib/generic/check_1flag.py index d98035a33..85897fb4b 100644 --- a/python/quantum-pecos/src/pecos/qeclib/generic/check_1flag.py +++ b/python/quantum-pecos/src/pecos/qeclib/generic/check_1flag.py @@ -43,6 +43,8 @@ def __init__( flag: Qubit, out: Bit, out_flag: Bit, + *, + with_barriers: bool = False, ) -> None: """Initialize a stabilizer check measurement with flag qubit. @@ -54,6 +56,8 @@ def __init__( flag: Flag qubit used to detect hook errors. out: Classical bit to store the measurement result. out_flag: Classical bit to store the flag measurement result. + with_barriers: Whether to insert barrier instructions between operations to prevent + gate reordering. Defaults to False. Raises: Exception: If check weight is less than 3. @@ -83,25 +87,54 @@ def __init__( Comment(f"Measure check {ops}"), Prep(a, flag), H(a), - Barrier(a, d[0]), + ) + if with_barriers: + self.extend( + Barrier(a, d[0]), + ) + self.extend( self.cu(ops[0], a, d[0]), - Barrier(a, flag), + ) + if with_barriers: + self.extend( + Barrier(a, flag), + ) + self.extend( CX(a, flag), - Barrier(a, flag), ) + if with_barriers: + self.extend( + Barrier(a, flag), + ) for i in range(1, n - 1): self.extend( self.cu(ops[i], a, d[i]), - Barrier(a, d[i]), # To preserve order ) + if with_barriers: + self.extend( + Barrier(a, d[i]), # To preserve order + ) + if with_barriers: + self.extend( + Barrier(a, flag), + ) self.extend( - Barrier(a, flag), CX(a, flag), - Barrier(a, flag), + ) + if with_barriers: + self.extend( + Barrier(a, flag), + ) + self.extend( self.cu(ops[-1], a, d[-1]), - Barrier(a, d[-1]), + ) + if with_barriers: + self.extend( + Barrier(a, d[-1]), + ) + self.extend( H(a), Measure(a) > out, Measure(flag) > out_flag, diff --git a/python/quantum-pecos/src/pecos/qeclib/steane/preps/plus_h_state.py b/python/quantum-pecos/src/pecos/qeclib/steane/preps/plus_h_state.py index cc035671a..c8a933b40 100644 --- a/python/quantum-pecos/src/pecos/qeclib/steane/preps/plus_h_state.py +++ b/python/quantum-pecos/src/pecos/qeclib/steane/preps/plus_h_state.py @@ -89,6 +89,7 @@ def __init__( flag=a[1], out=out[0], out_flag=out[1], + with_barriers=True, ), ) diff --git a/python/quantum-pecos/src/pecos/qeclib/steane/qec/qec_3parallel.py b/python/quantum-pecos/src/pecos/qeclib/steane/qec/qec_3parallel.py index 788147e4f..980d4f1f3 100644 --- a/python/quantum-pecos/src/pecos/qeclib/steane/qec/qec_3parallel.py +++ b/python/quantum-pecos/src/pecos/qeclib/steane/qec/qec_3parallel.py @@ -16,6 +16,7 @@ # specific language governing permissions and limitations under the License. from pecos.qeclib.steane.decoders.lookup import ( + FlagLookupQASM, FlagLookupQASMActiveCorrectionX, FlagLookupQASMActiveCorrectionZ, ) @@ -111,3 +112,89 @@ def __init__( scratch, ), ) + + +class ParallelFlagQEC(Block): + """Defining QEC Block that does adaptive syndrome extraction, decodes, and updates the Paul frame.""" + + def __init__( + self, + q: QReg, + a: QReg, + flag_x: CReg, + flag_z: CReg, + flags: CReg, + syn_x: CReg, + syn_z: CReg, + last_raw_syn_x: CReg, + last_raw_syn_z: CReg, + syndromes: CReg, + pf_x: Bit, + pf_z: Bit, + scratch: CReg, + ) -> None: + """Initialize ParallelFlagQECActiveCorrection block for error correction. + + Args: + q: Data register containing the 7 qubits of the Steane code. + a: Ancilla register for syndrome extraction. + flag_x: Classical register for X stabilizer flags. + flag_z: Classical register for Z stabilizer flags. + flags: Combined flags register. + syn_x: Classical register for X syndromes. + syn_z: Classical register for Z syndromes. + last_raw_syn_x: Previous X syndrome measurements. + last_raw_syn_z: Previous Z syndrome measurements. + syndromes: Classical register for syndrome storage. + pf_x: Pauli frame bit for X errors. + pf_z: Pauli frame bit for Z errors. + scratch: Scratch classical register for intermediate calculations. + """ + super().__init__( + # flagging XZZ checks + ThreeParallelFlaggingXZZ( + q, + a, + flag_x, + flag_z, + flags, + last_raw_syn_x, + last_raw_syn_z, + ), + # flagging ZXX checks + If(flags == 0).Then( + ThreeParallelFlaggingZXX( + q, + a, + flag_x, + flag_z, + flags, + last_raw_syn_x, + last_raw_syn_z, + ), + ), + # Remeasure all the checks unflagged + If(flags != 0).Then( + SixUnflaggedSyn(q, a, syn_x, syn_z), + ), + FlagLookupQASM( + basis="X", + syn=syn_x, + syndromes=syndromes, + raw_syn=last_raw_syn_x, + pf=pf_z, + flag=flag_x, + flags=flags, + scratch=scratch, + ), + FlagLookupQASM( + basis="Z", + syn=syn_z, + syndromes=syndromes, + raw_syn=last_raw_syn_z, + pf=pf_x, + flag=flag_z, + flags=flags, + scratch=scratch, + ), + ) diff --git a/python/quantum-pecos/src/pecos/qeclib/steane/steane_class.py b/python/quantum-pecos/src/pecos/qeclib/steane/steane_class.py index 81ed0fc4e..3593154a9 100644 --- a/python/quantum-pecos/src/pecos/qeclib/steane/steane_class.py +++ b/python/quantum-pecos/src/pecos/qeclib/steane/steane_class.py @@ -17,7 +17,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, NoReturn from warnings import warn from pecos.qeclib.steane.decoders.lookup import ( @@ -33,7 +33,12 @@ PrepEncodeTPlusFTRUS, PrepEncodeTPlusNonFT, ) -from pecos.qeclib.steane.qec.qec_3parallel import ParallelFlagQECActiveCorrection +from pecos.qeclib.steane.qec.qec_3parallel import ( + ParallelFlagQEC, + ParallelFlagQECActiveCorrection, +) +from pecos.qeclib.steane.syn_extract.bare import SynExtractBare +from pecos.qeclib.steane.syn_extract.flagged import SynExtractFlagged from pecos.slr import Block, CReg, If, Permute, QReg, Vars if TYPE_CHECKING: @@ -52,6 +57,7 @@ def __init__( name: str, default_rus_limit: int = 3, ancillas: QReg | None = None, + flag_qubits: QReg | None = None, ) -> None: """Initialize a Steane code instance with associated quantum and classical registers. @@ -60,13 +66,21 @@ def __init__( default_rus_limit: Default limit for repeat-until-success procedures. Defaults to 3. ancillas: Optional pre-existing ancilla register. If None, creates a new 3-qubit ancilla register. Must have at least 3 qubits if provided. + flag_qubits: Optional pre-existing flag qubit register. If None, creates a new 3-qubit + flag register when needed. Raises: ValueError: If provided ancilla register has fewer than 3 qubits. """ super().__init__() + self.check_indices = [[3, 2, 4, 1], [6, 3, 2, 5], [7, 6, 3, 4]] + self.d = QReg(f"{name}_d", 7) self.a = ancillas or QReg(f"{name}_a", 3) + if flag_qubits is not None: + self.f = flag_qubits or QReg(f"{name}_f", 3) + else: + self.f = None self.c = CReg(f"{name}_c", 32) if self.a.size < 3: @@ -98,6 +112,9 @@ def __init__( if ancillas is None: self.vars.append(self.a) + if flag_qubits is None: + self.vars.append(self.f) + self.vars.extend( [ self.c, @@ -545,6 +562,101 @@ def qec(self, flag: Bit | None = None) -> Block: block.extend(If(self.flags != 0).Then(flag.set(1))) return block + def qec_not_active( + self, + flag: Bit | None = None, + pf_x: Bit | None = None, + pf_z: Bit | None = None, + flag_x: CReg | None = None, + flag_z: CReg | None = None, + syn_x: CReg | None = None, + syn_z: CReg | None = None, + ) -> Block: + """Perform quantum error correction using parallel flag-based without active correction. + + There are potentially three syndrome extraction paths take: + 0: XZZ flag_x = 000, flag_z = 000 -> ZXX flag_x = 000, flag_z = 000 -> Done + 1: XZZ flag_x = 00*, flag_z = **0 -> measure XXXZZZ (syn_x, syn_z) + 2: XZZ flag_x = 000, flag_z = 000 -> ZXX flag_x = **0, flag_z = 00* -> measure XXXZZZ (syn_x, syn_z) + (where at least one of the *s is 1) + + Therefore: + if flag_x & flag_z == 0, we went down path 0 + if flag_x[0] | flag_z[1] | flag_z[2] == 1, we went down path 1 + if flag_x[1] | flag_z[2] | flag_z[0] == 1, we went down path 2 + + Args: + flag: Optional flag bit for conditional execution. + flag_x: Optional CReg of the syndrome measured by the X checks for the first two of flagged syndrome + extractions. It is a raw syndrome made during the first two rounds of syndrome extraction. + flag_z: Optional CReg of the syndrome measured by the X checks for the first two of flagged syndrome + extractions. It is a raw syndrome made during the first two rounds of syndrome extraction. + syn_x: Optional CReg of the syndrome measured by the X checks for the last round of non-flagged syndrome + extraction. It is a raw syndrome made during the final round of syndrome extraction. + syn_z: Optional CReg of the syndrome measured by the Z checks for the last round of non-flagged syndrome + extraction. It is a raw syndrome made during the final round of syndrome extraction. + pf_x: Optional Pauli frame bit for logical X corrections determined by lookup table decoder + pf_z: Optional Pauli frame bit for logical Z corrections determined by lookup table decoder + + Returns: + Block containing the quantum error correction operations. + """ + block = Block() + + block.extend( + ParallelFlagQEC( + q=self.d, + a=self.a, + flag_x=self.flag_x, + flag_z=self.flag_z, + flags=self.flags, + syn_x=self.syn_x, + syn_z=self.syn_z, + last_raw_syn_x=self.last_raw_syn_x, + last_raw_syn_z=self.last_raw_syn_z, + syndromes=self.syndromes, + pf_x=self.pf_x, + pf_z=self.pf_z, + scratch=self.scratch, + ), + ) + if flag is not None: + block.extend( + If(self.flags != 0).Then(flag.set(1)), + ) + + if flag_x is not None: + if len(flag_x) != 3: + msg = f"flag_x must have length 3, got {len(flag_x)}" + raise ValueError(msg) + block.extend(flag_x.set(self.flag_x)) + + if flag_z is not None: + if len(flag_z) != 3: + msg = f"flag_z must have length 3, got {len(flag_z)}" + raise ValueError(msg) + block.extend(flag_z.set(self.flag_z)) + + if syn_x is not None: + if len(syn_x) != 3: + msg = f"syn_x must have length 3, got {len(syn_x)}" + raise ValueError(msg) + block.extend(syn_x.set(self.syn_x)) + + if syn_z is not None: + if len(syn_z) != 3: + msg = f"syn_z must have length 3, got {len(syn_z)}" + raise ValueError(msg) + block.extend(syn_z.set(self.syn_z)) + + if pf_x is not None: + block.extend(pf_x.set(self.pf_x)) + + if pf_z is not None: + block.extend(pf_z.set(self.pf_z)) + + return block + def qec_steane( self, aux: Steane, @@ -699,12 +811,47 @@ def qec_tel_z( block.extend(If(self.syn_meas != 0).Then(flag.set(1))) return block + def qec_knill(self) -> NoReturn: + """Prepare a Bell state and then teleport.""" + # TODO: ... + msg = "qec_knill not implemented." + raise NotImplementedError(msg) + + def syn_bare(self, syn: CReg) -> Block: + """One single syndrome bit per check using bare syndrome extraction.""" + return SynExtractBare(self.d, self.a, self.check_indices, syn) + + def syn_flagged(self, syn: CReg, flags: CReg) -> Block: + """One single syndrome bit and one single flag bit per check.""" + return SynExtractFlagged(self.d, self.a, self.f, self.check_indices, syn, flags) + + def syn_2para_v1_flagged(self) -> NoReturn: + """Two-parallel syndrome extraction version 1 with flagging (not implemented). + + Raises: + NotImplementedError: This method is not yet implemented. + """ + # TODO: ... + msg = "syn_2para_v1_flagged not implemented." + raise NotImplementedError(msg) + + def syn_2para_v2_flagged(self) -> NoReturn: + """Two-parallel syndrome extraction version 2 with flagging (not implemented). + + Raises: + NotImplementedError: This method is not yet implemented. + """ + # TODO: ... + msg = "syn_2para_v2_flagged not implemented." + raise NotImplementedError(msg) + def permute(self, other: Steane) -> Block: """Permute this code block (including both quantum and classical registers) with another.""" block = Block( Permute(self.d, other.d), Permute(self.a, other.a), ) + # TODO: Use Permute on classical variables rather that a custom solution for var_a, var_b in zip(self.vars, other.vars, strict=False): if isinstance(var_a, CReg): block.extend( diff --git a/python/quantum-pecos/src/pecos/qeclib/steane/syn_extract/bare.py b/python/quantum-pecos/src/pecos/qeclib/steane/syn_extract/bare.py new file mode 100644 index 000000000..63c0a3ced --- /dev/null +++ b/python/quantum-pecos/src/pecos/qeclib/steane/syn_extract/bare.py @@ -0,0 +1,80 @@ +"""Bare syndrome extraction implementations for the Steane code. + +This module provides syndrome extraction without flag qubits for detecting +errors in the Steane 7-qubit quantum error correction code. +""" + +from itertools import cycle +from typing import Any + +from pecos.qeclib.generic.check import Check +from pecos.slr import Block, Comment, CReg, QReg + + +def poly2qubits(poly: list[Any], data: QReg) -> list[Any]: + """Convert polygon node IDs to qubit references. + + Args: + poly: Polygon representation with node IDs and color. + data: Quantum register containing the data qubits. + + Returns: + List of qubit references corresponding to the polygon nodes. + """ + return [data[q] for q in poly] + + +class SynExtractBare(Block): + """Bare syndrome extraction for Steane code without flag qubits.""" + + def __init__(self, data: QReg, ancillas: QReg, checks: list, syn: CReg) -> None: + """Initialize bare syndrome extraction. + + Args: + data: Data qubit register. + ancillas: Ancilla qubit register. + checks: List of check operators to apply. + syn: Classical register for syndrome storage. + + Raises: + ValueError: If syndrome register length doesn't match expected size. + """ + if len(syn) != 2 * len(checks) or len(syn) != 6: + msg = f"Expected syndrome register of length 6 (2 * {len(checks)} checks), got {len(syn)}" + raise ValueError(msg) + a = cycle(range(len(ancillas))) + s = iter(range(len(syn))) + + super().__init__() + + pauli = "Z" + for c in checks: + data_ids = c[:-1] + syn_id = next(s) + anc_id = next(a) + self.extend( + Comment(f"Check['{pauli}', {data_ids}] -> {syn}[{syn_id}]"), + Check( + d=poly2qubits(c, data), + paulis=pauli, + a=ancillas[anc_id], + out=syn[syn_id], + with_barriers=False, + ), + ) + + pauli = "X" + for c in checks: + data_ids = c[:-1] + syn_id = next(s) + anc_id = next(a) + self.extend( + Comment(f"Check['{pauli}', {data_ids}] -> {syn}[{syn_id}]"), + Check( + d=poly2qubits(c, data), + paulis=pauli, + a=ancillas[anc_id], + out=syn[syn_id], + with_barriers=False, + ), + ) diff --git a/python/quantum-pecos/src/pecos/qeclib/steane/syn_extract/flagged.py b/python/quantum-pecos/src/pecos/qeclib/steane/syn_extract/flagged.py new file mode 100644 index 000000000..305a46a72 --- /dev/null +++ b/python/quantum-pecos/src/pecos/qeclib/steane/syn_extract/flagged.py @@ -0,0 +1,104 @@ +"""Flagged syndrome extraction implementations for the Steane code. + +This module provides syndrome extraction with flag qubits for detecting +and diagnosing errors during the syndrome extraction process in the +Steane 7-qubit quantum error correction code. +""" + +from itertools import cycle +from typing import Any + +from pecos.qeclib.generic.check_1flag import Check1Flag +from pecos.slr import Block, Comment, CReg, QReg + + +def poly2qubits(poly: list[Any], data: QReg) -> list[Any]: + """Convert polygon node IDs to qubit references. + + Args: + poly: Polygon representation with node IDs and color. + data: Quantum register containing the data qubits. + + Returns: + List of qubit references corresponding to the polygon nodes. + """ + return [data[q] for q in poly] + + +class SynExtractFlagged(Block): + """Flagged syndrome extraction for Steane code with flag qubits for error detection.""" + + def __init__( + self, + data: QReg, + ancillas: QReg, + flag_qubits: QReg, + checks: list, + syn: CReg, + flag_bits: CReg, + ) -> None: + """Initialize flagged syndrome extraction. + + Args: + data: Data qubit register. + ancillas: Ancilla qubit register. + flag_qubits: Flag qubit register for hook error detection. + checks: List of check operators to apply. + syn: Classical register for syndrome storage. + flag_bits: Classical register for flag bit storage. + + Raises: + ValueError: If register lengths don't match expected sizes. + """ + if not (len(syn) == len(flag_bits) == 2 * len(checks) == 6): + msg = ( + f"Expected syndrome and flag registers of length 6 (2 * {len(checks)} checks), " + f"got syn={len(syn)}, flag_bits={len(flag_bits)}" + ) + raise ValueError(msg) + a = cycle(range(len(ancillas))) + f = cycle(range(len(flag_qubits))) + s = iter(range(len(syn))) + fb = iter(range(len(flag_bits))) + + super().__init__() + + pauli = "Z" + for c in checks: + data_ids = c[:-1] + syn_id = next(s) + anc_id = next(a) + flag_qubit_id = next(f) + flag_bit_id = next(fb) + self.extend( + Comment(f"Check['{pauli}', {data_ids}] -> {syn}[{syn_id}]"), + Check1Flag( + d=poly2qubits(c, data), + ops=pauli, + a=ancillas[anc_id], + flag=flag_qubits[flag_qubit_id], + out=syn[syn_id], + out_flag=flag_bits[flag_bit_id], + with_barriers=False, + ), + ) + + pauli = "X" + for c in checks: + data_ids = c[:-1] + syn_id = next(s) + anc_id = next(a) + flag_qubit_id = next(f) + flag_bit_id = next(fb) + self.extend( + Comment(f"Check['{pauli}', {data_ids}] -> {syn}[{syn_id}]"), + Check1Flag( + d=poly2qubits(c, data), + ops=pauli, + a=ancillas[anc_id], + flag=flag_qubits[flag_qubit_id], + out=syn[syn_id], + out_flag=flag_bits[flag_bit_id], + with_barriers=False, + ), + ) diff --git a/python/quantum-pecos/src/pecos/slr/gen_codes/gen_qasm.py b/python/quantum-pecos/src/pecos/slr/gen_codes/gen_qasm.py index 204a6ab77..61eb0dcef 100644 --- a/python/quantum-pecos/src/pecos/slr/gen_codes/gen_qasm.py +++ b/python/quantum-pecos/src/pecos/slr/gen_codes/gen_qasm.py @@ -53,17 +53,21 @@ def enter_block(self, block): self.write(f"// Generated using: PECOS version {__version__}") for var in block.vars: var_def = self.process_var_def(var) - self.write(var_def) + if var_def: + self.write(var_def) for op in block.ops: op_name = type(op).__name__ if op_name == "Vars": for var in op.vars: var_def = self.process_var_def(var) - self.write(var_def) + if var_def: + self.write(var_def) return previous_scope def process_var_def(self, var) -> str: + if var is None: + return "" var_type = type(var).__name__ return f"{var_type.lower()} {var.sym}[{var.size}];" diff --git a/uv.lock b/uv.lock index f9266783e..7d3648e69 100644 --- a/uv.lock +++ b/uv.lock @@ -920,15 +920,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, ] -[[package]] -name = "nanobind" -version = "2.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/7c/cc6e525b89cca06b9fab7ecb91a11c3fd8258b158897cc804679fcc7b203/nanobind-2.8.0.tar.gz", hash = "sha256:94e7bf6aa1d7dff9566eddc15252aba94fdadbf67a99a169bfab34b708427cd8", size = 979153, upload-time = "2025-07-16T05:52:17.547Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/3f/d81fa4c0d1450c6f58f5b5708082617949c12c5e98c1fae0d94a9e3a9b8f/nanobind-2.8.0-py3-none-any.whl", hash = "sha256:80fd403cfe4c8553b237ba5fbb62971921e2c5d1e6eb4a2fd457c67f987ab56f", size = 242647, upload-time = "2025-07-16T05:52:15.848Z" }, -] - [[package]] name = "networkx" version = "3.4.2" @@ -1117,12 +1108,12 @@ wheels = [ [[package]] name = "pecos-rslib" -version = "0.7.0.dev3" +version = "0.7.0.dev4" source = { editable = "python/pecos-rslib" } [[package]] name = "pecos-workspace" -version = "0.7.0.dev3" +version = "0.7.0.dev4" source = { virtual = "." } dependencies = [ { name = "wasmer" }, @@ -1138,7 +1129,6 @@ dev = [ { name = "mkdocs" }, { name = "mkdocs-material" }, { name = "mkdocstrings", extra = ["python"] }, - { name = "nanobind" }, { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "networkx", version = "3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, @@ -1172,7 +1162,6 @@ dev = [ { name = "mkdocs" }, { name = "mkdocs-material" }, { name = "mkdocstrings", extras = ["python"] }, - { name = "nanobind" }, { name = "networkx", specifier = ">=2.1.0" }, { name = "numpy", specifier = ">=1.15.0" }, { name = "phir", specifier = ">=0.3.3" }, @@ -1619,7 +1608,7 @@ wheels = [ [[package]] name = "quantum-pecos" -version = "0.7.0.dev3" +version = "0.7.0.dev4" source = { editable = "python/quantum-pecos" } dependencies = [ { name = "matplotlib" },