Skip to content

Commit

Permalink
Introducing Qubits and Clbits classes (Qiskit#2414)
Browse files Browse the repository at this point in the history
* bit class

* compare to tuple

* hashable bits

* iter

* getitem

* avoid duplication of code

* test_barrier_none

* allow direct access to index and register

* layout

* snapshot

* conditional

* defintions

* layout

* test.python.circuit.test_circuit_registers.TestCircuitRegisters.test_measure_slice

* removing some tuple representation

* removing some tuple representation

* repr

* None

* test.python.transpiler.test_layout

* dag

* test.python.compiler.test_compiler.TestCompiler.test_compile_single_qubit

* test.python.compiler.test_compiler

* order

* StochasticSwap

* lint

* register have order

* lint

* test.python.visualization.test_visualization

* test.python.visualization.test_circuit_text_drawer

* test.python.basicaer.test_basicaer_integration

* test.python.compiler.test_transpiler

* test.python.transpiler.test_remove_diagonal_gates_before_measure

* test.python.transpiler.test_stochastic_swap.TestStochasticSwap

* test.python.transpiler.test_unroller

* test.python.circuit.test_circuit_registers

* test.python.transpiler.test_noise_adaptive_layout

* test.python.quantum_info.operators.test_operator.TestOperator

* mappers

* pickles

* latex lint

* test.python.transpiler.test_full_ancilla_allocation

* test.python.transpiler.test_consolidate_blocks

* test.python.transpiler.test_commutative_cancellation

* test.python.transpiler.test_basic_swap

* test.python.quantum_info.operators.channel.test_superop

* lint qiskit/converters/ast_to_dag.py

* test/python/test_dagcircuit.py

* test/python/test_dagcircuit.py

* test.python.compiler.test_assembler

* test.python.circuit.test_unitary

* condition

* test.python.circuit.test_circuit_properties

* instruction.control

* lint

* latex condition

* qiskit/dagcircuit/dagcircuit.py

* qiskit/circuit/quantumcircuit.py

* qiskit/assembler/assemble_circuits.py

* test for 1898

* Qiskit#2414 (comment)

* docstrings

* removing order by comparing sets in Collect2qBlocks

* QuBit-> Qubit and ClBit-> Clbit

* errors

* lint

* QuBit -> Qubit

* ctrl_reg, ctrl_val = instruction._control

* https://github.com/Qiskit/qiskit-terra/pull/2414/files/ff8770f7b195f66997a45f01943059d1c6ffaf13#r284695050

* explicit globals

* lint

* __getitem__ for deprecation

* from_tuple

* new pickles

* docstring

* accept gate arguments as tuples and mark them as deprecated

* this fix contradicts whats expected from a negative key lookup

* promote __iter__

* simpler negative index check...

* https://github.com/Qiskit/qiskit-terra/pull/2414/files#r284542889

* docstring lint

* getitem

* layout backwards compatibility

* lint

* lint!

* deprecated messager only when _is_bit

* changelog

* expose less the contructor

* remove prints and raised text

* simplifications

* lint
  • Loading branch information
Luciano authored and kdk committed May 21, 2019
1 parent 00ee0c6 commit 330ed83
Show file tree
Hide file tree
Showing 59 changed files with 872 additions and 354 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ Removed
- The ``qiskit.qiskiterror`` module has been removed. Please use
``qiskit.exceptions`` instead. (#2399)

Changed
-------
- Qubits and classical bits are not represented as a tuples anymore, but as
instances of ``Qubit`` and ``Clbit`` respectively.

`0.8.0`_ - 2019-05-02
=====================

Expand Down
4 changes: 2 additions & 2 deletions qiskit/assembler/assemble_circuits.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ def assemble_circuits(circuits, run_config, qobj_id, qobj_header):
qargs = op_context[1]
cargs = op_context[2]
if qargs:
qubit_indices = [qubit_labels.index([qubit[0].name, qubit[1]])
qubit_indices = [qubit_labels.index([qubit.register.name, qubit.index])
for qubit in qargs]
instruction.qubits = qubit_indices
if cargs:
clbit_indices = [clbit_labels.index([clbit[0].name, clbit[1]])
clbit_indices = [clbit_labels.index([clbit.register.name, clbit.index])
for clbit in cargs]
instruction.memory = clbit_indices
# If the experiment has conditional instructions, assume every
Expand Down
4 changes: 2 additions & 2 deletions qiskit/circuit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

"""Module for Circuits."""
from .quantumcircuit import QuantumCircuit
from .classicalregister import ClassicalRegister
from .quantumregister import QuantumRegister
from .classicalregister import ClassicalRegister, Clbit
from .quantumregister import QuantumRegister, Qubit
from .gate import Gate
from .instruction import Instruction
from .instructionset import InstructionSet
Expand Down
64 changes: 64 additions & 0 deletions qiskit/circuit/bit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2019.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""
Quantum bit and Classical bit objects.
"""
from warnings import warn
from qiskit.exceptions import QiskitError


class Bit:
"""Implement a generic bit."""

def __init__(self, register, index):
"""Create a new generic bit.
"""
try:
index = int(index)
except Exception:
raise QiskitError("index needs to be castable to an int: type %s was provided" %
type(index))

if index < 0:
index += register.size

if index >= register.size:
raise QiskitError("index must be under the size of the register: %s was provided" %
index)

self.register = register
self.index = index

def __repr__(self):
"""Return the official string representing the bit."""
return "%s(%s, %s)" % (self.__class__.__name__, self.register, self.index)

def __getitem__(self, item):
warn('Accessing a bit register by bit[0] or its index by bit[1] is deprecated. '
'Go for bit.register and bit.index.', DeprecationWarning)
if item == 0:
return self.register
elif item == 1:
return self.index
else:
raise IndexError

def __hash__(self):
return hash((self.register, self.index))

def __eq__(self, other):
if isinstance(other, tuple):
return other[1] == self.index and other[0] == self.register
return other.index == self.index and other.register == self.register
14 changes: 14 additions & 0 deletions qiskit/circuit/classicalregister.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,20 @@
"""
import itertools

from qiskit.exceptions import QiskitError
from .register import Register
from .bit import Bit


class Clbit(Bit):
"""Implement a classical bit."""

def __init__(self, register, index):
if isinstance(register, ClassicalRegister):
super().__init__(register, index)
else:
raise QiskitError('Clbit needs a ClassicalRegister and %s was provided' %
type(register).__name__)


class ClassicalRegister(Register):
Expand All @@ -27,6 +40,7 @@ class ClassicalRegister(Register):
instances_counter = itertools.count()
# Prefix to use for auto naming.
prefix = 'c'
bit_type = Clbit

def qasm(self):
"""Return OPENQASM string for this register."""
Expand Down
62 changes: 33 additions & 29 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,28 @@
import itertools
import sys
import multiprocessing as mp
from warnings import warn

from qiskit.circuit.instruction import Instruction
from qiskit.qasm.qasm import Qasm
from qiskit.exceptions import QiskitError
from qiskit.circuit.parameter import Parameter
from .quantumregister import QuantumRegister
from .classicalregister import ClassicalRegister
from .quantumregister import QuantumRegister, Qubit
from .classicalregister import ClassicalRegister, Clbit
from .parametertable import ParameterTable
from .parametervector import ParameterVector
from .instructionset import InstructionSet
from .register import Register
from .bit import Bit


def _is_bit(obj):
"""Determine if obj is a bit"""
# If there is a bit type this could be replaced by isinstance.
if isinstance(obj, tuple) and len(obj) == 2:
if isinstance(obj[0], Register) and isinstance(obj[1], int) and obj[1] < len(obj[0]):
warn('Referring to a bit as a tuple is being deprecated. '
'Instead go of (qr, 0), use qr[0].', DeprecationWarning)
return True
return False

Expand Down Expand Up @@ -265,35 +269,43 @@ def cast(value, _type):

@staticmethod
def _bit_argument_conversion(bit_representation, in_array):
ret = None
try:
if _is_bit(bit_representation):
# circuit.h((qr, 0)) -> circuit.h([qr[0]])
ret = [bit_representation[0][bit_representation[1]]]
elif isinstance(bit_representation, Bit):
# circuit.h(qr[0]) -> circuit.h([qr[0]])
return [bit_representation]
ret = [bit_representation]
elif isinstance(bit_representation, Register):
# circuit.h(qr) -> circuit.h([qr[0], qr[1]])
return bit_representation[:]
ret = bit_representation[:]
elif isinstance(QuantumCircuit.cast(bit_representation, int), int):
# circuit.h(0) -> circuit.h([qr[0]])
return [in_array[bit_representation]]
ret = [in_array[bit_representation]]
elif isinstance(bit_representation, slice):
# circuit.h(slice(0,2)) -> circuit.h([qr[0], qr[1]])
return in_array[bit_representation]
ret = in_array[bit_representation]
elif isinstance(bit_representation, list) and \
all(_is_bit(bit) for bit in bit_representation):
ret = [bit[0][bit[1]] for bit in bit_representation]
elif isinstance(bit_representation, list) and \
all(isinstance(bit, Bit) for bit in bit_representation):
# circuit.h([qr[0], qr[1]]) -> circuit.h([qr[0], qr[1]])
return bit_representation
ret = bit_representation
elif isinstance(QuantumCircuit.cast(bit_representation, list), (range, list)):
# circuit.h([0, 1]) -> circuit.h([qr[0], qr[1]])
# circuit.h(range(0,2)) -> circuit.h([qr[0], qr[1]])
return [in_array[index] for index in bit_representation]
ret = [in_array[index] for index in bit_representation]
else:
raise QiskitError('Not able to expand a %s (%s)' % (bit_representation,
type(bit_representation)))
except IndexError:
raise QiskitError('Index out of range.')
except TypeError:
raise QiskitError('Type error handeling %s (%s)' % (bit_representation,
type(bit_representation)))
raise QiskitError('Type error handling %s (%s)' % (bit_representation,
type(bit_representation)))
return ret

def qbit_argument_conversion(self, qubit_representation):
"""
Expand Down Expand Up @@ -429,25 +441,17 @@ def _check_dups(self, qubits):

def _check_qargs(self, qargs):
"""Raise exception if a qarg is not in this circuit or bad format."""
if not all(isinstance(i, tuple) and
isinstance(i[0], QuantumRegister) and
isinstance(i[1], int) for i in qargs):
raise QiskitError("qarg not (QuantumRegister, int) tuple")
if not all(self.has_register(i[0]) for i in qargs):
if not all(isinstance(i, Qubit) for i in qargs):
raise QiskitError("qarg is not a Qubit")
if not all(self.has_register(i.register) for i in qargs):
raise QiskitError("register not in this circuit")
for qubit in qargs:
qubit[0].check_range(qubit[1])

def _check_cargs(self, cargs):
"""Raise exception if clbit is not in this circuit or bad format."""
if not all(isinstance(i, tuple) and
isinstance(i[0], ClassicalRegister) and
isinstance(i[1], int) for i in cargs):
raise QiskitError("carg not (ClassicalRegister, int) tuple")
if not all(self.has_register(i[0]) for i in cargs):
if not all(isinstance(i, Clbit) for i in cargs):
raise QiskitError("carg is not a Clbit")
if not all(self.has_register(i.register) for i in cargs):
raise QiskitError("register not in this circuit")
for clbit in cargs:
clbit[0].check_range(clbit[1])

def to_instruction(self, parameter_map=None):
"""Create an Instruction out of this circuit.
Expand Down Expand Up @@ -502,11 +506,11 @@ def qasm(self):
qubit = qargs[0]
clbit = cargs[0]
string_temp += "%s %s[%d] -> %s[%d];\n" % (instruction.qasm(),
qubit[0].name, qubit[1],
clbit[0].name, clbit[1])
qubit.register.name, qubit.index,
clbit.register.name, clbit.index)
else:
string_temp += "%s %s;\n" % (instruction.qasm(),
",".join(["%s[%d]" % (j[0].name, j[1])
",".join(["%s[%d]" % (j.register.name, j.index)
for j in qargs + cargs]))
return string_temp

Expand Down Expand Up @@ -627,7 +631,7 @@ def depth(self):
for ind, reg in enumerate(qargs + cargs):
# Add to the stacks of the qubits and
# cbits used in the gate.
reg_ints.append(reg_map[reg[0].name] + reg[1])
reg_ints.append(reg_map[reg.register.name] + reg.index)
levels.append(op_stack[reg_ints[ind]] + 1)
if instr.control:
# Controls operate over all bits in the
Expand Down Expand Up @@ -719,7 +723,7 @@ def num_connected_components(self, unitary_only=False):
break

for item in args:
reg_int = reg_map[item[0].name] + item[1]
reg_int = reg_map[item.register.name] + item.index
for k in range(num_sub_graphs):
if reg_int in sub_graphs[k]:
if k not in graphs_touched:
Expand Down
14 changes: 14 additions & 0 deletions qiskit/circuit/quantumregister.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,20 @@
"""
import itertools

from qiskit.exceptions import QiskitError
from .register import Register
from .bit import Bit


class Qubit(Bit):
"""Implement a quantum bit."""

def __init__(self, register, index):
if isinstance(register, QuantumRegister):
super().__init__(register, index)
else:
raise QiskitError('Qubit needs a QuantumRegister and %s was provided' %
type(register).__name__)


class QuantumRegister(Register):
Expand All @@ -26,6 +39,7 @@ class QuantumRegister(Register):
instances_counter = itertools.count()
# Prefix to use for auto naming.
prefix = 'q'
bit_type = Qubit

def qasm(self):
"""Return OPENQASM string for this register."""
Expand Down
Loading

0 comments on commit 330ed83

Please sign in to comment.