minimap2 0.2.30.2 → 0.2.30.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8528863219ede8de2b25b477d8258cca91aaafe7fcf6f34f3982d136cedb2bd3
4
- data.tar.gz: 58c280e7262bd1d15f0d7d3306ed8fa08759279f24680f6265e8366f6358465d
3
+ metadata.gz: 2a3bf89a18a50825f14454ce8683dd019377fc45e59a4d46eee617a55d0e64e8
4
+ data.tar.gz: c1dd61ced844c50b7aec1ba1f9da8d8b47ab3b94a1e2f4b0b4bcdd16169e4f0c
5
5
  SHA512:
6
- metadata.gz: bd3fd0229795796096f48a33683b23bad5005e0d77436338939b6332994727cd8bc6f0b29be15dc0ea05d7df57ebe703cf50bd319513cdb00943912f9a6f06b8
7
- data.tar.gz: 1a7ecc6b032699c91c7d06156a6b64eecbf4905820f108f1a18cdabddc8cf938cc94af2346b888c8591b86cddf7892d4afcf6627571509fe67907e832f301106
6
+ metadata.gz: 198ae12116da51051dcac0665a85611a2d5bbe5df49ff854fff02c1f686f6c5fd7d40378876de81542d8ca9fe6fb8d71c0c59cde53497368ae4fc83b06a4c685
7
+ data.tar.gz: 1226cb572e95c805d3817bcaf5048fcc6a3bb217e7ac86b56f866b132c3ffe9ed5f8a1ba8e67b1bb798a1c2852e060f611229ccae9364b477a9863366717ce5c
data/ext/cmappy/cmappy.c CHANGED
@@ -127,3 +127,8 @@ mm_idx_t *mappy_idx_seq(int w, int k, int is_hpc, int bucket_bits, const char *s
127
127
  free(s);
128
128
  return mi;
129
129
  }
130
+
131
+ void mappy_free(void *p)
132
+ {
133
+ free(p);
134
+ }
data/ext/cmappy/cmappy.h CHANGED
@@ -41,4 +41,6 @@ char *mappy_fetch_seq(const mm_idx_t *mi, const char *name, int st, int en, int
41
41
 
42
42
  mm_idx_t *mappy_idx_seq(int w, int k, int is_hpc, int bucket_bits, const char *seq, int len);
43
43
 
44
+ void mappy_free(void *p);
45
+
44
46
  #endif
@@ -56,7 +56,8 @@ module Minimap2
56
56
  extra_flags: nil,
57
57
  scoring: nil,
58
58
  sc_ambi: nil,
59
- max_chain_skip: nil
59
+ max_chain_skip: nil,
60
+ batch_size: nil
60
61
  )
61
62
  @idx_opt = FFI::IdxOpt.new
62
63
  @map_opt = FFI::MapOpt.new
@@ -66,7 +67,11 @@ module Minimap2
66
67
 
67
68
  # always perform alignment
68
69
  map_opt[:flag] |= 4
70
+
71
+ # Keep a large batch_size by default (mappy-compatible behavior) to avoid
72
+ # splitting indexes unless explicitly requested.
69
73
  idx_opt[:batch_size] = 0x7fffffffffffffff
74
+ idx_opt[:batch_size] = batch_size if batch_size
70
75
 
71
76
  # override preset options
72
77
  idx_opt[:k] = k if k
@@ -102,24 +107,53 @@ module Minimap2
102
107
  # The Ruby version raises an error here
103
108
  raise "Cannot open : #{fn_idx_in}" if reader.null?
104
109
 
105
- @index = FFI.mm_idx_reader_read(reader, n_threads)
106
- FFI.mm_idx_reader_close(reader)
110
+ @indexes = []
111
+ begin
112
+ loop do
113
+ idx = FFI.mm_idx_reader_read(reader, n_threads)
114
+ break if idx.nil? || idx.null?
115
+
116
+ # Initialize sequence name index for each part
117
+ FFI.mm_idx_index_name(idx)
118
+ @indexes << idx
119
+ end
120
+ ensure
121
+ FFI.mm_idx_reader_close(reader)
122
+ end
123
+
124
+ raise "Failed to read index parts from: #{fn_idx_in}" if @indexes.empty?
125
+
126
+ # Keep backward-compatible accessor for a single index
127
+ @index = @indexes[0]
107
128
  FFI.mm_mapopt_update(map_opt, index)
