def __init__(self, array): super(TripletMaker, self).__init__() if array is None or len(array) < 0: raise Exception("WTF man an empty array is not valid") self.tree = {} for item in range(-100, 101): self.tree[item] = 0 for item in array: try: if type(item) is str: item = int(item) self.tree[item] += 1 except ValueError as e: warning("Not a valid item {0}".format(item)) continue # Don't do this shit if we aren't in debug mode if messages.debug_mode: self.size = 0 for key in range(-100, 101): value = self.tree[key] self.size += value verbose("Key: {0}; Value: {1}".format(key, value)) verbose("size {0}".format(self.size)) self.size = len(array) - 1 self.time = None self.done = False self.triplets = [] self.domain = list(range(-100, 101))
def hashBase64(string, tsize=4): """Create a hash of a given string :string: TODO :returns: TODO """ global __values if len(__values) == 0: base64Values() start = time() bstring = "" for i in str(string): bits = bin(ord(i))[2:] bsize = len(bits) if bsize < 8: bits = "0" * (8 - bsize) + bits bstring = bstring + bits encode = "" while len(bstring) > 0: encode += __values[int(bstring[0:6], 2)] bstring = bstring[6:] hashvalue = sum(ord(x) for x in encode) end = time() verbose("Hash: {0}".format(hashvalue)) verbose("Hashing time: {0}".format(end - start)) return hashvalue % 4
def __init__(self, size=4, json_db=None, hashfunction=None): super(HashDataBase, self).__init__() self.size = size self.container = [] self.collisions = [] self.numbers = {} self.last_names = {} for item in range(0, size): # self.container.append(BTree()) self.container.append({}) self.collisions.append(0) self.hashfunction = hashBase64 if hashfunction is None else hashfunction if json_db is not None and path.isfile(json_db): with open(json_db, "r") as database: data = json.load(database) for rid, register in data.items(): verbose("Register: {0}".format(register)) element = self.Register( name=register["name"], last_name=register["last_name"], address=register["address"], cellphone=register["cellphone"], email=register["email"], social_network=register["social_network"]) self.insert(register=element) elif json_db is not None and not path.isfile(json_db): error("{0} must be a valid json file to load the registers")
def hashAscii(string, tsize=4): start = time() if type(string) != str: raise Exception( "Only strings are allow to be used in this hash function") hashvalue = sum(ord(x) for x in string) end = time() verbose("Hash: {0}".format(hashvalue)) verbose("Hashing time: {0}".format(end - start)) return hashvalue % tsize
def insert(self, register=None): """TODO: Docstring for insert. :register: TODO :returns: TODO """ if register is None: valid = False while not valid: name = input("Enter name: ") last_name = input("Enter last name: ") address = input("Enter address: ") cellphone = input("Enter cellphone: ") if cellphone in self.numbers: error("This cellphone is already in use") continue valid = True email = input("Enter email address: ") social_network = input("Enter social network: ") register = self.Register(name, last_name, address, cellphone, email, social_network) rc = False start = time() hashvalue = self.hashfunction(register.name) isEmpty = False # TODO: This must be changed for the tree if len(self.container[hashvalue]) == 0: isEmpty = True # TODO: This must be changed for the tree self.container[hashvalue][register.name] = register self.numbers[register.cellphone] = hashvalue if register.last_name not in self.last_names: self.last_names[register.last_name] = [hashvalue] else: self.last_names[register.last_name].append(hashvalue) if not isEmpty: self.collisions[hashvalue] += 1 verbose("Collisions in container {0}: {1}".format( hashvalue, self.collisions[hashvalue])) rc = True status("Register inserted") end = time() verbose("Insertion time {0}".format(end - start)) return rc
def _save_triplet(self, first, second, third): """TODO: Docstring for _save_triplet. :triplet: TODO :returns: TODO """ triplet = self._remove_numbers(first, second, third) verbose("Found triplet {0}".format(triplet)) self.done = False self.triplets.append(triplet)
def main(): """Main CLI function :returns: TODO """ global debug_mode global start_time cli_args = __parse_arguments() if cli_args.version: status("Current version {0}".format(__version__)) return 0 messages.debug_mode = cli_args.verbose messages.quiet = cli_args.quiet messages.logger = cli_args.logger if cli_args.hash == 1: hashfunction = hashAscii else: hashfunction = hashBase64 verbose("Hash function {0}".format(repr(hashfunction.__name__))) action = "" table = HashDataBase(hashfunction=hashfunction, json_db=cli_args.json) # While True is always a bad idea while action.upper() != "E": action = input(MAIN_MENU) if action == "1": table.insert() elif action == "2": result = table.search() if result is not None and len(result) == 0: status("Register: {0}".format(result)) elif result is not None and len(result) > 0: for item in result: status("Register: {0}".format(item)) else: error("Element was not found") elif action == "3": table.update() elif action == "4": table.delete() elif action == "5": for item in table.container: for name, register in item.items(): status("Register: {0}".format(register)) elif action.upper() != "E": status("Sin acción en {action}".format(action=action))
def check_files(size=1000, filename="", override=False): """TODO: Docstring for check_files. :size: TODO :returns: TODO """ if filename == "": filename = get_filename(size) + ".txt" if not os.path.isfile(filename) or override is True: if os.path.isfile(filename) and override is True: verbose("Removing {0}".format(filename)) gen_files(size, filename)
def delete(self, register=None, name=None, last_name=None, cellphone=None): """TODO: Docstring for insert. :register: TODO :returns: TODO """ selected_type = -1 if register is None and name is None and last_name is None and cellphone is None: parameter, selected_type = self._select_search_type() elif register is not None: parameter = register.name selected_type = 0 elif name is not None: parameter = name selected_type = 0 elif last_name is not None: parameter = last_name selected_type = 1 elif cellphone is not None: parameter = cellphone selected_type = 2 rc = False start = time() if selected_type == 0: register = self.search(name=parameter) elif selected_type == 1: register = self.search(last_name=parameter) elif selected_type == 2: register = self.search(cellphone=parameter) if register is not None: # Register is not None so if its len is 0 then is just one register hashvalue = self.hashfunction(register.name) if len(register) == 0: self._delete_register(register, hashvalue) else: for item in register: self._delete_register(item, hashvalue) else: error("{0} could not be deleted".format(parameter)) end = time() verbose("Deletion time {0}".format(end - start)) return rc
def update(self, register=None, name=None, last_name=None, cellphone=None): """TODO: Docstring for insert. :register: TODO :returns: TODO """ selected_type = -1 if register is None and name is None and last_name is None and cellphone is None: parameter, selected_type = self._select_search_type() elif register is not None: parameter = register.name selected_type = 0 elif name is not None: parameter = name selected_type = 0 elif last_name is not None: parameter = last_name selected_type = 1 elif cellphone is not None: parameter = cellphone selected_type = 2 rc = False start = time() hashvalue = self.hashfunction(parameter, selected_type) # register = self.container[hashvalue].search(parameter, selected_type) if parameter in self.container[hashvalue]: register = self.container[hashvalue][parameter] register = self._update_field(register) self.container[hashvalue][parameter] = register status("Register updated") else: # if register is None: error("{0} doesn't exists".format(parameter, selected_type)) # else: # pass end = time() verbose("Update time {0}".format(end - start)) return rc
def gen_files(size=1000, filename="", seed=None): """TODO: Docstring for gen_files. :size: TODO :returns: TODO """ # start_time = time.time() if filename == "": filename = get_filename(size) + ".txt" if seed is not None: verbose("Using seed {0}".format(seed)) with open(filename, "w") as data: verbose("Creating {0}".format(filename)) for x in range(size): number = str(randint(-100, 100)) data.write(number + ',')
def _delete_register(self, register, hashvalue): """TODO: Docstring for _delete_register. :register: TODO :returns: TODO """ # TODO: This must be changed for the tree self.container[hashvalue].pop(register.name, None) if self.collisions[hashvalue] > 0: self.collisions[hashvalue] -= 1 self.numbers.pop(register.cellphone, None) for container in self.last_names[register.last_name]: if container == hashvalue: self.last_names[register.last_name].remove(hashvalue) break verbose("Collisions in container {0}: {1}".format( hashvalue, self.collisions[hashvalue])) status("Register deleted: {0}".format(register))
def _find_triplet(self, number, domain): """Select the best next number of the triplet :returns: int, the number which is also the key of the self.tree dict """ usable = False # By default the domain is negative, we can reverse it to use the positive domain limits = self.domain if domain < 0 else list(reversed(self.domain)) verbose("Domain: {0}".format(limits)) for pair in limits: if self.tree[pair] > 0: if self._reduce_to_zero(number + pair) is True: repeated = repeated_numbers(number, pair, (number + pair) * -1) if len(repeated) != 0 and self.tree[repeated[0]] < len( repeated): continue self._save_triplet(number, pair, (number + pair) * -1) usable = True break return usable
def _remove_numbers(self, first, second, third): """Remove the triplet from the dictionary TODO: Should we use a vector instead ? :self.tree: dict, Dictionary with all the numbers :first: int, the first number of the triplet :second: int, the first number of the triplet :third: int, the first number of the triplet :returns: dict, the self.tree with decreased index if the found triplet """ repeated = repeated_numbers(first, second, third) minimun = 0 if len(repeated) == 0: verbose("All numbers are different") # All numbers are different from each other, so normal triplet minimun = min([ self.tree[first], self.tree[second], self.tree[third], ]) self.tree[first] -= minimun self.tree[second] -= minimun self.tree[third] -= minimun elif len(repeated) == 3: verbose("Using {0} three times with {1} elements".format( repeated[0], self.tree[repeated[0]])) # Same number in each case, just "0" can be here minimun = (self.tree[first] // 3) * 3 self.tree[first] -= minimun else: verbose("Using {0} two times with {1} elements".format( repeated[0], self.tree[repeated[0]])) # We have two repeated numbers so need to perform a division minimun = min([(self.tree[repeated[0]] // 2), self.tree[first]]) diff = 0 if not (first in repeated): diff = first elif not (second in repeated): diff = second elif not (third in repeated): diff = third self.tree[repeated[0]] -= (minimun * 2) self.tree[diff] -= minimun triplet = Triplet(first, second, third, minimun) return triplet
def search(self, register=None, name=None, last_name=None, cellphone=None): """TODO: Docstring for insert. :register: TODO :returns: TODO """ selected_type = -1 if register is None and name is None and last_name is None and cellphone is None: parameter, selected_type = self._select_search_type() elif register is not None and type(register) is self.Register: parameter = register.name selected_type = 0 elif name is not None: parameter = name selected_type = 0 elif last_name is not None: parameter = last_name selected_type = 1 elif cellphone is not None: parameter = cellphone selected_type = 2 else: # We fall here if register is not None and is not a Register type raise Exception("Unknown type {0}".format(repr(register))) start = time() register = None verbose("Searching for: {0}".format(parameter)) if selected_type == 0: hashvalue = self.hashfunction(parameter) # TODO: This must be changed for the tree verbose("Name {0}".format(parameter)) if parameter in self.container[hashvalue]: register = self.container[hashvalue][parameter] else: error("The register {0} doesn't exists".format(parameter)) elif selected_type == 1: if parameter in self.last_names: verbose("Last name {0}".format(parameter)) containers = self.last_names[parameter] verbose("List of containers {0}".format(containers)) # Since last names are not unic, the dictionary has a list with all the containers with the last name register = [] for container in containers: # TODO: This must be changed for the tree for key, value in self.container[container].items(): if value.last_name == parameter: register.append( self.container[container][parameter]) # status("Please select a register") else: error("The register {0} doesn't exists".format(parameter)) elif selected_type == 2: if parameter in self.numbers: verbose("Number to find {0}".format(parameter)) # TODO: This must be changed for the tree container = self.numbers[parameter] for key, value in self.container[container].items(): if value.cellphone == parameter: register = self.container[container][value.name] break else: error("The register {0} doesn't exists".format(parameter)) else: raise Exception("Not a valid option {0}".format(selected_type)) # register = self.container[hashvalue].search(parameter, selected_type) # if register is not None: # return register # error("{0} doesn't exists".format(parameter, selected_type)) end = time() verbose("Search time {0}".format(end - start)) return register
def start(self): """Look for the next triplet of numbers :returns: Tuple, Returns a tuple with a vector of the 3 numbers and the updated dictionary, And empty vector is return if no triplet was found """ start_time = time.time() while not self.done: self.done = True for item in range(-100, 101): # Check whether or not we have elements in the next number if self.tree[item] > 0: verbose("Looking triplet for {0} with {1} elements".format( item, self.tree[item])) usable = self._find_triplet(item, item * -1) if not usable: verbose("No triplet found for {0}".format(item)) else: verbose("Skipping {0}: {1}".format(item, self.tree[item])) end_time = time.time() self.time = end_time - start_time status("End time of {0}. {1} different triplets found".format( self.time, len(self.triplets))) # Save time by not doing this shit if is not debug mode if messages.debug_mode: total = 0 verbose("Unpaird numbers") for key in range(-100, 101): value = self.tree[key] if value > 0: total += value verbose("Key: {0}; Value: {1}".format(key, value)) verbose("Total {0}".format(total))