|
|
|
|
@ -1,301 +0,0 @@
|
|
|
|
|
from sympy import *
|
|
|
|
|
import itertools
|
|
|
|
|
x,y,z = symbols('x y z')
|
|
|
|
|
#累次极限:f为函数; var_points为字典,其中key为变量,value为变量趋近值
|
|
|
|
|
def repeated_limit(f, var_points, direction='+'):
|
|
|
|
|
if not isinstance(var_points, dict):
|
|
|
|
|
return "错误:var_points 必须是字典,例如 {x: 0, y: 0}"
|
|
|
|
|
if not all(isinstance(var, Symbol) for var in var_points.keys()):
|
|
|
|
|
return "错误:字典的键必须是 SymPy 符号变量,例如 x, y, z"
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
for var, point in var_points.items():
|
|
|
|
|
limitation = limit(f,var,point, dir=direction)
|
|
|
|
|
if f in (zoo, nan) or f.has(zoo, nan):
|
|
|
|
|
raise ValueError("极限不存在")
|
|
|
|
|
f = limitation
|
|
|
|
|
return f
|
|
|
|
|
|
|
|
|
|
except TypeError as e:
|
|
|
|
|
return f"类型错误:{str(e)}。请检查函数表达式和极限点是否为有效数学表达式"
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
return f"值错误:{str(e)}。请检查极限点是否有效"
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return f"计算极限时出错:{str(e)}。请检查输入格式是否正确"
|
|
|
|
|
|
|
|
|
|
#重极限:f为函数; var_points为字典,其中key为变量,value为变量趋近值
|
|
|
|
|
def mult_limit(f, var_points):
|
|
|
|
|
vars = list(var_points.keys())
|
|
|
|
|
values = list(var_points.values())
|
|
|
|
|
n = len(vars)
|
|
|
|
|
|
|
|
|
|
if n == 0:
|
|
|
|
|
return f
|
|
|
|
|
if n == 1:
|
|
|
|
|
return limit(f, vars[0], values[0])
|
|
|
|
|
|
|
|
|
|
t = symbols('t')
|
|
|
|
|
paths = []
|
|
|
|
|
|
|
|
|
|
# 基本坐标轴路径 (每个变量单独变化)
|
|
|
|
|
for i in range(n):
|
|
|
|
|
path = {}
|
|
|
|
|
for j, var in enumerate(vars):
|
|
|
|
|
if i == j:
|
|
|
|
|
path[var] = values[j] + t # 当前变量沿t变化
|
|
|
|
|
else:
|
|
|
|
|
path[var] = values[j] # 其他变量固定于趋近值
|
|
|
|
|
paths.append(path)
|
|
|
|
|
|
|
|
|
|
# 对角线路径 (所有变量同时变化)
|
|
|
|
|
path_all_t = {var: values[i] + t for i, var in enumerate(vars)}
|
|
|
|
|
paths.append(path_all_t)
|
|
|
|
|
|
|
|
|
|
# 二次混合路径
|
|
|
|
|
for i in range(n):
|
|
|
|
|
path = {}
|
|
|
|
|
for j, var in enumerate(vars):
|
|
|
|
|
if i == j:
|
|
|
|
|
path[var] = values[j] + t**2 # 当前变量二次变化
|
|
|
|
|
else:
|
|
|
|
|
path[var] = values[j] + t # 其他变量线性变化
|
|
|
|
|
paths.append(path)
|
|
|
|
|
|
|
|
|
|
# 三角函数路径
|
|
|
|
|
trig_funcs = [sin(t), cos(t), tan(t), sinh(t), cosh(t)]
|
|
|
|
|
for func in trig_funcs:
|
|
|
|
|
# 单变量三角函数路径
|
|
|
|
|
for i in range(n):
|
|
|
|
|
path = {var: values[j] for j, var in enumerate(vars)}
|
|
|
|
|
path[vars[i]] = values[i] + func
|
|
|
|
|
paths.append(path)
|
|
|
|
|
|
|
|
|
|
# 双变量三角函数路径
|
|
|
|
|
for i in range(n):
|
|
|
|
|
for j in range(i+1, n):
|
|
|
|
|
path = {var: values[k] for k, var in enumerate(vars)}
|
|
|
|
|
path[vars[i]] = values[i] + func
|
|
|
|
|
path[vars[j]] = values[j] + func
|
|
|
|
|
paths.append(path)
|
|
|
|
|
|
|
|
|
|
# 计算所有路径极限
|
|
|
|
|
path_limits = []
|
|
|
|
|
for path in paths:
|
|
|
|
|
try:
|
|
|
|
|
expr = f.subs(path)
|
|
|
|
|
lim = limit(expr, t, 0)
|
|
|
|
|
path_limits.append(lim)
|
|
|
|
|
except:
|
|
|
|
|
path_limits.append(None)
|
|
|
|
|
|
|
|
|
|
# 检查路径极限一致性
|
|
|
|
|
valid_limits = [lim for lim in path_limits if lim is not None]
|
|
|
|
|
if not valid_limits:
|
|
|
|
|
return '重极限不存在' # 所有路径极限计算失败
|
|
|
|
|
|
|
|
|
|
if not all(lim == valid_limits[0] for lim in valid_limits):
|
|
|
|
|
return '重极限不存在' # 路径极限不一致
|
|
|
|
|
|
|
|
|
|
# 计算累次极限 (所有顺序)
|
|
|
|
|
iterated_limits = []
|
|
|
|
|
for perm in itertools.permutations(range(n)):
|
|
|
|
|
try:
|
|
|
|
|
current = f
|
|
|
|
|
for idx in perm:
|
|
|
|
|
current = limit(current, vars[idx], values[idx])
|
|
|
|
|
iterated_limits.append(current)
|
|
|
|
|
except:
|
|
|
|
|
iterated_limits.append(None)
|
|
|
|
|
|
|
|
|
|
# 检查累次极限一致性
|
|
|
|
|
valid_iter_limits = [lim for lim in iterated_limits if lim is not None]
|
|
|
|
|
if not valid_iter_limits:
|
|
|
|
|
return '重极限不存在' # 所有累次极限计算失败
|
|
|
|
|
|
|
|
|
|
if not all(lim == valid_iter_limits[0] for lim in valid_iter_limits):
|
|
|
|
|
return '重极限不存在' # 累次极限不一致
|
|
|
|
|
|
|
|
|
|
# 检查路径极限与累次极限一致性
|
|
|
|
|
if valid_limits[0] != valid_iter_limits[0]:
|
|
|
|
|
return '重极限不存在'
|
|
|
|
|
|
|
|
|
|
return valid_limits[0] # 所有检查通过,返回极限值
|
|
|
|
|
|
|
|
|
|
#偏导数:f为函数; var_list为变量及其求导次数的列表
|
|
|
|
|
def partial_derivative(f, var_list):
|
|
|
|
|
if not isinstance(var_list, list):
|
|
|
|
|
raise ValueError("var_list 必须是列表,例如 [('x1', 1), ('y2', 2), ('x3', 1)]")
|
|
|
|
|
|
|
|
|
|
if not all(isinstance(item, tuple) and len(item) == 2 for item in var_list):
|
|
|
|
|
raise ValueError("var_list 中的每个元素必须是长度为2的元组,例如 ('x', 1)")
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
for var_s, n in var_list:
|
|
|
|
|
if not isinstance(var_s, str):
|
|
|
|
|
raise ValueError("变量名必须是字符串")
|
|
|
|
|
if not isinstance(n, int) or n < 0:
|
|
|
|
|
raise ValueError("求导次数必须是非负整数")
|
|
|
|
|
var = symbols(re.sub(r'\d+$', '', var_s)) # 去掉数字并转为符号
|
|
|
|
|
dif = diff(f, var, n)
|
|
|
|
|
f = dif
|
|
|
|
|
return dif
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return f"求导失败: {e}"
|
|
|
|
|
|
|
|
|
|
#全微分:f为函数; vars为变量组成的列表
|
|
|
|
|
def total_differential(f, vars):
|
|
|
|
|
if not isinstance(vars, list):
|
|
|
|
|
raise TypeError("vars 必须是变量列表,例如 [x, y, z]")
|
|
|
|
|
if not all(isinstance(v, (str, Symbol)) for v in vars):
|
|
|
|
|
raise TypeError("vars 中的每个元素必须是字符串或 SymPy 符号")
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
derivs = [0 for i in range(len(vars))]
|
|
|
|
|
|
|
|
|
|
for i in range(len(vars)):
|
|
|
|
|
derivs[i] = partial_derivative(f, [(str(vars[i]),1)])
|
|
|
|
|
diff_symbols = [Symbol(f'd{v}') for v in vars]
|
|
|
|
|
return sum(derivs[i]*diff_symbols[i] for i in range(len(vars)))
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return f"全微分计算失败: {e}"
|
|
|
|
|
|
|
|
|
|
#梯度:f为函数; vars为变量组成的列表
|
|
|
|
|
def grad_vector(f, vars):
|
|
|
|
|
if not isinstance(vars, list):
|
|
|
|
|
raise TypeError("vars 必须是变量列表,例如 [x, y, z]")
|
|
|
|
|
|
|
|
|
|
if not all(isinstance(v, (str, Symbol)) for v in vars):
|
|
|
|
|
raise TypeError("vars 中的每个元素必须是字符串或 SymPy 符号")
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
expr = f
|
|
|
|
|
return Array([diff(expr, v) for v in vars])
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return f"梯度计算失败: {e}"
|
|
|
|
|
|
|
|
|
|
#方向导数:f为函数; vars为变量组成的列表; direction为方向向量
|
|
|
|
|
def direct_derivative(f, vars, direction):
|
|
|
|
|
if not isinstance(vars, list):
|
|
|
|
|
raise TypeError("vars 必须是变量列表,例如 [x, y, z]")
|
|
|
|
|
|
|
|
|
|
if not isinstance(direction, list):
|
|
|
|
|
raise TypeError("direction 必须是列表,例如 [1, 2, 3]")
|
|
|
|
|
|
|
|
|
|
if len(direction) != len(vars):
|
|
|
|
|
raise ValueError("方向向量维度必须与变量数量一致")
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
grad = grad_vector(f, vars)
|
|
|
|
|
directs = 0
|
|
|
|
|
for i in range(len(vars)):
|
|
|
|
|
cos_ = direction[i]/sqrt((sum([i**2 for i in direction]))) #方向余弦
|
|
|
|
|
directs += grad[i]*cos_
|
|
|
|
|
return directs
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return f"方向导数计算失败: {e}"
|
|
|
|
|
|
|
|
|
|
#极值、鞍点
|
|
|
|
|
def extrema(f, vars, domain=None):
|
|
|
|
|
try:
|
|
|
|
|
if domain is None:
|
|
|
|
|
domain = Reals
|
|
|
|
|
|
|
|
|
|
expr = f
|
|
|
|
|
derivs = [diff(expr, v) for v in vars]
|
|
|
|
|
system = [Eq(d, 0) for d in derivs]
|
|
|
|
|
|
|
|
|
|
# 求解临界点
|
|
|
|
|
if len(vars) == 1:
|
|
|
|
|
points = solveset(system[0], vars[0], domain=domain)
|
|
|
|
|
else:
|
|
|
|
|
points = nonlinsolve(system, vars)
|
|
|
|
|
|
|
|
|
|
# 如果解集不是 FiniteSet,直接返回提示
|
|
|
|
|
if not isinstance(points, FiniteSet):
|
|
|
|
|
return f"函数在定义域 {domain} 内有复杂或无限多个临界点:{points}"
|
|
|
|
|
|
|
|
|
|
points = list(points)
|
|
|
|
|
|
|
|
|
|
# 构建黑塞矩阵
|
|
|
|
|
hessian = Matrix([[diff(expr, vi, vj) for vj in vars] for vi in vars])
|
|
|
|
|
|
|
|
|
|
min_p = []
|
|
|
|
|
max_p = []
|
|
|
|
|
sad_p = []
|
|
|
|
|
|
|
|
|
|
for point in points:
|
|
|
|
|
if len(vars) == 1:
|
|
|
|
|
point_dict = {vars[0]: point}
|
|
|
|
|
else:
|
|
|
|
|
point_dict = {vars[i]: point[i] for i in range(len(vars))}
|
|
|
|
|
|
|
|
|
|
# 检查 point_dict 是否包含复杂集合类型
|
|
|
|
|
if any(isinstance(val, (ConditionSet, Intersection, Union, ImageSet)) for val in point_dict.values()):
|
|
|
|
|
continue # 跳过复杂解
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
S = hessian.subs(point_dict)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
continue # 跳过无法代入的点
|
|
|
|
|
|
|
|
|
|
if S.is_positive_definite:
|
|
|
|
|
min_p.append(point_dict)
|
|
|
|
|
elif (-S).is_positive_definite:
|
|
|
|
|
max_p.append(point_dict)
|
|
|
|
|
else:
|
|
|
|
|
sad_p.append(point_dict)
|
|
|
|
|
|
|
|
|
|
return {'临界点': points,
|
|
|
|
|
'极大值点': max_p,
|
|
|
|
|
'极小值点': min_p,
|
|
|
|
|
'鞍点': sad_p}
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return f'计算过程中出错: {str(e)}'
|
|
|
|
|
|
|
|
|
|
#连续性
|
|
|
|
|
def is_continuous(f, var_points):
|
|
|
|
|
limit_value = mult_limit(f, var_points)
|
|
|
|
|
if limit_value == '重极限不存在':
|
|
|
|
|
return False
|
|
|
|
|
func_value = f.subs(var_points)
|
|
|
|
|
return limit_value == func_value
|
|
|
|
|
|
|
|
|
|
#拉格朗日乘数法求条件极值
|
|
|
|
|
#f目标函数; constraints约束条件; vars变量列表
|
|
|
|
|
def lagrange_multiplier(f, constraints, vars):
|
|
|
|
|
if not isinstance(constraints, (list, tuple)):
|
|
|
|
|
return "约束条件必须是一个列表或元组"
|
|
|
|
|
|
|
|
|
|
if not isinstance(vars, (list, tuple)):
|
|
|
|
|
return "变量列表必须是一个列表或元组"
|
|
|
|
|
|
|
|
|
|
if len(constraints) == 0:
|
|
|
|
|
return "至少需要一个约束条件"
|
|
|
|
|
|
|
|
|
|
if len(vars) == 0:
|
|
|
|
|
return "至少需要一个变量"
|
|
|
|
|
try:
|
|
|
|
|
n = len(constraints)
|
|
|
|
|
λ = symbols(f'λ1:{n+1}') #拉格朗日乘子
|
|
|
|
|
L = f
|
|
|
|
|
#构造拉格朗日函数
|
|
|
|
|
for i in range(n):
|
|
|
|
|
L += λ[i] * constraints[i]
|
|
|
|
|
#对所有变量和乘子求偏导
|
|
|
|
|
equations = [diff(L, var) for var in vars] + list(constraints)
|
|
|
|
|
solutions = solve(equations, vars + list(λ), dict=True)
|
|
|
|
|
if not solutions:
|
|
|
|
|
return "方程组无解或无法找到解析解"
|
|
|
|
|
|
|
|
|
|
return solutions
|
|
|
|
|
except TypeError as e:
|
|
|
|
|
return f"类型错误: {str(e)} - 请确保输入的函数和约束是有效的 sympy 表达式"
|
|
|
|
|
|
|
|
|
|
except AttributeError as e:
|
|
|
|
|
return f"属性错误: {str(e)} - 请确保输入的函数和约束包含正确的符号变量"
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
return f"求解过程中发生错误: {str(e)}"
|