Please note that there is a bug in this code which is currently being fixed. The code will NOT give the correct rate calculations at the moment. This notice will be removed once the code has been fixed. -- Peter
A python3 package for developing device-independent randomness expansion protocols - based on work in [DIRNG]. Package aims to provide a user-friendly method of constructing and analysing device-independent randomness expansion protocols. The semidefinite relaxations are performed using the ncpol2sdpa package [NCPOL] and the resulting SDPs are computed using the SDPA solver [SDPA]. Many thanks go to the developers of these latter two projects.
Hoping in the future to extend this to other DI tools, developing some DIQI library, e.g. DIQKD, DIRA, steering...
Happy to hear from anyone who's interested in a similar project :)
SDP solver
Currently the only supported solvers are those from the sdpa family. They can be downloaded and extracted from their sourceforge page.
Important configuration note
The default precision with which sdpa writes its solutions to file is 3 decimal places. This has to be increased prior to usage otherwise errors will be prevalent in computations. This precision can be modified by changing the param.sdpa file that comes with the solver. In particular, replacing
%+8.3e char* YPrint (default %+8.3e, NOPRINT skips printout)
with
%+8.8e char* YPrint (default %+8.3e, NOPRINT skips printout),
will increase the precision.
Note: To automatically point the package to the solver, one can edit the dirng_config.json file replacing '/path/to/solver/' with the appropriate path. The location of the config file can be found by running 'pip3 show dirng', it should be in the /etc/ subdirectory. (Windows users: Paths must be specified using '\\' instead of '\' in the path name.)
If this is done then the solver argument never has to be passed to the device, it will be set automatically.
To install the latest version run
pip3 install git+https://github.com/peterjbrown519/dirng.git
Explicit examples are provided in /examples/ directory. Here we review the main structure of the package and look at a general script demonstrating its usage. Those looking for a quick start can skip straight to that script. For full details on functionality please see the comments within the module's files.
There are three classes in dirng.
Game
Description
A Game object represents a nonlocal game which will be played by the untrusted devices.
Attributes
- name: Name of the game.
- score: Expected score achieved by the untrusted devices.
- delta: Width of confidence interval about the expected score.
- matrix: Matrix representing the coefficients of the Bell-expression.
Usage
from dirng import Game """ Let's create the CHSH game - 2 inputs / 2 outputs If p(a,b|x,y) is the distribution of the devices, then we write our Bell-expressions as \sum_{abxy} s_ab|xy p(a,b|x,y). The matrix of coefficients is then | s00|00 s01|00 s00|01 s01|01 | | s10|00 s11|00 s10|01 s11|01 | | s00|10 s01|10 s00|11 s01|11 | | s10|10 s11|10 s10|11 s11|11 | """ chsh_coefficients = [[ 0.25, 0.00, 0.25, 0.00], [ 0.00, 0.25, 0.00, 0.25], [ 0.25, 0.00, 0.00, 0.25], [ 0.00, 0.25, 0.25, 0.00]] # Initialising the game object chsh = Game(name = 'chsh', score = 0.853, matrix = chsh_coefficients, delta = 0.001) # If the score was maybe a little ambitious, we can change it... chsh.score = 0.75
Devices
Description
A pair of untrusted devices. They play nonlocal games and produce random numbers.
Attributes
- name: Name given to the devices.
- io_config: The input output configuration of the devices. If m_i, n_j are the number of outputs for the i-th and j-th measurement of the 1st and 2nd device respectively. Then we write the io_config as [[m_1,m_2,...],[n_1,n_2,...]].
- generation_inputs: Device inputs used during generation rounds.
- relaxation_level: Level of NPA hierarchy used during computations.
- solver: /path/to/the/solver/used/
- games: A list of Game objects played by the device.
Usage
from dirng import Devices # We can initialise the device by passing it a settings dictionary. device_settings = { 'name' : 'Mittens', 'io_config' : [[2,2], [2,2]], 'generation_inputs' : [0,0], 'relaxation_level' : 2, 'games' : [chsh], 'solver' : '/path/to/a/solver/' } dev = Devices(device_settings) # As before these attributes can be changed after initialisation dev.generation_inputs = [1,1] dev.relaxation_level = 3 # We can also add additional games if they are compatible with our devices alphabet. dev.games += another_game_object # The randomness can then be calculated by calling the hmin attribute randomness = dev.hmin print(randomness) # For a general view of the device we can also call print print(dev)
If we want to change the scores of the games played by the device, we can set them all at once by
# Setting scores (and the delta values) for the two games that dev plays dev.score = [0.8, 0.7] dev.delta = [0.0001, 0.001] # Recompute the min-entropy print(dev.hmin)
The games are ordered by the device alphabetically w.r.t. their names. So the list of scores should reflect that ordering.
A useful function for calculating score vectors is distribution2Score()
# Suppose we have some distribution p = [[0.20, 0.30, 0.30, 0.20], [0.30, 0.20, 0.20, 0.30], [0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25]] # We can calculate the expected score vector for a device pair by w = dev.distribution2Score(p) # We can then set that score like before dev.score = w
Protocol
Description
The protocol object stores the parameters of the randomness accumulation protocol and alongside the device object, it is used to calculate the randomness accumulation rates as certified by the entropy accumulation theorem [EAT].
Attributes
- n: The number of rounds (interactions with the devices) in the protocol.
- y: The independent probability with which any given round is a testing round.
- eps_smooth: The smoothing epsilon.
- eps_eat: The entropy accumulation error.
Usage
As before we can initialise the object by passing a settings dictionary.
from dirng import Protocol protocol_settings = { 'n' : 1e10, 'y' : 0.005, 'eps_smooth' : 1e-8, 'eps_eat' : 1e-8 } protocol = Protocol(protocol_settings) # Changing attributes still works in the same way protocol.n = 1e12 # The protocol can also display its current state via the print method print(protocol)
If we pass the untrusted device object we created earlier to the protocol then we can calculate the completeness error.
Now we have everything we need to compute the entropy accumulation rate (entropy gain per round) of our protocol. When the function eatRate() is called a min-tradeoff function (see [EAT]) is chosen, and the corresponding accumulation rates are calculated.
Note: The default choice of min-tradeoff function may not yield the best accumulation rates, to aid with this we include a second method optimiseFminChoice() which performs a gradient ascent algorithm to improve this choice.
original_eat_rate = protocol.eatRate(dev) optimised_eat_rate = protocol.optimiseFminChoice(dev) # Let's see how much we improved print('The default min-tradeoff choice gave {:.3f} bits per round of entropy.'.format(original_eat_rate)) print('Whereas the optimised choice of min-tradeoff function gave {:.3f} bits per round.'.format(optimised_eat_rate))
The package contains various other functions and the user is encouraged to read the explanatory comments within the files. Briefly, in addition to the class files there is
- dirng.qubit_methods: Contains functions implementing a simple model of the untrusted devices as entangled qubit systems. In particular includes modelling of inefficient detectors and white noise.
- dirng.eat_methods: Further functions relating to the EAT and the calculation of entropy accumulation rates.
Below is a script implementing the extended CHSH protocol which was given as an example protocol in [DIRNG]. A more verbose version is given in examples/chsh.py.
from dirng import Game, Protocol, Devices
from math import sqrt
SOLVER = '/path/to/a/solver/'
# Initialising the device
device_settings = {'name' : 'chsh',
'io_config' : [[2,2], [2,2,2]],
'relaxation_level' : 2,
'generation_inputs' : [1,2],
'solver' : SOLVER}
dev = di.Devices(device_settings)
# Creating the games and add them
alignment_coefficients = [[ 0.00, 0.00, 0.00, 0.00, 1.00, 0.00],
[ 0.00, 0.00, 0.00, 0.00, 0.00, 1.00],
[ 0.00, 0.00, 0.00, 0.00, 0.00, 0.00],
[ 0.00, 0.00, 0.00, 0.00, 0.00, 0.00]]
chsh_coefficients = [[ 0.25, 0.00, 0.25, 0.00, 0.00, 0.00],
[ 0.00, 0.25, 0.00, 0.25, 0.00, 0.00],
[ 0.25, 0.00, 0.00, 0.25, 0.00, 0.00],
[ 0.00, 0.25, 0.25, 0.00, 0.00, 0.00]]
align = Game(name = 'align', matrix = alignment_coefficients, score = 1.00, delta=0.001)
chsh = Game(name = 'chsh', matrix = chsh_coefficients, score = 0.5 + sqrt(2)/4, delta=0.001)
dev.games = [align, chsh]
# We should get hmin = 2 bits
print(dev.hmin)
"""
Part 2. accumulation rates
"""
# Protocol setup
protocol_settings = {'n' : 1e12,
'y' : 5e-3,
'eps_smooth' : 1e-12,
'eps_eat' : 1e-12}
protocol = Protocol(protocol_settings)
print('The completeness error is: ', protocol.completeness(dev))
# Calculate the initial accumulation rate -- this may be quite negative
# at T'sirelon's bound due to a steep gradient in min-tradeoff function space.
initial_rate = protocol.eatRate(dev)
print('The initial rate was {:.3f} bits per round'.format(initial_rate))
# Optimise the EAT rate
optimised_rate = protocol.optimiseFminChoice(dev, num_iterations = 24)
print('The optimised rate is {:.3f} bits per round'.format(random_rate))
av, lv, v, _, status = dev.fmin_variables
print('This was achieved by the min-tradeoff function corresponding to the score vector ', v)
- DIRNG
Peter J. Brown, Sammy Ragy and Roger Colbeck, "An adaptive framework for quantum-secure device-independent randomness expansion", arXiv:1810.13346, 2018.
- EAT
Frédéric Dupuis and Omar Fawzi, “Entropy accumulation with improved second-order,” arXiv:1805.11652, 2018.
- NCPOL
Peter Wittek. Algorithm 950: Ncpol2sdpa---Sparse Semidefinite Programming Relaxations for Polynomial Optimization Problems of Noncommuting Variables. ACM Transactions on Mathematical Software, 41(3), 21, 2015. DOI: 10.1145/2699464. arXiv:1308.6029. Code available on gitlab.
- SDPA
"A high-performance software package for semidefinite programs: SDPA 7," Makoto Yamashita, Katsuki Fujisawa, Kazuhide Nakata, Maho Nakata, Mituhiro Fukuda, Kazuhiro Kobayashi, and Kazushige Goto, Research Report B-460 Dept. of Mathematical and Computing Science, Tokyo Institute of Technology, Tokyo, Japan, September, 2010. Solvers available at their sourceforge page.