Skip to content

Commit

Permalink
Associate docstrings with public constants (#2471)
Browse files Browse the repository at this point in the history
- Add `cirq/_doc.py` with a `document` function
- Pass public constants into `document` when they are initialized
- Fixes the fact that e.g. [`cirq.OP_TREE` was being documented using `typing.Union`'s docstring](https://cirq.readthedocs.io/en/stable/generated/cirq.OP_TREE.html)
  • Loading branch information
Strilanc authored and CirqBot committed Nov 4, 2019
1 parent 0df878c commit 9c0eb4c
Show file tree
Hide file tree
Showing 25 changed files with 381 additions and 97 deletions.
1 change: 1 addition & 0 deletions cirq/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
# Low level
_version,
_compat,
_doc,
type_workarounds,
)
with _import.delay_import('cirq.protocols'):
Expand Down
40 changes: 40 additions & 0 deletions cirq/_doc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright 2018 The Cirq Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Workaround for associating docstrings with public constants."""
from typing import Any, Dict, NamedTuple, Optional

DocProperties = NamedTuple(
'DocProperties',
[
('doc_string', Optional[str]),
],
)

RECORDED_CONST_DOCS: Dict[int, DocProperties] = {}


def document(value: Any, doc_string: str):
"""Stores documentation details about the given value.
This method is used to associate a docstring with global constants.
The given documentation information is filed under `id(value)` in
`cirq._doc.RECORDED_CONST_DOCS`.
Args:
value: The value to associate with documentation information.
doc_string: The doc string to associate with the value.
"""
docs = DocProperties(doc_string=doc_string)
RECORDED_CONST_DOCS[id(value)] = docs
21 changes: 19 additions & 2 deletions cirq/devices/noise_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from typing import TYPE_CHECKING, Sequence, Union

from cirq import ops, protocols, value
from cirq._doc import document

if TYPE_CHECKING:
from typing import Iterable
Expand Down Expand Up @@ -206,6 +207,22 @@ def _json_dict_(self):
return protocols.obj_to_dict_helper(self, ['qubit_noise_gate'])


NO_NOISE = _NoNoiseModel() # type: cirq.NoiseModel
"""An object which can be unambiguously converted into a noise model."""
NO_NOISE: 'cirq.NoiseModel' = _NoNoiseModel()
document(
NO_NOISE, """The trivial noise model with no effects.
This is the noise model used when a `NOISE_MODEL_LIKE` noise parameter is
set to `None`.
""")

NOISE_MODEL_LIKE = Union[None, 'cirq.NoiseModel', 'cirq.SingleQubitGate']
document(
NOISE_MODEL_LIKE, # type: ignore
"""A `cirq.NoiseModel` or a value that can be trivially converted into one.
`None` is a `NOISE_MODEL_LIKE`. It will be replaced by the `cirq.NO_NOISE`
noise model.
A single qubit gate is a `NOISE_MODEL_LIKE`. It will be wrapped inside of a
`cirq.ConstantQubitNoiseModel`.
""")
3 changes: 3 additions & 0 deletions cirq/devices/unconstrained_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

from cirq import value, protocols
from cirq._doc import document
from cirq.devices import device


Expand Down Expand Up @@ -49,3 +50,5 @@ def _json_dict_(self):


UNCONSTRAINED_DEVICE: device.Device = _UnconstrainedDevice()
document(UNCONSTRAINED_DEVICE,
"""A device with no constraints on operations or qubits.""")
16 changes: 16 additions & 0 deletions cirq/google/devices/known_devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from typing import Dict, Optional, Iterable, List, Set, Tuple

from cirq._doc import document
from cirq.devices import GridQubit
from cirq.google import gate_sets, serializable_gate_set
from cirq.google.api import v2
Expand Down Expand Up @@ -186,6 +187,13 @@ def _json_dict_(self):
exp_w_duration=Duration(nanos=20),
exp_11_duration=Duration(nanos=50),
qubits=_parse_device(_FOXTAIL_GRID)[0])
document(Foxtail, f"""72 xmon qubit device.
**Qubit grid**:
```
{str(Foxtail)}
```
""")

# Duration dict in picoseconds
_DURATIONS_FOR_XMON = {
Expand Down Expand Up @@ -219,6 +227,14 @@ def _json_dict_(self):
exp_w_duration=Duration(nanos=20),
exp_11_duration=Duration(nanos=50),
qubits=_parse_device(_BRISTLECONE_GRID)[0])
document(
Bristlecone, f"""72 xmon qubit device.
**Qubit grid**:
```
{str(Bristlecone)}
```
""")

BRISTLECONE_PROTO = create_device_proto_from_diagram(_BRISTLECONE_GRID,
[gate_sets.XMON],
Expand Down
7 changes: 7 additions & 0 deletions cirq/google/gate_sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Gate sets supported by Google's apis."""
from cirq._doc import document
from cirq.google import serializable_gate_set
from cirq.google.common_serializers import (
SINGLE_QUBIT_SERIALIZERS,
Expand Down Expand Up @@ -44,6 +45,8 @@
MEASUREMENT_DESERIALIZER,
],
)
document(SYC_GATESET,
"""Gate set with fsim(pi/4, pi/6) as the core 2 qubit interaction.""")

