2012-02-24 20 views
6

Tôi đang gặp sự cố với gói vector-space một lần nữa. Tôi đã nhận được một câu trả lời rất hữu ích từ @mnish trong một số post gần đây, nhưng ở đó tôi chỉ xử lý một hàm phụ thuộc vào chỉ 1 biến. gì xảy ra khi tôi có, ví dụ, một chức năng mà bản đồ từ tọa độ cực để cartesiansDẫn xuất của một hàm đa biến và Jacobian tương ứng với gói véc-tơ

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

mà phụ thuộc vào 2 biến.

Tôi đã cố gắng này ra, với một cách tiếp cận khá ngây thơ:

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

tôi nhận được lỗi sau:

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)) 

Đối với một thành phần

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

tôi nhận được

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)' 

Rõ ràng có một số loại rối loạn, nhưng tôi không thể tìm ra những gì là sai.

Một câu hỏi khác nảy sinh, khi tôi muốn tính toán Jacobian của một bản đồ như vậy. Như tên cho thấy, nó có cái gì đó để làm với bản đồ tuyến tính, đó là, tất nhiên, được bao phủ bởi các gói, thực sự nó được dựa trên những bản đồ. Nhưng một lần nữa, kiến ​​thức Haskell của tôi là không đủ, để lấy được một giải pháp của riêng tôi.

+1

Tôi dường như nhớ lại rằng một hạn chế quan trọng của công thức phân biệt tự động rất thanh lịch của Conal là nó chỉ hoạt động trên các dẫn xuất dọc theo một trục đơn. Nếu bạn muốn Jacobians, vv, tôi nghĩ rằng gói quảng cáo của ekmett là con đường để đi: http://hackage.haskell.org/package/ad-1.3.0.1 – sclv

+1

Cảm ơn @sclv, tôi chỉ cần nhìn vào mô-đun này và tôi phải nói, wow, tôi rất ấn tượng. Tôi đã không nhận thấy gói này và tôi sẽ cung cấp cho nó một thử, nhờ cho chỉ này ra – TheMADMAN

+0

Bạn không đơn độc - Tôi đang đấu tranh để hiểu làm thế nào các loại đa chiều được trang bị với nhau. Tôi sẽ đọc bài báo 'Sự khác biệt đẹp' và hy vọng nó làm sáng tỏ một chút - gói quảng cáo trông khá đơn giản hơn một chút về các loại! – Oliver

Trả lời

2

Cuối cùng tôi đã tìm ra giải pháp cho vấn đề của mình, nó không quá khó, nhưng tôi vẫn phải mất một lúc để tìm ra. Trong trường hợp ai khác quan tâm, tôi trình bày chi tiết.

đầu tiên ở đây là mã của tôi đối với trường hợp cực:

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)) 

Mấu chốt là làm cho "biến nguồn gốc" (idD) nhận thức được tuple (r, phi) mà giữ hai biến tôi muốn phân biệt. Sau đó, tôi phải giải nén tuple qua unpairD và chọn phần đầu tiên và phần thứ hai của cặp kết quả (trong polarxpolary). Cả hai được đóng gói lại thành một cặp. Có lẽ có một cách thanh lịch hơn để làm điều này, nhưng đó là cách tôi hiểu nó cuối cùng.

Từ đây không khó để đi xa hơn đến tọa độ hình trụ hoặc trên thực tế, với bất kỳ hệ tọa độ trực giao cong nào khác. Đối với trụ phối tôi có được:

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 

nơi Vec3 Double thuộc về type Vec3 a = (a, a, a). Bây giờ chúng ta thậm chí có thể xây dựng một ma trận chuyển đổi:

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 là một chức năng tiện

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

Bây giờ nó sẽ là thú vị để chuyển đổi này "ma trận" các loại ma trận của Numeric Prelude và/hoặc hmatrix , nhưng tôi không chắc liệu điều này có hữu ích hay không. Nhưng vẫn còn, nó sẽ là một ví dụ tốt đẹp cho việc sử dụng các gói vector-space.

Tôi vẫn phải tìm ra cách sử dụng và đặc biệt là việc áp dụng bản đồ tuyến tính.

0

Chỉ cần nhìn thấy câu hỏi tiếp theo này. Tôi không chắc chắn những gì bạn muốn:

  • ma trận Jacobian
  • một Jacobian-vector sản phẩm
  • một sản phẩm Jacobian-transpose-vector

Trong một hệ thống thấp chiều như vậy, Tôi sẽ giả định đầu tiên. (Những người khác có ích chủ yếu khi hệ thống đủ cao mà bạn không muốn lưu trữ hoặc tính toán Jacobian, nhưng thay vào đó coi nó là ma trận thưa thớt tổng quát.) Trong mọi trường hợp:

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]] 
Các vấn đề liên quan