module

Minimap2

Pure-Crystal port of minimap2, a versatile pairwise sequence aligner for nucleotide sequences.

All algorithms are implemented directly in Crystal — no C bindings.

Quick start:

aligner = Minimap2::Aligner.from_strings(["ACGT" * 100], ["ref"], "map-ont")
aligner.map("ACGTACGT...") do |hit|
  puts "#{hit.rid}\t#{hit.rs}-#{hit.re}\t#{hit.rev ? '-' : '+'}"
end

Constants

BASES_LOWER = "acgtn"
BASES_STR = "ACGTN"
CIGAR_DEL = 2
CIGAR_EQ_MATCH = 7
CIGAR_HARDCLIP = 5
CIGAR_INS = 1
CIGAR_MATCH = 0

CIGAR operation codes

CIGAR_N_SKIP = 3
CIGAR_PADDING = 6
CIGAR_SOFTCLIP = 4
CIGAR_STR = "MIDNSHP=XB"
CIGAR_X_MISMATCH = 8
DBG_NO_KALLOC = 1

Debug flags

DBG_PRINT_ALN_SEQ = 8
DBG_PRINT_CHAIN = 16
DBG_PRINT_QNAME = 2
DBG_PRINT_SEED = 4
DBG_SEED_FREQ = 32
F_2_IO_THREADS = 32768_i64
F_ALL_CHAINS = 8388608_i64
F_CIGAR = 4_i64
F_COPY_COMMENT = 33554432_i64
F_EQX = 67108864_i64
F_FOR_ONLY = 1048576_i64
F_FRAG_MODE = 8192_i64
F_HARD_MLEVEL = 536870912_i64
F_HEAP_SORT = 4194304_i64
F_INDEPEND_SEG = 131072_i64
F_LONG_CIGAR = 65536_i64
F_NO_DIAG = 1_i64

Mapping / output flags (MM_F_*)

F_NO_DUAL = 2_i64
F_NO_END_FLT = 268435456_i64
F_NO_HASH_NAME = 17179869184_i64
F_NO_INV = 8589934592_i64
F_NO_LJOIN = 1024_i64
F_NO_PRINT_2ND = 16384_i64
F_NO_QUAL = 16_i64
F_OUT_CG = 32_i64
F_OUT_CS = 64_i64
F_OUT_CS_LONG = 2048_i64
F_OUT_DS = 137438953472_i64
F_OUT_JUNC = 1099511627776_i64
F_OUT_MD = 16777216_i64
F_OUT_SAM = 8_i64
F_PAF_NO_HIT = 134217728_i64
F_QSTRAND = 4294967296_i64
F_REV_ONLY = 2097152_i64
F_RMQ = 2147483648_i64
F_SAM_HIT_ONLY = 1073741824_i64
F_SECONDARY_SEQ = 68719476736_i64
F_SOFTCLIP = 524288_i64
F_SPLICE = 128_i64
F_SPLICE_FLANK = 262144_i64
F_SPLICE_FOR = 256_i64
F_SPLICE_OLD = 34359738368_i64
F_SPLICE_REV = 512_i64
F_SR = 4096_i64
F_SR_RNA = 549755813888_i64
F_WEAK_PAIRING = 274877906944_i64
I_HPC = 1

Index flags (MM_I_*)

I_NO_NAME = 4
I_NO_SEQ = 2
IDX_MAGIC = "MMI\u0002"

Index magic

INT32_MAX = 2147483647
INT32_MIN = -2147483648
JUNC_ANNO = 1

Junction flags

JUNC_MISC = 2
KSW_EZ_APPROX_DROP = 16
KSW_EZ_APPROX_MAX = 8
KSW_EZ_EXTZ_ONLY = 64
KSW_EZ_GENERIC_SC = 4
KSW_EZ_REV_CIGAR = 128
KSW_EZ_RIGHT = 2
KSW_EZ_SCORE_ONLY = 1
KSW_EZ_SPLICE_FLANK = 1024
KSW_EZ_SPLICE_FOR = 256
KSW_EZ_SPLICE_REV = 512
KSW_NEG_INF = -1073741824
KSW_SPSC_OFFSET = 64
LIB_VERSION = "2.30"

Library version

MAX_MAX_HIGH_OCC = 128
MAX_SEG = 255
PARENT_TMP_PRI = -2
PARENT_UNSET = -1

