多元函数的导数和带向量空间包的对应雅可比行列式

时间:2012-02-24 09:42:28

标签: haskell

我再次遇到vector-space包的问题。我在最近的post收到了@mnish的一个非常有用的答案,但在那里我只处理了一个仅依赖于1个变量的函数。 例如,当我有一个从极坐标映射到笛卡儿的函数时会发生什么

f:(0,oo) x [0,2pi] -> R²
(r,phi) -> (r*cos(phi),r*sin(phi))

取决于2个变量。

我尝试过这种方式,采用了一种天真的方法:

polar :: Double -> Double -> ((Double,Double) :~> (Double,Double))
polar r phi = \(r,phi) ->  (((idD) r)*cos( idD phi),((idD) r)*sin( idD phi))

我收到以下错误:

Couldn't match expected type `(Double, Double) :> (Double, Double)'
            with actual type `(t0, t1)'
In the expression:
  (((idD) r) * cos (idD phi), ((idD) r) * sin (idD phi))
In the expression:
  \ (r, phi)
    -> (((idD) r) * cos (idD phi), ((idD) r) * sin (idD phi))
In an equation for `polar':
    polar r phi
      = \ (r, phi)
          -> (((idD) r) * cos (idD phi), ((idD) r) * sin (idD phi))

对于一个组件

polarx :: Double -> Double -> ((Double,Double) :~> Double)
polarx r phi = \(r,phi) ->  ((idD) r)*cos( idD phi)

我得到了

Couldn't match expected type `Double'
            with actual type `(Double, Double)'
Expected type: (Double, Double) :> Double
  Actual type: (Double, Double) :> (Double, Double)
In the return type of a call of `idD'
In the first argument of `(*)', namely `((idD) r)'

显然存在一些类型障碍,但我无法弄清楚出了什么问题。

当我想计算这种映射的雅可比行列时,又出现了另一个问题。顾名思义,它与线性地图有关,当然,它是由包覆盖的,实际上它是基于这些地图。但同样,我的Haskell知识是不够的,我自己得出一个解决方案。

2 个答案:

答案 0 :(得分:2)

我终于找到了解决问题的方法,并不是那么难,但我花了一段时间才弄明白。如果有其他人感兴趣,我会提供详细信息。

首先是我的极地案例代码:

polarCoordD :: ((Double,Double) :~> (Double,Double))
polarCoordD = \(r,phi) ->  pairD (polarx (r,phi), polary (r,phi))
where polarx :: (Double,Double) :~> Double
      polarx = \(r,phi) -> (fst . unpairD $ (idD) (r,phi))*cos( snd . unpairD $ idD (r, phi))
      polary :: (Double,Double) :~> Double
      polary = \(r,phi) -> (fst . unpairD $ (idD) (r,phi))*sin( snd . unpairD $ idD (r, phi))

关键是让“派生变量”(idD)知道元组(r, phi),它包含我想要区分的两个变量。然后我必须通过unpairD解压缩元组并选择结果对的第一部分和第二部分(在polarxpolary中)。两者都被打包成一对。也许有更优雅的方式来做到这一点,但这就是我最终理解它的方式。

从这里开始,不难进入圆柱坐标,或者实际上是任何其他弯曲的正交坐标系。 对于圆柱坐标,我得到:

cylCoordD :: (Vec3 Double :~> Vec3 Double)
cylCoordD = \(r,phi,z) ->  tripleD (cylx (r,phi,z), cyly (r,phi,z),cylz (0,0,z))
where cylx :: (Double,Double,Double) :~> Double
      cylx = \(r,phi,z) -> (fst' . untripleD $ (idD) (r,phi,z))*cos( snd' . untripleD $ idD (r, phi,z))
      cyly :: (Double,Double,Double) :~> Double
      cyly = \(r,phi,z) -> (fst' . untripleD $ (idD) (r,phi,z))*sin( snd' . untripleD $ idD (r, phi,z))
      cylz :: (Double,Double,Double) :~> Double
      cylz = \(_,_,z) -> third . untripleD $ idD (0,0,z)
      fst' :: (a,b,c) -> a
      fst' (x,_,_) = x
      snd' :: (a,b,c) -> b
      snd' (_,y,_) = y
      third :: (a,b,c) -> c
      third (_,_,z) = z

其中Vec3 Double属于type Vec3 a = (a, a, a)。 现在我们甚至可以构建转换矩阵:

let transmat = \(r,phi,z) -> powVal $ liftD3 (,,) (normalized $ derivAtBasis (cylCoordD (r,phi,z)) (Left ())) (normalized $ derivAtBasis (cylCoordD (r,phi,z)) (Right (Left ()))) (normalized $ derivAtBasis (cylCoordD (r,phi,z)) (Right (Right ())))

*Main> transmat (2, rad 0, 0)
((1.0,0.0,0.0),(0.0,1.0,0.0),(0.0,0.0,1.0))

*Main> transmat (2, rad 90, 0)
((6.123233995736766e-17,1.0,0.0),(-1.0,6.123233995736766e-17,0.0),(0.0,0.0,1.0))

rad是便利功能

rad :: Double -> Double
rad = (pi*) . (*recip 180)

现在将这个“矩阵”转换为Numeric Prelude和/或hmatrix的矩阵类型会很有趣,但我不确定这是否有用。但是,它仍然是使用vector-space -package的一个很好的例子。

我仍然需要弄清楚线性地图的用途,特别是应用。

答案 1 :(得分:0)

刚看到这个后续问题。我不确定你想要什么:

  • 雅可比矩阵
  • 雅可比矢量产品
  • Jacobian-transpose-vector product

在这样一个低维系统中,我会假设第一个。 (其他人派上用场时主要是当系统具有足够的高维度而你不想存储或计算雅可比本身时,而是将其视为广义稀疏矩阵。)无论如何:

Prelude> :m + Numeric.AD
Prelude Numeric.AD> let f [r,phi] = map (r*) [cos phi, sin phi]
Prelude Numeric.AD> jacobian f [2,3::Float]
[[-0.9899925,-0.28224],[0.14112,-1.979985]]