def EvaluateWithKets(variables, functions, math_expr, case_sensitive=False):
    '''
    Evaluate expression with quantum mechanical "kets" in the expression.
    Each "ket" is of the form |...> and represents a unit vector.
    We assume the kets are either orthogonal or equal to each other:
    orthogonal when the labels are different, and equal when the labels
    are equal.
    '''
    
    # avoid all XML encoding issues by not having greater-than sign or ampersand in textr
    gtch = chr(62)
    ampch = chr(38)
    math_expr = math_expr.replace(ampch + 'gt;', gtch)

    # extract list of all kets
    kvlist = map(KetVector, re.findall('\|[^{0}|]+{0}'.format(gtch), math_expr))
    kvdict = {kv.kvstring: kv for kv in kvlist}

    mehex = str(map(ord, math_expr))

    # for debugging
    if 0:
        raise Exception('type=%s, vcnt=%d, gcnt=%d, len=%d, math_expr=%s, kvlist=%s' % (type(math_expr),
                                                                                        math_expr.count('|'),
                                                                                        math_expr.count(gtch),
                                                                                        
                                                                                        len(kvlist), 
                                                                                        mehex,
                                                                                        str(kvlist).replace('>','>')))
        raise Exception('kvdict=%s' % str(kvdict).replace('>','>'))

    if not kvlist:
        return VectorState({None: evaluator(variables, functions, math_expr, case_sensitive)})

    # get set of unique kets, after evaluating their labels
    try:
        kvlabels = set([ kv.evaluator(variables, functions, case_sensitive) for kv in kvlist ])
    except Exception as err:
        raise Exception('Cannot evaluate ket label, err=%s' % err)
    
    # raise Exception('labels=%s' % kvlabels)

    # for each unique label, get coefficient
    # do this by setting all but that ket to zero and evaulating the whole math expression
    coefficient = {}
    for label in kvlabels:
        
        def kvsub(match):
            kv = kvdict[match.group(1)]
            if kv.has_label(label):
                return '1'
            return '0'
        new_expr = re.sub('(\|[^>|]+>)', kvsub, math_expr)

        # print "    label=%s, new_expr=%s" % (label, new_expr)
        coefficient[label] = evaluator(variables, functions, new_expr, case_sensitive)
    vs = VectorState(coefficient)
    # print "%s -> %s" % (math_expr, vs)
    return vs
def compare_with_tolerance(complex1, complex2, tolerance=default_tolerance, relative_tolerance=False):
    """
    Compare complex1 to complex2 with maximum tolerance tol.

    If tolerance is type string, then it is counted as relative if it ends in %; otherwise, it is absolute.

     - complex1    :  student result (float complex number)
     - complex2    :  instructor result (float complex number)
     - tolerance   :  string representing a number or float
     - relative_tolerance: bool, used when`tolerance` is float to explicitly use passed tolerance as relative.

     Default tolerance of 1e-3% is added to compare two floats for
     near-equality (to handle machine representation errors).
     Default tolerance is relative, as the acceptable difference between two
     floats depends on the magnitude of the floats.
     (http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/)
     Examples:
        In [183]: 0.000016 - 1.6*10**-5
        Out[183]: -3.3881317890172014e-21
        In [212]: 1.9e24 - 1.9*10**24
        Out[212]: 268435456.0
    """
    def myabs(elem):
        if isinstance(elem, numpy.matrix):
            return numpy.sum(abs(elem))
        return abs(elem)

    if isinstance(tolerance, numbers.Number):
        tolerance = str(tolerance)
    if relative_tolerance:
        tolerance = tolerance * max(myabs(complex1), myabs(complex2))
    elif tolerance.endswith('%'):
        tolerance = evaluator(dict(), dict(), tolerance[:-1]) * 0.01
        tolerance = tolerance * max(myabs(complex1), myabs(complex2))
    else:
        tolerance = evaluator(dict(), dict(), tolerance)

    try:
        if numpy.isinf(complex1).any() or numpy.isinf(complex2).any():
            # If an input is infinite, we can end up with `abs(complex1-complex2)` and
            # `tolerance` both equal to infinity. Then, below we would have
            # `inf <= inf` which is a fail. Instead, compare directly.
            cmp = (complex1 == complex2)
            if isinstance(cmp, numpy.matrix):
                return cmp.all()
            return cmp
        else:
            # v1 and v2 are, in general, complex numbers:
            # there are some notes about backward compatibility issue: see responsetypes.get_staff_ans()).
            # return abs(complex1 - complex2) <= tolerance
            #
            # sum() used to handle matrix comparisons
            return numpy.sum(abs(complex1 - complex2)) <= tolerance
    except Exception as err:
        print "failure in comparison, complex1=%s, complex2=%s" % (complex1, complex2)
        print "err = ", err
        raise
