множественные интегралы и матрицы (сложные элементы) из numeric-prelude

Мне нужно вычислить интегралы вида

/t     /x
| P(x)*| P(y) dydx
/t0    /t0

где P — это функция R -> C^(nxn), обычно матрица, и я хочу сделать это на Haskell. Я добился этого для скалярных функций:

import Numeric.GSL.Integration
import Data.Complex
import Data.List

prec :: Double
prec = 1E-9

integrate :: (Double -> Double) -> Double -> Double -> Double
integrate f a b = fst $ integrateQNG prec f a b 

integrateC :: (Double -> Complex Double) -> Double -> Double -> Complex Double
integrateC cf a b = (integrate (\x -> realPart (cf x)) a b :+ integrate (\x -> imagPart (cf x)) a b)

multipleIntegration :: Int -> (Double -> Complex Double) -> Double -> (Double -> Complex Double)
multipleIntegration n f a =  foldl' (\ acc g' -> (\ x -> integrateC (g'*acc) a x)) (\_ -> 1:+0) (replicate n f)

Это работает до сих пор, хотя и довольно медленно для n>5.

Теперь мне нужно распространить это вычисление на матрицы, я пробовал это с числовой прелюдией, потому что я могу брать функции как элементы матрицы. Я могу интегрировать матрицу Double -> Complex Double, но моя реальная цель умножить матрицу внутри интеграла терпит неудачу, сначала мой код:

import MathObj.Matrix as Mat
import Algebra.Ring as AR
import Control.Applicative
import qualified Prelude as P
import Prelude hiding ((*))
import Number.Complex as NC
import Numeric.GSL.Integration
import Data.List

type Complex a = NC.T a

prec :: Double
prec = 1E-9

testMat :: Mat.T (Double -> Complex Double)
testMat = Mat.fromRows 2 2 [[\x-> 0.5 +: 2*x,\y-> cos y +: sin y],[\x-> 0.1*x +:x,\_-> 1 +: 1]]

integrateC :: (Double -> Complex Double) -> Double -> Double -> Complex Double
integrateC cf a b = (integrate (\x -> real (cf x)) a b +: integrate (\x -> imag (cf x)) a b)

integrate :: (Double -> Double) -> Double -> Double -> Double
integrate f a b = fst $ integrateQNG prec f a b 

integrateCMat' :: Mat.T (Double -> Complex Double) -> Double -> Mat.T (Double -> Complex Double)
integrateCMat' cmf a =  ((\f -> integrateC f a ) <$> cmf)

multipleIntegrationMat :: Int -> Mat.T (Double -> Complex Double) -> Double -> Mat.T (Double -> Complex Double)
multipleIntegrationMat n mf a =  integrateCMat' ( testMat * (integrateCMat' testMat a)) a

Здесь multipleIntegrationMat — это просто функция тестирования, я не использовал фолд, поэтому n лишнее. Сообщение об ошибке:

matmul.hs:27:59:
No instance for (C (Double -> Complex Double))
  arising from a use of `*'
Possible fix:
  add an instance declaration for (C (Double -> Complex Double))
In the first argument of `integrateCMat'', namely
  `(testMat * (integrateCMat' testMat a))'
In the expression:
  integrateCMat' (testMat * (integrateCMat' testMat a)) a
In an equation for `multipleIntegrationMat':
    multipleIntegrationMat n mf a
      = integrateCMat' (testMat * (integrateCMat' testMat a)) a
Failed, modules loaded: none.

Я понимаю, что нет экземпляра для умножения функций. Что было бы лучшим способом для такого экземпляра? С другой стороны, в скалярном примере умножение работает, хотя комплексный тип данных берется из Data.Complex. Когда я пробую скалярный пример с Number.Complex, я получаю ту же ошибку.

Что я могу сделать, чтобы решить эту проблему?

Спасибо.


person TheMADMAN    schedule 06.03.2012    source источник
comment
Возможно, я что-то упускаю, но... мне кажется, вы на самом деле описываете P : (ℝ → ℂ)ⁿˣⁿ, а не то, что имеете в виду, а именно P : ℝ → ℂⁿˣⁿ.   -  person leftaroundabout    schedule 06.03.2012
comment
да, это правда, у меня есть матрица, и эта матрица содержит функции одного и того же параметра, так что математически это: P:R->C^(nxn) один параметр, который отображается через P в матрицу nXn, которая содержит комплексные значения. В Haskell мне нужно отобразить интеграл в матрицу, по крайней мере, так я это делал, и тогда у меня есть матрица функций, которые зависят от реального параметра. это должно представлять математический контекст, надеюсь на это :) Но проблема та же, мне как-то надо перемножить 2 функции.   -  person TheMADMAN    schedule 06.03.2012
comment
Хорошо, я вижу, вы просто указали один и тот же параметр во всех элементах матрицы. Но какой в ​​этом смысл, разве Double -> Mat.T (Complex Double) не решит проблему немедленно и будет более простым, концептуально?   -  person leftaroundabout    schedule 06.03.2012
comment
Ну, когда я все обдумаю и попытаюсь вписать правильно, то должно быть так: P: R -> (R-> C)^nxn -> C^nxn , я думаю, что это должно быть правильно, но все же у меня есть матрица функций, которые мне нужно интегрировать, и через некоторое время применить к ней значение.   -  person TheMADMAN    schedule 06.03.2012
comment
Ну, я попробовал это, но у меня была проблема с интегралом. Когда я применяю функцию интеграции к матрице, я получаю желаемый результат, но как мне интегрировать: Double -> Mat.T (Complex Double), когда функция библиотеки обеспечивает только интеграцию по Double->Double?   -  person TheMADMAN    schedule 06.03.2012
comment
Не могли бы вы сделать свой последний комментарий в качестве ответа? Я должен все обдумать, но, как я понимаю, вы рисуете функцию интегрировать в матрице, что тогда происходит? cmf теперь `Double -> Mat.T (Complex Double)?   -  person TheMADMAN    schedule 06.03.2012


Ответы (1)


Вы могли сделать

integrateCMat' :: (Double -> Mat.T (Complex Double))
                -> Double -> Double
                 -> Mat.T (Complex Double)
integrateCMat' cmf a b = Mat.fromRows n m integratedRows 
     where (n,m) = Mat.dimension(cmf undefined)
           integratedCell idx = integrateC (cellFunction idx) a b
           cellFunction idx = (\(Mat.Cons arr) -> arr ! idx) . cmf
           integratedRows = [ [ integratedCell(i,j) | i<-[1..n] ] | j<-[1..m] ]

но я согласен, что это довольно уродливо, хотя ленивость Haskell должна гарантировать, что не все элементы матрицы будут вычисляться на каждом шаге интеграции.

person leftaroundabout    schedule 06.03.2012
comment
спасибо за ваш ответ, я попробовал ваш код, и с некоторыми незначительными изменениями он сработал (у меня были проблемы с Mat.Cons, поэтому я перешел на Mat.index и изменил понимание списка на integratedRows = [ [ integratedCell (i,j) | i<-[0..(n-1)] ] | j<-[0..(m-1)] ]). Но тогда я все равно не могу перемножить матрицы внутри интегрирования, вот так: let appval = \x -> ($x) <$> testMat в integrateCMat'' (appval*(integrateCMat'' appval 0 )) 0 1 Я что-то упускаю? - person TheMADMAN; 06.03.2012
comment
Теперь двойная интеграция должна быть совершенно простой, integrateCMat'' (\x -> integrateCMat'' testMat t0 x) t0 t. Не так? - person leftaroundabout; 07.03.2012
comment
действительно, это работает. Но тут возникает но, что мне действительно нужно, так это то, что первое интегрирование возвращает функцию, которая снова подается на интеграл, но внутри интеграла умножается на ту же матрицу первого интегрирования. сложно объяснить, в моем посте первая строка :): матричная функция P(y) интегрируется по y, от t0 до x что такое: f(x)=int^x_t0 P(y) dy эта функция умножается на P(x) и потом интегрируется по x: g(t)=int^t_t0 P(x)*f(x)dx. Можно сказать, что в f(x) матрица P(y) умножается на единицу, которую я опустил. - person TheMADMAN; 07.03.2012
comment
Это цепное интегрирование является частью мультипликативного интеграла, который является общим решением дифференциального уравнения: d/dt y(t) = P(t) y(t), где y и P могут быть матрицами, в моем случае y — это вектор, а P — матрица. Решение, которое я пытаюсь реализовать, представляет собой серию: O(t)=I+int^t_t0 P(x)*I dx + int^t_t0 P(x)*int^x_t0 P(y)*I dy dx +... и так далее, это работает для скаляров, хотя и очень медленно (см. пост для реализации) - person TheMADMAN; 07.03.2012
comment
Ах да... и все же, в чем проблема с: integrateCMat'' (\x -> testMat x * integrateCMat'' testMat t0 x)) t0 t? - person leftaroundabout; 07.03.2012
comment
Это работает, отлично! Как-то я где-то что-то не так сделал. integrateCMat'' (\x -> (appval x) * integrateCMat'' appval t0 x) t0 t, я забыл дополнительную лямбду, ну, это была тяжелая работа, большое спасибо. Но это невозможно применить к случаю матрицы функций, верно? Это было бы более элегантно :) - person TheMADMAN; 07.03.2012