# Results¶

class trueq.Results(value=None, n_measurements=None, dim=None)

A dictionary-like class which keeps track of measurement results for a single circuit that was run on quantum hardware or a simulator. This is stored as a map from bitstrings to corresponding counts.

Here are some examples:

from trueq import Results

# here we have 3 total measurements in the circuit, meaning we
# have to have a bitstring of length 3
res = Results()
res['000'] = 1000
res['100'] = 5

# unary addition with another (compatible) Results-like object is supported
res += {'100': 5, '110': 100}

res

Results({'000': 1000, '100': 10, '110': 100})

from trueq import Results

# here we have 2 total measurements in the circuit
res = Results(n_measurements=2)

# we can also index this using the decimal representation of the number
# so in the case of 2 total measurements, we can index, 0, 1, 2, 3.
# This only works if either measurements are already present, or
# n_measurements is specified on instantiation.
res[0] = 30
res[3] += 30

res

Results({'00': 30, '11': 30})


Note

This class works for ditstrings as well as bitstrings, for $$d<10$$. However, for simplicity, this documentation refers to bitstrings throughout.

Dimension can be specified at instantiation, but this dimension will be silently increased if bitstrings with larger numbers get inserted. For example, putting a bitstring of '002' in will mean the dimension will be at least 3, even if it was only 2 previously.

Parameters
• value (dict-like) – A dictionary-like object containing bitstrings and counts, see above examples.

• n_measurements (int | NoneType) – The number of measurements present. This is inferred if None provided. If not provided, the first measurement added sets this value. Using integer-based indexing of the results will not work unless either this number is specified, or has been inferred through another means.

• dim (int) – The dimension of the systems, which defaults to 2 for qubits. This number will automatically increase if bitstrings with larger values are used.

Raises

ValueError – If the dim value provided is greater than 9.

get(bitstring)

Gets the value associated with a given bitstring, if none is found, returns 0.

Bitstrings must match the number of measurements in the Results, this can be checked with n_measurements

Parameters

bitstring (int | str) – A valid bitstring or int, such as '101' or 5.

Return type

int

reset()

Resets all counts to 0, but leaves measurement positions intact. Resets last_modified to None.

property last_modified

The timestamp of the last modification to these results, which is automatically set whenever the results are modified. The automatically set value is the current UTC time in the ISO string format. This timestamp can also be set manually, in which case any subsequent changes to the results will not cause this timestamp to automatically change. Results that have never had counts added will have a value of None.

from trueq import Results

r = Results()
print(r.last_modified is None)

# automatically update the timestamp
r["00"] = 5
print(r.last_modified)

# manually update the timestamp
r.last_modified = "2019-10-02T00:00:00.0"
print(r.last_modified)

# we've adjusted it manually, so it is no longer automatically updated
r["01"] = 2
print(r.last_modified)

True
2021-07-16T16:11:45.407394
2019-10-02T00:00:00.0
2019-10-02T00:00:00.0

Type

str | NoneType

property dim

The system dimension; 2 for qubits, 3 for qutrits, etc.

Type

int

property vec

The vector representation of the results.

from trueq import Results

res = Results(n_measurements=2)
res[0] = 10
res[3] = 30

res.vec

array([10,  0,  0, 30])

Type

numpy.ndarray

Raises

ValueError – If the n_measurements exceeds the MAX_VEC_SYS value, which can be manually adjusted.

property n_measurements

The total number of measurements, i.e. the length of each bitstring.

Type

int

property n_shots

The total number of shots present.

This is useful in the normalization of the results.

from trueq import Results

res = Results(n_measurements=2)
res[0] = 10
res[3] = 30

res.n_shots

40

Type

int

sort(by_value=True)

Sorts the keys of the results in-place, either by value or by bitstring.

Parameters

by_value (bool) – If this is true, sort the results with the largest number of counts at the beginning of the results. If this is false, sort the results by the bitstring value, i.e. '00', '01', '10', '11'.

marginal(positions)

Returns a new Results object obtained by marginalizing this results object over the specified positions. The order of positions is respected, so this method can also be used to create a copy with reordered bitstrings.

from trueq import Results

res = Results({"0110": 15, "0111": 35})

print(res.marginal([1, 2]))
print(res.marginal([0, 3]))

Results({'11': 50})
Results({'00': 15, '01': 35})

Parameters

positions (Iterable) – A list of bitstring position indexes to keep in the new results object.

Return type

Results

from_vec(vec)