SQRT_ISWAP_GATESET = serializable_gate_set.SerializableGateSet(
gate_set_name='sqrt_iswap',
Expand All @@ -57,6 +60,8 @@
*SINGLE_QUBIT_DESERIALIZERS,
MEASUREMENT_DESERIALIZER,
])
document(SQRT_ISWAP_GATESET,
"""Gate set with sqrt(iswap) as the core 2 qubit interaction.""")


# The xmon gate set.
Expand All @@ -73,3 +78,5 @@
MEASUREMENT_DESERIALIZER,
],
)

document(XMON, """Gate set for XMON devices.""")
17 changes: 17 additions & 0 deletions cirq/google/ops/sycamore_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import numpy as np

from cirq import ops, protocols
from cirq._doc import document

if TYPE_CHECKING:
import cirq
Expand Down Expand Up @@ -57,3 +58,19 @@ def _json_dict_(self):


SYC = SycamoreGate()
document(
SYC,
"""The Sycamore gate is a two-qubit gate equivalent to FSimGate(π/2, π/6).
The unitary of this gate is
[[1, 0, 0, 0],
[0, 0, -1j, 0],
[0, -1j, 0, 0],
[0, 0, 0, exp(- 1j * π/6)]]
This gate can be performed on the Google's Sycamore chip and
is close to the gates that were used to demonstrate quantum
supremacy used in this paper:
https://www.nature.com/articles/s41586-019-1666-5
""")
10 changes: 9 additions & 1 deletion cirq/linalg/combinators.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import numpy as np

from cirq._doc import document


def kron(*factors: Union[np.ndarray, complex, float]) -> np.ndarray:
"""Computes the kronecker product of a sequence of values.
Expand All @@ -38,7 +40,13 @@ def kron(*factors: Union[np.ndarray, complex, float]) -> np.ndarray:
return np.array(product)


CONTROL_TAG = np.array([[float('nan'), 0], [0, 1]]) # For kron_with_controls
CONTROL_TAG = np.array([[float('nan'), 0], [0, 1]])
document(
CONTROL_TAG, """A special indicator value for `cirq.kron_with_controls`.
This value is a stand-in for "control operations on the other qubits based
on the value of this qubit", which otherwise doesn't have a proper matrix.
""")


def kron_with_controls(*factors: Union[np.ndarray, complex, float]
Expand Down
4 changes: 4 additions & 0 deletions cirq/linalg/operator_spaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@
import numpy as np

from cirq import value
from cirq._doc import document

PAULI_BASIS = {
'I': np.eye(2),
'X': np.array([[0., 1.], [1., 0.]]),
'Y': np.array([[0., -1j], [1j, 0.]]),
'Z': np.diag([1., -1]),
}
document(
PAULI_BASIS,
"""The four Pauli matrices (including identity) keyed by character.""")


def kron_bases(*bases: Dict[str, np.ndarray],
Expand Down
90 changes: 52 additions & 38 deletions cirq/ops/common_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@
Each of these are implemented as EigenGates, which means that they can be
raised to a power (i.e. cirq.H**0.5). See the definition in EigenGate.
"""
from typing import Any, cast, Iterable, List, Optional, Tuple, Union
from typing import Any, cast, Optional, Tuple, Union