Internal parent sentinels

SEED_IGNORE = 1_u64 << 41
SEED_LONG_JOIN = 1_u64 << 40

Internal seed flags

SEED_SEG_MASK = 255_u64 << 48
SEED_SEG_SHIFT = 48
SEED_SELF = 1_u64 << 43
SEED_TANDEM = 1_u64 << 42
SEQ_COMP_TABLE = begin t = Array(UInt8).new(256, &.to_u8) pairs = {'A' => 'T', 'T' => 'A', 'C' => 'G', 'G' => 'C', 'a' => 't', 't' => 'a', 'c' => 'g', 'g' => 'c', 'U' => 'A', 'u' => 'a', 'R' => 'Y', 'Y' => 'R', 'S' => 'S', 'W' => 'W', 'K' => 'M', 'M' => 'K', 'B' => 'V', 'V' => 'B', 'D' => 'H', 'H' => 'D', 'N' => 'N', 'r' => 'y', 'y' => 'r', 's' => 's', 'w' => 'w', 'k' => 'm', 'm' => 'k', 'b' => 'v', 'v' => 'b', 'd' => 'h', 'h' => 'd', 'n' => 'n'} pairs.each do |k, v| t[k.ord] = v.ord.to_u8 end t end

Complement table for seq_comp_table (used when reversing sequences)

SEQ_NT4_TABLE = begin t = Array(UInt8).new(256, 4_u8) t['A'.ord] = 0_u8 t['C'.ord] = 1_u8 t['G'.ord] = 2_u8 t['T'.ord] = 3_u8 t['U'.ord] = 3_u8 t['a'.ord] = 0_u8 t['c'.ord] = 1_u8 t['g'.ord] = 2_u8 t['t'.ord] = 3_u8 t['u'.ord] = 3_u8 t end

Nucleotide encoding table: A=0, C=1, G=2, T=3, other=4

VERSION = "0.1.0"

Class methods

align_skeleton(opt : MmMapOpt, mi : MmIdx, qlen : Int32, qstr : String | Array(UInt8), n_regs_ref : Pointer(Int32), regs : Array(MmReg1), a : Array(Mm128)) : Array(MmReg1)

Alignment skeleton: align all regions with CIGAR output. Mirrors mm_align_skeleton().

Source
bseq_read_frag(fps : Array(BSeqFile), chunk_size : Int64, with_qual : Bool = false, with_comment : Bool = false) : Array(BSeq1)

Multi-file fragment reader (mirrors mm_bseq_read_frag2)

Source
chain_backtrack(n : Int64, f : Array(Int32), p : Array(Int64), v : Array(Int32), t : Array(Int32), min_cnt : Int32, min_sc : Int32, max_drop : Int32) : Tuple(Array(UInt64), Int32, Array(Int32), Int32)

mg_chain_backtrack: extract chains from the DP arrays. Returns (u, v) or (nil, nil) if no chains found. u[i] = score<<32 | count; v[] = anchor indices (reversed)

Source
check_opt(io : MmIdxOpt, mo : MmMapOpt) : Int32

Validate option combination; returns 0 on success (mirrors mm_check_opt).

Source
collect_matches(qlen : Int32, max_occ : Int32, max_max_occ : Int32, dist : Int32, mi : MmIdx, mv : Array(Mm128)) : Tuple(Array(MmSeed), Int64, Int32, Array(UInt64))

Full seed collection pipeline (mirrors mm_collect_matches). Returns: seeds — filtered MmSeed array n_a — total reference anchor count rep_len — repetitive region length in query mini_pos — (q_span<<32 | q_pos) for each non-filtered seed

Source
cputime

CPU time consumed by the current process (user + system), in seconds

Source
dbg_flag
Source
dbg_flag=(v : Int32)
Source
encode_seq(s : String | Bytes) : Array(UInt8)

Encode a query string (ASCII) into 4-bit bases using SEQ_NT4_TABLE.

Source
est_err(mi : MmIdx, qlen : Int32, regs : Array(MmReg1), a : Array(Mm128), n_mini_pos : Int32, mini_pos : Array(UInt64)) : Nil

estimate divergence from chaining

Source
filter_regs(opt : MmMapOpt, qlen : Int32, n_regs_ref : Pointer(Int32), regs : Array(MmReg1)) : Nil

