from datetime import datetime
[docs]class Monitor(object):
def __init__(self):
"""
Initialize the monitor to identify the task progress.
Example
>>> from dsw import Monitor
>>> monitor = Monitor()
>>> monitor(current_state=1, total_state=10)
\r|███ | 10% ( 1/10) wait 0000:00:00.
>>> monitor(current_state=5, total_state=10)
\r|███████████ | 50% ( 5/10) wait 0000:00:00.
>>> monitor(current_state=10, total_state=10)
\r|████████████████████|100% (10/10) used 0000:00:00.
"""
self.last_time = None
def __call__(self, current_state, total_state, extra=None):
"""
Output the current state of process.
:param current_state: current state of process.
:type current_state: int
:param total_state: total state of process.
:type total_state: int
:param extra: extra vision information if required.
:type extra: dict
"""
if self.last_time is None:
self.last_time = datetime.now()
if current_state == 0:
return
position = int(current_state / total_state * 100)
string = "|"
for index in range(0, 100, 5):
if position >= index:
string += "█"
else:
string += " "
string += "|"
pass_time = (datetime.now() - self.last_time).total_seconds()
wait_time = int(pass_time * (total_state - current_state) / current_state)
string += " " * (3 - len(str(position))) + str(position) + "% ("
string += " " * (len(str(total_state)) - len(str(current_state))) + str(current_state) + "/" + str(total_state)
if current_state < total_state:
minute, second = divmod(wait_time, 60)
hour, minute = divmod(minute, 60)
string += ") wait " + "%04d:%02d:%02d" % (hour, minute, second)
else:
minute, second = divmod(pass_time, 60)
hour, minute = divmod(minute, 60)
string += ") used " + "%04d:%02d:%02d" % (hour, minute, second)
if extra is not None:
string += " " + str(extra).replace("\'", "").replace("{", "(").replace("}", ")") + "."
else:
string += "."
print("\r" + string, end="", flush=True)
if current_state >= total_state:
self.last_time = None
print()
[docs]def calculus_addition(number, base):
"""
Do huge number addition calculus with a small base value, as number + base.
:param number: huge number.
:type number: str
:param base: base value:
:type base: str
:return: number + base.
:rtype: str
.. note::
The integer of parameter "base" must less be than 10 in decimal system.
Example
>>> from dsw import calculus_addition
>>> calculus_addition(number="99999999999999999999999999999999999999999999999999", base="2")
'100000000000000000000000000000000000000000000000001'
"""
number, base = list(number), list(base.zfill(len(number)))
result = [0 for _ in range(len(number) + 1)]
for index in range(len(number) - 1, -1, -1):
sum_value = int(number[index]) + int(base[index]) + int(result[index + 1])
if sum_value < 10:
result[index + 1] = sum_value
else:
flag = 0
while sum_value > 0:
result[index + 1 - flag] = sum_value % 10
sum_value //= 10
flag += 1
result = "".join(list(map(str, result)))
return result if result[0] != "0" else result[1:]
[docs]def calculus_subtraction(number, base):
"""
Do huge number subtraction calculus with a small base value, as number - base.
:param number: huge number.
:type number: str
:param base: base value:
:type base: str
:return: number - base.
:rtype: str
.. note::
The integer of parameter "base" must less be than 10 in decimal system.
Example
>>> from dsw import calculus_subtraction
>>> calculus_subtraction(number="10000000000000000000000000000000000000000000000001", base="2")
'9999999999999999999999999999999999999999999999999'
"""
number, base = [int(item) for item in number], [int(item) for item in base]
residue = ""
for index in range(len(base)):
flag_a, flag_b = len(number) - 1 - index, len(base) - 1 - index
if int(number[flag_a]) >= int(base[flag_b]):
residue = str(int(number[flag_a]) - int(base[flag_b])) + residue
else:
residue = str(10 + int(number[flag_a]) - int(base[flag_b])) + residue
while number[flag_a - 1] == 0:
number[flag_a - 1] = 9
flag_a -= 1
number[flag_a - 1] -= 1
for flag in range(len(number) - 1 - index - 1, -1, -1):
residue = str(number[flag]) + residue
for index in range(len(residue)):
if residue[index] != "0":
return residue[index:]
return "0"
[docs]def calculus_multiplication(number, base):
"""
Do huge number multiplication calculus with a small base value, as number * base.
:param number: huge number.
:type number: str
:param base: base value:
:type base: str
:return: number * base.
:rtype: str
.. note::
The integer of parameter "base" must less be than 10 in decimal system.
Example
>>> from dsw import calculus_multiplication
>>> calculus_multiplication(number="9999999999999999999999999999999999999999999999999", base="2")
'19999999999999999999999999999999999999999999999998'
"""
if base == "0":
return "0"
if base == "1":
return number
number = [int(item) for item in number]
remainder = 0
for index in range(len(number))[::-1]:
current = number[index] * int(base) + remainder
if current >= 10:
number[index] = current % 10
remainder = current // 10
else:
number[index] = current
remainder = 0
while remainder > 0:
number.insert(0, remainder % 10)
remainder //= 10
result = "".join(list(map(str, number)))
return result
[docs]def calculus_division(number, base):
"""
Do huge number division calculus with a small base value, as number / base and number % base.
:param number: huge number.
:type number: str
:param base: base value:
:type base: str
:return: number // base and number % base.
:rtype: (str, str)
Example
>>> from dsw import calculus_division
>>> calculus_division(number="9999999999999999999999999999999999999999999999999", base="2")
('4999999999999999999999999999999999999999999999999', '1')
.. note::
The integer of parameter "base" must less be than 10 in decimal system.
When the divisor (base) is "0", the program will return "0", "0".
"""
if base == "0":
return "0", "0"
if base == "1":
return number, "0"
if len(number) == 1 and number[0] < base:
return "0", number[0]
number, new_number, remainder = [int(item) for item in number], [], 0
for index, quotient in enumerate(number):
current = quotient + remainder * 10
if current >= int(base):
new_number.append(current // int(base))
remainder = current - new_number[-1] * int(base)
else:
new_number.append(0)
remainder = current
quotient = "".join(list(map(str, new_number)))
for index in range(len(quotient)):
if quotient[index] != "0":
return quotient[index:], str(remainder)
return "0", str(remainder)
[docs]def bit_to_number(bit_array, is_string=True, verbose=False):
"""
Transform a bit array to the equivalent decimal number.
:param bit_array: bit array.
:type bit_array: list
:param is_string: type of equivalent decimal number is str.
:type: is_string: bool
:return: equivalent decimal number (may huge) of the inputted bit array.
:rtype: str or int
:param verbose: need to print log.
:type verbose: bool
Example
>>> from dsw import bit_to_number
>>> bit_to_number(bit_array=[1, 1, 1, 1, 1, 0, 0, 1, 1, 1], is_string=True)
'999'
>>> bit_to_number(bit_array=[1, 1, 1, 1, 1, 0, 0, 1, 1, 1], is_string=False)
999
"""
monitor = Monitor()
if is_string:
decimal_number = "0"
for index, a_bit in enumerate(bit_array):
# multiply by 2
decimal_number = calculus_multiplication(number=decimal_number, base="2")
# add current bit
decimal_number = calculus_addition(number=decimal_number, base=str(a_bit))
if verbose:
monitor(index + 1, len(bit_array))
else:
decimal_number = 0
for index, a_bit in enumerate(bit_array):
decimal_number = decimal_number * 2 + a_bit
if verbose:
monitor(index + 1, len(bit_array))
return decimal_number
[docs]def number_to_bit(decimal_number, bit_length):
"""
Transform a decimal number to the equivalent bit array with specific length.
:param decimal_number: decimal number (may huge) of the bit array.
:type decimal_number: str or int
:param bit_length: default length of the bit array.
:type bit_length: int
:return: bit array.
:rtype: list
Example
>>> from dsw import number_to_bit
>>> number_to_bit(decimal_number="999", bit_length=10)
[1, 1, 1, 1, 1, 0, 0, 1, 1, 1]
>>> number_to_bit(decimal_number=999, bit_length=10)
[1, 1, 1, 1, 1, 0, 0, 1, 1, 1]
"""
one_array = []
if type(decimal_number) == str:
while decimal_number != "0": # decimal number > 0
decimal_number, remainder = calculus_division(number=decimal_number, base="2")
one_array.insert(0, int(remainder))
elif type(decimal_number) == int:
while decimal_number > 0:
decimal_number, remainder = divmod(decimal_number, 2)
one_array.insert(0, remainder)
else:
raise ValueError("No such type of decimal number (" + str(type(decimal_number)) + ")!")
if len(one_array) == bit_length:
return one_array
elif len(one_array) < bit_length:
return [0] * (bit_length - len(one_array)) + one_array
else:
return one_array[:bit_length]
[docs]def dna_to_number(dna_sequence, is_string=True):
"""
Transform a DNA string to the equivalent decimal number.
:param dna_sequence: required DNA string.
:type dna_sequence: str
:param is_string: type of equivalent decimal number is str.
:type: is_string: bool
:return: equivalent decimal number (may huge) of the inputted DNA string.
:rtype: str or int
Example
>>> from dsw import dna_to_number
>>> dna_to_number(dna_sequence="ACGTACGT", is_string=True)
'6939'
>>> dna_to_number(dna_sequence="ACGTACGT", is_string=False)
6939
"""
nucleotides = "ACGT"
nucleotide_values = list(map(nucleotides.index, dna_sequence))
if is_string:
decimal_number = "0"
for nucleotide_value in nucleotide_values:
# multiply by length of usage of nucleotides.
decimal_number = calculus_multiplication(number=decimal_number, base=str(len(nucleotides)))
# add current nucleotide value.
decimal_number = calculus_addition(number=decimal_number, base=str(nucleotide_value))
else:
decimal_number = 0
for nucleotide_value in nucleotide_values:
decimal_number = decimal_number * 4 + nucleotide_value
return decimal_number
[docs]def number_to_dna(decimal_number, dna_length):
"""
Transform a decimal number to the equivalent DNA string with specific length.
:param decimal_number: decimal number (may huge) of the DNA string.
:type decimal_number: str or int
:param dna_length: default length of the DNA string.
:type dna_length: int
:return: equivalent DNA string of the decimal number.
:rtype: str
Example
>>> from dsw import number_to_dna
>>> number_to_dna(decimal_number=6939, dna_length=8)
'ACGTACGT'
>>> number_to_dna(decimal_number="6939", dna_length=8)
'ACGTACGT'
"""
nucleotides = "ACGT"
one_array = []
if type(decimal_number) == str:
while decimal_number != "0": # decimal number > 0
decimal_number, remainder = calculus_division(number=decimal_number, base=str(len(nucleotides)))
one_array.insert(0, nucleotides[int(remainder)])
elif type(decimal_number) == int:
while decimal_number > 0:
decimal_number, remainder = divmod(decimal_number, len(nucleotides))
one_array.insert(0, nucleotides[remainder])
else:
raise ValueError("No such type of decimal number (" + str(type(decimal_number)) + ")!")
one_array = "".join(one_array)
return nucleotides[0] * (dna_length - len(one_array)) + one_array