├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── enhancement_request.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── deploy.yml │ └── main.yml ├── .gitignore ├── .pylintrc ├── .readthedocs.yml ├── .stestr.conf ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── MANIFEST.in ├── README.md ├── constraints.txt ├── docs ├── Makefile ├── _static │ └── theme.css ├── api.rst ├── conf.py ├── images │ ├── fuzzy.png │ └── qrng_logo.png ├── index.rst ├── install.rst ├── requirements.txt └── usage.rst ├── qiskit_rng ├── VERSION.txt ├── __init__.py ├── constants.py ├── exceptions.py ├── generator.py ├── generator_job.py ├── generator_result.py ├── model.py └── utils.py ├── requirements-dev.txt ├── requirements.txt ├── setup.py ├── test ├── __init__.py └── test_generator.py └── tox.ini /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | labels: 'type: bug' 5 | --- 6 | 7 | 8 | 9 | 10 | ### Information 11 | 12 | - **Qiskit RNG version**: 13 | - **Python version**: 14 | - **Operating system**: 15 | 16 | ### What is the current behavior? 17 | 18 | 19 | 20 | ### Steps to reproduce the problem 21 | 22 | 23 | 24 | ### What is the expected behavior? 25 | 26 | 27 | 28 | ### Suggested solutions 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/enhancement_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Enhancement request 3 | about: Suggest an improvement for this project! 4 | labels: 'type: enhancement' 5 | --- 6 | 7 | 8 | 9 | 10 | ### What is the expected enhancement? 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: 'type: feature request' 6 | --- 7 | 8 | 9 | 10 | 11 | ### What is the expected behavior? 12 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | ### Summary 13 | 14 | 15 | 16 | ### Details and comments 17 | 18 | 19 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2020. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | name: Deployment 14 | 15 | on: 16 | push: 17 | tags: 18 | - '*' 19 | 20 | jobs: 21 | Deploy: 22 | runs-on: ubuntu-latest 23 | strategy: 24 | matrix: 25 | python-version: [3.7] 26 | steps: 27 | - uses: actions/checkout@v2 28 | - uses: actions/setup-python@v2 29 | with: 30 | python-version: ${{ matrix.python-version }} 31 | - name: Deploy to Pypi 32 | env: 33 | TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }} 34 | TWINE_USERNAME: qiskit 35 | run : | 36 | pip install -U twine pip setuptools virtualenv wheel 37 | python3 setup.py sdist bdist_wheel 38 | twine upload dist/qiskit* 39 | shell: bash 40 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: 3 | push: 4 | branches: [ master] 5 | pull_request: 6 | branches: [ master] 7 | jobs: 8 | tests: 9 | name: tests-python${{ matrix.python-version }}-${{ matrix.os }} 10 | runs-on: ${{ matrix.os }} 11 | strategy: 12 | matrix: 13 | python-version: [3.6, 3.7, 3.8] 14 | os: ["macOS-latest", "ubuntu-latest", "windows-latest"] 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up Python ${{ matrix.python-version }} 18 | uses: actions/setup-python@v2 19 | with: 20 | python-version: ${{ matrix.python-version }} 21 | - name: Install Deps 22 | run: python -m pip install -U tox setuptools virtualenv wheel 23 | - name: Install and Run Tests 24 | run: tox -e py 25 | lint: 26 | name: lint 27 | runs-on: ubuntu-latest 28 | steps: 29 | - uses: actions/checkout@v2 30 | - name: Set up Python 3.8 31 | uses: actions/setup-python@v2 32 | with: 33 | python-version: 3.8 34 | - name: Install Deps 35 | run: python -m pip install -U tox 36 | - name: Run lint 37 | run: tox -elint 38 | docs: 39 | name: docs 40 | runs-on: ubuntu-latest 41 | steps: 42 | - uses: actions/checkout@v2 43 | with: 44 | fetch-depth: 0 45 | - name: Set up Python 3.8 46 | uses: actions/setup-python@v2 47 | with: 48 | python-version: 3.8 49 | - name: Install Deps 50 | run: python -m pip install -U tox 51 | - name: Build Docs 52 | run: tox -edocs 53 | - uses: actions/upload-artifact@v2 54 | with: 55 | name: html_docs 56 | path: docs/_build/html -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | .DS_Store 131 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | 3 | # Specify a configuration file. 4 | #rcfile= 5 | 6 | # Python code to execute, usually for sys.path manipulation such as 7 | # pygtk.require(). 8 | #init-hook= 9 | 10 | # Add files or directories to the blacklist. They should be base names, not 11 | # paths. 12 | ignore=CVS 13 | 14 | # Add files or directories matching the regex patterns to the blacklist. The 15 | # regex matches against base names, not paths. 16 | ignore-patterns= 17 | 18 | # Pickle collected data for later comparisons. 19 | persistent=yes 20 | 21 | # List of plugins (as comma separated values of python modules names) to load, 22 | # usually to register additional checkers. 23 | load-plugins=pylint.extensions.docparams, # enable checking of docstring args 24 | pylint.extensions.docstyle, # basic docstring style checks 25 | 26 | # Use multiple processes to speed up Pylint. 27 | jobs=1 28 | 29 | # Allow loading of arbitrary C extensions. Extensions are imported into the 30 | # active Python interpreter and may run arbitrary code. 31 | unsafe-load-any-extension=no 32 | 33 | # A comma-separated list of package or module names from where C extensions may 34 | # be loaded. Extensions are loading into the active Python interpreter and may 35 | # run arbitrary code 36 | extension-pkg-whitelist= 37 | 38 | 39 | [MESSAGES CONTROL] 40 | 41 | # Only show warnings with the listed confidence levels. Leave empty to show 42 | # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED 43 | confidence= 44 | 45 | # Enable the message, report, category or checker with the given id(s). You can 46 | # either give multiple identifier separated by comma (,) or put this option 47 | # multiple time (only on the command line, not in the configuration file where 48 | # it should appear only once). See also the "--disable" option for examples. 49 | #enable= 50 | 51 | # Disable the message, report, category or checker with the given id(s). You 52 | # can either give multiple identifiers separated by comma (,) or put this 53 | # option multiple times (only on the command line, not in the configuration 54 | # file where it should appear only once).You can also use "--disable=all" to 55 | # disable everything first and then reenable specific checks. For example, if 56 | # you want to run only the similarities checker, you can use "--disable=all 57 | # --enable=similarities". If you want to run only the classes checker, but have 58 | # no Warning level messages displayed, use"--disable=all --enable=classes 59 | # --disable=W" 60 | disable=no-self-use, # disabled as it is too verbose 61 | fixme, # disabled as TODOs would show up as warnings 62 | protected-access, # disabled as we don't follow the public vs private 63 | # convention strictly 64 | duplicate-code, # disabled as it is too verbose 65 | redundant-returns-doc, # for @abstractmethod, it cannot interpret "pass" 66 | # disable the "too-many/few-..." refactoring hints 67 | too-many-lines, too-many-branches, too-many-locals, too-many-nested-blocks, 68 | too-many-statements, too-many-instance-attributes, too-many-arguments, 69 | too-many-public-methods, too-few-public-methods, too-many-ancestors, 70 | unnecessary-pass, # allow for methods with just "pass", for clarity 71 | no-else-return, # relax "elif" after a clause with a return 72 | docstring-first-line-empty, # relax docstring style 73 | import-outside-toplevel 74 | 75 | 76 | 77 | 78 | [REPORTS] 79 | 80 | # Set the output format. Available formats are text, parseable, colorized, msvs 81 | # (visual studio) and html. You can also give a reporter class, eg 82 | # mypackage.mymodule.MyReporterClass. 83 | output-format=text 84 | 85 | # Put messages in a separate file for each module / package specified on the 86 | # command line instead of printing them on stdout. Reports (if any) will be 87 | # written in a file name "pylint_global.[txt|html]". This option is deprecated 88 | # and it will be removed in Pylint 2.0. 89 | files-output=no 90 | 91 | # Tells whether to display a full report or only the messages 92 | reports=yes 93 | 94 | # Python expression which should return a note less than 10 (10 is the highest 95 | # note). You have access to the variables errors warning, statement which 96 | # respectively contain the number of errors / warnings messages and the total 97 | # number of statements analyzed. This is used by the global evaluation report 98 | # (RP0004). 99 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) 100 | 101 | # Template used to display messages. This is a python new-style format string 102 | # used to format the message information. See doc for all details 103 | #msg-template= 104 | 105 | 106 | [BASIC] 107 | 108 | # Good variable names which should always be accepted, separated by a comma 109 | # i,j,k = typical indices 110 | # n,m = typical numbers 111 | # ex = for exceptions and errors 112 | # v,w = typical vectors 113 | # x,y,z = typical axes 114 | # _ = placeholder name 115 | # q,r,qr,cr,qc = quantum and classical registers, and quantum circuit 116 | # pi = the PI constant 117 | # op = operation iterator 118 | # b = basis iterator 119 | good-names=i,j,k,n,m,ex,v,w,x,y,z,Run,_,logger,q,c,r,qr,cr,qc,nd,pi,op,b,ar,br, 120 | __unittest 121 | 122 | # Bad variable names which should always be refused, separated by a comma 123 | bad-names=foo,bar,toto,tutu,tata 124 | 125 | # Colon-delimited sets of names that determine each other's naming style when 126 | # the name regexes allow several styles. 127 | name-group= 128 | 129 | # Include a hint for the correct naming format with invalid-name 130 | include-naming-hint=no 131 | 132 | # List of decorators that produce properties, such as abc.abstractproperty. Add 133 | # to this list to register other decorators that produce valid properties. 134 | property-classes=abc.abstractproperty 135 | 136 | # Regular expression matching correct module names 137 | module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ 138 | 139 | # Naming hint for module names 140 | module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ 141 | 142 | # Regular expression matching correct constant names 143 | const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ 144 | 145 | # Naming hint for constant names 146 | const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ 147 | 148 | # Regular expression matching correct class names 149 | class-rgx=[A-Z_][a-zA-Z0-9]+$ 150 | 151 | # Naming hint for class names 152 | class-name-hint=[A-Z_][a-zA-Z0-9]+$ 153 | 154 | # Regular expression matching correct function names 155 | function-rgx=[a-z_][a-z0-9_]{2,30}$ 156 | 157 | # Naming hint for function names 158 | function-name-hint=[a-z_][a-z0-9_]{2,30}$ 159 | 160 | # Regular expression matching correct method names 161 | method-rgx=(([a-z_][a-z0-9_]{2,49})|(assert[A-Z][a-zA-Z0-9]{2,43})|(test_[_a-zA-Z0-9]{2,}))$ 162 | 163 | # Naming hint for method names 164 | method-name-hint=[a-z_][a-z0-9_]{2,30}$ or camelCase `assert*` in tests. 165 | 166 | # Regular expression matching correct attribute names 167 | attr-rgx=[a-z_][a-z0-9_]{2,30}$ 168 | 169 | # Naming hint for attribute names 170 | attr-name-hint=[a-z_][a-z0-9_]{2,30}$ 171 | 172 | # Regular expression matching correct argument names 173 | argument-rgx=[a-z_][a-z0-9_]{2,30}|ax|dt$ 174 | 175 | # Naming hint for argument names 176 | argument-name-hint=[a-z_][a-z0-9_]{2,30}$ 177 | 178 | # Regular expression matching correct variable names 179 | variable-rgx=[a-z_][a-z0-9_]{2,30}$ 180 | 181 | # Naming hint for variable names 182 | variable-name-hint=[a-z_][a-z0-9_]{2,30}$ 183 | 184 | # Regular expression matching correct class attribute names 185 | class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ 186 | 187 | # Naming hint for class attribute names 188 | class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ 189 | 190 | # Regular expression matching correct inline iteration names 191 | inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ 192 | 193 | # Naming hint for inline iteration names 194 | inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ 195 | 196 | # Regular expression which should only match function or class names that do 197 | # not require a docstring. 198 | no-docstring-rgx=^_ 199 | 200 | # Minimum line length for functions/classes that require docstrings, shorter 201 | # ones are exempt. 202 | docstring-min-length=-1 203 | 204 | 205 | [ELIF] 206 | 207 | # Maximum number of nested blocks for function / method body 208 | max-nested-blocks=5 209 | 210 | 211 | [FORMAT] 212 | 213 | # Maximum number of characters on a single line. 214 | max-line-length=100 215 | 216 | # Regexp for a line that is allowed to be longer than the limit. 217 | ignore-long-lines=^\s*(# )??$ 218 | 219 | # Allow the body of an if to be on the same line as the test if there is no 220 | # else. 221 | single-line-if-stmt=no 222 | 223 | # List of optional constructs for which whitespace checking is disabled. `dict- 224 | # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. 225 | # `trailing-comma` allows a space between comma and closing bracket: (a, ). 226 | # `empty-line` allows space-only lines. 227 | no-space-check=trailing-comma,dict-separator 228 | 229 | # Maximum number of lines in a module 230 | max-module-lines=1000 231 | 232 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 233 | # tab). 234 | indent-string=' ' 235 | 236 | # Number of spaces of indent required inside a hanging or continued line. 237 | indent-after-paren=4 238 | 239 | # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. 240 | expected-line-ending-format= 241 | 242 | 243 | [LOGGING] 244 | 245 | # Logging modules to check that the string format arguments are in logging 246 | # function parameter format 247 | logging-modules=logging 248 | 249 | 250 | [MISCELLANEOUS] 251 | 252 | # List of note tags to take in consideration, separated by a comma. 253 | notes=FIXME,XXX,TODO 254 | 255 | 256 | [SIMILARITIES] 257 | 258 | # Minimum lines number of a similarity. 259 | min-similarity-lines=4 260 | 261 | # Ignore comments when computing similarities. 262 | ignore-comments=yes 263 | 264 | # Ignore docstrings when computing similarities. 265 | ignore-docstrings=yes 266 | 267 | # Ignore imports when computing similarities. 268 | ignore-imports=no 269 | 270 | 271 | [SPELLING] 272 | 273 | # Spelling dictionary name. Available dictionaries: none. To make it working 274 | # install python-enchant package. 275 | spelling-dict= 276 | 277 | # List of comma separated words that should not be checked. 278 | spelling-ignore-words= 279 | 280 | # A path to a file that contains private dictionary; one word per line. 281 | spelling-private-dict-file= 282 | 283 | # Tells whether to store unknown words to indicated private dictionary in 284 | # --spelling-private-dict-file option instead of raising a message. 285 | spelling-store-unknown-words=no 286 | 287 | 288 | [TYPECHECK] 289 | 290 | # Tells whether missing members accessed in mixin class should be ignored. A 291 | # mixin class is detected if its name ends with "mixin" (case insensitive). 292 | ignore-mixin-members=yes 293 | 294 | # List of module names for which member attributes should not be checked 295 | # (useful for modules/projects where namespaces are manipulated during runtime 296 | # and thus existing member attributes cannot be deduced by static analysis. It 297 | # supports qualified module names, as well as Unix pattern matching. 298 | ignored-modules=numpy.random 299 | 300 | # List of class names for which member attributes should not be checked (useful 301 | # for classes with dynamically set attributes). This supports the use of 302 | # qualified names. 303 | ignored-classes=optparse.Values,thread._local,_thread._local,QuantumCircuit 304 | 305 | # List of members which are set dynamically and missed by pylint inference 306 | # system, and so shouldn't trigger E1101 when accessed. Python regular 307 | # expressions are accepted. 308 | generated-members= 309 | 310 | # List of decorators that produce context managers, such as 311 | # contextlib.contextmanager. Add to this list to register other decorators that 312 | # produce valid context managers. 313 | contextmanager-decorators=contextlib.contextmanager 314 | 315 | 316 | [VARIABLES] 317 | 318 | # Tells whether we should check for unused import in __init__ files. 319 | init-import=no 320 | 321 | # A regular expression matching the name of dummy variables (i.e. expectedly 322 | # not used). 323 | dummy-variables-rgx=(_+[a-zA-Z0-9]*?$)|dummy 324 | 325 | # List of additional names supposed to be defined in builtins. Remember that 326 | # you should avoid to define new builtins when possible. 327 | additional-builtins= 328 | 329 | # List of strings which can identify a callback function by name. A callback 330 | # name must start or end with one of those strings. 331 | callbacks=cb_,_cb 332 | 333 | # List of qualified module names which can have objects that can redefine 334 | # builtins. 335 | redefining-builtins-modules=six.moves,future.builtins 336 | 337 | 338 | [CLASSES] 339 | 340 | # List of method names used to declare (i.e. assign) instance attributes. 341 | defining-attr-methods=__init__,__new__,setUp 342 | 343 | # List of valid names for the first argument in a class method. 344 | valid-classmethod-first-arg=cls 345 | 346 | # List of valid names for the first argument in a metaclass class method. 347 | valid-metaclass-classmethod-first-arg=mcs 348 | 349 | # List of member names, which should be excluded from the protected access 350 | # warning. 351 | exclude-protected=_asdict,_fields,_replace,_source,_make 352 | 353 | 354 | [DESIGN] 355 | 356 | # Maximum number of arguments for function / method 357 | max-args=8 358 | 359 | # Argument names that match this expression will be ignored. Default to name 360 | # with leading underscore 361 | ignored-argument-names=_.* 362 | 363 | # Maximum number of locals for function / method body 364 | max-locals=15 365 | 366 | # Maximum number of return / yield for function / method body 367 | max-returns=6 368 | 369 | # Maximum number of branch for function / method body 370 | max-branches=12 371 | 372 | # Maximum number of statements in function / method body 373 | max-statements=50 374 | 375 | # Maximum number of parents for a class (see R0901). 376 | max-parents=7 377 | 378 | # Maximum number of attributes for a class (see R0902). 379 | max-attributes=10 380 | 381 | # Minimum number of public methods for a class (see R0903). 382 | min-public-methods=2 383 | 384 | # Maximum number of public methods for a class (see R0904). 385 | max-public-methods=35 386 | 387 | # Maximum number of boolean expressions in a if statement 388 | max-bool-expr=5 389 | 390 | 391 | [IMPORTS] 392 | 393 | # Deprecated modules which should not be used, separated by a comma 394 | deprecated-modules=optparse 395 | 396 | # Create a graph of every (i.e. internal and external) dependencies in the 397 | # given file (report RP0402 must not be disabled) 398 | import-graph= 399 | 400 | # Create a graph of external dependencies in the given file (report RP0402 must 401 | # not be disabled) 402 | ext-import-graph= 403 | 404 | # Create a graph of internal dependencies in the given file (report RP0402 must 405 | # not be disabled) 406 | int-import-graph= 407 | 408 | # Force import order to recognize a module as part of the standard 409 | # compatibility libraries. 410 | known-standard-library= 411 | 412 | # Force import order to recognize a module as part of a third party library. 413 | known-third-party=enchant 414 | 415 | # Analyse import fallback blocks. This can be used to support both Python 2 and 416 | # 3 compatible code, which means that the block might have code that exists 417 | # only in one or another interpreter, leading to false positives when analysed. 418 | analyse-fallback-blocks=no 419 | 420 | 421 | [EXCEPTIONS] 422 | 423 | # Exceptions that will emit a warning when being caught. Defaults to 424 | # "Exception" 425 | overgeneral-exceptions=Exception -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file 2 | version: 2 3 | 4 | build: 5 | image: latest 6 | 7 | python: 8 | version: 3.7 9 | install: 10 | - requirements: docs/requirements.txt 11 | - method: pip 12 | path: . 13 | 14 | sphinx: 15 | builder: html 16 | configuration: docs/conf.py 17 | -------------------------------------------------------------------------------- /.stestr.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | test_path=./test -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at qiskit@qiskit.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Contributing to Qiskit Random Number Generation 4 | 5 | ### Issue reporting 6 | 7 | When you encounter a problem please open an issue for it to 8 | the [issue tracker]. 9 | 10 | ### Improvement proposal 11 | 12 | If you have an idea for a new feature please open an **Feature Requestt** issue 13 | in the [issue tracker]. Opening 14 | an issue starts a discussion with the team about your idea, how it fits in with 15 | the project, how it can be implemented, etc. 16 | 17 | ### Code Review 18 | 19 | Code review is done in the open and open to anyone. While only maintainers have 20 | access to merge commits, providing feedback on pull requests is very valuable 21 | and helpful. It is also a good mechanism to learn about the code base. You can 22 | view a list of all open pull requests here: 23 | https://github.com/qiskit-community/qiskit_rng/pulls 24 | to review any open pull requests and provide feedback on it. 25 | 26 | ### Pull requests 27 | 28 | We use [GitHub pull requests]( 29 | https://help.github.com/articles/about-pull-requests) to accept contributions. 30 | 31 | While not required, opening a new issue about the bug you're fixing or the 32 | feature you're working on before you open a pull request is an important step 33 | in starting a discussion with the community about your work. The issue gives us 34 | a place to talk about the idea and how we can work together to implement it in 35 | the code. It also lets the community know what you're working on and if you 36 | need help, you can use the issue to go through it with other community and team 37 | members. 38 | 39 | If you've written some code but need help finishing it, want to get initial 40 | feedback on it prior to finishing it, or want to share it and discuss prior 41 | to finishing the implementation you can open a *Work in Progress* pull request. 42 | When you create the pull request prefix the title with the **\[WIP\]** tag (for 43 | **W**ork **I**n **P**rogress). This will indicate to reviewers that the code in 44 | the PR isn't in it's final state and will change. It also means that we will 45 | not merge the commit until it is finished. You or a reviewer can remove the 46 | [WIP] tag when the code is ready to be fully reviewed for merging. 47 | 48 | ### Contributor License Agreement 49 | 50 | Before you can submit any code we need all contributors to sign a 51 | contributor license agreement. By signing a contributor license 52 | agreement (CLA) you're basically just attesting to the fact 53 | that you are the author of the contribution and that you're freely 54 | contributing it under the terms of the Apache-2.0 license. 55 | 56 | When you contribute to this project with a new pull request, 57 | a bot will evaluate whether you have signed the CLA. If required, the 58 | bot will comment on the pull request, including a link to accept the 59 | agreement. The [individual CLA](https://qiskit.org/license/qiskit-cla.pdf) 60 | document is available for review as a PDF. 61 | 62 | **Note**: 63 | > If your contribution is part of your employment or your contribution 64 | > is the property of your employer, then you will likely need to sign a 65 | > [corporate CLA](https://qiskit.org/license/qiskit-corporate-cla.pdf) too and 66 | > email it to us at . 67 | 68 | 69 | ### Pull request checklist 70 | 71 | When submitting a pull request, and you feel it is ready for review, 72 | please ensure that: 73 | 74 | 1. The code follows the code style of the project and successfully 75 | passes the tests. 76 | 2. The documentation has been updated accordingly. In particular, if a 77 | function or class has been modified during the PR, please update the 78 | *docstring* accordingly. 79 | 3. If it makes sense for your change ensure that you have added new tests that 80 | cover your code changes. 81 | 82 | ### Commit messages 83 | 84 | As important as the content of the change, is the content of the commit message 85 | describing it. The commit message provides the context for not only code review 86 | but also the change history in the git log. Having a detailed commit message 87 | will make it easier for your code to be reviewed and provide context to the 88 | change when it's being looked at years in the future. When writing a commit 89 | message there are some important things to remember: 90 | 91 | * Do not assume the reviewer understands what the original problem was. 92 | 93 | When reading an issue, after a number of back & forth comments, it is often 94 | clear what the root cause problem is. The commit message should have a clear 95 | statement as to what the original problem is. The bug is merely interesting 96 | historical background on *how* the problem was identified. It should be 97 | possible to review a proposed patch for correctness from the commit message, 98 | without needing to read the bug ticket. 99 | bug ticket. 100 | 101 | * Do not assume the code is self-evident/self-documenting. 102 | 103 | What is self-evident to one person, might not be clear to another person. Always 104 | document what the original problem was and how it is being fixed, for any change 105 | except the most obvious typos, or whitespace only commits. 106 | 107 | * Describe why a change is being made. 108 | 109 | A common mistake is to just document how the code has been written, without 110 | describing *why* the developer chose to do it that way. By all means describe 111 | the overall code structure, particularly for large changes, but more importantly 112 | describe the intent/motivation behind the changes. 113 | 114 | * Read the commit message to see if it hints at improved code structure. 115 | 116 | Often when describing a large commit message, it becomes obvious that a commit 117 | should have in fact been split into 2 or more parts. Don't be afraid to go back 118 | and rebase the change to split it up into separate pull requests. 119 | 120 | * Ensure sufficient information to decide whether to review. 121 | 122 | When Github sends out email alerts for new pull request submissions, there is 123 | minimal information included, usually just the commit message and the list of 124 | files changes. Because of the high volume of patches, commit message must 125 | contain sufficient information for potential reviewers to find the patch that 126 | they need to look at. 127 | 128 | * The first commit line is the most important. 129 | 130 | In Git commits, the first line of the commit message has special significance. 131 | It is used as the default pull request title, email notification subject line, 132 | git annotate messages, gitk viewer annotations, merge commit messages, and many 133 | more places where space is at a premium. As well as summarizing the change 134 | itself, it should take care to detail what part of the code is affected. 135 | 136 | * Describe any limitations of the current code. 137 | 138 | If the code being changed still has future scope for improvements, or any known 139 | limitations, then mention these in the commit message. This demonstrates to the 140 | reviewer that the broader picture has been considered and what tradeoffs have 141 | been done in terms of short term goals vs. long term wishes. 142 | 143 | * Include references to issues 144 | 145 | If the commit fixes or is related to an issue make sure you annotate that in 146 | the commit message. Using the syntax: 147 | 148 | Fixes #1234 149 | 150 | if it fixes the issue (github will close the issue when the PR merges). 151 | 152 | The main rule to follow is: 153 | 154 | The commit message must contain all the information required to fully 155 | understand & review the patch for correctness. Less is not more. 156 | 157 | 158 | ### Installing qiskit_rng from source 159 | 160 | To install `qiskit_rng` from a local git checkout you should 161 | run: 162 | 163 | ```bash 164 | pip install -e $PATH_TO_REPO 165 | ``` 166 | 167 | which will install the local checkout in the editable mode. 168 | 169 | 170 | ### Test 171 | 172 | Once you've made a code change, it is important to verify that your change 173 | does not break any existing tests and that any new tests that you've added 174 | also run successfully. Before you open a new pull request for your change, 175 | you'll want to run the test suite locally. 176 | 177 | The easiest way to run the test suite is to use 178 | [**tox**](https://tox.readthedocs.io/en/latest/#). You can install tox 179 | with pip: `pip install -U tox`. Tox provides several advantages, but the 180 | biggest one is that it builds an isolated virtualenv for running tests. This 181 | means it does not pollute your system python when running. Additionally, the 182 | environment that tox sets up matches the CI environment more closely, and it 183 | runs the tests in parallel (resulting in much faster execution). To run tests 184 | on all installed supported python versions and lint/style checks you can simply 185 | run `tox`. Or if you just want to run the tests once run for a specific python 186 | version: `tox -epy37` (or replace py37 with the python version you want to use). 187 | 188 | If you just want to run a subset of tests you can pass a selection regex to 189 | the test runner. For example, if you want to run all tests that have "dag" in 190 | the test id you can run: `tox -epy37 -- dag`. You can pass arguments directly to 191 | the test runner after the bare `--`. To see all the options on test selection 192 | you can refer to the stestr manual: 193 | https://stestr.readthedocs.io/en/stable/MANUAL.html#test-selection 194 | 195 | If you want to run a single test module, test class, or individual test method 196 | you can do this faster with the `-n`/`--no-discover` option. For example: 197 | 198 | to run a module: 199 | ``` 200 | tox -epy37 -- -n test.test_examples 201 | ``` 202 | or to run the same module by path: 203 | 204 | ``` 205 | tox -epy37 -- -n test/test_examples.py 206 | ``` 207 | to run a class: 208 | 209 | ``` 210 | tox -epy37 -- -n test.test_examples.TestPythonExamples 211 | ``` 212 | to run a method: 213 | ``` 214 | tox -epy37 -- -n test.test_examples.TestPythonExamples.test_all_examples 215 | ``` 216 | 217 | 218 | ### Style guide 219 | 220 | To enforce a consistent code style in the project we use 221 | [Pylint](https://www.pylint.org) and 222 | [pycodesytle](https://pycodestyle.readthedocs.io/en/latest/) 223 | to verify that code contributions conform respect the projects 224 | style guide. To verify that your changes conform to the style 225 | guide you can run: `tox -elint` 226 | 227 | ## Documentation 228 | 229 | The documentation for the Python SDK is auto-generated from Python 230 | docstrings using [Sphinx](http://www.sphinx-doc.org. Please follow [Google's Python Style 231 | Guide](https://google.github.io/styleguide/pyguide.html?showone=Comments#Comments) 232 | for docstrings. A good example of the style can also be found with 233 | [Sphinx's napolean converter 234 | documentation](http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html). 235 | 236 | ## Development Cycle 237 | 238 | The development cycle for qiskit_rng is all handled in the open using 239 | the project boards in Github for project management. We use milestones 240 | in Github to track work for specific releases. The features or other changes 241 | that we want to include in a release will be tagged and discussed in Github. 242 | As we're preparing a new release we'll document what has changed since the 243 | previous version in the release notes and Changelog. 244 | 245 | [issue tracker]: https://github.com/qiskit-community/qiskit_rng/issues 246 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include qiskit_rng/VERSION.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qiskit Random Number Generation 2 | 3 | [![License](https://img.shields.io/github/license/Qiskit/qiskit-ignis.svg?style=popout-square)](https://opensource.org/licenses/Apache-2.0) 4 | [![Build Status](https://github.com/qiskit-community/qiskit_rng/workflows/Tests/badge.svg?style=popout-square)](https://github.com/qiskit-community/qiskit_rng/actions) 5 | [![](https://img.shields.io/github/release/qiskit-community/qiskit_rng.svg?style=popout-square)](https://github.com/qiskit-community/qiskit_rng/releases) 6 | [![](https://img.shields.io/pypi/dm/qiskit_rng.svg?style=popout-square)](https://pypi.org/project/qiskit_rng/) 7 | 8 | Qiskit is an open-source framework for working with noisy intermediate-scale 9 | quantum computers (NISQ) at the level of pulses, circuits, and algorithms. 10 | 11 | This project contains support for Random Number Generation using [Qiskit] 12 | and [IBM Quantum Experience] backends. The 13 | resulting raw numbers can then be passed to [Cambridge Quantum Computing] (CQC) 14 | randomness extractors to get higher-quality random numbers. 15 | 16 | ## Installation 17 | 18 | You can install the project using pip: 19 | 20 | ```bash 21 | pip install qiskit_rng 22 | ``` 23 | 24 | PIP will handle all python dependencies automatically, and you will always 25 | install the latest (and well-tested) version. 26 | 27 | 28 | ## Usage 29 | 30 | ### Setting up the IBM Quantum Provider 31 | 32 | You will need setup your IBM Quantum Experience account and provider in order to 33 | access IBM Quantum backends. See [qiskit-ibmq-provider](https://github.com/Qiskit/qiskit-ibmq-provider) 34 | for more details. 35 | 36 | ### Generating random numbers using an IBM Quantum backend 37 | 38 | To generate random numbers using an IBM Quantum backend: 39 | 40 | ```python 41 | from qiskit import IBMQ 42 | from qiskit_rng import Generator 43 | 44 | IBMQ.load_account() 45 | rng_provider = IBMQ.get_provider(hub='MY_HUB', group='MY_GROUP', project='MY_PROJECT') 46 | backend = rng_provider.backends.ibmq_ourence 47 | 48 | generator = Generator(backend=backend) 49 | output = generator.sample(num_raw_bits=1024).block_until_ready() 50 | print(output.mermin_correlator) 51 | ``` 52 | 53 | The `output` you get back contains useful information such as the 54 | Weak Source of Randomness (`result.wsr`) used to generate the circuits, the resulting bits 55 | (`result.raw_bits`), and the Mermin correlator value (`result.mermin_correlator`). 56 | 57 | 58 | ### Using CQC extractors to get highly random output 59 | 60 | If you have access to the CQC extractors, you can feed the outputs from the previous 61 | step to obtain higher quality random numbers: 62 | 63 | ```python 64 | random_bits = output.extract() 65 | ``` 66 | 67 | The code above uses the default parameter values, but the extractor is highly 68 | configurable. See documentation for some use case examples and parameter suggestions. 69 | 70 | ## Documentation 71 | 72 | Usage and API documentation can be found [here](https://qiskit-rng.readthedocs.io/en/latest/). 73 | 74 | ## License 75 | 76 | [Apache License 2.0]. 77 | 78 | 79 | [Qiskit]: https://qiskit.org 80 | [IBM Quantum Experience]: https://quantum-computing.ibm.com 81 | [Cambridge Quantum Computing]: https://cambridgequantum.com 82 | [Apache License 2.0]: https://github.com/qiskit-community/qiskit_rng/blob/master/LICENSE.txt 83 | -------------------------------------------------------------------------------- /constraints.txt: -------------------------------------------------------------------------------- 1 | astroid==2.3.3 2 | pylint==2.4.4 -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # This code is part of Qiskit. 2 | # 3 | # (C) Copyright IBM 2018. 4 | # 5 | # This code is licensed under the Apache License, Version 2.0. You may 6 | # obtain a copy of this license in the LICENSE.txt file in the root directory 7 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 8 | # 9 | # Any modifications or derivative works of this code must retain this 10 | # copyright notice, and modified files need to carry a notice indicating 11 | # that they have been altered from the originals. 12 | 13 | # You can set these variables from the command line. 14 | SPHINXOPTS = 15 | SPHINXBUILD = sphinx-build 16 | SOURCEDIR = . 17 | BUILDDIR = _build 18 | 19 | # Put it first so that "make" without argument is like "make help". 20 | help: 21 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 22 | 23 | .PHONY: help Makefile 24 | 25 | # Catch-all target: route all unknown targets to Sphinx using the new 26 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 27 | %: Makefile 28 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -j auto 29 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | API reference 3 | ============= 4 | 5 | .. automodule:: qiskit_rng 6 | :no-members: 7 | :no-inherited-members: 8 | :no-special-members: 9 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This code is part of Qiskit. 4 | # 5 | # (C) Copyright IBM 2020. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | # pylint: disable=invalid-name 16 | # Configuration file for the Sphinx documentation builder. 17 | # 18 | # This file does only contain a selection of the most common options. For a 19 | # full list see the documentation: 20 | # http://www.sphinx-doc.org/en/master/config 21 | 22 | # -- Path setup -------------------------------------------------------------- 23 | 24 | # If extensions (or modules to document with autodoc) are in another directory, 25 | # add these directories to sys.path here. If the directory is relative to the 26 | # documentation root, use os.path.abspath to make it absolute, like shown here. 27 | # 28 | # import os 29 | # import sys 30 | # sys.path.insert(0, os.path.abspath('.')) 31 | 32 | """ 33 | Sphinx documentation builder 34 | """ 35 | 36 | # The short X.Y version 37 | version = "0.2.2" 38 | 39 | 40 | rst_prolog = """ 41 | .. |version| replace:: {0} 42 | """.format(version) 43 | 44 | # -- Project information ----------------------------------------------------- 45 | project = 'Qiskit RNG {}'.format(version) 46 | copyright = '2020, Qiskit RNG Team' # pylint: disable=redefined-builtin 47 | author = 'Qiskit RNG Development Team' 48 | # -- General configuration --------------------------------------------------- 49 | 50 | # If your documentation needs a minimal Sphinx version, state it here. 51 | # 52 | # needs_sphinx = '1.0' 53 | 54 | # Add any Sphinx extension module names here, as strings. They can be 55 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 56 | # ones. 57 | extensions = [ 58 | 'sphinx.ext.napoleon', 59 | 'sphinx.ext.autodoc', 60 | 'sphinx.ext.autosummary', 61 | 'sphinx.ext.mathjax', 62 | 'sphinx.ext.viewcode', 63 | 'sphinx.ext.extlinks', 64 | ] 65 | html_static_path = ['_static'] 66 | #templates_path = ['_templates'] 67 | #html_css_files = ['gallery.css'] 68 | 69 | exclude_patterns = ['_build', '**.ipynb_checkpoints'] 70 | 71 | # ----------------------------------------------------------------------------- 72 | # Autosummary 73 | # ----------------------------------------------------------------------------- 74 | autosummary_generate = True 75 | 76 | # ----------------------------------------------------------------------------- 77 | # Autodoc 78 | # ----------------------------------------------------------------------------- 79 | 80 | autodoc_default_options = { 81 | 'inherited-members': None, 82 | } 83 | 84 | autoclass_content = 'both' 85 | 86 | 87 | # If true, figures, tables and code-blocks are automatically numbered if they 88 | # have a caption. 89 | numfig = True 90 | 91 | # A dictionary mapping 'figure', 'table', 'code-block' and 'section' to 92 | # strings that are used for format of figure numbers. As a special character, 93 | # %s will be replaced to figure number. 94 | numfig_format = { 95 | 'table': 'Table %s' 96 | } 97 | # The language for content autogenerated by Sphinx. Refer to documentation 98 | # for a list of supported languages. 99 | # 100 | # This is also used if you do content translation via gettext catalogs. 101 | # Usually you set "language" from the command line for these cases. 102 | language = None 103 | 104 | # A boolean that decides whether module names are prepended to all object names 105 | # (for object types where a “module” of some kind is defined), e.g. for 106 | # py:function directives. 107 | add_module_names = False 108 | 109 | # A list of prefixes that are ignored for sorting the Python module index 110 | # (e.g., if this is set to ['foo.'], then foo.bar is shown under B, not F). 111 | # This can be handy if you document a project that consists of a single 112 | # package. Works only for the HTML builder currently. 113 | modindex_common_prefix = ['qiskit_rng.'] 114 | 115 | # -- Configuration for extlinks extension ------------------------------------ 116 | # Refer to https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html 117 | 118 | 119 | # -- Options for HTML output ------------------------------------------------- 120 | 121 | # The theme to use for HTML and HTML Help pages. See the documentation for 122 | # a list of builtin themes. 123 | # 124 | html_theme = "pydata_sphinx_theme" 125 | 126 | html_logo = 'images/qrng_logo.png' 127 | 128 | html_theme_options = { 129 | "github_url": "", 130 | "use_edit_page_button": False, 131 | } 132 | 133 | html_context = { 134 | "github_user": "nonhermitian", 135 | "github_repo": "qiskit_rng", 136 | "github_version": "master", 137 | "doc_path": "docs", 138 | } 139 | #html_sidebars = {'**': ['globaltoc.html']} 140 | html_last_updated_fmt = '%Y/%m/%d' 141 | -------------------------------------------------------------------------------- /docs/images/fuzzy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit_rng/d785d0df17222c16ffb5acd5995eb697396c62fd/docs/images/fuzzy.png -------------------------------------------------------------------------------- /docs/images/qrng_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiskit-community/qiskit_rng/d785d0df17222c16ffb5acd5995eb697396c62fd/docs/images/qrng_logo.png -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ######################## 2 | Qiskit RNG (|version|) 3 | ######################## 4 | 5 | .. caution:: 6 | 7 | This package is currently provided in beta form and heavy modifications to 8 | both functionality and API are likely to occur. 9 | 10 | 11 | 12 | .. figure:: images/fuzzy.png 13 | :align: center 14 | 15 | 16 | Qiskit RNG is a collaboration between `Cambridge Quantum Computing `_ (CQC) 17 | and `IBM Quantum `_ 18 | for generating certified quantum randomness using IBM Quantum systems running three-qubit 19 | GHZ states with random X- and Y-measurements. Provided that the state is tripartite entangled, 20 | as measurement by a violation of the Mermin inequality (:math:`x,y\in \{1,2\}`): 21 | 22 | .. math:: 23 | 24 | M_{\rm obs} = \langle A_{1}B_{1}C_{1}\rangle - \langle A_{1}B_{2}C_{2}\rangle - \langle A_{2}B_{1}C_{2}\rangle - \langle A_{2}B_{2}C_{1}\rangle \le 2, 25 | 26 | the measured output can be certified quantum random for values :math:`2\sqrt{2} \le M_{\rm obs} \le 4`; the underlying 27 | state was truly tripartite entangled. The maximum value :math:`M_{\rm obs} = 4` indicates maximum randomness, and 28 | and that the measurement outcomes are uniformly random. These "raw bits" are passed through a two-source randomness extractor 29 | that creates a reduced length uniform random distribution (if :math:`M_{\rm obs} \neq 4`) of bits. 30 | 31 | Further technical details maybe found in: 32 | `Foreman et al., "Practical randomness and privacy amplification", arXiv:2009.06551 `_. 33 | 34 | ``qiskit_rng`` has passed the following RNG test suites: 35 | 36 | - `Dieharder `_ 37 | 38 | - `NIST Statistical Test Suite `_ 39 | 40 | 41 | .. toctree:: 42 | :maxdepth: 2 43 | :hidden: 44 | 45 | Installation 46 | Usage 47 | API reference 48 | 49 | 50 | Quick start 51 | ----------- 52 | 53 | .. code-block:: python 54 | 55 | from qiskit import IBMQ 56 | from qiskit_rng import Generator 57 | 58 | IBMQ.load_account() 59 | rng_provider = IBMQ.get_provider(hub='qrng') 60 | backend = rng_provider.backends.ibmq_ourence 61 | 62 | generator = Generator(backend=backend) 63 | output = generator.sample(num_raw_bits=1024).block_until_ready() 64 | 65 | random_bits = output.extract() 66 | 67 | 68 | License 69 | ----------- 70 | Qiskit RNG is provided under the `Apache 2 license `_. 71 | 72 | .. Hiding - Indices and tables 73 | :ref:`genindex` 74 | :ref:`modindex` 75 | :ref:`search` 76 | -------------------------------------------------------------------------------- /docs/install.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | Installation 3 | ============= 4 | 5 | Overview 6 | -------- 7 | 8 | Installation of ``qiskit_rng`` has two pieces. First, this module itself 9 | that contains the RNG number generation. And second, a subset of the 10 | `Qiskit `_ SDK that 11 | constructs quantum circuits, and makes the appropriate API calls to execute 12 | those circuits and later call the extractor API. Both of these pieces 13 | are installed with a single command. 14 | 15 | 16 | Install 17 | ------- 18 | 19 | Installation of ``qiskit_rng`` is accomplished with a simple call to ``pip`` 20 | to download and install everything needed from PyPI: 21 | 22 | .. code-block:: bash 23 | 24 | pip install qiskit_rng 25 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | Sphinx>=3.0 2 | pydata_sphinx_theme 3 | sphinx-tabs>=1.1.11 4 | sphinx-autodoc-typehints -------------------------------------------------------------------------------- /docs/usage.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | Usage 3 | ============= 4 | 5 | Workflow 6 | -------- 7 | 8 | The current workflow has three parts: 9 | 10 | 1. Instantiate a :class:`qiskit_rng.Generator` from a specified IBM Quantum backend: 11 | 12 | .. code-block:: python 13 | 14 | from qiskit import IBMQ 15 | from qiskit_rng import Generator 16 | 17 | IBMQ.load_account() 18 | rng_provider = IBMQ.get_provider(hub='qrng') 19 | backend = rng_provider.backends.ibmq_ourence 20 | 21 | generator = Generator(backend=backend) 22 | 23 | 2. Sample a given number of "raw" bits using the target backend: 24 | 25 | .. code-block:: python 26 | 27 | output = generator.sample(num_raw_bits=1024).block_until_ready() 28 | 29 | 3. Extract high quality random numbers from the generator output: 30 | 31 | .. code-block:: python 32 | 33 | random_bits = output.extract() 34 | 35 | If you want to examine the final parameters passed to the extractor, you can use: 36 | 37 | .. code-block:: python 38 | 39 | extractor = rng_provider.random.cqc_extractor 40 | extractor_params = result.get_cqc_extractor_params() 41 | random_bits = extractor.run(*extractor_params) 42 | 43 | 44 | Extractor Parameters 45 | -------------------- 46 | 47 | * rate_sv: The assumption on the initial randomness rate of the used Weak Source of Randomness (WSR) 48 | as a Santha-Vazirani source. Effectively epsilon_sec / number of bits from the WSR 49 | (in a rate format). 50 | 51 | * expected_correlator: The expected Mermin correlator value. 52 | :data:`qiskit_rng.constants.EXPECTED_CORRELATOR` 53 | contains known values for certain backends, which are calculated from long test samples and 54 | provide higher security (but lower generate rate). If set to ``None``, the observed value 55 | from the sampling output is used. 56 | 57 | * epsilon_sec: A (small) security parameter defining the distance to uniform of the final bit 58 | string. When performing privacy amplification as well, epsilon is the distance to a perfectly 59 | uniform and private string. 60 | 61 | * quantum_proof: Set to ``True`` for quantum-proof extraction in the Markov model (most secure) and 62 | to ``False`` for classical-proof extraction in the standard model (higher rates but lower 63 | security). This should be set to ``True`` for security against potential quantum adversaries. 64 | Note that setting ``quantum_proof`` to ``True`` reduces the generation rates considerably. 65 | 66 | * trusted_backend: Set to ``True`` if the backend used for sampling is trusted and the interaction 67 | is made using a secure channel. 68 | 69 | * privacy: Set to ``True`` to also perform privacy amplification and to ``False`` if the initial 70 | WSR is assumed private already. If set to ``True``, the final output is provably both private and 71 | unbiased. If set to ``False``, the final output is provably unbiased. 72 | 73 | 74 | Use Case Examples and Suggested Parameters 75 | ------------------------------------------ 76 | 77 | In this section, we list different possible set of parameters for specific use cases and have 78 | included only the ones that have a reasonable runtime on a real backend. The final output bit string 79 | is certified quantum, random and private (if selected). 80 | 81 | For all the use cases below, we recommend a `num_raw_bits` value of at least 30 million (`3e7`) 82 | to the :meth:`qiskit_rng.Generator.sample()` method. 83 | 84 | 1. Random numbers for mathematical simulation or non-adversarial 85 | 86 | When there is no adversary or privacy concern, you can run with the minimum security parameters 87 | that allow the highest generation rate: 88 | 89 | * rate_sv=0.95 90 | * expected_correlator=None 91 | * epsilon_sec=1e-30 92 | * quantum_proof=False 93 | * trusted_backend=True 94 | * privacy=False 95 | 96 | 2. A good trade-off: certified quantum randomness 97 | 98 | We recommend this set of parameter which offers good security but which also runs efficiently: 99 | 100 | * rate_sv=0.95 101 | * expected_correlator=None 102 | * epsilon_sec=1e-30 103 | * quantum_proof=True 104 | * trusted_backend=True 105 | * privacy=False 106 | 107 | 3. A good trade-off: certified quantum randomness with privacy amplification 108 | 109 | This option is only available if the backend is trusted. We recommend this set of parameters: 110 | 111 | * rate_sv=0.95 112 | * expected_correlator=None 113 | * epsilon_sec=1e-30 114 | * quantum_proof=True 115 | * trusted_backend=True 116 | * privacy=True 117 | 118 | 4. Towards cryptographic use: certified quantum randomness using a untrusted backend: 119 | 120 | In this case, privacy amplification cannot be performed, and previously profiled correlator value 121 | should be used. We recommend this set of parameters: 122 | 123 | * rate_sv=0.95 124 | * expected_correlator=EXPECTED_CORRELATOR.xxx 125 | * epsilon_sec=1e-30 126 | * quantum_proof=True 127 | * trusted_backend=False 128 | * privacy=False 129 | 130 | 5. Towards cryptographic use: certified quantum randomness and privacy with a trusted backend 131 | 132 | This is the most stringent set of parameters in the possible presence of a quantum adversary. 133 | We recommend this set of parameters: 134 | 135 | * rate_sv=0.95 136 | * expected_correlator=EXPECTED_CORRELATOR.xxx 137 | * epsilon_sec=1e-30 138 | * quantum_proof=True 139 | * trusted_backend=True 140 | * privacy=True 141 | -------------------------------------------------------------------------------- /qiskit_rng/VERSION.txt: -------------------------------------------------------------------------------- 1 | 0.2.2 -------------------------------------------------------------------------------- /qiskit_rng/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This code is part of Qiskit. 4 | # 5 | # (C) Copyright IBM 2020. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | # (C) Copyright CQC 2020. 16 | # 17 | # This code is licensed under the Apache License, Version 2.0. You may 18 | # obtain a copy of this license in the LICENSE.txt file in the Programs 19 | # directory of this source or at http://www.apache.org/licenses/LICENSE-2.0. 20 | # 21 | # Any modifications or derivative works of this code must retain this 22 | # copyright notice, and modified files need to carry a notice indicating 23 | # that they have been altered from the originals. 24 | 25 | """ 26 | ============================== 27 | Qiskit RNG (:mod:`qiskit_rng`) 28 | ============================== 29 | 30 | .. currentmodule:: qiskit_rng 31 | 32 | Modules representing Qiskit Random Number Generator. 33 | 34 | Classes 35 | ========= 36 | 37 | .. autosummary:: 38 | :toctree: stubs/ 39 | 40 | Generator 41 | GeneratorJob 42 | GeneratorResult 43 | 44 | Functions 45 | ========= 46 | .. autosummary:: 47 | :toctree: stubs/ 48 | 49 | generate_wsr 50 | """ 51 | 52 | from .generator import Generator 53 | from .generator_job import GeneratorJob 54 | from .generator_result import GeneratorResult 55 | from .utils import generate_wsr 56 | -------------------------------------------------------------------------------- /qiskit_rng/constants.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This code is part of Qiskit. 4 | # 5 | # (C) Copyright IBM 2020. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | # (C) Copyright CQC 2020. 16 | # 17 | # This code is licensed under the Apache License, Version 2.0. You may 18 | # obtain a copy of this license in the LICENSE.txt file in the Programs 19 | # directory of this source or at http://www.apache.org/licenses/LICENSE-2.0. 20 | # 21 | # Any modifications or derivative works of this code must retain this 22 | # copyright notice, and modified files need to carry a notice indicating 23 | # that they have been altered from the originals. 24 | 25 | """Constant values.""" 26 | 27 | EXPECTED_CORRELATOR = { 28 | 'ibmq_ourense': 3.15, 29 | 'ibmq_valencia': 2.98 30 | } 31 | """Previously profiled Mermin correlator values for certain backends.""" 32 | -------------------------------------------------------------------------------- /qiskit_rng/exceptions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This code is part of Qiskit. 4 | # 5 | # (C) Copyright IBM 2020. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | """Exceptions for the RNG modules.""" 16 | 17 | from qiskit.exceptions import QiskitError 18 | 19 | 20 | class RNGError(QiskitError): 21 | """Base class for errors raised by the RNG modules.""" 22 | pass 23 | 24 | 25 | class RNGNotAuthorizedError(RNGError): 26 | """Error raised when an unauthorized action is requested.""" 27 | pass 28 | -------------------------------------------------------------------------------- /qiskit_rng/generator.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This code is part of Qiskit. 4 | # 5 | # (C) Copyright IBM 2020. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | # (C) Copyright CQC 2020. 16 | # 17 | # This code is licensed under the Apache License, Version 2.0. You may 18 | # obtain a copy of this license in the LICENSE.txt file in the Programs 19 | # directory of this source or at http://www.apache.org/licenses/LICENSE-2.0. 20 | # 21 | # Any modifications or derivative works of this code must retain this 22 | # copyright notice, and modified files need to carry a notice indicating 23 | # that they have been altered from the originals. 24 | 25 | """Module for random number generator.""" 26 | 27 | import logging 28 | import pickle 29 | import uuid 30 | import os 31 | from itertools import product 32 | from typing import List, Tuple, Callable, Optional, Any, Union 33 | 34 | from qiskit import QuantumCircuit, transpile, assemble 35 | from qiskit.providers.basebackend import BaseBackend 36 | from qiskit.providers.basejob import BaseJob 37 | from qiskit.providers.ibmq.ibmqbackend import IBMQBackend 38 | from qiskit.providers.ibmq.managed.ibmqjobmanager import IBMQJobManager, ManagedJobSet 39 | from qiskit.providers.ibmq.accountprovider import AccountProvider 40 | 41 | from .generator_job import GeneratorJob 42 | from .utils import generate_wsr 43 | 44 | try: 45 | from qiskit.providers.backend import Backend 46 | HAS_V2_BACKEND = True 47 | except ImportError: 48 | HAS_V2_BACKEND = False 49 | 50 | logger = logging.getLogger(__name__) 51 | 52 | 53 | class Generator: 54 | """Class for generating random numbers. 55 | 56 | You can use the :meth:`sample` method to run quantum circuits on a backend 57 | to generate random bits. When the circuit jobs finish and their results 58 | processed, you can examine the generated random bits as well as the 59 | bell values. An example of this flow:: 60 | 61 | from qiskit import IBMQ 62 | from qiskit_rng import Generator 63 | 64 | provider = IBMQ.load_account() 65 | generator = Generator(backend=provider.backends.ibmq_valencia) 66 | output = generator.sample(num_raw_bits=1024).block_until_ready() 67 | print("Mermin correlator value is {}".format(output.mermin_correlator)) 68 | print("first 8 raw bits are {}".format(output.raw_bits[:8])) 69 | 70 | Note that due to the way the circuits are constructed and executed, the resulting 71 | size of ``raw_bits`` might be slightly larger than the input ``num_raw_bits``. 72 | 73 | The bits generated by the :meth:`sample` method are only weakly random. You 74 | will need to apply a randomness extractor to this output in order to obtain 75 | a more uniformly distributed string of random bits. 76 | """ 77 | 78 | _file_prefix = "qiskit_rng" 79 | _job_tag = 'qiskit_rng' 80 | 81 | def __init__( 82 | self, 83 | backend: BaseBackend, 84 | wsr_generator: Optional[Callable] = None, 85 | noise_model: Any = None, 86 | save_local: bool = False 87 | ) -> None: 88 | """Generator constructor. 89 | 90 | Args: 91 | backend: Backend to use for generating random numbers. 92 | wsr_generator: Function used to generate WSR. It must take the 93 | number of bits as the input and a list of random bits (0s and 1s) 94 | as the output. If ``None``, :func:`qiskit_rng.generate_wsr` is used. 95 | noise_model: Noise model to use. Only applicable if `backend` is a 96 | simulator. 97 | save_local: If ``True``, the generated WSR and other metadata is 98 | saved into a pickle file in the local directory. The file can 99 | be used to recover and resume a sampling if needed. 100 | The file name will be in the format of 101 | ``qiskit_rng___``. 102 | The file will be deleted automatically when the corresponding 103 | :meth:`GeneratorJob.block_until_ready()` method is invoked. 104 | Only supported if `backend` is an ``IBMQBackend``. 105 | """ 106 | self.backend = backend 107 | self.job_manager = IBMQJobManager() 108 | self.wsr_generator = wsr_generator or generate_wsr 109 | self.noise_model = noise_model 110 | self.save_local = save_local 111 | 112 | def sample( 113 | self, 114 | num_raw_bits: int 115 | ) -> GeneratorJob: 116 | """Use the target system to generate raw bit strings. 117 | 118 | Args: 119 | num_raw_bits: Number of raw bits to sample. Note that the raw 120 | bits are only weakly random and needs to go through extraction 121 | to generate highly random output. 122 | 123 | Returns: 124 | A :class:`GeneratorJob` instance that contains all the information 125 | needed to extract randomness. 126 | 127 | Raises: 128 | ValueError: If an input argument is invalid. 129 | """ 130 | if not isinstance(self.backend, BaseBackend) and \ 131 | (HAS_V2_BACKEND and not isinstance(self.backend, Backend)): 132 | raise ValueError("Backend needs to be a Qiskit `BaseBackend` or `Backend` instance.") 133 | 134 | max_shots = self.backend.configuration().max_shots 135 | num_raw_bits_qubit = int((num_raw_bits + 2)/3) 136 | if num_raw_bits_qubit <= max_shots: 137 | shots = num_raw_bits_qubit 138 | num_circuits = 1 139 | else: 140 | num_circuits = int((num_raw_bits_qubit + max_shots - 1)/max_shots) 141 | shots = int((num_raw_bits_qubit + num_circuits - 1)/num_circuits) 142 | 143 | logger.debug("Using %s circuits with %s shots each", num_circuits, shots) 144 | 145 | initial_wsr = self.wsr_generator(num_circuits * 3) 146 | 147 | wsr_bits = self._get_wsr(num_circuits, initial_wsr) 148 | circuits = self._generate_all_circuits(num_circuits, wsr_bits) 149 | 150 | job = self._run_circuits(circuits, shots) 151 | saved_fn = None 152 | if self.save_local and isinstance(self.backend, IBMQBackend): 153 | saved_fn = self._save_local(num_raw_bits, wsr_bits, job, shots) 154 | return GeneratorJob( 155 | initial_wsr=initial_wsr, 156 | wsr=wsr_bits, 157 | job=job, 158 | shots=shots, 159 | saved_fn=saved_fn 160 | ) 161 | 162 | def _run_circuits( 163 | self, 164 | circuits: List[QuantumCircuit], 165 | shots: int 166 | ) -> Union[ManagedJobSet, BaseJob]: 167 | """Run circuits on a backend. 168 | 169 | Args: 170 | circuits: Circuits to run. 171 | shots: Number of shots. 172 | 173 | Returns: 174 | An IBMQ managed job set or a job. 175 | """ 176 | transpiled = transpile(circuits, backend=self.backend, optimization_level=2) 177 | transpiled = [transpiled] if not isinstance(transpiled, list) else transpiled 178 | 179 | if isinstance(self.backend, IBMQBackend): 180 | job = self.job_manager.run(transpiled, backend=self.backend, shots=shots, 181 | job_tags=[self._job_tag], memory=True) 182 | logger.info("Jobs submitted to %s. Job set ID is %s.", self.backend, job.job_set_id()) 183 | else: 184 | job = self.backend.run(assemble(transpiled, backend=self.backend, shots=shots, 185 | memory=True, noise_model=self.noise_model)) 186 | logger.info("Jobs submitted to %s. Job ID is %s.", self.backend, job.job_id()) 187 | 188 | return job 189 | 190 | def _get_wsr(self, num_circuits: int, initial_wsr: List[int]) -> List: 191 | """Obtain the weak source of randomness bits used to generate circuits. 192 | 193 | Args: 194 | num_circuits: Number of circuits. 195 | initial_wsr: Raw WSR bits used to generate the output WSR. 196 | 197 | Returns: 198 | A list the size of `num_circuits`. Each element in the 199 | list is another list of 3 binary numbers. 200 | For example, 201 | [ [1, 0, 0], [0, 1, 1], [1, 1, 0], ...] 202 | """ 203 | output_wsr = [] 204 | for i in range(num_circuits): 205 | output_wsr.append( 206 | [int(initial_wsr[3*i]), int(initial_wsr[3*i+1]), int(initial_wsr[3*i+2])]) 207 | 208 | return output_wsr 209 | 210 | def _generate_circuit(self, label: Tuple[int, int, int]) -> QuantumCircuit: 211 | """Generate a circuit based on the input label. 212 | 213 | The size of the input label determines the number of qubits. 214 | An ``sdg`` is added to the circuit for the qubit if the corresponding 215 | label value is a ``1``. 216 | 217 | Args: 218 | label: Label used to determine how the circuit is to be constructed. 219 | A tuple of 1s and 0s. 220 | 221 | Returns: 222 | Constructed circuit. 223 | """ 224 | num_qubit = len(label) 225 | qc = QuantumCircuit(num_qubit, num_qubit) 226 | qc.h(0) 227 | for i in range(1, num_qubit): 228 | qc.cx(0, i) 229 | qc.s(0) 230 | qc.barrier() 231 | for i in range(num_qubit): 232 | if label[i] == 1: 233 | qc.sdg(i) 234 | for i in range(num_qubit): 235 | qc.h(i) 236 | qc.measure(qc.qregs[0], qc.cregs[0]) 237 | return qc 238 | 239 | def _generate_all_circuits(self, num_circuits: int, wsr_bits: List) -> List[QuantumCircuit]: 240 | """Generate all circuits based on input WSR bits. 241 | 242 | Args: 243 | num_circuits: Number of circuits to generate. 244 | wsr_bits: WSR bits used to determine which circuits to use. 245 | 246 | Returns: 247 | A list of generated circuits. 248 | """ 249 | # Generate 3-qubit circuits for each of the 8 permutations. 250 | num_qubits = 3 251 | labels = list(product([0, 1], repeat=num_qubits)) 252 | 253 | # Generate base circuits. 254 | circuits = [] 255 | for label in labels: 256 | circuits.append(self._generate_circuit(label)) 257 | 258 | # Construct final circuits using input WSR bits. 259 | final_circuits = [] 260 | for i in range(num_circuits): 261 | wsr_set = wsr_bits[i] # Get the 3-bit value. 262 | final_circuits.append(circuits[labels.index(tuple(wsr_set))]) 263 | 264 | return final_circuits 265 | 266 | def _save_local( 267 | self, 268 | num_raw_bits: int, 269 | wsr_bits: List, 270 | job: Union[ManagedJobSet, BaseJob], 271 | shots: int 272 | ) -> str: 273 | """Save context information for the sampling. 274 | 275 | Args: 276 | num_raw_bits: Number of raw bits requested. 277 | wsr_bits: WSR bits to save. 278 | job: Job whose ID is to be saved. 279 | shots: Number of shots. 280 | 281 | Returns: 282 | Name of the file with saved data. 283 | """ 284 | file_prefix = "{}_{}_{}_".format( 285 | self._file_prefix, self.backend.name(), num_raw_bits) 286 | file_name = file_prefix + str(uuid.uuid4())[:4] 287 | while os.path.exists(file_name): 288 | file_name = file_prefix + str(uuid.uuid4())[:4] 289 | 290 | data = {"wsr": wsr_bits, "shots": shots} 291 | if isinstance(job, ManagedJobSet): 292 | data["job_id"] = job.job_set_id() 293 | data["job_type"] = "jobset" 294 | else: 295 | data["job_id"] = job.job_id() 296 | data["job_type"] = "job" 297 | with open(file_name, 'wb') as file: 298 | pickle.dump(data, file) 299 | return file_name 300 | 301 | @classmethod 302 | def recover(cls, file_name: str, provider: AccountProvider) -> GeneratorJob: 303 | """Recover a previously saved sampling run. 304 | 305 | Args: 306 | file_name: Name of the file containing saved context. 307 | provider: Provider used to do the sampling. 308 | 309 | Returns: 310 | Recovered output of the original :meth:`sample` call. 311 | """ 312 | with open(file_name, 'rb') as file: 313 | data = pickle.load(file) 314 | job_id = data['job_id'] 315 | job_type = data['job_type'] 316 | if job_type == "jobset": 317 | job = IBMQJobManager().retrieve_job_set(job_id, provider) 318 | else: 319 | job = provider.backends.retrieve_job(job_id) 320 | 321 | return GeneratorJob( 322 | initial_wsr=[], 323 | wsr=data['wsr'], 324 | job=job, 325 | shots=data["shots"], 326 | saved_fn=file_name 327 | ) 328 | -------------------------------------------------------------------------------- /qiskit_rng/generator_job.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This code is part of Qiskit. 4 | # 5 | # (C) Copyright IBM 2020. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | # (C) Copyright CQC 2020. 16 | # 17 | # This code is licensed under the Apache License, Version 2.0. You may 18 | # obtain a copy of this license in the LICENSE.txt file in the Programs 19 | # directory of this source or at http://www.apache.org/licenses/LICENSE-2.0. 20 | # 21 | # Any modifications or derivative works of this code must retain this 22 | # copyright notice, and modified files need to carry a notice indicating 23 | # that they have been altered from the originals. 24 | 25 | """Generator job.""" 26 | 27 | import os 28 | import logging 29 | from typing import List, Union, Optional 30 | 31 | from qiskit.providers.basejob import BaseJob 32 | from qiskit.providers.ibmq.managed.ibmqjobmanager import ManagedJobSet 33 | from qiskit.result.result import Result 34 | 35 | from .generator_result import GeneratorResult 36 | 37 | logger = logging.getLogger(__name__) 38 | 39 | 40 | class GeneratorJob: 41 | """Representation of a job that executes on a backend that can generate random numbers.""" 42 | 43 | def __init__( 44 | self, 45 | initial_wsr: List[int], 46 | wsr: List[List], 47 | job: Union[BaseJob, ManagedJobSet], 48 | shots: int, 49 | saved_fn: Optional[str] = None 50 | ) -> None: 51 | """GeneratorJob constructor. 52 | 53 | Args: 54 | initial_wsr: Initial raw WSRs. 55 | wsr: Processed WSRs used to generate circuits. 56 | job: Circuit job(s). 57 | shots: Number of shots. 58 | saved_fn: Name of the file used to save context information. 59 | """ 60 | self.initial_wsr = initial_wsr 61 | self.wsr = wsr 62 | self.job = job 63 | self.backend = job._backend 64 | self.shots = shots 65 | 66 | self.raw_bits_list = None 67 | self.formatted_wsr = None 68 | self.saved_fn = saved_fn 69 | 70 | def block_until_ready(self) -> GeneratorResult: 71 | """Block until result data is ready. 72 | 73 | Returns: 74 | A :class:`GeneratorResult` instance that contains information 75 | needed to run the extractor. 76 | """ 77 | logger.info("Waiting for jobs to finish.") 78 | if isinstance(self.job, ManagedJobSet): 79 | js_results = self.job.results() 80 | job_result = js_results.combine_results() 81 | else: 82 | job_result = self.job.result() 83 | logger.info("All jobs finished, transforming job results.") 84 | 85 | self.raw_bits_list = self._ibmq_result_transform(job_result) 86 | self._format_wsr() 87 | if self.saved_fn: 88 | try: 89 | os.remove(self.saved_fn) 90 | except Exception: # pylint: disable=broad-except 91 | logger.warning("Unable to delete file %s", self.saved_fn) 92 | return GeneratorResult(wsr=self.formatted_wsr, raw_bits_list=self.raw_bits_list, 93 | backend=self.backend) 94 | 95 | def _format_wsr(self): 96 | """Format the wsr. 97 | 98 | Convert the WSR to the format of 99 | ``[wsr1, wsr1, ... wsr1_n, wsr2, wsr2, ...]`` 100 | where ``n`` is the number of shots. Each wsr is a list of 3 bits. 101 | """ 102 | if not self.formatted_wsr: 103 | # Convert [wsr1, wsr2] to [wsr1, wsr1, ...wsr1_n, wsr2, wsr2, ...], 104 | # where n is the number of shots. Each wsr is a list of 3 bits. 105 | self.formatted_wsr = \ 106 | [wsr_set[:] for wsr_set in self.wsr for _ in range(self.shots)] 107 | 108 | def _ibmq_result_transform(self, result: Result) -> List[List]: 109 | """Transform IBMQ result data into the proper format. 110 | 111 | Args: 112 | result: Job result. 113 | 114 | Returns: 115 | Job results in the format of 116 | ``[circ1_shot1, circ1_shot2, ..., circ2_shot1, circ2_shot2, ...]``. 117 | Each circn_shotn is a list of 3 bits. 118 | """ 119 | all_results = [] 120 | for i in range(len(result.results)): 121 | # Convert ['101', '110', ...] to [[1, 0, 1], [0, 1, 1], ...] 122 | circ_mem = result.get_memory(i) # ['101', '110', ...] 123 | for shot_mem in circ_mem: 124 | shot_list = [int(mem) for mem in shot_mem] 125 | shot_list.reverse() 126 | all_results.append(shot_list) 127 | 128 | return all_results 129 | -------------------------------------------------------------------------------- /qiskit_rng/generator_result.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This code is part of Qiskit. 4 | # 5 | # (C) Copyright IBM 2020. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | # (C) Copyright CQC 2020. 16 | # 17 | # This code is licensed under the Apache License, Version 2.0. You may 18 | # obtain a copy of this license in the LICENSE.txt file in the Programs 19 | # directory of this source or at http://www.apache.org/licenses/LICENSE-2.0. 20 | # 21 | # Any modifications or derivative works of this code must retain this 22 | # copyright notice, and modified files need to carry a notice indicating 23 | # that they have been altered from the originals. 24 | 25 | """Generator job result.""" 26 | 27 | from typing import List, Optional, Callable, Tuple 28 | from math import floor 29 | 30 | from qiskit.providers.basebackend import BaseBackend 31 | from qiskit.providers.ibmq.exceptions import IBMQError 32 | 33 | from .utils import (bell_value, generate_wsr, get_extractor_bits, bitarray_to_bytes, 34 | h_mins, na_set, dodis_output_size, hayashi_parameters) 35 | from .model import CQCExtractorParams 36 | from .exceptions import RNGNotAuthorizedError 37 | 38 | 39 | class GeneratorResult: 40 | """Representation of random number sampling result.""" 41 | 42 | def __init__( 43 | self, 44 | wsr: List[List[int]], 45 | raw_bits_list: List[List[int]], 46 | backend: BaseBackend 47 | ) -> None: 48 | """GeneratorResult constructor. 49 | 50 | Bell values are calculated based on the input parameters. The values include: 51 | 52 | * mermin_correlator: Mermin correlator value. The statistical value 53 | calculated from the probability distributions. 54 | This verifies quantum correlations when >2, as 2 is the maximal value possible 55 | in a classical setup. 56 | * winning_probability: Probability of "winning" each round in the Mermin 57 | quantum game. It is used to verify quantum correlations (the maximum 58 | probability in a classical implementation is 87.5%). 59 | * losing_probability: 1-`winning_probability`. 60 | 61 | Args: 62 | wsr: WSR used to generate the circuits. 63 | raw_bits_list: A list of formatted bits from job results. 64 | backend: Backend used to generate the bits. 65 | """ 66 | self.wsr = wsr 67 | self._raw_bits_list = raw_bits_list 68 | self.raw_bits = [bit for sublist in raw_bits_list for bit in sublist] 69 | self.backend = backend 70 | 71 | self.losing_probability, self.winning_probability, self.mermin_correlator = \ 72 | bell_value(wsr, raw_bits_list) 73 | 74 | def bell_values(self) -> Tuple[float, float, float]: 75 | """Return a tuple of the bell values. 76 | 77 | Returns: 78 | The losing probability, winning probability, and Mermin correlator. 79 | """ 80 | return self.losing_probability, self.winning_probability, self.mermin_correlator 81 | 82 | def get_cqc_extractor_params( 83 | self, 84 | rate_sv: float = 0.95, 85 | expected_correlator: Optional[float] = None, 86 | epsilon_sec: float = 1e-30, 87 | quantum_proof: bool = False, 88 | trusted_backend: bool = True, 89 | privacy: bool = False, 90 | wsr_generator: Optional[Callable] = None 91 | ) -> CQCExtractorParams: 92 | """Return parameters for the CQC extractors. 93 | 94 | Dodis is the first 2-source extractor that takes the Bell value 95 | and the WSR, in order to generate high-quality random bits. 96 | 97 | Hayashi is the second extractor. It takes the output of the first extractor 98 | and another WSR string to increase the size of the final output string. 99 | The second extractor is only used if `trusted_backend` is ``True`` and 100 | `privacy` is ``False``. 101 | 102 | Args: 103 | rate_sv: Assumed randomness rate of the initial WSR as a Santha-Vazirani source. 104 | expected_correlator: The expected correlator value. 105 | :data:`qiskit_rng.constants.EXPECTED_CORRELATOR` 106 | contains known values for certain backends. If ``None``, the observed value 107 | from the sampling output is used. 108 | epsilon_sec: The distance to uniformity of the final bit string. When performing 109 | privacy amplification as well, this is the distance to a perfectly 110 | uniform and private string. 111 | quantum_proof: Set to ``True`` for quantum-proof extraction in the Markov 112 | model (most secure), ``False`` for classical-proof extraction in the 113 | standard model. Note that setting this to ``True`` reduces the generation 114 | rates considerably. 115 | trusted_backend: ``True`` if the raw bits were generated by a trusted 116 | backend and communicated securely. 117 | privacy: ``True`` if privacy amplification is to be performed. 118 | wsr_generator: Function used to generate WSR. It must take the 119 | number of bits as the input and a list of random bits (0s and 1s) 120 | as the output. 121 | 122 | Returns: 123 | A ``CQCExtractorParams`` instance that contains all the parameters 124 | needed for the extractors. 125 | 126 | Raises: 127 | ValueError: If an input argument is invalid. 128 | """ 129 | expected_correlator = expected_correlator or self.mermin_correlator 130 | 131 | if self.mermin_correlator < expected_correlator: 132 | raise ValueError("Observed correlator value {} is lower than expected value {}. " 133 | "Rerun with a larger sample size or use a different backend.".format( 134 | self.mermin_correlator, expected_correlator)) 135 | 136 | if privacy and not trusted_backend: 137 | raise ValueError("Cannot perform privacy amplification using a untrusted backend.") 138 | 139 | if wsr_generator is None: 140 | wsr_generator = generate_wsr 141 | 142 | correlator = expected_correlator 143 | losing_prob = (4-correlator)/16 144 | 145 | bits = get_extractor_bits(self._raw_bits_list) 146 | num_bits = len(bits) 147 | rate_bt = h_mins(losing_prob, num_bits, rate_sv) 148 | 149 | # EXT1 (Dodis): 150 | epsilon_dodis = epsilon_sec/2 151 | n_dodis = na_set(num_bits-1)+1 152 | diff = num_bits - n_dodis 153 | # Adjust rate_bt in case bits need to be dropped due to 154 | # Dodis input size restriction. 155 | rate_bt = (num_bits*rate_bt-diff)/(num_bits-diff) 156 | bits = bits[:n_dodis] 157 | if na_set(n_dodis-1)+1 != n_dodis: 158 | raise ValueError("Wrong computation in the first extractor input size.") 159 | dodis_output_len = dodis_output_size( 160 | n_dodis, rate_bt, rate_sv, epsilon_dodis, quantum_proof) 161 | if dodis_output_len < 50: 162 | raise ValueError('Not enough output for the first extractor. Try ' 163 | 'reducing security parameters or increasing sample size.') 164 | 165 | raw_bytes = bitarray_to_bytes(bits) 166 | wsr_bytes = bitarray_to_bytes(wsr_generator(n_dodis)) 167 | 168 | # EXT2 (Hayashi): 169 | ext2_params = [0, 0] 170 | if trusted_backend and not privacy: 171 | max_hayashi_size = 5*10**8 172 | epsilon_hayashi_tolerance = epsilon_dodis 173 | 174 | tem = round((1 - rate_sv) * 10**8) / 10**8 175 | c_max = floor(1 / tem) 176 | hayashi_inputs = na_set(dodis_output_len) 177 | if hayashi_inputs > max_hayashi_size: 178 | raise ValueError('Input size is too large for the second extractor ' 179 | 'to handled.') 180 | 181 | epsilon_hayashi = 1 182 | c_pen = 0 183 | c = 0 184 | while epsilon_hayashi > epsilon_hayashi_tolerance: 185 | if c_pen == c_max: 186 | raise ValueError('Invalid security parameters for the second extractor.') 187 | c, epsilon_hayashi = hayashi_parameters(hayashi_inputs, rate_sv, c_max, c_pen) 188 | c_pen += 1 189 | 190 | ext2_params = [hayashi_inputs, c] 191 | 192 | return CQCExtractorParams( 193 | ext1_input_num_bits=n_dodis, 194 | ext1_output_num_bits=dodis_output_len, 195 | ext1_raw_bytes=raw_bytes, 196 | ext1_wsr_bytes=wsr_bytes, 197 | ext2_seed_num_bits=ext2_params[0], 198 | ext2_wsr_multiplier=ext2_params[1], 199 | ext2_wsr_generator=wsr_generator) 200 | 201 | def extract( 202 | self, 203 | rate_sv: float = 0.95, 204 | expected_correlator: Optional[float] = None, 205 | epsilon_sec: float = 1e-30, 206 | quantum_proof: bool = False, 207 | trusted_backend: bool = True, 208 | privacy: bool = False, 209 | wsr_generator: Optional[Callable] = None 210 | ) -> List[int]: 211 | """Invoke CQC extractor synchronously. 212 | 213 | Note: 214 | This method uses the CQC extractor service on IBM Quantum Experience 215 | and will raise an ``RNGNotAuthorizedError`` if you don't have access 216 | to the service. 217 | 218 | Args: 219 | rate_sv: Assumed randomness rate of the initial WSR as a Santha-Vazirani source. 220 | expected_correlator: The expected correlator value. 221 | :data:`qiskit_rng.constants.EXPECTED_CORRELATOR` 222 | contains known values for certain backends. If ``None``, the observed value 223 | from the sampling output is used. 224 | epsilon_sec: The distance to uniformity of the final bit string. When performing 225 | privacy amplification as well, this is the distance to a perfectly 226 | uniform and private string. 227 | quantum_proof: Set to ``True`` for quantum-proof extraction in the Markov 228 | model (most secure), ``False`` for classical-proof extraction in the 229 | standard model. Note that setting this to ``True`` reduces the generation 230 | rates considerably. 231 | trusted_backend: ``True`` if the raw bits were generated by a trusted 232 | backend and communicated securely. 233 | privacy: ``True`` if privacy amplification is to be performed. 234 | wsr_generator: Function used to generate WSR. It must take the 235 | number of bits as the input and a list of random bits (0s and 1s) 236 | as the output. 237 | 238 | Returns: 239 | The extracted random bits. 240 | 241 | Raises: 242 | RNGNotAuthorizedError: If you are not authorized to use the CQC extractor. 243 | """ 244 | try: 245 | extractor = self.backend.provider().random.get_service('cqc_extractor') 246 | except IBMQError: 247 | raise RNGNotAuthorizedError("You are not authorized to use the CQC extractor.") 248 | 249 | params = self.get_cqc_extractor_params( 250 | rate_sv=rate_sv, expected_correlator=expected_correlator, 251 | epsilon_sec=epsilon_sec, quantum_proof=quantum_proof, 252 | trusted_backend=trusted_backend, privacy=privacy, 253 | wsr_generator=wsr_generator) 254 | return extractor.run(*params) 255 | -------------------------------------------------------------------------------- /qiskit_rng/model.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This code is part of Qiskit. 4 | # 5 | # (C) Copyright IBM 2020. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | # (C) Copyright CQC 2020. 16 | # 17 | # This code is licensed under the Apache License, Version 2.0. You may 18 | # obtain a copy of this license in the LICENSE.txt file in the Programs 19 | # directory of this source or at http://www.apache.org/licenses/LICENSE-2.0. 20 | # 21 | # Any modifications or derivative works of this code must retain this 22 | # copyright notice, and modified files need to carry a notice indicating 23 | # that they have been altered from the originals. 24 | 25 | """Module for different object models.""" 26 | 27 | from typing import NamedTuple, Callable 28 | 29 | 30 | class CQCExtractorParams(NamedTuple): 31 | """Named tuple used to hold parameters to a CQC extractor.""" 32 | ext1_input_num_bits: int 33 | ext1_output_num_bits: int 34 | ext1_raw_bytes: bytes 35 | ext1_wsr_bytes: bytes 36 | ext2_seed_num_bits: int 37 | ext2_wsr_multiplier: int 38 | ext2_wsr_generator: Callable 39 | -------------------------------------------------------------------------------- /qiskit_rng/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This code is part of Qiskit. 4 | # 5 | # (C) Copyright IBM 2020. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | # (C) Copyright CQC 2020. 16 | # 17 | # This code is licensed under the Apache License, Version 2.0. You may 18 | # obtain a copy of this license in the LICENSE.txt file in the Programs 19 | # directory of this source or at http://www.apache.org/licenses/LICENSE-2.0. 20 | # 21 | # Any modifications or derivative works of this code must retain this 22 | # copyright notice, and modified files need to carry a notice indicating 23 | # that they have been altered from the originals. 24 | 25 | """Module for utility functions.""" 26 | 27 | import logging 28 | from typing import List, Tuple 29 | from math import sqrt, log2, floor 30 | 31 | import numpy as np 32 | 33 | logger = logging.getLogger(__name__) 34 | 35 | 36 | def bell_value( 37 | wsr: List[List[int]], 38 | raw_bits: List[List[int]] 39 | ) -> Tuple[float, float, float]: 40 | """Calculate the bell values. 41 | 42 | Args: 43 | wsr: WSR used to calculate the raw bits. 44 | raw_bits: Random bits used to calculate the bell values. 45 | 46 | Returns: 47 | A tuple of Mermin losing probability, winning probability, and correlator. 48 | """ 49 | losing_prob = 0 50 | for i in range(len(wsr)): # pylint: disable=consider-using-enumerate 51 | wsr_sum = sum(wsr[i]) 52 | raw_bits_sum = sum(raw_bits[i]) 53 | if wsr_sum == 1 and raw_bits_sum % 2 == 1: 54 | losing_prob += 1 55 | elif wsr_sum == 3 and raw_bits_sum % 2 == 0: 56 | losing_prob += 1 57 | losing_prob = losing_prob / len(wsr) 58 | winning_prob = 1 - losing_prob 59 | correlator = 4-16*losing_prob 60 | 61 | return losing_prob, winning_prob, correlator 62 | 63 | 64 | def get_extractor_bits(raw_bits: List[List[int]]) -> List[int]: 65 | """Return bits to be used by the extractor. 66 | 67 | Args: 68 | raw_bits: Input raw bits from sampling jobs. 69 | 70 | Returns: 71 | A list of bits that can be used by the extractor. 72 | """ 73 | bits = [] 74 | for bit_set in raw_bits: 75 | bits += bit_set[:2] 76 | return bits 77 | 78 | 79 | def h_mins(bt_value: float, num_bits: int, rate_sv: float) -> float: 80 | """Calculate the minimum entropy for each bit. 81 | 82 | Args: 83 | bt_value: Bell value. 84 | num_bits: The 2/3 outcomes bits from each circuit. 85 | rate_sv: The assumption on the initial randomness rate of the WSR as a 86 | Santha-Vazirani source. 87 | 88 | Returns: 89 | Minimum entropy for each bit. 90 | """ 91 | epsilon_sv = 2**(-rate_sv) - 1 / 2 92 | h_min_bt = -num_bits / 2 * log2(guessing_probability(bt_adjusting(bt_value, epsilon_sv))) 93 | rate_bt = h_min_bt / num_bits 94 | return rate_bt 95 | 96 | 97 | def na_set(num_bits: int) -> int: 98 | """Ensure the number of runs falls within the correct set. 99 | 100 | This is to validate the inputs to the extractor and involves checking the 101 | primality of the input. 102 | 103 | Args: 104 | num_bits: Number to check is in the set. 105 | 106 | Returns: 107 | Updated number in the set. 108 | """ 109 | if num_bits % 2 != 0: 110 | num_bits = num_bits - 1 111 | stop = False 112 | while not stop: 113 | stop = True 114 | while not prime_check(num_bits + 1): 115 | num_bits = num_bits - 2 116 | output = prime_factors(num_bits, True) 117 | prime_powers = output[1] 118 | primes = output[0] 119 | for i in range(len(prime_powers)): 120 | test = pow(2, int(num_bits / primes[i]), num_bits + 1) 121 | if test == 1: 122 | stop = False 123 | if not stop: 124 | num_bits = num_bits - 2 125 | return num_bits 126 | 127 | 128 | def prime_check(num: int) -> bool: 129 | """Check whether the input number is a prime number. 130 | 131 | Args: 132 | num: Number to be checked. 133 | 134 | Returns: 135 | Whether the number is a prime. 136 | """ 137 | for i in range(2, round(sqrt(num)) + 1): 138 | if num % i == 0: 139 | return False 140 | return True 141 | 142 | 143 | def prime_factors(num: int, use_power: bool) -> List: 144 | """Return the prime factors of the input number. 145 | 146 | Args: 147 | num: The number whose prime factors are to be returned. 148 | use_power: If ``True``, return the factors in the format of [[X, Y], [a, b]] 149 | where num=X**a*Y**b. For example, ``prime_factors(12, False)`` returns 150 | ``[2, 2, 3]`` and ``prime_factors(12, True)`` returns ``[[2, 3], [2, 1]]``. 151 | 152 | Returns: 153 | Prime factors. 154 | """ 155 | factors = [] 156 | i = 2 157 | while i <= round(sqrt(num))+1: 158 | if num % i == 0: 159 | factors = np.append(factors, i) 160 | num = num / i 161 | else: 162 | i = i + 1 163 | if num != 1: 164 | factors = np.append(factors, num) 165 | factors_size = factors.size 166 | factors2 = [factors[0]] 167 | powers = [1] 168 | power_idx = 0 169 | for i in range(1, factors_size): 170 | if factors[i] == factors[i-1]: 171 | powers[power_idx] = powers[power_idx]+1 172 | if factors[i] != factors[i-1]: 173 | powers.append(1) 174 | power_idx = power_idx+1 175 | factors2.append(factors[i]) 176 | if not use_power: 177 | return factors 178 | return [factors2, powers] 179 | 180 | 181 | def dodis_output_size( 182 | num_bits: int, 183 | rate_bt: float, 184 | rate_sv: float, 185 | epsilon_dodis: float, 186 | q_proof: bool 187 | ) -> int: 188 | """Calculate the output size of the Dodis extractor. 189 | 190 | Args: 191 | num_bits: The 2/3 outcomes bits from each circuit. 192 | rate_bt: How much randomness is in each bit. 193 | rate_sv: The assumption on the initial randomness rate f the WSR as 194 | a Santha-Vazirani source. 195 | epsilon_dodis: Security parameter defining the distance to uniformity of 196 | the final bit string. 197 | q_proof: Whether quantum proof extraction is needed. 198 | 199 | Returns: 200 | Output size of the Dodis extractor. 201 | """ 202 | if not q_proof: 203 | return floor(num_bits * (rate_bt + rate_sv - 1) + 1 - 2 * log2(1 / epsilon_dodis)) 204 | return floor(1 / 5 * (num_bits * (rate_bt + rate_sv - 1) + 1 - 8 * 205 | log2(1 / epsilon_dodis) - 8 * log2(sqrt(3) / 2))) 206 | 207 | 208 | def bt_adjusting(bt_value: float, epsilon: float, delta_finite_stat: int = 0) -> float: 209 | """Creates an adjustment value related to the probability of error due to finite stats. 210 | 211 | Args: 212 | bt_value: Bell value. 213 | epsilon: How close the output string is to that of a perfect distribution. 214 | delta_finite_stat: Set to zero to assume no finite statistical effects. 215 | 216 | Returns: 217 | Adjusted Bell value. 218 | """ 219 | bt_adjusted = (bt_value + delta_finite_stat) / (8 * ((0.5 - epsilon)**3)) 220 | return bt_adjusted 221 | 222 | 223 | def guessing_probability(bt_adjusted: float) -> float: 224 | """Calculate the probability an adversary could guess the bell value. 225 | 226 | Also known as the 'predictive power', this probability gives 227 | an indication of the quality of the randomness. 228 | 229 | Args: 230 | bt_adjusted: Adjusted bell value. 231 | 232 | Returns: 233 | The guessing probability. 234 | """ 235 | if bt_adjusted >= 1 / 16: 236 | probability = 0.5 + 4 * bt_adjusted 237 | if bt_adjusted < 1 / 16: 238 | probability = 0.25 + 2 * bt_adjusted + \ 239 | sqrt(3) * sqrt((bt_adjusted - 4 * (bt_adjusted**2))) 240 | if bt_adjusted >= 1 / 8: 241 | probability = 1 242 | return probability 243 | 244 | 245 | def hayashi_parameters( 246 | input_size: int, 247 | rate_sv: float, 248 | c_max: int, 249 | c_penalty: int 250 | ) -> Tuple[int, float]: 251 | """Generate parameters for the Hayashi extractor. 252 | 253 | Args: 254 | input_size: Size in bits of the input string. 255 | rate_sv: The assumption on the initial randomness rate of the WSR 256 | used as a Santha-Vazirani source. 257 | c_max: Computed maximum value. 258 | c_penalty: Computed penalty value. 259 | 260 | Returns: 261 | A tuple consists of the multiplier and the Hayashi epsilon value. 262 | 263 | Raises: 264 | ValueError: If the parameters are invalid for the second extractor. 265 | """ 266 | c = c_max - c_penalty 267 | if c < 2: 268 | raise ValueError("Invalid parameters for the second extractor.") 269 | epsilon_hayashi = sqrt(c - 1) * pow(2, input_size / 2 * (c * (1 - rate_sv) - 1)) 270 | 271 | return c, epsilon_hayashi 272 | 273 | 274 | def bitarray_to_bytes(bitarray: List[int]) -> bytes: 275 | """Convert an array of bits to bytes. 276 | 277 | Args: 278 | bitarray: Bit array to be converted. 279 | 280 | Returns: 281 | Input array in bytes. 282 | """ 283 | n_bits = len(bitarray) 284 | n_bytes = (n_bits + 7) >> 3 285 | int_array = [0] * n_bytes 286 | for i in range(n_bits): 287 | int_array[i >> 3] |= bitarray[i] << (i & 7) 288 | return bytes(int_array) 289 | 290 | 291 | def bytes_to_bitarray(the_bytes: bytes, num_bits: int) -> List[int]: 292 | """Convert input bytes into an array of bits. 293 | 294 | Args: 295 | the_bytes: Bytes to be converted. 296 | num_bits: Number of bits to return. 297 | 298 | Returns: 299 | An array of bits. 300 | """ 301 | return [(the_bytes[i >> 3] >> (i & 7)) & 1 for i in range(num_bits)] 302 | 303 | 304 | def generate_wsr(num_bits: int) -> List[int]: 305 | """Generate a list of WSR bits. 306 | 307 | Args: 308 | num_bits: Number of bits needed. 309 | 310 | Returns: 311 | A list of random binary numbers. 312 | """ 313 | return list(np.random.randint(2, size=num_bits)) 314 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | pylint==2.4.4 2 | pycodestyle 3 | Sphinx>=3.0 4 | pydata_sphinx_theme 5 | sphinx-tabs>=1.1.11 6 | sphinx-autodoc-typehints 7 | stestr>=2.5.0 -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | qiskit-ibmq-provider>=0.10 2 | qiskit-terra>=0.16.2 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This code is part of Qiskit. 4 | # 5 | # (C) Copyright IBM 2020. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | import os 16 | 17 | from setuptools import setup, find_packages 18 | 19 | REQUIREMENTS = [ 20 | "qiskit-ibmq-provider>=0.10", 21 | "qiskit-terra>=0.16.2" 22 | ] 23 | 24 | # Read long description from README. 25 | README_PATH = os.path.join(os.path.abspath(os.path.dirname(__file__)), 26 | 'README.md') 27 | with open(README_PATH) as readme_file: 28 | README = readme_file.read() 29 | 30 | version_path = os.path.abspath(os.path.join( 31 | os.path.dirname(__file__), 'qiskit_rng', 32 | 'VERSION.txt')) 33 | 34 | with open(version_path, 'r') as fd: 35 | version_str = fd.read().rstrip() 36 | 37 | setup( 38 | name="qiskit_rng", 39 | version=version_str, 40 | description="Qiskit Random Number Generator.", 41 | long_description=README, 42 | long_description_content_type='text/markdown', 43 | url="https://github.com/qiskit-community/qiskit_rng", 44 | author="Qiskit Development Team", 45 | author_email="hello@qiskit.org", 46 | license="Apache 2.0", 47 | classifiers=[ 48 | "Environment :: Console", 49 | "License :: OSI Approved :: Apache Software License", 50 | "Intended Audience :: Developers", 51 | "Intended Audience :: Science/Research", 52 | "Operating System :: Microsoft :: Windows", 53 | "Operating System :: MacOS", 54 | "Operating System :: POSIX :: Linux", 55 | "Programming Language :: Python :: 3 :: Only", 56 | "Programming Language :: Python :: 3.6", 57 | "Programming Language :: Python :: 3.7", 58 | "Programming Language :: Python :: 3.8", 59 | "Topic :: Scientific/Engineering", 60 | ], 61 | keywords="qiskit quantum cqc qrng", 62 | packages=find_packages(exclude=['test*']), 63 | install_requires=REQUIREMENTS, 64 | include_package_data=True, 65 | python_requires=">=3.6", 66 | project_urls={ 67 | "Bug Tracker": "https://github.com/qiskit-community/qiskit_rng/issues", 68 | "Documentation": "https://qiskit-rng.readthedocs.io", 69 | "Source Code": "https://github.com/qiskit-community/qiskit_rng", 70 | }, 71 | zip_safe=False 72 | ) 73 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This code is part of Qiskit. 4 | # 5 | # (C) Copyright IBM 2020. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | """Test for Qiskit RNG.""" 16 | -------------------------------------------------------------------------------- /test/test_generator.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # This code is part of Qiskit. 4 | # 5 | # (C) Copyright IBM 2020. 6 | # 7 | # This code is licensed under the Apache License, Version 2.0. You may 8 | # obtain a copy of this license in the LICENSE.txt file in the root directory 9 | # of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. 10 | # 11 | # Any modifications or derivative works of this code must retain this 12 | # copyright notice, and modified files need to carry a notice indicating 13 | # that they have been altered from the originals. 14 | 15 | """Test for the generator.""" 16 | 17 | from unittest import TestCase, mock 18 | import os 19 | 20 | from qiskit.test.mock.backends import FakeValencia 21 | from qiskit_rng import Generator, GeneratorJob, GeneratorResult 22 | 23 | 24 | class TestGenerator(TestCase): 25 | """Test random number generator.""" 26 | 27 | def test_sample_basic(self): 28 | """Test basic sampling.""" 29 | generator = Generator(FakeValencia()) 30 | job = generator.sample(num_raw_bits=100) 31 | self.assertIsInstance(job, GeneratorJob) 32 | result = job.block_until_ready() 33 | self.assertIsInstance(result, GeneratorResult) 34 | 35 | def test_custom_wsr(self): 36 | """Test using custom wsr generator.""" 37 | def _wsr_gen(num_bits): 38 | nonlocal gen_wsr 39 | gen_wsr = [1]*num_bits 40 | return gen_wsr 41 | 42 | gen_wsr = None 43 | generator = Generator(backend=FakeValencia(), wsr_generator=_wsr_gen) 44 | job = generator.sample(num_raw_bits=100) 45 | self.assertEqual(job.initial_wsr, gen_wsr) 46 | 47 | def test_save_local(self): 48 | """Test saving data locally.""" 49 | generator = Generator(FakeValencia(), save_local=True) 50 | job = generator.sample(num_raw_bits=100) 51 | # Need to manually save since the backend is not an IBMQBackend. 52 | generator._save_local(100, job.wsr, job.job, job.shots) 53 | saved_fn = None 54 | file_prefix = Generator._file_prefix + '_' 55 | for entry in os.listdir(): 56 | if entry.startswith(file_prefix): 57 | saved_fn = entry 58 | break 59 | self.assertTrue(saved_fn, "No saved file found.") 60 | job.saved_fn = saved_fn 61 | r_job = Generator.recover(saved_fn, mock.MagicMock()) 62 | job.block_until_ready() 63 | try: 64 | self.assertFalse(any(fn.startswith(file_prefix) for fn in os.listdir())) 65 | except AssertionError: 66 | os.remove(saved_fn) 67 | raise 68 | self.assertEqual(r_job.wsr, job.wsr) 69 | self.assertEqual(r_job.shots, job.shots) 70 | 71 | def test_num_circs_shots(self): 72 | """Test the number of circuits and shots generated.""" 73 | backend = FakeValencia() 74 | generator = Generator(backend) 75 | max_experiments = 5 76 | max_shots = 10 77 | backend._configuration.max_experiments = max_experiments 78 | backend._configuration.max_shots = max_shots 79 | sub_tests = [1, 3*max_shots, 3*max_shots+1, 3*max_shots-1, 80 | 3*max_shots*2, 3*max_shots*2+1, 3*max_shots*max_experiments-1] 81 | for num_raw_bits in sub_tests: 82 | with self.subTest(num_raw_bits=num_raw_bits): 83 | result = generator.sample(num_raw_bits=num_raw_bits).block_until_ready() 84 | self.assertGreaterEqual(len(result.raw_bits), num_raw_bits) 85 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | minversion = 2.1 3 | envlist = py36, py37, py38, lint 4 | skipsdist = True 5 | 6 | [testenv] 7 | usedevelop = true 8 | install_command = pip install -c{toxinidir}/constraints.txt -U {opts} {packages} 9 | setenv = 10 | VIRTUAL_ENV={envdir} 11 | LANGUAGE=en_US 12 | LC_ALL=en_US.utf-8 13 | deps = 14 | -r{toxinidir}/requirements.txt 15 | -r{toxinidir}/requirements-dev.txt 16 | commands = 17 | stestr run {posargs} 18 | 19 | [testenv:lint] 20 | deps = 21 | pycodestyle 22 | pylint 23 | commands = 24 | pycodestyle qiskit_rng test 25 | pylint -rn --rcfile={toxinidir}/.pylintrc qiskit_rng test 26 | 27 | [testenv:docs] 28 | basepython = python3 29 | deps = 30 | -r{toxinidir}/requirements-dev.txt 31 | commands = 32 | sphinx-build -b html -W {posargs} docs/ docs/_build/html 33 | 34 | [pycodestyle] 35 | max-line-length = 100 --------------------------------------------------------------------------------