Exemplo n.º 1
0
def openFunctionCache( name ):
    if name in g.functionCaches:
        return g.functionCaches[ name ]
    else:
        debugPrint( 'opening', name, 'function cache database' )
        g.functionCaches[ name ] = PersistentDict( getCacheFileName( name ) )
        return g.functionCaches[ name ]
Exemplo n.º 2
0
def openFunctionCache(name):
    if name in g.functionCaches:
        return g.functionCaches[name]

    debugPrint('opening', name, 'function cache database')
    g.functionCaches[name] = PersistentDict(getCacheFileName(name))
    return g.functionCaches[name]
Exemplo n.º 3
0
def runYAFU(n):
    fullOut = subprocess.run([
        g.userConfiguration['yafu_path'] + os.sep +
        g.userConfiguration['yafu_binary'], '-xover', '120'
    ],
                             input='factor(' + str(int(n)) + ')\n',
                             encoding='ascii',
                             stdout=subprocess.PIPE,
                             cwd=g.userConfiguration['yafu_path'],
                             check=True).stdout

    #print( 'out', fullOut )

    out = fullOut[fullOut.find('***factors found***'):]

    if len(out) < 2:
        if log10(n) > 40:
            raise ValueError('yafu seems to have crashed trying to factor ' +
                             str(int(n)) + '.\n\nyafu output follows:\n' +
                             fullOut)

        debugPrint(
            'yafu seems to have crashed, switching to built-in factoring code')
        return factorise(int(n))

    result = []

    while True:
        prime = ''

        out = out[out.find('P'):]

        if len(out) < 2:
            break

        out = out[out.find('='):]

        index = 2

        while out[index] >= '0' and out[index] <= '9':
            prime += out[index]
            index += 1

        result.append(mpmathify(prime))

    if not result:
        raise ValueError('yafu seems to have failed.')

    answer = fprod(result)

    if answer != n:
        debugPrint('\nyafu has barfed')
        for i in result:
            n = fdiv(n, i)

        result.extend(runYAFU(n))

    return sorted(result)
Exemplo n.º 4
0
def getFactors(target):
    if target < -1:
        result = [-1]
        result.extend(getFactors(fneg(target)))
        return result

    if target == -1:
        return [-1]

    if target == 0:
        return [0]

    if target == 1:
        return [1]

    n = int(floor(target))

    setAccuracy(floor(fadd(log10(n), 2)))

    if g.factorCache is None:
        loadFactorCache()

    if not g.ignoreCache:
        if n in g.factorCache:
            if g.verbose and n != 1:
                print('cache hit:', n)
                print()

            debugPrint('\nfactor cache', n, g.factorCache[n])

            return g.factorCache[n]

    try:
        result = factorByTrialDivision(n)  # throws if n is too big

        if n > g.minValueToCache and n not in g.factorCache:
            g.factorCache[n] = result

        return result

    except ValueError:
        pass

    if g.useYAFU and n > g.minValueForYAFU:
        result = runYAFU(n)
    else:
        result = factorise(int(n))

    if n > g.minValueToCache:
        if g.ignoreCache or (not g.ignoreCache and n not in g.factorCache):
            debugPrint('\ncaching factors of ', n, result)
            g.factorCache[n] = result

    return result
Exemplo n.º 5
0
def getPartitionNumber(n):
    '''
    This version is, um, less recursive than the original, which I've kept.
    The strategy is to create a list of the smaller partition numbers we need
    to calculate and then start calling them recursively, starting with the
    smallest.  This will minimize the number of recursions necessary, and in
    combination with caching values, will calculate practically any integer
    partition without the risk of a stack overflow.

    I can't help but think this is still grossly inefficient compared to what's
    possible.  It seems that using this algorithm, calculating any integer
    partition ends up necessitating calculating the integer partitions of
    every integer smaller than the original argument.
    '''
    debugPrint('partition', int(n))

    if n in (0, 1):
        return 1

    sign = 1
    i = 1
    k = 1

    estimate = log10(
        fdiv(power(e, fmul(pi, sqrt(fdiv(fmul(2, n), 3)))),
             fprod([4, n, sqrt(3)])))
    if mp.dps < estimate + 5:
        mp.dps = estimate + 5

    partitionList = []

    while n - k >= 0:
        partitionList.append((fsub(n, k), sign))
        i += 1

        if i % 2:
            sign *= -1

        k = getNthGeneralizedPolygonalNumber(i, 5)

    partitionList = partitionList[::-1]

    total = 0

    for partition, sign in partitionList:
        total = fadd(total, fmul(sign, getPartitionNumber(partition)))

    return total
