Skip to content

Commit

Permalink
Merge branch 'develop' into feature/persistent-token-storage
Browse files Browse the repository at this point in the history
  • Loading branch information
yao-cqc committed Oct 18, 2023
2 parents bbf9755 + 673a020 commit 8e37b0b
Show file tree
Hide file tree
Showing 22 changed files with 707 additions and 14 deletions.
2 changes: 1 addition & 1 deletion _metadata.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__extension_version__ = "0.23.0"
__extension_version__ = "0.25.0"
__extension_name__ = "pytket-quantinuum"
15 changes: 13 additions & 2 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,22 @@ Changelog
Unreleased
----------

* Don't include ``SimplifyInitial`` in default passes; instead make it an option
to ``process_circuits()``.
* Add ``QuantinuumConfigCredentialStorage`` for caching API tokens in local pytket
configuration file.

0.25.0 (October 2023)
---------------------

* Updated pytket version requirement to 1.21.

0.24.0 (October 2023)
---------------------

* Don't include ``SimplifyInitial`` in default passes; instead make it an option
to ``process_circuits()``.
* Fix: set default two-qubit gate when compilation config is provided without
specifying one.

0.23.0 (September 2023)
-----------------------

Expand Down
2 changes: 1 addition & 1 deletion docs/intro.txt
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,12 @@ The passes applied by different levels of optimisation are specified in the tabl
- `auto_squash_pass [4] <https://cqcl.github.io/tket/pytket/api/passes.html#pytket.passes.auto_rebase.auto_squash_pass>`_
* -
- `auto_squash_pass [4] <https://cqcl.github.io/tket/pytket/api/passes.html#pytket.passes.auto_rebase.auto_squash_pass>`_
* -
- `FlattenRelabelRegistersPass <https://cqcl.github.io/tket/pytket/api/passes.html#pytket.passes.FlattenRelabelRegistersPass>`_
* -
- `FlattenRelabelRegistersPass <https://cqcl.github.io/tket/pytket/api/passes.html#pytket.passes.FlattenRelabelRegistersPass>`_
-


* [1] If no value is specified then ``optimisation_level`` defaults to a value of 2.

* [2] ``self.rebase_pass`` is a rebase that converts the circuit to the Quantinuum native gate set (e.g. {Rz, PhasedX, ZZMax, ZZPhase}).
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion pytket/extensions/quantinuum/backends/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,5 @@ def set_quantinuum_config(username: Optional[str]) -> None:
"""Set default value for Quantinuum username.
Can be overriden in backend construction."""
hconfig = QuantinuumConfig.from_default_config_file()
hconfig.username = username # type: ignore
hconfig.username = username
hconfig.update_default_config_file()
2 changes: 2 additions & 0 deletions pytket/extensions/quantinuum/backends/quantinuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ def __init__(
)
else:
self.compilation_config = compilation_config
if self.compilation_config.target_2qb_gate is None:
self.compilation_config.target_2qb_gate = self._default_2q_gate

