File: linear_paths.rb

package info (click to toggle)
ruby-rgfa 1.3.1%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 820 kB
  • sloc: ruby: 5,649; makefile: 9
file content (140 lines) | stat: -rw-r--r-- 5,851 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#
# Methods for the RGFA class, which involve a traversal of the graph following
# links
#
module RGFATools::LinearPaths

  # @!method merge_linear_path(segpath, **options)
  #   Merge a linear path, i.e. a path of segments without extra-branches.
  #   @!macro [new] merge_more
  #     Extends the RGFA method, with additional functionality:
  #     - +name+: the name of the merged segment is set to the name of the
  #       single segments joined by underscore (+_+). If a name already
  #       contained an underscore, it is splitted before merging. Whenever a
  #       segment is reversed complemented, its name (or the name of all its
  #       components) is suffixed with a +^+; if the last letter was already
  #       +^+, it is removed; if it contained +_+ the name is splitted, the
  #       elements reversed and joined back using +_+; round parentheses are
  #       removed from the name before processing and added back after it.
  #     - +:or+: keeps track of the origin of the merged segment; the
  #       origin tag is set to an array of :or or name
  #       (if no :or available) tags of the segment which have been merged;
  #       the character +^+ is assigned the same meaning as in +name+
  #     - +:rn+: tag used to store possible inversion positions and
  #       it is updated by this method; i.e. it is passed from the single
  #       segments to the merged segment, and the coordinates updated
  #     - +:mp+: tag used to store the position of the
  #       single segments in the merged segment; it is created or updated by
  #       this method
  #     Note that the extensions to the original method will only be run
  #     if either #enable_extensions has been called on RGFA object
  #     or the enable_tracking parameter is set..
  #     After calling #enable_extensions, you may still obtain the original
  #     behaviour by setting the disable_tracking parameter.
  #   @!macro merge_more
  #
  #   @!macro [new] merge_lim
  #
  #     Limitations: all containments und paths involving merged segments are
  #     deleted.
  #   @!macro merge_lim
  #
  #   @param segpath [Array<RGFA::SegmentEnd>] a linear path, such as that
  #     retrieved by #linear_path (see RGFA API documentation)
  #   @!macro [new] merge_options
  #     @param options [Hash] optional keyword arguments
  #     @option options [String, :short, nil] :merged_name (nil)
  #       if nil, the merged_name is automatically computed; if :short,
  #       a name is computed starting with "merged1" and calling next until
  #       an available name is founf; if String, the name to use
  #     @option options [Boolean] :cut_counts (false)
  #       if true, total count in merged segment m, composed of segments
  #       s of set S is multiplied by the factor Sum(|s in S|)/|m|
  #     @option options [Boolean] :enable_tracking (false)
  #       if true, the extended method with RGFATools is called,
  #       no matter if RGFA#enable_extensions was called.
  #     @option options [Boolean] :disable_tracking (false)
  #       if true, the original method of RGFA without RGFATools is called,
  #       no matter if RGFA#enable_extensions was called.
  #   @!macro merge_options
  #
  #   @return [RGFA] self
  #   @see #merge_linear_paths

  # @!method merge_linear_paths(**options)
  #   Merge all linear paths in the graph, i.e.
  #   paths of segments without extra-branches
  #   @!macro merge_more
  #   @!macro merge_lim
  #   @!macro merge_options
  #
  #   @return [RGFA] self

  private

  Redefined = [:add_segment_to_merged]

  def reverse_segment_name(name, separator)
    name.to_s.split(separator).map do |part|
      openp = part[0] == "("
      part = part[1..-1] if openp
      closep = part[-1] == ")"
      part = part[0..-2] if closep
      part = (part[-1] == "^") ? part[0..-2] : part+"^"
      part += ")" if openp
      part = "(#{part}" if closep
      part
    end.reverse.join(separator)
  end

  def reverse_pos_array(pos_array, lastpos)
    return nil if pos_array.nil? or lastpos.nil?
    pos_array.map {|pos| lastpos - pos + 1}.reverse
  end

  def add_segment_to_merged_with_rgfatools(merged, segment, reversed, cut, init,
                                          options)
    if !options[:enable_tracking] and
        (options[:disable_tracking] or !@extensions_enabled)
      return add_segment_to_merged_without_rgfatools(merged, segment, reversed,
                                                    cut, init, options)
    end
    s = (reversed ? segment.sequence.rc[cut..-1] : segment.sequence[cut..-1])
    n = (reversed ? reverse_segment_name(segment.name, "_") : segment.name.to_s)
    rn = (reversed ? reverse_pos_array(segment.rn, segment.LN) : segment.rn)
    mp = (reversed ? reverse_pos_array(segment.mp, segment.LN) : segment.mp)
    mp = [1, segment.LN] if mp.nil? and segment.LN
    if segment.or.nil?
      o = n
    else
      o = (reversed ? reverse_segment_name(segment.or, ",") : segment.or)
    end
    if init
      merged.sequence = s
      merged.name = options[:merged_name].nil? ? n : options[:merged_name]
      merged.LN = segment.LN
      merged.rn = rn
      merged.or = o
      merged.mp = mp
    else
      (segment.sequence == "*") ? (merged.sequence = "*")
                                : (merged.sequence += s)
      merged.name = "#{merged.name}_#{n}" if options[:merged_name].nil?
      if merged.LN
        if rn
          rn = rn.map {|pos| pos - cut + merged.LN}
          merged.rn = merged.rn.nil? ? rn : merged.rn + rn
        end
        if mp and merged.mp
          merged.mp += mp.map {|pos| pos - cut + merged.LN}
        end
        segment.LN ? merged.LN += (segment.LN - cut)
                   : merged.LN = nil
      else
        merged.mp = nil
      end
      merged.or = merged.or.nil? ? o : "#{merged.or},#{o}"
    end
  end

end