代码之家  ›  专栏  ›  技术社区  ›  Mad Scientist

同态中的非序贯代换

  •  13
  • Mad Scientist  · 技术社区  · 14 年前

    我试图使用[SymPy][1]来同时替换表达式中的多个术语。我用字典作为参数尝试了[subs函数][2],但发现它是按顺序替换的。

    In : a.subs({a:b, b:c})
    Out: c
    

    问题是第一个替换产生了一个可以被第二个替换替换的术语,但是它不应该(因为我的原因)。

    你知道如何同时进行替换,而不让它们互相干扰吗?

    编辑:

    In [1]: I_x, I_y, I_z = Symbol("I_x"), Symbol("I_y"), Symbol("I_z")
    
    In [2]: S_x, S_y, S_z = Symbol("S_x"), Symbol("S_y"), Symbol("S_z")
    
    In [3]: J_is = Symbol("J_IS")
    
    In [4]: t = Symbol("t")
    
    In [5]: substitutions = (
    (2 * I_x * S_z, 2 * I_x * S_z * cos(2 * pi * J_is * t) + I_y * sin(2 * pi * J_is * t)),
    (I_x,  I_x * cos(2 * pi * J_is * t) + 2 * I_x * S_z * sin(2 * pi * J_is * t)),
    (I_y,  I_y * cos(2 * pi * J_is * t) - 2 * I_x * S_z * sin(2 * pi * J_is * t))
    )
    
    In [6]: (2 * I_x * S_z).subs(substitutions)
    Out[7]: (I_y*cos(2*pi*J_IS*t) - 2*I_x*S_z*sin(2*pi*J_IS*t))*sin(2*pi*J_IS*t) + 2*S_z*(I_x*cos(2*pi*J_IS*t) + 2*I_x*S_z*sin(2*pi*J_IS*t))*cos(2*pi*J_IS*t)
    

    只有适当的替代才应该发生,在这种情况下只有第一个。因此,预期输出应为:

    In [6]: (2 * I_x * S_z).subs(substitutions)
    Out[7]: I_y*sin(2*pi*J_IS*t) + 2*I_x*S_z*cos(2*pi*J_IS*t)
    
    5 回复  |  直到 14 年前
        1
  •  14
  •   Krastanov    12 年前

    sympy的当前版本提供了关键字sympolintal。前面答案中的复杂操作不再需要:

    In [1]: (x*sin(y)).subs([(x,y),(y,x)],simultaneous=True)
    Out[1]: y⋅sin(x)
    
        2
  •  2
  •   unutbu    14 年前

    这个 subs(self,*args) 方法的定义(部分)如下:

    In [11]: x.subs??
    ...
    sequence = args[0]
    if isinstance(sequence, dict):
        return self._subs_dict(sequence)
    elif isinstance(sequence, (list, tuple)):
        return self._subs_list(sequence)
    

    如果你通过了 subs 潜艇

    这不允许你同时替换。如果用户要传递诸如 x.subs([(x,y),(y,x)]) . 所以我怀疑sympy有没有同时替换的方法。相反,我认为所有的代换要么是无序的(如果你传递一个dict),要么充其量是通过一次有序的代换(如果你传递一个list或tuple):

    In [17]: x.subs([(x,y),(y,z)])
    Out[18]: z
    
    In [19]: x.subs([(y,z),(x,y)])
    Out[19]: y
    

    _subs_list(self, sequence) 定义(部分)如下:

    In [14]: x._subs_list??
    ...
        for old, new in sequence:
            result = result.subs(old, new)
    

        3
  •  1
  •   Community rohancragg    7 年前

    例如 @~unutbu's answer :

    >>> import ordereddict # collections.OrderedDict in Python 2.7+
    >>> from sympy import *
    >>> x,y,z = symbols('xyz')
    >>> x.subs(ordereddict.OrderedDict([(x,y),(y,z)]))
    y
    >>> x.subs(ordereddict.OrderedDict([(y,z),(x,y)]))
    z
    
        4
  •  1
  •   Gary Kerr    14 年前

    回答编辑好的问题。

    在您的示例中,您可以使用一些临时变量,这些变量不会被重写为后续替换。然后,一旦完成了所有可能重叠的替换,就可以用实际变量替换临时变量。

    这个例子适用于这个问题,如果您的完整问题包含更复杂的替换,我认为您应该仍然能够创建临时变量来避免重叠替换。

    from sympy import Symbol, sin, cos, pi
    
    I_x, I_y, I_z = Symbol("I_x"), Symbol("I_y"), Symbol("I_z")
    S_x, S_y, S_z = Symbol("S_x"), Symbol("S_y"), Symbol("S_z")
    J_is = Symbol("J_IS")
    t = Symbol("t")
    I_x_temp, I_y_temp, I_z_temp = Symbol("I_x_temp"), Symbol("I_y_temp"), Symbol("I_z_temp")
    
    f = 2*I_x*S_z
    answer = I_y*sin(2*pi*J_is*t) + 2*I_x*S_z*cos(2*pi*J_is*t)
    
    subs1a = [
        (2*I_x*S_z, 2*I_x_temp*S_z*cos(2*pi*J_is*t) + I_y_temp*sin(2*pi*J_is*t)),
        (I_x,  I_x_temp*cos(2* pi*J_is*t) + 2*I_x_temp*S_z*sin(2*pi*J_is*t)),
        (I_y,  I_y_temp*cos(2*pi*J_is*t) - 2*I_x_temp*S_z* sin(2*pi*J_is*t))
    ]
    
    subs_temp = [(I_x_temp, I_x), (I_y_temp, I_y), (I_z_temp, I_z)]
    
    print f
    f = f.subs(subs1a)
    print f
    f = f.subs(subs_temp)
    print f
    print f == answer # True
    

    注意,您还可以背对背地执行两个替换:

    f.subs(subs1a).subs(subs_temp) == answer
    
        5
  •  0
  •   smichr    10 年前

    关键字 simultaneous

    >>> x.subs([(x,y),(y,z)],simultaneous=1)
    y
    >>> x.subs([(y,z),(x,y)],simultaneous=1)
    y