Exemplo n.º 6
0
def evaluateDiceExpression(args, sumIfPossible=True):
    result = []
    modifierSum = 0  # currently only a single modifier is allowed

    if sumIfPossible:
        result = [0]

    for diceCount, diceValue, dropLowestCount, dropHighestCount, modifier in args:
        modifierSum += modifier

        if dropLowestCount == 0 and dropHighestCount == 0:
            if sumIfPossible:
                for _ in range(0, diceCount):
                    result[0] += (randrange(diceValue) + 1)
            else:
                for _ in range(0, diceCount):
                    result.append(randrange(diceValue) + 1)
        else:
            dice = []

            for _ in range(0, diceCount):
                dice.append(randrange(diceValue) + 1)

            dice.sort()
            debugPrint('dice', dice)

            if dropHighestCount > 0:
                debugPrint('drop', dice[dropLowestCount:-dropHighestCount])
                result.extend(dice[dropLowestCount:-dropHighestCount])
            else:
                debugPrint('drop', dice[dropLowestCount:])
                result.extend(dice[dropLowestCount:])

    return result, modifierSum
Exemplo n.º 7
0
def convertUnits(unit1, unit2):
    if isinstance(unit1, RPNGenerator):
        unit1 = list(unit1)

        if len(unit1) == 1:
            unit1 = unit1[0]

    if isinstance(unit2, RPNGenerator):
        unit2 = list(unit2)

        if len(unit2) == 1:
            unit2 = unit2[0]

    if isinstance(unit1, list):
        result = []

        for unit in unit1:
            result.append(convertUnits(unit, unit2))

        return result

    if not isinstance(unit1, RPNMeasurement):
        raise ValueError('cannot convert non-measurements')

    if isinstance(unit2, list):
        return unit1.convertValue(unit2)

    if isinstance(unit2, (str, RPNUnits)):
        measurement = RPNMeasurement(1, unit2)
        return RPNMeasurement(unit1.convertValue(measurement), unit2)

    if not isinstance(unit2, (list, str, RPNUnits, RPNMeasurement)):
        raise ValueError('cannot convert non-measurements')

    debugPrint('convertUnits')
    debugPrint('unit1:', unit1.getUnitTypes())
    debugPrint('unit2:', unit2.getUnitTypes())

    newValue = unit1.convertValue(unit2)

    debugPrint('*** value:', newValue)

    return RPNMeasurement(newValue, unit2.units)
Exemplo n.º 8
0
def findInput(value, func, estimator, minimum=0, maximum=inf):
    guess1 = floor(estimator(value))

    if guess1 > maximum:
        guess1 = maximum

    if guess1 < minimum:
        guess1 = minimum

    # closing in
    result = func(guess1)
    debugPrint('findInput func call', guess1)

    if result == value:
        return True, guess1
    elif result > value:
        over = True
        delta = -1
    else:
        over = False
        delta = 1

    guess2 = guess1 + delta

    if guess2 > maximum:
        guess2 = maximum

    if guess2 < minimum:
        guess2 = minimum

    result = func(guess2)
    debugPrint('findInput func call', guess2)

    if result == value:
        return True, guess2

    if over:

        def comparator(a, b):
            return a > b
    else:

        def comparator(a, b):
            return a < b

    while comparator(result, value):
        delta *= 2
        guess1 = guess2
        guess2 += delta

        if guess2 > maximum:
            return False, 0

        if guess2 < minimum:
            break

        result = func(guess2)
        debugPrint('findInput func call', guess2)

        if result == value:
            return True, guess2

    if guess1 < minimum:
        guess1 = minimum

    if guess2 < minimum:
        guess2 = minimum

    if guess1 == guess2:
        return False, 0
    elif guess1 > guess2:
        guess1, guess2 = int(guess2), int(guess1)
    else:
        guess1, guess2 = int(guess1), int(guess2)

    debugPrint('->guesses:', guess1, guess2)

    while guess1 + 1 != guess2:
        newGuess = guess1 + (guess2 - guess1) // 2

        result = func(newGuess)
        debugPrint('findInput func call', newGuess)

        if result == value:
            return True, newGuess
        elif result > value:
            guess2 = newGuess
        else:
            guess1 = newGuess

    debugPrint('didn\'t find anything')

    return False, 0
Exemplo n.º 9
0
    def convertValue(self, other):
        if not isinstance(other, (RPNUnits, RPNMeasurement, str, list)):
            raise ValueError(
                'convertValue must be called with an RPNUnits object, '
                'an RPNMeasurement object, a string or a list of RPNMeasurement'
            )

        if isinstance(other, (str, RPNUnits)):
            other = RPNMeasurement(1, other)

        if not self.isCompatible(other):
            # We can try to convert incompatible units.
            return self.convertIncompatibleUnit(other)

        if not g.unitConversionMatrix:
            loadUnitConversionMatrix()

        # handle list conversions like [ year, day, minute, hour ]
        if isinstance(other, list):
            # a list of length one is treated the same as a single measurement
            if len(other) == 1:
                return self.convertValue(other[0])
            else:
                listToConvert = []

                for i in other:
                    if isinstance(i, str):
                        listToConvert.append(RPNMeasurement(1, i))
                    elif isinstance(i, RPNMeasurement):
                        listToConvert.append(i)
                    else:
                        raise ValueError('we\'ve got something else')

                return self.convertUnitList(listToConvert)

        conversions = []

        value = self.value  # This is what we'll return down below

        # let's look for straightforward conversions
        units1 = self.units
        units2 = other.units

        unit1String = units1.getUnitString()
        unit2String = units2.getUnitString()

        if unit1String == unit2String:
            return value

        exponents = {}

        # look for a straight-up conversion
        if (unit1String, unit2String) in g.unitConversionMatrix:
            value = fmul(
                value,
                mpmathify(g.unitConversionMatrix[(unit1String, unit2String)]))
        elif (unit1String, unit2String) in specialUnitConversionMatrix:
            value = specialUnitConversionMatrix[(unit1String,
                                                 unit2String)](value)
        else:
            # TODO:  Should we just convert to base units regardless?  It would be safer...
            if other.doDimensionsCancel():
                other = other.convertToPrimitiveUnits()
                units2 = other.units
                value = fdiv(value, other.value)

            # otherwise, we need to figure out how to do the conversion
            conversionValue = value

            # if that isn't found, then we need to do the hard work and break the units down
            newUnits1 = RPNUnits(units1)
            newUnits2 = RPNUnits(units2)

            debugPrint('newUnits1:', newUnits1)
            debugPrint('newUnits2:', newUnits2)

            debugPrint()
            debugPrint('iterating through units to match for conversion:')

            for unit1 in newUnits1:
                foundConversion = False

                for unit2 in newUnits2:
                    debugPrint('units 1:', unit1, newUnits1[unit1],
                               getUnitType(unit1))
                    debugPrint('units 2:', unit2, newUnits2[unit2],
                               getUnitType(unit2))

                    if getUnitType(unit1) == getUnitType(unit2):
                        debugPrint('found a conversion:', unit1, unit2)
                        conversions.append((unit1, unit2))
                        exponents[(unit1, unit2)] = units1[unit1]
                        foundConversion = True
                        break

                if not foundConversion:
                    debugPrint()
                    debugPrint('didn\'t find a conversion, try reducing')
                    debugPrint()
                    reduced = self.convertToPrimitiveUnits()

                    debugPrint('reduced:', self.units, 'becomes',
                               reduced.units)

                    reducedOther = other.convertToPrimitiveUnits()

                    reduced.value = fdiv(reduced.value, reducedOther.value)

                    debugPrint('reduced other:', other.units, 'becomes',
                               reducedOther.units)

                    # check to see if reducing did anything and bail if it didn't... bail out
                    if (reduced.units == self.units) and (reducedOther.units
                                                          == other.units):
                        debugPrint('reducing didn\'t help')
                        break

                    return reduced.convertValue(reducedOther)

            debugPrint()

            value = conversionValue

            debugPrint('Iterating through conversions...')

            for conversion in conversions:
                if conversion[0] == conversion[1]:
                    continue  # no conversion needed

                debugPrint('----> conversion', conversion)

                conversionIndex = tuple(conversion)

                if conversionIndex in g.unitConversionMatrix:
                    debugPrint('unit conversion:',
                               g.unitConversionMatrix[tuple(conversion)])
                    debugPrint('exponents', exponents)

                    conversionValue = mpmathify(
                        g.unitConversionMatrix[conversionIndex])
                    conversionValue = power(conversionValue,
                                            exponents[conversionIndex])
                    debugPrint('conversion: ', conversion, conversionValue)

                    debugPrint('value before', value)
                    value = fmul(value, conversionValue)
                    debugPrint('value after', value)
                else:
                    # we're ignoring the exponents, but this works for dBm<->milliwatt, etc.
                    baseUnit = g.basicUnitTypes[getUnitType(
                        conversion[0])].baseUnit

                    conversion1 = (conversion[0], baseUnit)
                    conversion2 = (baseUnit, conversion[1])

                    debugPrint('conversion1', conversion1)
                    debugPrint('conversion2', conversion2)

                    debugPrint('value0', value)

                    if conversion1 in g.unitConversionMatrix:
                        debugPrint('standard conversion 1')
                        value = fmul(
                            value,
                            mpmathify(g.unitConversionMatrix[conversion1]))
                    else:
                        debugPrint('special conversion 1')
                        value = specialUnitConversionMatrix[conversion1](value)

                    debugPrint('value1', value)

                    if conversion2 in g.unitConversionMatrix:
                        debugPrint('standard conversion 2')
                        value = fmul(
                            value,
                            mpmathify(g.unitConversionMatrix[conversion2]))
                    else:
                        debugPrint('special conversion 2')
                        value = specialUnitConversionMatrix[conversion2](value)

                    debugPrint('value2', value)

        debugPrint('convertValue final', value)
        return value
Exemplo n.º 10
0
    def convertToPrimitiveUnits(self):
        debugPrint()
        debugPrint('convertToPrimitiveUnits:', self.value, self.units)

        if not g.unitConversionMatrix:
            loadUnitConversionMatrix()

        value = self.value
        units = RPNUnits()

        debugPrint('value', value)

        for unit in self.units:

            if self.units[unit] == 0:
                continue

            newUnits = g.basicUnitTypes[getUnitType(unit)].primitiveUnit

            debugPrint('unit', unit, 'newUnits', newUnits)

            if unit != newUnits:
                debugPrint('unit vs newUnits:', unit, newUnits)

                if (unit, newUnits) in g.unitConversionMatrix:
                    value = fmul(
                        value,
                        power(mpf(g.unitConversionMatrix[(unit, newUnits)]),
                              self.units[unit]))
                elif (unit, newUnits) in specialUnitConversionMatrix:
                    value = power(
                        specialUnitConversionMatrix[(unit, newUnits)](value),
                        self.units[unit])
                else:
                    if unit == '1' and newUnits == '_null_unit':
                        reduced = RPNMeasurement(value, units)
                        debugPrint('convertToPrimitiveUnits 2:', reduced.value,
                                   reduced.units)
                        return reduced

                    raise ValueError('cannot find a conversion for ' + unit +
                                     ' and ' + newUnits)

            newUnits = RPNUnits(newUnits)

            for newUnit in newUnits:
                newUnits[newUnit] *= self.units[unit]

            units.update(newUnits)

            debugPrint('value', value)

        baseUnits = RPNMeasurement(value, units)
        debugPrint('convertToPrimitiveUnits 3:', baseUnits.value,
                   baseUnits.units)
        debugPrint()
        return baseUnits
Exemplo n.º 11
0
    def isCompatible(self, other):
        if isinstance(other, str):
            return self.isCompatible(RPNMeasurement(1, other))

        if isinstance(other, RPNUnits):
            return self.getUnitTypes() == other.getUnitTypes()

        if isinstance(other, RPNMeasurement):
            debugPrint('isCompatible -----------------------')
            debugPrint('units: ', self.units, other.units)
            debugPrint('types: ', self.getUnitTypes(), other.getUnitTypes())
            debugPrint('dimensions: ', self.getDimensions(),
                       other.getDimensions())
            debugPrint()

            if self.getUnitTypes() == other.getUnitTypes():
                return True

            if self.getDimensions() == other.getDimensions():
                return True

            debugPrint('RPNMeasurement.isCompatible exiting with false...')
            return False

        if isinstance(other, list):
            result = True

            for item in other:
                result = self.isCompatible(item)

                if not result:
                    break

            return result

        raise ValueError('RPNMeasurement or dict expected')
