Skip to content

Commit

Permalink
Added support for RNG seeds
Browse files Browse the repository at this point in the history
  • Loading branch information
PabloAndresCQ committed Oct 23, 2024
1 parent e26cb32 commit 7ad5fc2
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 9 deletions.
12 changes: 4 additions & 8 deletions pytket/extensions/cutensornet/backends/cutensornet_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ def process_circuits(
n_shots: Number of shots in case of shot-based calculation.
Optionally, this can be a list of shots specifying the number of shots
for each circuit separately.
seed: An optional RNG seed. Different calls to ``process_circuits`` with the
same seed will generate the same list of shot outcomes.
valid_check: Whether to check for circuit correctness.
tnconfig: Optional. A dict of cuTensorNet ``TNConfig`` keys and
their values.
Expand All @@ -292,13 +294,7 @@ def process_circuits(
"""
scratch_fraction = float(kwargs.get("scratch_fraction", 0.8)) # type: ignore
tnconfig = kwargs.get("tnconfig", dict()) # type: ignore

if "seed" in kwargs and kwargs["seed"] is not None:
# Current CuTensorNet does not support seeds for Sampler. I created
# a feature request in their repository.
raise NotImplementedError( # TODO: Support seeds!
"The backend does not currently support user-defined seeds."
)
seed = kwargs.get("seed", None)

if n_shots is None:
raise ValueError(
Expand All @@ -318,7 +314,7 @@ def process_circuits(
circuit, attributes=tnconfig, scratch_fraction=scratch_fraction
)
handle = ResultHandle(str(uuid4()))
self._cache[handle] = {"result": tn.sample(circ_shots)}
self._cache[handle] = {"result": tn.sample(circ_shots, seed=seed)}
handle_list.append(handle)
return handle_list

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,17 +240,20 @@ def expectation_value(
self._logger.debug("(Expectation value) contracting the TN")
return complex(self.tn_state.compute_expectation(tn_operator))

def sample( # TODO: Support seeds (and test)
def sample(
self,
n_shots: int,
symbol_map: Optional[dict[Symbol, float]] = None,
seed: Optional[int] = None,
) -> BackendResult:
"""Obtains samples from the measurements at the end of the circuit.
Args:
n_shots: The number of samples to obtain.
symbol_map: A dictionary where each element of ``sef.free_symbols`` is
assigned a real number.
seed: An optional RNG seed. Different calls to ``sample`` with the same
seed will generate the same list of shot outcomes.
Returns:
A pytket ``BackendResult`` with the data from the shots.
Expand All @@ -275,9 +278,12 @@ def sample( # TODO: Support seeds (and test)
measured_modes = tuple(self._qubit_idx_map[qb] for qb in qbit_list)

self._logger.debug("(Sampling) contracting the TN")
if seed is not None:
seed = abs(seed) # Must be a positive integer
samples = self.tn_state.compute_sampling(
nshots=n_shots,
modes=measured_modes,
seed=seed,
)

# Convert the data in `samples` to an `OutcomeArray` using `from_readouts`
Expand Down
16 changes: 16 additions & 0 deletions tests/test_cutensornet_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,22 @@ def test_sampler_bell() -> None:
assert np.isclose(res.get_counts()[(1, 1)] / n_shots, 0.5, atol=0.01)


def test_sampler_bell_seed() -> None:
n_shots = 1000
c = Circuit(2, 2)
c.H(0)
c.CX(0, 1)
c.measure_all()
b = CuTensorNetShotsBackend()
c = b.get_compiled_circuit(c)
res1 = b.run_circuit(c, n_shots=n_shots, seed=1234)
res2 = b.run_circuit(c, n_shots=n_shots, seed=1234)
res3 = b.run_circuit(c, n_shots=n_shots, seed=4321)
print(type(res1.get_shots()))
assert np.all(res1.get_shots() == res2.get_shots())
assert np.any(res1.get_shots() != res3.get_shots())


def test_config_options() -> None:
c = Circuit(2, 2)
c.H(0)
Expand Down

0 comments on commit 7ad5fc2

Please sign in to comment.