首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >部分衍生物

部分衍生物
EN

Stack Overflow用户
提问于 2011-09-05 06:27:21
回答 4查看 6.8K关注 0票数 12

我试图写一个算法来执行N维混合偏导数。我知道我需要实现什么,但是我似乎不能想出实现N维情况所需的正确循环/递归。

以下是前四个维度的模式:

代码语言:javascript
复制
| 1D  wzyx  | 2D           | 3D           | 4D           |
----------------------------------------------------------
| dx (0001) | dx    (0001) | dx    (0001) | dx    (0001) |
|           | dy    (0010) | dy    (0010) | dy    (0010) |
|           | dyx   (0011) | dyx   (0011) | dyx   (0011) |
|           |              | dz    (0100) | dz    (0100) |
|           |              | dzx   (0101) | dzx   (0101) |
|           |              | dzy   (0110) | dzy   (0110) |
|           |              | dzyx  (0111) | dzyx  (0111) |
|           |              |              | dw    (1000) |
|           |              |              | dwx   (1001) |
|           |              |              | dwy   (1010) |
|           |              |              | dwyx  (1011) |
|           |              |              | dwz   (1100) |
|           |              |              | dwzx  (1101) |
|           |              |              | dwzy  (1110) |
|           |              |              | dxyzw (1111) |

每个维的导数数(因为它遵循二进制模式)是(2^dim)-1;例如,2^3 =8-1= 7。

导数dyx是y维数中相邻点的dx值。这对于所有混合的部分都是正确的。因此,dzyx是z维数中相邻点的dyx。我不确定这一段是否与这个问题有关,只是想把它放在这里是为了完整。

欢迎任何帮助指针的建议。黑体部分是我需要意识到的部分。

::编辑::

我将通过提供一个我所需要的例子来尝试更明确一些。这只是一个2D的例子,但它在某种程度上体现了整个过程,我认为。

我需要帮助提出一个算法,它将生成列dx、dy、dyx、et中的值。阿尔。

代码语言:javascript
复制
|  X  |  Y  | f(x, y) |  dx             |  dy       | dyx               |
-------------------------------------------------------------------------
|  0  |  0  |    4    |  (3-4)/2 = -0.5 |  (3-4)/2  | (-0.5 - (-2.0))/2 |
|  1  |  0  |    3    |  (0-4)/2 = -2.0 |  (2-3)/2  | (-2.0 - (-2.0))/2 |
|  2  |  0  |    0    |  (0-3)/2 = -1.5 | (-1-0)/2  | (-1.5 - (-1.5))/2 |
|  0  |  1  |    3    |  (2-3)/2 = -0.5 |  (0-4)/2  | (-0.5 - (-0.5))/2 |
|  1  |  1  |    2    | (-1-3)/2 = -2.0 | (-1-3)/2  | (-1.5 - (-2.0))/2 |
|  2  |  1  |   -1    | (-1-2)/2 = -1.5 | (-4-0)/2  | (-1.5 - (-1.5))/2 |
|  0  |  2  |    0    | (-1-0)/2 = -0.5 |  (0-3)/2  | (-0.5 - (-0.5))/2 |
|  1  |  2  |   -1    | (-4-0)/2 = -2.0 | (-1-2)/2  | (-2.0 - (-2.0))/2 |
|  2  |  2  |   -4    |(-4--1)/2 = -1.5 |(-4--1)/2  | (-1.5 - (-1.5))/2 |

f(x,y)是未知的,只有它的值是已知的;所以解析微分是无用的,它只能是数值。

欢迎任何帮助指针的建议。黑体部分是我需要意识到的部分。

::编辑-再一次::

在这里启动了一个Gist:https://gist.github.com/1195522

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-09-05 18:54:34

如果我对你的理解是正确的,我认为以下几点是可行的:

