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

The*_*MAN 6 haskell

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

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

这取决于2个变量.

我试过这个,用一种天真的方法:

polar :: Double -> Double -> ((Double,Double) :~> (Double,Double))
polar r phi = \(r,phi) ->  (((idD) r)*cos( idD phi),((idD) r)*sin( idD phi))
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

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))
Run Code Online (Sandbox Code Playgroud)

对于一个组件

polarx :: Double -> Double -> ((Double,Double) :~> Double)
polarx r phi = \(r,phi) ->  ((idD) r)*cos( idD phi)
Run Code Online (Sandbox Code Playgroud)

我明白了

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)'
Run Code Online (Sandbox Code Playgroud)

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

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

The*_*MAN 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))
Run Code Online (Sandbox Code Playgroud)

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

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

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
Run Code Online (Sandbox Code Playgroud)

哪里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))
Run Code Online (Sandbox Code Playgroud)

rad是一个便利函数

rad :: Double -> Double
rad = (pi*) . (*recip 180)
Run Code Online (Sandbox Code Playgroud)

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

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