def matrix_evaluator(variables, functions, math_expr, case_sensitive=False):
    '''
    Do same as normal evaluator, but override some functions with ones which
    can handle matrices, like expm for matrix exponentiation.
    '''
    #mfunctions = {'exp': mfun(scipy.linalg.expm3),
    mfunctions = {'exp': mfun(scipy.linalg.expm),
                  'cos': mfun(scipy.linalg.cosm),
                  'sin': mfun(scipy.linalg.sinm),
                  'tan': mfun(scipy.linalg.tanm),
                  'sqrt': mfun(scipy.linalg.sqrtm),
                 }
    return evaluator(variables, mfunctions, math_expr, case_sensitive)
def matrix_evaluator(variables, functions, math_expr, case_sensitive=False):
    '''
    Do same as normal evaluator, but override some functions with ones which
    can handle matrices, like expm for matrix exponentiation.
    '''
    #mfunctions = {'exp': mfun(scipy.linalg.expm3),
    mfunctions = {
        'exp': mfun(scipy.linalg.expm),
        'cos': mfun(scipy.linalg.cosm),
        'sin': mfun(scipy.linalg.sinm),
        'tan': mfun(scipy.linalg.tanm),
        'sqrt': mfun(scipy.linalg.sqrtm),
    }
    return evaluator(variables, mfunctions, math_expr, case_sensitive)
Example #5
0
def compare_with_tolerance(complex1,
                           complex2,
                           tolerance=default_tolerance,
                           relative_tolerance=False):
    """
    Compare complex1 to complex2 with maximum tolerance tol.

    If tolerance is type string, then it is counted as relative if it ends in %; otherwise, it is absolute.

     - complex1    :  student result (float complex number)
     - complex2    :  instructor result (float complex number)
     - tolerance   :  string representing a number or float
     - relative_tolerance: bool, used when`tolerance` is float to explicitly use passed tolerance as relative.

     Default tolerance of 1e-3% is added to compare two floats for
     near-equality (to handle machine representation errors).
     Default tolerance is relative, as the acceptable difference between two
     floats depends on the magnitude of the floats.
     (http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/)
     Examples:
        In [183]: 0.000016 - 1.6*10**-5
        Out[183]: -3.3881317890172014e-21
        In [212]: 1.9e24 - 1.9*10**24
        Out[212]: 268435456.0
    """
    def myabs(elem):
        if isinstance(elem, numpy.matrix):
            return numpy.sum(abs(elem))
        return abs(elem)

    if isinstance(tolerance, numbers.Number):
        tolerance = str(tolerance)
    if relative_tolerance:
        tolerance = tolerance * max(myabs(complex1), myabs(complex2))
    elif tolerance.endswith('%'):
        tolerance = evaluator(dict(), dict(), tolerance[:-1]) * 0.01
        tolerance = tolerance * max(myabs(complex1), myabs(complex2))
    else:
        tolerance = evaluator(dict(), dict(), tolerance)

    try:
        if numpy.isinf(complex1).any() or numpy.isinf(complex2).any():
            # If an input is infinite, we can end up with `abs(complex1-complex2)` and
            # `tolerance` both equal to infinity. Then, below we would have
            # `inf <= inf` which is a fail. Instead, compare directly.
            cmp = (complex1 == complex2)
            if isinstance(cmp, numpy.matrix):
                return cmp.all()
            return cmp
        else:
            # v1 and v2 are, in general, complex numbers:
            # there are some notes about backward compatibility issue: see responsetypes.get_staff_ans()).
            # return abs(complex1 - complex2) <= tolerance
            #
            # sum() used to handle matrix comparisons
            return numpy.sum(abs(complex1 - complex2)) <= tolerance
    except Exception as err:
        print "failure in comparison, complex1=%s, complex2=%s" % (complex1,
                                                                   complex2)
        print "err = ", err
        raise
 def evaluator(self, variables, functions, case_sensitive=False):
    exprs = self.kvstring[1:-1].split(',')
    self.label = tuple([ evaluator(variables, functions, x, case_sensitive) for x in exprs ])
    return self.label