Filter out low-quality hits.

Source
filter_strand_retained(regs : Array(MmReg1)) : Int32

Filter hits where strand_retained quality is poor.

Source
gen_regs(hash : UInt32, qlen : Int32, u : Array(UInt64), a : Array(Mm128), is_qstrand : Bool) : Array(MmReg1)

Convert chains (u[], a[]) to an Array(MmReg1), sorted by descending score. Mirrors mm_gen_regs().

Source
hit_sort(n_regs_ref : Pointer(Int32), regs : Array(MmReg1), alt_diff_frac : Float32) : Nil

Sort hits by score (descending), removing cnt==0 entries. Mirrors mm_hit_sort().

Source
idxopt_init(opt : MmIdxOpt) : Nil

Initialise MmIdxOpt with default values (mirrors mm_idxopt_init).

Source
kroundup32(x : Int32) : Int32

Utility: round x up to the next power of two (32-bit version of kroundup32 from ksort.h / mmpriv.h)

Source
kroundup64(x : Int64) : Int64
Source
ks_ksmall_uint32(a : Array(UInt32), kk : Int32) : UInt32

k-th smallest element (in-place sort, no .dup needed for callers)

Source
ksw_extd2(qlen : Int32, query : Array(UInt8) | Slice(UInt8), tlen : Int32, target : Array(UInt8) | Slice(UInt8), m : Int32, mat : Array(Int8), q : Int32, e : Int32, q2 : Int32, e2 : Int32, w : Int32, zdrop : Int32, end_bonus : Int32, flag : Int32) : KswExtz

ksw_extd2: scalar dual-gap-penalty banded extension alignment. Mirrors ksw_extd2_sse().

query, target: UInt8 arrays with encoded bases (0..m-1; m-1 = wildcard) mat: m×m scoring matrix (linearised row-major) q, e, q2, e2: primary and secondary gap open/extend penalties (positive) w: band width (<0 = no band) zdrop: Z-drop threshold (<0 = no zdrop) end_bonus: bonus when alignment reaches end of query/target flag: KSW_EZ_* flags

Source
ksw_exts2(qlen : Int32, query : Array(UInt8) | Slice(UInt8), tlen : Int32, target : Array(UInt8) | Slice(UInt8), m : Int32, mat : Array(Int8), q : Int32, e : Int32, q2 : Int32, noncan : Int32, zdrop : Int32, end_bonus : Int32, junc_bonus : Int32, junc_pen : Int32, flag : Int32, junc : Array(UInt8) | Nil = nil) : KswExtz

ksw_exts2: splice-aware extension — simplified scalar implementation. Mirrors ksw_exts2_sse().

Source
ksw_extz2(qlen : Int32, query : Array(UInt8) | Slice(UInt8), tlen : Int32, target : Array(UInt8) | Slice(UInt8), m : Int32, mat : Array(Int8), q : Int32, e : Int32, w : Int32, zdrop : Int32, end_bonus : Int32, flag : Int32) : KswExtz

ksw_extz2: single-gap extension — wraps ksw_extd2 with large secondary gap. Mirrors ksw_extz2_sse().

Source
ksw_gen_simple_mat(m : Int32, a : Int32, b : Int32, sc_ambi : Int32) : Array(Int8)

ksw_gen_simple_mat: build m×m substitution matrix

Source
ksw_gen_ts_mat(m : Int32, a : Int32, b : Int32, transition : Int32, sc_ambi : Int32) : Array(Int8)

Variant with transition penalty (A<->G and C<->T transitions penalized differently)

Source
ksw_gg2(qlen : Int32, query : Array(UInt8) | Slice(UInt8), tlen : Int32, target : Array(UInt8) | Slice(UInt8), m : Int32, mat : Array(Int8), q : Int32, e : Int32, w : Int32) : Tuple(Int32, Array(UInt32))

ksw_gg2: global alignment returning CIGAR. Simplified scalar implementation.

Source
lchain_dp(max_dist_x : Int32, max_dist_y : Int32, bw : Int32, max_skip : Int32, max_iter : Int32, min_cnt : Int32, min_sc : Int32, chn_pen_gap : Float32, chn_pen_skip : Float32, is_cdna : Bool, n_seg : Int32, a : Array(Mm128), u_out : Array(UInt64)) : Array(Mm128)

