numpy 以有用的形式存储SymPy solve()结果

hpcdzsge  于 10个月前  发布在  其他
关注(0)|答案(2)|浏览(72)

我写了一个for循环来求解一堆Angular 。我将所有结果存储在NumPy字典数组中。但我希望所有答案都以度(而不是弧度)为单位并四舍五入。这是基本的,但我很难得到我想要的结果。我的方程只有三个输入,其中一个没有解。每个输入都有两个解(两对Angular )。我的代码:

import numpy as np
import sympy as smp
#Enable LaTex display
smp.init_printing()

L1,L2,L3,L4,L5,theta1,theta2,theta3,theta4,theta5=smp.symbols('L1,L2,L3,L4,L5,theta1,theta2,theta3,theta4,theta5')
def lengths():
    L1=17
    L2=9
    L3=12
    L4=6
    L5=14
    return np.array([L1,L2,L3,L4,L5])
def thetas():
    theta1=np.repeat(np.radians(15),repeats=3)
    theta3=np.array([np.radians(30),np.radians(195),np.radians(330)])
    theta4=np.array([np.radians(100),np.radians(200),np.radians(300)])
    return np.array([theta1,theta3,theta4])
def position_vectors():
    R1=np.array([L1*smp.cos(theta1),L1*smp.sin(theta1)])
    R2=np.array([L2*smp.cos(theta2),L2*smp.sin(theta2)])
    R3=np.array([L3*smp.cos(theta3),L3*smp.sin(theta3)])
    R4=np.array([L4*smp.cos(theta4),L4*smp.sin(theta4)])
    R5=np.array([L5*smp.cos(theta5),L5*smp.sin(theta5)])
    return smp.Matrix([R1,R2,R3,R4,R5])
def loop_equations():
    R=position_vectors()
    i_comps=smp.Eq(R[1,0]+R[2,0]+R[3,0]-R[0,0]-R[4,0],0)
    j_comps=smp.Eq(R[1,1]+R[2,1]+R[3,1]-R[0,1]-R[4,1],0)
    return [i_comps,j_comps]
print('Equations necessary to perform position analysis:')
display(loop_equations()[0])
display(loop_equations()[1])

Solution_matrix=np.zeros((len(thetas()),2),dtype=object)
L1,L2,L3,L4,L5=lengths()
for k in range(len(thetas())):
    theta1,theta3,theta4=thetas()[:,k]
    i_comps_subs=loop_equations()[0]
    j_comps_subs=loop_equations()[1]
    Solution=smp.solve([i_comps_subs,j_comps_subs],[theta2,theta5],dict=True)
    if Solution==[]:
        Solution_matrix[k]='No solution'
    else:
        Solution_matrix[k]=Solution
print(Solution_matrix)

字符串
输出值:

Equations necessary to perform position analysis:
−𝐿1cos(𝜃1)+𝐿2cos(𝜃2)+𝐿3cos(𝜃3)+𝐿4cos(𝜃4)−𝐿5cos(𝜃5)=0
 
−𝐿1sin(𝜃1)+𝐿2sin(𝜃2)+𝐿3sin(𝜃3)+𝐿4sin(𝜃4)−𝐿5sin(𝜃5)=0
 
[[{theta2: 0.801807835029103, theta5: 1.62880348609314}
  {theta2: 3.85043163709124, theta5: 3.02343598602721}]
 ['No solution' 'No solution']
 [{theta2: 0.309428353211201, theta5: -1.16362912461926}
  {theta2: 2.44857937919009, theta5: -2.36154845015903}]]

rggaifut

rggaifut1#

要转换所有值,可以使用以下方法:

if Solution==[]:
    Solution_matrix[k]='No solution'
else:
    for dic in Solution:
        dic.update((key, round(degrees(value))) for key, value in dic.items())
    Solution_matrix[k]=Solution

#output
[[{theta2: 46, theta5: 93} {theta2: 221, theta5: 173}]
 ['No solution' 'No solution']
 [{theta2: 18, theta5: -67} {theta2: 140, theta5: -135}]]

字符串

nwlqm0z1

nwlqm0z12#

以有用的形式存储SymPy solve()结果
是没有意义的,因为你还没有指定存储的用途。如果你只关心打印,你可能根本不想存储任何东西。但是无论如何,你不应该存储文字字符串No solution;这是一个打印细节,应该推迟到打印阶段。
我希望所有的答案都是度(不是弧度)和四舍五入
这也是一个打印详细信息,应该推迟,而不是存储。
更一般地说,这段代码没有很好地利用Sympy。所有的项和方程都应该是符号化的(除非绝对必要,否则不要作为浮点计算)。不幸的是,通过Sympy的纯符号解决方案对这个问题来说非常慢,所以它可能只适用于数值求解。

from typing import Callable

import numpy as np
import sympy as smp
from sympy.matrices.dense import matrix_multiply_elementwise

def get_lengths() -> np.ndarray:
    return np.array((17, 9, 12, 6, 14))

def get_theta() -> smp.Matrix:
    theta2, theta5 = smp.symbols('theta2,theta5', real=True)
    return smp.pi/180 * smp.Matrix((
        (15, theta2,  30, 100, theta5),
        (15, theta2, 195, 200, theta5),
        (15, theta2, 330, 300, theta5),
    ))

def get_position_vectors(L: np.ndarray, theta: smp.Matrix) -> tuple[smp.Matrix, smp.Matrix]:
    def get_R(fun: Callable) -> smp.Matrix:
        return matrix_multiply_elementwise(
            theta.applyfunc(fun), L_tall
        )

    L_tall = smp.Matrix(np.broadcast_to(L, theta.shape))
    return get_R(smp.cos), get_R(smp.sin)

