module MathObj.RefinementMask2 (
T, coeffs, fromCoeffs,
fromPolynomial,
toPolynomial,
toPolynomialFast,
refinePolynomial,
convolvePolynomial,
convolveTruncatedPowerPolynomials,
) where
import qualified MathObj.Polynomial as Poly
import qualified MathObj.Polynomial.Core as PolyCore
import qualified Algebra.RealField as RealField
import qualified Algebra.Field as Field
import qualified Algebra.Ring as Ring
import qualified Algebra.Vector as Vector
import qualified Data.List as List
import qualified Data.List.HT as ListHT
import qualified Data.List.Match as Match
import Data.Maybe (fromMaybe, )
import Control.Monad (liftM2, )
import qualified Test.QuickCheck as QC
import qualified NumericPrelude.List.Generic as NPList
import NumericPrelude.Base
import NumericPrelude.Numeric
newtype T a = Cons {coeffs :: [a]}
fromCoeffs :: [a] -> T a
fromCoeffs = lift0
lift0 :: [a] -> T a
lift0 = Cons
instance Functor T where
fmap f (Cons xs) = Cons (map f xs)
appPrec :: Int
appPrec = 10
instance (Show a) => Show (T a) where
showsPrec p (Cons xs) =
showParen (p >= appPrec)
(showString "RefinementMask2.fromCoeffs " . shows xs)
instance (QC.Arbitrary a, Field.C a) => QC.Arbitrary (T a) where
arbitrary =
liftM2
(\degree body ->
let s = sum body
in Cons $ map ((2 ^- degree s) / NPList.lengthLeft body +) body)
(QC.choose (5,0)) QC.arbitrary
fromPolynomial ::
(Field.C a) => Poly.T a -> T a
fromPolynomial poly =
fromCoeffs $
foldr (\p ps ->
ListHT.mapAdjacent () (p:ps++[0]))
[] $
foldr (\(db,dp) cs ->
ListHT.switchR
(error "RefinementMask2.fromPolynomial: polynomial should be non-empty")
(\dps dpe ->
cs ++ [(db Ring.scalarProduct dps cs) / dpe])
dp) [] $
zip
(Poly.coeffs $ Poly.dilate 2 poly)
(List.transpose $
Match.take (Poly.coeffs poly) $
map Poly.coeffs $
iterate polynomialDifference poly)
polynomialDifference ::
(Ring.C a) => Poly.T a -> Poly.T a
polynomialDifference poly =
Poly.fromCoeffs $ init $ Poly.coeffs $
Poly.translate 1 poly poly
toPolynomial ::
(RealField.C a) => T a -> Maybe (Poly.T a)
toPolynomial (Cons []) = Just $ Poly.fromCoeffs []
toPolynomial mask =
let s = sum $ coeffs mask
ks = reverse $ takeWhile (<=1) $ iterate (2*) s
in case ks of
1:ks0 ->
Just $
foldl
(\p k ->
let ip = Poly.integrate zero p
in ip + Poly.const (correctConstant (fmap (k/s*) mask) ip))
(Poly.const 1) ks0
_ -> Nothing
correctConstant ::
(Field.C a) => T a -> Poly.T a -> a
correctConstant mask poly =
let refined = refinePolynomial mask poly
in head (Poly.coeffs refined) / (1 sum (coeffs mask))
toPolynomialFast ::
(RealField.C a) => T a -> Maybe (Poly.T a)
toPolynomialFast mask =
let s = sum $ coeffs mask
ks = reverse $ takeWhile (<=1) $ iterate (2*) s
in case ks of
1:ks0 ->
Just $
foldl
(\p k ->
let ip = Poly.integrate zero p
c = head (Poly.coeffs (refinePolynomial mask ip))
in ip + Poly.const (c*k / ((1k)*s)))
(Poly.const 1) ks0
_ -> Nothing
refinePolynomial ::
(Ring.C a) => T a -> Poly.T a -> Poly.T a
refinePolynomial mask =
Poly.shrink 2 .
Vector.linearComb (coeffs mask) .
iterate (Poly.translate 1)
convolve ::
(Ring.C a) => T a -> T a -> T a
convolve x y =
fromCoeffs $
PolyCore.mul (coeffs x) (coeffs y)
convolvePolynomial ::
(RealField.C a) =>
Poly.T a -> Poly.T a -> Poly.T a
convolvePolynomial x y =
fromMaybe
(error "RefinementMask2.convolvePolynomial: leading term should always be correct") $
toPolynomial $ fmap (/2) $
convolve (fromPolynomial x) (fromPolynomial y)
convolveTruncatedPowerPolynomials ::
(RealField.C a) =>
Poly.T a -> Poly.T a -> Poly.T a
convolveTruncatedPowerPolynomials x y =
let facs = scanl (*) 1 $ iterate (1+) 1
xl = Poly.coeffs x
yl = Poly.coeffs y
in Poly.integrate 0 $
Poly.fromCoeffs $
zipWith (flip (/)) facs $
PolyCore.mul
(zipWith (*) facs xl)
(zipWith (*) facs yl)