Module hybridq.dm.gate.property

Author: Salvatore Mandra (salvatore.mandra@nasa.gov)

Copyright © 2021, United States Government, as represented by the Administrator of the National Aeronautics and Space Administration. All rights reserved.

The HybridQ: A Hybrid Simulator for Quantum Circuits platform is 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 http://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.

Expand source code
"""
Author: Salvatore Mandra (salvatore.mandra@nasa.gov)

Copyright © 2021, United States Government, as represented by the Administrator
of the National Aeronautics and Space Administration. All rights reserved.

The HybridQ: A Hybrid Simulator for Quantum Circuits platform is 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
http://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.
"""

from __future__ import annotations
from hybridq.base import generate, staticvars, compare, requires, __Base__
from hybridq.base.property import Tuple
import numpy as np


class BaseTupleSuperGate(Tuple):
    """
    Gate defined as a tuple of gates.
    """

    @property
    def qubits(self) -> tuple[tuple[any, ...], tuple[any, ...]]:
        from hybridq.gate import BaseGate

        # Define flatten
        def _unique_flatten(l):
            from hybridq.utils import sort
            return tuple(sort(set(y for x in l for y in x)))

        # Get qubits
        def _get_qubits(gate):
            if isinstance(gate, BaseGate):
                # Get qubits
                qubits = gate.qubits
                return (qubits, qubits)
            else:
                return gate.qubits

        # Get all qubits
        _qubits = tuple(
            _get_qubits(g) if g.provides('qubits') else (None, None)
            for g in self)

        # Split in left and right qubits
        try:
            _lq, _rq = map(tuple, zip(*_qubits))
        except ValueError:
            return tuple(), tuple()

        # If any none is present, set to None
        _lq = None if any(q is None for q in _lq) else _unique_flatten(_lq)
        _rq = None if any(q is None for q in _rq) else _unique_flatten(_rq)

        # Return qubits
        return (_lq, _rq)

    @property
    def n_qubits(self) -> int:
        # Get left and right qubits
        _lq, _rq = self.qubits
        return None if _lq is None else len(_lq), None if _rq is None else len(
            _rq)


@requires('qubits,Matrix')
class Map(__Base__):

    def map(self, order: iter[any] = None):
        """
        Return map.

        Parameters
        ----------
        order: tuple[any, ...], optional
            If provided, Kraus' map is ordered accordingly to `order`.
        """
        # Get left and right qubits
        l_qubits, r_qubits = self.qubits

        # Get order
        if order is not None:
            from hybridq.utils import sort

            # Get order
            order = tuple(order)

            try:
                # Split
                l_order, r_order = order

                # Convert to tuples
                l_order = tuple(l_order)
                r_order = tuple(r_order)

                # Check that qubits are consistent
                if sort(l_order) != sort(l_qubits) or sort(r_order) != sort(
                        r_qubits):
                    raise RuntimeError("Something went wrong.")

                # Get order
                order = (l_order, r_order)
            except:
                if l_qubits != r_qubits or sort(order) != sort(l_qubits):
                    raise ValueError(
                        "'order' is not a valid permutation of qubits.")

                # Get order
                order = (order, order)

        # Get Matrix representing the map
        _U = self.Matrix

        # Transpose if order is provided
        if order is not None and (order[0] != self.l_qubits or
                                  order[1] != self.r_qubits):
            from hybridq.gate import MatrixGate

            # Get gate
            _g = MatrixGate(_U,
                            qubits=tuple((0, q) for q in l_qubits) + tuple(
                                (1, q) for q in r_qubits),
                            copy=False)

            # Transpose
            _U = _g.matrix(order=tuple((0, q) for q in order[0]) + tuple(
                (1, q) for q in order[1]))

        # Return map
        return _U

    def isclose(self, gate: Map, atol: float = 1e-8):

        # If gate is not a SuperGate or they qubits differ, they are different
        if not isinstance(gate, Map) or self.qubits != gate.qubits:
            return False

        # Get matrices
        _U1 = self.map(order=self.qubits)
        _U2 = gate.map(order=self.qubits)

        # Check
        return np.allclose(_U1, _U2, atol=atol)

    def commutes_with(self, gate: Map, atol: float = 1e-7):
        from hybridq.gate import MatrixGate

        # Gate must be a map
        if not isinstance(gate, Map):
            raise ValueError(
                f"Cannot compute commutation between 'Map' and '{type(gate).__name__}'"
            )

        # Get gates
        g1 = MatrixGate(self.Matrix,
                        qubits=[(0, q) for q in self.l_qubits] +
                        [(1, q) for q in self.r_qubits],
                        copy=False)
        g2 = MatrixGate(gate.Matrix,
                        qubits=[(0, q) for q in gate.l_qubits] +
                        [(1, q) for q in gate.r_qubits],
                        copy=False)

        # Return if they commute
        return g1.commutes_with(g2, atol=atol)

