
-- ==========================================================--
-- === Computes inverses of function applications.        ===--
-- ===                                         Inverse.hs ===--
-- ==========================================================--

module Inverse where
import BaseDefs
import Utils
import MyUtils
import AbstractVals2
import SuccsAndPreds2
import AbstractMisc
import Apply


-- ==========================================================--
--
inMinInverse :: Bool -> Domain -> Route -> Route -> [FrontierElem]

inMinInverse mindless fDomain (Rep f) res
   | mindless   = second (inMMI_mindless fDomain f res)
   | otherwise  = second (inMMI fDomain f res)


-- ==========================================================--
--
inMaxInverse :: Bool -> Domain -> Route -> Route -> [FrontierElem]

inMaxInverse mindless fDomain (Rep f) res
   | mindless   = first (inMMI_mindless fDomain f res)
   | otherwise  = first (inMMI fDomain f res)


-- ==========================================================--
--
inMMI_mindless :: Domain -> Rep -> Route -> ([FrontierElem], [FrontierElem])

inMMI_mindless (Func dss dt) f a
   = let totalInverseImage = inInverse_mindless dss f a
     in (avMaxfrel totalInverseImage, avMinfrel totalInverseImage)


-- ==========================================================--
--
inNormalise :: [FrontierElem] ->
               [FrontierElem] ->
               ([FrontierElem], [FrontierElem])

inNormalise max min
   = let new_max = filter (`avAboveMin1frel`     min) max
         new_min = filter (`avBelowMax0frel` new_max) min
     in
         (new_max, new_min)


-- ==========================================================--
--
inIntersect :: ([FrontierElem], [FrontierElem]) ->
               ([FrontierElem], [FrontierElem]) ->
               ([FrontierElem], [FrontierElem])

inIntersect (max1, min1) (max2, min2)
   = let new_max = avMaxfrel [ x `avGLBfrel` y | x <- max1, y <- max2 ]
         new_min = avMinfrel [ x `avLUBfrel` y | x <- min1, y <- min2 ]
     in  inNormalise new_max new_min


-- ==========================================================--
--
inMMI :: Domain -> Rep -> Route -> ([FrontierElem], [FrontierElem])

inMMI (Func dss dt) (RepTwo (Min1Max0 ar f1 f0)) Zero
   = (f0,
      if null f0 then [] else [MkFrel (map avBottomR dss)])

inMMI (Func dss Two) (RepTwo (Min1Max0 ar f1 f0)) One
   = (if null f1 then [] else [MkFrel (map avTopR dss)],
      f1)

inMMI (Func dss (Lift1 dts)) (Rep1 (Min1Max0 ar lf_f1 lf_f0) hfs) Stop1
   = (lf_f0,
      if null lf_f0 then [] else [MkFrel (map avBottomR dss)])

-- special case because this happens extremely frequently
inMMI (Func dss (Lift1 [dt])) (Rep1 (Min1Max0 ar lf_f1 lf_f0) [hf]) (Up1 [r])
   = let (hf_maxI, hf_minI) = inMMI (avUncurry dss dt) hf r
         min2 = avMinfrel [ x `avLUBfrel` y | x <- hf_minI, y <- lf_f1 ]
     in  inNormalise hf_maxI min2

inMMI (Func dss (Lift1 dts)) (Rep1 (Min1Max0 ar lf_f1 lf_f0) hfs) (Up1 rs)
   = let hf_domains = map (avUncurry dss) dts
         hf_MMIs = myZipWith3 inMMI hf_domains hfs rs
         (hf_maxI, hf_minI) = foldr1 inIntersect hf_MMIs
         min2 = avMinfrel [ x `avLUBfrel` y | x <- hf_minI, y <- lf_f1 ]
     in  inNormalise hf_maxI min2

-- cheat on this one, because I'm lazy
inMMI (Func dss (Lift2 dts)) (Rep2 lf mf hfs) a
   = let isoD              = Func dss (Lift1 [Lift1 dts])
         isoR              = Rep1 lf [Rep1 mf hfs]
         isoA Stop2        = Stop1
         isoA Up2          = Up1 [Stop1]
         isoA (UpUp2 rs)   = Up1 [Up1 rs]
     in
         inMMI isoD isoR (isoA a)

