o
    jge                     @   s  d Z ddlZddlmZ ddlmZ ddlmZ ddlm	Z	 ddl
mZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZmZ ddlmZ ddlmZ ddlmZmZmZ ddlm Z  ddl!m"Z" ddl#m$Z$m%Z% ddl&m'Z' g dZ(G dd deZ)G dd de)eZ*G dd de)eZ+G dd de)Z,G dd de,e*Z-G dd  d e,e+Z.d!d" Z/d#d$ Z0d3d&d'Z1d4d)d*Z2d4d+d,Z3d3d-d.Z4d/d0 Z5d3d1d2Z6dS )5zQubits for quantum computing.

Todo:
* Finish implementing measurement logic. This should include POVM.
* Update docstrings.
* Update tests.
    N)Add)Mul)Integer)Pow)S)	conjugate)log_sympify)
SYMPY_INTS)Matrixzeros)
prettyForm)ComplexSpace)KetBraState)QuantumError	represent)numpy_ndarrayscipy_sparse_matrix)bitcount)QubitQubitBraIntQubitIntQubitBraqubit_to_matrixmatrix_to_qubitmatrix_to_densitymeasure_allmeasure_partialmeasure_partial_oneshotmeasure_all_oneshotc                   @   sd   e Zd ZdZedd Zedd Zedd Zedd	 Z	ed
d Z
dd Zdd Zdd ZdS )
QubitStatez"Base class for Qubit and QubitBra.c                 C   s   t |dkrt|d tr|d jS t |dkr+t|d tr+tdd |d D }n	tdd |D }tdd |D }|D ]}|tjtjfvrOt	d| q?|S )N   r   c                 s   s$    | ]}|d krt jnt jV  qdS )0Nr   ZeroOne.0qb r-   S/var/www/html/zoom/venv/lib/python3.10/site-packages/sympy/physics/quantum/qubit.py	<genexpr>E   s   " z(QubitState._eval_args.<locals>.<genexpr>c                 s   s0    | ]}|d krt jn|dkrt jn|V  qdS )r&   1Nr'   r*   r-   r-   r.   r/   G   s   . c                 s       | ]}t |V  qd S Nr	   )r+   argr-   r-   r.   r/   H       z$Qubit values must be 0 or 1, got: %r)
len
isinstancer$   qubit_valuesstrtupler   r(   r)   
ValueError)clsargselementr-   r-   r.   
_eval_args<   s   
zQubitState._eval_argsc                 C   s   t dt| S )N   )r   r5   )r;   r<   r-   r-   r.   _eval_hilbert_spaceQ   s   zQubitState._eval_hilbert_spacec                 C   s
   t | jS )z"The number of Qubits in the state.)r5   r7   selfr-   r-   r.   	dimensionY   s   
zQubitState.dimensionc                 C      | j S r2   rC   rA   r-   r-   r.   nqubits^   s   zQubitState.nqubitsc                 C   rD   )z,Returns the values of the qubits as a tuple.)labelrA   r-   r-   r.   r7   b   s   zQubitState.qubit_valuesc                 C   rD   r2   rE   rA   r-   r-   r.   __len__k   s   zQubitState.__len__c                 C   s   | j t| j| d  S )Nr%   )r7   intrC   )rB   bitr-   r-   r.   __getitem__n   s   zQubitState.__getitem__c                 G   sR   t | j}|D ]}t| j| d }|| dkrd||< qd||< q| jt| S )zFlip the bit(s) given.r%   r   )listr7   rI   rC   	__class__r9   )rB   bitsnewargsirJ   r-   r-   r.   flipu   s   


zQubitState.flipN)__name__
__module____qualname____doc__classmethodr>   r@   propertyrC   rF   r7   rH   rK   rQ   r-   r-   r-   r.   r$   5   s    




r$   c                   @   sD   e Zd ZdZedd Zdd Zdd Zdd	 Zd
d Z	dd Z
dS )r   a  A multi-qubit ket in the computational (z) basis.

    We use the normal convention that the least significant qubit is on the
    right, so ``|00001>`` has a 1 in the least significant qubit.

    Parameters
    ==========

    values : list, str
        The qubit values as a list of ints ([0,0,0,1,1,]) or a string ('011').

    Examples
    ========

    Create a qubit in a couple of different ways and look at their attributes:

        >>> from sympy.physics.quantum.qubit import Qubit
        >>> Qubit(0,0,0)
        |000>
        >>> q = Qubit('0101')
        >>> q
        |0101>

        >>> q.nqubits
        4
        >>> len(q)
        4
        >>> q.dimension
        4
        >>> q.qubit_values
        (0, 1, 0, 1)

    We can flip the value of an individual qubit:

        >>> q.flip(1)
        |0111>

    We can take the dagger of a Qubit to get a bra:

        >>> from sympy.physics.quantum.dagger import Dagger
        >>> Dagger(q)
        <0101|
        >>> type(Dagger(q))
        <class 'sympy.physics.quantum.qubit.QubitBra'>

    Inner products work as expected:

        >>> ip = Dagger(q)*q
        >>> ip
        <0101|0101>
        >>> ip.doit()
        1
    c                 C      t S r2   )r   rA   r-   r-   r.   
