// Map routines to iterate a function over an array, potentially splitting the array slice into // chunks so that each chunk is processed concurrently. When using concurrent processing the // Chunk size is either the nearest even division of the total array over the chosen concurrent // processing goroutines or a specified maximum chunk size, whichever is smaller. Reducing // chunk size can reduce the impact of divergence in time for processing chunks, but may add // to overhead. func Map(set Mapper, threads, maxChunkSize int) (results []interface{}, err error) { queue := make(chan Operator, 1) p := NewProcessor(queue, 0, threads) defer p.Stop() chunkSize := util.Min(int(math.Ceil(float64(set.Len())/float64(threads))), maxChunkSize) quit := make(chan struct{}) go func() { for s := 0; s*chunkSize < set.Len(); s++ { select { case <-quit: break default: endChunk := util.Min(chunkSize*(s+1), set.Len()) queue <- set.Slice(chunkSize*s, endChunk) } } }() for r := 0; r*chunkSize < set.Len(); r++ { result := <-p.out if result.Err != nil { err = bio.NewError("Map failed", 0, err) close(quit) break } results = append(results, result.Value) } return }
// Stitch provides a function that may be used by polymer types to implement Stitcher. // It makes use of reflection and so may be slower than type-specific implementations. // This is the reference implementation and should be used to compare type-specific // implementation against in testing. func Stitch(pol interface{}, offset int, f feat.FeatureSet) (s interface{}, err error) { t := interval.NewTree() var i *interval.Interval for _, feature := range f { i, err = interval.New(emptyString, feature.Start, feature.End, 0, nil) if err != nil { return } else { t.Insert(i) } } pv := reflect.ValueOf(pol) pLen := pv.Len() end := pLen + offset span, err := interval.New(emptyString, offset, end, 0, nil) if err != nil { panic("Sequence.End() < Sequence.Start()") } fs, _ := t.Flatten(span, 0, 0) l := 0 for _, seg := range fs { l += util.Min(seg.End(), end) - util.Max(seg.Start(), offset) } tv := reflect.MakeSlice(pv.Type(), 0, l) for _, seg := range fs { tv = reflect.AppendSlice(tv, pv.Slice(util.Max(seg.Start()-offset, 0), util.Min(seg.End()-offset, pLen))) } return tv.Interface(), nil }
// Join segments of the sequence, returning any error. func (self *Seq) Compose(f feat.FeatureSet) (err error) { l := 0 for _, seg := range f { if seg.End < seg.Start { return bio.NewError("Feature end < start", 0, seg) } l += util.Min(seg.End, self.End()) - util.Max(seg.Start, self.Start()) } t := &Seq{} *t = *self t.S = &Packing{Letters: make([]alphabet.Pack, 0, (l+3)/4)} var tseg seq.Sequence for _, seg := range f { tseg, err = self.Subseq(util.Max(seg.Start, self.Start()), util.Min(seg.End, self.End())) if err != nil { return } tseg := tseg.(*Seq) if seg.Strand == -1 { tseg.RevComp() } tseg.S.Align(seq.Start) t.S.Align(seq.End) t.S.Letters = append(t.S.Letters, tseg.S.Letters...) t.S.RightPad = tseg.S.RightPad } *self = *t return }
func (self *Interval) adjustRange() { if self.left != nil && self.right != nil { self.minStart = util.Min(self.start, self.left.minStart) self.maxEnd = util.Max(self.end, self.left.maxEnd, self.right.maxEnd) } else if self.left != nil { self.minStart = util.Min(self.start, self.left.minStart) self.maxEnd = util.Max(self.end, self.left.maxEnd) } else if self.right != nil { self.minStart = util.Min(self.start, self.right.minStart) self.maxEnd = util.Max(self.end, self.right.maxEnd) } }
func (self *Multi) Stitch(f feat.FeatureSet) (err error) { tr := interval.NewTree() var i *interval.Interval for _, feature := range f { i, err = interval.New(emptyString, feature.Start, feature.End, 0, nil) if err != nil { return } else { tr.Insert(i) } } span, err := interval.New(emptyString, self.Start(), self.End(), 0, nil) if err != nil { panic("Sequence.End() < Sequence.Start()") } fs, _ := tr.Flatten(span, 0, 0) ff := feat.FeatureSet{} for _, seg := range fs { ff = append(ff, &feat.Feature{ Start: util.Max(seg.Start(), self.Start()), End: util.Min(seg.End(), self.End()), }) } return self.Compose(ff) }
func (self *Seq) stitch(f []*interval.Interval) (ts []byte) { for _, seg := range f { ts = append(ts, self.Seq[util.Max(seg.Start()-self.Offset, 0):util.Min(seg.End()-self.Offset, len(self.Seq))]...) } return }
// Pack a sequence into the Packed sequence. Returns a string giving diagnostic information. func (pa *Packer) Pack(sequence *seq.Seq) string { m := pa.Packed.Meta.(seqMap) c := contig{seq: sequence} padding := binSize - sequence.Len()%binSize if padding < minPadding { padding += binSize } pa.length += pa.lastPad c.from = pa.length pa.length += sequence.Len() pa.lastPad = padding bins := make([]int, (padding+sequence.Len())/binSize) for i := 0; i < len(bins); i++ { bins[i] = len(m.contigs) } m.binMap = append(m.binMap, bins...) m.contigs = append(m.contigs, c) pa.Packed.Meta = m return fmt.Sprintf("%20s\t%10d\t%7d-%-d", sequence.ID[:util.Min(20, len(sequence.ID))], sequence.Len(), len(m.binMap)-len(bins), len(m.binMap)-1) }
// Merge a range of intervals provided by r. Returns merged intervals in a slice and // intervals contributing to merged intervals groups in a slice of slices. func (self *Interval) flatten(r chan *Interval, tolerance int) (flat []*Interval, rich [][]*Interval) { flat = []*Interval{} rich = [][]*Interval{{}} min, max := util.MaxInt, util.MinInt var last *Interval for current := range r { if last != nil && current.start-tolerance > max { n, _ := New(current.seg, min, max, 0, nil) flat = append(flat, n) min = current.start max = current.end rich = append(rich, []*Interval{}) } else { min = util.Min(min, current.start) max = util.Max(max, current.end) } rich[len(rich)-1] = append(rich[len(rich)-1], current) last = current } n, _ := New(last.seg, min, max, 0, nil) flat = append(flat, n) return }
func (self *Quality) stitch(fs []*interval.Interval) (tq []Qsanger) { for _, seg := range fs { tq = append(tq, self.Qual[util.Max(seg.Start()-self.Offset, 0):util.Min(seg.End()-self.Offset, len(self.Qual))]...) } return }
// Join sequentially order disjunct segments of the sequence, returning any error. func (self *Seq) Stitch(f feat.FeatureSet) (err error) { tr := interval.NewTree() var i *interval.Interval for _, feature := range f { i, err = interval.New(emptyString, feature.Start, feature.End, 0, nil) if err != nil { return } else { tr.Insert(i) } } span, err := interval.New(emptyString, self.offset, self.End(), 0, nil) if err != nil { panic("packed: Sequence.End() < Sequence.Start()") } fs, _ := tr.Flatten(span, 0, 0) l := 0 for _, seg := range fs { l += util.Min(seg.End(), self.End()) - util.Max(seg.Start(), self.Start()) } t := &Seq{} *t = *self t.S = &Packing{Letters: make([]alphabet.Pack, 0, (l+3)/4)} var tseg seq.Sequence for _, seg := range fs { tseg, err = self.Subseq(util.Max(seg.Start(), self.Start()), util.Min(seg.End(), self.End())) if err != nil { return } s := tseg.(*Seq).S s.Align(seq.Start) t.S.Align(seq.End) t.S.Letters = append(t.S.Letters, s.Letters...) t.S.RightPad = s.RightPad } *self = *t return }
// Compose provides a function that may be used by polymer types to implement Composer. // It makes use of reflection and so may be slower than type-specific implementations. // This is the reference implementation and should be used to compare type-specific // implementation against in testing. func Compose(pol interface{}, offset int, f feat.FeatureSet) (s []interface{}, err error) { pv := reflect.ValueOf(pol) pLen := pv.Len() end := pLen + offset tv := make([]reflect.Value, len(f)) for i, seg := range f { if seg.End < seg.Start { return nil, bio.NewError("Feature End < Start", 0, f) } l := util.Min(seg.End, end) - util.Max(seg.Start, offset) tv[i] = reflect.MakeSlice(pv.Type(), l, l) reflect.Copy(tv[i], pv.Slice(util.Max(seg.Start-offset, 0), util.Min(seg.End-offset, pLen))) } s = make([]interface{}, len(tv)) for i := range tv { s[i] = tv[i].Interface() } return }
func (self *Interval) merge(i *Interval, overlap int) (inserted *Interval, removed []*Interval) { r := make(chan *Interval) removed = []*Interval{} wait := make(chan struct{}) go func() { defer close(wait) min, max := util.MaxInt, util.MinInt for old := range r { min, max = util.Min(min, old.start), util.Max(max, old.end) removed = append(removed, old) } i.start, i.end = util.Min(i.start, min), util.Max(i.end, max) inserted = i // TODO: Do something sensible when only one interval is found and the only action is to extend or ignore }() self.intersect(i, overlap, r) close(r) <-wait return }
// Write a single sequence and return the number of bytes written and any error. func (self *Writer) Write(s *seq.Seq) (n int, err error) { var ln int n, err = self.w.WriteString(string(self.IDPrefix) + s.ID + "\n") if err == nil { for i := 0; i*self.Width <= s.Len(); i++ { endLinePos := util.Min(self.Width*(i+1), s.Len()) for _, elem := range [][]byte{self.SeqPrefix, s.Seq[self.Width*i : endLinePos], {'\n'}} { ln, err = self.w.Write(elem) if n += ln; err != nil { return } } } } return }
// Render the rainbow based on block of sequence in the index with the given size. Left and right define the extent of the rendering. // Vary specifies which color values change in response to kmer frequency. func (self *KmerRainbow) Paint(vary int, block, size, left, right int) (i *image.RGBA, err error) { right = util.Min(right, self.Rect.Dx()) kmers := make([]uint32, self.RGBA.Rect.Dy()) kmask := util.Pow4(self.Index.GetK()) kmaskf := float64(kmask) f := func(index *kmerindex.Index, _, kmer int) { kmers[int(float64(kmer)*float64(self.RGBA.Rect.Dy())/kmaskf)]++ } self.Index.ForEachKmerOf(self.Index.Seq, block*size, (block+1)*size-1, f) c := color.HSVA{} lf := float64(len(kmers)) / 360 var val float64 scale := 1 / float64(self.Max) for y, v := range kmers { val = float64(v) / scale c.H = float64(y) / lf if vary&S != 0 { c.S = val } else { c.S = self.BackGround.S } if vary&V != 0 { c.V = val } else { c.V = self.BackGround.V } if vary&A != 0 { c.A = val } else { c.A = self.BackGround.A } if left >= 0 && right > left { for x := left; x < right; x++ { self.Set(x, y, c) } } else { println(left, right) for x := 0; x < self.Rect.Dx(); x++ { self.Set(x, y, c) } } } return self.RGBA, nil }