diff --git a/dev_tools/autogenerate-bloqs-notebooks-v2.py b/dev_tools/autogenerate-bloqs-notebooks-v2.py index e77bee4d6..74cf3d4b3 100644 --- a/dev_tools/autogenerate-bloqs-notebooks-v2.py +++ b/dev_tools/autogenerate-bloqs-notebooks-v2.py @@ -50,7 +50,806 @@ from qualtran_dev_tools.bloq_finder import get_bloqdocspecs from qualtran_dev_tools.jupyter_autogen import NotebookSpecV2, render_notebook -from qualtran_dev_tools.notebook_specs import GIT_ROOT, SOURCE_DIR, NB_BY_SECTION + +import qualtran.bloqs.arithmetic.addition +import qualtran.bloqs.arithmetic.bitwise +import qualtran.bloqs.arithmetic.comparison +import qualtran.bloqs.arithmetic.controlled_add_or_subtract +import qualtran.bloqs.arithmetic.controlled_addition +import qualtran.bloqs.arithmetic.conversions +import qualtran.bloqs.arithmetic.multiplication +import qualtran.bloqs.arithmetic.negate +import qualtran.bloqs.arithmetic.permutation +import qualtran.bloqs.arithmetic.sorting +import qualtran.bloqs.arithmetic.subtraction +import qualtran.bloqs.arithmetic.trigonometric +import qualtran.bloqs.basic_gates.swap +import qualtran.bloqs.block_encoding.block_encoding_base +import qualtran.bloqs.block_encoding.chebyshev_polynomial +import qualtran.bloqs.block_encoding.lcu_block_encoding +import qualtran.bloqs.block_encoding.linear_combination +import qualtran.bloqs.block_encoding.phase +import qualtran.bloqs.block_encoding.product +import qualtran.bloqs.block_encoding.sparse_matrix +import qualtran.bloqs.block_encoding.tensor_product +import qualtran.bloqs.block_encoding.unitary +import qualtran.bloqs.bookkeeping +import qualtran.bloqs.bookkeeping.allocate +import qualtran.bloqs.bookkeeping.auto_partition +import qualtran.bloqs.bookkeeping.cast +import qualtran.bloqs.bookkeeping.free +import qualtran.bloqs.bookkeeping.join +import qualtran.bloqs.bookkeeping.partition +import qualtran.bloqs.bookkeeping.split +import qualtran.bloqs.chemistry.df.double_factorization +import qualtran.bloqs.chemistry.hubbard_model.qubitization +import qualtran.bloqs.chemistry.pbc.first_quantization.prepare_t +import qualtran.bloqs.chemistry.pbc.first_quantization.prepare_uv +import qualtran.bloqs.chemistry.pbc.first_quantization.projectile.select_and_prepare +import qualtran.bloqs.chemistry.pbc.first_quantization.select_t +import qualtran.bloqs.chemistry.pbc.first_quantization.select_uv +import qualtran.bloqs.chemistry.quad_fermion.givens_bloq +import qualtran.bloqs.chemistry.sf.single_factorization +import qualtran.bloqs.chemistry.sparse.prepare +import qualtran.bloqs.chemistry.sparse.walk_operator +import qualtran.bloqs.chemistry.thc.prepare +import qualtran.bloqs.chemistry.trotter.grid_ham.inverse_sqrt +import qualtran.bloqs.chemistry.trotter.grid_ham.qvr +import qualtran.bloqs.chemistry.trotter.hubbard.hopping +import qualtran.bloqs.chemistry.trotter.hubbard.interaction +import qualtran.bloqs.chemistry.trotter.ising.unitaries +import qualtran.bloqs.chemistry.trotter.trotterized_unitary +import qualtran.bloqs.data_loading.qrom +import qualtran.bloqs.data_loading.qrom_base +import qualtran.bloqs.data_loading.select_swap_qrom +import qualtran.bloqs.factoring.ecc +import qualtran.bloqs.factoring.mod_exp +import qualtran.bloqs.gf_arithmetic.gf2_multiplication +import qualtran.bloqs.hamiltonian_simulation.hamiltonian_simulation_by_gqsp +import qualtran.bloqs.mcmt.and_bloq +import qualtran.bloqs.mcmt.controlled_via_and +import qualtran.bloqs.mcmt.ctrl_spec_and +import qualtran.bloqs.mcmt.multi_control_pauli +import qualtran.bloqs.mcmt.multi_target_cnot +import qualtran.bloqs.mod_arithmetic.mod_addition +import qualtran.bloqs.multiplexers.apply_gate_to_lth_target +import qualtran.bloqs.multiplexers.apply_lth_bloq +import qualtran.bloqs.multiplexers.black_box_select +import qualtran.bloqs.multiplexers.select_base +import qualtran.bloqs.multiplexers.select_pauli_lcu +import qualtran.bloqs.phase_estimation.lp_resource_state +import qualtran.bloqs.phase_estimation.qubitization_qpe +import qualtran.bloqs.phase_estimation.text_book_qpe +import qualtran.bloqs.qft.approximate_qft +import qualtran.bloqs.qft.qft_phase_gradient +import qualtran.bloqs.qft.qft_text_book +import qualtran.bloqs.qft.two_bit_ffft +import qualtran.bloqs.qsp.generalized_qsp +import qualtran.bloqs.qubitization.qubitization_walk_operator +import qualtran.bloqs.reflections +import qualtran.bloqs.reflections.prepare_identity +import qualtran.bloqs.reflections.reflection_using_prepare +import qualtran.bloqs.rotations.hamming_weight_phasing +import qualtran.bloqs.rotations.phase_gradient +import qualtran.bloqs.rotations.phasing_via_cost_function +import qualtran.bloqs.rotations.programmable_rotation_gate_array +import qualtran.bloqs.rotations.quantum_variable_rotation +import qualtran.bloqs.state_preparation.black_box_prepare +import qualtran.bloqs.state_preparation.prepare_base +import qualtran.bloqs.state_preparation.prepare_uniform_superposition +import qualtran.bloqs.state_preparation.state_preparation_alias_sampling +import qualtran.bloqs.state_preparation.state_preparation_via_rotation +import qualtran.bloqs.swap_network.cswap_approx +import qualtran.bloqs.swap_network.multiplexed_cswap +import qualtran.bloqs.swap_network.swap_with_zero + +GIT_ROOT = get_git_root() +SOURCE_DIR = GIT_ROOT / 'qualtran/' + +# -------------------------------------------------------------------------- +# ----- Basic Gates ---------------------------------------------------- +# -------------------------------------------------------------------------- +BASIC_GATES: List[NotebookSpecV2] = [ + NotebookSpecV2( + title='T Gate', + module=qualtran.bloqs.basic_gates.t_gate, + bloq_specs=[qualtran.bloqs.basic_gates.t_gate._T_GATE_DOC], + ), + NotebookSpecV2( + title='Toffoli', + module=qualtran.bloqs.basic_gates.toffoli, + bloq_specs=[qualtran.bloqs.basic_gates.toffoli._TOFFOLI_DOC], + ), + NotebookSpecV2( + title='Hadamard', + module=qualtran.bloqs.basic_gates.hadamard, + bloq_specs=[ + qualtran.bloqs.basic_gates.hadamard._HADAMARD_DOC, + qualtran.bloqs.basic_gates.hadamard._CHADAMARD_DOC, + ], + ), + NotebookSpecV2( + title='CNOT', + module=qualtran.bloqs.basic_gates.cnot, + bloq_specs=[qualtran.bloqs.basic_gates.cnot._CNOT_DOC], + ), + NotebookSpecV2( + title='Z, S, and CZ', + module=qualtran.bloqs.basic_gates.z_basis, + path_stem='diag_gates', + bloq_specs=[ + qualtran.bloqs.basic_gates.z_basis._Z_GATE_DOC, + qualtran.bloqs.basic_gates.s_gate._S_GATE_DOC, + qualtran.bloqs.basic_gates.z_basis._CZ_DOC, + ], + ), + NotebookSpecV2( + title='Y Gate', + module=qualtran.bloqs.basic_gates.y_gate, + bloq_specs=[ + qualtran.bloqs.basic_gates.y_gate._Y_GATE_DOC, + qualtran.bloqs.basic_gates.y_gate._CY_GATE_DOC, + ], + ), + NotebookSpecV2( + title='And', + module=qualtran.bloqs.mcmt.and_bloq, + bloq_specs=[ + qualtran.bloqs.mcmt.and_bloq._AND_DOC, + qualtran.bloqs.mcmt.and_bloq._MULTI_AND_DOC, + ], + ), + NotebookSpecV2( + title='States and Effects', + module=qualtran.bloqs.basic_gates.z_basis, + path_stem='states_and_effects', + bloq_specs=[ + qualtran.bloqs.basic_gates.z_basis._ZERO_STATE_DOC, + qualtran.bloqs.basic_gates.z_basis._ZERO_EFFECT_DOC, + qualtran.bloqs.basic_gates.z_basis._ONE_STATE_DOC, + qualtran.bloqs.basic_gates.z_basis._ONE_EFFECT_DOC, + qualtran.bloqs.basic_gates.z_basis._INT_STATE_DOC, + qualtran.bloqs.basic_gates.z_basis._INT_EFFECT_DOC, + qualtran.bloqs.basic_gates.x_basis._PLUS_STATE_DOC, + qualtran.bloqs.basic_gates.x_basis._PLUS_EFFECT_DOC, + qualtran.bloqs.basic_gates.x_basis._MINUS_STATE_DOC, + qualtran.bloqs.basic_gates.x_basis._MINUS_EFFECT_DOC, + ], + ), + NotebookSpecV2( + title='Basic Swaps', + module=qualtran.bloqs.basic_gates.swap, + bloq_specs=[ + qualtran.bloqs.basic_gates.swap._TWO_BIT_SWAP_DOC, + qualtran.bloqs.basic_gates.swap._TWO_BIT_CSWAP_DOC, + qualtran.bloqs.basic_gates.swap._SWAP_DOC, + qualtran.bloqs.basic_gates.swap._CSWAP_DOC, + ], + ), + NotebookSpecV2( + title='Swap Networks', + module=qualtran.bloqs.swap_network, + bloq_specs=[ + qualtran.bloqs.swap_network.cswap_approx._APPROX_CSWAP_DOC, + qualtran.bloqs.swap_network.swap_with_zero._SWZ_DOC, + qualtran.bloqs.swap_network.multiplexed_cswap._MULTIPLEXED_CSWAP_DOC, + ], + ), + NotebookSpecV2( + title='Global Phase', + module=qualtran.bloqs.basic_gates.global_phase, + bloq_specs=[qualtran.bloqs.basic_gates.global_phase._GLOBAL_PHASE_DOC], + ), + NotebookSpecV2( + title='Identity Gate', + module=qualtran.bloqs.basic_gates.identity, + bloq_specs=[qualtran.bloqs.basic_gates.identity._IDENTITY_DOC], + ), + NotebookSpecV2( + title='Bookkeeping Bloqs', + module=qualtran.bloqs.bookkeeping, + bloq_specs=[ + qualtran.bloqs.bookkeeping.allocate._ALLOC_DOC, + qualtran.bloqs.bookkeeping.free._FREE_DOC, + qualtran.bloqs.bookkeeping.split._SPLIT_DOC, + qualtran.bloqs.bookkeeping.join._JOIN_DOC, + qualtran.bloqs.bookkeeping.partition._PARTITION_DOC, + qualtran.bloqs.bookkeeping.auto_partition._AUTO_PARTITION_DOC, + qualtran.bloqs.bookkeeping.cast._CAST_DOC, + ], + ), + NotebookSpecV2( + title='Control Specification (And)', + module=qualtran.bloqs.mcmt.ctrl_spec_and, + bloq_specs=[qualtran.bloqs.mcmt.ctrl_spec_and._CTRLSPEC_AND_DOC], + ), + NotebookSpecV2( + title='Multi control bloq via single control bloq and `And` ladder', + module=qualtran.bloqs.mcmt.controlled_via_and, + bloq_specs=[qualtran.bloqs.mcmt.controlled_via_and._CONTROLLED_VIA_AND_DOC], + ), +] + + +# -------------------------------------------------------------------------- +# ----- Chemistry ------------------------------------------------------ +# -------------------------------------------------------------------------- +CHEMISTRY: List[NotebookSpecV2] = [ + NotebookSpecV2( + title='Sparse', + module=qualtran.bloqs.chemistry.sparse, + bloq_specs=[ + qualtran.bloqs.chemistry.sparse.prepare._SPARSE_PREPARE, + qualtran.bloqs.chemistry.sparse.select_bloq._SPARSE_SELECT, + ], + directory=f'{SOURCE_DIR}/bloqs/chemistry/sparse', + ), + NotebookSpecV2( + title='Single Factorization', + module=qualtran.bloqs.chemistry.sf.single_factorization, + bloq_specs=[ + qualtran.bloqs.chemistry.sf.single_factorization._SF_ONE_BODY, + qualtran.bloqs.chemistry.sf.single_factorization._SF_BLOCK_ENCODING, + ], + directory=f'{SOURCE_DIR}/bloqs/chemistry/sf', + ), + NotebookSpecV2( + title='Double Factorization', + module=qualtran.bloqs.chemistry.df.double_factorization, + bloq_specs=[ + qualtran.bloqs.chemistry.df.double_factorization._DF_ONE_BODY, + qualtran.bloqs.chemistry.df.double_factorization._DF_BLOCK_ENCODING, + ], + directory=f'{SOURCE_DIR}/bloqs/chemistry/df', + ), + NotebookSpecV2( + title='Tensor Hypercontraction', + module=qualtran.bloqs.chemistry.thc, + bloq_specs=[ + qualtran.bloqs.chemistry.thc.prepare._THC_UNI_PREP, + qualtran.bloqs.chemistry.thc.prepare._THC_PREPARE, + qualtran.bloqs.chemistry.thc.select_bloq._THC_SELECT, + ], + directory=f'{SOURCE_DIR}/bloqs/chemistry/thc', + ), + NotebookSpecV2( + title='First Quantized Hamiltonian', + module=qualtran.bloqs.chemistry.pbc.first_quantization, + bloq_specs=[ + qualtran.bloqs.chemistry.pbc.first_quantization.select_and_prepare._FIRST_QUANTIZED_PREPARE_DOC, + qualtran.bloqs.chemistry.pbc.first_quantization.select_and_prepare._FIRST_QUANTIZED_SELECT_DOC, + qualtran.bloqs.chemistry.pbc.first_quantization.prepare_t._PREPARE_T, + qualtran.bloqs.chemistry.pbc.first_quantization.prepare_uv._PREPARE_UV, + qualtran.bloqs.chemistry.pbc.first_quantization.select_t._SELECT_T, + qualtran.bloqs.chemistry.pbc.first_quantization.select_uv._SELECT_UV, + ], + directory=f'{SOURCE_DIR}/bloqs/chemistry/pbc/first_quantization', + ), + NotebookSpecV2( + title='First Quantized Hamiltonian with Quantum Projectile', + module=qualtran.bloqs.chemistry.pbc.first_quantization.projectile, + bloq_specs=[ + qualtran.bloqs.chemistry.pbc.first_quantization.projectile.select_and_prepare._FIRST_QUANTIZED_WITH_PROJ_PREPARE_DOC, + qualtran.bloqs.chemistry.pbc.first_quantization.projectile.select_and_prepare._FIRST_QUANTIZED_WITH_PROJ_SELECT_DOC, + ], + directory=f'{SOURCE_DIR}/bloqs/chemistry/pbc/first_quantization/projectile', + ), + NotebookSpecV2( + title='Trotter Bloqs', + module=qualtran.bloqs.chemistry.trotter.grid_ham, + bloq_specs=[ + qualtran.bloqs.chemistry.trotter.grid_ham.inverse_sqrt._POLY_INV_SQRT, + qualtran.bloqs.chemistry.trotter.grid_ham.inverse_sqrt._NR_INV_SQRT, + qualtran.bloqs.chemistry.trotter.grid_ham.qvr._QVR, + qualtran.bloqs.chemistry.trotter.grid_ham.kinetic._KINETIC_ENERGY, + qualtran.bloqs.chemistry.trotter.grid_ham.potential._PAIR_POTENTIAL, + qualtran.bloqs.chemistry.trotter.grid_ham.potential._POTENTIAL_ENERGY, + ], + path_stem='trotter', + ), + NotebookSpecV2( + title='Trotterization', + module=qualtran.bloqs.chemistry.trotter.trotterized_unitary, + bloq_specs=[qualtran.bloqs.chemistry.trotter.trotterized_unitary._TROTT_UNITARY_DOC], + directory=f'{SOURCE_DIR}/bloqs/chemistry/trotter', + ), + NotebookSpecV2( + title='Ising Trotter Bloqs', + module=qualtran.bloqs.chemistry.trotter.ising, + bloq_specs=[ + qualtran.bloqs.chemistry.trotter.ising.unitaries._ISING_X_UNITARY_DOC, + qualtran.bloqs.chemistry.trotter.ising.unitaries._ISING_ZZ_UNITARY_DOC, + ], + directory=f'{SOURCE_DIR}/bloqs/chemistry/trotter/ising', + ), + NotebookSpecV2( + title='Trotterized Hubbard', + module=qualtran.bloqs.chemistry.trotter.hubbard, + bloq_specs=[ + qualtran.bloqs.chemistry.trotter.hubbard.hopping._HOPPING_DOC, + qualtran.bloqs.chemistry.trotter.hubbard.hopping._PLAQUETTE_DOC, + qualtran.bloqs.chemistry.trotter.hubbard.hopping._HOPPING_TILE_HWP_DOC, + qualtran.bloqs.chemistry.trotter.hubbard.interaction._INTERACTION_DOC, + qualtran.bloqs.chemistry.trotter.hubbard.interaction._INTERACTION_HWP_DOC, + ], + directory=f'{SOURCE_DIR}/bloqs/chemistry/trotter/hubbard', + ), + NotebookSpecV2( + title='Givens Rotations', + module=qualtran.bloqs.chemistry.quad_fermion.givens_bloq, + bloq_specs=[ + qualtran.bloqs.chemistry.quad_fermion.givens_bloq._REAL_GIVENS_DOC, + qualtran.bloqs.chemistry.quad_fermion.givens_bloq._CPLX_GIVENS_DOC, + ], + ), +] + +# -------------------------------------------------------------------------- +# ----- Arithmetic ----------------------------------------------------- +# -------------------------------------------------------------------------- +ARITHMETIC = [ + NotebookSpecV2( + title='Addition', + module=qualtran.bloqs.arithmetic.addition, + bloq_specs=[ + qualtran.bloqs.arithmetic.addition._ADD_DOC, + qualtran.bloqs.arithmetic.addition._ADD_OOP_DOC, + qualtran.bloqs.arithmetic.addition._ADD_K_DOC, + ], + ), + NotebookSpecV2( + title='Controlled Addition', + module=qualtran.bloqs.arithmetic.controlled_addition, + bloq_specs=[qualtran.bloqs.arithmetic.controlled_addition._CADD_DOC], + ), + NotebookSpecV2( + title='Negation', + module=qualtran.bloqs.arithmetic.negate, + bloq_specs=[qualtran.bloqs.arithmetic.negate._NEGATE_DOC], + ), + NotebookSpecV2( + title='Subtraction', + module=qualtran.bloqs.arithmetic.subtraction, + bloq_specs=[ + qualtran.bloqs.arithmetic.subtraction._SUB_DOC, + qualtran.bloqs.arithmetic.subtraction._SUB_FROM_DOC, + ], + ), + NotebookSpecV2( + title='Controlled Add-or-Subtract', + module=qualtran.bloqs.arithmetic.controlled_add_or_subtract, + bloq_specs=[ + qualtran.bloqs.arithmetic.controlled_add_or_subtract._CONTROLLED_ADD_OR_SUBTRACT_DOC + ], + ), + NotebookSpecV2( + title='Multiplication', + module=qualtran.bloqs.arithmetic.multiplication, + bloq_specs=[ + qualtran.bloqs.arithmetic.multiplication._PLUS_EQUALS_PRODUCT_DOC, + qualtran.bloqs.arithmetic.multiplication._PRODUCT_DOC, + qualtran.bloqs.arithmetic.multiplication._SQUARE_DOC, + qualtran.bloqs.arithmetic.multiplication._SUM_OF_SQUARES_DOC, + qualtran.bloqs.arithmetic.multiplication._SCALE_INT_BY_REAL_DOC, + qualtran.bloqs.arithmetic.multiplication._MULTIPLY_TWO_REALS_DOC, + qualtran.bloqs.arithmetic.multiplication._SQUARE_REAL_NUMBER_DOC, + qualtran.bloqs.arithmetic.multiplication._INVERT_REAL_NUMBER_DOC, + ], + ), + NotebookSpecV2( + title='Comparison', + module=qualtran.bloqs.arithmetic.comparison, + bloq_specs=[ + qualtran.bloqs.arithmetic.comparison._LT_K_DOC, + qualtran.bloqs.arithmetic.comparison._GREATER_THAN_DOC, + qualtran.bloqs.arithmetic.comparison._GREATER_THAN_K_DOC, + qualtran.bloqs.arithmetic.comparison._EQUALS_DOC, + qualtran.bloqs.arithmetic.comparison._EQUALS_K_DOC, + qualtran.bloqs.arithmetic.comparison._BI_QUBITS_MIXER_DOC, + qualtran.bloqs.arithmetic.comparison._SQ_CMP_DOC, + qualtran.bloqs.arithmetic.comparison._LEQ_DOC, + qualtran.bloqs.arithmetic.comparison._CLinearDepthGreaterThan_DOC, + ], + ), + NotebookSpecV2( + title='Integer Conversions', + module=qualtran.bloqs.arithmetic.conversions, + bloq_specs=[ + qualtran.bloqs.arithmetic.conversions.ones_complement_to_twos_complement._SIGNED_TO_TWOS, + qualtran.bloqs.arithmetic.conversions.sign_extension._SIGN_EXTEND_DOC, + qualtran.bloqs.arithmetic.conversions.sign_extension._SIGN_TRUNCATE_DOC, + ], + ), + NotebookSpecV2( + title='Sorting', + module=qualtran.bloqs.arithmetic.sorting, + bloq_specs=[ + qualtran.bloqs.arithmetic.sorting._COMPARATOR_DOC, + qualtran.bloqs.arithmetic.sorting._PARALLEL_COMPARATORS_DOC, + qualtran.bloqs.arithmetic.sorting._BITONIC_MERGE_DOC, + qualtran.bloqs.arithmetic.sorting._BITONIC_SORT_DOC, + ], + directory=f'{SOURCE_DIR}/bloqs/arithmetic/', + ), + NotebookSpecV2( + title='Indexing', + module=qualtran.bloqs.arithmetic.conversions.contiguous_index, + bloq_specs=[qualtran.bloqs.arithmetic.conversions.contiguous_index._TO_CONTG_INDX], + ), + NotebookSpecV2( + title='Permutations', + module=qualtran.bloqs.arithmetic.permutation, + bloq_specs=[ + qualtran.bloqs.arithmetic.permutation._PERMUTATION_DOC, + qualtran.bloqs.arithmetic.permutation._PERMUTATION_CYCLE_DOC, + ], + ), + NotebookSpecV2( + title='Bitwise Operations', + module=qualtran.bloqs.arithmetic.bitwise, + bloq_specs=[ + qualtran.bloqs.arithmetic.bitwise._XOR_DOC, + qualtran.bloqs.arithmetic.bitwise._BITWISE_NOT_DOC, + ], + ), + NotebookSpecV2( + title='Trigonometric Functions', + module=qualtran.bloqs.arithmetic.trigonometric, + bloq_specs=[qualtran.bloqs.arithmetic.trigonometric.arcsin._ARCSIN_DOC], + ), +] + +MOD_ARITHMETIC = [ + NotebookSpecV2( + title='Modular Addition', + module=qualtran.bloqs.mod_arithmetic.mod_addition, + bloq_specs=[ + qualtran.bloqs.mod_arithmetic.mod_addition._MOD_ADD_DOC, + qualtran.bloqs.mod_arithmetic.mod_addition._MOD_ADD_K_DOC, + qualtran.bloqs.mod_arithmetic.mod_addition._C_MOD_ADD_DOC, + ], + ), + NotebookSpecV2( + title='Modular Subtraction', + module=qualtran.bloqs.mod_arithmetic.mod_subtraction, + bloq_specs=[ + qualtran.bloqs.mod_arithmetic.mod_subtraction._MOD_NEG_DOC, + qualtran.bloqs.mod_arithmetic.mod_subtraction._CMOD_NEG_DOC, + qualtran.bloqs.mod_arithmetic.mod_subtraction._MOD_SUB_DOC, + qualtran.bloqs.mod_arithmetic.mod_subtraction._CMOD_SUB_DOC, + ], + ), + NotebookSpecV2( + title='Modular Multiplication', + module=qualtran.bloqs.mod_arithmetic.mod_multiplication, + bloq_specs=[ + qualtran.bloqs.mod_arithmetic.mod_multiplication._MOD_DBL_DOC, + qualtran.bloqs.mod_arithmetic.mod_multiplication._C_MOD_MUL_K_DOC, + qualtran.bloqs.mod_arithmetic.mod_multiplication._DIRTY_OUT_OF_PLACE_MONTGOMERY_MOD_MUL_DOC, + ], + ), + NotebookSpecV2( + title='Modular Exponentiation', + module=qualtran.bloqs.factoring.mod_exp, + bloq_specs=[qualtran.bloqs.factoring.mod_exp._MODEXP_DOC], + directory=f'{SOURCE_DIR}/bloqs/factoring', + ), + NotebookSpecV2( + title='Elliptic Curve Addition', + module=qualtran.bloqs.factoring.ecc.ec_add, + bloq_specs=[qualtran.bloqs.factoring.ecc.ec_add._EC_ADD_DOC], + ), + NotebookSpecV2( + title='Elliptic Curve Cryptography', + module=qualtran.bloqs.factoring.ecc, + bloq_specs=[ + qualtran.bloqs.factoring.ecc.find_ecc_private_key._ECC_BLOQ_DOC, + qualtran.bloqs.factoring.ecc.ec_phase_estimate_r._EC_PE_BLOQ_DOC, + qualtran.bloqs.factoring.ecc.ec_add_r._ECC_ADD_R_BLOQ_DOC, + qualtran.bloqs.factoring.ecc.ec_add_r._EC_WINDOW_ADD_BLOQ_DOC, + ], + ), +] + +GF_ARITHMETIC = [ + # -------------------------------------------------------------------------- + # ----- Galois Fields (GF) Arithmetic --------------------------------- + # -------------------------------------------------------------------------- + NotebookSpecV2( + title='GF($2^m$) Multiplication', + module=qualtran.bloqs.gf_arithmetic.gf2_multiplication, + bloq_specs=[qualtran.bloqs.gf_arithmetic.gf2_multiplication._GF2_MULTIPLICATION_DOC], + ) +] + + +ROT_QFT_PE = [ + # -------------------------------------------------------------------------- + # ----- Rotations ----------------------------------------------------- + # -------------------------------------------------------------------------- + NotebookSpecV2( + title='Basic Rotation Gates', + module=qualtran.bloqs.basic_gates.rotation, + bloq_specs=[ + qualtran.bloqs.basic_gates.rotation._X_POW_DOC, + qualtran.bloqs.basic_gates.rotation._Y_POW_DOC, + qualtran.bloqs.basic_gates.rotation._Z_POW_DOC, + ], + ), + NotebookSpecV2( + title='SU2 Rotation', + module=qualtran.bloqs.basic_gates.su2_rotation, + bloq_specs=[qualtran.bloqs.basic_gates.su2_rotation._SU2_ROTATION_GATE_DOC], + ), + NotebookSpecV2( + title='Quantum Variable Rotation', + module=qualtran.bloqs.rotations.quantum_variable_rotation, + bloq_specs=[ + qualtran.bloqs.rotations.quantum_variable_rotation._QVR_ZPOW, + qualtran.bloqs.rotations.quantum_variable_rotation._QVR_PHASE_GRADIENT, + ], + directory=f'{SOURCE_DIR}/bloqs/rotations/', + ), + NotebookSpecV2( + title='Phasing via Cost function', + module=qualtran.bloqs.rotations.phasing_via_cost_function, + bloq_specs=[qualtran.bloqs.rotations.phasing_via_cost_function._PHASING_VIA_COST_FUNCTION], + directory=f'{SOURCE_DIR}/bloqs/rotations/', + ), + NotebookSpecV2( + title='Rotations via Phase Gradients', + module=qualtran.bloqs.rotations.phase_gradient, + bloq_specs=[ + qualtran.bloqs.rotations.phase_gradient._PHASE_GRADIENT_UNITARY_DOC, + qualtran.bloqs.rotations.phase_gradient._PHASE_GRADIENT_STATE_DOC, + qualtran.bloqs.rotations.phase_gradient._ADD_INTO_PHASE_GRAD_DOC, + qualtran.bloqs.rotations.phase_gradient._ADD_SCALED_VAL_INTO_PHASE_REG_DOC, + ], + ), + NotebookSpecV2( + title='Z Rotations via Hamming Weight Phasing', + module=qualtran.bloqs.rotations.hamming_weight_phasing, + bloq_specs=[ + qualtran.bloqs.rotations.hamming_weight_phasing._HAMMING_WEIGHT_PHASING_DOC, + qualtran.bloqs.rotations.hamming_weight_phasing._HAMMING_WEIGHT_PHASING_VIA_PHASE_GRADIENT_DOC, + ], + ), + NotebookSpecV2( + title='Programmable Rotation Gate Array', + module=qualtran.bloqs.rotations.programmable_rotation_gate_array, + bloq_specs=[ + qualtran.bloqs.rotations.programmable_rotation_gate_array._PROGRAMMABLE_ROTATAION_GATE_ARRAY_DOC + ], + ), + # -------------------------------------------------------------------------- + # ----- QFT ----------------------------------------------------- + # -------------------------------------------------------------------------- + NotebookSpecV2( + title='Two Bit FFFT Gate', + module=qualtran.bloqs.qft.two_bit_ffft, + bloq_specs=[qualtran.bloqs.qft.two_bit_ffft._TWO_BIT_FFFT_DOC], + ), + NotebookSpecV2( + title='Approximate QFT', + module=qualtran.bloqs.qft.approximate_qft, + bloq_specs=[qualtran.bloqs.qft.approximate_qft._CC_AQFT_DOC], + ), + NotebookSpecV2( + title='Textbook QFT', + module=qualtran.bloqs.qft.qft_text_book, + bloq_specs=[qualtran.bloqs.qft.qft_text_book._QFT_TEXT_BOOK_DOC], + ), + NotebookSpecV2( + title='Phase Gradient QFT', + module=qualtran.bloqs.qft.qft_phase_gradient, + bloq_specs=[qualtran.bloqs.qft.qft_phase_gradient._QFT_PHASE_GRADIENT_DOC], + ), + # -------------------------------------------------------------------------- + # ----- Phase Estimation ---------------------------------------- + # -------------------------------------------------------------------------- + NotebookSpecV2( + title='Optimal resource states for Phase Estimation by A. Luis and J. Peřina', + module=qualtran.bloqs.phase_estimation.lp_resource_state, + bloq_specs=[ + qualtran.bloqs.phase_estimation.lp_resource_state._CC_LPRS_INTERIM_PREP_DOC, + qualtran.bloqs.phase_estimation.lp_resource_state._CC_LP_RESOURCE_STATE_DOC, + ], + ), + NotebookSpecV2( + title='Textbook Quantum Phase Estimation', + module=qualtran.bloqs.phase_estimation.text_book_qpe, + bloq_specs=[ + qualtran.bloqs.phase_estimation.qpe_window_state._CC_RECTANGULAR_WINDOW_STATE_DOC, + qualtran.bloqs.phase_estimation.text_book_qpe._CC_TEXTBOOK_PHASE_ESTIMATION_DOC, + ], + ), + NotebookSpecV2( + title='Kaiser Window State for Quantum Phase Estimation', + module=qualtran.bloqs.phase_estimation.kaiser_window_state, + bloq_specs=[ + qualtran.bloqs.phase_estimation.kaiser_window_state._CC_KAISER_WINDOW_STATE_DOC + ], + ), + NotebookSpecV2( + title='Qubitization Walk Operator', + module=qualtran.bloqs.qubitization.qubitization_walk_operator, + bloq_specs=[qualtran.bloqs.qubitization.qubitization_walk_operator._QUBITIZATION_WALK_DOC], + ), + NotebookSpecV2( + title='Qubitization Phase Estimation', + module=qualtran.bloqs.phase_estimation.qubitization_qpe, + bloq_specs=[qualtran.bloqs.phase_estimation.qubitization_qpe._QUBITIZATION_QPE_DOC], + ), +] + +# -------------------------------------------------------------------------- +# ----- Block Encoding ---------------------------------------------------------- +# -------------------------------------------------------------------------- +BLOCK_ENCODING: List[NotebookSpecV2] = [ + NotebookSpecV2( + title='Block Encoding Interface', + module=qualtran.bloqs.block_encoding, + bloq_specs=[qualtran.bloqs.block_encoding.block_encoding_base._BLOCK_ENCODING_DOC], + ), + NotebookSpecV2( + title='Unitary', + module=qualtran.bloqs.block_encoding.unitary, + bloq_specs=[qualtran.bloqs.block_encoding.unitary._UNITARY_DOC], + ), + NotebookSpecV2( + title='Tensor Product', + module=qualtran.bloqs.block_encoding.tensor_product, + bloq_specs=[qualtran.bloqs.block_encoding.tensor_product._TENSOR_PRODUCT_DOC], + ), + NotebookSpecV2( + title='Product', + module=qualtran.bloqs.block_encoding.product, + bloq_specs=[qualtran.bloqs.block_encoding.product._PRODUCT_DOC], + ), + NotebookSpecV2( + title='Phase', + module=qualtran.bloqs.block_encoding.phase, + bloq_specs=[qualtran.bloqs.block_encoding.phase._PHASE_DOC], + ), + NotebookSpecV2( + title='Linear Combination', + module=qualtran.bloqs.block_encoding.linear_combination, + bloq_specs=[qualtran.bloqs.block_encoding.linear_combination._LINEAR_COMBINATION_DOC], + ), + NotebookSpecV2( + title='Sparse Matrix', + module=qualtran.bloqs.block_encoding.sparse_matrix, + bloq_specs=[qualtran.bloqs.block_encoding.sparse_matrix._SPARSE_MATRIX_DOC], + ), + NotebookSpecV2( + title='Chebyshev Polynomial', + module=qualtran.bloqs.block_encoding.chebyshev_polynomial, + bloq_specs=[ + qualtran.bloqs.block_encoding.chebyshev_polynomial._CHEBYSHEV_BLOQ_DOC, + qualtran.bloqs.block_encoding.chebyshev_polynomial._SCALED_CHEBYSHEV_BLOQ_DOC, + ], + ), + NotebookSpecV2( + title='LCU Select/Prepare Oracles', + module=qualtran.bloqs.block_encoding.lcu_block_encoding, + bloq_specs=[ + qualtran.bloqs.block_encoding.lcu_block_encoding._SELECT_BLOCK_ENCODING_DOC, + qualtran.bloqs.block_encoding.lcu_block_encoding._LCU_BLOCK_ENCODING_DOC, + qualtran.bloqs.multiplexers.select_base._SELECT_ORACLE_DOC, + qualtran.bloqs.state_preparation.prepare_base._PREPARE_ORACLE_DOC, + qualtran.bloqs.multiplexers.black_box_select._BLACK_BOX_SELECT_DOC, + qualtran.bloqs.state_preparation.black_box_prepare._BLACK_BOX_PREPARE_DOC, + ], + ), +] + +# -------------------------------------------------------------------------- +# ----- Other ---------------------------------------------------------- +# -------------------------------------------------------------------------- +OTHER: List[NotebookSpecV2] = [ + NotebookSpecV2( + title='Prepare Uniform Superposition', + module=qualtran.bloqs.state_preparation.prepare_uniform_superposition, + bloq_specs=[ + qualtran.bloqs.state_preparation.prepare_uniform_superposition._PREP_UNIFORM_DOC + ], + ), + NotebookSpecV2( + title='Qubitized Hubbard Model', + module=qualtran.bloqs.chemistry.hubbard_model.qubitization, + path_stem='hubbard_model', + bloq_specs=[ + qualtran.bloqs.chemistry.hubbard_model.qubitization.select_hubbard._SELECT_HUBBARD, + qualtran.bloqs.chemistry.hubbard_model.qubitization.prepare_hubbard._PREPARE_HUBBARD, + ], + ), + NotebookSpecV2( + title='Apply to Lth Target', + module=qualtran.bloqs.multiplexers.apply_gate_to_lth_target, + bloq_specs=[qualtran.bloqs.multiplexers.apply_gate_to_lth_target._APPLY_TO_LTH_TARGET_DOC], + ), + NotebookSpecV2( + title='Apply Lth Bloq', + module=qualtran.bloqs.multiplexers.apply_lth_bloq, + bloq_specs=[qualtran.bloqs.multiplexers.apply_lth_bloq._APPLY_LTH_BLOQ_DOC], + ), + NotebookSpecV2( + title='QROM', + module=qualtran.bloqs.data_loading.qrom, + bloq_specs=[ + qualtran.bloqs.data_loading.qrom_base._QROM_BASE_DOC, + qualtran.bloqs.data_loading.qrom._QROM_DOC, + ], + ), + NotebookSpecV2( + title='SelectSwapQROM', + module=qualtran.bloqs.data_loading.select_swap_qrom, + bloq_specs=[ + qualtran.bloqs.data_loading.qrom_base._QROM_BASE_DOC, + qualtran.bloqs.data_loading.select_swap_qrom._SELECT_SWAP_QROM_DOC, + ], + ), + NotebookSpecV2( + title='Advanced QROM (aka QROAM) using clean ancilla', + module=qualtran.bloqs.data_loading.qroam_clean, + bloq_specs=[ + qualtran.bloqs.data_loading.qrom_base._QROM_BASE_DOC, + qualtran.bloqs.data_loading.qroam_clean._QROAM_CLEAN_DOC, + ], + ), + NotebookSpecV2( + title='Reflections', + module=qualtran.bloqs.reflections, + bloq_specs=[ + qualtran.bloqs.reflections.prepare_identity._PREPARE_IDENTITY_DOC, + qualtran.bloqs.reflections.reflection_using_prepare._REFL_USING_PREP_DOC, + ], + directory=f'{SOURCE_DIR}/bloqs/reflections', + ), + NotebookSpecV2( + title='Multi-Paulis', + module=qualtran.bloqs.mcmt, + bloq_specs=[ + qualtran.bloqs.mcmt.multi_target_cnot._C_MULTI_NOT_DOC, + qualtran.bloqs.mcmt.multi_control_pauli._CC_PAULI_DOC, + ], + directory=f'{SOURCE_DIR}/bloqs/mcmt/', + path_stem='multi_control_multi_target_pauli', + ), + NotebookSpecV2( + title='Generic Select', + module=qualtran.bloqs.multiplexers.select_pauli_lcu, + bloq_specs=[qualtran.bloqs.multiplexers.select_pauli_lcu._SELECT_PAULI_LCU_DOC], + ), + NotebookSpecV2( + title='State Preparation via Alias Sampling', + module=qualtran.bloqs.state_preparation.state_preparation_alias_sampling, + bloq_specs=[ + qualtran.bloqs.state_preparation.state_preparation_alias_sampling._STATE_PREP_ALIAS_DOC, + qualtran.bloqs.state_preparation.state_preparation_alias_sampling._SPARSE_STATE_PREP_ALIAS_DOC, + ], + ), + NotebookSpecV2( + title='State Preparation Using Rotations', + module=qualtran.bloqs.state_preparation.state_preparation_via_rotation, + bloq_specs=[ + qualtran.bloqs.state_preparation.state_preparation_via_rotation._STATE_PREP_VIA_ROTATIONS_DOC + ], + directory=f'{SOURCE_DIR}/bloqs/state_preparation/', + ), + NotebookSpecV2( + title='Generalized Quantum Signal Processing', + module=qualtran.bloqs.qsp.generalized_qsp, + bloq_specs=[qualtran.bloqs.qsp.generalized_qsp._Generalized_QSP_DOC], + ), + NotebookSpecV2( + title='Hamiltonian Simulation by Generalized Quantum Signal Processing', + module=qualtran.bloqs.hamiltonian_simulation.hamiltonian_simulation_by_gqsp, + bloq_specs=[ + qualtran.bloqs.hamiltonian_simulation.hamiltonian_simulation_by_gqsp._Hamiltonian_Simulation_by_GQSP_DOC + ], + ), +] # -------------------------------------------------------------------------- # ----- Concepts ------------------------------------------------------- @@ -70,6 +869,17 @@ 'state_preparation/state_preparation_via_rotation_tutorial.ipynb', ] +NB_BY_SECTION = [ + ('Basic Gates', BASIC_GATES), + ('Chemistry', CHEMISTRY), + ('Arithmetic', ARITHMETIC), + ('Modular Arithmetic', MOD_ARITHMETIC), + ('GF Arithmetic', GF_ARITHMETIC), + ('Rotations', ROT_QFT_PE), + ('Block Encoding', BLOCK_ENCODING), + ('Other', OTHER), +] + def _all_nbspecs() -> Iterable[NotebookSpecV2]: for _, nbspecs in NB_BY_SECTION: diff --git a/docs/bloqs/index.rst b/docs/bloqs/index.rst index 34df92ddb..4dc18012a 100644 --- a/docs/bloqs/index.rst +++ b/docs/bloqs/index.rst @@ -87,6 +87,12 @@ Bloqs Library factoring/ecc/ec_add.ipynb factoring/ecc/ecc.ipynb +.. toctree:: + :maxdepth: 2 + :caption: GF Arithmetic: + + gf_arithmetic/gf2_multiplication.ipynb + .. toctree:: :maxdepth: 2 :caption: Rotations: diff --git a/qualtran/bloqs/bookkeeping/allocate.py b/qualtran/bloqs/bookkeeping/allocate.py index 7f566a714..cbb779a22 100644 --- a/qualtran/bloqs/bookkeeping/allocate.py +++ b/qualtran/bloqs/bookkeeping/allocate.py @@ -69,7 +69,7 @@ def adjoint(self) -> 'Bloq': return Free(self.dtype, self.dirty) def on_classical_vals(self) -> Dict[str, int]: - return {'reg': 0} + return {'reg': self.dtype.from_bits([0] * self.dtype.num_qubits)} def my_tensors( self, incoming: Dict[str, 'ConnectionT'], outgoing: Dict[str, 'ConnectionT'] diff --git a/qualtran/bloqs/gf_arithmetic/__init__.py b/qualtran/bloqs/gf_arithmetic/__init__.py new file mode 100644 index 000000000..6fc27f4c6 --- /dev/null +++ b/qualtran/bloqs/gf_arithmetic/__init__.py @@ -0,0 +1,15 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from qualtran.bloqs.gf_arithmetic.gf2_multiplication import GF2Multiplication diff --git a/qualtran/bloqs/gf_arithmetic/gf2_multiplication.ipynb b/qualtran/bloqs/gf_arithmetic/gf2_multiplication.ipynb new file mode 100644 index 000000000..03bb4ddca --- /dev/null +++ b/qualtran/bloqs/gf_arithmetic/gf2_multiplication.ipynb @@ -0,0 +1,182 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "87c95c4a", + "metadata": { + "cq.autogen": "title_cell" + }, + "source": [ + "# GF($2^m$) Multiplication" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31c1f087", + "metadata": { + "cq.autogen": "top_imports" + }, + "outputs": [], + "source": [ + "from qualtran import Bloq, CompositeBloq, BloqBuilder, Signature, Register\n", + "from qualtran import QBit, QInt, QUInt, QAny\n", + "from qualtran.drawing import show_bloq, show_call_graph, show_counts_sigma\n", + "from typing import *\n", + "import numpy as np\n", + "import sympy\n", + "import cirq" + ] + }, + { + "cell_type": "markdown", + "id": "307679ec", + "metadata": { + "cq.autogen": "GF2Multiplication.bloq_doc.md" + }, + "source": [ + "## `GF2Multiplication`\n", + "Out of place multiplication over GF($2^m$).\n", + "\n", + "The bloq implements out of place multiplication of two quantum registers storing elements\n", + "from GF($2^m$) using construction described in Ref[1], which extends the classical construction\n", + "of Ref[2].\n", + "\n", + "To multiply two m-bit inputs $a = [a_0, a_1, ..., a_{m-1}]$ and $b = [b_0, b_1, ..., b_{m-1}]$,\n", + "the construction computes the output vector $c$ via the following three steps:\n", + " 1. Compute $e = U.b$ where $U$ is an upper triangular matrix constructed using $a$.\n", + " 2. Compute $Q.e$ where $Q$ is an $m \\times (m - 1)$ reduction matrix that depends upon the\n", + " irreducible polynomial $P(x)$ of the galois field $GF(2^m)$. The i'th column of the\n", + " matrix corresponds to coefficients of the polynomial $x^{m + i} % P(x)$. This matrix $Q$\n", + " is a linear reversible circuit that can be implemented only using CNOT gates.\n", + " 3. Compute $d = L.b$ where $L$ is a lower triangular matrix constructed using $a$.\n", + " 4. Compute $c = d + Q.e$ to obtain the final product.\n", + "\n", + "Steps 1 and 3 are performed using $n^2$ Toffoli gates and step 2 is performed only using CNOT\n", + "gates.\n", + "\n", + "#### Parameters\n", + " - `bitsize`: The degree $m$ of the galois field $GF(2^m)$. Also corresponds to the number of qubits in each of the two input registers $a$ and $b$ that should be multiplied. \n", + "\n", + "#### Registers\n", + " - `x`: Input THRU register of size $m$ that stores elements from $GF(2^m)$.\n", + " - `y`: Input THRU register of size $m$ that stores elements from $GF(2^m)$.\n", + " - `result`: Output RIGHT register of size $m$ that stores the product $x * y$ in $GF(2^m)$. \n", + "\n", + "#### References\n", + " - [On the Design and Optimization of a Quantum Polynomial-Time Attack on Elliptic Curve Cryptography](https://arxiv.org/abs/0710.1093). \n", + " - [Low complexity bit parallel architectures for polynomial basis multiplication over GF(2m)](https://ieeexplore.ieee.org/abstract/document/1306989). \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "872a44d1", + "metadata": { + "cq.autogen": "GF2Multiplication.bloq_doc.py" + }, + "outputs": [], + "source": [ + "from qualtran.bloqs.gf_arithmetic import GF2Multiplication" + ] + }, + { + "cell_type": "markdown", + "id": "d0f0db7d", + "metadata": { + "cq.autogen": "GF2Multiplication.example_instances.md" + }, + "source": [ + "### Example Instances" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "131bc962", + "metadata": { + "cq.autogen": "GF2Multiplication.gf16_multiplication" + }, + "outputs": [], + "source": [ + "gf16_multiplication = GF2Multiplication(4)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69f564d8", + "metadata": { + "cq.autogen": "GF2Multiplication.gf2_multiplication_symbolic" + }, + "outputs": [], + "source": [ + "import sympy\n", + "\n", + "m = sympy.Symbol('m')\n", + "gf2_multiplication_symbolic = GF2Multiplication(m)" + ] + }, + { + "cell_type": "markdown", + "id": "2a62c2b8", + "metadata": { + "cq.autogen": "GF2Multiplication.graphical_signature.md" + }, + "source": [ + "#### Graphical Signature" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf003e98", + "metadata": { + "cq.autogen": "GF2Multiplication.graphical_signature.py" + }, + "outputs": [], + "source": [ + "from qualtran.drawing import show_bloqs\n", + "show_bloqs([gf16_multiplication, gf2_multiplication_symbolic],\n", + " ['`gf16_multiplication`', '`gf2_multiplication_symbolic`'])" + ] + }, + { + "cell_type": "markdown", + "id": "f14ef0c5", + "metadata": { + "cq.autogen": "GF2Multiplication.call_graph.md" + }, + "source": [ + "### Call Graph" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4b7bf2c", + "metadata": { + "cq.autogen": "GF2Multiplication.call_graph.py" + }, + "outputs": [], + "source": [ + "from qualtran.resource_counting.generalizers import ignore_split_join\n", + "gf16_multiplication_g, gf16_multiplication_sigma = gf16_multiplication.call_graph(max_depth=1, generalizer=ignore_split_join)\n", + "show_call_graph(gf16_multiplication_g)\n", + "show_counts_sigma(gf16_multiplication_sigma)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/qualtran/bloqs/gf_arithmetic/gf2_multiplication.py b/qualtran/bloqs/gf_arithmetic/gf2_multiplication.py new file mode 100644 index 000000000..4f91ecaa0 --- /dev/null +++ b/qualtran/bloqs/gf_arithmetic/gf2_multiplication.py @@ -0,0 +1,226 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from functools import cached_property +from typing import Dict, Set, TYPE_CHECKING, Union + +import attrs +import numpy as np +from galois import GF, Poly + +from qualtran import ( + Bloq, + bloq_example, + BloqDocSpec, + DecomposeTypeError, + QBit, + QGF, + Register, + Side, + Signature, +) +from qualtran.bloqs.basic_gates import CNOT, Toffoli +from qualtran.symbolics import ceil, is_symbolic, log2, Shaped, SymbolicInt + +if TYPE_CHECKING: + from qualtran import BloqBuilder, Soquet + from qualtran.resource_counting import BloqCountDictT, BloqCountT, SympySymbolAllocator + from qualtran.simulation.classical_sim import ClassicalValT + + +def _data_or_shape_to_tuple(data_or_shape: Union[np.ndarray, Shaped]) -> tuple: + return ( + tuple(data_or_shape.flatten()) + if isinstance(data_or_shape, np.ndarray) + else (data_or_shape,) + ) + + +@attrs.frozen +class SynthesizeLRCircuit(Bloq): + """Synthesize linear reversible circuit using CNOT gates. + + Args: + matrix: An n x m matrix describing the linear transformation. + + References: + [Efficient Synthesis of Linear Reversible Circuits](https://arxiv.org/abs/quant-ph/0302002) + """ + + matrix: Union[Shaped, np.ndarray] = attrs.field(eq=_data_or_shape_to_tuple) + + def __attrs_post_init__(self): + assert len(self.matrix.shape) == 2 + n, m = self.matrix.shape + assert is_symbolic(n, m) or n >= m + + @cached_property + def signature(self) -> 'Signature': + n, _ = self.matrix.shape + return Signature([Register('q', QBit(), shape=(n,))]) + + def on_classical_vals(self, *, q: 'ClassicalValT') -> Dict[str, 'ClassicalValT']: + matrix = self.matrix + assert isinstance(matrix, np.ndarray) + _, m = matrix.shape + assert isinstance(q, np.ndarray) + q_in = q[:m] + return {'q': (matrix @ q_in) % 2} + + def build_call_graph( + self, ssa: 'SympySymbolAllocator' + ) -> Union['BloqCountDictT', Set['BloqCountT']]: + n = self.matrix.shape[0] + return {CNOT(): ceil(n**2 / log2(n))} + + +@attrs.frozen +class GF2Multiplication(Bloq): + r"""Out of place multiplication over GF($2^m$). + + The bloq implements out of place multiplication of two quantum registers storing elements + from GF($2^m$) using construction described in Ref[1], which extends the classical construction + of Ref[2]. + + To multiply two m-bit inputs $a = [a_0, a_1, ..., a_{m-1}]$ and $b = [b_0, b_1, ..., b_{m-1}]$, + the construction computes the output vector $c$ via the following three steps: + 1. Compute $e = U.b$ where $U$ is an upper triangular matrix constructed using $a$. + 2. Compute $Q.e$ where $Q$ is an $m \times (m - 1)$ reduction matrix that depends upon the + irreducible polynomial $P(x)$ of the galois field $GF(2^m)$. The i'th column of the + matrix corresponds to coefficients of the polynomial $x^{m + i} % P(x)$. This matrix $Q$ + is a linear reversible circuit that can be implemented only using CNOT gates. + 3. Compute $d = L.b$ where $L$ is a lower triangular matrix constructed using $a$. + 4. Compute $c = d + Q.e$ to obtain the final product. + + Steps 1 and 3 are performed using $n^2$ Toffoli gates and step 2 is performed only using CNOT + gates. + + Args: + bitsize: The degree $m$ of the galois field $GF(2^m)$. Also corresponds to the number of + qubits in each of the two input registers $a$ and $b$ that should be multiplied. + + Registers: + x: Input THRU register of size $m$ that stores elements from $GF(2^m)$. + y: Input THRU register of size $m$ that stores elements from $GF(2^m)$. + result: Output RIGHT register of size $m$ that stores the product $x * y$ in $GF(2^m)$. + + + References: + [On the Design and Optimization of a Quantum Polynomial-Time Attack on + Elliptic Curve Cryptography](https://arxiv.org/abs/0710.1093) + + [Low complexity bit parallel architectures for polynomial basis multiplication + over GF(2m)](https://ieeexplore.ieee.org/abstract/document/1306989) + """ + + bitsize: SymbolicInt + + @cached_property + def signature(self) -> 'Signature': + return Signature( + [ + Register('x', dtype=self.qgf), + Register('y', dtype=self.qgf), + Register('result', dtype=self.qgf, side=Side.RIGHT), + ] + ) + + @cached_property + def qgf(self) -> QGF: + return QGF(characteristic=2, degree=self.bitsize) + + @cached_property + def reduction_matrix_q(self) -> np.ndarray: + m = int(self.bitsize) + f = self.qgf.gf_type.irreducible_poly + M = np.zeros((m - 1, m)) + alpha = [1] + [0] * m + for i in range(m - 1): + # x ** (m + i) % f + coeffs = (Poly(alpha, GF(2)) % f).coeffs.tolist()[::-1] + coeffs = coeffs + [0] * (m - len(coeffs)) + M[i] = coeffs + alpha += [0] + return np.transpose(M) + + @cached_property + def synthesize_reduction_matrix_q(self) -> SynthesizeLRCircuit: + m = self.bitsize + return ( + SynthesizeLRCircuit(Shaped((m, m - 1))) + if is_symbolic(m) + else SynthesizeLRCircuit(self.reduction_matrix_q) + ) + + def build_composite_bloq( + self, bb: 'BloqBuilder', *, x: 'Soquet', y: 'Soquet' + ) -> Dict[str, 'Soquet']: + if is_symbolic(self.bitsize): + raise DecomposeTypeError(f"Cannot decompose symbolic {self}") + result = bb.allocate(dtype=self.qgf) + x, y, result = bb.split(x)[::-1], bb.split(y)[::-1], bb.split(result)[::-1] + m = int(self.bitsize) + # Step-1: Multiply Monomials. + for i in range(m): + for j in range(i + 1, m): + ctrl = np.array([x[m - j + i], y[j]]) + ctrl, result[i] = bb.add(Toffoli(), ctrl=ctrl, target=result[i]) + x[m - j + i], y[j] = ctrl[0], ctrl[1] + + # Step-2: Reduce polynomial + result = bb.add(self.synthesize_reduction_matrix_q, q=result) + + # Step-3: Multiply Monomials + for i in range(m): + for j in range(i + 1): + ctrl = np.array([x[j], y[i - j]]) + ctrl, result[i] = bb.add(Toffoli(), ctrl=ctrl, target=result[i]) + x[j], y[i - j] = ctrl[0], ctrl[1] + + # Done :) + x, y, result = ( + bb.join(x[::-1], dtype=self.qgf), + bb.join(y[::-1], dtype=self.qgf), + bb.join(result[::-1], dtype=self.qgf), + ) + return {'x': x, 'y': y, 'result': result} + + def build_call_graph( + self, ssa: 'SympySymbolAllocator' + ) -> Union['BloqCountDictT', Set['BloqCountT']]: + m = self.bitsize + return {Toffoli(): m**2, self.synthesize_reduction_matrix_q: 1} + + def on_classical_vals(self, *, x, y) -> Dict[str, 'ClassicalValT']: + assert isinstance(x, self.qgf.gf_type) and isinstance(y, self.qgf.gf_type) + return {'x': x, 'y': y, 'result': x * y} + + +@bloq_example +def _gf16_multiplication() -> GF2Multiplication: + gf16_multiplication = GF2Multiplication(4) + return gf16_multiplication + + +@bloq_example +def _gf2_multiplication_symbolic() -> GF2Multiplication: + import sympy + + m = sympy.Symbol('m') + gf2_multiplication_symbolic = GF2Multiplication(m) + return gf2_multiplication_symbolic + + +_GF2_MULTIPLICATION_DOC = BloqDocSpec( + bloq_cls=GF2Multiplication, examples=(_gf16_multiplication, _gf2_multiplication_symbolic) +) diff --git a/qualtran/bloqs/gf_arithmetic/gf2_multiplication_test.py b/qualtran/bloqs/gf_arithmetic/gf2_multiplication_test.py new file mode 100644 index 000000000..94eaba106 --- /dev/null +++ b/qualtran/bloqs/gf_arithmetic/gf2_multiplication_test.py @@ -0,0 +1,46 @@ +# Copyright 2024 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest +from galois import GF + +from qualtran.bloqs.gf_arithmetic.gf2_multiplication import ( + _gf2_multiplication_symbolic, + _gf16_multiplication, + GF2Multiplication, +) +from qualtran.testing import assert_consistent_classical_action + + +def test_gf16_multiplication(bloq_autotester): + bloq_autotester(_gf16_multiplication) + + +def test_gf2_multiplication_symbolic(bloq_autotester): + bloq_autotester(_gf2_multiplication_symbolic) + + +def test_gf2_multiplication_classical_sim_quick(): + m = 2 + bloq = GF2Multiplication(m) + GFM = GF(2**m) + assert_consistent_classical_action(bloq, x=GFM.elements, y=GFM.elements) + + +@pytest.mark.slow +@pytest.mark.parametrize('m', [3, 4, 5]) +def test_gf2_multiplication_classical_sim(m): + bloq = GF2Multiplication(m) + GFM = GF(2**m) + assert_consistent_classical_action(bloq, x=GFM.elements, y=GFM.elements) diff --git a/qualtran/conftest.py b/qualtran/conftest.py index 988cc06fc..f1bee79a2 100644 --- a/qualtran/conftest.py +++ b/qualtran/conftest.py @@ -90,6 +90,8 @@ def assert_bloq_example_serializes_for_pytest(bloq_ex: BloqExample): 'qubitization_qpe_sparse_chem', # too slow 'trott_unitary', 'symbolic_hamsim_by_gqsp', + 'gf16_multiplication', # cannot serialize QGF + 'gf2_multiplication_symbolic', # cannot serialize QGF 'gqsp_1d_ising', 'auto_partition', 'unitary_block_encoding', diff --git a/qualtran/testing.py b/qualtran/testing.py index 31080e993..fbb268c69 100644 --- a/qualtran/testing.py +++ b/qualtran/testing.py @@ -20,6 +20,7 @@ import numpy as np import sympy +from numpy.typing import NDArray from qualtran import ( Bloq, @@ -692,7 +693,9 @@ def check_bloq_example_qtyping(bloq_ex: BloqExample) -> Tuple[BloqCheckResult, s return BloqCheckResult.PASS, '' -def assert_consistent_classical_action(bloq: Bloq, **parameter_ranges: Sequence[int]): +def assert_consistent_classical_action( + bloq: Bloq, **parameter_ranges: Union[NDArray, Sequence[int]] +): """Check that the bloq has a classical action consistent with its decomposition. Args: