GithubHelp home page GithubHelp logo

pedrorrivero / qrand Goto Github PK

View Code? Open in Web Editor NEW
22.0 4.0 13.0 592 KB

A multiprotocol and multiplatform quantum random number generation framework

Home Page: https://pypi.org/project/qrand/

License: Apache License 2.0

Python 99.83% TeX 0.17%
random-number-generator quantum-computing numpy qrng-protocols

qrand's People

Contributors

avhijit-codeboy avatar charmerdark avatar pedrorrivero avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

qrand's Issues

Name QRAND generated jobs

Is your feature request related to a problem? Please describe.

QRAND will make requests to quantum backends in order to randomly generate numbers. These requests (i.e. jobs) will have a unique id associated to each of them given by the backend; however, it is very difficult to tell apart which of these requests were made from QRAND when looking at the information stored in the provider.

Describe the solution you'd like

By given QRAND's jobs a particular, easily distinguishable, friendly name we will be able to tell them apart in the provider (e.g. IBM-Q website). Ideally this name will contain:

  1. The word QRAND.
  2. The name of the author.
  3. The name of theBareQuantumProtocol being run.
  4. Timestamp id.

E.g.: QRAND by Pedro Rivero - EntanglementProtocol | 2021-06-06T20:14:00Z

If we want to include the name of the protocol, we will need to add a name str parameter to create_job in QuantumFactory. The easiest way to implement this is by defining a property in QuantumProtocol called job_name. This will be inherited by all protocols, and produce an updated name every time it is called (i.e. updating the protocol name through self.__class__.__name__ or type(self).__name__, as well as the timestamp). Since we are using a decorator structure, the name will have to be produce by BareQuantumProtocol and tunneled all the way up through the ValidationDecorator class.

Describe alternatives you've considered

The alternative would be to hardcode the name inside every platform's QuantumJob, but this will not be able to display the name of the protocol.

Additional context

Qiskit: Qiskit/qiskit-ibmq-provider#118, and job_name
Q#: azure.execute documentation.

Unable to install qrand

Describe the bug

Unable to install qrand using pip in Windows, Colab and IBM Quantum Experience portal.

To Reproduce

Steps to reproduce the behavior:

  1. Open Python terminal
  2. run pip install qrand
  3. See error

Expected behavior

Install qrand library

Error

ERROR: Could not find a version that satisfies the requirement qrand
ERROR: No matching distribution found for qrand

Desktop (please complete the following information):

  • Device: all
  • OS: Win, Linux
  • QRAND version: 0.4.0

Additional context

Add any other context about the problem here.

Q# support

The following classes need to be developed implementing the corresponding interfaces:

  • QsharpPlatformQuantumPlatform
  • QsharpBackendQuantumBackend
  • QsharpJobQuantumJob
  • QsharpCircuitQuantumCircuit

The first of these classes follows the Facade/Abstract Factory pattern, while the other two are Class Adapters. For an example check the Qiskit variants.

Test case associated with `get_random_complex_polar` failing

Describe the bug

TestBitCache.test_get_random_complex_polar test case failing

To Reproduce

Steps to reproduce the behavior:

  1. Go to 'qrng.py'
  2. Make some relevant changes to the file
  3. Git commit the file
  4. See error

Expected behavior

All the test cases passing and the commit being successful.

Screenshots

image

Desktop (please complete the following information):

  • Device: Acer aspire E 15
  • OS: Windows 10 home edition
  • QRAND version: 0.3.0a1

Additional context

The entire error message -

isort....................................................................Passed
mypy.....................................................................Passed
black....................................................................Passed
flake8...................................................................Passed
pytest...................................................................Failed
- hook id: pytest
- exit code: 1

============================= test session starts =============================
platform win32 -- Python 3.8.3, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: F:\QuantumProgrammes\unitaryHack\qrand
plugins: cov-2.11.1
collected 32 items

tests\test_qiskit_bit_generator.py .....................                 [ 65%]
tests\test_qrand.py ..                                                   [ 71%]
tests\test_qrng.py .F.......                                             [100%]

================================== FAILURES ===================================
_________________ TestBitCache.test_get_random_complex_polar __________________

self = <tests.test_qrng.TestBitCache object at 0x000001BCCF8B1E20>

    def test_get_random_complex_polar(self):
        bitgen = QiskitBitGenerator()
        qrng = Qrng(bitgen)
        cache = "100" * 1000
        bitgen.load_cache(cache)
        assert (
            qrng.get_random_complex_polar()
            == 0.4713139887723277 + 0.5910090485061033j
        )
        assert (
            qrng.get_random_complex_polar(4)
            == -1.9263524684802522 - 0.9276824556973191j
        )
>       assert (
            qrng.get_random_complex_polar(4, 3.14)
            == 0.9431657500378959 + 1.1815890375548252j
        )
E       assert (0.9431657500378958+1.1815890375548252j) == (0.9431657500378959 + 1.1815890375548252j)
E        +  where (0.9431657500378958+1.1815890375548252j) = <bound method Qrng.get_random_complex_polar of <qrand.qrng.Qrng object at 0x000001BCCF8B1AF0>>(4, 3.14)
E        +    where <bound method Qrng.get_random_complex_polar of <qrand.qrng.Qrng object at 0x000001BCCF8B1AF0>> = <qrand.qrng.Qrng object at 0x000001BCCF8B1AF0>.get_random_complex_polar

tests\test_qrng.py:57: AssertionError
============================== warnings summary ===============================
tests/test_qiskit_bit_generator.py: 15 warnings
tests/test_qrand.py: 1 warning
tests/test_qrng.py: 9 warnings
  F:\QuantumProgrammes\unitaryHack\qrand\qrand\_qiskit_bit_generator.py:119: FutureWarning: QiskitBitGenerator will be deprecated in version 1.0.0. Use QuantumBitGenerator and QiskitPlatform instead.
    warn(WARNING_MESSAGE, FutureWarning)

tests/test_qrng.py::TestBitCache::test_state
  F:\QuantumProgrammes\unitaryHack\qrand\qrand\qrng.py:308: FutureWarning: state() will be deprecated in version 1.0.0.
    warn(WARNING_MESSAGE, FutureWarning)

-- Docs: https://docs.pytest.org/en/stable/warnings.html

----------- coverage: platform win32, python 3.8.3-final-0 -----------
Coverage HTML written to dir coverage-html

=========================== short test summary info ===========================
FAILED tests/test_qrng.py::TestBitCache::test_get_random_complex_polar - asse...
================== 1 failed, 31 passed, 26 warnings in 2.91s ==================

Expand Python version compatibility

Is your feature request related to a problem? Please describe.

Currently, QRAND can only be installed for Python >= 3.9.

Describe the solution you'd like

QRAND should work with Python versions >=:

  • 3.8
  • 3.7

Additional context

The reason why Python 3.9 was used initially is that previous version seemed to be unstable when interfaced with Qiskit.

Read The Docs

What is the nature of the issue?

Missing documentation.

Describe the issue

Build a Read The Docs website.

What content needs to be added, updated, or replaced?

  • Theme
  • Menu
  • Docstrings

Additional context

Project already created: https://qrand.readthedocs.io/

Use of a deprecated syntax for `super()`

Describe the bug

The QiskitCircuit class contains 21 occurrences of super(QuantumCircuit, self).

With a restrictive linter, this generates 21 error-level messages Bad first argument 'QuantumCircuit' given to super().

PEP 3135 introduced a new syntax for super(), where the child class calling super() should not be mentioned any longer. See here and here.

Unless there is a reason for using this ancient syntax?

To Reproduce

Steps to reproduce the behavior:

  1. Open QiskitCircuit with a restrictive linter, such as pylint.

Expected behavior

No error messages thrown by the linter (that is no use of the ancient syntax).

Screenshots

Not appllicable.

Desktop (please complete the following information):

  • pylint version: v2.8.2
  • Python version: v3.9.5
  • QRAND version: v0.4.0

Additional context

Not applicable.

Random OCTAL, HEX, BASE32, and BASE64

Is your feature request related to a problem? Please describe.

There is no functionality for retrieving bitstrings in a more compact base:

  • OCTAL
  • HEX
  • BASE32
  • BASE64

Describe the solution you'd like

Add random hex, base32, and base64 functionality to QRNG

Describe alternatives you've considered

The user can translate the output bitstring manually

Additional context

Upgrade Qrng from object to class wrapper

Is your feature request related to a problem? Please describe.

