def openFunctionCache( name ): if name in g.cursors: return g.cursors[ name ] else: debugPrint( 'opening', name, 'function cache database' ) g.databases[ name ] = sqlite3.connect( getCacheFileName( name ) ) g.cursors[ name ] = g.databases[ name ].cursor( ) g.cursors[ name ].execute( '''CREATE TABLE IF NOT EXISTS cache( id TEXT PRIMARY KEY NOT NULL, value TEXT NOT NULL, precision INTEGER )''' ) return g.cursors[ name ]
def isCompatible( self, other ): if isinstance( other, RPNUnits ): return self.getUnitTypes( ) == other.getUnitTypes( ) elif isinstance( other, dict ): return self.getUnitTypes( ) == other elif isinstance( other, list ): result = True for item in other: result = self.isCompatible( item ) if not result: break return result elif isinstance( other, RPNMeasurement ): debugPrint( 'units: ', self.units, other.units ) debugPrint( 'types: ', self.getUnitTypes( ), other.getUnitTypes( ) ) debugPrint( 'dimensions: ', self.getDimensions( ), other.getDimensions( ) ) if self.getUnitTypes( ) == other.getUnitTypes( ): return True elif self.getDimensions( ) == other.getDimensions( ): return True else: debugPrint( 'RPNMeasurement.isCompatible exiting with false...' ) return False else: raise ValueError( 'RPNMeasurement or dict expected' )
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 real_int( n ) < 0: raise ValueError( 'non-negative argument expected' ) elif 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 = [ ] signList = [ ] 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
def flushDirtyCaches( ): for name in g.dirtyCaches: saveOperatorCache( g.operatorCaches[ name ], name ) g.dirtyCaches.clear( ) if g.factorCacheIsDirty: saveFactorCache( ) for name in g.dirtyCaches: debugPrint( 'flushing the', name, 'pickle cache' ) saveOperatorCache( g.operatorCaches[ name ], name ) for name in g.databases: debugPrint( 'closing the', name, 'function cache database' ) g.databases[ name ].close( )
def evaluateDiceExpression( args, sumIfPossible=True ): result = [ ] for diceCount, diceValue, dropLowestCount, dropHighestCount, modifier in args: if dropLowestCount == 0 and dropHighestCount == 0: if sumIfPossible: result = [ 0 ] for i in range( 0, diceCount ): result[ 0 ] += ( randrange( diceValue ) + 1 ) else: for i in range( 0, diceCount ): result.append( randrange( diceValue ) + 1 ) else: dice = [ ] for i 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, modifier
def evaluateDiceExpression( args ): result = 0 for diceCount, diceValue, dropLowestCount, dropHighestCount, modifier in args: if dropLowestCount == 0 and dropHighestCount == 0: for i in range( 0, diceCount ): result += randrange( diceValue ) + 1 else: dice = [ ] for i in range( 0, diceCount ): dice.append( randrange( diceValue ) + 1 ) dice.sort( ) debugPrint( 'dice', dice ) if dropHighestCount > 0: debugPrint( 'drop', dice[ dropLowestCount : -dropHighestCount ] ) result += sum( dice[ dropLowestCount : -dropHighestCount ] ) else: debugPrint( 'drop', dice[ dropLowestCount : ] ) result += sum( dice[ dropLowestCount : ] ) result += modifier return result
def getReduced( self ): debugPrint( 'getReduced 1:', self, [ ( i, self.units[ i ] ) for i in self.units ] ) if not g.unitConversionMatrix: loadUnitConversionMatrix( ) value = self.value units = RPNUnits( ) debugPrint( 'value', value ) for unit in self.units: newUnit = g.basicUnitTypes[ getUnitType( unit ) ].baseUnit debugPrint( 'unit', unit, 'newUnit', newUnit ) if unit != newUnit: value = fmul( value, power( mpf( g.unitConversionMatrix[ ( unit, newUnit ) ] ), self.units[ unit ] ) ) units.update( RPNUnits( g.unitOperators[ newUnit ].representation + "^" + str( self.units[ unit ] ) ) ) debugPrint( 'value', value ) reduced = RPNMeasurement( value, units ) debugPrint( 'getReduced 2:', reduced ) return reduced
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 ) elif isinstance( unit2, str ): measurement = RPNMeasurement( 1, { unit2 : 1 } ) return RPNMeasurement( unit1.convertValue( measurement ), unit2 ) elif not isinstance( unit2, RPNMeasurement ): raise ValueError( 'cannot convert non-measurements' ) else: debugPrint( 'convertUnits' ) debugPrint( 'unit1:', unit1.getUnitTypes( ) ) debugPrint( 'unit2:', unit2.getUnitTypes( ) ) return RPNMeasurement( unit1.convertValue( unit2 ), unit2.getUnits( ), unit2.getUnitName( ), unit2.getPluralUnitName( ) )
def convertValue( self, other, tryReverse=True ): if self.isEquivalent( other ): return self.getValue( ) if self.isCompatible( other ): conversions = [ ] if isinstance( other, list ): result = [ ] source = self for count, measurement in enumerate( other ): with extradps( 1 ): conversion = source.convertValue( measurement ) if count < len( other ) - 1: result.append( RPNMeasurement( floor( conversion ), measurement.getUnits( ) ) ) source = RPNMeasurement( chop( frac( conversion ) ), measurement.getUnits( ) ) else: result.append( RPNMeasurement( conversion, measurement.getUnits( ) ) ) return result units1 = self.getUnits( ) units2 = other.getUnits( ) unit1String = units1.getUnitString( ) unit2String = units2.getUnitString( ) debugPrint( 'unit1String: ', unit1String ) debugPrint( 'unit2String: ', unit2String ) if unit1String == unit2String: return fmul( self.getValue( ), other.getValue( ) ) if unit1String in g.operatorAliases: unit1String = g.operatorAliases[ unit1String ] if unit2String in g.operatorAliases: unit2String = g.operatorAliases[ unit2String ] exponents = { } if not g.unitConversionMatrix: loadUnitConversionMatrix( ) # look for a straight-up conversion unit1NoStar = unit1String.replace( '*', '-' ) unit2NoStar = unit2String.replace( '*', '-' ) debugPrint( 'unit1NoStar: ', unit1NoStar ) debugPrint( 'unit2NoStar: ', unit2NoStar ) if ( unit1NoStar, unit2NoStar ) in g.unitConversionMatrix: value = fmul( self.value, mpmathify( g.unitConversionMatrix[ ( unit1NoStar, unit2NoStar ) ] ) ) elif ( unit1NoStar, unit2NoStar ) in specialUnitConversionMatrix: value = specialUnitConversionMatrix[ ( unit1NoStar, unit2NoStar ) ]( self.value ) else: # otherwise, we need to figure out how to do the conversion conversionValue = mpmathify( 1 ) # if that isn't found, then we need to do the hard work and break the units down newUnits1 = RPNUnits( ) for unit in units1: newUnits1.update( RPNUnits( g.unitOperators[ unit ].representation + "^" + str( units1[ unit ] ) ) ) newUnits2 = RPNUnits( ) for unit in units2: newUnits2.update( RPNUnits( g.unitOperators[ unit ].representation + "^" + str( units2[ unit ] ) ) ) debugPrint( 'units1:', units1 ) debugPrint( 'units2:', units2 ) debugPrint( 'newUnits1:', newUnits1 ) debugPrint( 'newUnits2:', newUnits2 ) debugPrint( ) debugPrint( 'iterating through units:' ) 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 ): conversions.append( [ unit1, unit2 ] ) exponents[ ( unit1, unit2 ) ] = units1[ unit1 ] foundConversion = True break if not foundConversion: debugPrint( 'didn\'t find a conversion, try reducing' ) reduced = self.getReduced( ) debugPrint( 'reduced:', self.units, 'becomes', reduced.units ) reducedOther = other.getReduced( ) 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 ): break reduced = reduced.convertValue( reducedOther ) return RPNMeasurement( fdiv( reduced, reducedOther.value ), reducedOther.getUnits( ) ).getValue( ) debugPrint( ) value = conversionValue if not foundConversion: # This is a cheat. The conversion logic has flaws, but if it's possible to do the # conversion in the opposite direction, then we can do that and return the reciprocal. # This allows more conversions without fixing the underlying problems, which will # require some redesign. if tryReverse: return fdiv( 1, other.convertValue( self, False ) ) else: raise ValueError( 'unable to convert ' + self.getUnitString( ) + ' to ' + other.getUnitString( ) ) for conversion in conversions: if conversion[ 0 ] == conversion[ 1 ]: continue # no conversion needed debugPrint( 'unit conversion:', g.unitConversionMatrix[ tuple( conversion ) ] ) debugPrint( 'exponents', exponents ) conversionValue = mpmathify( g.unitConversionMatrix[ tuple( conversion ) ] ) conversionValue = power( conversionValue, exponents[ tuple( conversion ) ] ) debugPrint( 'conversion: ', conversion, conversionValue ) value = fmul( value, conversionValue ) value = fmul( self.value, value ) return value else: if isinstance( other, list ): otherUnit = '[ ' + ', '.join( [ unit.getUnitString( ) for unit in other ] ) + ' ]' else: otherUnit = other.getUnitString( ) raise ValueError( 'incompatible units cannot be converted: ' + self.getUnitString( ) + ' and ' + otherUnit )
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 \'-\')' ) import re 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
def parseDiceExpression( arg ): import re 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 < 0 ): raise ValueError( 'drop lowest count must be non-negative' ) state = defaultState elif state == dropHighestCountState: if piece == '': dropHighestCount = 1 else: dropHighestCount = int( piece ) 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 # trailing x means drop count is 1 if state == dropLowestCountState: dropLowestCount = 1 elif state == dropHighestCountState: dropHighestCount = 1 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 >= diceCount: raise ValueError( 'drop lowest count \'x\' cannot be greater than or equal to dice count \'d\'' ) if dropHighestCount >= diceCount: raise ValueError( 'drop highest count \'h\' cannot be greater than or equal to dice count \'d\'' ) 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