简体   繁体   English

使用 SymPy 生成动态符号

[英]Dynamic symbol generation with SymPy

I recently asked this question about solving a system of nonlinear equations, over on Math SE.我最近在 Math SE 上问了这个关于求解非线性方程组的问题。 I am now attempting to implement the accepted answer using SymPy in Python .我现在正在尝试在Python使用SymPy实现公认的答案。 I'll begin by briefly recreating the solution here.我将首先在这里简要地重新创建解决方案。


Problem.问题。

Suppose I have three receivers, with coordinates given by vectors p1 , p2 , and p3 .假设我有三个接收器,坐标由向量p1p2p3 Further, I have a transmitter, emitting radio pulses at unknown times t1, t2, t3, t4, ... with known speed c , and which has unknown initial coordinates at time t = t1 given by the vector x0 = <x,y,z> and is moving with an unknown constant velocity given by the vector v .此外,我有一个发射器,在未知时间t1, t2, t3, t4, ...以已知速度c发射无线电脉冲,并且在时间t = t1具有未知的初始坐标,由向量x0 = <x,y,z>并且以向量v给出的未知恒定速度移动。 My data consists of the pulse arrival time at each station, denoted air (for arrival of time of signal i at receiver r ).我的数据包括每个站的脉冲到达时间,表示为air (用于信号i到达接收器r )。

My goal is to determine this velocity.我的目标是确定这个速度。 The solution given in the attached answer is as follows:所附答案中给出的解决方案如下:

The position of the transmitter at time t will be given by xo = v(t - t1) .发送器在时间t的位置由xo = v(t - t1) Hence, the distance between the transmitter and the rth receiver at the time the ith pulse is emitted will be given by:因此,发射ith脉冲时发射器和第rth接收器之间的距离将由下式给出:

||(ti - t1)v + x0 - pr||

Therefore, the time of arrival at the rth receiver is given by:因此,到达第rth接收器的时间由下式给出:

ti + (1/c) * ||(ti - t1)v + x0 - pr||

Which we know to be air .我们知道这是air Therefore:所以:

c**2(air - ti)**2 = ||v||**2(ti - t1)**2 + 2(ti -t1)<v, c0 - pr>

(where <a, b> denotes the scalar/dot product of vectors a and b ). (其中<a, b>表示向量ab的标量/点积)。

This results in a system of # receivers x # pulses equations.这导致了一个由# receivers x # pulses方程组成的系统。

(see the attached answer for far nicer formatting) (有关更好的格式,请参阅随附的答案)


Implementation.执行。

I'm most familiar with the SymPy package, so I'm attempting to implement a solution using its solvers.我最熟悉SymPy包,所以我试图使用它的求解器来实现一个解决方案。 I'm a bit stuck, however, on where to begin.然而,我对从哪里开始有点困惑。

The number of pulses is not known before hand thus, as SymPy is a symbolic solver, I must be able to dynamically define variables t1, t2, t3... tn .脉冲数事先未知,因此,由于SymPy是一个符号求解器,我必须能够动态定义变量t1, t2, t3... tn

My rough outline for an implementation is as follows:我对实现的粗略概述如下:

import sympy as sp

def find_transmitter(arrival_times):
    equations = []

    for receiver in arrival_times:
        for pulse in arrival_times:
            equations.append(sp.Eq(c**2(pulse - ti...

    sp.solve(equations...

Where arrival_times is a list, where each column corresponds to a receiver, and each row corresponds to a pulse.其中arrival_times是一个列表,其中每一列对应一个接收器,每一行对应一个脉冲。 Ie: IE:

[[a11, a21, a31...],[a12, a22, a32...],[a13, a23, a33...]]

It doesn't occur to me that there's a nice alternative to this approach.我没有想到这种方法有一个很好的替代方案。 I'm not sure, however, eg how to dynamically define enough ti 's and iterate through them.但是,我不确定,例如如何动态定义足够的ti并遍历它们。 That is, eg, I'll have an unknown number of equations looking like:也就是说,例如,我将有一个未知数量的方程,如下所示:

equations.append(sp.Eq(c**2(pulse - t1...
equations.append(sp.Eq(c**2(pulse - t2...
equations.append(sp.Eq(c**2(pulse - t3...
equations.append(sp.Eq(c**2(pulse - t4...
equations.append(sp.Eq(c**2(pulse - t5...
.
.
.

Is there a nice way to do this?有没有很好的方法来做到这一点? Very likely, I'm overlooking some obvious solution.很可能,我忽略了一些明显的解决方案。

Perhaps surprisingly, can dynamically create any number of symbols with symbols using space as a delimiter!也许令人惊讶,可以动态地创建与任意数量的符号的symbols使用空格作为分隔符!

You can also subscript with _N你也可以用_N下标

arrival_times_count = 100  # from data length
chunksize = 10  # some factor of arrival_times_count

def chunks(lst, n):
    """Yield successive n-sized chunks from lst."""
    for i in range(0, len(lst), n):
        yield lst[i:i + n]

from sympy import *
# create a huge collection
collection = symbols(" ".join(f"t_{x}" for x in range(arrival_times_count)), real=True)
# fold it into rows
collection = list(chunks(collection, chunksize))
>>> for row in collection:
...     print(row)
...
(t_0, t_1, t_2, t_3, t_4, t_5, t_6, t_7, t_8, t_9)
(t_10, t_11, t_12, t_13, t_14, t_15, t_16, t_17, t_18, t_19)
(t_20, t_21, t_22, t_23, t_24, t_25, t_26, t_27, t_28, t_29)
(t_30, t_31, t_32, t_33, t_34, t_35, t_36, t_37, t_38, t_39)
(t_40, t_41, t_42, t_43, t_44, t_45, t_46, t_47, t_48, t_49)
(t_50, t_51, t_52, t_53, t_54, t_55, t_56, t_57, t_58, t_59)
(t_60, t_61, t_62, t_63, t_64, t_65, t_66, t_67, t_68, t_69)
(t_70, t_71, t_72, t_73, t_74, t_75, t_76, t_77, t_78, t_79)
(t_80, t_81, t_82, t_83, t_84, t_85, t_86, t_87, t_88, t_89)
(t_90, t_91, t_92, t_93, t_94, t_95, t_96, t_97, t_98, t_99)

chunks function from How do you split a list into evenly sized chunks? chunks函数来自如何将列表拆分为大小均匀的块?


However, there's a good chance this is an XY problem and you may be better off doing something like packing your data into a pandas.DataFrame , lambdifying your equation, and then calling .apply() to find the result of each row然而,有一个很好的机会,这是一个XY的问题,你可能会更好做这样的事情打包数据成pandas.DataFramelambdifying你的公式,然后调用.apply()找到每一行的结果

A dirty way to dynamically define variables is to make a string pattern (with python code) and then process it with exec .动态定义变量的一种肮脏方法是创建一个字符串模式(使用 python 代码),然后使用exec处理它。 So you can have access to the variables without passing though list, tuples, ... The best way would be to use substitution (vector -> components), hence you work with a vector & lambdify to perform componentwise operations.因此,您无需通过列表、元组等即可访问变量……最好的方法是使用替换(向量 -> 组件),因此您可以使用向量和 Lambdify 来执行组件操作。

from sympy import *
n = 4
t_s = ( ''.join((i, str(j))) for i, j in  zip('t'*n, range(1, n+1)))
exec( f"{', '.join(t_s)}  = symbols('t1:{n+1}')")

print(t2, type(t2))

Output输出

t2 <class 'sympy.core.symbol.Symbol'>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM