Ejemplo n.º 1
0
    def eval(cls, a, b):
        """The Commutator [A,B] is on canonical form if A < B.
        """
        if not (a and b): return S.Zero
        if a == b: return Integer(2) * a**2
        if a.is_commutative or b.is_commutative:
            return Integer(2) * a * b

        # [xA,yB]  ->  xy*[A,B]
        # from sympy.physics.qmul import QMul
        c_part = []
        nc_part = []
        nc_part2 = []
        if isinstance(a, Mul):
            c_part, nc_part = split_commutative_parts(a)
        if isinstance(b, Mul):
            c_part2, nc_part2 = split_commutative_parts(b)
            c_part.extend(c_part2)
        if c_part:
            a = nc_part or [a]
            b = nc_part2 or [b]
            return Mul(Mul(*c_part), cls(Mul(*a), Mul(*b)))

        # Canonical ordering of arguments
        if a.compare(b) == 1:
            return cls(b, a)
Ejemplo n.º 2
0
    def eval(cls, a, b):
        """The Commutator [A,B] is on canonical form if A < B.
        """
        if not (a and b): return S.Zero
        if a == b: return Integer(2)*a**2
        if a.is_commutative or b.is_commutative:
            return Integer(2)*a*b

        # [xA,yB]  ->  xy*[A,B]
        # from sympy.physics.qmul import QMul
        c_part = []
        nc_part = []
        nc_part2 = []
        if isinstance(a, Mul):
            c_part, nc_part = split_commutative_parts(a)
        if isinstance(b, Mul):
            c_part2, nc_part2 = split_commutative_parts(b)
            c_part.extend(c_part2)
        if c_part:
            a = nc_part or [a]
            b = nc_part2 or [b]
            return Mul(Mul(*c_part), cls(Mul(*a), Mul(*b)))

        # Canonical ordering of arguments
        if a.compare(b) == 1:
            return cls(b,a)
Ejemplo n.º 3
0
def __separate_scalar_factor(monomial):
    """Separate the constant factor from a monomial.
    """
    scalar_factor = 1
    if is_number_type(monomial):
        return S.One, monomial
    if monomial == 0:
        return S.One, 0
    comm_factors, _ = split_commutative_parts(monomial)
    if len(comm_factors) > 0:
        if isinstance(comm_factors[0], Number):
            scalar_factor = comm_factors[0]
    if scalar_factor != 1:
        return monomial / scalar_factor, scalar_factor
    else:
        return monomial, scalar_factor
Ejemplo n.º 4
0
 def flatten(cls, args):
     # TODO: disallow nested TensorProducts.
     c_part = []
     nc_parts = []
     for arg in args:
         if isinstance(arg, Mul):
             cp, ncp = split_commutative_parts(arg)
             ncp = Mul(*ncp)
         else:
             if arg.is_commutative:
                 cp = [arg]; ncp = 1
             else:
                 cp = []; ncp = arg
         c_part.extend(cp)
         nc_parts.append(ncp)
     return c_part, nc_parts
Ejemplo n.º 5
0
def separate_scalar_factor(monomial):
    """Separate the constant factor from a monomial.
    """
    scalar_factor = 1
    if isinstance(monomial, int):
        return S.One, monomial
    if monomial == 0:
        return S.One, 0
    comm_factors, non_commfactors = split_commutative_parts(monomial)
    if len(comm_factors) > 0:
        if isinstance(comm_factors[0], Number):
            scalar_factor = comm_factors[0]
    if scalar_factor != 1:
        return monomial / scalar_factor, scalar_factor
    else:
        return monomial, scalar_factor
Ejemplo n.º 6
0
def get_support_variables(polynomial):
    """Gets the support of a polynomial.
    """
    support = []
    if is_number_type(polynomial):
        return support
    polynomial = polynomial.expand()
    for monomial in polynomial.as_coefficients_dict():
        monomial, _ = __separate_scalar_factor(monomial)
        symbolic_support = flatten(split_commutative_parts(monomial))
        for s in symbolic_support:
            if isinstance(s, Pow):
                base = s.base
                if is_adjoint(base):
                    base = base.adjoint()
                support.append(base)
            elif is_adjoint(s):
                support.append(s.adjoint())
            elif isinstance(s, Operator):
                support.append(s)
    return support
Ejemplo n.º 7
0
def get_support(variables, polynomial):
    """Gets the support of a polynomial.
    """
    support = []
    if is_number_type(polynomial):
        support.append([0] * len(variables))
        return support
    polynomial = polynomial.expand()
    for monomial in polynomial.as_coefficients_dict():
        tmp_support = [0] * len(variables)
        monomial, _ = __separate_scalar_factor(monomial)
        symbolic_support = flatten(split_commutative_parts(monomial))
        for s in symbolic_support:
            if isinstance(s, Pow):
                base = s.base
                if is_adjoint(base):
                    base = base.adjoint()
                tmp_support[variables.index(base)] = s.exp
            elif is_adjoint(s):
                tmp_support[variables.index(s.adjoint())] = 1
            elif isinstance(s, (Operator, Symbol)):
                tmp_support[variables.index(s)] = 1
        support.append(tmp_support)
    return support
Ejemplo n.º 8
0
def get_support(variables, polynomial):
    """Gets the support of a polynomial.
    """
    support = []
    if isinstance(polynomial, (int, float, complex)):
        support.append([0] * len(variables))
        return support
    polynomial = polynomial.expand()
    for monomial in polynomial.as_coefficients_dict():
        tmp_support = [0] * len(variables)
        monomial, _ = separate_scalar_factor(monomial)
        symbolic_support = flatten(split_commutative_parts(monomial))
        for s in symbolic_support:
            if isinstance(s, Pow):
                base = s.base
                if isinstance(base, Dagger):
                    base = Dagger(base)
                tmp_support[variables.index(base)] = s.exp
            elif isinstance(s, Dagger):
                tmp_support[variables.index(Dagger(s))] = 1
            elif isinstance(s, Operator):
                tmp_support[variables.index(s)] = 1
        support.append(tmp_support)
    return support
Ejemplo n.º 9
0
def get_support(variables, polynomial):
    """Gets the support of a polynomial.
    """
    support = []
    if isinstance(polynomial, (int, float, complex)):
        support.append([0] * len(variables))
        return support
    polynomial = polynomial.expand()
    for monomial in polynomial.as_coefficients_dict():
        tmp_support = [0] * len(variables)
        monomial, scalar = separate_scalar_factor(monomial)
        symbolic_support = flatten(split_commutative_parts(monomial))
        for s in symbolic_support:
            if isinstance(s, Pow):
                base = s.base
                if isinstance(base, Dagger):
                    base = Dagger(base)
                tmp_support[variables.index(base)] = s.exp
            elif isinstance(s, Dagger):
                tmp_support[variables.index(Dagger(s))] = 1
            elif isinstance(s, Operator):
                tmp_support[variables.index(s)] = 1
        support.append(tmp_support)
    return support
