ffsim 0.0.73__tar.gz → 0.0.74__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ffsim-0.0.73 → ffsim-0.0.74}/PKG-INFO +1 -1
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/conf.py +1 -1
- {ffsim-0.0.73 → ffsim-0.0.74}/pyproject.toml +1 -1
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/_lib.pyi +3 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/gates/orbital_rotation.py +3 -3
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/linalg/double_factorized_decomposition.py +48 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/linalg/givens.py +4 -75
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/operators/fermion_action.py +7 -1
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/variational/ucj_spin_balanced.py +126 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/src/gates/orbital_rotation.rs +9 -25
- {ffsim-0.0.73 → ffsim-0.0.74}/src/lib.rs +2 -0
- ffsim-0.0.74/src/linalg/givens.rs +148 -0
- ffsim-0.0.74/src/linalg/mod.rs +11 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/linalg/double_factorized_decomposition_test.py +5 -48
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/variational/ucj_spin_balanced_test.py +32 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/uv.lock +1 -1
- {ffsim-0.0.73 → ffsim-0.0.74}/.dockerignore +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/.github/workflows/build-and-release.yml +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/.github/workflows/check.yml +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/.github/workflows/docker.yml +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/.github/workflows/docs-dev.yml +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/.github/workflows/docs-release.yml +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/.github/workflows/test-latest-versions.yml +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/.github/workflows/test-minimum-versions.yml +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/.gitignore +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/.pre-commit-config.yaml +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/CONTRIBUTING.md +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/Cargo.lock +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/Cargo.toml +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/Dockerfile +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/LICENSE +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/README.md +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/compose.yaml +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/_templates/autosummary/class.rst +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/explanations/diag-coulomb-hamiltonian.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/explanations/double-factorized.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/explanations/fermion-operator.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/explanations/hamiltonians.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/explanations/index.md +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/explanations/lucj.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/explanations/orbital-rotation.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/explanations/protocols.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/explanations/qubit-gate-decompositions.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/explanations/state-vectors-and-gates.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/explanations/variational-ansatzes.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/generate_api_docs.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/how-to-guides/compute-expectation-values.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/how-to-guides/entanglement-forging.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/how-to-guides/index.md +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/how-to-guides/qiskit-circuits-sim.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/how-to-guides/qiskit-lucj.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/how-to-guides/qiskit-merge-orbital-rotations.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/how-to-guides/qiskit-trotter.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/how-to-guides/sample-from-state-vectors.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/how-to-guides/sample-slater.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/how-to-guides/simulate-trotter-hubbard.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/how-to-guides/simulate-trotter-mol-ham.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/how-to-guides/simulate-vqe.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/index.md +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/install.md +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/tutorials/double-factorized-trotter.ipynb +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/docs/tutorials/index.md +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/_cistring.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/_slow/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/_slow/contract/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/_slow/contract/diag_coulomb.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/_slow/contract/num_op_sum.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/_slow/fermion_operator.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/_slow/gates/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/_slow/gates/diag_coulomb.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/_slow/gates/num_op_sum.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/_slow/gates/orbital_rotation.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/contract/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/contract/diag_coulomb.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/contract/num_op_sum.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/contract/one_body.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/contract/two_body.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/gates/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/gates/basic_gates.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/gates/diag_coulomb.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/gates/num_op_sum.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/gates/quad_ham.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/hamiltonians/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/hamiltonians/diagonal_coulomb_hamiltonian.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/hamiltonians/double_factorized_hamiltonian.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/hamiltonians/molecular_hamiltonian.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/hamiltonians/single_factorized_hamiltonian.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/init_cache.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/linalg/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/linalg/linalg.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/linalg/predicates.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/linalg/util.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/molecular_data.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/operators/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/operators/common_operators.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/operators/coupled_cluster.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/operators/fermi_hubbard.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/operators/fermion_operator.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/optimize/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/optimize/_util.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/optimize/linear_method.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/protocols/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/protocols/apply_unitary_protocol.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/protocols/approximate_equality_protocol.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/protocols/diagonal_protocol.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/protocols/fermion_operator_protocol.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/protocols/linear_operator_protocol.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/protocols/trace_protocol.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/py.typed +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/gates/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/gates/diag_coulomb.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/gates/diag_coulomb_trotter_split_op.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/gates/double_factorized_trotter.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/gates/givens_ansatz.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/gates/num_num_ansatz.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/gates/num_op_sum.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/gates/orbital_rotation.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/gates/slater_determinant.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/gates/ucj.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/jordan_wigner.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/sampler.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/sim.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/transpiler_passes/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/transpiler_passes/drop_negligible.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/transpiler_passes/merge_orbital_rotations.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/transpiler_stages.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/qiskit/util.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/random/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/random/random.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/states/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/states/bitstring.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/states/dimensions.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/states/product_state_sum.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/states/rdm.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/states/sample_slater.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/states/slater.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/states/spin.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/states/states.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/states/wick.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/testing/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/testing/testing.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/trotter/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/trotter/_util.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/trotter/diagonal_coulomb_split_op.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/trotter/double_factorized.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/trotter/qdrift.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/variational/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/variational/givens.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/variational/hopgate.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/variational/multireference.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/variational/num_num.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/variational/orbital_optimization.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/variational/uccsd.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/variational/ucj_angles_spin_balanced.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/variational/ucj_spin_unbalanced.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/variational/ucj_spinless.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/python/ffsim/variational/util.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/src/contract/diag_coulomb.rs +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/src/contract/mod.rs +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/src/contract/num_op_sum.rs +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/src/fermion_operator.rs +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/src/gates/diag_coulomb.rs +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/src/gates/mod.rs +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/src/gates/num_op_sum.rs +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/src/gates/phase_shift.rs +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/src/jordan_wigner.rs +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/_slow/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/_slow/contract/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/_slow/contract/diag_coulomb_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/_slow/contract/num_op_sum_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/_slow/gates/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/_slow/gates/diag_coulomb_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/_slow/gates/num_op_sum_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/_slow/gates/orbital_rotation_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/contract/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/contract/diag_coulomb_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/contract/num_op_sum_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/contract/two_body_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/gates/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/gates/basic_gates_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/gates/diag_coulomb_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/gates/num_op_sum_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/gates/orbital_rotation_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/gates/quad_ham_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/hamiltonians/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/hamiltonians/diagonal_coulomb_hamiltonian_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/hamiltonians/double_factorized_hamiltonian_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/hamiltonians/molecular_hamiltonian_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/hamiltonians/single_factorized_hamiltonian_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/linalg/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/linalg/givens_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/linalg/linalg_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/linalg/util_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/molecular_data_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/operators/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/operators/common_operators_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/operators/coupled_cluster_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/operators/fermi_hubbard_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/operators/fermion_action_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/operators/fermion_operator_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/optimize/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/optimize/linear_method_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/protocols/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/protocols/trace_protocol_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/gates/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/gates/diag_coulomb_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/gates/diag_coulomb_trotter_split_op_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/gates/double_factorized_trotter_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/gates/givens_ansatz_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/gates/num_num_ansatz_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/gates/num_op_sum_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/gates/orbital_rotation_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/gates/slater_determinant_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/gates/ucj_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/jordan_wigner_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/sampler_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/sim_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/transpiler_passes/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/transpiler_passes/drop_negligible_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/transpiler_passes/merge_orbital_rotations_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/qiskit/util_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/random_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/states/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/states/bitstring_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/states/rdm_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/states/sample_slater_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/states/slater_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/states/states_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/states/wick_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/test_data/orbital_rotation-0.npy +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/test_no_warnings.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/testing_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/trotter/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/trotter/diag_coulomb_split_op_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/trotter/double_factorized_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/trotter/qdrift_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/variational/__init__.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/variational/givens_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/variational/hopgate_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/variational/multireference_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/variational/num_num_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/variational/orbital_optimization_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/variational/uccsd_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/variational/ucj_angles_spin_balanced_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/variational/ucj_spin_unbalanced_test.py +0 -0
- {ffsim-0.0.73 → ffsim-0.0.74}/tests/python/variational/ucj_spinless_test.py +0 -0
|
@@ -52,7 +52,7 @@ intersphinx_mapping = {
|
|
|
52
52
|
"python": ("https://docs.python.org/3", None),
|
|
53
53
|
"numpy": ("https://numpy.org/doc/stable", None),
|
|
54
54
|
"scipy": ("https://docs.scipy.org/doc/scipy", None),
|
|
55
|
-
"qiskit": ("https://
|
|
55
|
+
"qiskit": ("https://quantum.cloud.ibm.com/docs/api/qiskit", None),
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
# nbsphinx options (for tutorials)
|
|
@@ -39,6 +39,9 @@ def apply_phase_shift_in_place(
|
|
|
39
39
|
def apply_givens_rotation_in_place(
|
|
40
40
|
vec: np.ndarray, c: float, s: complex, slice1: np.ndarray, slice2: np.ndarray
|
|
41
41
|
) -> None: ...
|
|
42
|
+
def givens_decomposition(
|
|
43
|
+
mat: np.ndarray,
|
|
44
|
+
) -> tuple[list[tuple[float, complex, int, int]], np.ndarray]: ...
|
|
42
45
|
def apply_num_op_sum_evolution_in_place(
|
|
43
46
|
vec: np.ndarray,
|
|
44
47
|
phases: np.ndarray,
|
|
@@ -20,7 +20,7 @@ import numpy as np
|
|
|
20
20
|
from pyscf.fci import cistring
|
|
21
21
|
|
|
22
22
|
from ffsim._lib import apply_givens_rotation_in_place, apply_phase_shift_in_place
|
|
23
|
-
from ffsim.linalg import
|
|
23
|
+
from ffsim.linalg import givens_decomposition
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
@overload
|
|
@@ -157,8 +157,8 @@ def _apply_orbital_rotation_spinful(
|
|
|
157
157
|
def _get_givens_decomposition(
|
|
158
158
|
mat: np.ndarray | tuple[np.ndarray | None, np.ndarray | None],
|
|
159
159
|
) -> tuple[
|
|
160
|
-
tuple[list[
|
|
161
|
-
tuple[list[
|
|
160
|
+
tuple[list[tuple[float, complex, int, int]], np.ndarray] | None,
|
|
161
|
+
tuple[list[tuple[float, complex, int, int]], np.ndarray] | None,
|
|
162
162
|
]:
|
|
163
163
|
if isinstance(mat, np.ndarray) and mat.ndim == 2:
|
|
164
164
|
decomp = givens_decomposition(mat)
|
|
@@ -1131,3 +1131,51 @@ def _double_factorized_t2_alpha_beta_explicit(
|
|
|
1131
1131
|
|
|
1132
1132
|
def _quadrature(mat: np.ndarray, sign: int):
|
|
1133
1133
|
return 0.5 * (1 - sign * 1j) * (mat + sign * 1j * mat.T.conj())
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
def reconstruct_t2(
|
|
1137
|
+
diag_coulomb_mats: np.ndarray, orbital_rotations: np.ndarray, nocc: int
|
|
1138
|
+
) -> np.ndarray:
|
|
1139
|
+
"""Reconstruct t2 amplitudes from double factorization tensors."""
|
|
1140
|
+
return (
|
|
1141
|
+
1j
|
|
1142
|
+
* contract(
|
|
1143
|
+
"kpq,kap,kip,kbq,kjq->ijab",
|
|
1144
|
+
diag_coulomb_mats,
|
|
1145
|
+
orbital_rotations,
|
|
1146
|
+
orbital_rotations.conj(),
|
|
1147
|
+
orbital_rotations,
|
|
1148
|
+
orbital_rotations.conj(),
|
|
1149
|
+
)[:nocc, :nocc, nocc:, nocc:]
|
|
1150
|
+
)
|
|
1151
|
+
|
|
1152
|
+
|
|
1153
|
+
def reconstruct_t2_alpha_beta(
|
|
1154
|
+
diag_coulomb_mats: np.ndarray,
|
|
1155
|
+
orbital_rotations: np.ndarray,
|
|
1156
|
+
norb: int,
|
|
1157
|
+
nocc_a: int,
|
|
1158
|
+
nocc_b: int,
|
|
1159
|
+
) -> np.ndarray:
|
|
1160
|
+
"""Reconstruct alpha-beta t2 amplitudes from double factorization tensors."""
|
|
1161
|
+
n_terms = diag_coulomb_mats.shape[0]
|
|
1162
|
+
expanded_diag_coulomb_mats = np.zeros((n_terms, 2 * norb, 2 * norb))
|
|
1163
|
+
expanded_orbital_rotations = np.zeros((n_terms, 2 * norb, 2 * norb), dtype=complex)
|
|
1164
|
+
for k in range(n_terms):
|
|
1165
|
+
(mat_aa, mat_ab, mat_bb) = diag_coulomb_mats[k]
|
|
1166
|
+
expanded_diag_coulomb_mats[k] = np.block([[mat_aa, mat_ab], [mat_ab.T, mat_bb]])
|
|
1167
|
+
orbital_rotation_a, orbital_rotation_b = orbital_rotations[k]
|
|
1168
|
+
expanded_orbital_rotations[k] = scipy.linalg.block_diag(
|
|
1169
|
+
orbital_rotation_a, orbital_rotation_b
|
|
1170
|
+
)
|
|
1171
|
+
return (
|
|
1172
|
+
1j
|
|
1173
|
+
* contract(
|
|
1174
|
+
"kpq,kap,kip,kbq,kjq->ijab",
|
|
1175
|
+
expanded_diag_coulomb_mats,
|
|
1176
|
+
expanded_orbital_rotations,
|
|
1177
|
+
expanded_orbital_rotations.conj(),
|
|
1178
|
+
expanded_orbital_rotations,
|
|
1179
|
+
expanded_orbital_rotations.conj(),
|
|
1180
|
+
)[:nocc_a, norb : norb + nocc_b, nocc_a:norb, norb + nocc_b :]
|
|
1181
|
+
)
|
|
@@ -17,7 +17,8 @@ from typing import NamedTuple
|
|
|
17
17
|
|
|
18
18
|
import numpy as np
|
|
19
19
|
from scipy.linalg.blas import zrotg as zrotg_
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
from ffsim import _lib
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
class GivensRotation(NamedTuple):
|
|
@@ -92,7 +93,7 @@ def zrotg(a: complex, b: complex, tol=1e-12) -> tuple[float, complex]:
|
|
|
92
93
|
|
|
93
94
|
def givens_decomposition(
|
|
94
95
|
mat: np.ndarray,
|
|
95
|
-
) -> tuple[list[
|
|
96
|
+
) -> tuple[list[tuple[float, complex, int, int]], np.ndarray]:
|
|
96
97
|
r"""Givens rotation decomposition of a unitary matrix.
|
|
97
98
|
|
|
98
99
|
The Givens rotation decomposition of an :math:`n \times n` unitary matrix :math:`U`
|
|
@@ -145,76 +146,4 @@ def givens_decomposition(
|
|
|
145
146
|
|
|
146
147
|
.. _Clements et al., "Optimal design for universal multiport interferometers" (2016): https://doi.org/10.1364/OPTICA.3.001460
|
|
147
148
|
""" # noqa: E501
|
|
148
|
-
|
|
149
|
-
current_matrix = mat.astype(complex, copy=True)
|
|
150
|
-
left_rotations = []
|
|
151
|
-
right_rotations = []
|
|
152
|
-
|
|
153
|
-
# compute left and right Givens rotations
|
|
154
|
-
for i in range(n - 1):
|
|
155
|
-
if i % 2 == 0:
|
|
156
|
-
# rotate columns by right multiplication
|
|
157
|
-
for j in range(i + 1):
|
|
158
|
-
target_index = i - j
|
|
159
|
-
row = n - j - 1
|
|
160
|
-
if not cmath.isclose(current_matrix[row, target_index], 0.0):
|
|
161
|
-
# zero out element at target index in given row
|
|
162
|
-
c, s = zrotg(
|
|
163
|
-
current_matrix[row, target_index + 1],
|
|
164
|
-
current_matrix[row, target_index],
|
|
165
|
-
)
|
|
166
|
-
right_rotations.append(
|
|
167
|
-
GivensRotation(c, s, target_index + 1, target_index)
|
|
168
|
-
)
|
|
169
|
-
(
|
|
170
|
-
current_matrix[:, target_index + 1],
|
|
171
|
-
current_matrix[:, target_index],
|
|
172
|
-
) = zrot(
|
|
173
|
-
current_matrix[:, target_index + 1],
|
|
174
|
-
current_matrix[:, target_index],
|
|
175
|
-
c,
|
|
176
|
-
s,
|
|
177
|
-
)
|
|
178
|
-
else:
|
|
179
|
-
# rotate rows by left multiplication
|
|
180
|
-
for j in range(i + 1):
|
|
181
|
-
target_index = n - i + j - 1
|
|
182
|
-
col = j
|
|
183
|
-
if not cmath.isclose(current_matrix[target_index, col], 0.0):
|
|
184
|
-
# zero out element at target index in given column
|
|
185
|
-
c, s = zrotg(
|
|
186
|
-
current_matrix[target_index - 1, col],
|
|
187
|
-
current_matrix[target_index, col],
|
|
188
|
-
)
|
|
189
|
-
left_rotations.append(
|
|
190
|
-
GivensRotation(c, s, target_index - 1, target_index)
|
|
191
|
-
)
|
|
192
|
-
(
|
|
193
|
-
current_matrix[target_index - 1],
|
|
194
|
-
current_matrix[target_index],
|
|
195
|
-
) = zrot(
|
|
196
|
-
current_matrix[target_index - 1],
|
|
197
|
-
current_matrix[target_index],
|
|
198
|
-
c,
|
|
199
|
-
s,
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
# convert left rotations to right rotations
|
|
203
|
-
for c, s, i, j in reversed(left_rotations):
|
|
204
|
-
c, s = zrotg(c * current_matrix[j, j], s.conjugate() * current_matrix[i, i])
|
|
205
|
-
right_rotations.append(
|
|
206
|
-
# clamp c between -1 and 1 to account for floating point error
|
|
207
|
-
GivensRotation(min(1.0, max(-1.0, c)), -s.conjugate(), i, j)
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
givens_mat = np.array([[c, -s], [s.conjugate(), c]])
|
|
211
|
-
givens_mat[:, 0] *= current_matrix[i, i]
|
|
212
|
-
givens_mat[:, 1] *= current_matrix[j, j]
|
|
213
|
-
c, s = zrotg(givens_mat[1, 1], givens_mat[1, 0])
|
|
214
|
-
new_givens_mat = np.array([[c, s], [-s.conjugate(), c]])
|
|
215
|
-
phase_matrix = givens_mat @ new_givens_mat
|
|
216
|
-
current_matrix[i, i] = phase_matrix[0, 0]
|
|
217
|
-
current_matrix[j, j] = phase_matrix[1, 1]
|
|
218
|
-
|
|
219
|
-
# return decomposition
|
|
220
|
-
return right_rotations, np.diagonal(current_matrix)
|
|
149
|
+
return _lib.givens_decomposition(np.asarray(mat, dtype=complex))
|
|
@@ -14,7 +14,13 @@ from typing import NamedTuple
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class FermionAction(NamedTuple):
|
|
17
|
-
"""A fermionic action.
|
|
17
|
+
"""A fermionic action.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
action: ``False`` = destroy (annihilate), ``True`` = create
|
|
21
|
+
spin: ``False`` = alpha (spin up), ``True`` = beta (spin down)
|
|
22
|
+
orb: Index of the orbital to act on
|
|
23
|
+
"""
|
|
18
24
|
|
|
19
25
|
action: bool # False = destroy (annihilate), True = create
|
|
20
26
|
spin: bool # False = alpha, True = beta
|
|
@@ -13,10 +13,12 @@
|
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
|
|
15
15
|
import itertools
|
|
16
|
+
import math
|
|
16
17
|
from dataclasses import InitVar, dataclass
|
|
17
18
|
from typing import cast
|
|
18
19
|
|
|
19
20
|
import numpy as np
|
|
21
|
+
import pyscf.ci
|
|
20
22
|
|
|
21
23
|
from ffsim import gates, linalg, protocols
|
|
22
24
|
from ffsim.linalg.util import unitary_from_parameters, unitary_to_parameters
|
|
@@ -532,6 +534,130 @@ class UCJOpSpinBalanced(
|
|
|
532
534
|
final_orbital_rotation=final_orbital_rotation,
|
|
533
535
|
)
|
|
534
536
|
|
|
537
|
+
@staticmethod
|
|
538
|
+
def from_cisd_vec(
|
|
539
|
+
cisd_vec: np.ndarray,
|
|
540
|
+
*,
|
|
541
|
+
norb: int,
|
|
542
|
+
nocc: int,
|
|
543
|
+
c0_threshold: float = 1e-12,
|
|
544
|
+
n_reps: int | None = None,
|
|
545
|
+
interaction_pairs: tuple[
|
|
546
|
+
list[tuple[int, int]] | None, list[tuple[int, int]] | None
|
|
547
|
+
]
|
|
548
|
+
| None = None,
|
|
549
|
+
tol: float = 1e-8,
|
|
550
|
+
optimize: bool = False,
|
|
551
|
+
method: str = "L-BFGS-B",
|
|
552
|
+
callback=None,
|
|
553
|
+
options: dict | None = None,
|
|
554
|
+
regularization: float = 0,
|
|
555
|
+
multi_stage_start: int | None = None,
|
|
556
|
+
multi_stage_step: int | None = None,
|
|
557
|
+
) -> UCJOpSpinBalanced:
|
|
558
|
+
r"""Initialize the UCJ operator from a CISD vector.
|
|
559
|
+
|
|
560
|
+
The CISD amplitudes are converted to CC-style amplitudes using
|
|
561
|
+
|
|
562
|
+
.. math::
|
|
563
|
+
|
|
564
|
+
t_{1,ia} = \frac{c^{(1)}_{ia}}{c_0},
|
|
565
|
+
\qquad
|
|
566
|
+
t_{2,ijab} = \frac{c^{(2)}_{ijab}}{c_0} - \frac{t_{1,ia} t_{1,jb}}{2},
|
|
567
|
+
|
|
568
|
+
and the resulting amplitudes are then passed to
|
|
569
|
+
:meth:`from_t_amplitudes`.
|
|
570
|
+
|
|
571
|
+
Args:
|
|
572
|
+
cisd_vec: The CISD vector. This is a one-dimensional array containing the
|
|
573
|
+
reference coefficient :math:`c_0` in the first entry, followed by the
|
|
574
|
+
singles and then doubles coefficients.
|
|
575
|
+
norb: The number of spatial orbitals.
|
|
576
|
+
nocc: The number of occupied orbitals.
|
|
577
|
+
c0_threshold: Absolute value threshold for the reference coefficient. An
|
|
578
|
+
error is raised if the absolute value of :math:`c_0` is smaller than
|
|
579
|
+
this threshold.
|
|
580
|
+
n_reps: The number of ansatz repetitions. If not specified, then it is set
|
|
581
|
+
to the number of terms resulting from the double factorization of the
|
|
582
|
+
t2 amplitudes. If the specified number of repetitions is larger than the
|
|
583
|
+
number of terms resulting from the double factorization, then the ansatz
|
|
584
|
+
is padded with additional identity operators up to the specified number
|
|
585
|
+
of repetitions.
|
|
586
|
+
interaction_pairs: Optional restrictions on allowed orbital interactions
|
|
587
|
+
for the diagonal Coulomb operators.
|
|
588
|
+
If specified, `interaction_pairs` should be a pair of lists,
|
|
589
|
+
for alpha-alpha and alpha-beta interactions, in that order.
|
|
590
|
+
Either list can be substituted with ``None`` to indicate no restrictions
|
|
591
|
+
on interactions.
|
|
592
|
+
Each list should contain pairs of integers representing the orbitals
|
|
593
|
+
that are allowed to interact. These pairs can also be interpreted as
|
|
594
|
+
indices of diagonal Coulomb matrix entries that are allowed to be
|
|
595
|
+
nonzero.
|
|
596
|
+
Each integer pair must be upper triangular, that is, of the form
|
|
597
|
+
:math:`(i, j)` where :math:`i \leq j`.
|
|
598
|
+
tol: Tolerance for error in the double-factorized decomposition of the
|
|
599
|
+
converted t2 amplitudes.
|
|
600
|
+
The error is defined as the maximum absolute difference between
|
|
601
|
+
an element of the original tensor and the corresponding element of
|
|
602
|
+
the reconstructed tensor.
|
|
603
|
+
optimize: Whether to optimize the tensors returned by the decomposition to
|
|
604
|
+
to minimize the error in the factorization.
|
|
605
|
+
method: The optimization method. See the documentation of
|
|
606
|
+
`scipy.optimize.minimize`_ for possible values.
|
|
607
|
+
This argument is ignored if `optimize` is set to ``False``.
|
|
608
|
+
callback: Callback function for the optimization. See the documentation of
|
|
609
|
+
`scipy.optimize.minimize`_ for usage.
|
|
610
|
+
This argument is ignored if `optimize` is set to ``False``.
|
|
611
|
+
options: Options for the optimization. See the documentation of
|
|
612
|
+
`scipy.optimize.minimize`_ for usage.
|
|
613
|
+
This argument is ignored if `optimize` is set to ``False``.
|
|
614
|
+
regularization: See :func:`ffsim.linalg.double_factorized_t2` for a
|
|
615
|
+
description of this argument.
|
|
616
|
+
This argument is ignored if `optimize` is set to ``False``.
|
|
617
|
+
multi_stage_start: See :func:`ffsim.linalg.double_factorized_t2` for a
|
|
618
|
+
description of this argument.
|
|
619
|
+
This argument is ignored if `optimize` is set to ``False``.
|
|
620
|
+
multi_stage_step: See :func:`ffsim.linalg.double_factorized_t2` for a
|
|
621
|
+
description of this argument.
|
|
622
|
+
This argument is ignored if `optimize` is set to ``False``.
|
|
623
|
+
|
|
624
|
+
Returns:
|
|
625
|
+
The UCJ operator with parameters initialized from the CISD amplitudes.
|
|
626
|
+
|
|
627
|
+
Raises:
|
|
628
|
+
ValueError: The CISD reference coefficient is smaller than the
|
|
629
|
+
specified threshold c0_tol.
|
|
630
|
+
|
|
631
|
+
.. _scipy.optimize.minimize: https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html
|
|
632
|
+
"""
|
|
633
|
+
c0, c1, c2 = pyscf.ci.cisd.cisdvec_to_amplitudes(
|
|
634
|
+
cisd_vec, norb, nocc, copy=False
|
|
635
|
+
)
|
|
636
|
+
|
|
637
|
+
if math.isclose(c0, 0.0, abs_tol=c0_threshold):
|
|
638
|
+
raise ValueError(
|
|
639
|
+
f"CISD reference coefficient c0={c0} is smaller than the"
|
|
640
|
+
f"specified threshold, c0_tol={c0_threshold}."
|
|
641
|
+
)
|
|
642
|
+
|
|
643
|
+
t1 = c1 / c0
|
|
644
|
+
t2 = c2 / c0 - 0.5 * np.einsum("ia,jb->ijab", t1, t1)
|
|
645
|
+
|
|
646
|
+
return UCJOpSpinBalanced.from_t_amplitudes(
|
|
647
|
+
t2,
|
|
648
|
+
t1=t1,
|
|
649
|
+
n_reps=n_reps,
|
|
650
|
+
interaction_pairs=interaction_pairs,
|
|
651
|
+
tol=tol,
|
|
652
|
+
optimize=optimize,
|
|
653
|
+
method=method,
|
|
654
|
+
callback=callback,
|
|
655
|
+
options=options,
|
|
656
|
+
regularization=regularization,
|
|
657
|
+
multi_stage_start=multi_stage_start,
|
|
658
|
+
multi_stage_step=multi_stage_step,
|
|
659
|
+
)
|
|
660
|
+
|
|
535
661
|
def _apply_unitary_(
|
|
536
662
|
self, vec: np.ndarray, norb: int, nelec: int | tuple[int, int], copy: bool
|
|
537
663
|
) -> np.ndarray:
|
|
@@ -8,10 +8,6 @@
|
|
|
8
8
|
// copyright notice, and modified files need to carry a notice indicating
|
|
9
9
|
// that they have been altered from the originals.
|
|
10
10
|
|
|
11
|
-
extern crate blas_src;
|
|
12
|
-
|
|
13
|
-
use blas::zdrot;
|
|
14
|
-
use blas::zscal;
|
|
15
11
|
use numpy::Complex64;
|
|
16
12
|
use numpy::PyReadonlyArray1;
|
|
17
13
|
|
|
@@ -36,11 +32,6 @@ pub fn apply_givens_rotation_in_place(
|
|
|
36
32
|
let slice1 = slice1.as_array();
|
|
37
33
|
let slice2 = slice2.as_array();
|
|
38
34
|
let dim_b = vec.shape()[1];
|
|
39
|
-
let dim_b_i32 = dim_b as i32;
|
|
40
|
-
let s_abs = s.norm();
|
|
41
|
-
let angle = s.arg();
|
|
42
|
-
let phase = Complex64::new(angle.cos(), angle.sin());
|
|
43
|
-
let phase_conj = phase.conj();
|
|
44
35
|
|
|
45
36
|
let n_pairs = slice1.len();
|
|
46
37
|
let n_threads = std::env::var("RAYON_NUM_THREADS")
|
|
@@ -61,9 +52,7 @@ pub fn apply_givens_rotation_in_place(
|
|
|
61
52
|
let vec_ptr = vec.as_mut_ptr();
|
|
62
53
|
for (&i, &j) in slice1_slice.iter().zip(slice2_slice) {
|
|
63
54
|
unsafe {
|
|
64
|
-
_apply_givens_rotation_to_pair(
|
|
65
|
-
vec_ptr, i, j, dim_b, dim_b_i32, c, s_abs, phase, phase_conj,
|
|
66
|
-
);
|
|
55
|
+
_apply_givens_rotation_to_pair(vec_ptr, i, j, dim_b, c, s);
|
|
67
56
|
}
|
|
68
57
|
}
|
|
69
58
|
return;
|
|
@@ -85,9 +74,7 @@ pub fn apply_givens_rotation_in_place(
|
|
|
85
74
|
let vec_ptr = vec_ptr as *mut Complex64;
|
|
86
75
|
for (&i, &j) in slice1_chunk.iter().zip(slice2_chunk) {
|
|
87
76
|
unsafe {
|
|
88
|
-
_apply_givens_rotation_to_pair(
|
|
89
|
-
vec_ptr, i, j, dim_b, dim_b_i32, c, s_abs, phase, phase_conj,
|
|
90
|
-
);
|
|
77
|
+
_apply_givens_rotation_to_pair(vec_ptr, i, j, dim_b, c, s);
|
|
91
78
|
}
|
|
92
79
|
}
|
|
93
80
|
});
|
|
@@ -96,23 +83,20 @@ pub fn apply_givens_rotation_in_place(
|
|
|
96
83
|
}
|
|
97
84
|
|
|
98
85
|
/// Apply Givens rotation to a pair of rows
|
|
99
|
-
#[allow(clippy::too_many_arguments)]
|
|
100
86
|
unsafe fn _apply_givens_rotation_to_pair(
|
|
101
87
|
vec_ptr: *mut Complex64,
|
|
102
88
|
i: usize,
|
|
103
89
|
j: usize,
|
|
104
90
|
dim_b: usize,
|
|
105
|
-
dim_b_i32: i32,
|
|
106
91
|
c: f64,
|
|
107
|
-
|
|
108
|
-
phase: Complex64,
|
|
109
|
-
phase_conj: Complex64,
|
|
92
|
+
s: Complex64,
|
|
110
93
|
) {
|
|
111
94
|
let row_i = std::slice::from_raw_parts_mut(vec_ptr.add(i * dim_b), dim_b);
|
|
112
95
|
let row_j = std::slice::from_raw_parts_mut(vec_ptr.add(j * dim_b), dim_b);
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
96
|
+
for k in 0..dim_b {
|
|
97
|
+
let i_old = row_i[k];
|
|
98
|
+
let j_old = row_j[k];
|
|
99
|
+
row_i[k] = c * i_old + s * j_old;
|
|
100
|
+
row_j[k] = c * j_old - s.conj() * i_old;
|
|
101
|
+
}
|
|
118
102
|
}
|
|
@@ -14,6 +14,7 @@ mod contract;
|
|
|
14
14
|
mod fermion_operator;
|
|
15
15
|
mod gates;
|
|
16
16
|
mod jordan_wigner;
|
|
17
|
+
mod linalg;
|
|
17
18
|
|
|
18
19
|
/// Python module exposing Rust extensions.
|
|
19
20
|
#[pymodule]
|
|
@@ -38,6 +39,7 @@ fn _lib(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
|
38
39
|
gates::diag_coulomb::apply_diag_coulomb_evolution_in_place_z_rep,
|
|
39
40
|
m
|
|
40
41
|
)?)?;
|
|
42
|
+
m.add_function(wrap_pyfunction!(linalg::givens::givens_decomposition, m)?)?;
|
|
41
43
|
m.add_function(wrap_pyfunction!(
|
|
42
44
|
contract::diag_coulomb::contract_diag_coulomb_into_buffer_num_rep,
|
|
43
45
|
m
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// (C) Copyright IBM 2026
|
|
2
|
+
//
|
|
3
|
+
// This code is licensed under the Apache License, Version 2.0. You may
|
|
4
|
+
// obtain a copy of this license in the LICENSE.txt file in the root directory
|
|
5
|
+
// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
//
|
|
7
|
+
// Any modifications or derivative works of this code must retain this
|
|
8
|
+
// copyright notice, and modified files need to carry a notice indicating
|
|
9
|
+
// that they have been altered from the originals.
|
|
10
|
+
|
|
11
|
+
use blas::zrotg as zrotg_blas;
|
|
12
|
+
use ndarray::Array2;
|
|
13
|
+
use numpy::{Complex64, IntoPyArray, PyArray1, PyReadonlyArray2};
|
|
14
|
+
use pyo3::exceptions::PyValueError;
|
|
15
|
+
use pyo3::prelude::*;
|
|
16
|
+
|
|
17
|
+
type GivensRotationTuple = (f64, Complex64, usize, usize);
|
|
18
|
+
type GivensDecompositionResult = (Vec<GivensRotationTuple>, Py<PyArray1<Complex64>>);
|
|
19
|
+
|
|
20
|
+
fn zrotg_safe(a: Complex64, b: Complex64, tol: f64) -> (f64, Complex64) {
|
|
21
|
+
if a.norm() <= tol {
|
|
22
|
+
return (0.0, Complex64::new(1.0, 0.0));
|
|
23
|
+
}
|
|
24
|
+
if b.norm() <= tol {
|
|
25
|
+
return (1.0, Complex64::new(0.0, 0.0));
|
|
26
|
+
}
|
|
27
|
+
let mut a_mut = a;
|
|
28
|
+
let mut c = 0.0;
|
|
29
|
+
let mut s = Complex64::new(0.0, 0.0);
|
|
30
|
+
unsafe {
|
|
31
|
+
zrotg_blas(&mut a_mut, b, &mut c, &mut s);
|
|
32
|
+
}
|
|
33
|
+
(c, s)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
fn rotate_columns_in_place(
|
|
37
|
+
mat: &mut Array2<Complex64>,
|
|
38
|
+
col_x: usize,
|
|
39
|
+
col_y: usize,
|
|
40
|
+
c: f64,
|
|
41
|
+
s: Complex64,
|
|
42
|
+
) {
|
|
43
|
+
let n_rows = mat.nrows();
|
|
44
|
+
for row in 0..n_rows {
|
|
45
|
+
let x_old = mat[[row, col_x]];
|
|
46
|
+
let y_old = mat[[row, col_y]];
|
|
47
|
+
mat[[row, col_x]] = c * x_old + s * y_old;
|
|
48
|
+
mat[[row, col_y]] = c * y_old - s.conj() * x_old;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fn rotate_rows_in_place(
|
|
53
|
+
mat: &mut Array2<Complex64>,
|
|
54
|
+
row_x: usize,
|
|
55
|
+
row_y: usize,
|
|
56
|
+
c: f64,
|
|
57
|
+
s: Complex64,
|
|
58
|
+
) {
|
|
59
|
+
let n_cols = mat.ncols();
|
|
60
|
+
for col in 0..n_cols {
|
|
61
|
+
let x_old = mat[[row_x, col]];
|
|
62
|
+
let y_old = mat[[row_y, col]];
|
|
63
|
+
mat[[row_x, col]] = c * x_old + s * y_old;
|
|
64
|
+
mat[[row_y, col]] = c * y_old - s.conj() * x_old;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/// Givens rotation decomposition of a unitary matrix.
|
|
69
|
+
#[pyfunction]
|
|
70
|
+
pub fn givens_decomposition(
|
|
71
|
+
py: Python<'_>,
|
|
72
|
+
mat: PyReadonlyArray2<Complex64>,
|
|
73
|
+
) -> PyResult<GivensDecompositionResult> {
|
|
74
|
+
let mat_view = mat.as_array();
|
|
75
|
+
let shape = mat_view.shape();
|
|
76
|
+
if shape[0] != shape[1] {
|
|
77
|
+
return Err(PyValueError::new_err("mat must be a square matrix"));
|
|
78
|
+
}
|
|
79
|
+
let n = shape[0];
|
|
80
|
+
let mut current_matrix: Array2<Complex64> = mat_view.to_owned();
|
|
81
|
+
let mut left_rotations: Vec<GivensRotationTuple> = Vec::new();
|
|
82
|
+
let mut right_rotations: Vec<GivensRotationTuple> = Vec::new();
|
|
83
|
+
let tol = 1e-12;
|
|
84
|
+
|
|
85
|
+
for i in 0..n.saturating_sub(1) {
|
|
86
|
+
if i % 2 == 0 {
|
|
87
|
+
for j in 0..=i {
|
|
88
|
+
let target_index = i - j;
|
|
89
|
+
let row = n - j - 1;
|
|
90
|
+
if current_matrix[[row, target_index]] != Complex64::new(0.0, 0.0) {
|
|
91
|
+
let (c, s) = zrotg_safe(
|
|
92
|
+
current_matrix[[row, target_index + 1]],
|
|
93
|
+
current_matrix[[row, target_index]],
|
|
94
|
+
tol,
|
|
95
|
+
);
|
|
96
|
+
right_rotations.push((c, s, target_index + 1, target_index));
|
|
97
|
+
rotate_columns_in_place(
|
|
98
|
+
&mut current_matrix,
|
|
99
|
+
target_index + 1,
|
|
100
|
+
target_index,
|
|
101
|
+
c,
|
|
102
|
+
s,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
for j in 0..=i {
|
|
108
|
+
let target_index = n - i + j - 1;
|
|
109
|
+
let col = j;
|
|
110
|
+
if current_matrix[[target_index, col]] != Complex64::new(0.0, 0.0) {
|
|
111
|
+
let (c, s) = zrotg_safe(
|
|
112
|
+
current_matrix[[target_index - 1, col]],
|
|
113
|
+
current_matrix[[target_index, col]],
|
|
114
|
+
tol,
|
|
115
|
+
);
|
|
116
|
+
left_rotations.push((c, s, target_index - 1, target_index));
|
|
117
|
+
rotate_rows_in_place(&mut current_matrix, target_index - 1, target_index, c, s);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
for &(c_left, s_left, i, j) in left_rotations.iter().rev() {
|
|
124
|
+
let (c, s) = zrotg_safe(
|
|
125
|
+
Complex64::new(c_left, 0.0) * current_matrix[[j, j]],
|
|
126
|
+
s_left.conj() * current_matrix[[i, i]],
|
|
127
|
+
tol,
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
right_rotations.push((c.clamp(-1.0, 1.0), -s.conj(), i, j));
|
|
131
|
+
|
|
132
|
+
let diag_i = current_matrix[[i, i]];
|
|
133
|
+
let diag_j = current_matrix[[j, j]];
|
|
134
|
+
let g00 = Complex64::new(c, 0.0) * diag_i;
|
|
135
|
+
let g01 = -s * diag_j;
|
|
136
|
+
let g10 = s.conj() * diag_i;
|
|
137
|
+
let g11 = Complex64::new(c, 0.0) * diag_j;
|
|
138
|
+
let (c_new, s_new) = zrotg_safe(g11, g10, tol);
|
|
139
|
+
|
|
140
|
+
let phase00 = g00 * Complex64::new(c_new, 0.0) + g01 * (-s_new.conj());
|
|
141
|
+
let phase11 = g10 * s_new + g11 * Complex64::new(c_new, 0.0);
|
|
142
|
+
current_matrix[[i, i]] = phase00;
|
|
143
|
+
current_matrix[[j, j]] = phase11;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
let diagonal = current_matrix.diag().to_owned();
|
|
147
|
+
Ok((right_rotations, diagonal.into_pyarray(py).unbind()))
|
|
148
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// (C) Copyright IBM 2026
|
|
2
|
+
//
|
|
3
|
+
// This code is licensed under the Apache License, Version 2.0. You may
|
|
4
|
+
// obtain a copy of this license in the LICENSE.txt file in the root directory
|
|
5
|
+
// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
|
6
|
+
//
|
|
7
|
+
// Any modifications or derivative works of this code must retain this
|
|
8
|
+
// copyright notice, and modified files need to carry a notice indicating
|
|
9
|
+
// that they have been altered from the originals.
|
|
10
|
+
|
|
11
|
+
pub mod givens;
|