def get_loop_equations(Ri: smp.Matrix, Rj: smp.Matrix) -> smp.Matrix:
    factors = smp.Matrix((-1, 1, 1, 1, -1))
    lhs = smp.Matrix((
        (Ri*factors).T,
        (Rj*factors).T,
    ))
    return lhs.T

def print_solutions(solutions: list[list[dict[smp.Symbol, float]]]) -> None:
    for i, row in enumerate(solutions, start=1):
        print(f'Problem {i}:')
        if row:
            for solution in row:
                print('  ' + ', '.join(
                    f'{smp.pretty(v)}={val:6.1f}°'
                    for v, val in solution.items()
                ))
        else:
            print('  No solution')

def main() -> None:
    smp.init_printing()

    L = get_lengths()
    theta = get_theta()
    Ri, Rj = get_position_vectors(L, theta)
    lhs = get_loop_equations(Ri, Rj)

    print('Equations necessary to perform position analysis:')
    print('lhs_i =')
    smp.pprint(lhs[:, 0])
    print('lhs_j =')
    smp.pprint(lhs[:, 1])

    solutions = []

    for i in range(lhs.shape[0]):
        # Without floating-point evaluation, solve() is extremely slow
        lhs_row = lhs[i, :].evalf()
        solution = smp.solve(lhs_row, lhs_row.free_symbols, dict=True)
        solutions.append(solution)

    print_solutions(solutions)

if __name__ == '__main__':
    main()

个字符

指数形式

这个问题可以很好地表示为对单个指数形式的复表达式的求根,并且从前面的方法中相当简化了很多矩阵数学:

import numpy as np
import sympy as smp
from sympy.matrices.dense import matrix_multiply_elementwise

def get_lengths() -> np.ndarray:
    return np.array((17, 9, 12, 6, 14))

def get_theta() -> smp.Matrix:
    theta2, theta5 = smp.symbols('theta2,theta5', real=True)
    return smp.pi/180 * smp.Matrix((
        (15, theta2,  30, 100, theta5),
        (15, theta2, 195, 200, theta5),
        (15, theta2, 330, 300, theta5),
    ))

def get_position_vectors(L: np.ndarray, theta: smp.Matrix) -> smp.Matrix:
    from sympy import I

    def eI(x: smp.Expr) -> smp.Expr:
        return smp.exp(I*x)

    L_tall = smp.Matrix(np.broadcast_to(L, theta.shape))
    return matrix_multiply_elementwise(L_tall, theta.applyfunc(eI))

def get_loop_equations(R: smp.Matrix) -> smp.Matrix:
    return R * smp.Matrix((-1, 1, 1, 1, -1))

def print_solutions(solutions: list[list[dict[smp.Symbol, float]]]) -> None:
    for i, row in enumerate(solutions, start=1):
        print(f'Problem {i}:')
        if row:
            for solution in row:
                print('  ' + ', '.join(
                    f'{smp.pretty(v)}={val:6.1f}°'
                    for v, val in solution.items()
                ))
        else:
            print('  No solution')

def main() -> None:
    smp.init_printing()

    L = get_lengths()
    theta = get_theta()
    R = get_position_vectors(L, theta)
    lhs = get_loop_equations(R)

    print('Equations necessary to perform position analysis:')
    print('lhs =')
    smp.pprint(lhs)

    solutions = []
    for lhs_row in lhs:
        # Without floating-point evaluation, solve() is extremely slow
        solution = smp.solve(lhs_row.evalf(), lhs_row.free_symbols, dict=True)
        solutions.append(solution)

    print_solutions(solutions)

if __name__ == '__main__':
    main()
Equations necessary to perform position analysis:
lhs =
⎡      ⅈ⋅π⋅θ₂       ⅈ⋅π⋅θ₅       ⅈ⋅π      5⋅ⅈ⋅π       ⅈ⋅π    ⎤
⎢      ──────       ──────       ───      ─────       ───    ⎥
⎢       180          180          12        9          6     ⎥
⎢   9⋅ℯ       - 14⋅ℯ       - 17⋅ℯ    + 6⋅ℯ      + 12⋅ℯ       ⎥
⎢                                                            ⎥
⎢   ⅈ⋅π⋅θ₂       ⅈ⋅π⋅θ₅       ⅈ⋅π       -11⋅ⅈ⋅π       -8⋅ⅈ⋅π ⎥
⎢   ──────       ──────       ───       ────────      ───────⎥
⎢    180          180          12          12            9   ⎥
⎢9⋅ℯ       - 14⋅ℯ       - 17⋅ℯ    + 12⋅ℯ         + 6⋅ℯ       ⎥
⎢                                                            ⎥
⎢     ⅈ⋅π⋅θ₂       ⅈ⋅π⋅θ₅       -ⅈ⋅π       -ⅈ⋅π        ⅈ⋅π   ⎥
⎢     ──────       ──────       ─────      ─────       ───   ⎥
⎢      180          180           6          3          12   ⎥
⎣  9⋅ℯ       - 14⋅ℯ       + 12⋅ℯ      + 6⋅ℯ      - 17⋅ℯ      ⎦
Problem 1:
  θ₂=  45.9°, θ₅=  93.3°
  θ₂= 220.6°, θ₅= 173.2°
Problem 2:
  No solution
Problem 3:
  θ₂=  17.7°, θ₅= -66.7°
  θ₂= 140.3°, θ₅=-135.3°

的字符串

相关问题