Ejemplo n.º 10
0
def fast_substitute(monomial, old_sub, new_sub):
    """Experimental fast substitution routine that considers only restricted
    cases of noncommutative algebras. In rare cases, it fails to find a
    substitution. Use it with proper testing.

    :param monomial: The monomial with parts need to be substituted.
    :param old_sub: The part to be replaced.
    :param new_sub: The replacement.
    """
    if is_number_type(monomial):
        return monomial
    if monomial.is_Add:
        return sum([fast_substitute(element, old_sub, new_sub) for element in
                    monomial.as_ordered_terms()])

    comm_factors, ncomm_factors = split_commutative_parts(monomial)
    old_comm_factors, old_ncomm_factors = split_commutative_parts(old_sub)
    # This is a temporary hack
    if not isinstance(new_sub, int) and not isinstance(new_sub, float):
        new_comm_factors, _ = split_commutative_parts(new_sub)
    else:
        new_comm_factors = [new_sub]
    comm_monomial = 1
    is_constant_term = False
    if len(comm_factors) == 1 and is_number_type(comm_factors[0]):
        is_constant_term = True
        comm_monomial = comm_factors[0]
    if not is_constant_term and len(comm_factors) > 0:
        for comm_factor in comm_factors:
            comm_monomial *= comm_factor
        if len(old_comm_factors) > 0:
            comm_old_sub = 1
            for comm_factor in old_comm_factors:
                comm_old_sub *= comm_factor
            comm_new_sub = 1
            for comm_factor in new_comm_factors:
                comm_new_sub *= comm_factor
            # Dummy heuristic to get around retarded SymPy bug
            if isinstance(comm_old_sub, Pow):
                # In this case, we are in trouble
                old_base = comm_old_sub.base
                if comm_monomial.has(old_base):
                    old_degree = comm_old_sub.exp
                    new_monomial = 1
                    match = False
                    for factor in comm_monomial.as_ordered_factors():
                        if factor.has(old_base):
                            if isinstance(factor, Pow):
                                degree = factor.exp
                                if degree >= old_degree:
                                    match = True
                                    new_monomial *= \
                                        old_base**(degree-old_degree) * \
                                        comm_new_sub

                            else:
                                new_monomial *= factor
                        else:
                            new_monomial *= factor
                    if match:
                        comm_monomial = new_monomial
            else:
                comm_monomial = comm_monomial.subs(comm_old_sub, comm_new_sub)
    if len(ncomm_factors) == 0 or len(old_ncomm_factors) == 0:
        return comm_monomial
    # old_factors = old_sub.as_ordered_factors()
    # factors = monomial.as_ordered_factors()
    new_var_list = []
    new_monomial = 1
    match = False
    left_remainder = 1
    right_remainder = 1
    for i in range(len(ncomm_factors) - len(old_ncomm_factors) + 1):
        for j in range(len(old_ncomm_factors)):
            if isinstance(ncomm_factors[i + j], Number) and \
                ((not isinstance(old_ncomm_factors[j], Number) or
                  ncomm_factors[i + j] != old_ncomm_factors[j])):
                break
            if isinstance(ncomm_factors[i + j], Symbol) and \
                (not isinstance(old_ncomm_factors[j], Operator) or
                 (isinstance(old_ncomm_factors[j], Symbol) and
                  ncomm_factors[i + j] != old_ncomm_factors[j])):
                break
            if isinstance(ncomm_factors[i + j], Operator) and \
                isinstance(old_ncomm_factors[j], Operator) and \
                    ncomm_factors[i + j] != old_ncomm_factors[j]:
                break
            if is_adjoint(ncomm_factors[i + j]) and \
                (not is_adjoint(old_ncomm_factors[j]) or
                 ncomm_factors[i + j] != old_ncomm_factors[j]):
                break
            if not is_adjoint(ncomm_factors[i + j]) and \
                not isinstance(ncomm_factors[i + j], Pow) and \
                    is_adjoint(old_ncomm_factors[j]):
                break
            if isinstance(ncomm_factors[i + j], Pow):
                if isinstance(old_ncomm_factors[j], Pow):
                    old_base = old_ncomm_factors[j].base
                    old_degree = old_ncomm_factors[j].exp
                else:
                    old_base = old_ncomm_factors[j]
                    old_degree = 1
                if old_base != ncomm_factors[i + j].base:
                    break
                if old_degree > ncomm_factors[i + j].exp:
                    break
                if old_degree < ncomm_factors[i + j].exp:
                    if j != len(old_ncomm_factors) - 1:
                        if j != 0:
                            break
                        else:
                            left_remainder = old_base ** (
                                ncomm_factors[i + j].exp - old_degree)
                    else:
                        right_remainder = old_base ** (
                            ncomm_factors[i + j].exp - old_degree)
            if isinstance(ncomm_factors[i + j], Operator) and \
                    isinstance(old_ncomm_factors[j], Pow):
                break
        else:
            match = True
        if not match:
            new_var_list.append(ncomm_factors[i])
        else:
            new_monomial = 1
            for var in new_var_list:
                new_monomial *= var
            new_monomial *= left_remainder * new_sub * right_remainder
            for j in range(i + len(old_ncomm_factors), len(ncomm_factors)):
                new_monomial *= ncomm_factors[j]
            new_monomial *= comm_monomial
            break
    else:
        if not is_constant_term and len(comm_factors) > 0:
            new_monomial = comm_monomial
            for factor in ncomm_factors:
                new_monomial *= factor
        else:
            return monomial
    if not isinstance(new_sub, (float, int, complex)) and new_sub.is_Add:
        return expand(new_monomial)
    else:
        return new_monomial