Classes

class BaseTupleSuperGate (elements=(), tags=None, **kwargs)

Gate defined as a tuple of gates.

Expand source code
class BaseTupleSuperGate(Tuple):
    """
    Gate defined as a tuple of gates.
    """

    @property
    def qubits(self) -> tuple[tuple[any, ...], tuple[any, ...]]:
        from hybridq.gate import BaseGate

        # Define flatten
        def _unique_flatten(l):
            from hybridq.utils import sort
            return tuple(sort(set(y for x in l for y in x)))

        # Get qubits
        def _get_qubits(gate):
            if isinstance(gate, BaseGate):
                # Get qubits
                qubits = gate.qubits
                return (qubits, qubits)
            else:
                return gate.qubits

        # Get all qubits
        _qubits = tuple(
            _get_qubits(g) if g.provides('qubits') else (None, None)
            for g in self)

        # Split in left and right qubits
        try:
            _lq, _rq = map(tuple, zip(*_qubits))
        except ValueError:
            return tuple(), tuple()

        # If any none is present, set to None
        _lq = None if any(q is None for q in _lq) else _unique_flatten(_lq)
        _rq = None if any(q is None for q in _rq) else _unique_flatten(_rq)

        # Return qubits
        return (_lq, _rq)

    @property
    def n_qubits(self) -> int:
        # Get left and right qubits
        _lq, _rq = self.qubits
        return None if _lq is None else len(_lq), None if _rq is None else len(
            _rq)

Ancestors

Instance variables

var n_qubits : int
Expand source code
@property
def n_qubits(self) -> int:
    # Get left and right qubits
    _lq, _rq = self.qubits
    return None if _lq is None else len(_lq), None if _rq is None else len(
        _rq)
var qubits : tuple[tuple[any, ...], tuple[any, ...]]
Expand source code
@property
def qubits(self) -> tuple[tuple[any, ...], tuple[any, ...]]:
    from hybridq.gate import BaseGate

    # Define flatten
    def _unique_flatten(l):
        from hybridq.utils import sort
        return tuple(sort(set(y for x in l for y in x)))

    # Get qubits
    def _get_qubits(gate):
        if isinstance(gate, BaseGate):
            # Get qubits
            qubits = gate.qubits
            return (qubits, qubits)
        else:
            return gate.qubits

    # Get all qubits
    _qubits = tuple(
        _get_qubits(g) if g.provides('qubits') else (None, None)
        for g in self)

    # Split in left and right qubits
    try:
        _lq, _rq = map(tuple, zip(*_qubits))
    except ValueError:
        return tuple(), tuple()

    # If any none is present, set to None
    _lq = None if any(q is None for q in _lq) else _unique_flatten(_lq)
    _rq = None if any(q is None for q in _rq) else _unique_flatten(_rq)

    # Return qubits
    return (_lq, _rq)

Inherited members

class Map

Basic features.