mg_lchain_dp: DP-based linear chaining (mirrors mg_lchain_dp in lchain.c).

Input: a[].x = rev<<63 | tid<<32 | tpos a[].y = flags<<40 | q_span<<32 | q_pos Output: n_u (via return value): number of chains u[i] = score<<32 | #anchors returns rearranged a[] (may be empty if no chains)

Source
lchain_rmq(max_dist : Int32, max_dist_inner : Int32, bw : Int32, max_chn_skip : Int32, cap_rmq_size : Int32, min_cnt : Int32, min_sc : Int32, chn_pen_gap : Float32, chn_pen_skip : Float32, a : Array(Mm128), u_out : Array(UInt64)) : Array(Mm128)
Source
map(mi : MmIdx, qlen : Int32, seq : String, opt : MmMapOpt, qname : String | Nil = nil) : Array(MmReg1)

Map a single query string against the index. Mirrors mm_map().

Source
map_frag(mi : MmIdx, seqs : Array(String), qlens : Array(Int32), opt : MmMapOpt, qname : String | Nil = nil) : Array(Array(MmReg1))

Map multiple query sequences (e.g. for fragment mode).

Source
map_frag_core(mi : MmIdx, n_segs : Int32, qlens : Array(Int32), seqs : Array(String), n_regs_arr : Array(Int32), regs_arr : Array(Array(MmReg1)), opt : MmMapOpt, qname : String | Nil = nil) : Nil

Map a single query fragment (internal core).

Source
mapopt_init(opt : MmMapOpt) : Nil

Initialise MmMapOpt with default values (mirrors mm_mapopt_init).

Source
mapopt_max_intron_len(opt : MmMapOpt, max_intron_len : Int32) : Nil

Set bw/bw_long/max_gap_ref based on intron length (mirrors mm_mapopt_max_intron_len).

Source
mapopt_update(opt : MmMapOpt, mi : MmIdx) : Nil

Update mid_occ in opt based on the index mi (mirrors mm_mapopt_update).

Source
mark_alt(mi : MmIdx, regs : Array(MmReg1)) : Nil

Mark ALT sequences in hits.

Source
mark_sam_pri(regs : Array(MmReg1)) : Int32

Set SAM primary flag; returns number of primary hits.

Source
max_spsc_bonus(mo : MmMapOpt) : Int32

Maximum supplementary-chain bonus (mirrors mm_max_spsc_bonus).

Source
mg_log2(x : Float32) : Float32

Fast log₂ approximation (mg_log2 from mmpriv.h) Only works for x >= 2.

Source
mm_sketch(seq : String | Bytes, len : Int32, w : Int32, k : Int32, rid : UInt32, is_hpc : Bool, p : Array(Mm128)) : Nil

Compute (w,k)-minimizers on a DNA sequence, appending to p.

Encoding: p[i].x = hash<<8 | kmer_span p[i].y = rid<<32 | last_pos<<1 | strand

Equivalent to mm_sketch() in sketch.c.

Source
mm_sketch(seq : Slice(UInt8), w : Int32, k : Int32, rid : UInt32, is_hpc : Bool, p : Array(Mm128)) : Nil

Overload accepting Slice(UInt8) directly (internal use)

Source
peakrss

Peak resident-set size in bytes (Linux only; 0 on other platforms)

Source
push_cigar(cigar : Array(UInt32), op : Int32, len : Int32) : Nil

push_cigar helper: append an operation, merging with previous if same op.

Source
radix_sort_128x(a : Array(Mm128), from : Int32, to : Int32) : Nil
Source
radix_sort_128x(a : Array(Mm128)) : Nil
Source
radix_sort_64(a : Array(UInt64), from : Int32, to : Int32) : Nil
Source
radix_sort_64(a : Array(UInt64)) : Nil
Source
realtime

Seconds elapsed since program start on the monotonic clock (equivalent to realtime() in C — used only for logging, not wall time).

Source
realtime0

Seconds elapsed since program start (used as realtime0 baseline: always 0.0).

Source
rev_comp(seq : Array(UInt8)) : Array(UInt8)

Build reverse complement of a 4-bit encoded sequence. Delegates to ksw2.seq_rev_comp (shared implementation).

Source
run_cli(argv : Array(String)) : Int32