代码语言:javascript
复制
function partial_dev(point, dimension):
    neighbor_selector = top_bit(dimension)
    value_selector = dimension XOR neighbor_selector
    prev_point = point_before(point,neighbor_selector)
    next_point = pointafter(point,neighbor_selector)
    if value_selector == 0:
        return (f[prev_point] - f[next_point])/2
    else:
        return ( partial_dev(prev_point, value_selector) -
                 partial_dev(next_point, value_selector) )/2

其思想是:维度值的顶部位是选择前后点的坐标。如果维度值的其余部分为0,则使用f值作为偏导数计算的点。如果不是,您将得到由其余位表示的偏导数来计算值。

如果需要计算出的所有维度值的所有值,那么根本不需要递归:只需使用维度选择器作为数组索引,其中每个数组元素包含该维度的全部值集。对数组进行初始化,以便使vals[0][coords] = f(coords)。然后计算vals[1]vals[2],在计算vals[3]时,使用vals[1]作为值表而不是vals[0] (因为3= 0b11,其中邻居选择器是0b10,value_selector是0b01)。

票数 2
EN

Stack Overflow用户

发布于 2011-09-05 19:45:29

这个问题通过函数式程序设计得到了很好的解决。实际上,\partial_{xy}f是\partial_y f沿x的偏导数。

我假设您有一个黑匣子函数(或函数对象) f,将其值作为指向内存缓冲区的指针。它的签名被认为是

代码语言:javascript
复制
double f(double* x);

下面是一个将(二阶有限差分)偏导数转化为f的代码:

代码语言:javascript
复制
template <typename F>
struct partial_derivative
{
    partial_derivative(F f, size_t i) : f(f), index(i) {}

    double operator()(double* x)
    {
        // Please read a book on numerical analysis to tweak this one
        static const double eps = 1e-4;

        double old_xi = x[index];
        x[index] = old_xi + eps;
        double f_plus = f(x);

        // circumvent the fact that a + b - b != a in floating point arithmetic
        volatile actual_eps = x[index];
        x[index] = old_xi - eps;
        actual_2eps -= x[index]
        double f_minus = f(x);

        return (f_plus - f_minus) / actual_2eps;
    }

private:
    F f;
    size_t index;
};

template <typename F>
partial_derivative<F> partial(F f, index i)
{
    return partial_derivative<F>(f, i);
}

现在,要计算\partial_{123}f,您需要:

代码语言:javascript
复制
boost::function<double(double*)> f_123 = partial(partial(partial(f, 0), 1), 2);

如果您需要计算它们,那么:

代码语言:javascript
复制
template <typename F>
boost::function<double(double*)> mixed_derivatives(F f, size_t* i, size_t n_indices)
{
    if (n_indices == 0) return f;
    else return partial(mixed_derivatives(f, i + 1, n_indices - 1), i[0]);
}

所以你可以:

代码语言:javascript
复制
size_t indices[] = { 0, 1, 2 };
boost::function<double(double*)> df_123 
    = mixed_derivatives(f, indices, sizeof(indices) / sizeof(size_t));
票数 4
EN

Stack Overflow用户

发布于 2011-09-05 07:39:55

显然,您可以根据维度(二进制位置的数量)进行循环,然后再递归到下一个二进制数字。

粗糙(非C++)伪码:

代码语言:javascript
复制
Function partialcalc(leadingdigit, dimension)

  If dimension > 1 {
    For i = 1 to dimension {
      //do stuff with these two calls
      partialcalc(0, i - 1)
      partialcalc(1, i - 1)
    }
  }
  Else {
    //partialcalc = 1D case
  }

return partialcalc

End Function

递归的工作方式是,您有一个问题,它可以分解为子问题,相当于较大的问题,只是较小的问题。因为你用了所有的二进制数字来表示维数,所以你只需要在最上面的维数上进行计算,根据维数中的0和1值递归到两个子问题。递归的底部是维度=1级别。由于您强调只需要知道如何构造循环递归,并且已经解决了数学问题,这个结构应该适用于您。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7304511

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档