Exemplo n.º 12
0
    def normalizeUnits(self):
        units = self.units.normalizeUnits()

        debugPrint()
        debugPrint('normalize', units)

        if units == RPNUnits():
            return self.value

        # look for units that cancel between the numerator and denominator
        numerator, denominator = units.splitUnits()

        # if we don't have a numerator or denominator, we're done
        if not numerator or not denominator:
            return RPNMeasurement(self.value, units)

        if not g.basicUnitTypes:
            loadUnitData()

        debugPrint('numerator', numerator)
        debugPrint('denominator', denominator)

        nOriginalElements = sorted(list(numerator.elements()))
        dOriginalElements = sorted(list(denominator.elements()))

        changed = False

        nElements = []

        for nUnit in numerator:
            for i in range(min(numerator[nUnit], 3)):
                nElements.append(nUnit)

        dElements = []

        for dUnit in denominator:
            for i in range(min(denominator[dUnit], 3)):
                dElements.append(dUnit)

        debugPrint('nOriginalElements', nOriginalElements)
        debugPrint('nElements', nElements)

        debugPrint('dOriginalElements', dOriginalElements)
        debugPrint('dElements', dElements)

        matchFound = True  # technically not true yet, but it gets us into the loop

        conversionsNeeded = []

        while matchFound:
            matchFound = False

            for nSubset in getPowerSet(nElements):
                for dSubset in getPowerSet(dElements):
                    #debugPrint( '))) nSubset', list( nSubset ) )
                    #debugPrint( '))) dSubset', list( dSubset ) )

                    nSubsetUnit = RPNUnits('*'.join(sorted(list(nSubset))))
                    dSubsetUnit = RPNUnits('*'.join(sorted(list(dSubset))))

                    #debugPrint( '1 nSubset', dSubsetUnit )
                    #debugPrint( '2 dSubset', dSubsetUnit )

                    if nSubsetUnit.getDimensions(
                    ) == dSubsetUnit.getDimensions():
                        debugPrint('dimensions matched',
                                   dSubsetUnit.getDimensions())
                        newNSubset = []
                        newDSubset = []

                        for nUnit in nSubset:
                            baseUnit = g.basicUnitTypes[getUnitType(
                                nUnit)].baseUnit

                            if nUnit != baseUnit:
                                debugPrint('conversion added:', nUnit,
                                           baseUnit)
                                conversionsNeeded.append((nUnit, baseUnit))

                            newNSubset.append(baseUnit)

                        for dUnit in dSubset:
                            baseUnit = g.basicUnitTypes[getUnitType(
                                dUnit)].baseUnit

                            if dUnit != baseUnit:
                                debugPrint('conversion added:', dUnit,
                                           baseUnit)
                                conversionsNeeded.append((dUnit, baseUnit))

                            newDSubset.append(baseUnit)

                        # This maybe isn't quite what we want.
                        debugPrint('conversions added',
                                   '*'.join(sorted(newNSubset)),
                                   '*'.join(sorted(newDSubset)))
                        conversionsNeeded.append(
                            ('*'.join(sorted(newNSubset)),
                             '*'.join(sorted(newDSubset))))
                        matchFound = True

                        for nUnit in nSubset:
                            #print( 'nOriginalElements', nOriginalElements, 'n', nUnit )
                            nOriginalElements.remove(nUnit)
                            changed = True

                        for dUnit in dSubset:
                            #print( 'dOriginalElements', dOriginalElements, 'd', dUnit )
                            dOriginalElements.remove(dUnit)
                            changed = True

                        break

                if matchFound:
                    break

            if matchFound:
                break

        debugPrint('final nElements', nOriginalElements)
        debugPrint('final dElements', dOriginalElements)

        # convert the value based on all the conversions we queued up
        convertedValue = self.value

        if not g.unitConversionMatrix:
            loadUnitConversionMatrix()

        for i in conversionsNeeded:
            if i in g.unitConversionMatrix:
                convertedValue = fmul(convertedValue,
                                      g.unitConversionMatrix[i])
            else:
                convertedValue = fmul(
                    convertedValue,
                    RPNMeasurement(1, i[0]).convertValue(i[1]))

        # build up the resulting units
        units = RPNUnits('*'.join(nOriginalElements))
        denominator = RPNUnits('*'.join(dOriginalElements))

        for dUnit in denominator:
            units[dUnit] += denominator[dUnit] * -1

        debugPrint('normalizeUnits final units', units)
        debugPrint()

        if units and units != RPNUnits():
            result = RPNMeasurement(convertedValue, units)

            if changed:
                return result.normalizeUnits()

            return result

        return convertedValue
