Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Fxp classical simulation #859

Closed
wants to merge 48 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
8d31061
Ensure dtypes get used when joining typed registers.
fdmalone Mar 21, 2024
e97cff3
Fix tests.
fdmalone Mar 22, 2024
bd8027e
Update for black?
fdmalone Mar 22, 2024
b15ce91
Ensure dtypes get used when joining typed registers.
fdmalone Mar 21, 2024
a937349
Fix tests.
fdmalone Mar 22, 2024
dae08f0
Update for black?
fdmalone Mar 22, 2024
f3eed5e
Don't rely on soq reg.
fdmalone Mar 22, 2024
776ec28
WIP testing.
fdmalone Mar 22, 2024
60183cd
Add bloq autotesting + update report card.
fdmalone Mar 22, 2024
b4e28ea
Merge branch 'propagate_split_dtype_to_join' of github.com:fdmalone/Q…
fdmalone Mar 22, 2024
019812b
Fix interop.
fdmalone Mar 24, 2024
8b2b1b5
Better typed show_bloqs.
fdmalone Mar 24, 2024
08b514b
Fixes.
fdmalone Mar 25, 2024
f01af84
Fix lint errors.
fdmalone Mar 25, 2024
7b42be7
Merge branch 'main' into propagate_split_dtype_to_join
fdmalone Mar 25, 2024
b49171e
Fix formatting.
fdmalone Mar 25, 2024
5d1adec
Fix test failures.
fdmalone Mar 25, 2024
da2f1b7
Fix formatting.
fdmalone Mar 25, 2024
819f9df
Merge branch 'main' into propagate_split_dtype_to_join
fdmalone Mar 29, 2024
6d9ab70
Merge branch 'main' into propagate_split_dtype_to_join
fdmalone Apr 5, 2024
1080ea1
Clean cirq_bloq_interop typing.
fdmalone Apr 5, 2024
7d10c75
Remove prints.
fdmalone Apr 5, 2024
281dcf8
Safer casting.
fdmalone Apr 5, 2024
b620f4f
Safer checking.
fdmalone Apr 6, 2024
c52390b
Remove print.
fdmalone Apr 6, 2024
2de1b34
Format / lint.
fdmalone Apr 6, 2024
2c79572
Only cast Fxp.
fdmalone Apr 6, 2024
f78ce7a
Custom hash for _QReg for single-qubit lookup.
fdmalone Apr 8, 2024
31519a8
Address review comments.
fdmalone Apr 10, 2024
bbf40c3
Add assertion.
fdmalone Apr 10, 2024
a8cc8be
Move location of assert.
fdmalone Apr 10, 2024
5259aa9
Merge branch 'main' into propagate_split_dtype_to_join
fdmalone Apr 10, 2024
86d4429
Move assert back.
fdmalone Apr 10, 2024
5ba5cb7
Merge branch 'propagate_split_dtype_to_join' of github.com:fdmalone/Q…
fdmalone Apr 10, 2024
35b0f83
Update ClassicalValT.
fdmalone Apr 10, 2024
36e3b45
Update split / join classical sim.
fdmalone Apr 10, 2024
b5daf2e
Fix casting bug in _cirq_to_bloq.py
fdmalone Apr 10, 2024
0cc0cfd
Use correct type for z_basis.
fdmalone Apr 10, 2024
9c5a341
Add classical sim for multiplication.
fdmalone Apr 10, 2024
f676f9d
Use multiplication bloqs in error analysis notebook.
fdmalone Apr 10, 2024
48124cd
Add fxp utility function.
fdmalone Apr 10, 2024
3765da5
Add fxp utility function.
fdmalone Apr 10, 2024
419411e
Add phase gradient notebook.
fdmalone Apr 10, 2024
ccefa53
Classical sim for phase gradient.
fdmalone Apr 10, 2024
3589c11
Fix lint / format.
fdmalone Apr 10, 2024
984d58e
Merge branch 'main' into typed_classical_sim
fdmalone Apr 10, 2024
388fbec
Fix indentation for test.
fdmalone Apr 10, 2024
6d5df7a
Revert int / np.uint.
fdmalone Apr 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions dev_tools/autogenerate-bloqs-notebooks-v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
import qualtran.bloqs.qsp.generalized_qsp
import qualtran.bloqs.qubitization_walk_operator
import qualtran.bloqs.reflection
import qualtran.bloqs.rotations.phase_gradient
import qualtran.bloqs.rotations.phasing_via_cost_function
import qualtran.bloqs.rotations.quantum_variable_rotation
import qualtran.bloqs.state_preparation.prepare_uniform_superposition
Expand Down Expand Up @@ -374,6 +375,12 @@
bloq_specs=[qualtran.bloqs.rotations.phasing_via_cost_function._PHASING_VIA_COST_FUNCTION],
directory=f'{SOURCE_DIR}/bloqs/rotations/',
),
NotebookSpecV2(
title='Phase Gradient',
module=qualtran.bloqs.rotations.phase_gradient,
bloq_specs=[qualtran.bloqs.rotations.phase_gradient._ADD_INTO_PHASE_GRAD_DOC],
directory=f'{SOURCE_DIR}/bloqs/rotations/',
),
# --------------------------------------------------------------------------
# ----- QFT -----------------------------------------------------
# --------------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions docs/bloqs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ Bloqs Library
basic_gates/su2_rotation.ipynb
rotations/quantum_variable_rotation.ipynb
rotations/phasing_via_cost_function.ipynb
rotations/phase_gradient.ipynb
qft/two_bit_ffft.ipynb
qft/approximate_qft.ipynb
phase_estimation/lp_resource_state.ipynb
Expand Down
1 change: 1 addition & 0 deletions qualtran/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
QUInt,
BoundedQUInt,
QMontgomeryUInt,
val_to_fxp,
)