Users need to go through several steps in order to instantiate a Qrng object:

  1. Instantiate a QuantumPlatform.
  2. Instantiate a QuantumProtocol.
  3. Instantiate a QuantumBitGenerator from the previous two objects.
  4. Instantiate a Qrng from the bit generator.

Describe the solution you'd like

By transforming Qrng from a QuantumBitGenerator object wrapper to a class wrapper (i.e. through inheritance), the user can disregard QuantumBitGenerator altogether (i.e. step 3) and jump straight to using Qrng. Furtheremore, Qrng will then also be able to interface with NumPy.

Describe alternatives you've considered

Build facades to simplify the four-step process described above.

Additional context

  • This is a breaking change.
  • While instantiating a Qrng we can set a default protocol (e.g. Hadamard) to further simplify the process, or we can set the default on the QuantumBirGenerator class directly.
  • The reason to keep a distinction between QantumBitGenerator and Qrng is to segregate/isolate responsibilities. All the critical functionality will be implemented in QuantumBitGenerator (e.g. NumPy interface, caching), while the Qrng child will simply add extra functionality.

Cache persistence

Is your feature request related to a problem? Please describe.

Cache is hold in memory and gets erased when the python job holding it finishes.

Describe the solution you'd like

It should be possible to choose between holding the cache in memory or storage.

Describe alternatives you've considered

It is currently possible for the user to save and load the cache manually. However, if two programs are running at the same time and one uses bits in the cache, this will not be reflected on the other one. Leading to possible security issues and statistical biases.

Additional context

Concurrent access to the local file holding the cache has to be handled. This suggests using a singleton pattern along with semaphores in order to make it thread-safe. Performance has to be taken into account, since accessing a local file is always slower than simply reading from memory. Also, this feature should be available for all major OS distributions (i.e. Windows, MacOS, and Linux/Unix).

Graphic identity

What is the nature of the issue?

New content.

Describe the issue

We need to design QRAND's graphic identity. All files should be in SVG format.

Which files need to be updated?

  • README.md
  • TUTORIAL.ipyn
  • ReadTheDocs
  • PyPI

What content needs to be added, updated, or replaced?

  • Logo: graphic only, no text.
  • Full name logo: Logo and name text.
  • Header billboard.

Additional context

Checkout Qiskit for inspiration.

Simulator backend not randomized.

Describe the bug

Hello there. I have cited your library in a paper currently under peer review. I am trying to validate use of Qrand with simulator backend on qiskit client. The sampling does not appear to return random values, although it works with a live circuit backend.

To Reproduce

from qrand import QuantumBitGenerator
from qrand.platforms import QiskitPlatform
from qrand.protocols import HadamardProtocol
from qiskit import IBMQ

provider = IBMQ.load_account()
backend = provider.get_backend('ibmq_qasm_simulator')

#I added a backend assignment here and it allowed it to compile the cell
#it worked with a live circuit
#so I am assuming that backend assignment is supported functionality

platform = QiskitPlatform(provider, backend)
protocol = HadamardProtocol()
bitgen = QuantumBitGenerator(platform, protocol)

#and then to validate tried sampling 5 points from numpy's standard_normal
import numpy as np
from numpy.random import Generator
gen = Generator(bitgen)
gen.standard_normal(5)

#the array returned 5 equal values

array([-7.42778876e-09, -7.42778876e-09, -7.42778876e-09, -7.42778876e-09,
-7.42778876e-09])

It also generated a bunch of qiskit printouts as follows (repeated for each sampled number):