dual_class      zQubit.dual_classc                 K   s   | j |j kr	tjS tjS r2   )rG   r   r)   r(   rB   brahintsr-   r-   r.   _eval_innerproduct_QubitBra   s   z!Qubit._eval_innerproduct_QubitBrac                 K   s   | j di |S )Nr2   )_represent_ZGate)rB   optionsr-   r-   r.   _represent_default_basis   s   zQubit._represent_default_basisc           
      K   s   | dd}d}d}t| jD ]}||| 7 }|d }qdgd| j  }d|t|< |dkr2t|S |dkrCddl}|j|dd	 S |d
krVddl	m
}	 |	j|dd	 S dS )zBRepresent this qubits in the computational basis (ZGate).
        formatsympyr%   r   r?   numpyNcomplex)dtypescipy.sparse)sparse)getreversedr7   rC   rI   r   rd   array	transposescipyrh   
csr_matrix)
rB   basisr`   _formatndefinite_stateitresultnprh   r-   r-   r.   r_      s"   
zQubit._represent_ZGatec                 K   s   | dg }t|}t|dkrttd| j}|  | | }tt|d ddD ]}| |t|| }q*t|| jkrB|d S t|S )Nindicesr   r%   )	ri   rL   r5   rangerF   sort_reduced_densityrI   r   )rB   r\   kwargsrv   
sorted_idxnew_matrP   r-   r-   r.   _eval_trace   s   zQubit._eval_tracec              	   K   s   dd }t |fi |}|j}|d }t |}t|D ]*}	t|D ]#}
tdD ]}||
||}||	||}||	|
f  |||f 7  < q)q#q|S )zCompute the reduced density matrix by tracing out one qubit.
           The qubit argument should be of type Python int, since it is used
           in bit operations
        c                 S   s,   d| d }| |? d| > | |@  ||>  S )Nr?   r%   r-   )jkqubitbit_maskr-   r-   r.   find_index_that_is_projected   s    z<Qubit._reduced_density.<locals>.find_index_that_is_projectedr?   )r   colsr   r   rx   )rB   matrixr   r`   r   
old_matrixold_sizenew_size
new_matrixrP   r   r   colrowr-   r-   r.   rz      s   zQubit._reduced_densityN)rR   rS   rT   rU   rV   rY   r^   ra   r_   r~   rz   r-   r-   r-   r.   r      s    6
r   c                   @      e Zd ZdZedd ZdS )r   a  A multi-qubit bra in the computational (z) basis.

    We use the normal convention that the least significant qubit is on the
    right, so ``|00001>`` has a 1 in the least significant qubit.

    Parameters
    ==========

    values : list, str
        The qubit values as a list of ints ([0,0,0,1,1,]) or a string ('011').

    See also
    ========

    Qubit: Examples using qubits

    c                 C   rX   r2   )r   rA   r-   r-   r.   rY     rZ   zQubitBra.dual_classNrR   rS   rT   rU   rV   rY   r-   r-   r-   r.   r     s    r   c                   @   sJ   e Zd ZdZedddZedd Zdd Zd	d
 Zdd Z	eZ
eZdS )IntQubitStatez>A base class for qubits that work with binary representations.Nc                    s$  t  dkrt d trt S tdd  D s)tdtdd  D f |d urQt|ttfs<tdt	| t  dkrItd f | 
 d |S t  dkrw d dkrwtttt d } fd	d