import numpy as np
import sympy

import cirq
from cirq import protocols, value
from cirq._compat import proper_repr
from cirq._doc import document
from cirq.ops import gate_features, eigen_gate, raw_types

from cirq.type_workarounds import NotImplementedType
Expand Down Expand Up @@ -848,51 +849,64 @@ def Rz(rads: value.TParamVal) -> ZPowGate:
return ZPowGate(exponent=rads / pi, global_shift=-0.5)


# The Hadamard gate.
#
# Matrix:
#
# [[s, s],
# [s, -s]]
# where s = sqrt(0.5).
H = HPowGate()
document(
H, """The Hadamard gate.
The `exponent=1` instance of `cirq.HPowGate`.
Matrix:
[[s, s],
[s, -s]]
where s = sqrt(0.5).
""")

# The Clifford S gate.
#
# Matrix:
#
# [[1, 0],
# [0, i]]
S = ZPowGate(exponent=0.5)
document(
S, """The Clifford S gate.
The `exponent=0.5` instance of `cirq.ZPowGate`.
Matrix:
[[1, 0],
[0, i]]
""")

# The non-Clifford T gate.
#
# Matrix:
#
# [[1, 0]
# [0, exp(i pi / 4)]]
T = ZPowGate(exponent=0.25)
document(
T, """The non-Clifford T gate.
The `exponent=0.25` instance of `cirq.ZPowGate`.
Matrix:
[[1, 0]
[0, exp(i pi / 4)]]
""")

# The controlled Z gate.
#
# Matrix:
#
# [[1, 0, 0, 0],
# [0, 1, 0, 0],
# [0, 0, 1, 0],
# [0, 0, 0, -1]]
CZ = CZPowGate()
document(
CZ, """The controlled Z gate.
The `exponent=1` instance of `cirq.CZPowGate`.
# The controlled NOT gate.
#
# Matrix:
#
# [[1, 0, 0, 0],
# [0, 1, 0, 0],
# [0, 0, 0, 1],
# [0, 0, 1, 0]]
CNOT = CNotPowGate()
CX = CNOT
Matrix:
[[1 . . .],
[. 1 . .],
[. . 1 .],
[. . . -1]]
""")

CNOT = CX = CNotPowGate()
document(
CNOT, """The controlled NOT gate.
The `exponent=1` instance of `cirq.CNotPowGate`.
Matrix:
[[1 . . .],
[. 1 . .],
[. . . 1],
[. . 1 .]]
""")
15 changes: 9 additions & 6 deletions cirq/ops/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import sympy

from cirq import protocols, value
from cirq._doc import document
from cirq.ops import raw_types


Expand Down Expand Up @@ -236,13 +237,15 @@ def _from_json_dict_(cls, qubits, **kwargs):
return cls(qubits=qubits)


# The one qubit identity gate.
#
# Matrix:
#
# [[1, 0],
# [0, 1]]
I = IdentityGate(num_qubits=1)
document(
I, """The one qubit identity gate.
Matrix:
[[1, 0],
[0, 1]]
""")


def identity_each(*qubits: raw_types.Qid) -> raw_types.Operation:
Expand Down
Loading

0 comments on commit 9c0eb4c

Please sign in to comment.