Expand source code
class Map(__Base__):

    def map(self, order: iter[any] = None):
        """
        Return map.

        Parameters
        ----------
        order: tuple[any, ...], optional
            If provided, Kraus' map is ordered accordingly to `order`.
        """
        # Get left and right qubits
        l_qubits, r_qubits = self.qubits

        # Get order
        if order is not None:
            from hybridq.utils import sort

            # Get order
            order = tuple(order)

            try:
                # Split
                l_order, r_order = order

                # Convert to tuples
                l_order = tuple(l_order)
                r_order = tuple(r_order)

                # Check that qubits are consistent
                if sort(l_order) != sort(l_qubits) or sort(r_order) != sort(
                        r_qubits):
                    raise RuntimeError("Something went wrong.")

                # Get order
                order = (l_order, r_order)
            except:
                if l_qubits != r_qubits or sort(order) != sort(l_qubits):
                    raise ValueError(
                        "'order' is not a valid permutation of qubits.")

                # Get order
                order = (order, order)

        # Get Matrix representing the map
        _U = self.Matrix

        # Transpose if order is provided
        if order is not None and (order[0] != self.l_qubits or
                                  order[1] != self.r_qubits):
            from hybridq.gate import MatrixGate

            # Get gate
            _g = MatrixGate(_U,
                            qubits=tuple((0, q) for q in l_qubits) + tuple(
                                (1, q) for q in r_qubits),
                            copy=False)

            # Transpose
            _U = _g.matrix(order=tuple((0, q) for q in order[0]) + tuple(
                (1, q) for q in order[1]))

        # Return map
        return _U

    def isclose(self, gate: Map, atol: float = 1e-8):

        # If gate is not a SuperGate or they qubits differ, they are different
        if not isinstance(gate, Map) or self.qubits != gate.qubits:
            return False

        # Get matrices
        _U1 = self.map(order=self.qubits)
        _U2 = gate.map(order=self.qubits)

        # Check
        return np.allclose(_U1, _U2, atol=atol)

    def commutes_with(self, gate: Map, atol: float = 1e-7):
        from hybridq.gate import MatrixGate

        # Gate must be a map
        if not isinstance(gate, Map):
            raise ValueError(
                f"Cannot compute commutation between 'Map' and '{type(gate).__name__}'"
            )

        # Get gates
        g1 = MatrixGate(self.Matrix,
                        qubits=[(0, q) for q in self.l_qubits] +
                        [(1, q) for q in self.r_qubits],
                        copy=False)
        g2 = MatrixGate(gate.Matrix,
                        qubits=[(0, q) for q in gate.l_qubits] +
                        [(1, q) for q in gate.r_qubits],
                        copy=False)

        # Return if they commute
        return g1.commutes_with(g2, atol=atol)

Ancestors

  • hybridq.base.base.__Base__

Methods

def commutes_with(self, gate: Map, atol: float = 1e-07)
Expand source code
def commutes_with(self, gate: Map, atol: float = 1e-7):
    from hybridq.gate import MatrixGate

    # Gate must be a map
    if not isinstance(gate, Map):
        raise ValueError(
            f"Cannot compute commutation between 'Map' and '{type(gate).__name__}'"
        )

    # Get gates
    g1 = MatrixGate(self.Matrix,
                    qubits=[(0, q) for q in self.l_qubits] +
                    [(1, q) for q in self.r_qubits],
                    copy=False)
    g2 = MatrixGate(gate.Matrix,
                    qubits=[(0, q) for q in gate.l_qubits] +
                    [(1, q) for q in gate.r_qubits],
                    copy=False)

    # Return if they commute
    return g1.commutes_with(g2, atol=atol)
def isclose(self, gate: Map, atol: float = 1e-08)
Expand source code
def isclose(self, gate: Map, atol: float = 1e-8):

    # If gate is not a SuperGate or they qubits differ, they are different
    if not isinstance(gate, Map) or self.qubits != gate.qubits:
        return False

    # Get matrices
    _U1 = self.map(order=self.qubits)
    _U2 = gate.map(order=self.qubits)

    # Check
    return np.allclose(_U1, _U2, atol=atol)
def map(self, order: iter[any] = None)

Return map.

Parameters

order : tuple[any, …], optional
If provided, Kraus' map is ordered accordingly to order.
Expand source code
def map(self, order: iter[any] = None):
    """
    Return map.

    Parameters
    ----------
    order: tuple[any, ...], optional
        If provided, Kraus' map is ordered accordingly to `order`.
    """
    # Get left and right qubits
    l_qubits, r_qubits = self.qubits

    # Get order
    if order is not None:
        from hybridq.utils import sort

        # Get order
        order = tuple(order)

        try:
            # Split
            l_order, r_order = order

            # Convert to tuples
            l_order = tuple(l_order)
            r_order = tuple(r_order)

            # Check that qubits are consistent
            if sort(l_order) != sort(l_qubits) or sort(r_order) != sort(
                    r_qubits):
                raise RuntimeError("Something went wrong.")

            # Get order
            order = (l_order, r_order)
        except:
            if l_qubits != r_qubits or sort(order) != sort(l_qubits):
                raise ValueError(
                    "'order' is not a valid permutation of qubits.")

            # Get order
            order = (order, order)

    # Get Matrix representing the map
    _U = self.Matrix

    # Transpose if order is provided
    if order is not None and (order[0] != self.l_qubits or
                              order[1] != self.r_qubits):
        from hybridq.gate import MatrixGate

        # Get gate
        _g = MatrixGate(_U,
                        qubits=tuple((0, q) for q in l_qubits) + tuple(
                            (1, q) for q in r_qubits),
                        copy=False)

        # Transpose
        _U = _g.matrix(order=tuple((0, q) for q in order[0]) + tuple(
            (1, q) for q in order[1]))

    # Return map
    return _U