Skip to content
This repository was archived by the owner on Dec 7, 2021. It is now read-only.

Adapt to using the circuit arithmetics library #895

Merged
merged 18 commits into from
Apr 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .pylintdict
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ lor
lr
lst
majorana
mapsto
mathbb
mathsf
matrixoperator
Expand Down Expand Up @@ -434,6 +435,7 @@ qubits
quine
qutip
randgiven
rangle
rbf
rcccx
rccx
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Added
-----

- NFT optimizer, part of a project of Qiskit Camp Asia 2019 (#729)
- Algorithm interface and result classes (#849)
- Algorithm interface and result classes (#849)
- Chemistry FCIDump file driver (#859)
- Chemistry stack automatic Z2 symmetry reduction (#870)
- Ising Optimization: The 0-1 Knapsack problem (#878)
Expand All @@ -42,6 +42,7 @@ Removed

- Declarative api (#758) (#759) (#760) (#762) (#763)
- Moved to Terra: multi-controlled Toffoli, U1 and Pauli rotation gates (including tests) (#833)
- Moved to the circuit library in Terra: arithmetic circuits in qiskit/aqua/circuits (#895)

Fixed
-----
Expand Down
95 changes: 23 additions & 72 deletions qiskit/aqua/circuits/fixed_value_comparator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2019.
# (C) Copyright IBM 2018, 2020.
#
# 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
Expand All @@ -14,17 +14,18 @@

"""Fixed Value Comparator."""

import warnings
import numpy as np

from qiskit.circuit.library import IntegerComparator
from qiskit.aqua.utils.circuit_factory import CircuitFactory
from qiskit.aqua.circuits.gates import logical_or # pylint: disable=unused-import

# pylint: disable=invalid-name


class FixedValueComparator(CircuitFactory):
r"""
Fixed Value Comparator.
r"""Fixed Value Comparator.

Operator compares basis states \|i>_n against a classically
given fixed value L and flips a target qubit if i >= L (or < depending on parameters):
Expand All @@ -39,7 +40,6 @@ class FixedValueComparator(CircuitFactory):

def __init__(self, num_state_qubits, value, geq=True, i_state=None, i_target=None):
"""

Args:
num_state_qubits (int): number of state qubits, the target qubit comes on top of this
value (int): fixed value to compare with
Expand All @@ -50,17 +50,21 @@ def __init__(self, num_state_qubits, value, geq=True, i_state=None, i_target=Non
i_target (Optional(int)): index of target qubit in given list
of qubits / register, if None, i_target = num_state_qubits is used
"""
warnings.warn('The qiskit.aqua.circuits.FixedValueComparator object is deprecated and will '
'be removed no earlier than 3 months after the 0.7.0 release of Qiskit Aqua. '
'You should use qiskit.circuit.library.IntegerComparator instead.',
DeprecationWarning, stacklevel=2)

super().__init__(num_state_qubits + 1)
self._num_state_qubits = num_state_qubits
self._value = value
self._geq = geq
self._comparator_circuit = IntegerComparator(value=value,
num_state_qubits=num_state_qubits,
geq=geq)

# get indices
self.i_state = None
if i_state is not None:
self.i_state = i_state
else:
self.i_state = list(range(num_state_qubits))
self.i_state = range(num_state_qubits)

self.i_target = None
if i_target is not None:
Expand All @@ -71,18 +75,18 @@ def __init__(self, num_state_qubits, value, geq=True, i_state=None, i_target=Non
@property
def num_state_qubits(self):
""" returns num state qubits """
return self._num_state_qubits
return self._comparator_circuit._num_state_qubits

@property
def value(self):
""" returns value """
return self._value
return self._comparator_circuit._value

def required_ancillas(self):
return self._num_state_qubits - 1
return self.num_state_qubits - 1

def required_ancillas_controlled(self):
return self._num_state_qubits - 1
return self.num_state_qubits - 1

def _get_twos_complement(self):
"""
Expand All @@ -99,62 +103,9 @@ def _get_twos_complement(self):
return twos_complement

def build(self, qc, q, q_ancillas=None, params=None):

# get parameters
i_state = self.i_state
i_target = self.i_target

# get qubits
q_result = q[i_target]
q_state = [q[i] for i in i_state]

if self.value <= 0: # condition always satisfied for non-positive values
if self._geq: # otherwise the condition is never satisfied
qc.x(q_result)
# condition never satisfied for values larger than or equal to 2^n
elif self.value < pow(2, self.num_state_qubits):

if self.num_state_qubits > 1:

tc = self._get_twos_complement()
for i in range(self.num_state_qubits):
if i == 0:
if tc[i] == 1:
qc.cx(q_state[i], q_ancillas[i])
elif i < self.num_state_qubits-1:
if tc[i] == 1:
qc.OR([q_state[i], q_ancillas[i-1]], q_ancillas[i], None)
else:
qc.ccx(q_state[i], q_ancillas[i-1], q_ancillas[i])
else:
if tc[i] == 1:
qc.OR([q_state[i], q_ancillas[i-1]], q_result, None)
else:
qc.ccx(q_state[i], q_ancillas[i-1], q_result)

# flip result bit if geq flag is false
if not self._geq:
qc.x(q_result)

# uncompute ancillas state
for i in reversed(range(self.num_state_qubits-1)):
if i == 0:
if tc[i] == 1:
qc.cx(q_state[i], q_ancillas[i])
else:
if tc[i] == 1:
qc.OR([q_state[i], q_ancillas[i - 1]], q_ancillas[i], None)
else:
qc.ccx(q_state[i], q_ancillas[i - 1], q_ancillas[i])
else:

# num_state_qubits == 1 and value == 1:
qc.cx(q_state[0], q_result)

# flip result bit if geq flag is false
if not self._geq:
qc.x(q_result)

else:
if not self._geq: # otherwise the condition is never satisfied
qc.x(q_result)
instr = self._comparator_circuit.to_instruction()
qr = [q[i] for i in self.i_state] + [q[self.i_target]]
if q_ancillas:
# pylint:disable=unnecessary-comprehension
qr += [qi for qi in q_ancillas[:self.required_ancillas()]]
qc.append(instr, qr)
42 changes: 17 additions & 25 deletions qiskit/aqua/circuits/linear_rotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@

"""Linearly-controlled X, Y or Z rotation."""

import numpy as np
import warnings

from qiskit.circuit.library.arithmetic import LinearPauliRotations
from qiskit.aqua.utils import CircuitFactory


class LinearRotation(CircuitFactory):
r"""
Linearly-controlled X, Y or Z rotation.
r"""Linearly-controlled X, Y or Z rotation.

For a register of state qubits \|x> and a target qubit \|0> this operator acts as:

\|x>\|0> --> \|x>( cos(slope * x + offset)\|0> + sin(slope * x + offset)\|1> )
Expand All @@ -42,9 +43,19 @@ def __init__(self, slope, offset, num_state_qubits, basis='Y', i_state=None, i_t
Raises:
ValueError: invalid input
"""
warnings.warn('The qiskit.aqua.circuits.LinearRotation object is deprecated and will be '
'removed no earlier than 3 months after the 0.7.0 release of Qiskit Aqua. '
'You should use qiskit.circuit.library.arithmetic.LinearRotation instead.',
DeprecationWarning, stacklevel=2)

super().__init__(num_state_qubits + 1)

# store the circuit
self._linear_rotation_circuit = LinearPauliRotations(num_state_qubits=num_state_qubits,
slope=slope,
offset=offset,
basis=basis)

# store parameters
self.num_control_qubits = num_state_qubits
self.slope = slope
Expand All @@ -67,25 +78,6 @@ def __init__(self, slope, offset, num_state_qubits, basis='Y', i_state=None, i_t
self.i_target = num_state_qubits

def build(self, qc, q, q_ancillas=None, params=None):

# get indices
i_state = self.i_state
i_target = self.i_target

# apply linear rotation
if not np.isclose(self.offset / 4 / np.pi % 1, 0):
if self.basis == 'X':
qc.rx(self.offset, q[i_target])
elif self.basis == 'Y':
qc.ry(self.offset, q[i_target])
elif self.basis == 'Z':
qc.rz(self.offset, q[i_target])
for i, j in enumerate(i_state):
theta = self.slope * pow(2, i)
if not np.isclose(theta / 4 / np.pi % 1, 0):
if self.basis == 'X':
qc.crx(self.slope * pow(2, i), q[j], q[i_target])
elif self.basis == 'Y':
qc.cry(self.slope * pow(2, i), q[j], q[i_target])
elif self.basis == 'Z':
qc.crz(self.slope * pow(2, i), q[j], q[i_target])
instr = self._linear_rotation_circuit.to_instruction()
qr = [q[i] for i in self.i_state] + [q[self.i_target]]
qc.append(instr, qr)
86 changes: 25 additions & 61 deletions qiskit/aqua/circuits/piecewise_linear_rotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# This code is part of Qiskit.
#
# (C) Copyright IBM 2019.
# (C) Copyright IBM 2019, 2020.
#
# 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
Expand All @@ -14,18 +14,18 @@

"""Piecewise-linearly-controlled rotation."""

import warnings
import numpy as np

from qiskit.circuit.library import PiecewiseLinearPauliRotations
from qiskit.aqua.utils import CircuitFactory
from qiskit.aqua.circuits.fixed_value_comparator import FixedValueComparator as Comparator
from qiskit.aqua.circuits.linear_rotation import LinearRotation as LinR

# pylint: disable=invalid-name


class PiecewiseLinearRotation(CircuitFactory):
"""
Piecewise-linearly-controlled rotation.
"""Piecewise-linearly-controlled rotation.

For a piecewise linear (not necessarily continuous) function f(x).
The function f(x) is defined through breakpoints, slopes and offsets as follows.
Suppose the breakpoints { x_0, ..., x_J } are a subset of [0, 2^n-1], where
Expand Down Expand Up @@ -60,6 +60,11 @@ def __init__(self, breakpoints, slopes, offsets, num_state_qubits,
i_target (Optional(int)): index of target qubit, set to num_state_qubits if None
"""

warnings.warn('The qiskit.aqua.circuits.PiecewiseLinearRotation object is deprecated and '
'will be removed no earlier than 3 months after the 0.7.0 release of Qiskit '
'Aqua. You should use qiskit.circuit.library.PiecewiseLinearPauliRotations '
'instead.', DeprecationWarning, stacklevel=2)

super().__init__(num_state_qubits + 1)

# store parameters
Expand Down Expand Up @@ -101,8 +106,8 @@ def __init__(self, breakpoints, slopes, offsets, num_state_qubits,
self.i_target = num_state_qubits

def evaluate(self, x):
"""
Classically evaluate the piecewise linear rotation
"""Classically evaluate the piecewise linear rotation

Args:
x (float): value to be evaluated at
Returns:
Expand All @@ -117,63 +122,22 @@ def evaluate(self, x):
return y

def required_ancillas(self):

"""Return the number of required ancillas."""
num_ancillas = self.num_state_qubits - 1 + len(self.breakpoints)
if self.contains_zero_breakpoint:
num_ancillas -= 1
return num_ancillas

def build(self, qc, q, q_ancillas=None, params=None):

# get parameters
i_state = self.i_state
i_target = self.i_target

# apply comparators and controlled linear rotations
for i, bp in enumerate(self.breakpoints):

if i == 0 and self.contains_zero_breakpoint:

# apply rotation
lin_r = LinR(self.mapped_slopes[i], self.mapped_offsets[i],
self.num_state_qubits, basis=self.basis,
i_state=i_state, i_target=i_target)
lin_r.build(qc, q)

elif self.contains_zero_breakpoint:

# apply comparator
comp = Comparator(self.num_state_qubits, bp)
q_ = [q[i] for i in range(self.num_state_qubits)] # map register to list
q_ = q_ + [q_ancillas[i - 1]] # add ancilla as compare qubit
# take remaining ancillas as ancilla register (list)
q_ancillas_ = [q_ancillas[j] for j in range(i, len(q_ancillas))]
comp.build(qc, q_, q_ancillas_)

# apply controlled rotation
lin_r = LinR(self.mapped_slopes[i], self.mapped_offsets[i],
self.num_state_qubits, basis=self.basis,
i_state=i_state, i_target=i_target)
lin_r.build_controlled(qc, q, q_ancillas[i - 1], use_basis_gates=False)

# uncompute comparator
comp.build_inverse(qc, q_, q_ancillas_)

else:

# apply comparator
comp = Comparator(self.num_state_qubits, bp)
q_ = [q[i] for i in range(self.num_state_qubits)] # map register to list
q_ = q_ + [q_ancillas[i]] # add ancilla as compare qubit
# take remaining ancillas as ancilla register (list)
q_ancillas_ = [q_ancillas[j] for j in range(i + 1, len(q_ancillas))]
comp.build(qc, q_, q_ancillas_)

# apply controlled rotation
lin_r = LinR(self.mapped_slopes[i],
self.mapped_offsets[i], self.num_state_qubits, basis=self.basis,
i_state=i_state, i_target=i_target)
lin_r.build_controlled(qc, q, q_ancillas[i], use_basis_gates=False)

# uncompute comparator
comp.build_inverse(qc, q_, q_ancillas_)
"""Build the circuit."""
pwlr = PiecewiseLinearPauliRotations(num_state_qubits=self.num_state_qubits,
breakpoints=self.breakpoints,
slopes=self.slopes,
offsets=self.offsets,
basis=self.basis).to_instruction()

qr = [q[i] for i in self.i_state] + [q[self.i_target]]
if q_ancillas:
# pylint:disable=unnecessary-comprehension
qr += [qi for qi in q_ancillas[:self.required_ancillas()]]
qc.append(pwlr, qr)
Loading