108
- FFI.mm_idx_index_name(index)
109
129
  elsif seq
110
130
  @index = FFI.mappy_idx_seq(
111
131
  idx_opt[:w], idx_opt[:k], idx_opt[:flag] & 1,
112
132
  idx_opt[:bucket_bits], seq, seq.size
113
133
  )
134
+ @indexes = [@index]
114
135
  FFI.mm_mapopt_update(map_opt, index)
115
136
  map_opt[:mid_occ] = 1000 # don't filter high-occ seeds
137
+ else
138
+ @indexes = []
139
+ @index = FFI::Idx.new(::FFI::Pointer::NULL)
116
140
  end
117
141
  end
118
142
 
119
143
  # Explicitly releases the memory of the index object.
120
144
 
121
145
  def free_index
122
- FFI.mm_idx_destroy(index) unless index.null?
146
+ indexes = @indexes
147
+ if indexes && !indexes.empty?
148
+ indexes.each do |idx|
149
+ FFI.mm_idx_destroy(idx) unless idx.nil? || idx.null?
150
+ end
151
+ elsif defined?(@index) && !@index.nil? && !@index.null?
152
+ FFI.mm_idx_destroy(@index)
153
+ end
154
+ ensure
155
+ @indexes = []
156
+ @index = FFI::Idx.new(::FFI::Pointer::NULL)
123
157
  end
124
158
 
125
159
  # @param seq [String]
@@ -147,62 +181,122 @@ module Minimap2
147
181
  return if index.null?
148
182
  return if (map_opt[:flag] & 4).zero? && (index[:flag] & 2).zero?
149
183
 
150
- map_opt[:max_frag_len] = max_frag_len if max_frag_len
151
- map_opt[:flag] |= extra_flags if extra_flags
184
+ orig_map_opt_bytes = map_opt.to_ptr.read_bytes(FFI::MapOpt.size)
185
+ orig_best_n = map_opt[:best_n]
186
+
187
+ owned_buf = false
188
+ if buf.nil?
189
+ buf = FFI.mm_tbuf_init
190
+ owned_buf = true
191
+ end
152
192
 
153
- buf ||= FFI::TBuf.new
154
193
  km = FFI.mm_tbuf_get_km(buf)
194
+ alignments = []
155
195
 
156
- n_regs_ptr = ::FFI::MemoryPointer.new :int
157
- regs_ptr = FFI.mm_map_aux(index, name, seq, seq2, n_regs_ptr, buf, map_opt)
158
- n_regs = n_regs_ptr.read_int
196
+ idx_parts = @indexes
197
+ idx_parts = [index] if idx_parts.nil? || idx_parts.empty?
159
198
 
160
- regs = Array.new(n_regs) do |i|
161
- FFI::Reg1.new(regs_ptr + i * FFI::Reg1.size)
162
- end
199
+ begin
200
+ idx_parts.each do |idx_part|
201
+ next if idx_part.nil? || idx_part.null?
163
202
 
164
- hit = FFI::Hit.new
203
+ # Update options for this specific index part
204
+ FFI.mm_mapopt_update(map_opt, idx_part)
165
205
 
166
- cs_str = ::FFI::MemoryPointer.new(::FFI::MemoryPointer.new(:string))
167
- m_cs_str = ::FFI::MemoryPointer.new :int
206
+ # Per-call options (do not leak across calls)
207
+ map_opt[:flag] |= 4
208
+ map_opt[:best_n] = orig_best_n
209
+ map_opt[:max_frag_len] = max_frag_len if max_frag_len
210
+ map_opt[:flag] |= extra_flags if extra_flags
168
211
 
169
- alignments = []
212
+ n_regs_ptr = ::FFI::MemoryPointer.new :int
213
+ regs_ptr = FFI.mm_map_aux(idx_part, name, seq, seq2, n_regs_ptr, buf, map_opt)
214
+ n_regs = n_regs_ptr.read_int
170
215
 
171
- i = 0
172
- begin
173
- while i < n_regs
174
- FFI.mm_reg2hitpy(index, regs[i], hit)
216
+ next if regs_ptr.nil? || regs_ptr.null? || n_regs <= 0
217
+
218
+ regs = Array.new(n_regs) do |i|
219
+ FFI::Reg1.new(regs_ptr + i * FFI::Reg1.size)
220
+ end
175
221
 
