packages feed

bio 0.3.3.4 → 0.3.5

raw patch · 26 files changed

+1731/−61 lines, 26 filesdep +mtldep +old-timedep +randomdep ~bytestringPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: mtl, old-time, random

Dependency ranges changed: bytestring

API changes (from Hackage documentation)

- Bio.Sequence.TwoBit: instance Arbitrary Word8
+ Bio.Alignment.Soap: SA :: !SeqName -> !SeqData -> !QualData -> !Int -> !Char -> !Offset -> !Strand -> !SeqName -> !Offset -> !Int -> ![SoapAlignMismatch] -> SoapAlign
+ Bio.Alignment.Soap: SAM :: !Char -> !Char -> !Offset -> !Qual -> SoapAlignMismatch
+ Bio.Alignment.Soap: data SoapAlign
+ Bio.Alignment.Soap: data SoapAlignMismatch
+ Bio.Alignment.Soap: group :: [SoapAlign] -> [[SoapAlign]]
+ Bio.Alignment.Soap: instance Eq SoapAlign
+ Bio.Alignment.Soap: instance Eq SoapAlignMismatch
+ Bio.Alignment.Soap: instance Ord SoapAlign
+ Bio.Alignment.Soap: instance Ord SoapAlignMismatch
+ Bio.Alignment.Soap: instance Read SoapAlign
+ Bio.Alignment.Soap: instance Read SoapAlignMismatch
+ Bio.Alignment.Soap: instance Show SoapAlign
+ Bio.Alignment.Soap: instance Show SoapAlignMismatch
+ Bio.Alignment.Soap: length :: SoapAlign -> !Offset
+ Bio.Alignment.Soap: mismatchSeqPos :: SoapAlign -> SoapAlignMismatch -> SeqPos
+ Bio.Alignment.Soap: mismatches :: SoapAlign -> ![SoapAlignMismatch]
+ Bio.Alignment.Soap: name :: SoapAlign -> !SeqName
+ Bio.Alignment.Soap: nhit :: SoapAlign -> !Int
+ Bio.Alignment.Soap: nmismatch :: SoapAlign -> !Int
+ Bio.Alignment.Soap: offset :: SoapAlignMismatch -> !Offset
+ Bio.Alignment.Soap: pairend :: SoapAlign -> !Char
+ Bio.Alignment.Soap: parse :: (Error e, MonadError e m) => ByteString -> m SoapAlign
+ Bio.Alignment.Soap: parseMismatch :: (Error e, MonadError e m) => ByteString -> m SoapAlignMismatch
+ Bio.Alignment.Soap: qual :: SoapAlign -> !QualData
+ Bio.Alignment.Soap: qualnt :: SoapAlignMismatch -> !Qual
+ Bio.Alignment.Soap: readnt :: SoapAlignMismatch -> !Char
+ Bio.Alignment.Soap: refCSeqLoc :: SoapAlign -> ContigSeqLoc
+ Bio.Alignment.Soap: refSeqLoc :: SoapAlign -> SeqLoc
+ Bio.Alignment.Soap: refSeqPos :: SoapAlign -> SeqPos
+ Bio.Alignment.Soap: refname :: SoapAlign -> !SeqName
+ Bio.Alignment.Soap: refnt :: SoapAlignMismatch -> !Char
+ Bio.Alignment.Soap: refstart :: SoapAlign -> !Offset
+ Bio.Alignment.Soap: sequ :: SoapAlign -> !SeqData
+ Bio.Alignment.Soap: strand :: SoapAlign -> !Strand
+ Bio.Alignment.Soap: unparse :: SoapAlign -> ByteString
+ Bio.Alignment.Soap: unparseMismatch :: SoapAlignMismatch -> ByteString
+ Bio.GFF3.Escape: escapeAllBut :: String -> ByteString -> ByteString
+ Bio.GFF3.Escape: escapeAllOf :: String -> ByteString -> ByteString
+ Bio.GFF3.Escape: escapeByteString :: (Char -> Bool) -> ByteString -> ByteString
+ Bio.GFF3.Escape: unEscapeByteString :: (Error e, MonadError e m) => ByteString -> m ByteString
+ Bio.GFF3.Feature: Feature :: !ByteString -> !ByteString -> !ByteString -> !Offset -> !Offset -> !Maybe Double -> !Maybe Strand -> !Maybe Offset -> ![GFFAttr] -> Feature
+ Bio.GFF3.Feature: GFFAttr :: !ByteString -> ![ByteString] -> GFFAttr
+ Bio.GFF3.Feature: attrByTag :: ByteString -> Feature -> [ByteString]
+ Bio.GFF3.Feature: attrTag :: GFFAttr -> !ByteString
+ Bio.GFF3.Feature: attrValues :: GFFAttr -> ![ByteString]
+ Bio.GFF3.Feature: attributes :: Feature -> ![GFFAttr]
+ Bio.GFF3.Feature: contigLoc :: Feature -> ContigLoc
+ Bio.GFF3.Feature: data Feature
+ Bio.GFF3.Feature: data GFFAttr
+ Bio.GFF3.Feature: end :: Feature -> !Offset
+ Bio.GFF3.Feature: ftype :: Feature -> !ByteString
+ Bio.GFF3.Feature: ids :: Feature -> [ByteString]
+ Bio.GFF3.Feature: instance Eq Feature
+ Bio.GFF3.Feature: instance Eq GFFAttr
+ Bio.GFF3.Feature: instance Ord Feature
+ Bio.GFF3.Feature: instance Ord GFFAttr
+ Bio.GFF3.Feature: instance Show Feature
+ Bio.GFF3.Feature: instance Show GFFAttr
+ Bio.GFF3.Feature: length :: Feature -> Offset
+ Bio.GFF3.Feature: loc :: Feature -> Loc
+ Bio.GFF3.Feature: name :: (Error e, MonadError e m) => Feature -> m SeqName
+ Bio.GFF3.Feature: parentIds :: Feature -> [ByteString]
+ Bio.GFF3.Feature: parse :: (Error e, MonadError e m) => ByteString -> m Feature
+ Bio.GFF3.Feature: parseWithFasta :: (Error e, MonadError e m) => ByteString -> m ([Feature], [ByteString])
+ Bio.GFF3.Feature: phase :: Feature -> !Maybe Offset
+ Bio.GFF3.Feature: score :: Feature -> !Maybe Double
+ Bio.GFF3.Feature: seqLoc :: Feature -> SeqLoc
+ Bio.GFF3.Feature: seqid :: Feature -> !ByteString
+ Bio.GFF3.Feature: source :: Feature -> !ByteString
+ Bio.GFF3.Feature: start :: Feature -> !Offset
+ Bio.GFF3.Feature: strand :: Feature -> !Maybe Strand
+ Bio.GFF3.Feature: unparse :: Feature -> ByteString
+ Bio.GFF3.FeatureHier: checkInvariants :: FeatureHier -> [String]
+ Bio.GFF3.FeatureHier: children :: FeatureHier -> Feature -> [Feature]
+ Bio.GFF3.FeatureHier: childrenM :: (MonadReader FeatureHier m) => Feature -> m [Feature]
+ Bio.GFF3.FeatureHier: data FeatureHier
+ Bio.GFF3.FeatureHier: delete :: (Error e, MonadError e m) => Feature -> FeatureHier -> m FeatureHier
+ Bio.GFF3.FeatureHier: features :: FeatureHier -> (Set Feature)
+ Bio.GFF3.FeatureHier: fromList :: (Error e, MonadError e m) => [Feature] -> m FeatureHier
+ Bio.GFF3.FeatureHier: insert :: (Error e, MonadError e m) => Feature -> FeatureHier -> m FeatureHier
+ Bio.GFF3.FeatureHier: instance Show FeatureHier
+ Bio.GFF3.FeatureHier: lookupId :: (Error e, MonadError e m) => FeatureHier -> ByteString -> m Feature
+ Bio.GFF3.FeatureHier: lookupIdChildren :: (Error e, MonadError e m) => FeatureHier -> ByteString -> m [Feature]
+ Bio.GFF3.FeatureHier: parents :: FeatureHier -> Feature -> [Feature]
+ Bio.GFF3.FeatureHier: parentsM :: (MonadReader FeatureHier m) => Feature -> m [Feature]
+ Bio.GFF3.FeatureHierSequences: asksGFF :: (Error e, MonadError e m, MonadReader FeatureHierSequences m) => (FeatureHierSequences -> a -> m b) -> a -> m b
+ Bio.GFF3.FeatureHierSequences: children :: FeatureHierSequences -> Feature -> [Feature]
+ Bio.GFF3.FeatureHierSequences: data FeatureHierSequences
+ Bio.GFF3.FeatureHierSequences: featureSequence :: (Error e, MonadError e m) => FeatureHierSequences -> Feature -> m Sequence
+ Bio.GFF3.FeatureHierSequences: features :: FeatureHierSequences -> Set Feature
+ Bio.GFF3.FeatureHierSequences: fromLists :: (Error e, MonadError e m) => [Feature] -> [Sequence] -> m FeatureHierSequences
+ Bio.GFF3.FeatureHierSequences: getSequence :: (Error e, MonadError e m) => FeatureHierSequences -> SeqName -> m SeqData
+ Bio.GFF3.FeatureHierSequences: instance Show FeatureHierSequences
+ Bio.GFF3.FeatureHierSequences: lookupId :: (Error e, MonadError e m) => FeatureHierSequences -> SeqName -> m Feature
+ Bio.GFF3.FeatureHierSequences: parents :: FeatureHierSequences -> Feature -> [Feature]
+ Bio.GFF3.FeatureHierSequences: parse :: (Error e, MonadError e m) => ByteString -> m FeatureHierSequences
+ Bio.GFF3.FeatureHierSequences: runGFF :: FilePath -> (ErrorT String (Reader FeatureHierSequences) a) -> ErrorT String IO a
+ Bio.GFF3.FeatureHierSequences: runGFFIO :: FilePath -> (ErrorT String (ReaderT FeatureHierSequences IO) a) -> ErrorT String IO a
+ Bio.GFF3.FeatureHierSequences: seqData :: (Error e, MonadError e m) => FeatureHierSequences -> SeqLoc -> m SeqData
+ Bio.GFF3.FeatureHierSequences: sequences :: FeatureHierSequences -> [Sequence]
+ Bio.GFF3.SGD: chromosomes :: FeatureHierSequences -> [Feature]
+ Bio.GFF3.SGD: geneCDS_SLM :: (Error e, MonadError e m) => FeatureHierSequences -> m (SeqLocMap Feature)
+ Bio.GFF3.SGD: geneCDSes :: FeatureHierSequences -> Feature -> [Feature]
+ Bio.GFF3.SGD: geneSeqLoc :: (Error e, MonadError e m) => FeatureHierSequences -> Feature -> m SeqLoc
+ Bio.GFF3.SGD: geneSequence :: (Error e, MonadError e m) => FeatureHierSequences -> Feature -> m Sequence
+ Bio.GFF3.SGD: genes :: FeatureHierSequences -> [Feature]
+ Bio.GFF3.SGD: namedSLM :: FeatureHierSequences -> SeqLocMap Feature
+ Bio.GFF3.SGD: noncodingExons :: FeatureHierSequences -> Feature -> [Feature]
+ Bio.GFF3.SGD: noncodingSeqLoc :: (Error e, MonadError e m) => FeatureHierSequences -> Feature -> m SeqLoc
+ Bio.GFF3.SGD: noncodingSequence :: (Error e, MonadError e m) => FeatureHierSequences -> Feature -> m Sequence
+ Bio.GFF3.SGD: rRNAs :: FeatureHierSequences -> [Feature]
+ Bio.GFF3.SGD: sortExons :: (Error e, MonadError e m) => [Feature] -> m [Feature]
+ Bio.Location.ContigLocation: ContigLoc :: !Offset -> !Offset -> !Strand -> ContigLoc
+ Bio.Location.ContigLocation: bounds :: ContigLoc -> (Offset, Offset)
+ Bio.Location.ContigLocation: data ContigLoc
+ Bio.Location.ContigLocation: display :: ContigLoc -> String
+ Bio.Location.ContigLocation: endPos :: ContigLoc -> Pos
+ Bio.Location.ContigLocation: extend :: (Offset, Offset) -> ContigLoc -> ContigLoc
+ Bio.Location.ContigLocation: fromPosLen :: Pos -> Offset -> ContigLoc
+ Bio.Location.ContigLocation: fromStartEnd :: Offset -> Offset -> ContigLoc
+ Bio.Location.ContigLocation: instance Eq ContigLoc
+ Bio.Location.ContigLocation: instance Ord ContigLoc
+ Bio.Location.ContigLocation: instance Show ContigLoc
+ Bio.Location.ContigLocation: instance Stranded ContigLoc
+ Bio.Location.ContigLocation: isWithin :: Pos -> ContigLoc -> Bool
+ Bio.Location.ContigLocation: length :: ContigLoc -> !Offset
+ Bio.Location.ContigLocation: offset5 :: ContigLoc -> !Offset
+ Bio.Location.ContigLocation: overlaps :: ContigLoc -> ContigLoc -> Bool
+ Bio.Location.ContigLocation: posInto :: Pos -> ContigLoc -> Maybe Pos
+ Bio.Location.ContigLocation: posOutof :: Pos -> ContigLoc -> Maybe Pos
+ Bio.Location.ContigLocation: seqData :: (Error e, MonadError e m) => SeqData -> ContigLoc -> m SeqData
+ Bio.Location.ContigLocation: seqDataPadded :: SeqData -> ContigLoc -> SeqData
+ Bio.Location.ContigLocation: slide :: Offset -> ContigLoc -> ContigLoc
+ Bio.Location.ContigLocation: startPos :: ContigLoc -> Pos
+ Bio.Location.ContigLocation: strand :: ContigLoc -> !Strand
+ Bio.Location.LocMap: checkInvariants :: LocMap a -> [String]
+ Bio.Location.LocMap: data LocMap a
+ Bio.Location.LocMap: defaultZonesize :: Offset
+ Bio.Location.LocMap: delete :: (Eq a) => (Loc, a) -> LocMap a -> LocMap a
+ Bio.Location.LocMap: deleteBy :: ((Loc, a) -> Bool) -> LocMap a -> LocMap a
+ Bio.Location.LocMap: fromList :: Offset -> [(Loc, a)] -> LocMap a
+ Bio.Location.LocMap: insert :: Loc -> a -> LocMap a -> LocMap a
+ Bio.Location.LocMap: instance Monoid (LocMap a)
+ Bio.Location.LocMap: lookupOverlaps :: Loc -> LocMap a -> [(Loc, a)]
+ Bio.Location.LocMap: lookupWithin :: Pos -> LocMap a -> [(Loc, a)]
+ Bio.Location.LocMap: mkLocMap :: Offset -> LocMap a
+ Bio.Location.Location: Loc :: [ContigLoc] -> Loc
+ Bio.Location.Location: bounds :: Loc -> (Offset, Offset)
+ Bio.Location.Location: display :: Loc -> String
+ Bio.Location.Location: endPos :: Loc -> Pos
+ Bio.Location.Location: extend :: (Offset, Offset) -> Loc -> Loc
+ Bio.Location.Location: instance Eq Loc
+ Bio.Location.Location: instance Ord Loc
+ Bio.Location.Location: instance Show Loc
+ Bio.Location.Location: instance Stranded Loc
+ Bio.Location.Location: isWithin :: Pos -> Loc -> Bool
+ Bio.Location.Location: length :: Loc -> Offset
+ Bio.Location.Location: newtype Loc
+ Bio.Location.Location: overlaps :: Loc -> Loc -> Bool
+ Bio.Location.Location: posInto :: Pos -> Loc -> Maybe Pos
+ Bio.Location.Location: posOutof :: Pos -> Loc -> Maybe Pos
+ Bio.Location.Location: seqData :: (Error e, MonadError e m) => SeqData -> Loc -> m SeqData
+ Bio.Location.Location: seqDataPadded :: SeqData -> Loc -> SeqData
+ Bio.Location.Location: startPos :: Loc -> Pos
+ Bio.Location.OnSeq: OnSeq :: !SeqName -> !a -> OnSeq a
+ Bio.Location.OnSeq: andSameSeq :: (a -> b -> Bool) -> OnSeq a -> OnSeq b -> Bool
+ Bio.Location.OnSeq: data OnSeq a
+ Bio.Location.OnSeq: instance (Eq a) => Eq (OnSeq a)
+ Bio.Location.OnSeq: instance (Ord a) => Ord (OnSeq a)
+ Bio.Location.OnSeq: instance (Show a) => Show (OnSeq a)
+ Bio.Location.OnSeq: instance Functor OnSeq
+ Bio.Location.OnSeq: onSameSeq :: (Monad m) => (a -> b -> m c) -> OnSeq a -> OnSeq b -> m c
+ Bio.Location.OnSeq: onSeqName :: OnSeq a -> !SeqName
+ Bio.Location.OnSeq: onSeqObj :: OnSeq a -> !a
+ Bio.Location.OnSeq: perSeq :: (Monoid b) => (a -> b -> c) -> OnSeq a -> OnSeqs b -> c
+ Bio.Location.OnSeq: perSeqUpdate :: (Monoid b) => (a -> b -> b) -> OnSeq a -> OnSeqs b -> OnSeqs b
+ Bio.Location.OnSeq: type OnSeqs a = Map SeqName a
+ Bio.Location.OnSeq: type SeqName = SeqData
+ Bio.Location.OnSeq: withNameAndSeq :: (Monad m) => (SeqName -> a -> b -> m c) -> OnSeq a -> OnSeqs b -> m c
+ Bio.Location.OnSeq: withSeqData :: (Error e, MonadError e m) => (SeqData -> a -> m b) -> (SeqName -> m SeqData) -> OnSeq a -> m b
+ Bio.Location.Position: Pos :: !Offset -> !Strand -> Pos
+ Bio.Location.Position: data Pos
+ Bio.Location.Position: display :: Pos -> String
+ Bio.Location.Position: instance Eq Pos
+ Bio.Location.Position: instance Ix Pos
+ Bio.Location.Position: instance Ord Pos
+ Bio.Location.Position: instance Read Pos
+ Bio.Location.Position: instance Show Pos
+ Bio.Location.Position: instance Stranded Pos
+ Bio.Location.Position: offset :: Pos -> !Offset
+ Bio.Location.Position: seqNt :: (Error e, MonadError e m) => SeqData -> Pos -> m Char
+ Bio.Location.Position: seqNtPadded :: SeqData -> Pos -> Char
+ Bio.Location.Position: slide :: Pos -> Offset -> Pos
+ Bio.Location.Position: strand :: Pos -> !Strand
+ Bio.Location.SeqLocMap: empty :: SeqLocMap a
+ Bio.Location.SeqLocMap: fromList :: [(SeqLoc, a)] -> SeqLocMap a
+ Bio.Location.SeqLocMap: insert :: SeqLoc -> a -> SeqLocMap a -> SeqLocMap a
+ Bio.Location.SeqLocMap: lookupOverlaps :: SeqLoc -> SeqLocMap a -> [(SeqLoc, a)]
+ Bio.Location.SeqLocMap: lookupWithin :: SeqPos -> SeqLocMap a -> [(SeqLoc, a)]
+ Bio.Location.SeqLocMap: type SeqLocMap a = OnSeqs (LocMap a)
+ Bio.Location.SeqLocation: display :: SeqLoc -> String
+ Bio.Location.SeqLocation: displayContigSeqLoc :: ContigSeqLoc -> String
+ Bio.Location.SeqLocation: displaySeqPos :: SeqPos -> String
+ Bio.Location.SeqLocation: isWithin :: SeqPos -> SeqLoc -> Bool
+ Bio.Location.SeqLocation: overlaps :: SeqLoc -> SeqLoc -> Bool
+ Bio.Location.SeqLocation: seqData :: (Error e, MonadError e m) => (SeqName -> m SeqData) -> SeqLoc -> m SeqData
+ Bio.Location.SeqLocation: type ContigSeqLoc = OnSeq ContigLoc
+ Bio.Location.SeqLocation: type SeqLoc = OnSeq Loc
+ Bio.Location.SeqLocation: type SeqPos = OnSeq Pos
+ Bio.Location.SeqLocation: withinContigSeqLoc :: SeqPos -> ContigSeqLoc -> Bool
+ Bio.Location.Strand: Fwd :: Strand
+ Bio.Location.Strand: RevCompl :: Strand
+ Bio.Location.Strand: class Stranded s
+ Bio.Location.Strand: data Strand
+ Bio.Location.Strand: instance Bounded Strand
+ Bio.Location.Strand: instance Enum Strand
+ Bio.Location.Strand: instance Eq Strand
+ Bio.Location.Strand: instance Ix Strand
+ Bio.Location.Strand: instance Ord Strand
+ Bio.Location.Strand: instance Read Strand
+ Bio.Location.Strand: instance Show Strand
+ Bio.Location.Strand: instance Stranded ByteString
+ Bio.Location.Strand: instance Stranded Char
+ Bio.Location.Strand: instance Stranded Strand
+ Bio.Location.Strand: revCompl :: (Stranded s) => s -> s
+ Bio.Location.Strand: stranded :: (Stranded s) => Strand -> s -> s
+ Bio.Sequence: hReadFastQ :: Handle -> IO [Sequence]
+ Bio.Sequence: hWriteFastQ :: Handle -> [Sequence] -> IO ()
+ Bio.Sequence: readFastQ :: FilePath -> IO [Sequence]
+ Bio.Sequence: writeFastQ :: FilePath -> [Sequence] -> IO ()
+ Bio.Sequence.FastQ: hReadFastQ :: Handle -> IO [Sequence]
+ Bio.Sequence.FastQ: hWriteFastQ :: Handle -> [Sequence] -> IO ()
+ Bio.Sequence.FastQ: parse :: [ByteString] -> Maybe (Either String Sequence, [ByteString])
+ Bio.Sequence.FastQ: readFastQ :: FilePath -> IO [Sequence]
+ Bio.Sequence.FastQ: unparse :: Sequence -> ByteString
+ Bio.Sequence.FastQ: writeFastQ :: FilePath -> [Sequence] -> IO ()
+ Bio.Sequence.Fasta: type Qual = Word8
+ Bio.Sequence.KEGG: KO :: ByteString -> KO
+ Bio.Sequence.KEGG: decodeKO :: ByteString -> KO
+ Bio.Sequence.KEGG: decodeUP :: ByteString -> UniProtAcc
+ Bio.Sequence.KEGG: genReadKegg :: FilePath -> IO [(ByteString, ByteString)]
+ Bio.Sequence.KEGG: instance Show KO
+ Bio.Sequence.KEGG: newtype KO
+ Bio.Sequence.KEGG: removePrefix :: String -> String -> (ByteString -> a) -> ByteString -> a
+ Bio.Sequence.SFF: CommonHeader :: Int64 -> Int32 -> Int32 -> Int16 -> Int16 -> Word8 -> ByteString -> ByteString -> CommonHeader
+ Bio.Sequence.SFF: ReadBlock :: ReadHeader -> [Flow] -> ByteString -> ByteString -> ByteString -> ReadBlock
+ Bio.Sequence.SFF: ReadHeader :: Int16 -> Int32 -> Int16 -> Int16 -> Int16 -> Int16 -> ByteString -> ReadHeader
+ Bio.Sequence.SFF: SFF :: !CommonHeader -> [ReadBlock] -> SFF
+ Bio.Sequence.SFF: bases :: ReadBlock -> ByteString
+ Bio.Sequence.SFF: clip_adapter_left :: ReadHeader -> Int16
+ Bio.Sequence.SFF: clip_adapter_right :: ReadHeader -> Int16
+ Bio.Sequence.SFF: clip_qual_left :: ReadHeader -> Int16
+ Bio.Sequence.SFF: clip_qual_right :: ReadHeader -> Int16
+ Bio.Sequence.SFF: convert :: FilePath -> IO ()
+ Bio.Sequence.SFF: data CommonHeader
+ Bio.Sequence.SFF: data ReadBlock
+ Bio.Sequence.SFF: data ReadHeader
+ Bio.Sequence.SFF: data SFF
+ Bio.Sequence.SFF: flow :: CommonHeader -> ByteString
+ Bio.Sequence.SFF: flow_index :: ReadBlock -> ByteString
+ Bio.Sequence.SFF: flow_length :: CommonHeader -> Int16
+ Bio.Sequence.SFF: flowgram :: ReadBlock -> [Flow]
+ Bio.Sequence.SFF: flowgram_fmt :: CommonHeader -> Word8
+ Bio.Sequence.SFF: index_length :: CommonHeader -> Int32
+ Bio.Sequence.SFF: index_offset :: CommonHeader -> Int64
+ Bio.Sequence.SFF: instance Binary CommonHeader
+ Bio.Sequence.SFF: instance Binary ReadHeader
+ Bio.Sequence.SFF: instance Binary SFF
+ Bio.Sequence.SFF: instance Show CommonHeader
+ Bio.Sequence.SFF: instance Show ReadBlock
+ Bio.Sequence.SFF: instance Show ReadHeader
+ Bio.Sequence.SFF: instance Show SFF
+ Bio.Sequence.SFF: key :: CommonHeader -> ByteString
+ Bio.Sequence.SFF: key_length :: CommonHeader -> Int16
+ Bio.Sequence.SFF: name_length :: ReadHeader -> Int16
+ Bio.Sequence.SFF: num_bases :: ReadHeader -> Int32
+ Bio.Sequence.SFF: num_reads :: CommonHeader -> Int32
+ Bio.Sequence.SFF: quality :: ReadBlock -> ByteString
+ Bio.Sequence.SFF: readSFF :: FilePath -> IO SFF
+ Bio.Sequence.SFF: read_header :: ReadBlock -> ReadHeader
+ Bio.Sequence.SFF: read_name :: ReadHeader -> ByteString
+ Bio.Sequence.SFF: sffToSequence :: SFF -> [Sequence]
+ Bio.Sequence.SFF: test :: FilePath -> IO ()
+ Bio.Sequence.SFF: type Flow = Int16
+ Bio.Sequence.SFF: type Index = Word8
+ Bio.Sequence.SFF: type Qual = Word8
+ Bio.Sequence.SFF: writeSFF :: FilePath -> SFF -> IO ()
+ Bio.Util.TestBase: E :: Sequence -> EST
+ Bio.Util.TestBase: EL :: Sequence -> EST_long
+ Bio.Util.TestBase: ES :: Sequence -> EST_short
+ Bio.Util.TestBase: ESet :: [Sequence] -> EST_set
+ Bio.Util.TestBase: Eq :: Sequence -> ESTq
+ Bio.Util.TestBase: N :: Char -> Nucleotide
+ Bio.Util.TestBase: P :: Sequence -> Protein
+ Bio.Util.TestBase: Q :: Word8 -> Quality
+ Bio.Util.TestBase: T :: String -> t -> Test
+ Bio.Util.TestBase: data Test
+ Bio.Util.TestBase: fromN :: Nucleotide -> Char
+ Bio.Util.TestBase: fromQ :: Quality -> Word8
+ Bio.Util.TestBase: genNonNegOffset :: Gen Offset
+ Bio.Util.TestBase: genOffset :: Gen Offset
+ Bio.Util.TestBase: genPositiveOffset :: Gen Offset
+ Bio.Util.TestBase: instance Arbitrary Char
+ Bio.Util.TestBase: instance Arbitrary EST
+ Bio.Util.TestBase: instance Arbitrary EST_long
+ Bio.Util.TestBase: instance Arbitrary EST_set
+ Bio.Util.TestBase: instance Arbitrary EST_short
+ Bio.Util.TestBase: instance Arbitrary ESTq
+ Bio.Util.TestBase: instance Arbitrary Nucleotide
+ Bio.Util.TestBase: instance Arbitrary Quality
+ Bio.Util.TestBase: instance Arbitrary Word8
+ Bio.Util.TestBase: instance Random Word8
+ Bio.Util.TestBase: instance Show EST
+ Bio.Util.TestBase: instance Show EST_long
+ Bio.Util.TestBase: instance Show EST_set
+ Bio.Util.TestBase: instance Show EST_short
+ Bio.Util.TestBase: instance Show ESTq
+ Bio.Util.TestBase: instance Show Nucleotide
+ Bio.Util.TestBase: instance Show Protein
+ Bio.Util.TestBase: instance Show Quality
+ Bio.Util.TestBase: integralRandomR :: (Integral a, RandomGen g) => (a, a) -> g -> (a, g)
+ Bio.Util.TestBase: newtype EST
+ Bio.Util.TestBase: newtype EST_long
+ Bio.Util.TestBase: newtype EST_set
+ Bio.Util.TestBase: newtype EST_short
+ Bio.Util.TestBase: newtype ESTq
+ Bio.Util.TestBase: newtype Nucleotide
+ Bio.Util.TestBase: newtype Protein
+ Bio.Util.TestBase: newtype Quality
+ Bio.Util.TestBase: showT :: (Integral a) => a -> String
+ Bio.Util.TestBase: time :: String -> IO () -> IO ()

Files

Bio/Alignment/Blast.hs view
@@ -73,6 +73,7 @@  -- parse metadata from the preamble parse_preamble :: [ByteString] -> BlastResult+parse_preamble [] = error "Blast: can't parse preamble - empty input" parse_preamble (l:ls) = BlastResult { blastprogram = w1, blastversion = w2, blastdate = w3                                     , blastreferences = B.concat $ map (B.drop (B.length str_refer)) rs                                     , database = B.drop (B.length str_datab) d@@ -108,3 +109,4 @@                  q_from = ee, q_to = ee, h_from = ee, h_to = ee                }      where ee = error "hit coordinates is not supported - use XML format"+parse_match _ = error "Blast: parse_match: pattern match failed"
Bio/Alignment/BlastXML.hs view
@@ -18,12 +18,17 @@ import Text.HTML.TagSoup import Control.Monad import Control.Parallel+import Data.List (isPrefixOf)  -- | Parse BLAST results in XML format readXML :: FilePath -> IO [BlastResult] readXML fp = do -    ts <- return . parseTags =<< readFile fp-    let (h:iters) = breaks (\t -> isTagOpenName "Iteration" t || isTagOpenName "Hit" t) ts+    fc <- readFile fp+    when (not $ isPrefixOf "<?xml" fc) +             $ error ("Bio.Sequence.BlastXML.readXML:\n   The file '"+                      ++fp++"' does not look like an XML file - aborting!")+    let ts = parseTags fc+        (h:iters) = breaks (\t -> isTagOpenName "Iteration" t || isTagOpenName "Hit" t) ts     return [xml2br h iters]  -- | breaks p = groupBy (const (not.p))@@ -98,6 +103,7 @@     where get = getFrom ms           mkFrame f = Frame (strand' $ signum $ read f) (abs $ read f)           mkStrands h q = Strands (strand' $ read h) (strand' $ read q)+          strand' :: Int -> Strand           strand' s = case s of 1 -> Plus; -1 -> Minus                                 _ -> error ("Strand must be +1 or -1, but was: "++show s) 
Bio/Alignment/Multiple.hs view
@@ -9,7 +9,7 @@  import Bio.Alignment.AlignData import Bio.Sequence-import Bio.Clustering+-- import Bio.Clustering  -- | Progressive multiple alignment. --   Calculate a tree from agglomerative clustering, then align@@ -21,15 +21,15 @@ --    This is central for 'Coffee' evaluation of alignments, and T-Coffee construction --    of alignments. indirect :: EditList -> EditList -> EditList-indirect (Repl x1 x2:xs) (Repl y1 y2:ys) = Repl x1 y2 : indirect xs ys -- assert x2==y1-indirect xs@(Repl _ _:_) (Ins y1:ys)     = Ins y1     : indirect xs ys-indirect (Repl x1 _:xs) (Del y1:ys)      = Del x1     : indirect xs ys+indirect (Repl x1 _x2:xs) (Repl _y1 y2:ys) = Repl x1 y2 : indirect xs ys -- assert x2==y1+indirect xs@(Repl _ _:_) (Ins y1:ys)       = Ins y1     : indirect xs ys+indirect (Repl x1 _:xs) (Del _y1:ys)       = Del x1     : indirect xs ys -indirect (Del x1:xs) ys                  = Del x1     : indirect xs ys -- imply del+ins/=repl+indirect (Del x1:xs) ys                    = Del x1     : indirect xs ys -- imply del+ins/=repl -indirect (Ins x1:xs) (Repl _ y2:ys)      = Ins y2     : indirect xs ys -- assert x1==y1-indirect (Ins x1:xs) (Del y1:ys)         = indirect xs ys -- assert x1 == y1-indirect xs@(Ins _:_) (Ins y1:ys)        = Ins y1 : indirect xs ys+indirect (Ins _x1:xs) (Repl _ y2:ys)       = Ins y2     : indirect xs ys -- assert x1==y1+indirect (Ins _x1:xs) (Del _y1:ys)         = indirect xs ys -- assert x1 == y1+indirect xs@(Ins _:_) (Ins y1:ys)          = Ins y1 : indirect xs ys  indirect [] ys                           = ys -- assert: all Ins indirect xs []                           = xs -- assert: all Del
+ Bio/Alignment/Soap.hs view
@@ -0,0 +1,134 @@+module Bio.Alignment.Soap ( SoapAlign(..), SoapAlignMismatch(..)+                          , refSeqPos, refCSeqLoc, refSeqLoc, mismatchSeqPos+                          , parse, unparse, parseMismatch, unparseMismatch+                          , group+                          )+    where ++import Prelude hiding (length)+import Control.Monad.Error+import qualified Data.ByteString.Lazy as LBSW+import qualified Data.ByteString.Lazy.Char8 as LBS+import Data.Char+import qualified Data.List as List (length)+import Data.List (groupBy)++import qualified Bio.Location.ContigLocation as CLoc+import qualified Bio.Location.Location as Loc+import qualified Bio.Location.Position as Pos+import Bio.Location.OnSeq+import qualified Bio.Location.SeqLocation as SeqLoc+import Bio.Location.Strand+import Bio.Sequence.SeqData+++-- | Alignment output from SOAP+data SoapAlign = SA { name :: !SeqName+                    , sequ :: !SeqData     -- ^ Reference strand orientation sequence+                    , qual :: !QualData    -- ^ Reference strand orientation quality data+                    , nhit :: !Int+                    , pairend :: !Char+                    , length :: !Offset+                    , strand :: !Strand+                    , refname :: !SeqName+                    , refstart :: !Offset  -- ^ 1-based index, as output by SOAP, of reference strand 5' end+                    , nmismatch :: !Int+                    , mismatches :: ![SoapAlignMismatch]+                    } deriving (Read, Show, Eq, Ord)++data SoapAlignMismatch = SAM { readnt :: !Char   -- ^ Read nt in reference strand orientation+                             , refnt :: !Char    -- ^ Reference nt in reference strand orientation+                             , offset :: !Offset -- ^ Offset from reference strand 5' end in reference strand orientation+                             , qualnt :: !Qual   -- ^ Quality score of read nt+                             } deriving (Read, Show, Eq, Ord)++mismatchSeqPos :: SoapAlign -> SoapAlignMismatch -> SeqLoc.SeqPos+mismatchSeqPos sa sam = OnSeq (refname sa) $ Pos.Pos (refstart sa + offset sam - 1) (strand sa)++refSeqPos :: SoapAlign -> SeqLoc.SeqPos+refSeqPos sa = OnSeq (refname sa) $ CLoc.startPos $ refCLoc sa++refCSeqLoc :: SoapAlign -> SeqLoc.ContigSeqLoc+refCSeqLoc sa = OnSeq (refname sa) (refCLoc sa)++refCLoc :: SoapAlign -> CLoc.ContigLoc+refCLoc sa = CLoc.ContigLoc (refstart sa - 1) (length sa) (strand sa)++refSeqLoc :: SoapAlign -> SeqLoc.SeqLoc+refSeqLoc sa = OnSeq (refname sa) (Loc.Loc [ refCLoc sa ])++qualScale :: Qual+qualScale = 64++parse :: (Error e, MonadError e m) => LBS.ByteString -> m SoapAlign+parse bstr+    = case LBS.split '\t' bstr of+        (nameStr:sequStr:qualStr:nhitStr:pairendStr:lengthStr:strandStr:refnameStr:refstartStr:nmismatchStr:mismatchesStrs)+            -> do let scQualStr = LBSW.map (subtract qualScale) qualStr+                  nhitInt <- parseIntBStr nhitStr+                  pairendCh <- parseCharBStr pairendStr+                  lengthOff <- parseOffsetBStr lengthStr+                  strandVal <- parseCharBStr strandStr >>= parseStrandChar+                  refstartOff <- parseOffsetBStr refstartStr+                  nmismatchInt <- parseIntBStr nmismatchStr+                  mismatchesList <- mapM parseMismatch mismatchesStrs+                  verifyNMismatches nmismatchInt mismatchesList+                  return $ SA nameStr sequStr scQualStr nhitInt pairendCh lengthOff strandVal refnameStr refstartOff nmismatchInt mismatchesList+        fs -> throwError $ strMsg $ "Bio.Alignment.Soap.parse: too few fields in soapAlign: " ++ show (List.length fs)+    where verifyNMismatches n l = unless (List.length l == n) $ throwError $ strMsg $+                                  "Bio.Alignment.Soap.parse: wrong number of errors: " ++ show (n, List.length l)+          parseStrandChar '+' = return Fwd+          parseStrandChar '-' = return RevCompl+          parseStrandChar ch  = throwError $ strMsg $ "Unknown strand " ++ show ch++parseMismatch :: (Error e, MonadError e m) => LBS.ByteString -> m SoapAlignMismatch+parseMismatch mstr = do (ref, rest1) <- maybe malformed return $ LBS.uncons mstr+                        unless (LBS.isPrefixOf (LBS.pack "->") rest1) malformed+                        let (offstr, rest2) = LBS.span isDigit $ LBS.drop 2 rest1+                        (rd, qualstr) <- maybe malformed return $ LBS.uncons rest2+                        o <- parseOffsetBStr offstr+                        q <- liftM fromIntegral $ parseIntBStr qualstr+                        return $ SAM rd ref o q+    where malformed = throwError $ strMsg $ "Bio.Alignment.Soap.parseMismatch: malformed mismatch field " +                      ++ (show $ LBS.unpack mstr)++parseIntBStr :: (Error e, MonadError e m) => LBS.ByteString -> m Int+parseIntBStr zstr = case LBS.readInt zstr of+                      Just (z, rest) | LBS.null rest -> return z+                      _ -> throwError $ strMsg $ "parseIntBStr: Malformed int field " ++ show zstr++parseOffsetBStr :: (Error e, MonadError e m) => LBS.ByteString -> m Offset+parseOffsetBStr zstr = case LBS.readInteger zstr of+                         Just (z, rest) | LBS.null rest -> return $ fromIntegral z+                         _ -> throwError $ strMsg $ "parseOffsetBStr: Malformed integer field " ++ show zstr++parseCharBStr :: (Error e, MonadError e m) => LBS.ByteString -> m Char+parseCharBStr chstr | LBS.length chstr == 1 = return $ LBS.head chstr+                    | otherwise = throwError $ strMsg $ "parseCharBStr: Malformed char field " ++ show chstr++unparse :: SoapAlign -> LBS.ByteString+unparse sa = LBS.intercalate (LBS.singleton '\t') $ [ name sa+                                                    , sequ sa+                                                    , LBSW.map (+ qualScale) $ qual sa+                                                    , LBS.pack $ show $ nhit sa+                                                    , LBS.singleton $ pairend sa+                                                    , LBS.pack $ show $ length sa+                                                    , unparseStrand $ strand sa+                                                    , refname sa+                                                    , LBS.pack $ show $ refstart sa+                                                    , LBS.pack $ show $ nmismatch sa+                                                    ] ++ map unparseMismatch (mismatches sa)+    where unparseStrand Fwd      = LBS.singleton '+'+          unparseStrand RevCompl = LBS.singleton '-'++unparseMismatch :: SoapAlignMismatch -> LBS.ByteString+unparseMismatch (SAM rd ref off q) = LBS.concat [ LBS.singleton ref+                                                , LBS.pack "->"+                                                , LBS.pack $ show off+                                                , LBS.singleton rd+                                                , LBS.pack $ show q+                                                ]++group :: [SoapAlign] -> [[SoapAlign]]+group = groupBy (equating name)+    where equating f x y = (f x) == (f y)
+ Bio/GFF3/Escape.hs view
@@ -0,0 +1,55 @@+module Bio.GFF3.Escape ( unEscapeByteString+                       , escapeByteString, escapeAllBut, escapeAllOf+                       )+    where++import Control.Monad.Error+import Data.Array.ST+import Data.Array.Unboxed+import qualified Data.ByteString.Lazy as LBSW+import qualified Data.ByteString.Lazy.Char8 as LBS+import Data.Char+import Data.Word++-- (Un)Escaping++unEscapeByteString :: (Error e, MonadError e m) => LBS.ByteString -> m LBS.ByteString+unEscapeByteString bstr = case LBS.split '%' bstr of+                            [] -> return LBS.empty+                            [_] -> return bstr+                            (bstr0:brest) -> foldM unEscapeOneSplit bstr0 brest+    where unEscapeOneSplit leftBStr nextBStr+              = do (x1, next1) <- maybe shortEscape return $ LBS.uncons nextBStr+                   (x2, rest) <- maybe shortEscape return $ LBS.uncons next1+                   xch <- unescapeChar x1 x2+                   return $ leftBStr `LBS.append` LBS.singleton xch `LBS.append` rest+          unescapeChar x1 x2+              | isHexDigit x1 && isHexDigit x2 = return $ chr (digitToInt x1 * 16 + digitToInt x2)+              | otherwise = throwError $ strMsg $ "Bad %-escape, " ++ show ['%',x1,x2]+          shortEscape = throwError $ strMsg $ "Bad %-escape, too short"++escapeByteString :: (Char -> Bool) -> LBS.ByteString -> LBS.ByteString+escapeByteString isNotEscaped bstr +    = case LBS.span isNotEscaped bstr of+        (leftStr, rightStr) -> case LBSW.uncons rightStr of+                                 Nothing -> leftStr+                                 Just (escch, rest) -> leftStr `LBS.append` escapeWord8 escch `LBS.append` escapeByteString isNotEscaped rest++escapeWord8 :: Word8 -> LBS.ByteString+escapeWord8 wch = case (fromIntegral wch) `quotRem` 16 of+                    (lch, rch) -> LBS.pack ['%',intToDigit lch, intToDigit rch]+                                 +escapeTable :: Bool -> [Char] -> UArray Char Bool+escapeTable def exc = runSTUArray $ do starr <- newArray (minBound, maxBound) def+                                       mapM_ (\ch -> writeArray starr ch $ not def) exc+                                       return starr++escapeAllBut :: String -> LBS.ByteString -> LBS.ByteString+escapeAllBut notEscaped = escapeByteString isNotEscaped+    where isNotEscaped ch = table ! ch+          table = escapeTable False notEscaped++escapeAllOf :: String -> LBS.ByteString -> LBS.ByteString+escapeAllOf allEscaped = escapeByteString isNotEscaped+    where isNotEscaped ch = table ! ch+          table = escapeTable True allEscaped
+ Bio/GFF3/Feature.hs view
@@ -0,0 +1,139 @@+module Bio.GFF3.Feature ( GFFAttr(..)+                        , Feature(..), length+                        , parse, unparse+                        , parseWithFasta+                        , attrByTag+                        , ids, parentIds+                        , contigLoc, loc, seqLoc+                        , name+                        )+    where++import Prelude hiding (length)+import Control.Monad.Error+import qualified Data.ByteString.Lazy.Char8 as LBS+import Data.List hiding (length)+import qualified Data.List as List (length)+import Data.Maybe++import Bio.GFF3.Escape++import qualified Bio.Location.ContigLocation as CLoc+import qualified Bio.Location.Location as Loc+import Bio.Location.OnSeq+import qualified Bio.Location.SeqLocation as SeqLoc+import Bio.Location.Strand+import Bio.Sequence.SeqData++data GFFAttr = GFFAttr { attrTag :: !LBS.ByteString, attrValues :: ![LBS.ByteString] } deriving (Eq, Ord, Show)++data Feature = Feature { seqid :: !LBS.ByteString+                       , source :: !LBS.ByteString+                       , ftype :: !LBS.ByteString+                       , start, end :: !Offset+                       , score :: !(Maybe Double)+                       , strand :: !(Maybe Strand)+                       , phase :: !(Maybe Offset)+                       , attributes :: ![GFFAttr]+                       } deriving (Eq, Ord, Show)++length :: Feature -> Offset+length f = 1 + end f - start f++dot :: LBS.ByteString+dot = LBS.singleton '.' -- for Nothing in optional fields++parse :: (Error e, MonadError e m) => LBS.ByteString -> m Feature+parse line = case LBS.split '\t' line of+               [seqidStr,sourceStr,typeStr,startStr,endStr,scoreStr,strandStr,phaseStr,attrStr]+                   -> do fSeqid <- unEscapeByteString seqidStr+                         fSource <- unEscapeByteString sourceStr+                         fFtype <- unEscapeByteString typeStr+                         fStart <- unEscapeByteString startStr >>= parseInteger+                         fEnd <- unEscapeByteString endStr >>= parseInteger+                         fScore <- unEscapeByteString scoreStr >>= parseMaybe parseDouble+                         fStrand <- unEscapeByteString strandStr >>= parseMaybe parseStrand+                         fPhase <- unEscapeByteString phaseStr >>= parseMaybe parseInteger+                         fAttrs <- parseAttrs attrStr+                         return $ Feature fSeqid fSource fFtype fStart fEnd fScore fStrand fPhase fAttrs+               fs -> throwError $ strMsg $ "Malformed GFF line with " ++ show (List.length fs) ++ " tab-delimited fields"+    where parseInteger zstr = case LBS.readInteger zstr of+                                Just (z, rest) | LBS.null rest -> return $ fromIntegral z+                                _ ->  throwError $ strMsg $ "Malformed integer " ++ show (LBS.unpack zstr)+          parseMaybe subparse str = if str == dot then return Nothing else liftM Just $ subparse str+          parseDouble xstr = case reads $ LBS.unpack xstr of+                               [(x, "")] -> return x+                               _ -> throwError $ strMsg $ "Malformed double " ++ show (LBS.unpack xstr)+          parseStrand sstr | sstr == (LBS.singleton '+') = return Fwd+                           | sstr == (LBS.singleton '-') = return RevCompl+                           | otherwise = throwError $ strMsg $ "Malformed strand " ++ show (LBS.unpack sstr)+          parseAttrs = mapM parseAttr . LBS.split ';'+          parseAttr attrStr = case LBS.break (== '=') attrStr of+                                (tagStr,equalValStr) +                                    -> case LBS.uncons equalValStr of+                                         Just ('=', valStr) -> do tag <- unEscapeByteString tagStr+                                                                  vals <- parseAttrVals valStr+                                                                  return $ GFFAttr tag vals+                                         _ -> throwError $ strMsg $ "Malformed attribute " ++ show (LBS.unpack attrStr)+          parseAttrVals valStr | LBS.null valStr = return [LBS.empty] -- Special case for single null value+                               | otherwise = mapM unEscapeByteString $ LBS.split ',' valStr++escapeField :: LBS.ByteString -> LBS.ByteString+escapeField = escapeAllOf "\t\r\n;=%&,"++escapeSeqid :: LBS.ByteString -> LBS.ByteString+escapeSeqid = escapeAllBut $ ".:^*$@!+_?-|" ++ ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9']++unparse :: Feature -> LBS.ByteString+unparse feat = LBS.intercalate (LBS.singleton '\t') [ escapeSeqid $ seqid feat+                                                    , escapeField $ source feat+                                                    , escapeField $ ftype feat+                                                    , escapeField $ unparseInteger $ start feat+                                                    , escapeField $ unparseInteger $ end feat+                                                    , escapeField $ unparseMaybe (LBS.pack . show) $ score feat+                                                    , escapeField $ unparseMaybe unparseStrand $ strand feat+                                                    , escapeField $ unparseMaybe (LBS.pack . show) $ phase feat+                                                    , unparseAttributes $ attributes feat+                                                    ]+    where unparseMaybe unparseJust = maybe dot unparseJust+          unparseStrand Fwd = LBS.singleton '+'+          unparseStrand RevCompl = LBS.singleton '-'+          unparseInteger = LBS.pack . show+          unparseAttributes = LBS.intercalate (LBS.singleton ';') . map unparseAttribute+          unparseAttribute (GFFAttr tag values) = LBS.concat [ escapeField tag, LBS.singleton '=', +                                                               LBS.intercalate (LBS.singleton ',') $ map escapeField values ]++gffFastaDirective :: LBS.ByteString+gffFastaDirective = LBS.pack "##FASTA"++parseWithFasta :: (Error e, MonadError e m) => LBS.ByteString -> m ([Feature], [LBS.ByteString])+parseWithFasta str = case break (== gffFastaDirective) $ LBS.lines str of+                       (featStrs, rest) -> do gffLines <- mapM parse $ filter notComment featStrs+                                              return (gffLines, rest)+    where notComment = maybe False ((/= '#') . fst) . LBS.uncons ++attrByTag :: LBS.ByteString -> Feature -> [LBS.ByteString]+attrByTag tag = findByTag . attributes+    where findByTag = maybe [] attrValues . find ((== tag) . attrTag)++idTag, parentTag :: LBS.ByteString+idTag = LBS.pack "ID"+parentTag = LBS.pack "Parent"++ids :: Feature -> [LBS.ByteString]+ids = attrByTag idTag++parentIds :: Feature -> [LBS.ByteString]+parentIds = attrByTag parentTag++contigLoc :: Feature -> CLoc.ContigLoc+contigLoc f = CLoc.ContigLoc (start f - 1) (1 + end f - start f) (fromMaybe Fwd $ strand f)++loc :: Feature -> Loc.Loc+loc f = Loc.Loc [ contigLoc f ]++seqLoc :: Feature -> SeqLoc.SeqLoc+seqLoc f = OnSeq (seqid f) (loc f)++name :: (Error e, MonadError e m) => Feature -> m SeqName+name f = maybe (throwError $ strMsg $ "No ID for feature " ++ show f) return $ listToMaybe $ ids f
+ Bio/GFF3/FeatureHier.hs view
@@ -0,0 +1,115 @@+{-# OPTIONS_GHC -XFlexibleContexts #-}++module Bio.GFF3.FeatureHier ( FeatureHier, features, lookupId, lookupIdChildren+                            , fromList, insert, delete+                            , parents, children, parentsM, childrenM+                            , checkInvariants+                            )+    where ++import Control.Monad.Error+import Control.Monad.Reader+import qualified Data.ByteString.Lazy.Char8 as LBS+import Data.Graph+import Data.List hiding (insert, delete)+import qualified Data.List as List (delete)+import qualified Data.Map as M+import Data.Maybe+import qualified Data.Set as S++import Bio.GFF3.Feature++data FeatureHier = FeatureHier { features :: !(S.Set Feature)+                               , idToFeature :: !(M.Map LBS.ByteString Feature)+                               , idToChildren :: !(M.Map LBS.ByteString [Feature])+                               } deriving (Show)++empty :: FeatureHier+empty = FeatureHier { features = S.empty, idToFeature = M.empty, idToChildren = M.empty }++lookupId :: (Error e, MonadError e m) => FeatureHier -> LBS.ByteString -> m Feature+lookupId fh idstr = maybe idNotFound return $ M.lookup idstr $ idToFeature fh+    where idNotFound = throwError $ strMsg $ "lookupId: feature ID " ++ show (LBS.unpack idstr) ++ " not found"++lookupIdChildren :: (Error e, MonadError e m) => FeatureHier -> LBS.ByteString -> m [Feature]+lookupIdChildren fh idstr = maybe idNotFound return $ M.lookup idstr $ idToChildren fh+    where idNotFound = throwError $ strMsg $ "lookupIdChildren: feature ID " ++ show (LBS.unpack idstr) ++ " not found"++fromList :: (Error e, MonadError e m) => [Feature] -> m FeatureHier+fromList feats = foldM (flip insert) empty $ parentsFirst feats++-- topSort, i < j when i --> j and j /-> i+-- parents first mean edges go parent --> child+parentsFirst :: [Feature] -> [Feature]+parentsFirst feats = let !(graph, fromVertex, _) = graphFromEdges $ featureEdges feats+                     in map (toFeature fromVertex) $ topSort graph+    where toFeature fromVertex v = case fromVertex v of (feat, _, _) -> feat++-- Feature -> (Feature, its key, keys of its out-edges)+featureEdges :: [Feature] -> [(Feature, Int, [Int])]+featureEdges feats = map featureEdge $ keyedFeats+    where keyedFeats = zip feats [1..]+          idToChildKeys = foldl' insertParentsToKey M.empty keyedFeats+          insertParentsToKey m0 (f, k) = foldl' (insertParentToKey k) m0 $ parentIds f+          insertParentToKey k m0 pid = M.insertWith' (++) pid [k] m0+          featureEdge (feat, key) = (feat, key, concatMap childKeys $ ids feat)+          childKeys pid = M.findWithDefault [] pid idToChildKeys+++insert :: (Error e, MonadError e m) => Feature -> FeatureHier -> m FeatureHier+insert f hier0+    = liftM3 FeatureHier doNewAllFeatures doNewIdToFeature doNewIdToChildren+    where doNewAllFeatures = return $ S.insert f $ features hier0+          doNewIdToFeature = foldM insertIdToFeature (idToFeature hier0) $ ids f+          insertIdToFeature m0 fid = if M.member fid m0+                                     then throwError $ strMsg $ "insertFeature: Duplicate ID " ++ show fid+                                     else return $ M.insert fid f m0+          doNewIdToChildren = foldM insertIdToChildren (idToChildren hier0) $ parentIds f+          insertIdToChildren m0 pid = if M.member pid $ idToFeature hier0+                                      then return $ M.insertWith' (++) pid [f] m0+                                      else throwError $ strMsg $ "insertFeature: Parent ID " ++ show pid ++ " not present"++delete :: (Error e, MonadError e m) => Feature -> FeatureHier -> m FeatureHier+delete f hier0+    = liftM3 FeatureHier doNewAllFeatures doNewIdToFeature doNewIdToChildren+    where doNewAllFeatures = if S.member f $ features hier0+                             then return $ S.delete f $ features hier0+                             else throwError $ strMsg $ "deleteFeature: Feature not present " ++ show f+          doNewIdToFeature = foldM deleteIdToFeature (idToFeature hier0) $ ids f+          deleteIdToFeature m0 fid = if M.member fid m0+                                     then return $ M.delete fid m0+                                     else throwError $ strMsg $ "deleteFeature: ID not present for feature " ++ show (fid, f)+          doNewIdToChildren = if any (flip M.member $ idToChildren hier0) $ ids f+                              then throwError $ strMsg $ "deleteFeature: Feature has children: " ++ show f+                              else foldM deleteIdToChildren (idToChildren hier0) $ parentIds f+          deleteIdToChildren m0 pid = if maybe False (elem f) $ M.lookup pid m0+                                      then throwError $ strMsg $ "deleteFeature: Child not present for parent ID " ++ show (f, pid)+                                      else return $ M.adjust (List.delete f) pid m0++parents :: FeatureHier -> Feature -> [Feature]+parents fh f = map parent $ parentIds f+    where parent pid = M.findWithDefault noParent pid $ idToFeature fh+              where noParent = error $ "featParents: Unknown parent id " ++ show pid ++ " for " ++ show f++children :: FeatureHier -> Feature -> [Feature]+children fh f = concatMap chs $ ids f+    where chs fid = M.findWithDefault [] fid $ idToChildren fh++parentsM :: (MonadReader FeatureHier m) => Feature -> m [Feature]+parentsM = asks . flip parents++childrenM :: (MonadReader FeatureHier m) => Feature -> m [Feature]+childrenM = asks . flip children++checkInvariants :: FeatureHier -> [String]+checkInvariants hier+    = concat [ checkAllFeatureIDs, checkAllFeatureParents, checkFeaturesInAll, checkChildrenInAll ]+    where checkAllFeatureIDs = concatMap checkFeatureIDs $ S.toList $ features hier+          checkFeatureIDs f = concatMap checkFeatureID $ ids f+              where checkFeatureID fid = case M.lookup fid $ idToFeature hier of+                                           Nothing -> ["Feature ID " ++ show fid ++ " missing for " ++ show f]+                                           Just f' | f' /= f -> ["Wrong feature " ++ show f' ++ " /= " ++ show f ++ " for ID " ++ show fid]+                                                   | otherwise -> []+          checkAllFeatureParents = []+          checkFeaturesInAll = []+          checkChildrenInAll = []
+ Bio/GFF3/FeatureHierSequences.hs view
@@ -0,0 +1,87 @@+{-# OPTIONS_GHC -XFlexibleContexts #-}++module Bio.GFF3.FeatureHierSequences ( FeatureHierSequences, features, sequences+                                     , fromLists, parse+                                     , lookupId, parents, children+                                     , seqData, getSequence, featureSequence+                                     , runGFF, runGFFIO, asksGFF+                                     )+    where ++import Control.Monad.Error+import Control.Monad.Reader+import qualified Data.ByteString.Lazy.Char8 as LBS+import qualified Data.Map as M+import Data.Maybe+import qualified Data.Set as S++import Bio.Sequence.SeqData+import Bio.Sequence.Fasta++import qualified Bio.GFF3.Feature as F+import qualified Bio.GFF3.FeatureHier as FH+import qualified Bio.Location.Location as Loc+import qualified Bio.Location.SeqLocation as SeqLoc+import Bio.Location.OnSeq++data FeatureHierSequences = FeatureHierSequences { featureHier :: !FH.FeatureHier+                                                 , sequenceMap :: !(M.Map SeqName SeqData)+                                                 } deriving (Show)++parse :: (Error e, MonadError e m) => LBS.ByteString -> m FeatureHierSequences+parse str = do (feats, seqlines) <- F.parseWithFasta str+               fromLists feats $ mkSeqs seqlines++fromLists :: (Error e, MonadError e m) => [F.Feature] -> [Sequence] -> m FeatureHierSequences+fromLists feats seqs = let !seqmap = M.fromList $ map seqAssoc seqs+                           !featSeqids = S.fromList $ map F.seqid feats+                           !missingSeqids = featSeqids `S.difference` M.keysSet seqmap+                       in if S.null missingSeqids+                          then liftM (\fh -> FeatureHierSequences fh seqmap) $ FH.fromList feats+                          else throwError $ strMsg $ "Missing sequences for seqids " ++ show (map LBS.unpack $ S.toList missingSeqids)+    where seqAssoc (Seq seqname sequ _) = (seqname, sequ)++features :: FeatureHierSequences -> S.Set F.Feature+features = FH.features . featureHier++sequences :: FeatureHierSequences -> [Sequence]+sequences = M.foldWithKey mkSeqList [] . sequenceMap+    where mkSeqList seqname sequ = ((Seq seqname sequ Nothing) :)++lookupId :: (Error e, MonadError e m) => FeatureHierSequences -> SeqName -> m F.Feature+lookupId fhs = FH.lookupId $ featureHier fhs++children :: FeatureHierSequences -> F.Feature -> [F.Feature]+children = FH.children . featureHier++parents :: FeatureHierSequences -> F.Feature -> [F.Feature]+parents = FH.parents . featureHier++seqData :: (Error e, MonadError e m) => FeatureHierSequences -> SeqLoc.SeqLoc -> m SeqData+seqData fhs (OnSeq chrname loc) = do chrseq <- getSequence fhs chrname+                                     return $ Loc.seqDataPadded chrseq loc++getSequence :: (Error e, MonadError e m) => FeatureHierSequences -> SeqName -> m SeqData+getSequence fhs seqid = maybe seqidNotFound return $ M.lookup seqid $ sequenceMap fhs+    where seqidNotFound = throwError $ strMsg $ "SeqID " ++ show (LBS.unpack seqid) ++ " not found"++featureSequence :: (Error e, MonadError e m) => FeatureHierSequences -> F.Feature -> m Sequence+featureSequence fhs f = do sequ <- seqData fhs $ F.seqLoc f+                           let seqname = fromMaybe (LBS.pack $ SeqLoc.display $ F.seqLoc f) $ listToMaybe $ F.ids f+                           return $ Seq seqname sequ Nothing++catchIOErrors :: IO a -> ErrorT String IO a+catchIOErrors m = ErrorT { runErrorT = liftM Right m `catch` (return . Left . show) }++runGFF :: FilePath -> (ErrorT String (Reader FeatureHierSequences) a) -> ErrorT String IO a+runGFF gffname m = do gff <- catchIOErrors $ LBS.readFile gffname+                      fhs <- parse gff+                      either throwError return $ runReader (runErrorT m) fhs++runGFFIO :: FilePath -> (ErrorT String (ReaderT FeatureHierSequences IO) a) -> ErrorT String IO a+runGFFIO gffname m =  do gff <- catchIOErrors $ LBS.readFile gffname+                         fhs <- parse gff+                         mapErrorT (flip runReaderT fhs) m++asksGFF :: (Error e, MonadError e m, MonadReader FeatureHierSequences m) => (FeatureHierSequences -> a -> m b) -> a -> m b+asksGFF f x = do fhs <- ask; f fhs x
+ Bio/GFF3/SGD.hs view
@@ -0,0 +1,94 @@+module Bio.GFF3.SGD ( chromosomes, genes, rRNAs+                    , sortExons+                    , geneSequence, geneSeqLoc, geneCDSes+                    , noncodingSequence, noncodingSeqLoc, noncodingExons+                    , namedSLM, geneCDS_SLM+                    )+    where++import Control.Arrow ((&&&))+import Control.Monad.Error+import Control.Monad.Reader+import qualified Data.ByteString.Lazy.Char8 as LBS+import Data.List+import Data.Maybe+import Data.Ord+import qualified Data.Set as S++import Bio.Sequence.SeqData++import qualified Bio.GFF3.Feature as F+import Bio.GFF3.FeatureHierSequences+-- import qualified Bio.Location.ContigLocation as CLoc+import qualified Bio.Location.Location as Loc+import Bio.Location.OnSeq+import qualified Bio.Location.SeqLocation as SeqLoc+import Bio.Location.Strand+import qualified Bio.Location.SeqLocMap as SLM++-- SGD feature types+cdsType, chromosomeType, geneType, noncodingExonType :: LBS.ByteString+chromosomeType = LBS.pack "chromosome"+cdsType = LBS.pack "CDS"+geneType = LBS.pack "gene"+noncodingExonType = LBS.pack "noncoding_exon"++chromosomes :: FeatureHierSequences -> [F.Feature]+chromosomes = filter isChromosome . S.toList . features+    where isChromosome = (== chromosomeType) . F.ftype++genes :: FeatureHierSequences -> [F.Feature]+genes = filter isGene . S.toList . features+    where isGene = (== geneType) . F.ftype++rRNAs :: FeatureHierSequences -> [F.Feature]+rRNAs = filter isRRNA . S.toList . features+    where isRRNA = any (flip S.member $ S.fromList rRNAFeatureIDs) . F.ids+          rRNAFeatureIDs = map LBS.pack ["RDN25-1", "RDN58-1", "RDN18-1", "RDN5-1"]++geneSequence :: (Error e, MonadError e m) => FeatureHierSequences -> F.Feature -> m Sequence+geneSequence fhs g = do sequ <- geneSeqLoc fhs g >>= SeqLoc.seqData (getSequence fhs)+                        seqname <- maybe (throwError $ strMsg $ "No gene ID for " ++ show g) return $ listToMaybe $ F.ids g+                        return $ Seq seqname sequ Nothing++geneSeqLoc :: (Error e, MonadError e m) => FeatureHierSequences -> F.Feature -> m SeqLoc.SeqLoc+geneSeqLoc fhs g = exonSeqLoc $ geneCDSes fhs g++geneCDSes :: FeatureHierSequences -> F.Feature -> [F.Feature]+geneCDSes fhs g = filter isCDS $ children fhs g+    where isCDS = (== cdsType) . F.ftype          ++noncodingSequence :: (Error e, MonadError e m) => FeatureHierSequences -> F.Feature -> m Sequence+noncodingSequence fhs nc = do sequ <- noncodingSeqLoc fhs nc >>= SeqLoc.seqData (getSequence fhs)+                              seqname <- maybe (throwError $ strMsg $ "No gene ID for " ++ show nc) return $ listToMaybe $ F.ids nc+                              return $ Seq seqname sequ Nothing++noncodingSeqLoc :: (Error e, MonadError e m) => FeatureHierSequences -> F.Feature -> m SeqLoc.SeqLoc+noncodingSeqLoc fhs nc = exonSeqLoc $ noncodingExons fhs nc++noncodingExons :: FeatureHierSequences -> F.Feature -> [F.Feature]+noncodingExons fhs nc = filter isNoncodingExon $ children fhs nc+    where isNoncodingExon = (== noncodingExonType) . F.ftype++sortExons :: (Error e, MonadError e m) => [F.Feature] -> m [F.Feature]+sortExons exons | all fwdStrand exons = return $ sortBy (comparing F.start) exons+                | all rcStrand exons = return $ sortBy (comparing $ negate . F.start) exons+                | otherwise = throwError $ strMsg "sortExons: discordant strands"+    where fwdStrand = (== (Just Fwd)) . F.strand+          rcStrand = (== (Just RevCompl)) . F.strand ++exonSeqLoc :: (Error e, MonadError e m) => [F.Feature] -> m SeqLoc.SeqLoc+exonSeqLoc [] = throwError $ strMsg "exonSeqLoc: empty list of exons"+exonSeqLoc exons@(exon0:exonrest)+    = let seqid = F.seqid exon0+      in if all ((== seqid) . F.seqid) exonrest+         then liftM (OnSeq seqid . Loc.Loc . map F.contigLoc) $ sortExons exons+         else throwError $ strMsg "exonSeqLoc: discordant seqid amongst exons"++namedSLM :: FeatureHierSequences -> SLM.SeqLocMap F.Feature+namedSLM = SLM.fromList . map (F.seqLoc &&& id) . filter isNamed . S.toList . features+    where isNamed = not . null . F.ids++geneCDS_SLM :: (Error e, MonadError e m) => FeatureHierSequences -> m (SLM.SeqLocMap F.Feature)+geneCDS_SLM fhs = liftM SLM.fromList $ mapM cdsLocAndGene $ genes fhs+    where cdsLocAndGene g = liftM (flip (,) g) $ geneSeqLoc fhs g
+ Bio/Location/ContigLocation.hs view
@@ -0,0 +1,135 @@+-- |Data types for working with locations in a sequence.  Zero-based+--  'Int64' indices are used throughout, to facilitate direct use of+--  indexing functions on 'SeqData'.++module Bio.Location.ContigLocation ( ContigLoc(..), fromStartEnd, fromPosLen+                                   , bounds, startPos, endPos+                                   , slide, extend, posInto, posOutof+                                   , seqData, seqDataPadded, isWithin, overlaps+                                   , display+                                   )+    where ++import Prelude hiding (length)++import Control.Monad.Error+import qualified Data.ByteString.Lazy.Char8 as LBS++import Bio.Sequence.SeqData++import qualified Bio.Location.Position as Pos+import Bio.Location.Strand++-- | Contiguous set of positions in a sequence+data ContigLoc = ContigLoc { offset5 :: !Offset   -- ^ 5' end of region on target sequence, 0-based index+                           , length :: !Offset -- ^ length of region on target sequence+                           , strand :: !Strand -- ^ strand of region+                           } deriving (Eq, Ord, Show)++instance Stranded ContigLoc where+    revCompl (ContigLoc seq5 len str) = ContigLoc seq5 len $ revCompl str++-- | Create a 'ContigLoc' from 0-based starting and ending positions.+--   When 'start' is less than 'end' the position will be on the 'Fwd'+--   'Strand', otherwise it will be on the 'RevCompl' strand.+fromStartEnd :: Offset -> Offset -> ContigLoc+fromStartEnd start end+    | start < end = ContigLoc start (1 + end - start) Fwd+    | otherwise   = ContigLoc end   (1 + start - end) RevCompl++-- | Create a 'ContigLoc' from a Pos.Pos defining the start+-- ('ContigLoc' 5 prime end) position on the sequence and the length.+fromPosLen :: Pos.Pos -> Offset -> ContigLoc+fromPosLen (Pos.Pos off5 Fwd)      len = ContigLoc off5               len Fwd+fromPosLen (Pos.Pos off3 RevCompl) len = ContigLoc (off3 - (len - 1)) len RevCompl++-- | The bounds of a 'ContigLoc', a pair of the lowest and highest+--   sequence indices covered by the region, which ignores the strand+--   of the 'ContigLoc'.  The first element of the pair will always be+--   lower than the second.+bounds :: ContigLoc -> (Offset, Offset)+bounds (ContigLoc seq5 len _) = (seq5, seq5 + len - 1)++-- | 0-based starting (5' in the region orientation) position+startPos :: ContigLoc -> Pos.Pos+startPos (ContigLoc seq5 len str) +    = case str of+        Fwd      -> Pos.Pos seq5             str+        RevCompl -> Pos.Pos (seq5 + len - 1) str++-- | 0-based ending (3' in the region orientation) position+endPos :: ContigLoc -> Pos.Pos+endPos (ContigLoc seq5 len str) +    = case str of+        Fwd      -> Pos.Pos (seq5 + len - 1) str+        RevCompl -> Pos.Pos seq5             str++-- | Move a 'ContigLoc' region by a specified offset+slide :: Offset -> ContigLoc -> ContigLoc+slide dpos (ContigLoc seq5 len str) = ContigLoc (seq5 + dpos) len str++-- | Subsequence 'SeqData' for a 'ContigLoc', provided that the region+--   is entirely within the sequence.+seqData :: (Error e, MonadError e m) => SeqData -> ContigLoc -> m SeqData+seqData sequ (ContigLoc seq5 len str)+    | seq5 < 0 = outOfBounds+    | otherwise = case LBS.take len $ LBS.drop seq5 sequ of+                    fwdseq | LBS.length fwdseq == len -> return $ stranded str fwdseq+                           | otherwise -> outOfBounds+    where outOfBounds = throwError $ strMsg $ "contig seq loc " ++ show (seq5, seq5 + len - 1) ++ " out of SeqData bounds"++-- | Subsequence 'SeqData' for a 'ContigLoc', padded as needed with Ns+seqDataPadded :: SeqData -> ContigLoc -> SeqData+seqDataPadded sequ (ContigLoc seq5 len str) = stranded str fwdseq+    where fwdseq+              | seq5 + len <= 0         = LBS.replicate len 'N'+              | seq5 >= LBS.length sequ = LBS.replicate len 'N'+              | seq5 < 0  = LBS.replicate (negate seq5) 'N' `LBS.append` takePadded (len + seq5) sequ+              | otherwise = takePadded len $ LBS.drop seq5 sequ+          takePadded sublen subsequ+              | sublen <= LBS.length subsequ = LBS.take sublen subsequ+              | otherwise = subsequ `LBS.append` LBS.replicate (sublen - LBS.length subsequ) 'N'++-- | For a 'Pos' and a 'ContigLoc' on the same sequence, find the+--   corresponding 'Pos' relative to the 'ContigLoc', provided it is+--   within the 'ContigLoc'.+posInto :: Pos.Pos -> ContigLoc -> Maybe Pos.Pos+posInto (Pos.Pos pos pStrand) (ContigLoc seq5 len cStrand)+    | pos < seq5 || pos >= seq5 + len = Nothing+    | otherwise = Just $ case cStrand of+                           Fwd      -> Pos.Pos (pos - seq5)              pStrand+                           RevCompl -> Pos.Pos (seq5 + len  - (pos + 1)) (revCompl pStrand)++-- | For a 'Pos' specified relative to a 'ContigLoc', find the+--   corresponding 'Pos' relative to the outer sequence, provided that+--   the 'Pos' is within the bounds of the 'ContigLoc'.+posOutof :: Pos.Pos -> ContigLoc -> Maybe Pos.Pos+posOutof (Pos.Pos pos pStrand) (ContigLoc seq5 len cStrand)+    | pos < 0 || pos >= len = Nothing+    | otherwise = Just $ case cStrand of+                           Fwd      -> Pos.Pos (pos + seq5)             pStrand+                           RevCompl -> Pos.Pos (seq5 + len - (pos + 1)) (revCompl pStrand)++-- | 'ContigLoc' extended on the 5' and 3' ends.+extend :: (Offset, Offset) -> ContigLoc -> ContigLoc+extend (ext5, ext3) (ContigLoc seq5 len str)+    = case str of+        Fwd -> ContigLoc (seq5 - ext5) (len + ext5 + ext3) str+        RevCompl -> ContigLoc (seq5 - ext3) (len + ext5 + ext3) str++-- | For a 'Pos' and a 'ContigLoc' on the same sequence, is the 'Pos'+--   within the 'ContigLoc'.+isWithin :: Pos.Pos -> ContigLoc -> Bool+isWithin (Pos.Pos pos pStrand) (ContigLoc seq5 len cStrand)+    = (pos >= seq5) && (pos < seq5 + len) && (cStrand == pStrand)++-- | For a pair of 'ContigLoc' regions on the same sequence, indicates+--   if they overlap at all.+overlaps :: ContigLoc -> ContigLoc -> Bool+overlaps contig1 contig2+    = case (bounds contig1, bounds contig2) of+        ((low1, high1),(low2, high2)) -> (strand contig1 == strand contig2)+                                         && (low1 <= high2) && (low2 <= high1)++display :: ContigLoc -> String+display cloc = show (Pos.offset $ startPos cloc) ++ "to" ++ show (Pos.offset $ endPos cloc)
+ Bio/Location/LocMap.hs view
@@ -0,0 +1,115 @@+-- | A structure to allow fast lookup of objects whose sequence+--   location lines up with a give position.+module Bio.Location.LocMap (LocMap, mkLocMap, defaultZonesize, fromList+                           , lookupWithin, lookupOverlaps+                           , delete, deleteBy, insert+                           , checkInvariants+                           )+    where ++import qualified Data.IntMap as IM+import qualified Data.IntSet as IS+import Data.List hiding (insert, delete, deleteBy)+import Data.Maybe+import Data.Monoid++import qualified Bio.Location.Location as Loc+import qualified Bio.Location.Position as Pos+import Bio.Sequence.SeqData (Offset)++defaultZonesize :: Offset+defaultZonesize = 65536++-- | Collection mapping a collection of 'Loc' locations, possibly+--   overlapping, binned for efficient lookup by position.+data LocMap a = LocMap !Offset !(IM.IntMap (Loc.Loc, a)) !(IM.IntMap IS.IntSet)++instance Monoid (LocMap a) where+    mempty = mkLocMap defaultZonesize+    mappend lm0 (LocMap _ keyToLoc1 _) = foldl' (\lm (l,x) -> insert l x lm) lm0 $ IM.elems keyToLoc1++-- | Create an empty 'LocMap' with a specified position bin size+mkLocMap :: Offset -> LocMap a+mkLocMap zonesize = LocMap zonesize IM.empty IM.empty++-- | Create a 'LocMap' from an associated list.+fromList :: Offset -> [(Loc.Loc, a)] -> LocMap a+fromList zonesize = foldl' (\lm0 (l,x) -> insert l x lm0) (mkLocMap zonesize)++-- | Add an object with an associated 'Loc' sequence region+insert :: Loc.Loc -> a -> LocMap a -> LocMap a+insert l x (LocMap zonesize keyToLoc zoneKeys) +    = let !key = case IM.maxViewWithKey keyToLoc of+                   Just ((k, _), _) -> k + 1+                   Nothing -> 1+          !newKeyToLoc = IM.insertWithKey duplicateError key (l, x) keyToLoc+          !newZoneKeys = foldl' (insertIntoZone key) zoneKeys $ locZones zonesize l+      in LocMap zonesize newKeyToLoc newZoneKeys+    where insertIntoZone key currZoneKeys z = case IM.lookup z currZoneKeys of+                                                Nothing -> IM.insert z (IS.singleton key) currZoneKeys+                                                Just currZoneKeySet -> IM.insert z (IS.insert key currZoneKeySet) currZoneKeys+          duplicateError k (l1, _) (l2, _) = error $ "LocMap: key " ++ show k ++ " duplicated: " ++ show (l1, l2)++-- | Find the (possibly empty) list of sequence regions and associated+--   objects that contain a 'Pos' position, in the sense of 'withinLoc'+lookupWithin :: Pos.Pos -> LocMap a -> [(Loc.Loc, a)]+lookupWithin pos (LocMap zonesize keyToLoc zoneKeys) +    = let !zoneKeySet = IM.findWithDefault IS.empty (posZone zonesize pos) zoneKeys+      in filter ((Loc.isWithin pos) . fst) $ keySetLocs keyToLoc zoneKeySet++-- | Find the (possibly empty) list of sequence regions and associated+--   objects that overlap a 'Loc' region, in the sense of 'overlapsLoc'+lookupOverlaps :: Loc.Loc -> LocMap a -> [(Loc.Loc, a)]+lookupOverlaps loc (LocMap zonesize keyToLoc zoneKeys)+    = let !zonesKeySet = IS.unions $ map (\z -> IM.findWithDefault IS.empty z zoneKeys) $ locZones zonesize loc+      in filter ((Loc.overlaps loc) . fst) $ keySetLocs keyToLoc zonesKeySet++-- | Remove a region / object association from the map, if it is+-- present.  If it is present multiple times, only the first+-- occurrence will be deleted.+delete :: (Eq a) => (Loc.Loc, a) -> LocMap a -> LocMap a+delete target = deleteBy (== target)++-- | Remove the first region / object association satisfying a+-- predicate function.+deleteBy :: ((Loc.Loc, a) -> Bool) -> LocMap a -> LocMap a+deleteBy isTarget lm0@(LocMap zonesize keyToLoc zoneKeys) +    = case filter (isTarget . snd) $ IM.toList keyToLoc of+        [] -> lm0+        ((key,(l,_)):_) -> let !newKeyToLoc = IM.delete key keyToLoc+                               !newZoneKeys = foldl' (deleteFromZone key) zoneKeys $ locZones zonesize l+                           in LocMap zonesize newKeyToLoc newZoneKeys+    where deleteFromZone key currZoneKeys z = let !currZoneKeySet = IM.findWithDefault missingZone z currZoneKeys +                                              in IM.insert z (IS.delete key currZoneKeySet) currZoneKeys+              where missingZone = error $ "LocMap deleteBy: empty keyset for zone " ++ show z++posZone :: Offset -> Pos.Pos -> Int+posZone zonesize pos = fromIntegral $ (Pos.offset pos) `div` zonesize++locZones :: Offset -> Loc.Loc -> [Int]+locZones zonesize loc = let !(pmin, pmax) = Loc.bounds loc+                            !zmin = fromIntegral $ pmin `div` zonesize+                            !zmax = fromIntegral $ pmax `div` zonesize+                        in [zmin..zmax]++keySetLocs :: (IM.IntMap (Loc.Loc, a)) -> IS.IntSet -> [(Loc.Loc, a)]+keySetLocs keyToLoc = map keyLoc . IS.toList+    where keyLoc key = IM.findWithDefault unknownKey key keyToLoc+              where unknownKey = error $ "LocMap: unknown key " ++ show key++checkInvariants :: LocMap a -> [String]+checkInvariants (LocMap zonesize keyToLoc zoneKeys)+    = concat $ checkAllKeys : map checkKeyLoc (IM.toList keyToLoc)+    where checkAllKeys = let !allZoneKeys = IS.unions $ IM.elems zoneKeys +                             !allLocKeys = IM.keysSet keyToLoc+                             !missingKeys = IS.toAscList $ allZoneKeys `IS.difference` allLocKeys+                             !extraKeys = IS.toAscList $ allLocKeys `IS.difference` allZoneKeys+                         in concat [ map (\key -> "Missing key " ++ show key) missingKeys+                                   , map (\key -> "Extra key " ++ show key) extraKeys]+          checkKeyLoc (key, (loc, _)) = let !keyZoneSet = IM.keysSet $ IM.filter (\keyset -> key `IS.member` keyset) zoneKeys+                                            !locZoneSet = IS.fromList $ locZones zonesize loc+                                            !missingZones = IS.toAscList $ locZoneSet `IS.difference` keyZoneSet+                                            !extraZones = IS.toAscList $ keyZoneSet `IS.difference` locZoneSet+                                        in concat [ map (\zone -> "Missing zone " ++ show zone ++ " for " ++ show (key, loc)) missingZones+                                                  , map (\zone -> "Extra zone " ++ show zone ++ " for " ++ show (key, loc)) extraZones]+
+ Bio/Location/Location.hs view
@@ -0,0 +1,119 @@+-- |Data types for working with locations in a sequence.  Zero-based+--  'Int64' indices are used throughout, to facilitate direct use of+--  indexing functions on 'SeqData'.++module Bio.Location.Location ( Loc(..), bounds, length, startPos, endPos+                             , extend, posInto, posOutof, isWithin, overlaps+                             , seqData, seqDataPadded+                             , display+                             )+    where ++import Prelude hiding (length)++import Control.Arrow ((***))+import Control.Monad.Error+import qualified Data.ByteString.Lazy.Char8 as LBS+import Data.List (intercalate)+--import Data.Maybe++import qualified Bio.Location.ContigLocation as CLoc+import qualified Bio.Location.Position as Pos+import Bio.Location.Strand+import Bio.Sequence.SeqData++-- | General (disjoint) sequence region consisting of a concatenated+--   set of contiguous regions+newtype Loc = Loc [CLoc.ContigLoc] deriving (Eq, Ord, Show)++instance Stranded Loc where+    revCompl (Loc contigs) = Loc $ reverse $ map revCompl contigs++-- | Length of the region+length :: Loc -> Offset+length (Loc contigs) = sum $ map CLoc.length contigs++-- | The bounds of a 'Loc', consisting of the lowest & highest+--   sequence indices lying within the region.  The first element of+--   the pair will always be lower than the second.+bounds :: Loc -> (Offset, Offset)+bounds (Loc []) = error "locBounds on zero-contig Loc"+bounds (Loc contigs) = (minimum *** maximum) $ unzip $ map CLoc.bounds contigs++-- | 0-based starting (5' in the region orientation) offset of the+--   region on its sequence.+startPos :: Loc -> Pos.Pos+startPos (Loc [])      = error "startPos: zero-contig Loc"+startPos (Loc contigs) = CLoc.startPos $ head contigs++-- | 0-based ending (3' in the region orientation) offset of the+--   region on its sequence.+endPos :: Loc -> Pos.Pos+endPos (Loc [])      = error "endPos: zero-contig Loc"+endPos (Loc contigs) = CLoc.endPos $ last contigs++-- | Subsequence 'SeqData' for a 'Loc', provided that the region is+--   entirely within the sequence.+seqData :: (Error e, MonadError e m) => SeqData -> Loc -> m SeqData+seqData sequ (Loc contigs)+    = liftM LBS.concat $ mapM (CLoc.seqData sequ) contigs++seqDataPadded :: SeqData -> Loc -> SeqData+seqDataPadded sequ (Loc contigs)+    = LBS.concat $ map (CLoc.seqDataPadded sequ) contigs++-- | For a 'Pos' and a 'Loc' region on the same sequence, find the+--   corresponding 'Pos' relative to the region, if the 'Pos' is+--   within the region.  If the 'Loc' region has redundant positions+--   for a given sequence position, the first is returned.+posInto :: Pos.Pos -> Loc -> Maybe Pos.Pos+posInto seqpos (Loc contigs) = posIntoContigs seqpos contigs++posIntoContigs :: Pos.Pos -> [CLoc.ContigLoc] -> Maybe Pos.Pos+posIntoContigs _ [] = Nothing+posIntoContigs seqpos (contig@(CLoc.ContigLoc _ len _):rest)+    = case CLoc.posInto seqpos contig of+        just@(Just _) -> just+        Nothing -> liftM (flip Pos.slide len) $ posIntoContigs seqpos rest++-- | For a 'Loc' region on a sequence and a 'Pos' relative to the+--   region, find the corresponding 'Pos' on the sequence, provided+--   that the position is within the bounds of the region.+posOutof :: Pos.Pos -> Loc -> Maybe Pos.Pos+posOutof pos (Loc contigs) = posOutofContigs pos contigs++posOutofContigs :: Pos.Pos -> [CLoc.ContigLoc] -> Maybe Pos.Pos+posOutofContigs _ [] = Nothing+posOutofContigs seqpos (contig@(CLoc.ContigLoc _ len _):rest)+    = case CLoc.posOutof seqpos contig of+        just@(Just _) -> just+        Nothing -> posOutofContigs (Pos.slide seqpos $ negate len) rest++-- | Extend a 'Loc' region by incorporating contigous nucleotide+--   regions of the specified lengths on the 5' and 3' ends+extend :: (Offset, Offset) -- ^ (5' extension, 3' extension)+       -> Loc -> Loc+extend _ (Loc []) = error "extendLoc on zero-contig Loc"+extend (ext5, ext3) (Loc contigs) = Loc $ case extendContigs3 contigs of+                                            [] -> error "Empty contigs after extendContigs3"+                                            (cfirst:crest) -> (CLoc.extend (ext5, 0) cfirst):crest+    where extendContigs3 [] = error "Empty contigs in extendContigs3"+          extendContigs3 [clast] = [CLoc.extend (0, ext3) clast]+          extendContigs3 (contig:crest) = contig : extendContigs3 crest++-- | For a 'Pos' and a 'Loc' on the same sequence, does the position+--   fall within the 'Loc' region?+isWithin :: Pos.Pos -> Loc -> Bool+isWithin seqpos (Loc contigs) = or $ map (CLoc.isWithin seqpos) contigs++overlappingContigs :: Loc -> Loc -> [(CLoc.ContigLoc, CLoc.ContigLoc)]+overlappingContigs (Loc contigs1) (Loc contigs2) +    = filter (uncurry CLoc.overlaps) [(c1, c2) | c1 <- contigs1, c2 <- contigs2 ]++-- | For a pair of 'Loc' regions on the same sequence, do they overlap+--   at all?+overlaps :: Loc -> Loc -> Bool+overlaps l1 l2 = not $ null $ overlappingContigs l1 l2++display :: Loc -> String+display (Loc contigs) = intercalate ";" $ map CLoc.display contigs
+ Bio/Location/OnSeq.hs view
@@ -0,0 +1,48 @@+module Bio.Location.OnSeq ( SeqName +                          , OnSeq(..), withSeqData, andSameSeq, onSameSeq+                          , OnSeqs, perSeq, perSeqUpdate, withNameAndSeq+                          )+    where ++import Control.Monad.Error+import qualified Data.ByteString.Lazy.Char8 as LBS+import Data.List+import qualified Data.Map as M+import Data.Monoid++import Bio.Sequence.SeqData++type SeqName = SeqData++data OnSeq a = OnSeq { onSeqName :: !SeqName+                     , onSeqObj :: !a+                     } deriving (Eq, Ord, Show)++instance Functor OnSeq where+    fmap f (OnSeq seqname x) = OnSeq seqname (f x)++withSeqData :: (Error e, MonadError e m) => (SeqData -> a -> m b) -> (SeqName -> m SeqData) -> OnSeq a -> m b+withSeqData f lookupSeq (OnSeq seqname x) = lookupSeq seqname >>= flip f x++andSameSeq :: (a -> b -> Bool) -> OnSeq a -> OnSeq b -> Bool+andSameSeq f (OnSeq xname x) (OnSeq yname y) | xname == yname = f x y+                                             | otherwise = False++onSameSeq :: (Monad m) => (a -> b -> m c) -> OnSeq a -> OnSeq b -> m c+onSameSeq f (OnSeq xname x) (OnSeq yname y) +    | xname == yname = f x y+    | otherwise      = fail $ "onSameSeq: " ++ show (LBS.unpack xname) ++ " /= " ++ show (LBS.unpack yname)+++type OnSeqs a = M.Map SeqName a++perSeq :: (Monoid b) => (a -> b -> c) -> OnSeq a -> OnSeqs b -> c+perSeq f (OnSeq seqname x) = f x . M.findWithDefault mempty seqname++perSeqUpdate :: (Monoid b) => (a -> b -> b) -> OnSeq a -> OnSeqs b -> OnSeqs b+perSeqUpdate upd onseq@(OnSeq seqname _) seqmap0 = M.insert seqname (perSeq upd onseq seqmap0) seqmap0++withNameAndSeq :: (Monad m) => (SeqName -> a -> b -> m c) -> OnSeq a -> OnSeqs b -> m c+withNameAndSeq f (OnSeq seqname x) = mylookup seqname >=> f seqname x+    where mylookup k = maybe nameNotFound return . M.lookup k+              where nameNotFound = fail $ "withNameAndSeq: sequence " ++ show (LBS.unpack k) ++ " not found"
+ Bio/Location/Position.hs view
@@ -0,0 +1,41 @@+-- | Positions on a sequence.  Zero-based 'Int64' indices are used+-- throughout, to facilitate direct use of indexing functions on+-- 'SeqData'.++module Bio.Location.Position ( Pos(..), slide, seqNt, seqNtPadded, display )+    where ++import Control.Monad.Error+import qualified Data.ByteString.Lazy.Char8 as LBS+import Data.Ix (Ix)+import Data.List++import Bio.Location.Strand+import Bio.Sequence.SeqData++-- | Position in a sequence+data Pos = Pos { offset :: !Offset -- ^ 0-based index of the position+               , strand :: !Strand -- ^ Optional strand of the position+               }+              deriving (Eq, Ord, Show, Read, Ix)++instance Stranded Pos where+    revCompl (Pos off str) = Pos off $ revCompl str++-- | Slide a position by an offset+slide :: Pos -> Offset -> Pos+slide (Pos off str) doff = Pos (off + doff) str++seqNt :: (Error e, MonadError e m) => SeqData -> Pos -> m Char+seqNt sequ (Pos off str) | off >= 0 && off < LBS.length sequ = return $ stranded str $ sequ `LBS.index` off+                         | otherwise = throwError $ strMsg $ "position " ++ show off ++ " out of SeqData bounds"++seqNtPadded :: SeqData -> Pos -> Char+seqNtPadded sequ (Pos off str) | off >= 0 && off < LBS.length sequ = stranded str $ sequ `LBS.index` off+                               | otherwise = 'N'++display :: Pos -> String+display (Pos off str) = show off ++ displayStrand+    where displayStrand = case str of+                            Fwd -> "(+)"+                            RevCompl -> "(-)"
+ Bio/Location/SeqLocMap.hs view
@@ -0,0 +1,33 @@+module Bio.Location.SeqLocMap ( SeqLocMap+                              , empty+                              , fromList, insert+                              , lookupWithin, lookupOverlaps+                              )+    where ++import Control.Arrow (first)+import Data.List hiding (insert)+import qualified Data.Map as M++import Bio.Location.OnSeq+import qualified Bio.Location.LocMap as LM+import qualified Bio.Location.SeqLocation as SeqLoc++type SeqLocMap a = OnSeqs (LM.LocMap a)++empty :: SeqLocMap a+empty = M.empty++fromList :: [(SeqLoc.SeqLoc, a)] -> SeqLocMap a+fromList = foldl' (\lm (sl,x) -> insert sl x lm) M.empty++insert :: SeqLoc.SeqLoc -> a -> SeqLocMap a -> SeqLocMap a+insert sloc x = perSeqUpdate (\loc locmap -> LM.insert loc x locmap) sloc++lookupWithin :: SeqLoc.SeqPos -> SeqLocMap a -> [(SeqLoc.SeqLoc, a)]+lookupWithin = withNameAndSeq namedLookupWithin+    where namedLookupWithin seqname pos = map (first $ OnSeq seqname) . LM.lookupWithin pos++lookupOverlaps :: SeqLoc.SeqLoc -> SeqLocMap a -> [(SeqLoc.SeqLoc, a)]+lookupOverlaps = withNameAndSeq namedLookupOverlaps+    where namedLookupOverlaps seqname loc = map (first $ OnSeq seqname) . LM.lookupOverlaps loc
+ Bio/Location/SeqLocation.hs view
@@ -0,0 +1,46 @@+module Bio.Location.SeqLocation ( SeqPos, displaySeqPos+                                , ContigSeqLoc, withinContigSeqLoc, displayContigSeqLoc +                                , SeqLoc+                                , isWithin, overlaps, seqData+                                , display+                                )+    where ++import Control.Monad.Error+import qualified Data.ByteString.Lazy.Char8 as LBS+--import Data.List++import qualified Bio.Location.ContigLocation as CLoc+import qualified Bio.Location.Location as Loc+import Bio.Location.OnSeq+import qualified Bio.Location.Position as Pos+import Bio.Sequence.SeqData++type SeqPos = OnSeq Pos.Pos++displaySeqPos :: SeqPos -> String+displaySeqPos (OnSeq refname pos) = LBS.unpack refname ++ "@" ++ Pos.display pos++type ContigSeqLoc = OnSeq CLoc.ContigLoc++withinContigSeqLoc :: SeqPos -> ContigSeqLoc -> Bool+withinContigSeqLoc = andSameSeq CLoc.isWithin++displayContigSeqLoc :: ContigSeqLoc -> String+displayContigSeqLoc (OnSeq refname cloc) = LBS.unpack refname ++ "@" ++ CLoc.display cloc++type SeqLoc = OnSeq Loc.Loc++isWithin :: SeqPos -> SeqLoc -> Bool+isWithin = andSameSeq Loc.isWithin++overlaps :: SeqLoc -> SeqLoc -> Bool+overlaps = andSameSeq Loc.overlaps++seqData :: (Error e, MonadError e m) => (SeqName -> m SeqData) -> SeqLoc -> m SeqData+seqData = withSeqData Loc.seqData++display :: SeqLoc -> String+display (OnSeq refname loc) = LBS.unpack refname ++ "@" ++ Loc.display loc++
+ Bio/Location/Strand.hs view
@@ -0,0 +1,33 @@+module Bio.Location.Strand ( Strand(..)+                           , Stranded(..), stranded+                           )+    where ++import qualified Data.ByteString.Lazy.Char8 as LBS+import Data.Ix (Ix)++import Bio.Sequence.SeqData++-- | Sequence strand+data Strand = Fwd | RevCompl deriving (Eq, Ord, Show, Read, Bounded, Enum, Ix)++-- | Anything, such as a location or a sequence, which lies on a+-- strand and can thus be reverse complemented.+class Stranded s where+    revCompl :: s -> s++stranded :: (Stranded s) => Strand -> s -> s+stranded Fwd      = id+stranded RevCompl = revCompl++instance Stranded Strand where+    revCompl Fwd      = RevCompl+    revCompl RevCompl = Fwd++instance Stranded Char where+    revCompl = compl++-- Avoid using -XTypeSynonymInstances+instance Stranded LBS.ByteString where+    revCompl = LBS.reverse . LBS.map compl+
Bio/Sequence.hs view
@@ -29,6 +29,11 @@     , readFastaQual     , writeFastaQual, hWriteFastaQual +    -- ** The FastQ format ("Bio.Sequence.FastQ") +    -- Combines sequence data and quality in one file.+    -- Warning: Solexa uses a different formula for the quality values!+    , readFastQ, writeFastQ, hReadFastQ, hWriteFastQ+     -- ** The phd file format ("Bio.Sequence.Phd")     -- | These contain base (nucleotide) calling information,     --   and are generated by @phred@.@@ -53,6 +58,7 @@  -- file formats import Bio.Sequence.Fasta+import Bio.Sequence.FastQ import Bio.Sequence.Phd import Bio.Sequence.TwoBit 
+ Bio/Sequence/FastQ.hs view
@@ -0,0 +1,70 @@+{- |+   Module: Bio.Sequence.FastQ++   Support the FastQ format that combines sequence and quality. See:++   * <http://www.bioperl.org/wiki/FASTQ_sequence_format>++   Of course, this is yet another vaguely defined pseudo-standard with +   conflicting definitions.  Of course Solexa had to go and invent a different, +   but indistinguishably so, way to do it:++   * <http://www.bcgsc.ca/pipermail/ssrformat/2007-March/000137.html>++   * <http://maq.sourceforge.net/fastq.shtml>++   Currently, we only support the non-Solexa FastQ, adding\/subtracting 33 for +   the quality values.+-}++module Bio.Sequence.FastQ +    (+     -- * Reading FastQ+    readFastQ, hReadFastQ, parse+     -- * Writing FastQ+    , writeFastQ, hWriteFastQ, unparse+    ) where++import System.IO+import qualified Data.ByteString.Lazy.Char8 as B+import qualified Data.ByteString.Lazy as BB+import Data.List (unfoldr)++import Bio.Sequence.SeqData++readFastQ :: FilePath -> IO [Sequence]+readFastQ f = (go . B.lines) `fmap` B.readFile f ++hReadFastQ :: Handle -> IO [Sequence]+hReadFastQ h = (go . B.lines) `fmap` B.hGetContents h++go :: [B.ByteString] -> [Sequence]+go = map (either error id) . unfoldr parse++-- | Parse one FastQ entry, suitable for using in 'unfoldr' over+--   'B.lines' from a file+parse :: [B.ByteString] -> Maybe (Either String Sequence, [B.ByteString])+parse (h1:sd:h2:sq:rest) = +    case (B.uncons h1,B.uncons h2) of+      (Just ('@',h1name), Just ('+',h2name))+          | h1name == h2name -> Just (Right $ Seq h1name sd (Just (BB.map (subtract 33) sq)), rest)+          | otherwise        -> Just (Left $ "Bio.Sequence.FastQ: name mismatch:" ++ showStanza, rest)+      _                      -> Just (Left $ "Bio.Sequence.FastQ: illegal FastQ format:" ++ showStanza, rest)+    where showStanza = unlines $ map B.unpack [ h1, sd, h2, sq ]+parse [] = Nothing+parse fs = let showStanza = unlines (map B.unpack fs)+               err = Left $ "Bio.Sequence.FastQ: illegal number of lines in FastQ format: " ++ showStanza+           in Just (err, [])++writeFastQ :: FilePath -> [Sequence] -> IO ()+writeFastQ f = B.writeFile f . B.concat . map unparse++hWriteFastQ :: Handle -> [Sequence] -> IO ()+hWriteFastQ h = B.hPut h . B.concat . map unparse++-- helper function for writing+unparse :: Sequence -> B.ByteString+unparse (Seq h sd (Just sq)) = +    B.unlines [B.cons '@' h, sd, B.cons '+' h, BB.map (+33) sq]+unparse (Seq h _ Nothing) = error ("Bio.Sequence.FastQ: sequence " ++ show (B.unpack h) +                                   ++" doesn not have quality data!")
Bio/Sequence/Fasta.hs view
@@ -19,6 +19,8 @@     , countSeqs     -- * Helper function for reading your own sequences     , mkSeqs+    -- * Data structures+    , Qual ) where  @@ -27,10 +29,8 @@ import Data.Int import Data.Maybe import System.IO-import System.IO.Unsafe import Control.Monad -import qualified Data.ByteString.Char8 as BS import qualified Data.ByteString.Lazy.Char8 as B import qualified Data.ByteString.Lazy as BB import Data.ByteString.Lazy.Char8 (ByteString)@@ -58,9 +58,7 @@  -- | Lazily read sequences from a FASTA-formatted file readFasta :: FilePath -> IO [Sequence]-readFasta f = do-  ls <- getLines f-  return (mkSeqs ls)+readFasta f = (mkSeqs . B.lines) `fmap` B.readFile f  -- | Write sequences to a FASTA-formatted file. --   Line length is 60.@@ -72,9 +70,7 @@  -- | Read quality data for sequences to a file. readQual :: FilePath -> IO [Sequence]-readQual f = do-  ls <- getLines f-  return (mkQual ls)+readQual f = (mkQual . B.lines) `fmap` B.readFile f  -- | Write quality data for sequences to a file. writeQual :: FilePath -> [Sequence] -> IO ()@@ -89,7 +85,6 @@ readFastaQual  s q = do   ss <- readFasta s   qs <- readQual q-  return ss   -- warning: assumes correct qual file!   let mkseq s1@(Seq x y _) s2@(Seq _ _ (Just z))           | seqlabel s1 /= seqlabel s2 = error ("mismatching sequence and quality: "@@ -98,7 +93,10 @@                                                 ++ toStr (seqlabel s1)++","++show (B.length y,B.length z))           | otherwise   = Seq x y (Just z)       mkseq _ _ = error "readFastaQual: could not combine Fasta and Qual information"-  return $ zipWith mkseq ss qs+      zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys+      zipWith' _ [] [] = []+      zipWith' _ _ _ = error "readFastaQual: Unbalanced sequence and quality"+  return $ zipWith' mkseq ss qs  -- | Write sequence and quality data simulatnously --   This may be more laziness-friendly.@@ -116,9 +114,7 @@  -- | Lazily read sequence from handle hReadFasta :: Handle -> IO [Sequence]-hReadFasta h = do-  ls <- hGetLines h-  return (mkSeqs ls)+hReadFasta h = (mkSeqs . B.lines) `fmap` B.hGetContents h  -- | Write sequences in FASTA format to a handle. hWriteFasta :: Handle -> [Sequence] -> IO ()@@ -147,31 +143,6 @@       qs = B.pack . unwords . map show . BB.unpack   mapM_ ((\l' -> B.hPut h l' >> B.hPut h (B.pack "\n")) . qs) qls wQual _ (Seq _ _ Nothing) = return ()---- ByteString operations--- These aren't (or possible weren't) provided by the FPS library.--- Implement line-based IO (in retrospect it'd be simpler--- and better to just use 'lines'.)---- lazily read lines from file-getLines :: FilePath -> IO [ByteString]-getLines f = do-  h <- openFile f ReadMode-  hGetLines' (hClose h) h---- lazily read lines from handle-hGetLines :: Handle -> IO [ByteString]-hGetLines = hGetLines' (return ())---- add an optional handle-closing parameter-hGetLines' :: IO () -> Handle -> IO [ByteString]-hGetLines' c h = do-  e <- hIsEOF h-  if e then c >> return []-       else do l' <- BS.hGetLine h-               let l = B.fromChunks $ if BS.null l' then [] else  [l']-               ls <- unsafeInterleaveIO $ hGetLines' c h-               return (l:ls)  -- | Convert a list of FASTA-formatted lines into a list of sequences. --   Blank lines are ignored.
Bio/Sequence/KEGG.hs view
@@ -16,3 +16,33 @@  module Bio.Sequence.KEGG where +import Bio.Sequence.GeneOntology (UniProtAcc)++import qualified Data.ByteString.Lazy.Char8 as B+import Data.ByteString.Lazy.Char8 (ByteString)+import Control.Arrow ((&&&))++-- | Most KEGG files that contain associations, have one association per line,+--   consisting of two items separated by whitespace.  This is a generalized reader+--   function.+genReadKegg :: FilePath -> IO [(ByteString,ByteString)]+genReadKegg f = return . map (((!!0) &&& (!!1)) . B.words) . B.lines =<< B.readFile f++newtype KO = KO ByteString+instance Show KO where show (KO x) = B.unpack x++-- | Convert UniProt IDs (up:xxxxxx) to the "UniProtAcc" type.+decodeUP :: ByteString -> UniProtAcc+decodeUP = removePrefix "up" "UniProt accession" id++-- | Convert KO IDs (ko:xxxxx) to the "KO" data type.+decodeKO :: ByteString -> KO+decodeKO = removePrefix "ko" "KEGG KO id" KO++-- | KEGG uses strings with an identifying prefix for IDs. This helper function checks+--   and removes prefix to construct native values.+removePrefix :: String -> String ->  (ByteString -> a) -> ByteString -> a+removePrefix pfx err conv bs+    | (B.pack (pfx++":") `B.isPrefixOf` bs) = conv $ B.drop (fromIntegral (length pfx+1)) bs+    | otherwise                             = error ("Can't parse as "++err ++":\n"+                                                        ++B.unpack bs)
+ Bio/Sequence/SFF.hs view
@@ -0,0 +1,247 @@+{- | Read (and write?) the SFF file format used by+   Roche\/454 sequencing to store flowgram data.++   A flowgram is a series of values (intensities) representing homopolymer runs of+   A,G,C, and T in a fixed cycle, and usually displayed as a histogram.++   The Staden Package contains an io_lib, with a C routine for parsing this format.+   According to comments in the sources, the io_lib implementation is based on a file+   called getsff.c, which I've been unable to track down.++   It is believed that all values are stored big endian.+-}++module Bio.Sequence.SFF ( SFF(..), CommonHeader(..)+                        , ReadHeader(..), ReadBlock(..)+                        , readSFF, writeSFF+                        , sffToSequence+                        , test, convert+                        , Flow, Qual, Index+                        ) where++import Bio.Sequence.SeqData++import Data.Int+import qualified Data.ByteString.Lazy as LB+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as BC+import Data.ByteString (ByteString)+import Control.Monad (when,replicateM,replicateM_)++import Data.List (intersperse)+import Data.Binary+import Data.Binary.Get (getByteString)+import qualified Data.Binary.Get as G+import Data.Binary.Put (putByteString)++import Text.Printf (printf)++-- | The type of flowgram value+type Flow = Int16+type Index = Word8++-- Global variables holding static information+magic :: Int32+magic = 0x2e736666++versions :: [Int32]+versions = [1]+++readSFF :: FilePath -> IO SFF+readSFF f = return . decode =<< LB.readFile f++sffToSequence :: SFF -> [Sequence]+sffToSequence (SFF ch rs) = map r2s rs+    where r2s r = clip (read_name $ read_header r, bases r, quality r)+          lb x = LB.fromChunks [x]+          clip (n,s,q) = let (k,s2) = B.splitAt (fromIntegral $ key_length ch) s+                         in if k==key ch then Seq (lb n) (lb s2) (Just $ lb $ B.drop (fromIntegral $ key_length ch) q)+                                else error ("Couldn't match key in sequence "++BC.unpack n++" ("++BC.unpack k++" vs. "++BC.unpack (key ch)++")!")++writeSFF :: FilePath -> SFF -> IO ()+writeSFF = encodeFile++-- --------------------------------------------------+-- | test serialization by output'ing the header and first two reads +--   in an SFF, and the same after a decode + encode cycle.+test :: FilePath -> IO ()+test file = do +  (SFF h rs) <- readSFF file +  let sff = (SFF h (take 2 rs))+  putStrLn $ show $ sff+  putStrLn ""+  putStrLn $ show $ (decode $ encode sff :: SFF)++-- --------------------------------------------------+-- | Convert a file by decoding it and re-encoding it+--   This will lose the index (which isn't really necessary)+convert :: FilePath -> IO ()+convert file = writeSFF (file++".out") =<< readSFF file++-- | Generalized function for padding+pad :: Integral a => a -> Put+pad x = replicateM_ (fromIntegral x) (put zero) where zero = 0 :: Word8 ++-- | Generalized function to skip padding+skip :: Integral a => a -> Get ()+skip = G.skip . fromIntegral++-- | The data structure storing the contents of an SFF file (modulo the index)+data SFF = SFF !CommonHeader [ReadBlock]++instance Show SFF where +    show (SFF h rs) = (show h ++ "Read Blocks:\n\n" ++ concatMap show rs)++instance Binary SFF where+    get = do+      -- Parse CommonHeader+      chead <- get+      -- Parse ReadHeaders+      rds <- replicateM (fromIntegral (num_reads chead))+                                   (do +                                      rh <- get :: Get ReadHeader+                                      let nb = fromIntegral $ num_bases rh+                                          fl = fromIntegral $ flow_length chead+                                      fg <- getByteString (2*fl)+                                      fi <- getByteString nb+                                      bs <- getByteString nb+                                      qty <- getByteString nb+                                      let l = (fl*2+nb*3) `mod` 8+                                      when (l > 0) (skip (8-l))+                                      return (ReadBlock rh (decodeArray fg) fi bs qty)+                                   )+      return (SFF chead rds)++    put (SFF hd rds) = do+      put hd+      mapM_ (putRB (fromIntegral $ flow_length hd)) rds++-- | A ReadBlock can't be an instance of Binary directly, since it depends on+--   information from the CommonHeader.+putRB :: Int -> ReadBlock -> Put+putRB fl rb = do+  put (read_header rb)+  mapM_ put (flowgram rb)+  putByteString (flow_index rb)+  putByteString (bases rb)+  putByteString (quality rb)+  let nb = fromIntegral $ num_bases $ read_header rb+      l = (fl*2+nb*3) `mod` 8+  when (l > 0) (pad (8-l))++-- | What the name and type says.+decodeArray :: ByteString -> [Flow]+decodeArray = dec . map fromIntegral . B.unpack +    where dec (d1:d2:rest) = d1*256+d2 : dec rest+          dec [] = []+          dec _  = error "odd flowgram length?!"++-- ----------------------------------------------------------+-- | SFF has a 31-byte common header+--   Todo: remove items that are derivable (counters, magic, etc)+--   cheader_lenght points to the first read header.+--   Also, the format is open to having the index anywhere between reads,+--   we should really keep count and check for each read.  In practice, it+--   seems to be places after the reads.+--   +--   The following two fields are considered part of the header, but as+--   they are static, they are not part of the data structure+--     magic   :: Word32   -- ^ 0x2e736666, i.e. the string ".sff"+--     version :: Word32   -- ^ 0x00000001++data CommonHeader = CommonHeader {+          index_offset                            :: Int64    -- ^ Points to a text(?) section+        , index_length, num_reads                 :: Int32+        , key_length, flow_length                 :: Int16+        , flowgram_fmt                            :: Word8+        , flow, key                               :: ByteString +        }++instance Show CommonHeader where+    show (CommonHeader io il nr kl fl fmt f k) =+        "Common Header:\n\n" ++ (unlines $ map ("    "++) +                                 ["index_off:\t"++show io ++"\tindex_len:\t"++show il+                                 ,"num_reads:\t"++show nr+                                 ,"key_len:\t"  ++show kl ++ "\tflow_len:\t"++show fl+                                 ,"format\t:"   ++show fmt+                                 ,"flow\t:"     ++BC.unpack f+                                 ,"key\t:"      ++BC.unpack k+                                 , ""+                                 ])++instance Binary CommonHeader where+    get = do { m <- get ; when (m /= magic)   $ error (printf "Incorrect magic number - got %8x, expected %8x" m magic)+             ; v <- get ; when (not (v `elem` versions)) $ error (printf "Unexpected version - got %d, supported are: %s" v (unwords $ map show versions))+             ; io <- get ; ixl <- get ; nrd <- get+             ; chl <- get ; kl <- get ; fl <- get ; fmt <- get+             ; fw <- getByteString (fromIntegral fl)+             ; k  <- getByteString (fromIntegral kl)+             ; skip (chl-(31+fl+kl)) -- skip to boundary+             ; return (CommonHeader io ixl nrd kl fl fmt fw k)+             }++    put ch = let CommonHeader io il nr kl fl fmt f k = ch { index_offset = 0 } in+        do { let cl = 31+fl+kl+                 l = cl `mod` 8+                 padding = if l > 0 then 8-l else 0+           ; put magic; put (last versions); put io; put il; put nr; put (cl+padding); put kl; put fl; put fmt+           ; putByteString f; putByteString k+           ; pad padding -- skip to boundary+           }++-- ---------------------------------------------------------- +-- | Each Read has a fixed read header+data ReadHeader = ReadHeader {+      name_length                           :: Int16+    , num_bases                             :: Int32+    , clip_qual_left, clip_qual_right+    , clip_adapter_left, clip_adapter_right :: Int16+    , read_name                             :: ByteString+}++instance Show ReadHeader where+    show (ReadHeader nl nb cql cqr cal car rn) =+        ("    Read Header:\n" ++) $ unlines $ map ("        "++) +                    [ "name_len:\t"++show nl, "num_bases:\t"++show nb+                    , "clip_qual:\t"++show cql++"..."++show cqr+                    , "clip_adap:\t"++show cal++"..."++show car+                    , "read name:\t"++BC.unpack rn+                    , "" +                    ]++instance Binary ReadHeader where+    get = do+      { rhl <- get; nl <- get; nb <- get+      ; cql <- get; cqr <- get ; cal <- get ; car <- get+      ; n <- getByteString (fromIntegral nl)+      ; skip (rhl - (16+ nl))+      ; return (ReadHeader nl nb cql cqr cal car n)+      }+    put (ReadHeader nl nb cql cqr cal car rn) = +        do { let rl = 16+nl+                 l = rl `mod` 8+                 padding = if l > 0 then 8-l else 0+           ; put (rl+padding); put nl; put nb; put cql; put cqr; put cal; put car+           ; putByteString rn +           ; pad padding+           }++-- ----------------------------------------------------------+-- | This contains the actual flowgram for a single read.+data ReadBlock = ReadBlock {+      read_header                :: ReadHeader+    -- The data block+    , flowgram                   :: [Flow]+    , flow_index, bases, quality :: ByteString+    }++instance Show ReadBlock where+    show (ReadBlock h f i b q) =+        show h ++ unlines (map ("     "++) +            ["flowgram:\t"++show f+            , "index:\t"++(concat . intersperse " " . map show . B.unpack) i+            , "bases:\t"++BC.unpack b+            , "quality:\t"++(concat . intersperse " " . map show . B.unpack) q+            , ""+            ])
Bio/Sequence/TwoBit.hs view
@@ -51,11 +51,12 @@ unbytes :: Integral a => [Word8] -> a unbytes = Data.List.foldr (\x y -> y*256+x) 0 . map fromIntegral -instance Arbitrary Word8 where-    arbitrary = choose (0,255::Int) >>= return . fromIntegral+-- Conflicts with Bio.Util.TestBase+-- instance Arbitrary Word8 where+--    arbitrary = choose (0,255::Int) >>= return . fromIntegral -prop_bswap :: Word8 -> Word8 -> Word8 -> Word8 -> Bool-prop_bswap a1 a2 a3 a4 = (bswap 4 . decode . BB.pack) [a1,a2,a3,a4] == ((decode . BB.pack) [a4,a3,a2,a1] :: Word32)+-- prop_bswap :: Word8 -> Word8 -> Word8 -> Word8 -> Bool+-- prop_bswap a1 a2 a3 a4 = (bswap 4 . decode . BB.pack) [a1,a2,a3,a4] == ((decode . BB.pack) [a4,a3,a2,a1] :: Word32)  -- basic data types data Header = Header { swap :: Bool,  version, count, reserved :: Word32 }
Bio/Util.hs view
@@ -14,6 +14,8 @@ lines, mylines :: B.ByteString -> [B.ByteString] lines = case length (B.lines $ B.pack "\n") of 1 -> B.lines                                                0 -> mylines+                                               _ -> error "Unknown implementaion of 'lines'!?"+ mylines s = case B.elemIndex '\n' s of               Nothing -> if B.null s then [] else [s]               Just i  -> B.take i s : mylines (B.drop (i+1) s)
+ Bio/Util/TestBase.hs view
@@ -0,0 +1,132 @@+{-# OPTIONS -fglasgow-exts #-}++module Bio.Util.TestBase where++import Control.Monad (liftM)+import System.CPUTime+import System.Time+import Test.QuickCheck+import System.Random+-- import Data.Char (ord)+import Data.Word+import Data.ByteString.Lazy (pack)++import Bio.Sequence.SeqData++data Test = forall t . Testable t => T String t++newtype Nucleotide = N Char deriving Show+newtype Quality    = Q Word8 deriving Show++fromN :: Nucleotide -> Char+fromN (N c) = c++fromQ :: Quality -> Word8+fromQ (Q c) = c++-- | For testing, variable lengths+newtype EST = E Sequence deriving Show+newtype ESTq = Eq Sequence deriving Show+newtype Protein = P Sequence deriving Show++-- | For benchmarking, fixed lengths+newtype EST_short = ES Sequence deriving Show+newtype EST_long  = EL Sequence deriving Show+newtype EST_set  = ESet [Sequence] deriving Show++-- | Take time (CPU and wall clock) and report it+time :: String -> IO () -> IO ()+time msg action = do+    d1 <- getClockTime+    t1 <- getCPUTime+    action+    t2 <- getCPUTime+    d2 <- getClockTime+    putStrLn $ "\n"++msg++", CPU time: " ++ showT (t2-t1) ++ ", wall clock: "+                 ++ timeDiffToString (diffClockTimes d2 d1)++-- | Print a CPUTime difference+showT :: Integral a => a -> String+showT t = show (fromIntegral t/1e12::Double)++"s"++-- | Shamelessly stolen from FPS+integralRandomR :: (Integral a, RandomGen g) => (a,a) -> g -> (a,g)+integralRandomR  (a,b) g = case randomR (fromIntegral a :: Integer,+                                         fromIntegral b :: Integer) g of+                            (x,g') -> (fromIntegral x, g')++-- | Constrained position generators++genOffset :: Gen Offset+genOffset = do isneg <- arbitrary+               nnoff <- genNonNegOffset+               return $ (if isneg then negate else id) nnoff++genNonNegOffset :: Gen Offset+genNonNegOffset = liftM (subtract 1) genPositiveOffset++genPositiveOffset :: Gen Offset+genPositiveOffset = do scale <- chooseInteger (1, 13)+                       liftM fromIntegral $ chooseInteger (1, 2^scale)+    where chooseInteger :: (Integer, Integer) -> Gen Integer+          chooseInteger = choose+++instance Random Word8 where+    randomR = integralRandomR+    random = randomR (minBound,maxBound)++instance Arbitrary Word8 where+    arbitrary = choose (0,255)+    coarbitrary _ = id++instance Arbitrary Nucleotide where+    arbitrary = elements (map N "aaacccgggtttn")+    coarbitrary _ = id++instance Arbitrary Quality where+    arbitrary = do c <- choose (0,60)+                   return (Q c)+    coarbitrary _ = id++instance Arbitrary ESTq where+    arbitrary = do n <- choose (1,100)+                   s <- vector n+                   q <- vector n+                   return $ Eq $ Seq (fromStr "qctest")+                              (fromStr $ map fromN s) (Just $ pack $ map fromQ q)+    coarbitrary _ = id++instance Arbitrary EST where+    arbitrary = do n <- choose (1,100)+                   s <- vector n+                   return $ E $ Seq (fromStr "qctest")+                              (fromStr $ map fromN s) Nothing+    coarbitrary _ = id++instance Arbitrary Char where+    arbitrary = elements (['A'..'Z']++['a'..'z']++" \t\n\r")+    coarbitrary _ = id++instance Arbitrary EST_short where+    arbitrary = do let n = 200+                   s <- vector n+                   q <- vector n+                   return $ ES $ Seq (fromStr "qctest")+                              (fromStr $ map fromN s) (Just $ pack $ map fromQ q)+    coarbitrary _ = id++instance Arbitrary EST_long where+    arbitrary = do let n = 1000+                   s <- vector n+                   q <- vector n+                   return $ EL $ Seq (fromStr "qctest")+                              (fromStr $ map fromN s) (Just $ pack $ map fromQ q)+    coarbitrary _ = id++-- 1000 ESTs of length 1000+instance Arbitrary EST_set where+    arbitrary = do let n = 1000+                   s <- vector n+                   return (ESet $ map (\(EL x) -> x) s)+    coarbitrary _ = id
bio.cabal view
@@ -1,5 +1,5 @@ Name:                bio-Version:             0.3.3.4+Version:             0.3.5 License:             LGPL License-file:        LICENSE Author:              Ketil Malde@@ -17,15 +17,16 @@                      phd formats.  Rudimentary support for doing alignments - including                      dynamic adjustment of scores based on sequence quality - and Blast                      output parsing.  Partly implemented single linkage clustering, and-                     multiple alignment.-                     .+		     multiple alignment.  Reading Gene Ontology (GO) annotations (GOA) and+		     definitions\/hierarchy.+		     .                      The Darcs repository is at: <http://malde.org/~ketil/biohaskell/biolib>.-Homepage:            http://malde.org/~ketil/+Homepage:            http://blog.malde.org/index.php/the-haskell-bioinformatics-library/  Tested-With:         GHC==6.8.2 Build-Type:          Simple-Build-Depends:       base>3, QuickCheck<2, binary, tagsoup>=0.4, bytestring,-                     containers, array, parallel, parsec+Build-Depends:       base>3, QuickCheck<2, binary, tagsoup>=0.4, bytestring >= 0.9.1,+                     containers, array, parallel, parsec, random, old-time, mtl -- add fps for ghc 6.4.2; change imports in Bio/Sequence/TwoBit.hs if you want QC 2  -- We omit the debian/ and Test/ files because those are for development, not installation.@@ -33,18 +34,26 @@  Exposed-modules:     Bio.Sequence,                      Bio.Sequence.SeqData,-                     Bio.Sequence.Fasta, Bio.Sequence.TwoBit, Bio.Sequence.Phd,+                     Bio.Sequence.Fasta, Bio.Sequence.FastQ,+		     Bio.Sequence.TwoBit, Bio.Sequence.Phd,                      Bio.Sequence.Entropy, Bio.Sequence.HashWord,                      Bio.Sequence.GOA,                      Bio.Sequence.GeneOntology, 		     Bio.Sequence.KEGG,+		     Bio.Sequence.SFF,                      Bio.Alignment.BlastData, Bio.Alignment.BlastFlat,                      Bio.Alignment.Blast, Bio.Alignment.BlastXML,                      Bio.Alignment.AlignData, Bio.Alignment.Matrices,                      Bio.Alignment.SAlign, Bio.Alignment.AAlign, Bio.Alignment.QAlign-                     Bio.Alignment.Multiple, Bio.Alignment.ACE+                     Bio.Alignment.Multiple, Bio.Alignment.ACE,+                     Bio.Alignment.Soap,                      Bio.Clustering,-                     Bio.Util, Bio.Util.Parsex+                     Bio.Util, Bio.Util.Parsex, Bio.Util.TestBase+		 Bio.Location.Strand, Bio.Location.Position,+		 Bio.Location.ContigLocation, Bio.Location.Location, Bio.Location.LocMap,+		 Bio.Location.OnSeq, Bio.Location.SeqLocation, Bio.Location.SeqLocMap,+		 Bio.GFF3.Escape, Bio.GFF3.Feature, Bio.GFF3.FeatureHier, Bio.GFF3.FeatureHierSequences,+		 Bio.GFF3.SGD  extensions:          CPP, ParallelListComp ghc-options:         -Wall -O2 -fexcess-precision -funbox-strict-fields -auto-all