|D }t|S t  dkr d dkr| 
 d  d S t S )Nr%   r   c                 s   s    | ]
}t |ttfV  qd S r2   )r6   rI   r   r+   ar-   r-   r.   r/   (  s    z+IntQubitState._eval_args.<locals>.<genexpr>z!values must be integers, got (%s)c                 s   r1   r2   )typer   r-   r-   r.   r/   )  r4   z$nqubits must be an integer, got (%s)zAtoo many positional arguments (%s). should be (number, nqubits=n)c                    s   g | ]
} d  |? d@ qS )r   r%   r-   r+   rP   r<   r-   r.   
<listcomp>7  s    z,IntQubitState._eval_args.<locals>.<listcomp>r?   )r5   r6   r$   r>   allr:   r9   rI   r   r   _eval_args_with_nqubitsrj   rx   r   abs)r;   r<   rF   rvaluesr7   r-   r   r.   r>   "  s&   


zIntQubitState._eval_argsc                    sH   t t }||k rtd |f  fddtt|D }t|S )Nz cannot represent %s with %s bitsc                    s   g | ]} |? d @ qS )r%   r-   r   numberr-   r.   r   F  s    z9IntQubitState._eval_args_with_nqubits.<locals>.<listcomp>)r   r   r:   rj   rx   r$   r>   )r;   r   rF   needr7   r-   r   r.   r   @  s   

z%IntQubitState._eval_args_with_nqubitsc                 C   s0   d}d}t | jD ]}||| 7 }|d> }q	|S )z(Return the numerical value of the qubit.r   r%   )rj   r7   )rB   r   rq   rP   r-   r-   r.   as_intI  s   
zIntQubitState.as_intc                 G   s   t |  S r2   )r8   r   )rB   printerr<   r-   r-   r.   _print_labelR     zIntQubitState._print_labelc                 G   s   | j |g|R  }t|S r2   )r   r   )rB   r   r<   rG   r-   r-   r.   _print_label_prettyU  s   z!IntQubitState._print_label_prettyr2   )rR   rS   rT   rU   rV   r>   r   r   r   r   _print_label_repr_print_label_latexr-   r-   r-   r.   r     s    
	r   c                   @   s$   e Zd ZdZedd Zdd ZdS )r   ax  A qubit ket that store integers as binary numbers in qubit values.

    The differences between this class and ``Qubit`` are:

    * The form of the constructor.
    * The qubit values are printed as their corresponding integer, rather
      than the raw qubit values. The internal storage format of the qubit
      values in the same as ``Qubit``.

    Parameters
    ==========

    values : int, tuple
        If a single argument, the integer we want to represent in the qubit
        values. This integer will be represented using the fewest possible
        number of qubits.
        If a pair of integers and the second value is more than one, the first
        integer gives the integer to represent in binary form and the second
        integer gives the number of qubits to use.
        List of zeros and ones is also accepted to generate qubit by bit pattern.

    nqubits : int
        The integer that represents the number of qubits.
        This number should be passed with keyword ``nqubits=N``.
        You can use this in order to avoid ambiguity of Qubit-style tuple of bits.
        Please see the example below for more details.

    Examples
    ========

    Create a qubit for the integer 5:

        >>> from sympy.physics.quantum.qubit import IntQubit
        >>> from sympy.physics.quantum.qubit import Qubit
        >>> q = IntQubit(5)
        >>> q
        |5>

    We can also create an ``IntQubit`` by passing a ``Qubit`` instance.

        >>> q = IntQubit(Qubit('101'))
        >>> q
        |5>
        >>> q.as_int()
        5
        >>> q.nqubits
        3
        >>> q.qubit_values
        (1, 0, 1)

    We can go back to the regular qubit form.

        >>> Qubit(q)
        |101>

    Please note that ``IntQubit`` also accepts a ``Qubit``-style list of bits.
    So, the code below yields qubits 3, not a single bit ``1``.

        >>> IntQubit(1, 1)
        |3>

    To avoid ambiguity, use ``nqubits`` parameter.
    Use of this keyword is recommended especially when you provide the values by variables.

        >>> IntQubit(1, nqubits=1)
        |1>
        >>> a = 1
        >>> IntQubit(a, nqubits=1)
        |1>
    c                 C   rX   r2   )r   rA   r-   r-   r.   rY     rZ   zIntQubit.dual_classc                 K   s   t | |S r2   )r   r^   r[   r-   r-   r.   _eval_innerproduct_IntQubitBra  r   z'IntQubit._eval_innerproduct_IntQubitBraN)rR   rS   rT   rU   rV   rY   r   r-   r-   r-   r.   r   ]  s
    F
r   c                   @   r   )r   zBA qubit bra that store integers as binary numbers in qubit values.c                 C   rX   r2   )r   rA   r-   r-   r.   rY     rZ   zIntQubitBra.dual_classNr   r-   r-   r-   r.   r     s    r   c           	         s(  d}t | tr	d}t | trd}| jd dkr&| jd }t|d}d}t}n| jd dkr<| jd }t|d}d}t}ntd	|  t |tsMtd
|  d}t	|D ]2 |r^|  df }n| d f }|dv rlt
|}|r fddt	|D }|  ||||   }qSt |tttfr| }|S )aU  Convert from the matrix repr. to a sum of Qubit objects.

    Parameters
    ----------
    matrix : Matrix, numpy.matrix, scipy.sparse
        The matrix to build the Qubit representation of. This works with
        SymPy matrices, numpy matrices and scipy.sparse sparse matrices.

    Examples
    ========

    Represent a state and then go back to its qubit form:

        >>> from sympy.physics.quantum.qubit import matrix_to_qubit, Qubit
        >>> from sympy.physics.quantum.represent import represent
        >>> q = Qubit('01')
        >>> matrix_to_qubit(represent(q))
        |01>
    rc   rd   rg   r   r%   r?   FTz*Matrix must be a row/column vector, got %rz>Matrix must be a row/column vector of size 2**nqubits, got: %r)rd   rg   c                    s    g | ]}t  d |> @ dkqS )r%   r   )rI   )r+   xrP   r-   r.   r     s     z#matrix_to_qubit.<locals>.<listcomp>)r6   r   r   shaper   r   r   r   r   rx   re   reverser   r   r   expand)	r   rb   mlistlenrF   ketr;   rt   r=   qubit_arrayr-   r   r.   r     sJ   