# Internal imports: none
Expand Down
47 changes: 47 additions & 0 deletions qualtran/_infra/data_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,34 @@ def __str__(self):
return f'{self.__class__.__name__}({self.bitsize}, {self.iteration_length})'


def val_to_fxp(
val: Union[int, float, Fxp],
num_bits: int,
num_frac: int,
op_sizing: str = 'same',
overflow: str = 'saturate',
const_op_sizing: str = 'same',
shifting='trunc',
signed=False,
) -> Fxp:
"""Create a fxp value from a python float or int. If passed Fxp is passed do nothing."""
if isinstance(val, (int, np.int64, float)):
_val = bin(abs(val)) if isinstance(val, int) else val
# Dtype Format: f'fxp-{signed/unsigned}{total_bitsize}/{frac_bitsize}'
fxp_dtype_str = f'fxp-u{num_bits}/{num_frac}'
return Fxp(
_val,
dtype=fxp_dtype_str,
op_sizing=op_sizing,
shifting=shifting,
const_op_sizing=const_op_sizing,
# op_input_size='best',
overflow=overflow, # values are wrappen into the range of the qdtype
signed=signed,
)
return val


@attrs.frozen
class QFxp(QDType):
r"""Fixed point type to represent real numbers.
Expand Down Expand Up @@ -464,6 +492,25 @@ def __attrs_post_init__(self):
if self.bitsize < self.num_frac:
raise ValueError("bitsize must be >= num_frac.")

def to_fxp(
self,
val: Union[int, float, Fxp],
op_sizing: str = 'same',
overflow: str = 'saturate',
const_op_sizing: str = 'same',
shifting='trunc',
) -> Fxp:
return val_to_fxp(
val,
num_bits=self.bitsize,
num_frac=self.num_frac,
op_sizing=op_sizing,
overflow=overflow,
const_op_sizing=const_op_sizing,
shifting=shifting,
signed=self.signed,
)

def get_classical_domain(self) -> Iterable[Fxp]:
qint = QIntOnesComp(self.bitsize) if self.signed else QUInt(self.bitsize)
for x in qint.get_classical_domain():
Expand Down
75 changes: 15 additions & 60 deletions qualtran/bloqs/arithmetic/error_analysis_for_fxp_arithmetic.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,6 @@
"from fxpmath import Fxp\n",
"import numpy as np\n",
"\n",
"# Initial setup - Helpers\n",
"def fxp(x: float, d: int, *, d_word: Optional[int]=None) -> Fxp:\n",
" \"\"\"Creates an unsigned fixed-point representation of `x` with `d` bits of precision after decimal.\"\"\"\n",
" assert 0 <= x < 1\n",
" d_word = d if d_word is None else d_word\n",
" # Dtype Format: f'fxp-{signed/unsigned}{total_bitsize}/{frac_bitsize}'\n",
" dtype = f'fxp-u{d_word}/{d}'\n",
"\n",
" # `op_sizing` and `const_op_sizing` controls the behavior of fixed point type when performing \n",
" # arithmetic with other fixed point types. Setting the value to `same` ensures that no addition\n",
" # bits are used during arithmetic. \n",
" # shifting='trunc' sets the behavior of fixed point type to truncate shifted bits when doing a\n",
" # bitwise left/right shift operation.\n",
" return Fxp(x, dtype=dtype, op_sizing='same', const_op_sizing='same', shifting='trunc')\n",
"\n",
"def assert_allclose(x: Fxp, y: float, eps: float):\n",
" np.testing.assert_allclose(x.get_val(), y, atol=eps)"
]
Expand Down Expand Up @@ -65,28 +50,20 @@
"metadata": {},
"outputs": [],
"source": [
"from qualtran import val_to_fxp\n",
"from qualtran.bloqs.arithmetic.multiplication import ScaleIntByReal\n",
"# Multiplying a real numbers with an d_B-bit integer.\n",
"def get_bitsize_for_fxp_mul_with_integer(eps: float, d_B: int):\n",
" return d_B + int(np.ceil(np.log2(d_B / eps))) # Equation D7\n",
"\n",
"def mul_with_int_via_repeated_add(a: float, b: int, d_A: int, d_B: int):\n",
" \"\"\"Multiplicaiton via repeated additions algorithm described in Appendix D5\"\"\"\n",
" a_fxp = fxp(a, d=d_A, d_word=d_A+d_B-1) # The paper proposes to use `d_A-1` bits of `a` but we instead need to use `d_A` bits.\n",
" res = fxp(0, d=d_A-d_B, d_word=d_A)\n",
" for i in range(d_B):\n",
" b_i = (b >> i) & 1\n",
" a_i = (a_fxp << i).like(res)\n",
" res += a_i * b_i\n",
" return res\n",
"\n",
"def test_multiplication_with_integer_for_eps(eps: float, d_B: int, d_A: int):\n",
" rng = np.random.default_rng(int(eps * d_B * 1e9))\n",
" try:\n",
" for _ in range(100):\n",
" a, = rng.random(1)\n",
" b = rng.integers(0, 1 << d_B)\n",
" res = mul_with_int_via_repeated_add(a, b, d_A, d_B)\n",
" assert_allclose(res, a * b, eps)\n",
" res = ScaleIntByReal(r_bitsize=d_A, i_bitsize=d_B).on_classical_vals(**{'real_in': a, 'int_in': b})\n",
" assert_allclose(res['result'], a * b, eps)\n",
" print(f'Success! {eps=}, {d_A=}, {d_B=}')\n",
" except AssertionError:\n",
" print(f'Failed! {eps=}, {d_A=}, {d_B=}')\n",
Expand Down Expand Up @@ -121,26 +98,19 @@
"outputs": [],
"source": [
"# Multiplying two real numbers\n",
"from qualtran.bloqs.arithmetic.multiplication import MultiplyTwoReals\n",
"\n",
"\n",
"def get_bitsize_for_fxp_mul(eps: float):\n",
" return int(np.ceil(1 + np.log2(1/eps)) + np.log2(1 + np.log2(1/eps))) # Equation D17\n",
"\n",
"def mul_via_repeated_add(a: float, b: float, d: int):\n",
" \"\"\"Multiplicaiton via repeated additions algorithm described in Appendix D5\"\"\"\n",
" a_fxp, b_fxp = fxp(a, d=d), fxp(b, d=d)\n",
" res = fxp(0, d=d)\n",
" for i, b_bin in enumerate(b_fxp.bin()[:-1]):\n",
" a_fxp >>= 1\n",
" if int(b_bin):\n",
" res += a_fxp\n",
" return res\n",
"\n",
"def test_multiplication_for_eps(eps: float, d: int):\n",
" rng = np.random.default_rng(int(eps * 1e9))\n",
" try:\n",
" for _ in range(100):\n",
" a, b = rng.random(2)\n",
" res = mul_via_repeated_add(a, b, d)\n",
" assert_allclose(res, a * b, eps)\n",
" res = MultiplyTwoReals(bitsize=d).on_classical_vals(**{'a': a, 'b': b})\n",
" assert_allclose(res['result'], a * b, eps)\n",
" print(f'Success! {d=}, {eps=}')\n",
" except AssertionError:\n",
" print(f'Failed! {d=}, {eps=}')\n",
Expand Down Expand Up @@ -174,34 +144,19 @@
"outputs": [],
"source": [
"# Squaring a real number\n",
"from qualtran.bloqs.arithmetic.multiplication import SquareRealNumber\n",
"\n",
"\n",
"def get_bitsize_for_fxp_square(eps: float):\n",
" return int(np.ceil(np.log2(1/eps) + np.log2(11/3 + np.log2(1/eps)))) # Equation D36\n",
"\n",
"def square_via_repeated_add(a: float, d: int):\n",
" a = fxp(a, d)\n",
" res = fxp(0, d=d)\n",
" a_bin = [int(x) for x in a.bin()]\n",
" one = fxp(0.5, d=d)\n",
" \n",
" # Equation D23 & D29\n",
" for n in range(d//2, d-1):\n",
" res += (a >> n) * a_bin[n]\n",
" mask = fxp(0, d=d)\n",
" for n in range((d - 1) // 2):\n",
" res += (((a & mask) >> n) + ((one >> (2*n+1)) * a_bin[n])) * a_bin[n]\n",
" mask |= (one >> n)\n",
" if not d & 1: # Equation D29\n",
" n = d // 2 - 1\n",
" res += ((a & mask) >> n) * a_bin[n]\n",
" return res\n",
"\n",
"def test_square_for_eps(eps: float, d: int):\n",
" rng = np.random.default_rng(int(eps * 1e9))\n",
" try:\n",
" for _ in range(100):\n",
" a, = rng.random(1)\n",
" res = square_via_repeated_add(a, d)\n",
" assert_allclose(res, a**2, eps)\n",
" res = SquareRealNumber(bitsize=d).on_classical_vals(a=a)\n",
" assert_allclose(res['result'], a**2, eps)\n",
" print(f'Success! {d=}, {eps=}')\n",
" except AssertionError:\n",
" print(f'Failed! {d=}, {eps=}')\n",
Expand Down Expand Up @@ -229,7 +184,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.4"
"version": "3.11.7"
}
},
"nbformat": 4,
Expand Down
23 changes: 14 additions & 9 deletions qualtran/bloqs/arithmetic/multiplication.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@
"\n",
"#### Parameters\n",
" - `a_bitsize`: Number of bits used to represent the first integer.\n",
" - `b_bitsize`: Number of bits used to represent the second integer. \n",
" - `b_bitsize`: Number of bits used to represent the second integer.\n",
" - `uncompute`: Whether to uncompute the result or not. \n",
"\n",
"#### Registers\n",
" - `a`: a_bitsize-sized input register.\n",
Expand Down Expand Up @@ -231,7 +232,8 @@
"Implements $U|a\\rangle|0\\rangle \\rightarrow |a\\rangle|a^2\\rangle$ using $n^2 - n$ Toffolis.\n",
"\n",
"#### Parameters\n",
" - `bitsize`: Number of bits used to represent the integer to be squared. The result is stored in a register of size 2*bitsize. \n",
" - `bitsize`: Number of bits used to represent the integer to be squared. The result is stored in a register of size 2*bitsize.\n",
" - `uncompute`: Whether to uncompute the result or not. \n",
"\n",
"#### Registers\n",
" - `a`: A bitsize-sized input register (register a above).\n",
Expand Down Expand Up @@ -342,14 +344,15 @@
"\n",
"#### Parameters\n",
" - `bitsize`: Number of bits used to represent each of the k integers.\n",
" - `k`: The number of integers we want to square. \n",
" - `k`: The number of integers we want to square.\n",
" - `uncompute`: Whether to uncompute the result or not. \n",
"\n",
"#### Registers\n",
" - `input`: k n-bit registers.\n",
" - `result`: 2 * bitsize + ceil(log2(k)) sized output register. \n",
"\n",
"#### References\n",
" - [Fault-Tolerant Quantum Simulations of Chemistry in First Quantization](https://arxiv.org/abs/2105.12767). pg 80 gives a Toffoli complexity for squaring.\n"
" - [Fault-Tolerant Quantum Simulations of Chemistry in First Quantization](https://arxiv.org/abs/2105.12767). pg 80 gives a Toffoli complexity for computing the sum of squares.\n"
]
},
{
Expand Down Expand Up @@ -455,7 +458,8 @@
"\n",
"#### Parameters\n",
" - `r_bitsize`: Number of bits used to represent the real number.\n",
" - `i_bitsize`: Number of bits used to represent the integer. \n",
" - `i_bitsize`: Number of bits used to represent the integer.\n",
" - `uncompute`: Whether to uncompute the result or not. \n",
"\n",
"#### Registers\n",
" - `real_in`: r_bitsize-sized input fixed-point register.\n",
Expand Down Expand Up @@ -568,7 +572,8 @@
"The real numbers are assumed to be in the range [0, 1).\n",
"\n",
"#### Parameters\n",
" - `bitsize`: Number of bits used to represent the real number. \n",
" - `bitsize`: Number of bits used to represent the real number.\n",
" - `uncompute`: Whether to uncompute the result or not. \n",
"\n",
"#### Registers\n",
" - `a`: bitsize-sized input register.\n",
Expand Down Expand Up @@ -678,14 +683,14 @@
" |a\\rangle|0\\rangle \\rightarrow |a\\rangle|a^2\\rangle\n",
"$$\n",
"\n",
"The real numbers are assumed to be in the range [0, 1).\n",
"The real number is assumed to be in the range [0, 1).\n",
"\n",
"#### Parameters\n",
" - `bitsize`: Number of bits used to represent the real number. \n",
" - `bitsize`: Number of bits used to represent the real number.\n",
" - `uncompute`: Whether to uncompute the result or not. \n",
"\n",
"#### Registers\n",
" - `a`: bitsize-sized input register.\n",
" - `b`: bitsize-sized input register.\n",
" - `result`: bitsize output register \n",
"\n",
"#### References\n",
Expand Down
Loading
Loading