Exemplo n.º 13
0
def rpn(cmdArgs):
    '''
    This is the main function which processes the command-line arguments,
    handling both options and the expression to evaluate.   This function is
    mainly concerned with parsing and handling the command-line options.

    It finally calls evaluate( ) with the expression to be calculated, and
    returns the results, which can be formatted for output or used in another
    way (such as the unit test functionality).
    '''
    # initialize globals
    g.outputRadix = 10

    # look for help argument before we start setting everything up (because it's faster this way)
    showHelp = False
    helpArgs = []

    for arg in cmdArgs:
        if arg == 'help':
            showHelp = True
        else:
            if showHelp:
                helpArgs.append(arg)

    if showHelp:
        parser = argparse.ArgumentParser(
            prog=PROGRAM_NAME,
            description=RPN_PROGRAM_NAME + ' - ' + PROGRAM_DESCRIPTION +
            '\n    ' + COPYRIGHT_MESSAGE,
            add_help=False,
            formatter_class=argparse.RawTextHelpFormatter,
            prefix_chars='-')

        parser.add_argument('terms', nargs='*', metavar='term')
        parser.add_argument('-l',
                            '--line_length',
                            type=int,
                            action='store',
                            default=g.defaultLineLength)

        args = parser.parse_args(cmdArgs)

        loadUnitNameData()

        g.aliases.update(operatorAliases)

        printHelp(helpArgs)
        return None

    # set up the command-line options parser
    parser = argparse.ArgumentParser(
        prog=PROGRAM_NAME,
        description=RPN_PROGRAM_NAME + ' - ' + PROGRAM_DESCRIPTION + '\n    ' +
        COPYRIGHT_MESSAGE,
        add_help=False,
        formatter_class=argparse.RawTextHelpFormatter,
        prefix_chars='-')

    parser.add_argument('-a',
                        '--output_accuracy',
                        nargs='?',
                        type=int,
                        default=g.defaultOutputAccuracy,
                        const=g.defaultOutputAccuracy)
    parser.add_argument('-b',
                        '--input_radix',
                        type=str,
                        default=g.defaultInputRadix)
    parser.add_argument('-c', '--comma', action='store_true')
    parser.add_argument('-d',
                        '--decimal_grouping',
                        nargs='?',
                        type=int,
                        default=0,
                        const=g.defaultDecimalGrouping)
    parser.add_argument('-D', '--DEBUG', action='store_true')
    parser.add_argument('-e', '--profile', action='store_true')
    parser.add_argument('-E', '--echo_command', action='store_true')
    parser.add_argument('-g',
                        '--integer_grouping',
                        nargs='?',
                        type=int,
                        default=0,
                        const=g.defaultIntegerGrouping)
    parser.add_argument('-h', '--help', action='store_true')

    parser.add_argument('-I', '--ignore_cache', action='store_true')
    parser.add_argument('-l',
                        '--line_length',
                        type=int,
                        default=g.defaultLineLength)
    parser.add_argument('-m',
                        '--maximum_fixed',
                        type=int,
                        default=g.defaultMaximumFixed)
    parser.add_argument('-n',
                        '--numerals',
                        type=str,
                        default=g.defaultNumerals)
    parser.add_argument('-o', '--octal', action='store_true')
    parser.add_argument('-p',
                        '--precision',
                        type=int,
                        default=g.defaultPrecision)
    parser.add_argument('-r',
                        '--output_radix',
                        type=str,
                        default=g.defaultOutputRadix)
    parser.add_argument('-s',
                        '--list_format_level',
                        nargs='?',
                        type=int,
                        default=0,
                        const=g.defaultListFormatLevel)
    parser.add_argument('-t', '--timer', action='store_true')
    parser.add_argument('-T',
                        '--time_limit',
                        nargs='?',
                        type=int,
                        default=0,
                        const=g.timeLimit)
    parser.add_argument('-V', '--version', action='store_true')
    parser.add_argument('-v', '--verbose', action='store_true')
    parser.add_argument('-w',
                        '--bitwise_group_size',
                        type=int,
                        default=g.defaultBitwiseGroupSize)
    parser.add_argument('-x', '--hex', action='store_true')
    parser.add_argument('-y', '--identify', action='store_true')
    parser.add_argument('-z', '--leading_zero', action='store_true')
    parser.add_argument('-!', '--print_options', action='store_true')
    parser.add_argument('-?', '--other_help', action='store_true')

    # pull out the options and the terms
    options = []
    terms = []

    loadUserVariablesFile()
    loadUserFunctionsFile()
    loadUserConfigurationFile()

    if 'yafu_path' in g.userConfiguration and 'yafu_binary' in g.userConfiguration:
        g.useYAFU = True
    else:
        g.useYAFU = False

    for arg in cmdArgs:
        if len(arg) > 1:
            if arg[0] == '$' and arg[1:] not in g.userVariables:
                raise ValueError('undefined user variable referenced: ' + arg)

            if arg[0] == '@' and arg[1:] not in g.userFunctions:
                raise ValueError('undefined user function referenced: ' + arg)

            if arg[0] == '-':
                if arg[1].isdigit():  # a negative number, not an option
                    terms.append(arg)
                elif arg[1] in ('i', 'j'):  # -i and -j are also numbers
                    terms.append('-1j')
                else:
                    options.append(arg)
            else:
                terms.append(arg)
        else:
            terms.append(arg)

    debugPrint('terms', terms)
    debugPrint('options', options)

    # OK, let's parse and validate the options
    args = parser.parse_args(options)

    g.aliases.update(operatorAliases)

    if args.help or args.other_help:
        loadUnitNameData()

        printHelp()
        return None

    valid, errorString = validateOptions(args)

    if not valid:
        print('rpn:  ' + errorString)
        return None

    # these are either globals or can be modified by other options (like -x)
    g.bitwiseGroupSize = args.bitwise_group_size
    g.integerGrouping = args.integer_grouping
    g.leadingZero = args.leading_zero

    # handle -a
    setAccuracy(args.output_accuracy)

    # handle -b
    g.inputRadix = int(args.input_radix)

    # handle -c
    g.comma = args.comma

    # handle -d
    g.decimalGrouping = args.decimal_grouping

    # handle -D
    if args.DEBUG:
        g.debugMode = True

    # handle -e
    g.echo_command = args.echo_command

    # handle -g
    g.integerGrouping = args.integer_grouping

    # handle -i
    g.identify = args.identify

    # handle -I
    g.ignoreCache = args.ignore_cache
    g.refreshOEISCache = args.ignore_cache

    # handle -l
    g.lineLength = args.line_length

    # handle -m
    g.maximumFixed = args.maximum_fixed

    # handle -n
    g.numerals = parseNumerals(args.numerals)

    # handle -o
    if args.octal:
        g.outputRadix = 8
        g.leadingZero = True
        g.integerGrouping = 3
        g.bitwiseGroupSize = 9

    # handle -p
    setPrecision(args.precision)

    # handle -r
    if args.output_radix in specialBaseNames:
        g.outputRadix = specialBaseNames[args.output_radix]
    else:
        try:
            # if g.outputRadix was already set (e.g., by -o) then we don't want to override it
            if g.outputRadix == 10:
                g.outputRadix = int(args.output_radix)
        except ValueError:
            print('rpn:  cannot interpret output radix \'%s\' as a number' %
                  args.output_radix)
            return [nan]

    # -r validation
    if ((g.outputRadix < g.maxSpecialBase) or (g.outputRadix == 0)
            or (g.outputRadix == 1) or (g.outputRadix > 62)):
        print(
            'rpn:  output radix must be from 2 to 62, fib, phi, fac, doublefac, square, lucas'
        )
        return [nan]

    # handle -s
    g.listFormatLevel = args.list_format_level

    # handle -t
    g.timer = args.timer

    # handle -T
    g.timeLimit = args.time_limit

    # handle -v
    g.verbose = args.verbose

    # handle -V
    if args.version:
        return [int(i) for i in PROGRAM_VERSION.split('.')]

    # handle -x
    if args.hex:
        g.outputRadix = 16
        g.leadingZero = True
        g.integerGrouping = 4
        g.bitwiseGroupSize = 16

    # handle -u and -y:  mpmath wants precision of at least 53 for these functions
    if args.identify and mp.dps < 53:
        setAccuracy(53)

    if args.print_options:
        print('--output_accuracy:  %d' % g.outputAccuracy)
        print('--input_radix:  %d' % g.inputRadix)
        print('--comma:  ' + ('true' if g.comma else 'false'))
        print('--decimal_grouping:  %d' % g.decimalGrouping)
        print('--integer_grouping:  %d' % g.integerGrouping)
        print('--line_length:  %d' % g.lineLength)
        print('--numerals:  ' + g.numerals)
        print('--octal:  ' + ('true' if args.octal else 'false'))
        print('--precision:  %d' % args.precision)
        print('--output_radix:  %d' % g.outputRadix)
        print('--list_format_level:  %d' % g.listFormatLevel)
        print('--timer:  ' + ('true' if args.timer else 'false'))
        print('--verbose:  ' + ('true' if g.verbose else 'false'))
        print('--bitwise_group_size:  %d' % g.bitwiseGroupSize)
        print('--hex:  ' + ('true' if args.hex else 'false'))
        print('--identify:  ' + ('true' if args.identify else 'false'))
        print('--leading_zero:  ' + ('true' if g.leadingZero else 'false'))
        print('--ignore_cache:  ' + ('true' if g.ignoreCache else 'false'))
        print()

    g.creatingFunction = False

    # enter interactive mode if there are no arguments
    if not terms:
        if not loadUnitNameData():
            return None

        enterInteractiveMode()
        return None

    # let's check out the arguments before we start to do any calculations
    if not validateArguments(terms):
        return None

    #newTerms = preprocessTerms( terms )
    #print( 'newTerms', newTerms )

    # waiting until we've validated the arguments to do this because it's slow
    if not loadUnitNameData():
        return None

    if g.echo_command:
        print(*sys.argv)

    if g.timer:
        g.startTime = time_ns()

    return evaluate(terms)
