From: Robert Klemme Date: 2011-04-19T21:21:50+09:00 Subject: Re: Need for speed -> a C extension? On Tue, Apr 19, 2011 at 12:30 PM, Martin Hansen wrote: >>>  def match?(char1, char2) >>>    (EQUAL[char1.upcase.ord] & EQUAL[char2.upcase.ord]) != 0 >>>  end >> >> That would be really easy to write tests and a benchmark against and >> then rewrite in C using RubyInline... without tests and a benchmark tho, >> you won't know that you've done it correctly and provides a measurable >> benefit. > > They bottlenecks are the iteration over the sequence (while loop at line > 68) and the vector_update (line 120). I am a bit surprised that match? > is that slow - I expect it to be almost instantaneous in C. I would like > to test that with a benchmark and Inline C. Frankly, I find your code has a design issue: it seems you mix data and iteration in a single class. This is visible from how #match works def match(pattern, pos = 0, max_edit_distance = 0) @pattern = pattern @pos = pos @max_edit_distance = max_edit_distance @vector = vector_init ... IMHO it would be better to separate representation of the sequence and the matching process. The matcher then would only carry a reference to the sequence and all the data it needs to do matching. Also #vector_update creates a lot of objects and does so for each position in the sequence. That's likely where you can improve things. I am not sure what the matching algorithm is exactly. Can you summarize it? Ah, and one thing: if you add lowercase entries EQUAL['a'.ord] = BIT_A EQUAL['t'.ord] = BIT_T EQUAL['u'.ord] = BIT_T EQUAL['c'.ord] = BIT_C EQUAL['g'.ord] = BIT_G EQUAL['m'.ord] = (BIT_A|BIT_C) EQUAL['r'.ord] = (BIT_A|BIT_G) EQUAL['w'.ord] = (BIT_A|BIT_T) EQUAL['s'.ord] = (BIT_C|BIT_G) EQUAL['y'.ord] = (BIT_C|BIT_T) EQUAL['k'.ord] = (BIT_G|BIT_T) EQUAL['b'.ord] = (BIT_C|BIT_G|BIT_T) EQUAL['d'.ord] = (BIT_A|BIT_G|BIT_T) EQUAL['h'.ord] = (BIT_A|BIT_C|BIT_T) EQUAL['v'.ord] = (BIT_A|BIT_C|BIT_G) EQUAL['n'.ord] = (BIT_A|BIT_C|BIT_G|BIT_T) you can make matching simpler def match?(char1, char2) (EQUAL[char1.ord] & EQUAL[char2.ord]) != 0 end You might as well consider changing the Array into a Hash. Then you can even get rid of the #ord call. A different approach would just use regular expressions, e.g. MAP = { 'a' => 1, 't' => 2, 'w' => '[12]', ... } seq = Array.new(20) { %w{1 2 4 8}.sample } pat = "acgw" rx = Regexp.new(pat.chars.map {|c| MAP[c.downcase]}.join) seq.scan pat do |m| p m end Cheers robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/