Ejemplo n.º 11
0
def tensor_product_simp_Mul(e):
    """Simplify a Mul with TensorProducts.

    Current the main use of this is to simplify a ``Mul`` of
    ``TensorProduct``s to a ``TensorProduct`` of ``Muls``. It currently only
    works for relatively simple cases where the initial ``Mul`` only has
    scalars and raw ``TensorProduct``s, not ``Add``, ``Pow``, ``Commutator``s
    of ``TensorProduct``s.

    Parameters
    ==========
    e : Expr
        A ``Mul`` of ``TensorProduct``s to be simplified.

    Returns
    =======
    e : Expr
        A ``TensorProduct`` of ``Mul``s.

    Examples
    ========

    This is an example of the type of simplification that this function
    performs::

        >>> from sympy.physics.quantum.tensorproduct import tensor_product_simp_Mul, TensorProduct
        >>> from sympy import Symbol
        >>> A = Symbol('A',commutative=False)
        >>> B = Symbol('B',commutative=False)
        >>> C = Symbol('C',commutative=False)
        >>> D = Symbol('D',commutative=False)
        >>> e = TensorProduct(A,B)*TensorProduct(C,D)
        >>> e
        AxB*CxD
        >>> tensor_product_simp_Mul(e)
        (A*C)x(B*D)

    """
    # TODO: This won't work with Muls that have other composites of
    # TensorProducts, like an Add, Pow, Commutator, etc.
    # TODO: This only works for the equivalent of single Qbit gates.
    if not isinstance(e, Mul):
        return e
    c_part, nc_part = split_commutative_parts(e)
    n_nc = len(nc_part)
    if n_nc == 0 or n_nc == 1:
        return e
    elif e.has(TensorProduct):
        current = nc_part[0]
        if not isinstance(current, TensorProduct):
            raise TypeError('TensorProduct expected, got: %r' % current)
        n_terms = len(current.args)
        new_args = list(current.args)
        for next in nc_part[1:]:
            # TODO: check the hilbert spaces of next and current here.
            if isinstance(next, TensorProduct):
                if n_terms != len(next.args):
                    raise QuantumError(
                        'TensorProducts of different lengths: %r and %r' % \
                        (current, next)
                    )
                for i in range(len(new_args)):
                    new_args[i] = new_args[i]*next.args[i]
            else:
                # this won't quite work as we don't want next in the TensorProduct
                for i in range(len(new_args)):
                    new_args[i] = new_args[i]*next
            current = next
        return Mul(*c_part)*TensorProduct(*new_args)
    else:
        return e
