diff --git a/qualtran/bloqs/chemistry/trotter/hubbard/interaction.py b/qualtran/bloqs/chemistry/trotter/hubbard/interaction.py index 9783ee833..5a1d23cd0 100644 --- a/qualtran/bloqs/chemistry/trotter/hubbard/interaction.py +++ b/qualtran/bloqs/chemistry/trotter/hubbard/interaction.py @@ -130,7 +130,7 @@ def _interaction() -> Interaction: @bloq_example def _interaction_hwp() -> InteractionHWP: length = 8 - angle = 0.5 + angle = 0.52728 hubb_u = 4.0 interaction_hwp = InteractionHWP(length, angle, hubb_u) return interaction_hwp diff --git a/qualtran/bloqs/chemistry/trotter/hubbard/interaction_test.py b/qualtran/bloqs/chemistry/trotter/hubbard/interaction_test.py index d41c4401f..deeccb2a5 100644 --- a/qualtran/bloqs/chemistry/trotter/hubbard/interaction_test.py +++ b/qualtran/bloqs/chemistry/trotter/hubbard/interaction_test.py @@ -11,29 +11,9 @@ # 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 attrs -from qualtran import Bloq -from qualtran.bloqs.basic_gates import Rz -from qualtran.bloqs.basic_gates.rotation import ZPowGate -from qualtran.bloqs.bookkeeping import ArbitraryClifford from qualtran.bloqs.chemistry.trotter.hubbard.interaction import _interaction, _interaction_hwp from qualtran.resource_counting import get_cost_value, QECGatesCost -from qualtran.resource_counting.generalizers import PHI - - -def catch_rotations(bloq) -> Bloq: - if isinstance(bloq, Rz): - if isinstance(bloq.angle, float) and abs(bloq.angle) < 1e-12: - return ArbitraryClifford(1) - else: - return attrs.evolve(bloq, angle=PHI) - if isinstance(bloq, ZPowGate): - if isinstance(bloq.exponent, float) and abs(bloq.exponent) < 1e-12: - return ArbitraryClifford(1) - else: - return attrs.evolve(bloq, exponent=PHI, global_shift=0) - return bloq def test_hopping_tile(bloq_autotester): @@ -46,7 +26,7 @@ def test_interaction_hwp(bloq_autotester): def test_interaction_hwp_bloq_counts(): bloq = _interaction_hwp() - costs = get_cost_value(bloq, QECGatesCost(), generalizer=catch_rotations) + costs = get_cost_value(bloq, QECGatesCost()) n_rot_par = bloq.length**2 // 2 assert costs.rotation == 2 * n_rot_par.bit_length() assert costs.total_t_count(ts_per_rotation=0) == 2 * 4 * (n_rot_par - n_rot_par.bit_count()) diff --git a/qualtran/bloqs/chemistry/trotter/hubbard/qpe_cost_optimization.ipynb b/qualtran/bloqs/chemistry/trotter/hubbard/qpe_cost_optimization.ipynb index ecd254510..ef5a26f31 100644 --- a/qualtran/bloqs/chemistry/trotter/hubbard/qpe_cost_optimization.ipynb +++ b/qualtran/bloqs/chemistry/trotter/hubbard/qpe_cost_optimization.ipynb @@ -112,32 +112,12 @@ "import sympy\n", "import attrs\n", "\n", - "from qualtran.bloqs.basic_gates.rotation import ZPowGate\n", - "from qualtran.resource_counting.generalizers import PHI\n", "from qualtran.cirq_interop.t_complexity_protocol import TComplexity\n", - "from qualtran import Bloq\n", - "from qualtran.bloqs.basic_gates import Rz\n", - "from qualtran.bloqs.bookkeeping import ArbitraryClifford\n", "from qualtran.resource_counting import get_cost_value, QECGatesCost\n", "\n", "\n", - "def catch_rotations(bloq) -> Bloq:\n", - " \"\"\"Generalizer to catch rotations.\"\"\"\n", - " if isinstance(bloq, Rz):\n", - " if isinstance(bloq.angle, float) and abs(bloq.angle) < 1e-12:\n", - " return ArbitraryClifford(1)\n", - " else:\n", - " return Rz(angle=PHI, eps=bloq.eps)\n", - " if isinstance(bloq, ZPowGate):\n", - " if isinstance(bloq.exponent, float) and abs(bloq.exponent) < 1e-12:\n", - " return ArbitraryClifford(1)\n", - " else:\n", - " return attrs.evolve(bloq, exponent=PHI, global_shift=0)\n", - " return bloq\n", - "\n", - "\n", "def t_and_rot_counts_from_bloq(bloq) -> Tuple[int, int]:\n", - " costs = get_cost_value(bloq, QECGatesCost(), generalizer=catch_rotations)\n", + " costs = get_cost_value(bloq, QECGatesCost())\n", " n_rot = costs.rotation\n", " n_t = costs.total_t_count(ts_per_rotation=0)\n", " return n_t, n_rot\n", @@ -289,6 +269,7 @@ "outputs": [], "source": [ "from qualtran.drawing import show_call_graph\n", + "from qualtran.resource_counting.generalizers import generalize_rotation_angle \n", "# get appropriate epsilon given our input parameters now we know the number of rotations\n", "eps_single_rot = get_single_rot_eps(n_rot, delta_ht, timestep)\n", "print(f\"Adjusted eps_single_rot: {eps_single_rot}\")\n", @@ -298,7 +279,7 @@ "# But let's show the call graph anyway to check the parameters all all what we expect.\n", "updated_eps_bloqs = tuple(attrs.evolve(b, eps=eps_single_rot) for b in trotter_step.bloqs)\n", "trotter_step = attrs.evolve(trotter_step, bloqs=updated_eps_bloqs)\n", - "trotter_step_g, _ = trotter_step.call_graph(generalizer=catch_rotations)\n", + "trotter_step_g, _ = trotter_step.call_graph(generalizer=generalize_rotation_angle)\n", "show_call_graph(trotter_step_g)" ] }, @@ -517,14 +498,18 @@ "metadata": {}, "outputs": [], "source": [ - "s_eps_r, s_length, s_hubb_u, s_timestep, s_tau = sympy.symbols(r'\\epsilon_{R}, L, u, t, \\tau')" + "s_eps_r, s_length, s_hubb_u, s_timestep, s_tau = sympy.symbols(r'\\epsilon_{R}, L, u, t, \\tau')\n", + "s_delta_ht, s_delta_ts, s_delta_pe, s_p, s_xi = sympy.symbols(\n", + " '\\Delta_{HT}, \\Delta_{TS}, \\Delta_{PE}, p, xi'\n", + ")\n", + "s_n_rot, s_n_t, s_n_pe = sympy.symbols('N_R, N_T, N_PE')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "First let's check the Bloq counts look correct for the Trotter step, there are two sources rotations from the interaction and hopping bloq and some direct T gates from the `TwoBitFFFT` gate." + "First let's check the Bloq counts look correct for the Trotter step, there are two sources: rotations from the interaction and hopping bloq, and some direct T gates from the `TwoBitFFFT` gate." ] }, { @@ -538,8 +523,8 @@ "s_trotter_step = build_plaq_unitary_second_order_suzuki(\n", " s_length, s_hubb_u, s_timestep, eps=s_eps_r, hubb_t=s_tau\n", ")\n", - "t_counts = t_counts_from_sigma(s_trotter_step.call_graph(generalizer=catch_rotations)[1])\n", - "t_counts" + "t_counts, n_rot = t_and_rot_counts_from_bloq(s_trotter_step)\n", + "t_counts + rotation_cost(n_rot, s_delta_ht, s_timestep)" ] }, { @@ -549,7 +534,7 @@ "outputs": [], "source": [ "# check the symbolic counts match the expected counts\n", - "t_counts_orig = t_counts_from_sigma(trotter_step.call_graph(generalizer=catch_rotations)[1])\n", + "t_counts_orig, n_rot = t_and_rot_counts_from_bloq(trotter_step)\n", "# for some reason substituting both at once leads to a precision error\n", "t_counts = t_counts.evalf(subs={s_eps_r: eps_single_rot})\n", "t_counts_symb = t_counts.evalf(subs={s_length: length})\n", @@ -569,10 +554,6 @@ "metadata": {}, "outputs": [], "source": [ - "s_delta_ht, s_delta_ts, s_delta_pe, s_p, s_xi = sympy.symbols(\n", - " '\\Delta_{HT}, \\Delta_{TS}, \\Delta_{PE}, p, xi'\n", - ")\n", - "s_n_rot, s_n_t, s_n_pe = sympy.symbols('N_R, N_T, N_PE')\n", "s_timestep = (s_delta_ts / s_xi) ** (1 / s_p)\n", "s_eps_r = (s_delta_ht * s_timestep) / s_n_rot\n", "s_n_pe = 0.76 * sympy.pi / (s_delta_pe * s_timestep)\n", @@ -581,8 +562,9 @@ ")\n", "# just use this cost in lieu of a QPE bloq\n", "# See: https://github.com/quantumlib/Qualtran/issues/932 this should be replaced by a real bloq.\n", - "t_counts = s_n_pe * t_counts_from_sigma(s_trotter_step.call_graph(generalizer=catch_rotations)[1])\n", - "t_counts" + "s_t_counts, s_n_rot = t_and_rot_counts_from_bloq(s_trotter_step)\n", + "qpe_cost_symb = s_n_pe * (s_t_counts + rotation_cost(s_n_rot, s_delta_ht, s_timestep))\n", + "qpe_cost_symb" ] }, { @@ -591,7 +573,7 @@ "metadata": {}, "outputs": [], "source": [ - "symb_t_count = t_counts.evalf(\n", + "symb_t_count = qpe_cost_symb.evalf(\n", " subs={\n", " s_length: length,\n", " s_delta_ht: delta_ht,\n", @@ -601,7 +583,7 @@ " s_n_rot: n_rot,\n", " }\n", ")\n", - "symb_t_count = symb_t_count.evalf(subs={s_p: prod_ord})\n", + "symb_t_count = symb_t_count.evalf(subs={s_p: prod_ord}, maxn=500)\n", "tot_t_count = qpe_t_count(delta_pe, delta_ts, delta_ht, n_rot, n_t, xi_bound, prod_ord)\n", "assert int(symb_t_count) == int(tot_t_count)" ] @@ -623,7 +605,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.9" + "version": "3.10.4" } }, "nbformat": 4, diff --git a/qualtran/bloqs/chemistry/trotter/hubbard/trotter_step_test.py b/qualtran/bloqs/chemistry/trotter/hubbard/trotter_step_test.py index 26f24f2cb..c69b7b196 100644 --- a/qualtran/bloqs/chemistry/trotter/hubbard/trotter_step_test.py +++ b/qualtran/bloqs/chemistry/trotter/hubbard/trotter_step_test.py @@ -13,7 +13,6 @@ # limitations under the License. import pytest -from qualtran.bloqs.chemistry.trotter.hubbard.interaction_test import catch_rotations from qualtran.bloqs.chemistry.trotter.hubbard.trotter_step import ( build_plaq_unitary_second_order_suzuki, ) @@ -24,10 +23,9 @@ def test_second_order_suzuki_costs(): length = 8 u = 4 - dt = 0.1 + dt = 0.1234 unitary = build_plaq_unitary_second_order_suzuki(length, u, dt) - # _, sigma = unitary.call_graph(generalizer=catch_rotations) - costs = get_cost_value(unitary, QECGatesCost(), generalizer=catch_rotations) + costs = get_cost_value(unitary, QECGatesCost()) # there are 3 hopping unitaries contributing 8 Ts from from the F gate assert costs.total_t_count(ts_per_rotation=0) == (3 * length**2 // 2) * 8 # 3 hopping unitaries and 2 interaction unitaries