module Data.Number.ER.RnToRm.UnitDom.ChebyshevBase.Polynom.Bounds
where
import Data.Number.ER.RnToRm.UnitDom.ChebyshevBase.Polynom.Basic
import Data.Number.ER.RnToRm.UnitDom.ChebyshevBase.Polynom.Ring
import Data.Number.ER.RnToRm.UnitDom.ChebyshevBase.Polynom.Reduce
import Data.Number.ER.RnToRm.UnitDom.ChebyshevBase.Polynom.Eval
import qualified Data.Number.ER.Real.Approx as RA
import qualified Data.Number.ER.Real.Base as B
import Data.Number.ER.Real.Approx.Interval
import Data.Number.ER.Real.Arithmetic.LinearSolver
import qualified Data.Number.ER.Real.DomainBox as DBox
import Data.Number.ER.Real.DomainBox (VariableID(..), DomainBox, DomainBoxMappable, DomainIntBox)
import Data.Number.ER.BasicTypes
import Data.Number.ER.Misc
import qualified Data.Map as Map
import Data.List
chplUpperBound ::
(B.ERRealBase b, DomainBox box varid Int, Ord box) =>
EffortIndex ->
ERChebPoly box b ->
b
chplUpperBound ix p = snd $ chplBounds ix p
chplLowerBound ::
(B.ERRealBase b, DomainBox box varid Int, Ord box) =>
EffortIndex ->
ERChebPoly box b ->
b
chplLowerBound ix p = fst $ chplBounds ix p
chplBounds ::
(B.ERRealBase b, DomainBox box varid Int, Ord box) =>
EffortIndex ->
ERChebPoly box b ->
(b,b)
chplBounds = chplBoundsAffine
chplBoundsAffine ::
(B.ERRealBase b, DomainBox box varid Int, Ord box) =>
EffortIndex ->
ERChebPoly box b ->
(b,b)
chplBoundsAffine ix p@(ERChebPoly coeffs) =
result
where
result =
(constTerm `plusDown` ( noConstCoeffAbsSum),
constTerm `plusUp` noConstCoeffAbsSum)
noConstCoeffAbsSum = Map.fold plusUp 0 absCoeffs
absCoeffs = Map.map abs $ Map.delete chplConstTermKey coeffs
constTerm = Map.findWithDefault 0 chplConstTermKey coeffs
chplUpperBoundQuadr ::
(B.ERRealBase b, RealFrac b, DomainBox box varid Int, Ord box,
DomainBoxMappable boxra boxras varid (ERInterval b) [ERInterval b],
DomainBoxMappable boxra boxra varid (ERInterval b) (ERInterval b),
DomainIntBox boxra varid (ERInterval b), Num varid, Enum varid) =>
EffortIndex ->
ERChebPoly box b ->
b
chplUpperBoundQuadr ix p@(ERChebPoly coeffs) =
quadBound (coeffsQ, vars)
where
pQ@(ERChebPoly coeffsQ) = chplReduceDegreeUp 2 p
vars = chplGetVars pQ
quadBound (coeffs, vars)
| null vars =
Map.findWithDefault 0 chplConstTermKey coeffs
| hasInteriorPeak =
foldl max peakValue edgeBounds
| otherwise =
foldl1 max edgeBounds
where
edgeBounds =
map quadBound $ concat $ map removeVar vars
(hasInteriorPeak, peakValue) =
case maybePeak of
Just peak ->
(noPositiveSquare
&&
(and $ map maybeInUnit $ DBox.elems peak)
,
erintv_right $
chplRAEval makeInterval p peak
)
Nothing -> (False, undefined)
where
noPositiveSquare =
and $ map (<= 0) $ map getQuadCoeff vars
getQuadCoeff var =
Map.findWithDefault 0 (DBox.singleton var 2) coeffs
maybeInUnit r =
case (RA.compareReals r (1), RA.compareReals (1) r) of
(Just LT, _) -> False
(_, Just LT) -> False
_ -> True
maybePeak =
linearSolver
(map derivZeroLinearEq vars)
(DBox.fromList $ map (\v -> (v,(1) RA.\/ 1)) vars)
(2^^(ix))
where
derivZeroLinearEq var =
(linCoeffs, constCoeff)
where
constCoeff =
makeInterval $
Map.findWithDefault 0 (DBox.singleton var 1) coeffs
linCoeffs =
DBox.fromList $
(var, 4 * quadCoeff)
: (map getVarVarCoeff $ var `delete` vars)
quadCoeff =
makeInterval $
Map.findWithDefault 0 (DBox.singleton var 2) coeffs
getVarVarCoeff var2 =
(var2,
makeInterval $
Map.findWithDefault 0 (DBox.fromList [(var,1), (var2,1)]) coeffs)
makeInterval b = ERInterval b b
removeVar var =
[(substVar True, newVars),
(substVar False, newVars)]
where
newVars = var `delete` vars
substVar isOne =
chplCoeffs $
foldl (+^) (chplConst 0) $
map (makeMonomial isOne) $
Map.toList coeffs
makeMonomial isOne (term, coeff) =
ERChebPoly $ Map.fromList $
case (DBox.toList term) of
[(v,2)] | v == var ->
[(chplConstTermKey, coeff)]
[(v,1)] | v == var ->
[(chplConstTermKey,
case isOne of True -> coeff; False -> coeff)]
[(v1,1), (v2,1)] | v1 == var ->
[(DBox.fromList [(v2,1)],
case isOne of True -> coeff; False -> coeff)]
[(v1,1), (v2,1)] | v2 == var ->
[(DBox.fromList [(v1,1)],
case isOne of True -> coeff; False -> coeff)]
_ ->
[(term, coeff)]
chplMax ::
(B.ERRealBase b, RealFrac b, DomainBox box varid Int, Ord box) =>
Int ->
Int ->
ERChebPoly box b ->
ERChebPoly box b ->
(ERChebPoly box b, ERChebPoly box b)
chplMax maxDegree maxSize p1 p2 =
(p1 +. differenceDown, p1 +^ differenceUp)
where
(differenceDown, _) = chplNonneg maxDegree maxSize p2MinusP1Down
(_, differenceUp) = chplNonneg maxDegree maxSize $ p2MinusP1Up
(p2MinusP1Down, p2MinusP1Up, _) = chplAdd p2 (chplNeg p1)
chplMaxDn m s a b = fst $ chplMax m s a b
chplMaxUp m s a b = snd $ chplMax m s a b
chplMinDn m s a b = fst $ chplMin m s a b
chplMinUp m s a b = snd $ chplMin m s a b
chplMin ::
(B.ERRealBase b, RealFrac b, DomainBox box varid Int, Ord box) =>
Int ->
Int ->
ERChebPoly box b ->
ERChebPoly box b ->
(ERChebPoly box b, ERChebPoly box b)
chplMin m s a b =
(chplNeg u,chplNeg l)
where
(l,u) = chplMax m s (chplNeg a) (chplNeg b)
chplNonnegDown m s p = fst $ chplNonneg m s p
chplNonnegUp m s p = snd $ chplNonneg m s p
chplNonposDown m s p = fst $ chplNonpos m s p
chplNonposUp m s p = snd $ chplNonpos m s p
chplNonpos m s p =
(chplNeg h, chplNeg l)
where
(l,h) = chplNonneg m s (chplNeg p)
chplNonneg ::
(B.ERRealBase b, RealFrac b, DomainBox box varid Int, Ord box) =>
Int ->
Int ->
ERChebPoly box b ->
(ERChebPoly box b, ERChebPoly box b)
chplNonneg = chplNonnegCubic
chplNonnegCubic ::
(B.ERRealBase b, RealFrac b, DomainBox box varid Int, Ord box) =>
Int ->
Int ->
ERChebPoly box b ->
(ERChebPoly box b, ERChebPoly box b)
chplNonnegCubic maxDegree maxSize p
| upperB <= 0 = (chplConst 0, chplConst 0)
| lowerB >= 0 = (p, p)
| not allInterimsBounded = (chplConst (1/0), chplConst (1/0))
| otherwise =
(chplAddConstDown ( valueAt0B) cubicAppliedOnPDown,
chplAddConstUp correctionB cubicAppliedOnPUp)
where
(lowerB, upperB) = chplBounds 10 p
(cubicAppliedOnPDown, cubicAppliedOnPUp, width) =
p0 `scaleByPositiveConsts` (rbLo, rbHi)
where
p0 = (multiplyByP p1) `addConsts` (a0Lo, a0Hi)
p1 = (multiplyByP p2) `addConsts` (a1Lo, a1Hi)
p2 = (multiplyByP p3) `addConsts` (a2Lo, a2Hi)
p3 = (chplConst a3Lo, chplConst a3Hi, a3Hi a3Lo)
multiplyByP (lo,hi,wd) =
(ploRed, phiRed, pwd)
where
ploRed = reduceDgSzDown plo
phiRed = reduceDgSzUp phi
pwd = chplUpperBound 10 $ phiRed -^ ploRed
(plo, phi, _) = chplTimesLoHi p (lo,hi,wd)
reduceDgSzUp =
chplReduceTermCountUp maxSize . chplReduceDegreeUp maxDegree
reduceDgSzDown =
chplReduceTermCountDown maxSize . chplReduceDegreeDown maxDegree
addConsts (lo, hi, wd) (cLo, cHi) =
(alo, ahi, wd + wdlo + wdhi)
where
(alo, _, wdlo) = chplAddConst cLo lo
(_, ahi, wdhi) = chplAddConst cHi hi
scaleByPositiveConsts (lo, hi, wd) (cLo, cHi) =
(slo, shi, wd + wdlo + wdhi)
where
(slo, _, wdlo) = chplScale cLo lo
(_, shi, wdhi) = chplScale cHi hi
ERInterval rbLo rbHi = rb
ERInterval a3Lo a3Hi = a3
ERInterval a2Lo a2Hi = a2
ERInterval a1Lo a1Hi = a1
ERInterval a0Lo a0Hi = a0
allInterimsBounded =
and $ map RA.isBounded [w, s, rb, a0, a1, a2, a3, correction]
rb = recip b
b = w3
w = r l
r = ERInterval upperB upperB
l = ERInterval lowerB lowerB
a3 = s
s = r + l
a2 = 2 * (r2PrlPl2)
r2PrlPl2 = s2 rl
rl = r * l
a1 = ( l) * (r2PrlPl2 + 3*r2)
a0 = 2*r2*l2
w3 = ERInterval (wLo * wLo * wLo) (wHi * wHi * wHi)
ERInterval wLo wHi = w
s2 = ERInterval (max 0 s2Lo) s2Hi
s2Lo = min sLo2 sHi2
s2Hi = max sLo2 sHi2
sLo2 = sLo * sLo
sHi2 = sHi * sHi
ERInterval sLo sHi = s
r2 = ERInterval (upperB `timesDown` upperB) (upperB `timesUp` upperB)
l2 = ERInterval (lowerB `timesDown` lowerB) (lowerB `timesUp` lowerB)
ERInterval _ correctionB = correction
correction =
case (RA.compareReals (2 * r2) (l*s), RA.compareReals (2 * l2) (r*s)) of
(Just LT, _) ->
(peak0 * (peak0 * (peak0 * (a3) a2) a1) a0) / b
(_, Just LT) ->
((peakP * (peakP * (peakP * (a3) a2) a1) a0) / b) + peakP
_ -> 0
where
peak0 = (l + 4*r2/s) / 3
peakP = (r + 4*l2/s) / 3
valueAt0B =
case a0 / b of
ERInterval lo hi -> hi
ERIntervalAny -> 1/0
chplTimesLoHi ::
(B.ERRealBase b, DomainBox box varid Int, Ord box) =>
ERChebPoly box b ->
(ERChebPoly box b, ERChebPoly box b, b) ->
(ERChebPoly box b, ERChebPoly box b, b)
chplTimesLoHi p1 (p2Low, p2High, p2Width) =
(prodMid -. (chplConst width),
prodMid +^ (chplConst width),
2 * width)
where
prodMid = prodLowUp
(prodLowDown, prodLowUp, prodLowWidth) =
chplMultiply p1 p2Low
(prodHighDown, prodHighUp, prodHighWidth) =
chplMultiply p1 p2High
width =
p1Norm `timesUp` p2Width `plusUp` prodLowWidth `plusUp` prodHighWidth
p1Norm =
max (abs $ p1LowerBound) (abs $ p1UpperBound)
(p1LowerBound, p1UpperBound) =
chplBounds ix p1
ix = 10