def get_compilation_config(self) -> QuantinuumBackendCompilationConfig:
"""Get the current compilation configuration."""
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
packages=find_namespace_packages(include=["pytket.*"]),
include_package_data=True,
install_requires=[
"pytket ~= 1.20",
"pytket ~= 1.21",
"requests >= 2.2",
"types-requests",
"websockets >= 7.0",
Expand Down
195 changes: 192 additions & 3 deletions tests/integration/backend_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from base64 import b64encode
from collections import Counter
from pathlib import Path
from typing import cast, Callable, Any # pylint: disable=unused-import
from typing import cast, Callable, Any, Tuple # pylint: disable=unused-import
import json
import gc
import os
Expand Down Expand Up @@ -46,6 +46,7 @@
)
from pytket.extensions.quantinuum import (
QuantinuumBackend,
QuantinuumBackendCompilationConfig,
Language,
prune_shots_detected_as_leaky,
)
Expand Down Expand Up @@ -716,7 +717,7 @@ def test_device_state(
def test_wasm(
authenticated_quum_backend: QuantinuumBackend, language: Language
) -> None:
wasfile = WasmFileHandler(str(Path(__file__).parent / "testfile.wasm"))
wasfile = WasmFileHandler(str(Path(__file__).parent.parent / "wasm" / "add1.wasm"))
c = Circuit(1)
c.name = "test_wasm"
a = c.add_c_register("a", 8)
Expand All @@ -739,7 +740,7 @@ def test_wasm(
def test_wasm_costs(
authenticated_quum_backend: QuantinuumBackend,
) -> None:
wasfile = WasmFileHandler(str(Path(__file__).parent / "testfile.wasm"))
wasfile = WasmFileHandler(str(Path(__file__).parent.parent / "wasm" / "add1.wasm"))
c = Circuit(1)
c.name = "test_wasm"
a = c.add_c_register("a", 8)
Expand Down Expand Up @@ -999,3 +1000,191 @@ def test_scratch_removal(authenticated_quum_backend: QuantinuumBackend) -> None:
shots = r.get_shots()
assert len(shots) == 3
assert all(len(shot) == 5 for shot in shots)


@pytest.mark.skipif(skip_remote_tests, reason=REASON)
@pytest.mark.parametrize(
"authenticated_quum_backend", [{"device_name": "H1-1E"}], indirect=True
)
@pytest.mark.parametrize(
"language",
[
Language.QASM,
# https://github.com/CQCL/pytket-quantinuum/issues/236
# Language.QIR,
],
)
@pytest.mark.timeout(120)
def test_wasm_collatz(
authenticated_quum_backend: QuantinuumBackend, language: Language
) -> None:
wasfile = WasmFileHandler(
str(Path(__file__).parent.parent / "wasm" / "collatz.wasm")
)
c = Circuit(8)
a = c.add_c_register("a", 8)
b = c.add_c_register("b", 8)

# Use Hadamards to set "a" register to a random value.
for i in range(8):
c.H(i)
c.Measure(Qubit(i), Bit("a", i))
# Compute the value of the Collatz function on this value.
c.add_wasm_to_reg("collatz", wasfile, [a], [b])

backend = authenticated_quum_backend

c = backend.get_compiled_circuit(c)
h = backend.process_circuit(
c, n_shots=10, wasm_file_handler=wasfile, language=language # type: ignore
)

r = backend.get_result(h)
shots = r.get_shots()

def to_int(C: np.ndarray) -> int:
assert len(C) == 8
return sum(pow(2, i) * C[i] for i in range(8))

def collatz(n: int) -> int:
if n == 0:
return 0
m = 0
while n != 1:
n = (3 * n + 1) // 2 if n % 2 == 1 else n // 2
m += 1
return m

for shot in shots:
n, m = to_int(shot[:8]), to_int(shot[8:16])
assert collatz(n) == m


@pytest.mark.skipif(skip_remote_tests, reason=REASON)
@pytest.mark.parametrize(
"authenticated_quum_backend", [{"device_name": "H1-1E"}], indirect=True
)
@pytest.mark.parametrize(
"language",
[
Language.QASM,
# https://github.com/CQCL/pytket-quantinuum/issues/236
# Language.QIR,
],
)
@pytest.mark.timeout(120)
def test_wasm_state(
authenticated_quum_backend: QuantinuumBackend, language: Language
) -> None:
wasfile = WasmFileHandler(str(Path(__file__).parent.parent / "wasm" / "state.wasm"))
c = Circuit(8)
a = c.add_c_register("a", 8).to_list() # measurement results
b = c.add_c_register("b", 4) # final count
s = c.add_c_register("s", 1) # scratch bit

# Use Hadamards to set "a" register to random values.
for i in range(8):
c.H(i)
c.Measure(Qubit(i), a[i])
# Count the number of 1s in the "a" register and store in the "b" register.
c.add_wasm_to_reg("set_c", wasfile, [s], []) # set c to zero
for i in range(8):
# Copy a[i] to s
c.add_c_copybits([a[i]], [Bit("s", 0)])
# Conditionally increment the counter
c.add_wasm_to_reg("conditional_increment_c", wasfile, [s], [])
# Put the counter into "b"
c.add_wasm_to_reg("get_c", wasfile, [], [b])

backend = authenticated_quum_backend

c = backend.get_compiled_circuit(c)
h = backend.process_circuit(
c, n_shots=10, wasm_file_handler=wasfile, language=language # type: ignore
)

r = backend.get_result(h)
shots = r.get_shots()

def to_int(C: np.ndarray) -> int:
assert len(C) == 4
return sum(pow(2, i) * C[i] for i in range(4))

for shot in shots:
a_count = sum(shot[:8])
b_count = to_int(shot[8:12])
assert a_count == b_count


@pytest.mark.skipif(skip_remote_tests, reason=REASON)
@pytest.mark.parametrize(
"authenticated_quum_backend", [{"device_name": "H1-1E"}], indirect=True
)
@pytest.mark.parametrize(
"language",
[
Language.QASM,
# https://github.com/CQCL/pytket-quantinuum/issues/236
# Language.QIR,
],
)
@pytest.mark.timeout(120)
def test_wasm_multivalue(
authenticated_quum_backend: QuantinuumBackend, language: Language
) -> None:
wasfile = WasmFileHandler(
str(Path(__file__).parent.parent / "wasm" / "multivalue.wasm")
)
c = Circuit(8)
a = c.add_c_register("a", 4) # measurement results
b = c.add_c_register("b", 4) # measurement results
x = c.add_c_register("x", 4) # quotient
y = c.add_c_register("y", 4) # remainder

# Use Hadamards to set "a" register to random values.
for i in range(8):
c.H(i)
# Measure
for i in range(4):
c.Measure(Qubit(i), Bit("a", i))
c.Measure(Qubit(4 + i), Bit("b", i))
# Compute divmod
c.add_wasm_to_reg("divmod", wasfile, [a, b], [x, y])

backend = authenticated_quum_backend

c = backend.get_compiled_circuit(c)
h = backend.process_circuit(
c, n_shots=10, wasm_file_handler=wasfile, language=language # type: ignore
)

r = backend.get_result(h)
shots = r.get_shots()

def to_int(C: np.ndarray) -> int:
assert len(C) == 4
return sum(pow(2, i) * C[i] for i in range(4))

for shot in shots:
A = to_int(shot[:4])
B = to_int(shot[4:8])
X = to_int(shot[8:12])
Y = to_int(shot[12:16])
if B == 0:
assert X == 0
assert Y == 0
else:
assert A == X * B + Y


@pytest.mark.skipif(skip_remote_tests, reason=REASON)
@pytest.mark.timeout(120)
def test_default_2q_gate(authenticated_quum_handler: QuantinuumAPI) -> None:
# https://github.com/CQCL/pytket-quantinuum/issues/250
config = QuantinuumBackendCompilationConfig(allow_implicit_swaps=False)
b = QuantinuumBackend(
"H1-1E", api_handler=authenticated_quum_handler, compilation_config=config
)
c = Circuit(2).H(0).CX(0, 1).measure_all()
c1 = b.get_compiled_circuit(c)
assert any(cmd.op.type == b.default_two_qubit_gate for cmd in c1)
5 changes: 0 additions & 5 deletions tests/unit/add1.c

This file was deleted.

26 changes: 26 additions & 0 deletions tests/wasm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Create a C file containing

```c
void init() {}
```

at the top, and any other int-to-int functions below.

Run:

```shell
clang --target=wasm32 -mmultivalue -Xclang -target-abi -Xclang experimental-mv --no-standard-libraries -Wl,--export-all -Wl,--no-entry -o <filename>.wasm <filename>.c
```

to generate the wasm file.

(Multi-valued functions should be implemented using C functions that return a
struct composed of ints.)

You can then run:

```shell
wasm2wat <filename>.wasm -o <filename>.wast
```

to convert the WASM to human-readable text format.
5 changes: 5 additions & 0 deletions tests/wasm/add1.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
void init() {}

int add_one(int n) {
return n + 1;
}
Binary file added tests/wasm/add1.wasm
Binary file not shown.
48 changes: 48 additions & 0 deletions tests/wasm/add1.wast
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
(module
(type (;0;) (func))
(type (;1;) (func (param i32) (result i32)))
(func $__wasm_call_ctors (type 0))
(func $init (type 0)
return)
(func $add_one (type 1) (param i32) (result i32)
(local i32 i32 i32 i32 i32 i32)
global.get $__stack_pointer
local.set 1
i32.const 16
local.set 2
local.get 1
local.get 2
i32.sub
local.set 3
local.get 3
local.get 0
i32.store offset=12
local.get 3
i32.load offset=12
local.set 4
i32.const 1
local.set 5
local.get 4
local.get 5
i32.add
local.set 6
local.get 6
return)
(memory (;0;) 2)
(global $__stack_pointer (mut i32) (i32.const 66560))
(global (;1;) i32 (i32.const 1024))
(global (;2;) i32 (i32.const 1024))
(global (;3;) i32 (i32.const 1024))
(global (;4;) i32 (i32.const 66560))
(global (;5;) i32 (i32.const 0))
(global (;6;) i32 (i32.const 1))
(export "memory" (memory 0))
(export "__wasm_call_ctors" (func $__wasm_call_ctors))
(export "init" (func $init))
(export "add_one" (func $add_one))
(export "__dso_handle" (global 1))
(export "__data_end" (global 2))
(export "__global_base" (global 3))
(export "__heap_base" (global 4))
(export "__memory_base" (global 5))
(export "__table_base" (global 6)))
Loading

0 comments on commit 8e37b0b

Please sign in to comment.