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

64 bit signed arithmetic support #57

Merged
merged 13 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
12 changes: 8 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v4.6.0
hooks:
- id: trailing-whitespace
exclude: ^docs/reference/_autosummary/
Expand All @@ -15,19 +15,23 @@ repos:
- id: debug-statements

- repo: https://github.com/crate-ci/typos
rev: v1.19.0
rev: v1.20.10
hooks:
- id: typos
args: []
exclude: |
(?x)^(
python/pecos/simulators/cuquantum_old/.*|
)$

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.3
rev: v0.4.1
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]

- repo: https://github.com/psf/black
rev: 24.3.0
rev: 24.4.0
hooks:
- id: black
exclude: |
Expand Down
2 changes: 2 additions & 0 deletions .typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ ba = "ba"
datas = "datas"
ket = "ket"
wqs = "wqs"
thr = "thr"
IY = "IY"
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ updatereqs: upgrade-pip ## Autogenerate requirements.txt
$(VENV_BIN)/pip-compile --extra=tests --no-annotate --no-emit-index-url --output-file=requirements.txt --strip-extras pyproject.toml

metadeps: upgrade-pip ## Install extra dependencies used to develop/build this package
$(VENV_BIN)/pip install -U build pip-tools pre-commit wheel pytest
$(VENV_BIN)/pip install -U build pip-tools pre-commit wheel pytest hypothesis

# Installation
# ------------
Expand Down
2 changes: 1 addition & 1 deletion docs/api_guide/quantum_circuits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ A ``tick`` keyword can be used to specify which tick the gate is discarded from.
Retrieving Information
----------------------

Next, how to retrieve information from a ``QuantumCircuit`` will be dicuss, for example, through attributes or for
Next, how to retrieve information from a ``QuantumCircuit`` will be discussed, for example, through attributes or for
loops.

