{-# LANGUAGE FlexibleContexts #-} {-| Module : Data.Number.ER.RnToRm.UnitDom.ChebyshevBase.Polynom.Derivative Description : (internal) derivative of polynomials Copyright : (c) 2009 Michal Konecny License : BSD3 Maintainer : mik@konecny.aow.cz Stability : experimental Portability : portable Internal module for "Data.Number.ER.RnToRm.UnitDom.ChebyshevBase.Polynom". Implementation of safely rounded derivative of polynomials. -} module Data.Number.ER.RnToRm.UnitDom.ChebyshevBase.Polynom.Derivative where import Data.Number.ER.RnToRm.UnitDom.ChebyshevBase.Polynom.Basic import Data.Number.ER.RnToRm.UnitDom.ChebyshevBase.Polynom.Ring import qualified Data.Number.ER.Real.Base as B import qualified Data.Number.ER.BasicTypes.DomainBox as DBox import Data.Number.ER.BasicTypes.DomainBox (VariableID(..), DomainBox, DomainBoxMappable, DomainIntBox) import Data.Number.ER.Misc import qualified Data.Map as Map {-| Differentiate a polynomial using one of its variables. -} chplDifferentiate :: (B.ERRealBase b, DomainBox box varid Int, Ord box) => ERChebPoly box b -> varid {-^ variable to differentiate over -} -> (ERChebPoly box b, ERChebPoly box b) chplDifferentiate p diffVar = chplBall2DownUp $ ballDifferentiate p diffVar {-| Differentiate a polynomial using one of its variables. -} ballDifferentiate :: (B.ERRealBase b, DomainBox box varid Int, Ord box) => ERChebPoly box b -> varid {-^ variable to differentiate over -} -> (ERChebPoly box b, b) ballDifferentiate (ERChebPoly coeffs) diffVar = (ERChebPoly diffCoeffs, diffRadius) where (diffCoeffs, diffRadius) = -- ((term |-> coeff), radius) Map.foldWithKey extractTerm (Map.empty, 0) coeffs extractTerm term c prevBall = addDiffTerms (diffVarDegree - 1) prevBall where diffVarDegree = DBox.findWithDefault 0 diffVar term cConstUp = c * (B.fromIntegerUp $ toInteger diffVarDegree) cConstDown = c `timesDown` (B.fromIntegerDown $ toInteger diffVarDegree) cConstErr = cConstUp - cConstDown cNonconstUp = 2 * cConstUp cNonconstDown = 2 `timesDown` cConstDown cNonconstErr = cNonconstUp - cNonconstDown addDiffTerms degreeToAdd ball@(coeffs, radius) | degreeToAdd < 0 = ball | degreeToAdd == 0 = addTermWithDegree 0 cConstDown cConstErr | otherwise = addDiffTerms (degreeToAdd - 2) $ addTermWithDegree degreeToAdd cNonconstUp cNonconstErr where addTermWithDegree diffVarDegree c cErr = (newCoeffs, radius + cErr + newCoeffErr) where newCoeffs = Map.insert newTerm newCoeffDown coeffs newCoeffUp = oldCoeff + c newCoeffDown = oldCoeff `plusDown` c newCoeffErr = newCoeffUp - newCoeffDown oldCoeff = case Map.lookup newTerm coeffs of Nothing -> 0 Just c -> c newTerm = DBox.insert diffVar degreeToAdd term addRadius (p,r) = (p, r + radius) -- -- -- (centrePolyWithDiffTerm, prevRadius + ) -- Map.insertWith Map.union substVarDegree (Map.singleton termNoSubstVar c) prevPolynomMap