Если вы хотите сделать это из коробки, не полагаясь на библиотеки, я думаю, что проблемы, которые вы найдете, не связаны с Python. Если вы хотите найти такие уравнения, вы должны описать эвристику, необходимую для решения этих уравнений.
Во-первых, вы должны представить свое уравнение. Как насчет разделения:
- операнды:
- символические операнды (а, б)
- числовые операнды (1,2)
- операторы:
- унарные операторы (-, триг функции)
- бинарные операторы (+, -, *, /)
Унарные операторы, очевидно, будут содержать один операнд, а двоичные операции - два.
А как насчет типов?
Я думаю, что все эти компоненты должны быть производными от одного общего expression
типа.
И этот класс будет иметь getsymbols
метод для быстрого поиска символов в ваших выражениях.
А затем различать унарные и бинарные операторы, добавить несколько базовых примитивов дополнения / переупорядочения ...
Что-то вроде:
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)
С этой базовой структурой вы сможете описать простую эвристику для решения очень простых уравнений. Просто подумайте о простых правилах, которые вы узнали для решения уравнений, и запишите их. Это должно работать:)
А потом очень наивный решатель:
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