r   c                 C   s<   ddl m} |  }dd |D }t|dkrtjS || S )z
    Works by finding the eigenvectors and eigenvalues of the matrix.
    We know we can decompose rho by doing:
    sum(EigenVal*|Eigenvect><Eigenvect|)
    r   )Densityc                 S   s<   g | ]}|d  D ]}|d dkrt t|g|d gqqS )r?   r   )r   r   )r+   r   vectorr-   r-   r.   r     s    z%matrix_to_density.<locals>.<listcomp>)sympy.physics.quantum.densityr   
eigenvectsr5   r   r(   )matr   eigenr<   r-   r-   r.   r     s   r   rc   c                 C   s   t | |dS )zConverts an Add/Mul of Qubit objects into it's matrix representation

    This function is the inverse of ``matrix_to_qubit`` and is a shorthand
    for ``represent(qubit)``.
    )rb   r   )r   rb   r-   r-   r.   r     s   r   Tc                 C   s   t | |}|dkrDg }|r| }t|j}tt|td }t|D ]}|| rA|t	t
||d|| t||  f q&|S td)a  Perform an ensemble measurement of all qubits.

    Parameters
    ==========

    qubit : Qubit, Add
        The qubit to measure. This can be any Qubit or a linear combination
        of them.
    format : str
        The format of the intermediate matrices to use. Possible values are
        ('sympy','numpy','scipy.sparse'). Currently only 'sympy' is
        implemented.

    Returns
    =======

    result : list
        A list that consists of primitive states and their probabilities.

    Examples
    ========

        >>> from sympy.physics.quantum.qubit import Qubit, measure_all
        >>> from sympy.physics.quantum.gate import H
        >>> from sympy.physics.quantum.qapply import qapply

        >>> c = H(0)*H(1)*Qubit('00')
        >>> c
        H(0)*H(1)*|00>
        >>> q = qapply(c)
        >>> measure_all(q)
        [(|00>, 1/4), (|01>, 1/4), (|10>, 1/4), (|11>, 1/4)]
    rc   r?   )rF   8This function cannot handle non-SymPy matrix formats yet)r   
normalizedmaxr   rI   mathr   rx   appendr   r   r   NotImplementedError)r   rb   	normalizemresultssizerF   rP   r-   r-   r.   r      s"   
"
"r    c           
      C   s   t | |}t|ttfrt|f}|dkrL|r| }t||}g }|D ]%}d}||j| d 7 }|dkrI|r>t| }	nt|}	|	|	|f q$|S t