Exemplo n.º 14
0
def parseDiceExpression(arg):
    counter = Counter(arg)

    if counter['a'] > 1:
        raise ValueError('dice expressions can only contain a single \'x\'')

    if counter['h'] > 1:
        raise ValueError('dice expressions can only contain a single \'h\'')

    if counter['+'] > 1:
        raise ValueError('dice expressions can only contain a single \'+\'')

    if counter['-'] > 1:
        raise ValueError('dice expressions can only contain a single \'-\'')

    if counter['+'] + counter['-'] > 1:
        raise ValueError(
            'dice expressions can only have a single modifier (\'+\' or \'-\')'
        )

    expressions = re.split(',', arg)

    result = []

    for expr in expressions:
        pieces = re.split('([dhx+-])', expr)

        debugPrint('pieces', pieces)

        diceValue = 0
        diceCount = 0
        dropLowestCount = 0
        dropHighestCount = 0
        modifier = 0

        defaultState = 0
        diceValueState = 1
        dropLowestCountState = 2
        dropHighestCountState = 3
        plusModifierState = 4
        minusModifierState = 5

        state = defaultState

        for piece in pieces:
            if state == defaultState:
                if piece == 'd':
                    state = diceValueState
                elif piece == 'x':
                    state = dropLowestCountState
                elif piece == 'h':
                    state = dropHighestCountState
                elif piece == '-':
                    state = minusModifierState
                elif piece == '+':
                    state = plusModifierState
                else:
                    if piece == '':
                        diceCount = 1
                    else:
                        diceCount = int(piece)
            elif state == diceValueState:
                diceValue = int(piece)

                if diceValue < 2:
                    raise ValueError('dice value must be greater than 1')

                state = defaultState
            elif state == dropLowestCountState:
                if piece == '':
                    dropLowestCount = 1
                else:
                    dropLowestCount = int(piece)

                if dropLowestCount < 1:
                    raise ValueError('drop lowest count must be positive')

                state = defaultState
            elif state == dropHighestCountState:
                if piece == '':
                    dropHighestCount = 1
                else:
                    dropHighestCount = int(piece)

                if dropHighestCount < 1:
                    raise ValueError('drop highest count must be positive')

            elif state == plusModifierState:
                if piece == '':
                    modifier = 1
                else:
                    modifier = int(piece)

                state = defaultState
            elif state == minusModifierState:
                if piece == '':
                    modifier = -1
                else:
                    modifier = -int(piece)

                state = defaultState

        if diceCount == 0:
            diceCount = 1

        if dropLowestCount != 0 and diceValue == 0:
            raise ValueError('dice expression requires \'d\' if \'x\' is used')

        if dropHighestCount != 0 and diceValue == 0:
            raise ValueError('dice expression requires \'d\' if \'h\' is used')

        if (dropLowestCount + dropHighestCount) >= diceCount:
            raise ValueError(
                'this dice expression is dropping as many or more dice than are being rolled'
            )

        debugPrint('expression', expr)
        debugPrint('diceCount', diceCount)
        debugPrint('diceValue', diceValue)
        debugPrint('dropLowestCount', dropLowestCount)
        debugPrint('dropHighestCount', dropHighestCount)
        debugPrint('modifier', modifier)

        result.append((diceCount, diceValue, dropLowestCount, dropHighestCount,
                       modifier))

    return result