Sets the bitstring counts from a given vector having a length which is a power of the system dimension.

from trueq import Results

Results().from_vec([0.5, 0, 0, 0.5])

Results({'00': 0.5, '11': 0.5})

Parameters

vec (Iterable) – A vector whose length is a power of the system dimension.

Returns

This instance.

Return type

Results

Raises

ValueError – If the vec length is incompatible with the number of measurements.

subsample(n_shots, copy=True)

Randomly chooses a subset of shots. This is done uniformly and without replacement.

Parameters
• n_shots (int) – The number of shots to subsample, must be no bigger than the number of shots present.

• copy (bool) – If True, a new copy of the results will be made and returned, otherwise, the operation will happen in-place.

Return type

Results

Raises
• ValueError – If the number of shots to subsample exceeds the number of shots.

• TypeError – If the Results values are not integers.

tvd(other, multinomial=None, n_samples=2000)

Computes the total variational distance (TVD) between these results and another Results object. Each result object is treated as an empirical probability distribution by dividing each value by the sum of all values. The TVD between two probabality vectors $$p$$ and $$q$$ is given by

$\operatorname{tvd}(p,q) = \sum_i |p_i - q_i| / 2.$
from trueq import Results

r1 = Results({"00": 50, "11": 50})
r2 = Results({"00": 498, "11": 492, "01": 1, "10": 9})
print(r1.tvd(r2))

# here, both results sum to 1 so there is assumed to be no multinomial
# sampling error, and hence the variance is reported at 0.
r1 = Results({"00": 0.5, "11": 0.5})
r2 = Results({"00": 0.498, "11": 0.492, "01": 0.001, "10": 0.009})
print(r1.tvd(r2))

(0.010000000000000004, 0.03052776626420714)
(0.010000000000000004, 0.0)


If one or both of these results are assumed to come from a multinomial distribution sampled from some true underlying probabilties (which will in practice usually be the (noisy) measurement probabilities of some final state of a quantum circuit), then the TVD itself is also a random variable. This function reports an estimate of the variance of the TVD, along with the TVD itself described above, as follows.

First, this result object and/or the other result object are determined to be multinomial samples if n_shots is different than 1. However, this can be overridden by the argument multinomial.

To estimate the variance of the TVD, for this result object and/or the other result object (whichever are classified as multinomial by the above criteria), n_samples samples are drawn from the posterior distribution

$\operatorname{Dirichlet}(x)$

where $$x$$ is a vector of result counts, and where the prior distribution in this model is the non-informative improper prior $$\operatorname{Dirichlet}(0)$$. The standard deviation returned by this method is the standard deviation of the TVD of these samples with the samples or values of the other results object.

Parameters
• other (Results) – Another results object to compute the TVD with.

• multinomial (Iterable) – A pair of boolean values (self_multi, other_multi) which specify whether these results and/or the other results should be treated as multinomial samples, thereby contributing to estimated standard deviation. The default value of None results in the behaviour explained above.

• n_samples (int) – The number of Dirichlet samples to use in the estimation of std.

Returns

A pair (tvd, std) where tvd is the TVD and std is an estimate of its standard deviation.

Return type

tuple

Raises

ValueError – If the result objects are not compatible with one another, where either the dimension or number of measurements do not match.

decompiled_results(pauli)

Returns a new results object where the outcomes are flipped for each qubit where the given pauli is 'X' or 'Y'.

Parameters

pauli (str) – A pauli string that specifies which bits to flip.

Return type

Results

Raises
• NotImplementedError – If called on anything other than bitstrings.

• ValueError – If the input pauli does not match the n_measurements.

to_dict()

Returns a dictionary representation of a Results object. This dictionary representation contains only base Python classes.

Return type

dict

static from_dict(dic)

Returns a Results constructed from a dictionary representation.

Parameters

dic (dict) – A dictionary used to construct a new Results.

Return type

Results

plot(sparse_cutoff=True, axis=None)

Plots a bar graph of these results.

from numpy.random import randint
from trueq import Results

Results().from_vec(randint(0, 100, 32)).plot()

Parameters
• sparse_cutoff (bool | float) – Optional cutoff for plotting small values. By default this is True, and will not plot values bigger than $$1/s^2$$, where $$s$$ is the number of possible ditstrings for $$s>256$$. If False, no cutoff is applied. The cutoff can be set manually by inputing a float.

• axis (matplotlib.Axis | NoneType) – An existing axis to plot on, or None to create a new one.