我想向下面给出的代码添加一个参数,来自这个线程。
import Numeric.GSL.ODE
import Numeric.LinearAlgebra
import Numeric.AD
vanderpol :: Vector Double -- ^ Time points
-> [Vector Double]
vanderpol ts = toColumns $
odeSolveV (BSimp $ \t -> fromLists . jac t . toList)
0.1 1e-8 1e-8
(\t -> fromList . xdot t . toList)
(fromList [0.5,0]) ts
where xdot :: Num a => a -> [a] -> [a]
xdot t [x,v] = [v, -x*(1-x^2)]
jac :: Double -> [Double] -> [[Double]]
jac t = jacobian (xdot $ realToFrac t)
但是,我似乎不知道该怎么做。我的想法是这样的,我们将
mu
传递给 xdot
,我认为这会导致需要将 mu
传递给 jac
。
import Numeric.GSL.ODE
import Numeric.LinearAlgebra
import Numeric.AD
vanderpol :: Vector Double -- ^ Time points
-> [Vector Double]
vanderpol ts = toColumns $
odeSolveV (BSimp $ \t -> fromLists . jac t mu . toList)
0.1 1e-8 1e-8
(\t -> fromList . xdot t mu . toList)
(fromList [0.5,0]) ts
where xdot :: Num a => a -> [a] -> [a]
xdot t mu [x,v] = [v, -x*mu*(1-x^2)]
jac :: Double -> [Double] -> [[Double]]
jac t = jacobian (xdot $ realToFrac t mu)
mu = 2 :: Double
如何编辑此代码以便将
Double
或 (Double, Double)
传递给 xdot
?这需要编辑jac
吗?
根据 @leftroundabout 的评论,您不需要将
mu
设置为 xdot
或 jac
的参数,但在这里获取类型很棘手。如果你想将 mu
作为参数传递给 vanderpol
,秘密是 mu
需要有一个足够通用的类型,它可以用作 Double
(如 xdot
中所要求的) odeSolveV
的第五个参数,作为 ReverseDouble s
,ad
包 jacobian
函数所需的奇怪类型。
将其定义为一般多态类型是不够的:
vanderpol :: Num a => a -- Not polymorphic enough!
-> Vector Double
-> [Vector Double]
vanderpol mu ts = ...
因为
vanderpol
的特定使用需要将 mu
专门化为特定的数字类型 a
,它可以是 Double
或 ReverseDouble s
,但不能同时是两者。相反,您需要更高级别的类型:
vanderpol :: (forall a. (Num a) => a) -- rank 2 type
-> Vector Double
-> [Vector Double]
vanderpol mu ts = ...
然后就可以了。
出现以下内容则键入 check OK。请注意,
mu
仅作为vanderpol
的参数出现,并在xdot
内使用,就像普通的mu
参数一样:
{-# LANGUAGE RankNTypes #-}
import Numeric.GSL.ODE
import Numeric.LinearAlgebra
import Numeric.AD.Mode.Reverse.Double
vanderpol :: (forall a. (Num a) => a)
-> Vector Double -- ^ Time points
-> [Vector Double]
vanderpol mu ts = toColumns $
odeSolveV (BSimp $ \t -> fromLists . jac t . toList)
0.1 1e-8 1e-8
(\t -> fromList . xdot t . toList)
(fromList [0.5,0]) ts
where xdot t [x,v] = [v, -x*mu*(1-x^2)]
jac t = jacobian (xdot t)
当你实际使用
vanderpol
时,你必须确保它的第一个参数“足够通用”。所以这有效:
main = print $ vanderpol 2 (fromList [1,2,3])
但这不是:
main = do
mu <- readLn
print $ vanderpol mu (fromList [1,2,3])
因为你不能
readLn
使用未指定类型的系数。
无论如何,看看您能做到什么程度,如果您在特定用例中设置
mu
时遇到困难,请发布后续问题。