Ejemplo n.º 12
0
def fast_substitute(monomial, old_sub, new_sub):
    """Experimental fast substitution routine that considers only restricted
    cases of noncommutative algebras. In rare cases, it fails to find a
    substitution. Use it with proper testing.

    :param monomial: The monomial with parts need to be substituted.
    :param old_sub: The part to be replaced.
    :param new_sub: The replacement.
    """
    if isinstance(monomial, Number):
        return monomial
    if isinstance(monomial, int):
        return monomial
    comm_factors, ncomm_factors = split_commutative_parts(monomial)
    old_comm_factors, old_ncomm_factors = split_commutative_parts(old_sub)
    # This is a temporary hack
    if not isinstance(new_sub, int):
        new_comm_factors, new_ncomm_factors = split_commutative_parts(new_sub)
    comm_monomial = 1
    is_constant_term = False
    if len(comm_factors) == 1 and isinstance(comm_factors[0], Number):
        is_constant_term = True
        comm_monomial = comm_factors[0]
    if not is_constant_term and len(comm_factors) > 0:
        for comm_factor in comm_factors:
            comm_monomial *= comm_factor
        if len(old_comm_factors) > 0:
            comm_old_sub = 1
            for comm_factor in old_comm_factors:
                comm_old_sub *= comm_factor
            comm_new_sub = 1
            for comm_factor in new_comm_factors:
                comm_new_sub *= comm_factor
            comm_monomial = comm_monomial.subs(comm_old_sub, comm_new_sub)
    if len(ncomm_factors) == 0 or len(old_ncomm_factors) == 0:
        return comm_monomial
    # old_factors = old_sub.as_ordered_factors()
    # factors = monomial.as_ordered_factors()
    new_var_list = []
    new_monomial = 1
    match = False
    left_remainder = 1
    right_remainder = 1
    for i in range(len(ncomm_factors) - len(old_ncomm_factors) + 1):
        for j in range(len(old_ncomm_factors)):
            if isinstance(ncomm_factors[i + j], Number) and \
                ((not isinstance(old_ncomm_factors[j], Number) or
                  ncomm_factors[i + j] != old_ncomm_factors[j])):
                break
            if isinstance(ncomm_factors[i + j], Symbol) and \
                (not isinstance(old_ncomm_factors[j], Operator) or
                 (isinstance(old_ncomm_factors[j], Symbol) and
                  ncomm_factors[i + j] != old_ncomm_factors[j])):
                break
            if isinstance(ncomm_factors[i + j], Operator) and \
                isinstance(old_ncomm_factors[j], Operator) and \
                    ncomm_factors[i + j] != old_ncomm_factors[j]:
                break
            if isinstance(ncomm_factors[i + j], Dagger) and \
                (not isinstance(old_ncomm_factors[j], Dagger) or
                 ncomm_factors[i + j] != old_ncomm_factors[j]):
                break
            if not isinstance(ncomm_factors[i + j], Dagger) and \
                not isinstance(ncomm_factors[i + j], Pow) and \
                    isinstance(old_ncomm_factors[j], Dagger):
                break
            if isinstance(ncomm_factors[i + j], Pow):
                old_degree = 1
                old_base = 1
                if isinstance(old_ncomm_factors[j], Pow):
                    old_base = old_ncomm_factors[j].base
                    old_degree = old_ncomm_factors[j].exp
                else:
                    old_base = old_ncomm_factors[j]
                if old_base != ncomm_factors[i + j].base:
                    break
                if old_degree > ncomm_factors[i + j].exp:
                    break
                if old_degree < ncomm_factors[i + j].exp:
                    if j != len(old_ncomm_factors) - 1:
                        if j != 0:
                            break
                        else:
                            left_remainder = old_base**(
                                ncomm_factors[i + j].exp - old_degree)
                    else:
                        right_remainder = old_base**(ncomm_factors[i + j].exp -
                                                     old_degree)
            if isinstance(ncomm_factors[i + j], Operator) and \
                    isinstance(old_ncomm_factors[j], Pow):
                break
        else:
            match = True
        if not match:
            new_var_list.append(ncomm_factors[i])
        else:
            new_monomial = 1
            for var in new_var_list:
                new_monomial *= var
            new_monomial *= left_remainder * new_sub * right_remainder
            for j in range(i + len(old_ncomm_factors), len(ncomm_factors)):
                new_monomial *= ncomm_factors[j]
            new_monomial *= comm_monomial
            break
    else:
        if not is_constant_term and len(comm_factors) > 0:
            new_monomial = comm_monomial
            for factor in ncomm_factors:
                new_monomial *= factor
        else:
            return monomial
    return new_monomial