Python中数学表达式的等价性测试
我有两个Python字符串Python中数学表达式的等价性测试,python,equality,sympy,mathematical-expressions,Python,Equality,Sympy,Mathematical Expressions,我有两个Python字符串 A m * B s / (A m + C m) 及 它们都是无序集(A,C)和无序集(B)的等价函数。m和s表示可以在同一个单元之间交换,但不能与另一个单元交换的单元 到目前为止,我正在做A、B和C的排列,并使用eval和SymPy的==运算符对它们进行测试。这有多个缺点: 对于更复杂的表达式,我必须生成大量的排列(在我的例子中是8嵌套for循环) 我需要将A、B、C定义为符号,当我不知道将拥有哪些参数时,这不是最佳的(因此我必须生成所有参数->效率极低,并且弄乱
A m * B s / (A m + C m)
及
它们都是无序集(A,C)和无序集(B)的等价函数。m和s表示可以在同一个单元之间交换,但不能与另一个单元交换的单元
到目前为止,我正在做A、B和C的排列,并使用eval和SymPy的==运算符对它们进行测试。这有多个缺点:
- 对于更复杂的表达式,我必须生成大量的排列(在我的例子中是8嵌套for循环)
- 我需要将A、B、C定义为符号,当我不知道将拥有哪些参数时,这不是最佳的(因此我必须生成所有参数->效率极低,并且弄乱了变量名称空间)
有没有一种pythonian方法来测试这种等价性?它应该适用于任意表达式。我曾经在一个数学数学研究模拟器中做过一次。。 在我的例子中,我知道将要使用的变量是什么 所以,我测试了将值放入变量中的结果
A = 10
B = 20
C = 30
m = Math.e
s = Math.pi
因此,我们解决:
s1 = 'A m * B s / (A m + C m)'
s2 = 'C m * B s / (C m + A m)'
如果s1!=s2,证明了不存在等价性
用这种方法不可能说两个表达式是等价的,
但你可以说这两者并不等同
if s1 != s2:
print "Not equivalent"
else:
print "Try with another sample"
嗯。。我希望这能对您有所帮助。不要迭代所有可能的排列,而是假设存在一个排列并尝试构造它。我相信,如果采用正确的方法,算法的失败将意味着置换的不存在 以下是适用于上述表达的想法的概要: 让我们: 我们正在寻找一个集合(a,C)的置换,它将使表达式相同。根据A和C在str2中首次出现的顺序,将其重新标记为X1和X2,以便:
X1 = C
X2 = A
因为在str2中C出现在A之前。接下来,创建数组Y,使得Y[i]是str1中第一次出现的第i个符号A或C。因此:
Y[1] = A
Y[2] = C
因为在str1中,A出现在C之前
现在用X1和X2替换A和C,从str2构建str3:
str3 = "X1 m * B s / (X1 m + X2 m)"
然后用席函数代替y [i]。首先,X1变为Y[1]=A:
str3_1 = "A m * Bs / (A m + X2 m)"
在这个阶段,将str3_1和str1与任何Xi的第一次出现进行比较,在本例中为X2,因为这两个字符串相等:
str3_1[:18] = "A m * B s / (A m + "
str1[:18] = "A m * B s / (A m + "
你有机会构造排列。如果它们是不相等的,那么就证明不存在合适的置换(因为任何置换都必须至少进行替换),并且可以推断出不等价性。但是它们是相等的,所以继续下一步,用X2代替Y[2]=C:
str3_2 = "A m * B s / (A m + C m)"
这等于str1,所以你有你的排列(A->C,C->A),并且展示了表达式的等价性
这只是对特定情况下算法的演示,但它应该是通用的。不确定你能得到的最低顺序是什么,但它应该比n快!生成n个变量上的所有置换
如果我正确理解了这些单位的重要性,它们会限制哪些变量可以通过排列来交换哪些变量。因此,在上述表达式中,A可以用C代替,因为两者都有“m”单位,但B没有“s”单位。您可以通过以下方式处理此问题:
通过删除所有没有m个单位的符号,从str1和str2中构造表达式str1_m和str2_m,然后对str1_m和str2_m执行上述算法。如果构造失败,则不存在排列。如果构造成功,则保留该置换(称之为m置换),并通过移除所有没有s单位的符号,从str1和str2构造str1和str2,然后再次对str1和str2执行该算法。如果建造失败,它们就不是等价物。如果成功,最终的置换将是m置换和s置换的组合(尽管您可能甚至不需要构造它,但您只关心它的存在)。根据我之前的回答,这里有一个简化的方法 其思想是,如果两个表达式在置换下等价,则将一个表达式传递给另一个表达式的置换必须将第一个字符串中的第i个符号(按第一次出现的索引排序)映射到第二个字符串中的第i个符号(同样按第一次出现的索引排序)。这个原理可以用来构造一个置换,将它应用于第一个字符串,然后检查与第二个字符串是否相等-如果相等,则相等,否则不相等 以下是一种可能的实现:
import re
# Unique-ify list, preserving order
def uniquify(l):
return reduce(lambda s, e: s + ([] if e in s else [e]), l, [])
# Replace all keys in replacements with corresponding values in str
def replace_all(str, replacements):
for old, new in replacements.iteritems():
str = str.replace(old, new)
return str
class Expression:
units = ["m", "s"]
def __init__(self, exp):
self.exp = exp
# Returns a list of symbols in the expression that are preceded
# by the given unit, ordered by first appearance. Assumes the
# symbol and unit are separated by a space. For example:
# Expression("A m * B s / (A m + C m)").symbols_for_unit("m")
# returns ['A', 'C']
def symbols_for_unit(self, unit):
sym_re = re.compile("(.) %s" % unit)
symbols = sym_re.findall(self.exp)
return uniquify(symbols)
# Returns a string with all symbols that have units other than
# unit "muted", that is replaced with the empty string. Example:
# Expression("A m * B s / (A m + C m)").mute_symbols_for_other_units("m")
# returns "A m * s / (A m + C m)"
def mute_symbols_for_other_units(self, unit):
other_units = "".join(set(self.units) - set(unit))
return re.sub("(.) ([%s])" % "".join(other_units), " \g<2>", self.exp)
# Returns a string with all symbols that have the given unit
# replaced with tokens of the form $0, $1, ..., by order of their
# first appearance in the string, and all other symbols muted.
# For example:
# Expression("A m * B s / (A m + C m)").canonical_form("m")
# returns "$0 m * s / ($0 m + $1 m)"
def canonical_form(self, unit):
symbols = self.symbols_for_unit(unit)
muted_self = self.mute_symbols_for_other_units(unit)
for i, sym in enumerate(symbols):
muted_self = muted_self.replace("%s %s" % (sym, unit), "$%s %s" % (i, unit))
return muted_self
# Define a permutation, represented as a dictionary, according to
# the following rule: replace $i with the ith distinct symbol
# occurring in the expression with the given unit. For example:
# Expression("C m * B s / (C m + A m)").permutation("m")
# returns {'$0':'C', '$1':'A'}
def permutation(self, unit):
enum = enumerate(self.symbols_for_unit(unit))
return dict(("$%s" % i, sym) for i, sym in enum)
# Return a string produced from the expression by first converting it
# into canonical form, and then performing the replacements defined
# by the given permutation. For example:
# Expression("A m * B s / (A m + C m)").permute("m", {"$0":"C", "$1":"A"})
# returns "C m * s / (C m + A m)"
def permute(self, unit, permutation):
new_exp = self.canonical_form(unit)
return replace_all(new_exp, permutation)
# Test for equality under permutation and muting of all other symbols
# than the unit provided.
def eq_under_permutation(self, unit, other_exp):
muted_self = self.mute_symbols_for_other_units(unit)
other_permuted_str = other_exp.permute(unit, self.permutation(unit))
return muted_self == other_permuted_str
# Test for equality under permutation. This is done for each of
# the possible units using eq_under_permutation
def __eq__(self, other):
return all([self.eq_under_permutation(unit, other) for unit in self.units])
e1 = Expression("A m * B s / (A m + C m)")
e2 = Expression("C m * B s / (C m + A m)")
e3 = Expression("A s * B s / (A m + C m)")
f1 = Expression("A s * (B s + D s) / (A m + C m)")
f2 = Expression("A s * (D s + B s) / (C m + A m)")
f3 = Expression("D s")
print "e1 == e2: ", e1 == e2 # True
print "e1 == e3: ", e1 == e3 # False
print "e2 == e3: ", e2 == e3 # False
print "f1 == f2: ", f1 == f2 # True
print "f1 == f3: ", f1 == f3 # False
重新导入
#唯一的列表,保持顺序
def uniquify(l):
返回reduce(λs,e:s+([]如果e在s中,则为[e]),l,[]))
#用str中的相应值替换替换中的所有键
def更换_全部(str,更换):
对于替换中的旧项和新项。iteritems():
str=str.replace(旧、新)
返回str
类表达式:
单位=[“m”,“s”]
定义初始化(self,exp):
self.exp=exp
#返回表达式中前面的符号列表
#按给定单位,按首次出现顺序排列。假定
#符号和单位之间用空格隔开。例如:
#表达式(“AM*BS/(AM+CM)”)。符号表示单位(“m”)
#返回['A','C']
def符号\u用于\u装置(自身,装置):
sym_re=re.compile(“()%s”%unit)
symbols=sym_re.findall(self.exp)
返回uniquify(符号)
#返回一个字符串,其中包含除
#单位“静音”,被替换为空字符串。例子:
#表达式(“AM*BS/(AM+CM)”)。表示其他单位(“m”)的静音符号
#返回“AM*s/(AM+CM)”
def静音\u符号\u用于其他\u装置(自身、装置):
其他单位=“连接(集合(自我单位)-集合(单位))
返回re.sub(“()([%s])“%”。加入(其他单位),“\g”,self.exp)
#返回具有给定单位的所有符号的字符串
#替换wi
str3_2 = "A m * B s / (A m + C m)"
import re
# Unique-ify list, preserving order
def uniquify(l):
return reduce(lambda s, e: s + ([] if e in s else [e]), l, [])
# Replace all keys in replacements with corresponding values in str
def replace_all(str, replacements):
for old, new in replacements.iteritems():
str = str.replace(old, new)
return str
class Expression:
units = ["m", "s"]
def __init__(self, exp):
self.exp = exp
# Returns a list of symbols in the expression that are preceded
# by the given unit, ordered by first appearance. Assumes the
# symbol and unit are separated by a space. For example:
# Expression("A m * B s / (A m + C m)").symbols_for_unit("m")
# returns ['A', 'C']
def symbols_for_unit(self, unit):
sym_re = re.compile("(.) %s" % unit)
symbols = sym_re.findall(self.exp)
return uniquify(symbols)
# Returns a string with all symbols that have units other than
# unit "muted", that is replaced with the empty string. Example:
# Expression("A m * B s / (A m + C m)").mute_symbols_for_other_units("m")
# returns "A m * s / (A m + C m)"
def mute_symbols_for_other_units(self, unit):
other_units = "".join(set(self.units) - set(unit))
return re.sub("(.) ([%s])" % "".join(other_units), " \g<2>", self.exp)
# Returns a string with all symbols that have the given unit
# replaced with tokens of the form $0, $1, ..., by order of their
# first appearance in the string, and all other symbols muted.
# For example:
# Expression("A m * B s / (A m + C m)").canonical_form("m")
# returns "$0 m * s / ($0 m + $1 m)"
def canonical_form(self, unit):
symbols = self.symbols_for_unit(unit)
muted_self = self.mute_symbols_for_other_units(unit)
for i, sym in enumerate(symbols):
muted_self = muted_self.replace("%s %s" % (sym, unit), "$%s %s" % (i, unit))
return muted_self
# Define a permutation, represented as a dictionary, according to
# the following rule: replace $i with the ith distinct symbol
# occurring in the expression with the given unit. For example:
# Expression("C m * B s / (C m + A m)").permutation("m")
# returns {'$0':'C', '$1':'A'}
def permutation(self, unit):
enum = enumerate(self.symbols_for_unit(unit))
return dict(("$%s" % i, sym) for i, sym in enum)
# Return a string produced from the expression by first converting it
# into canonical form, and then performing the replacements defined
# by the given permutation. For example:
# Expression("A m * B s / (A m + C m)").permute("m", {"$0":"C", "$1":"A"})
# returns "C m * s / (C m + A m)"
def permute(self, unit, permutation):
new_exp = self.canonical_form(unit)
return replace_all(new_exp, permutation)
# Test for equality under permutation and muting of all other symbols
# than the unit provided.
def eq_under_permutation(self, unit, other_exp):
muted_self = self.mute_symbols_for_other_units(unit)
other_permuted_str = other_exp.permute(unit, self.permutation(unit))
return muted_self == other_permuted_str
# Test for equality under permutation. This is done for each of
# the possible units using eq_under_permutation
def __eq__(self, other):
return all([self.eq_under_permutation(unit, other) for unit in self.units])
e1 = Expression("A m * B s / (A m + C m)")
e2 = Expression("C m * B s / (C m + A m)")
e3 = Expression("A s * B s / (A m + C m)")
f1 = Expression("A s * (B s + D s) / (A m + C m)")
f2 = Expression("A s * (D s + B s) / (C m + A m)")
f3 = Expression("D s")
print "e1 == e2: ", e1 == e2 # True
print "e1 == e3: ", e1 == e3 # False
print "e2 == e3: ", e2 == e3 # False
print "f1 == f2: ", f1 == f2 # True
print "f1 == f3: ", f1 == f3 # False
>>> from sympy import *
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> sympify("x**2 + cos(x)")
x**2 + cos(x)
>>> sympify("diff(x**2 + cos(x), x)")
2*x - sin(x)
#SOURCE FOR HELPERS: https://github.com/sympy/sympy/wiki/Faq
import sympy
import sympy.parsing.sympy_parser
ExampleExpressionString1 = 'exp( i*( (x0 - 1)*(x0 + 2) ) )'
ExampleExpressionSympy1 = sympy.parsing.sympy_parser.parse_expr(ExampleExpressionString1)
ExampleExpressionString2 = 'i*sin( (x0 - 1)*(x0 + 2) ) + cos( (x0 - 1)*(x0 + 2) )'
ExampleExpressionSympy2 = sympy.parsing.sympy_parser.parse_expr(ExampleExpressionString2)
print '(ExampleExpressionSympy1 == ExampleExpressionSympy2):'
print ' ', (ExampleExpressionSympy1 == ExampleExpressionSympy2)
print '(ExampleExpressionSympy1.simplify() == ExampleExpressionSympy2.simplify()):'
print ' ', (ExampleExpressionSympy1.simplify() == ExampleExpressionSympy2.simplify())
print '(ExampleExpressionSympy1.expand() == ExampleExpressionSympy2.expand()):'
print ' ', (ExampleExpressionSympy1.trigsimp() == ExampleExpressionSympy2.trigsimp())
print '(ExampleExpressionSympy1.trigsimp() == ExampleExpressionSympy2.trigsimp()):'
print ' ', (ExampleExpressionSympy1.trigsimp() == ExampleExpressionSympy2.trigsimp())
print '(ExampleExpressionSympy1.simplify().expand().trigsimp() == ExampleExpressionSympy2.simplify().expand().trigsimp()):'
print ' ', (ExampleExpressionSympy1.simplify().expand().trigsimp() == ExampleExpressionSympy2.simplify().expand().trigsimp())
import sympy
import sympy.parsing.sympy_parser
Expression.simplify().expand().trigsimp()