如何在SymPy中创建带区间的分段函数?解决逻辑与运算无法使用问题
SymPy分段函数创建问题:逻辑与运算符替代方案
我需要在区间内创建分段函数,但SymPy的Piecewise不支持逻辑与(&)运算符。知道它不能接收布尔值后,我尝试用条件相加的方式,但结果不对。相关代码如下:
import numpy as np import sympy as sp import matplotlib as plt # This is all the library's i need import mpmath n = 10 x = sp.symbols('x', positive=True) c = list(sp.symbols('c0:%d'%(n + 1))) f = 1+(((sp.exp(x) * (1 - np.exp(-1))) + (sp.exp(-x)) * (np.exp(1) - 1)) / (np.exp(-1) - np.exp(1))) xx = np.linspace(0, 1, n + 1) i = 0 N = [] a = sp.Piecewise( (0, x < float(xx[i])), (((xx[i + 1] - x) / (xx[i + 1] - xx[i])), (x >= float((xx[i])))), ((xx[i + 1] - x) / (xx[i + 1] - xx[i]), x <= float((xx[i + 1]))), (0, x > float(xx[i + 1])), ) N.append(a) for i in range(1, n): a = sp.Piecewise( (0, x < float(xx[i - 1])), ((xx[i - 1] - x) / xx[i - 1] - xx[i], x >= float((xx[i - 1]))), ((xx[i - 1] - x) / (xx[i - 1] - xx[i]), x <= float(xx[i])), (0, x > float(xx[i])), ) b = sp.Piecewise( (0, x < float(xx[i])), ((xx[i + 1] - x) / (xx[i + 1] - xx[i]), x >= float(xx[i])), ((xx[i + 1] - x) / (xx[i + 1] - xx[i]), x <= float(xx[i + 1])), (0, x > float(xx[i + 1])), ) N.append(a + b) i = i + 1 a = sp.Piecewise( (0, x < float(xx[i - 1])), ((xx[i - 1] - x) / (xx[i - 1] - xx[i]), x >= float((xx[i - 1]))), ((xx[i - 1] - x) / (xx[i - 1] - xx[i]), x <= float(xx[i])), (0, x > float(xx[i])), ) N.append(a)
问题根源
- SymPy的Piecewise不支持Python原生的
&逻辑与运算符,必须用SymPy内置的sp.And()函数合并多条件。 - 原代码把分段条件拆分书写,导致逻辑判断混乱——Piecewise是按顺序匹配第一个满足的条件,拆分的条件会让同一区间多次匹配,结果出错。
- 存在语法错误:中间循环里的
(xx[i - 1] - x) / xx[i - 1] - xx[i]少了括号,实际是先做除法再减xx[i],和预期的分子分母整体除法不符。 - matplotlib导入错误,
import matplotlib as plt无法直接调用绘图接口,应该导入pyplot。 - 混合使用numpy和SymPy的exp函数,容易引发符号与数值计算的冲突。
修正后的代码
import numpy as np import sympy as sp import matplotlib.pyplot as plt import mpmath n = 10 x = sp.symbols('x', positive=True) c = list(sp.symbols('c0:%d'%(n + 1))) # 统一用SymPy的exp函数,避免符号与数值混合问题 f = 1 + ((sp.exp(x) * (1 - sp.exp(-1)) + sp.exp(-x) * (sp.exp(1) - 1)) / (sp.exp(-1) - sp.exp(1))) xx = np.linspace(0, 1, n + 1) N = [] # 第一个基函数:仅在[xx[0], xx[1]]区间生效 a = sp.Piecewise( (0, x < xx[0]), ((xx[1] - x) / (xx[1] - xx[0]), sp.And(x >= xx[0], x <= xx[1])), (0, x > xx[1]) ) N.append(a) # 中间基函数:由左右两个线性段组成的帽形函数 for i in range(1, n): # 左段:[xx[i-1], xx[i]]区间的递增线性函数 left_segment = sp.Piecewise( (0, x < xx[i-1]), ((x - xx[i-1]) / (xx[i] - xx[i-1]), sp.And(x >= xx[i-1], x <= xx[i])), (0, x > xx[i]) ) # 右段:[xx[i], xx[i+1]]区间的递减线性函数 right_segment = sp.Piecewise( (0, x < xx[i]), ((xx[i+1] - x) / (xx[i+1] - xx[i]), sp.And(x >= xx[i], x <= xx[i+1])), (0, x > xx[i+1]) ) N.append(left_segment + right_segment) # 最后一个基函数:仅在[xx[n-1], xx[n]]区间生效 a = sp.Piecewise( (0, x < xx[n-1]), ((x - xx[n-1]) / (xx[n] - xx[n-1]), sp.And(x >= xx[n-1], x <= xx[n])), (0, x > xx[n]) ) N.append(a)
关键修正说明
- 用
sp.And(条件1, 条件2)合并区间判断,这是SymPy中表示“且”逻辑的正确方式,避免布尔值报错。 - 修正了分母的括号问题,确保除法运算的正确性。
- 调整基函数表达式为标准的分段线性帽形函数,左段递增、右段递减,符合区间基函数的定义。
- 统一使用SymPy的
sp.exp处理符号变量,避免与numpy数值函数冲突。 - 修正matplotlib的导入方式,保证后续可以正常绘图。
内容的提问来源于stack exchange,提问作者Or Milo
相关产品推荐
相关产品推荐

