adp-multi-0.1.0: src/ADP/Multi/Rewriting/Explicit.hs
{-# LANGUAGE FlexibleInstances #-}
module ADP.Multi.Rewriting.Explicit (
determineYieldSize1,
determineYieldSize2,
constructRanges1,
constructRanges2
) where
import Control.Exception
import Data.List (elemIndex, find)
import qualified Data.Map as Map
import Data.Maybe
import ADP.Debug
import ADP.Multi.Parser
import ADP.Multi.Rewriting
import ADP.Multi.Rewriting.YieldSize
type Subword1 = (Int,Int)
type Subword2 = (Int,Int,Int,Int)
constructRanges1 :: RangeConstructionAlgorithm Dim1
constructRanges1 _ _ b | trace ("constructRanges1 " ++ show b) False = undefined
constructRanges1 f infos [i,j] =
assert (i <= j) $
let parserCount = length infos
elemInfo = buildInfoMap infos
rewritten = f (Map.keys elemInfo)
remainingSymbols = [parserCount,parserCount-1..1] `zip` infos
rangeDesc = [(i,j,rewritten)]
rangeDescFiltered = filterEmptyRanges rangeDesc
in trace ("f " ++ show (Map.keys elemInfo) ++ " = " ++ show rewritten) $
assert (length rewritten == Map.size elemInfo && all (`elem` rewritten) (Map.keys elemInfo)) $
if any (\(m,n,d) -> null d && m /= n) rangeDesc then []
else constructRangesRec elemInfo remainingSymbols rangeDescFiltered
constructRanges2 :: RangeConstructionAlgorithm Dim2
constructRanges2 _ _ b | trace ("constructRanges2 " ++ show b) False = undefined
constructRanges2 f infos [i,j,k,l] =
assert (i <= j && j <= k && k <= l) $
let parserCount = length infos
elemInfo = buildInfoMap infos
(left,right) = f (Map.keys elemInfo)
remainingSymbols = [parserCount,parserCount-1..1] `zip` infos
rangeDesc = [(i,j,left),(k,l,right)]
rangeDescFiltered = filterEmptyRanges rangeDesc
in trace ("f " ++ show (Map.keys elemInfo) ++ " = (" ++ show left ++ "," ++ show right ++ ")") $
assert (length left + length right == Map.size elemInfo && all (`elem` (left ++ right)) (Map.keys elemInfo)) $
if any (\(m,n,d) -> null d && m /= n) rangeDesc then []
else constructRangesRec elemInfo remainingSymbols rangeDescFiltered
determineYieldSize1 :: YieldAnalysisAlgorithm Dim1
determineYieldSize1 _ infos | trace ("determineYieldSize1 " ++ show infos) False = undefined
determineYieldSize1 f infos = doDetermineYieldSize1 f infos
determineYieldSize2 :: YieldAnalysisAlgorithm Dim2
determineYieldSize2 _ infos | trace ("determineYieldSize2 " ++ show infos) False = undefined
determineYieldSize2 f infos = doDetermineYieldSize2 f infos
type RangeDesc = (Int,Int,[(Int,Int)])
constructRangesRec :: InfoMap -> [(Int,ParserInfo)] -> [RangeDesc] -> [Ranges]
constructRangesRec a b c | trace ("constructRangesRec " ++ show a ++ " " ++ show b ++ " " ++ show c) False = undefined
constructRangesRec _ [] [] = []
constructRangesRec infoMap ((current,ParserInfo2 {}):rest) rangeDescs =
let symbolLoc = findSymbol2 current rangeDescs
subwords = calcSubwords2 infoMap symbolLoc
in trace ("calc subwords for dim2") $
trace ("subwords: " ++ show subwords) $
[ RangeMap [i,j,k,l] restRanges |
(i,j,k,l) <- subwords,
let newDescs = constructNewRangeDescs2 rangeDescs symbolLoc (i,j,k,l),
let restRanges = constructRangesRec infoMap rest newDescs
]
constructRangesRec infoMap ((current,ParserInfo1 {}):rest) rangeDescs =
let symbolLoc = findSymbol1 current rangeDescs
subwords = calcSubwords1 infoMap symbolLoc
in trace ("calc subwords for dim1") $
trace ("subwords: " ++ show subwords) $
[ RangeMap [i,j] restRanges |
(i,j) <- subwords,
let newDescs = constructNewRangeDescs1 rangeDescs symbolLoc (i,j),
let restRanges = constructRangesRec infoMap rest newDescs
]
constructRangesRec _ [] r@(_:_) = error ("programming error " ++ show r)
findSymbol :: Int -> Int -> [RangeDesc] -> (RangeDesc,Int)
findSymbol s idx r | trace ("findSymbol " ++ show s ++ "," ++ show idx ++ " " ++ show r) False = undefined
findSymbol s idx rangeDesc =
let Just (i,j,r) = find (\(_,_,l') -> any (\(s',i') -> s' == s && i' == idx) l') rangeDesc
Just aIdx = elemIndex (s,idx) r
in ((i,j,r),aIdx)
findSymbol1 :: Int -> [RangeDesc] -> (RangeDesc,Int)
findSymbol1 s = findSymbol s 1
findSymbol2 :: Int -> [RangeDesc] -> ((RangeDesc,Int),(RangeDesc,Int))
findSymbol2 s rangeDesc = (findSymbol s 1 rangeDesc, findSymbol s 2 rangeDesc)
-- TODO refactor (code duplication with Explicit module)
constructNewRangeDescs1 :: [RangeDesc] -> (RangeDesc,Int) -> Subword1 -> [RangeDesc]
constructNewRangeDescs1 d p s | trace ("constructNewRangeDescs1 " ++ show d ++ " " ++ show p ++ " " ++ show s) False = undefined
constructNewRangeDescs1 descs symbolPosition subword =
let newDescs = [ newDesc |
desc <- descs
, newDesc <- processRangeDesc1 desc symbolPosition subword
]
count = foldr (\(_,_,l) r -> r + length l) 0
in assert (count descs > count newDescs) $
trace (show newDescs) $
newDescs
constructNewRangeDescs2 :: [RangeDesc] -> ((RangeDesc,Int),(RangeDesc,Int)) -> Subword2 -> [RangeDesc]
constructNewRangeDescs2 d p s | trace ("constructNewRangeDescs2 " ++ show d ++ " " ++ show p ++ " " ++ show s) False = undefined
constructNewRangeDescs2 descs symbolPositions subword =
let newDescs = [ newDesc |
desc <- descs
, newDesc <- processRangeDesc2 desc symbolPositions subword
]
count = foldr (\(_,_,l) r -> r + length l) 0
in assert (count descs > count newDescs) $
trace (show newDescs) $
newDescs
processRangeDesc1 :: RangeDesc -> (RangeDesc,Int) -> Subword1 -> [RangeDesc]
processRangeDesc1 a b c | trace ("processRangeDesc1 " ++ show a ++ " " ++ show b ++ " " ++ show c) False = undefined
processRangeDesc1 inp (desc,aIdx) (m,n)
| inp /= desc = [inp]
| otherwise = processRangeDescSingle desc aIdx (m,n)
processRangeDesc2 :: RangeDesc -> ((RangeDesc,Int),(RangeDesc,Int)) -> Subword2 -> [RangeDesc]
processRangeDesc2 a b c | trace ("processRangeDesc2 " ++ show a ++ " " ++ show b ++ " " ++ show c) False = undefined
processRangeDesc2 inp ((left,a1Idx),(right,a2Idx)) (m,n,o,p)
| inp /= left && inp /= right = [inp]
| inp == left && inp == right =
-- at this point it doesn't matter what the actual ordering is
-- so we just swap if necessary to make it easier for processRangeDescDouble
let (a1Idx',a2Idx',m',n',o',p') =
if a1Idx < a2Idx then
(a1Idx,a2Idx,m,n,o,p)
else
(a2Idx,a1Idx,o,p,m,n)
in processRangeDescDouble inp a1Idx' a2Idx' (m',n',o',p')
| inp == left = processRangeDescSingle left a1Idx (m,n)
| inp == right = processRangeDescSingle right a2Idx (o,p)
filterEmptyRanges :: [RangeDesc] -> [RangeDesc]
filterEmptyRanges l =
let f (i,j,d) = not $ null d && i == j
in filter f l
processRangeDescSingle :: RangeDesc -> Int -> Subword1 -> [RangeDesc]
processRangeDescSingle a b c | trace ("processRangeDescSingle " ++ show a ++ " " ++ show b ++ " " ++ show c) False = undefined
processRangeDescSingle (i,j,r) aIdx (k,l)
| aIdx == 0 = filterEmptyRanges [(l,j,tail r)]
| aIdx == length r - 1 = [(i,k,init r)]
| otherwise = [(i,k,take aIdx r),(l,j,drop (aIdx + 1) r)]
-- assumes that a1Idx < a2Idx, see processRangeDesc
processRangeDescDouble :: RangeDesc -> Int -> Int -> Subword2 -> [RangeDesc]
processRangeDescDouble a b c d | trace ("processRangeDescDouble " ++ show a ++ " " ++ show b ++ " " ++ show c ++ " " ++ show d) False = undefined
processRangeDescDouble (i,j,r) a1Idx a2Idx (k,l,m,n) =
assert (a1Idx < a2Idx) result where
result | a1Idx == 0 && a2Idx == length r - 1 = filterEmptyRanges [(l,m,init (tail r))]
| a1Idx == 0 = filterEmptyRanges [(l,m,slice 1 (a2Idx-1) r),(n,j,drop (a2Idx+1) r)]
| a2Idx == length r - 1 = filterEmptyRanges [(i,k,take a1Idx r),(l,m,slice (a1Idx+1) (a2Idx-1) r)]
| otherwise = filterEmptyRanges [(i,k,take a1Idx r),(l,m,slice (a1Idx+1) (a2Idx-1) r),(n,j,drop (a2Idx+1) r)]
where slice from to xs = take (to - from + 1) (drop from xs)
infoFromPos :: InfoMap -> (RangeDesc,Int) -> Info
infoFromPos infoMap ((_,_,r),aIdx) =
-- TODO !! might be expensive as it's a list
infoMap Map.! (r !! aIdx)
-- calculates the combined yield size of all symbols left of the given one
combinedInfoLeftOf :: InfoMap -> (RangeDesc,Int) -> Info
combinedInfoLeftOf infoMap (desc,axIdx)
| axIdx == 0 = (0, Just 0)
| otherwise =
let leftInfos = map (\i -> infoFromPos infoMap (desc,i)) [0..axIdx-1]
in combineYields leftInfos
-- calculates the combined yield size of all symbols right of the given one
combinedInfoRightOf :: InfoMap -> (RangeDesc,Int) -> Info
combinedInfoRightOf infoMap (desc@(_,_,r),axIdx)
| axIdx == length r - 1 = (0, Just 0)
| otherwise =
let rightInfos = map (\i -> infoFromPos infoMap (desc,i)) [axIdx+1..length r - 1]
in combineYields rightInfos
-- Subword construction doesn't yet take the maximum yield sizes into account.
-- This will further decrease the number of generated subwords and thus increase performance.
calcSubwords2 :: InfoMap -> ((RangeDesc,Int),(RangeDesc,Int)) -> [Subword2]
calcSubwords2 a b | trace ("calcSubwords2 " ++ show a ++ " " ++ show b) False = undefined
calcSubwords2 infoMap (left@((i,j,r),a1Idx),right@((m,n,r'),a2Idx))
| r == r' = calcSubwords2Dependent infoMap (i,j,r) a1Idx a2Idx
| length r == 1 && length r' == 1 = [(i,j,m,n)]
| length r == 1 = [ (i',j',k',l') |
let (i',j') = (i,j)
, (k',l') <- calcSubwords1 infoMap right
]
| length r' == 1 = [ (i',j',k',l') |
let (k',l') = (m,n)
, (i',j') <- calcSubwords1 infoMap left
]
| otherwise = [ (i',j',k',l') |
(i',j') <- calcSubwords1 infoMap left
, (k',l') <- calcSubwords1 infoMap right
]
-- assumes that other component is in a different part
calcSubwords1 :: InfoMap -> (RangeDesc,Int) -> [Subword1]
calcSubwords1 _ b | trace ("calcSubwords1 " ++ show b) False = undefined
calcSubwords1 infoMap pos@((i,j,r),axIdx)
| axIdx == 0 =
[ (k,l) |
Just (minY',minYRight') <- [adjustMinYield (i,j) (minY,minYRight) (maxY,maxYRight)]
, let k = i
, l <- [i+minY'..j-minYRight']
]
| axIdx == length r - 1 =
[ (k,l) |
Just (minYLeft',minY') <- [adjustMinYield (i,j) (minYLeft,minY) (maxYLeft,maxY)]
, let l = j
, k <- [i+minYLeft'..j-minY']
]
| otherwise =
[ (k,l) |
k <- [i+minYLeft..j-minY]
, l <- [k+minY..j-minYRight]
]
where (minY,maxY) = infoFromPos infoMap pos
(minYLeft,maxYLeft) = combinedInfoLeftOf infoMap pos
(minYRight,maxYRight) = combinedInfoRightOf infoMap pos
adjustMinYield :: Subword1 -> (Int,Int) -> (Maybe Int,Maybe Int) -> Maybe (Int,Int)
adjustMinYield (i,j) (minl,minr) (maxl,maxr) =
let len = j-i
adjust oldMinY maxY = let x = maybe oldMinY (\m -> len - m) maxY
in if x > oldMinY then x else oldMinY
minrAdj = adjust minr maxl
minlAdj = adjust minl maxr
in do
minlRes <- maybe (Just minlAdj) (\m -> if minlAdj > m then Nothing else Just minlAdj) maxl
minrRes <- maybe (Just minrAdj) (\m -> if minrAdj > m then Nothing else Just minrAdj) maxr
Just (minlRes,minrRes)
-- assumes that other component is in the same part
calcSubwords2Dependent :: InfoMap -> RangeDesc -> Int -> Int -> [Subword2]
calcSubwords2Dependent _ b c d | trace ("calcSubwords2Dependent " ++ show b ++ " " ++ show c ++ " " ++ show d) False = undefined
calcSubwords2Dependent infoMap (i,j,r) a1Idx a2Idx =
let a1Idx' = if a1Idx < a2Idx then a1Idx else a2Idx
a2Idx' = if a1Idx < a2Idx then a2Idx else a1Idx
subs = doCalcSubwords2Dependent infoMap (i,j,r) a1Idx' a2Idx'
in if a1Idx < a2Idx then subs
else [ (k,l,m,n) | (m,n,k,l) <- subs ]
doCalcSubwords2Dependent :: InfoMap -> RangeDesc -> Int -> Int -> [Subword2]
doCalcSubwords2Dependent infoMap desc@(i,j,r) a1Idx a2Idx =
assert (a1Idx < a2Idx) $
trace ("min yields: " ++ show minY1 ++ " " ++ show minY2 ++ " " ++ show minYLeft1 ++ " " ++
show minYLeft2 ++ " " ++ show minYRight1 ++ " " ++ show minYRight2 ++ " " ++ show minYBetween) $
trace ("max yields: " ++ show maxY1 ++ " " ++ show maxY2 ++ " " ++ show maxYLeft1 ++ " " ++
show maxYLeft2 ++ " " ++ show maxYRight1 ++ " " ++ show maxYRight2 ++ " " ++ show maxYBetween) $
result where
(minY1,maxY1) = infoFromPos infoMap (desc,a1Idx)
(minY2,maxY2) = infoFromPos infoMap (desc,a2Idx)
(minYLeft1,maxYLeft1) = combinedInfoLeftOf infoMap (desc,a1Idx)
(minYLeft2,maxYLeft2) = combinedInfoLeftOf infoMap (desc,a2Idx)
(minYRight1,maxYRight1) = combinedInfoRightOf infoMap (desc,a1Idx)
(minYRight2,maxYRight2) = combinedInfoRightOf infoMap (desc,a2Idx)
minYBetween = minYRight1 - minYRight2 - minY2
maxYBetween = if isNothing maxYRight1
then Nothing
else Just $ fromJust maxYRight1 - fromJust maxYRight2 - fromJust maxY2
neighbors = a1Idx + 1 == a2Idx
result | a1Idx == 0 && a2Idx == length r - 1 && neighbors =
[ (k,l,l,n) |
let (k,n) = (i,j)
, l <- [i+minY1..j-minY2]
]
| a1Idx == 0 && a2Idx == length r - 1 =
[ (k,l,m,n) |
let (k,n) = (i,j)
, l <- [i+minY1..j-minYRight1]
, m <- [l+minYBetween..j-minY2]
]
| a1Idx == 0 && neighbors =
[ (k,l,l,n) |
let k = i
, l <- [i+minY1..j-minYRight1]
, n <- [l+minY2..j-minYRight2]
]
| a1Idx == 0 =
[ (k,l,m,n) |
let k = i
, l <- [i+minY1..j-minYRight1]
, m <- [l+minYBetween..j-minY2-minYRight2]
, n <- [m+minY2..j-minYRight2]
]
| a2Idx == length r - 1 && neighbors =
[ (k,m,m,n) |
let n = j
, m <- [i+minYLeft2..j-minY2]
, k <- [i+minYLeft1..m-minY1]
]
| a2Idx == length r - 1 =
[ (k,l,m,n) |
let n = j
, m <- [i+minYLeft2..j-minY2]
, l <- [i+minY1+minYLeft1..m-minYBetween]
, k <- [i+minYLeft1..l-minY1]
]
| a1Idx > 0 && a2Idx < length r - 1 && neighbors =
[ (k,l,l,n) |
k <- [i+minYLeft1..j-minY1-minYRight1]
, l <- [k+minY1..j-minYRight1]
, n <- [l+minY2..j-minYRight2]
]
| a1Idx > 0 && a2Idx < length r - 1 =
[ (k,l,m,n) |
k <- [i+minYLeft1..j-minY1-minYRight1]
, l <- [k+minY1..j-minYRight1]
, m <- [l+minYBetween..j-minY2-minYRight2]
, n <- [m+minY2..j-minYRight2]
]
| otherwise = error "invalid conditions, e.g. a1Idx == a2Idx == 0"