From: martinahansen Date: Thu, 22 Mar 2012 08:29:21 +0000 (+0000) Subject: added bitmap.rb X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=ca870e4e9b4c27ac8c4eef1706d71702f6a94838;p=biopieces.git added bitmap.rb git-svn-id: http://biopieces.googlecode.com/svn/trunk@1773 74ccb610-7750-0410-82ae-013aeee3265d --- diff --git a/code_ruby/lib/maasha/bitmap.rb b/code_ruby/lib/maasha/bitmap.rb new file mode 100644 index 0000000..d1a1a12 --- /dev/null +++ b/code_ruby/lib/maasha/bitmap.rb @@ -0,0 +1,269 @@ +# Copyright (C) 2012 Martin A. Hansen. + +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# http://www.gnu.org/copyleft/gpl.html + +# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + +# This software is part of the Biopieces framework (www.biopieces.org). + +# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + +require 'inline' + +# Error class for all exceptions to do with Base36. +class BitMapError < StandardError; end + +BitsInChar = 8 + +class BitMap + attr_accessor :byte_array + + def initialize(rows, cols, byte_array = nil) + @rows = rows + @cols = cols + @size = rows * cols + + if byte_array.nil? + @byte_array_size = (rows * cols.to_f / BitsInChar).ceil + @byte_array = "\0" * @byte_array_size + else + @byte_array_size = (rows * cols.to_f / BitsInChar).ceil + @byte_array = byte_array + end + end + + def slice(rows, cols) + rows = rows.first.to_a if rows.first.respond_to? :to_a + cols = cols.first.to_a if cols.first.respond_to? :to_a + + new_byte_array_size = (rows.size * cols.size.to_f / BitsInChar).ceil + new_byte_array = "\0" * new_byte_array_size + + slice_c(new_byte_array, rows, cols) + + BitMap.new(rows.size, cols.size, new_byte_array) + end + + def flip! + @rows, @cols = @cols, @rows + end + + # Method to convert a bit array to a string. + def to_s + string = "" + + (0 ... @size).each do |pos| + if self.bit_set? pos + string << "1" + else + string << "0" + end + end + + string.gsub(/.{#{@cols}}/, "\\0#{$/}") + end + + inline do |builder| + builder.add_static "rows", 'rb_intern("@rows")', "ID" + builder.add_static "cols", 'rb_intern("@cols")', "ID" + builder.add_static "size", 'rb_intern("@size")', "ID" + builder.add_static "byte_array_size", 'rb_intern("@byte_array_size")', "ID" + builder.add_static "byte_array", 'rb_intern("@byte_array")', "ID" + + builder.prefix %s{ + unsigned char bit_count[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 + }; + } + + builder.prefix %{ + #define COUNT_BITS(c) (bit_count[c]) + } + + builder.prefix %{ + #define BYTE_POS(pos) (pos / CHAR_BIT) + } + + builder.prefix %{ + #define BIT_POS(pos) (1 << (CHAR_BIT - 1 - (pos % CHAR_BIT))) + } + + builder.c %{ + void fill_c() + { + VALUE _size = rb_ivar_get(self, byte_array_size); + VALUE _byte_array = rb_ivar_get(self, byte_array); + int size = NUM2INT(_size); + unsigned char* byte_array = StringValuePtr(_byte_array); + int i = 0; + + for (i = 0; i < size; i++) byte_array[i] = ~0; + } + } + + builder.c %{ + void empty_c() + { + VALUE _size = rb_ivar_get(self, byte_array_size); + VALUE _byte_array = rb_ivar_get(self, byte_array); + int size = NUM2INT(_size); + unsigned char* byte_array = StringValuePtr(_byte_array); + int i = 0; + + for (i = 0; i < size; i++) byte_array[i] = 0; + } + } + + builder.c %{ + void bit_set_c(int row, int col) + { + VALUE _rows = rb_ivar_get(self, rows); + VALUE _cols = rb_ivar_get(self, cols); + VALUE _byte_array = rb_ivar_get(self, byte_array); + int rows = NUM2INT(_rows); + int cols = NUM2INT(_cols); + unsigned char* byte_array = StringValuePtr(_byte_array); + int pos = 0; + + if (row >= rows) + rb_raise(rb_eval_string("BitMapError"), "row out of range: %d >= %d\\n", row, rows); + + if (col >= cols) + rb_raise(rb_eval_string("BitMapError"), "col out of range: %d >= %d\\n", col, cols); + + pos = row * cols + col; + + byte_array[BYTE_POS(pos)] |= BIT_POS(pos); + } + } + + builder.c %{ + VALUE bit_test_c(int pos) + { + VALUE _byte_array = rb_ivar_get(self, byte_array); + unsigned char* byte_array = StringValuePtr(_byte_array); + + return ((byte_array[BYTE_POS(pos)] & BIT_POS(pos)) != 0); + } + } + + builder.c %{ + void slice_c(char* new_array, VALUE _new_rows, VALUE _new_cols) + { + VALUE _old_array = rb_ivar_get(self, byte_array); + VALUE _old_rows = rb_ivar_get(self, rows); + VALUE _old_cols = rb_ivar_get(self, cols); + unsigned char* old_array = StringValuePtr(_old_array); + int old_rows = NUM2INT(_old_rows); + int old_cols = NUM2INT(_old_cols); + + VALUE *rows_array = RARRAY_PTR(_new_rows); + VALUE *cols_array = RARRAY_PTR(_new_cols); + int row_count = (int) RARRAY_LEN(_new_rows); + int col_count = (int) RARRAY_LEN(_new_cols); + int r = 0; + int c = 0; + int old_pos = 0; + int new_pos = 0; + + for (r = 0; r < row_count; r++) + { + for (c = 0; c < col_count; c++) + { + old_pos = NUM2INT(rows_array[r]) * old_cols + NUM2INT(cols_array[c]); + new_pos = r * col_count + c; + + new_array[BYTE_POS(new_pos)] |= BIT_POS(new_pos) & (old_array[BYTE_POS(old_pos)] & BIT_POS(old_pos)); + } + } + } + } + + builder.c %{ + VALUE sum_c() + { + VALUE _size = rb_ivar_get(self, byte_array_size); + VALUE _byte_array = rb_ivar_get(self, byte_array); + int size = NUM2INT(_size); + unsigned char* byte_array = StringValuePtr(_byte_array); + int i = 0; + int sum = 0; + + for (i = 0; i < size; i++) + sum += COUNT_BITS(byte_array[i]); + + return INT2NUM(sum); + } + } + + builder.c %{ + VALUE sum_rows_c() + { + VALUE _rows = rb_ivar_get(self, rows); + VALUE _cols = rb_ivar_get(self, cols); + VALUE _byte_array = rb_ivar_get(self, byte_array); + int rows = NUM2INT(_rows); + int cols = NUM2INT(_cols); + unsigned char* byte_array = StringValuePtr(_byte_array); + int row = 0; + int col = 0; + int sums[rows]; + VALUE rb_sums = rb_ary_new(); + + int pos = 0; + + for (row = 0; row < rows; row++) sums[row] = 0; + + for (row = 0; row < rows; row++) + { + for (col = 0; col < cols; col++) + { + pos = row * cols + col; + sums[row] += ((byte_array[BYTE_POS(pos)] & BIT_POS(pos)) != 0); + } + } + + for (row = 0; row < rows; row++) rb_ary_push(rb_sums, INT2FIX(sums[row])); + + return rb_sums; + } + } + end + + alias :sum :sum_c + alias :sum_rows :sum_rows_c + alias :bit_set :bit_set_c + alias :bit_set? :bit_test_c + alias :fill! :fill_c + alias :empty! :empty_c + alias :zero! :empty_c +end