def search(mass, tolerance, delta, restrict): """ :param mass: the formula mass :param tolerance: tolerance to accommodate equipment errors :param delta: computation error allowed :param restrict: True indicates CHNOPS_restricted :return: a list of candidate formulas """ global formulas formulas = [] if restrict: formula = {element: 0 for element in CHNOPS} # order is important, need to be decreasing element_list = [SULFUR, PHOSPHORUS, OXYGEN, NITROGEN, CARBON, HYDROGEN] else: formula = {element: 0 for element in elements} element_list = elements # scale the input data mass *= scalar tolerance *= scalar # this algorithm work with int masses mass_total = int(math.ceil(mass) + 1) # n is the enumber of decision points # for this unbounded implementation: n <= number_elements * mass # but early termination is implemented n = len(formula) * mass_total # initialise row 0 odd_row = [] even_row = [(0, formula) for i in range(0, mass_total)] i = 0 last_index = -1 repetitions = 0 terminate = False while i < n and not terminate: i += 1 if i % 2 == 0: (even_row, last_index, repetitions, terminate) = helper_search(odd_row, mass_total, element_list, last_index, repetitions, formula, terminate) (candidate_mass, candidate) = even_row[-1] if candidate_mass - mass > tolerance + delta and len(even_row) > 1: (candidate_mass, candidate) = even_row[-2] candidate_mass = get_formula_mass(candidate) if candidate_mass + tolerance - mass >= -delta and mass + tolerance - candidate_mass >= -delta and not candidate in formulas: formulas.append(candidate) else: (odd_row, last_index, repetitions, terminate) = helper_search(even_row, mass_total, element_list, last_index, repetitions, formula, terminate) (candidate_mass, candidate) = odd_row[-1] if candidate_mass - mass > tolerance + delta and len(odd_row) > 1: (candidate_mass, candidate) = odd_row[-2] if candidate_mass + tolerance - mass >= -delta and mass + tolerance - candidate_mass >= -delta and not candidate in formulas: formulas.append(candidate) return formulas
def find_all(mass_in, mass, i, c, a, rt): if i == -1: c[0] = mass / a[0] formula = {elem: c[i] for i, elem, in enumerate(sorted_CHNOPS())} formula_mass = get_formula_mass(formula) if abs(formula_mass - mass_in) < 1: formulas.append(formula) else: lcm = a[0] * a[i] / fractions.gcd(a[0],a[i]) l = lcm / a[i] for j in range(0, l): c[i] = j m = mass - j * a[i] r = m % a[0] lbound = rt[i-1][r] while m >= lbound: find_all(mass_in, m, i-1, c, a, rt) m = m - lcm c[i] = c[i] + l
def rule1(formula, restrict): """ restrictions for the number of elements, from table 1 in 7 golden rules paper using the largest from the two sets, rather than a consecvent set :param formula: a formula :param restrict: True if the formula is within restrictions :return: true if it passes the test """ mass = get_formula_mass(formula) if mass < 500: if element_numbers_restriction(formula, 39, 72, 20, 20, 9, 10, 16, 10, 5, restrict): return False elif mass < 1000: if element_numbers_restriction(formula, 78, 126, 25, 27, 9, 14, 34, 12, 8, restrict): return False elif mass < 2000: if element_numbers_restriction(formula, 156, 236, 32, 63, 9, 12, 48, 12, 10, restrict): return False elif mass < 3000: if element_numbers_restriction(formula, 162, 208, 48, 78, 6, 9, 16, 11, 8, restrict): return False return True