Python 如何将Symphy中的非常小的数字简化为0?

Python 如何将Symphy中的非常小的数字简化为0?,python,sympy,Python,Sympy,我正在用Python2.7.10中的Symphy 0.7.6进行一些矩阵计算。比如说, M = [cos(q1), -6.12323399573677e-17*sin(q1), -1.0*sin(q1), 150*sin(q1)] [sin(q1), 6.12323399573677e-17*cos(q1), 1.0*cos(q1), 150*sin(q1)] [ 0, -1.0, 6.123233

我正在用Python2.7.10中的Symphy 0.7.6进行一些矩阵计算。比如说,

M = 
[cos(q1), -6.12323399573677e-17*sin(q1),         -1.0*sin(q1), 150*sin(q1)]
[sin(q1),  6.12323399573677e-17*cos(q1),          1.0*cos(q1), 150*sin(q1)]
[      0,                          -1.0, 6.12323399573677e-17,         445]
[      0,                             0,                    0,           1]
然后我将
simplify
应用于
M
,结果是:

M = 
[cos(q1),    0,         -1.0*sin(q1), 150*sin(q1)]
[sin(q1),    0,          1.0*cos(q1), 150*sin(q1)]
[      0, -1.0, 6.12323399573677e-17,         445]
[      0,    0,                    0,           1]
很明显,
-6.12323399573677e-17*sin(q1)
被简化为
0
,但
6.12323399573677e-17
不是。是否可以使用
simplify
简化纯数字项?

如果使用矩阵(sympy.Matrix.dense.MutableDenseMatrix),包括带有合成元素的矩阵,则可以使用以下函数进行转换:

def round2zero(m, e):
    for i in range(m.shape[0]):
        for j in range(m.shape[1]):
            if (isinstance(m[i,j], Float) and m[i,j] < e):
                m[i,j] = 0
如果您使用的是矩阵(sympy.Matrix.dense.MutableDenseMatrix),包括带有合成元素的矩阵,则可以使用以下函数进行转换:

def round2zero(m, e):
    for i in range(m.shape[0]):
        for j in range(m.shape[1]):
            if (isinstance(m[i,j], Float) and m[i,j] < e):
                m[i,j] = 0

一些模糊可以帮助检测更多可设置为零的值:

import sympy
import random


def fuzz_simplify(matrix, min=-1.0, max=1.0, iterations=1000, tolerance=0.005):
    m = sympy.Matrix(matrix)
    free_sym = range(len(J.free_symbols))
    f = sympy.lambdify(m.free_symbols,m)

    sum = f(*[0 for i in free_sym])

    for i in range(0, iterations):
        rand_params = [random.uniform(min,max) for i in free_sym]
        sum += f(*rand_params)

    for i in range(0, J.shape[0]):
        for j in range(0, J.shape[1]):
            if sum[i,j] < tolerance:
                m[i,j] *= 0

    return m
导入sympy
随机输入
def fuzz_simplify(矩阵,最小值=-1.0,最大值=1.0,迭代次数=1000,公差=0.005):
m=共矩阵(矩阵)
自由符号=范围(len(J.自由符号))
f=符号lambdify(m.free_符号,m)
总和=f(*[0表示自由符号中的i])
对于范围内的i(0,迭代次数):
rand_params=[自由符号中i的随机均匀(最小值、最大值)]
总和+=f(*rand_参数)
对于范围(0,J.shape[0])中的i:
对于范围(0,j.shape[1])内的j:
如果总和[i,j]<公差:
m[i,j]*=0
返回m

一些模糊化可以帮助检测更多可以设置为零的值:

import sympy
import random


def fuzz_simplify(matrix, min=-1.0, max=1.0, iterations=1000, tolerance=0.005):
    m = sympy.Matrix(matrix)
    free_sym = range(len(J.free_symbols))
    f = sympy.lambdify(m.free_symbols,m)

    sum = f(*[0 for i in free_sym])

    for i in range(0, iterations):
        rand_params = [random.uniform(min,max) for i in free_sym]
        sum += f(*rand_params)

    for i in range(0, J.shape[0]):
        for j in range(0, J.shape[1]):
            if sum[i,j] < tolerance:
                m[i,j] *= 0

    return m
导入sympy
随机输入
def fuzz_simplify(矩阵,最小值=-1.0,最大值=1.0,迭代次数=1000,公差=0.005):
m=共矩阵(矩阵)
自由符号=范围(len(J.自由符号))
f=符号lambdify(m.free_符号,m)
总和=f(*[0表示自由符号中的i])
对于范围内的i(0,迭代次数):
rand_params=[自由符号中i的随机均匀(最小值、最大值)]
总和+=f(*rand_参数)
对于范围(0,J.shape[0])中的i:
对于范围(0,j.shape[1])内的j:
如果总和[i,j]<公差:
m[i,j]*=0
返回m

Symphy的
n使用
rational=True
参数将表达式中的浮点数转换为有理数(在给定公差范围内)。如果低于阈值,则类似于
6.12323399573677e-17的内容将转换为0。因此,在你的情况下:

from sympy import Symbol, Matrix, sin, cos, nsimplify

q1 = Symbol("q1")
M = Matrix([
        [cos(q1), -6.12323e-17*sin(q1),  1.0*sin(q1), 150*sin(q1)],
        [sin(q1),  6.12323e-17*cos(q1),  1.0*cos(q1), 150*sin(q1)],
        [      0,                 -1.0, 6.123233e-17,         445],
        [      0,                    0,            0,           1],
    ])

nsimplify(M,tolerance=1e-10,rational=True)
# Matrix([
# [cos(q1),  0, -sin(q1), 150*sin(q1)],
# [sin(q1),  0,  cos(q1), 150*sin(q1)],
# [      0, -1,        0,         445],
# [      0,  0,        0,           1]])

请注意,这也是如何将
-1.0
转换为
1

Sympy的
n使用
rational=True
参数将表达式中的浮点数转换为有理数(在给定公差内)的。如果低于阈值,则类似于
6.12323399573677e-17的内容将转换为0。因此,在你的情况下:

from sympy import Symbol, Matrix, sin, cos, nsimplify

q1 = Symbol("q1")
M = Matrix([
        [cos(q1), -6.12323e-17*sin(q1),  1.0*sin(q1), 150*sin(q1)],
        [sin(q1),  6.12323e-17*cos(q1),  1.0*cos(q1), 150*sin(q1)],
        [      0,                 -1.0, 6.123233e-17,         445],
        [      0,                    0,            0,           1],
    ])

nsimplify(M,tolerance=1e-10,rational=True)
# Matrix([
# [cos(q1),  0, -sin(q1), 150*sin(q1)],
# [sin(q1),  0,  cos(q1), 150*sin(q1)],
# [      0, -1,        0,         445],
# [      0,  0,        0,           1]])

请注意,这也是如何将
-1.0
转换为
1

的。您有完整的scipy堆栈还是只有sympy?我有scipy 0.13.0b1请注意,在当前版本的sympy中,像
-6.12323399573677e-17*sin(q1)
这样的表达式不再简化为
0
(这是我希望它的行为方式)。你有完整的scipy堆栈还是只有sympy?我有scipy 0.13.0b1请注意,像
-6.12323399573677e-17*sin(q1)
这样的表达式在当前版本的sympy中不再简化为
0
(这是我希望它的行为)。非常感谢你的回复。然而,np.abs()不能应用于辛矩阵中的符号项。它返回TypeError:无法确定Abs的真值(cos(q1))<0.0001。我原以为这个问题会有简单的解决办法,但似乎没有。我必须仔细检查每一项,并检查它是否是数字。非常感谢您的回复。然而,np.abs()不能应用于辛矩阵中的符号项。它返回TypeError:无法确定Abs的真值(cos(q1))<0.0001。我原以为这个问题会有简单的解决办法,但似乎没有。我必须检查每一项,看它是否是数字。