Can I limit the Python eval() result range? - python

Can I limit the value range of eval()?
eval('12345678**9') returns a large number
eval('1234567**8**9') neither returns nor throws an exception
I could live with #1 but not with #2. All I need is results in the range of 32bit integers. I fear there is no way to tell eval to stop calculating too large numbers, or is there?

I've written "calculators" before using ast to parse the string into a tree and then walk the tree. In this case, if you want to do some trickery, you can make this work:
import ast
import ctypes
import operator
def _pow(a, b):
if isinstance(a, (ctypes.c_int, ctypes.c_float, ctypes.c_double)):
a = float(a.value)
if isinstance(b, (ctypes.c_int, ctypes.c_float, ctypes.c_double)):
b = float(b.value)
return ctypes.c_double(a ** b)
def _wrap_bin_op(op):
def wrapper(a, b):
if isinstance(a, (ctypes.c_int, ctypes.c_float, ctypes.c_double)):
a = float(a.value)
if isinstance(b, (ctypes.c_int, ctypes.c_float, ctypes.c_double)):
b = float(b.value)
return ctypes.c_double(op(a, b))
return wrapper
def _wrap_unary_op(op):
def wrapper(a):
if isinstance(a, (ctypes.c_int, ctypes.c_float)):
a = float(a.value)
return ctypes.c_double(op(a))
return wrapper
_OP_MAP = {
ast.Add: _wrap_bin_op(operator.add),
ast.Sub: _wrap_bin_op(operator.sub),
ast.Pow: _wrap_bin_op(operator.pow),
ast.Mult: _wrap_bin_op(operator.mul),
ast.Div: _wrap_bin_op(operator.truediv),
ast.Invert: _wrap_unary_op(operator.neg),
}
class Calc(ast.NodeVisitor):
def visit_BinOp(self, node):
left = self.visit(node.left)
right = self.visit(node.right)
return _OP_MAP[type(node.op)](left, right)
def visit_Num(self, node):
if isinstance(node.n, int):
val = ctypes.c_int(node.n)
elif isinstance(node.n, float):
val = ctypes.c_double(node.n)
return val
def visit_Expr(self, node):
return self.visit(node.value)
#classmethod
def evaluate(cls, expression):
tree = ast.parse(expression)
calc = cls()
return calc.visit(tree.body[0])
print(Calc.evaluate('12345678**8'))
print(Calc.evaluate('5 * 8'))
Note that unlike eval, I'm specifically picking and choosing what operations I want to allow -- and I have control over how they behave. In this case, I'm doing all of my math with ctypes to avoid HUGE numbers. I'm also preventing integer __pow__ and forcing those arguments to become floats before raising to a specific power.

As John Coleman recommended, I'll add my own solution here. Thanks for the discussion, I learned a lot about pythons capabilities.
As I commented already:
I found a solution by making any number a float via concatenating '.0', eval('1234567.0**8.0**9.0') throws an exception, that's fine.
Here's the bigger context, where this evaluation is embedded:
import itertools
digits1to8 = list(str(i+1) for i in range(8)) #('1','2','3','4','5','6','7','8')
with open("expressions.txt", "w") as outfile:
for operators in itertools.product(['','.0+','.0-','.0*','.0/','.0**'], repeat=8):
calculation = zip(digits1to8,operators)
expression = (''.join(list(itertools.chain(*calculation))))+'9.0'
try:
out = str(eval(expression))+','
expression = expression.replace('.0','')
out = out.replace('.0,',',') + expression
if (not out.find('.')>0):
print(out, file=outfile)
except:
pass
beforehand I had ['','+','-','*','/','**'] instead of ['','.0+','.0-','.0*','.0/','.0**']. Overall this just is a little mathematical experimentation in response to https://www.youtube.com/watch?v=-ruC5A9EzzE

Something along these lines:
from math import log
def bounded_eval(expression, bits = 32):
nums = expression.split('**')
if len(nums) == 1:
val = eval(expression)
if log(val,2) > bits:
return "too large"
else:
return val
else:
base = nums[0]
power = '**'.join(nums[1:])
base = eval(base)
power = eval(power)
if power*log(base,2) > bits:
return "too large"
else:
return pow(base,power)
This does use eval() which is potentially a security risk, but if you are just calling it on arithmetical expressions that your own code generates then it isn't really a problem. Obviously, you can replace the code which returns "too large" by code which raises an error.