176
- c = hit[:cigar32].read_array_of_uint32(hit[:n_cigar32])
177
- cigar = c.map { |x| [x >> 4, x & 0xf] } # 32-bit CIGAR encoding -> Ruby array
222
+ hit = FFI::Hit.new
178
223
 
179
- _cs = ""
180
- _md = ""
181
- if cs or md
182
- cur_seq = hit[:seg_id] > 0 && seq2 ? seq2 : seq
224
+ cs_buf_ptr = nil
225
+ m_cs_ptr = nil
226
+ if cs || md
227
+ cs_buf_ptr = ::FFI::MemoryPointer.new(:pointer)
228
+ cs_buf_ptr.write_pointer(::FFI::Pointer::NULL)
229
+ m_cs_ptr = ::FFI::MemoryPointer.new(:int)
230
+ m_cs_ptr.write_int(0)
231
+ end
183
232
 
184
- if cs
185
- l_cs_str = FFI.mm_gen_cs(km, cs_str, m_cs_str, @index, regs[i], cur_seq, 1)
186
- _cs = cs_str.read_pointer.read_string(l_cs_str)
187
- end
233
+ i = 0
234
+ begin
235
+ while i < n_regs
236
+ FFI.mm_reg2hitpy(idx_part, regs[i], hit)
237
+
238
+ c = hit[:cigar32].read_array_of_uint32(hit[:n_cigar32])
239
+ cigar = c.map { |x| [x >> 4, x & 0xf] } # 32-bit CIGAR encoding -> Ruby array
240
+
241
+ _cs = ""
242
+ _md = ""
243
+ if cs or md
244
+ cur_seq = hit[:seg_id] > 0 && seq2 ? seq2 : seq
245
+
246
+ if cs
247
+ l_cs_str = FFI.mm_gen_cs(km, cs_buf_ptr, m_cs_ptr, idx_part, regs[i], cur_seq, 1)
248
+ cs_ptr = cs_buf_ptr.read_pointer
249
+ _cs = cs_ptr.null? || l_cs_str <= 0 ? "" : cs_ptr.read_string(l_cs_str)
250
+ end
188
251
 
189
- if md
190
- l_cs_str = FFI.mm_gen_md(km, cs_str, m_cs_str, @index, regs[i], cur_seq)
191
- _md = cs_str.read_pointer.read_string(l_cs_str)
252
+ if md
253
+ l_cs_str = FFI.mm_gen_md(km, cs_buf_ptr, m_cs_ptr, idx_part, regs[i], cur_seq)
254
+ cs_ptr = cs_buf_ptr.read_pointer
255
+ _md = cs_ptr.null? || l_cs_str <= 0 ? "" : cs_ptr.read_string(l_cs_str)
256
+ end
257
+ end
258
+
259
+ alignments << Alignment.new(hit, cigar, _cs, _md)
260
+
261
+ FFI.mm_free_reg1(regs[i])
262
+ i += 1
263
+ end
264
+ ensure
265
+ while i < n_regs
266
+ FFI.mm_free_reg1(regs[i])
267
+ i += 1
192
268
  end
193
- end
194
269
 
195
- alignments << Alignment.new(hit, cigar, _cs, _md)
270
+ if cs_buf_ptr
271
+ cs_ptr = cs_buf_ptr.read_pointer
272
+ FFI.mappy_free(cs_ptr) unless cs_ptr.nil? || cs_ptr.null?
273
+ end
196
274
 
197
- FFI.mm_free_reg1(regs[i])
198
- i += 1
275
+ # Free the mm_map/mm_map_aux return value array itself
276
+ FFI.mappy_free(regs_ptr) unless regs_ptr.nil? || regs_ptr.null?
277
+ end
199
278
  end
200
279
  ensure
201
- while i < n_regs
202
- FFI.mm_free_reg1(regs[i])
203
- i += 1
280
+ FFI.mm_tbuf_destroy(buf) if owned_buf
281
+
282
+ # Restore map_opt to the state before this call
283
+ map_opt.to_ptr.put_bytes(0, orig_map_opt_bytes)
284
+ end
285
+
286
+ if orig_best_n && orig_best_n > 0 && alignments.length > orig_best_n
287
+ alignments.sort_by! do |aln|
288
+ [
289
+ aln.primary? ? 1 : 0,
290
+ aln.mapq,
291
+ aln.mlen,
292
+ aln.blen,
293
+ -aln.nm
294
+ ]
204
295
  end