Command-line interface — mirrors the minimap2 main() options

Source
sdust(seq : Bytes, l_seq : Int32 = -1, big_t : Int32 = 20, big_w : Int32 = 64) : Array(UInt64)

sdust: allocate a buffer, run sdust_core, return results. Equivalent to sdust() in sdust.c.

Source
sdust_core(seq : Bytes, l_seq : Int32, big_t : Int32, big_w : Int32, buf : SdustBuf) : Array(UInt64)

sdust_core: run DUST on one sequence, using a reusable buffer. Returns a Slice view into buf.res.

Source
seed_collect_all(mi : MmIdx, mv : Array(Mm128)) : Array(MmSeed)

Collect all seed matches between query minimizers and the index. Mirrors mm_seed_collect_all(). Returns an Array(MmSeed) with all matches (including high-freq ones).

Source
seed_mz_flt(mv : Array(Mm128), q_occ_max : Int32, q_occ_frac : Float32) : Nil

Filter overly-frequent minimizers from a query minimizer set. Mirrors mm_seed_mz_flt().

Source
seed_select(seeds : Array(MmSeed), qlen : Int32, max_occ : Int32, max_max_occ : Int32, dist : Int32) : Nil

Select up to max_high_occ high-frequency minimizers per streak. Mirrors mm_seed_select().

Source
seg_gen(hash : UInt32, n_segs : Int32, qlens : Array(Int32), regs0 : Array(MmReg1), a : Array(Mm128)) : Array(MmSeg)

Generate per-segment chains from the full (concatenated) chain set. Mirrors mm_seg_gen().

Source
select_sub(pri_ratio : Float32, min_diff : Int32, best_n : Int32, check_strand : Bool, min_strand_sc : Int32, n_regs_ref : Pointer(Int32), regs : Array(MmReg1)) : Nil

Select secondary hits up to best_n.

Source
seq_rev(len : Int32, seq : Array(UInt8)) : Nil
Source
seq_rev_comp(len : Int32, seq : Array(UInt8)) : Array(UInt8)

Reverse complement a 4-bit encoded sequence.

Source
set_mapq2(regs : Array(MmReg1), n_regs : Int32, min_chain_sc : Int32, match_sc : Int32, rep_len : Int32, is_sr : Bool, is_splice : Bool) : Nil

Set MAPQ scores for hits. Simplified version of mm_set_mapq2 from hit.c.

Source
set_opt(preset : String | Nil, io : MmIdxOpt, mo : MmMapOpt) : Int32

Apply preset on top of already-initialised io and mo. Mirrors mm_set_opt(). When preset is nil the options are first reset to defaults (equivalent to calling mm_set_opt(NULL,...) in C). Returns 0 on success, -1 if the preset is unknown.

Source
set_parent(mask_level : Float32, mask_len : Int32, regs : Array(MmReg1), sub_diff : Int32, hard_mask_level : Bool, alt_diff_frac : Float32) : Nil

Set parent/secondary relationships. Mirrors mm_set_parent().

Source
split_reg(r : MmReg1, r2 : MmReg1, n : Int32, qlen : Int32, a : Array(Mm128), is_qstrand : Bool) : Nil

Split region r at anchor position n, creating r2 as the second half.

Source
squeeze_a(regs : Array(MmReg1), a : Array(Mm128)) : Int32

Compact the anchor array to only include anchors referenced by regs.

Source
sync_regs(regs : Array(MmReg1)) : Nil

Keep id/parent in sync after hits are removed.

Source
u64_to_i32(v : UInt64) : Int32

Truncate UInt64 to lower 32 bits and reinterpret as Int32. Equivalent to the C cast (int32_t)v — truncates without raising.

Source
verbose
Source
verbose=(v : Int32)
Source
write_paf(io : IO, mi : MmIdx, t : BSeq1, r : MmReg1, opt_flag : Int64, rep_len : Int32 = 0) : Nil

Write one PAF record. Mirrors mm_write_paf4().

Source
write_sam(io : IO, mi : MmIdx, t : BSeq1, r : MmReg1, n_regs : Int32, all_regs : Array(MmReg1), opt_flag : Int64) : Nil

Write one SAM record.

Source
write_sam_hdr(io : IO, mi : MmIdx | Nil, version : String = LIB_VERSION) : Nil

Write SAM header.

Source

Nested types