Related

Rational numbers' test got warning '11/12 != 11/12'

I am trying to practice with how to write classes and methods with Python, the content of this exercise is to add/sub/mul/div rational numbers. I got the correct output with the main() block. However, I got the following warning with test file:
RationalTest: test_plusminus
11/12 != 11/12 : Incorrect result for operation 1/4 + 2/3!
I checked my __str__ method and did not find a mistake there. Have spend long here but could not find the error. Therefore I pasted codes here to ask for help. Thank you in advance.
Attached are my codes:
class Rational(object):
def __init__(self, nu, denom):
self.nu = nu
self.denom = denom
def __repr__(self):
return self.__str__()
def __str__(self):
return str(self.nu) + '/' + str(self.denom)
def __mul__(self, p):
new_numerator = self.nu * p.nu
new_denominator = self.denom * p.denom
return Rational(new_numerator, new_denominator)
def __truediv__(self, p):
new_param = Rational(p.denom, p.nu)
return self.__mul__(new_param)
def __add__(self, p):
new_denominator = self.denom * p.denom
new_numerator = self.nu*p.denom + p.nu*self.denom
return Rational(new_numerator, new_denominator)
def __sub__(self, p):
new_denominator = self.denom * p.denom
new_numerator = self.nu*p.denom - p.nu*self.denom
return Rational(new_numerator, new_denominator)
def __gt__(self, p):
return self.nu*p.denom > self.denom*p.nu
def __lt__(self, p):
return self.nu*p.denom < self.denom * p.nu
def main():
r1=Rational(1,4)
r2=Rational(2,3)
print(r1)
print(r2)
print(r1*r2)
print(r1/r2)
print(r1+r2)
print(r1-r2)
print(Rational(1,2) == Rational(2,4))
print(Rational(1,2) > Rational(2,4))
print(Rational(1,2) < Rational(2,4))
if __name__ == "__main__":
main()
Attached are the part of the test method:
def test_plusminus(self):
r1=Rational(1,4)
r2=Rational(2,3)
self.assertEqual(r1+r2, Rational(11,12), msg="Incorrect result for operation %s + %s!" % (r1,r2))
self.assertEqual(r1-r2, Rational(-5,12), msg="Incorrect result for operation %s - %s!" % (r1,r2))
You are not implementing equality, therefore you inherit the default implementation which tests whether two objects are the same single identical object.
You should override the equality operator (magic method __eq__) with a version that checks for value equality.
Alternatively, or in addition, you could make sure that the same rational actually is the same object. This would save memory and object allocation, but add complexity to your implementation. You would probably need some sort of WeakMap to cache the objects.
Note, you should also implement __hash__ properly as well, otherwise you will get the same surprise again, when you try to use a rational in a set or as a dict key.
Note that there are some other problems with your implementation as well. For example, you never simplify rationals, so you are treating 1∕2 and 2∕4 as completely unrelated numbers.

Creating a rational class and operator overloading in python