296
+ alignments.reverse!
297
+ alignments = alignments.take(orig_best_n)
205
298
  end
299
+
206
300
  alignments
207
301
  end
208
302
 
@@ -215,12 +309,28 @@ module Minimap2
215
309
  return if index.null?
216
310
  return if (map_opt[:flag] & 4).zero? && (index[:flag] & 2).zero?
217
311
 
218
- lp = ::FFI::MemoryPointer.new(:int)
219
- s = FFI.mappy_fetch_seq(index, name, start, stop, lp)
220
- l = lp.read_int
221
- return nil if l == 0
312
+ idx_parts = @indexes
313
+ idx_parts = [index] if idx_parts.nil? || idx_parts.empty?
314
+
315
+ idx_parts.each do |idx_part|
316
+ next if idx_part.nil? || idx_part.null?
222
317
 
223
- s.read_string(l)
318
+ lp = ::FFI::MemoryPointer.new(:int)
319
+ s = FFI.mappy_fetch_seq(idx_part, name, start, stop, lp)
320
+ l = lp.read_int
321
+ if l == 0
322
+ FFI.mappy_free(s) unless s.nil? || s.null?
323
+ next
324
+ end
325
+
326
+ begin
327
+ return s.read_string(l)
328
+ ensure
329
+ FFI.mappy_free(s) unless s.nil? || s.null?
330
+ end
331
+ end
332
+
333
+ nil
224
334
  end
225
335
 
226
336
  # k-mer length, no larger than 28
@@ -236,14 +346,35 @@ module Minimap2
236
346
  end
237
347
 
238
348
  def n_seq
239
- index[:n_seq]
349
+ return 0 if index.null?
350
+
351
+ indexes = @indexes
352
+ return index[:n_seq] if indexes.nil? || indexes.empty?
353
+
354
+ indexes.sum { |idx| idx.nil? || idx.null? ? 0 : idx[:n_seq] }
240
355
  end
241
356
 
242
357
  def seq_names
243
- ptr = index[:seq].to_ptr
244
- Array.new(index[:n_seq]) do |i|
245
- FFI::IdxSeq.new(ptr + i * FFI::IdxSeq.size)[:name]
358
+ return [] if index.null?
359
+
360
+ indexes = @indexes
361
+ indexes = [index] if indexes.nil? || indexes.empty?
362
+
363
+ names = []
364
+ seen = {}
365
+ indexes.each do |idx|
366
+ next if idx.nil? || idx.null?
367
+
368
+ ptr = idx[:seq].to_ptr
369
+ idx[:n_seq].times do |i|
370
+ name = FFI::IdxSeq.new(ptr + i * FFI::IdxSeq.size)[:name]
371
+ next if seen[name]
372
+
373
+ seen[name] = true
374
+ names << name
375
+ end
246
376
  end
377
+ names
247
378
  end
248
379
  end
249
380
  end
@@ -79,7 +79,12 @@ module Minimap2
79
79
  attach_function \
80
80
  :mappy_revcomp,
81
81
  %i[int pointer],
82
- :string
82
+ :pointer
83
+
84
+ attach_function \
85
+ :mappy_free,
86
+ [:pointer],
87
+ :void
83
88
 
84
89
  attach_function \
85
90
  :mappy_fetch_seq,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Minimap2
4
- VERSION = "0.2.30.2"
4
+ VERSION = "0.2.30.3"
5
5
  end
data/lib/minimap2.rb CHANGED
@@ -105,7 +105,14 @@ module Minimap2
105
105
  l = seq.size
106
106
  bseq = ::FFI::MemoryPointer.new(:char, l)
107
107
  bseq.put_bytes(0, seq)
108
- FFI.mappy_revcomp(l, bseq)
108
+ p = FFI.mappy_revcomp(l, bseq)
109
+ return "" if p.nil? || p.null?
110
+
111
+ begin
112
+ p.read_string(l)
113
+ ensure
114
+ FFI.mappy_free(p) unless p.nil? || p.null?
115
+ end
109
116
  end
110
117
 
111
118
  private
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minimap2
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.30.2
4
+ version: 0.2.30.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - kojix2
@@ -167,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
167
  - !ruby/object:Gem::Version
168
168
  version: '0'
169
169
  requirements: []
170
- rubygems_version: 3.6.9
170
+ rubygems_version: 4.0.3
171
171
  specification_version: 4
172
172
  summary: minimap2
173
173
  test_files: []