Number of Ticks
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ visualization = [
"plotly~=5.9.0",
]
tests = [
"pytest>=5.0.0"
"pytest>=5.0.0",
"hypothesis"
]
all = [
"quantum-pecos[simulators]",
Expand Down
2 changes: 1 addition & 1 deletion python/pecos/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from pecos import circuit_converters, circuits, decoders, engines, error_models, misc, qeccs, simulators, tools
from pecos.circuits.quantum_circuit import QuantumCircuit
from pecos.engines import circuit_runners
from pecos.engines.cvm.binarray import BinArray
from pecos.engines.cvm.binarray2 import BinArray2 as BinArray
from pecos.engines.hybrid_engine_old import HybridEngine

__all__ = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,10 @@ def assign_int(self, cvar, val: int):
cval &= ~(1 << i)
cval |= (val & 1) << i

# mask off bits give the size of the register
cval &= (1 << size) - 1
if not isinstance(cval, (np.int64, np.int32)):
qciaran marked this conversation as resolved.
Show resolved Hide resolved
# mask off bits give the size of the register
# (doesn't work for negative integers)
cval &= (1 << size) - 1
self.cenv[cid] = cval

def handle_cops(self, op):
Expand Down
9 changes: 7 additions & 2 deletions python/pecos/engines/cvm/binarray2.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@


class BinArray2:
def __init__(self, size, value=0, dtype=np.int32) -> None:
"""As opposed to the original unsigned 32-bit BinArray, this class defaults to signed 64-bit type."""

def __init__(self, size, value=0, dtype=np.int64) -> None:
self.size = size
self.value = None
self.dtype = dtype
Expand All @@ -33,6 +35,8 @@ def __init__(self, size, value=0, dtype=np.int32) -> None:
def set(self, value):
if isinstance(value, self.dtype):
self.value = value
elif isinstance(value, BinArray2):
self.value = value.value
else:
if isinstance(value, str):
value = int(value, 2)
Expand All @@ -41,7 +45,8 @@ def set(self, value):

def new_val(self, value):
b = BinArray2(self.size, value, self.dtype)
b.clamp(self.size)
if self.dtype in (np.uint32, np.uint64):
qciaran marked this conversation as resolved.
Show resolved Hide resolved
b.clamp(self.size)
return b

def num_bits(self):
Expand Down
2 changes: 1 addition & 1 deletion python/pecos/engines/cvm/classical.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

from __future__ import annotations

from pecos.engines.cvm.binarray import BinArray
from pecos.engines.cvm.binarray2 import BinArray2 as BinArray


def set_output(state, circuit, output_spec, output):
Expand Down
2 changes: 1 addition & 1 deletion python/pecos/engines/cvm/wasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import pickle
from pathlib import Path

from pecos.engines.cvm.binarray import BinArray
from pecos.engines.cvm.binarray2 import BinArray2 as BinArray
from pecos.engines.cvm.sim_func import sim_exec
from pecos.engines.cvm.wasm_vms.pywasm import read_pywasm
from pecos.engines.cvm.wasm_vms.pywasm3 import read_pywasm3
Expand Down
3 changes: 2 additions & 1 deletion python/pecos/engines/hybrid_engine_old.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@

import numpy as np

from pecos.engines.cvm.classical import BinArray, eval_condition, eval_cop, set_output
from pecos.engines.cvm.binarray2 import BinArray2 as BinArray
from pecos.engines.cvm.classical import eval_condition, eval_cop, set_output
from pecos.engines.cvm.wasm import eval_cfunc, get_ccop
from pecos.error_models.fake_error_model import FakeErrorModel
from pecos.errors import NotSupportedGateError
Expand Down
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
# pip-compile --extra=tests --no-annotate --no-emit-index-url --output-file=requirements.txt --strip-extras pyproject.toml
#
annotated-types==0.6.0
attrs==23.2.0
contourpy==1.2.0
cycler==0.12.1
fonttools==4.50.0
hypothesis==6.100.1
iniconfig==2.0.0
kiwisolver==1.4.5
markdown-it-py==3.0.0
Expand All @@ -28,4 +30,5 @@ python-dateutil==2.9.0.post0
rich==13.7.1
scipy==1.12.0
six==1.16.0
sortedcontainers==2.4.0
typing-extensions==4.10.0
35 changes: 35 additions & 0 deletions tests/integration/test_phir_64_bit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from pecos.engines.hybrid_engine import HybridEngine


def bin2int(result: list[str]) -> int:
return int(result[0], base=2)


def test_setting_cvar():
phir = {
"format": "PHIR/JSON",
"version": "0.1.0",
"ops": [
{"data": "cvar_define", "data_type": "i32", "variable": "vi32", "size": 32},
{"data": "cvar_define", "data_type": "u32", "variable": "vu32", "size": 32},
{"data": "cvar_define", "data_type": "i64", "variable": "vi64", "size": 64},
{"data": "cvar_define", "data_type": "u64", "variable": "vu64", "size": 64},
{"data": "cvar_define", "data_type": "i32", "variable": "vi32neg", "size": 32},
{"data": "cvar_define", "data_type": "i64", "variable": "vi64neg", "size": 64},
{"cop": "=", "returns": ["vi32"], "args": [2**31 - 1]},
{"cop": "=", "returns": ["vu32"], "args": [2**32 - 1]},
{"cop": "=", "returns": ["vi64"], "args": [2**63 - 1]},
{"cop": "=", "returns": ["vu64"], "args": [2**64 - 1]},
{"cop": "=", "returns": ["vi32neg"], "args": [-(2**31)]},
{"cop": "=", "returns": ["vi64neg"], "args": [-(2**63)]},
],
}

results = HybridEngine(qsim="stabilizer").run(program=phir, shots=5)

assert bin2int(results["vi32"]) == 2**31 - 1
assert bin2int(results["vu32"]) == 2**32 - 1
assert bin2int(results["vi64"]) == 2**63 - 1
assert bin2int(results["vu64"]) == 2**64 - 1
assert bin2int(results["vi32neg"]) == -(2**31)
assert bin2int(results["vi64neg"]) == -(2**63)
106 changes: 106 additions & 0 deletions tests/unit/test_binarray.py
qciaran marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from typing import Final

import numpy as np
from hypothesis import assume, given
from hypothesis import strategies as st
from pecos.engines.cvm.binarray2 import BinArray2 as BinArray

# from pecos.engines.cvm.binarray import BinArray
qartik marked this conversation as resolved.
Show resolved Hide resolved

DEFAULT_SIZE: Final = 63
MIN: Final = -(2**DEFAULT_SIZE)
MAX: Final = 2**DEFAULT_SIZE - 1
int_range = st.integers(min_value=MIN, max_value=MAX)


@given(st.text(alphabet=["0", "1"], min_size=1))
def test_init(x):
ba = BinArray(x)
assert ba == f"0b{x}"


def test_set_bit():
ba = BinArray("0000")
ba[2] = 1
assert ba == 0b0100


def test_get_bit():
ba = BinArray("1010")
assert ba[2] == 0
assert ba[3] == 1


def test_to_int():
ba = BinArray("1010")
assert int(ba) == 10


@given(int_range, int_range)
def test_addition(x, y):
assume(MIN <= x + y <= MAX)
ba1 = BinArray(DEFAULT_SIZE, x)
ba2 = BinArray(DEFAULT_SIZE, y)
result = ba1 + ba2
assert int(result) == x + y


def test_subtraction():
ba1 = BinArray("1101") # 13
ba2 = BinArray("1010") # 10
result = ba1 - ba2
assert int(result) == 3


@given(int_range, int_range)
def test_multiplication(x, y):
assume(MIN <= x * y <= MAX)
ba1 = BinArray(DEFAULT_SIZE, x)
ba2 = BinArray(DEFAULT_SIZE, y)
result = ba1 * ba2
assert int(result) == x * y


def test_comparison():
ba1 = BinArray("1010") # 10
ba2 = BinArray("1010") # 10
ba3 = BinArray("1101") # 13
assert ba1 == ba2
assert ba1 != ba3
assert ba1 != ba3
assert ba1 < ba3
assert ba3 > ba1


def test_bitwise_and():
ba1 = BinArray("1010") # 10
ba2 = BinArray("1101") # 13
result = ba1 & ba2
assert result == 0b1000


def test_bitwise_or():
ba1 = BinArray("1010") # 10
ba2 = BinArray("1101") # 13
result = ba1 | ba2
assert result == 0b1111


def test_bitwise_xor():
ba1 = BinArray("1010") # 10
ba2 = BinArray("1101") # 13
result = ba1 ^ ba2
assert result == 0b0111


def test_unsigned_bitwise_not():
ba = BinArray("1010", dtype=np.uint64) # 10
result = ~ba
assert result == 0b0101


@given(int_range)
def test_signed_bitwise_not(x):
ba = BinArray(DEFAULT_SIZE, x)
result = ~ba
assert int(result) == -x - 1 # (two's complement)
Loading