Exception ignored on calling ctypes callback function: <function QuantumBitGenerator._next_64.<locals>.next_64 at 0x7f79a8f8eee0>
Traceback (most recent call last):
  File "/Users/nicholasteague/opt/anaconda3/envs/qiskit/lib/python3.9/site-packages/qrand/quantum_bit_generator.py", line 311, in next_64
    return uint64(self.random_uint(64))
  File "/Users/nicholasteague/opt/anaconda3/envs/qiskit/lib/python3.9/site-packages/qrand/quantum_bit_generator.py", line 259, in random_uint
    return int(self.random_bitstring(num_bits), base=2)
  File "/Users/nicholasteague/opt/anaconda3/envs/qiskit/lib/python3.9/site-packages/qrand/quantum_bit_generator.py", line 207, in random_bitstring
    self._refill_cache()
  File "/Users/nicholasteague/opt/anaconda3/envs/qiskit/lib/python3.9/site-packages/qrand/quantum_bit_generator.py", line 277, in _refill_cache
    bitstring: str = self.platform.fetch_random_bits(self.protocol)
  File "/Users/nicholasteague/opt/anaconda3/envs/qiskit/lib/python3.9/site-packages/qrand/platforms/qiskit/platform.py", line 117, in fetch_random_bits
    result: ProtocolResult = protocol.run(self)
  File "/Users/nicholasteague/opt/anaconda3/envs/qiskit/lib/python3.9/site-packages/qrand/protocols/hadamard.py", line 88, in run
    circuit: QuantumCircuit = factory.create_circuit(num_qubits)
  File "/Users/nicholasteague/opt/anaconda3/envs/qiskit/lib/python3.9/site-packages/qrand/platforms/qiskit/platform.py", line 105, in create_circuit
    return QiskitCircuit(num_qubits)
  File "/Users/nicholasteague/opt/anaconda3/envs/qiskit/lib/python3.9/site-packages/qrand/platforms/qiskit/circuit.py", line 33, in __init__
    super(QuantumCircuit, self).__init__(num_qubits, num_qubits)
  File "/Users/nicholasteague/opt/anaconda3/envs/qiskit/lib/python3.9/site-packages/qiskit/circuit/quantumcircuit.py", line 226, in __init__
    raise CircuitError(
qiskit.circuit.exceptions.CircuitError: "Circuit args must be Registers or integers. (['str', 'str'] '('32', '32')' was provided)"

Expected behavior

I expected the sampling to generate 5 unique numbers when running the simulator backend

Screenshots

Desktop (please complete the following information):

  • Device: MacBook Pro 2019
  • QRAND version: 0.4.0
  • qiskit version: 0.34.2

Additional context

This might be related. I was running some code from a qiskit book and it appears that some kind of convention may have changed for their library in a recent update with respect to representing qubit counts .configuration().n_qubits for various backends as strings instead of integers. Wondering if a simple type conversion somewhere could resolve .

Stable bounded factorization algorithm

Is your feature request related to a problem? Please describe.

QiskitPlatform splits job repetitions into shots and experiments. Therefore, in order to build a QiskitJob, we need to factor any user input number of repetitions into a number of shots and a number of experiments such that shots * experiments = repetitions. Also, we need to take into account the fact that these two amounts are bounded by max_shots and max_experiments respectively.

Because of this last restriction, said task can be impossible to perform: for instance, if repetitions is a prime number larger than both bounds. To address this issue, we would like to find the factorization which is closest to the actual number of repetitions requested without exceeding it.

Describe the solution you'd like

Representing the solution algorithm as a function, this problem can be mathematically modeled as follows:

Find f: ℕ³ → D ⊆ ℕ² such that f(n, A, B) = (a, b) minimizes n-a•b, where:

  1. a•b ≤ n < A•B
  2. a ≤ A < n and b ≤ B < n
  3. f(a•b, A, B) = (a', b') : a•b = a'•b'

Notice how we require A < n otherwise the trivial solution (a=n, b=1) would be available. The same applies to B < n. Additionally, we require n < A•B to scape the trivial solution (a=A, b=B).

The last (stability) condition is needed to guarantee performance (i.e. running the algorithm iteratively does not worsen the approximation). Notice that this condition is automatically satisfied if the function always returns an optimal solution. However, since (a, b) ∈ D —as opposed to being general natural numbers— this condition is, in principle, less restrictive than asking for perfect factoring of any given composite number.

By convention, we assume zero to not be contained in the natural numbers (ℕ).

Describe alternatives you've considered

Due to symmetry considerations, we can assume the first bound to be lower than the second without loss of generality. Otherwise, we would only need to swap them.

A naive approach to solving this problem would be as follows:

def g(
    n: int, bound_A: int, bound_B: int
) -> Tuple[int, int]:
    if not bound_A * bound_B > n:
        return bound_A, bound_B
    swapped: bool = bound_A > bound_B
    bound_A, bound_B = sorted([bound_A, bound_B])
    a = min(bound_A, n // bound_B + 1)
    b = min(bound_B, n // a)
    return (b, a) if swapped else (a, b)

However, this violates (3): as displayed for n=11, A=4, B=5 which returns (a=3, b=3). Updating n=3•3 it follows (a'=2, b'=4), so we have 11 > 3•3 > 2•4. Nonetheless, this process seems to converge, so a workaround would be to repeat the process until the output stabilizes.

def f(
    n: int, bound_A: int, bound_B: int
) -> Tuple[int, int]:
    last_a, last_b = g(n, bound_A, bound_B)
    a, b = g(last_a * last_b, bound_A, bound_B)
    while a * b != last_a * last_b:
        last_a, last_b = a, b
        a, b = g(n, bound_A, bound_B)
    return a, b

In order to implement this approach we would need:

  1. Formal proof of fast convergence
  2. Show that the result minimizes n-a•b in some acceptable way, even if suboptimal*

The algorithm currently used finds the optimal solution through exhaustive search:

def compute_bounded_factorization(
    n: int, bound_A: int, bound_B: int
) -> Tuple[int, int]:
    if bound_A * bound_B < n:
        return bound_A, bound_B
    swapped: bool = bound_A > bound_B
    bound_A, bound_B = sorted([bound_A, bound_B])
    final_delta: int = n
    b: int = bound_B
    a: int = n // b
    delta: int = n - a * b
    while a <= bound_A and a <= b and final_delta != 0:
        if delta < final_delta:
            final_a, final_b, final_delta = a, b, delta
        a += 1
        b = n // a
        delta = n - a * b
    return (final_b, final_a) if swapped else (final_a, final_b)

Additional context

Due to the nature of the qiskit backends experiments are more expensive than shots, so we would ideally want to keep the number of experiments as low as possible if several equally good, or even optimal, solutions exist.

Although we do not provide a formal proof, we believe this problem to be beyond NP. This is so because it reduces to the factoring problem for A = B = n-1, when n is the product of only two primes. Additionally, verifying an answer does not seem to be efficient either, since we do not know a way of finding the optimal gap n-a•b without going through the same process required for solving the problem to begin with.

*Therefore, we are open to considering suboptimal solutions that are capable of improving performance (i.e. speed) significantly.

A few errors when type-checking with mypy

Describe the bug

  • qrand\platforms\qiskit\backend.py:45: error: Returning Any from function declared to return "Dict[Any, Any]"
  • qrand\platforms\qiskit\backend.py:49: error: Returning Any from function declared to return "int"
  • qrand\platforms\qiskit\backend.py:62: error: Returning Any from function declared to return "int"
  • qrand\platforms\qiskit\backend.py:71: error: Returning Any from function declared to return "int"
  • qrand\platforms\qiskit\backend.py:81: error: Returning Any from function declared to return "bool"
  • qrand\platforms\qiskit\circuit.py:37: error: Returning Any from function declared to return "int"
  • qrand\_qiskit_bit_generator.py:397: error: Returning Any from function declared to return "Dict[Any, Any]"
  • qrand\platforms\qsharp\job.py:76: error: unused 'type: ignore' comment
  • qrand\platforms\qsharp\job.py:99: error: Returning Any from function declared to return "List[str]"
  • qrand\platforms\qsharp\job.py:103: error: Returning Any from function declared to return "List[str]"
  • Found 10 errors in 4 files (checked 46 source files)

To Reproduce

Steps to reproduce the behavior:

  1. Run mypy on the module

Expected behavior

No type-check error thrown by mypy.

Screenshots

Not applicable.

Desktop (please complete the following information):

  • mypy version: 0.812
  • QRAND version: 0.4.0

Additional context

Not applicable.

Remove dependencies

Is your feature request related to a problem? Please describe.

As of May 2021, QRAND depends on NumPy and randomgen, but it only needs certain parts of these packages. Particularly, it only needs a number of data types (float64, uint32, uint64) from the former, and the UserBitGenerator class from the latter.

Describe the solution you'd like

Removing this dependencies would make QRAND faster, lighter, and less fragile. We would need:

  • Data-type stubs for NumPy. These should not change very often and so they will be easy to maintain.
  • An interface equivalent to UserBitGenerator that can be implemented by QuantumBitGenerator.

Describe alternatives you've considered

Apparently, randomgen is slowly merging into NumPy, so maybe in some time from now we will be able to naturally reduce the dependencies to only the latter with no additional effort. Nonetheless, NumPy is a rather large library and we would only make use of a very limited portion of it.

Additional context

The randomgen package depends on NumPy itself, so it would be necessary to assess wether this dependency could be entirely removed.

Even if impractical, removing the explicit NumPy dependency would help mitigating conflicts. Luckily, this should be easy to do. A possible solution would be building data-type stubs through Python's own ctypes.

Regardless of the above, since QRAND is meant to be able to interface with NumPy we would still need to keep it as an extra dependency.

Remove `qiskit-terra` dependency in favor of `qiskit`

qrand depends on qiskit-terra (<0.18.0,>=0.17.2) https://www.wheelodex.org/projects/qrand/ which is reaching EoL:

Important

The package qiskit-terra is not going to be updated after August 15th, 2024. Since Qiskit 0.44 (released on July 27th, 2023), the qiskit meta-package only contains qiskit-terra. In Qiskit 1.0 and beyond, the meta-package architecture is removed.
If you are installing or depending on qiskit-terra, consider changing that to qiskit: Either qiskit>=0.x,<1 (if you did not transition to Qiskit 1.0 yet) or qiskit>=0.x,<2 (to also include Qiskit 1.*).
Read more.

CIRQ support

The following classes need to be developed implementing the corresponding interfaces:

  • CirqPlatformQuantumPlatform
  • CirqBackendQuantumBackend
  • CirqJobQuantumJob
  • CirqCircuitQuantumCircuit

The first of these classes follows the Facade/Abstract Factory pattern, while the other two are Class Adapters. For an example check the Qiskit variants.

Jupyter notebook tutorial

What is the nature of the issue?

New content

Describe the issue

Build an interactive and up-to-date Jupyter Notebook tutorial for QRAND v1.0.0

Which files need to be updated?

  • [new] tutorial.ipynb

What content needs to be added, updated, or replaced?

The tutorial should at least include:

  • Multiplatform examples (e.g. qiskit and cirq)
  • Several randomness generation protocols
  • Entropy validation (i.e. independent and as a protocol decorator)
  • NumPy Generator interface → Different probability distributions
  • BitCache persistence explanation
  • Multithreading caching explanation
  • QRNG capabililties (bitstring, uint, double, hex, complex)

Additional context

This has to be targeted for v1.0.0 → QiskitBitGenerator deprecated in favor of QuantumBitGenerator

BitCache should implement matching data structures from the collections.abc module

Is your feature request related to a problem? Please describe.

The internal structure of BitCache is very similar to some common data structures. However, it does not implement any of their interfaces, making it incompatible with many of the already existing (and very useful) libraries and functions.

Describe the solution you'd like

BitCache should be refactored so that it adheres to all relevant and applicable data structures from the collections.abc module.

Describe alternatives you've considered

The alternative consists on relying on duck-typing alone.

Additional context

This might require changing the signature of some of the methods already defined, nonetheless, as of June 2021, this would not mean a breaking change; since BitCache and its specific implementations are only used internally.

Concurrent/Parallel caching

Is your feature request related to a problem? Please describe.

Currently, calls to the quantum backends are not made until the BitCache does not hold enough bits to satisfy the next request.

Describe the solution you'd like

Calls should be made automatically once the BitCache reaches a certain minimum amount of bits to have stored. Since the task of fetching new random bits from online quantum backends is I/O bound, these calls can be performed on a new thread (i.e. concurrent, non-blocking). This functionality can be implemented by means of the observer or state patters.

Additional context

When using a local quantum simulator the process will no longer be I/O bound, but CPU bound instead. Multiprocessing (i.e. parallelism) should be a better alternative in this case, so it can be useful to choose from one or the other depending on the type of backend being used at runtime.

Entropy validation suite

Develop an initial set of classes implementing the ValidationStrategy interface.

These classes will need to expose a validate method which takes in a bitstring (i.e. a string of only zeros and ones) and returns either True or False depending on whether it passes a particular entropy/randomness validation test or not.

Please, develop each test class on a separate file/module inside the validation subpackage, and use descriptive names. Also, remember to include a precise reference to the test documentation in the docstring (e.g. document, website, pages...).

References:

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.