From b47eb50ec8575a950c0ae60db9d150dfb5d5469c Mon Sep 17 00:00:00 2001 From: Charles Ferenbaugh Date: Thu, 6 Aug 2026 15:38:39 -0600 Subject: [PATCH 1/6] Add unit tests for PauliStringLCU block encoding --- analysis/tests/test_pauli_string_lcu.py | 88 +++++++++++++++++++++++++ analysis/unitary.py | 13 ++-- 2 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 analysis/tests/test_pauli_string_lcu.py diff --git a/analysis/tests/test_pauli_string_lcu.py b/analysis/tests/test_pauli_string_lcu.py new file mode 100644 index 00000000..3796f40a --- /dev/null +++ b/analysis/tests/test_pauli_string_lcu.py @@ -0,0 +1,88 @@ +""" +Test construction of Pauli String LCU block encodings. +""" + +import numpy as np +import pytest + +from qhat.analysis.config_types import ( + GeneralConfiguration, + GeneralConfigurationUser, +) +from qhat.analysis.hamiltonian import ( + Hamiltonian, + LinearCombinationOfPauliStrings, +) +from qhat.analysis.unitary import PauliStringLCU + + +def test_pauli_string_lcu_simple(): + """Test converting a small, simple Hamiltonian to Pauli String LCU + block encoding.""" + # Create a simple 2-qubit Hamiltonian + pauli_data = { + 'XX': 1.0, + 'YZ': 1.0, + } + lcps = LinearCombinationOfPauliStrings(num_qubits=2, dense=pauli_data) + H = Hamiltonian(lcps) + + # Convert Hamiltonian to matrix + H_matrix = H.to_matrix(memory_threshold_gb=1.0) + + # Create unitary operator and convert to matrix + unitaryop = PauliStringLCU(H, 'AS', probability_eps=0.25) + unitarymx = unitaryop.tensor_contract() + + # Contract unitary tensor in the selection register + # (highest-order bit) + h = len(unitarymx) // 2 + unitarytc = 0.5 * ( + unitarymx[0:h,0:h] + unitarymx[0:h,h:] + + unitarymx[h:,0:h] + unitarymx[h:,h:] + ) + + # Verify that the upper corner of our unitary is equal to the + # original Hamiltonian matrix, scaled + np.testing.assert_array_almost_equal(unitarytc[0:4,0:4], 0.5 * H_matrix) + + +def test_pauli_string_lcu_harder(): + """Test converting a small, slightly more complex Hamiltonian to + Pauli String LCU block encoding.""" + # Create a more complex 2-qubit Hamiltonian + # Note: we are cheating slightly with this. After taking square + # roots and normalizing, the relative probabilities for the three + # terms should be (0.5, 0.5, sqrt(2)/2). But since our selection + # register has only two-bit precision, these probabilities will get + # rounded to (0.25, 0.25, 0.5), which are proportional to the + # original coefficients. + pauli_data = { + 'II': 1.0, + 'XX': 1.0, + 'YZ': 2.0, + } + lcps = LinearCombinationOfPauliStrings(num_qubits=2, dense=pauli_data) + H = Hamiltonian(lcps) + + # Convert Hamiltonian to matrix + H_matrix = H.to_matrix(memory_threshold_gb=1.0) + + # Create unitary operator and convert to matrix + unitaryop = PauliStringLCU(H, 'AS', probability_eps=0.25) + unitarymx = unitaryop.tensor_contract() + + # Contract unitary tensor in the selection register + # (highest-order 2 bits) + q = len(unitarymx) // 4 + unitarytc = np.array(q * [q * [0.+0.j]]) + for r in range(4): + for c in range(4): + unitarytc[:,:] += unitarymx[r*q:(r+1)*q,c*q:(c+1)*q] + unitarytc = 0.25 * unitarytc + + # Verify that the upper corner of our unitary is equal to the + # original Hamiltonian matrix, scaled + np.testing.assert_array_almost_equal(unitarytc[0:4,0:4], 0.25 * H_matrix) + + diff --git a/analysis/unitary.py b/analysis/unitary.py index 9b132862..2a492ebf 100644 --- a/analysis/unitary.py +++ b/analysis/unitary.py @@ -36,10 +36,9 @@ def __init__(self, hamiltonian, prepare_type=None, probability_eps=0.002, **kwar n_tot = 2**(int(np.ceil(np.log2(n_terms)))) n_pad = n_tot - n_terms - alphas = [np.sqrt(np.abs(t.coefficient)) for t in pauli_terms] - alpha = np.sum([a**2 for a in alphas]) - alphas_scaled = [a/np.sqrt(alpha) for a in alphas] - alphas_scaled.extend([0.0 for i in range(n_pad)]) + weights = [np.sqrt(np.abs(t.coefficient)) for t in pauli_terms] + weights.extend([0.0 for _ in range(n_pad)]) + alpha = np.sum([np.abs(t.coefficient) for t in pauli_terms]) selection_bitsize = int(np.ceil(np.log2(n_tot))) @@ -54,7 +53,7 @@ def __init__(self, hamiltonian, prepare_type=None, probability_eps=0.002, **kwar # see https://github.com/quantumlib/Qualtran/issues/1045 #prepare = StatePreparationViaRotations( # phase_bitsize = 4, - # state_coefficients = alphas_scaled, + # state_coefficients = weights, # ) raise NotImplementedError("PauliStringLCU") @@ -68,9 +67,7 @@ def __init__(self, hamiltonian, prepare_type=None, probability_eps=0.002, **kwar break prepare = StatePreparationAliasSampling.from_lcu_probs( - lcu_probabilities=[ - np.abs(np.real(t.coefficient)) for t in pauli_terms - ], + lcu_probabilities=weights, probability_epsilon=probability_eps, ) From 6458f01cfeec16d76005eefa0f6c2b1a803983fd Mon Sep 17 00:00:00 2001 From: Charles Ferenbaugh Date: Mon, 10 Aug 2026 16:47:25 -0600 Subject: [PATCH 2/6] Backport Qualtran LCUBlockEncoding fix from v0.5.0 --- analysis/tests/test_pauli_string_lcu.py | 22 +++------------------- analysis/unitary.py | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/analysis/tests/test_pauli_string_lcu.py b/analysis/tests/test_pauli_string_lcu.py index 3796f40a..e445b260 100644 --- a/analysis/tests/test_pauli_string_lcu.py +++ b/analysis/tests/test_pauli_string_lcu.py @@ -34,20 +34,13 @@ def test_pauli_string_lcu_simple(): unitaryop = PauliStringLCU(H, 'AS', probability_eps=0.25) unitarymx = unitaryop.tensor_contract() - # Contract unitary tensor in the selection register - # (highest-order bit) - h = len(unitarymx) // 2 - unitarytc = 0.5 * ( - unitarymx[0:h,0:h] + unitarymx[0:h,h:] + - unitarymx[h:,0:h] + unitarymx[h:,h:] - ) - # Verify that the upper corner of our unitary is equal to the # original Hamiltonian matrix, scaled - np.testing.assert_array_almost_equal(unitarytc[0:4,0:4], 0.5 * H_matrix) + np.testing.assert_array_almost_equal(unitarymx[0:4,0:4], 0.5 * H_matrix) def test_pauli_string_lcu_harder(): +#def dummy(): """Test converting a small, slightly more complex Hamiltonian to Pauli String LCU block encoding.""" # Create a more complex 2-qubit Hamiltonian @@ -72,17 +65,8 @@ def test_pauli_string_lcu_harder(): unitaryop = PauliStringLCU(H, 'AS', probability_eps=0.25) unitarymx = unitaryop.tensor_contract() - # Contract unitary tensor in the selection register - # (highest-order 2 bits) - q = len(unitarymx) // 4 - unitarytc = np.array(q * [q * [0.+0.j]]) - for r in range(4): - for c in range(4): - unitarytc[:,:] += unitarymx[r*q:(r+1)*q,c*q:(c+1)*q] - unitarytc = 0.25 * unitarytc - # Verify that the upper corner of our unitary is equal to the # original Hamiltonian matrix, scaled - np.testing.assert_array_almost_equal(unitarytc[0:4,0:4], 0.25 * H_matrix) + np.testing.assert_array_almost_equal(unitarymx[0:4,0:4], 0.25 * H_matrix) diff --git a/analysis/unitary.py b/analysis/unitary.py index 2a492ebf..cce78e20 100644 --- a/analysis/unitary.py +++ b/analysis/unitary.py @@ -1,8 +1,14 @@ import logging import math +from typing import Dict import cirq import numpy as np +from qualtran import ( + Bloq, + BloqBuilder, + SoquetT, +) from qualtran.bloqs.block_encoding import LCUBlockEncoding from qualtran.bloqs.multiplexers.select_pauli_lcu import SelectPauliLCU from qualtran.bloqs.state_preparation import StatePreparationAliasSampling @@ -85,6 +91,16 @@ def _select_gate(self): def _prepare_gate(self): return self.prepare + # Backport corrected LCUBlockEncoding method from v0.5.0 + def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: SoquetT) -> Dict[str, 'SoquetT']: + def _extract_soqs(bloq: Bloq) -> Dict[str, 'SoquetT']: + return {reg.name: soqs.pop(reg.name) for reg in bloq.signature.lefts()} + + soqs |= bb.add_d(self.prepare, **_extract_soqs(self.prepare)) + soqs |= bb.add_d(self.select, **_extract_soqs(self.select)) + soqs |= bb.add_d(self.prepare.adjoint(), **_extract_soqs(self.prepare.adjoint())) + return soqs + # ------------------------------------------------------------------------------------------------- def encode_linear_t( From c70ee8434b33c06c884e5076820de262b9c50822 Mon Sep 17 00:00:00 2001 From: Charles Ferenbaugh Date: Mon, 10 Aug 2026 17:03:52 -0600 Subject: [PATCH 3/6] Reduce size of unit test matrices --- analysis/tests/test_pauli_string_lcu.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/analysis/tests/test_pauli_string_lcu.py b/analysis/tests/test_pauli_string_lcu.py index e445b260..773604fa 100644 --- a/analysis/tests/test_pauli_string_lcu.py +++ b/analysis/tests/test_pauli_string_lcu.py @@ -31,7 +31,7 @@ def test_pauli_string_lcu_simple(): H_matrix = H.to_matrix(memory_threshold_gb=1.0) # Create unitary operator and convert to matrix - unitaryop = PauliStringLCU(H, 'AS', probability_eps=0.25) + unitaryop = PauliStringLCU(H, 'AS', probability_eps=0.5) unitarymx = unitaryop.tensor_contract() # Verify that the upper corner of our unitary is equal to the @@ -40,7 +40,6 @@ def test_pauli_string_lcu_simple(): def test_pauli_string_lcu_harder(): -#def dummy(): """Test converting a small, slightly more complex Hamiltonian to Pauli String LCU block encoding.""" # Create a more complex 2-qubit Hamiltonian @@ -62,7 +61,7 @@ def test_pauli_string_lcu_harder(): H_matrix = H.to_matrix(memory_threshold_gb=1.0) # Create unitary operator and convert to matrix - unitaryop = PauliStringLCU(H, 'AS', probability_eps=0.25) + unitaryop = PauliStringLCU(H, 'AS', probability_eps=0.5) unitarymx = unitaryop.tensor_contract() # Verify that the upper corner of our unitary is equal to the From 1c66a9cee552c2b135285eaba1f61c30112ec5ff Mon Sep 17 00:00:00 2001 From: Charles Ferenbaugh Date: Tue, 11 Aug 2026 13:39:31 -0600 Subject: [PATCH 4/6] Simplify unit tests to make them computable by hand --- analysis/tests/test_pauli_string_lcu.py | 24 ++++++++---------------- analysis/unitary.py | 1 - 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/analysis/tests/test_pauli_string_lcu.py b/analysis/tests/test_pauli_string_lcu.py index 773604fa..0027fc84 100644 --- a/analysis/tests/test_pauli_string_lcu.py +++ b/analysis/tests/test_pauli_string_lcu.py @@ -15,16 +15,15 @@ ) from qhat.analysis.unitary import PauliStringLCU - def test_pauli_string_lcu_simple(): """Test converting a small, simple Hamiltonian to Pauli String LCU block encoding.""" - # Create a simple 2-qubit Hamiltonian + # Create a simple 1-qubit Hamiltonian pauli_data = { - 'XX': 1.0, - 'YZ': 1.0, + 'X': 1.0, + 'Z': 1.0, } - lcps = LinearCombinationOfPauliStrings(num_qubits=2, dense=pauli_data) + lcps = LinearCombinationOfPauliStrings(num_qubits=1, dense=pauli_data) H = Hamiltonian(lcps) # Convert Hamiltonian to matrix @@ -36,23 +35,16 @@ def test_pauli_string_lcu_simple(): # Verify that the upper corner of our unitary is equal to the # original Hamiltonian matrix, scaled - np.testing.assert_array_almost_equal(unitarymx[0:4,0:4], 0.5 * H_matrix) + np.testing.assert_array_almost_equal(unitarymx[0:2,0:2], 0.5 * H_matrix) def test_pauli_string_lcu_harder(): """Test converting a small, slightly more complex Hamiltonian to Pauli String LCU block encoding.""" - # Create a more complex 2-qubit Hamiltonian - # Note: we are cheating slightly with this. After taking square - # roots and normalizing, the relative probabilities for the three - # terms should be (0.5, 0.5, sqrt(2)/2). But since our selection - # register has only two-bit precision, these probabilities will get - # rounded to (0.25, 0.25, 0.5), which are proportional to the - # original coefficients. + # Create a simple 2-qubit Hamiltonian pauli_data = { - 'II': 1.0, 'XX': 1.0, - 'YZ': 2.0, + 'YZ': 1.0, } lcps = LinearCombinationOfPauliStrings(num_qubits=2, dense=pauli_data) H = Hamiltonian(lcps) @@ -66,6 +58,6 @@ def test_pauli_string_lcu_harder(): # Verify that the upper corner of our unitary is equal to the # original Hamiltonian matrix, scaled - np.testing.assert_array_almost_equal(unitarymx[0:4,0:4], 0.25 * H_matrix) + np.testing.assert_array_almost_equal(unitarymx[0:4,0:4], 0.5 * H_matrix) diff --git a/analysis/unitary.py b/analysis/unitary.py index cce78e20..129fd1fe 100644 --- a/analysis/unitary.py +++ b/analysis/unitary.py @@ -43,7 +43,6 @@ def __init__(self, hamiltonian, prepare_type=None, probability_eps=0.002, **kwar n_pad = n_tot - n_terms weights = [np.sqrt(np.abs(t.coefficient)) for t in pauli_terms] - weights.extend([0.0 for _ in range(n_pad)]) alpha = np.sum([np.abs(t.coefficient) for t in pauli_terms]) selection_bitsize = int(np.ceil(np.log2(n_tot))) From 8d274cb7cb217c9c62fa56a970cf2bc6ada70f6a Mon Sep 17 00:00:00 2001 From: Charles Ferenbaugh Date: Fri, 14 Aug 2026 13:47:28 -0600 Subject: [PATCH 5/6] Add unit tests for PyLIQTR PauliStringLCU encoding --- analysis/tests/test_pauli_string_lcu.py | 75 ++++++++++++++++++++++++- analysis/unitary.py | 13 ++++- 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/analysis/tests/test_pauli_string_lcu.py b/analysis/tests/test_pauli_string_lcu.py index 0027fc84..2d3d4f58 100644 --- a/analysis/tests/test_pauli_string_lcu.py +++ b/analysis/tests/test_pauli_string_lcu.py @@ -5,6 +5,8 @@ import numpy as np import pytest +from pyLIQTR.ProblemInstances.ProblemInstance import ProblemInstance + from qhat.analysis.config_types import ( GeneralConfiguration, GeneralConfigurationUser, @@ -13,9 +15,10 @@ Hamiltonian, LinearCombinationOfPauliStrings, ) -from qhat.analysis.unitary import PauliStringLCU +from qhat.analysis.unitary import PauliStringLCU, PyLIQTRPauliStringLCU + -def test_pauli_string_lcu_simple(): +def test_pauli_string_lcu1(): """Test converting a small, simple Hamiltonian to Pauli String LCU block encoding.""" # Create a simple 1-qubit Hamiltonian @@ -38,7 +41,7 @@ def test_pauli_string_lcu_simple(): np.testing.assert_array_almost_equal(unitarymx[0:2,0:2], 0.5 * H_matrix) -def test_pauli_string_lcu_harder(): +def test_pauli_string_lcu2(): """Test converting a small, slightly more complex Hamiltonian to Pauli String LCU block encoding.""" # Create a simple 2-qubit Hamiltonian @@ -61,3 +64,69 @@ def test_pauli_string_lcu_harder(): np.testing.assert_array_almost_equal(unitarymx[0:4,0:4], 0.5 * H_matrix) +# Define a wrapper class to make a QHAT PauliString Hamiltonian behave +# like a PyLIQTR ProblemInstance +class PauliStringInstance(Hamiltonian, ProblemInstance): + def __init__(self, hamiltonian): + super().__init__(hamiltonian) + + def __str__(self): + return str(self.get_all_pauli_strings(return_as='strings')) + + def n_terms(self, **kwargs): + return len(self.get_all_pauli_strings()) + + def n_qubits(self): + return self.num_qubits() + + def yield_PauliLCU_Info(self, do_pad=0, return_as='strings'): + for t in self.get_all_pauli_strings(return_as=return_as).items(): + yield t + + +def test_pauli_string_lcu_pyliqtr1(): + """Test converting a small, simple Hamiltonian to Pauli String LCU + block encoding.""" + # Create a simple 1-qubit Hamiltonian + pauli_data = { + 'X': 1.0, + 'Z': 1.0, + } + lcps = LinearCombinationOfPauliStrings(num_qubits=1, dense=pauli_data) + inst = PauliStringInstance(lcps) + + # Convert Hamiltonian to matrix + H_matrix = inst.to_matrix(memory_threshold_gb=1.0) + + # Create unitary operator and convert to matrix + unitaryop = PauliStringLCU(inst, 'AS', probability_eps=0.5) + unitarymx = unitaryop.tensor_contract() + + # Verify that the upper corner of our unitary is equal to the + # original Hamiltonian matrix, scaled + np.testing.assert_array_almost_equal(unitarymx[0:2,0:2], 0.5 * H_matrix) + + +def test_pauli_string_lcu_pyliqtr2(): + """Test converting a small, slightly more complex Hamiltonian to + Pauli String LCU block encoding.""" + # Create a simple 2-qubit Hamiltonian + pauli_data = { + 'XX': 1.0, + 'YZ': 1.0, + } + lcps = LinearCombinationOfPauliStrings(num_qubits=2, dense=pauli_data) + inst = PauliStringInstance(lcps) + + # Convert Hamiltonian to matrix + H_matrix = inst.to_matrix(memory_threshold_gb=1.0) + + # Create unitary operator and convert to matrix + unitaryop = PyLIQTRPauliStringLCU(inst, 'AS', probability_eps=0.5) + unitarymx = unitaryop.tensor_contract() + + # Verify that the upper corner of our unitary is equal to the + # original Hamiltonian matrix, scaled + np.testing.assert_array_almost_equal(unitarymx[0:4,0:4], 0.5 * H_matrix) + + diff --git a/analysis/unitary.py b/analysis/unitary.py index 129fd1fe..f64fd558 100644 --- a/analysis/unitary.py +++ b/analysis/unitary.py @@ -9,13 +9,14 @@ BloqBuilder, SoquetT, ) +from qualtran._infra.registers import Signature from qualtran.bloqs.block_encoding import LCUBlockEncoding from qualtran.bloqs.multiplexers.select_pauli_lcu import SelectPauliLCU from qualtran.bloqs.state_preparation import StatePreparationAliasSampling from pyLIQTR.BlockEncodings.DoubleFactorized import DoubleFactorized from pyLIQTR.BlockEncodings.LinearT import Fermionic_LinearT -from pyLIQTR.BlockEncodings.PauliStringLCU import PauliStringLCU as PyLIQTRPauliStringLCU +from pyLIQTR.BlockEncodings.PauliStringLCU import PauliStringLCU as PyLIQTRPauliStringLCU_orig from pyLIQTR.ProblemInstances.ChemicalHamiltonian import ChemicalHamiltonian from qhat.analysis.config_types import UnitaryConfiguration @@ -102,6 +103,16 @@ def _extract_soqs(bloq: Bloq) -> Dict[str, 'SoquetT']: # ------------------------------------------------------------------------------------------------- +# add bugfix: correct ordering of Signature registers +class PyLIQTRPauliStringLCU(PyLIQTRPauliStringLCU_orig): + @property + def signature(self): + return Signature( + [*self.control_registers, *self.selection_registers, + *self.junk_registers, *self.target_registers] ) + +# ------------------------------------------------------------------------------------------------- + def encode_linear_t( config_unitary: UnitaryConfiguration, hamiltonian): From 3b40617755e80b086773b7239da83a8372376174 Mon Sep 17 00:00:00 2001 From: Charles Ferenbaugh Date: Tue, 25 Aug 2026 13:37:49 -0600 Subject: [PATCH 6/6] Add changes per @johngolden review --- analysis/tests/test_pauli_string_lcu.py | 25 ++++++++++++++++++------- analysis/unitary.py | 12 ++---------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/analysis/tests/test_pauli_string_lcu.py b/analysis/tests/test_pauli_string_lcu.py index 2d3d4f58..6062e766 100644 --- a/analysis/tests/test_pauli_string_lcu.py +++ b/analysis/tests/test_pauli_string_lcu.py @@ -38,7 +38,9 @@ def test_pauli_string_lcu1(): # Verify that the upper corner of our unitary is equal to the # original Hamiltonian matrix, scaled - np.testing.assert_array_almost_equal(unitarymx[0:2,0:2], 0.5 * H_matrix) + alpha = np.sum([v for v in H.get_all_pauli_strings().values()]) + scale = 1. / alpha + np.testing.assert_array_almost_equal(unitarymx[0:2,0:2], scale * H_matrix) def test_pauli_string_lcu2(): @@ -48,6 +50,7 @@ def test_pauli_string_lcu2(): pauli_data = { 'XX': 1.0, 'YZ': 1.0, + 'ZY': 2.0, } lcps = LinearCombinationOfPauliStrings(num_qubits=2, dense=pauli_data) H = Hamiltonian(lcps) @@ -56,12 +59,14 @@ def test_pauli_string_lcu2(): H_matrix = H.to_matrix(memory_threshold_gb=1.0) # Create unitary operator and convert to matrix - unitaryop = PauliStringLCU(H, 'AS', probability_eps=0.5) + unitaryop = PauliStringLCU(H, 'AS', probability_eps=0.1) unitarymx = unitaryop.tensor_contract() # Verify that the upper corner of our unitary is equal to the # original Hamiltonian matrix, scaled - np.testing.assert_array_almost_equal(unitarymx[0:4,0:4], 0.5 * H_matrix) + alpha = np.sum([v for v in H.get_all_pauli_strings().values()]) + scale = 1. / alpha + np.testing.assert_array_almost_equal(unitarymx[0:4,0:4], scale * H_matrix) # Define a wrapper class to make a QHAT PauliString Hamiltonian behave @@ -79,6 +84,9 @@ def n_terms(self, **kwargs): def n_qubits(self): return self.num_qubits() + def get_alpha(self): + return np.sum([v for v in self.get_all_pauli_strings().values()]) + def yield_PauliLCU_Info(self, do_pad=0, return_as='strings'): for t in self.get_all_pauli_strings(return_as=return_as).items(): yield t @@ -99,12 +107,13 @@ def test_pauli_string_lcu_pyliqtr1(): H_matrix = inst.to_matrix(memory_threshold_gb=1.0) # Create unitary operator and convert to matrix - unitaryop = PauliStringLCU(inst, 'AS', probability_eps=0.5) + unitaryop = PyLIQTRPauliStringLCU(inst, 'AS', probability_eps=0.5) unitarymx = unitaryop.tensor_contract() # Verify that the upper corner of our unitary is equal to the # original Hamiltonian matrix, scaled - np.testing.assert_array_almost_equal(unitarymx[0:2,0:2], 0.5 * H_matrix) + scale = 1. / inst.get_alpha() + np.testing.assert_array_almost_equal(unitarymx[0:2,0:2], scale * H_matrix) def test_pauli_string_lcu_pyliqtr2(): @@ -114,6 +123,7 @@ def test_pauli_string_lcu_pyliqtr2(): pauli_data = { 'XX': 1.0, 'YZ': 1.0, + 'ZY': 2.0, } lcps = LinearCombinationOfPauliStrings(num_qubits=2, dense=pauli_data) inst = PauliStringInstance(lcps) @@ -122,11 +132,12 @@ def test_pauli_string_lcu_pyliqtr2(): H_matrix = inst.to_matrix(memory_threshold_gb=1.0) # Create unitary operator and convert to matrix - unitaryop = PyLIQTRPauliStringLCU(inst, 'AS', probability_eps=0.5) + unitaryop = PyLIQTRPauliStringLCU(inst, 'AS', probability_eps=0.1) unitarymx = unitaryop.tensor_contract() # Verify that the upper corner of our unitary is equal to the # original Hamiltonian matrix, scaled - np.testing.assert_array_almost_equal(unitarymx[0:4,0:4], 0.5 * H_matrix) + scale = 1. / inst.get_alpha() + np.testing.assert_array_almost_equal(unitarymx[0:4,0:4], scale * H_matrix) diff --git a/analysis/unitary.py b/analysis/unitary.py index f64fd558..817adfb0 100644 --- a/analysis/unitary.py +++ b/analysis/unitary.py @@ -43,8 +43,8 @@ def __init__(self, hamiltonian, prepare_type=None, probability_eps=0.002, **kwar n_tot = 2**(int(np.ceil(np.log2(n_terms)))) n_pad = n_tot - n_terms - weights = [np.sqrt(np.abs(t.coefficient)) for t in pauli_terms] - alpha = np.sum([np.abs(t.coefficient) for t in pauli_terms]) + weights = [np.abs(t.coefficient) for t in pauli_terms] + alpha = np.sum(weights) selection_bitsize = int(np.ceil(np.log2(n_tot))) @@ -64,14 +64,6 @@ def __init__(self, hamiltonian, prepare_type=None, probability_eps=0.002, **kwar raise NotImplementedError("PauliStringLCU") elif prepare_type=='AS': - for t in pauli_terms: - coeff = np.real(t.coefficient) - if coeff < 0: - logger.warning("Alias sampling preparation with negative coefficients is not " - "supported yet. Circuits and estimates will assume positive " - "coefficients.") - break - prepare = StatePreparationAliasSampling.from_lcu_probs( lcu_probabilities=weights, probability_epsilon=probability_eps,