module Persistence.Filtration (
FilterSimplex
, SimpleFiltration
, Filtration
, Extended (MinusInfty, Finite, Infinity)
, BarCode
, Landscape
, sim2String
, filtr2String
, getComplex
, getDimension
, simple2Filtr
, filterByWeightsFast
, makeRipsFiltrationFast
, makeRipsFiltrationFastPar
, filterByWeightsLight
, makeRipsFiltrationLight
, makeRipsFiltrationLightPar
, indexBarCodes
, indexBarCodesSimple
, scaleBarCodes
, scaleBarCodesSimple
, indexMetric
, bottleNeckDistance
, bottleNeckDistances
, calcLandscape
, evalLandscape
, evalLandscapeAll
, linearComboLandscapes
, avgLandscapes
, diffLandscapes
, normLp
, metricLp
) where
import Persistence.Util
import Persistence.SimplicialComplex
import Data.Maybe
import Data.List as L
import Data.Vector as V
import Data.Algorithm.MaximalCliques
import Control.Parallel.Strategies
type FilterSimplex = (Int, Vector Int, Vector Int)
type SimpleFiltration = (Int, Vector (Vector FilterSimplex))
type Filtration = Vector (Vector FilterSimplex)
data Extended a = Finite a
| Infinity
| MinusInfty
deriving (Eq, Show)
instance (Ord a, Eq a) => Ord (Extended a) where
_ > Infinity = False
Infinity > _ = True
Finite a > Finite b = a > b
MinusInfty > _ = False
_ > MinusInfty = True
Infinity >= _ = True
_ >= Infinity = False
Finite a >= Finite b = a >= b
MinusInfty >= MinusInfty = True
MinusInfty >= _ = False
Infinity < _ = False
_ < Infinity = True
Finite a < Finite b = a < b
MinusInfty < MinusInfty = False
MinusInfty < _ = True
_ <= Infinity = True
Infinity <= _ = False
Finite a <= Finite b = a <= b
MinusInfty <= _ = True
_ <= MinusInfty = False
instance Num a => Num (Extended a) where
_ + Infinity = Infinity
_ + MinusInfty = MinusInfty
Infinity + _ = Infinity
MinusInfty + _ = MinusInfty
Finite x + Finite y = Finite (x + y)
_ - Infinity = MinusInfty
_ - MinusInfty = Infinity
Infinity - _ = Infinity
MinusInfty - _ = MinusInfty
Finite x - Finite y = Finite (x - y)
_ * Infinity = Infinity
_ * MinusInfty = MinusInfty
Infinity * _ = Infinity
MinusInfty * _ = MinusInfty
Finite x * Finite y = Finite (x * y)
abs Infinity = Infinity
abs MinusInfty = Infinity
abs (Finite x) = Finite $ abs x
fromInteger = Finite . fromInteger
signum Infinity = Finite (fromInteger 1)
signum MinusInfty = Finite (fromInteger (-1))
signum (Finite x) = Finite (signum x)
fi :: (Integral a, Floating b) => Extended a -> Extended b
fi (Finite i) = Finite $ fromIntegral i
fi Infinity = Infinity
fi MinusInfty = MinusInfty
unExtend :: Floating a => Extended a -> a
unExtend Infinity = 1.0/0.0
unExtend (Finite x) = x
unExtend MinusInfty = -1.0/0.0
type BarCode a = (a, Extended a)
type Landscape = Vector (Vector (Extended Double, Extended Double))
sim2String :: FilterSimplex -> String
sim2String (index, vertices, faces) =
"Filtration index: " L.++ (show index) L.++
"; Vertex indices: " L.++ (show vertices) L.++
"; Boundary indices: " L.++ (show faces) L.++ "\n"
filtr2String :: Either SimpleFiltration Filtration -> String
filtr2String (Left f) =
"Simple filtration:\n" L.++ ((intercalate "\n") $ toList
$ V.map (L.concat . toList . (V.map sim2String)) $ snd f)
filtr2String (Right f) =
(intercalate "\n") $ toList $ V.map (L.concat . toList . (V.map sim2String)) f
getComplex :: Int -> Either SimpleFiltration Filtration -> SimplicialComplex
getComplex index (Left (n, simplices)) =
(n, dropRightWhile V.null
$ V.map (V.map not1 . V.filter (\(i, _, _) -> i <= index)) simplices)
getComplex index (Right simplices) =
(V.length $ V.filter (\v ->
one v <= index) (V.head simplices),
dropRightWhile V.null $ V.map (V.map not1
. V.filter (\(i, _, _) -> i <= index)) (V.tail simplices))
getDimension :: Either SimpleFiltration Filtration -> Int
getDimension (Left sf) = V.length $ snd sf
getDimension (Right f) = V.length f - 1
simple2Filtr :: SimpleFiltration -> Filtration
simple2Filtr (n, x) =
let x' = (V.map (\(i, v, _) -> (i, v, V.reverse v)) $ V.head x) `cons` (V.tail x)
in (mapWithIndex (\i (a,b,c) ->
(a,i `cons` V.empty,c)) $ V.replicate n (0, V.empty, V.empty)) `cons` x'
filterByWeightsFast :: Ord a
=> Either (Vector a) [a]
-> (SimplicialComplex, Graph a)
-> SimpleFiltration
filterByWeightsFast scales' ((numVerts, simplices), graph) =
let scales = case scales' of Left v -> V.toList v; Right l -> l
edgeInSimplex edge simplex =
(V.any (\x -> V.head edge == x) simplex) && (V.any (\x -> V.last edge == x) simplex)
edgeTooLong scale edge = scale <= (fst $ graph ! (edge ! 0) ! (edge ! 1))
maxIndex = (L.length scales) - 1
calcIndices 0 [] sc = sc
calcIndices i (scl:scls) sc =
let longEdges = V.filter (edgeTooLong scl) $ V.map (\(i, v, f) -> v) $ V.head sc
in calcIndices (i - 1) scls $ V.map (V.map (\(j, v, f) ->
if j == 0 then
if V.any (\edge -> edgeInSimplex edge v) longEdges then (i, v, f)
else (0, v, f)
else (j, v, f))) sc
sortFiltration simplices =
let sortedSimplices =
V.map (quickSort (\((i, _, _), _) ((j, _, _), _) -> i > j)) $
V.map (mapWithIndex (\i s -> (s, i))) simplices
newFaces dim (i, v, f) =
let findNew j =
case V.findIndex (\x -> snd x == j) $ sortedSimplices ! (dim - 1) of
Just k -> k
Nothing -> error "Persistence.Filtration.sortFiltration.newFaces.findNew. This is a bug. Please email the Persistence maintainers."
in (i, v, (V.map findNew f))
in
if V.null simplices then simplices
else mapWithIndex (\i ss -> V.map ((newFaces i) . fst) ss) sortedSimplices
sortBoundaries = V.map (V.map (\(i, v, f) -> (i, v, quickSort (\a b -> a <= b) f)))
in (numVerts, sortBoundaries $ sortFiltration $
calcIndices maxIndex (L.tail scales) $
V.map (V.map (\(v, f) -> (0, v, f))) $ simplices)
makeRipsFiltrationFast :: (Ord a, Eq b)
=> Either (Vector a) [a]
-> (b -> b -> a)
-> Either (Vector b) [b]
-> SimpleFiltration
makeRipsFiltrationFast scales metric =
let scale = case scales of Left v -> V.head v; Right l -> L.head l
in (filterByWeightsFast scales) . (makeRipsComplexFast scale metric)
makeRipsFiltrationFastPar :: (Ord a, Eq b)
=> Either (Vector a) [a]
-> (b -> b -> a)
-> Either (Vector b) [b]
-> SimpleFiltration
makeRipsFiltrationFastPar scales metric =
let scale = case scales of Left v -> V.head v; Right l -> L.head l
in (filterByWeightsFast scales) . (makeRipsComplexFastPar scale metric)
filterByWeightsLight :: Ord a
=> Either (Vector a) [a]
-> (b -> b -> a)
-> Either (Vector b) [b]
-> SimplicialComplex
-> SimpleFiltration
filterByWeightsLight scales' metric dataSet (numVerts, simplices) =
let scales = case scales' of Left v -> V.toList v; Right l -> l
edgeInSimplex edge simplex =
(V.any (\x -> V.head edge == x) simplex) && (V.any (\x -> V.last edge == x) simplex)
vector = case dataSet of Left v -> v; Right l -> V.fromList l
edgeTooLong scale edge = scale <= (metric (vector ! (edge ! 0)) (vector ! (edge ! 1)))
maxIndex = (L.length scales) - 1
calcIndices 0 [] sc = sc
calcIndices i (scl:scls) sc =
let longEdges = V.filter (edgeTooLong scl) $ V.map (\(i, v, f) -> v) $ V.head sc
in calcIndices (i - 1) scls $ V.map (V.map (\(j, v, f) ->
if j == 0 then
if V.any (\edge -> edgeInSimplex edge v) longEdges then (i, v, f)
else (0, v, f)
else (j, v, f))) sc
sortFiltration simplices =
let sortedSimplices =
V.map (quickSort (\((i, _, _), _) ((j, _, _), _) -> i > j)) $
V.map (mapWithIndex (\i s -> (s, i))) simplices
newFaces dim (i, v, f) =
let findNew j =
case V.findIndex (\x -> snd x == j) $ sortedSimplices ! (dim - 1) of
Just k -> k
Nothing -> error "Persistence.Filtration.filterByWeightsLight.sortFiltration.newFaces.findNew. This is a bug. Please email the Persistence maintainers."
in (i, v, (V.map findNew f))
in
if V.null simplices then simplices
else mapWithIndex (\i ss -> V.map ((newFaces i) . fst) ss) sortedSimplices
in (numVerts, sortFiltration $
calcIndices maxIndex (L.tail scales) $
V.map (V.map (\(v, f) -> (0, v, f))) $ simplices)
makeRipsFiltrationLight :: (Ord a, Eq b)
=> Either (Vector a) [a]
-> (b -> b -> a)
-> Either (Vector b) [b]
-> SimpleFiltration
makeRipsFiltrationLight scales metric dataSet =
let scale = case scales of Left v -> V.head v; Right l -> L.head l
in filterByWeightsLight scales metric dataSet $ makeRipsComplexLight scale metric dataSet
makeRipsFiltrationLightPar :: (Ord a, Eq b)
=> Either (Vector a) [a]
-> (b -> b -> a)
-> Either (Vector b) [b]
-> SimpleFiltration
makeRipsFiltrationLightPar scales metric dataSet =
let scale = case scales of Left v -> V.head v; Right l -> L.head l
in filterByWeightsLight scales metric dataSet $ makeRipsComplexLightPar scale metric dataSet
type Chain = Vector Int
indexBarCodes :: Filtration -> Vector (Vector (BarCode Int))
indexBarCodes filtration =
let maxdim = getDimension (Right filtration)
removeUnmarked :: Vector Int -> Vector (Int, Chain) -> Vector (Int, Chain)
removeUnmarked marked = V.map (\(i, c) -> (i, V.filter (\j -> V.elem j marked) c))
removePivotRows :: Vector (Maybe Chain) -> Chain -> Chain
removePivotRows slots chain =
if V.null chain then V.empty
else
case slots ! (V.head chain) of
Nothing -> chain
Just c -> removePivotRows slots (chain `uin` c)
makeFiniteBarCodes :: Int
-> Vector Int
-> Vector (Maybe Chain)
-> Vector (Int, Chain)
-> Vector (BarCode Int)
-> (Vector Int, Vector (Maybe Chain), Vector (BarCode Int))
makeFiniteBarCodes dim newMarked slots boundaries barcodes =
if V.null boundaries then (newMarked, slots, barcodes)
else
let boundary = V.head boundaries
reduced = removePivotRows slots $ snd boundary
in
if V.null reduced then
makeFiniteBarCodes dim
(newMarked `snoc` (fst boundary)) slots (V.tail boundaries) barcodes
else
let pivot = V.head reduced
in makeFiniteBarCodes dim newMarked (replaceElem pivot
(Just reduced) slots) (V.tail boundaries) ((one $ filtration ! (dim - 1) ! pivot,
Finite $ one $ filtration ! dim ! (fst boundary)) `cons` barcodes)
loopFiniteBarCodes :: Int
-> Vector (Vector Int)
-> Vector (Vector (Maybe Chain))
-> Vector (Vector (BarCode Int))
-> ( Vector (Vector Int), Vector (Vector (Maybe Chain))
, Vector (Vector (BarCode Int)))
loopFiniteBarCodes dim marked slots barcodes =
if dim > maxdim then (marked, V.tail slots, (V.tail barcodes) V.++ (V.empty `cons` V.empty))
else
let numSlots = if dim == 0 then 0 else V.length $ filtration ! (dim - 1)
boundaries =
removeUnmarked (V.last marked)
$ mapWithIndex (\i (_, _, f) -> (i, f)) $ filtration ! dim
(newMarked, newSlots, newCodes) =
makeFiniteBarCodes dim V.empty (V.replicate numSlots Nothing) boundaries V.empty
in loopFiniteBarCodes (dim + 1) (marked `snoc` newMarked)
(slots `snoc` newSlots) (barcodes V.++ (newCodes `cons` V.empty))
makeInfiniteBarCodes :: Int -> Vector Int -> Vector (Maybe Chain) -> Vector (BarCode Int)
makeInfiniteBarCodes dim marked slots =
V.map (\i -> (one $ filtration ! dim ! i, Infinity))
$ V.filter (\i -> slots ! i == Nothing) marked
loopInfiniteBarCodes :: Int
-> ( Vector (Vector Int), Vector (Vector (Maybe Chain))
, Vector (Vector (BarCode Int)))
-> Vector (Vector (BarCode Int))
loopInfiniteBarCodes dim (marked, slots, barcodes) =
if dim > maxdim then barcodes
else
loopInfiniteBarCodes (dim + 1) (marked, slots, replaceElem dim ((barcodes ! dim)
V.++ (makeInfiniteBarCodes dim (marked ! dim) (slots ! dim))) barcodes)
in V.map (V.filter (\(a, b) -> b /= Finite a))
$ loopInfiniteBarCodes 0 $ loopFiniteBarCodes 0 V.empty V.empty V.empty
indexBarCodesSimple :: SimpleFiltration -> Vector (Vector (BarCode Int))
indexBarCodesSimple (numVerts, allSimplices) =
let removeUnmarked marked = V.filter (\x -> V.elem x marked)
removePivotRows reduced chain =
if V.null chain then chain
else
case reduced ! (V.head chain) of
Nothing -> chain
Just t -> removePivotRows reduced (chain `uin` t)
makeBarCodesAndMark :: Int
-> Int
-> Vector Int
-> Vector (Maybe (Vector Int))
-> Vector (Int, Vector Int, Vector Int)
-> (Vector (BarCode Int), Vector Int)
-> (Vector (BarCode Int), Vector Int, Vector Int)
makeBarCodesAndMark dim index marked reduced simplices (codes, newMarked)
| V.null simplices = (codes, newMarked, V.findIndices (\x -> x == Nothing) reduced)
| V.null d =
makeBarCodesAndMark dim (index + 1) marked reduced
(V.tail simplices) (codes, newMarked `snoc` index)
| otherwise =
let maxindex = V.head d
begin = one $ allSimplices ! (dim - 1) ! maxindex
in makeBarCodesAndMark dim (index + 1) marked
(replaceElem maxindex (Just d) reduced) (V.tail simplices)
((begin, Finite i) `cons` codes, newMarked)
where (i, v, f) = V.head simplices
d = removePivotRows reduced $ removeUnmarked marked f
makeEdgeCodes :: Int
-> Vector (Maybe (Vector Int))
-> Vector (Int, Vector Int, Vector Int)
-> (Vector (BarCode Int), Vector Int)
-> (Vector (BarCode Int), Vector Int, Vector Int)
makeEdgeCodes index reduced edges (codes, marked)
| V.null edges = (codes, marked, V.findIndices (\x -> x == Nothing) reduced)
| V.null d =
makeEdgeCodes (index + 1) reduced (V.tail edges) (codes, marked `snoc` index)
| otherwise =
makeEdgeCodes (index + 1) (replaceElem (V.head d)
(Just d) reduced) (V.tail edges) ((0, Finite i) `cons` codes, marked)
where (i, v, f) = V.head edges
d = removePivotRows reduced f
makeFiniteBarCodes :: Int
-> Int
-> Vector (Vector (BarCode Int))
-> Vector (Vector Int)
-> Vector (Vector Int)
-> ( Vector (Vector (BarCode Int))
, Vector (Vector Int)
, Vector (Vector Int)
)
makeFiniteBarCodes dim maxdim barcodes marked slots =
if dim == maxdim then (barcodes, marked, slots)
else
let (newCodes, newMarked, unusedSlots) =
makeBarCodesAndMark dim 0 (V.last marked) (V.replicate (V.length
$ allSimplices ! (dim - 1)) Nothing) (allSimplices ! dim) (V.empty, V.empty)
in makeFiniteBarCodes (dim + 1) maxdim
(barcodes V.++ (newCodes `cons` V.empty))
(marked `snoc` newMarked) (slots `snoc` unusedSlots)
makeInfiniteBarCodes :: ( Vector (Vector (BarCode Int))
, Vector (Vector Int)
, Vector (Vector Int)
)
-> Vector (Vector (BarCode Int))
makeInfiniteBarCodes (barcodes, marked, unusedSlots) =
let
makeCodes :: Int -> Vector (BarCode Int) -> Vector (BarCode Int)
makeCodes i codes =
let slots = unusedSlots ! i; marks = marked ! i
in codes V.++ (V.map (\j -> (one
$ allSimplices ! (i - 1) ! j, Infinity)) $ slots |^| marks)
loop :: Int -> Vector (Vector (BarCode Int)) -> Vector (Vector (BarCode Int))
loop i v
| V.null v = V.empty
| i == 0 =
((V.head v) V.++ (V.map (\j -> (0, Infinity))
$ (unusedSlots ! 0) |^| (marked ! 0))) `cons` (loop 1 $ V.tail v)
| otherwise = (makeCodes i $ V.head v) `cons` (loop (i + 1) $ V.tail v)
in loop 0 barcodes
edges = V.map (\(i, v, f) -> (i, v, (V.reverse v))) $ V.head allSimplices
numEdges = V.length edges
(fstCodes, fstMarked, fstSlots) =
makeEdgeCodes 0 (V.replicate numVerts Nothing) edges (V.empty, V.empty)
verts = 0 `range` (numVerts - 1)
in
V.map (V.filter (\(a, b) -> b /= Finite a))
$ makeInfiniteBarCodes $ makeFiniteBarCodes 1
(V.length allSimplices) (fstCodes `cons` V.empty)
(verts `cons` (fstMarked `cons` V.empty)) (fstSlots `cons` V.empty)
scaleBarCodes :: Either (Vector a) [a] -> Filtration -> Vector (Vector (BarCode a))
scaleBarCodes scales filtration =
let s = V.reverse $ (\a -> case a of Left v -> v; Right l -> V.fromList l) scales
translateBarCode (i, Infinity) = (s ! i, Infinity)
translateBarCode (i, Finite j) = (s ! i, Finite $ s ! j)
in V.map (V.map translateBarCode) $ indexBarCodes filtration
scaleBarCodesSimple :: Either (Vector a) [a] -> SimpleFiltration -> Vector (Vector (BarCode a))
scaleBarCodesSimple scales filtration =
let s = V.reverse $ (\a -> case a of Left v -> v; Right l -> V.fromList l) scales
translateBarCode (i, Infinity) = (s ! i, Infinity)
translateBarCode (i, Finite j) = (s ! i, Finite $ s ! j)
in V.map (V.map translateBarCode) $ indexBarCodesSimple filtration
indexMetric :: BarCode Int -> BarCode Int -> Extended Double
indexMetric (_, Finite _) (_, Infinity) = Infinity
indexMetric (_, Infinity) (_, Finite _) = Infinity
indexMetric (i, Infinity) (j, Infinity) =
Finite $ fromIntegral $ abs $ i - j
indexMetric (i, Finite j) (k, Finite l) =
let x = i - k; y = j - l
in Finite $ sqrt $ fromIntegral $ x*x + y*y
bottleNeckDistance :: Ord b
=> (BarCode a -> BarCode a -> Extended b)
-> Vector (BarCode a)
-> Vector (BarCode a)
-> Maybe (Extended b)
bottleNeckDistance metric diagram1 diagram2
| V.null diagram1 = Nothing
| V.null diagram2 = Nothing
| otherwise =
let first = V.maximum $ V.map (\p -> V.minimum $ V.map (metric p) diagram2) diagram1
second = V.maximum $ V.map (\p -> V.minimum $ V.map (metric p) diagram1) diagram2
in Just $ max first second
bottleNeckDistances :: Ord b => (BarCode a -> BarCode a -> Extended b)
-> Vector (Vector (BarCode a))
-> Vector (Vector (BarCode a))
-> Vector (Maybe (Extended b))
bottleNeckDistances metric diagrams1 diagrams2 =
let d = (L.length diagrams1) - (L.length diagrams2)
in
if d >= 0
then (V.zipWith (bottleNeckDistance metric) diagrams1 diagrams2) V.++ (V.replicate d Nothing)
else (V.zipWith (bottleNeckDistance metric) diagrams1 diagrams2) V.++ (V.replicate (-d) Nothing)
calcLandscape :: Vector (BarCode Int) -> Landscape
calcLandscape brcds =
let half = Finite 0.5
(i,j) `leq` (k,l) = i > k || j <= l
innerLoop :: (Extended Double, Extended Double)
-> Vector (Extended Double, Extended Double)
-> Landscape
-> Landscape
innerLoop (b, d) barcodes result =
case V.findIndex (\(b', d') -> d' > d) barcodes of
Nothing ->
outerLoop barcodes (((V.fromList [(0, b), (Infinity, 0)])
V.++ (V.head result)) `cons` (V.tail result))
Just i -> let (b', d') = barcodes ! i in
if b' >= d then
if b == d then
let new = [(Finite 0.0, b')]
in
if d' == Infinity then
outerLoop (rmIndex i barcodes) (((V.fromList ((Infinity, Infinity):new))
V.++ (V.head result)) `cons` (V.tail result))
else
innerLoop (b', d') (rmIndex i barcodes)
((V.fromList ((half*(b' + d'), half*(d' - b')):new)
V.++ (V.head result)) `cons` (V.tail result))
else
let new = [(Finite 0.0, d), (Finite 0.0, b')]
in
if d' == Infinity then
outerLoop (rmIndex i barcodes) (((V.fromList ((Infinity, Infinity):new))
V.++ (V.head result)) `cons` (V.tail result))
else
innerLoop (b', d') (rmIndex i barcodes)
(((V.fromList ((half*(b' + d'), half*(d' - b')):new))
V.++ (V.head result)) `cons` (V.tail result))
else
let newbr = (half*(b' + d), half*(d - b'))
in
if d' == Infinity then
outerLoop (orderedInsert leq newbr barcodes)
(((V.fromList [(Infinity, Infinity), newbr])
V.++ (V.head result)) `cons` (V.tail result))
else
innerLoop (b', d') (orderedInsert leq newbr barcodes)
(((V.fromList [(half*(b' + d'), half*(d' - b')), newbr])
V.++ (V.head result)) `cons` (V.tail result))
outerLoop :: Vector (Extended Double, Extended Double) -> Landscape -> Landscape
outerLoop barcodes result =
if not $ V.null barcodes then
let (b, d) = V.head barcodes
in
if (b, d) == (MinusInfty, Infinity)
then
outerLoop (V.tail barcodes)
((V.fromList [(MinusInfty, Infinity),
(Infinity, Infinity)]) `cons` result)
else if d == Infinity
then
outerLoop (V.tail barcodes) ((V.fromList
[(MinusInfty, Finite 0.0),(b, Finite 0.0),(Infinity,Infinity)]) `cons` result)
else
let newCritPoints =
if b == Infinity
then [(MinusInfty, Infinity)]
else [(MinusInfty, Finite 0.0), (half*(b + d), half*(d - b))]
in innerLoop (b, d) (V.tail barcodes) ((V.fromList newCritPoints) `cons` result)
else result
in V.map (quickSort (\(x1, _) (x2, _) -> x1 > x2))
$ outerLoop (quickSort leq $ V.map (\(i, j) -> (fi $ Finite i, fi j)) brcds) V.empty
evalLandscape :: Landscape -> Int -> Extended Double -> Extended Double
evalLandscape landscape i arg =
let fcn = landscape ! i
findPointNeighbors :: Ord a => Int -> a -> Vector a -> (Int, Int)
findPointNeighbors helper x vector =
let len = V.length vector
i = len `div` 2
y = vector ! i
in
if x == y
then (helper + i, helper + i)
else if x > y
then
case vector !? (i + 1) of
Nothing -> (helper + i, helper + i)
Just z ->
if x < z
then (helper + i, helper + i + 1)
else findPointNeighbors (helper + i) x $ V.drop i vector
else
case vector !? (i - 1) of
Nothing -> (helper + i, helper + i)
Just z ->
if x > z
then (helper + i - 1, helper + i)
else findPointNeighbors helper x $ V.take i vector
(i1, i2) = findPointNeighbors 0 arg $ V.map fst fcn
(x1, x2) = (fst $ fcn ! i1, fst $ fcn ! i2)
(y1, y2) = (snd $ fromMaybe (error "Persistence.Filtration.evalLandscape. This is a bug. Please email the Persistence mainstainers.") $ V.find (\a -> x1 == fst a) fcn, snd $ fromMaybe (error "Persistence.Filtration.evalLandscape. This is a bug. Please email the Persistence mainstainers.") $ V.find (\a -> x2 == fst a) fcn)
in
if x1 == x2
then y1
else
case (x1, x2) of
(MinusInfty, Infinity) -> arg
(MinusInfty, Finite _) -> y1
(Finite a, Finite b) ->
case arg of
Finite c ->
let t = Finite $ (c - a)/(b - a)
in t*y2 + ((Finite 1.0) - t)*y1
_ -> error "Persistence.Filtration.evalLandscape.findPointNeighbors. This is a bug. Please email the Persistence maintainers."
(Finite a, Infinity) ->
case arg of
Infinity -> y2
Finite c ->
case y2 of
Infinity -> Finite $ c - a
Finite 0.0 -> Finite 0.0
_ -> error $ "Persistence.Filtration.evalLandscape: y2 = " L.++ (show y2) L.++ ". This is a bug. Please email the Persistence maintainers."
_ -> error "Persistence.Filtration.evalLandscape.findPointNeighbors: bad argument. This is a bug. Please email the Persistence maintainers."
anything -> error $ "Persistence.Filtration.evalLandscape.findPointNeighbors: " L.++ (show anything) L.++ ". This is a bug. Please email the Persistence maintainers."
evalLandscapeAll :: Landscape -> Extended Double -> Vector (Extended Double)
evalLandscapeAll landscape arg =
if V.null landscape then V.empty
else (evalLandscape landscape 0 arg) `cons` (evalLandscapeAll (V.tail landscape) arg)
linearComboLandscapes :: [Double] -> [Landscape] -> Landscape
linearComboLandscapes coeffs landscapes =
let maxlen = L.maximum $ L.map V.length landscapes
emptylayer = V.fromList [(MinusInfty, Finite 0.0), (Infinity, Finite 0.0)]
landscapes' = L.map (\l -> l V.++ (V.replicate (maxlen - V.length l) emptylayer)) landscapes
myconcat v1 v2
| V.null v1 = v2
| V.null v2 = v1
| otherwise = ((V.head v1) V.++ (V.head v2)) `cons` (myconcat (V.tail v1) (V.tail v2))
xs = L.map (V.map (V.map fst)) landscapes'
concatted = L.foldl myconcat V.empty xs
unionXs = V.map ((quickSort (>)) . V.fromList . L.nub . V.toList) concatted
yVals = L.map (\landscape ->
mapWithIndex (\i v -> V.map (evalLandscape landscape i) v) unionXs) landscapes'
yVals' = L.zipWith (\coeff yvals ->
V.map (V.map ((Finite coeff)*)) yvals) coeffs yVals
finalY = L.foldl1 (\acc new -> V.zipWith (V.zipWith (+)) acc new) yVals'
in V.zipWith V.zip unionXs finalY
avgLandscapes :: [Landscape] -> Landscape
avgLandscapes landscapes =
let numscapes = L.length landscapes
coeffs = L.replicate numscapes (1.0/(fromIntegral numscapes))
in linearComboLandscapes coeffs landscapes
diffLandscapes :: Landscape -> Landscape -> Landscape
diffLandscapes scape1 scape2 = linearComboLandscapes [1, -1] [scape1, scape2]
normLp :: Extended Double
-> (Double, Double)
-> Double
-> Landscape
-> Maybe Double
normLp p interval step landscape =
let len = V.length landscape
a = fst interval
b = snd interval
fcn x =
let vals = V.map (\n ->
abs $ unExtend $ evalLandscape landscape n (Finite x)) $ 0 `range` (len - 1)
in
case p of
Infinity -> V.maximum vals
Finite 1.0 -> V.sum vals
Finite 2.0 -> sqrt $ V.sum $ V.map (\a -> a*a) vals
Finite p' -> (**(1.0/p')) $ V.sum $ V.map (**p') vals
computeSum :: Double -> Double -> Double
computeSum currentX result =
let nextX = currentX + step
in
if nextX > b then result + (fcn nextX)
else computeSum nextX (result + 2.0*(fcn nextX))
in
if p < (Finite 1.0) then Nothing
else Just $ 0.5*step*(computeSum a $ fcn a)
metricLp :: Extended Double
-> (Double, Double)
-> Double
-> Landscape
-> Landscape
-> Maybe Double
metricLp p interval step scape1 scape2 = normLp p interval step $ diffLandscapes scape1 scape2