【问题标题】:Calculate the value range of a math formula with given bounds计算具有给定边界的数学公式的值范围
【发布时间】:2020-09-15 16:43:27
【问题描述】:

美好的一天!

我正在使用 python v3.8,我想用(也给定的)边界计算给定公式的值范围(最小值和最大值),例如:

formula1: a * sqrt(b/c)

formula2: a^2 * b/1000 + 3 * (a+b)

formula3: (1/(2 * PI * (a * 1000) * (b * 1000)) * 10^12

..with a=[0,5], b=[10,20], c=[30,40]

我对 scipy、numpy、sympy 不太熟悉。我想知道是否有一种“简单”的方法来计算具有不同值的公式,将其写入数组并从中获取最小值/最大值?我在“写入数组并获得最小值/最大值”时遇到的问题是,给定的浮点数存在一些界限 [-100000, 100000],这会产生太多的值。

我不需要达到最小值/最大值的信息,而只需要可以达到的最小值/最大值。

【问题讨论】:

  • 有方法吗?是的。
  • 创建一个包含 3 列的矩阵,其中包含您要评估的 a、b 和 c 的值,然后使用其中一个公式创建第四列。计算最大值和最小值应该很简单。
  • @Adirio 是的,现在我正在使用这种“求解器”。 Numpy 为浮点数提供了一个函数/for-loop,这非常有帮助。不幸的是,这一切都取决于变量迭代的“步骤”。在一种情况下,我给出了一个从 0.1 到 2 的范围,我选择了 0.1 的步长范围,我得到了 ~3600 的结果。步长为 0.01 时,结果约为 3900 .. 对于第一次粗略估计,我猜它是“好的”。谢谢
  • 是的,这一步会影响您的结果,因为您基本上是在离散世界中使用连续公式。想象一下最大值是a = 1.324567。如果您获得0.1 的步长,您的本地最大值可能是a = 1.3,但这不是真正的最大值。如果您将步长减小到 0.01,则您的 loxal 最大值将位于 a = 1.32,其值将不同于 a = 1.3。如果你想准确,你将不得不计算偏导数。

标签: python


【解决方案1】:

试试SymPy 求解器,他们有可以执行以下操作的求解集:

>>> solveset(Eq(x**2, 1), x)
{-1, 1}

【讨论】:

  • sympy.solveset 解方程,但他没有发布任何方程。
【解决方案2】:

象征性:

最大和最小点称为临界点。要找到一个临界点,您需要对每个变量(f'_a = df/daf'_b = df/dbf'_c = df/dc)进行偏导,并求解所有变量都等于 0 的方程组。我们可以使用 @987654324 来做到这一点@。

import sympy as sp

a = sp.Symbol('a', real=True)
b = sp.Symbol('b', real=True)
c = sp.Symbol('c', real=True)

functions = [
    a * sp.sqrt(b / c),
    a**2 * b/1000 + 3*(a+b),
    10**6 / (2 * sp.pi * a * b),
]

for f in functions:
    f_a, f_b, f_c = f.diff(a), f.diff(b), f.diff(c)
    print(f"f(a, b, c) = {f}")
    print(f"f'_a(a, b, c) = {f_a} = 0")
    print(f"f'_b(a, b, c) = {f_b} = 0")
    print(f"f'_c(a, b, c) = {f_c} = 0")
    print("Critical points:", sp.solve([f_a, f_b, f_c], a, b, c))
    print()

如您所见,如果执行此代码,则没有临界点,因此实域中的任何这些函数都没有绝对最大值或最小值(虚域中的第二个方程有两个临界点) .

数值方法:

使用numpypandas,我们可以创建一个包含所有可能组合的矩阵,然后应用我们的每个函数。最大值和最小值是每列的,它们在列之间不相关。正如预期的那样,a、b 和 c 列的最大值和最小值是范围的下限和上限。

import pandas as pd
from pandas.core.reshape.util import cartesian_product
import numpy as np


# Number of values per range
N = 21

# Functions
functions = [
    lambda row: row['a'] * np.sqrt(row['b'] / row['c']),
    lambda row: row['a']**2 * row['b']/1000 + 3*(row['a']+row['b']),
    lambda row: 10**6 / (2 * np.pi * row['a'] * row['b']),
]

# Lower and upper bounds
a_lower, a_upper = 0, 5
b_lower, b_upper = 10, 20
c_lower, c_upper = 30, 40


def min_max(col):
    return pd.Series(index=['min', 'max'], data=[col.min(), col.max()])


values = [
    np.linspace(a_lower, a_upper, N),
    np.linspace(b_lower, b_upper, N),
    np.linspace(c_lower, c_upper, N),
]

df = pd.DataFrame(cartesian_product(values), index=['a', 'b', 'c']).T
for i, f in enumerate(functions):
    df[f'f_{i + 1}'] = df.apply(f, axis=1)
print(df.apply(min_max))

输出:

       a     b     c       f_1   f_2          f_3
min  0.0  10.0  30.0  0.000000  30.0  1591.549431
max  5.0  20.0  40.0  4.082483  75.5          inf

N = 101 具有完全相同的输出(它需要一些处理,因为它必须计算公式 101^3 > 1M 次)

【讨论】:

  • 哇!非常感谢阿迪里奥。这比我之前的尝试好得多。这也让我有机会阅读 String-formula 并将它们转换为 numpy-formula 来计算不仅仅是“在 python 中预先构建”的公式。并且很容易也可以添加更多变量和跨度。好的!我为此使用了 eval() 函数(我知道 eval() 的安全问题)。我搜索了 eval() 的用法,发现评论“numpy.eval() 应该比纯 eval() 函数更好”,但我看不到 numpy.eval() 的优点
猜你喜欢
  • 2013-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多