def is_palindrome_perm_bitvector(phrase: str) -> bool: ''' Uses a bitvector to trace the odd or eveness of the frequency count for each char ''' phrase = phrase.replace(' ', '').lower() print(phrase) # E.g. using intVal (integer value) of 7 would give 00...111 bv = BitVector(intVal=0, size=26) for char in phrase: # Calculate the place in alphabet for the char, # and flip/xor 1 the bit at that place ordinal = ord(char) - 96 - 1 bv[ordinal] = bv[ordinal] ^ 1 ''' Some binary number Fu... if there is only one bit set to 1, then the value of that vector when ANDed (&) with that vector minus 1 will be 0. E.g. 01000 - 00001 = 00111; 01000 & 00111 = 00000''' # max(..) is needed as the entire vector may be all zeros bv_minus_one = BitVector(intVal=max(int(bv) - 1, 0), size=26) ''' Or you could just use the built-in count_bits() method, but where's the fun that. Either random selection should always pass the tests here ''' ''' For readability, define two booleans for random selection ''' one_or_zero = bv.count_bits() in (0, 1) bv_and_minus_one = int(bv & bv_minus_one) == 0 return random.choice([one_or_zero, bv_and_minus_one])
def generateNLFSR(self, maxAnds, density): self.tau = int(density * self.size) tapped = BitVector(intVal=0, size=self.size) self.shiftTerms( [term for term in self.fn[self.size - 1] if term[0] > self.tau], self.size - 1, self.tau) while tapped.count_bits() < self.tau: newTaps = self.addNonLinearTerm(maxAnds) for tap in newTaps: tapped[tap] = 1 return
def btSelect(): SIZE = random.randrange(1000,100000) # randomly generate bit-vector with SIZE bv = BitVector(intVal=64) bv = bv.gen_random_bits(SIZE) TARGET_RANK = random.randrange(0,bv.count_bits()) # class of SelectSupport: make Rs, Rb, Rp tables select = SelectSupport(bv, SIZE) ''' # print bitvector print(bv) ''' start = time.time() SELECT = select.select_rankOf(bv, TARGET_RANK) end = time.time() timeCost = end - start bitSize = sys.getsizeof(SELECT) return SIZE, SELECT, timeCost
class A(): def __init__(self, s=0, e=0, initial="all"): self.e = e self.s = s if initial.lower() == "all": self.vec = BitVector(size=self.s - 1) self.set_one() elif initial.lower() == "none": self.vec = BitVector(size=self.s - 1) self.set_zero() elif initial.lower() == "rand": self.vec = BitVector(size=self.s - 1) # for i in range(0, self.s - 1): # self.vec[i] = random.randint(0, 1) self.set_random() else: raise ValueError( f'{initial}.lower() can be one of ["all", "none", "rand"]') self.a = [x**self.e for x in range(1, self.s)] self.maxval = sum(self.a) self.val = self.sum() def set_zero(self): self.vec.reset(0) self.val = 0 self.bits_set = 0 def set_one(self): self.vec.reset(1) self.val = self.sum() self.bits_set = self.s - 1 def set_random(self): for i in range(0, self.s - 1): self.vec[i] = random.randint(0, 1) self.val = self.sum() self.bits_set = self.vec.count_bits() def sum(self): sum_a = 0 for ix, i in enumerate(self.vec, 1): sum_a += (ix * i)**self.e return sum_a def diff(self): return self.s**self.e - self.val def __str__(self): s = f"{self.s}^{self.e}=>" + "{" val_list = list() for ix, val in enumerate(self.vec, 1): if val: val_list.append(str(ix)) s += ",".join(val_list) s += "}" return s def __repr__(self): return self.__str__() def __len__(self): return self.vec.__len__() def __iter__(self): return self.vec.__iter__() def flip_bit(self, pos): if pos < 0: raise OverflowError( f"trying to change bit {pos} < 0 ({(pos + 1) ** self.e} < {0})" ) elif pos >= self.s - 1: raise OverflowError( f"trying to change bit {pos} >= {self.s-1} ({(pos + 1) ** self.e} > {self.maxval})" ) if self.vec[pos]: self.val -= self.a[pos] self.vec[pos] = 0 self.bits_set -= 1 return -self.a[pos] else: self.val += self.a[pos] self.vec[pos] = 1 self.bits_set += 1 return self.a[pos] # self.val += -(self.a[pos]) if self.vec[pos] else (pos + 1)**self.e # self.vec[pos] = 0 if self.vec[pos] else 1 # return -(self.a[pos]) if self.vec[pos] else (pos + 1)**self.e def flip_all(self): for pos in range(self.s - 1): self.flip_bit(pos) def add_one(self): for i in range(self.s): change = self.flip_bit(i) if self.vec[i]: break return change def sub_one(self): for i in range(self.s): change = self.flip_bit(i) if not self.vec[i]: break return change def iter_values(self): while True: yield self.val self.add_one() def riter_values(self): while True: yield self.val self.sub_one() def get_change(self, pos): change_sign = -1 if self.vec[pos] else 1 change_value = self.a[pos] return change_sign * change_value def is_set(self, pos): if pos < 0: raise OverflowError( f"trying to read bit {pos} < 0 ({(pos + 1) ** self.e} < {0})") elif pos >= self.s - 1: raise OverflowError( f"trying to read bit {pos} >= {self.s-1} ({(pos + 1) ** self.e} > {self.maxval})" ) return False if self.vec[pos] else True def get_pos_value(self, pos): return pos**self.e def get_best_bit(self, diff): sign = utils.intsign(diff) # pos_set represents if a bit is set or unset # 0 is we want to find a bit that is 0 # 1 is we want to find a bit that is 1 # finding a bit that is 0 corresponds to increasing the signed difference # finding a bit that is 1 corresponds to decreasing the signed difference pos_set = 0 if sign == 1 else 1 diff = sign * diff a_diffs = map( lambda x: (abs(x[1] - diff), x[0]), filter(lambda x: self.vec[x[0]] == pos_set, enumerate(self.a))) min_diff = min(a_diffs) pos = min_diff[1] return pos # only used with old _get_best_bit def _closest_pos_available(self, closest_pos, pos_set): if self.vec.count_bits() > self.s // 2 and pos_set: # if there are more set bits than unset bits, and we want to change a bit from 1 to 0 # then we want to travsere to lower values # because we want to remain on this side of the diff change_direction = -1 elif self.vec.count_bits() > self.s // 2 and pos_set: # if there are more set unset bits than set bits, and we want to change a bit from 0 to 1 # then we want to travsere to lower values # because we want to remain on this side of the diff change_direction = -1 else: # otherwise we want to traverse to higher bits # because we want to change the sign of diff change_direction = 1 if closest_pos >= self.s - 1: pos = self.s - 2 elif closest_pos < 0: pos = 0 else: pos = closest_pos # print("diff", diff) # print("sign", sign) # print("pos_set", pos_set) # print("root", root) # print("closest_pos", closest_pos) # print("change_direction", change_direction) # print("pos", pos) # print("self.vec[pos]", self.vec[pos]) while self.vec[pos] == pos_set: # print(f"changing pos from {pos} to {pos + change_direction}") pos += change_direction if pos >= self.s - 1: # print(f"changing pos from {pos} to {0}") pos = 0 if pos < 0: # print(f"changing pos from {pos} to {self.s - 2}") pos = self.s - 2 return pos # obsolete, but is the new version really better? def _get_best_bit(self, diff): sign = utils.intsign(diff) # pos_set represents if a bit should be set or unset # 0 is we want to change a bit to 0 # 1 is we want to change a bit to 1 # changing a bit to 0 corresponds to decreasing the signed difference # changing a bit to 1 corresponds to increasing the signed difference pos_set = 1 if sign == 1 else 0 # -1 because the value of bit x is (x+1)**e root = abs(diff)**(1 / self.e) - 1 closest_pos = int(root + sign * 0.5) return self._closest_pos_available(closest_pos, pos_set) def get_most_impactful_bit(self): diff = self.diff() return self.get_best_bit(diff)