--inMMI (DFunc dss (Cross dts), RFunc (RepCross reps))
--    (Cross dts2, Split rs)
--    | dts == dts2 {-INVARIANT-}
--    = let doOne n
--             = inMMI (avUncurryDomain (DFunc dss (dts##n)),
--                      RFunc (reps##n)) (dts##n, rs##n)
--      in foldr1 inIntersect (map doOne [0 .. length reps - 1])
--
---- special case for partial applications of [... -> 2]
--inMMI f@(DFunc dssf Two, RFunc (RepTwo (Min1Max0 arf f1 f0)))
--      g@(DFunc dssg Two, RFunc (RepTwo (Min1Max0 arg g1 g0)))
--    | arf > arg && {-INVARIANT-}
--      dssg == drop (length dssf - length dssg) dssf {-INVARIANT-}
--    = let (g1Max, g1Min) = inMMI g (Two, One)
--          (g0Max, g0Min) = inMMI g (Two, Zero)
--          fMaxs = [inPapL f fels | MkFrel fels <- g1Min]
--          fMins = [inPapL f fels | MkFrel fels <- g0Max]
--          iMaxs = [inMMI fn (Two, One)  | fn <- fMaxs]
--          iMins = [inMMI fn (Two, Zero) | fn <- fMins]
--      in foldr1 inIntersect (iMaxs ++ iMins)
--
--inMMI f@(DFunc dssf (Lift dtf), RFunc (RepLift lff hff))
--      g@(DFunc dssg (Lift dtg), RFunc (RepLift lfg hfg))
--    | dtf == dtg && {-INVARIANT-}
--      dssg == drop (length dssf - length dssg) dssf {-INVARIANT-}
--    = let lofac_f = (DFunc dssf Two, RFunc (RepTwo lff))
--          lofac_g = (DFunc dssg Two, RFunc (RepTwo lfg))
--          hifac_f = (avUncurryDomain (DFunc dssf dtf), RFunc hff)
--          hifac_g = (avUncurryDomain (DFunc dssg dtg), RFunc hfg)
--      in  inIntersect (inMMI lofac_f lofac_g) (inMMI hifac_f hifac_g)
--
--inMMI f@(DFunc dssf (Cross dtfs), RFunc (RepCross repsf))
--      g@(DFunc dssg (Cross dtgs), RFunc (RepCross repsg))
--    = let doOne n
--             = inMMI (avUncurryDomain (DFunc dssf (dtfs##n)), RFunc (repsf##n))
--                     (avUncurryDomain (DFunc dssg (dtgs##n)), RFunc (repsg##n))
--          in foldr1 inIntersect (map doOne [0 :: Int .. length repsf - 1])

-- otherwise, give up and call the mindless method
inMMI dss f a
   = inMMI_mindless dss f a


-- ==========================================================--
----
--inPapL :: Point -> [Point] -> Point
--
--inPapL (DFunc dss Two, RFunc (RepTwo (Min1Max0 ar f1 f0))) args
--   = let argCount = length args
--         argDomainAfter = revDrop argCount dss
--         revDrop n = reverse . drop n . reverse
--         revTake n = reverse . take n . reverse
--         newf1 = sort (avMinfrel [MkFrel (revDrop argCount fel) |
--                                  MkFrel fel <- f1,
--                                  and (myZipWith2 avBelowEQ
--                                     (revTake argCount fel) args)])
--         newf0 = sort (avMaxfrel [MkFrel (revDrop argCount fel) |
--                                  MkFrel fel <- f0,
--                                  and (myZipWith2 avBelowEQ
--                                     args (revTake argCount fel))])
--     in (DFunc argDomainAfter Two,
--         RFunc (RepTwo (Min1Max0 (ar-argCount) newf1 newf0)))
--

-- ==========================================================--
--
inInverse_mindless :: [Domain] -> Rep -> Route -> [FrontierElem]

inInverse_mindless argDomains f a
   = let isPartialApp
            = case a of { Rep _ -> True; _ -> False }
         aRep
            = case a of { Rep r -> r }
         actualArgDomains
            = if     isPartialApp
              then   take (amRepArity f - amRepArity aRep) argDomains
              else   argDomains
         allArgs
            = myCartesianProduct (map amAllRoutes actualArgDomains)
     in
         [MkFrel args | args <- allArgs, apApply (Rep f) args == a]

--inTrace :: Bool -> Bool
--inTrace x = x

-- ==========================================================--
-- === end                                     Inverse.hs ===--
-- ==========================================================--