d)a  Perform a partial ensemble measure on the specified qubits.

    Parameters
    ==========

    qubits : Qubit
        The qubit to measure.  This can be any Qubit or a linear combination
        of them.
    bits : tuple
        The qubits to measure.
    format : str
        The format of the intermediate matrices to use. Possible values are
        ('sympy','numpy','scipy.sparse'). Currently only 'sympy' is
        implemented.

    Returns
    =======

    result : list
        A list that consists of primitive states and their probabilities.

    Examples
    ========

        >>> from sympy.physics.quantum.qubit import Qubit, measure_partial
        >>> from sympy.physics.quantum.gate import H
        >>> from sympy.physics.quantum.qapply import qapply

        >>> c = H(0)*H(1)*Qubit('00')
        >>> c
        H(0)*H(1)*|00>
        >>> q = qapply(c)
        >>> measure_partial(q, (0,))
        [(sqrt(2)*|00>/2 + sqrt(2)*|10>/2, 1/2), (sqrt(2)*|01>/2 + sqrt(2)*|11>/2, 1/2)]
    rc   r   r   )r   r6   r   r   rI   r   _get_possible_outcomesHr   r   r   )
r   rN   rb   r   r   possible_outcomesoutputoutcomeprob_of_outcomenext_matrixr-   r-   r.   r!   T  s0   
$

r!   c           	      C   sx   ddl }t| |}|dkr8| }t||}|  }d}|D ]}||j| d 7 }||kr5t|   S qdS td)a  Perform a partial oneshot measurement on the specified qubits.

    A oneshot measurement is equivalent to performing a measurement on a
    quantum system. This type of measurement does not return the probabilities
    like an ensemble measurement does, but rather returns *one* of the
    possible resulting states. The exact state that is returned is determined
    by picking a state randomly according to the ensemble probabilities.

    Parameters
    ----------
    qubits : Qubit
        The qubit to measure.  This can be any Qubit or a linear combination
        of them.
    bits : tuple
        The qubits to measure.
    format : str
        The format of the intermediate matrices to use. Possible values are
        ('sympy','numpy','scipy.sparse'). Currently only 'sympy' is
        implemented.

    Returns
    -------
    result : Qubit
        The qubit that the system collapsed to upon measurement.
    r   Nrc   r   )randomr   r   r   r   r   r   )	r   rN   rb   r   r   r   random_number
total_probr   r-   r-   r.   r"     s    

r"   c           
      C   s   t | j}tt|d }g }tdt|> D ]}|td| d qg }|D ]	}|d|>  q)td| D ]!}d}tt|D ]}	|||	 @ rQ||	d 7 }qC| | || |< q9|S )a  Get the possible states that can be produced in a measurement.

    Parameters
    ----------
    m : Matrix
        The matrix representing the state of the system.
    bits : tuple, list
        Which bits will be measured.

    Returns
    -------
    result : list
        The list of possible states which can occur given this measurement.
        These are un-normalized so we can derive the probability of finding
        this state by taking the inner product with itself
    皙?r%   r?   r   )	r   r   rI   r   log2rx   r5   r   r   )
r   rN   r   rF   output_matricesrP   	bit_masksrJ   truenessr   r-   r-   r.   r     s    
r   c                 C   s   ddl }t| }|dkr@| }|  }d}d}|D ]}|||  7 }||kr* n|d7 }qtt|ttt	|j
d S td)ad  Perform a oneshot ensemble measurement on all qubits.

    A oneshot measurement is equivalent to performing a measurement on a
    quantum system. This type of measurement does not return the probabilities
    like an ensemble measurement does, but rather returns *one* of the
    possible resulting states. The exact state that is returned is determined
    by picking a state randomly according to the ensemble probabilities.

    Parameters
    ----------
    qubits : Qubit
        The qubit to measure.  This can be any Qubit or a linear combination
        of them.
    format : str
        The format of the intermediate matrices to use. Possible values are
        ('sympy','numpy','scipy.sparse'). Currently only 'sympy' is
        implemented.

    Returns
    -------
    result : Qubit
        The qubit that the system collapsed to upon measurement.
    r   Nrc   r%   r   r   )r   r   r   r   r   r   rI   r   r   r   r   r   )r   rb   r   r   r   totalrt   rP   r-   r-   r.   r#     s    
"r#   )rc   )rc   T)7rU   r   sympy.core.addr   sympy.core.mulr   sympy.core.numbersr   sympy.core.powerr   sympy.core.singletonr   $sympy.functions.elementary.complexesr   &sympy.functions.elementary.exponentialr   sympy.core.basicr
   sympy.external.gmpyr   sympy.matricesr   r    sympy.printing.pretty.stringpictr   sympy.physics.quantum.hilbertr   sympy.physics.quantum.stater   r   r   sympy.physics.quantum.qexprr   sympy.physics.quantum.representr   !sympy.physics.quantum.matrixutilsr   r   mpmath.libmp.libintmathr   __all__r$   r   r   r   r   r   r   r   r   r    r!   r"   r   r#   r-   r-   r-   r.   <module>   sF    	L >NF


8
K03