You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python使用Sympy解析含不等式的方程时遇语法与索引错误的求助

错误原因分析与解决方法

一、错误原因拆解

1. SyntaxError 根源

当处理形如X1 + X2 - 4 == 0的等式时,原代码错误地用Eq(parse_expr(parsed_eq), 0)构造方程。parse_expr(parsed_eq)会直接将==解析为SymPy的Eq对象,再套一层Eq(..., 0)会生成无效表达式结构,导致eval执行时出现表达式=0的语法错误。

若手动将等式中的=替换为==但未修正分离逻辑,会进一步导致后续代码处理混乱。

2. IndexError 根源

该错误由solve()返回空列表后直接用[0]取索引引发,常见场景:

  • 错误将已为Eq的约束再套Eq(constraint, 0),生成无解的方程(如(a==b) ==0);
  • 等式与不等式的分离逻辑错误,将等式混入linear_constraints列表,后续用错误方式求解。

二、针对性解决方法

1. 修正等式与不等式的分离逻辑

利用SymPy自带的类型判断,直接解析表达式后区分约束类型:

# 替换原分离逻辑
for equation in sel:
    parsed_eq = equation.replace('X1', 'x1').replace('X2', 'x2')
    expr = parse_expr(parsed_eq)
    if isinstance(expr, Relational):
        if expr.rel_op in ('>=', '<='):
            linear_constraints.append(expr)
        elif expr.rel_op == '==':
            equations.append(expr)
    else:
        # 处理无关系运算符的表达式,默认视为等于0
        equations.append(Eq(expr, 0))

2. 修正约束求解逻辑

对不等式约束,直接取左右两边相减构造方程求解,避免额外嵌套Eq:

# 替换原linear_constraints处理循环
for constraint in linear_constraints:
    eq = Eq(constraint.lhs - constraint.rhs, 0)
    # 求解与y轴交点
    try:
        r_x2 = solve(eq, x2)[0]
        intersections.append((0, r_x2.subs(x1, 0)))
    except IndexError:
        pass
    # 求解与x轴交点
    try:
        r_x1 = solve(eq, x1)[0]
        intersections.append((r_x1.subs(x2, 0), 0))
    except IndexError:
        pass

3. 修正等式的求解逻辑

针对二元一次方程的参数化解,补充与其他约束的交点计算(生成有效顶点):

# 替换原equations处理循环
for eq in equations:
    # 计算与坐标轴交点
    try:
        intersections.append((0, solve(eq, x2)[0].subs(x1, 0)))
    except IndexError:
        pass
    try:
        intersections.append((solve(eq, x1)[0].subs(x2, 0), 0))
    except IndexError:
        pass
    
    # 计算等式与其他约束的交点(生成顶点)
    for constraint in linear_constraints:
        constraint_eq = Eq(constraint.lhs - constraint.rhs, 0)
        solution = solve((eq, constraint_eq), (x1, x2))
        if solution:
            intersections.append((solution[x1], solution[x2]))

4. 修正绘图逻辑中的符号判断

取消错误的字符串拆分,直接通过表达式类型获取关系运算符:

# 替换原绘图循环
for equation in sel:
    parsed_eq = equation.replace('X1', 'x1').replace('X2', 'x2')
    expr = parse_expr(parsed_eq)
    
    # 统一构造绘图用等式
    eq = Eq(expr.lhs - expr.rhs, 0) if isinstance(expr, Relational) else Eq(expr, 0)
    
    # 绘制直线(兼容垂直于x轴的情况)
    try:
        r = solve(eq, x2)[0]
        linear_constraint = lambdify(x1, r, 'numpy')
        plt.plot(x, linear_constraint(x), label=equation)
    except IndexError:
        plt.axvline(x=float(solve(eq, x1)[0].evalf()), label=equation)

5. 完整修正后的代码

import matplotlib.pyplot as plt
import numpy as np
from sympy import symbols, Eq, solve, lambdify, parse_expr
from sympy.core.relational import Relational

# 定义符号变量
x1, x2 = symbols('x1 x2')

# 约束列表
sel = ["2 * X1 + 1 * X2 >= 2", "3 * X1 + 4 * X2 <= 12", "4 * X1 + 3 * X2 <= 12", "X1 + X2 - 4 == 0"]

linear_constraints = []
equations = []

# 分离不等式与等式
for equation in sel:
    parsed_eq = equation.replace('X1', 'x1').replace('X2', 'x2')
    expr = parse_expr(parsed_eq)
    if isinstance(expr, Relational):
        if expr.rel_op in ('>=', '<='):
            linear_constraints.append(expr)
        elif expr.rel_op == '==':
            equations.append(expr)
    else:
        equations.append(Eq(expr, 0))

# x轴取值范围
x = np.linspace(-10, 10, 100)

intersections = []

# 处理不等式,计算与坐标轴交点
for constraint in linear_constraints:
    eq = Eq(constraint.lhs - constraint.rhs, 0)
    try:
        intersections.append((0, solve(eq, x2)[0].subs(x1, 0)))
    except IndexError:
        pass
    try:
        intersections.append((solve(eq, x1)[0].subs(x2, 0), 0))
    except IndexError:
        pass

# 处理等式,计算与坐标轴及其他约束的交点
for eq in equations:
    try:
        intersections.append((0, solve(eq, x2)[0].subs(x1, 0)))
    except IndexError:
        pass
    try:
        intersections.append((solve(eq, x1)[0].subs(x2, 0), 0))
    except IndexError:
        pass
    
    for constraint in linear_constraints:
        constraint_eq = Eq(constraint.lhs - constraint.rhs, 0)
        solution = solve((eq, constraint_eq), (x1, x2))
        if solution:
            intersections.append((solution[x1], solution[x2]))

# 筛选第一象限的顶点并去重
vertices = []
seen = set()
for point in intersections:
    px = float(point[0].evalf()) if hasattr(point[0], 'evalf') else float(point[0])
    py = float(point[1].evalf()) if hasattr(point[1], 'evalf') else float(point[1])
    if px >= 0 and py >= 0 and (px, py) not in seen:
        seen.add((px, py))
        vertices.append((px, py))

# 打印顶点
for i, vertex in enumerate(vertices):
    print(f"Vertex {i+1}: ({vertex[0]:.2f}, {vertex[1]:.2f})")

# 绘制顶点
x_coords = [v[0] for v in vertices]
y_coords = [v[1] for v in vertices]
plt.plot(x_coords, y_coords, 'ro')

# 绘制约束直线
for equation in sel:
    parsed_eq = equation.replace('X1', 'x1').replace('X2', 'x2')
    expr = parse_expr(parsed_eq)
    
    eq = Eq(expr.lhs - expr.rhs, 0) if isinstance(expr, Relational) else Eq(expr, 0)
    
    try:
        r = solve(eq, x2)[0]
        linear_constraint = lambdify(x1, r, 'numpy')
        plt.plot(x, linear_constraint(x), label=equation)
    except IndexError:
        plt.axvline(x=float(solve(eq, x1)[0].evalf()), label=equation)

# 调整绘图范围
plt.xlim(-2, 6)
plt.ylim(-2, 6)

plt.legend()
plt.xlabel('x1')
plt.ylabel('x2')
plt.xticks(np.arange(-2, 7, 1))
plt.yticks(np.arange(-2, 7, 1))
plt.title('Constraint Graph')
plt.axhline(0, color='black', linewidth=0.5)
plt.axvline(0, color='black', linewidth=0.5)
plt.grid(True, linestyle='--', alpha=0.7)

plt.show()

内容的提问来源于stack exchange,提问作者Elektvocal95

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 10:52:01