I'm defining rational class, so for example a = Rational(1,2) #1/2, and b = Rational(2,3) #2/3, and I want to have c = a + b so that c = Rational(7,6) #7/6. My code so far is:
class Rational(object):
def __init__(self, v1, v2):
self.value = v1/v2
def __add__(self, value2):
return Rational(self.value + value2.value)
a = Rational(1,2)
b = Rational(2,3)
c = a+b
But I get the TypeError message that init requires 3 arguments (2 given), where did it get wrong in the coding above pls? Thank you!
class RationalNumber:
numerator=1
denominator=1
lcm=1
def __init__(self,numerator,denominator):
if(denominator<=0):
print('Denominator can not be <=0')
else:
gcd=1
divisorsOfNum1 = []
divisorsOfNum2 = []
gotlcm=False
for i in range(1, int(numerator)+1):
if numerator % i == 0:
divisorsOfNum1.append(i)
for i in range(1, int(denominator)+1):
if denominator % i == 0:
divisorsOfNum2.append(i)
for i in range(0, len(divisorsOfNum1)):
for j in range(0, len(divisorsOfNum2)):
if divisorsOfNum1[i] == divisorsOfNum2[j]:
if(gotlcm==False):
gotlcm=True
self.lcm=divisorsOfNum1[i]
gcd = divisorsOfNum1[i]
continue
self.numerator=numerator/gcd
self.denominator=denominator/gcd
print(self.numerator,self.denominator)
def __add__(self,other):
numeratr=self.numerator*other.denominator + other.numerator*self.denominator
denominatr=self.denominator*other.denominator
return RationalNumber(numeratr,denominatr)
def __sub__(self,other):
numeratr=self.numerator*other.denominator - other.numerator*self.denominator
denominatr=self.denominator*other.denominator
return RationalNumber(numeratr,denominatr)
def __truediv__(self,other):
numeratr=self.numerator*other.denominator
denominatr=other.numerator*self.denominator
return RationalNumber(numeratr,denominatr)
def __mul__(self,other):
numeratr=self.numerator*other.numerator
denominatr=other.denominator*self.denominator
return RationalNumber(numeratr,denominatr)
def __ne__(self,other):
if self.numerator!=other.numerator and other.denominator!=self.denominator:
return True
else:
return False
def __eq__(self,other):
if self.numerator==other.numerator and other.denominator==self.denominator:
return True
else:
return False
def __gt__(self,other):
if (self.numerator/self.denominator)>(other.numerator/other.denominator):
return True
else:
return False
def __lt__(self,other):
if (self.numerator/self.denominator)<(other.numerator/other.denominator):
return True
else:
return False
def __ge__(self,other):
if (self.numerator/self.denominator)>=(other.numerator/other.denominator):
return True
else:
return False
def __le__(self,other):
if (self.numerator/self.denominator)<=(other.numerator/other.denominator):
return True
else:
return False
r1=RationalNumber(48,36)
r2=RationalNumber(48,36)
print(r1+r2)
you can perform
addition, subtraction, multiplication, division, relational and equality operations
According to your class, you create an instance of Rational by passing the numerator and denominator to it, but here you're trying to create one just by passing its (floating-point) value. Of course, it's possible to find a rational equivalent to a float, but you haven't taught your class how to do it, and it's not going to magically reverse-engineer itself.
Given the definition of adding fractions: p/q + r/s = (ps + qr) / qs, your addition function should return Rational(ps + qr, qs). The problem is, you haven't kept track of your numerator and denominator in your class, so you have no way of retrieving this information.
As things stand, the best you can do with your addition function is return a self.value + value2.value as a float. So as it stands, your class is basically a long-winded way to do division! To have a meaningful Rational class, I would strongly suggest you keep everything in terms of the numerator and denominator as far as possible.
Edit: I forgot to mention - if you're using Python 2.x your division won't work as it should unless you either convert one (or both) of v1 or v2 to float before doing division, or better still, include the line from __future__ import division at the top, so that division behaves as you'd expect.

Subclass/Child class

I had this class and subclass :
class Range:
def __init__(self, start, end):
self.setStart(start)
self.setEnd(end)
def getStart(self):
return self.start
def setStart(self, s):
self.start = s
def getEnd(self):
return self.end
def setEnd(self, e):
self.end = e
def getLength(self):
return len(range(self.start, self.end))
def overlaps(self, r):
if (r.getStart() < self.getEnd() and r.getEnd() >= self.getEnd()) or \
(self.getStart() < r.getEnd() and self.getEnd() >= r.getEnd()) or \
(self.getStart() >= r.getStart() and self.getEnd() <= r.getEnd()) or \
(r.getStart() >= self.getStart() and r.getEnd() <= self.getEnd()):
return True
else:
return False
class DNAFeature(Range):
def __init__(self, start, end):
self.setStart(start)
self.setEnd(end)
self.strand = none
self.sequencename = none
def getSeqName(self, s):
return self.SeqName
def setSeqName(self, s):
self.sequencename = s
def getStrand(self):
if self.SeqName == 'plus':
return 1
elif self.SeqName == 'minus':
return -1
else:
return 0
def setStrand(self, s):
self.strand = s
And here is what I have to do:
Create
 a 
new 
class
– 
GeneModel
‐
 that 
contains 
a 
group
 of 
DNAFeature 
objects
 representing
 exons
 and
 is 
a 
child 
class 
of 
DNAFeature. 
It
 should 
implement 
the
 following 
methods:


getFeats() 
–
returns 
a 
list
 of
 DNAFeature 
objects,
sorted
 by
 start 
position
addFeat(feat)
–
 accepts 
a 
DNAFeature 
feat 
and
 adds 
it 
to 
its 
internal 
group
 of
 DNAFeature 
objects
setTranslStart(i)
– 
accepts 
a 
non‐negative 
int,
sets 
the
 start
 position 
of
 the
 initiating 
ATG
 codon
getTranslStart()
–
returns 
an 
int, 
the
 start 
position 
of 
the
 initiating 
ATG
 codon
setTranslStop(i)
– 
accepts
 a 
positive 
int,
sets
 the
 end
 position 
for 
the
 stop
 codon
getTranslStop()
–
 returns
 an 
int,
the
 end 
position 
for
 the
 stop 
codon
setDisplayId(s) 
–
sets 
the
 name
 of
 the
 gene
 model; 
s 
is 
a 
string
getDisplayId()
– 
return
 the
 name 
of 
the 
gene
 model,
 returns 
a 
string,
e.g.,
AT1G10555.1
 
 GeneModel
 should 
raise
 appropriate 
ValueError 
and 
TypeError 
exceptions 
when
 users
 pass
 incorrect 
types 
and
 values 
to 
constructors 
and 
“set” 
methods.
I have tried to write whatever comes to my mind, and read the books as well as searching the way to put codes together, but I am so new to programming and hardly can understand how to write the codes correctly. To be honest, this is the first time I ever do a programming class. So if I make any funny mistake in my codes, please forgive me. I haven't finish my codes yet and still reading the books to see where I am doing wrong and right with my codes. However, I really need your help to guide me to the right path. Thank you guys very much. Below is my codes:
class GeneModel(DNAFeature):
def __init__(self, translstart, translend, displayid):
self.setTranslStart(translstart)
self.setTranslStop(translend)
setDisplayId(displayid)
def getFeats():
result = []
sort.self.getStart()
return result
def addFeat(feat):
self.addFeat = feat
return self.getStart+self.getEnd
def setTranslStart(i):
self.translstart = self.setStart
self.translstart = non-negative int
def getTranslStart():
return self.translstart
def setTranslStop(i):
self.translend = self.setEnd
self.translend = "+" int
def getTranslStop():
return self.translend
def setDisplayId(s):
self.displayid = re.compile('r'\AT1G[0-9]{5,5}\.[0-9]{,1}, IGNORECASE')
def getDisplayId():
return self.displayid
I don't understand what the name of the gene model is. I think it's subject specific, but I think this will work for you:
class GenoModel(DNAFeature):
def __init__(self, start, end):
self.setStart(start)
self.setEnd(end)
self.strand = None
self.sequencename = None
self.exons = []
self.translStart = None
self.translStop = None
self.displayId = None
def getFeats(self):
self.exons.sort(cmp=self.start)
return self.exons
def addFeat(self, f):
if type(f) == DNAFeature:
self.exons.append(f)
else:
raise TypeError("Cannot add feature as it is not of type DNAFeature")
def setTranslStart(self, i):
if type(i) != int:
raise TypeError("Cannot set translStart as it is not of type int")
elif i < 0:
raise ValueError("Cannot set tanslStart to a negative int")
else:
self.translStart = i
def getTranslStart(self):
return self.translStart
def setTranslStop(self, i):
if type(i) != int:
raise TypeError("Cannot set translStop as it is not of type int")
elif i <= 0:
raise ValueError("Cannot set tanslStop to anything less than 1")
else:
self.translStop = i
def getTranslStop(self):
return self.translStop
def setDisplayId(self, s):
if type(s) != str:
raise TypeError("Cannot set desiplayId as it is not of type string")
else:
self.displayId = s
def getDisplayId(self):
return self.displayId
Hope this helps.
First, a little bit of cleanup. I'm not completely convinced that your original class, DNAFeature, is actually correct. DNAFeature seems to be inheriting from some other class, named Range, that we're missing here so if you have that code please offer it as well. In that original class, you need to define the variable SeqName (also, its preferable to keep variables lower-cased) since otherwise self.SeqName will be meaningless. Additionally, unless they're inherited from the Range class, you should also define the methods "setStart" and "setEnd". You're getter should not any additional variables, so feel free to change it to "def getSeqName(self)" instead of adding "s". I'm not sure what else your code is really supposed to do, so I'll hold any further comment.
Additionally, though you stated otherwise in your comment, I have to believe from the naming conventions (and what little I remember from bio) that you actually want GeneModel to be a container for a set of DNAFeature instances. That's different from GeneModel subclassing DNAFeature. If I'm right, then you can try:
class GeneModel(object):
def __init__(dnafeatures):
self.dnafeatures = dnafeatures
def get_features(self):
return self.dnafeatures
def add_feature(self, feature):
self.dnafeatures.append(feature)
Here dnafeatures would just be a list of dnafeature instances. This would then allow you to write methods to access these features and do whatever fun stuff you need to do.
My advice would be to make sure your DNAFeature class is correct and that your model of how you want your problem solved (in terms of what your classes do) and try asking again when its a little clearer. Hope this helps!

has_next in Python iterators?

Have Python iterators got a has_next method?
There's an alternative to the StopIteration by using next(iterator, default_value).
For exapmle:
>>> a = iter('hi')
>>> print next(a, None)
h
>>> print next(a, None)
i
>>> print next(a, None)
None
So you can detect for None or other pre-specified value for end of the iterator if you don't want the exception way.
No, there is no such method. The end of iteration is indicated by an exception. See the documentation.
If you really need a has-next functionality, it's easy to obtain it with a little wrapper class. For example:
class hn_wrapper(object):
def __init__(self, it):
self.it = iter(it)
self._hasnext = None
def __iter__(self): return self
def next(self):
if self._hasnext:
result = self._thenext
else:
result = next(self.it)
self._hasnext = None
return result
def hasnext(self):
if self._hasnext is None:
try: self._thenext = next(self.it)
except StopIteration: self._hasnext = False
else: self._hasnext = True
return self._hasnext
now something like
x = hn_wrapper('ciao')
while x.hasnext(): print next(x)
emits
c
i
a
o
as required.
Note that the use of next(sel.it) as a built-in requires Python 2.6 or better; if you're using an older version of Python, use self.it.next() instead (and similarly for next(x) in the example usage). [[You might reasonably think this note is redundant, since Python 2.6 has been around for over a year now -- but more often than not when I use Python 2.6 features in a response, some commenter or other feels duty-bound to point out that they are 2.6 features, thus I'm trying to forestall such comments for once;-)]]
===
For Python3, you would make the following changes:
from collections.abc import Iterator # since python 3.3 Iterator is here
class hn_wrapper(Iterator): # need to subclass Iterator rather than object
def __init__(self, it):
self.it = iter(it)
self._hasnext = None
def __iter__(self):
return self
def __next__(self): # __next__ vs next in python 2
if self._hasnext:
result = self._thenext
else:
result = next(self.it)
self._hasnext = None
return result
def hasnext(self):
if self._hasnext is None:
try:
self._thenext = next(self.it)
except StopIteration:
self._hasnext = False
else: self._hasnext = True
return self._hasnext
In addition to all the mentions of StopIteration, the Python "for" loop simply does what you want:
>>> it = iter("hello")
>>> for i in it:
... print i
...
h
e
l
l
o
Try the __length_hint__() method from any iterator object:
iter(...).__length_hint__() > 0
You can tee the iterator using, itertools.tee, and check for StopIteration on the teed iterator.
hasNext somewhat translates to the StopIteration exception, e.g.:
>>> it = iter("hello")
>>> it.next()
'h'
>>> it.next()
'e'
>>> it.next()
'l'
>>> it.next()
'l'
>>> it.next()
'o'
>>> it.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
StopIteration docs: http://docs.python.org/library/exceptions.html#exceptions.StopIteration
Some article about iterators and generator in python: http://www.ibm.com/developerworks/library/l-pycon.html
No. The most similar concept is most likely a StopIteration exception.
I believe python just has next() and according to the doc, it throws an exception is there are no more elements.
http://docs.python.org/library/stdtypes.html#iterator-types
The use case that lead me to search for this is the following
def setfrom(self,f):
"""Set from iterable f"""
fi = iter(f)
for i in range(self.n):
try:
x = next(fi)
except StopIteration:
fi = iter(f)
x = next(fi)
self.a[i] = x
where hasnext() is available, one could do
def setfrom(self,f):
"""Set from iterable f"""
fi = iter(f)
for i in range(self.n):
if not hasnext(fi):
fi = iter(f) # restart
self.a[i] = next(fi)
which to me is cleaner. Obviously you can work around issues by defining utility classes, but what then happens is you have a proliferation of twenty-odd different almost-equivalent workarounds each with their quirks, and if you wish to reuse code that uses different workarounds, you have to either have multiple near-equivalent in your single application, or go around picking through and rewriting code to use the same approach. The 'do it once and do it well' maxim fails badly.
Furthermore, the iterator itself needs to have an internal 'hasnext' check to run to see if it needs to raise an exception. This internal check is then hidden so that it needs to be tested by trying to get an item, catching the exception and running the handler if thrown. This is unnecessary hiding IMO.
Maybe it's just me, but while I like https://stackoverflow.com/users/95810/alex-martelli 's answer, I find this a bit easier to read:
from collections.abc import Iterator # since python 3.3 Iterator is here
class MyIterator(Iterator): # need to subclass Iterator rather than object
def __init__(self, it):
self._iter = iter(it)
self._sentinel = object()
self._next = next(self._iter, self._sentinel)
def __iter__(self):
return self
def __next__(self): # __next__ vs next in python 2
if not self.has_next():
next(self._iter) # raises StopIteration
val = self._next
self._next = next(self._iter, self._sentinel)
return val
def has_next(self):
return self._next is not self._sentinel
No, there is no such method. The end of iteration is indicated by a StopIteration (more on that here).
This follows the python principle EAFP (easier to ask for forgiveness than permission). A has_next method would follow the principle of LBYL (look before you leap) and contradicts this core python principle.
This interesting article explains the two concepts in more detail.
Suggested way is StopIteration.
Please see Fibonacci example from tutorialspoint
#!usr/bin/python3
import sys
def fibonacci(n): #generator function
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(5) #f is iterator object
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
It is also possible to implement a helper generator that wraps any iterator and answers question if it has next value:
Try it online!
def has_next(it):
first = True
for e in it:
if not first:
yield True, prev
else:
first = False
prev = e
if not first:
yield False, prev
for has_next_, e in has_next(range(4)):
print(has_next_, e)
Which outputs:
True 0
True 1
True 2
False 3
The main and probably only drawback of this method is that it reads ahead one more element, for most of tasks it is totally alright, but for some tasks it may be disallowed, especially if user of has_next() is not aware of this read-ahead logic and may missuse it.
Code above works for infinite iterators too.
Actually for all cases that I ever programmed such kind of has_next() was totally enough and didn't cause any problems and in fact was very helpful. You just have to be aware of its read-ahead logic.
The way has solved it based on handling the "StopIteration" execption is pretty straightforward in order to read all iterations :
end_cursor = False
while not end_cursor:
try:
print(cursor.next())
except StopIteration:
print('end loop')
end_cursor = True
except:
print('other exceptions to manage')
end_cursor = True
I think there are valid use cases for when you may want some sort of has_next functionality, in which case you should decorate an iterator with a has_next defined.
Combining concepts from the answers to this question here is my implementation of that which feels like a nice concise solution to me (python 3.9):
_EMPTY_BUF = object()
class BufferedIterator(Iterator[_T]):
def __init__(self, real_it: Iterator[_T]):
self._real_it = real_it
self._buf = next(self._real_it, _EMPTY_BUF)
def has_next(self):
return self._buf is not _EMPTY_BUF
def __next__(self) -> _T_co:
v = self._buf
self._buf = next(self._real_it, _EMPTY_BUF)
if v is _EMPTY_BUF:
raise StopIteration()
return v
The main difference is that has_next is just a boolean expression, and also handles iterators with None values.
Added this to a gist here with tests and example usage.
With 'for' one can implement his own version of 'next' avoiding exception
def my_next(it):
for x in it:
return x
return None
very interesting question, but this "hasnext" design had been put into leetcode:
https://leetcode.com/problems/iterator-for-combination/
here is my implementation:
class CombinationIterator:
def __init__(self, characters: str, combinationLength: int):
from itertools import combinations
from collections import deque
self.iter = combinations(characters, combinationLength)
self.res = deque()
def next(self) -> str:
if len(self.res) == 0:
return ''.join(next(self.iter))
else:
return ''.join(self.res.pop())
def hasNext(self) -> bool:
try:
self.res.insert(0, next(self.iter))
return True
except:
return len(self.res) > 0
The way I solved my problem is to keep the count of the number of objects iterated over, so far. I wanted to iterate over a set using calls to an instance method. Since I knew the length of the set, and the number of items counted so far, I effectively had an hasNext method.
A simple version of my code:
class Iterator:
# s is a string, say
def __init__(self, s):
self.s = set(list(s))
self.done = False
self.iter = iter(s)
self.charCount = 0
def next(self):
if self.done:
return None
self.char = next(self.iter)
self.charCount += 1
self.done = (self.charCount < len(self.s))
return self.char
def hasMore(self):
return not self.done
Of course, the example is a toy one, but you get the idea. This won't work in cases where there is no way to get the length of the iterable, like a generator etc.

Mathematical equation manipulation in Python

I want to develop a GUI application which displays a given mathematical equation. When you click upon a particular variable in the equation to signify that it is the unknown variable ie., to be calculated, the equation transforms itself to evaluate the required unknown variable.
For example:
a = (b+c*d)/e
Let us suppose that I click upon "d" to signify that it is the unknown variable. Then the equation should be re-structured to:
d = (a*e - b)/c
As of now, I just want to know how I can go about rearranging the given equation based on user input. One suggestion I got from my brother was to use pre-fix/post-fix notational representation in back end to evaluate it.
Is that the only way to go or is there any simpler suggestion?
Also, I will be using not only basic mathematical functions but also trignometric and calculus (basic I think. No partial differential calculus and all that) as well. I think that the pre/post-fix notation evaluation might not be helpful in evaluation higher mathematical functions.
But that is just my opinion, so please point out if I am wrong.
Also, I will be using SymPy for mathematical evaluation so evaluation of a given mathematical equation is not a problem, creating a specific equation from a given generic one is my main problem.
Using SymPy, your example would go something like this:
>>> import sympy
>>> a,b,c,d,e = sympy.symbols('abcde')
>>> r = (b+c*d)/e
>>> l = a
>>> r = sympy.solve(l-r,d)
>>> l = d
>>> r
[(-b + a*e)/c]
>>>
It seems to work for trigonometric functions too:
>>> l = a
>>> r = b*sympy.sin(c)
>>> sympy.solve(l-r,c)
[asin(a/b)]
>>>
And since you are working with a GUI, you'll (probably) want to convert back and forth from strings to expressions:
>>> r = '(b+c*d)/e'
>>> sympy.sympify(r)
(b + c*d)/e
>>> sympy.sstr(_)
'(b + c*d)/e'
>>>
or you may prefer to display them as rendered LaTeX or MathML.
If you want to do this out of the box, without relying on librairies, I think that the problems you will find are not Python related. If you want to find such equations, you have to describe the heuristics necessary to solve these equations.
First, you have to represent your equation. What about separating:
operands:
symbolic operands (a,b)
numeric operands (1,2)
operators:
unary operators (-, trig functions)
binary operators (+,-,*,/)
Unary operators will obviously enclose one operand, binary ops will enclose two.
What about types?
I think that all of these components should derivate from a single common expression type.
And this class would have a getsymbols method to locate quickly symbols in your expressions.
And then distinguish between unary and binary operators, add a few basic complement/reorder primitives...
Something like:
class expression(object):
def symbols(self):
if not hasattr(self, '_symbols'):
self._symbols = self._getsymbols()
return self._symbols
def _getsymbols(self):
"""
return type: list of strings
"""
raise NotImplementedError
class operand(expression): pass
class symbolicoperand(operand):
def __init__(self, name):
self.name = name
def _getsymbols(self):
return [self.name]
def __str__(self):
return self.name
class numericoperand(operand):
def __init__(self, value):
self.value = value
def _getsymbols(self):
return []
def __str__(self):
return str(self.value)
class operator(expression): pass
class binaryoperator(operator):
def __init__(self, lop, rop):
"""
#type lop, rop: expression
"""
self.lop = lop
self.rop = rop
def _getsymbols(self):
return self.lop._getsymbols() + self.rop._getsymbols()
#staticmethod
def complementop():
"""
Return complement operator:
op.complementop()(op(a,b), b) = a
"""
raise NotImplementedError
def reorder():
"""
for op1(a,b) return op2(f(b),g(a)) such as op1(a,b) = op2(f(a),g(b))
"""
raise NotImplementedError
def _getstr(self):
"""
string representing the operator alone
"""
raise NotImplementedError
def __str__(self):
lop = str(self.lop)
if isinstance(self.lop, operator):
lop = '(%s)' % lop
rop = str(self.rop)
if isinstance(self.rop, operator):
rop = '(%s)' % rop
return '%s%s%s' % (lop, self._getstr(), rop)
class symetricoperator(binaryoperator):
def reorder(self):
return self.__class__(self.rop, self.lop)
class asymetricoperator(binaryoperator):
#staticmethod
def _invert(operand):
"""
div._invert(a) -> 1/a
sub._invert(a) -> -a
"""
raise NotImplementedError
def reorder(self):
return self.complementop()(self._invert(self.rop), self.lop)
class div(asymetricoperator):
#staticmethod
def _invert(operand):
if isinstance(operand, div):
return div(self.rop, self.lop)
else:
return div(numericoperand(1), operand)
#staticmethod
def complementop():
return mul
def _getstr(self):
return '/'
class mul(symetricoperator):
#staticmethod
def complementop():
return div
def _getstr(self):
return '*'
class add(symetricoperator):
#staticmethod
def complementop():
return sub
def _getstr(self):
return '+'
class sub(asymetricoperator):
#staticmethod
def _invert(operand):
if isinstance(operand, min):
return operand.op
else:
return min(operand)
#staticmethod
def complementop():
return add
def _getstr(self):
return '-'
class unaryoperator(operator):
def __init__(self, op):
"""
#type op: expression
"""
self.op = op
#staticmethod
def complement(expression):
raise NotImplementedError
def _getsymbols(self):
return self.op._getsymbols()
class min(unaryoperator):
#staticmethod
def complement(expression):
if isinstance(expression, min):
return expression.op
else:
return min(expression)
def __str__(self):
return '-' + str(self.op)
With this basic structure set up, you should be able to describe a simple heuristic to solve very simple equations. Just think of the simple rules you learned to solve equations, and write them down. That should work :)
And then a very naive solver:
def solve(left, right, symbol):
"""
#type left, right: expression
#type symbol: string
"""
if symbol not in left.symbols():
if symbol not in right.symbols():
raise ValueError('%s not in expressions' % symbol)
left, right = right, left
solved = False
while not solved:
if isinstance(left, operator):
if isinstance(left, unaryoperator):
complementor = left.complement
right = complementor(right)
left = complementor(left)
elif isinstance(left, binaryoperator):
if symbol in left.rop.symbols():
left = left.reorder()
else:
right = left.complementop()(right, left.rop)
left = left.lop
elif isinstance(left, operand):
assert isinstance(left, symbolicoperand)
assert symbol==left.name
solved = True
print symbol,'=',right
a,b,c,d,e = map(symbolicoperand, 'abcde')
solve(a, div(add(b,mul(c,d)),e), 'd') # d = ((a*e)-b)/c
solve(numericoperand(1), min(min(a)), 'a') # a = 1
Things have sure changed since 2009. I don't know how your GUI application is going, but this is now possible directly in IPython qtconsole (which one could embed inside a custom PyQt/PySide application, and keep track of all the defined symbols, to allow GUI interaction in a separate listbox, etc.)
(Uses the sympyprt extension for IPython)
What you want to do isn't easy. Some equations are quite straight forward to rearrange (like make b the subject of a = b*c+d, which is b = (a-d)/c), while others are not so obvious (like make x the subject of y = x*x + 4*x + 4), while others are not possible (especially when you trigonometric functions and other complications).
As other people have said, check out Sage. It does what you want:
You can solve equations for one variable in terms of others:
sage: x, b, c = var('x b c')
sage: solve([x^2 + b*x + c == 0],x)
[x == -1/2*b - 1/2*sqrt(b^2 - 4*c), x == -1/2*b + 1/2*sqrt(b^2 - 4*c)]
Sage has support for symbolic math. You could just use some of the equation manipulating functions built-in:
http://sagemath.org/

Categories